16位实模式裸机nasm汇编实现毫秒级休眠及打印延迟方案问询
16位实模式汇编延迟功能实现方案
在16位实模式的裸机环境下,可以直接调用BIOS提供的时钟中断实现指定时长的延迟,无需额外硬件驱动。
实现原理
- 系统内置的定时器会以约18.2Hz的频率触发中断,对应每次中断间隔约55ms
- BIOS维护了全局的时钟滴答计数器,每触发一次定时器中断,计数器值加1
- 调用
int 0x1A中断的AH=0x00子功能,可以读取当前的滴答计数器值,结果存储在CX:DX寄存器组中 - 你需要的300ms延迟对应约6次滴答计数(55ms * 6 = 330ms,误差可忽略,完全满足字符打印的间隔效果要求)
修改后的完整打印代码
[bits 16] ; 运行在16位模式下 [org 0x7c00] ; 设置程序起始地址 init: mov si, msg ; 将字符串msg的地址加载到SI寄存器 mov ah, 0x0e ; 设置AH为0xe,对应BIOS中断的 teletype 打印功能 print_char: lodsb ; 将SI指向的字节加载到AL,同时SI地址自增1 cmp al, 0 ; 判断AL是否为字符串结束标记0 je done ; 到字符串末尾则跳转到结束逻辑 int 0x10 ; 调用BIOS中断打印当前AL中的字符 mov cx, 6 ; 设置需要等待的滴答数,6次对应约300ms call delay ; 调用延迟函数 jmp print_char ; 循环处理下一个字符 ; 延迟函数:输入CX为需要等待的滴答数 delay: push ax push cx push dx .wait_loop: mov ah, 0x00 int 0x1A ; 读取当前滴答计数到CX:DX mov bx, dx ; 保存当前低16位计数 .check_tick: mov ah, 0x00 int 0x1A cmp dx, bx ; 对比当前计数和之前保存的计数 je .check_tick ; 计数未更新就继续轮询 dec cx ; 完成一次滴答等待,计数减1 jnz .wait_loop ; 未到指定滴答数就继续循环 pop dx pop cx pop ax ret done: hlt ; 停止CPU执行 msg: db "The quick brown fox jumps over the lazy dog.", 0 ; 要打印的字符串,末尾补0作为结束标记 times 510-($-$$) db 0 ; 填充0直到程序总大小为510字节 dw 0xaa55 ; 引导扇区魔数,BIOS识别该值才会认为这是可引导的程序
精度调整说明
如果需要更精准的延迟,可以直接对PIT(可编程间隔定时器)芯片进行编程,设置自定义的定时器频率,实现毫秒级的精准控制,实现复杂度更高,对于打字效果的场景不需要这么高的精度,上述方案已经满足需求。
内容的提问来源于stack exchange,提问作者H4ZE
相关产品推荐
相关产品推荐

