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

如何在8086x汇编中测量用户键盘输入的打字时长

8086汇编打字计时程序实现方案

实现原理说明

你要的计时功能不需要直接操作硬件定时器,直接调用BIOS维护的系统全局计数器即可,原理如下:

  • 8086平台的BIOS会自动维护一个32位的计时计数器,存放在内存地址0040H:006CH处,系统定时器每间隔约55ms(精确值为54.925ms)会触发一次INT 1CH中断,每触发一次该计数器加1,每秒大约累加18.2次
  • 计时逻辑只需要记录两个时间点的计数器值:用户按下第一个按键时的计数值、按下回车键时的计数值,二者的差值乘以55就可以得到近似的毫秒耗时,误差在可接受范围内
  • 字符串数组在8086汇编里直接用指针数组实现即可:数据段先定义10个字符串,再定义一个字数组存储每个字符串的首地址,和高级语言的字符串数组逻辑完全一致

完整示例代码

; 运行环境:DOSBox、MASM/TASM编译
DATA SEGMENT
    ; 字符串指针数组,对应长度为10的字符串数组
    STR_ARR DW STR0, STR1, STR2, STR3, STR4, STR5, STR6, STR7, STR8, STR9
    ; 10个测试单词
    STR0 DB 'hello',0
    STR1 DB 'world',0
    STR2 DB 'x86asm',0
    STR3 DB 'assembly',0
    STR4 DB 'dosbox',0
    STR5 DB 'bios',0
    STR6 DB 'interrupt',0
    STR7 DB 'counter',0
    STR8 DB 'keyboard',0
    STR9 DB 'program',0
    INPUT_TIP DB 0DH,0AH,'Please input the word above: $'
    RES_TIP DB 0DH,0AH,'Total time used: $'
    MS_UNIT DB ' ms',0DH,0AH,'$'
    START_CNT DD 0 ; 存储开始计时的计数器值
DATA ENDS

CODE SEGMENT
ASSUME CS:CODE, DS:DATA
START:
    MOV AX, DATA
    MOV DS, AX

; ----------------------
; 1. 随机取一个单词打印
; ----------------------
RAND_GET:
    MOV AX, 0040H
    MOV ES, AX
    MOV AL, ES:[006CH] ; 取系统计数器低字节做随机种子
    XOR AH, AH
    MOV BL, 10
    DIV BL ; 模10得到0-9的索引
    MOV AL, AH
    XOR AH, AH
    MOV BX, AX
    SHL BX, 1 ; 每个指针占2字节,索引乘2
    MOV SI, STR_ARR[BX] ; 取对应字符串首地址

; 打印目标单词
PRINT_STR:
    MOV AL, [SI]
    CMP AL, 0
    JZ PRINT_TIP
    MOV AH, 0EH
    INT 10H
    INC SI
    JMP PRINT_STR

PRINT_TIP:
    MOV AH, 09H
    LEA DX, INPUT_TIP
    INT 21H

; ----------------------
; 2. 等待第一次按键,开始计时
; ----------------------
WAIT_FIRST_KEY:
    MOV AH, 00H
    INT 16H ; 阻塞读键盘,无输入不返回
    ; 回显第一个按键
    MOV AH, 02H
    MOV DL, AL
    INT 21H
    ; 记录开始计数值
    MOV AX, 0040H
    MOV ES, AX
    MOV AX, ES:[006CH]
    MOV WORD PTR START_CNT, AX
    MOV AX, ES:[006CH+2]
    MOV WORD PTR START_CNT+2, AX

; ----------------------
; 3. 等待用户输入直到回车,停止计时
; ----------------------
INPUT_LOOP:
    MOV AH, 00H
    INT 16H
    CMP AL, 0DH ; 判断是否是回车键
    JZ STOP_COUNT
    ; 回显按键
    MOV AH, 02H
    MOV DL, AL
    INT 21H
    JMP INPUT_LOOP

STOP_COUNT:
    ; 读取结束计数值
    MOV AX, 0040H
    MOV ES, AX
    MOV DX, ES:[006CH]
    MOV CX, ES:[006CH+2]
    ; 计算差值 = 结束值 - 开始值
    SUB DX, WORD PTR START_CNT
    SBB CX, WORD PTR START_CNT+2
    ; 差值乘以55得到毫秒数(默认差值不超过65535,足够日常测试)
    MOV AX, DX
    MOV BX, 55
    MUL BX ; 结果存在DX:AX,这里只取AX即可

; ----------------------
; 4. 打印耗时
; ----------------------
PRINT_RES:
    MOV AH, 09H
    LEA DX, RES_TIP
    INT 21H
    ; AX存毫秒数,转十进制打印
    CALL PRINT_NUM
    MOV AH, 09H
    LEA DX, MS_UNIT
    INT 21H

; 退出程序
EXIT:
    MOV AH, 4CH
    INT 21H

; 子程序:打印AX中的十进制数字
PRINT_NUM:
    PUSH BX
    PUSH CX
    PUSH DX
    MOV CX, 0
    MOV BX, 10
LOOP1:
    DIV BL
    PUSH AX
    INC CX
    XOR AH, AH
    CMP AL, 0
    JNZ LOOP1
LOOP2:
    POP AX
    MOV DL, AH
    ADD DL, 30H
    MOV AH, 02H
    INT 21H
    LOOP LOOP2
    POP DX
    POP CX
    POP BX
    RET
CODE ENDS
END START

注意事项

  • 上述代码直接使用BIOS提供的计数器,不需要手动配置8253定时器、不需要修改中断向量,兼容性最高,在所有8086 DOS环境下都可以正常运行
  • 如果需要更高精度的计时,可以自行挂钩INT 1CH中断,在中断服务程序里维护自定义的计数器,但是需要注意退出程序前要恢复原中断向量,避免系统崩溃
  • 随机取词逻辑使用系统计数器的低字节作为随机源,不需要额外实现随机数算法,足够满足普通测试需求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.19 10:06:05