汇编实验:自定义键盘中断的处理函数
汇编实验报告-键盘中断
1. 实验任务:采用键盘中断方式,当输入是字符或数字的时候,回显输入并回车换行;否则退出。
2. 运行环境:Windows11+MASM
3. 题目分析:
在课上我们刚刚学习了中断的概念以及自定义中断,且有一个例程是对键盘中断进行获取的。因此我们可以借鉴例程,通过mov ah 25h/35h完成对键盘中断的存取和设置,获取键入的字符。
但是最开始想直接输出获取的字符却发现均为乱码,查询后才发现由键盘中断方式读取的是字符的扫描码,该码与ASCII码不同,是键盘上第一排“0-9,-=”有邻近的扫描码,第二排“qwertyuiop[]|”有邻近的扫描码等等。于是我们找到扫描码和字符的对应表,手动创建一个字符串,存储从00H-39H的所有字符,如果不是可显示字符,或是控制字符,就用#代替。通过这种方式可以把扫描码直接映射到对应字符的ASCII码输出。
4. 流程图绘制:根据分析和题目要求绘制主函数的流程图:
5. 各部分与功能的流程图/程序:
- 数据段定义:当我们定义数据段时,我们要考虑的有以下几方面因素:
-
由于设置中断前必须保存原有中断处理函数,结束后必须恢复原中断,因此需要2个存储区分别存储原有中断的段地址和偏移地址。
-
由于需要把扫描码转换为ASCII码输出,我们需要定义一个字符串,其与串首址的偏移距离即为扫描码,其值即为ASCII码。
数据段定义:
data segment
old_ip09 dw ?
old_cs09 dw ?
endmsg db 0ah,0dh,'END',0ah,0dh,'$'
scan db "##1234567890-=##qwertyuiop[]##asdfghjkl;'###zxcvbnm,./",'$'
data ends
codesg segment
- 中断处理函数kbdit:
该函数就是当我们触发键盘中断时,会调用的处理程序。其功能为首先从键盘缓冲区端口60H接受扫描码,然后与数据段中我们定义的字符串偏移量匹配,如果是#则放弃输出,否则判断为正确字符、输出该字符。
- 流程图
- 程序段代码如下:
kbdit PROC
push dx
push ax
push bx
in al,60h
push ax
in al,61h
mov ah,al
or al,80h
out 61h,al
xchg ah,al
out 61h,al
pop ax
in al,60h
test al,80h;若超过127,退出
jnz return
lea bx,scan
DISPLAY:
;CBW
; mov cx,ax
; GO:
sub ah,ah
ADD bx,ax
mov dl,[bx]
cmp dl,'#';不合格
je exit
mov ah,02H
int 21h
return:
cli
mov al,20h
out 20h,al
pop bx
pop dx
pop ax
iret
kbdit ENDP
-
主函数main
主函数的作用是设置中断向量,并且进行延时,等待中断程序的调用。
-
流程图
-
程序段代码如下:
main proc near
start:
push ds
sub ax,ax
push ax
mov ax,data
mov ds,ax
mov es,ax
;save old inter
mov al,09h
mov ah,35h;取中断向量
int 21h
mov old_cs09,es;保存原有中断
mov old_ip09,bx
push ds
lea dx,kbdit
mov ax,seg kbdit
mov ds,ax
mov al,09h
mov ah,25h;中断向量设置
int 21h
pop ds
;打开键盘中断屏蔽
in al,21h
and al,0fdh;00001111
out 21h,al
sti
;开始准备服务中断
mov di,20000
wait1:
mov si,3000
wait2:
dec si
jnz wait2
dec di
jnz wait1
mov ah,09h
lea dx,endmsg
int 21h
cli
;恢复原先的中断
push ds
mov dx,old_ip09
mov ax,old_cs09
mov ds,ax
mov al,09h
mov ah,25h
INT 21h
pop ds
ret
;结束
exit:
lea dx,endmsg
mov ah,09h
int 21h
mov ah,4ch
int 21h
main ENDP
6.运行结果
-
0-9数字排的输出
-
三个字母排的输出
可见功能正常,成功实现。
- 现存问题:由于我们认为SHIFT是不合法的字符,因此我们无法实现SHIFT+小写字母输出大写字母的功能。