彙編語言(王爽)第十七章 使用BIOS進行鍵盤輸入和磁盤讀寫

第十七章

17.1 int 9中斷例程對鍵盤輸入的處理

一般的鍵盤輸入,在CPU執行完int 9中斷例程後,都放到了鍵盤緩衝區中。鍵盤緩衝區共有16個字單元。可存儲15個按鍵的掃描碼和對應的ASCII碼

那麼它們是如何寫入的:

初始狀態下,沒有鍵盤輸入,緩衝區爲空(緩衝區是用環形隊列結構管理的內存區)

image-20200330165414436

按下A,引發鍵盤中斷,CPU執行int 9中斷例程,從60h端口讀出A鍵的通碼,然後檢測狀態字節,看是否有按下Shift、Ctrl等鍵,若沒有,則將A的掃描碼1eh和“a”的ASCII碼61h寫入緩衝區,字單元中,高位字節存儲掃描碼,低位字節存儲ASCII碼

image-20200330170237463

按下B、C、D、E鍵,同理

image-20200330171138833

Shift_A:按下做Shift,引發鍵盤中斷,int 9中斷例程接收左Shift鍵的通碼,設置0040:17處的狀態字節的第1位爲1,表示左Shift鍵按下

按下A,引發鍵盤中斷,……,發現左Shift鍵被按下,則將A的掃描碼和Shift_A對應的ASCII碼,即“A”的ASCII碼41h寫入緩衝區

image-20200330172143906

鬆開左Shift,引發鍵盤中斷,int 9中斷例程接收左Shift的斷碼,設置0040:17處的狀態字節第1位爲0,表示左Shift鬆開

按下A鍵……

image-20200330172909569

17.2 使用int 16h中斷例程讀取鍵盤緩衝區

BIOS 提供int 16h中斷例程供程序員調用,int 16h中斷例程中包含的一個重要的功能是從鍵盤緩衝區中讀取一個鍵盤輸入,該功能編號爲0

; 從鍵盤緩衝區中讀取一個鍵盤輸入
; 並將其從緩衝區中刪除
mov ah,0
int 16h
; 結果 (ah)=掃描碼 (al)=ASCII碼

那麼int 16h是如何讀取的,接着上一節

執行

mov ah,0
int 16h

image-20200330213644535

ah中的內容爲1Eh,al中的內容爲61h

執行

mov ah,0
int 16h

image-20200330214414051

執行多次以後

image-20200330214545339

此時再執行

mov ah,0
int 16h

int 16h中斷例程檢測鍵盤緩衝區,發現緩衝區空,則循環等待,直到緩衝區中有數據

按下A鍵後

image-20200330215156951

循環等待的中斷例程檢測到緩衝區中有數據,將其讀出

image-20200330215323257

可見BIOS的int 9和int 16是一對互相配合的程序,但是寫入和讀出的時機不同一個是有鍵按下時執行,一個是應用程序對其進行調用時執行

在編寫處理鍵盤輸入的程序的時候,可以調用int 16h從鍵盤緩衝區中讀取鍵盤的輸入

編程,接收用戶的鍵盤輸入,輸入“r”,將屏幕上的字符設置爲紅色,“g”綠色,“b”藍色

assume cs:code

code segment
	start:	mov ah,0
			int 16h
			
			mov ah,1	; 1表示藍色
			cmp al,'r'
			je red
			cmp al,'g'
			je green
			cmp al,'b'
			je blue
			jmp short sret
			
	  red:	shl ah,1	; 4表示紅色
    green:	shl ah,1	; 2表示綠色
     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
     		
code ends
end start

在int 16h中斷例程中,一定有設置IF=1的指令,因爲當鍵盤緩衝區爲空時,如果設置IF=0,int 9中斷無法執行,循環等待會死鎖

17.3 字符串的輸入

編寫一個接收字符串輸入的子程序,實現3個基本功能:輸入的同時顯示這個字符串,在輸入回車後輸入結束,刪除已經輸入的字符

參數:(dh)、(dl)=字符串在屏幕上顯示的行、列位置,ds:si指向字符串的存儲空間

因爲刪除是從尾開始刪,即後進先出,所以字符串的存儲空間實際是一個字符棧

輸入回車後,在字符串中加0,表示結束

每次有輸入或刪除時,都應該從棧底到棧頂的字符都顯示一遍

這些功能可以編寫爲子程序

(ah)=功能號 0表示入棧,1表示出棧,2表示顯示,(al)=入棧/出棧的字符

getstr:		push ax

getstrs:	mov ah,0
			int 16h
			cmp al,20h
			jb nochar		; ASCII碼小於20h說明不是字符
			mov ah,0
			call charstack	; 字符入棧
			mov ah,2
			call charstack	; 顯示棧中的字符
			jmp getstrs
			
 nochar:	cmp ah,0eh		; 退格鍵的掃描碼
 			je backspace
 			cmp ah,1ch		; Enter鍵的掃描碼
 			je enter
 			jmp getstrs
 			
 backspace:	mov ah,1
 			call charstack	; 字符出棧
 			mov ah,2
 			call charstack	; 顯示棧中的字符
 			jmp getstrs
 			
 	enter:	mov al,0
 			mov ah,0		; 把0入棧
 			call charstack
 			mov ah,2
 			call charstack	; 顯示棧中的字符
 			pop ax
 			ret
 			
 			
charstack:	jmp short charstart

	table	dw charpush,charpop,charshow
	top		dw 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 sret
			
charpop:	cmp top,0		; 判斷當前棧是否爲空
			je sret
			dec top
			mov bx,top
			mov al,[si][bx]
			jmp sret
			
 charshow:	mov bx,0b800h
 			mov es,bx
 			mov al,160
 			mov ah,0
 			mul dh			; (dh)、(dl)分別表示顯示的行、列
 			mov di,ax
 			add dl,dl
 			mov dh,0
 			add di,dx		; di表示要顯示的偏移地址
 			
 			mov bx,0		; 從棧底開始顯示
 			
charshows:	cmp bx,top		; 判斷字符串是否已經全部顯示
			jne noempty
			mov byte ptr es:[di],' '
			jmp 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

image-20200331164451847

17.4 應用int 13h中斷例程對磁盤進行讀寫

以3.5英寸軟盤爲例,分爲上下面,每面80個磁道,每個磁道18個扇區,每個扇區爲512字節

磁盤的訪問由磁盤控制器進行,以扇區爲單位進行磁盤讀寫,讀寫扇區時要給出面號、磁道號和扇區號,面號、磁道號從0開始,扇區號從1開始

我們可以通過調用BIOS提供的中斷例程(int 13h)來訪問磁盤

; 讀取0面0道1扇區的內容到0:200
; es:bx指向接收從扇區讀入數據的內存區
mov ax,0
mov es,ax
mov bx,200h

; (ah)=int 13h的功能號(3表示寫扇區)
; (al)=寫入的扇區數
; (ch)=磁道號
; (cl)=扇區號
; (dh)=磁頭號(面號)
; (dl)=驅動器號 
; 軟驅從0開始	0:軟驅A 1:軟驅B
; 硬盤從80h開始	80h:硬盤C 81h:硬盤D
mov al,1
mov ch,0
mov cl,1
mod dl,0
mov dh,0
mov ah,2
int 13h
; 返回參數:
; 操作成功:(ah)=0 (al)=寫入的扇區數
; 操作失敗:(ah)=出錯的代碼

但是直接向磁盤扇區寫數據是很危險的,必須找一張空閒的軟盤,同時注意驅動器號是否正確

編程:將當前屏幕的內容保存到磁盤中

assume cs:code
code segment
	start:	mov ax,0b800h
			mov es,ax
			mov bx,0
			
			mov al,8	; 一屏4000字節,需要8個扇區
			mov ch,0
			mov cl,1
			mov dl,0
			mov dh,0
			mov ah,3
			int 13h
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章