📄 电子闹钟.asm
字号:
;**********************电子闹钟*******************
;本电子闹钟最多可设定10个闹铃时间,还具有秒表功能.
;编程环境:WAVE6000
;MCU: AT89S51
;*************************************************
STATEH EQU 2AH ;状态码高8位
STATEL EQU 2BH ;状态码低8位
B_ON BIT STATEH.5;蜂鸣器软开关
FLAG EQU 2CH ;辅助标志字节
DISP_P EQU 30H ;显示扫描指针
KEYC EQU 2DH ;键码
KEYT EQU 33H ;键龄
KEYOK BIT FLAG.0 ;按键已响应标志位
DHEAD EQU 3AH ;显存首地址(3AH-3FH为显存)
HOUR EQU 40H ;时
MINUTE EQU 41H ;分
SEC EQU 42H ;秒
SECD EQU 43H ;0.01秒
SECD2 EQU 44H ;2ms
MMIN EQU 45H ;秒表分
MSEC EQU 46H ;秒表秒
MSECD EQU 47H ;秒表0.01秒
MSTA BIT STATEH.3;秒表启动标志位
ALARM EQU 48H ;闹铃时间表首地址(48H-5BH为闹铃时间表)
M_1S BIT FLAG.1 ;秒时钟
BUZZER BIT P1.5 ;蜂鸣器控制端
;注:
;STATEH的高2位=00,01,10时分别表示当前显示的数据为时钟,秒表,闹钟.
;STATEH.5为蜂鸣器响标志位.STATEH.4为修改标志位.STATEH.3为秒表
;启动标志位.在修改状态时,STATEH的低3位=0,1,2分别表示修改时,分,秒.
;在显示闹钟表状态时STATEL表示当前显示的闹铃时间在闹钟表中的序号.
;在闹铃时间表中,每一个时间用2个字节表示,地址小的字节的最高为表示
;该时间是否已打开,低7为表示时,还有一个字节表示分.
;--------------------------------------------------
ORG 0000H
AJMP START
ORG 000BH
AJMP TIME
ORG 0030H
;--------------------初始化------------------
START: MOV SP,#60H
MOV R0,#30H
MOV @R0,#0
INC R0
CJNE R0,#61H,$-3
MOV TMOD,#01H
MOV TL0,#30H ;2ms中断(12M晶振)
MOV TH0,#0E8H
MOV HOUR,#12H
MOV MINUTE,#00H
MOV SEC,#00H
MOV STATEH,#0
MOV STATEL,#0
MOV DISP_P,#0
SETB TR0
SETB ET0
SETB EA
ACALL DISP
;-----------------------------------------
MAIN: SJMP MAIN ;等待中断
;--------------T0 中断服务子程序--------------
TIME: ORL TL0,#30H ;用ORL可提高计时精度
MOV TH0,#0F8H
INC SECD2
NOP
MOV A,SECD2
CJNE A,#5,TIME1
MOV SECD2,#0 ;10ms到
;--------------------------------------------
;运行时钟
CLR F0 ;时间改变标志
CLR F1 ;秒为0标志位
MOV A,SECD ;加0.01秒
ADD A,#1
DA A
MOV SECD,A
CJNE A,#50H,$+3
MOV M_1S,C ;产生秒方波
JNZ TIME0
MOV A,SEC ;秒加1
ADD A,#1
DA A
MOV SEC,A
SETB F0 ;标志时间改变
CJNE A,#60H,TIME0
MOV SEC,#0
SETB F1 ;标志秒为0
MOV A,MINUTE ;分加1
ADD A,#1
DA A
MOV MINUTE,A
CJNE A,#60H,TIME0
MOV MINUTE,#0
MOV A,HOUR ;时加1
ADD A,#1
DA A
MOV HOUR,A
CJNE A,#24H,TIME0
MOV HOUR,#0
TIME0: JNB F0,TMB ;时间未改变,转
JNB F1,$+5
ACALL BJIAO ;秒为0,比较
MOV A,STATEH
ANL A,#0C0H
JNZ TMB ;不是显示时间,转
ACALL DISP ;刷新显示
;运行秒表
TMB: JNB MSTA,FMQI ;秒表未开,转
CLR F0
MOV A,MSECD
ADD A,#1 ;加0.01秒
DA A
SETB F0
MOV MSECD,A
JNZ TIME1
MOV A,MSEC ;加1秒
ADD A,#1
DA A
MOV MSEC,A
CJNE A,#60H,TIME1
MOV MSEC,#0
MOV A,MMIN
ADD A,#1
DA A
MOV MMIN,A
TIME1: JNB F0,FMQI
MOV A,STATEH
ANL A,#0C0H
CJNE A,#40H,FMQI
ACALL DISP
;----------------------------------------
;蜂鸣器控制
FMQI: MOV C,B_ON
ANL C,M_1S
CPL C
MOV BUZZER,C
;--------------------
ACALL SCAN
RETI
;--------------------动态扫描---------------------
SCAN: MOV P2,#0FFH ;关显示器
INC DISP_P ;指向下一位
MOV A,DISP_P
CJNE A,#6,SCAN0
MOV DISP_P,#0FFH
AJMP SCNKEY ;每扫完一遍显示器就扫描一次按键
SCAN0: MOV A,DISP_P
ADD A,#DHEAD ;加上显存首地址,得到实际地址
MOV R0,A
MOV A,@R0
ADD A,#2
MOVC A,@A+PC ;查段码
SJMP SCAN1
DB 0C0H,0F9H,0A4H,0B0H,99H,92H,82H,0F8H,80H,90H ;0-9
DB 0BFH,0FFH ;-,"灭"
SCAN1: MOV P0,A
MOV A,DISP_P
ADD A,#2
MOVC A,@A+PC ;查位码
SJMP SCAN2
DB 0DFH,0EFH,0F7H,0FBH,0FDH,0FEH ;位码
;闪亮控制
SCAN2: JNB STATEH.4,SCAN3 ;非修改状态,不用控制
JB M_1S,SCAN3 ;全亮,转
JNB KEYOK,SCAN3
MOV R7,A ;保存位码
MOV A,STATEH
ANL A,#07H
ADD A,#3
MOVC A,@A+PC
ORL A,R7
SJMP SCAN3
DB 30H,0CH,03H
;-----------
SCAN3: MOV P2,A
RET
;-----------------扫描键盘-------------------
SCNKEY: MOV A,P1
CPL A
ANL A,#5FH
JZ NOKEY ;无按键,转
MOV KEYC,A
DEC KEYT ;键龄减1
MOV A,KEYT
JNZ SKEND
MOV KEYT,#70 ;连击延时的时间
JBC KEYOK,SKEY1 ;未响应则标志已响应,并转移
MOV KEYT,#5 ;连击的速度
JB KEYC.0,SKEY1
JB KEYC.1,SKEY1
SJMP SKEND ;不允许连击,转
SKEY1: SJMP KEYJX ;解释按键
NOKEY: SETB KEYOK ;清响应标志位
MOV KEYT,#2 ;消抖时间
MOV KEYC,#00H
SKEND: RET
;----------------------解释按键------------------
KEYJX: JNB B_ON,KEYJX1
CLR B_ON ;若蜂鸣器开
RET
KEYJX1: MOV A,STATEH ;判断当前状态
RL A
RL A
ANL A,#03H
CJNE A,#1,$+5
AJMP MBIAO ;显示秒表状态
CJNE A,#2,SZHONG
AJMP NZHONG ;显示闹钟表状态
;---------------显示时钟状态-----------------
SZHONG: JNB STATEH.4,SZ
AJMP SZ_XIU ;修改时钟状态
;-------正常运行-----
SZ: JNB KEYC.2,$+5
AJMP SZK2
JNB KEYC.6,$+5
AJMP SZK5
RET
;"修改/确定"键
SZK2: SETB STATEH.4 ;进入修改状态
ANL STATEH,#0F8H ;修改"时"
RET
;"切换"键
SZK5: ACALL QHUAN
ACALL DISP ;刷新显示
RET
;----切换显示状态子程序-----
QHUAN: MOV A,STATEH
ANL A,#0C0H
ADD A,#40H
CJNE A,#0C0H,$+4
CLR A
ANL STATEH,#3FH
ORL A,STATEH
MOV STATEH,A
RET
;--------修改时钟-------
SZ_XIU: JNB KEYC.0,$+5
AJMP SXK0
JNB KEYC.1,$+5
AJMP SXK1
JNB KEYC.2,$+5
AJMP SXK2 ;修改/确定
RET
;"加"键
SXK0: CLR C ;设立加1标志
ACALL S_ADD ;修改
ACALL DISP
RET
;"减"键
SXK1: SETB C ;设立减1标志
ACALL S_ADD ;修改
ACALL DISP
RET
;"修改/确定"键
SXK2: MOV B,#2 ;修改完"秒"后,退出修改状态
ACALL W_G
RET
;-----------改变修改位置子程序-----------
;修改完第(B)位后,退出修改状态.
W_G: MOV A,STATEH
ANL A,#07H
CJNE A,B,W_G1
CLR STATEH.4 ;退出修改状态
RET
W_G1: INC STATEH ;修改下一位
RET
;---------------显示秒表状态----------------
MBIAO: JB MSTA,MBRUN ;运行状态
AJMP MBSTOR ;停止状态
;------运行状态------
MBRUN: JNB KEYC.3,$+5
AJMP MBRUN1
JNB KEYC.6,$+5
ACALL QHUAN ;切换显示状态
ACALL DISP
RET
;"开/关"键
MBRUN1: CLR MSTA ;停秒表
RET
;------停止状态------
MBSTOR: JNB KEYC.3,$+5
AJMP MSTK3
JNB KEYC.4,$+5
AJMP MSTK4
JNB KEYC.6,$+5
AJMP MSTK5
RET
;"开/关"键
MSTK3: SETB MSTA ;开秒表
RET
;"清0"键
MSTK4: MOV MMIN,#0
MOV MSEC,#0
MOV MSECD,#0
ACALL DISP
RET
;"切换"键
MSTK5: ACALL QHUAN
ACALL DISP
RET
;-----------------显示闹钟表状态--------------
NZHONG: JNB STATEH.4,NZ
AJMP NZ_XIU
;---------查看闹钟表状态--------
NZ: JNB KEYC.0,$+5
AJMP NZK0
JNB KEYC.1,$+5
AJMP NZK1
JNB KEYC.2,$+5
AJMP NZK2
JNB KEYC.3,$+5
AJMP NZK3
JNB KEYC.6,$+5
AJMP NZK5
RET
;"加"键
NZK0: MOV A,STATEL ;查看上一个时间
ADD A,#1
DA A
ANL A,#0FH ;只有10个时间,从0-9循环翻看
MOV STATEL,A
ACALL DISP
RET
;"减"键
NZK1: MOV A,STATEL ;查看下一个时间
ADD A,#99H
DA A
ANL A,#0FH
MOV STATEL,A
ACALL DISP
RET
;"修改/确定"键
NZK2: SETB STATEH.4 ;进入修改状态
ANL STATEH,#0F8H ;修改"时"
RET
;"开/关"键
NZK3: MOV A,STATEL
RL A
ADD A,#ALARM
MOV R0,A
MOV A,@R0
CPL ACC.7 ;开/关当前显示的那个闹铃时间
MOV @R0,A
ACALL DISP
RET
;"切换"键
NZK5: ACALL QHUAN
ACALL DISP
RET
;-------修改闹钟表状态------
NZ_XIU: JNB KEYC.0,$+5
ACALL NXK0
JNB KEYC.1,$+5
ACALL NXK1
JNB KEYC.2,$+5
ACALL NXK2
RET
;"加"键
NXK0: CLR C ;设立加1标志
ACALL S_ADD ;修改
ACALL DISP
RET
;"减"键
NXK1: SETB C ;设立减1标志
ACALL S_ADD ;修改
ACALL DISP
RET
;"修改/确定"键
NXK2: MOV B,#1 ;修改完"分"后,退出修改状态
ACALL W_G ;改变修改位置
RET
;_______________________按键解释完毕_______________________
;----------------显示模块---------------
DISP: MOV A,STATEH
RL A
RL A
ANL A,#03H
CJNE A,#0,$+5
AJMP DIS0
CJNE A,#1,$+5
AJMP DIS1
CJNE A,#2,$+5
AJMP DIS2
RET
;显示时钟状态
DIS0: MOV R0,#HOUR
MOV R2,#3
SJMP DIS
;显示秒表状态
DIS1: MOV R0,#MMIN
MOV R2,#3
SJMP DIS
;显示闹钟表状态
DIS2: MOV A,STATEL
RL A
ADD A,#ALARM
MOV R0,A
MOV R1,#DHEAD+4
MOV @R1,#0AH ;插入闹钟开标志
MOV A,@R0
JB ACC.7,DIS2_1
MOV @R1,#0BH ;插入闹钟关标志
DIS2_1: INC R1
MOV A,STATEL
MOV @R1,A ;插入序号
MOV R2,#2
;-----------------
DIS: MOV R1,#DHEAD
DISL: MOV A,@R0
CLR ACC.7
SWAP A
ANL A,#0FH
MOV @R1,A
INC R1
MOV A,@R0
ANL A,#0FH
MOV @R1,A
INC R0
INC R1
DJNZ R2,DISL
RET
;-----------------比较模块---------------
BJIAO: MOV A,HOUR
SETB ACC.7
MOV R6,A
MOV R7,MINUTE
ACALL FIND ;查找
MOV B_ON,C ;若找到则开闹铃
RET
;查找
FIND: MOV R2,#10
MOV R0,#ALARM
FIND0: MOV A,@R0
INC R0
XRL A,R6
JNZ FIND1
MOV A,@R0
XRL A,R7
JNZ FIND1
SETB C ;设立找到标志
RET
FIND1: INC R0
DJNZ R2,FIND0
CLR C ;标志未找到
RET
;---------------修改闪亮位子程序---------------
;入口条件:加1 C=0,减1 C=1.
S_ADD: MOV R7,#01H
JNC S_AD
MOV R7,#99H ;-1的BCD码补码
;求闪亮位地址
S_AD: MOV A,STATEH
RL A
RL A
ANL A,#3
JNZ S_ADD0
MOV R0,#HOUR ;修改时钟
SJMP S_ADD1
S_ADD0: CJNE A,#2,S_ADD5
MOV A,STATEL ;修改闹钟表
RL A
ADD A,#ALARM
MOV R0,A
S_ADD1: MOV A,STATEH
ANL A,#07H
ADD A,R0
MOV R0,A
;求进制值
S_ADD2: MOV A,STATEH
ANL A,#07H
ADD A,#2
MOVC A,@A+PC
SJMP S_ADD3
DB 24H,60H,60H
S_ADD3: MOV B,A ;保存进制值
;修改闪亮位
MOV A,@R0
CLR ACC.7
ADD A,R7
DA A
MOV @R0,A
CJNE A,B,S_ADD4
MOV @R0,#0 ;上溢,清0?
RET
S_ADD4: CJNE A,#99H,S_ADD5
ADD A,B ;下溢,付与最大值
DA A
MOV @R0,A
S_ADD5: RET
;**************************************************
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -