求一个51单片机数码管实现电子钟的程序,最好能带写了一天错误越写越多心态已经炸了,求大神帮我T.T

2022-03-17 科技 51阅读
;--------------------------------------------------------------
;-------------------简易秒表的制作----------------------------
;--------------------------------------------------------------
BANK0_REG EQU 00H ;选择第0组寄存器
BANK1_REG EQU 08H ;选择第1组寄存器
BANK2_REG EQU 10H ;选择第2组寄存器
BANK3_REG EQU 18H ;选择第3组寄存器
LED_MAX_BITS EQU 06H ;LED最大位数

LED_SCL EQU P1.0
LED_SDA EQU P1.1
HD_K0 EQU P1.2
HD_K1 EQU P1.3
HD_K2 EQU P1.4
HD_CBP EQU P1.5

K0_FLAG EQU 00H
K1_FLAG EQU 01H
K2_FLAG EQU 02H
SEC_FLAG EQU 03H ;定义各标识位符号地址
MIN_FLAG EQU 04H
HOUR_FLAG EQU 05H
RMIN_FLAG EQU 06H
RHOUR_FLAG EQU 07H
RTIM_FLAG EQU 08H
ARM_FLAG EQU 09H ;是否设定闹钟标识

TIMDATA EQU 30H ;时钟修改记忆单元
RTIMDATA EQU 31H ;闹钟修改记忆单元清零
MSEC1 EQU 32H
MSEC2 EQU 33H
HOUR EQU 34H
MIN EQU 35H
SEC EQU 36H
RHOUR EQU 37H
RMIN EQU 38H
RSEC EQU 39H
COUNT EQU 3AH
LED_DIS_PTR EQU 3BH

ORG 0000H
LJMP MAIN
ORG 000BH
LJMP TIMER_INT ;定时器中断服务程序
ORG 0100H

MAIN:
CLR EA
MOV PSW,#BANK0_REG
MOV SP,#0DFH
MOV R0,#20H
MOV R7,#80H-20H
LCALL PUB_CLEAR_RAM1 ;清0RAM单元

LCALL LED_CLR
MOV LED_DIS_PTR,#HOUR
LCALL LED_DISP_DATA

MOV TMOD,#02H ;定时器T0方式2,
MOV TL0,#06H ;定时250us初始值
MOV TH0,#06H
SETB EA ;中断允许
SETB ET0
SETB TR0 ;启动定时器
BEGIN:
LCALL KEY_TEST ;调用判别键入测试程序
JC RETEST ;有键输入则转去抖程序
JNB ARM_FLAG,BEGIN ;判别闹钟设定标识位,未设定则返回
LCALL ALARM ;调闹钟程序
LJMP BEGIN ;返回
RETEST:
LCALL KEY_SCAN
JB K0_FLAG,PRO_K0 ;判别是否时钟修改功能键
JB K1_FLAG,PRO_K1 ;判别是否闹钟修改功能键
JB K2_FLAG,PRO_K2 ;判别是否加1功能键
SJMP BEGIN
PRO_K0:
LCALL FTION0 ;是时钟参数修改功能键则调用时钟修改程序
SJMP BEGIN
PRO_K1:
LCALL FTION1 ;是闹钟参数修改功能键则调用闹钟设定程序
SJMP BEGIN
PRO_K2:
LCALL CUM ;是加1功能键则调用加1修改程序
SJMP BEGIN
;--------------------------------------------------
;时钟参数修改子程序FTION0
;功能:根据时钟修改功能键按下的次数
;分别将时钟修改标识位SECBIT,MIN_FLAG,HOURBIT置1
;入口:TIMDAT
;出口:TIMDAT
;--------------------------------------------------
FTION0:
JB RMIN_FLAG,BACK_B
JB RHOUR_FLAG,BACK_B ;当正在设置闹钟不能设置时间,需先结束闹钟设置状态
CLR TR0 ;关定时器
CLR SEC_FLAG ;时钟秒标识位清零
CLR MIN_FLAG ;时钟分标识位清零
CLR HOUR_FLAG ;时钟小时标识位清零

MOV LED_DIS_PTR,#HOUR ;将时钟小时单元设为显示首地址
MOV RTIMDATA,#00H ;清闹钟修改位置标识记录
INC TIMDATA ;将时钟修改记录值加1
MOV A,TIMDATA
CJNE A,#01H,TW0 ;若记录值为1则将时钟秒修改标识置1
SETB SEC_FLAG ;时钟秒标识位置1
SJMP BACK_C
TW0:
CJNE A,#02H,THREE0 ;若记录值为2则将时钟分修改标识置1
SETB MIN_FLAG ;时钟分标识位置1
SJMP BACK_C
THREE0:
CJNE A,#03H,BACK_A ;若记录值为3则将时钟小时修改标识置1
SETB HOUR_FLAG ;时钟小时标识位置1
SJMP BACK_C
BACK_A:
MOV TIMDATA,#00H ;若按4次则清时钟单元修改位置记录
SETB TR0 ;定时器重新启动
BACK_B:
RET
BACK_C:
LCALL LED_DISP_DATA
RET
;--------------------------------------------------
;闹钟参数修改功能键设定子程序FTION1
;功能:根据闹钟修改功能键按下的次数
;分别将闹钟修改标识位RMINBIT,RHOURBIT置1
;入口:RTIMDAT
;出口:RTIMDAT,ARM_FLAG,B
;--------------------------------------------------
FTION1:
JB SEC_FLAG,FTION1_A
JB MIN_FLAG,FTION1_A
JB HOUR_FLAG,FTION1_A ;当处于设置时间状态时不能设置闹钟,需先结束时间设置状态
CLR RMIN_FLAG ;将闹钟分单元修改标识位
CLR RHOUR_FLAG ;将闹钟小时单元修改标识位清零

MOV LED_DIS_PTR,#RHOUR ;将闹钟单元地址设为显示首地址
MOV TIMDATA,#00H
INC RTIMDATA ;将闹钟修改记录值加1
MOV A,RTIMDATA
CJNE A,#01H,TOW1
SETB RMIN_FLAG ;若记录值为1则将闹钟分单元修改标识位
LJMP FTION1_B ;置1
TOW1:
CJNE A,#02H,THREE1
SETB RHOUR_FLAG ;若记录值为2,将闹钟小时单元修改标识位置1
LJMP FTION1_B
THREE1:
SETB ARM_FLAG ;F0标识位为1表示闹钟已设定
MOV LED_DIS_PTR,#HOUR ;恢复时钟显示单元首地址
MOV RTIMDATA,#00H ;将闹钟修改记录值清零
FTION1_A:
RET
FTION1_B:
LCALL LED_DISP_DATA
RET
;---------------------------------------------------------------
;加1键修改子程序CUM
;功能:根据时钟和闹钟修改标识位的状态,将时钟或闹钟对应RAM内容+1
;入口:SEC_FLAG,MIN_FLAG,HOUR_FLAG,RSECBIT,RMIN_FLAG,RHOUR_FLAG
;---------------------------------------------------------------
CUM:
JNB SEC_FLAG,CUM0 ;若时钟秒修改标识位为1则秒单元内
MOV A,SEC ;容加1
ADD A,#01H
DA A
MOV SEC,A
CJNE A,#60H,CUMEND
MOV SEC,#00H
LJMP CUMEND
CUM0:
JNB MIN_FLAG,CUM1 ;若时钟分修改标识位为1,则分单元
MOV A,MIN ;内容加1
ADD A,#01H
DA A
MOV MIN,A
CJNE A,#60H,CUMEND
MOV MIN,#00H
LJMP CUMEND
CUM1:
JNB HOUR_FLAG,CUM2 ;若时钟小时修改标识位为1,则小时
MOV A,HOUR ;单元内容加1
ADD A,#01H
DA A
MOV HOUR,A
CJNE A,#24H,CUMEND
MOV HOUR,#00H
LJMP CUMEND
CUM2:
JNB RMIN_FLAG,CUM3 ;若闹钟分修改标识位为1,则分单元
MOV A,RMIN ;内容加1
ADD A,#01H
DA A
MOV RMIN,A
CJNE A,#60H,CUMEND
MOV RMIN,#00H
LJMP CUMEND
CUM3:
JNB RHOUR_FLAG,CUMEND ;若闹钟小时修改标识位为1,则小
MOV A,RHOUR ;时单元内容加1
ADD A,#01H
DA A
MOV RHOUR,A
CJNE A,#24H,CUMEND
MOV RHOUR,#00H
CUMEND:
LCALL LED_DISP_DATA
RET

;--------------------------------------------------
;闹钟判断与启动子程序ALARM
;功能:判断闹钟是否设定,控制闹钟的启,停
;入口:MIN,RMIN,HOUR,RHOUR
;出口:HD_BP,ARM_FLAG
;--------------------------------------------------
ALARM:
MOV A,RMIN
CJNE A,MIN,DONT0 ;比较分单元内容,若相同则继续比较小时单
MOV A,RHOUR ;元内容,否则返回
CJNE A,HOUR,DONT0
CLR HD_CBP ;启动闹钟
SETB RTIM_FLAG ;设置闹钟计时标时,时钟开始10秒计时
DONT0:
MOV A,COUNT ;取闹钟保持计时时间
CJNE A,#10,DONT ;判断闹钟保持10秒时间到否
MOV COUNT,#00H ;清除闹钟保持10秒计时
SETB HD_CBP ;清除闹钟
CLR ARM_FLAG ;清闹钟标识,取消闹钟设置
CLR RTIM_FLAG ;清闹钟计时标识,
DONT:
RET
;--------------------------------------------------
;时钟修正中断服务子程序
;功能:通过定时器中断,自动修改时钟参数
;入口:MSEC1,MSEC2,,SEC,MIN,HOUR
;出口:MSEC1,MSEC2,,SEC,MIN,HOUR
;--------------------------------------------------
TIMER_INT:
CLR EA ;关中断
PUSH PSW ;保护现场
PUSH ACC
MOV PSW,#BANK3_REG
INC MSEC1
MOV A,MSEC1
CJNE A,#28H,TIMER_INT_EXIT ;到10毫秒否
MOV MSEC1,#00H
INC MSEC2
MOV A,MSEC2
CJNE A,#64H,TIMER_INT_EXIT ;到1秒否
MOV MSEC2,#00H
JNB RTIM_FLAG,TIMER_INT_A ;由标识位判别闹钟启动否
INC COUNT
TIMER_INT_A:
MOV A,SEC
ADD A,#01H ;时钟秒单元内容加1
DA A
MOV SEC,A
CJNE A,#60H,TIMER_INT_B ;到1分钟否
MOV SEC,#00H
MOV A,MIN
ADD A,#01H ;分单元内容加1
DA A
MOV MIN,A
CJNE A,#60H,TIMER_INT_B ;到1小时否
MOV MIN,#00H
MOV A,HOUR
ADD A,#01H ;小时单元内容加1
DA A
MOV HOUR,A
CJNE A,#24H,TIMER_INT_B ;到24小时否
MOV HOUR,#00H
TIMER_INT_B:
LCALL LED_DISP_DATA
TIMER_INT_EXIT:
POP ACC ;恢复现场
POP PSW
SETB EA ;开中断
RETI ;中断返回
;--------------------------------------------------
;测键入子程序
;功能:判断是否有键输入
;入口:按键
;出口:A
;--------------------------------------------------
KEY_TEST:
JNB P1.2,KEY_TEST_OK
JNB P1.3,KEY_TEST_OK
JNB P1.4,KEY_TEST_OK
CLR C
RET
KEY_TEST_OK:
SETB C
RET

;--------------------------------------------------
;键盘扫描程序
;--------------------------------------------------
KEY_SCAN:
CLR K0_FLAG
CLR K1_FLAG
CLR K2_FLAG

JNB P1.2,KEY_SCAN_K0
JNB P1.3,KEY_SCAN_K1
JNB P1.4,KEY_SCAN_K2
SJMP KEY_SCAN_END
KEY_SCAN_K0:
SETB K0_FLAG
JNB P1.2,$
SJMP KEY_SCAN_END
KEY_SCAN_K1:
SETB K1_FLAG
JNB P1.3,$
SJMP KEY_SCAN_END
KEY_SCAN_K2:
SETB K2_FLAG
JNB P1.4,$
SJMP KEY_SCAN_END
KEY_SCAN_END:
RET

;--------------------------------
;发送一字节数据
;入口:ACC
;--------------------------------
LED_DISP_BYTE:
PUSH ACC
CLR LED_SCL
MOV R7,#8
LED_DISP_BYTE1:
RLC A
MOV LED_SDA,C
NOP
NOP
SETB LED_SCL
NOP
NOP
CLR LED_SCL
DJNZ R7,LED_DISP_BYTE1
POP ACC
RET
;-----------------------------------
;发送LED_MAX_BIT字节
;入口:LED_DIS_PTR:起始地址
;-----------------------------------
LED_DISP_DATA:
PUSH PSW
PUSH ACC
PUSH DPH
PUSH DPL
MOV PSW,#BANK2_REG
MOV A,LED_DIS_PTR
ADD A,#LED_MAX_BITS/2-1
MOV R0,A
MOV R6,#3
MOV DPTR,#DIS_TAB
LED_DISP_DATA_A:
MOV A,@R0
ANL A,#0FH
MOVC A,@A+DPTR
CJNE R6,#3,LED_DISP_DATA_B ;是在显示秒吗
JNB SEC_FLAG,LED_DISP_DATA_D
ANL A,#07FH ;设置显示小数点指示操作位置
SJMP LED_DISP_DATA_D
LED_DISP_DATA_B:
CJNE R6,#2,LED_DISP_DATA_C ;是在显示分吗
ANL A,#07FH
JB MIN_FLAG,LED_DISP_DATA_D
JB RMIN_FLAG,LED_DISP_DATA_D
ORL A,#80H
SJMP LED_DISP_DATA_D
LED_DISP_DATA_C:
ANL A,#07FH
JB HOUR_FLAG,LED_DISP_DATA_D
JB RHOUR_FLAG,LED_DISP_DATA_D
ORL A,#80H
LED_DISP_DATA_D:
LCALL LED_DISP_BYTE
MOV A,@R0
SWAP A
ANL A,#0FH
MOVC A,@A+DPTR
LCALL LED_DISP_BYTE
DEC R0
DJNZ R6,LED_DISP_DATA_A
POP DPL
POP DPH
POP ACC
POP PSW
RET
;------------------------------------
;清除LED上的显示内容
;------------------------------------
LED_CLR:
PUSH PSW
PUSH ACC
PUSH DPH
PUSH DPL
MOV PSW,#BANK2_REG
MOV R6,#6
LED_CLR_A:
MOV A,#0FFH
LCALL LED_DISP_BYTE
DJNZ R6,LED_CLR_A
POP DPL
POP DPH
POP ACC
POP PSW
RET
;----------------------------------------------------------------------
DIS_TAB: ;字形表
DB 0C0H,0F9H,0A4H,0B0H,99H,92H,82H,0F8H,80H,90H,88H,83H,0C6H,0A1H,86H,8EH,0FFH ;共阳极LED
NOP9:
NOP
NOP
NOP
NOP
NOP
NOP
NOP
RET
;------------------------------------
;清除指定的RAM单元
;入口: R0:源地址R7:长度
;------------------------------------
PUB_CLEAR_RAM1:
CJNE R7,#0,PUB_CLEAR_RAM1_1
SJMP PUB_CLEAR_RAM1_E
PUB_CLEAR_RAM1_1:
MOV @R0,#0
INC R0
DJNZ R7,PUB_CLEAR_RAM1_1
PUB_CLEAR_RAM1_E:
RET
END

声明:你问我答网所有作品(图文、音视频)均由用户自行上传分享,仅供网友学习交流。若您的权利被侵害,请联系fangmu6661024@163.com