第一篇:单片机电子钟实习报告
学院:xxx 班级:自动化xx班 姓名:xxx 学号:xxx 日期:2013-3-15
单片机LCD1602电子钟设计实习报告
一、引言
1.1设计的背景及目的
随着计算机科学与技术的飞速发展,计算机的应用已经渗透到国民经济与人们生活的各个角落,正在日益改变着传统的人类工作方式和生活方式,而单片机技术又作为计算机技术中的一个独立分支,有着性价比高,集成度高,体积小,可靠性高,控制功能强大,低功耗,低电压,便于生产,便于携带等特点,所以得到越来越广泛的应用,特别是在工业控制和仪表仪器智能化中起极其重要的作用.本文利用单片机强大的控制功能和内部定时器重要部件,设计了一款自行对时间进行调整以及把时、分、秒用LCD显示的电子钟。
电子钟从原理上讲是一种典型的数字电路,其中包括了组合逻辑电路和时序电路。因此,我们此次设计与制做数字钟就是为了了解数字钟的原理,从而学会制作数字钟.而且通过数字钟的制作进一步的了解各种在制作中用到的中小规模集成电路的作用及实用方法.且由于数字钟包括组合逻辑电路和时叙电路.通过它可以进一步学习与掌握各种组合逻辑电路与时序电路的原理与使用方法
1.2设计的内容要求及研究方法 ① 时间以24小时为一个周期; ② 显示时、分、秒;
③ 具有校时功能,可以分别对时及分进行单独校时,使其校正到标准时间;
二、设计的原理图、程序及调试
1、基本原理
本设计基于单片机技术原理,以单片机芯片AT89S51作为核心控制器,通过硬件电路的制作以及软件程序的编制,设计制作出一个多功能数字时钟系统。单片机扩展的LCD显示器用来显示秒、分、时计数单元中的值。整个设计包括两大部分: 硬件部分和软件部分,以单片机为核心, 配以一定的外围电路和软件。硬件是整个系统的基础, 软件部分则要合理、充分地支持和使用系统的硬件, 从而完成系统所要完成的任务。
该时钟系统主要由时钟模块、液晶显示模块、键盘控制模块以及信号提示模块组成。能够准确显示时间(显示格式为时时:分分:秒秒,24小时制),可随时进行时间调整。设计以硬件软件化为指导思想,充分发挥单片机功能,大部分功能通过软件编程来实现,电路简单明了,系统稳定性高。单片机在这种情况下诞生了基于单片机电子时钟。
2、硬件电路原理图
3、原理仿真图
4.硬件模块功能介绍
4.1 AT89S51单片机:AT89S51提供以下标准功能:8k字节Flash闪速存储器,256字节内部RAM,32个I/O口线,3个16位定时/计数器,一个6向量两级中断结构,一个全双工串行通信口,片内振荡器及时钟电路[2]。同时,AT89S51可降至0HZ的静态逻辑操作,并支持两种软件可选的节电工作模式。空闲方式停止CPU的工作,但允许RAM,定时/计数器,串行通信口及中断系统继续工作。掉电方式保存RAM中的内容,但振荡器停止工作并禁止其它所有部件工作直到下一个硬件复位。
4.2 液晶显示器LCD:液晶显示器简称是利用液晶经过处理后能够改变光线传输方向的特性,达到显示字符或者图形的目的。其特点是体积小、重量轻、功耗极低、显示内容丰富等特点,在单片机应用系统中有着日益广泛的应用。
1602芯片:主要用于显示时间和定时时间。1602芯片由点阵字符液晶显示器件和专用的行、列驱动器、控制及必要的链接件、结构件组装而成,可以显示数字和西文字符,但不能显示图形,已经可以满足本次设计的需要。1602型LCD可以显示2行16个字符,有8位数据总线D0~D7和RS,R/W,EN三个控制端口,工作电压为5V,并且具有字符对比度调节和背光功能。
4.3 键盘控制模块:按键中有一个复位键及定时键、调时键加一键和减一键,一个按键接在复位电路上,另外三个按键接在P3.0——P3.2口,低电平表示有按钮按下;按钮没有接防抖电路,需要设计软件防抖。
1、定时。按下定时键后可以开始定时,过程如下:定时---〉小时加/减---〉按定时---分钟加/减---按定时。
2、调时。按下调时键后可以调时,过程如下:调时---年加/减---调时--月加/减---调时---日加/减---调时---时加/减---调时---分加/减---调时---秒加/减---调时。
4.4 直流稳压电源部分:直流稳压电源是给电子设备提供稳定直流电压的电子电路。这次电路需要的是+5V直流电源。5.软件设计
5.1 代码附录
#include
void delay(uint x){ uint i, j;for(i=0;i uchar code table[]=“ 2013-01-18 MON ”;//定义数组 表示年月日 uchar code table1[]=“ 12-30-16 ”;//定义数组 表示时分秒 //********************写命令******************************** //=========== void write_com(uchar com){ lcdrs = 0;//表示写入的是指令,即对指令进行操作 lcdrw = 0;lcden = 0;//使能信号为0 delay(2);WUFU = com;//向端口传送命令 lcden = 1;delay(2);lcden = 0;} //*********************写数据********************************** //=============== void write_date(uchar date)//写数据初始化 { lcdrw = 0;lcdrs = 1;//表示写入的是数据,即对数据进行操作 delay(2);lcden = 0;WUFU = date;lcden = 1;delay(2);lcden = 0;} //********************函数初始化***************************** //---------------------------- void init()//写入时间函数 { shi = 12;fen =30;miao = 16;write_com(0x38);//这句意思是用1602,5*7,的点整来显示数据 能显示16个字节 write_com(0x0c);//光标不闪烁 write_com(0x06);//输入数据光标制动加1,数据地址制动加1 write_com(0x01);//清屏指令 write_com(0x80);//1602液晶第一行 for(num=0;num<16;num++)//通过for循环调用数组里面的元素 { write_date(table[num]);//写入数据 delay(5);//延时5秒 } write_com(0xc0);//1602液晶第二行 for(num=0;num<14;num++){ write_date(table1[num]); delay(5);} TMOD = 0x01;//T0工作模式1 TH0 =(65532-50000)/256;//赋初值高8位 想定时器中写入初始值为50毫秒 TL0 =(65532-50000)%256;//赋初值低8位 EA = 1;//cpu开中断 ET0 = 1;//打开定时器 TR0 = 1;//启动定时器 } void write_sfm(uchar add, uchar date){ uchar shi,ge;shi= date/10;//把时间的十位分离出来 ge = date%10;//把时间的各位分离出来 write_com(0xc0+add);//显示这个时间的地址,这具体是显示十位的地址,但因为显示了十位地址制动加加所以不用现出显示个位的地址 write_date(0x30+shi);//在1602中要显示1它的地址是0x31,以此类推显示数字9是为0x39,所以前面要加上0x30 write_date(0x30+ge);//与上同理 } void write_nyr(uchar add, uchar date){ uchar shi,ge;shi= date/10;ge = date%10;write_com(0x80+add);write_date(0x30+shi);write_date(0x30+ge);} void write_week(uchar we){ write_com(0x80+12);switch(we){ case 1: write_date('M'); delay(5); write_date('o'); delay(5); write_date('N'); break; case 2: write_date('T'); delay(5); write_date('U'); delay(5); write_date('E'); break; case 3: write_date('W'); delay(5); write_date('E'); delay(5); write_date('D'); break; case 4: write_date('T'); delay(5); write_date('H'); delay(5); write_date('U'); break; case 5: write_date('F'); delay(5); write_date('R'); delay(5); write_date('I'); break; case 6: write_date('S'); delay(5); write_date('A'); delay(5); write_date('T'); break; case 7: write_date('S'); delay(5); write_date('U'); delay(5); write_date('N'); break;} } void timer0()interrupt 1 { TH0 =(65532-50000)/256;TL0 =(65532-50000)%256;count ++; if(count == 20){ count = 0; miao ++; if(miao == 60) { miao = 0; fen ++; if(fen == 60) { fen = 0; shi ++; if(shi == 24) { shi = 0; } write_sfm(3,shi);//刷新在屏幕上显示变化的小时数值 } write_sfm(6,fen);// 刷新在屏幕上显示变化的分钟数值 } write_sfm(9,miao);// 刷新在屏幕上显示变化的秒的数值 } } void keyscan(){ if(key1 == 0){ delay(5); if(key1 == 0) { keynum ++; while(!key1); if(keynum == 1) { TR0 = 0;//关定时器 write_com(0xc0+9);//光标定位在秒的位置 write_com(0x0f);//光标开始闪烁 } if(keynum == 2) { write_com(0xc0+6); } if(keynum == 3) { write_com(0xc0+3);//光标定位在时的位置上 } if(keynum == 4) { //keynum = 0; //write_com(0x0c);//取消光标闪烁 //TR0 = 1; write_com(0x80+12); } if(keynum == 5) { write_com(0x80+9); } if(keynum == 6) { write_com(0x80+6); } if(keynum == 7) { write_com(0x80+3); } if(keynum == 8) { keynum = 0; write_com(0x0c);//光标不闪烁 TR0 = 1;//启动定时器 时间又开始走了 } } } if(keynum!= 0)//如果k1没有按到第四次 { if(key2 == 0)//如果k2按键按下 { delay(5); if(key2!= 0)//松手检测 { while(!key2); if(keynum == 1) { miao ++;//秒表进行++ if(miao == 60)//当秒加到60秒后 miao = 0;//把秒值为0 write_sfm(9,miao);//把调好的秒值写打屏幕上 write_com(0xc0+9);//把光标还到 原来的位置 } if(keynum == 2) { fen ++; if(fen == 60) fen = 0; write_sfm(6,fen);//把调好的分值写打屏幕上 write_com(0xc0+6);//把光标还到原来的位置 } if(keynum == 3) { shi ++; if(shi == 24) shi = 0; write_sfm(3,shi);//把调好的时值写打屏幕上 write_com(0xc0+3);//把光标还到原来的位置 } if(keynum == 4) { week ++; if(week == 8) week = 1; write_week(week); write_com(0x80+12); } if(keynum == 5) { day ++; if(day == 32) day = 1; write_nyr(9,day); write_com(0x80+9); } if(keynum == 6) { month ++; if(month == 13) month = 1; write_nyr(6,month); write_com(0x80+6); } if(keynum == 7) { nian ++; if(nian == 100) nian = 0; write_nyr(3,nian); write_com(0x80+3); } } } if(key3 == 0) { delay(5); if(key3 == 0) { while(!key3); if(keynum == 1) { miao--; if(miao ==-1) miao = 59; write_sfm(9,miao); write_com(0xc0+9); } if(keynum == 2) { fen--; if(fen ==-1) fen = 59; write_sfm(6,fen); write_com(0xc0+6); } if(keynum == 3) { shi--; if(shi ==-1) shi = 24; write_sfm(3,shi); write_com(0xc0+3); } if(keynum == 4) { week--; if(week ==-1) week = 7; write_week(week); write_com(0x80+12); } if(keynum == 5)//与函数递增函数一样只是按键不同还有就是功能相反了 { day--; if(day == 0) day = 31; write_nyr(9,day); write_com(0x80+9); } if(keynum == 6)//与函数递增函数一样只是按键不同还有就是功能相反了 { month--; if(month == 0) month = 12; write_nyr(6,month); write_com(0x80+6); } if(keynum == 7)//与函数递增函数一样只是按键不同还有就是功能相反了 { nian--; if(nian == 0) nian = 100; write_nyr(3,nian); write_com(0x80+3); } } } } } //============================================= //函数主程序 //============================================= void main(){ init();while(1){ keyscan();} } 5.2调试过程 调试的主要过程包括硬件调试和软件调试,其中软件调试,也即程序编译与仿真过程处于本次设计调试过程的核心环节。由于本设计已经制作出液晶显示电子钟,所以硬件调试也很重要。两种调试过程并非孤立或者分开的,而是紧密相关。在此我们用到的开发工具是仿真器。5.3硬件调试 完成仿真器软件仿真后,就要连接上硬件也即液晶显示电子钟成品板进行硬件调试。 将仿真器通过串行电缆连接计算机上,将仿真头接到仿真器,检查接线是否有误,确信没有接错后,接上电源,打开仿真器的电源开关。再进行仿真器和通信设置。 仿真器和仿真头设置正确,并且硬件连接没有错误,出现 “硬件仿真”的对话框,并显示仿真器、仿真头的型号及仿真器的序列号。表明仿真器初始化正确。 硬件调试很重要也很麻烦,由于本次设计硬件非PCB制板,而是手工焊板,焊点质量、布线是否合理等对系统的影响比较大,这无疑增加硬件调试的难度。由于此前没有很多的练习,本次设计我所制作的液晶显示电子钟在质量工艺上很难达到满意程度,不过在调试中还算稳定,基本功能都能较稳定地实现。5.4软件调试 系统仿真分析电路原理图在ISIS里设计完成,并将系统软件编译成.Hex文件,再进行电子时钟的系统虚拟仿真。(1)在ISIS的原理图中,右键单击AT89S51将其选中,然后单击左键打开AT89C51的Edit Component 对话框,如下图所示。(2)选择相应的.Hex文件,再在Proteus ISIS 编辑窗口的File菜单中选择Save Design 选项,保存设计,生成.DSN文件。5.5测试数据与数据分析 实现功能的具体方法:当进入调整功能时,按第二个键K2进行加运算按第三个键K3进行减运算。 按下第一个键K1,实现日期时间调整及定时功能,等数字闪烁后,按二三键进行加减,从而可以进行具体日期时间调整。按下第四个键K4回到原始设计时间,采用24小时制。时间显示格式为:时-分-秒;日期显示格式为:日-月-年。具有显示时间和日期的功能。 三、总结:个人心得体会 微机实习让我对计算机理论知识和自动化专业知识有了一定的了解,但真正操作起来就没有那么容易.纸上得来终觉浅, 绝此事要躬行。经过过去3个星期的实训,我对自己有了新的认识及前进的方向。1.继续学习,不断提升理论素养。 在信息时代,学习是不断地汲取新信息,获得事业进步的动力。现在通过实习总感觉自己学的不够,要用到知识时总感觉脑袋是空白的。很后悔自己当时在学校为什么不多学一点,多练习一点。总在后悔也没有用,只能自己去努力学习。为了能更好的适应工作,我利用自己空闲时间去附近的书店去看书,希望能弥补不足。2.加强信心,坚持下去 现在大家都说,能珍惜现在的日子就好好珍惜。等工作了才真的有另外的领悟。每天起早贪黑,忙忙碌碌,做了第一天可能就想回到学校接着做学生。感觉学生时代真是最美好的时间。可是既然真的出来了,就得踏出来了就要继续走下去,因为这一天也终究要来到。 对给自己点信心,多给自己点赞赏,多给自己鼓鼓劲。相信总会走出一条宽敞大道的。 3、友善相处 学生时代都感觉很美好,大家相互嘘寒问暖,不必勾心斗角。我感觉这里才真的有纯洁的友谊。其实想说,这就是一个小型的社会,我们互相的关照,互相体谅,学习上你我照应,工作上你我参与,和谐相处,这样,我们的友谊才会深刻,所以我们应该正确的对待与人之间的关系,友善相处。 最后想说,实习训是开端也是结束。在书本上学过很多理论,但从未付诸实践过,也许等到真正运用时,才会体会到难度有多大。在今后的工作和生活中,自己需要更加努力的奋斗下去。 实训的同时也让我了解到了自己的不足,我会继续努力,完善自我。对于学校的精心安排和指导老师的用心辅导非常感谢。 课程设计任务书 (指导教师填写) 课程设计名称电子技术课程设计学生姓名专业班级设计题目数字钟 一、课程设计的任务和目的任务:设计一台能显示“时”、“分”、“秒”的数字钟,周期为24小时;具有校时、正点报时功能。 目的:培养学生综合运用所学知识的能力,综合设计能力,培养动手能力及分析问题、解决问题的能力。 二、设计内容、技术条件和要求 1.数字钟可显示“时”、“分”、“秒”,且“时”、“分”、“秒”分别用两个数码管显示,计满23小时60分钟60秒,则全部清零。 2.具有校时功能,时、分校时用1HZ的信号进行,而秒较时用2HZ时钟信号进行。 3.整点能自动报时。要求报时声响为四低一高,最后一响为整点,前四声用500HZ信号让喇叭发声,最后一声用1000HZ信号。 4.根据上述要求,画出电路总框图,简述各部分工作原理。 5.进行各部分电路的设计,要求有分析过程、原理图表示。 6.对原理图进行仿真。 7.在实验箱上组装、调试。 8.撰写设计总结报告。 三、时间进度安排 第一周:理论设计。 周一上午布置设计任务,讲解设计要求,安排答疑、实验时间; 周三、周四下午课程设计答疑,其他时间学生查资料,做初步理论设计; 周五交设计初稿,由指导教师审查; 第二周:仿真和安装调试、撰写设计总结报告 周一、二学生进实验室做仿真实验,并根据实验情况修正设计图; 周三至周五做插接线实验,最后根据实验情况总结、撰写设计说明书。 四、主要参考文献 1.各种版本的数字电子技术基础教材 2.各种版本的电子技术课程设计指导书 3.集成电路手册 指导教师签字:年月日 单片机课程设计 题目 专业 通信工程 班级 11级1班 学号 姓名 电 子 钟 设 计 单片机原理与应用课程设计 电子钟设计 功能要求: 1、设计一个电子时钟,要求可以显示时、分、秒,用户可以设置时间。 2、实现秒表功能。 功能描述 (1) 时钟。初始界面是时钟显示,按键S1是调时选位,按键S2是加数。根据不同的闪烁位置进行调节。 (2) 年与日,星期。在初始状态下,按下S2,则跳转,显示年月日,5S后跳回初始界面。若在年月日界面再次按下S2,则再次跳转,显示星期,几秒后跳转回初始界面。 (3) 秒表。在初始界面下,按下S3,则跳转,进入秒表。秒表功能键如下:S1 退出秒表;S2 停止开始计时;S3 秒表清零。 (4) 闹钟。在设置中设置好时间,最高位设为“1”则打开闹钟。最高位设为“0”则关闭闹钟。在闹钟响是,按S3进行关闹钟。 工作原理 硬件 采用80C51系列单片机作为CPU,P0口作为数据线,通过锁存器进行段选和位选,是数码管不断地显示数字。数码管的显示是扫描式。(1) 本电子钟用的单片机型号是STC89C516RD+。P0口作为段选和位选的数据线。P10口为段选寄存器的使能端。P11口为位选寄存器的使能端。晶振采用的12MHz晶振。要求频率稳定。 (2) 本电子钟用的是共阴极数码管。从左到右,第1,2位是秒位;第4,5位是分位;第7,8位是时位。第3,6位是“--”。 (3) 通过单片机的P0口,先对数码管进行位选,即在位锁存器使能是将P0口数据进行锁存。再通过段锁存器将P0口送来的段数据进行锁存。此时数码管的第一位显示数字。同样的步骤进行第二位显示。以非常快的速度进行,由于人眼的余辉效应,会看到8位数码管一起亮。即可以显示时间。通过单片机的内部TO,T1的计数。即可以实现时钟,秒表等功能。(4)电路图如下: 软件 程序代码包括三部分:1.bujian(部件库)2.main(主函数)3.H(头文件库)。一 .bujian(部件库)(1)xianshi.c #include //数码管秒个位 P0=t[s%10];p11=0;P0=0xff;delay(m);p10=1;p10=0;p11=1;P0=0xbf;p11=0; //消隐 P0=t[s/10]; //消隐 //数码管秒十位 P0=0xff;delay(m);} void led_f(unsigned int s){ p10=1;// P0=t[s%10];p10=0;p11=1;P0=0xef; p11=0; P0=0xff;delay(m);p10=1; P0=t[s/10];p10=0;p11=1;P0=0xf7;p11=0; P0=0xff;delay(m);} void led_h(unsigned int s){ // p10=1;P0=t[s%10];p10=0;p11=1;P0=0xfd; p11=0;// P0=0xff;delay(m);p10=1; P0=t[s/10];p10=0;p11=1;P0=0xfe;p11=0; 数码管分个位 //消隐 //数码管分十位 //消隐 数码管时个位 消隐 //数码管时十位 //消隐 P0=0xff;delay(m);} void line(void){ p10=1;P0=0x40;p10=0;p11=1;P0=0xfb;delay(m);p11=0; p10=1;P0=0x40;p10=0;p11=1;P0=0xdf;p11=0;delay(m);} //消隐 P0=0xff; //数码管“---” //消隐 P0=0xff; //数码管“---” (2)miaobiao.c #include #include { while(!s3){led_s(mms);led_f(ms);line();led_h(mf);} TR1=0;mms=0;ms=0;mf=0;} } } (3)Delay.c #include void delay(unsigned int a) { unsigned char l; while(a--) {for(l=0;l<100;l++);} } (4)gongneng.c #include #include if(s2==0){ delay(3);if(s2==0)while(!s2){ led_s(s);delay(1);line();led_f(f);delay(1);led_h(h);delay(1);} // while(1){ led_s(r);delay(2);led_f(y);delay(2);line();led_h(nian);delay(2);aa++;if(s2==0) { while(!s2) { led_s(r);delay(1);line();led_f(y);delay(1);led_h(nian);delay(1);} //星期显示 while(1) {led_f(xing);delay(2); bb++; if(bb==100){bb=0;break;} 日期显示 } } if(aa==100) line();led_f(y);delay(1);led_h(nian);delay(1); } } if(s1==0){ delay(3);if(s1==0){ switch(x){ case 1 : if(shanshuo==1){led_s(s);} line();led_f(f);delay(2);led_h(h);delay(2);break;case 2 :led_s(s);if(shanshuo==1){led_f(f);} delay(2);line();led_h(h);delay(2);break;case 3 : led_s(s);led_f(f);delay(2);line();if(shanshuo==1){led_h(h);} delay(2);break;case 4 : if(shanshuo==1){led_s(r);} led_f(y);delay(2);line();led_h(nian);delay(2);break;case 5 : led_s(r);if(shanshuo==1){led_f(y);} delay(2);line();led_h(nian);delay(2);break;case 6 :led_s(r);led_f(y);delay(2);line();if(shanshuo==1){led_h(nian);} delay(2);break;case 7 :if(shanshuo==1){led_f(xing);delay(5);} break;case 8 :if(shanshuo==1){led_s(nf);} line();led_f(nh);delay(2);led_h(ns);delay(2);break;case 9 :led_s(nf);if(shanshuo==1){led_f(nh);} delay(2);line();led_h(ns);delay(2);break;case 10:led_s(nf);led_f(nh);delay(2);line();if(shanshuo==1){led_h(ns);} delay(2);break;default : break;} aa++;if(s2==0){ while(!s2){if(x==1||x==2||x==3){ led_s(s);delay(1);line();led_f(f);delay(1);led_h(h);delay(1);} if(x==4||x==5||x==6){ led_s(r);delay(1);line();led_f(y);delay(1);led_h(nian);delay(1);} if(x==7){ led_f(xing);} if(x==8||x==9||x==10){led_s(nf);led_f(nh);delay(2);line();led_h(ns);delay(2);} } switch(x) { case 1 : s++;if(s>59)s=0;break; while(!s1);while(1) { if(x==1||x==2||x==3)TR0=0;else TR0=1;if(aa==20){shanshuo=!shanshuo;aa=0;} { break;} { led_s(r);delay(1); } if(s1==0) case 2 : } f++;if(f>59)f=0;break; case 3 : h++;if(h>23)h=0;break;case 4 : r++;if(r>31)r=1;break;case 5 : y++;if(y>12)y=1;break;case 6 : case 7 : nian++;if(nian>20)nian=10;break;xing++;if(xing>7)xing=1;break; case 8 : nf++;if(nf>59)nf=0;break;case 9 : nh++;if(nh>23)nh=0;break;case 10: ns=!ns;break; default: break;{while(!s1){if(x==1||x==2||x==3){ led_s(s);delay(1);line();led_f(f);delay(1);led_h(h);delay(1);} if(x==4||x==5||x==6){ led_s(r);delay(1);line();led_f(y);delay(1);led_h(nian);delay(1);} if(x==7){ led_f(xing);} if(x==8||x==9||x==10){led_s(nf);led_f(nh);delay(2);line();led_h(ns);delay(2);} } x++;if(x>10){ x=0;TR0=1;break;} } } } } } } 二.H(头文件库)(1)Delay.h #ifndef _DELAY_H__ void led_s(unsigned int s);void led_h(unsigned int s);#define _DELAY_H__ void delay(unsigned int a);#endif(2)xianshi.h #ifndef _XIANSHI_H__ #define _XIANSHI_H__ void led_f(unsigned int s);void line(void);#endif(3)gongneng.h #ifndef _DONGNENG_H__ #define _GONGNENG_H__ void gongneng(void);#endif(4)miaobiao.h #ifndef _MIAOBIAO_H__ #define _MIAOBIAO_H__ void miaobiao(void);#endif(5)dingyi.h #ifndef _DINGYI_H__ #define _DINGYI_H__ sbit s1=P2^4; sbit s2=P2^5; sbit s3=P2^6;sbit p10=P1^0;sbit p11=P1^1;sbit p12=P1^2;#endif //流水灯使能端 //按键1 //按键2 //按键3 sbit p37=P3^7;//蜂鸣器时能 三.Main(主函数)(1)main.c #include ET0=1;TH0=6;TR0=1; //关闭流水灯 ET1=1;TH1=(65535-5000)/256;TL1=(65535-5000)%256;TR1=0;while(1){ if((s3==0)&&(ns==0)){while(!s3);miaobiao();} if(s1==0||s2==0)gongneng();else { led_s(s);line();led_f(f);line();led_h(h);} if((f==nf)&&(h==nh)&&(ns==1))ll=1;else ll=0;} } void zhongduan(void)interrupt 1 { if((ll==1)&&(ns==1)) { p37=!p37;if((s3==0)&&(ns==1)){ while(!s3)ns=0;p37=1;} } n++;if(n==5000){n=0;s++;if(s==60){ s=0;f++;} if(f==60){ f=0;h++;} if(h==24){ h=0;r++;xing++;} switch(r){ case 29 : if(nian/4==0){if(y==2)r=0;} y++;case 31 : if(y==4||y==6||y==9||y==11){ } if(xing>7)xing=1;if(y==13){ y=1;nian++;} } } default : break; break;case 30 : if((nian/4)!=0){if(y==2){ r=0;y++;}} break; r=0;y++;} break;case 32 : if(y==1||y==3||y==5||y==7||y==8||y==10||y==12){r=0;y++;} break;void zhongduan1(void)interrupt 3 { TH1=(65535-5000)/256; m++;TL1=(65535-5000)%256;if(m==2){mms++;m=0;if(mms>=100){ mms=0;ms++;} if(ms==60){ ms=0;mf++;} if(mf==60){ mf=0;} } } 参考文献: 单片机中级教程(第2版)、单片机语言C51程序设计(赵文博)感想: 这次课程设计整体来说是成功的,但我也发现了自己许多错漏和不足之处。譬如,最简单的程序没写好就想着写更复杂的程序,做事还是缺乏耐性和细心,当有时遇到问题时,总觉得无从下手,对于课本上的知识不能很好的组织起来。在编写各功能程序时,特别是后来增添的比较复杂的程序 目 录 一、课程设计的主要内容和要求 ……………………………………………… 1 二、实现原理等知识的介绍 …………………………………………………… 2 2.1电子时钟的设计 2.2单片机识的相关知识 三、系统的总体方案设计说明;3.1总体设计方案 3.2总设计原理框图 四、具体实现步骤的设计说明; 五、单片机系统程序的编制; 六、测量过程的操作说明,原始测量数据的记录; 七、结论及存在问题; 八、心得体会总结; 九、参考文献。 一、主要内容和要求 主要内容:设计一个数字式电子钟,它具有时,分,秒的计时功能,可以 通过键盘进行时间设定, 并且将时间显示在 LED 数码管上。用按键设定时钟的时、分、秒,用扫描方式动态显示。时钟用定时中断方式工作,单片机晶体震荡器频 率 11.0592Mhz.。可选做双机通信实验, 实现子母钟功能, 即由其中一台做时钟, 另一台采集时钟值并显示。对于基本题目要求是: 用按键设定时钟的时、分、秒。要求用 4键方式,即选择、加、减、确认键, 选择键用于选择修改起始时、分、秒值,每按一次,被修改数码管顺序移动并闪 烁。用 +,键修改数值,确认键确定后秒位清零,修改结束。 2.2单片机的相关知识 1单片机简介 单片机全称为单片机微型计算机(Single Chip Microsoftcomputer。从应用领 域来看,单片机主要用来控制,所以又称为微控制器(Microcontroller Unit或 嵌入式控制器。单片机是将计算机的基本部件微型化并集成在一块芯片上的微型 计算机。单片机的发展史 3 4位单片机 1975年,美国德克萨斯仪器公司首次推出 4位单片机 TMS-1000;此后,各 个计算机公司竞相推出四位单片机。日本松下公司的 MN1400系列,美国洛 克威尔公司的 PPS/1系列等。四位单片机的主要应用领域有:PC 机的输入装 置,电池充电器,运动器材,带液晶显示的音 /视频产品控制器,一般家用 电器的控制 8位单片机 1972年,美国 Intel 公司首先推出 8位微处理器 8008,并于 1976年 9月率 先推出 MCS-48系列单片机。在这以后, 8位单片机纷纷面市。例如,莫斯特克 和仙童公司合作生产的 3870系列, 摩托罗拉公司生产的 6801系列等。随着集成 电路工艺水平的提高,一些高性能的 8位单片机相继问世。例如, 1978年摩托 罗拉公司的 MC6801系列及齐洛格公司的 Z8系列, 1979年 NEC 公司的 UPD78XX 系列。这类单片机的寻址能力达 64KB ,片内 ROM 容量达 4--8KB ,片内除带有并 行 IO口外,还有串行 IO口,甚至还有 AD转化器功能。8位单片机由于功能 强,被广泛用于自动化装置、智能仪器仪表、智能接口、过程控制、通信、家用 电器等各个领域。16位单片机 1983年以后,集成电路的集成度可达几十万只管 /片,各系列 16位单片机 纷纷面市。这一阶段的代表产品有 1983年 Intel 公司推出的 MCS-96系列, 1987年 Intel 推出了 80C96,美国国家半导体公司推出的 HPC16040, NEC 公司推出的 783XX 系列等。16位单片机主要用于工业控制, 智能仪器仪表, 便携式设备等场 合。32位单片机 随着高新技术只智能机器人, 光盘驱动器,激光打印机,图像与数据实时处 理,复杂实时控制,网络服务器等领域的应用与发展, 20世纪 80年代末推出了 32位单片机,如 Motorlora 公司的 MC683XX 系列, Intel 的 80960系列,以及近年来流行的 ARM 系列单片机。32位单片机是单片机的发展趋势,随着技术的发 展及开发成本和产品价格的下降,将会与 8位单片机并驾齐驱。64位单片机 近年来, 64位单片机在引擎控制,智能机器人,磁盘控制,语音图像通信, 算法密集的实时控制场合已有应用, 如英国 Inmos 公司的 Transputer T800是高性 能的 64位单片机。2.2.3单片机的特点 1单片机的存储器 ROM 和 RAM 时严格区分的。ROM 称为程序存储器,只存 放程序,固定常数,及数据表格。RAM 则为数据存储器,用作工作区及存放用 户数据。采用面向控制的指令系统。为满足控制需要,单片机有更强的逻辑控制能 力,特别是单片机具有很强的位处理能力。 3单片机的 I/O口通常时多功能的。由于单片机芯片上引脚数目有限,为了 解决实际引脚数和需要的信号线的矛盾, 采用了引脚功能复用的方法, 引脚处于 何种功能,可由指令来设置或由机器状态来区分。单片机的外部扩展能力很强。在内部的各种功能部件不能满足应用的需 求时,均可在外部进行扩展, 与许多通用的微机接口芯片兼容, 给应用系统设计 带来了很大的方便。 2.2.4数码管显示工作原理 LED 数码管分共阳极与共阴极两种,其工作特点是,当笔段电极接低电平,公共阳极 接高电平时,相应笔段可以发光。共阴极 LED 数码管则与之相反,它是将发光二极管的阴 极(负极 短接后作为反映出半导体材料的特性。常见管芯材料有磷化镓(GaP、砷化镓(GaAs、磷砷化镓(GaAsP、氮化镓(GaN等,其中氮化镓可发蓝光。发光颜色不仅与管芯材料有关, 还与所掺杂质有关,因此用同一种管芯材料可以制成发出红、橙、黄、绿等不同颜色的数码 管。其他颜色 LED 数码管的光谱曲线形状与之相似,仅入,值不同。LED 数码管的产品中, 以发红光、绿光的居多、这两种颜色也比较醒目。 LED 数码管等效于多只具有发光性能的 PN 结。当 PN 结导通时,依靠少数载流子的注 人及随后的复合而辐射发光, 其伏安特性与普通二极管相似。在正向导通之前, 正向电流近似于零,笔段不发光。当电压超过开启电压时,电流就急剧上升,笔段发光。因此, LED 数码管属于电流控制型器件,其发光亮度 L(单位是 cd /m2 与正向电流 IF 有关,用公式表 示:L=KIF即亮度与正向电流成正比。LED 的正向电压 U ,则与正向电流以及管芯材料有 关。使用 LED 数码管时,工作电流一般选 10mA 左右/段,既保证亮度适中,又不会损坏 器件。 三、系统的总体方案设计说明 3.1总体设计方案 本次设计时钟电路,使用了 ATC89C52单片机芯片控制电路,单片机控制电 路简单且省去了很多复杂的线路, 使得电路简明易懂, 使用键盘键上的按键来调 整时钟的时、分、秒,用一扬声器来进行定时提醒,同时使用汇编程序来控制整 个时钟显示,使得编程变得更容易,这样通过四个模块:按键、芯片、扬声器、LED 数码管即可满足设计要求。 3.2总设计原理框图如下图所示: 四、具体实现步骤的设计说明 4.1 电路设计原理说明 本设计电路,硬件部分共由五个模块组成:按键模块、复位电路模块、晶振 电路模块、发声模块、时间显示模块。晶振电路模块负责给单片机提供时钟周期。复位单路模块负责上电后自动复位,或按键后强制复位。上电后, 由单片机内部 定时器计时,同时通过动态显示函数自动将时分秒显示到数码管上。与此同时, 按键扫描函数,一直扫描按键引脚状态, 一旦扫描到按键被按下, 即进入相应的 功能函数。4.2各部分电路说明 1按键模块 按键模块如图所示。 在该模块中, 采用四个按键作为电子时钟的控制输入, 通过按键来实现时钟 的时间设置功能。电路中将四个按键的一端接公共地,而单片机的 P2口默认为 高电平, 一旦按键被按下, 则该按键对应的额管脚被拉低, 通过软件扫描按键即 可知道用户所要实现的功能,调用相应的按键子程序来完成该操作。 2单片机的复位电路 单片机的复位电路 , 如图所示。 图单片机的复位电路 当 MCS-5l 系列单片机的复位引脚 RST(全称 RESET 出现 2个机器周期以上的 高电平时,单片机就执行复位操作。如果 RST 持续为高电平,单片机就处于循环 复位状态。根据应用的要求, 复位操作通常有两种基本形式:上电复位和上电或 开关复位。上电复位要求接通电源后,自动实现复位操作。上电后,保持 RST 一 段高电平时间。 3单片机的晶振电路 单片机的晶振电路,如图所示。 图 单片机的晶振电路 石英晶体也连接在晶振引脚的输入和输出之间,等效为一个并联谐振回路, 振荡频率应该是石英晶体的并联谐振频率。晶体旁边的两个电容接地, 实际上就 是电容三点式电路的分压电容 , 接地点就是分压点。以接地点即分压点为参考点, 振荡引脚的输入和输出是反相的,但从并联谐振回路即石英晶体两端来看 , 形成 一个正反馈以保证电路持续振荡。 4发声模块 发声模块,如图所示。 图 发声指示模块 发声模块由蜂鸣器、电源、8550三极管、限流电阻组成。蜂鸣器由 PNP 三 极管驱动,当 BZ 管脚为高时,三极管 be 级没电压差,三极管截止;反之,三极 管导通,有电流流经蜂鸣器,蜂鸣器发声。 5时间显示模块 时间显示模块如图所示。 图 时间显示模块 时间显示部分的电路也很简单, 由五个一位的共阴 8段数码管、五盏发光二 极管组成。在显示过程中, 单片机将要显示的数字传递给 89C52芯片, 同时通过 位选选通要显示的数码管。 五、单片机系统程序的编制 5.1程序设计 ORG 0000H LJMP START;转初始化 ORG 000BH LJMP PGT0;T0中断入口 ORG 0033H START: DIS1 EQU 30H DIS2 EQU 31H DIS3 EQU 32H DIS4 EQU 33H DIS5 EQU 34H DIS6 EQU 35H DISXS EQU 36H DISFZ EQU 37H DISMZ EQU 38H MS500 EQU 39H K1 BIT P3.2 K2 BIT P3.3 K3 BIT P3.4 K4 BIT P3.5 BDP BIT 01H bd BIT 02H MOV SP,#50H;初始化程序 MOV P0,#0FFH MOV P1,#0FFH MOV P2,#0FFH MOV P3,#0FFH MOV TMOD,#01H;定时器 T0工作于方式 1 MOV TH0,#4CH;定时器初值 MOV TL0,#05H MOV IE,#82H MOV R3,#10 SETB TR0 MOV DIS1,#00H;清显示缓冲区 MOV DIS2,#00H MOV DIS3,#00H MOV DIS4,#00H MOV DIS5,#00H MOV DISXS,#12;初始化时间为 12:30:00 MOV DISFZ,#30 MOV DISMZ,#0 MOV MS500,#0 MAIN:;主程序 jnb k2,d1 jnb k3,d2 jnb k4,d3 jnb k1,d4 d1: ljmp send d2: ljmp send d3: ljmp send d4: jnb k1,qu1 qu1:lcall sound ajmp god1 k1dd: jb k2,k2dd lcall ys10ms 11 5.2 程序流程图 六、测量过程的操作说明,原始测量数据的记录。6.1 操作说明操作功能说明 功能说明表 按键 K1 K2 K3 K4 发光二极管 功能 当按一下 K1,进入调整小时状态,再按一下,进入到调整分 钟状态,如此循环 用来对 小时 和 分钟 进行加时间(每次加 1)用来对 小时 和 分钟 进行减时间(每次减 1)确认键,退出选中小时或分钟 对秒数的十位数进行记录,亮一盏灯代表十秒,亮两盏灯代表 二十秒,如此累推 6.2 原始测量数据的记录 数据记录表 初始值 按一次 K1 按一次 K2 按一次 K3 第二次按 K1 按一次 K2 按一次 K3 按 K4 12.30.0 12.##.# 13.##.# 12.##.# ##.30.# ##.31.# ##.30.# 12.30.0 16 七、结论及存在问题 通过用汇编对 K1、K2、K3、K4 的编译,可以初步实现调整时钟时间的功能。但在编译过程中也遇到不少问题,第一,编译时有跳出转移范围的问题,这是由 于判断语句 JB、JNB 的转移范围是-128~+127 字节,出现这样的问题是由于超出 转移范围。第二,要实现选中小时或者分钟位上的闪烁,要用到延时和对数码管 的显示效果,但达不到指定目的,数码管闪烁的效果不明显,这是由于延时的时 间不够长,使得人眼难以看得清。 八、心得体会总结 本文介绍的是利用 AT89C51 单片机设计的有调时功能的电子时钟。并详细说 明了软件和硬件设计方法。在设计过程中可以看出,汇编语言有着其独特的魅力,它简单易学,语法错误容易纠正;用单片机实现电子时钟的设计是比较方便和易 于实现。通过电子时钟的设计和制作,加深了对单片机的理解,能够更熟练地应用单 片机实现预期的功能,对今后的学习有很大的帮助。电子时钟各项功能的实现,为自动控制的实现打下了理论基础,获得了实现方法。当然,该电子钟还有很多不足之处,比如不能定时,不能报时。断电后不能 只能调时。在今后的学习中还要对此加以研究,九、参考文献及网站 《单片机原理及其接口技术》胡汉才 编著 北京 清华大学出版社 《51 系列单片机及 C51 程序设计》王建校等 科学出版社 其它有关资料 几个有关单片机和芯片资料的网站: http://www.teniu.cc http://www.teniu.cc http://www.teniu.cc http://www.teniu.cc http://www.teniu.cc 等及其相关链接 17 http://www.teniu.cc http://www.teniu.cc http://www.teniu.cc/ …………. 目录 一 引言...............................................................................................................................5 二 硬件设计.......................................................................................................................5 三 软件设计.......................................................................................................................5 四 调试过程及问题分析.................................................................................................6 五 结论.............................................................................................................................7 六 参考文献.....................................................................................................................7 附件.....................................................................................................................................8 一 引言 单片机应用技术飞速发展,纵观我们现在生活的各个领域,从导弹的导航装置,到飞机上各种仪表的控制,从计算机的网络通讯与数据传输,到工业自动化过程的实时控制和数据处理,以及我们生活中广泛使用的各种智能IC卡、电子宠物等,单片机都起到了举足轻重的作用。 所以单片机技术也日趋成熟。单片机是集CPU,RAM,ROM,定时,计数和多种接口于一体的微控制器。它体积小,成本低,功能强。而52系列单片机是各单片机中最为典型和最有代表性的一种。 此次单片机原理及应用实习通过利用52单片机对电子钟的设计,从而达到学习、了解单片机相关指令在各方面的应用,以及初步了解开发软、硬件的知识。 二 硬件设计 本次单片机原理及应用实习我们组用到的硬件为MCS51开发板和一个LCD12864液晶显示器。 在MCS51开发板中,对于我们组做数字电子钟而言应用到ds1302芯片,蜂鸣器,LED点阵显示屏,STC89S52单片机,锁存器等等硬件设备。 通过对这些硬件的使用实现我们组规定的以及我们拓展的要求。 三 软件设计 此次基于单片机的电子钟的实习基本要求为: 基本要求 (1)能通过键盘设定年月日时分秒; (2)在LCD12864上显示年月日时分秒及星期;(3)整点蜂鸣器响6次,每秒响一次,最后一响是整点;(4)按学校的作息时间表定时打铃(可用一个LED灯模拟打铃)扩展要求 自动计算和显示阴历 基于这些功能,我们用到了如下程序 (1)时钟程序ds1302(2)按键控制程序keyscan (3)整点报时程序fengming(4)作息时间表程序schooltime fengming(5)显示程序LCD12864(6)自动计算阴历程序 Chinesecalender(7)自动计算星期程序conver_week 我们最初的整体思路是将我们的实习课题分成几个模块,每个人负责一个部分,争取第一周弄完个人部分.第二周主要进行不同模块的整合,以及整个程序的调试和改进.此外准备答辩的PPT,由组长答辩。 程序设计流程图如下: 四 调试过程及问题分析 在这一次单片机原理及应用的实习中,我学到了很多。虽然整个过程并不是一帆风顺的,但是通过 我们的共同努力,最终完成了任务。充分发挥了团队精神,我们互帮互助,共同提高。 我觉得在拿到一个课题的时候,我们首先应该思考的是干什么?然后才是怎么干?最后是如何优化。于是我开始上网搜有关电子钟设计的相关资料,我了解到:我们本次是利用MCS51开发板和LCD12864液晶显示器制作的,可以完成计时、计分、几秒和校时、校分的功能。微处理器是单片机的核心,完成运算和控制的操作串行口数据存储器与复位电路、时钟电路、校时电路由微处理器控制完成各自的任务。最后通过液晶显示器显示时分秒。 在这次实习中我负责的是显示程序LCD12864,刚开始我对于LCD显示程序并不是太了解。在校园网上找到了些相关的初步显示程序。通过LCD12864中的一些程序的调用,才能进行显示,但那是以图片的形式显示的,与我们所期望的显示还是有一定的差别,所以我又做进一步的修改,通过和组员的讨论,我才知道有一个显示汉字的程序是通过字模软件实现的,之后我们的显示这一块就可以依据我们自己的想法进行设计了。 而在整个的程序综合中,也遇到了一些问题。比如在阴历显示在屏幕上的时候,最初只显示阴历两个字,不显示具体的阴历,后来经过检查发现程序调用出现问题,改正后继续进行优化。 就这样,我们反复的修改调试,最终完成了我们的整个课程设计。 五 结论 在本次的课程设计中,我们虽然走了些小弯路,但是通过我们的共同努力,最终完成了任务。我从中我学到了很多,比如团队协作精神,众人拾材火焰高。任何大问题,在一步一步细化之后,解决起来就轻松得多了!我相信只要付出了就会有收获。无论什么事情,只有当你用心去做了之后你才会发现它的真实意义所在。我觉得这一次实习是非常有意义的,不仅提高了专业素养,还培养了我们的合作精神。我要把握每一次学习的机会,认真对待,为以后的就业及更深层次的发展添砖加瓦。 六 参考文献 一、谭浩强 C语言课程设计(第三版)清华大学出版社 2005.7 二、杨恢先 黄辉先 单片机原理及应用[M] 北京人民邮电出版社 2006.10 三、C编写组编 常用C语言速查手册 龙门书局 1995 附件 *********************************初始化LCD*******************************/ void Lcminit(void){ cbyte=DISPOFF; WrL(cbyte); WrR(cbyte); cbyte=DISPON; WrL(cbyte); WrR(cbyte); cbyte=DISPFIRST; WrL(cbyte); WrR(cbyte); Lcmcls(); Locatexy(0,0);} /***********************************LCD清屏********************************/ void Lcmcls(void){ uchar i,j; for(i=0;i<8;i++){ delay(6); for(j=0;j delay(6); Wrdata(0x0,i,j); } } } /************************************写左区*********************************/ void WrL(uchar x){ P0=0xFF;//P0口送FF,准备读 lck = 0; P1 = 0x2a;//ELCD=1/W=1(读),CSB=1,CSA=0 lck = 1; while(P0 & LCDBUZY);//最高位为1,表示忙,则循环 lck = 0; P1 = 0x00;//ELCD=0,R/W=0(读),CSB=0,CSA=0 lck = 1; P0 = x; //数据送到P0口 lck = 0; P1 = 0x22;//ELCD=1,RW = 0(写),CSB=1,CSA=0 lck = 1; lck = 0; P1 = 0x00;//ELCD=0,RW = 0(写),CSB=0,CSA=0 lck = 1;} /***********************************写右区***********************************/ void WrR(uchar data x){ P0=0xFF;//P0口送FF,准备读 lck = 0; P1 = 0x29;//ELCD=1,R/W=1(读),CSB=0,CSA=1 lck = 1; while(P0 & LCDBUZY);//最高位为1,表示忙,则循环 lck = 0; P1 = 0x00;//ELCD=0,R/W=0(读),CSB=0,CSA=1 lck = 1; P0=x; //数据送到P0口 lck = 0; P1 = 0x21;//ELCD=1,RW = 0(写),CSB=0,CSA=1 lck = 1;lck = 0;P1 = 0x00;//ELCD=0,RW = 0(写),CSB=0,CSA=0 lck = 1; } /**********************************显示定位***********************************/ void Locatexy(uchar row,uchar col){ uchar x, y, right; switch(col&0xc0) { case 0:{ P0=0xFF;//P0口送FF,准备读 lck = 0; P1 = 0x29;//ELCD=1,R/W=1(读),CSB=0,CSA=1 lck = 1; while(P0 & LCDBUZY);//最高位为1,表示忙,则循环 lck = 0; P1 = 0x00; lck = 1; right = 1;break;}//置右半屏标志 case 0x40:{ P0=0xFF;//P0口送FF,准备读 lck = 0; P1 = 0x2a;//ELCD=1,R/W=1(读),CSB=1,CSA=0 lck = 1; while(P0 & LCDBUZY);//最高位为1,表示忙,则循环 lck = 0; P1 = 0x00;//ELCD=0,R/W=0(读)CSB=0,CSA=0 lck = 1; right = 0;break;}//置左半屏标志 } x=col&0x3f|SETX;//把列数据变成行命令 y=row&0x07|SETY;//把行数据变成行命令 /****************************************************************************/ lck = 0; if(right) P1 = 0x29; else P1 = 0x2a; lck = 1; while(P0 & LCDBUZY);//最高位为1,表示忙,则循环 lck = 0; P1 = 0x00; lck = 1;/***********************************以上为判断忙标志**************************/ P0 = y; lck = 0; if(right) P1 = 0x21; else P1 = 0x22; lck = 1; lck = 0; P1 = 0x00; lck = 1;/************************************以上为送行命令*****************************/ P0=0xFF; lck = 0; if(right) P1 = 0x29; else P1 = 0x2a; lck = 1; while(P0 & LCDBUZY);//最高位为1,表示忙,则循环 lck = 0; P1 = 0x00; lck = 1;/*************************************以上为判断忙标志***************************/ P0 = x; lck = 0; if(right) P1 = 0x21; else P1 = 0x22; lck = 1; lck = 0; P1 = 0x00; lck = 1;/*************************************以上为送列命令***************************/ if(right) statu = 1; else statu = 0;//置左又半区标志 } /*************************************数据写输出*******************************/ void Wrdata(uchar x,uchar row,uchar col){ Locatexy(row,col);//定位显示位置 lck = 0; if(statu) P1 = 0x05;//ELCD=0R/W=0(写),D/I= 1,CSB=0,CSA=1 else P1 = 0x06;//ELCD=0,R/W=0(写),D/I= 1,CSB=1,CSA=0 lck = 1; P0 = x; lck = 0; if(statu) P1 = 0x25;//ELCD=1,R/W=0(写),D/I= 1,CSB=0,CSA=1 else P1 = 0x26;//ELCD=1,R/W=0(写),D/I= 1,CSB=1,CSA=0 lck = 1; lck = 0; P1 = 0x00; lck = 1;} /**********************************半角数据点阵输出******************************/ void Puthalf(uchar *strch,uchar row,uchar col){ uchar i,bakerx; bakerx = row; for(i=0;i<16;i++)//上半字输出 { cbyte=strch[i]; Wrdata(cbyte,bakerx,col); cbyte=strch[i+1]; Wrdata(cbyte,bakerx+1,col); col++; i++;} } void Puthz(uchar *str,uchar row,uchar col){ uchar i,bakerx; bakerx=row; for(i=0;i<32;i++) { cbyte=str[i]; Wrdata(cbyte,row,col); //上半字节输出 i++; row=bakerx+1; cbyte=str[i]; Wrdata(cbyte,row,col); //下半字节输出 row=bakerx; col=col+1; } } /****************************字符型点阵行--》列转换************************/ void VtoH8x16change(uchar *hzbuf){ uchar i,j,k, cash[16]; uchar newbyte, savebit[8]; for(k=0;k<16;k++){ newbyte = 0; for(i=0;i<8;i++){ savebit[i]=hzbuf[i] & 0x80;} for(j=0;j<8;j++){ savebit[j] = savebit[j] >>(7-j); newbyte = newbyte | savebit[j];} cash[k] = newbyte; newbyte = 0; for(i=8;i<16;i++){ savebit[i-8]=hzbuf[i] & 0x80;} for(j=0;j<8;j++){ savebit[j] = savebit[j] >>(7-j); newbyte = newbyte |savebit[j];} cash[k+1] = newbyte; for(j=0;j<16;j++){ hzbuf[j] = hzbuf[j] <<1; } k++;} for(i=0;i<16;i++) hzbuf[i] = cash[i];} /*******************************显示英文和符号字符*******************************/ void vWrite8x16Character(uchar *ch,uchar row,uchar col,bit flag){uchar ucXArray[16],i; if(flag){ // 反白显示英文 for(i = 0;i < 16;i++) ucXArray[i] = ~ch[i];}else{ for(i = 0;i < 16;i++) ucXArray[i] = ch[i];} VtoH8x16change(ucXArray);Puthalf(ucXArray,row,col);} /****************************显示中英文字符串************************************/ void vWrite8x16String(uchar *str,uchar row, uchar col, bit flag){ /************************v_RTInputByte*************************/ void v_RTInputByte(uchar ucDa){ uchar i;ACC = ucDa;for(i=8;i>0;i--){ T_IO = ACC0;/*相当于汇编中的 RRC */ T_CLK = 1;T_CLK = 0;ACC = ACC >> 1;} } /********************** uchar uc_RTOutputByte*************************/ uchar uc_RTOutputByte(void){ uchar i;for(i=8;i>0;i--){ ACC = ACC >>1;/*相当于汇编中的 RRC */ ACC7 = T_IO;T_CLK = 1;T_CLK = 0;} return(ACC);} /************************v_W1302 *************************************/ void v_W1302(uchar ucAddr, uchar ucDa){ lck = 0;P1 = 0x00;lck = 1;unsigned char i, j,thiscol;j = strlen(str);for(i = 0;i < j;i++){ thiscol =(i % 16)* 8 + col;//计算列地址 if(str[i] < 0xa1)//当前显示内容为英文字符 vWrite8x16Character(&char_Table[str[i]-0x20][0],row,thiscol,flag); }} T_CLK = 0; lck = 0;P1 = 0x10;lck = 1;v_RTInputByte(ucAddr);/* 地址,命令 */ v_RTInputByte(ucDa);/* 写1Byte数据*/ T_CLK = 1;lck = 0;P1 = 0x00;lck = 1;} /**************************uc_R1302***********************************/ uchar uc_R1302(uchar ucAddr){ uchar ucDa; lck = 0;P1 = 0x00;lck = 1; T_CLK = 0; lck = 0;P1 = 0x10;lck = 1;v_RTInputByte(ucAddr);/* 地址,命令 */ ucDa = uc_RTOutputByte();/* 读1Byte数据 */ T_CLK = 1;lck = 0;P1 = 0x00;lck = 1;return(ucDa);} /************************* v_Set1302 *********************************/ void v_Set1302(uchar *pSecDa){ uchar i;uchar ucAddr = 0x80; v_W1302(0x8e,0x00);/* 控制命令,WP=0,写操作?*/ for(i =7;i>0;i--){ v_W1302(ucAddr,*pSecDa);/* 秒 分 时 日 月 星期 年 */ pSecDa++;ucAddr +=2;} v_W1302(0x8e,0x80);/* 控制命令,WP=1,写保护?*/ } /*******************************v_Get1302**************************************/ void v_Get1302(uchar ucCurtime[]){ uchar i;uchar ucAddr = 0x81;for(i=0;i<7;i++){ ucCurtime[i] = uc_R1302(ucAddr);/*格式为: 秒 分 时 日 月 星期 年 */ ucAddr += 2;delay(100);} } /**********************************屏幕显示*********************************/ void pingmu(){ uchar disp,copymt; uchar temp; copymt = 0xff; P0=0xff; v_Get1302(&buffer);//读取DS1302 Conver_week(0,buffer[6],buffer[4],buffer[3]);Chinesecalender(0,buffer[6],buffer[4],buffer[3]);disp = buffer[0] % 0x10 + '0'; vWrite8x16Character(&char_Table[disp-0x20][0],2,100,0);//秒个位 temp =buffer[0] & 0x7f;temp = temp/16;disp = temp%10 + '0';vWrite8x16Character(&char_Table[disp-0x20][0],2,92,0);//秒十位 copymt = buffer[1]; disp = buffer[1] % 0x10 + '0'; vWrite8x16Character(&char_Table[disp-0x20][0],2,68,0);//分个位 temp =buffer[1] & 0x7f; temp = temp/16; disp = temp%10 + '0'; vWrite8x16Character(&char_Table[disp-0x20][0],2,60,0);//分十位 disp = buffer[2] % 0x10 + '0'; vWrite8x16Character(&char_Table[disp-0x20][0],2,30,0);//时个位 temp =buffer[2] & 0x7f; temp = temp/16; disp = temp%10 + '0'; vWrite8x16Character(&char_Table[disp-0x20][0],2,22,0);//时十位 disp = buffer[3] % 0x10 + '0'; vWrite8x16Character(&char_Table[disp-0x20][0],0,100,0);//日个位 temp =buffer[3] & 0x7f; temp = temp/16; disp = temp%10 + '0'; vWrite8x16Character(&char_Table[disp-0x20][0],0,92,0);//日十位 disp = buffer[4] % 0x10 + '0'; vWrite8x16Character(&char_Table[disp-0x20][0],0,68,0);//月个位 temp =buffer[4] & 0x7f; temp = temp/16; disp = temp%10 + '0'; vWrite8x16Character(&char_Table[disp-0x20][0],0,60,0);//月十位 disp = buffer[6] % 0x10 + '0'; vWrite8x16Character(&char_Table[disp-0x20][0],0,30,0);//年个位 temp =buffer[6] & 0x7f; temp = temp/16; disp = temp%10 + '0'; vWrite8x16Character(&char_Table[disp-0x20][0],0,22,0);//年十位 disp = buffer[7] % 0x10 + '0'; vWrite8x16Character(&char_Table[disp-0x20][0],0,14,0);//年百位 temp =buffer[7] & 0x7f; temp = temp/16; disp = temp%10 + '0'; vWrite8x16Character(&char_Table[disp-0x20][0],0,6,0);//年千位 }第二篇:单片机课程设计电子钟
第三篇:单片机课程设计-电子钟-完整
第四篇:单片机电子钟设计任务书.
第五篇:长沙理工大学《单片机课程设计》电子钟单片机实习报告