8086系列(23):例3.6 键盘处理程序(1)

题目

键盘处理程序

思路

在这里插入图片描述
该程序修改了键盘I/O,09号中断,并对键盘的按下和弹起进行中断检测,并把来自键盘的83个键的扫描码转换成相应的ascii字符。

我们要知道事有:
1、当键盘上“按下”或“放开”一个键时,如果键盘中断是允许的,就会产生一个9号中断
2、键盘触点电路按照16×8=128矩阵排列每个按键分为“按下”和“放开”两种情况,
通码:最高位为0
断码:最高位为1
3、扫描码:一个字节,8位(256种情况),入60H号端口寄存器
在这里插入图片描述
我们要做的事就是

主程序:

  • (1) 保存原来的09号中断向量
  • (2) 设置中断向量kint
  • (3) 设置中断屏蔽字

在这里插入图片描述

  • (4)forever循环:

    call kbget:检测并等待键盘中断,如果有键盘输入,则从缓冲区buffer取出字符并进行队列管理。kbflag用于判断是否为功能键,这里对功能键不做任何处理,如果是功能键则退出,如果不是功能键则显示,继续输入。如果是回车则外加换行。

键盘中断程序kint:

  • (1)保存寄存器的内容
  • (2) 取得原来60H的扫描码并保存
  • (3) 取得控制端口,应答键盘,应答复位
  • (4) 根据扫描码获取ascii码
  • (5)获取ascii码后进行相关功能操作,加入缓冲区
  • (6)EOI,中断返回

关于循环队列的几种工作状态:
在这里插入图片描述在这里插入图片描述

代码

;-----------------------
stack segment
    db 256 dup(0)
stack ends
;-----------------------
datasg segment
    buffer db 16 dup(0)
    bufpt1 dw 0
    bufpt2 dw 0
    ;bufpt1 = bufpt2 ,the buffer is empty 16个字的缓冲区
    kbflag db 0
    prompt  db '---kbd_io program begin---' , 0dh , 0ah , '$'
    scantab db 0,0,'1234567890-=',8,0
            db 'qwertyuiop[]',0dh,0
            db 'asdfghjkl;',0,0,0,0
            db 'zxcvbnm,./',0,0,0
            db ' ',0,0,0,0,0,0,0,0,0,0,0,0,0
            db  '789-456+1230.'
    oldcs9 dw ?
    oldip9 dw ?
datasg ends
;-------------------------
codesg segment
main proc far
    assume cs:codesg,ds:datasg
start:
    push ds
    mov ax,0
    push ax
    mov ax,datasg
    mov ds,ax

    cli ;关中断
    ;第一步 保存中断向量
    mov ah,09
    mov ah,35h          
    int 21h
    mov oldcs9,es    
    mov oldip9,bx

    ;第二步 设置中断向量
    push ds    ;保护一下ds,因为设置中断时用到ds,ax
    mov dx,offset kbint
    mov ax,seg kbint
    mov ds,ax
    mov al,09
    mov ah,25h       
    int 21h
    pop ds 

    ;第三步 设置中断屏蔽字
    in al,21h
    and al,0fdh         
    out 21h,al

    mov dx,offset prompt   ;显示提示'---kbd_io program begin---' 
    mov ah,9
    int 21h 
    sti                ;保险起见 , 在设置中断的时候关中断后在开中断 if

forever:
    call kbget         ;wait get a key
    test kbflag,80h    ;判断是否为功能键
    jnz endint         
    push ax            ;如果不是功能键显示字符
    call dispchar      ;display the character
    pop ax
    cmp al,0dh         ;如果是换行,则换到下一行
    jnz forever
    mov al,0ah
    call dispchar      ;display CR/LF
    jmp forever


    ;第七步  设置回原中断
endint:
    mov dx,oldip9
    mov ax,oldcs9
    mov ds,ax
    mov al,09h
    mov ah,25h
    int 21h            
exit:
    ret 
main endp
;----------主程序结束-------------
;----------kbget-----------------
kbget proc near
    push bx
    cli      ;关中断,在处理缓冲区时防止接受字符
    mov bx,bufpt1
    cmp bx,bufpt2
    jnz kbget2        ;没满,继续接受字符
    cmp kbflag,0
    jnz kbget3
    sti
    pop bx
    jmp kbget
kbget2:
    mov al,[buffer+bx] ;get ascii code
    inc bx            ;inc a buffer pointer
    cmp bx,16         ;at end of buffer ?
    jc kbget3         ;no,continue
    mov bx,0          ;reset to buf begining   相当于是一个循环队列
kbget3:
    mov bufpt1,bx     
    pop bx
    ret 
kbget endp
;-----------------------
;-----------kbint-------接管中断
kbint proc far
    ;第四步 保护寄存器内容
    push bx
    push ax
    
    ;第五步 执行中断处理程序(如果允许中断嵌套,则sti,cli)
    in al,60h             ;取得扫描码
    push ax               ;save it
    in al,61h             ;取得控制端口
    or al,80h             ;应答键盘,最高位置1
    out 61h,al
    and al,7fh            ;应答复位 最高位置0
    out 61h,al

    pop ax                ;恢复扫描码
    test al,80h           ;按下或松开
    jnz kbint2           ;如果松开,return 断码
    mov bx,offset scantab
    xlat scantab          ;根据扫描码获得ASCII码
    cmp al,0              ;判断是否为功能键 scantab功能键都设为0
    jnz kbint4            ;不是功能键
    mov kbflag,80h        ;如果是功能键,kbflag=80h
    jmp kbint2

kbint4:
    mov bx,bufpt2          ;取出尾指针
    mov [buffer+bx],al     ;ASCII fill in buffer  (al保存着扫描码)
    inc bx
    cmp bx,16              ;是最后一个?
    jc kbint3              ;no
    mov bx,0               ;reset to buf beginning
kbint3:
    cmp bx,bufpt1          ;缓冲区是否已满?
    jz kbint2              ;满了,lose character
    mov bufpt2,bx          ;保存尾指针

    ;第六步 送中断结束命令EOI给中断命令程序,恢复寄存器,返回
kbint2:
    cli
    mov al,20h            ;相当于EOI 允许同或低级的中断
    out 20h,al
    pop ax
    pop bx
    sti
    iret              ;中断返回
kbint endp
;-------------dispchar-------------
dispchar proc near
    ;push bx
    ;mov bx,0
    ;mov ah,0eh
    ;int 10h            ;call video routine
    ;pop bx
    push dx
    mov dl,al
    mov ah,02
    int 21h
    pop dx
    ret
dispchar endp

codesg ends
end start

结果

在这里插入图片描述
体验了才知道!

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值