1、单片机万年历实训报告382020年4月19日文档仅供参考,不当之处,请联系改正。 单片机万年历实训报告 系 部:电气自动化系 班 级:13电信2班 姓 名:周祝福 指导老师:黄丽英、侯聪玲 实训时间: 1月19日23日用AT89C51与LCD1602设计的可调式电子日历时钟一、总体设计1.1、设计目的 为巩固所学的单片机知识,把所学理论运用到实践中,用LCD1602与AT89C51 设计可调式电子日历时钟。 1.2、设计要求(1)显示:年、月、日、时、分、秒和星期;(2)设置年、月、日、时、分、秒和星期的初始状态;(3)能够用4个按键调整日历时钟的年、月、日、时、分、秒和星期 ; 完成可调式电
2、子日历时钟的硬件和软件的设计,包括单片机的相关内容;日历时钟模块的设计,液晶显示模块的设计,按键模块的设计。控制程序的编写等。1.3、 系统基本方案选择和论证1.3.1、单片机芯片的选择方案 方案一: 采用89C51芯片作为硬件核心,采用Flash ROM,内部具有4KB ROM 存储空间,能于3V的超低压工作,而且与MCS-51系列单片机完全兼容。方案二: 采用STC12C5A60S2系列单片机是宏晶科技生产的单时钟/机器周期(1T)的单片机,是高速/低功耗/超强抗干扰的新一代8051单片机,指令代码完全兼容传统8051,但速度快8-12倍。内部集成MAX810专用复位电路,2路PWM,8路
3、高速10位A/D转换(250K/S),针对电机控制,强干扰场合。但造价较高。1.3.2 、显示模块选择方案和论证:方案一: 采用点阵式数码管显示,点阵式数码管是由八行八列的发光二极管组成,对于显示文字比较适合,如采用显示数字显得太浪费,且价格也相对较高。因此不用此种作为显示。方案二: 采用LED数码管动态扫描,虽然LED数码管价格适中,但要显示多个数字所需要的个数偏多,功耗较大,显示出来的只是拼音,而不是汉字。因此也不用此种作为显示。方案三: 采用LCD液晶显示屏,液晶显示屏的显示功能强大,可显示大量字符,且视觉效果较好,外形美观。LCD1602可实现显示2行十六个字符。1.3.4、 电路设计
4、最终方案决定 综上各方案所述,对此次作品的方案选定:采用80C51作为主控制系统; LCD1602液晶带汉字库显示屏作为显示部分。二、硬件设计2.1、电路设计模块图如图AT89C51LCD162按键控制模块2.3、 用proteus仿真软件仿真并抓图。三、软件设计3.1、画出各个函数流程图。3.1.1、LCD1602液晶显示控制流程图如图3.1.2、调时函数控制流程如图实训心得:经过为期一周的单片机实训,是我们对这门课有了许多新的了解,弥补了在课堂上学习的不足。相信这对我们以后的学习和工作都会有很大的帮助。我们一定要在最短的时间里对这些不足加以改正! 在试训中有苦有甜,当我们为一个很难攻破的程
5、序找出路时,心情烦躁,感觉自己很不可理喻,当程序一点一点编好后,自己从心底感觉到一点小小的安慰,看着自己的成果。感觉很欣慰。总而言之,单片机课程设计对于我们有很大的帮助,我们从中受益匪浅。程序代码。#include#define uchar unsigned char#define uint unsigned intuchar a,count,S1num,xqnum;uchar yue,ri,shi,fen,miao;uint nian;sbit lcdrs=P25;sbit lcdrw=P24;sbit lcden=P23;sbit S1=P30;/定义键-进入设置sbit S2=P31;/
6、定义键-增大sbit S3=P32;/定义键-减小sbit S4=P33;/定义键-退出设置uchar code table0= -01-11 SUN;uchar code table1=00:00:00;uchar code xingqi3=MON,TUE,WED,THU,FRI,SAT,SUN;void delay(uint z)uint x,y;for(x=z;x0;x-)for(y=110;y0;y-);/*1602液晶显示器模块*/void write_com(uchar com)/液晶写指令lcdrw=0;lcdrs=0;P0=com;delay(5);lcden=1;delay(
7、5);lcden=0;void write_data(uchar dat)/液晶写数据lcdrw=0;lcdrs=1;P0=dat;delay(5);lcden=1;delay(5);lcden=0; /*年月日写入1602函数*/void write_sfm(uchar add,uchar dat) /写时分秒函数uchar shi,ge;shi=dat/10;ge=dat%10;write_com(0x80+0x40+add);write_data(0x30+shi);write_data(0x30+ge);void write_yr(uchar add,uchar dat) /写月日函数
8、uchar shi,ge;shi=dat/10;ge=dat%10;write_com(0x80+add);write_data(0x30+shi);write_data(0x30+ge);void write_nian(uchar add,uint dat) /写年函数uint qian,bai,shi,ge;qian=dat/1000;bai=dat%1000/100;shi=dat%100/10;ge=dat%10;write_com(0x80+add);write_data(0x30+qian);write_data(0x30+bai);write_data(0x30+shi);wri
9、te_data(0x30+ge);/*1602初始化*/void init_lcd() /液晶初始化lcden=0;nian= ;yue=1;ri=11;shi=0; /初始shi、fen、miaofen=0;miao=0;write_com(0x38); /设置16x2显示,5x7点阵,8位数据口write_com(0x0c); /设置开显示,不显示光标write_com(0x06); /写一个字符后地址指针加1write_com(0x01); /显示清0,数据指针清0 void init()/初始化函数init_lcd(); /液晶初始化write_com(0x80); /设置显示初始坐标
10、for(a=0;a14;a+) /显示年月日初始值write_data(table0a);delay(5);write_com(0x80+0x40); /设置显示初始坐标for(a=0;a8;a+)/显示时分秒初始值write_data(table1a);delay(5);write_nian(0,nian);write_sfm(6,miao); /分别将shi、fen、miao送去液晶显示write_sfm(3,fen);write_sfm(0,shi);count=0;xqnum=0;S1num=0; /初始化全局变量countTMOD=0x01; /设置定时器0工作模式1TH0=(655
11、35-50000)/256; /定时器装初始值TL0=(65535-50000)%256;EA=1;/开总中断ET0=1;/开定时器0中断TR0=1;/启动定时器0 /*独立键盘*/void keyscan()if(S1=0)delay(5);/确认定义键被按下if(S1=0)S1num+;/定义键S1按下次数记录while(!S1);/释放按键确认if(S1num=1)/S1按下一次时TR0=0;/关闭定时器write_com(0xc0+7);/光标定位到秒位置write_com(0x0f);/光标闪烁if(S1num=2) /S1按下两次时write_com(0xc0+4); /光标定位到
12、分位置if(S1num=3) /S1按下三次时write_com(0xc0+1); /光标定位到时位置if(S1num=4) /S1按下四次时write_com(0x80+13); /光标定位到星期位置if(S1num=5) /S1按下五次时write_com(0x80+9); /光标定位到日位置if(S1num=6) /S1按下六次时write_com(0x80+6); /光标定位到月位置if(S1num=7) /S1按下七次时write_com(0x80+3); /光标定位到年位置if(S1num=8) /S1按下八次时S1num=0; /S1记录按键次数清零TR0=1; /开启定时器wr
13、ite_com(0x0c); /取消光标闪烁if(S1num!=0) /只有定义键按下后S2、S3、S4才有效if(S2=0)delay(5);/防抖if(S2=0) /确认按键被按下while(!S2);/释放按键确认if(S1num=1)/S1按下一次时miao+;/调整秒加1if(miao=60)/满60清零miao=0;write_sfm(6,miao); /每调节一次送液晶显示一次write_com(0x80+0x40+6); /显示位置重新回到调节处if(S1num=2) /S1按下两次时fen+;/调整分加1if(fen=60)fen=0;write_sfm(3,fen);wri
14、te_com(0x80+0x40+3);if(S1num=3) /S1按下三次时shi+; /调整时加1if(shi=24)shi=0;write_com(0x80+0x40);write_sfm(0,shi);if(S1num=4) /星期加调整xqnum+;if(xqnum=7)xqnum=0;write_com(0x80+0x0b);for(a=0;a3;a+)write_data(xingqixqnuma);delay(5);if(S1num=5)/日加调整ri+;if(yue=2)if(nian%400=0)if(ri=30)ri=1;if(nian%400!=0)if(ri=29)
15、ri=1;else if(yue=8)if(yue%2=0)if(ri=32)ri=1;else if(yue%2!=0)if(ri=31)ri=1;write_yr(8,ri);if(S1num=6)/月加调整yue+;if(yue=13)yue=1;write_yr(5,yue); if(S1num=7) /年加调整nian+;if(nian= )nian= ;write_nian(0,nian);if(S3=0)delay(5);if(S3=0) /确认按键被按下while(!S3);if(S1num=1) miao-; /调整秒减1if(miao=-1) /减到00后再减重新设置为59
16、miao=59;write_sfm(6,miao);write_com(0x80+0x40+6);if(S1num=2)fen-; /调整分减1if(fen=-1)fen=59;write_sfm(3,fen);write_com(0x80+0x40+3);if(S1num=3)shi-;/调整时减1if(shi=-1)shi=23;write_sfm(0,shi);write_com(0x80+0x40);if(S1num=4)xqnum-;/调整星期减一if(xqnum=-1)xqnum=6;write_com(0x80+0x0b);for(a=0;a3;a+)write_data(xin
17、gqixqnuma);delay(5);if(S1num=5) /调整日ri-;if(yue=2)if(nian%400=0)if(ri=0)ri=29;if(nian%400!=0)if(ri=0)ri=28;else if(yue=8)if(yue%2=0)if(ri=0)ri=31;else if(yue%2!=0)if(ri=0)ri=30;write_yr(8,ri); if(S1num=6) /调整月yue-;if(yue=0)yue=12;write_yr(5,yue);if(S1num=7) /调整年nian-;if(nian= )nian= ;write_nian(0,nia
18、n);if(S4=0) /退出设置、开启中断delay(5);if(S4=0)S1num=0;TR0=1;write_com(0x0c);/*定时器0*/void timer0() interrupt 1 /定时器0中断服务程序TH0=(65535-50000)/256; /重装定时器初始值TL0=(65535-50000)%256;count+; /中断次数累加if(count=20) /20次50毫秒即一秒count=0;miao+;if(miao=60) /秒加到60时分进位miao=0;fen+;if(fen=60) /分加到60时时进位fen=0;shi+;if(shi=24)/时加
19、到24时清0shi=0;xqnum+;ri+;if(yue=2)/如果是二月if(nian%400=0) /闰年判断if(ri=30)ri=1;yue+;write_yr(5,yue);if(nian%400!=0) /平年判断if(ri=29)ri=1;yue+;write_yr(5,yue);else if(yue=8) /八月到12月if(yue%2=0)/偶数月(除二月)if(ri=32) ri=1;yue+;if(yue=13) /如果判断月份为12月,则加一后重新定义月份为1yue=1;nian+;write_nian(0,nian);write_yr(5,yue);else if(yue%2!=0) /奇数月if(ri=31)ri=1;yue+;write_yr(5,yue);write_yr(8,ri);if(xqnum=7)/星期写入xqnum=0;write_com(0x80+0x0b);for(a=0;a3;a+)write_data(xingqixqnuma);delay(5);write_sfm(0,shi);/重新写入数据write_sfm(3,fen);/重新写入数据write_sfm(6,miao);/重新写入数据/*主函数*/void main()init();while(1)keyscan();/不停的检测按键是否被按下