第 9章 BIOS和 DOS中断
9.1 键盘 I/O
9.2 显示器 I/O
9.3 打印机 I/O
9.4 串行通信口 I/O
9.1 键盘 I/O
键盘的中断有 3个:
(1)DOS的 21H号中断,提供功能较强的读键功能;
(2)BIOS的 16H号中断,提供较低层次的服务;
(3)BIOS的 9号中断,这是键盘硬中断,每当键盘上有键被按下,键盘都会通过接口向 CPU提出 9号中断请求。
9.1.1 9号中断与键盘工作原理键盘上的按键分为普通键和控制键两类 。 控制键包括 Shift、
Ctrl,Alt,CapsLock 等,其余为普通键 。
对于每个普通键,根据各键在键盘上的分布位置对键进行编码,得到键盘扫描码 (P317)。 每个键还有 ASCII码 。
当发生 9号中断请求时,表明键盘有按键信息需要送到主机中,
在没有被屏蔽的情况下,CPU将响应该中断,执行一次 9号中断服务程序,处理从键盘传来的信息。
9号中断服务程序的功能主要有:如果是控制键被按下或松开,
就把 BIOS数据区中的键盘状态字节作相应调整;如果是普通键,则把按键的扫描码和 ASCII码一起存入键盘缓冲区。
计算机启动后,在内存较低端 (物理地址 400H起,紧接在中断向量表的后面 )有一段供 BIOS使用的数据区,其中包括存放各控制键状态的键盘状态字节和存放普通键的 32字节键盘缓冲区。
键盘缓冲区是一个先进先出的环形队列,共 32字节,可以存放 15个键的扫描码和 ASCII码。其所占内存区域如下:
KBHead DW? ;其内存地址为 0000:041AH,缓冲区头指针
KBTail DW? ;其内存地址为 0000:041CH,缓冲区尾指针
KBBuff DW 16 DUP(?);其内存地址为 0000:041EH,
读键时可以从队列首部取走键值,9号中断则把新的按键置入队列尾部。
当键盘缓冲区已满,而键盘上还有普通键被按下时,键盘仍然会提出中断申请,但 9号中断的服务程序中会忽略该按键,并使计算机的小喇叭发出,嘀,的一声,以表示缓冲区已满。
表 9.4 状态字节与控制键的对应关系位号 7 6 5 4 3 2 1 0
控制键 Insert CapsLock Num Lock Scroll Lock Alt Ctrl 左 shift 右 shift
键盘状态字节在物理地址 417H处,每一位代表一个控制键,
为 1表示该键处于按下的状态,为 0则是松开的。状态字节的各个位与控制键的对应关系见表 9.4。
9.1.2 BIOS键盘中断
16H号中断是 BIOS提供给用户程序使用的一个软件中断,
以 INT 16H指令调用,提供基本的键盘服务,包括读键,判断有无普通键按下,读取控制键的状态等子功能 。
1,0号子功能 ──读普通键如果键盘缓冲区不空,则从缓冲区的环型队列首部取走一个按键,把按键的扫描码放到 AH中,ASCII码放到 AL中作为出口参数;
如果键盘缓冲区是空的,则等待有效按键输入 。
2,1号子功能 ──不改变缓冲区的读键当键盘缓冲区中还存放有没取走的有效按键时,出口参数中 ZF=0,AX=扫描码与 ASCII码 。
如果键盘缓冲区已空,则 ZF=1表示无键可读 。
1号子功能与 0号的差别 。
首先,在缓冲区为空时,0号子功能将等待按键,1号子功能则不等待,而是以 ZF置 1表示 ( 这是很多电脑游戏软件典型的读键方式 ) 。
其次,如果缓冲区不空,0号子功能会取走该键,而 1号子功能并不取走,只把它复制到 AX中 。
3,2号子功能 ──读控制键状态直接从 BIOS数据区中复制出键盘状态字节的值,放到
AL中作为出口参数 。
4,10H号子功能 ──读键并清除键盘缓冲区读键的情况与 0号子功能完全相同,10H号子功能在读完键后还会清除键盘缓冲区中剩余的所有按键数据。
9.1.3 DOS的输入子功能
DOS提供的输入子功能见 P320。
1,7号子功能 ──无回显输入直接调用前面所说的 16H号中断的 0号子功能 。
2,8号子功能 ──无回显输入
7号非常接近,只是对按键增加了 Ctrl+Break的处理 。
3,0AH号子功能 ──输入字符串 ( P321)
读入一串字符并存入用户定义的缓冲区中 。
4,0BH号子功能 ──判断按键状态用于判断键盘缓冲区是否为空,出口参数是:
当键盘缓冲区不空时,AL= 0FFH;
当键盘缓冲区为空时,AL≠0FFH。
5,0CH号子功能 ──清除键盘缓冲区后再读键入口参数:
AH= 0CH;
AL=清除缓冲区后再执行的功能号,可以是 1,7,8。
出口参数:
按 AL中的功能号,与 DOS的 3个子功能出口参数对应相同 。
先把键盘缓冲区清空,然后再根据 AL中的值,执行 DOS
的 1号,7号或 8号子功能 。
9.2.4 封锁键盘的方法封锁键盘就是让键盘不能工作,使系统不能接收从键盘输入的数据 。
屏蔽键盘中断有两种方法:一是把标志寄存器中的 IF标志位清 0,二是利用系统的中断控制器 。
封锁键盘的程序段:
IN AL,21H
OR AL,00000010B
OUT 21H,AL
例 9.1 用键盘最多输入 10个字符,并存入内存变量 Buff中,若按,Enter”键,
则表示输入结束。
1、方法 1
.MODEL SMALL
CR EQU 0DH ;定义“回车”键的符号名
.DATA
Buff DB 10 DUP(?)
.CODE
,STARTUP ;p127
MOV CX,0AH
LEA BX,Buff
LP,MOV AH,0H
INT 16H ;用 BIOS中的中断功能
CMP AL,CR
JZ EXIT
MOV [BX],AL
INC BX
LOOP LP
EXIT,.EXIT 0
END
2、方法 2
.MODEL SMALL
.DATA
Buff DB 10,?,10 DUP(?) ;注意缓冲区的定义方式
.CODE
.STARTUP
LEA DX,Buff
MOV AH,0AH
INT 21H ;用 DOS中的功能调用
.EXIT 0
END
9.2 显示器 I/O
常用的显示分辨率为 800× 600或 1024× 768等。
常用的显示卡类型为 VGA,SVGA,EVGA和 TVGA等。
1、显示模式计算机系统中的显示器都有二种显示方式:文本显示方式和图形显示方式。在 DOS操作系统环境下,其默认的显示方式为文本显示方式,而在 Windows操作系统环境下,其显示方式是图形显示方式,其绝大多数操作界面是以图形界面的窗口形式出现的。
1)、文本显示方式在常用的文本显示模式 (模式 3)下,每屏最多可显示
2000(80× 25)个字符。
规定:屏幕的左上角坐标为 (0,0),右下角坐标为 (24,79)。
在显示字符时,用一个字节存储该字符的 ASCII码,用另一个字节存储的显示属性,即:显示颜色。
彩色显示器的字符显示属性定义如图 (P325)
存储内容与显示位置的对应关系下如图,
2)、图形显示方式图形显示的最小单位是象素,对每个象素可用不同的颜色来显示。所以,在显示缓冲区内记录的信息是屏幕各象素的显示颜色。
由于各种图形显示模式所能显示的颜色和象素是不同的,它决定了显示缓冲区的存储方式也是不同的。下面给出一个具体的图形显示模式及其存储方式。
256色 320× 200图形显示模式表达 256种不同颜色需要 8位二进制,即一个字节。在该模式下,其显示缓冲区的存储方式是非常简单的,即:
第一个字节存储第一个象素的颜色,第二个字节存储第二个象素的颜色,以此类推,
所以,存储满屏象素所需要的字节数为,320× 200× 1
= 64000。其显示缓冲区的存储方式如图 8.10所示。
2、显示缓冲区显示缓冲区是用来记录屏幕显示信息的。
在文本显示方式下,显示信息包括:每个显示字符的 ASCII
码及其显示属性。
在图形显示方式下,显示缓冲区内存储每个象素的显示颜色。
文本显示方式下,单色显示器的显示缓冲区段地址为 0B000H;
文本显示方式下,彩色显示器显示缓冲区段地址为 0B800H;
图形显示方式下,其显示缓冲区段地址为 0A000H。
9.2.1 BIOS的 10H号中断服务程序
9.2.1.1 对光标的控制
1,改变光标的大小
CX= 0E0FH,光标是在字符下部的一条小短线;
CX= 080FH,光标是下半格的小方块;
CX= 0102H,光标是在字符上部的一条小短线;
CX= 0FFFFH,消隐光标,即不显示闪烁的光标 。
2,改变光标的位置其入口参数是:
AH= 2,子功能号;
BH=显示页的页号;
DH=光标移动到哪一行,屏幕顶端为第 0行;
DL=光标移动到哪一列,屏幕左端为第 0列。
3,读光标位置入口参数:
AH= 3,子功能号;
BH=显示页的页号 。
出口参数:
DH/DL=该显示页的光标所在行 /列坐标;
CH/CL=该显示页的光标起始线 /结束线 。
9.2.1.2 清屏与卷屏
AH= 6/7,子功能号,6为上卷屏,7为下卷屏;
AL=卷动行数,若 AL为 0则为清屏;
BH=卷动后留出的空白部分的属性;
CH/CL=左上角的行 /列坐标;
DH/DL=右下角的行 /列坐标。
下面的程序段可以把屏幕设置成中间是绿色,四周是蓝色的无字画面 。
MOV AX,600H
MOV BH,1FH
XOR CX,CX ;屏幕左上角坐标
MOV DX,184FH ;屏幕右下角坐标
INT 10H ;用蓝底白字把指定窗口清屏
MOV BH,2FH
MOV CX,408H ;窗口左上在第 4行,第 8列
MOV DX,1447H ;窗口右下在第 20行,第 71列
INT 10H ;用绿底白字把指定窗口清屏
【 例 9.2】 清屏,并为整个屏幕画一个蓝底白字的外框 。
【 解 】
disp MACRO x,y ;定义一个重复使用的程序段为一个宏
MOV AL,x
MOV DX,y
CALL onechar
ENDM
code SEGMENT
ASSUME CS:code
clrscr PROC NEAR ;以蓝底白字属性清屏子程序
MOV AX,600H
MOV BH,1FH
XOR CX,CX
MOV DX,184FH
INT 10H
RET
clrscr ENDP;入口,AL=待显示字符,DX=显示的位置
Onechar PROC NEAR
PUSH AX
MOV AH,2
MOV BH,0
INT 10H ;移动光标到 DX指定的位置
POP AX
MOV CX,1
MOV BL,1FH
MOV AH,9
INT 10H ;在当前光标处显示 AL中的字符,只显示一个
RET
onechar ENDP
start,CALL clrscr ;清屏
disp 218,0 ;显示外框的左上角
disp 191,4FH ;显示外框的右上角
disp 192,1800H ;显示外框的左下角
disp 217,184FH ;显示外框的右下角
MOV AH,2
MOV DX,1
INT 10H ;移光标到第 0行第 1列
MOV AX,9C4H
MOV BL,1FH
MOV CX,78
INT 10H ;显示 78个小短线,是外框的顶部
MOV AH,2
MOV DX,1801H
INT 10H ;移光标到第 24行第 1列
MOV AX,9C4H
MOV CX,78
INT 10H ;显示 78个小短线,是外框的底部
MOV SI,100H ;取第 1行第 0列的位置
s1,disp 179,SI ;以 SI高 /低 8位作为行 /列坐标,显示一个小竖线
ADD SI,100H ;表示行数的高 8位加 1
CMP SI,1800H
JB s1 ;没到最底一行转
MOV SI,14FH ;取第 1行第 79列的位置
s2,disp 179,SI ;以 SI高 /低 8位作为行 /列坐标,显示一个小竖线
ADD SI,100H
CMP SI,1800H
JB s2
MOV AH,0
INT 16H ;保持屏幕上的状态,等待按键
MOV AH,4CH
INT 21H
code ENDS
END start
【 例 9.3】 设计一个输入并验证口令的程序,口令可以预置在程序中 。
【 解 】
data SEGMENT
buf DB 201,21 DUP(205),187,'$'
DB 186,' PASSWORD,',186,'$'
DB 200,21 DUP(205),188,‘$’ ; 定义画方框的字符串
pass DB '12345678'
inpass DB 8 DUP(0)
passlen DW 0
msg1 DB 'PASSED !$ '
msg2 DB 'FAILED !$ '
data ENDS
code SEGMENT
ASSUME CS:code,DS:data
clrscr PROC NEAR ;以蓝底白字清屏
MOV AX,600H
MOV BH,1FH
XOR CX,CX
MOV DX,184FH
INT 10H
RET
clrscr ENDP
disp PROC NEAR ;显示输入口令的画面
MOV CX,3
LEA BX,[buf]
d1,MOV AL,3
SUB AL,CL
ADD DH,AL
MOV AH,2
INT 10H ;移动光标到第 AL+12行,第 28列
MOV DX,BX
MOV AH,9
INT 21H ;显示方框的一行
ADD BX,24 ;使 BX指向下方框符号串 buf的下一行
LOOP d1 ;3次循环,在屏幕中心显示加框的
PASSWORD字样
RET
MOV DX,0B1CH
disp ENDP
pwd PROC NEAR ;输入口令子程序
XOR BX,BX
p0,MOV DX,0C29H
ADD DX,BX
MOV AH,2
INT 10H ;移动光标到正确位置
MOV AH,0
INT 16H ;等待按键
CMP AL,8
JNZ p1 ;不是退格键转
AND BX,BX
JZ p0 ;已到最左边,不能退格转
DEC BX
MOV AH,2
MOV DL,8
INT 21H
MOV DL,' '
INT 21H ;退一格,清除前一格上的星号
JMP p0
p1,CMP AL,0DH
JZ p3 ;是回车键转
MOV [inpass+BX],AL ;把按键作为一个口令字符送入 inpass变量中
MOV AH,2
MOV DL,'*'
INT 21H ;显示一个星号,光标后移
INC BX
CMP BX,8
JB p0 ;不足 8个符号转
p3,MOV [passlen],BX ;记载口令长度
RET
pwd ENDP;出口,CF= 0,口令正确; CF= 1,口令错误
check PROC NEAR ;验证口令子程序
MOV CX,[passlen] ;取输入口令长度
CMP CX,8
JB c1 ;小于 8转
LEA SI,pass
PUSH DS
POP ES
LEA DI,inpass
CLD
REP CMPSB
STC ;置口令错标记,作为出口参数
JNZ c1 ;口令错误转
CLC ;置口令正确标记
c1,RET
check ENDP
start,MOV AX,data
MOV DS,AX
CALL clrscr
CALL disp
CALL pwd
CALL clrscr
CALL check
JC s1
LEA DX,msg1
JMP s2
s1,LEA DX,msg2
s2,MOV AH,9
INT 21H ;显示验证口令的结果
MOV AH,4CH
INT 21H
code ENDS
END start
【 例 9.4】 设计一个菜单控制程序,在屏幕的第 1行显示有若干功能项的菜单条,用左右箭头控制亮条的移动 。 当亮条移到某一选项后,可以按回车键表示选中该项功能 。 把最后一个选项定为,退出,,选中该项后程序结束 。
【 解 】
itemnum = 5 ;菜单由 5项组成
itemlen = 8 ;每个功能项字符串长度为 8
data SEGMENT
buf DB 'Menu Item Number selected,[ ]$ '
data ENDS
stack SEGMENT STACK
DW 4096 DUP(?)
stack ENDS
code SEGMENT
ASSUME CS:code;=============================================; 改变变量 menubar中的菜单项颜色;=============================================;入口,AL = 菜单项号码,0到 itemnum-1之间; DL = 新的颜色属性值;=============================================
ASSUME DS:code
menuattr PROC NEAR
PUSH BX
PUSH CX
MOV BL,(itemlen+2)*2
MUL BL
MOV BX,AX
INC BX ;计算需要改变颜色的字符位置
MOV CX,itemlen+2
attr1,MOV [menubar+BX],DL ;设置成新的颜色
INC BX
INC BX
LOOP attr1
AND DL,40H
OR DL,3CH ;设置热键的颜色
MOV [menubar+BX-itemnum*2-6],DL
POP CX
POP BX
RET
menuattr ENDP;=============================================; 菜单控制子程序;=============================================; 出口参数,AL=选中的菜单项号码;=============================================
MENU PROC NEAR
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSH DS
PUSH ES
CLD
MOV AX,code
MOV DS,AX
MOV AX,0B800H ;彩色显示器的显示缓冲区段地址
MOV ES,AX
XOR DI,DI
MOV AX,7020H
MOV CX,80
REP STOSW ;清屏幕第 0行
MOV AL,[itemc]
MOV DL,70H ;白底黑字属性
CALL menuattr
MOV CS:[itemc],0
menu0,MOV AL,[itemc]
MOV DL,3FH ;湖蓝底色,白字
CALL menuattr ;置当前菜单项为 itemc记载值
menu1,XOR DI,DI
LEA SI,menubar
MOV CX,itemnum*(itemlen+2)
REP MOVSW ;直写屏方式显示
XOR AX,AX
INT 16H ;等待按键
CMP AX,4B00H ;左箭头
JNZ menu2
MOV AL,[itemc]
MOV DL,70H ;白底黑字
CALL menuattr
DEC [itemc] ;记载当前菜单项的变量值减 1,左移一项
CMP [itemc],0
JGE menu1a
ADD [itemc],itemnum ;小于 0则移到最右一项上
menu1a,MOV AL,[itemc]
MOV DL,3FH ;湖蓝底色,白字
CALL menuattr
JMP menu0
menu2,CMP AX,4D00H ;右箭头
JNZ menu3
MOV AL,[itemc]
MOV DL,70H
CALL menuattr
INC [itemc] ;记载当前菜单项的变量值加 1,
右移一项
CMP [itemc],itemnum
JB menu1b
MOV [itemc],0 ;从最右一项再右移,则移到最左一项
menu1b,MOV AL,[itemc]
MOV DL,3FH
CALL menuattr
JMP menu0
menu3,CMP AL,0DH ;回车键
JZ menu4
MOV AH,2
MOV DL,7
INT 21H ;按键错,发声警告
JMP menu0
menu4,MOV AL,[itemc]
POP ES
POP DS
POP DI
POP SI
POP DX
POP CX
POP BX
RET
menubar DB ' ',70H,' (',70H,'1',7CH,') ',70H,'I',70H
DB 't',70H,'e',70H,'m',70H,'1',70H,' ',70H
DB ' ',70H,' (',70H,'2',7CH,') ',70H,'I',70H
DB 't',70H,'e',70H,'m',70H,'2',70H,' ',70H
DB ' ',70H,'(',70H,'3',7CH,') ',70H,'I',70H
DB 't',70H,'e',70H,'m',70H,'3',70H,' ',70H
DB ' ',70H,'(',70H,'4',7CH,') ',70H,'I',70H
DB 't',70H,'e',70H,'m',70H,'4',70H,' ',70H
DB ' ',70H,'(',70H,'5',7CH,') ',70H,'I',70H
DB 't',70H,'e',70H,'m',70H,'5',70H,' ',70H
itemc DB itemnum-1
MENU ENDP
ASSUME DS:data
main,MOV AX,DATA
MOV DS,AX
MOV AH,1
MOV CX,-1
INT 10H ;消隐光标
MOV AX,600H
MOV BH,17H
XOR CX,CX
MOV DX,184FH
INT 10H ;清屏
next,CALL MENU
CMP AL,itemnum-1
JE finish ;选中最右一项则结束
ADD AL,31H
MOV [buf+30],AL
MOV AH,2
MOV DX,1212H
XOR BH,BH
INT 10H ;移动光标到第 18行 18列
LEA DX,[buf]
MOV AH,9
INT 21H ;显示刚才选中的是第几项
JMP next
finish,MOV AX,600H
MOV BH,7
XOR CX,CX
MOV DX,184FH
INT 10H ;清屏
MOV AH,1
MOV CX,0F0FH
INT 10H ;显示光标
MOV AX,4C00H
INT 21H
code ENDS
END main
9.3 打印机 I/O
打印输出是一种硬拷贝输出,也是一种常用的输出形式。
1、打印控制命令字符值 功能描述
09H 水平制表符,跳到下一个制表位置
0AH 换行
0CH 换页
0DH 回车
2,DOS功能中的打印输出 (P337)
在 DOS操作系统中,INT 21H提供了一种打印输出的功能调用。其具体描述如下:
05H—— 向连接在 LPT1端口上的打印机输出一个字符
40H—— 向先前打开的文件写入指定数量的字节,可以把打印机看作为标准的输出文件
3,BIOS中的打印输出 (P337)
BIOS系统提供了中断 17H来实现打印输出功能。其具体的功能如下:
00H—— 向指定的打印机输出一个字符
01H—— 初始化指定的打印机
02H—— 读取指定打印机的状态例 1 在每页的开始处打印,Assember Language”字符串,并空一行才打印其它内容。
.MODEL SMALL
.DATA
Title1 DB 0CH,"Assember Language",0DH,0AH,0AH
Count EQU $ - Title1
.CODE
.STARTUP
……
MOV AH,1
MOV DX,0
INT 17H ;初始化连接在 LPT1上的打印机
……
MOV CX,Count ;待打印的字符个数
XOR BX,BX
again,MOV AH,5H
MOV DL,Title1[BX]
INT 21H ;调用 DOS功能打印字符
INC BX
LOOP again
…… ; 可在此打印其它任意字符
.EXIT 0
END
例 2 当打印机不能正常打印 (非硬件故障 )时,提示使用者其原因,以便解决打印问题。
.MODEL SMALL
.DATA
MSG1 DB "Time Out$”
MSG2 DB "I/O Error$”
MSG3 DB "Out of Paper$”
TOut EQU 01H
IOErr EQU 08H
Opaper EQU 20H (P287)
.CODE
.STARTUP
……
MOV AH,1
MOV DX,0
INT 17H ;初始化连接在 LPT1上的打印机
……
MOV AH,2
MOV DX,0
INT 17H ;读取 LPT1打印机的状态字节
TEST AL,TOut or IOErr or OPaper
JNZ ErrMsg
……
ErrMsg:
TEST AL,TOut
JZ next1
LEA DX,MSG1 ;Time Out
JMP disp
next1,
TEST AL,IOErr
JZ next2
LEA DX,MSG2 ;I/O Error
JMP disp
next2:
LEA DX,MSG3 ;Out of Paper
disp:
MOV AH,9H
INT 21H
……
.EXIT 0
END
9.4 串行通信口的中断功能
1,DOS中的通信功能
INT 21H提供了对通信口 COM1操作的功能调用。
03H—— 从辅助设备读入一个字符,该辅助设备的缺省值 为
COM1
04H—— 向辅助设备输出一个字符,该辅助设备的缺省值为
COM1
2,BIOS中的通信功能
BIOS系统提供了中断 14H来实现对通信端口的控制能。 (P350)
00H—— 初始化通信口
01H—— 向通信口输出字符
02H—— 从通信口读入字符
03H—— 读取通信口状态例 1 把字符串 "Hello,World"从 COM1端口传输出去。在传输过程中,要求传输速率为 9600波特,字长为 8位,1位停止位,无齐偶校验。
.MODEL SMALL
.DATA
MSG DB "Hello,World"
MLen EQU $-MSG
.CODE
.STARTUP
MOV AL,0E3H ;0E3— 9600、无齐偶校验、字长 8位,1位停止位 (P351)
MOV DX,0
MOV AH,0
INT 14H ;初始化通信口 COM1
MOV BX,OFFSET MSG
MOV CX,MLen
MOV DX,0
again:
MOV AL,[BX]
MOV AH,1
INT 14H
TEST AH,80H ;如果发送字符失败,继续发同一个字符,这里可能
JNZ again ;构成死循环。在实际工作过程中,还有其它考虑。
INC BX
LOOP again
.EXIT 0
END
例 2 把从 COM1端口读入的字符显示在屏幕上。如果通信端口数据未准备好,则程序处于等待状态;若传输出错,则用红色显示字符 "?"。
……
Again,MOV DX,0
MOV AH,3
INT 14H
TEST AH,1H ;检测状态字节 AH的最后一位,
看数据是否准备好 (P351)
JZ again
MOV DX,0
MOV AH,2
INT 14H ;从 COM1端口读字符
TEST AH,80H ;检测读字符是否成功
JNZ ERROR ;读字符失败,转
MOV BL,15 ;正常颜色:白色
JMP DISP
ERROR,MOV AL,'? ' ;显示字符 "?"
MOV BL,12 ;错误颜色:红字
JMP again
DISP:
MOV BH,0
MOV AH,0EH ;显示字符
INT 10H
JMP again
……