You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

16位实模式OS中RTC读取值异常问题求助

解决RTC读取返回异常时间值的问题

嘿,这个坑我当年折腾实模式OS的时候实打实踩过!你看到的“每分钟90秒、每小时90分钟”本质是RTC默认输出BCD编码,而你直接把它当成十进制数打印了。

问题根源

RTC(实时时钟)的时间字段(秒、分、时等)默认是以BCD(Binary-Coded Decimal)格式存储的。比如59秒在BCD里是0x59,如果你直接把这个十六进制值转成十进制打印,就会得到89(因为0x59的十进制就是89)——这就是你看到0-89秒的原因,分钟和小时的问题也是同理。

修复方案:BCD转十进制

你需要在读取端口值后,把BCD编码转换成真正的十进制数,再传给print_decimal。修改你的代码片段如下:

get_seconds:
    xor ax, ax          ; 清空AX寄存器
    mov al, 0x00        ; 指定读取秒数的索引
    out 0x70, al        ; 向RTC索引端口写入索引值
    in al, 0x71         ; 读取RTC数据端口的秒数(此时是BCD格式)
    
    ; 核心:BCD转十进制
    mov ah, al          ; 把BCD值暂存到AH
    shr ah, 4           ; 右移4位,取出高4位(十位数字)
    and al, 0x0f        ; 保留低4位,取出个位数字
    mov cl, 10
    mul cl              ; 十位数字乘以10(结果存在AL)
    add al, ah          ; 加上个位数字,此时AL就是十进制的秒数
    
    call print_decimal  ; 打印十进制值

可选优化:切换RTC到二进制模式

如果你不想每次读取都做BCD转换,可以通过修改RTC的控制寄存器B,让它直接输出二进制格式的数据:

; 设置RTC为二进制输出模式(只需执行一次)
setup_rtc_binary:
    mov al, 0x0B        ; 指定控制寄存器B的索引
    out 0x70, al
    in al, 0x71         ; 读取当前寄存器B的值
    or al, 0x04         ; 置位第2位(DM位),启用二进制输出
    out 0x71, al        ; 写回修改后的值
    ret

之后读取RTC的所有时间字段都会是二进制数,直接调用print_decimal就能得到正确的0-59秒、0-59分这类结果。

额外提醒:避免读取到更新中的数据

读取RTC时最好先等待RTC完成当前的更新操作,不然可能读到半更新的错误值。可以在读取前加一段等待逻辑:

; 等待RTC更新完成,确保读取的数据稳定
wait_rtc_update:
    mov al, 0x0A        ; 指定控制寄存器A的索引
    out 0x70, al
    in al, 0x71
    test al, 0x80       ; 检查UIP位(第7位),1表示正在更新
    jnz wait_rtc_update ; 如果正在更新,继续等待

把这段代码放在get_seconds的开头,就能避免因RTC正在更新导致的随机错误。

内容的提问来源于stack exchange,提问作者bjarke15

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:35:44