汇编语言随笔(15)- 对键盘输入进行处理(int 9 和 int 16h 中断例程)

键盘输入

      1,前面讲过, int 9 中断例程负责对键盘输入进行处理,具体为:从 60h 端口读出扫描码,并将其转化为相应的ASCII码或状态信息,一起存储到内存的指定空间(键盘缓冲区或状态字节)中。
      其中键盘缓冲区一共有16个字单元,可以存储15个按键的扫描码和对应的ASCII码。这是因为采用了循环队列来实现的,会有一个单元被浪费掉。

      例如:当摁下 A、B、C、shift_A、A 时键盘缓冲区的状态如下:
      当摁下 A 键时,int 9 例程从 60h 端口读取A键的通码;检测状态字节判断是否有控制键(Ctrl、Shift)按下,发现没有被按下时,将A键的扫描码 1eh 和对应的字母 ’a’ 的ASCII码 61h写入键盘缓冲区中。高位字节存储扫描码,低位字节存储ASCII码。
      当摁下 B、C 键时进行类似的操作。
      当摁下 Shift_A 键时,(1)当按下左 Shift 键时,发生键盘中断,int 9 中断例程接收左 Shift 键的通码,设置 0040:17 处的状态字节的第1位为1,表示左 Shift 键按下。(2)当按下 A 键时,int 9 例程从 60h 端口读出A键的通码;检测状态字节发现左 Shift 键按下,则将 A 键的扫描码 1Eh 和 Shift_A 对应的大写字母 ‘A’ 的ASCII码 41h 写入键盘缓冲区。(3)当松开左 Shift 键时,发生键盘中断,int 9 中断例程接收左 Shift 键的断码,设置0040:17处的状态字节的第1位为0,表示左 Shift 键松开。
      最后再次按下 A 键时的操作同上。
                                                            5次按键的键盘缓冲区图示

0123456789101112131415
1,1E61
2,1E613062
3,1E6130622E63
4,1E6130622E631E41
5,1E6130622E631E411E61

      2,使用 int 16h 中断例程的 0 号子程序可以从键盘缓冲区中读取一个键盘输入,并将其从缓冲区中删除。具体步骤如下:
      (1)检测键盘缓冲区中是否有数据。
      (2)没有则继续做第1步。即一直在等待,等待有数据被输入到键盘缓冲区中。
      (3)读取缓冲区中最早进入的键盘输入,从队头开始读取。
      (4)将读取的扫描码送入 ah,ASCII码送入 al。
      (5)将已读取的键盘输入从缓冲区中删除。
      对上面的键盘缓冲区执行:

			mov ah,0
			int 16h

      缓冲区中的结果为

0123456789101112131415
30622E631E411E61

      ah 中的内容为 1eh,al 中的内容为 61h。

      总结:int 9 和 int 16h 可以相互配合使用,int 9 是在有键按下的时候向键盘缓冲区中写入数据,int 16h 是在应用程序对其进行调用的时候,将数据从键盘缓冲区中读出。当我们需要对某一个特定的按键实现一个特别的功能时,有两种方法,一种是通过 Int 9 中断例程在处理键盘输入时来实现;另一种是通过调用 int 16h 从键盘缓冲区中读取键盘输入来实现。后者的优点在于不需要重写编写 int 9 中断例程。

练习1

      编写程序,接收用户的键盘输入,输入 ‘r’,将屏幕上的字符设置为红色;输入 ’g‘,将将屏幕上的字符设置为绿色;输入 ’b’,将屏幕上的字符设置为蓝色。
      关于在屏幕上显示颜色的细节可参考      https://blog.csdn.net/Little_ant_/article/details/108227058

		assume cs:code
		code segment
		 		;调用 16h 号中断例程的 0 号子程序来读取一个键盘输入。
		start: mov ah,0
			   int 16h			
				;处理已经读取的键盘输入,ah中存放扫描码,al 中存放字符码(可直接来进行比较)。
			  我们用 ah 来保存颜色属性,01h表示蓝色,02h表示绿色,04h表示红色。
			   mov ah,1		;初始设置颜色为蓝色,通过左移来改变颜色,这点需要注意。
			   cmp al,'r'
			   je red
			   cmp al,'g'
			   je green
			   cmp al,'b'
			   je blue
			   jmp short sret

		  red: shl ah,1
		green: shl ah,1
		 blue: mov bx,0b800h
		 	   mov es,bx
		 	   mov bx,1
		 	   mov cx,2000
		 	s: and byte ptr es:[bx],11111000b
		 	   or es:[bx],ah			;设置对应的颜色
		 	   add bx,2
		 	   loop s

		 sret: mov ax,4c00h
		 	   int 21h
		

练习2

      编写字符串输入程序,需具备下面的功能。
      (1)在输入的同时需要显示这个字符串。
      (2)一般在输入回车符后,字符串输入结束。
      (3)能够删除已经输入的字符。
      因为需要显示字符串,故,子程序的参数为:(dh)、(dl) = 字符串在屏幕上显示的行、列位置;ds:si 指向字符串的存储空间,字符串以0为结尾符。
      首先,我们采用栈的方式来管理字符串的存储空间,即字符串的存储空间实际上是一个字符栈。输入字符时,字符入栈;删除字符时,字符出栈;显示字符时,从栈底到栈顶来显示。其次,输入回车符后,可以在字符串中加入 0,表示字符串结束。最后,每次当有新的字符输入或删除字符时,都应该重新显示该字符串。
      程序的处理过程如下:
      1,调用 int 16h 读取键盘输入
      2,如果是字符,进入字符栈,显示字符栈中的所有字符,继续执行 1。
      3,如果是退格键,从字符栈中弹出一个字符,显示字符栈中的所有字符,继续执行1。
      4,如果是回车键,向字符栈中压入 0,返回。

      因为包含多次字符入栈、出栈和显示,我们将它们编写为子程序。
其中用(ah)=功能号,0 表示入栈、1 表示出栈、2 表示显示。用ds:si 指向字符栈空间。在入栈时,(al)= 入栈字符;出栈时,(al)= 出栈字符;显示时,(dh)、(dl)为屏幕上显示的行、列位置。

		charstack: jmp short charstart
		     table dw charpush,charpop,charshow		;直接定址表
		       top dw 0			;用数据标号top中的内容来表示栈顶,初始栈顶为0

		charstart: push bx
				   push dx
				   push di
				   push es

				   cmp ah,2
				   ja sret			;功能号ah大于2直接返回
				   mov bl,ah
				   mov bh,0
				   add bx,bx
				   jmp word ptr table[bx]	;跳转到对应的子程序

		 charpush: mov bx,top
		 		   mov [si+bx],al		;先将字符入栈
		 		   inc top				;栈顶指针自增
		 		   jmp short sret		;字符入栈结束,返回
		 		   
		  charpop: cmp top,0			;若top为0,此时栈为空,返回
		  		   je sret
		  		   dec top
		  		   mov bx,top
		  		   mov al,[si+bx]		;al 保存出栈字符
		  		   jmp short sret

		charshow: mov bx,0b800h
				  mov es,bx
				  mov al,160
				  mov ah,0				
				  mul dh
				  mov di,ax				;(al)*(dh)的结果放在di中
				  add dl,dl
				  mov dh,0
				  add di,dx				;将最终的显示地址放在di中。即es:di作为目的地址。
				  mov bx,0
	   charshows: cmp bx,top
	   			  jne noempty
				  mov byte ptr es:[di],' '	;字符栈为空时显示空格符;或在字符串末尾再显示一个空格符。
				  jmp short sret

		 noempty: mov al,[si+bx]
		 		  mov es:[di],al
		 		  mov byte ptr es:[di+2],' '	;总是在字符串输出的末尾加上空格符
		 		  inc bx
		 		  add di,2
		 		  jmp charshows

			sret: pop es
				  pop di
				  pop dx
				  pop bx
				  ret
				  

      编写完整的接受字符串输入的子程序如下:(注意:在显示栈中字符的时候,需要清除屏幕上一次显示的内容):

		getstr: push ax
		
	   getstrs: mov ah,0
	   			int 16h			;接收键盘输入,ah中放扫描码,al中放字符码
	   			cmp al,20h
	   			jb nochar		;ASCII码小于20h,说明不是字符
	   			mov ah,0
	   			call charstack	;存放在(al)中的字符入栈,ah表示调用0号子程序
	   			mov ah,2
	   			call charstack	;显示栈中的字符串
	   			jmp short getstrs

		nochar: cmp ah,0eh		;退格键的扫描码
			    je backspace
			    cmp ah,1ch		;回车键的扫描码
			    je enter
			    jmp short getstrs

	backspace: mov ah,1
			   call charstack	;字符出栈
			   mov ah,2
			   call charstack	;显示栈中字符
			   jmp short getstrs

	    enter: mov al,0
	    	   mov ah,0
	    	   call charstack	;将0入栈
	    	   mov ah,2
	    	   call cahrstack	;显示栈中的字符
	    	   
	    	   pop ax			;退出
	    	   ret
  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
汇编语言可以使用int 16h中断例程的0号子程序来读取键盘输入。具体步骤如下: 1. 首先,需要检测键盘缓冲区中是否有数据。 2. 如果没有数据,程序将一直等待,直到有数据被输入到键盘缓冲区中。 3. 一旦有数据进入键盘缓冲区,程序将读取缓冲区中最早进入的键盘输入,从队头开始读取。 4. 将读取的扫描码送入ah寄存器,将ASCII码送入al寄存器。 5. 最后,将已读取的键盘输入从缓冲区中删除。 在汇编语言中,可以使用以下指令来执行上述步骤: ``` mov ah, 0 int 16h ``` 这样就可以读取键盘输入,并且从键盘缓冲区中删除。执行以上指令后,扫描码将存储在ah寄存器中,ASCII码将存储在al寄存器中。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [汇编语言-使用BIOS进行键盘输入和磁盘读写](https://blog.csdn.net/Cdreamfly/article/details/104908167)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [汇编语言随笔15)- 对键盘输入进行处理int 9 和 int 16h 中断例程)](https://blog.csdn.net/Little_ant_/article/details/108691941)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值