📄 timer.asm
字号:
HOUR EQU 20H
MIN EQU 21H
SEC EQU 22H ;时钟单元
A_HOUR EQU 24H
A_MIN EQU 25H
A_SEC EQU 26H ;闹钟单元
INT_NUM EQU 23H ;中断次数
ADD_TIME EQU 27H ;加16H的次数
ADD_NUM EQU 28H ;按键加的数字
REDUCE_NUM EQU 29H ;按键减的数字
SELECT_TIME EQU 2AH ;选择键按的次数
FUN_TIME EQU 2BH ;功能键按的次数
HIGH_NUM EQU 2CH
LOW_NUM EQU 2DH ;定时器T1的计数值
MUSIC_CODE EQU 2EH ;音乐编码
CLAP EQU 30H ;节拍数
ALARM_EN BIT 78H ;2FH字节的第1位,闹钟使能标志
ADD_SYMBOL BIT 79H ;2FH字节的第2位,‘+’标志位
HOUR_SYMBOL BIT 7AH ;小时标志位
ALARM_SYMBOL BIT 7BH ;闹钟标志位
BUZZER BIT P3.7
KEY1 BIT P3.2
KEY2 BIT P3.3
KEY3 BIT P2.6
KEY4 BIT P2.7
ORG 0000H
LJMP START
ORG 000BH
LJMP TSERV ;定时器T0中断入口地址
ORG 001BH
LJMP ASERV ;定时器T1中断入口地址
ORG 0030H
;****************************************************
;初始化
START:
CLR BUZZER ;关闭蜂鸣器
MOV INT_NUM,#14H ;1s中断20次
MOV R0,#0FEH
CLR ALARM_EN
CLR ADD_SYMBOL
CLR HOUR_SYMBOL
CLR ALARM_SYMBOL
MOV A,#0
MOV SELECT_TIME,A
MOV FUN_TIME,A
MOV A_SEC,A
MOV A_MIN,A
MOV A_HOUR,A
MOV HOUR,A
MOV MIN,A
MOV SEC,A ;时、分、秒单元初始化
MOV R2,A ;提取编码
MOV R3,A ;音乐编码
MOV TMOD,#11H ;设置定时器工作方式为方式1
MOV IE,#8AH ;允许定时器中断
MOV TH0,#4CH
MOV TL0,#0 ;装定时器T0初值,定时50ms
SETB TR0 ;启动定时器T0
;****************************************************
;主程序
MAIN:
KL1: JB KEY1,KL2
ACALL ALARM_FUN
AJMP ALR
KL2: JB KEY2,KL3
ACALL SELECT
AJMP ALR
KL3: JB KEY3,KL4
ACALL ADD_FUN
AJMP ALR
KL4: JB KEY4,ALR
ACALL REDUCE_FUN ;键盘扫描
ALR: JNB ALARM_EN,LOOP
ACALL ALARM_DIS
AJMP MAIN ;闹钟设置时的显示
LOOP: JNB ALARM_SYMBOL,LP
ACALL ALARM_DIST
LP: ACALL TIME_DIS ;时间的显示
AJMP MAIN
;****************************************************
;判断闹钟是否到时间
ALARM_DIST:
MOV A,HOUR
CJNE A,A_HOUR,RETAD
MOV A,MIN
CJNE A,A_MIN,RETAD
MOV A,SEC
CJNE A,A_SEC,RETAD ;如果时间到,即转到音乐程序
AJMP MUSIC
RETAD: RET
;****************************************************
;闹钟设置键
ALARM_FUN:
WOB1: ACALL TIME_DIS
JNB KEY1,WOB1 ;去抖动
MOV SELECT_TIME,#0 ;清除选择键的按键次数
INC FUN_TIME
MOV A,FUN_TIME
CJNE A,#1,LPA
SETB ALARM_EN ;置位闹钟设置
SETB ALARM_SYMBOL
AJMP LPAL
LPA: CJNE A,#2,LPAL ;第二次按键,返回时钟显示
CLR ALARM_EN
MOV FUN_TIME,#0
LPAL: RET
;****************************************************
;选择功能键
SELECT:
WOB2: JNB ALARM_EN,TIMES
ACALL ALARM_DIS
JNB KEY2,WOB2
AJMP NORS
TIMES: ACALL TIME_DIS
JNB KEY2,WOB2 ;去抖动
NORS: INC SELECT_TIME
MOV A,SELECT_TIME
CJNE A,#4,LPS ;超过4次,清零
MOV SELECT_TIME,#0
LPS: RET
;****************************************************
;‘+’功能键
ADD_FUN:
SETB ADD_SYMBOL
ACALL JUDGEA
WOB3: JNB ALARM_EN,TIMEA ;判断是时钟还是闹钟
ACALL ALARM_DIS
JNB KEY3,WOB3
AJMP NORA
TIMEA: ACALL TIME_DIS
JNB KEY3,WOB3 ;去抖动
NORA: MOV A,#01H
ADD A,ADD_NUM
DA A
MOV ADD_NUM,A
JNB HOUR_SYMBOL,HOUS
CJNE A,#24H,BACKA
MOV ADD_NUM,#0 ;调整小时,加到24H清零
AJMP BACKA
HOUS: CJNE A,#60H,BACKA ;调整分秒,60H清零
MOV ADD_NUM,#00H
BACKA: ACALL JUDGEB
CLR ADD_SYMBOL
RET
;****************************************************
;‘-’功能键
REDUCE_FUN:
ACALL JUDGEA
WOB4: JNB ALARM_EN,TIMER ;判断是时钟还是闹钟
ACALL ALARM_DIS
JNB KEY4,WOB4
AJMP NORR
TIMER: ACALL TIME_DIS
JNB KEY4,WOB4 ;去抖动
NORR: MOV A,REDUCE_NUM
ANL A,#0F0H
SWAP A
MOV B,#10
MUL AB
ANL REDUCE_NUM,#0FH
ADD A,REDUCE_NUM ;将BCD码转为16进制数
MOV REDUCE_NUM,A
CJNE A,#00H,BACKR
JNB HOUR_SYMBOL,HOU
MOV REDUCE_NUM,#24
AJMP BACKR
HOU: MOV REDUCE_NUM,#60
BACKR: DEC REDUCE_NUM
MOV A,REDUCE_NUM
ANL A,#0F0H
SWAP A
CJNE A,#0,UNZERO
AJMP ZERO ;如果十位为零,则跳转
UNZERO: MOV ADD_TIME,A
CLR A
MOV B,#16H
PLUS: ADD A,B
DA A
DJNZ ADD_TIME,PLUS
ZERO: ANL REDUCE_NUM,#0FH
ADD A,REDUCE_NUM
DA A
MOV REDUCE_NUM,A
ACALL JUDGEB
RET
;****************************************************
;判断调整的时间单位,将数值赋予调整数
JUDGEA:
MOV A,SELECT_TIME
JNB ALARM_EN,LPM
;闹钟
CJNE A,#1,LPMA1
MOV ADD_NUM,A_SEC
MOV REDUCE_NUM,A_SEC
AJMP LPMA3
LPMA1: CJNE A,#2,LPMA2
MOV ADD_NUM,A_MIN
MOV REDUCE_NUM,A_MIN
AJMP LPMA3
LPMA2: CJNE A,#3,LPMA3
MOV ADD_NUM,A_HOUR
MOV REDUCE_NUM,A_HOUR
SETB HOUR_SYMBOL
LPMA3: ACALL ALARM_DIS
AJMP JDM
;时钟
LPM: CJNE A,#1,LPM1
MOV ADD_NUM,SEC
MOV REDUCE_NUM,SEC
AJMP LPM3
LPM1: CJNE A,#2,LPM2
MOV ADD_NUM,MIN
MOV REDUCE_NUM,MIN
AJMP LPM3
LPM2: CJNE A,#3,LPM3
MOV ADD_NUM,HOUR
MOV REDUCE_NUM,HOUR
SETB HOUR_SYMBOL
LPM3: ACALL TIME_DIS
JDM: RET
;****************************************************
;判断调整的时间单位,从调整数返回数值
JUDGEB:
MOV A,SELECT_TIME
JNB ALARM_EN,LPJ
;闹钟
CJNE A,#1,LPJA1
JNB ADD_SYMBOL,REDA1
MOV A_SEC,ADD_NUM
AJMP LPJA3
REDA1: MOV A_SEC,REDUCE_NUM
AJMP LPJA3
LPJA1: CJNE A,#2,LPJA2
JNB ADD_SYMBOL,REDA2
MOV A_MIN,ADD_NUM
AJMP LPJA3
REDA2: MOV A_MIN,REDUCE_NUM
AJMP LPJA3
LPJA2: CJNE A,#3,LPJA3
JNB ADD_SYMBOL,REDA3
MOV A_HOUR,ADD_NUM
CLR HOUR_SYMBOL
AJMP LPJA3
REDA3: MOV A_HOUR,REDUCE_NUM
CLR HOUR_SYMBOL
LPJA3: ACALL ALARM_DIS
AJMP JDJ
;时钟
LPJ: CJNE A,#1,LPJ1
JNB ADD_SYMBOL,RED1
MOV SEC,ADD_NUM
AJMP LPJ3
RED1: MOV SEC,REDUCE_NUM
AJMP LPJ3
LPJ1: CJNE A,#2,LPJ2
JNB ADD_SYMBOL,RED2
MOV MIN,ADD_NUM
AJMP LPJ3
RED2: MOV MIN,REDUCE_NUM
AJMP LPJ3
LPJ2: CJNE A,#3,LPJ3
JNB ADD_SYMBOL,RED3
MOV HOUR,ADD_NUM
CLR HOUR_SYMBOL
AJMP LPJ3
RED3: MOV HOUR,REDUCE_NUM
CLR HOUR_SYMBOL
LPJ3: ACALL TIME_DIS
JDJ: RET
;****************************************************
;时钟显示
TIME_DIS:
MOV DPTR,#TABA ;送数码管编码的首地址
MOV A,SEC
ANL A,#0FH ;屏蔽秒单元高位
MOVC A,@A+DPTR
MOV P0,A
MOV P2,#0FEH
ACALL DELAY
MOV P2,#0FFH ;消隐
MOV A,SEC
ANL A,#0F0H ;屏蔽秒单元低位
SWAP A
MOVC A,@A+DPTR
MOV P0,A
MOV P2,#0FDH
ACALL DELAY ;秒单元拆字,送出显示
MOV P2,#0FFH
MOV A,MIN
ANL A,#0FH ;屏蔽分单元高位
MOV DPTR,#TABB
MOVC A,@A+DPTR
MOV DPTR,#TABA
MOV P0,A
MOV P2,#0FBH
ACALL DELAY
MOV P2,#0FFH
MOV A,MIN
ANL A,#0F0H ;屏蔽分单元低位
SWAP A
MOVC A,@A+DPTR
MOV P0,A
MOV P2,#0F7H
ACALL DELAY ;分单元拆字,送出显示
MOV P2,#0FFH
MOV A,HOUR
ANL A,#0FH ;屏蔽时单元高位
MOV DPTR,#TABB
MOVC A,@A+DPTR
MOV DPTR,#TABA
MOV P0,A
MOV P2,#0EFH
ACALL DELAY
MOV P2,#0FFH
MOV A,HOUR
ANL A,#0F0H ;屏蔽时单元低位
SWAP A
MOVC A,@A+DPTR
MOV P0,A
MOV P2,#0DFH
ACALL DELAY ;时单元拆字,送出显示
MOV P2,#0FFH
RET ;反复调用显示程序,等待中断
;****************************************************
;闹钟设置显示
ALARM_DIS:
MOV DPTR,#TABA ;送数码管编码的首地址
MOV A,A_SEC
ANL A,#0FH ;屏蔽秒单元高位
MOVC A,@A+DPTR
MOV P0,A
MOV P2,#0FEH
ACALL DELAY
MOV P2,#0FFH ;消隐
MOV A,A_SEC
ANL A,#0F0H ;屏蔽秒单元低位
SWAP A
MOVC A,@A+DPTR
MOV P0,A
MOV P2,#0FDH
ACALL DELAY ;秒单元拆字,送出显示
MOV P2,#0FFH
MOV A,A_MIN
ANL A,#0FH ;屏蔽分单元高位
MOV DPTR,#TABB
MOVC A,@A+DPTR
MOV DPTR,#TABA
MOV P0,A
MOV P2,#0FBH
ACALL DELAY
MOV P2,#0FFH
MOV A,A_MIN
ANL A,#0F0H ;屏蔽分单元低位
SWAP A
MOVC A,@A+DPTR
MOV P0,A
MOV P2,#0F7H
ACALL DELAY ;分单元拆字,送出显示
MOV P2,#0FFH
MOV A,A_HOUR
ANL A,#0FH ;屏蔽时单元高位
MOV DPTR,#TABB
MOVC A,@A+DPTR
MOV DPTR,#TABA
MOV P0,A
MOV P2,#0EFH
ACALL DELAY
MOV P2,#0FFH
MOV A,A_HOUR
ANL A,#0F0H ;屏蔽时单元低位
SWAP A
MOVC A,@A+DPTR
MOV P0,A
MOV P2,#0DFH
ACALL DELAY ;时单元拆字,送出显示
MOV P2,#0FFH
RET ;反复调用显示程序,等待中断
;****************************************************
;音乐程序
MUSIC: SETB TR1
MUSIC_START:
MOV A,R2
MOV DPTR,#MUSIC_TAB ;取音乐编码的首地址
MOVC A,@A+DPTR
MOV MUSIC_CODE,A
JNZ AGAIN
MOV R2,#0 ;若取得的编码为0,则重新开始音乐
AJMP MUSIC
AGAIN: ANL A,#0F0H ;屏蔽低位
SWAP A
CLR C
RLC A
MOV R3,A
MOV DPTR,#TUNE_TAB ;送曲调地址
MOVC A,@A+DPTR
MOV HIGH_NUM,A
INC R3
MOV A,R3
MOVC A,@A+DPTR
MOV LOW_NUM,A
MOV A,MUSIC_CODE
ANL A,#0FH
MOV CLAP,A
ACALL MUSIC_DELAY ;一个编码运行时间
INC R2
MOV A,MIN
CJNE A,A_MIN,TIMEOUT
AJMP NEXT_TUNE
TIMEOUT:MOV A,SEC
CJNE A,A_SEC,NEXT_TUNE
CLR TR1 ;一分钟到,关闭T1,结束音乐
MOV P1,#0FFH
AJMP MAIN
NEXT_TUNE:
CPL P1.0
CPL P1.1
CPL P1.2
CPL P1.3
CPL P1.4
AJMP MUSIC_START ;执行下一个编码
;****************************************************
;节拍延时,0.1s的整数倍
MUSIC_DELAY:
MOV TH1,HIGH_NUM
MOV TL1,LOW_NUM
MOV R5,CLAP
DLYM1: MOV R4,#16
DLYM2: ACALL TIME_DIS
DJNZ R4,DLYM2
DJNZ R5,DLYM1
RET
;****************************************************
;延时1ms
DELAY: MOV R6,#02H
DELAY1: MOV R7,#0FFH
DJNZ R7,$
DJNZ R6,DELAY1
RET
;****************************************************
TABA: DB 0C0H,0F9H,0A4H,0B0H,99H
DB 92H,82H,0F8H,80H,90H ;不带点数码管编码
TABB: DB 40H,79H,24H,30H,19H
DB 12H,02H,78H,00H,10H ;带点数码管编码
TUNE_TAB:
DW 64580,64684,64777,64820
DW 64898,64968,65030,64260
DW 64400,64524,65058,63835,64021 ;曲调编码
MUSIC_TAB:
DB 02H,82H
DB 16H,32H,54H,02H,52H
DB 0A6H,32H,54H,02H,52H
DB 64H,74H,0B6H,64H
DB 52H,5CH,32H,22H
DB 16H,12H,14H,32H,22H
DB 16H,12H,14H,22H,32H
DB 26H,12H,94H,22H,32H
DB 2CH
DB 32H,52H
DB 36H,22H,14H,54H
DB 0ACH,92H,0A2H
DB 96H,0A2H,96H,82H
DB 3CH,54H
DB 36H,22H,14H,54H
DB 0ACH,92H,0A2H
DB 16H,12H,14H,22H,32H
DB 2CH,02H,82H
DB 16H,32H,56H,12H
DB 0A6H,32H,56H,52H
DB 66H,72H,0B6H,62H
DB 62H,52H,58H,32H,22H
DB 16H,12H,14H,32H,22H
DB 16H,12H,14H,22H,32H
DB 26H,92H,0A4H,12H,22H
DB 1CH
DB 00 ;“月亮代表我的心”编码
;中断服务程序
;定时器T0
TSERV: PUSH PSW
PUSH ACC
MOV TH0,#4CH
MOV TL0,#0
DJNZ INT_NUM,RETUNT ;1s未到,返回
MOV INT_NUM,#14H
MOV A,#01H
ADD A,SEC ;秒加1
DA A
MOV SEC,A ;秒单元转换为BCD码
CJNE A,#60H,RETUNT
MOV SEC,#00H
MOV A,#01H
ADD A,MIN ;分加1
DA A
MOV MIN,A ;分单元转换为BCD码
CJNE A,#60H,RETUNT
MOV MIN,#00H
MOV A,#01H
ADD A,HOUR ;时加1
DA A
MOV HOUR,A ;时单元转换为BCD码
CJNE A,#24H,RETUNT
MOV HOUR,#00H
RETUNT: POP ACC
POP PSW
RETI
;定时器T1
ASERV: PUSH PSW
PUSH ACC
MOV TH1,HIGH_NUM
MOV TL1,LOW_NUM ;重装计数值
CPL BUZZER ;频率输出
POP ACC
POP PSW
RETI
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -