led数码管电子时钟制作及程序
一、 题目及功能要求
1 制作一个电子日历时钟使用汇编语言进行软件编程
2 实现功能
(1) 显示北京时间并能校准
(2) 时、分、秒之间以及年、月、日之间以小数点隔开
(3) 显示公历日期并能校准能够自动识别“闰年”以及“大月、小月”
(4) 运动秒表能够后台计时秒表精确到 0.05S
(5) 闹钟功能有闹钟开关并能显示当前闹钟是否开启
(6) 整点报时提醒
二、 硬件方案
1 AT89S52 最小系统
2 显示电路采用动态扫描驱动电路AT89S52 的 P0 口连接 74LS244 总线驱动器输
出信号利用三极管 8550 进行放大通过 P1 口对数码管进行段选扫描AT89S52 的
P1.2~P1.7 口对数码管进行位选扫描
3 两个按键开关分别接 AT89S52 的两个外部中断引脚
4 AT89S52 的 P2.0 口输出经三极管 9012 放大驱动有源蜂鸣器发声
三、 电路原理图
四、 系统元件布局、布线图
五、 元器件清单
六、 软件方案
1 “时钟”基准时间由 AT89S52 定时器 0 中断提供设置为最高优先级定时器 0
设为工作方式 1即 16 进制计数器方式计数初值设为 15536即可实现 0.05s 中
断一次连续中断 20 次即可实现一秒定时。
2 由于使用较多数码管显示模块使用动态扫描方式定义全局变量保存各个数位
的 BCD 码通过查表将字模送到 P0 口进行输出为了显示闹钟的状态设置了
另一字模数据表在显示前进行判断若为闹钟开关设置状态则调用此字模数据表。
3 按键中断的时候在 2 个按键都没按下的状态2 个中断引脚都为低电平则一直
调用中断 0 的子程序每次进入中断 0 子程序中便检测中断 1 的引脚是否为高电平
即检测开关 KEY1 是否按下相反在按下 KEY0 时进入中断 1 子程序每次进
入中断 1 子程序都检测中断 0 的引脚是否为高电平为高电平则表示已按下。
4 用寄存器 R7 来记录当前切换的功能分别为0时间1日期2-闹钟3-闹钟
开关4-秒表。
5 秒表的实现采用基准时钟作为秒表时钟源,精度可以达到 0.05s。
6 闹钟的实现在主程序中循环判断闹钟设置的时分与当前时分是否相等闹钟持
续 1 分钟
7 整点报时的实现在主程序中先判断当前时间的秒若为 0 再判断分再为 0 则
使蜂鸣器嘀一声循环判断。
七、 程序框图
1. 主程序
2. 定时器 0 中断子程序
3. 外部中断 0 子程序
4. 外部中断 1 子程序
八、 系统使用说明
1 接通电源自动复位读取初始状态时钟--“00.00.00”日期—“10.06.06”闹钟
—“06.00.00”闹钟状态—“OFF”秒表—“00.00.00”。
2 按键 KEY1 为“切换功能/调节”按钮按键 KEY0 为“确定/计时开始/计时暂停/
闹钟开关按钮
3 第一功能----电子时钟按 KEY0 键进入时校准状态“时”数码管闪烁此时按
KEY1 键可以调节小时“时”调节范围为 00~24按 KEY0 可切换到“分”设置
调节范围为 00~59 再按 KEY0 可切换到“秒”设置 调节范围为 00~59。
4 第二功能----电子日历在电子时钟功能下按 KEY1 可以切换到电子日历功能。
进入电子日历功能可以对“年”.“月”.“日”进行校准校准方式同电子时钟
的校准方式一样自行摸索。
5 第三功能----闹钟设置在电子日历功能下按 KEY1 可以切换到闹钟设置功能。
闹钟的设置同电子时钟的设置一样。
6 第四功能----闹钟开关在闹钟设置功能下按 KEY1 可以切换到闹钟开关设置。
默认状态为关闭闹钟功能显示“OFF”按 KEY0 可以调节闹钟开关打开闹钟
功能则显示“ON”。闹钟设置为“ON”时最后一个数码管的小数点会亮起可
以在任何功能状态下提示闹钟功能已开启。
7 第五功能----秒表在闹钟设置功能下按 KEY1 可以切换到秒表功能。进入秒表
功能按 KEY0 开始计时再按 KEY0 则暂停计时在秒表计时的时候按 KEY1 可
以切换到其他功能而秒表则在后台计时在秒表暂停时按 KEY1 可以将秒表清零。
九、 体会
第一次使用Atmel Designer Winter 09布出一个完整的PCB制板图并用覆铜板做成实
物最大的体会是软件能画出来的图我们不一定就能把这样的 电路板做出来。布线时
要考虑的因素除整体布局、飞线数目外最重要的是线的宽度、线与线的间距、焊盘的大小。
唯有线宽合适、间距合 理才能做出符合要求的电路板。刚制成的电路板要先使用万用表检
测各导线的连接情况解决断路、短路的问题之后方能进行焊接。这样做 的好处是保证
了调试程序时不会受硬件接触不良等情况的影响。
由于第一次尝试完全使用汇编语言对AT89S52进行编程操作对汇编语言的陌生给前期
编程工作带来诸多不便。汇编语言不同于C或其它高级 语言程序间的跳转各种寄存器的
压栈出栈都需要人工考虑而这种疏漏编译器也不会给出任何提示于是往往一些大意的疏
忽程序便 无法达到预期的效果。加之没有相关条件使用在线调试也给故障排除带来一
些障碍。
对此的体会是确定是程序出现问题时优先往程序间的跳转条件、重要寄存器等的现
场保护、循环退出的条件方面考虑寻找原因。由于 此次硬件电路设计采用低电平导通的
PNP三极管和74LS244电平驱动器也没有将IO口做通用数据传输口用故不需考虑上拉电
阻的选用及 将相应管脚写入高电平以正确接收数据的问题。当然在调试的过程中合理的使
用软件仿真机熟练的设置程序断点同时观察单片机各寄存 器值的变化可以极大方便
我们查找程序漏洞解决问题。
在书写代码的过程中应该注意代码的规范化尤其是使用汇编编程时必须加上必要
的注释方便程序阅读及故障排查。对于需要使用 到的各个变量必须在程序开头集中定
义存储位置以求一目了然在新增变量的时候也不至于出现存储单元被重复使用而导致数
据丢失的 情况。
最后看着忙碌数日得来的劳动成果乖乖的工作确实蛮有成就感。希望今后有更多的
机会进行这样的实践实验。
十、 附录
;AT89S52CLOCK_FINAL.asm
; (Electronic Calendar and Clock)
; Reference for Grade 2008, s.c.u.t.
; Key0(for shift/adjust) connected to INT1
; Key1(for un-flash/flash) connected to INT0
; 学生姓名黄锦波黄卓佳
; 学生学号200830240380200830240434
; 分组编号007
;变量定义
TICK_CNT EQU 20H ;T0 倍乘
;------------------
SECOND_BCD EQU 21H ;时间记录
MINUTE_BCD EQU 22H
HOUR_BCD EQU 23H
;------------------
DAY_BCD EQU 24H ;日期记录
MONTH_BCD EQU 25H
YEAR_BCD EQU 26H
;------------------
FLASH_FLAG EQU 27H ;是否闪烁
DIS_FLAG EQU R7 ;当前显示内容标志 ;DIS_FLAG: 0时间1日期;2-闹钟3-闹钟开
关4-秒表
;------------------
NSECOND_BCD EQU 2BH ;闹钟时间
NMINUTE_BCD EQU 2CH
NHOUR_BCD EQU 2DH
;------------------
TCC_BCD EQU 2EH ;秒表计时器
TBB_BCD EQU 2FH
TAA_BCD EQU 30H
;------------------
TIMER_FLAG EQU 31H ;秒表模式
TIMER_START_FLAG EQU 32H ;秒表开始
;------------------
ALAM_STATE EQU 33H ;闹钟开启标志
;------------------
DI_40H EQU 34H ;提示音延时变量
DI_41H EQU 35H ;延时
;------------------
ALAM_ON1 EQU 36H ;闹钟状态显示
ALAM_ON2 EQU 37H
ALAM_ON3 EQU 38H
ALAM_OFF1 EQU 39H
ALAM_OFF2 EQU 3AH
ALAM_OFF3 EQU 3BH
;------------------
;中断向量表
ORG 0000H
LJMP MAIN
ORG 0003H
LJMP EX0_INT ; port INT0
ORG 000BH
LJMP T0_INT ; port T0
ORG 0013H
LJMP EX1_INT ; port INT1
;主程序
ORG 0030H
MAIN: NOP ; main program
;初始化堆栈
MOV SP,#60H
;初始化变量
MOV SECOND_BCD,#00H ; BCD of "second"
MOV MINUTE_BCD,#00H ; BCD of "minute"
MOV HOUR_BCD,#00H ; BCD of "hour"
MOV NSECOND_BCD,#00H ; BCD of "second"
MOV NMINUTE_BCD,#00H ; BCD of "minute"
MOV NHOUR_BCD,#06H ; BCD of "hour"
MOV TCC_BCD,#00H ; BCD of "second"
MOV TBB_BCD,#00H ; BCD of "minute"
MOV TAA_BCD,#00H ; BCD of "hour"
MOV TIMER_START_FLAG,#00H ;秒表工作标志
MOV TIMER_FLAG,#00H ;秒表模式标志
MOV DAY_BCD,#06H ; BCD of "day"
MOV MONTH_BCD,#06H ; BCD of "month"
MOV YEAR_BCD,#010H ; BCD of "year"
MOV FLASH_FLAG,#00H ; flag for un-flash/flash
MOV DIS_FLAG,#00H ; flag for shift(time/date)
MOV ALAM_ON1,#55H ; BCD OF 闹钟状态显示
MOV ALAM_ON2,#01H
MOV ALAM_ON3,#55H
MOV ALAM_OFF1,#63H
MOV ALAM_OFF2,#42H
MOV ALAM_OFF3,#33H
MOV ALAM_STATE,#00H ;初始化闹钟状态为 OFF
;------------------
MOV TL0,#0B0H ; constant for 0.05s
MOV TH0,#3CH ; 65536-15536=50,000 for 12MHz
MOV TICK_CNT,#14H ; times of overflow 0.05*20=1s
MOV TMOD,#01H ; Mode 1 for T0, Timer Mode
SETB ET0 ; open T0
SETB EX0 ; open INT0, Key1
SETB EX1 ; open INT1, Key0
SETB EA ; total open
SETB PT0 ; priority for T0高优先级
SETB TR0 ; start T0, Run
SCAN_HOUR: ;闹钟扫描
MOV A,SECOND_BCD
CJNE A,#00H,SCANALARM
MOV A,MINUTE_BCD
CJNE A,#00H,SCANALARM
HOUR:
CLR P2.0
NOP ;整点滴
SETB P2.0
SCANALARM: ;闹钟扫描
MOV A,ALAM_STATE
JZ SCAN_HOUR ;闹钟开关已打开
MOV A,NHOUR_BCD
CJNE A,HOUR_BCD,WAIT
MOV A,NMINUTE_BCD
CJNE A,MINUTE_BCD,WAIT
ALARM:
CLR P2.0 ;闹铃滴滴滴滴``````
SETB P2.0
CLR P2.0
SETB P2.0
CLR P2.0
SETB P2.0
CLR P2.0
SETB P2.0
NOP
NOP
NOP
WAIT:
SETB P2.0
SJMP SCAN_HOUR ; wait for interrupt
; -------------------------------------------------
; sub: T0 interrupt
; 定时器 0 中断
T0_INT:
PUSH ACC
MOV TL0,#0B0H ; constant for 0.05s
MOV TH0,#3CH ; Timer 0 重装载
MOV A,TIMER_START_FLAG
CJNE A,#01H,TIMER_NEXT ;秒表模式
LJMP TIMER_INC ;秒表计时
TIMER_NEXT:
DJNZ TICK_CNT,NOT_1S ; is up to 1 second ?
SJMP IS_1S
NOT_1S:
LJMP T0_RET
; 1 秒时间到
IS_1S:
MOV A,SECOND_BCD ; take BCD of "second"
CJNE A,#59H,IN3 ; is up to 59 seconds ?
SJMP IN4
IN3:LJMP SECOND_INC ; 秒加 1
IN4:MOV SECOND_BCD,#00H ; 秒进位
MOV A,MINUTE_BCD ; take BCD of "minute"
CJNE A,#59H,IN5 ; is up to 59 minutes ?
SJMP IN6
IN5: LJMP MINUTE_INC
IN6: MOV MINUTE_BCD,#00H ; 分进位
MOV A,HOUR_BCD ; take BCD of "hour"
CJNE A,#23H,HOUR_INC ; is up to 23 hours ?
MOV HOUR_BCD,#00H ; “时”进位
MOV A,MONTH_BCD ; take BCD of "month"
CJNE A,#02H,NOT_FEB ; is February ?
;2 月处理
;--------------------------
FEB: NOP
ACALL BCD_DIV4 ; BCD of "year in 26H" divided by 4
MOV A,R3 ; remainder in R3
CJNE A,#00H,NOT_LEAP_Y ; "00" means leap year
;闰年29 天
LEAP_Y: MOV A,DAY_BCD ; take BCD of "day" in Feb.
CJNE A,#29H,DAY_INC ; is up to 29 days (leap year)?
MOV DAY_BCD,#01H ; keep the first day
MOV MONTH_BCD,#03H ; increase "month"
SJMP RESET_CNT
;非闰年
NOT_LEAP_Y: MOV A,DAY_BCD ; take BCD of "day" in Feb.
CJNE A,#28H,DAY_INC ; is up to 28 days (common year)?
MOV DAY_BCD,#01H ; keep the first day
MOV MONTH_BCD,#03H ; increase "month"
SJMP RESET_CNT
;---------------------------
;非 2 月处理
;30/31 天
NOT_FEB:NOP ; other "month" except Feb.
CJNE A,#04H,Y01 ; is April ?
AJMP MON_30D
Y01: CJNE A,#06H,Y02 ; is June ?
AJMP MON_30D
Y02: CJNE A,#09H,Y03 ; is September ?
AJMP MON_30D
Y03: CJNE A,#11H,T11 ; is November ?
AJMP MON_30D
;31 天
T11: MOV A,DAY_BCD ; take BCD of "day"
CJNE A,#31H,DAY_INC ; is up to 31 days ?
AJMP NEXT_MONTH
;30 天
MON_30D:MOV A,DAY_BCD ; take BCD of "day"
CJNE A,#30H,DAY_INC ; is up to 30 days ?
;天进位
NEXT_MONTH: MOV DAY_BCD,#01H ; keep the first day
MOV A,MONTH_BCD ; take BCD of "month"
CJNE A,#12H,MONTH_INC; is December ?
; 月进位
MOV MONTH_BCD,#01H ; keep the first month
MOV A,YEAR_BCD ; take BCD of "year"
CJNE A,#99H,YEAR_INC ; is up to 99 years ?
MOV YEAR_BCD,#00H ; keep the first year
SJMP RESET_CNT
;年加 1
YEAR_INC: MOV A,YEAR_BCD ; take BCD of "year"
ADD A,#01H ; increase "year"
DA A ; adjust BCD
MOV YEAR_BCD,A ; keep "year"
SJMP RESET_CNT
MONTH_INC: MOV A,MONTH_BCD ; take BCD of "month"
ADD A,#01H ; increase "month"
DA A ; BCD 码调整
MOV MONTH_BCD,A ; keep "month"
SJMP RESET_CNT
DAY_INC: MOV A,DAY_BCD ; take BCD of "day"
ADD A,#01H ; increase "day"
DA A ; BCD 码调整
MOV DAY_BCD,A ; keep "day"
SJMP RESET_CNT
HOUR_INC: MOV A,HOUR_BCD ; take BCD of "hour"
ADD A,#01H ; increase "hour"
DA A ; BCD 码调整
MOV HOUR_BCD,A ; keep "hour"
SJMP RESET_CNT
MINUTE_INC: MOV A,MINUTE_BCD ; take BCD of "minute"
ADD A,#01H ; increase "minute"
DA A ; BCD 码调整
MOV MINUTE_BCD,A ; keep "minute"
SJMP RESET_CNT
SECOND_INC: MOV A,SECOND_BCD ; take BCD of "second"
ADD A,#01H ; increase "second"
DA A ; BCD 码调整
MOV SECOND_BCD,A ; save back "second"
RESET_CNT: MOV TICK_CNT,#14H ; retrieve times of overflow
T0_RET:
POP ACC
RETI
;--------------------------------------------------------------------
;秒表增
TIMER_INC:
TCC_INC:
MOV A,TCC_BCD ; take BCD of "0.05S"
CLR C
SUBB A,#95H
JZ TBB_INC
MOV A,TCC_BCD
ADD A,#05H ; increase "0.05S"
DA A ; BCD 码调整
MOV TCC_BCD,A ; keep "0.05S"
AJMP TIMER_OUT
TBB_INC:
MOV TCC_BCD,#00H
MOV A,TBB_BCD ; take BCD of "SECOND"
CLR C
SUBB A,#59H
JZ TAA_INC
MOV A,TBB_BCD
ADD A,#01H ; increase "SECOND"
DA A ; BCD 码调整
MOV TBB_BCD,A ; keep "SECOND"
AJMP TIMER_OUT
TAA_INC:
MOV TBB_BCD,#00H
MOV A,TAA_BCD ; take BCD of "MINUTE"
CLR C
SUBB A,#59H
JZ TDD_INC
MOV A,TAA_BCD
ADD A,#01H ; increase "MINUTE"
DA A ; BCD 码调整
MOV TAA_BCD,A ; save back "MINUTE"
AJMP TIMER_OUT
TDD_INC:MOV TAA_BCD,00H
TIMER_OUT: LJMP TIMER_NEXT ;返回定时器中断
;------------------------------------------------------------------
; -------------------------------------------------------------------
; sub: LED Display
;显示子程序
DISPLAY:
MOV A,DIS_FLAG
CJNE A,#03H,DISPLAY2 ;选择不同字模
MOV DPTR,#TAB2
SJMP DISPLAY3
DISPLAY2:
MOV DPTR,#TAB ; set address of code table
DISPLAY3:
MOV A,DIS_FLAG ; take flag for shift
CJNE A,#00H,DISP_DATE ; "00" 当前显示内容为时间
;R0: point to display buffer
DISP_TIME: MOV R0,#SECOND_BCD ; beginning from "second"
SJMP TSA
DISP_DATE:
CJNE A,#01H,DISP_ALAM ; "01" 当前显示内容为日期
MOV R0,#DAY_BCD ; "FF" for showing date
SJMP TSA;显示时间或日期
DISP_ALAM:
CJNE A,#02H,DISP_ALAM_SET ; "02" 当前显示内容为闹钟
MOV R0,#NSECOND_BCD ; beginning from "second"
SJMP TSA
DISP_ALAM_SET:
CJNE A,#03H,DISP_TIMER ; "03" 当前显示内容为闹钟设置
MOV A,ALAM_STATE ; 闹钟状态显示
JZ SHOWOFF
MOV R0,#ALAM_ON1 ; 显示”ON“
SJMP TSA
SHOWOFF:
MOV R0,#ALAM_OFF1 ;显示“OFF”
SJMP TSA
DISP_TIMER: ;"04"当前显示内容为秒表
MOV R0,#TCC_BCD ; beginning from "second"
TSA: MOV A,@R0 ; begin from "day"
ANL A,#0FH ; get the "low half byte"
MOVC A,@A+DPTR ; take character from code table
MOV R1,A ; keep in R1 for DS6 showing
MOV A,@R0
SWAP A
ANL A,#0FH ; get the "high half byte"
MOVC A,@A+DPTR ; take character from code table
MOV R2,A ; keep in R2 for DS5 showing
;---------------
INC R0
MOV A,@R0 ; next one from "month"
ANL A,#0FH ; get the "low half byte"
MOVC A,@A+DPTR
MOV R3,A ; keep in R3 for DS4 showing
MOV A,@R0
SWAP A
ANL A,#0FH ; get the "high half byte"
MOVC A,@A+DPTR
MOV R4,A ; keep in R4 for DS3 showing
;-------------
INC R0
MOV A,@R0 ; next one from "year"
ANL A,#0FH ; get the "low half byte"
MOVC A,@A+DPTR
MOV R5,A ; keep in R5 for DS2 showing
MOV A,@R0
SWAP A
ANL A,#0FH ; get the "high half byte"
MOVC A,@A+DPTR
MOV R6,A ; keep in R6 for DS1 showing
;---------------------
;P1位选线
;P0段选线
NOP
TDP: MOV P1,#0FFH ; close all showing///
;Display DS6
MOV A,ALAM_STATE ;是否显示闹钟状态位最末位小数点
JZ DIS_NEXT
MOV A,R1
ANL A,#7FH
MOV R1,A
DIS_NEXT:
MOV A,R1
MOV P0,A ; send character to DS6
MOV A,FLASH_FLAG ; get flag of un-flash/flash
CJNE A,#03H,A02 ; "03" is flash on DS5&DS6
SJMP A03
A02: CJNE A,#03H,A04; ; "03" is flash on DS5&DS6
A03: MOV A,TICK_CNT ; take Counter of overflow
RRC A
JNC A05 ; check bit C ( 1 or 0 )
A04: MOV P1,#0FBH ; turn on DS6
A05: LCALL DELAY
MOV P1,#0FFH ; close all showing
;Display DS5
MOV P0,R2 ; send character to DS5
MOV A,FLASH_FLAG ; get flag of un-flash/flash
CJNE A,#03H,B02 ; "03" is flash on DS5&DS6
SJMP B03
B02: CJNE A,#03H,B04
B03: MOV A,TICK_CNT ; take times of overflow
RRC A
JNC B05 ; check bit C ( 1 or 0 )
B04: MOV P1,#0F7H ; turn on DS5
B05: LCALL DELAY
MOV P1,#0FFH ; close all showing
;Display DS4
MOV A,R3
ANL A,#7FH ;该位增加小数点显示
MOV P0,A ; send character to DS4
MOV A,FLASH_FLAG ; get flag of un-flash/flash
CJNE A,#02H,C02 ; "02" is flash on DS3&DS4
SJMP C03
C02: CJNE A,#02H,C04
C03: MOV A,TICK_CNT ; take times of overflow
RRC A
JNC C05 ; check bit C ( 1 or 0 )
C04: MOV P1,#0EFH ; turn on DS4
C05: LCALL DELAY
MOV P1,#0FFH ; close all showing
;Display DS3
MOV P0,R4 ; send character to DS3
MOV A,FLASH_FLAG ; get flag of un-flash/flash
CJNE A,#02H,D02 ; "02" is flash on DS3&DS4
SJMP D03
D02: CJNE A,#02H,D04
D03: MOV A,TICK_CNT ; take times of overflow
RRC A
JNC D05 ; check bit C ( 1 or 0 )
D04: MOV P1,#0DFH ; turn on DS3
D05: LCALL DELAY
MOV P1,#0FFH ; close all showing
;Display DS2
MOV A,R5
ANL A,#7FH ;该位增加小数点显示
MOV P0,A ; send character to DS2
MOV A,FLASH_FLAG ; get flag of un-flash/flash
CJNE A,#01H,E02 ; "01" is flash on DS1&DS2
SJMP E03
E02: CJNE A,#01H,E04
E03: MOV A,TICK_CNT ; take times of overflow
RRC A
JNC E05 ; check bit C ( 1 or 0 )
E04: MOV P1,#0BFH ; turn on DS2
E05: LCALL DELAY
MOV P1,#0FFH ; close all showing
MOV P0,R6 ; send character to DS1
MOV A,FLASH_FLAG ; get flag of un-flash/flash
CJNE A,#01H,F02 ; "01" is flash on DS1&DS2
SJMP F03
F02: CJNE A,#01H,F04
F03: MOV A,TICK_CNT ; take times of overflow
RRC A
JNC F05 ; check bit C ( 1 or 0 )
F04: MOV P1,#07FH ; turn on DS1
F05: LCALL DELAY
MOV P1,#0FFH ; close all showing
RET
; -------------------------------------------------------------------
; ----------------------------------------
; sub: delay (1.542ms for 12MHz, 3.084ms for 6MHz)
;延时子程序
D_CNT_2 EQU 28H
D_CNT_1 EQU 29H
DELAY:MOV D_CNT_2,#03H
D_LOOP2: MOV D_CNT_1,#0FFH ;[1]
D_LOOP1: DJNZ D_CNT_1,D_LOOP1 ;[2]
DJNZ D_CNT_2,D_LOOP2 ;[2]
RET
; ----------------------------------------
; ---------------------------------------------------------
;外部中断 0
; sub: INT0 interrupt
; 处理按键 K0,切换时间/日期/闹钟/闹钟设置/秒表显示或者调整
EX0_INT: NOP ; switch or adjust with date/time
PUSH ACC
PUSH PSW
LCALL DIS_DELAY ; re-bounce (with LED display)
JNB P3.3,OUT ; check port INT1
;K0 按下
NOP ; inhibit INT1 ( use k0)
;---------------------------------------------------
MOV A,FLASH_FLAG
CJNE A,#00H,JUDGE_MODE ;有闪烁进入调整模式
SET_DIS: ;无闪烁进入设置显示或秒表模式
CLR P2.0 ;按键滴一声
MOV DI_41H,#19H
DI_LPO:
MOV DI_40H,#0FFH
DI_LP:
DJNZ DI_40H,DI_LP
DJNZ DI_41H,DI_LPO
SETB P2.0
;---------------------------------------------------
MOV A,DIS_FLAG
INC A
MOV DIS_FLAG,A
CJNE A,#04H,CROSSTIMER ;进入秒表
;---------------------------------------------------
TIMER:
MOV TIMER_FLAG,#01H ;进入秒表秒表模式设置为开
LJMP EX0_RET ;退出
;---------------------------------------------------
CROSSTIMER: ;显示模式切换
CJNE A,#05H,OUT
MOV DIS_FLAG,#00H ;已到 5 需置零
MOV TIMER_FLAG,#00H
MOV A,TIMER_START_FLAG
JNZ OUT ;秒表后台工作暂停计数时退出则对秒表清零
MOV TCC_BCD,#00H ; BCD of "second" 秒表清零
MOV TBB_BCD,#00H ; BCD of "minute"
MOV TAA_BCD,#00H ; BCD of "hour"
OUT: LJMP EX0_RET ; 退出
;---------------------------------------------------
JUDGE_MODE: ;进入调整模式
MOV A,DIS_FLAG ; 读取当前显示内容为时间/日期/秒表/闹钟
CJNE A,#00H,JDATE ;是否进入时间调整 00
;---------------------------------------------------
JTIME: ;调整时间
MOV A,FLASH_FLAG ; take flag of un-flash/flash
ADH: CJNE A,#01H,ADM ; "03" for adjusting "hour"
MOV A,HOUR_BCD ; take BCD of "hour"
CJNE A,#23H,JH0 ; is up to 23 hours ?
MOV HOUR_BCD,#00H ; keep the first hour
LJMP JHF
JH0: ADD A,#01H ; increase "hour"
DA A ; adjust BCD
MOV HOUR_BCD,A ; keep "hour"
JHF: LJMP EX0_RET
;-----------------------------------------
ADM: CJNE A,#02H,ADS ; "02" for adjusting "minute"
MOV A,MINUTE_BCD ; take BCD of "minute"
CJNE A,#59H,JM0 ; is up to 59 minutes ?
MOV MINUTE_BCD,#00H ; keep the first minute
LJMP JMF
JM0: ADD A,#01H ; increase "minute"
DA A ; adjust BCD
MOV MINUTE_BCD,A ; keep "minute"
JMF: LJMP EX0_RET
ADS: MOV A,SECOND_BCD ; take BCD of "second"
CJNE A,#59H,JS0 ; is up to 59 seconds ?
MOV SECOND_BCD,#00H ; keep the first second
LJMP JSF
JS0: ADD A,#01H ; increase "second"
DA A ; adjust BCD
MOV SECOND_BCD,A ; keep "second"
JSF: NOP
LJMP EX0_RET
;---------------------------------------------------
JALAM0: LJMP JALAM
JDATE: CJNE A,#01H,JALAM0 ;是否进入日期调整 01
JYY: NOP ; "01 to 06" is in flash
MOV A,FLASH_FLAG
CJNE A,#01H,JMM ; "01" for adjusting "year"
;调节年
MOV A,YEAR_BCD ; take BCD of "year"
CJNE A,#99H,YY0 ; is up to 99 year ?
MOV YEAR_BCD,#00H ; keep the first year
LJMP YYF
YY0: ADD A,#01H ; increase "year"
DA A ; adjust BCD
MOV YEAR_BCD,A ; keep "year"
YYF: LJMP EX0_RET
;---------------------------------------
JMM: CJNE A,#02H,JDD ; "02" for adjusting "month"
;调节月
MOV A,MONTH_BCD ; take BCD of "month"
CJNE A,#12H,MM0 ; is December ?
MOV MONTH_BCD,#01H ; keep the first month
LJMP MMF
MM0: ADD A,#01H ; increase "month"
DA A ; adjust BCD
MOV MONTH_BCD,A ; keep "month"
MMF: LJMP EX0_RET
;---------------------------------------
JDD: CJNE A,#03H,AA1 ; "03" for adjusting "day"
LJMP BB1
AA1: LJMP ADH ;
BB1: MOV A,MONTH_BCD ; first, should take "month"
CJNE A,#02H,NFB ; is February ?
IFB: NOP
ACALL BCD_DIV4 ; BCD of "year in YEAR_BCD" divided by 4
MOV A,R3 ; remainder in R3
CJNE A,#00H,ANG ; "00" means leap year
ARN: MOV A,DAY_BCD ; take BCD of "day"
CJNE A,#29H,D0A ; is up to 29 days in Feb.?
LJMP D0B
D0A: LJMP DDA
D0B: LJMP DD1
ANG: MOV A,DAY_BCD ; take BCD of "day"
CJNE A,#28H,D0A ; is up to 28 days in Feb.?
LJMP DD1
NFB: NOP ; check "little/large" month
CJNE A,#04H,Y04 ; is April ?
LJMP AD1
Y04: CJNE A,#06H,Y05 ; is June ?
LJMP AD1
Y05: CJNE A,#09H,Y06 ; is September ?
LJMP AD1
Y06: CJNE A,#11H,Y07 ; is November ?
LJMP AD1
Y07: NOP ; for "large" month
MOV A,DAY_BCD ; take BCD of "day"
CJNE A,#31H,D0A ; is up to 31 days ?
LJMP DD1
AD1: NOP ; for "little" month
MOV A,DAY_BCD ; take BCD of "day"
CJNE A,#30H,D0A ; is up to 30 days ?
DD1: MOV DAY_BCD,#01H ; keep the first day
LJMP DDF
DDA: ADD A,#01H ; increase "day"
DA A ; adjust BCD
MOV DAY_BCD,A ; keep "day"
DDF: LJMP EX0_RET
;---------------------------------------------------
JALAM: ;调整闹钟
MOV A,FLASH_FLAG ; take flag of un-flash/flash
NADH: CJNE A,#01H,NADM ; "03" for adjusting "hour"
MOV A,NHOUR_BCD ; take BCD of "hour"
CJNE A,#23H,NJH0 ; is up to 23 hours ?
MOV NHOUR_BCD,#00H ; keep the first hour
LJMP NJHF
NJH0: ADD A,#01H ; increase "hour"
DA A ; adjust BCD
MOV NHOUR_BCD,A ; keep "hour"
NJHF: LJMP EX0_RET
;-----------------------------------------
NADM: CJNE A,#02H,NADS ; "02" for adjusting "minute"
MOV A,NMINUTE_BCD ; take BCD of "minute"
CJNE A,#59H,NJM0 ; is up to 59 minutes ?
MOV NMINUTE_BCD,#00H ; keep the first minute
LJMP NJMF
NJM0: ADD A,#01H ; increase "minute"
DA A ; adjust BCD
MOV NMINUTE_BCD,A ; keep "minute"
NJMF: LJMP EX0_RET
NADS: MOV A,NSECOND_BCD ; take BCD of "second"
CJNE A,#59H,NJS0 ; is up to 59 seconds ?
MOV NSECOND_BCD,#00H ; keep the first second
LJMP NJSF
NJS0: ADD A,#01H ; increase "second"
DA A ; adjust BCD
MOV NSECOND_BCD,A ; keep "second"
NJSF: NOP
LJMP EX0_RET
;---------------------------------------------------
EX0_RET:NOP ;中断退出
POP PSW
POP ACC
RETI
;---------------------------------------------------
;---------------------------------------------------
; sub: INT1 interrupt
; 处理按键 K1,设置闪烁
EX1_INT:NOP ; revise flag(00 to 06) in FLASH_FLAG
PUSH ACC
PUSH PSW
JNB P3.2,EX1_RET ; check port INT0
LCALL DIS_DELAY ; re-bounce (with LED display)
;;K1 按键按下
NOP ; inhibit INT0 (use k1)
MOV A,DIS_FLAG
CJNE A,#03H,TIMER_START0 ;非设置闹钟开关模式
MOV A,ALAM_STATE
CPL A ;取非
ANL A,#01H ;保留最后
MOV ALAM_STATE,A ;设置闹钟开关
AJMP DI_START ;提示音后退出
;---------------------------------------------------
TIMER_START0:
MOV A,TIMER_FLAG
CJNE A,#01,FLASH_SHIFT ;非秒表模式
TIMER_START:
MOV A,TIMER_START_FLAG
CPL A
ANL A,#01H ;保留最低位
MOV TIMER_START_FLAG,A ;设置秒表开关
;---------------------------------------------------
DI_START:
CLR P2.0 ;按键滴一声
MOV DI_41H,#19H
DI_LOOPO:
MOV DI_40H,#0FFH
DI_LOOP:
DJNZ DI_40H,DI_LOOP
DJNZ DI_41H,DI_LOOPO
SETB P2.0
AJMP EX1_RET ;退出
;---------------------------------------------------
FLASH_SHIFT: ;进入切换闪烁
MOV A,FLASH_FLAG ; take flag of un-flash/flash
CJNE A,#00H,ED1 ; "00" 无闪烁
MOV FLASH_FLAG,#01H ; 设置 1,2 号数码管闪烁
SJMP EX1_RET
ED1: CJNE A,#01H,ED2 ; "01" 1,2 号闪烁中
MOV FLASH_FLAG,#02H ; 设置 3,4 号闪烁
SJMP EX1_RET
ED2: CJNE A,#02H,ED3 ; "02" 3,4 号闪烁
MOV FLASH_FLAG,#03H ; 设置 5,6 号闪烁
SJMP EX1_RET
ED3: MOV FLASH_FLAG,#00H ; 关闭所有闪烁
EX1_RET:NOP
POP PSW
POP ACC
RETI
;------------------------------------
; ---------------------------------------------
; 带显示延迟
D_CNT_DIS EQU 2AH
DIS_DELAY: MOV D_CNT_DIS,#10H ; or(#0BH)
DELAY_LOOP: LCALL DISPLAY ; with LED display
DJNZ D_CNT_DIS,DELAY_LOOP
RET
; -----------------------------------------------
; ----------------------------------------------------------
; sub: BCD division
; BCD 除法除 4
; 输出
; R3: 余数
; R2: 商
BCD_DIV4: MOV R0,YEAR_BCD ; dividend in BCD
MOV R1,#04H ; divider in BCD
MOV R2,#00H ; R2输出商
MOV A,R1
CPL A
ADD A,#9BH
MOV R1,A ; R1BCD 补码
MOV A,R0
ANL A,#0F0H ; BCD 高位
SWAP A
LP0: MOV R3,A ; BCD 码的余数
ADD A,R1
DA A
JNC LP1
INC R2
SJMP LP0
LP1: MOV A,R3
SWAP A
MOV R3,A
MOV A,R2
SWAP A
MOV R2,A ; 商的高位
MOV A,R0
ANL A,#0FH ; 年 BCD 的低位
ORL A,R3
LP2: MOV R3,A
ADD A,R1
DA A
JNC LP3
INC R2
SJMP LP2
LP3: NOP ; no rounding
RET
;----------------------------------------------
; ------------------------------------------------------
; 放在代码段的字模表
TAB:
DB 0c0H ; for "0"
DB 0f9H ; for "1"
DB 0a4H ; for "2"
DB 0b0H ; for "3"
DB 99H ; for "4"
DB 92H ; for "5"
DB 82H ; for "6"
DB 0f8H ; for "7"
DB 80H ; for "8"
DB 90H ; for "9"
TAB2: ;闹钟状态显示的字模
DB 0C0H ; "0"
DB 11001000B ; "N"
DB 10001110B ; "F"
DB 0FFH ; " "
DB 40H ; "0."
DB 07FH ; "."
DB 00001110B ; "F."
END
同类文章排行
- LED数码管的检测
- LED数码管故障检测检修
- LED数显温度控制器设计论述
- LED大屏幕数显装置在随流孕育装置上的应用
- LED数码管正装与倒装结构区别
- led数码管静态显示方式和动态显示方式
- LED七段数码管数字钟
- led数码管显示种类简介
- LED数码管显示器介绍
- LED数码管动态扫描显示控制器设计