如何设置定时器?能否用指定汇编代码实现60秒定时功能?
DOS环境下定时器设置与汇编定时按键问题解答
嘿,我来帮你拆解这两个问题:
一、如何设置定时器?
在DOS/BIOS环境下(从你用的int 16h中断来看,应该是这个场景),常用的定时器实现方式有三种:
- BIOS实时时钟中断法:调用
int 1Ah中断获取系统从午夜开始的时钟滴答数(每秒约18.2次),通过记录起始时间、循环计算时间差来实现定时,这种方法精度适中,不需要操作硬件。 - 硬件定时器(8253/8254)法:直接编程操作PC的可编程定时器芯片,设置计数初值并开启中断,当计数结束时触发定时事件,精度很高,但需要熟悉硬件寄存器操作。
- 循环延时代码:通过空循环消耗CPU时间来模拟定时,这种方法最简单但精度极差,不同主频的CPU执行速度差异大,时间误差会很明显。
二、你给出的汇编代码能实现60秒定时+检测S键吗?
先把你的代码贴出来方便分析:
xor ah,ah Enter_Again: xor ah, ah ; I should put 60 seconds here int 16h ; The user should press S before 60 seconds mov bl,al cmp al,"S"
很遗憾,这段代码完全做不到60秒定时的需求。原因很简单:当ah=0时调用int 16h,是BIOS的「阻塞式按键读取」——程序会卡在这一步,直到用户按下任意键才会继续执行,根本不会去计时。
要实现“60秒内按下S键”的功能,需要结合非阻塞按键检测和定时逻辑,这里给你一个基于BIOS实时时钟的修改示例:
; 定义存储起始时间的变量 start_cx dw ? start_dx dw ? ; 程序入口 start: ; 记录起始时钟滴答数(int 1Ah ah=0:获取系统时间,cx:dx为总滴答数,每秒约18.2次) mov ah, 00h int 1Ah mov [start_cx], cx mov [start_dx], dx check_loop: ; 第一步:非阻塞检查是否有按键输入(int 16h ah=1:有按键则ZF=0,al存按键ASCII) mov ah, 01h int 16h jz check_timer ; 没按键,先检查时间 ; 有按键,读取按键并判断是否是S mov ah, 00h int 16h cmp al, 'S' je success ; 按下S,跳转到成功逻辑 ; 不是S,回到循环继续等待 jmp check_loop check_timer: ; 获取当前时间 mov ah, 00h int 1Ah ; 计算时间差:当前cx:dx - 起始cx:dx sub dx, [start_dx] sbb cx, [start_cx] ; 60秒对应的滴答数约为 60*18.2065 ≈ 10924 cmp cx, 0 jne time_up ; cx不为0说明时间远超60秒 cmp dx, 10924 jge time_up ; 时间达到60秒,跳转到超时逻辑 ; 时间还没到,回到循环继续检测 jmp check_loop success: ; 这里可以添加成功提示,比如调用int 21h显示字符串 mov ah, 09h mov dx, offset success_msg int 21h jmp exit time_up: ; 超时提示 mov ah, 09h mov dx, offset timeout_msg int 21h exit: ; 退出程序 mov ah, 4Ch int 21h ; 定义提示字符串 success_msg db "恭喜!你在60秒内按下了S键!$" timeout_msg db "超时啦!你没在60秒内按下S键...$"
这段代码的核心逻辑是:循环交替做两件事——非阻塞检查用户是否按了S,以及计算当前时间和起始时间的差值,一旦时间到60秒或者用户按下S,就跳出循环执行对应逻辑。
内容的提问来源于stack exchange,提问作者Omega Zero




