1、 本科课程设计课程名称: 单片机原理与接口技术 课设项目: 电子万年历课程设计 课设地点: 专业班级: 学号 学生姓名: 同组人: 指导教师: 2012年 05月30 日设计题目:电子万年历设计任务与要求:1、显示年月日时分秒及星期信息2、具有可调整日期和时间功能3、增加闰年计算功能4、增加了显示温度的模块设计方案:由于我是在网上购买的现成的开发板来学习和使用的,故在方案的选择上也只能限于开发板设计好的电路和芯片.系统分为主控模块、时钟电路模块、温度检测模块,按键扫描模块,LCD显示模块,电源电路、复位电路、晶振电路等模块。主控模块采用AT89C52单片机,按键模块用四个按键,用于调整时间,显
2、示模块采用LCD1602,时钟电路模块采用DS1302时钟芯片实现对时间、日期的操作,温度模块使用18B20实现度温度的操作。STC89C52,ATMEL的51系列单片机,价格便宜,在国内使用者非常多。支持串口下载,使用非常方便,且具有很大的价格优势。缺点是仅支持串口下载,不支持在线下载,使用中会有些不方便。1.显示模块:方案一: 普通的共阴LED数码管,用点阵LED实现文字的显示.方案二: LCD1602液晶显示屏.LED数码管价格适中,对于数字显示效果较好,而且使用单片机的端口也较少; LCD1602液晶显示屏,显示功能强大,可以显示大量文字、图形,显示多样性,清晰可见,价格相对LED数码
3、管来说要昂贵些,但是基于本设计显示的东西较多,若采用LED数码管的话,所需数码管较多,而且不利于控制,因此选择LCD1602作为显示模块.故选择方案二.2.时钟电路模块:方案一:用单片机的定时器产生1S的时基信号,然后用程序来实现时钟的时、分、秒计时,同时用程序来产生年、月、日。该方案优点是减少使用外设芯片;缺点是用单片机模拟时钟,使编程量增大,且用定时器产生时基信号,精度不高。方案二:DS1302是一款高性能的实时时钟芯片,以计时准确、接口简单、使用方便、工作电压范围宽和低功耗等优点,得到广泛的应用,实时时钟有秒、分、时、星期、日、月和年,月小于31天时可以自动调整,并具有闰年补偿功能,而且
4、在掉电时能够在外部纽扣电池的供电下继续工作。单片机有定时器的功能,但时间误差较大,且需要编写时钟程序.因此采用DS1302方案二作为时钟电路。3.温度模块:直接采用常用的18B20.系统框图:液晶显示(LED)1602单片AT89C52时钟芯片DS1302温度传感器18B20单元电路设计:单片机中央处理系统的方案设计,选用AT89C52单片机作为中央处理器,如图所示。该单片机除了拥有MCS-51系列单片机的所有优点外,内部还具有8K的在系统可编程FLASH存储器,低功耗的空闲和掉电模式,极大的降低了电路的功耗,还包含了定时器、程序存储器、数据存储器等硬件,其硬件能符合整个控制系统的要求,不需要
5、外接其他存储器芯片和定时器件,方便地构成一个最小系统。整个系统结构紧凑,抗干扰能力强,性价比高。2、时钟振荡电路用主振11.0592MHZ的晶振,使用内部晶振接法并上俩个30PF的电容,如图所示.3、复位电路复位电路由电阻和极性电容组成,通过高电平使单片机复位,在时钟电路开始工作后,当高电平的时间超过大约2us时,即可实现复位。此复位电路为上电复位,较为简单。若改进可以添加手动复位的功能,上电复位发生在开机加电时,由系统自动完成,手动复位通过一个按键来实现,在程序运行时,若遇到死机,死循环等情况,通过手动复位就可以实现重新启动的操作。手动按钮复位需要人为在复位输入端RST上加入高电平。一般采用
6、的办法是在RST端和正电源Vcc之间接一个按钮和一个电阻。 4、DS1302时钟电路时钟电路主要由时钟芯片DS1302、备用电池、晶振等几部分组成,如图(6)所示。DS1302采用3线串行接口,占用引脚少,内部集成了可编程日历时钟,用户可以根据需要通过单片机的控制来自行设置,支持双电源供电,可以使用外部主电源和备用电源,备份电源能够使时钟芯片继续工作。 DS1302管脚图 DS1302时钟电路DS1302各引脚的功能为:8: Vcc1:备用电池端;1: Vcc2:5V电源。当Vcc2Vcc1+0.2V时,由Vcc2向DS1302供电,当Vcc2 Vcc1时,由Vcc1向DS1302供电;7:
7、SCLK:串行时钟,输入; 6: I/O:数据输入输出口;5: CE/RST:复位脚;2、3: X1、X2 是外接晶振脚 (32.768KHZ的晶振);4: 地(GND)。DS1302有关日历、时间的寄存器:DS1302有关日历、时间的寄存器1、秒寄存器(81h、80h)的位7定义为时钟暂停标志(CH)。当初始上电时该位置为1,时钟振荡器停止,DS1302处于低功耗状态;只有将秒寄器的该位置改写为0时,时钟才能开始运行。2、小时寄存器(85h、84h)的位7用于定义DS1302是运行于12小时模式还是24小时模式。当为高时,选择12小时模式。在12小时模式时,位5是 ,当为1时,表示PM。在2
8、4小时模式时,位5是第二个10小时位3、控制寄存器(8Fh、8Eh)的位7是写保护位(WP),其它7位均置为0。在对任何的时钟和RAM的写操作之前,WP位必须为0。当WP位为1时,写保护位防止对任一寄存器的写操作。也就是说在电路上电的初始态WP是1,这时是不能改写上面任何一个时间寄存器的,只有首先将WP改写为0,才能进行其它寄存器的写操作。DS1302读写时序 DS1302是SPI总线驱动方式。它不仅要向寄存器写入控制字,还需要读取相应寄存器的数据。DS1302的控制字如下图:DS1302的控制字图控制字的最高有效位(位7)必须是逻辑1,如果它为0,则不能把数据写入到DS1302中。位6:如果
9、为0,则表示存取日历时钟数据,为1表示存取RAM数据;位5至位1(A4A0):指示操作单元的地址;位0(最低有效位):如为0,表示要进行写操作,为1表示进行读操作。读数据:读数据时在紧跟8位的控制字指令后的下一个SCLK脉冲的下降沿,读出DS1302的数据,读出的数据是从最低位到最高位。写数据:控制字总是从最低位开始输出。在控制字指令输入后的下一个SCLK时钟的上升沿时,数据被写入DS1302,数据输入也是从最低位(0位)开始。5:温度传感器18B20通过18B20进行读数据,将读出来的数据进行进制转换,转换后送到DS18B20是单总线的数字温度传感器。其与单片机的接口只需要一根数据线即可。当
10、然连线简单意味着软件处理上可能要麻烦一点。下面来看看它的优点看看它的靓照。外形和我们常用的三极管没有什么两样哦。DS18B20的内部存储器分为以下几部分 ROM:存放该器件的编码。前8位为单线系列的编码(DS18B20的编码是19H)后面48位为芯片的唯一序列号。在出场的时候就已经设置好,用户无法更改。最后8位是以上56位的CRC码。 DS18B20的温度存放如上图所示。其中S位符号位。当温度值为负值时,S = 1 ,反之则S = 0 。我们把得到的温度数据乘上对应的分辨率即可以得到转换后的温度值。 DS18B20的通讯协议: 在对DS18B20进行读写编程时,必须严格保证读写的时序。否则将无
11、法读取测温结果。根据DS18B20的通讯协议,主机控制DS18B20完成温度转换必须经过3个步骤:每一次读写之前都要对DS18B20进行复位,复位成功后发送一条ROM指令,最后发送RAM指令。这样才能对DS18B20进行预定的操作。 复位要求主机将数据线下拉500us,然后释放,DS18B20收到信号后等待16160us然后发出60240us的存在低脉冲,主机收到此信号表示复位成功。上图即DS18B20的复位时序图。 下面是读操作的时序图这是写操作的时序图6.按键电路按键电路由四个轻触开关组成。按键用来调整时间,其一端直接接到单片机的端口,另一端接地,当按下按键时,相应的端口变为低电平,通过一
12、个与门只要这四个按键有一个按下就会在P3.2检测到一低电平就触发外部中断0进入按键调节程序中,通过与个各键相连的端口P3.4_P3.7可以判断是哪个键按下,从而作相应的操作。用软件设计扫描程序。7.实现功能:K1按键进入设定状态按K2,依次进入闹钟功能是否启用,闹钟时,分秒,年,月,日及时间时,分,秒的设置,直到退出设置状态按K3,调整是否起用闹钟和调节闹钟时,分,秒,年,月,日,时间的时,分,秒的数字LCD第二排中间显示小喇叭,表示启用闹钟功能,无则禁止闹钟功能(可在调整状态进行设置)正常状态,LCD上排最前面显示自定义字符,LCD下排最前面闪动RICHMCU设置状态,LCD上排最前面显示P
13、,下排最前面在设置闹钟时间时显示alarm:,其它状态显示time8.程序流程图:1主程序:首先初始化定时器、LCD1602及DS1302,然后就开始查询按键,有键按下则开始调整时间和日期,若没有按下,则执行下面的时间、日期的显示,最后依次循环这些相同的操作:18b20子程序:复位初始化向1820写数据,跳过rom,读数据提取百、十、个、小数点后一位 读到的数转换为整型Ds1302子程序:初始化Flag=1?Dnum=?1:小时加一 2:分加一 3:秒加一4:年加一 5:月加一 6:日加一 7:星期加一 1:小时减一 2:分减一 3:秒减一4:年减一 5:月减一 6:日减一 7:星期减一计算要
14、显示的数据送到1602显示Dnum=?2、软件设计软件总设计:主程序首先对系统环境初始化,设置定时器T0工作模式为16位定时/计数器模式,置位总中断允许位EA,并对键盘端口置位,再对LCD1602初始化,DS1302初始化。接着扫描键盘,在键盘程序里面是对时间、日期,闹钟的调整,温度的选择,最下面是时间的显示。例如:闰年的计算bit leap_year()bit leap;if(year%4=0&year%100!=0)|year%400=0)/闰年的条件leap=1;elseleap=0;return leap;仿真结果分析:电子万年历硬件电路图及仿真如图所示,系统由AT89C52单片机,按
15、键扫描电路、显示电路、时钟电路、晶振电路、复位电路及电源指示电路。仿真正确显示了时间,在LCD1602中正确显示了当前日期、时间,按K1按键进入设定状态,按K2,依次进入闹钟功能是否启用,闹钟时,分秒,年,月,日及时间时,分,秒的设置,直到退出设置状态,按K3,调整是否起用闹钟和调节闹钟时,分,秒,年,月,日,时间的时,分,秒的数字, 按K4,选择温度的显示.LCD第二排中间显示小喇叭,表示启用闹钟功能,无则禁止闹钟功能(可在调整状态进行设置),正常状态,LCD上排最前面显示自定义字符,LCD下排最前面闪动TIME,设置状态,LCD上排最前面显示P,下排最前面在设置闹钟时间时显示alarm:,
16、其它状态显示time仿真正确显示了时间和日期,符合设计的要求。增加温度的显示按下K4时出现温度的显示界面,上排显示”wendu made byFMZ”,下排显示温度.仿真图如下所示:参考文献:单片机原理与接口技术(李晓林.第二版)RZ-51V20开发板论坛实物图:闹钟设置时间显示平闰年判断,修改天数温度显示整体实物图实验源程序:#include #include #include unsigned char code digit11=0123456789-; /定义字符数组显示数字unsigned char code Str=wendu made byFMZ; /说明显示的是温度unsigne
17、d char code Error= DS18B20 ERROR; /说明没有检测到DS18B20unsigned char code Error1= PLEASE CHECK; /说明没有检测到DS18B20unsigned char code Temp=wendu made byFMZ:; unsigned char code Cent=Cent; /温度单位unsigned char flag,tltemp;unsigned char code dis_week=SUN,MON,TUE,WED,THU,FRI,SAT;unsigned char code para_month13=0,0
18、,3,3,6,1,4,6,2,5,0,3,5;/星期月参变数unsigned char data dis_buf116;/lcd上排显示缓冲区unsigned char data dis_buf216;/lcd下排显示缓冲区unsigned char data year,month,date,week;/年、月、日、星期unsigned char data armhour,armmin,armsec;/闹钟时、分、秒unsigned char data hour,min,sec,sec100;/时、分、秒、百分之一秒unsigned char data flag,vkey,skey;/设置状态
19、计数标志、按键先前值、按键当前值bitalarm;/标识是否启用闹钟,1-启用,0-关闭sbit rs = P20;/LCD数据/命令选择端(H/L)sbit rw = P21;/LCD读/写选择端(H/L)sbit ep = P22;/LCD使能控制sbitPRE = P33;/调整键(AN3)sbitSET = P34;/调整键(AN4)sbitSPK = P36;void delayms(unsigned char ms);/延时程序bit lcd_busy();/测试LCD忙碌状态程序void lcd_wcmd(char cmd);/写入指令到LCD程序void lcd_wdat(ch
20、ar dat);/写入数据到LCD程序void lcd_pos(char pos);/LCD数据指针位置程序void lcd_init();/LCD初始化设定程序void pro_timedate();/时间日期处理程序void pro_display();/显示处理程序void pro_key();/按键处理程序void time_alarm();/定时报警功能(闹钟)unsigned char scan_key();/按键扫描程序unsigned char week_proc();/星期自动计算与显示函数bit leap_year();/判断是否为闰年void lcd_sef_chr();
21、/LCD自定义字符程序void update_disbuf(unsigned char t1,unsigned char t2,unsigned char dis_h,unsigned char dis_m,unsigned char dis_s);/ 延时程序void delay(unsigned char ms)while(ms-)unsigned char i;for(i = 0; i 250; i+)_nop_(); /执行一条_nop_()指令为一个机器周期_nop_();_nop_();_nop_(); void delay1ms() unsigned char i,j; for(
22、i=0;i4;i+) for(j=0;j33;j+) /n毫秒 void delaynms(unsigned char n) unsigned char i;for(i=0;in;i+) delay1ms(); /测试LCD忙碌状态bit lcd_busy()bit result;rs = 0;rw = 1;ep = 1;_nop_();_nop_();_nop_();_nop_();result =(bit)(P0&0x80);/LCD的D0-D7中,D7=1为忙碌,D7=0为空闲ep = 0;return result;/写入指令到LCDvoid lcd_wcmd(char cmd)whi
23、le(lcd_busy();/当lcd_busy为1时,再次检测LCD忙碌状态,lcd-busy为0时,开始写指令rs = 0;rw = 0;ep = 0;_nop_();_nop_();P0 = cmd;_nop_();_nop_();_nop_();_nop_();ep = 1;_nop_();_nop_();_nop_();_nop_();ep = 0;/写入数据到LCDvoid lcd_wdat(char dat)while(lcd_busy();rs = 1;rw = 0;ep = 0;P0 = dat;_nop_();_nop_();_nop_();_nop_();ep = 1;_
24、nop_();_nop_();_nop_();_nop_();ep = 0;/LCD数据指针位置程序void lcd_pos(char pos)lcd_wcmd(pos|0x80);/数据指针=80+地址码(00H27H,40H67H)void lcd_sef_chr()/第一个自定义字符lcd_wcmd(0x40);/01 000 000 第1行地址 (D7D6为地址设定命令形式D5D4D3为字符存放位置(0-7),D2D1D0为字符行地址(0-7)) lcd_wdat(0x1f);/XXX 11111第1行数据(D7D6D5为XXX,表示为任意数(一般用000),D4D3D2D1D0为字符
25、行数据(1-点亮,0-熄灭)lcd_wcmd(0x41);/01 000 001 第2行地址 lcd_wdat(0x11);/XXX 10001第2行数据lcd_wcmd(0x42);/01 000 010 第3行地址 lcd_wdat(0x15);/XXX 10101第3行数据lcd_wcmd(0x43);/01 000 011 第4行地址 lcd_wdat(0x11);/XXX 10001第4行数据lcd_wcmd(0x44);/01 000 100 第5行地址 lcd_wdat(0x1f);/XXX 11111第5行数据lcd_wcmd(0x45);/01 000 101 第6行地址 l
26、cd_wdat(0x0a);/XXX 01010第6行数据lcd_wcmd(0x46);/01 000 110 第7行地址 lcd_wdat(0x1f);/XXX 11111第7行数据lcd_wcmd(0x47);/01 000 111 第8行地址 lcd_wdat(0x00);/XXX 00000第8行数据/第二个自定义字符lcd_wcmd(0x48);/01 001 000 第1行地址 lcd_wdat(0x01);/XXX 00001第1行数据lcd_wcmd(0x49);/01 001 001 第2行地址 lcd_wdat(0x1b);/XXX 11011第2行数据lcd_wcmd(0
27、x4a);/01 001 010 第3行地址 lcd_wdat(0x1d);/XXX 11101第3行数据lcd_wcmd(0x4b);/01 001 011 第4行地址 lcd_wdat(0x19);/XXX 11001第4行数据lcd_wcmd(0x4c);/01 001 100 第5行地址 lcd_wdat(0x1d);/XXX 11101第5行数据lcd_wcmd(0x4d);/01 001 101 第6行地址 lcd_wdat(0x1b);/XXX 11011第6行数据lcd_wcmd(0x4e);/01 001 110 第7行地址 lcd_wdat(0x01);/XXX 00001
28、第7行数据lcd_wcmd(0x4f);/01 001 111 第8行地址 lcd_wdat(0x00);/XXX 00000第8行数据/LCD初始化设定void lcd_init()lcd_wcmd(0x38);/设置LCD为16X2显示,5X7点阵,八位数据借口delay(1);lcd_wcmd(0x0c);/LCD开显示及光标设置(光标不闪烁,不显示-)delay(1);lcd_wcmd(0x06);/LCD显示光标移动设置(光标地址指针加1,整屏显示不移动)delay(1);lcd_wcmd(0x01);/清除LCD的显示内容delay(1);/闰年的计算bit leap_year()
29、bit leap;if(year%4=0&year%100!=0)|year%400=0)/闰年的条件leap=1;elseleap=0;return leap;/星期的自动运算和处理unsigned char week_proc()unsigned char num_leap;unsigned char c;num_leap=year/4-year/100+year/400;/自00年起到year所经历的闰年数if( leap_year()& month 59)sec = 0; min+; if(min59)min=0; hour+; if(hour23)hour=0; date+; if
30、(month=1|month=3|month=5|month=7|month=8|month=10|month=12) if (date31) date=1;month+;/大月31天 if (month=4|month=6|month=9|month=11) if (date30) date=1;month+;/小月30天 if (month=2) if( leap_year()if (date29) date=1;month+; elseif (date28) date=1;month+; if (month12) month=1;year+; if (year99) year=0;wee
31、k_proc();if (sec=armsec & min=armmin & hour=armhour)if (alarm)TR1=1;/闹钟启用时,报警时间到,启动Timer1/显示处理程序void pro_display()unsigned char i;lcd_pos(0x00);for (i=0;i=15;i+)lcd_wdat(dis_buf1i);lcd_pos(0x40);for (i=0;i= 100)/1秒时间 (100*10ms=1000ms=1s)sec100 = 0; pro_timedate();/调用时间和日期处理程序if (sec&0x01)update_disb
32、uf(0x00, ,hour,min,sec); else update_disbuf(0x00,FMZTIME,hour,min,sec); pro_display(); /调用显示处理函数/按键扫描程序unsigned char scan_key()skey=0x00;/给变量vkey置初值skey|=PRE;/读取PRE键的状态skey=skey1;/将PRE键的状态存于skey的B1位skey|=SET;/读取SET键的状态,并存于skey的B0位return skey;/返回skey的键值(即PRE,SET的状态)/外部中断INT0中断处理程序void int0() interrup
33、t 0TR0=0;/禁止Timer0IE=0;/禁止中断lcd_wcmd(0x0e);/显示光标_,整个光标不闪烁alarm=1;update_disbuf(0x50,alarm:,armhour,armmin,armsec);pro_display();/调用显示处理程序lcd_pos(0x47); /使光标位于第一个调整项下flag=0;vkey=0x03;while(flag0x0a)skey = scan_key();/扫描按键状态if (skeyvkey)/若skey与vkey相同,跳出循环,相异执行循环体delay(10);/去按键抖动skey = scan_key();/转回扫描
34、按键状态if (skeyvkey)/若skey与vkey相同,跳出循环,相异执行循环体 vkey=skey;/将skey的值付给vkeyif (skey=0x01)/PRE键按下 flag+;/调整标志位加1switch (flag)/将光标置于相应调整位置case 1: lcd_pos(0x49);break;/ case 2:lcd_pos(0x4c);break;case 3:lcd_pos(0x4f);break;case 4:update_disbuf(0x50,time: ,hour,min,sec);pro_display();lcd_pos(0x05);break;case 5
35、:lcd_pos(0x08);break;case 6:lcd_pos(0x0b);break;case 7: lcd_pos(0x49);break;/ case 8:lcd_pos(0x4c);break;case 9:lcd_pos(0x4f);break;default:break;if (skey=0x02) /SET键按下pro_key();/转设置按键处理程序 if (skey=0x03) wendu()lcd_wcmd(0x0c);lcd_wcmd(0x01); /清除LCD的显示内容IE=0x8f; /CPU开中断,INT0,INT1,开中断TR0=1;/Timer0启动 / DS18B20的操作程序 sbit DQ=P33; unsigned char time; /设置全局变量,专门用于严格延时 / 函数功能:将DS18B20传感器初始化,读取应答信号/出口参数:flag bit Ini