单片机日历时钟与键盘显示程序设计报告_第1页
单片机日历时钟与键盘显示程序设计报告_第2页
单片机日历时钟与键盘显示程序设计报告_第3页
单片机日历时钟与键盘显示程序设计报告_第4页
单片机日历时钟与键盘显示程序设计报告_第5页
已阅读5页,还剩16页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、 日历时钟与键盘显示程序 设计 学院名称: 专业班级: 学生姓名: 学生学号: 指导教师: 1、 设计目的: 掌握日历时钟的编程方法,了解SMBus的编程方法。进一步掌握T0计数器的用法和中断服务的过程。用C51语言设计一个时钟,使其有自动报时和闹铃功能,并且可以通过键盘对当前时间进行校正,可以用键盘设置闹钟时间。2、 设计要求: 1、能在LED显示器上实现正常的时分秒计时 2、能通过键盘输入当前时间,并从该时间开始计时 3、有校时、校分功能 4、有报时功能,通过指示灯表示 5、有闹时功能,闹时时间可以设定,通过指示灯表示3、 流程图: HD7279流程图 3530流程图4、 源程序: 1、H

2、D7279芯片功能: HD7279是一片具有串行接口的,可用于驱动8位共阴极式数码管(或64只独立LED)的智能显示驱动芯片,该芯片同时还可连接多达64键的键盘矩阵,单片即可完成LED显示、键盘接口的全部功能。 HD7279内部含有译码器,可直接接受BCD码或者16进制码,并同时具有两种译码方式,此外还有消隐、闪烁、左移、右移、段寻址等多种控制指令。 HD7279具有片选信号,可方便地实现多于8位的显示或多于64键的键盘接口。 2.LED数码管工作原理及显示码:图1 这是一个7段两位带小数点 10引脚的LED数码管图2 引脚定义每一笔划都是对应一个字母表示 DP是小数点. 数码管分为共阳极的L

3、ED数码管、共阴极的LED数码管两种。下图例举的是共阳极的LED数码管,共阳就是7段的显示字码共用一个电源的正。led数码管原理图示意:图3 引脚示意图 从上图可以看出,要是数码管显示数字,有两个条件:1、是要在VT端(3/8脚)加正电源;2、要使(a,b,c,d,e,f,g,dp)端接低电平或“0”电平。这样才能显示的。 共阳极LED数码管的内部结构原理图:abcdefgdpVT图4 共阳极LED数码管的内部结构原理图VTabcdefgdp共阴极LED数码管的内部结构原理图:图5 共阴极LED数码管的内部结构原理图LED数码管要正常显示,就要用驱动电路来驱动数码管的各个段码,从而显示出我们要

4、的数位,因此根据LED数码管的驱动方式的不同,可以分为静态式和动态式两类。A、静态显示驱动: 静态驱动也称直流驱动。静态驱动是指每个数码管的每一个段码都由一个单片机的I/O埠进行驱动,或者使用如BCD码二-十进位*器*进行驱动。静态驱动的优点是编程简单,显示亮度高,缺点是占用I/O埠多,如驱动5个数码管静态显示则需要5×840根I/O埠来驱动,要知道一个89S51单片机可用的I/O埠才32个呢。故实际应用时必须增加*驱动器进行驱动,增加了硬体电路的复杂性。B、动态显示驱动: 数码管动态显示介面是单片机中应用最为广泛的一种显示方式之一,动态驱动是将所有数码管的8个显示笔划"a

5、,b,c,d,e,f,g,dp "的同名端连在一起,另外为每个数码管的公共极COM增加位元选通控制电路,位元选通由各自独立的I/O线控制,当单片机输出字形码时,所有数码管都接收到相同的字形码,但究竟是那个数码管会显示出字形,取决于单片机对位元选通COM端电路的控制,所以我们只要将需要显示的数码管的选通控制打开,该位元就显示出字形,没有选通的数码管就不会亮。 透过分时轮流控制各个LED数码管的COM端,就使各个数码管轮流受控显示,这就是动态驱动。在轮流显示过程中,每位元数码管的点亮时间为12ms,由于人的视觉暂留现象及发光二极体的余辉效应,尽管实际上各位数码管并非同时点亮,但只要扫描的

6、速度足够快,给人的印象就是一组稳定的显示资料,不会有闪烁感,动态显示的效果和静态显示是一样的,能够节省大量的I/O埠,而且功耗更低。(1)、HD7279程序#include<c8051f020.h>sbit HD7279_DAT=P17; /数据线SDAsbit HD7279_CLK=P16; /时钟线SCLsbit HD7279_CS=P15; /片选CS,低电平有效/*信号设置宏定义*/#define NOSELECT7279 P5|=0x80 /片选置1,未选中#define SELECT7279 P5&=(0x80) /片选清0,选中#define Set7279D

7、AT HD7279_DAT=1 /数据线置1#define Clr7279DAT HD7279_DAT=0 /数据线清0#define Set7279CLK HD7279_CLK=1 /时钟线置1#define Clr7279CLK HD7279_CLK=0 /时钟线清0/*函数的声明*/void Delay1ms(unsigned char T); /延时T毫秒void Delay1s(unsigned char T); /延时T秒void Delay1us(unsigned char T); /延时T微秒/*仿真I2C总线时序发送一字节*/void Send7279Byte(unsigne

8、d char ch) char i; SELECT7279; /使能HD7279A Delay1us(50); /延时50us for(i=0;i<8;i+) if(ch&0x80) /按位输出字节数据 Set7279DAT; else Clr7279DAT; Set7279CLK; ch=ch<<1; /待发数据左移 Delay1us(8); Clr7279CLK; Delay1us(8); Clr7279DAT; /数据信号SDA清0 /*仿真I2C总线时序接收一字节*/ unsigned char Receive7279Byte(void) unsigned c

9、har i,ch=0; Set7279DAT; /数据信号SDA置1 Delay1us(50); for(i=0;i<8;i+) Set7279CLK; Delay1us(8);ch=ch<<1; /接收数据左移1位if(HD7279_DAT)ch+=1; /接收1位数据Clr7279CLK;Delay1us(8);Clr7279DAT; /数据信号SDA清0return ch; /*让第No位7段数码管闪烁*/ void FlashLED(unsigned char No) unsigned char i; Send7279Byte(0x88); /发送闪烁指令 i=0x0

10、1; while(No) i=i<<1; /将1移到第No位 No-; Send7279Byte(i); /0闪烁、1不闪烁NOSELECT7279; /*HD7279A左移命令*/ void MoveLeft(void) Send7279Byte(0xA1); /发左移指令 NOSELECT7279; /*采用不译码方式显示时数字0到F的段码*/unsigned char code BdSeg= 0x7e,0x30,0x6d,0x79, /0 1 2 3 0x33,0x5d,0x5f,0x70, /4 5 6 7 0x7f,0x7b,0x77,0x1f, /8 9 a b 0x4

11、e,0x3d,0x4f,0x47, /c d e f 0x00,0x01; /' '和'_'/*显示指针DispBuf所指6个单元数据*/void DispLED(unsigned char *DispBuf,unsigned char ShowDot) char i,ch; ShowDot-; for(i=0;i<6;i+) ch=DispBufi; /取一字符 if(ch>='a')&&(ch<='f') ch-='a' ch+=0xa; /转换成数组序号 if(ch>=

12、'A')&&(ch<='F') ch-='A' ch+=0xa; Send7279Byte(0x90+5-i); /发送显示命令及位置if(ch=' ') /发送命令的第2字节 Send7279Byte(0x00); Else if(ch='-') Send7279Byte(0x01);else /查表显示 if(ShowDot=i) /小数点处理 Send7279Byte(0x80|BdSegch&0x0f); else Send7279Byte(BdSegch&0x0f);

13、 NOSELECT7279; /停止选中 /*读取按键值*/ unsigned char GetKeyValue(void) unsigned char KeyValue; if(P17=1) return -1; /无键按下 Send7279Byte(0x15); /发读键盘命令 KeyValue=Receive7279Byte(); NOSELECT7279; return KeyValue;/*等待按键释放,此处采用比较器硬件检测,也可以用软件延时实现*/void WaitKeyOff(void) while (!(CPT1CN&0x40);/*显示任意长整型数据*/void D

14、ispValue(unsigned long xx) unsigned char buf6; buf0=(xx%1000000)/100000; /最高位 buf1=(xx%100000)/10000; buf2=(xx%10000)/1000; buf3=(xx%1000)/100; buf4=(xx%100)/10; buf5=(xx%10); /最低位 DispLED(buf,0); / 调用显示函数 /*从键盘读取6位数据,格式是HHMMSS,所读数据转换成长整型*/unsigned long InputNum(void) unsigned long Num=0; unsigned c

15、har i=0,KeyValue,KeyValue1; DispLED(" -",0); /输入提示 FlashLED(0); /第一位闪烁 Delay1s(1); while(1) KeyValue=GetKeyValue(); if(i=6) FlashLED(8); /数据输入完成,关闪烁 return Num; if(KeyValue>=0)&&(KeyValue<=9) /只接收十进制的0到9 i+; Send7279Byte(0xC8); /发送方式1译码显示命令 Send7279Byte(KeyValue); /发送命令第2 字节

16、MoveLeft(); /显示左移 Send7279Byte(0x90); Send7279Byte(0x01); NOSELECT7279; WaitKeyOff(); Num*=10; /转换成十进制 Num+=KeyValue; (2)、与S3530A有关的代码和延时函数代码#include<c8051f020.h>#include<intrins.h> /_crol_()循环左移头文件 /*宏定义* /#define WRITE 0x00 /SMBus写命令#define READ 0x01 /SMB读命令 /*S3530A命令类型* /#define CLOC

17、K3530_ADDRESS_RESET 0x60 /时间值复位命令,1个ACK#define CLOCK3530_ADDRESS_STATUS 0x62 /状态寄存器读取,2个ACK#define CLOCK3530_ADDRESS_DATEHOUR 0x64 /时间读取年份开始,8个ACK#define CLOCK3530_ADDRESS_HOUR 0x66 /时间读取,从小时开始,4个ACK#define CLOCK3530_ADDRESS_INT1 0x68 /中断1频率设置,3个ACK#define CLOCK3530_ADDRESS_INT2 0x6A /中断2频率设置,3个ACK/

18、*SMBus状态:MT=主发送器、MR=主接收器*/#define SMB_BUS_ERROR 0x00 /(所有模式)总线错#define SMB_START 0x08 /(MTMR)开始条件已发送#define SMB_RP_START 0x10/(MTMR)重复开始条件已发送#define SMB_MTADDACK 0x18/(MT)从地址+W已发送,收到ACK#define SMB_MTADDNACK 0x20 /(MT)从地址+W已发送,收到NACK#define SMB_MTDBACK 0x28 /(MT)数据字节已发送,收到ACK#define SMB_MTDBNACK 0x30

19、 /(MT)数据字节已发送,收到NACK#define SMB_MTARBLOST 0x38 /(MT)竞争失败#define SMB_MRADDACK 0x40 /(MR)从地址+R已发送,收到ACK#define SMB_MRADDNACK 0x48 /(MR)从地址+R已发送,收到NACK#define SMB_MRDBACK 0x50 /(MR)数据字节已收到,ACK已发出#define SMB_MRDBNACK 0x58 /(MR)数据字节已收到,NACK已发出/*引用的全局变量声明*/union unsigned char ClockString7; struct RealCloc

20、k unsigned char Year,Month,Day,Week,Hour,Minute,Second; RT; RealTime; /实时时间 unsigned char xdata NowTime7,Timer2; /当前时间,用于当前时间的设置 unsigned char xdata Year,Month,Day,Week,Hour,Minute,Second; char COMMAND; /发送的命令(从地址+R/W) unsigned char *I2CDataBuff; /I2C总线数据缓冲区指针 unsigned char KeyValue; char BYTE_NUMBE

21、R; /需发送的字节数 bit SM_BUSY; /SMBus总线忙标志 unsigned char Count1ms; /延时时间(单位为毫秒) /*对所调用其他文件中函数的声明*/ void Send7279Byte(unsigned char ch); unsigned char GetkeyValue(void); void FlashLED(unsigned char No); unsigned long InputNum(void); void DispValue(unsigned long xx); unsigned char GetkeyValue(void); /*时钟初始化

22、*/ void SYSCLK_Init(void) int i;OSCXCN=0x67; /外部晶振22.1184MHzfor(i=0;i<256;i+);while(!(OSCXCN & 0x80); /等待外部晶振稳定OSCICN=0x88; /选择外部晶振系统时钟源,允许时钟丢失检测 /*端口初始化*/ void PORT_Init(void) XBR0 = 0x07; /允许SMBus、SPI0和UART0 XBR1 = 0x00; XBR2 = 0x44; /使能交叉开关和弱上拉 /*定时器T0初始化*/ void Timer0_Init (void) CKCON|=0

23、x8; /T0按系统时钟频率计数 TMOD|=0x1; /T0方式1 Count1ms=10; /停止T0 TR0=0; TH0=(-SYSCLK/1000)>>8; /定时1ms的时间常数 TL0=-SYSCLK/1000; TR0=1; /启动T0 IE|=0x2; /开T0中断 /*定时器T0中断服务程序(每隔1ms中断1次)*/void Timer0_ISR (void) interrupt 1 TH0=(-SYSCLK/1000)>>8; /重新装入初值 TL0=-SYSCLK/1000; if(Count1ms) Count1ms-; /定时时间减1 /*延

24、时Tus(软件实现)*/void Delay1us(unsigned char T) while(T) _nop_();_nop_();_nop_();_nop_();_nop_();-T; /*延时Tms(定时器T0实现)*/void Delay1ms(unsigned char T) Count1ms=T; while(Count1ms); /在T0中断服务程序中减1 /*延时Ts(定时器T0实现)*/void Delay1s(unsigned char T) while(T) Delay1ms(200);Delay1ms(200);Delay1ms(200);Delay1ms(200);

25、Delay1ms(200);T-; /*定时器T3初始化)*/void Timer3_Init(void) TMR3RLL = 0xff; /定时25ms的时间常数 TMR3RLH = 0x69; TMR3L = 0xff; TMR3H = 0x69; TMR3CN = 0x00; /清零T3溢出标志、12分频计数、禁止T3 EIE2 |=0x01; /开T3中断 TMR3CN |=0x04; /启动T3 /*定时器T3中断服务程序*/void Timer3_ISR(void) interrupt 14 SM_BUSY = 0; ENSMB=0; /ENSMB短暂清0后置1,复位SMBus E

26、NSMB=1; /*复位S3530A*/void ResetRealClock(void) while(SM_BUSY) /等待SMBus空闲 SM_BUSY = 1; /置SMBus忙标志 SMB0CN = 0x44; /使能SMBus,应答类型为ACK BYTE_NUMBER = 0; /命令字节数,1字节 COMMAND = (CLOCK3530_ADDRESS_RESET | READ); STA=1; /开始发送 Timer3_Init(); /允许T3工作以保证通信不超时 while(SM_BUSY); /等待发送完成 TMR3CN &= 0x82; /禁止T3 /*写S3

27、530A内部实时数据寄存器(年、月、日、星期、时、分、秒)*/ void SetRealClock(void) while(SM_BUSY); SM_BUSY = 1; SMB0CN = 0x44; BYTE_NUMBER = 7; /命令字节数,8字节 COMMAND = (CLOCK3530_ADDRESS_DATEHOUR | WRITE); RealTime.ClockString0=Year; RealTime.ClockString1=Month; RealTime.ClockString2=Day; RealTime.ClockString4=Hour; RealTime.Clo

28、ckString5=Minute; RealTime.ClockString6=Second; I2CDataBuff = &RealTime.ClockString0; /数据发送缓冲区 STA = 1; /开始传送 Timer3_Init(); while(SM_BUSY); TMR3CN &= 0x82; /*读S3530A实时数据(接收数据放RealTime变量)*/ void GetRealClock(void) while(SM_BUSY);SM_BUSY = 1;SMB0CN = 0x44;BYTE_NUMBER = 7;COMMAND = (CLOCK3530_

29、ADDRESS_DATEHOUR | READ);I2CDataBuff = &RealTime.ClockString0; /数据发送缓冲区STA = 1; Timer3_Init(); while(SM_BUSY); TMR3CN &=0x82;/*读S3530A状态寄存器程序*/unsigned char GetRealClockStatus(void) unsigned char result; while(SM_BUSY); SM_BUSY=1; SMB0CN=0x44; BYTE_NUMBER=1; COMMAND=(CLOCK3530_ADDRESS_STATUS

30、|READ); I2CDataBuff=&result; /读取结果放在result中 STA=1; Timer3_Init(); while(SM_BUSY); TMR3CN&=0x82; return result;/*写状态寄存器程序,对S3530A进行设置*/void SetRealClockStatus(unsigned char status) while(SM_BUSY); SM_BUSY=1; SMB0CN=0x44; BYTE_NUMBER=1; COMMAND=(CLOCK3530_ADDRESS_STATUS|WRITE); I2CDataBuff=&am

31、p;status; /新设置值送缓冲区 STA=1; Timer3_Init(); while(SM_BUSY); TMR3CN&=0x82;/*将无符号字节数高低位交换*/unsigned char revolve(unsigned char val) char i; unsigned char val1=0; for(i=0;i<8;i+) if(val&0x1) val1+; val1=_crol_(val1,1); val=_cror_(val,1); val1=_cror_(val1,1); return val1;/*时间显示*/void DispTime(v

32、oid) int j; GetRealClock(); /读取当前时间 Send7279Byte(0x85); /在最高位(第5位)LED显示 j=(RealTime.RT.Hour>>4)&0x03; /小时高位 Send7279Byte(j); Send7279Byte(0x84); /在第4位LED显示 j=RealTime.RT.Hour&0x0f; /小时的低位 Send7279Byte(j); Send7279Byte(0x83); /在第3位LED显示 j=(RealTime.RT.Minute>>4)&0x0f; /分钟的高位 S

33、end7279Byte(j); Send7279Byte(0x82); /在第2位LED显示 j=RealTime.RT.Minute&0x0f; /分钟的低位 Send7279Byte(j); Send7279Byte(0x81); /在第1位LED显示 j=(RealTime.RT.Second>>4)&0x0f; /秒钟的高位 Send7279Byte(j); Send7279Byte(0x80); /在第0位LED显示 j=RealTime.RT.Second&0x0f; /秒钟的低位 Send7279Byte(j); Delay1s(1);/*SM

34、Bus中断服务程序*/void SMBUS_ISR(void) interrupt 7 switch(SMB0STA) /根据SMBus不同状态码转不同分支 case SMB_START: /主发送器/接收器起始条件已发送 SMB0DAT=COMMAND; /z装入要访问的从器件的地址 STA=0; /手动清除START位 break; case SMB_RP_START: /主发送器/接收器重复起始条件已发送 SMB0DAT=COMMAND; STA=0; break; case SMB_MTADDACK: /主发送器从地址+W已发送,收到ACK case SMB_MTDBACK: /主发送

35、器数据字节已发送收到ACK if(BYTE_NUMBER) /数据字节没写完 SMB0DAT=revolve(*I2CDataBuff); /缓冲区内容送数据寄存器 I2CDataBuff+; BYTE_NUMBER-; else /数据字节已写完,释放总线 STO=1;SM_BUSY=0; break; case SMB_MTADDNACK: /主发送器从地址+W已发,收到NACK STO=1; /置位ST0+STA,重试STA=1;break; case SMB_MTDBNACK: /主发送器数据字节已发送,收到NACK STO=1; /置位ST0+STA,重试 STA=1;break;

36、case SMB_MTARBLOST: /主发送器竞争失败 STO=1; /不应出现,如果出现重新开始传输过程STA=1;break; case SMB_MRADDACK: /主接收器从地址+R已发送,收到ACK AA=1; /在应答周期发ACKif(!BYTE_NUMBER) STO=1; /释放SMBusSM_BUSY=0; break; case SMB_MRADDNACK: /主接收器从地址+R已发送,收到NACK STA=1;/从器件不应答,发送重复起始条件重试break; case SMB_MRDBACK: /收到数据字节,ACK已发送 if(BYTE_NUMBER)/ 读SMB0

37、DAT *I2CDataBuff=revolve(SMB0DAT); I2CDataBuff+; BYTE_NUMBER-; if(!BYTE_NUMBER) /最后一字节,清楚AA AA=0; break; case SMB_MRDBNACK: /收到数据字节NACK已发送 STO=1; /读操作已完成发送停止条件 SM_BUSY=0; /释放SMBus break; default: /本例中其他状态没有意义,通信复位 STO=1; SM_BUSY=0; break; SI=0; /清楚中断标志/*主程序*;/void main(void) unsigned char var; unsig

38、ned long CurrentTime=0; WDTCN=0xde; /关看门狗 WDTCN=0xad; SYSCLK_Init(); /初始化系统时钟 PORT_Init(); /初始化I/O口 Timer0_Init(); /初始化定时器 CPT1CN|=0x80; /使能比较器1 SM_BUSY=0; EIE1|=0x0A; /SMBUS中断允许,PCA中断允许 ET0=1; /开定时器0中断 EA=1; /开中断 Delay1ms(25); /7279上电复位的延时时间 Send7279Byte(0xA4); /7279复位 var=GetRealClockStatus(); /读取

39、S3530A当前状态 ResetRealClock(); /复位S3530A SetRealClockStatus(0xc2); /设置S3530A状态 Do /从键盘输入时间,格式HHMMSS CurrentTime=InputNum();DispValue(CurrentTime); NowTime4=(unsigned char)(CurrentTime/100000)<<4); /时CurrentTime=CurrentTime%100000;NowTime4=NowTime4|(CurrentTime/10000);CurrentTime=CurrentTime%1000

40、0; NowTime5=(unsigned char)(CurrentTime/1000)<<4); /分 CurrentTime=CurrentTime%1000;NowTime5=NowTime5|(CurrentTime/100);CurrentTime=CurrentTime%100; NowTime6=(unsigned char)(CurrentTime/10)<<4); /秒 CurrentTime=CurrentTime%10;NowTime6=NowTime6|CurrentTime; while(NowTime4>0x24)|(NowTime5>0x59)|(NowTime6>0x59); Hour=NowTime4; Minute=NowTime5; Second=NowTime6; SetRealClock(); /键盘输入时间写入S3530A while(1) DispTime(); /显示实时时间 KeyValue=GetKeyValue(); if(KeyValue=10) /按键'A'校时、校分、校秒 do CurrentTime=InputNum(); DispValue(CurrentTime); NowTime4=(unsigned char)(CurrentTime/1000

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论