m0_73504569 2023-05-28 15:06 采纳率: 50%
浏览 54
已结题

倒计时汇编语言RTC实时时钟,使用汇编语言

基于51单片机,及其RTC实时时钟,设计一个可以实现倒计时功能的电子倒计时牌系统。
具体要求如下:
(1)可以用数码管显示倒计时的时分秒信息
(2)可以通过按键对倒计时设置初值;倒计时结束时可发出提示音或者用二极灯管指示。

  • 写回答

6条回答 默认 最新

  • qllaoda 2023-05-28 15:29
    关注
    获得1.95元问题酬金
    
    ; 定义端口和控制信号
    DIO_PORT   equ P1   ; 数码管段选控制端口
    DIO_CTRL   equ P2   ; 数码管位选控制端口
    DS1302_RST equ P3.7 ; DS1302复位信号
    DS1302_CLK equ P3.6 ; DS1302时钟信号
    DS1302_DAT equ P3.5 ; DS1302数据信号
    BUZZER     equ P0.0 ; 蜂鸣器信号
    LED        equ P0.1 ; 二极灯管信号
    BTN_SET    equ P0.2 ; 设置按键信号
    
    ; 定义数码管显示字符表
    SEG_TABLE  db 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f
    
    ; 定义计时变量
    hours      dw 0     ; 小时
    minutes    dw 0     ; 分钟
    seconds    dw 0     ; 秒钟
    
    ; 主程序入口
    MAIN:
        mov A, #0FFh  ; 设置A寄存器为全1,用于数码管清零
        mov DIO_CTRL, A  ; 数码管位选控制端口置1,关闭所有数码管
        mov DIO_PORT, A  ; 数码管段选控制端口置1,清空显示内容
        mov BUZZER, #0   ; 关闭蜂鸣器
        mov LED, #1      ; 关闭二极灯管
        mov BTN_SET, #1  ; 设置按键信号口为输入
        call DS1302_Init  ; 初始化DS1302时钟芯片
        call SetInitialTime  ; 设置初始时间
    
    COUNTDOWN_LOOP:
        call DS1302_ReadTime  ; 读取当前时间
        call DisplayTime  ; 显示当前时间
        call CheckButton  ; 检查设置按键是否按下
        call Countdown  ; 倒计时处理
        sjmp COUNTDOWN_LOOP
    
    ; DS1302时钟芯片初始化
    DS1302_Init:
        mov DS1302_RST, #0  ; 拉低DS1302复位信号
        acall DelayShort  ; 延时一段时间
        mov DS1302_RST, #1  ; 拉高DS1302复位信号
        acall DelayShort  ; 延时一段时间
        ret
    
    ; 设置初始时间
    SetInitialTime:
        acall DisplayTime  ; 显示当前时间
        acall WaitForButtonPress  ; 等待设置按键按下
        acall DelayShort  ; 延时一段时间,防止按键抖动
        acall ReadButton  ; 读取设置按键状态
        cjne A, #0, SetHours  ; 如果按键按下,则设置小时
        acall WaitForButtonRelease  ; 等待设置按键释放
        acall DelayShort  ; 延时一段时间,防止按键抖动
        acall ReadButton  ; 读取设置按键状态
        cjne A, #0, SetMinutes  ; 如果按键按下,则设置分钟
        acall WaitForButtonRelease  ; 等待设置按键释放
        acall DelayShort  ; 延时一段时间,防止按键抖动
        acall ReadButton  ; 读取设置按键状态
        cjne A, #0, SetSeconds  ; 如果按键按下,则设置秒钟
        ret
    
    SetHours:
        acall WaitForButtonRelease  ; 等待设置按键释放
        acall DelayShort  ; 延时一段时间,防止按键抖动
        acall ReadButton  ; 读取设置按键状态
        inc hours  ; 小时加1
        cjne A, #0, SetHours  ; 如果按键按下,则继续增加小时
        ret
    
    SetMinutes:
        acall WaitForButtonRelease  ; 等待设置按键释放
        acall DelayShort  ; 延时一段时间,防止按键抖动
        acall ReadButton  ; 读取设置按键状态
        inc minutes  ; 分钟加1
        cjne A, #0, SetMinutes  ; 如果按键按下,则继续增加分钟
        ret
    
    SetSeconds:
        acall WaitForButtonRelease  ; 等待设置按键释放
        acall DelayShort  ; 延时一段时间,防止按键抖动
        acall ReadButton  ; 读取设置按键状态
        inc seconds  ; 秒钟加1
        cjne A, #0, SetSeconds  ; 如果按键按下,则继续增加秒钟
        ret
    
    ; 显示当前时间
    DisplayTime:
        mov A, DIO_CTRL  ; 保存数码管位选控制端口状态
        push A  ; 将数码管位选控制端口状态保存到栈中
        mov DIO_CTRL, #0FFh  ; 数码管位选控制端口置1,关闭所有数码管
        mov A, DIO_PORT  ; 保存数码管段选控制端口状态
        push A  ; 将数码管段选控制端口状态保存到栈中
    
        ; 显示小时
        mov A, hours
        mov R7, #2  ; 循环计数器
        mov R6, #10  ; 循环次数
    DISPLAY_HOURS:
        mov R0, #0
        mov R1, A
        div AB, R6
        mov A, B
        add A, #48  ; 转换为ASCII码
        mov DIO_PORT, A
        acall DelayShort  ; 延时一段时间
        mov A, R1
        mov R1, B
        cjne R7, #0, DISPLAY_HOURS  ; 循环显示小时的十位和个位
        mov A, #0  ; 显示冒号
        mov DIO_PORT, A
        acall DelayShort  ; 延时一段时间
    
        ; 显示分钟
        mov A, minutes
        mov R7, #2  ; 循环计数器
        mov R6, #10  ; 循环次数
    DISPLAY_MINUTES:
        mov R0, #0
        mov R1, A
        div AB, R6
        mov A, B
        add A, #48  ; 转换为ASCII码
        mov DIO_PORT, A
        acall DelayShort  ; 延时一段时间
        mov A, R1
        mov R1, B
        cjne R7, #0, DISPLAY_MINUTES  ; 循环显示分钟的十位和个位
        mov A, #0  ; 显示冒号
        mov DIO_PORT, A
        acall DelayShort  ; 延时一段时间
    
        ; 显示秒钟
        mov A, seconds
        mov R7, #2  ; 循环计数器
        mov R6, #10  ; 循环次数
    DISPLAY_SECONDS:
        mov R0, #0
        mov R1, A
        div AB, R6
        mov A, B
        add A, #48  ; 转换为ASCII码
        mov DIO_PORT, A
        acall DelayShort  ; 延时一段时间
        mov A, R1
        mov R1, B
        cjne R7, #0, DISPLAY_SECONDS  ; 循环显示秒钟的十位和个位
    
        pop A  ; 恢复数码管段选控制端口状态
        mov DIO_PORT, A  ; 恢复数码管段选控制端口状态
        acall DelayShort  ; 延时一段时间
        pop A  ; 恢复数码管位选控制端口状态
        mov DIO_CTRL, A  ; 恢复数码管位选控制端口状态
        acall DelayShort  ; 延时一段时间
        ret
    
    ; 检查设置按键是否按下
    CheckButton:
        acall ReadButton  ; 读取设置按键状态
        cjne A, #0, Exit  ; 如果按键按下,则跳出循环
        ret
    
    Exit:
        ret
    
    ; 倒计时处理
    Countdown:
        mov A, seconds
        orl A, minutes
        orl A, hours
        jz CountdownEnd  ; 如果时间为0,则倒计时结束
    
        ; 减少一秒钟
        dec seconds
        cjne seconds, #0FFh, CountdownCheckMin  ; 如果秒钟不为0xFF,则跳过减少分钟的步骤
        dec minutes  ; 秒钟减少到0后,减少一分钟
    CountdownCheckMin:
        cjne minutes, #0FFh, CountdownCheckHour  ; 如果分钟不为0xFF,则跳过减少小时的步骤
        dec hours  ; 分钟减少到0后,减少一小时
    CountdownCheckHour:
        ret
    
    CountdownEnd:
        acall Beep  ; 发出提示音
        acall BlinkLED  ; 闪烁二极灯管
        ret
    
    ; 延时一段时间
    DelayShort:
        ; 在此处填入延时代码
        ret
    
    ; 读取设置按键状态
    ReadButton:
        ; 在此处填入读取按键状态代码
        ret
    
    ; 等待设置按键按下
    WaitForButtonPress:
        ; 在此处填入等待按键按下代码
        ret
    
    ; 等待设置按键释放
    WaitForButtonRelease:
        ; 在此处填入等待按键释放代码
        ret
    
    ; 发出提示音
    Beep:
        ; 在此处填入发出提示音代码
        ret
    
    ; 闪烁二极灯管
    BlinkLED:
        ; 在此处填入闪烁二极灯管代码
        ret
    
    ; DS1302时钟芯片读取当前时间
    DS1302_ReadTime:
        ; 在此处填入读取当前时间代码
        ret
    
    
    评论
  • 热爱编程的小K C/C++领域新星创作者 2023-05-28 16:50
    关注
    获得2.25元问题酬金

    下面是一个使用汇编语言编写的基于51单片机的倒计时电子牌系统的示例代码。这个代码使用了DS1302实时时钟模块来实现倒计时功能,并通过数码管显示剩余的时分秒信息。同时,按键可以用于设置倒计时的初始值,倒计时结束时会通过蜂鸣器发出提示音。

    ; 倒计时电子牌系统
    ; 使用51单片机和DS1302实时时钟模块
    ; 数码管显示倒计时的时分秒信息
    ; 按键设置倒计时初值,倒计时结束时发出提示音或使用二极管指示
    
    ; 定义I/O端口
    DSEG    AT  0
    LEDDATA DB  0x0F ; 用于控制数码管显示的数据端口
    KEYDATA DB  0xFF ; 用于读取按键输入的数据端口
    BUZZER  DB  0xFE ; 用于控制蜂鸣器的数据端口
    LED     DB  0xFD ; 用于控制指示二极管的数据端口
    
    ; 定义常量
    TM_SECOND   EQU 0x00 ; DS1302的秒寄存器地址
    TM_MINUTE   EQU 0x01 ; DS1302的分寄存器地址
    TM_HOUR     EQU 0x02 ; DS1302的时寄存器地址
    
    ; 定义变量
    COUNT_DOWN  DS  3 ; 倒计时剩余的时分秒信息
    SET_FLAG    DS  1 ; 按键设置倒计时初值的标志
    BEEP_FLAG   DS  1 ; 发出提示音的标志
    
    ; 初始化DS1302
    INIT_DS1302:
        MOV     P1, #0x00 ; 将P1端口用于DS1302的数据传输
        MOV     P2, #0x01 ; 将P2.0端口用于DS1302的时钟信号
        MOV     P3, #0x02 ; 将P3.1端口用于DS1302的复位信号
        MOV     A, #0x8E  ; 写入DS1302的控制命令,打开写保护
        ACALL   DS1302_WRITE
        MOV     A, #0x90  ; 写入DS1302的控制命令,关闭写保护并启用时钟
        ACALL   DS1302_WRITE
        RET
    
    ; 从DS1302读取时间
    READ_TIME:
        MOV     A, #TM_SECOND ; 要读取的寄存器地址
        ACALL   DS1302_READ
        MOV     COUNT_DOWN, A ; 保存秒数
        MOV     A, #TM_MINUTE ; 要读取的寄存器地址
        ACALL   DS1302_READ
        MOV     COUNT_DOWN+1, A ; 保存分钟
        MOV     A, #TM_HOUR ; 要读取的寄存器地址
        ACALL   DS1302_READ
        MOV
    
         COUNT_DOWN+2, A ; 保存小时
        RET
    
    ; 向DS1302写入时间
    WRITE_TIME:
        MOV     A, #TM_SECOND ; 要写入的寄存器地址
        MOV     A, COUNT_DOWN ; 秒数
        ACALL   DS1302_WRITE
        MOV     A, #TM_MINUTE ; 要写入的寄存器地址
        MOV     A, COUNT_DOWN+1 ; 分钟
        ACALL   DS1302_WRITE
        MOV     A, #TM_HOUR ; 要写入的寄存器地址
        MOV     A, COUNT_DOWN+2 ; 小时
        ACALL   DS1302_WRITE
        RET
    
    ; DS1302读取操作
    DS1302_READ:
        MOV     P1, A ; 将要读取的寄存器地址写入P1
        MOV     P3.1, #0 ; 复位信号置低
        NOP
        NOP
        MOV     P3.1, #1 ; 复位信号置高
        MOV     R0, #0 ; 初始化计数器
        MOV     A, P1 ; 读取数据
        ACALL   DS1302_DELAY ; 延时
        NOP
        MOV     C, P1.7 ; 读取最高位标志位
        RRC     A ; 右移一位
        MOV     C, P1.7 ; 读取最高位标志位
        RLC     A ; 左移一位,还原最高位
        INC     R0 ; 计数器加1
        CJNE    R0, #8, DS1302_READ ; 循环读取8位数据
        RET
    
    ; DS1302写入操作
    DS1302_WRITE:
        MOV     P1, A ; 将要写入的数据写入P1
        MOV     P3.1, #0 ; 复位信号置低
        NOP
        NOP
        MOV     P3.1, #1 ; 复位信号置高
        MOV     R0, #0 ; 初始化计数器
        MOV     A, P1 ; 写入数据
        ACALL   DS1302_DELAY ; 延时
        NOP
        SETB    P1.7 ; 设置最高位标志位
        RLC     A ; 左移一位,最高位置0
        MOV     C, P1.7 ; 读取最高位标志位
        RRC     A ; 右移一位,还原最高位
        INC     R0 ; 计数器加1
        CJNE    R0, #8, DS1302_WRITE ; 循环写入8位数据
        RET
    
    ; DS1302读写延时
    DS1302_DELAY:
        MOV     R1, #10 ; 设置延时计数
        DJNZ    R1, $ ; 延时
        RET
    
    ; 7段数码管显示
    DISPLAY:
        MOV     A, COUNT_DOWN ; 获取秒数
        ACALL   DISPLAY_DIGIT ; 显示个位数
        MOV     A, COUNT_DOWN+1 ; 获取分钟
        ACALL   DISPLAY_DIGIT ; 显示十位数
        MOV     A, COUNT_DOWN+2 ; 获取小时
        ACALL   DISPLAY_DIGIT ; 显示
    
    百位数
        RET
    
    ; 数码管显示单个数位
    DISPLAY_DIGIT:
        MOV     LEDDATA, A ; 将数值写入数码管显示端口
        ACALL   DELAY ; 延时
        MOV     LEDDATA, #0x00 ; 关闭数码管
        ACALL   DELAY ; 延时
        RET
    
    ; 延时函数
    DELAY:
        MOV     R2, #0xFF ; 设置延时计数
    DELAY_LOOP:
        DJNZ    R2, DELAY_LOOP ; 延时
        RET
    
    ; 按键检测
    CHECK_KEY:
        MOV     A, KEYDATA ; 读取按键输入
        CJNE    A, #0xFF, KEY_PRESSED ; 判断是否有按键按下
        RET
    
    ; 按键按下处理
    KEY_PRESSED:
        MOV     SET_FLAG, #1 ; 设置倒计时初值的标志置位
        RET
    
    ; 发出提示音
    BEEP:
        MOV     BUZZER, #0x01 ; 发出蜂鸣器信号
        ACALL   DELAY ; 延时
        MOV     BUZZER, #0x00 ; 停止蜂鸣器
        ACALL   DELAY ; 延时
        RET
    
    ; 倒计时功能
    COUNT_DOWN_FUNC:
        MOV     SET_FLAG, #0 ; 清除设置倒计时初值的标志
        MOV     BEEP_FLAG, #0 ; 清除发出提示音的标志
    COUNT_DOWN_LOOP:
        CALL    READ_TIME ; 读取当前时间
        CALL    DISPLAY ; 显示剩余时间
        CALL    CHECK_KEY ; 检测按键
        JZ      COUNT_DOWN_LOOP ; 如果没有按键按下,继续倒计时
        CJNE    SET_FLAG, #1, COUNT_DOWN_LOOP ; 如果设置倒计时初值的标志不为1,继续倒计时
        CALL    SET_COUNT_DOWN ; 设置倒计时初值
        JMP     COUNT_DOWN_LOOP ; 继续倒计时
    
    ; 设置倒计时初值
    SET_COUNT_DOWN:
        MOV     A, #0x00 ; 清零
        MOV     COUNT_DOWN, A ; 秒数
        MOV     COUNT_DOWN+1, A ; 分钟
        MOV     COUNT_DOWN+2, A ; 小时
    SET_COUNT_DOWN_LOOP:
        CALL    DISPLAY ; 显示设置的初值
        CALL    CHECK_KEY ; 检测按键
        JZ      SET_COUNT_DOWN_LOOP ; 如果没有按键按下,继续设置
        CJNE    SET_FLAG, #0, SET_COUNT_DOWN_LOOP ; 如果设置倒计时初值的标志不为0,继续设置
        CALL    WRITE_TIME ; 写入设置的初值
        RET
    
    ; 主程序入口
    MAIN:
        ACALL   INIT_DS1302 ; 初始化DS1302
        ACALL   COUNT_DOWN_FUNC ; 开始倒计时功能
        JMP     MAIN ; 循环执行
    
    END
    

    请注意,以上代码仅为示例,实际使用时需要根据具体的硬件电路和单片机的引脚分配进行适

    当的修改。此外,需要确保正确连接DS1302实时时钟模块、数码管、按键、蜂鸣器和二极管,并在代码中使用正确的I/O端口进行控制。

    评论
  • 鱼弦 全栈领域创作新星创作者 2023-05-29 10:36
    关注
    获得1.05元问题酬金

    以下是基于51单片机和RTC实时时钟的倒计时电子钟系统的汇编语言实现,使用了4位共阳数码管进行显示,其中,P0.0-P0.3用于控制数码管的位选,P2.0-P2.7用于控制数码管的段选,P3.2-P3.3用于接收按键输入,P3.4用于发出提示音,P3.5用于控制二极管显示。

    
    ; 定义常数
    CountDownMin equ 10 ; 初值为10分钟
    CountDownSec equ CountDownMin * 60 ; 初值转换为秒数
    DelayTime equ 50 ; 延时时间
    
    ; 定义端口地址
    DataPort equ P2
    SelectPort equ P0
    
    ; 定义按键和二极管的端口地址
    KeyPort equ P3
    BuzzerPort equ P3.4
    LEDPort equ P3.5
    
    ; 定义数码管显示表
    DisplayTable: db 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x以下是基于51单片机和RTC实时时钟的倒计时电子钟系统的汇编语言实现,使用了4位共阳数码管进行显示,其中,P0.0-P0.3用于控制数码管的位选,P2.0-P2.7用于控制数码管的段选,P3.2-P3.3用于接收按键输入,P3.4用于发出提示音,P3.5用于控制二极管显示。
    
    ```assembly
    ; 定义常数
    CountDownMin equ 10 ; 初值为10分钟
    CountDownSec equ CountDownMin * 60 ; 初值转换为秒数
    DelayTime equ 50 ; 延时时间
    
    ; 定义端口地址
    DataPort equ P2
    SelectPort equ P0
    
    ; 定义按键和二极管的端口地址
    KeyPort equ P3
    BuzzerPort equ P3.4
    LEDPort equ P3.5
    
    ; 定义数码管显示表
    DisplayTable: db 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x以下是基于51单片机和RTC实时时钟的倒计时电子钟系统的汇编语言实现,使用了4位共阳数码管进行显示,其中,P0.0-P0.3用于控制数码管的位选,P2.0-P2.7用于控制数码管的段选,P3.2-P3.3用于接收按键输入,P3.4用于发出提示音,P3.5用于控制二极管显示。
    
    ```assembly
    ; 定义常数
    CountDownMin equ 10 ; 初值为10分钟
    CountDownSec equ CountDownMin * 60 ; 初值转换为秒数
    DelayTime equ 50 ; 延时时间
    
    ; 定义端口地址
    DataPort equ P2
    SelectPort equ P0
    
    ; 定义按键和二极管的端口地址
    KeyPort equ P3
    BuzzerPort equ P3.4
    LEDPort equ P3.5
    
    ; 定义数码管显示表
    DisplayTable: db 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x以下是基于51单片机和RTC实时时钟的倒计时电子钟系统的汇编语言实现,使用了4位共阳数码管进行显示,其中,P0.0-P0.3用于控制数码管的位选,P2.0-P2.7用于控制数码管的段选,P3.2-P3.3用于接收按键输入,P3.4用于发出提示音,P3.5用于控制二极管显示。
    
    ```assembly
    ; 定义常数
    CountDownMin equ 10 ; 初值为10分钟
    CountDownSec equ CountDownMin * 60 ; 初值转换为秒数
    DelayTime equ 50 ; 延时时间
    
    ; 定义端口地址
    DataPort equ P2
    SelectPort equ P0
    
    ; 定义按键和二极管的端口地址
    KeyPort equ P3
    BuzzerPort equ P3.4
    LEDPort equ P3.5
    
    ; 定义数码管显示表
    DisplayTable: db 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x80 ; 显示0-7的数字
    
    ; 定义变量
    CountDownValue dw CountDownSec ; 倒计时初值,单位为秒
    CurrentCountDownValue dw ? ; 当前倒计时值
    IsCountingDown bit ? ; 是否正在倒计时
    
    ; 定义子程序
    ; 数码管显示子程序
    DisplayDigit: ; 参数:DL-要显示的数字
        mov DataPort, DL ; 将要显示的数字送入数据口
        mov SelectPort, #0x01 ; 第一位数码管选通
        acall Delay ; 延时
        mov SelectPort, #0x02 ; 第二位数码管选通
        acall Delay ; 延时
        mov SelectPort, #0x04 ; 第三位数码管选通
        acall Delay ; 延时
        mov SelectPort, #0x08 ; 第四位数码管选通
        acall Delay ; 延时
        ret
    
    ; 延时子程序
    Delay: ; 无参数
        mov R7, #DelayTime ; 将延时时间送入R7
        Delay1: ; 延时循环
            djnz R7, Delay1 ; 循环延时
            ret
    
    ; RTC由于没有具体的RTC模块的型号和接口信息,因此无法提供完整的RTC模块的代码实现。以下是基于假设的RTC模块接口实现的部分代码,需要根据实际的RTC模块接口进行修改。
    
    ; RTC读取子程序
    ReadRTC: ; 无参数
        ; 假设RTC模块的接口为I2C
        ; 具体的I2C读取操作需要根据实际情况进行修改
        ; 假设读取的RTC数据保存在R0中
        ret
    
    ; 主程序
    Main:
        ; 初始化
        mov IsCountingDown, #0 ; 清零计数标志
        mov CurrentCountDownValue, #0 ; 清零当前倒计时值
        mov BuzzerPort, #0 ; 关闭提示音
        mov LEDPort, #0 ; 关闭二极管显示
    
        ; 设置倒计时初值
        acall SetCountDownValue
    
        MainLoop:
            ; 读取RTC数据
            acall ReadRTC
    
            ; 更新倒计时值
            acall UpdateCountDownValue
    
            ; 显示倒计时值
            acall DisplayCountDownValue
    
            ; 判断是否倒计时结束
            cjne CurrentCountDownValue, #0, NotFinished ; 倒计时未结束,跳转到NotFinished标记
            mov IsCountingDown, #0 ; 倒计时结束,清零计数标志
            mov BuzzerPort, #1 ; 发出提示音
            mov LEDPort, #1 ; 显示二极管
    
            NotFinished:
            ; 处理按键输入
            acall CheckKeyInput
    
            ; 循环执行
            sjmp MainLoop
    
        ; 结束程序
        end
    
    ; 设置倒计时初值子程序
    SetCountDownValue:
        ; 显示当前倒计时初值
        mov A, CountDownMin ; 将初值转换为十进制
        acall DisplayDigit ; 显示分钟数
        mov A, #':'
        acall DisplayDigit ; 显示冒号
        mov A, #0 ; 显示秒数的十位
        acall DisplayDigit ; 显示秒数的十位
    mov A, #0 ; 显示秒数的个位
    acall DisplayDigit ; 显示秒数的个位
    
    mipsasm
    Copy
    ; 等待按键输入
    WaitForKey:
        jb KeyPort.2, WaitForKey ; 等待按键按下
        mov A, KeyPort ; 读取按键值
        anl A, #0x0C ; 只保留第3和第2位
        jz WaitForKey ; 如果按下的不是第3或第2个按键,则继续等待
        cjne A, #0x04, SetMin ; 如果按下的是第3个按键,则跳转到SetMin标记
        cjne A, #0x08, SetSec ; 如果按下的是第2个按键,则跳转到SetSec标记
    
    ; 设置分钟数
    SetMin:
        mov A, CountDownMin ; 将初值转换为十进制
        acall DisplayDigit ; 显示分钟数
        mov A, #':'
        acall DisplayDigit ; 显示冒号
        mov A, #0 ; 显示秒数的十位
        acall DisplayDigit ; 显示秒数的十位
        mov A, #0 ; 显示秒数的个位
        acall DisplayDigit; 等待按键输入
    WaitForKey:
        jb KeyPort.2, WaitForKey ; 等待按键按下
        mov A, KeyPort ; 读取按键值
        anl A, #0x0C ; 只保留第3和第2位
        jz WaitForKey ; 如果按下的不是第3或第2个按键,则继续等待
        cjne A, #0x04, SetMin ; 如果按下的是第3个按键,则跳转到SetMin标记
        cjne A, #0x08, SetSec ; 如果按下的是第2个按键,则跳转到SetSec标记
    
    ; 设置分钟数
    SetMin:
        mov A, CountDownMin ; 将初值转换为十进制
        acall DisplayDigit ; 显示分钟数
        mov A, #':'
        acall DisplayDigit ; 显示冒号
        mov A, #0 ; 显示秒数的十位
        acall DisplayDigit ; 显示秒数的十位
        mov A, #0 ; 显示秒数的个位
        acall DisplayDigit
        ; 等待按键输入
        WaitForRelease:
            jnb KeyPort.2, WaitForRelease ; 等待按键释放
        acall Delay ; 延时
    
        ; 设置秒数
        SetSec:
            mov A, CurrentCountDownValue ; 将当前倒计时值转换为十进制
            div AB, #60 ; 将秒数转换为十进制
            mov A, B ; 取出十位数字
            acall DisplayDigit ; 显示秒数的十位
            mov A, #':'
            acall DisplayDigit ; 显示冒号
            mov A, AmodB ; 取出个位数字
            acall DisplayDigit ; 显示秒数的个位
    
            ; 等待按键输入
            WaitForKey2:
                jb KeyPort.2, WaitForKey2 ; 等待按键按下
                mov A, KeyPort ; 读取按键值
                anl A, #0x0C ; 只保留第3和第2位
                jz WaitForKey2 ; 如果按下的不是第3或第2个按键,则继续等待
                cjne A, #0x04, SetMin ; 如果按下的是第3个按键,则跳转到SetMin标记
                cjne A, #0x08, SetSec ; 如果按下的是第2个按键,则继续设置秒数
    
            ; 更新倒计时初值
            mov A, B ; 取出十位数字
            mov B, AmodB ; 取出个位数字
            mul AB, #60 ; 将十位数字乘以60
            add A, B ; 加上个位数字
            mov CountDownValue, A ; 将更新后的初值存入CountDownValue变量
            mov CurrentCountDownValue, A ; 将更新后的初值存入CurrentCountDownValue变量
            ret
    ; 更新倒计时值子程序
    UpdateCountDownValue:
    ; 如果正在倒计时,则减去1秒
    jb IsCountingDown, NotCountingDown ; 如果没有在倒计时,则跳转到NotCountingDown标记
    dec CurrentCountDownValue ; 减去1秒
    NotCountingDown:
    ret
    
    ; 显示倒计时值子程序
    DisplayCountDownValue:
    ; 将当前倒计时值转换为十进制
    mov A, CurrentCountDownValue
    div AB, #60 ; 将秒数转换为十进制
    mov R7, A ; 保存十位数字
    mov A, B ; 取出十位数字
    acall DisplayDigit ; 显示秒数的十位
    mov A, #':'
    acall DisplayDigit ; 显示冒号
    mov A, AmodB ; 取出个位数字
    acall DisplayDigit ; 显示秒数的个位
    ret
    
    ; 显示数字子程序
    DisplayDigit:
    ; 将数字转换为7段LED的编码
    anl A, #0x0F ; 只保留低4位
    mov R6, #0xFF ; 设置默认值为全灭
    cjne A, #0, CheckOne ; 如果是0以外的数字,则跳转到CheckOne标记
    mov R6, #0xC0 ; 如果是0,则设置为0的编码
    sjmp DisplayLEDs ; 跳转到DisplayLEDs标记
    CheckOne:
    cjne A, #1, CheckTwo ; 如果是1以外的数字,则跳转到CheckTwo标记
    mov R6, #0xF9 ; 如果是1,则设置为1的编码
    sjmp DisplayLEDs ; 跳转到DisplayLEDs标记
    CheckTwo:
    cjne A, #2, CheckThree ; 如果是2以外的数字,则跳转到CheckThree标记
    mov R6, #0xA4 ; 如果是2,则设置为2的编码
    sjmp DisplayLEDs ; 跳转到DisplayLEDs标记
    CheckThree:
    cjne A, #3, CheckFour ; 如果是3以外的数字,则跳转到CheckFour标记
    mov R6, #0xB0 ; 如果是3,则设置为3的编码
    sjmp DisplayLEDs ; 跳转到DisplayLEDs标记
    CheckFour:
    cjne A, #4, CheckFive ; 如果是4以外的数字,则跳转到CheckFive标记
    mov R6, #0x99 ; 如果是4,则设置为4的编码
    sjmp DisplayLEDs ; 跳转到DisplayLEDs标记
    CheckFive:
    cjne A, #5, CheckSix ; 如果是5以外的数字,则跳转到CheckSix标记
    mov R6, #0x92 ; 如果是5,则设置为5的编码
    sjmp DisplayLEDs ; 跳转到DisplayLEDs标记
    CheckSix:
    cjne A, #6, CheckSeven ; 如果是6以外的数字,则跳转到CheckSeven标记
    mov R6, #0x82 ; 如果是6,则设置为6的编码
    sjmp DisplayLEDs ; 跳转到DisplayLEDs标记
    CheckSeven:
    cjne A, #7, CheckEight ; 如果是7以外的数字,则跳转到CheckEight标记
    mov R6, #0xF8 ; 如果是7,则设置为7的编码
    sjmp DisplayLEDs ; 跳转到DisplayLEDs标记
    CheckEight:
    cjne A, #8, CheckNine ; 如果是8以外的数字,则跳转到CheckNine标记
    mov R6, #0x80 ; 如果是8,则设置为8的编码
    sjmp DisplayLEDs ; 跳转到DisplayLEDs标记
    CheckNine:
    mov R6, #0x90 ; 如果是9,则设置为9的编码
    ; 显示数字
    DisplayLEDs:
    mov P1, R6 ; 将编码输出到7段LED
    acall Delay ; 延时
    mov P1, #0xFF ; 关闭7段LED
    acall Delay ; 延时
    
    
    评论
  • 还有头发的程序员- 2023-05-30 11:31
    关注
    获得0.30元问题酬金
    
    
    #define ds1302_sec_add          0x80        
    #define ds1302_min_add          0x82        
    #define ds1302_hr_add           0x84        
    #define ds1302_date_add         0x86        
    #define ds1302_month_add        0x88        
    #define ds1302_day_add          0x8a        
    #define ds1302_year_add         0x8c        
    #define ds1302_control_add      0x8e        
    #define ds1302_charger_add      0x90                     
    #define ds1302_clkburst_add     0xbe
    
    sbit SCK = P2^2;
    sbit IO = P2^3;
    sbit RST = P2^4;
    
    void ds1302_write_byte(unsigned char addr, unsigned char byte)
    {
          unsigned char i;
          addr = addr & 0xfe;
          SCK = 0;
          RST = 0;
    
          RST = 1;
          for(i = 0; i < 8; i++)
          {
                   IO = addr & 0x01;
                  SCK = 0;
                  SCK = 1;
                  addr >>= 1;
           }
          for(i = 0; i < 8; i++)
          {
                   IO = byte & 0x01;
                  SCK = 0;
                  SCK = 1;
                  byte >>= 1;
          }
    }
    
    unsigned char ds1302_read_byte(unsigned char addr)
    {
          unsigned char i;
          unsigned char temp = 0;
          addr = addr & 0xfe;
          SCK = 0;
          RST = 0;
    
          RST = 1;
          addr =addr + 1;
          for(i = 0; i < 8; i++)
          {
                   IO = addr & 0x01;
                  SCK = 0;
                  SCK = 1;
                  addr >>= 1;
           }
           for(i = 0; i < 8; i++)
           {
                  SCK = 1;
                  SCK = 0;
                  temp >>= 1;
                  if(IO)
                  {
                      temp += 0x80;
                  }
            }
            RST = 0;
            return temp;
    }
    void ds1302_write_time()
    {
          unsigned char temp;
          unsigned char temp1;
          unsigned char i;
          for(i = 0; i < 7; i++)
          {
                  temp = timebuf[i]/10;
                  temp1 = timebuf[i]%10;
                  disbuf[i] = (temp << 4) | temp1;
          }
        ds1302_write_byte(ds1302_control_add, 0x00);
        ds1302_write_byte(ds1302_hr_add, disbuf[0]);
        ds1302_write_byte(ds1302_min_add, disbuf[1]);
        ds1302_write_byte(ds1302_sec_add, disbuf[2]);
        ds1302_write_byte(ds1302_year_add, disbuf[3]);
        ds1302_write_byte(ds1302_month_add, disbuf[4]);
        ds1302_write_byte(ds1302_date_add, disbuf[5]);
        ds1302_write_byte(ds1302_day_add, disbuf[6]);
        ds1302_write_byte(ds1302_control_add, 0x80);
    }
    void ds1302_read_time()
    {
        unsigned char temp;
        unsigned char temp1;
        unsigned char i;
        readbuf[0] = ds1302_read_byte(ds1302_hr_add);
        readbuf[1] = ds1302_read_byte(ds1302_min_add);
        readbuf[2] = ds1302_read_byte(ds1302_sec_add);
        readbuf[3] = ds1302_read_byte(ds1302_year_add);
        readbuf[4] = ds1302_read_byte(ds1302_month_add);
        readbuf[5] = ds1302_read_byte(ds1302_date_add);
        readbuf[6] = ds1302_read_byte(ds1302_day_add);
    
        for(i = 0; i < 7; i++)
        {
            temp = readbuf[i]>>4;
            temp1 = readbuf[i]&0x0f;
            disbuf[i] = temp*10+temp1;
        }
    }
    
    
    
    评论
  • GIS工具开发 2023-06-03 11:19
    关注
    获得1.50元问题酬金

    下面是示例代码,可以参考一下

    ;---------------------51单片机及RTC实时时钟倒计时系统---------------------
    
    ;---------------------数据定义---------------------
    ;定时器常数值
    TH0 equ 4ch
    TL0 equ 4dh
    ;RTC寄存器地址
    RTC_Addr equ 30h
    ;数码管的控制信号
    DIG1 equ P2.0
    DIG2 equ P2.1
    DIG3 equ P2.2
    DIG4 equ P2.3
    ;数码管的显示数据
    digit_num equ 4
    number_table:     db 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f
    ;初始倒计时时间(20秒)
    timebase equ 20
    ;按键控制
    KEY1 equ P3.1
    
    ;---------------------程序代码---------------------
    ;中断服务程序
    Timer0_ISR:         ;定时器0中断服务程序
        push    ACC
        push    PSW
        mov     RTC_Addr,#0ch
        inc     @RTC_Addr
        cjne    @RTC_Addr,#0x60,SECOND_EXIT   ;累加秒计数
        mov     @RTC_Addr,#0               ;清零秒计数
        mov     RTC_Addr,#0dh              ;取出分钟寄存器地址
        inc     @RTC_Addr
        cjne    @RTC_Addr,#0x60,MINUTE_EXIT   ;累加分计数
        mov     @RTC_Addr,#0               ;清零分计数
        mov     RTC_Addr,#0eh              ;取出小时寄存器地址
        inc     @RTC_Addr
        cjne    @RTC_Addr,#0x24,HOUR_EXIT   ;累加时计数
        mov     @RTC_Addr,#0               ;清零时计数
    HOUR_EXIT:
    MINUTE_EXIT:
    SECOND_EXIT:
        pop     PSW
        pop     ACC
        reti
    
    ;子程序:延时1ms
    Delay1ms:           ;在12MHz下,定时器0计数65536次为1秒,所以6553次为1ms
        push    ACC
        push    P0
        push    P1
        push    PSW         
        mov     TMOD,#1h         ;定时器0,模式1
        mov     TH0,#0f9h       ;定时1ms
        mov     TL0,#0h
        setb    TR0             ;定时器0开始计时
    DELAY:  
        jnb     TF0,$          ;等待1ms
        clr     TF0             ;清除定时器0中断标志位
        djnz    R6,$           ;再次计数
        clr     TR0             ;时钟停止
        pop     PSW
        pop     P1
        pop     P0
        pop     ACC
        ret
    
    ;子程序:LED指示灯亮
    LED_ON:             ;LED指示灯亮
        setb    P3.2
        ret
        
    ;子程序:LED指示灯灭
    LED_OFF:            ;LED指示灯灭
        clr     P3.2
        ret
    
    ;主程序
    MAIN:
        mov     R7,#digit_num-1  ;从右往左扫描数码管
    
        INIT:
            ;初始化定时器0
            mov     R6,#5           ;延时5ms用于给数码管稳定时间
            mov     TMOD,#1h        ;定时器0,模式1
            mov     TH0,#0f9h      ;定时1ms
            mov     TL0,#0h
            setb    TR0             ;定时器0开始计时
            init_ds1302:
                ;初始化DS1302
                mov     RTC_Addr,#8ch   ;写入控制命令字,禁止写保护
                mov     ACC,#0x80
                movx    @DPTR,ACC
                mov     RTC_Addr,#0cch  ;写入年月日寄存器地址,禁止写保护
                mov     ACC,#20h       ;年
                movx    @DPTR,ACC
                mov     RTC_Addr,#0dch  ;写入星期寄存器地址,禁止写保护
                mov     ACC,#06h       ;星期六
                movx    @DPTR,ACC
                mov     RTC_Addr,#0ach  ;写入时分秒寄存器地址,禁止写保护
                mov     ACC,#0         ;秒
                movx    @DPTR,ACC
                mov     ACC,#0         ;分
                movx    @DPTR,ACC
                mov     ACC,#0         ;小时
                movx    @DPTR,ACC
                ;读取RTC时间
                mov     RTC_Addr,#81h   ;启动DS1302读取时钟寄存器数据
                mov     ACC,#0         ;全选
                movx    @DPTR,ACC
        ;主循环
        LOOP:
            ;读取按键,以重新设置倒计时时间
            mov     A,KEY1
            cjne    A,#0,RELOAD      ;按键按下,则重新设置倒计时时间
    
            ;读取RTC时间
            mov     RTC_Addr,#81h   ;启动DS1302读取时钟寄存器数据
            mov     ACC,#0         ;全选
            movx    @DPTR,ACC
            mov     RTC_Addr,#0ah   ;读秒寄存器
            movx    A,@DPTR
            push    ACC
            mov     RTC_Addr,#0bh   ;读分寄存器
            movx    A,@DPTR
            push    ACC
            mov     RTC_Addr,#0ch   ;读时寄存器
            movx    A,@DPTR
            push    ACC
    
            ;显示倒计时时间
            mov     A,R7            ;取出当前扫描的位数
            mov     P2,#0ffh
            cjne    A,#3,SHIFT     ;第一位不需要移位
            mov     A,#0c0h        ;第一位显示冒号
            jmp     DIG_DISPLAY    
    SHIFT:
            mov     A,R7            ;取出当前扫描的位数
            subb    A,#4
            mov     C,A
            mov     A,#1
            rlc     A
            add     A,#8
            rlc     A
            addc    A,#0
            rlc     A
            addc    A,#0
            rlc     A
            addc    A,C
            anl     A,#0fh
            mov     R0,A
            mov     A,number_table(R0)  ;读取当前数码
    DIG_DISPLAY:
            mov     @R0,A          ;将当前数码送入缓存区    
            mov     A,P2
            anl     A,8-R7
            jz      DIG_END            ;该位是当前显示位
            orl     A,#0fh
            mov     P2,A            ;关闭该位数码管
            sjmp    NEXT_DIG
    DIG_END:
            mov     A,@R0
            mov     P2,A
            sjmp    NEXT_DIG
    
        ;扫描下一位数码管
        NEXT_DIG:
            DEC     R7
            cpl     P2            ;打开下一位数码管
            mov     R6,#4
            djnz    R6,$          ;等待若干微秒
            cpl     P2            ;关闭当前数码管
            mov     R6,#5
            djnz    R6,$          ;等待若干微秒
            jnb     P3.7,NEXT_DIG    ;等待下一次定时时钟中断
    
        ;重新设置倒计时时间
        RELOAD:
            mov     R6,#10          ;延时10ms用于去抖
            Delay1ms
            mov     R6,#10          ;设置10秒倒计时
            mov     A,#10
            mov     RTC_Addr,#0ch   ;写时寄存器地址
            movx    @DPTR,A
            dec     A
            mov     RTC_Addr,#0bh   ;写分寄存器地址
            movx    @DPTR,A
            mov     RTC_Addr,#0ah   ;写秒寄存器地址
            movx    @DPTR,#0
            LED_OFF             ;LED指示灯熄灭
            clr     P1.0            ;蜂鸣器停止发声
            jnb     KEY1,$          ;等待按键松开
            mov     R7,#digit_num-1  ;从右往左扫描数码管
            sjmp    INIT
    
        END
    
    评论
  • CSDN-Ada助手 CSDN-AI 官方账号 2023-05-28 18:11
    关注
    • 这篇博客: 蓝桥杯嵌入式 ---- 十二届官方模拟试题解析中的 5.RTC实时时钟 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
    • 代码如下:rtc.c:

      #include "rtc.h"
      u8 TimeDisplay=0;
      void rtc_init(void)
      {
        NVIC_InitTypeDef NVIC_InitStructure;
      
        /* Configure one bit for preemption priority */
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
      
        /* Enable the RTC Interrupt */
        NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
      
        /* Enable PWR and BKP clocks */
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
      
        /* Allow access to BKP Domain */
        PWR_BackupAccessCmd(ENABLE);
      
        /* Reset Backup Domain */
        BKP_DeInit();
      
        /* Enable the LSI OSC */
        RCC_LSICmd(ENABLE);
        /* Wait till LSI is ready */
        while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET)
        {}
        /* Select the RTC Clock Source */
        RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
      
        /* Enable RTC Clock */
        RCC_RTCCLKCmd(ENABLE);
      
        /* Wait for RTC registers synchronization */
        RTC_WaitForSynchro();
      
        /* Wait until last write operation on RTC registers has finished */
        RTC_WaitForLastTask();
      
        /* Enable the RTC Second */
        RTC_ITConfig(RTC_IT_SEC, ENABLE);
      
        /* Wait until last write operation on RTC registers has finished */
        RTC_WaitForLastTask();
      
        /* Set RTC prescaler: set RTC period to 1sec */
        RTC_SetPrescaler(40000);
      
        /* Wait until last write operation on RTC registers has finished */
        RTC_WaitForLastTask();
      }
      void RTC_IRQHandler(void)   //每1S进入中断
      {
        if (RTC_GetITStatus(RTC_IT_SEC) != RESET)
        {
          /* Clear the RTC Second interrupt */
          RTC_ClearITPendingBit(RTC_IT_SEC);
      
      
          /* Enable time update */
          TimeDisplay = 1;         //主函数死循环里的标志位,对定时值进行自加,达到计时的效果
      
          /* Wait until last write operation on RTC registers has finished */
          RTC_WaitForLastTask();
          
        }
      }
      
      

      rtc.h:

      #ifndef RTC_H
      #define RTC_H
      
      #include "stm32f10x.h"
      extern u8 TimeDisplay;
      void rtc_init(void);
      
      #endif
      
      
      

    评论

报告相同问题?

问题事件

  • 系统已结题 6月5日
  • 修改了问题 5月29日
  • 创建了问题 5月28日

悬赏问题

  • ¥15 vue引入sdk后的回调问题
  • ¥15 求一个智能家居控制的代码
  • ¥15 ad软件 pcb布线pcb规则约束编辑器where the object matpcb布线pcb规则约束编辑器where the object matchs怎么没有+15v只有no net
  • ¥15 虚拟机vmnet8 nat模式可以ping通主机,主机也能ping通虚拟机,但是vmnet8一直未识别怎么解决,其次诊断结果就是默认网关不可用
  • ¥20 求各位能用我能理解的话回答超级简单的一些问题
  • ¥15 yolov5双目识别输出坐标代码报错
  • ¥15 这个代码有什么语法错误
  • ¥15 给予STM32按键中断与串口通信
  • ¥15 使用QT实现can通信
  • ¥15 关于sp验证的一些东西,求告知如何解决,