基于ATMEGA8和PCF8563的多功能数字闹钟,要求显示时分秒(6个数码管),按键可以设置时间,闹钟响10s。。

基于ATMEGA8和PCF8563的多功能数字闹钟,要求显示时分秒(6个数码管),按键可以设置时间,闹钟响10s。。,第1张

#include <avr/io.h>

#include <util/delay.h>

#include <stdio.h>

#include <avr/interrupt.h>//ISR(BADISR_vect){ //服务程序}

#include<1602_PADATA_PB13CON.h>//LCD1602驱动

//#include<ws_iic_port.h>//IIC的驱动

#include<ws_iic.h>

/////////////////////sssssssssssssssssssssssssssssssssssssss///////////////////////////////////////////////////////////////////////////

//若有 这样的错误 c:/avr/winavr/lib/gcc/../../avr/include/util/delay.h:85:3: warning: #warning "F_CPU not defined for <util/delay.h>"

//一定要定义:在PROJECT===》CONFIGURATION OPTIONS===>GENNRAL===》Frequency===》填写你晶体的频率,就这样,你的问题就可以解决掉了。

//#define _pcf8563_ 4

#define uchar unsigned char

#define uint unsigned int

uchar line1[11]={0,0,'-',0,0,'-',0,0,'w','0'}//显示年月日和星期;放一个空字符。可能是lcd写字符串函数存在问题

uchar line2[9]={0,0,'-',0,0,'-',0,0}//小时,分,秒

//PCF8563的时间存储为 秒-分-小时-日-星期-月/世纪-年7个字节

uchar set_time[7]={56,59,9,27,4,128+7,11}//这些是十进制,使用时要转为bcd码

uchar get_time[7]//读出为bcd码,使用时转为十进制

volatile uchar int_time//设置报警中断的次数

//PCF 8563 iic总线,INTA低电平有效,32.768KHz 的振荡

//16 个寄存器设计棚腔成可寻址的8 位并行寄存器但不是所有位都有用前两个寄存器内存地址00H 01H 用于控制寄存器和状态寄存器内存地址02H 08H 用于时钟计数器秒~年计数器地址

//09H 0CH 用于报警寄存器定义报警条件地址0DH 控制CLKOUT 管脚的输出频率地址0EH 和0FH分别用于定时器控制寄存器和定时器寄存链源衫器秒分钟小时日月年分钟报警小时报警日报

//警寄存器编码格式为BCD 星期和星期报警寄存器不以BCD 格式编码

/*

400kHz I2C 总线(VDD=1.8 5.5V) 其从地址读0A3H写0A2H

//地址 寄存器名称 Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0

00H 控制/状态寄存器1 TEST1 0 STOP 0 TESTC 0 0 0 .1)TEST1=0 普通模式TEST1=1 EXT_CLK 测试模式2)STOP=0 芯片时钟运行STOP=1 所有芯片分频器异步置逻辑

0 芯片时钟停止运行CLKOUT 在32.768kHz 时可用3)TESTC=0 电源复位功能失效普通模式时置逻辑0

TESTC=1 电源复位功能有效4)位6,4,2,1,0 缺省值置逻辑0

01H 控制/状态寄存器2 0 0 0 TI/TP AF TF AIE TIE

AF 和AIE 都裂神有效时则INT 一直有效;

当报警发生时AF 被置逻辑1 在定时器倒计数结束时TF 被置逻辑1

AIE=0 报警中断无效AIE=1 报警中断有效

TIE=0 定时器中断无效TIE=1 定时器中断有效

0DH CLKOUT 输出寄存器 FE ·····FD1 FD0

0EH 定时器控制寄存器 TE ·····TD1 TD0

0FH 定时器倒计数数值寄存器 定时器倒计数数值(二进制)

02h 秒 VL 00 -59 BCD 码格式数 VL=0 保证准确的时钟/日历数据VL=1 不保证准确的时钟/日历数据

03h 分钟 00 -59 BCD 码格式数

04h 小时 00 -59 BCD 码格式数

05h 日 01- 31 BCD 码格式数

06h 星期 0- 6

07h 月/世纪 C 01 -12 BCD 码格式数

08h 年 00- 99 BCD 码格式数

09h 分钟报警 AE 00 -59 BCD 码格式数

0Ah 小时报警 AE 00 -23 BCD 码格式数

0BH 日报警 AE 01- 31 BCD 码格式数

0CH 星期报警 AE 0- 6

*/

/*

atmega16中,IIC 的SCL, SDA端口可以设置上拉电阻,这样可节约外部上拉电阻。

SCL frequency= CPU Clock frequency/(16 + 2(TWBR) . 4^TWPS)

TWI 工作在主机模式时,TWBR 值应该不小于10。否则主机会在SDA 与 SCL 产生错误输出作为提示信号。问题出现于TWI 工作在主机模式下,向从机发送Start + SLA + R/W 的

时候( 不需要真的有从机与总线连接)。

*/

//器件地址:A0 A1 A2 = 0 0 0

#define WR_SLA8563_ADDR 0xA2 //write device-address

#define RD_SLA8563_ADDR 0xA3 //read device-address

//以下为控制器寄存器地址

//以下为二进制存储

#define CTRL_BUF1 0x00

#define CTRL_BUF2 0x01

//以下为BCD 存储

#define SECOND_DATA_BUF 0x02

#define MINUTE_DATA_BUF 0x03

#define HOUR_DATA_BUF 0x04

#define DAY_DATA_BUF 0x05

#define WEEK_DATA_BUF 0x06

#define MONTH_DATA_BUF 0x07

#define YEAR_DATA_BUF 0x08

#define MINUTE_AE_BUF 0x09

#define HOUR_AE_BUF 0x0A

#define DAY_AE_BUF 0x0B

#define WEEK_AE_BUF 0x0C

//以下为二进制存储

#define CLK_FRQ_BUF 0x0D //80-37.768kHz81--1024Hz82--32Hz83--1Hz

#define TIMER_CTRL_BUF 0x0E

#define COUNT_VAL_BUF 0x0F

#define PCF8563_ERR 0

#define PCF8563_CRR 1

//十进制转BCD码,即高位取出来后左移4位,低位取出不变

//BCD码这种编码形式利用了四个位元来储存一个十进制的数码

#define Int_To_BCD(dec) (((dec/10)<<4)+dec%10) //PCF8563的时间以及报警设置都是BCDB码 32(DEC)-->32(BCD)

#define BCD_To_Int(bcd) ((bcd>>4)*10+(bcd&0x0f)) //高位乘10,低位不变

//写一个数据

uchar Write_Abyte(uchar Addr,uchar data)

{

//判断写地址是否成功,成功返回1,否者范围0

if ((I2C_Write(WR_SLA8563_ADDR,Addr,data))==PCF8563_ERR)

return PCF8563_ERR

return PCF8563_CRR

}

//设置小时,分,秒

void Set_time_HSS(uchar hour,uchar minute,uchar second)

{

hour=Int_To_BCD(hour)

minute=Int_To_BCD(minute)

second=Int_To_BCD(second)

Write_Abyte(HOUR_DATA_BUF,hour)

Write_Abyte(MINUTE_DATA_BUF,minute)

Write_Abyte(SECOND_DATA_BUF,second)

}

//设置年月日

void Set_time_YMD(uchar year,uchar month,uchar day)

{

year=Int_To_BCD(year)

month=Int_To_BCD(month)

day=Int_To_BCD(day)

Write_Abyte(YEAR_DATA_BUF,year)

Write_Abyte(MONTH_DATA_BUF,month)//包含世纪

Write_Abyte(DAY_DATA_BUF,day)

}

void Set_Time_Week(uchar week)

{

week=Int_To_BCD(week)

Write_Abyte(WEEK_DATA_BUF,week )

}

//一次将数组中时间写入芯片,n应<=7.

void Set_Time_All(uchar start_adr,uchar *ptdata,uchar n)

{

uchar i,temp

for(i=0i<ni++)

{

temp=Int_To_BCD(ptdata[i])//化为bcd码

Write_Abyte(start_adr+i,temp)

}

}

//读N个数据

uchar Read_Nbyte(uchar start_addr,uchar *pRdDat,uchar num)//使用 uint8_t I2C_Read_(uint16_t wrDAdr,uint8_t wordAdr,uint8_t rdDAdr,uint8_t *pRdDat,uint8_t num)

{

if( I2C_Read_(WR_SLA8563_ADDR,start_addr,RD_SLA8563_ADDR,pRdDat,num)==I2C_ERR )

return PCF8563_ERR

return PCF8563_CRR

}

//uchar get_time(uchar start_adr,uchar *ptdata,uchar n)

//{

//}

//初始化8563的工作方式

void PCF8563_Init(void)

{

//报警设置

//CTRL_BUF1=0x00 //TEST1 0 STOP 0 TESTC 0 0 0 普通模式都置0

//CTRL_BUF2= 0x00010010 //0 0 0 TI/TP AF TF AIE TIE 报警中断有效

//这里需要将控制字内容写入,需要调用IIC的写数据 *** 作 uint8_t I2C_Write(uint16_t wrDAdr,uint8_t wordAdr,uint8_t dat) wrDAdr-->器件写地址

Write_Abyte(CTRL_BUF1,0x00)

Write_Abyte(HOUR_AE_BUF,Int_To_BCD(10) )

Write_Abyte(MINUTE_AE_BUF,Int_To_BCD(20) )

Write_Abyte(CTRL_BUF2,0x13)

}

void Disp_Time_In_LCD1602( )

{

uchar i

//第一行 年月日 周次;第二行 小时 分 秒

Read_Nbyte(SECOND_DATA_BUF, get_time,7)//一次获得所有数据

get_time[0]= get_time[0]&0x7f//秒

get_time[1]= get_time[1]&0x7f//分

get_time[2]= get_time[2]&0x3f//小时

get_time[3]= get_time[3]&0x3f//日

get_time[4]= get_time[4]&0x0f//星期

get_time[5]= get_time[5]&0x1f//月再下一个为年

for(i=0i<7i++)

{

get_time[i]=BCD_To_Int(get_time[i])//将BCD转为十进制后处理

}

//uchar line1[11]={0,0,'-',0,0,'-',0,0,'w','0'}//显示年月日和星期

line1[0]=(get_time[6]/10)|0x30//取十位数

line1[1]=(get_time[6]%10)|0x30//取个位数,其它同

line1[3]=(get_time[5]/10)|0x30//取十位数

line1[4]=(get_time[5]%10)|0x30//取个位数,其它同

line1[6]=(get_time[3]/10)|0x30//取十位数

line1[7]=(get_time[3]%10)|0x30//取个位数,其它同

line1[9]=get_time[4]|0x30//取个位数,其它同,week

//uchar line2[8]={0,0,'-',0,0,'-',0,0}//小时,分,秒

line2[0]=(get_time[2]/10)|0x30//取十位数

line2[1]=(get_time[2]%10)|0x30//取个位数,其它同

line2[3]=(get_time[1]/10)|0x30//取十位数

line2[4]=(get_time[1]%10)|0x30//取个位数,其它同

line2[6]=(get_time[0]/10)|0x30//取十位数

line2[7]= get_time[0] |0x30 //取个位数,其它同

i=LCD_Show_Num_New(0,0,20)//在年份前加入20

LCD_Str_Write(i,0,line1)

LCD_Str_Write(0,1,line2)

}

//增加中断1来设置初始时间;低电平有效

ISR(INT1_vect)

{

Set_Time_All(SECOND_DATA_BUF,set_time,7)

// Write_Abyte(CTRL_BUF2,0x1f)

}

//增加中断0来记录报警次数;低电平有效

ISR(INT0_vect)

{

int_time++

// Write_Abyte(CTRL_BUF2,0x0A)//清除中断

//Write_Abyte(HOUR_AE_BUF,Int_To_BCD(11))

}

void Interrupt_init()

{

DDRD&=~(_BV(PD2)|_BV(PD3))//2个中断口为输入口

GICR|=_BV(7)|_BV(6)//开启中断0,1

MCUCR|=_BV(3)|_BV(1) //INT1下降沿触发,INT0下降沿中断

GIFR|=_BV(7)|_BV(6)//清除中断标志

SREG|=_BV(7)//开启中断

}

int main(void)

{uchar i

TWBR = 0X0F //设置TWI波特率

TWSR &= 0XFC //设置TWI预分频 为 1

LCD_Init()

PCF8563_Init()

_delay_ms(100)

///中断设置

Interrupt_init()

// Write_Abyte(CLK_FRQ_BUF,0x81)//1024Hz的频率发生

i=LCD_Str_Write(8,1,"times")

while(1)

{

_delay_ms(100)

Disp_Time_In_LCD1602()

LCD_Show_Num_New(13,1,int_time)//显示中断次数

}

}

前段时间用pcf8563芯片做了个电子时钟,这个芯片自动走时间,我只用去读和写就行了,pcf8563要加一个后备电池,这样就不怕单片机掉电了。这个不太符合你的要求,不过这是我现成的,我可不想在这里重新写氏册代码。代码不是很规范,但是能正常运行。

你在Keil里建个工程,下面一段是display.c的代码:

#include "at89x51.h"

#include "PCF8563.h"

//#include "TG12232.h"

#define Key_Set P2_2

#define Key_Add P2_1

#define Key_Sub P2_0

//#define LCD_CS P2_5

//#define LCD_DATA P2_6

//#define LCD_CLK P2_7

void Key_down()

void Displaybuffer(char Location)

//void LCD_Display()

unsigned char LedTable[10]={0x3f,0x03,0x6d,0x67,0x53,0x76,0x7e,0x23,0x7f,0x77}

bit state=0

char set=0

void main()

{

unsigned char i,j,n=2

P1=0

TMOD=0x01

TH0=0x4c

TL0=0x00

ET0=1

EA=1

// P8563_init()

P2=0xff

P3=0x02

P1=LedTable[8]

// while(n--)

for(i=0i<250i++)

 for(j=0j<6j++)

 {

  delay(10)

  P3<<=1

  if(P3==0x80)

  P3=0x02

 御告 delay(10)

 }

delay(5000)

// lcd_init()

// set_lcd_position(0,1)    //汉字定位到上行左端

// lcd_display(0,0,"Welcome to use!")

// lcd_display(1,0,"  Leo.Zheng  ")

// delay(1000)

// lcd_send_com(0x01)//清除

// lcd_display(0,0,"20  /  /")

while(1)

{

Key_down()

Displaybuffer(set)

// LCD_Display()

}

}

void Time0_H() interrupt 1

{

static unsigned char i=0

TH0=0x4c

TL0=0x00

i++

if(i==8)

i=0

state=~state

}

}

/*

void LCD_Display()

{

lcd_display_char(0,2,((g8563_Store[6]&0xf0)>>4)+0x30)//年

lcd_display_char(0,3,(g8563_Store[6]&0x0f)+0x30)//

}*/

void Key_down()

{

// static char set=0

unsigned char buffer

if(!Key_Set)

for(buffer=0buffer<250buffer++)

 _nop_()

if(!Key_Set)

{

if(set==0)

{

 writeData(0x0,0x20)//使时间停止

 TR0=1

}

set++

if(set==4)

{

 set=0

 TR0=0

 writeData(0x0,0x00)

}

while(!Key_Set)

 Displaybuffer(set)

}

if(!Key_Add)

for(buffer=0buffer<250buffer++)

 _nop_()

if(!Key_Add)

{

if(set==0)

 歼拆宏return

P8563_gettime()

buffer= g8563_Store[set-1]

buffer=((buffer&0xf0)>>4)*10+(buffer&0x0f)

if(buffer>=59)

 buffer=0

else if(buffer>=23 && set==3)

 buffer=0

else

 buffer++

buffer=(buffer/10<<4)+(buffer%10)

writeData(set+1,buffer)

while(!Key_Add)

 Displaybuffer(set)

}

if(!Key_Sub)

for(buffer=0buffer<250buffer++)

 _nop_()

if(!Key_Sub)

{

if(set==0)

 return

P8563_gettime()

buffer= g8563_Store[set-1]

buffer=((buffer&0xf0)>>4)*10+(buffer&0x0f)

if(buffer == 0)

{

 if(set==3)

  buffer=23

 else

  buffer=59

}

else

 buffer--

buffer=(buffer/10<<4)+(buffer%10)

writeData(set+1,buffer)

while(!Key_Sub)

 Displaybuffer(set)

}

}

void Displaybuffer(char Location)

{

unsigned char i

P8563_gettime()

/*****************************************/   

if(Location==1 && state==0)

{

P1=0

P3=0

goto sec_bit1

}

P3=0x02

P1=LedTable[g8563_Store[0]&0x0f] //sec

sec_bit1:

for(i=0i<250i++)

P1=0

if(Location==1 && state==0)

{

P1=0

P3=0

goto sec_bit2

}

P3=0x04

P1=LedTable[(g8563_Store[0]&0xf0)>>4]

sec_bit2:

for(i=0i<250i++)

P1=0

/*****************************************/

if(Location==2 && state==0)

{

P1=0

P3=0

goto min_bit1

}

P3=0x08

P1=LedTable[g8563_Store[1]&0x0f]  //min

min_bit1:

for(i=0i<250i++)

P1=0

if(Location==2 && state==0)

{

P1=0

P3=0

goto min_bit2

}

P3=0x10

P1=LedTable[(g8563_Store[1]&0xf0)>>4]

min_bit2:

for(i=0i<250i++)

P1=0

/*****************************************/

if(Location==3 && state==0)

{

P1=0

P3=0

goto hour_bit1

}

P3=0x20

P1=LedTable[g8563_Store[2]&0x0f]    //hour

hour_bit1:

for(i=0i<250i++)

P1=0

if(Location==3 && state==0)

{

P1=0

P3=0

goto hour_bit2

}

P3=0x40

P1=LedTable[(g8563_Store[2]&0xf0)>>4]

hour_bit2:

for(i=0i<250i++)

P1=0

P3=0x02

/*****************************************/

}

这下面一段是pcf8563.h的代码:

#ifndef __PFC8563_H__

#define __PFC8563_H__

#include <intrins.h>

#define uchar unsigned char

sbit SDA=P2^4

sbit SCL=P2^3

//extern void          _nop_     (void)

//extern void delay(unsigned int ms)

uchar g8563_Store[7] /*时间交换区,全局变量声明*/

uchar code c8563_Store[7]={0x01,0x02,0x07,0x09,0x04,0x02,0x12} /*写入时间初值:秒,分,时,日,周,月,年(BCD码)

07:59:00*/

void delay(long time)

{while(time--)

}

/********************************************

内部函数,延时1

********************************************/

void DD()

{

//delay(1)

// uchar i

//    for(i=0i<250i++)

_nop_()

  _nop_() /*根据晶振频率制定延时时间*/

}

/********************************************

内部函数,I2C开始

********************************************/

void Start()

{  EA=0

 SDA=1

 SCL=1

 DD()

 SDA=0

 DD()

 SCL=0

}

/********************************************

内部函数,I2C结束

********************************************/

void Stop()

{

 SDA=0

 SCL=0

 DD()

 SCL=1

 DD()

 SDA=1

 DD()

 EA=1

}

/********************************************

内部函数,输出ACK ,每个字节传输完成,输出ack=0,结束读数据,ack=1

********************************************/

void WriteACK(uchar ack)

{

 SDA=ack

 DD()

 SCL=1

 DD()

 SCL=0

}

/********************************************

内部函数,等待ACK

********************************************/

void WaitACK()

{  uchar errtime=20

 SDA=1

 DD() /*读ACK*/

 SCL=1

 DD()

 while(SDA)

 {  errtime--

    if(!errtime)

    {

Stop()

SDA=0  //自己加的******

    }

 }

 SDA=1 //自己加的******

 SCL=0

 DD()

}

/********************************************

内部函数.输出数据字节

入口:B=数据

********************************************/

void writebyte(uchar wdata)

{

 uchar i

 for(i=0i<8i++)

 {

     if(wdata&0x80) SDA=1

     else SDA=0

     wdata<<=1

     SCL=1

     DD()

     SCL=0

 }

 WaitACK()     //I2C器件或通讯出错,将会退出I2C通讯

}

/********************************************

内部函数.输入数据

出口:B

********************************************/

uchar Readbyte()

{

 uchar i,bytedata

 SDA=1

 for(i=0i<8i++)

 {

    SCL=1

    bytedata<<=1

    bytedata|=SDA

    SCL=0

    DD()

 }

 return(bytedata)

}

/********************************************

输出数据->pcf8563

********************************************/

void writeData(uchar address,uchar mdata)

{

 Start()

 writebyte(0xa2) /*写命令*/

 writebyte(address) /*写地址*/

 writebyte(mdata) /*写数据*/

 Stop()

}

/********************************************

输入数据<-pcf8563

********************************************/

uchar ReadData(uchar address) /*单字节*/

{  uchar rdata

 Start()

 writebyte(0xa2) /*写命令*/

 writebyte(address) /*写地址*/

 Start()

 writebyte(0xa3) /*读命令*/

 rdata=Readbyte()

 WriteACK(1)

 Stop()

 return(rdata)

}

void ReadData1(uchar address,uchar count,uchar * buff) /*多字节*/

{  uchar i

 Start()

 writebyte(0xa2) /*写命令*/

 writebyte(address) /*写地址*/

 Start()

 writebyte(0xa3) /*读命令*/

 for(i=0i<counti++)

 {

 buff[i]=Readbyte()

 if(i<count-1) WriteACK(0)

 }

WriteACK(1)

 Stop()

}

/********************************************

内部函数,读入时间到内部缓冲区

********************************************/

void P8563_Read()

{   uchar time[7]

  ReadData1(0x02,0x07,time)

  g8563_Store[0]=time[0]&0x7f /*秒*/

  g8563_Store[1]=time[1]&0x7f /*分*/

  g8563_Store[2]=time[2]&0x3f /*小时*/

  g8563_Store[3]=time[4]&0x07 /*星期*/

g8563_Store[4]=time[3]&0x3f /*日*/

g8563_Store[5]=time[5]&0x1f /*月*/

g8563_Store[6]=time[6] /*年*/

}

/********************************************

读入时间到内部缓冲区----外部调用

********************************************/

void P8563_gettime()

{

  P8563_Read()

  if(g8563_Store[0]==0)

    P8563_Read() /*如果为秒=0,为防止时间变化,再读一次*/

}

/********************************************

写时间修改值

********************************************/

//void P8563_settime()

//{

//     uchar i

//     for(i=2i<=8i++) { writeData(i,g8563_Store[i-2]) }

//     writeData(6,g8563_Store[3])

//}

/********************************************

P8563的初始化-----外部调用

********************************************/

/*

void P8563_init()

{

  uchar i

  if((ReadData(0xa)&0x3f)!=0x8) //检查是否第一次启动,是则初始化时间

  {

 //     for(i=0i<=6i++) g8563_Store[i]=c8563_Store[i] //初始化时间

//      P8563_settime()

      writeData(0x0,0x00)

      writeData(0xa,0x8) //8:00报警

      writeData(0x1,0x12) //报警有效

      writeData(0xd,0xf0)

  }

}

*/

#endif

www.ledshow.net也是一个led网站

摘 要

本系统是从实际应用角度出发,针对当前市场上流行的LED产品的应用领域而设计制作的多功能电子显示屏,可用于商场导购促销显示、新闻与广告显示、车站机场班次时间资讯显示等。

本简易16行*64列LED电子显示屏根据颤带题目设计要求,硬件部分主要包括SPCE061A单片机系统、16块8*8LED点阵显示模块构茄拆芦成16*64点阵、显示驱动电路、SPR4096存储器、PCF8563实时时钟电路、键盘御碧输入控制器等部分,还外扩了液晶显示、温度实时检测、无线通讯、电机驱动屏幕旋转等电路,。本系统不仅能够实现数字、字母、汉字等预存信息的切换显示,同时还可以实现信息的定时循环、上下左右滚屏、LED显示亮度连续可调、实时时间显示、实时温度显示、无线遥控、显示屏旋转等扩展功能。另外,本系统可以和PC机通讯,通过PC机串口对显示信息进行更新。

关键词:LED电子显示屏 SPCE061A 串行通信

Abstract

The LED lattice display system is a kind of new information display media with the rapid development of the computer, micro-electronics, photoelectron technology.

This 16*64 LED display system includes SPCE061A MCU system, sixteen 8*8 LED lattice modules, display driving circuit, SPR4096 memory module, PCF8563 as the real-time clock chip, keyboard controller et. In addition, it includes LCD circuit, real-time temperature detective, RF communication circuit. This system can display the numbers, letters, Chinese characters. It can display the information timely and circularly, up-rollingly, down rollingly left-rollingly, right-rollingly. The lightness of the displaying information can be adjusted continuously. Further more, this system can be remote controlled and communicate with PC by COM1 to update the display information.

Keywords: LED lattice display system SPCE061A serial communication

目 录

一、方案比较 4

1、控制系统 4

2、点阵信息提取方案 4

3、显示驱动电路 5

二、硬件设计与论证 5

1、主控制单片机 6

2、LED显示驱动电路 6

3、数据存储器 8

4、键盘液晶显示模块 9

5、无线通信模块 9

6、时钟电路的设计 10

7、温度检测 10

8、打印机的选择 11

9、旋转底盘的设计 11

三、系统的软件设计 11

1、主程序流程图 12

2、点阵字模信息提取程序流程图 12

3、LED各显示程序 12

4、串行通信程序 12

5、PC机客户程序 12

四、系统功能测试 16

1、测试及制作中所用仪器 16

2、键盘各键功能 16

3、单元模块电路测试 16

4、系统整体功能测试 16

五、总结 17

一、方案比较

1、控制系统

LED点阵电子显示屏的设计一般有两种方案:

方案一:采用可编程逻辑器件作为核心控制器产生LED点阵的行、列驱动信号。由于该系统不仅要实现信息的显示,还要具备键盘控制器、显示亮度连续可调、实时时钟显示、与PC机通讯等功能及其他发挥功能,这就要求需要用中大规模的PLD,设计多个接口电路,开发周期长,不易进一步扩展,同时系统的成本会急剧上升(相对于第二种方案)。因此,本设计并未采用这种方案。

方案二:采用单片机系统来实现。鉴于SPCE061A单片机比传统的51系列8位单片机具有更加丰富的资源,而且数据处理速度快,同时“61板除了具备单片机最小系统电路外还包括有电源电路、音频电路(含MIC输入部分和DAC音频输出部分)、复位电路等,体积小,可靠性高。本系统的设计采用双单片机系统,一个主要用于完成多功能显示控制功能,另一个主要用于实时时钟显示、实时温度检测显示、无线通讯以及其他的扩展发挥部分功能,这样提供了充足的内部空间和更多的外部接口;同时由于安装和调试工作可以并行进行,极大地缩短了总体设计和制造的时间。

2、点阵信息提取方案

要用LED点阵来显示数字、字母和汉字等信息,首先要能够提取出其字模数据,即一个16*8的点阵数字、字母的字模数据共有16个字节,一个16*16的点阵汉字的字模数据共有32个字节。首先要确定点阵信息提取方案。

方案一:固定汉字显示,就是将要显示的语句中全部汉字的字母数据依次提取出来,按顺序存放在存储器中,当有显示任务时,直接取出字模数据送至显示器即可。这种方法占用空间少,程序实现简单,显示速度快。本系统中对10组预存信息的点阵信息的提取和存储就是采用这种方案。但是,要想显示大量的汉字信息或直接对显示信息进行更新,则几乎是不可能的事。因此,要实现这样的功能就要采用第二种方案。

方案二:将标准的点阵信息字模数据的字库文件(本系统中采用汉字库文件HZK16、ASCII码库文件ASC16)装入外扩ROM存储器,采用与PC机相同的编码(机内码),先进行基于PC机的预处理,提取需显示内容的机内码,通过串口发给单片机,单片机首先进行判断,若是ASCII码,则直接计算出起始地址,在ASC16文件中指定位置取出连续的16个字节即为其字模信息;若为汉字,单片机将机内码转换为区码和位码,再计算出起始地址,在HZK16文件中指定位置取出连续的32个字节即为其字模信息,然后送到显示器去显示。另外,PC机与单片机之间串口通信只是传输机内码,而不是传输字模信息,传输信息量小,不需要复杂的通信协议。这样既可以减轻单片机的负担,而且可以根据要求随时改变显示内容,非常简单灵活。

3、显示驱动电路

常用的显示驱动方式有三种:

方案一:串行控制驱动,这种方式的好处是单元内的线路连接简单,给印刷电路板的设计带来方便,减少了布线的密度,方便以后的制作与调试,而且相对提高了每个单元的可靠性;

方案二:并行控制驱动,将显示数据通过并行(一般为8位)方式送入驱动电路,这样的好处是:相对于串行控制而言,数据的刷新速度快,在处理同等数量的数据时,对处理速度要求可以大大降低,从而提高了系统的稳定性,但也正因为“并行”使单元内的数据线路的连接更加复杂,布线后的排错难度大大增加;

方案三:采用专用集成电路(ASIC)直接驱动,由于这种专用集成电路是集行控制、列控制和外围驱动于一体,使系统的稳定性更为可靠,特别适合户外的大型或者超大型显示屏。因为这种类型的显示屏对图像显示要求高,不仅要保证图像的一致性,而且要保证图像的稳定、高亮。

本次设计的显示屏仅为16行*64列,更适合采用串行控制这种方式,这样做既省去了并行控制驱动在制版过程中十分复杂的布线,又因为没有采用专用集成电路在一定程度上降低了整个系统的成本。

二、硬件设计与论证

根据以上的系统方案比较与分析,本设计的系统总体组成框图如图1所示:

图1 系统的总体组成框图

系统整体由三大部分构成:

以单片机1#为核心的模块一:包括16*64LED点阵、驱动电路、STR4096存储器、无线数传模块、旋转底盘、光电传感器、音箱、打印机。实现功能:主要用来实现点阵的显示,包括特定标语库内容的显示,适时时间显示、适时温度显示,并实现上下左右滚屏等各种花样显示;存储器用来存储汉字和ASCII码的点阵库,并实现掉电不丢失功能;无线模块实现标语库更新和接受设置信息;底盘可实现显示屏的左右转动,摆动幅度可调;在商场导购中,光电传感器用于检测人员进出,可与自动门配合使用,音箱播放“欢迎光临”等语音信息;在广告牌应用中,打印机用于名片打印。

以单片机2#为核心的模块二:包括4*4键盘、液晶、无线数传模块。实现功能:该部分实现遥控器的功能,可以遥控设置显示屏的滚动模式,选择标语库,设置时间,设置摆头幅度;实现标语库的更新。(键盘使用说明见附录一)

以上位PC机为核心的模块三:包括上位机软件和MAX232。实现功能:上位机主要实现标语库的数据更新,上位机软件通过MAX232将更新内容(汉字或者ASCII码的机内码)送到单片机2#,然后无线传输到单片机1#实现数据更新。

以下是各单元电路的具体设计:

1、主控制单片机

采用凌阳公司的16位单片机SPCE061A作为主控制器。由于SPCE061A内置有2K字的SRAM和32K字的内存FLASH,能满足本系统数据处理及LED点阵显示所需数据的存储要求;CPU时钟频率高达49.152MHz,能满足刷新速度要求。另外,“61板”功能较强、性价比高,具有体积小、集成度高、易扩展、功耗小等优点,简化主控制系统的硬件电路设计,可靠性高,而且凌阳单片机具有C语言风格的汇编语言,有与标准C兼容的C语言,C语言函数可以与汇编函数互相调用,使其开发更加容易,实现整个系统更加简单。

2、LED显示驱动电路

本次设计中16行*64列LED电子显示屏的制作以及其显示驱动电路的设计制作都是非常关键的部分。下面主要介绍一下显示驱动电路的设计。

本LED点阵屏采用动态扫描的方式显示,即逐行扫描,工作时先将一行点阵字模通过列驱动输出,然后运用译码器选中对应行,使该行得以显示,接着再送下一行数据,再选中下一行有效,直到16行全被扫描一遍。至此,一幅完整的文字信息就显现出来。然后在反复扫描这16行直至显示新的信息。采用这种方式的优点是耗电少,成本低,寿命长,但是也存在显示亮度及内容显示稳定的问题。根据视觉滞留原理,根据视觉滞留原理,每屏的完整的显示时间应控制在20ms之内,即50Hz,人眼看上去才不会觉得闪烁。由于要扫描16 行的点阵,所以每行的时间绝不能超过20ms÷16=1.25ms,同时也不是每行的扫描时间越短越好,因为LED的亮度同电流的大小和维持时间的长短有关。LED点阵块的单点静态电流一般在10mA左右,由于占空比是1/16,所以单点的动态电流最大可以达到160mA。在维持时间恒定的情况下,电流越大(不超过额定电流),点阵亮度也越亮,而在电流恒定的情况下,需要一段维持时间来保持亮度。试验表明当输入LED的电流为15mA时,维持时间至少需要1ms,否则LED呈微亮状态。由于设计时设置SPCE061A单片机的时钟频率为24MHz,而每次传送移行的字模数据有64位,经计算传输所需的时间小于1ms,这样就能充分利用列驱动74HC595的锁存功能,即在它接收下一行待显示的数据,还没有锁存新数据的这段时间来显示本行的内容,这样就不需要额外加延时来增加显示屏的亮度。采用这个方法就不要再增加LED的列驱动器件,从而使整个硬件结构更简化,成本降低。

行信号的处理是由四十六译码器CD4514来完成译码,输出为高。由于显示屏行的组成是多个模块并联而成的,因而行驱动得功率要求比较大,而且我们进行行扫描时需要所选行为低,故加反相驱动器ULN2803来满足要求。

列信号的处理列信号的处理主要由8片8位带锁存的串入并出移位寄存器74HC595来完成。从单片机IO口串行输出的64位点阵数据随着移位时钟的作用逐位移动到对应位置,在接收到锁存信号后,将数据并行输出至LED的列线,最后在行驱动信号作用下点亮一行LED象素。

显示扫描电路的电路图如图2所示。

图2 LED显示扫描驱动电路

3、数据存储器

设计题目要求能增大到10组预存信息,且显示信息具有掉电保护功能,同时考虑到要把汉字点阵字库文件HZK16(261K字节)和ASCII码点阵字库文件ASC16(4K字节)装入到ROM存储器中,以便根据机内码在字库中寻址,找到对应的字模,提取后再送到点阵显示屏显示。因为SPCE061单片机的内存Flash只有32K,还要存放程序,因此需外扩数据存储器。我们选择了凌阳“61板”的配套模组SPR4096。SPR4096是一个高性能的4M-bit(512K字节)FLASH,分为256个扇区,每个扇区为2K字节。SPR4096串行接口的工作频率可达5MHz,数据存取速度和存储容量都能够达到我们的要求。硬件图连接如图3所示:

图3 SPR4096硬件连接图

4、键盘液晶显示模块

为使用键盘作为显示屏控制器,实现多功能显示控制,我们使用智能型键盘显示控制芯片HD7279A作为4*4键盘与单片机之间的接口,其与微处理器仅需4条接口线,采用串行通信方式,占用CPU端口少,同时HD7279得到键盘码后通过中断服务程序把按键信息送给单片机,使单片机可以腾出更多时间质性其他 *** 作。设计中我们需要用液晶模块显示遥控单片机菜单的各信息。在本系统中选用了OCM4×8C模块,可以显示字母、数字符号、中文字型及图形,具有绘图及文字画面混合显示功能,既可采用并行接口,又可采用串行接口,连线较为方便。HD7229、OCM4×8C与单片机连接原理图如图4所示。

5、无线通信模块

在本设计中,我们采用了两块61板,1#板主要用于完成控制LED显示屏,2#板主要用于键盘液晶控制、实时时钟、实时温度检测显示、与PC机通讯以及其他的扩展发挥部分功能。两板之间采用无线通讯进行数据传输。为满足系统的要求我们选择了SRWF-1型微功率无线数传模块,该模块的特点是:高抗干扰能力和低误码率、完善的通讯协议、数据实时同步、看门狗实时监控、传输距离远、低功耗及休眠功能高可靠性,体积小、重量轻。

图4 键盘显示电路

SRWF-1型模块提供2个串口3种接口方式,COM1为TTL电平UART接口,COM2由用户自定义为标准的RS-232/RS-485接口(用户只需拔/插短路器再上电即可改变接口类型)。SRWF-1提供的两个串口,在使用时注意以下事项:(1)对于空中接收的数据,SRWF-1通过串口转送给终端设备时,COM1和COM2同时输出,即用户如果在COM1和COM2各连接了1个设备,他们都可同时收到数据;(2)对于由终端设备送来,准备向空中发射的数据,SRWF-1只能正确接收COM1或COM2其中1个串口送来的数据,否则将造成数据通讯混乱。如终端设备在向COM1发送1个0x12(数据正在传送)时,再向COM2发送1个0x34,模块将收到一个数据串0x12,0x34。

图5 SRWF-1与用户设备接口电路

注:没有使用的引脚可以悬空不连。但不能连接长悬空线,以免引入干扰。

6、时钟电路的设计

系统要求实现实时时间的显示,这里我们选用串行日历时钟芯片PCF8563,,与单片机的连线大为减少,极大的节省了单片机的系统资源。PCF8563与单片机的接口电路如图6所示。而且该部分电路还加了掉电保护功能,在主供电系统意外断电时,即Vcc为0V时,D1截止, 3.6V备用电源通过D2继续给PCF8563供电,保证8563的正常运行。

图6 PCF8563时钟电路

7、温度检测

本系统扩展了实时温度检测显示功能,选用DS18B20一线式数字温度传感器,通过单片机读取当前环境温度可通过键盘切换显示时间和温度。

图6 DS18B20与单片机的接口电路

8、打印机的选择

本系统还扩展了打印机功能,在广告牌应用中用来打印名片等相关信息。我们选择了北京市兴伟机电应用技术研究所研制的微型热敏/针打打印机。通过通用的ESC/P打印命令实现字符的打印。

图7 打印机接口控制时序图

9、旋转底盘的设计

针对应用的需要,系统扩展了显示屏旋转功能,用普通小型直流电机提供动力,由变速箱减速并加大驱动能力,实现显示屏幕左右摆动,并且幅度可调。

图8 直流电机驱动电路

三、系统的软件设计

本系统的软件部分主要包括主程序、点阵字模信息提取程序、LED各显示程序、串行通信程序以及PC机客户程序等。

1、主程序流程图

见图8。

2、点阵字模信息提取程序流程图

见图9。

3、LED各显示程序

LED显示屏的显示方式有静止、上下滚屏、左右滚屏等多种方式。其中上下滚屏显示程序类似,左右滚屏显示程序类似,其他多花样的显示方式程序都是在此基础上进行改动而来的。因此主要给出静态显示、上移显示、左移显示这三种典型方式的程序流程图,见图10、图11、图12。

4、串行通信程序

每当向PC机客户程序里输入新显示内容并发送给单片机时,单片机就产生串行中断,接受待显示信息的机内码,然后再利用点阵字模信息提取程序得到点阵数据送到LED显示屏显示。单片机接受数据采用中断的方式。串行中断程序流程图见图13。

5、PC机客户程序

本系统的PC机客户程序是采用Visual Basic 6.0进行开发的,主要利用其串行通信控件MSComm,其主要流程图及运行效果见图14、图15。

图8 主程序流程图 图9 点阵字模信息提取程序流程图

图10 静态显示程序流程图 图11 上移显示程序流程图

图12 左移显示程序流程图

图13 串行中断程序流程图 图14 PC机客户程序流程图

图15 PC机客户控制程序的界面

四、系统功能测试

1、测试及制作中所用仪器

GDS-820C型双踪数字示波器、UNT-T型台式数字万用表、

SK1731SL2A直流稳压电源、F10型数字合成函数信号发生器、

联想PC、烙铁等

2、键盘各键功能

1 2 3 4

5 6 7 8

9 0 ./+ C/-

确定 上 下 取消

“0—9” :数字键;

“. /+” :小数点/数据加1;

“C/-” : 删格/数据减1;

“确定” :进入菜单,保存设置

“取消” :返回上一级菜单

“上” : 菜单上翻,插入点左移

“下” : 菜单下翻,插入点右移

3、单元模块电路测试

1)LED点阵测试:用程序实现所有点阵全部点亮,显示部分点阵块无法完全点亮,更换点阵块后显示正常。

2)无线数传测试:由单片机#2无线发送1000字节数据,单片机#1接收并存储,通过开发环境查看接收数据,发送一百次,成功接收100次,经测试系统稳定;

3)与上位机通信测试:上位机循环发送1000字节数据,单片机接收并校验,接受成功后送液晶显示,然后停止发送,经测试接收时间相对于人的反映时间可以忽略。测试20次,成功接受20次。

4)键盘液晶测试:用键盘控制菜单进出,上下翻页,键盘无抖动,液晶无闪烁。

4、系统整体功能测试

各单元模块整合后,系统上电,显示屏上显示预存信息,通过2#机上的键盘可以成功控制1#机上的显示,包括预存信息切换显示、翻页、上下滚屏、左右滚屏、对流、展开等各花样显示方式、LED显示屏亮度连续可调,能成功地显示出字母、数字、汉字等信息,通过按键可以控制显示实时时间、实时温度等信息,而且断电后,重新开机,预存的显示信息与时间均可掉电保护。通过PC机的客户程序发送需更新信息数据到2#机,由2#机通过无线数传模块发送给1#机,可以成功地更新显示内容。

经过多次测试,整个系统工作稳定可靠,能够实现上述所有功能。

五、总结

我们制作的这套LED点阵电子显示屏系统不仅完成了题目要求的基本功能和发挥功能,还在实时温度检测显示、无线遥控、显示方式等方面有所创新。本系统以凌阳16位单片机SPCE061A为核心部件,最终完成了竞赛题目中要求的各项任务,包括可以控制16*64LED点阵显示屏实现信息的左右滚屏、显示屏亮度连续可调、实时时间和实时温度的显示等,在设计过程中,力求硬件线路简单,充分发挥软件在编程方面灵活的特点,来满足系统设计的要求。

在竞赛的过程中,我们遇到了许多突发性的不太好解决的问题,例如,在整个系统的调试过程中,我们体会到无论是硬件还是软件的调试都要注意模块化,要从最底层开始,逐级通过后才能进行下一步的工作;同时在联合调试的过程中,应注意各模块之间的时序配合问题,有时都是正确的模块程序却因为按照不恰当的顺序来执行从而导致程序运行结果完全出错。

通过这次比赛,我们深深的体会到了团队间的共同协作的重要性,提高了自己的动手能力和解决问题的能力。


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/yw/12566389.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-26
下一篇 2023-05-26

发表评论

登录后才能评论

评论列表(0条)

保存