1、第一章:实验概要及相关器材摘要:单片计算机即单片微型计算机(Single-Chip Microcomputer),是集 CPU,RAM,ROM,定时,计数和多种接口于一体的微控制器。体积小,成本低,功能强,广泛应用于智能产品和工业自动化上。而 51 单片机是各单片机中最为典型和最有代表性的一种。这次课程设计可以提高我们的设计、开发软、硬的能力。前言:本文通过用对一个能实现定时,时钟,日历显示功能的时间系统的设计学习,详细介绍了 51 单片机应用中的数据转换显示,数码管显示原理,动态扫描显示原理,单片机的定时中断原理、从而达到学习,了解单片机相关指令在各方面的应用。系统由 AT89C52、LED
2、 数码管、按键、二极管等部分构成,能实现时钟日历的功能:能进行时、分、秒的显示。也具有日历计算、显示和时钟,日历的校准、定时时间的设定输出等功能。后附有电路图,程序清单,各数据存储单元的所在地址, 输入输出口对应表。以供读者参考.因我们也是个初学者,水平有限,难免有疏落不足之处,敬请老师给与批评指正。说明书:系统由 AT89C52、LED 数码管、按键、发光二极管等部分构成,能实现时间的调整、定时时间的设定,输出等功能。系统的功能选择由 SB0、SB1 、SB2、SB3、SB4 完成。其中 SB0 为时间校对,定时器调整功能键,按 SB 0 进入调整状态。SB1 为功能切换键。第一轮按动 SB
3、1 依次进入一路、二路、三路定时时间设置提示程序,按 SB3 进入各路定时调整状态。定时时间到,二极管发亮。到了关断时间后灭掉。如果不进入继续按 SB1 键,依次进入时间 ?年?位校对、?月?位校对、?日?位校对、?时?位校对、?分?位校对、?秒?位校对状态。不管是进入那种状态,按动 SB2 皆可以使被调整位进行不进位增量加 1 变化。各预置量设置完成后,系统将所有的设置存入 RAM 中,按SB1 退出调整状态。上电后,系统自动进入计时状态,起始于?00? 时?00?分。SB4 为年月日显示转换键,可使原来显示时分秒转换显示年月日。器材一览表:IC 89S52,IC 74LS244 各一个,I
4、C CD4511 两个,IC 座 40 脚三个,IC 座 20 脚一个,IC 座 18脚两个,LED 七段数码管 6 个,晶体振荡器 12MHZ 一个, 小型蜂鸣器一个,晶体三极管 PNP8550 六个,微型按钮 4 脚 3 个, 电阻 10K4 个,4.7K 两个,3K9 个,330 欧姆 17 个,100 欧姆 8 个,电解电容10UF 一个,瓷片电容 30P 两个, 万用表一个,焊锡及万能电路板一个.第二章:电路原理分析 :1:显示原理:电原由 6 个共阴极的数码管组成时、分、秒的显示。 P0 口的 8 条数据线 P0.0 至 P0.7 分别与两个CD4511 译码的 ABCD 口相接,
5、P2 口的 P2.0 至 P2.2 分别通过电阻 R10 至 R13 与 VT1 至 VT3的基极相连接。这样通过 P0 口送出一个存储单元的高位、低位 BCD 显示代码,通过 P2 口送出扫描选通代码轮流点亮 LED1 至 LED6,就会将要显示的数据在数码管中显示出来。从 P0 口输出的代码是 BCD 码,从 P2 口输出的就是位选码。这是扫描显示原理。2:数码管结构及代码显示 :共阴 LED 数码管由 8 只发光二极管 VD1 至 VD8 共阴连接并按?8?字形结构排列而成。这样,我们将这些二极管的正极接高低不同的电位,把所有的负极接地,当正极为高电位时相应的二极管就会导通而发光,从而使
6、数码管呈现不同的字符。而只有 P2 相应呈现高电位,VT 个管导通,LED1 的GND 与地相接,LED 位被选中才具备发光的使能条件;可见,在利用 P2 口送出位选码,使各位轮流得到发光使能条件的同时,通过 P0 口分别送出不同的段选码,就会在 LED1 至 LED4 中显示出不同的数字来。3:键盘及读数原理 : 键盘是人与微机打交道的主要设备,按键的读取容易引起误动作。可采用件去动的方法处理,软件的触点在闭合和断开的时候会产生抖动,这时触点的逻辑电是不稳定的,如不采取妥善处理的话,将引起按键命令错误或重复执行,在这里用软件延时的方法来避开抖动,延时时间 20ms.4:连击功能的实现 :按下
7、某键时,对应的功能键解释程序得到执行,如操作者没有释放按键,则对应的功能会反复执行,好象连续执行,在这里我们采用软件延时 250ms,当按键没释放则执行下一条对应程序。利用连击功能,能实现快速调时操作。第三章 程序设计中的思想本系统的主程序主要完成时间显示和定时输出判断功能。而年月日显示和各时间单元进位,时间设定时,调定时间设定时等功能全部在中断服务程序中完成。1:数据与代码转换由前述可知,从 P2 口输出位选码,从 P0 口输出段选码,LED 就会显示出数字来。但 P0 口的输出的数据是要 BCD 码,各存储单元存储的是二进制数,也就是和要显示出的字符表达的含义是不一致的。可见,将要显示的存
8、储单元的数据直接送到 P0 口去驱动 LED 数码管显示是不能正确表达的,必须在系统内部将要显示的数据经过 BCD 码行转换后,将各个单元数据的段选代码送入 P0 口,给CD4511 译码后去驱动数码管显示。具体转换过程如下: 我们先将要显示的数据装入累加器 A 中,再将 A 中的数据转换成高低两位的BCD 码,再放回 A 中,然后将 A 中的值输出。如:有一个单元存储了 45 这样一位数,则需转换成四位的 BCD 码:(0100 )(0101)然后放入 A 中。A 中 BCD 码,高位四位代表?4?低四位代表?5?同时送给两个译码器中,译码后?45?字就在两个 LED 中显示出来。2:计时功
9、能的实现与中断服务程序时间的运行依靠定时中断子程序对时钟单元数值进位调整来实现的。计数器 T0 打开后,进入计时,满 100 毫秒后,重装定时。中断一次,满一秒后秒进位,满 60 秒后即为 1 分钟,分钟单元进位,60 分到了后,时单元进位,24 小时满后,天单元进位。这样然后根据进率,得到年、月、日、时、分、秒存储单元的值,并经译码后,通过扫描程序送 LED 中显示出来,实现时钟计时功能。累加是用指令 INC 来实现的。进入中断服务程序以后,执行 PUSH PSW 和 PUSH A 将程序状态寄存器PSW 的内容和累加器 A 中的数据保存起来,这便是所谓的?保护现场 ?.以保护现场和恢复现场
10、时存取关键数据的存储区叫做堆栈。在软件的控制之下,堆栈可在片内 RAM 中的任一区间设定,而堆栈的数据存取与一般的 RAM 存取又有区别,对它的操作,要遵循 ?后进先出?的原则。 3:时钟误差分析开启定时器/计数器 0,使之开始计时,中断后进入中断程序。自停止计数到、计数又开始,中间执行了 7 条指令,也就是延迟了 13 个单周期共用时间 26us,这样,每个中断的总时间应为为100.026sm,而原来定时是 100ms,所以,也就是说每次中断定时多了 26um.这样,可改变计数重装值,使每次中断定时时间为 99.974sm,加上原来的 7 条指令所用的时间,正好 100sm.计数 10 次得
11、 1s.这样就可得到较精确的计时秒数,然后根据进率,得到时. 分的值。4:时间控制功能与比较指令系统的另一功能就是实现对执行设备的定时开关控制,其主要控制思想是这样的:先将执行设备开启的时间和关闭时间置入 RAM 某一单元,在计时主程序当中执行几条比较指令,如果当前计时时间与执行设备的设定开启时间相等,就执行一条 CLR 指令,将对应的那路 P3 置为高电位,开启;如果当前计时时间与执行设备设定的关闭时间相等,就执行 SETB 对应的 P3 置低电位,二极管截止,。实现此控制功能用到的比较指令为 CJNE A,#direct, rel,其转移条件是累加器 A 中的值与立即数不等则转移。第四章
12、程序流程图第四章 电路原理图第五章 源程序及注释/*电子钟程序,功能:时钟,日期,定时,秒表。*/*按键功能:键 1切换状态;键 2调整;键 3加调整;键 4减调整。*/*操作:按键 1 切换显示页面,按以下顺序切换:时钟日期闹钟秒表 */*按键 2 进入调整状态,闪烁位为调整位,在调整状态按键 2 则进行调整位的移动,按键 1 则返回当前显示状态。*/*在调整状态时,按键 3 和 4 进行当前调整位的调整,按键 3 和 4 只在调整状态有效。按键 3 进行当前所在位的增加,按键 4 进行当前位的减少。特别的,在按按键 2 切换到秒表状态时,再按 2开始计时,再按 2,秒表暂停,再按 3 秒表
13、清零。*/*程序开始*#include#define uchar unsigned charuchar data state=0; /设置状态变量 /*state=0 时间;state=1 日期;state=2 闹钟; state=3 秒表 */uchar data adjuststate=0; /设置调整位 /*adjuststate=0 不调整;adjuststate=1 调整*/ 用于决定是否开启计时器 T1uchar data timedata3=0,0 ,12; /时间状态值uchar data datedata3=1,10,7; /日期状态值uchar data alarmdata
14、3=0,0,7; /闹钟状态值uchar data watchdata3=0,0,0; /秒表状态值uchar data display6=0,0,0,0,0,0;uchar data shift=0; /设置当前调整位 , 0 表示不调整uchar data button = 0; /记录获得的按键, 0 表示没有按键uchar data temp=0; /判断闹钟是否启动uchar data counter1=0; /T0 定时器中断次数计数器uchar data counter2=0; /T1 定时器中断次数计数器uchar data flag=0; /0.4 秒闪烁的标志sbit ke
15、y0=P10; /定义 P1.0,P1.1,P1.2,P1.3 键为不同的按键的命令输入端sbit key1=P11;sbit key2=P12;sbit key3=P13;char code dis_711=0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xff; /共阳极控制字/*共阳 LED 段码表 “0“ “1“ “2“ “3“ “4“ “5“ “6“ “7“ “8“ “9“ “不亮“ */uchar code scan_col6=0xfe,0xfd,0xfb,0xf7,0xef,0xdf; /列扫描控制字uchar code da
16、te_table13 = 29,31,28,31,30,31,30,31,31,30,31,30,31; /日期与月份关系表,闰年的二月的天数置于数组的第一位/*定义原函数*/void statedisplay(); /显示函数void getbutton(); /获取按键函数void statescan(); /扫描函数void increase(); /增加调整位函数void decrease(); /减少调整位函数void stopwatchstart(); /秒表启动函数void alarm(); /闹钟启动函数void delay10ms() /延时 10ms 函数void dela
17、y10ms(void) /*延时 10ms*/ unsigned char i,j,k;for(i=5;i0;i-) for(j=4;j0;j-)for(k=248;k0;k-); /定时器 T0 的中断函数void time1_interrupt() interrupt 1 ET0=0;TR0=0;TH0=0xB1;TL0=0xE0;TR0=1; /重置计数器 T0 和关闭计数器 T0 中断counter1+; if(counter1=49) counter1= 0;if (timedata0=59) timedata0 = 0;if (timedata1=59) timedata1 = 0
18、;if (timedata2=23)timedata2 = 0;if (datedata1=2)datedata1+;else datedata0+;else if(datedata0=date_tabledatedata1) datedata0 = 1;if(datedata1=12) datedata1 = 1;if(datedata2=99)datedata2 = 0;else datedata2+;else datedata1+;else datedata0+;else timedata2+;else timedata1+;else timedata0+;counter1=0;ET0
19、= 1; /开启中断/定时器 T1 的中断函数void time2_interrupt(void) interrupt 3 ET1=0;TR1=0;TH1=0xB1;TL1=0xE0;TR1=1; /重置计数器 T1 和关闭计数器 T1 中断counter2+;if(counter2=20) counter2=0;if(flag=0) flag= 1;else flag=0;ET1 = 1; /获取按键函数/void getbutton() button = 0;if(key0=0) delay10ms();if(key0=0) while(key0=0) delay10ms();stated
20、isplay();button = 1; if(key1=0) delay10ms();if(key1=0)while(key1=0) delay10ms();statedisplay();button = 2;if(key2=0) delay10ms();if(key2=0)while(key2=0) delay10ms();statedisplay();button = 3;if(key3=0) delay10ms();if(key3=0)while(key3=0) delay10ms();statedisplay();button = 4;/扫描函数/void statescan()ge
21、tbutton();if(button!=0)if(adjuststate=0) /当前处于非调整状态 if(button=1) if(statedate_table0)datedata0=date_table0;elseif(datedata0date_tabledatedata1)datedata0=date_tabledatedata1;else datedata1=1;if(shift=3) /调整年if(datedata20) timedatashift-1=timedatashift-1-1;else timedatashift-1=59;if(shift=3)if(timedat
22、a20) timedata2=timedata2-1;else timedata2=23;/调整日期if(state=1) if(shift=1)if(datedata2%4=0else datedata0 = date_table0;elseif(datedata01) datedata0=datedata0-1;else datedata0= date_tabledatedata1;if(shift=2)if(datedata11)datedata1=datedata1-1;if(datedata0date_tabledatedata1) if(datedata1=2else dateda
23、ta0=date_tabledatedata1;else datedata1=12;if(shift=3)if(datedata20)if(datedata2%4=0datedata2=datedata2-1;else if(datedata1=2datedata2=99;/调整闹钟if(state=2) if(shift=1|shift=2)if(alarmdatashift-10) alarmdatashift-1-;else alarmdatashift-1=59;if(shift=3)if(alarmdata20) alarmdatashift-1-;else alarmdata2=23;/秒表启动函数void stopwatchstart()while(1) getbutton();if(button=2)break; /若按键 2,则暂停秒表if(button=0) /没有按键,秒表计时 watchdata0=watchdata0+1;if(watchdata0=100)watchdata 0 = 0;watchdata1=watchdata1+1;if(watchdata1=100)watchdata1 = 0;watchdata2=watchdata2+1;if(watchdata2=100) watchdata2 = 0;