# 实验九 BIOS中断实验报告 ## 一、实验目的 1. 掌握BIOS中断调用的基本原理和方法 2. 学会使用INT 10H进行屏幕显示和图形操作 3. 学会使用INT 16H进行键盘输入处理 4. 学会使用INT 1AH读取系统时间和日期 5. 掌握通过端口操作控制硬件的方法 ## 二、实验内容 ### 2.1 基础性实验 #### 实验1-1:字符串显示程序 **实验题目**:使用INT 10H的13H功能显示字符串 **程序源码** (string_display.asm): ```asm ; 实验九 - 字符串显示程序 ; 功能: 使用INT 10H的13H功能在屏幕上显示字符串 ; 模式: 文本模式 80x25 彩色 .MODEL SMALL .DATA MSG DB 'Hello, BIOS Interrupt!', 0DH, 0AH, '$' CRLF DB 0DH, 0AH, '$' .CODE .STARTUP MOV AX, @DATA MOV DS, AX ; 设置光标位置 (0, 0) MOV AH, 02H MOV BH, 0 MOV DH, 0 MOV DL, 0 INT 10H ; 使用INT 10H的13H功能显示字符串 MOV AH, 13H MOV AL, 01H MOV BH, 0 MOV BL, 0FH MOV CX, 24 LEA BP, MSG INT 10H MOV AH, 01H INT 21H .EXIT END ``` **说明**:INT 10H的13H功能用于显示带属性的字符串,AL=01H表示字符串包含属性,BL中指定前景色。 --- #### 实验1-2:键盘输入程序 **实验题目**:使用INT 16H读取键盘输入 **程序源码** (keyboard_input.asm): ```asm ; 实验九 - 键盘输入程序 .MODEL SMALL .DATA PROMPT DB 'Please press any key: ', '$' KEY_MSG DB 'You pressed: ', '$' CRLF DB 0DH, 0AH, '$' BUFFER DB 80 DUP(?) .CODE .STARTUP MOV AX, @DATA MOV DS, AX LEA DX, PROMPT MOV AH, 09H INT 21H MOV AH, 10H INT 16H MOV [BUFFER], AL MOV [BUFFER+1], AH LEA DX, CRLF MOV AH, 09H INT 21H LEA DX, KEY_MSG MOV AH, 09H INT 21H MOV AL, [BUFFER] CALL PRINT_CHAR MOV AH, 02H MOV DL, ' ' INT 21H MOV AL, [BUFFER+1] CALL PRINT_HEX MOV AH, 00H INT 16H .EXIT PRINT_CHAR PROC PUSH AX MOV DL, AL MOV AH, 02H INT 21H POP AX RET PRINT_CHAR ENDP PRINT_HEX PROC PUSH CX PUSH DX MOV DL, AL MOV CL, 4 SHR DL, CL CALL PRINT_NIBBLE MOV DL, AL AND DL, 0FH CALL PRINT_NIBBLE POP DX POP CX RET PRINT_HEX ENDP PRINT_NIBBLE PROC PUSH DX CMP DL, 10 JB IS_DIGIT ADD DL, 'A' - 10 JMP PRINT_IT IS_DIGIT: ADD DL, '0' PRINT_IT: MOV AH, 02H INT 21H POP DX RET PRINT_NIBBLE ENDP END ``` **说明**:INT 16H的10H功能读取扩展键盘,00H功能读取基本键盘,返回值AL=ASCII码,AH=扫描码。 --- #### 实验1-3:读取时间程序 **实验题目**:使用INT 1AH读取系统时间 **程序源码** (read_time.asm): ```asm ; 实验九 - 读取时间程序 .MODEL SMALL .DATA TIME_MSG DB 'Current system time: ', '$' HOUR_DB '00', ':', '$' MIN_DB '00', ':', '$' SEC_DB '00', '$' CRLF DB 0DH, 0AH, '$' .CODE .STARTUP MOV AX, @DATA MOV DS, AX MAIN_LOOP: MOV AH, 02H INT 1AH ; DL=日, DH=时, CL=分, CH=秒 (BCD) MOV AL, DH CALL BIN_TO_BCD MOV [HOUR_DB], AH MOV [HOUR_DB+1], AL MOV AL, CL CALL BIN_TO_BCD MOV [MIN_DB], AH MOV [MIN_DB+1], AL MOV AL, CH CALL BIN_TO_BCD MOV [SEC_DB], AH MOV [SEC_DB+1], AL MOV AX, 0600H MOV BH, 07H MOV CX, 0000H MOV DX, 184FH INT 10H MOV AH, 02H MOV BH, 0 MOV DH, 10 MOV DL, 30 INT 10H LEA DX, TIME_MSG MOV AH, 09H INT 21H LEA DX, HOUR_DB MOV AH, 09H INT 21H LEA DX, MIN_DB MOV AH, 09H INT 21H LEA DX, SEC_DB MOV AH, 09H INT 21H MOV CX, 0 MOV DX, 0 MOV AH, 86H INT 15H JMP MAIN_LOOP .EXIT BIN_TO_BCD PROC PUSH DX MOV AH, 0 MOV DL, 10 DIV DL MOV DL, AH MOV AH, AL MOV AL, DL POP DX RET BIN_TO_BCD ENDP END ``` **说明**:INT 1AH的02H功能返回BCD格式时间,需要转换为ASCII字符串显示。 --- #### 实验1-4:声音程序 **实验题目**:通过端口操作产生声音 **程序源码** (sound_porgram.asm): ```asm ; 实验九 - 声音程序 .MODEL SMALL .DATA TONE_DB 200, 400, 600, 800, 1000 COUNT DB 5 .CODE .STARTUP MOV AX, @DATA MOV DS, AX MOV AL, 10110110B OUT 43H, AL LEA SI, TONE_DB MOV CL, [COUNT] TONE_LOOP: LODSB CBW OUT 42H, AL MOV AL, AH OUT 42H, AL IN AL, 61H OR AL, 00000011B OUT 61H, AL MOV CX, 0FFFFH DELAY1: LOOP DELAY1 IN AL, 61H AND AL, 11111100B OUT 61H, AL MOV CX, 0FFFFH DELAY2: LOOP DELAY2 DEC CL JNZ TONE_LOOP MOV AH, 01H INT 21H .EXIT END ``` **说明**:通过端口61H控制扬声器,端口42H设置8253计数器2的频率。频率=1193180/计数值。 --- ### 2.2 加强性实验 #### 实验2-1:图形显示程序 **实验题目**:设置图形模式并画线 **程序源码** (graphics_display.asm): ```asm ; 实验九 - 图形显示程序 .MODEL SMALL .DATA MSG DB 'Press any key to exit...', '$' .CODE .STARTUP MOV AH, 00H MOV AL, 13H INT 10H ; 红色水平线 MOV CX, 20 MOV DX, 50 LINE1: MOV AL, 0FCH MOV AH, 0CH INT 10H INC CX CMP CX, 100 JNE LINE1 ; 绿色垂直线 MOV CX, 150 MOV DX, 30 LINE2: MOV AL, 3FH MOV AH, 0CH INT 10H INC DX CMP DX, 90 JNE LINE2 ; 蓝色斜线 MOV CX, 200 MOV DX, 100 LINE3: MOV AL, 9FH MOV AH, 0CH INT 10H INC CX INC DX CMP CX, 260 JNE LINE3 MOV AH, 00H MOV AL, 03H INT 10H LEA DX, MSG MOV AH, 09H INT 21H MOV AH, 00H INT 16H .EXIT END ``` **说明**:INT 10H的00H功能设置图形模式13H(320x200x256色),0CH功能在图形模式下画点。 --- #### 实验2-2:键盘计数器程序 **实验题目**:统计按键次数 **程序源码** (keyboard_counter.asm): ```asm ; 实验九 - 键盘计数器程序 .MODEL SMALL .DATA TITLE_MSG DB '=== Keyboard Counter ===', 0DH, 0AH, '$' COUNT_MSG DB 'Key presses: ', '$' COUNT_STR DB '00000', '$' .CODE .STARTUP MOV AX, @DATA MOV DS, AX MOV AX, 0600H MOV BH, 07H MOV CX, 0000H MOV DX, 184FH INT 10H LEA DX, TITLE_MSG MOV AH, 09H INT 21H LEA DX, COUNT_MSG MOV AH, 09H INT 21H LEA DX, COUNT_STR MOV AH, 09H INT 21H XOR CX, CX COUNT_LOOP: MOV AH, 01H INT 16H JZ NO_KEY MOV AH, 00H INT 16H CMP AH, 01H JE EXIT_PROGRAM INC CX CALL WORD_TO_STR MOV AH, 02H MOV BH, 0 MOV DH, 2 MOV DL, 12 INT 10H LEA DX, COUNT_STR MOV AH, 09H INT 21H NO_KEY: MOV CX, 0FFFFH DELAY: LOOP DELAY JMP COUNT_LOOP EXIT_PROGRAM: .EXIT WORD_TO_STR PROC PUSH AX PUSH BX PUSH DX MOV AX, CX MOV BX, 10 MOV DX, 0 DIV BX ADD DL, '0' MOV [COUNT_STR+4], DL MOV DX, 0 DIV BX ADD DL, '0' MOV [COUNT_STR+3], DL MOV DX, 0 DIV BX ADD DL, '0' MOV [COUNT_STR+2], DL MOV DX, 0 DIV BX ADD DL, '0' MOV [COUNT_STR+1], DL MOV DX, 0 DIV BX ADD DL, '0' MOV [COUNT_STR], DL POP DX POP BX POP AX RET WORD_TO_STR ENDP END ``` **说明**:INT 16H的01H功能检查是否有按键(ZF=1表示无按键),00H功能读取按键。 --- #### 实验2-3:时钟显示程序 **实验题目**:实时显示系统时间 **程序源码** (clock_display.asm): ```asm ; 实验九 - 时钟显示程序 .MODEL SMALL .DATA TIME_FORMAT DB '00:00:00', '$' TITLE DB '=== Real Time Clock ===', 0DH, 0AH, '$' DATE_FMT DB 'Date: 20XX/XX/XX', '$' .CODE .STARTUP MOV AX, @DATA MOV DS, AX MAIN_LOOP: MOV AH, 02H INT 1AH MOV AL, DH CALL BCD_TO_STR MOV [TIME_FORMAT], AH MOV [TIME_FORMAT+1], AL MOV AL, CL CALL BCD_TO_STR MOV [TIME_FORMAT+3], AH MOV [TIME_FORMAT+4], AL MOV AL, CH CALL BCD_TO_STR MOV [TIME_FORMAT+6], AH MOV [TIME_FORMAT+7], AL MOV AH, 04H INT 1AH MOV AL, CH CALL BCD_TO_STR MOV [DATE_FMT+8], AH MOV [DATE_FMT+9], AL MOV AL, CL CALL BCD_TO_STR MOV [DATE_FMT+12], AH MOV [DATE_FMT+13], AL MOV AL, DH CALL BCD_TO_STR MOV [DATE_FMT+15], AH MOV [DATE_FMT+16], AL MOV AL, DL CALL BCD_TO_STR MOV [DATE_FMT+18], AH MOV [DATE_FMT+19], AL MOV AX, 0600H MOV BH, 07H MOV CX, 0000H MOV DX, 184FH INT 10H MOV AH, 02H MOV BH, 0 MOV DH, 10 MOV DL, 35 INT 10H LEA DX, TITLE MOV AH, 09H INT 21H MOV AH, 02H MOV BH, 0 MOV DH, 12 MOV DL, 35 INT 10H LEA DX, TIME_FORMAT MOV AH, 09H INT 21H MOV AH, 02H MOV BH, 0 MOV DH, 14 MOV DL, 32 INT 10H LEA DX, DATE_FMT MOV AH, 09H INT 21H MOV CX, 0 MOV DX, 0 MOV AH, 86H INT 15H MOV AH, 01H INT 16H JZ MAIN_LOOP MOV AH, 00H INT 16H CMP AH, 01H JNE MAIN_LOOP .EXIT BCD_TO_STR PROC PUSH DX MOV AH, AL AND AH, 0F0H MOV DL, 4 SHR AH, DL ADD AH, '0' MOV DL, AL AND DL, 0FH ADD DL, '0' MOV AL, DL POP DX RET BCD_TO_STR ENDP END ``` **说明**:INT 1AH的02H读取BCD时间,04H读取BCD日期。BCD转ASCII需要分离高低4位并加上'0'。 --- ## 三、思考题 ### 3.1 图形显示程序中如何切换到图形模式? **答**:通过INT 10H的00H功能设置显示模式: ```asm MOV AH, 00H MOV AL, 13H ; 320x200x256色图形模式 INT 10H ``` 切回文本模式:AL=03H ### 3.2 键盘计数器程序中如何检测是否有按键按下? **答**:使用INT 16H的01H功能: ```asm MOV AH, 01H INT 16H JZ NO_KEY ; ZF=1表示无按键 ``` ZF=0表示有按键可用。 ### 3.3 时钟显示程序中如何将二进制时间转换为ASCII字符串? **答**:BIOS返回的是BCD码,需分离高低4位并加上ASCII'0': ```asm MOV AH, AL AND AH, 0F0H ; 取高位 SHR AH, 4 ADD AH, '0' MOV DL, AL AND DL, 0FH ; 取低位 ADD DL, '0' ``` ### 3.4 上述三个程序分别使用了哪些BIOS中断? **答**: | 程序 | 使用的中断 | |------|------------| | 图形显示程序 | INT 10H (00H设置模式, 0CH画点), INT 16H (00H读取按键) | | 键盘计数器程序 | INT 10H (02H光标, 13H显示), INT 16H (01H检查, 00H读取) | | 时钟显示程序 | INT 10H (00H清除, 02H光标, 09H显示), INT 1AH (02H时间, 04H日期), INT 15H (86H延时), INT 16H (01H检查, 00H读取) | --- ## 四、文件清单 | 文件名 | 功能描述 | |--------|----------| | string_display.asm | 字符串显示程序 - 使用INT 10H的13H功能 | | keyboard_input.asm | 键盘输入程序 - 使用INT 16H | | read_time.asm | 读取时间程序 - 使用INT 1AH | | sound_porgram.asm | 声音程序 - 通过端口61H/42H控制扬声器 | | graphics_display.asm | 图形显示程序 - 图形模式13H画线 | | keyboard_counter.asm | 键盘计数器程序 - 统计按键次数 | | clock_display.asm | 时钟显示程序 - 实时显示系统时间 | | REPORT.md | 本实验报告 |