汇编语言 | 定制键盘输入的处理过程
<h1 id="汇编语言--定制键盘输入的处理过程">汇编语言 | 定制键盘输入的处理过程</h1><h2 id="一键盘输入的处理过程">一、键盘输入的处理过程</h2>
<ol>
<li>键盘产生扫描码</li>
<li>扫描码送入60h端口</li>
<li>引发9号中断</li>
<li>CPU执行int 9中断例程,处理键盘输入</li>
</ol>
<p> 1.~3.由硬件系统用完成。4.中的int 9中断例程可以由DOS系统提供,也可以按照开发需求定制处理键盘的输入。</p>
<h2 id="二编程任务分析">二、编程任务分析</h2>
<ul>
<li>
<p>在屏幕中间依次显示'a'~'z',并可以让人看清</p>
</li>
<li>
<p>在显示的过程中按下Esc键后改变显示的颜色</p>
</li>
</ul>
<h2 id="三工作策略">三、工作策略</h2>
<ul>
<li>
<p>尽可能忽略硬件处理细节,充分利用BIOS提供的int 9中断例程处理硬件细节。</p>
</li>
<li>
<p>在改写后的中断例程中满足特定要求,并能调用BIOS的原int 9中断例程</p>
</li>
</ul>
<h2 id="四实现">四、实现</h2>
<h3 id="1依次显示az">(1)依次显示'a'~'z':</h3>
<pre><code class="language-assembly"> ; 显示'a'-'z'
mov ax,0b800h
mov es,ax
mov ah,'a'
s: mov es:,ah ; 操作显存,找到中间位置
call delay
inc ah
cmp ah,'z'
jna s
mov ax,0
mov es,ax
</code></pre>
<p> 但是这样做字母切换太快,在屏幕上无法看清每个字母的显示。需要在每个字母显示后延时一段时间。</p>
<h3 id="2延时程序">(2)延时程序:</h3>
<p> 用两个16位寄存器来存放32位的循环次数。一共循环10,0000h次。</p>
<pre><code class="language-assembly"> ; 定义延迟程序
delay:
push ax
push dx
mov dx,10h
mov ax,0
s1:
sub ax,1
sbb dx,0
cmp ax,0
jne s1
cmp dx,0
jne s1
pop dx
pop ax
ret
</code></pre>
<h3 id="3按下esc键后改变显示的颜色">(3)按下Esc键后改变显示的颜色</h3>
<p> 键盘输入到达60h端口后会引发9号中断,CPU会转去执行int 9中断例程。</p>
<p> (1) 从60h端口读出键盘的输入</p>
<p> (2) 调用BIOS的int 9中断例程,处理硬件细节</p>
<ul>
<li>
<p>将中断向量表中的int 9中断例程的入口地址改为自编的中断处理程序的入口地址</p>
</li>
<li>
<p>在新中断例程中调用原有的int 9中断例程,因此仍需保存原来的int 9中断例程的地址</p>
<p> <strong>解决方案:将原来int 9中断例程的偏移地址和段地址保存在ds:和ds:单元中。</strong></p>
</li>
</ul>
<pre><code class="language-assembly"> ; 保存旧中断例程入口
mov ax,0
mov es,ax
push es:
pop ds:
push es:
pop ds:
; 设置新的中断向量的位置
mov word ptr es:,offset int9
mov es:,cs
</code></pre>
<p> 调用原int 9指令的中断例程:</p>
<ol>
<li>
<p>标志寄存器入栈</p>
</li>
<li>
<p>IF=0, TF=0</p>
</li>
<li>
<p>CS、IP入栈</p>
</li>
<li>
<p>(IP) = ((ds)*16 + 0)</p>
<p>(CS) = ((ds)*16 + 2)</p>
</li>
</ol>
<pre><code class="language-assembly"> pushf ; 标志寄存器入栈
; IF=0, TF=0
pushf
pop bx
and bh,11111100b
push bx
popf
; CS、IP入栈 (IP) = ((ds)*16 + 0) (CS) = ((ds)*16 + 2)
call dword ptr ds:
</code></pre>
<p>(3) 判断是否为Esc的扫描码,如果是则改变显示颜色。否则直接返回。</p>
<pre><code class="language-assembly">; 定义中断例程
int9:
push ax
push bx
push es
in al,60h
pushf
pushf
pop bx
and bh,11111100b
push bx
popf
call dword ptr ds:
cmp al,1 ; ESC扫描码1
jne int9ret
; 改变颜色
mov ax,0b800h
mov es,ax
inc byte ptr es:
int9ret:
pop es
pop bx
pop ax
iret
</code></pre>
<h2 id="五完整代码">五、完整代码</h2>
<pre><code class="language-assembly">; 编写int 9中断例程改变显示的颜色
; (1)从60h端口读出键盘的输入 in al,60h
; (2)调用BIOS的int 9中断例程, 处理硬件细节
; (3)判断是否为Esc扫描码 如果是则改变显示的颜色后返回
; 如果不是则直接返回
assume cs:code
stack segment
db 128 dup (0)
stack ends
data segment
dw 0,0
data ends
code segment
start:
mov ax,stack
mov ss,ax
mov sp,128
mov ax,data
mov ds,ax
; 更改中断例程的入口地址
mov ax,0
mov es,ax
push es:
pop ds:
push es:
pop ds:
mov word ptr es:,offset int9
mov es:,cs
; 显示'a'-'z'
mov ax,0b800h
mov es,ax
mov ah,'a'
s: mov es:,ah
call delay
inc ah
cmp ah,'z'
jna s
mov ax,0
mov es,ax
; 恢复原来的地址
push ds:
pop es:
push ds:
pop es:
mov ax,4c00h
int 21h
; 定义延迟程序
delay:
push ax
push dx
mov dx,10h
mov ax,0
s1:
sub ax,1
sbb dx,0
cmp ax,0
jne s1
cmp dx,0
jne s1
pop dx
pop ax
ret
; 定义中断例程
int9:
push ax
push bx
push es
in al,60h
pushf
pushf
pop bx
and bh,11111100b
push bx
popf
call dword ptr ds:
cmp al,1 ; ESC扫描码为1
jne int9ret
; 改变颜色
mov ax,0b800h
mov es,ax
inc byte ptr es: ; 高8位存放的是字符的属性
int9ret:
pop es
pop bx
pop ax
iret
code ends
end start
</code></pre><br><br>
来源:https://www.cnblogs.com/tedukuri/p/14397572.html
頁:
[1]