x86汇编直接读取Port 60h按键异常问题求助
问题分析与解决思路
你的代码核心问题在于混用了直接端口读取和BIOS键盘中断函数,同时没有正确处理键盘控制器的输出缓冲区残留数据,导致按键事件逻辑混乱。
具体问题点
- 多余的
int 16h ah=0调用:你已经直接读取Port 60h获取键盘扫描码,但每次匹配到按下码后又调用BIOS的键盘读取函数,这会让BIOS取走键盘缓冲区的事件,和你的端口读取逻辑冲突,导致后续按键事件被BIOS拦截,你的代码无法读到。 - 未清空键盘输出缓冲区:键盘控制器的Port 60h输出缓冲区可能存在多个待读取的字节(比如前一个按键的松开码、新按键的按下码),你的代码只读取一次就处理,残留的字节会干扰下一次读取。
- 无效的
loop指令:你的逻辑是处理完按键后跳回循环,cx的计数完全没用,反而可能导致循环提前终止。
修正方案
- 移除所有
mov ah,0; int 16h调用,完全用端口读取逻辑处理按键。 - 读取扫描码时,循环清空输出缓冲区:通过检查Port 64h的第0位(输出缓冲区满标志),确保读完所有待处理的扫描码。
- 去掉无用的
loop指令,改用无限循环处理按键。
修正后的代码示例
mov ah, 0 mov al, 2 int 10h ; 设置文本模式 ll: ; 循环清空键盘输出缓冲区,确保读取最新的扫描码 check_buffer: in al, 64h test al, 01h ; 检查输出缓冲区是否有数据(第0位为1表示有) jz check_buffer ; 缓冲区为空则等待 in al, 60h ; 读取扫描码 mov dl, al test al, 80h ; 检查是否是松开码(最高位为1) jnz ll ; 松开码直接丢弃,继续等待按下 ; 匹配按下的按键扫描码 cmp dl, 48h je print_msg1 cmp dl, 50h je print_msg2 cmp dl, 4Dh je print_msg3 cmp dl, 4Bh je print_msg4 jmp ll ; 未匹配的按键,回到循环 print_msg1: mov dx, offset msg1 mov ah, 9 int 21h jmp ll print_msg2: mov dx, offset msg2 mov ah, 9 int 21h jmp ll print_msg3: mov dx, offset msg3 mov ah, 9 int 21h jmp ll print_msg4: mov dx, offset msg4 mov ah, 9 int 21h jmp ll d: ; 这里可以添加程序退出逻辑,比如 mov ah,4Ch; int 21h
额外说明
- 键盘扫描码:按下键时返回的是00h-7Fh的扫描码,松开时返回对应的扫描码+80h,你的代码只需要处理按下事件,所以遇到松开码直接丢弃即可。
- Port 64h是键盘控制器的状态端口,第0位表示输出缓冲区(Port60h)是否有数据可读,第1位表示输入缓冲区是否满。
内容的提问来源于stack exchange,提问作者zizo
相关产品推荐
相关产品推荐

