;**************************************************
;带键盘设置的秒计时器
;功能:倒计时的秒计时器,从59倒计到0,然后又从59开始倒计到0;
;各个键的功能
;S1:开始运行
;S2:停止运行
;S3:高位加1,按一次,数码管的十位加1,从0-5循环变化
;S4:低位加1,按一次,数码管的个位加1,从0-9循环变化
;**************************************************
KEYOK BIT 00H
STARTRUN BIT 01H
VALUE EQU 21H
SETVAL EQU 22H ;设置值
COUNTER EQU 23H ;用于显示的计数器
COUNT EQU 24H ;秒计数器
KEYVAL EQU 25H
DISPBUF EQU 5EH
FIRST BIT P2.7 ;第一位数码管的位控制
SECOND BIT P2.6 ;第二位数码管的位控制
P1LED EQU 22H
TMRVAR EQU 60110 ;65536-5000*12/11.0592 定时器初值5毫秒
ORG 0000H
JMP START
ORG 0*8+3 ;INT0中断入口
RETI
ORG 1*8+3 ;TIMER0中断入口
JMP INT_T0 ;转去定时器0中断服务程序入口
ORG 2*8+3 ;INT1中断入口
RETI
ORG 3*8+3 ;TIMER1中断入口
RETI
ORG 4*8+3 ;串行中断入口
RETI
START:
MOV SP,#5FH
MOV P1,#0FFH ;所有LED全部熄灭
MOV VALUE,#0
MOV P1LED,#0FEH
MOV SETVAL,#59
MOV VALUE,SETVAL
MOV DISPBUF,#5
MOV DISPBUF+1,#9
CLR STARTRUN
CLR KEYOK
CALL INIT_T0
SETB EA
LOOP:
CALL KEY ;调用键盘程序
JB KEYOK,KEYPROC ;如果有键按下,转键盘处理
NEXT:
MOV A,VALUE ;获得秒的数值
MOV B,#10
DIV AB ;二进制转化为十进制,十位和个位分送显示缓冲区
NEXT1:
MOV DISPBUF,A
MOV DISPBUF+1,B ;个位送显示缓冲区
JMP LOOP
;以下是键值处理
KEYPROC:
MOV A,KEYVAL ;取得键值
JZ KEYRUN ;如果键值是0
DEC A
JZ KEYSTOP ;如果键值是1
DEC A
JZ KEYLEFT ;如果键值是2
JMP KEYRIGHT ;键值是3,转
KEYRUN:
SETB STARTRUN
JMP LOOP
KEYSTOP:
CLR STARTRUN
JMP LOOP
KEYLEFT:
CLR STARTRUN
INC DISPBUF
MOV A,DISPBUF
CJNE A,#6,LEFT0
MOV A,#0
LEFT0:
MOV B,#10
MUL AB
MOV SETVAL,A
MOV VALUE,SETVAL
JMP LOOP
KEYRIGHT:
CLR STARTRUN
INC DISPBUF+1
MOV A,DISPBUF+1
CJNE A,#10,REFT0
MOV DISPBUF+1,#0
REFT0:
MOV A,DISPBUF
MOV B,#10
MUL AB
ADD A,DISPBUF+1
MOV SETVAL,A
MOV VALUE,SETVAL
JMP LOOP
;键盘程序
KEY:
MOV P3,#0FFH
CLR KEYOK
MOV A,P3
ORL A,#11000011B
CPL A
JZ KEY_RET
CALL DELAY
MOV A,P3
ORL A,#11000011B
CPL A
JZ KEY_RET
SETB KEYOK
JNB ACC.2,KEY_1 ;S1没有按下,转
MOV KEYVAL,#0
JMP KEY_RET
KEY_1:
JNB ACC.3,KEY_2 ;S2没有按下,转
MOV KEYVAL,#1
JMP KEY_RET
KEY_2:
JNB ACC.4,KEY_3
MOV KEYVAL,#2
JMP KEY_RET
KEY_3:
MOV KEYVAL,#3
KEY_RET:
MOV A,P3
ORL A,#11000011B
CPL A
JNZ KEY_RET
RET
DELAY:
PUSH PSW
SETB RS0
MOV R7,#50
D1: MOV R6,#50
D2: DJNZ R6,D2
DJNZ R7,D1
POP PSW
RET
INIT_T0: ;初始化T0为5毫秒的定时器
MOV TMOD,#01H
MOV TH0,#HIGH(TMRVAR)
MOV TL0,#LOW(TMRVAR)
SETB ET0 ;开T0中断
SETB TR0 ;定时器0开始运行
RET ;返回
;以下是中断程序,实现秒计数和显示
INT_T0: ;定时器T0的中断响应程序
PUSH ACC ;ACC入栈
PUSH PSW ;PSW入栈
MOV TH0,#HIGH(TMRVAR)
MOV TL0,#LOW(TMRVAR)
INC COUNT ;软件计数器加1
MOV A,COUNT
CJNE A,#20,INT_N2
MOV COUNT,#0 ;计到20,软件计数器清0
INT_N1:
JNB STARTRUN,INT_N2 ;停止运行,转
DEC VALUE ;计数器减1
MOV A,VALUE
JNZ INT_N2 ;不等于0,转
MOV VALUE,SETVAL;否则,再置初值
INT_N2: ;以下是显示部份
SETB FIRST
SETB SECOND ;关显示
MOV A,#DISPBUF ;显示缓冲区首地址
ADD A,Counter
MOV R0,A
MOV A,@R0 ;根据计数器的值取相应的显示缓冲区的值
MOV DPTR,#DISPTAB ;字形表首地址
MOV C A,@A+DPTR ;取字形码
MOV P0,A ;将字形码送P0位(段口)
MOV A,Counter ;取计数器的值
JZ DISPFIRST ;如果是0则显示第一位
CLR SECOND ;否则显示第二位
AJMP DISPNEXT
DISPFIRST:
CLR FIRST ;显示第一位
DISPNEXT:
INC Counter ;计数器加1
MOV A,Counter
DEC A ;如果计数器计到2,则让它回0
DEC A
JZ RSTCOUNT
AJMP DISPEXIT
RSTCOUNT:
MOV Counter,#0 ;计数器的值只能是0或1
DISPEXIT:
POP PSW
POP ACC
RETI
DISPTAB: DB 28H,7EH,0a4H,64H,72H,61H,21H,7CH,20H,60H
END