1、 3 / 3151单片机汇编语言与C语言经典实例实验与课程设计51单片机汇编语言与C语言经典实例一、闪烁灯如图1 所示为一简单单片机系统原理图:在 P1.0 端口上接一个发光二极管 L1,使 L1 在不停地一亮一灭,一亮一灭的时间间隔为 0.2 秒。延时程序的设计方法,作为单片机的指令的执行的时间是很短,数量大微秒级,因此,我们要求的闪烁时间间隔为 0.2 秒,相对于微秒来说,相差太大,所以我们在执行某一指令时,插入延时程序,来达到我们的要求,但这样的延时程序是如何设计呢?下面具体介绍其原理:如图 4.1.1 所示的石英晶体为 12MHz,因此,1 个机器周期为 1 微秒,机器周期 微秒如图
2、1 所示,当 P1.0 端口输出高电平,即 P1.01 时,根据发光二极管的单向导电性可知,这时发光二极管 L1 熄灭;当 P1.0 端口输出低电平,即 P1.00 时,发光二极管 L1 亮;我们可以使用 SETB P1.0 指令使 P1.0端口输出高电平,使用 CLR P1.0 指令使 P1.0 端口输出低电平。C 语言源程序#include sbit L1=P10;void delay02s(void) /延时 0.2 秒子程序图1 单片机原理图unsigned char i,j,k;for(i=20;i0;i-)for(j=20;j0;j-)for(k=248;k0;k-);void m
3、ain(void)while(1)L1=0;delay02s();L1=1;delay02s();汇编源程序ORG 0START: CLR P1.0LCALL DELAY图2 程序设计流程图SETB P1.0LCALL DELAYLJMP STARTDELAY: MOV R5,#20 ;延时子程序,延时 0.2 秒D1: MOV R6,#20D2: MOV R7,#248DJNZ R7,$DJNZ R6,D2DJNZ R5,D1RETEND二、多路开关状态指示如图 3 所示,AT89S51 单片机的 P1.0P1.3 接四个发光二极管 L1L4,P1.4P1.7 接了四个开关 K1K4,编程将
4、开关的状态反映到发光二极管上。(开关闭合,对应的灯亮,开关断开,对应的灯灭)。对于开关状态检测,相对单片机来说,是输入关系,我们可轮流检测每个开关状态,根据每个开关的状态让相应的发光二极管指示,可以采用 P1.X,REL或 JNB P1.X,REL 指令来完成;也可以一次性检测四路开关状态,然后让其指示,可以采用 MOV A,P1 指令一次把 P1 端口的状态全部读入,然后取高 4 位的状态来指示。方法1(汇编源程序)ORG 00HSTART: MOV A,P1ANL A,#0F0HRR ARR ARR ARR AORL A,#0F0HMOV P1,ASJMP STARTEND方法1(C语言程
5、序)图4 程序流程图#INClude unsigned char temp;void main(void)while(1)temp=P14;temp=temp | 0xf0;P1=temp;方法2(汇编源程序)ORG 00HSTART: P1.4,NEXT1CLR P1.0SJMP NEX1图3 单片机原理图NEXT1: SETB P1.0NEX1: P1.5,NEXT2CLR P1.1SJMP NEX2NEXT2: SETB P1.1NEX2: P1.6,NEXT3CLR P1.2SJMP NEX3NEXT3: SETB P1.2NEX3: P1.7,NEXT4CLR P1.3SJMP NE
6、X4NEXT4: SETB P1.3NEX4: SJMP STARTEND方法2(C 语言源程序)#INClude void main(void)while(1)if(P1_4=0)P1_0=0;ElseP1_0=1;if(P1_5=0)P1_1=0;elseP1_1=1;if(P1_6=0)P1_2=0;elseP1_2=1;if(P1_7=0)P1_3=0;else图5 单片机原理图三、广告灯的设计利用取表的方法,使端口 P1 做单一灯的变化:左移 2 次,右移 2 次,闪烁 2 次(延时的时间 0.2 秒)。利用 MOV DPTR,DATA16 的指令来使数据指针寄存器指到表的开头。利用
7、 MOVC A,ADPTR 的指令,根据累加器的值再加上 DPTR 的值,就可以使程序计数器 PC 指到表格所要取出的数据。因此,只要把控制码建成一个表,而利用 MOVC A,ADPTR 做取码的操作,就可方便地处理一些复杂的控制动作,取表过程如下图所示:汇编源程序ORG 0START: MOV DPTR,#TABLELOOP: CLR AMOVC A,A+DPTRCJNE A,#01H,LOOP1JMP STARTLOOP1: MOV P1,AMOV R3,#20LCALL DELAYINC DPTRJMP LOOPDELAY: MOV R4,#20D1: MOV R5,#248图6 程序流
8、程图DJNZ R5,$DJNZ R4,D1DJNZ R3,DELAYR RETTABLE: DB 0FEH,0FDH,0FBH,0F7HDB 0EFH,0DFH,0BFH,07FHDB 0FEH,0FDH,0FBH,0F7HDB 0EFH,0DFH,0BFH,07FHDB 07FH,0BFH,0DFH,0EFHDB 0F7H,0FBH,0FDH,0FEHDB 07FH,0BFH,0DFH,0EFHDB 0F7H,0FBH,0FDH,0FEHDB 00H, 0FFH,00H, 0FFHDB 01HENDC 语言源程序#INClude unsigned char code table=0xfe,0
9、xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f,0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f,0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe,0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe,0x00,0xff,0x00,0xff,0x01;unsigned char i;void delay(void)unsigned char m,n,s;for(m=20;m0;m-)for(n=20;n0;n-)for(s=248;s0;s-);void main(void)while(1
10、)if(tablei!=0x01)P1=tablei;i+;delay();elsei=0;四、 0059 秒计时器如下图8所示,在 AT89S51 单片机的 P0 和 P2 端口分别接有两个共阴数码管,P0 口驱动显示秒的时间的十位,而 P2 口驱动显示秒的时间的个位。在设计过程中我们用一个存储单元作为秒计数单元,当一秒钟到来时,就让秒计数单元加 1,当秒计数达到 60 时,就自动返回到 0,重新秒计数。对于秒计数单元中的数据要把它十位数和个位数分开,方法仍采用对 10 整除和对 10 求余。汇编源程序Second EQU 30HORG 0000HSTART: MOV Second,#00H
11、NEXT: MOV A,SecondMOV B,#10DIV ABMOV DPTR,#TABLEMOVC A,A+DPTRMOV P0,AMOV A,BMOVC A,A+DPTRMOV P2,ALCALL DELY1SINC SecondMOV A,SecondCJNE A,#60,NEXT图7 程序流程图LJMP STARTDELY1S: MOV R5,#100D2: MOV R6,#20D1: MOV R7,#248DJNZ R7,$DJNZ R6,D1DJNZ R5,D2RETTABLE: DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FHENDC 语言
12、源程序#include unsigned char code table=0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f;unsigned char Second;void delay1s(void)unsigned char i,j,k;for(k=100;k0;k-)for(i=20;i0;i-)for(j=248;j0;j-);void main(void)Second=0;P0=tableSecond/10;P2=tableSecond%10;while(1)delay1s();Second+;if(Second=60)Second=
13、0;P0=tableSecond/10;P2=tableSecond%10;图8 单片机原理图五、动态数码显示技术如图9所示,P0 端口接动态数码管的字形码笔段,P2 端口接动态数码管的数位选择端,P1.7 接一个开关,当开关接高电平时,显示“12345”字样;当开关接低电平时,显示“HELLO”字样。动态扫描方法:动态接口采用各数码管循环轮流显示的方法,当循环显示频率较高时,利用人眼的暂留特性,看不出闪烁显示现象,这种显示需要一个接口完成字形码的输出(字形选择),另一接口完成各数码管的轮流点亮(数位选择)。在进行数码显示的时候,要对显示单元开辟 8 个显示缓冲区,每个显示缓冲区装有显示的不同
14、数据即可。对于显示的字形码数据我们采用查表方法来完成。汇编源程序图9 单片机原理图ORG 0000HSTART: P1.7,DIR1MOV DPTR,#TABLE1SJMP DIRDIR1: MOV DPTR,#TABLE2DIR: MOV R0,#00HMOV R1,#01HNEXT: MOV A,R0MOVC A,A+DPTRMOV P0,AMOV A,R1MOV P2,ALCALL DAYINC R0RL AMOV R1,ACJNE R1,#0DFH,NEXTSJMP STARTDAY: MOV R6,#4D1: MOV R7,#248DJNZ R7,$DJNZ R6,D1图10 单片机
15、原理图RETTABLE1: DB 06H,5BH,4FH,66H,6DHTABLE2: DB 78H,79H,38H,38H,3FHENDC 语言源程序#include Unsigned char code table1=0x06,0x5b,0x4f,0x66,0x6d;Unsignedcharcode table2=0x78,0x79,0x38,0x38,0x3f;Unsignedchar i;Unsignedchar a,b;Unsignedchar temp;void main(void)while(1)temp=0xfe;for(i=0;i5;i+)if(P1_7=1)P0=table
16、1i;elseP0=table2i;P2=temp;a=temp(7-i);temp=a|b;for(a=4;a0;a-)for(b=248;b0;b-);六、44 矩阵式键盘识别技术如图11所示,用 AT89S51 的并行口 P1 接 44 矩阵键盘,以 P1.0P1.3作输入线,以 P1.4P1.7 作输出线;在数码管上显示每个按键的“0F”序。对应的按键的序号排列如图12所示每个按键有它的行值和列值,行值和列值的组合就是识别这个按键的编码。矩阵的行线和列线分别通过两并行接口和 CPU 通信。每个按键的状态同样需变成数字量“0”和“1”,开关的一端(列线)通过电阻接 VCC,而接地是通过程
17、序输出数字“0”实现的。键盘处理程序的任务是:确定有无键按下,判断哪一个键按下,键的功能是什么;还要消除按键在闭合或断开时的抖动。两个并行口中,一个输出扫描码,使按键逐行动态接地,另一个并行口输入按键状态,由行扫描值和回馈信号共同形成键编码而识别按键,通过软件查表,查出该键的功能。汇编源程序KEYBUF EQU 30HORG 00HSTART: MOV KEYBUF,#2WAIT:MOV P3,#0FFHCLR P3.4MOV A,P3ANL A,#0FHXRL A,#0FHJZ NOKEY1LCALL DELY10MSMOV A,P3ANL A,#0FHXRL A,#0FHJZ NOKEY1
18、MOV A,P3ANL A,#0FHCJNE A,#0EH,NK1MOV KEYBUF,#0LJMP DK1NK1: CJNE A,#0DH,NK2MOV KEYBUF,#1LJMP DK1NK2: CJNE A,#0BH,NK3MOV KEYBUF,#2LJMP DK1NK3: CJNE A,#07H,NK4MOV KEYBUF,#3LJMP DK1NK4: NOPDK1:MOV A,KEYBUFMOV DPTR,#TABLEMOVC A,A+DPTRMOV P0,ADK1A: MOV A,P3ANL A,#0FHXRL A,#0FHJNZ DK1ANOKEY1:MOV P3,#0FFHCL
19、R P3.5MOV A,P3ANL A,#0FHXRL A,#0FHJZ NOKEY2LCALL DELY10MSMOV A,P3ANL A,#0FHXRL A,#0FHJZ NOKEY2MOV A,P3ANL A,#0FHCJNE A,#0EH,NK5MOV KEYBUF,#4LJMP DK2NK5: CJNE A,#0DH,NK6MOV KEYBUF,#5LJMP DK2NK6: CJNE A,#0BH,NK7MOV KEYBUF,#6LJMP DK2NK7: CJNE A,#07H,NK8MOV KEYBUF,#7LJMP DK2NK8: NOPDK2:MOV A,KEYBUFMOV D
20、PTR,#TABLEMOVC A,A+DPTRMOV P0,ADK2A: MOV A,P3ANL A,#0FHXRL A,#0FHJNZ DK2ANOKEY2:MOV P3,#0FFHCLR P3.6MOV A,P3ANL A,#0FHXRL A,#0FHJZ NOKEY3LCALL DELY10MSMOV A,P3ANL A,#0FHXRL A,#0FHJZ NOKEY3MOV A,P3ANL A,#0FHCJNE A,#0EH,NK9MOV KEYBUF,#8LJMP DK3NK9: CJNE A,#0DH,NK10MOV KEYBUF,#9LJMP DK3NK10: CJNE A,#0B
21、H,NK11MOV KEYBUF,#10LJMP DK3NK11: CJNE A,#07H,NK12MOV KEYBUF,#11LJMP DK3NK12: NOPDK3:MOV A,KEYBUFMOV DPTR,#TABLEMOVC A,A+DPTRMOV P0,ADK3A: MOV A,P3ANL A,#0FHXRL A,#0FHJNZ DK3ANOKEY3:MOV P3,#0FFHCLR P3.7MOV A,P3ANL A,#0FHXRL A,#0FHJZ NOKEY4LCALL DELY10MSMOV A,P3ANL A,#0FHXRL A,#0FHJZ NOKEY4MOV A,P3AN
22、L A,#0FHCJNE A,#0EH,NK13MOV KEYBUF,#12LJMP DK4NK13: CJNE A,#0DH,NK14MOV KEYBUF,#13LJMP DK4NK14: CJNE A,#0BH,NK15MOV KEYBUF,#14LJMP DK4NK15: CJNE A,#07H,NK16MOV KEYBUF,#15LJMP DK4NK16: NOPDK4:MOV A,KEYBUFMOV DPTR,#TABLEMOVC A,A+DPTRMOV P0,ADK4A: MOV A,P3ANL A,#0FHXRL A,#0FHJNZ DK4ANOKEY4:LJMP WAITDEL
23、Y10MS:MOV R6,#10D1: MOV R7,#248DJNZ R7,$DJNZ R6,D1RETTABLE: DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07HDB 7FH,6FH,77H,7CH,39H,5EH,79H,71HENDC 语言源程序#INClude unsigned char code table=0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71;unsigned char temp;unsigned char key;unsigned ch
24、ar i,j;void main(void)while(1)P3=0xff;P3_4=0;temp=P3;temp=temp & 0x0f;if (temp!=0x0f)for(i=50;i0;i-)for(j=200;j0;j-);temp=P3;temp=temp & 0x0f;if (temp!=0x0f)temp=P3;temp=temp & 0x0f;switch(temp)case 0x0e:key=7;break;case 0x0d:key=8;break;case 0x0b:key=9;break;case 0x07:key=10;break;temp=P3;P1_0=P1_0
25、;P0=tablekey;temp=temp & 0x0f;while(temp!=0x0f)temp=P3;temp=temp & 0x0f;P3=0xff;P3_5=0;temp=P3;temp=temp & 0x0f;if (temp!=0x0f)for(i=50;i0;i-)for(j=200;j0;j-);temp=P3;temp=temp & 0x0f;if (temp!=0x0f)temp=P3;temp=temp & 0x0f;switch(temp)case 0x0e:key=4;break;case 0x0d:key=5;break;case 0x0b:key=6;brea
26、k;case 0x07:key=11;break;temp=P3;P1_0=P1_0;P0=tablekey;temp=temp & 0x0f;while(temp!=0x0f)temp=P3;temp=temp & 0x0f;P3=0xff;P3_6=0;temp=P3;temp=temp & 0x0f;if (temp!=0x0f)for(i=50;i0;i-)for(j=200;j0;j-);temp=P3;temp=temp & 0x0f;if (temp!=0x0f)temp=P3;temp=temp & 0x0f;switch(temp)case 0x0e:key=1;break;
27、case 0x0d:key=2;break;case 0x0b:key=3;break;case 0x07:key=12;break;temp=P3;P1_0=P1_0;P0=tablekey;temp=temp & 0x0f;while(temp!=0x0f)temp=P3;temp=temp & 0x0f;P3=0xff;P3_7=0;temp=P3;temp=temp & 0x0f;if (temp!=0x0f)for(i=50;i0;i-)for(j=200;j0;j-);temp=P3;temp=temp & 0x0f;if (temp!=0x0f)temp=P3;temp=temp
28、 & 0x0f;switch(temp)case 0x0e:key=0;break;case 0x0d:key=13;break;case 0x0b:key=14;break;case 0x07:key=15;break;temp=P3;P1_0=P1_0;P0=tablekey;temp=temp & 0x0f;while(temp!=0x0f)temp=P3;temp=temp & 0x0f;七、按键识别方法每按下一次开关 SP1,计数值加 1,通过AT89S51 单片机的 P1 端口的 P1.0 到 P1.3显示出其二进制计数值。*程序设计方法:作为一个按键从没有按下到按下以与释放是一个
29、完整的过程,也就是说,当我们按下一个按键时,总希望某个命令只执行一次,而在按键按下的 过程中,不要有干扰进来,因为,在按下的过程中,一旦有干扰过来,可能造成误触发过程,这并不是我们所想要的。因此在按键按下的时候,要把我们手上的干扰信号以与按键的机械接触等干扰信号给滤除掉,一般情况下,我们可以采用电容来滤除掉这些干扰信号,但实际上,会增加硬件成本与硬件电路的体积,这是我们不希望,总得有个办法解决这个问题,因此我们可以采用软件滤波的方法去除这些干扰信号,一般情况下,一个按键按下的时候,总是在按下的时刻存在着一定的干扰信号,按下之后就基本上进入了稳定的状态。具体的一个按键从按下到释放的全过程的信号图
30、如上图所示:从图中可以看出,我们在程序设计时,从按键被识别按下之后,延时 5ms 以上,从而避开了干扰信号区域,我们再来检测一次,看按键是否真得已经按下,若真得已经按下,这时肯定输出为低电平,若这时检测到的是高电平,证明刚才是由于干扰信号引起的误触发,CPU 就认为是误触发信号而舍弃这次的按键识别过程。从而提高了系统的可靠性。由于要求每按下一次,命令被执行一次,直到下一次再按下的时候,再执行一次命令,因此从按键被识别出来之后,我们就可以执行这次的命令,所以要有一个等待按键释放的过程,显然释放的过程,就是使其恢复成高电平状态。1 汇编源程序ORG 0000HSTART: MOV R1,#00H
31、;初始化 R1 为 0,表示从 0 开始计数MOV A,R1 ;CPL A ;取反指令MOV P1,A ;送出 P1 端口由发光二极管显示REL: P3.7,REL ;判断 SP1 是否按下LCALL DELAY10MS ;若按下,则延时 10ms 左右 P3.7,REL ;再判断 SP1 是否真得按下INC R1 ;若确实按下,则进行按键处理,使MOV A,R1 ;计数容加 1,并送出 P1 端口由CPL A ;发光二极管显示MOV P1,A ;JNB P3.7,$ ;等待 SP1 释放SJMP REL ;继续对 K1 按键扫描DELAY10MS: MOV R6,#20 ;延时 10ms 子
32、程序L1: MOV R7,#248DJNZ R7,$DJNZ R6,L1RETEND2. C 语言源程序#include unsigned char count;void delay10ms(void)unsigned char i,j;for(i=20;i0;i-)for(j=248;j0;j-);void main(void)while(1)if(P3_7=0)delay10ms();if(P3_7=0)count+;if(count=16)count=0;P1=count;while(P3_7=0);八、数字钟(1 开机时,显示 12:00:00 的时间开始计时;(2 P0.0/AD0
33、控制“秒”的调整,每按一次加 1 秒;(3 P0.1/AD1 控制“分”的调整,每按一次加 1 分;(4 P0.2/AD2 控制“时”的调整,每按一次加 1 个小时6 汇编源程序SECOND EQU 30HMINITE EQU 31HHOUR EQU 32HHOURK BIT P0.0MINITEK BIT P0.1SECONDK BIT P0.2DISPBUF EQU 40HDISPBIT EQU 48HT2SCNTA EQU 49HT2SCNTB EQU 4AHTEMP EQU 4BHORG 00HLJMP STARTORG 0BHLJMP INT_T0START: MOV SECOND,
34、#00HMOV MINITE,#00HMOV HOUR,#12MOV DISPBIT,#00HMOV T2SCNTA,#00HMOV T2SCNTB,#00HMOV TEMP,#0FEHLCALL DISPMOV TMOD,#01HMOV TH0,#(65536-2000) / 256MOV TL0,#(65536-2000) MOD 256SETB TR0SETB ET0SETB EAWT: SECONDK,NK1LCALL DELY10MS SECONDK,NK1INC SECONDMOV A,SECONDCJNE A,#60,NS60MOV SECOND,#00HNS60: LCALL
35、DISPJNB SECONDK,$NK1: MINITEK,NK2LCALL DELY10MS MINITEK,NK2INC MINITEMOV A,MINITECJNE A,#60,NM60MOV MINITE,#00HNM60: LCALL DISPJNB MINITEK,$NK2: HOURK,NK3LCALL DELY10MS HOURK,NK3INC HOURMOV A,HOURCJNE A,#24,NH24MOV HOUR,#00HNH24: LCALL DISPJNB HOURK,$NK3: LJMP WTDELY10MS:MOV R6,#10D1: MOV R7,#248DJN
36、Z R7,$DJNZ R6,D1RETDISP:MOV A,#DISPBUFADD A,#8DEC AMOV R1,AMOV A,HOURMOV B,#10DIV ABMOV R1,ADEC R1MOV A,BMOV R1,ADEC R1MOV A,#10MOVR1,ADEC R1MOV A,MINITEMOV B,#10DIV ABMOV R1,ADEC R1MOV A,BMOV R1,ADEC R1MOV A,#10MOVR1,ADEC R1MOV A,SECONDMOV B,#10DIV ABMOV R1,ADEC R1MOV A,BMOV R1,ADEC R1RETINT_T0:MOV
37、 TH0,#(65536-2000) / 256MOV TL0,#(65536-2000) MOD 256MOV A,#DISPBUFADD A,DISPBITMOV R0,AMOV A,R0MOV DPTR,#TABLEMOVC A,A+DPTRMOV P1,AMOV A,DISPBITMOV DPTR,#TABMOVC A,A+DPTRMOV P3,AINC DISPBITMOV A,DISPBITCJNE A,#08H,KNAMOV DISPBIT,#00HKNA: INC T2SCNTAMOV A,T2SCNTACJNE A,#100,DONEMOV T2SCNTA,#00HINC T
38、2SCNTBMOV A,T2SCNTBCJNE A,#05H,DONEMOV T2SCNTB,#00HINC SECONDMOV A,SECONDCJNE A,#60,NEXTMOV SECOND,#00HINC MINITEMOV A,MINITECJNE A,#60,NEXTMOV MINITE,#00HINC HOURMOV A,HOURCJNE A,#24,NEXTMOV HOUR,#00HNEXT: LCALL DISPDONE: RETITABLE: DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH,40HTAB: DB 0FEH,0FDH,0F
39、BH,0F7H,0EFH,0DFH,0BFH,07FHEND7 C 语言源程序#INClude unsigned char code dispcode=0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00;unsigned char dispbitcode=0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f;unsigned char dispbuf8=0,0,16,0,0,16,0,0;unsigned char dispbitcnt;unsigne
40、d char second;unsigned char minite;unsigned char hour;unsigned int tcnt;unsigned char mstcnt;unsigned char i,j;void main(void)TMOD=0x02;TH0=0x06;TL0=0x06;TR0=1;ET0=1;EA=1;while(1)if(P0_0=0)for(i=5;i0;i-)for(j=248;j0;j-);if(P0_0=0)second+;if(second=60)second=0;dispbuf0=second%10;dispbuf1=second/10;wh
41、ile(P0_0=0);if(P0_1=0)for(i=5;i0;i-)for(j=248;j0;j-);if(P0_1=0)minite+;if(minite=60)minite=0;dispbuf3=minite%10;dispbuf4=minite/10;while(P0_1=0);if(P0_2=0)for(i=5;i0;i-)for(j=248;j0;j-);if(P0_2=0)hour+;if(hour=24)hour=0;dispbuf6=hour%10;dispbuf7=hour/10;while(P0_2=0);void t0(void) interrupt 1 using 0mstcnt+;if(mstcnt=8)mstcnt=0;P1=dispcodedispbufdispbitcnt;P