⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 clock.txt

📁 (转载)在C51单片机上的万年历带农历,不需要时钟芯片、感觉不错、很准。
💻 TXT
📖 第 1 页 / 共 3 页
字号:
;寄存器配置:(时间和日期)
;    第3组(18~1FH)(RS1、RS0=11)R0~R3,公历年月日;
;                         R4~R7,时间的时、分、秒、百分之一秒(0.01秒)
;    第2组(10~17H)(RS1、RS0=10)计算农历日期存储中间临时数据
;    第1组(08~0FH)(RS1、RS0=01)键盘处理程序存储
;           闹钟设置状态:R4、R5设置时间时、分,R6、R7计算分钟数
;           万年历状态:R0~R3查看的公历年月日,R6、R7农历月日,R4、R5总天数
;           时间设置时:直接在第3组寄存器操作
;    第0组(00~07H)(RS1、RS0=00)计算中间值临时存储器
;
;总天数、星期、当天分钟计数器、农历日期寄存器
;    30H、31H--距1925.1.1日总天数
;    32H--高四位星期几,低四位与33H当天的分钟数
;    34~37H--农历年月日
;寄存器配置:(闹钟),两个字节为一个单位
;           低地址最高位表示是否设置闹钟,低四位与27H为闹钟时间(当天的分钟数)
;    闹钟1:28H、29H,星期一到五闹钟
;    闹钟2:2AH、2BH,配置与闹钟1相同
;    闹钟3:2CH、2DH,为每日闹钟
;    闹钟4:2EH、2FH,为一次性闹钟
;运行状态寄存器:27H单元,00H,正常的时间显示模式
;    1xH,闹铃设置模式,0~1位第几个闹钟(0~3号),第3位设置时(0)和分(1)
;    2xH,万年历查看模式,0~3分别加减10年、1年、1月、1日,1有效
;    4xH,时间日期设置,低四位都是0设置年,第0~3位分别为1时设置月、日、时、分(加减1)
;方波信号:位地址的07H、06H分别为1秒和0.5秒等脉宽信号,用于控制设置时闪烁显示
;显示缓冲区:6F~7F单元,分别为星期、年月日、时分、农历月日,星期1个单元、年4个单元、其余2个单元
;在计算过程中所示用的位寄存器:
;    在计算农历时用00H位(位地址)表示是否闰月
;    y年m月的天数用25H单元存储临时数据,01H位(位地址)表示当月是29天或30天
;    05H计时满一天后或者调整日期后请求进行农历日期计算标志为
;    04H调整小时或分钟后重新计算当天分钟数请求标识
;    06H、07H周期1秒和0.5秒的方波信号,前者用于秒闪烁,后者调整项闪烁

;****************************************************************************************
ORG 0000H
;开机及复位后从第一行起运行
LJMP 0080H  ;INITTHECLOCK

ORG 0003H
;INT0中断服务程序,若有键按下则产转入键处理
LJMP THEKEYDOWNSERVER ;900H

ORG 000BH
;定时/计数器0中断服务程序,预计每10毫秒产生一次中断
LJMP SETTIMEVALUE ;0300H

ORG 001BH
;定时/计数器1中断服务程序,用于延时5秒后将状态寄存器复位为00H
PUSH A
DEC 03H
MOV A, 03H
JNZ TIMER1RET
;按键后16秒中如果没有其他按键操作,自动转换为时间显示状态
MOV A, 27H
JZ TIMER1SERVERRET ;如果是状态0,直接返回
TIMER1STATE1:
JNB 3CH, TIMER1STATE2
PUSH PSW ;如果是在闹钟设置状态下调用闹钟设置程序
MOV PSW, #00001000B
LCALL SETALARMTIME
POP PSW
AJMP TIMER1SERVERRET
TIMER1STATE2:
JNB 3DH, TIMER1STATE3
AJMP TIMER1SERVERRET ;如果在万年历查看方式下直接换到时间显示状态
TIMER1STATE3:
JNB 3EH, TIMER1SERVERRET
;如果在时间设置状态下,更改当前分钟数
SETB 05H ;设置农历日期计算请求标识
JNB 04H, TIMER1SERVERRET
PUSH PSW
PUSH B
MOV PSW, #00011000B ;
MOV A, R4 ;如果调整了时间,重新计算当天分钟数
MOV B, #60
MUL AB
ADD A, R5
MOV 33H, A
MOV A, B
ADDC A, #0
MOV 32H, A
MOV R6, #0 ;秒清零
CLR 04H
POP B
POP PSW
;AJMP TIMER1SERVERRET
TIMER1SERVERRET:
MOV 27H, #00H
CLR TR1
TIMER1RET:
POP A
RETI

;****************************************************************************************
ORG 0080H
INITTHECLOCK:
MOV SP, #38H
JNB 08H, INITRESET
MOV PSW, #00011000B ;使用3组寄存器(0、1、2、3四组寄存器)
MOV R7, #00 ;初始时间:00:00:00.00
MOV R6, #00
MOV R5, #00
MOV R4, #00
MOV R3, #15 ;初始日期:2000.1.1
MOV R2, #12
MOV R1, #0D4H
MOV R0, #7
MOV 33H, #0 ;初始当天分钟计数器,32H高4位为星期
MOV 32H, #0
MOV 27H, #0
SETB 08H; 标识上电启动,在复位启动时不初始化时间日期
SETB 05H ;
INITRESET:
MOV PSW, #00H
MOV R0, #28H
LOOPINIT:
MOV @R0, #00
INC R0
CJNE R0, #30H, LOOPINIT
CLR P1.7
CLR P2.2

MOV IE, #10001011B ;开定时/计数器0、1中断,开外部中断0,关其余中断
SETB IT0 ;设置INT0为负边沿触发
MOV IP, #00000010B ;设置定时/计数器0的中断优先级为高
MOV TMOD, #00010010B ;定义定时/计数器0计数模式,与INT0无关,计数模式为8位自动重装模式
                     ;定义定时/计数器1计数模式,与INT1无关,计数模式为16位计数模式
MOV TH0, #6 ;拟计数脉冲频率为25K,计数满250时间为10毫秒
MOV TL0, #6
SETB TR0 ;启动定时/计数器0

MOV PSW, #00000000B
MOV P2, #11111111B
;显示字符、闹铃检测比较循环程序
DISPLAYPREPARATIVE:
JNB 05H, LUNARDATETODISPLAY
CLR 05H
PUSH PSW ;计算农历日期
MOV PSW, #00010000B
ACALL SETLUNARDATE
POP PSW
LUNARDATETODISPLAY:
LCALL ALARMCLOCK ;闹铃检测及服务程序
MOV DPTR, #0F90H ;数字1~9的共阴极显示码首地址
MOV A, 27H       ;取运行状态寄存器,以选择显示方式
JNZ DISABNORMAL
DISPLAYNORMAL:
MOV A, 32H ;正常时间显示模式下,取星期显示码
SWAP A
ANL A, #0FH
JNZ DISWEEKDAY
MOV A, #8
DISWEEKDAY:
MOVC A, @A+DPTR
MOV 6FH, A
MOV R0, #19H  ;取年分显示码,共4位
MOV R1, #70H
ACALL DISYEARCODE
MOV R0, #1AH  ;取日期(月日)显示码,共4位
ACALL DISCODE
INC R0        ;取时间(时分)显示码,共4位
ACALL DISCODE
MOV R0, #36H  ;取农历日期(月日)显示码,共4位
ACALL DISCODE
AJMP DISPLAYRUN
DISABNORMAL: ;设置及万年历模式下,显示方式
JB 3CH, DISSTATE1XH
JB 3DH, DISSTATE2XH
JB 3EH, DISSTATE3XH
JB 3FH, DISSTATE4XH
AJMP DISPLAYPREPARATIVE
DISSTATE3XH:
AJMP JMPDISSTATE3XH
DISSTATE4XH:
AJMP JMPDISSTATE4XH
DISSTATE1XH: ;状态1(设置闹钟),星期栏显示闹钟号(1~4),闹铃标志亮,时间栏显示,其余不显示
MOV A, 27H ;取状态字
ANL A, #00000111B
INC A
MOVC A, @A+DPTR
MOV 6FH, A  ;在星期一栏显示闹钟号(1~4)
MOV R1, #70H ;阳历的年月日日期都不显示,送显示码00H到显示缓冲区
LOOPDISSTATE1XH:
MOV @R1, #0
INC R1
CJNE R1, #78H, LOOPDISSTATE1XH
DEC R1
MOV R0, #0CH ;时间时,分显示码,第1组寄存器R4、R5
ACALL DISCODE
INC R1
LOOPDISSTATE1XH1: ;农历日期兰不显示,送显示码00H到显示缓冲区
MOV @R1, #0
INC R1
CJNE R1, #80H, LOOPDISSTATE1XH1
JB 07H, DISSTATE1XHFLICKER
AJMP DISPLAYRUN
DISSTATE1XHFLICKER: ;设置时的闪烁显示
JB 3BH, DISSTATE1XHFLICKERMINUTE
MOV 78H, #0         ;时消隐
MOV 79H, #0
AJMP DISPLAYRUN
DISSTATE1XHFLICKERMINUTE:
MOV 7AH, #0         ;分消隐
MOV 7BH, #0
AJMP DISPLAYRUN
DISSTATE2XH: ;状态2(万年历),时间栏不显示,只显示阴阳历日期及星期
MOV A, 26H  ;取星期显示码,高4位
ANL A, #0F0H
SWAP A
JNZ DISSTATE2XHWEEKDAY
MOV A, #8
DISSTATE2XHWEEKDAY:
MOVC A, @A+DPTR
MOV 6FH, A
MOV R0, #09H  ;取年显示码,共4位
MOV R1, #70H
ACALL DISYEARCODE
MOV R0, #0AH  ;取日期(月日)显示码,共4位
ACALL DISCODE
LOOPDISSTATE2XH: ;时间不显示,送0为显示码
INC R1
MOV @R1, #0
CJNE R1, #7BH, LOOPDISSTATE2XH
MOV R0, #0EH   ;取阴历(月日)显示码,共4位
;MOV R1, #7BH
ACALL DISCODE
JB 07H, DISSTATE2XHFLICKER
AJMP DISPLAYRUN
DISSTATE2XHFLICKER:
JB 38H, DISSTATE2XHFLICKERYEAR10
JB 39H, DISSTATE2XHFLICKERYEAR1
JB 3AH, DISSTATE2XHFLICKERMONTH
JB 3BH, DISSTATE2XHFLICKERDATE
AJMP DISPLAYRUN
DISSTATE2XHFLICKERYEAR10:
MOV 72H, #0
AJMP DISPLAYRUN
DISSTATE2XHFLICKERYEAR1:
MOV 73H, #0
AJMP DISPLAYRUN
DISSTATE2XHFLICKERMONTH:
MOV 74H, #0
MOV 75H, #0
AJMP DISPLAYRUN
DISSTATE2XHFLICKERDATE:
MOV 76H, #0
MOV 77H, #0
AJMP DISPLAYRUN
JMPDISSTATE3XH: ;状态3(设置时间日期),不显示农历的日期和星期
MOV 6FH, #0  ;星期,不显示
MOV R0, #19H  ;取年分显示码,共4位
MOV R1, #70H
ACALL DISYEARCODE
MOV R0, #1AH  ;取日期(月日)显示码,共4位
ACALL DISCODE
INC R0        ;取时间(时分)显示码,共4位
ACALL DISCODE
LOOPDISSTATE3XH: ;时间不显示,送0为显示码
INC R1
MOV @R1, #0
CJNE R1, #7FH, LOOPDISSTATE3XH
JB 07H, DISSTATE3XHFLICKER
AJMP DISPLAYRUN
DISSTATE3XHFLICKER:
JB 38H, DISSTATE3XHFLICKERYEAR
JB 39H, DISSTATE3XHFLICKERMONTH
JB 3AH, DISSTATE3XHFLICKERDATE
JB 3BH, DISSTATE3XHFLICKERHOUR
;DISSTATE3XHFLICKERINUTE:
MOV 7AH, #0
MOV 7BH, #0
AJMP DISPLAYRUN
DISSTATE3XHFLICKERYEAR:
MOV 70H, #0
MOV 71H, #0
MOV 72H, #0
MOV 73H, #0
AJMP DISPLAYRUN
DISSTATE3XHFLICKERMONTH:
MOV 74H, #0
MOV 75H, #0
AJMP DISPLAYRUN
DISSTATE3XHFLICKERDATE:
MOV 76H, #0
MOV 77H, #0
AJMP DISPLAYRUN
DISSTATE3XHFLICKERHOUR:
MOV 78H, #0
MOV 79H, #0
AJMP DISPLAYRUN
JMPDISSTATE4XH:
AJMP DISPLAYNORMAL
;AJMP DISPLAYRUN
DISPLAYRUN: ;显示码送显示驱动器
MOV C, 06H
MOV P2.0, C ;
MOV C, 07H
MOV P2.1, C ;
MOV P0, 6FH
SETB P2.2
ACALL DELAY
CLR P2.2
MOV R0, #70H
MOV R2, #0
LOOPDISPLAY:
MOV P0, @R0
MOV A, R2
SWAP A
ANL P2, #0FH
ORL P2, A
CLR P2.3
ACALL DELAY
SETB P2.3
INC R0
INC R2
CJNE R2, #16, LOOPDISPLAY
LJMP DISPLAYPREPARATIVE

DELAY:
;显示延迟
;((2*R6+1)*R7+1)机器周期
MOV R7, #5
LOOPDALAY:
MOV R6, #100
LOOPDALAY1:
DJNZ R6, LOOPDALAY1
DJNZ R7, LOOPDALAY
RET

DISYEARCODE:
MOV A, @R0 ;计算年的显示码
CLR C
SUBB A, #0D0H ;(2000->7D0H)
MOV B, A
DEC R0
MOV A, @R0
SUBB A, #07H
JNC DISYEAR2000
INC R0
MOV A, @R0
CLR C
SUBB A, #06CH ;(1900->76CH)
MOV B, A
;MOV A, 18H
;SUBB A, #07H
MOV A, #1
MOVC A, @A+DPTR
MOV @R1, A
MOV A, #9
MOVC A, @A+DPTR
INC R1
MOV @R1, A
AJMP DISYEAR10
DISYEAR2000:
MOV A, #2
MOVC A, @A+DPTR
MOV @R1, A
MOV A, #0
MOVC A, @A+DPTR
INC R1
MOV @R1, A
DISYEAR10:
MOV A, B
MOV B, #10
DIV AB
MOVC A, @A+DPTR
INC R1
MOV @R1, A
MOV A, B
MOVC A, @A+DPTR
INC R1
MOV @R1, A
RET

DISCODE:
MOV A, @R0
MOV B, #10
DIV AB
MOVC A, @A+DPTR
INC R1
MOV @R1, A
MOV A, B
MOVC A, @A+DPTR
INC R1
MOV @R1, A
INC R0
MOV A, @R0
MOV B, #10
DIV AB
MOVC A, @A+DPTR
INC R1
MOV @R1, A
MOV A, B
MOVC A, @A+DPTR
INC R1
MOV @R1, A
RET
;****************************************************************************************

SETLUNARDATE:
MOV A, 19H         ;设置计算总天数程序的入口参数,(年-1925)送R2
SUBB A, #85H       ;1925D=785H
MOV R2, A
MOV R3, 1AH        ;月送R3
MOV R4, 1BH        ;日送R4
LCALL CALCULATETOTALDAYS ;计算距离1925年1月1日的总天数
MOV 30H, R6        ;计算结果送30H、31H单元保存
MOV 31H, R7
LCALL SETWEEKDAYS  ;计算星期几
MOV A, R5
SWAP A
ANL 32H, #0FH
ORL 32H, A         ;计算结果送32H单元高四位保存
MOV R4, 30H        ;计算农历日期程序入口参数,总天数送R4、R5
MOV R5, 31H
LCALL LUNARDATECALULATE
MOV 37H, R7        ;
MOV 36H, R4        ;
MOV A, R2
ADD A, #85H        ;1925D=785H
MOV 35H, A
MOV A, #0
ADDC A, #07H
MOV 34H, A
RET

;****************************************************************************************
ORG 0300H
;时间计数器累加,设置当前时间,年月日、时分秒、0.01秒
;设置时间
SETTIMEVALUE:
PUSH PSW            ;压栈保护现场PSW、A、B
PUSH A
PUSH B
MOV PSW, #00011000B ;使用第三组寄存器
INC 24H             ;250微秒计数器
MOV A, 24H
CJNE A, #40, RETTIME
MOV 24H, #00H
INC R7              ;百分之一秒(0.01秒)时间计数器
;产生周期为1秒及0.5秒的方波脉冲信号
MS250:
CJNE R7, #25, MS500
CPL 07H
MS500:
CJNE R7, #50, MS750
CPL 07H
CPL 06H
MS750:
CJNE R7, #75, MS1000
CPL 07H
MS1000:
CJNE R7, #100, RETTIME
CPL 07H
CPL 06H
MOV R7, #0          ;满一秒钟,百分秒计数器清零
INC R6              ;秒计数器
CJNE R6, #60, RETTIME
MOV R6, #0          ;满一分钟,分计数器清零
INC R5              ;分钟计数器
MOV A, 33H          ;当天分钟数计数器(32H低四位、33H)
ADD A, #1
MOV 33H, A
MOV A, #0
ADDC A, 32H
MOV 32H, A
CJNE R5, #60, RETTIME
MOV R5, #0         ;满一小时,分钟计数器清零
INC R4             ;时计数器
CJNE R4, #24, RETTIME
MOV R4, #0         ;满一天,时计数器清零
MOV 33H, #0        ;当天分钟计数器清零
MOV 32H, #0
ACALL SETDATEVALUE ;设置日期计数器
;计算日期入口条件设置
SETB 05H           ;设置请求计算农历日期指示
RETTIME:
POP B              ;出栈恢复现场B、A、PSW
POP A
POP PSW
RETI

;设置日期
SETDATEVALUE:
INC R3              ;天计数器
MOV A, R2           ;判断月份以确定当月的天数
DEC A
JZ DAY31;1月
DEC A
JZ DAY28;2月
DEC A
JZ DAY31;3月
DEC A
JZ DAY30;4月
DEC A
JZ DAY31;5月
DEC A
JZ DAY30;6月
DEC A
JZ DAY31;7月
DEC A
JZ DAY31;8月
DEC A
JZ DAY30;9月
DEC A
JZ DAY31;10月
DEC A
JZ DAY30;11月
DEC A
JZ DAY31;12月
DAY31:
CJNE R3,#32,RETDATE ;大月,31天
AJMP SETMONTH
DAY30:
CJNE R3,#31,RETDATE ;小月,30天
AJMP SETMONTH
DAY28:              ;2月,平年28天,闰年29天
MOV A, R1;计算当年-1925年
SUBB A, #84H ;
MOV B, #4
DIV AB
MOV A, B
JZ DAY29
CJNE R3, #29, RETDATE;平年2月28天
AJMP SETMONTH
DAY29:
CJNE R3,#30,RETDATE  ;闰年2月29天
;AJMP SETMONTH
SETMONTH:
MOV R3, #1           ;满一个月,日计数器设置为1
INC R2               ;月计数器
CJNE R2, #13, RETDATE
MOV R2, #1           ;满一年,月计数器设置为1
MOV A, #1            ;年计数器(R0、R1)
ADD A, R1
MOV R1, A
MOV A, #0
ADDC A, R0
MOV R0, A
RETDATE:
RET

;*****************************************************************************************
ORG 0400H

;*****************************************************************************************
ORG 0500H
;计算当天距离1925年1月1日的总天数,使用第2组寄存器
;入口:R2=年-1925,R3=月,R4=日
;出口:R6、R7=总天数
CALCULATETOTALDAYS:
MOV A, R2   ;假设1年有365天,计算(年-1925)年的总天数
MOV B, #6DH ;16DH(365)的低位字节
MUL AB
MOV R7, A
MOV A, R2
ADD A, B

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -