📄 clock.asm
字号:
;*********************************************************
; 带有时间设置和秒显示的数字闹钟(1个闹钟功能)
; Date : 2008.3.15 11。0592MHZ晶振
; Create by :lus2008 email: yrg200510@126.com
; P3.0 分钟调整键 P3.3小时 调整键 P3.2 设置键(闹钟设置) P3.4 p3.5 闹钟时间到输出
;**************************************************************
;*********************************************************
; 变量地址分配
;*********************************************************
DisplayBuffer equ 30h ;设置显示缓冲区的地址为30h-35h共6个字节
OneSecondCounter equ 39h ;设置1秒计数器的地址,1秒计数器是用来计数1秒内计时器的中断次数
Hour equ 3ah ;设置小时计数器的地址
Minute equ 3bh ;设置分钟计数器的地址
Second equ 3ch ;设置秒计数器的地址
ClockMode equ 20h.0 ;模式(正常走时/闹时)设置寄存器地址,值为0时正常走时,为1时闹时设定
AlarmOnOff equ 20h.1 ;闹钟开启/关闭标志,为0关闭,为1开启
AlarmTimeOn equ 20h.2 ;此位为1时表示闹时时间到
DispHour equ 21h ;设置小时显示寄存器的地址
DispMinute equ 22h ;设置分钟显示寄存器的地址
DispSecond equ 23h ;设置秒显示寄存器的地址
AlarmHour equ 2eh ;设置闹时小时计数器的地址
AlarmMinute equ 2fh ;设置闹时分钟计数器的地址
AlarmSetKey bit P3.2 ;闹钟设置键
MinuteKey bit P3.4 ;定义分设置键
HourKey bit P3.3 ;定义小时设置键
RelayOut equ P3.0 ;定义输出引脚,扬声器控制
RelayOut1 equ P3.5 ;定义输出引脚,继电器1控制
;**********************************************************************
; 程序开始,初始化
;**********************************************************************
org 00h
ajmp Start ;程序开始
org 0bh ;Timer0中断向量地址
ajmp TimeInt ;跳到中断处理程序
org 0020h
Start: ;以下为初始化程序,为各个变量赋初值
mov sp,#70h
setb RelayOut ;输出高电平,闹钟服务程序驱动口
setb RelayOut1 ;输出高电平,闹钟服务程序驱动口
mov OneSecondCounter,#125 ;1秒钟中断次数
;
mov Hour,#12 ;开机时间
mov Minute,#00
mov Second,#00 ;设置上电时时钟显示的初值
;
mov AlarmHour,#06 ;开机时闹钟默认时间
mov AlarmMinute,#00 ;设置上电时闹时时间的初值
;
clr AlarmOnOff ;上点复位后闹时功能处于关闭状态
clr ClockMode ;正常走时模式
clr AlarmTimeOn ;闹钟时间还没有到
setb RelayOut; 清闹时输出
setb RelayOut1; 清闹时输出
;************************************
; 定时器初始化,定时器0方式1,8ms
;th0=0e3 tl0=33
;
;************************************
mov tmod,#00000001b ;
mov th0,#0E3h ;
mov tl0,#33h ;
mov ie,#82h ;开全局中断
setb tr0 ;开定时中断,启动定时器
;*****************************************
; 以下为主程序,按键扫描
;*****************************************
MainLoop:
jb AlarmSetKey,CheckMinuteKey;闹时设置键按下了吗?没有则转去检测秒设置键篇p3.2
lcall Delay2
jb AlarmSetKey,CheckMinuteKey ;按下的时间超过15ms吗?
setb ClockMode ;置为闹时设置模式
call AlarmSet
CheckMinuteKey:
jb MinuteKey,CheckHourKey ;分设置键按下了吗?没有则转去检测小时设置键
call Delay2
jb MinuteKey,CheckHourKey ;按下的时间超过15ms吗? ;如按下调用蜂鸣器发音程序
mov a,Minute
add a,#1; 如果按下则将分钟加一 十进制调整
mov Minute,a;
cjne a,#3ch,NotOver1; 到60分钟了吗?
mov Minute,#0; 到60分钟则将分钟清0
NotOver1: ;以下等待按键释放及防抖动
jnb MinuteKey,$
CheckHourKey:
jb HourKey,CheckAlarm ;小时设置键按下了吗?没有则转去闹时状态检测
call Delay2
jb HourKey,CheckAlarm ;按下的时间超过15ms吗? ;如按下调用蜂鸣器发音程序
mov a,Hour
add a,#1 ;如果按下则将小时加1
mov Hour,a
cjne a,#18h,NotOver2
mov Hour,#0 ;到24小时则将小时清0
NotOver2: ;以下等待按键释放及防抖动
jnb HourKey,$
CheckAlarm: ;
jnb AlarmTimeOn,ToReturn ;闹钟时间到没有
call AlarmProcess ;闹钟子程序
ToReturn:
ajmp MainLoop
;**********************************************
; 定时器Timer0中断服务程序(此程序每8ms执行一次)
;**********************************************
TimeInt:
mov th0,#0E3h; 重新加载定时参数
mov tl0,#33h;
push acc
push psw; 保护累加器及程序状态字的内容
setb rs0; 选择工作寄存器组1,
clr rs1; 这样可保护原工作寄存器组(0组)的内容
djnz OneSecondCounter,NotoneSecond; 中断了125次了吗?即够1秒了吗?
mov OneSecondCounter,#125; 如够1秒则重新设置"OneSecondCounter"计数器
call Clock ; 调用将时钟内容加1秒的子程序
call ConvertoBuffer ; 调用将时钟内容转换到显示缓冲区子程序
NotoneSecond:
call ScanDisplay ; 调用扫描显示子程序
pop psw
pop acc ; 恢复累加器及程序状态字的内容
reti ; 中断返回
;*********************************************
; 扫描显示子程序,将缓冲区的数值显示在对应的数码管上
;*********************************************
ScanDisplay:
MOV R1,#DisplayBuffer ;指向显示数据首址,利用c语言指针原理读取缓冲区的数值
;子程序ConvertoBuffer已经将相应的值存放在displaybuffer的缓冲区中
MOV R4,#11011111b ;扫描控制字初值,显示右边第一个数码管
PLAY: MOV A,R4 ;扫描字放入A
MOV P2,A ;从P2口输出,p2口的低六位分别控制对应的六个数码管的显示
MOV A,@R1 ;取显示数据到A
MOV DPTR,#TAB ;取段码表地址
MOVC A,@A+DPTR ;查显示数据对应段码
MOV P0,A ;段码放入P0口,具体显示位
INC R1 ;指向下一地址
MOV A,R4 ;扫描控制字放入A
;显示时分秒分隔位
JB ACC.1,LPP1 ;显示时分位
CLR P0.7
;CALL Delay
;SETB P0.7
LPP1: JB ACC.3,LPP2 ;显示秒分位
CLR P0.7
;CALL Delay
; SETB P0.7
LPP2:
JNB ACC.7,ENDOUT ;扫到第六位时结束
RR A ;A中数据循环左移
MOV R4,A ;放回R4内
LCALL Delay ;每位数码管显示间隔时间为2ms
SETB P0.7 ;关闭分位显示点
AJMP PLAY ;跳回PLAY循环
;ENDOUT: SETB P2.0 ;一次显示结束,P2口复位
; MOV P0,#0FFH ;P0口复位
ENDOUT: MOV P0,#0FFH ;P0口复位
RET ;子程序返回
TAB: DB 0C0H,0F9H,0A4H,0B0H,99H,92H,82H,0F8H,80H,90H,7FH,0B7H,0FFH
;共阳段码表 "0""1""2" "3""4""5""6""7" "8""9"".""=""不亮"
;****************************************************
; 时钟内容加1秒的子程序(1秒时间到)
;****************************************************
Clock:
mov a,Second ;将原秒值送入a
add a,#1 ;加1秒
mov Second,a
cjne a,#3cH,NotOverFlow ;够60秒了吗?
mov Second,#0; 够了则将秒值清0
;
mov a,Minute
add a,#1
mov Minute,a; 分钟加1
cjne a,#3cH,NotOverFlow; 够60分了吗?
mov Minute,#0; 够了则将分值清0
;
mov a,Hour
add a,#1
mov Hour,a; 小时加1
cjne a,#18H,NotOverFlow; 够24小时吗?
mov Hour,#0; 够了则将小时值清0
NotOverFlow:
jnb AlarmOnOff,NotAlarm; 闹钟开启了吗?如没有开启则无需理会是否到闹时时间
mov a,Second
jnz NotAlarm; 秒为零吗?
mov a,Minute
cjne a,AlarmMinute,NotAlarm; 时间分钟值和闹时设置分钟值相等吗?
mov a,Hour
cjne a,AlarmHour,NotAlarm; 时间小时值和闹时设置小时值相等吗?
setb AlarmTimeOn; 到了闹时时间则将“闹时时间到”标志设为1*******
NotAlarm:
ret
;
;**************************************************************************
; 将时钟内容或闹时设置值转换到显示缓冲区子程序
;**************************************************************************
ConvertoBuffer:
mov r1,#DisplayBuffer
jb ClockMode,DispAlarmSet; 判断时钟模式,以决定是显示实时时间还是闹时时间,ClockMode,0为正常走时,1为闹钟设定
;
mov a,Second;
mov DispSecond,a
;
mov a,Minute;
mov Dispminute,a
;
mov a,Hour;
mov DispHour,a; 显示实时时间,显示寄存器地址
;
ajmp Convert ;在数码管显示缓冲区的数值
DispAlarmSet: ;闹钟设定
jb AlarmOnOff,AlarmOn ;闹钟开关,0为关,1为开
mov DispSecond,#00h
ajmp Next
AlarmOn:
mov DispSecond,#11; 显示闹时时间及显示闹钟状态:显示“00”表示关闭闹钟,
Next: ;“11”表示开启闹钟
mov a,AlarmMinute;
mov Dispminute,a;
mov a,AlarmHour;
mov DispHour,a;
; 将数值显示到数码管
Convert:
mov a,DispSecond; 取秒值,将待显示的数值存储到缓冲区
mov b,#10
div ab
mov @r1,b
inc r1; 缓冲寄存器的地址加1
mov @r1,a
inc r1
mov a,DispMinute
mov b,#10
div ab
mov @r1,b;
inc r1; 缓冲寄存器的地址加1
mov @r1,a; 将秒值的十位值存入缓冲区
;
inc r1
mov a,DispHour
mov b,#10
div ab
mov @r1,b;
inc r1; 缓冲寄存器的地址加1
mov @r1,a; 将秒值的十位值存入缓冲区
ret;
;**************************************************
; 闹钟时间设置子程序
;**************************************************
AlarmSet:
jnb AlarmSetKey,$
call Delay2; 等待“AlarmSetKey”键释放
CheckArmMinuteKey: ;
jb MinuteKey,CheckArmHourKey ;分设置键按下了吗?没有则转去检测小时设置键 p3.5
call Delay2
jb MinuteKey,CheckArmHourKey ;按下的时间超过500ms吗?
setb AlarmOnOff ;闹钟开
mov a,AlarmMinute
add a,#1 ;如果按下则将分钟加1,十进制调整
mov AlarmMinute,a
cjne a,#3ch,ArmNotOver1 ;到60分钟了吗?
mov AlarmMinute,#0 ;到60分钟则将分钟清0
ArmNotOver1: ;以下等待按键释放及防抖动
jnb MinuteKey,$ ;等待对应设置时间的按键释放
CheckArmHourKey:
jb HourKey,AlarmSetEnd; 小时设置键按下了吗?没有则返回反复检测
call Delay2
jb HourKey,AlarmSetEnd ;按下的时间超过500ms吗?
setb AlarmOnOff
mov a,AlarmHour
add a,#1; 如果按下则将小时加1
mov AlarmHour,a
cjne a,#18h,ArmNotOver2
mov AlarmHour,#0; 到24小时则将小时清0
ArmNotOver2: ;以下等待按键释放及防抖动
jnb HourKey,$
AlarmSetEnd:
jb AlarmSetKey,AlarmSet; 闹钟设置 完毕了吗?
call Delay2
jb AlarmSetKey,AlarmSet ;按下的时间超过500ms吗?
jnb AlarmSetKey,$
clr ClockMode; 从设置模式转为走时模式
ret
;**************************************************
; 闹时服务子程序
;**************************************************
AlarmProcess:
mov r2,#10
loop2:
cpl RelayOut
cpl RelayOut1
call Delay1
jb AlarmSetKey,AlarmReturn; 停止闹时键(即闹时设置键)按下了吗?
call Delay2
jb AlarmSetKey,AlarmReturn
clr AlarmOnOff ;关闭闹钟
jnb AlarmSetKey,$
setb RelayOut ;如停止闹时键按下则停止闹时
setb RelayOut1
clr AlarmTimeOn;
ajmp loop6
AlarmReturn:
dec r2
mov a,r2
cjne a,#00h,loop2
setb RelayOut ;如停止闹时键按下则停止闹时
setb RelayOut1
clr AlarmOnOff ;关闭闹钟
clr AlarmTimeOn
loop6: ret
;**************************************************
; 延时子程序
;**************************************************
Delay:
mov r6,#2 ;延时产生1ms,数码管 动态 显示间隔时间
del: mov r7,#249
djnz r7,$
djnz r6,del
ret
;
Delay1:
mov r5,#2 ;延时间产生1s,扬声器的震动间隔时间
de3: mov r6,#200
de2: mov r7,#250
djnz r7,$
djnz r6,de2
djnz r5,de3
ret
Delay2:
mov r6,#10 ;延时产生15ms,按键防止抖动时间
de4: mov r7,#245
djnz r7,$
djnz r6,de4
ret
end
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -