【汇编&硬件】键盘读取中断的具体实现

时间:2026-02-17 16:21:00


前言

int 9h是8086系统中键盘中断的中断服务程序,用于处理键盘输入。其功能包括读取键盘扫描码、处理特殊键(如Shift、Ctrl等)、将扫描码转换为ASCII码以及设置键盘缓冲区等。它与面向用户的int 16h相互配合。前面我们说过int 9h涉及到硬件的处理,所以当时没有尝试自己编写。下面我们尝试自己实现这个中断。

代码实现

; 定义段寄存器
code segment
    assume cs:code

; 键盘中断服务程序(替代int 9h)
keyboard_int proc far
    push ax
    push bx
    push cx
    push dx
    push si
    push di
    push es
    push ds ; 保存所有寄存器状态

    ; 1. 读取键盘扫描码(从端口60h读取)
    in al, 60h ; 读取扫描码到AL(通码:按键按下,断码:按键松开,断码=通码+80h)

    ; 2. 向8259A发送中断结束信号(EOI),允许后续中断
    mov al, 20h ; EOI命令字
    out 20h, al ; 发送到主8259A

    ; 3. 处理扫描码(此处简化处理:仅响应部分按键,忽略断码和特殊键)
    cmp al, 80h ; 判断是否为断码(若AL>=80h,说明按键松开,不处理)
    jae int_end ; 是断码则直接结束

    ; 4. 扫描码转ASCII码(简化映射表,仅举例常用键)
    mov bx, offset scancode_to_ascii ; BX指向映射表
    xlat ; AL = [BX + AL](根据扫描码获取ASCII码,0表示无对应ASCII)

    ; 5. 若有有效ASCII码,存入键盘缓冲区(简化,实际需检查缓冲区状态)
    cmp al, 0
    je int_end ; 无对应ASCII,结束

    ; 此处仅演示,实际缓冲区操作需更复杂(如使用BIOS数据区的键盘缓冲区)
    mov ah, 0eh ; 调用BIOS中断,在屏幕上显示字符(模拟输入效果)
    int 10h

int_end:
    pop ds
    pop es
    pop di
    pop si
    pop dx
    pop cx
    pop bx
    pop ax ; 恢复寄存器状态
    iret ; 中断返回
keyboard_int endp

; 扫描码到ASCII码的简化映射表(仅部分键,通码对应)
; 索引:扫描码(通码),值:ASCII码(0表示无对应)
scancode_to_ascii db 0 ; 00h(无键)
                  db 27 ; 01h(Esc,ASCII 27)
                  db '1' ; 02h(1键)
                  db '2' ; 03h(2键)
                  db '3' ; 04h(3键)
                  db '4' ; 05h(4键)
                  db '5' ; 06h(5键)
                  db '6' ; 07h(6键)
                  db '7' ; 08h(7键)
                  db '8' ; 09h(8键)
                  db '9' ; 0Ah(9键)
                  db '0' ; 0Bh(0键)
                  db '-' ; 0Ch(-键)
                  db '=' ; 0Dh(=键)
                  db 8 ; 0Eh(Backspace,ASCII 8)
                  db 9 ; 0Fh(Tab,ASCII 9)
                  db 'q' ; 10h(Q键)
                  db 'w' ; 11h(W键)
                  db 'e' ; 12h(E键)
                  db 'r' ; 13h(R键)
                  db 't' ; 14h(T键)
                  db 'y' ; 15h(Y键)
                  db 'u' ; 16h(U键)
                  db 'i' ; 17h(I键)
                  db 'o' ; 18h(O键)
                  db 'p' ; 19h(P键)
                  ; 更多键的映射可继续添加...

; 安装中断向量(将自定义中断服务程序地址写入中断向量表)
install proc
    cli ; 关中断,防止安装过程被打断
    mov ax, 0
    mov es, ax ; ES指向中断向量表段(0段)
    mov di, 9*4 ; int 9h的向量地址:9*4=36(0000:0024)
    mov ax, offset keyboard_int ; 中断服务程序偏移地址
    stosw ; 写入偏移量到向量表
    mov ax, cs ; 中断服务程序段地址(当前代码段)
    stosw ; 写入段地址到向量表
    sti ; 开中断
    ret
install endp

; 主程序:安装中断后等待(实际使用中需保持程序运行以响应中断)
main:
    call install ; 安装自定义int 9h中断
    jmp $ ; 无限循环,等待中断

code ends
    end main

代码说明

  1. 中断服务程序结构:遵循中断处理规范,先保存所有寄存器,处理完成后恢复并通过 iret 返回。
  2. 扫描码读取:从端口 60h 读取键盘扫描码(通码/断码),通码表示按键按下,断码(通码+80h)表示按键松开。
  3. 中断结束信号:向8259A中断控制器发送 EOI (20h),允许后续中断。
  4. 扫描码转ASCII:通过映射表将常用按键的通码转换为对应的ASCII码(简化处理,实际需考虑Shift、CapsLock等修饰键)。
  5. 缓冲区与输出:简化演示中直接调用BIOS中断显示字符,实际应将数据存入键盘缓冲区。
  6. 中断安装:修改中断向量表(0段)中int 9h对应的地址,指向自定义服务程序。

评论

还没有评论,来说两句吧!

发表评论