第17 使用BIOS进行键盘输入和磁盘读写

转载:http://www.cnblogs.com/dennisOne

☞使用BIOS进行键盘输入和读取键盘缓冲区

  1. 复习键盘缓冲区和状态字节
    (1). BIOS键盘缓冲区是系统启动后,BIOS用于存放int 9中断例程所接受的键盘输入的内存区。键盘缓冲区有16个字单元,可以存储15个按键的扫描码和对应的ASCII码,高位字节是扫描码,低位字节是字符码。
    (2). 状态字节存放在0040:17单元。该字节记录了控制键和切换键的状态。

  2. int 9中断例程
    键盘输入将引发9号中断,BIOS提供了int 9中断例程。CPU在9号中断发生后,执行9号中断例程,从60号端口读出扫描码,将其转化为相应的ASCII码或者状态信息,存储在内存的指定空间(键盘缓冲区或状态字节)中。
    eg:简述Shift_A
    (1). 按下左Shift键,引发键盘中断;int 9中断例程接受左Shift键的通码,设置0040:17处的状态字节的第1位为1,表示左Shift键按下。
    (2). 按下A键,引发键盘中断;CPU执行int 9中断例程,从60h端口读出A键的通码;检测状态字节,看看是否有切换键按下,发现左Shift键被按下,则将A键的扫描码1Eh和Shift_A对应的ASCII码,即大"A"的ASCII码41h,写入键盘缓冲区。
    (3). 松开左Shift键,引发键盘中断;int 9中断例程接受左Shift键的断码,设置0040:17处的状态字节的第1位为0,表示左Shift键松开。

  3. 使用int 16h中断例程读取键盘缓冲区
    mov ah, 0
    int 16h
    结果: (ah)=扫描码,(al)=ASCII码。
    int 16h中断例程检测键盘缓冲区,发现缓冲区空,则循环等待,直到缓冲区中有数据。
    第17 使用BIOS进行键盘输入和磁盘读写

  4. int 9 中断例程和int 16h 中断例程 是一对相互配合的程序。int 9 中断例程向键盘缓冲区中写入,int 16 例程 从缓冲区读出

☞模拟dos的字符串输入程序
第17 使用BIOS进行键盘输入和磁盘读写
tips:
(1)在数据读入的时候,采用队列的形式。先进,先读取。
(2)在数据操作(删除)的时候,采用栈的形式。后进,先删。

代码
下面的程序写的非常漂亮。
(1)用ds指向段地址,si指向栈底,top指向栈顶。此时si有点像数组的首地址。回想一下,ss:sp,由于没有栈底,只有栈顶,无法判断是否越界。
(2) 这次程序中使用的是 jmp word ptr table[bx] 。上一张的大程序,用的是call。这也是处理标号常量的一种思路,当然在这次的代码中没有涉及到而已。它让所有的程序都从结尾处返回。调用函数的时候,用call和jmp都有他们的好处。但是我个人爱好call。比较统一。

assume cs:code, ds:data
    
    data segment
        dw 100 dup (0)   ; 模拟读取字符的栈
    data ends
    
    code segment
    start:
            mov ax, data
            mov ds, ax
            mov si, 0
            ; 将ds:si设置为存放字符的栈
            call getstr
    return:
            mov ax, 4c00h
            int 21h
            
    ; 完整的接受字符串输入的子程序
    getstr:
            push ax
    
    getstrs:
            mov ah, 0
            int 16h
            cmp al, 20h
            jb nochar                        ; ASCII码小于20h, 说明不是字符
            
            ; 字符的处理分为两步,1:入栈,2:显示栈中的字符
            mov ah, 0                        ; 1: 字符入栈
            call charstack
            mov ah, 2                        ; 2: 显示栈中的字符
            call charstack
            jmp getstrs
                    
    nochar:    
            cmp ah, 0eh                    ; 退格键的扫描码
            je backspace
            cmp ah, 1ch                    ; Enter键的扫描码
            je enters
            jmp getstrs                    ; 其他控制键忽略
    
    backspace:
            mov ah, 1
            call charstack                    ; 字符出栈
            mov ah, 2
            call charstack                    ; 字符显示
            jmp getstrs
    
    enters:
            mov al, 0
            mov ah, 0
            call charstack                    ; 0入栈
            mov ah, 2
            call charstack                    ; 显示栈中的字符串
            
            pop ax
            ret
            
    
    ; 子程序: 字符栈的入栈、出栈和显示
    ; 参数说明:(ah)=功能号,0表示入栈,1表示出栈,2表示显示
    ; ds:si指向字符栈的空间
    ; 对于0号功能:(al)=入栈字符;
    ; 对于1号功能: (al)=返回的字符;
    ; 对于2号功能:(dh)、(dl)=字符串在屏幕上显示的行、列位置。
    
    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
                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:   ;(dh)、(dl)=字符串在屏幕上显示的行、列位置。
                cmp bx, 0b800h
                mov es, bx
                mov al, 160
                mov ah, 0
                mul dh
                mov di, ax
                add dl, dl
                mov dh, 0
                add di, dx        ; 设置 es: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
    
    code ends

end start

☞对磁盘进行读写实验:略

上一篇:再见,网易云音乐!


下一篇:电池容量单位 Wh和 Ah的关系