8086系列(24):实验3.6 键盘处理程序(2)

题目

扩充键盘处理功能程序
在示例3.6的基础上,增加left_shift和right_shift键的功能,即在按下left_shift键或right_shift键的同时,又按下0-9或a-z等键,则CPU显示的是键的上档符号或大写字母。

思路

和上一题类似,这一题增加处理的功能就是在kbint中断处理程序中判断是否按下了left_shift键或right_shift键。如何判断是否按下shift键呢,我们可以把按动状态记录在一个标志单元(kbflag1中),设按下right_shift键或按下left_shift键,kbflag1置1,放开左或右shift键,kbflag恢复0。
当kbflag为1时,再按下其他数字键或字母键,则应转化为在shiftab表格里面查找。

代码

;-----------------------
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
    kbflag1 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.'
    shiftab db 0,0,'!@#$%^&*()_+',0,0
            db 'QWERTYUIOP{}',0Dh,0
            db 'ASDFGHJKL:"',0,0,0
            db 'ZXCVBNM<>?',0,0,0
            db ' ',26 dup(0)
    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 断码

    ;以下为按下的情况
    ;判断是否为左Shift键
    cmp al,2ah
    jnz shift5     ;不是左shift键
    cmp kbflag1,1
    jz shift1
    mov kbflag1,1  ;标志位置1
    jmp shift1
shift5:
    cmp al,36h     ;不是左shift,判断是否为右shift键
    jnz shift2
    cmp kbflag1,1
    jz shift1
    mov kbflag1,1
    jmp shift1
shift2:
    cmp kbflag1,1
    jnz shift3
    lea bx,shiftab   ;shiftab换码
    xlat
    jmp shift4
shift3:
    lea bx,scantab
    xlat
shift4:
    cmp al,0          ;判断是否为其他控制符
    jnz kbint4
    mov 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:
    cmp al,0aah
    jnz shift6
    mov kbflag1,0
shift6:
    cmp al,0b6h
    jnz shift1
    mov kbflag1,0
shift1:
    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

结果

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值