实现一个24小时制的电子钟程序,在实验箱的6个数码管上显示时分秒(用定时器0中断更新计时时间,时间值以压缩BCD码形式保存在内部RAM的30H31H和32H单元)。
PC机可通过串行口发送要设置的时间给单片机(发送的时间格式为压缩BCD码),单片机接收到设置时间后从该时间继续计时(此为串口调时功能)。
代码
;数码管接到CS0,位选地址8001,段选地址8002
;R7:数码管位,R6:T0中断次数,R5R4:演示程序,R3:2位BCD转十进制暂存,R0:指针
ORG 0000H
LJMP MAIN
ORG 000BH; T0_INT
LJMP T0_INT
ORG 0023H;串口中断
LJMP S_INT
ORG 0050H
MAIN:
;初始化定时器
MOV TMOD, #21H
MOV TL0, #40536 MOD 256 ;T0定时50ms
MOV TH0, #40536 / 256
MOV TL1, #232;设置波特率为2400
MOV TH1, #232
SETB EA
SETB ET0
SETB ES
SETB TR0
SETB TR1
MOV PCON, #80H;波特率倍增
MOV SCON, #50H
MOV R7, #01H;用于循环左移,选择某个数码管,从秒的个位开始
MOV R6,#40;T0每中断20次,更新一次数码管时间
MOV R0,#32H;指针
SJMP $
T0_INT:
MOV TL0, #40536 MOD 256 ;T0重装初值
MOV TH0, #40536 / 256
DJNZ R6,T0LOOP;没到1s,只刷新显示
MOV R6,#40;重装计数值
T0LOOP1:
MOV A,@R0
LCALL TBCD2D
CJNE R0,#30H,T0L1
CJNE A,#23,JIA
SJMP T0L2
T0L1:
CJNE A,#59,JIA
T0L2: MOV @R0, #00H;59+1=0
DEC R0;如果溢出,则判断前一个数
CJNE R0,#2FH, T0LOOP1
JIA:
INC A;如果没溢出,就+1;然后再恢复成BCD码
LCALL D2TBCD
MOV @R0, A
MOV R0, #32H;恢复R0的数值,准备刷新数码管
T0LOOP:
MOV A,@R0
LCALL SHOW
MOV A,@R0
SWAP A
LCALL SHOW
DEC R0
CJNE R0, #2FH,T0LOOP;刷新显示
MOV R7, #01H
MOV R0,#32H
RETI
S_INT:;串口中断服务程序
JNB RI,$
CLR RI
MOV A, SBUF
LCALL TBCD2D
PUSH ACC
CLR C
CJNE R0,#30H,s1
SUBB A,#24
SJMP s2
s1:
SUBB A,#60
s2: POP ACC
JC store
CLR A
store:
LCALL D2TBCD
MOV @R0,A
DEC R0
CJNE R0, #2FH,S_INT
MOV R0,#32H
RETI
SHOW:;把A的底4位当作BCD码,送入数码管显示,每调用一次,位选左移一次
PUSH ACC
MOV A,R7
MOV DPTR,#8001H
MOVX @DPTR,A
RL A
MOV R7,A
POP ACC
ANL A,#0FH
MOV DPTR,#TAB
MOVC A,@A+DPTR;获取字形码
MOV DPTR,#8002H
MOVX @DPTR,A;写入字形码
LCALL DELAY
CLR A
MOVX @DPTR,A;写入字形码
RET
TBCD2D:;把A的内容当作两位BCD数据,转换成对应十进制数,并放回A
PUSH ACC;保护ACC,等下还要用
ANL A,#0FH;
MOV R3, A
POP ACC
SWAP A
ANL A, #0FH
MOV B, #10
MUL AB
ADD A,R3;高4位*10+低4位
RET
D2TBCD:;把A的内容当作十进制数,转换成对应两位BCD数据,并放回A
MOV B, #10
DIV AB;十位在A,个位在B
SWAP A
ORL A, B;数据合并
RET
DELAY:;10ms则X=23,Y=204
MOV R5,#20
D1: MOV R4,#20
DJNZ R4,$
DJNZ R5,D1
RET
; 0 1 2 3 4 5 6 7 8 9
TAB:DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH
END