1. 课程说明
本课程基于《汇编语言(第 2 版)》郑晓薇 编著,机械工业出版社,可以配合该教材使用。本课程由郑晓薇授权制作,提取教材中的实例以及实验内容,可以在实验楼环境中完成所有实例及实验。实验课程制作符合教材原版实例驱动教学以及实验训练贯穿始终的特点。
本教材可在 当当网 购买(点击链接即可进入购买页面)。
本课程实验列表中的最后模块为配套教材的习题参考答案,可供读者学习参考。
2. 实验环境
DOS 环境:
实验环境中安装有 dosemu
可以模拟 DOS 环境,并提供 DEBUG
、MASM
、LINK
等汇编语言开发程序。
3. 综合实验说明
汇编语言是一门理论与实践相结合的课程,只有在大量的编程训练下,才能很好地掌握基础理论与编程技巧。
本章先介绍 I/O 端口实验、图形动画实验以及磁盘文件读写实验,再给出综合实验题目及实验要求。
通过学习和实践,为下一步学习操作系统、微机原理与接口技术、单片机原理与应用、嵌入式课程等打下良好的基础,也为读者计算机程序设计能力的增强、编程视野的拓展提供帮助。
4. I/O 端口实验
本例子为教材的示例 10-1。
设计目标
利用 I / O 指令读取 CMOS 实时钟值,将时间显示出来。
设计思路
- (1)将 CMOS 中存放小时、分、秒单元的地址值分别输出到地址端口 70H,再从数据端口 71H 中读入时间值;
- (2)读入的 BCD 码的高 4 位是十进制的十位,低 4 位为十进制的个位,分别加上 30H 变为 ASCII 码;
- (3)将 DOS 的 2 号显示功能定义为宏 DISPL,用宏调用显示时间值。
- (4)采用循环方式执行写地址端口 70H、读取数据端口 71H 的程序段,简化程序结构。代码实现
程序如下:
;10-1.asm 利用I/O指令读取CMOS实时钟值,并显示出来。
displ macro opr ;宏DISPL
mov ah,2
mov dl,opr
int 21h
endm
.model small
.data
time1 db ?
time2 db ?
n db 4
.code
start:
mov ax,@data
mov ds,ax
lll:
mov al,n ;n=4、2、0,为时、分、秒单元地址
out 70h,al ;输出到地址口
in al,71h ;从数据口读取小时、分、秒
mov ah,al ;al=压缩BCD码,如15点00010101
mov cl,4
shr ah,cl ;ah右移4位,高4位→低4位00000001
add ah,30h ;ASCII码
and al,0fh ;保留个位数
add al,30h ;ASCII码
mov time1,ah
mov time2,al
displ time1 ;显示十位
displ time2 ;显示个位
sub n,2 ;下一个地址
js exit
displ ':' ;显示:
jmp lll
exit:
mov ah,4ch
int 21h
end start
运行结果:
5. 随机数实验
本小节有两个实验,分别是:
- 用 CMOS 时钟产生随机数
- 用 DOS 时间功能出算术题
5.1 用 CMOS 时钟产生随机数
本例子为教材的示例 10-2。
设计目标
利用 CMOS 实时钟产生 5 组 0-255 随机数。
设计思路
- (1) CMOS 中存放秒单元的地址值 0 输出到地址端口 70H,再从数据端口 71H 中读入秒值到 AL 寄存器;
- (2) 产生随机数 0-255,方法为 AL=AL+12,再将 AL 循环左移 4 次;
- (3) 调用 DISP_2_10 子程序显示随机数;
- (4) 利用宏库 9-4.MAC;
- (5) 延迟后再次读该端口,将读入的秒值生成下一个随机数,共生成 5 个。
实现代码
程序如下:
;10-2.asm 利用I/O指令读取CMOS实时钟值秒值,生成0-255随机数。
include 9-4.mac
.model small
.data
n db 5
.code
start:
mov ax,@data
mov ds,ax
let0:
xor ax,ax
;产生随机数
mov al,0 ;秒单元地址=0
out 70h,al ;输出到地址口
in al,71h ;从数据口读取秒值
add al,12 ;+12
mov cl,4 ;循环左移4次
rol al,cl
mov bx,ax
call disp_2_10
enter ;回车换行宏
;延时
mov cx,30000
rept1:push cx
rept2:loop rept2
pop cx
loop rept1
dec n
jnz let0
exit:
mov ah,4ch
int 21h
;子程序。2-10进制数显示。一个bx值,显示十进制结果。
disp_2_10 proc
store_ss ;保护现场
mov ax,bx ;bx传参
mov cx,0
mov bx,10 ;将ax变为十进制数
let1:
mov dx,0
inc cx ;统计余数个数
idiv bx
push dx ;保存余数
cmp ax,0
jnz let1
let2: ;显示结果
pop ax ;将余数弹入ax
add ax,0030h ;调整为ascii码
displ al ;显示一个数字
loop let2
restore_ss
ret
disp_2_10 endp
end start
运行结果:
5.2 用 DOS 时间功能出算术题
本例子为教材的示例 10-3。
设计目标
DOS 中断 INT 21H 的 2CH 功能可以获得系统时间的百分秒,可直接作为 0-99 随机数。由于该值是十六进制数,要经过转换后用十进制显示。利用该功能经变换后扩大或缩小倍数可得到任意位的随机数值。
利用 INT 21H 的 2CH 功能读出百分秒作为 0~99 的随机数,并在第 5 行 30 列上显示出 3 道加法题。可从键盘输入计算结果。
设计思路
- (1) 用 2CH 功能读出的百分秒值在 DL 寄存器中,作为一个随机数;
- (2) 用子程序 disp_2_10 将随机数转换成十进制并显示;
- (3) 利用第 9 章中的 9-4.mac 宏库清屏、置光标、显示单字符;
- (4) 在两个随机数之间要加上一段延时,以保证两个数不重复。
实现代码
程序如下:
;10-3.asm 用INT 21H的2CH功能读出百分秒作为随机数0-99,出加法题。
include 9-4.mac ;调入宏库
.model small
.data
exer db 'x+y=','$'
persec db ?
answer db 5,?,6 dup(?) ;保存键入的计算结果
n db 3 ;出3道题
han db 5 ;第5行
.code
start:
mov ax,@data
mov ds,ax
clearsc ;清屏
rept0:
enter ;回车换行
cursor han,30 ;置光标(5,30)
mov ah,9 ;显示提示
mov dx,offset exer
int 21h
;读时间并显示
mov ah,2ch ;CH=小时,CL=分,DH=秒,DL=百分秒
int 21h
mov persec,dl ;将百分秒作为随机数
;调用2-10显示子程序
mov bl,persec
call disp_2_10 ;显示随机数1
displ '+' ;显示+
;延时后再读下一百分秒
mov cx,10000 ;延迟计数
lot1:push cx
lot2:loop lot2
pop cx
loop lot1
mov ah,2ch ;读百分秒
int 21h
mov bx,0
mov bl,dl ;dl=百分秒
call disp_2_10 ;显示随机数2
displ '=' ;显示=
mov dx,offset answer ;10号功能,从键盘输入计算值
mov ah,10
int 21h
dec n ;循环出n=3道题
cmp n,0
jz out1
inc han ;算题显示在下一行
jmp rept0
out1:
mov ah,4ch
int 21h
;子程序。2-10进制数显示。一个bx值,显示十进制数。
disp_2_10 proc
store_ss ;保护现场
mov ax,bx ;bx传参
mov cx,0
mov bx,10 ;将ax变为十进制数
let1:
mov dx,0
inc cx ;统计余数个数
idiv bx
push dx ;保存余数
cmp ax,0
jnz let1
let2: ;显示十进制数
pop ax ;将余数弹入ax
add ax,0030h ;调整为ascii码
displ al ;显示一个数字
loop let2
restore_ss ;恢复现场
ret
disp_2_10 endp
end start
运行结果:
**思考
**:算式的计算值是人为输入的,例如运行结果中最后一题输入的值是错误的。要加上判断运算结果是否正确,该段程序如何编写?
6. 图形动画实验
在前面章节的程序中我们利用了 DOS 功能调用 INT 21H 来显示字母和数字,但是只能是标准的字符格式。在第 9 章 9.3.1 节中介绍了 BIOS 中断的 INT 10H 对屏幕及光标的控制方法,本节中我们进一步介绍 BIOS 中断的显示模式设置,屏幕上的像素点的读写等功能。
利用 INT 10H 的 9H 号功能显示带颜色的字符块,构成放大的字母或艺术字,也可以用来画图形。在 ASCII 码扩展字符集里有一些方块符如 0DBH、0DCH、0DDH、0DEH、0DFH,利用它们来构成图形文字。利用控制光标移动和字符消隐方法产生动画效果。
6.1 文本模式下的大号字体绘制
本例子为教材的示例 10-4。
设计目标
利用 INT 10H 的 9H 号功能显示用字符块构成的灰白底红字单词 Well。
设计思路
- (1) 先在方格上描写出大号字符,如运行结果所示,共 7 行 25 列;
- (2) 字符块阵列每行以 0FFH 作为结束标志,最后以 00H 作为整个图形结束;
- (3) 清屏置光标后调用 GRAPH_BLOCK 子程序写字符块;
- (4) 利用宏库 9-4.MAC 清屏、置光标、设置颜色;
- (5) 在正常文本方式下显示。
实现代码
程序如下:
;10-4.asm 显示大字单词Well
include 9-4.mac
data segment
init db 2,4,74h
;2行4列灰白底红字74h,字颜色:1蓝,2绿,3浅蓝,4红,5紫,6黄,7灰白,8灰
;===第1行==================================================================
well_s db 3 dup(0dch), 20h, 3 dup(0dch),2 dup(20h), 3 dup(0dch),0ffh
;===2======================================================================
db 20h,0dbh,3 dup(20h),0dbh,4 dup(20h),0dbh,5 dup(20h),2 dup(0dch)
db 3 dup(20h),2 dup(0dch),2 dup(20h), 0ffh
;===3======================================================================
db 20h,0dbh,3 dup(20h),0dbh,3 dup(20h),0dbh,7 dup(20h)
db 0dbh,4 dup(20h),0dbh,2 dup(20h),0ffh
;===4======================================================================
db 20h,0dbh,2 dup(20h),2 dup(0dbh),2 dup(20h),0dbh,2 dup(20h),0dch
db 2 dup(0dfh),0dch,2 dup(20h),0dbh,4 dup(20h),0dbh,2 dup(20h),0ffh
;===5======================================================================
db 20h,0dbh,20h,0dbh,20h,0dbh,20h,0dbh,3 dup(20h),0dbh,2 dup(0dch),0dfh
db 2 dup(20h),0dbh,4 dup(20h),0dbh,2 dup(20h),0ffh
;===6======================================================================
db 20h,2 dup(0dbh),2 dup(20h),2 dup(0dbh),4 dup(20h),0dbh,5 dup(20h),0dbh
db 4 dup(20h),0dbh,2 dup(20h),0ffh
;===7======================================================================
db 20h,0dbh,3 dup(20h),0dbh,5 dup(20h),0dfh,2 dup(0dch),0dfh,2 dup(20h)
db 0dbh,0dch,0dfh,2 dup(20h),0dbh,0dch,0dfh,0ffh
db 00
;==========================================================================
well_col db ?
data ends
code segment
assume cs:code,ds:data
start:
mov ax,data
mov ds,ax
mov si,0
clearsc ;清屏
mov si,offset init ;初始化
mov dh,[si] ;起始行
inc si
mov dl,[si]
mov well_col,dl ;保存起始列位置
inc si
mov bl,[si] ;颜色
cursor dh,dl ;置光标2行4列
mov si,offset well_s ;字符阵列地址
call graph_block
mov ah,4ch
int 21h
;-------------------
graph_block proc near
write:
mov al,[si] ;取出well_s中的矩形块
inc si
cmp al,0ffh ;一行结束
je next1
cmp al,0 ;所有行显示完了?
jz exit
mov ah,9 ;显示AL中字符块
mov bh,0
mov cx,1 ;写1个字符
int 10h
inc dl
cursor dh,dl ;光标移到下一位置
jmp write
next1:
inc dh
mov dl,well_col ;下一行起始列位置
cursor dh,dl
jmp write
exit:
cursor 30,10 ;退出后光标的位置
ret
graph_block endp
code ends
end start
运行结果:
**练习
**:利用上述方法,在屏幕上画出一个五角星。
6.2 文本模式下的动画效果
本例子为教材的示例 10-5。
设计目标
在文本模式下利用移动光标和字符消隐的方法产生字符移动的动画效果。
三行字符串分别从屏幕右边第 4 行 50 列向左边移动显示出来。
设计思路
- (1) 利用地址表 TABLE 保存 3 个字串单元的地址,通过相对寄存器寻址方式
TABLE[SI]
访问字串单元; - (2) 用宏库 9-4.MAC 清屏、置光标,并用显示空格定义消隐宏,设置延时宏;
- (3) 在光标位置处,用 DOS 中断
INT 21H
的 9 号功能显示字串; - (4) 变动光标位置,使字串不断左移,并将之前显示的最后字符消隐;
- (5) 用延时来控制字串移动速度。
实现代码
程序如下:
;10-5.asm 显示字符移动动画效果
include 9-4.mac ;宏库
displd macro opr ;字母显示消隐宏。在当前光标位置写字符或空格
mov ah,0ah
mov al,opr
mov bh,00h
mov cx,01h
int 10h
endm
displs macro opr ;显示字符串宏
mov ah,09h
mov dx,opr ;opr应为字串偏移地址
int 21h
endm
delay macro ;延时宏
local rept1,rept2
mov cx,15000
rept1:push cx
rept2:loop rept2
pop cx
loop rept1
endm
;-----------------------------------------------
data segment
w_s0 db 'Knowledge is power.','$'
w_s1 db 'Practice makes perfect.','$'
w_s2 db 'I wish you success!','$'
w_s3 db ?
table dw w_s0,w_s1,w_s2,w_s3 ;存储单元地址表
w_row db 4
w_col db 50
w_width db ?
x db 3 ;3行字符串
data ends
;-----------------------------------------------
code segment
assume cs:code,ds:data
start:
mov ax,data
mov ds,ax
clearsc ;清屏
xor ax,ax
mov al,w_col ;列
mov si,0
rept1:
push ax ;保存列值
cursor w_row,w_col ;置光标4行50列
mov bx,table[si+2] ;第2个字串地址w_s1→bx
sub bx,table[si] ;两个单元地址相减如 w_s1-w_s0
mov w_width,bl ;获得字串长度
call w_move ;调用字串移动子程序
pop ax
mov w_col,al ;恢复列值
inc w_row ;下一行
add si,2
dec x
jnz rept1
mov ah,4ch
int 21h
;子程序
w_move proc near
let0:
delay ;延时
dec w_col ;光标左移
cursor w_row,w_col
displs table[si] ;显示w_s0等单元中的字串
mov dl,w_col
dec dl
add dl,w_width ;光标置于串尾
cursor w_row,dl
displd 20h ;消隐尾部字符
dec bx
cmp bx,0
jnz let0 ;串继续左移
ret
w_move endp
code ends
end start
运行结果:
**思考
**:要显示带颜色的字符移动动画效果,如何编写程序?
**提示
**:用 INT 10H 中断的 09 号功能可以显示单个带颜色的字符。
6.3 图形模式下的绘图
本例子为教材的示例 10-6。
设计目标
将示例 10-4 修改为在 640×480、16 色图形模式下显示紫色大字单词 Well。
设计思路
- (1) 用 INT 10H 的 0 号功能、AL=12H 设置图形显示模式;
- (2) 字符块阵列每行以 0FFH 作为结束标志,最后以 00H 作为整个图形结束;
- (3) 清屏置光标后调用 GRAPH_BLOCK 子程序写字符块;
- (4) 用键盘输入功能等待按键后退出图形模式;
- (5) 返回 DOS 之前要将显示模式设置回文本模式。
实现代码
程序如下:
;10-6.asm显示单词Well,显示模式640*480,16色图形
data segment
;字颜色:1蓝,2绿,3浅蓝,4红,5紫,6黄,7灰白,8灰
;===第1行====================================================
well_s db 3 dup(0dch),20h,3 dup(0dch),2 dup(20h),3 dup(0dch),0ffh
;===第2-7行同示例10-4=========================================
db 00H
;============================================================
well_col db ?
data ends
code segment
assume cs:code,ds:data
start:
mov ax,data
mov ds,ax
mov si,0
mov ah,0 ;设置显示模式
mov al,12h ;640*480,16色图形
int 10h
mov dh,2 ;2行
mov dl,4 ;4列
mov well_col,dl ;保存起始列位置
mov bl,05h ;紫色
mov ah,2 ;置光标2行4列
mov bh,0
int 10h
mov si,offset well_s
call graph_block ;调用写字符块子程序
mov ah,1 ;暂停,键入任意键继续
int 21h
mov ah,0 ;设置返回后显示模式
mov al,03h ;80*25,16色标准文本模式
int 10h
mov ah,4ch
int 21h
;-------------------
graph_block proc near
write:
mov al,[si] ;取出well_s中的矩形块
inc si
cmp al,0ffh ;一行结束
je next1
cmp al,0 ;所有行显示完了?
jz exit
mov ah,9 ;写AL中字符块
mov bh,0
mov cx,1 ;写1个字符
int 10h
inc dl
mov ah,2
mov bh,0
int 10h ;光标移到下一位置
jmp write
next1:
inc dh
mov dl,well_col ;下一行起始列位置
mov ah,2 ;置光标
mov bh,0
int 10h
jmp write
exit:
ret
graph_block endp
code ends
end start
运行说明:执行后进入全屏图形模式,显示紫色大字 Well,按回车键后退回到纯 DOS 下。按 Windows 窗口键返回到 Windows 下。
6.4 图形模式下的动画
本例子为教材的示例 10-7。
设计目标
在 320×200、256 色图形模式下显示一行红色字串横向移动的动画效果。
设计思路
- (1) 用 INT 10H 的 0 号功能、AL=13H 设置图形显示模式;
- (2) 用 INT 10H 的 9 号功能显示带颜色的字符;
- (3) 移动光标位置使字符左移,同时对尾部字符消隐;
- (4) 返回 DOS 之前要将显示模式设回文本模式。
实现代码
程序如下:
;10-7.asm 在320×200,256色图形模式下显示彩色字符横向移动动画效果。
cursor macro row,rank ;置光标
mov ah,2
mov dh,row ;row行rank列
mov dl,rank
mov bh,0
int 10h
endm
displd macro opr ;字母显示消隐宏。在当前光标位置写空格
mov ah,0ah ;无颜色属性
mov al,opr
mov bh,00h
mov cx,01h
int 10h
endm
show_c macro opr1,opr2 ;显示带颜色字符宏
mov ah,09h ;有颜色属性
mov al,opr1 ;字符
mov bh,00h
mov bl,opr2 ;颜色
mov cx,01h
int 10h
endm
delay macro ;延时宏
local rept1,rept2
mov cx,3000
rept1:push cx
rept2:loop rept2
pop cx
loop rept1
endm
;-----------------------------------------------
data segment
mess0 db 'A miss is as good as a mile. '
mess1 db '$'
m_row db 6
m_col db 30
m_width dw ?
cont1 dw ?
cont2 dw ?
data ends
;-----------------------------------------------
code segment
assume cs:code,ds:data
start:
mov ax,data
mov ds,ax
mov ah,0 ;设置显示模式
mov al,13h ;320*200,256色图形
int 10h
mov di,0
mov bx,mess1-mess0
mov m_width,bx ;获得字串长度
call m_move ;调用字串移动子程序
mov ah,0 ;设置返回后显示模式
mov al,03h ;80*25,16色标准文本模式
int 10h
mov ah,4ch
int 21h
;-------------------------------------------------
;子程序
m_move proc near
mov cx,m_width ;移动次数
mov cont2,cx
mov cont1,cx
let1: ;循环左移一串字符
delay
cursor m_row,m_col ;在6行30列
show_c mess0[di],04h ;显示字母,红色字
mov dl,m_col
inc dl
cursor m_row,dl
displd 20h ;消隐
dec m_col ;左移光标
dec cont1
jnz let1 ;一个字符移动
mov m_col,30
inc di ;取下一个字符
sub cont2,1
mov bx,cont2
mov cont1,bx
jnz let1
ret
m_move endp
code ends
end start
**思考:
**若要显示出字符下落的动画效果,程序如何编写?
6.5 绘制浅蓝色线的正方体
本例子为教材的示例 10-8。
设计目标
在 320×200、4 色彩色图形方式下画出浅蓝色线的正方体。
设计思路
- (1) 用 INT 10H 的 0FH 号功能测试当前的显示模式并保存;
- (2) 用 INT 10H 的 4 号功能设置图形显示模式;
- (3) 用 INT 10H 的 0BH 号功能设置调色板;
- (4) 用 INT 10H 的 0CH 号功能画像素点;
- (5) 调用 3 个子程序分别画横线、竖线、斜线;
- (6) 返回 DOS 之前要将显示模式恢复为原模式。
代码实现
程序如下:
;10-8 在320×200 4色彩色图形方式下画浅蓝色正方体
.model small
.data
lie dw ?
hang dw ?
.code
start:
mov ax,@data
mov ds,ax
main proc far
mov ah,0fh ;测试当前显示模式
int 10h
push ax ;保存当前显示状态
mov ah,00h
mov al,04h ;设置320×200彩色图形方式
int 10h
mov ah,0bh ;设置彩色调色板
mov bh,01h
mov bl,01h ;1号调色板
int 10h
;----------------------------------------------------
mov lie,180 ;第1条横线
mov cx,120 ;60,120--60,180
mov dx,60
call dot_draw1 ;调画点子程序1
mov lie,160 ;第2横线
mov cx,100 ;80,100--80,160
mov dx,80
call dot_draw1
mov lie,160 ;第3横线
mov cx,100 ;140,100--140,160
mov dx,140
call dot_draw1
mov hang,140 ;第1竖线
mov dx,80 ;80,100--140,100
mov cx,100
call dot_draw2
mov hang,140 ;第2竖线
mov dx,80 ;80,160--140,160
mov cx,160
call dot_draw2
mov hang,120 ;第3竖线
mov dx,60 ;60,180--120,180
mov cx,180
call dot_draw2
mov hang,80 ;第1斜线
mov dx,60 ;60,120--80,100
mov cx,120
call dot_draw3
mov hang,80 ;第2斜线
mov dx,60 ;60,180--80,180
mov cx,180
call dot_draw3
mov hang,140 ;第3斜线
mov dx,120 ;120,180--140,160
mov cx,180
call dot_draw3
mov ah,1 ;暂停,待键入任意键
int 21h
pop ax ;恢复原设置
mov ah,00h
int 10h
mov ah,4ch
int 21h
main endp
;---------------------
dot_draw1 proc ;画点子程序1,横线
back1:
mov ah,0ch
mov al,1 ;颜色
mov bh,0 ;0页
int 10h
inc cx ;下一个像素点
cmp cx,lie
jnz back1
ret
dot_draw1 endp
dot_draw2 proc ;画点子程序2,竖线
back2:
mov ah,0ch
mov al,1
mov bh,0
int 10h
inc dx ;下一个像素点
cmp dx,hang
jnz back2
ret
dot_draw2 endp
dot_draw3 proc ;画点子程序3,斜线
back3:
mov ah,0ch
mov al,1
mov bh,0
int 10h
inc dx
dec cx
cmp dx,hang
jnz back3
ret
dot_draw3 endp
end start
**思考
**:要画出正方体内部的虚线,程序如何修改?
7. 磁盘文件读写实验
在计算机系统中,保存在磁盘上的程序和数据都是以文件形式存放的,I/O 设备也采用文件形式进行管理。
操作系统对文件最基本的操作包括创建文件、删除文件、读文件、写文件等;在打开文件后通过读/写指针访问磁盘文件,结束时要关闭文件。而对于标准 I/O 设备不需要打开就可直接使用系统为其配置的文件句柄。
7.1 读入文件并显示
本例子为教材的示例 10-9。
设计目标
打开 C 盘 HB 子目录下的文本文件并显示出来;文件名从键盘输入。
设计思路
- (1) 用小模式将数据段、附加段和代码段定义在一起;
- (2) 用 10 号功能从键盘输入文件名,并用 N2 单元存放路径、N3 单元存放文件名;
- (3) 用 3DH 号功能打开文件,若打开出错则显示出错号和出错信息;
- (4) 用 42H 号功能移动指针到文件尾得到文件长度;
- (5) 用 2 号功能循环显示读入的文件内容。
实现代码
程序如下:
;10-9.asm 从键盘输入文件名并将c:\hb\路径下的文件并显示出来。
.model small
.code
emess1 db 0ah,'read error! ','$'
emess2 db 0ah,'error2! file no find.','$'
emess3 db 0ah,'error3! path no find.','$'
mess1 db 'file name:','$'
fname db 41,?,40 dup(?)
n2 db 'c:\hb\'
n3 db 40 dup(0)
count dw ?
handle dw ? ;文件句柄
leng equ 8000h ;文件长度8000H=32768
buff db leng dup(0) ;文件暂存区
;---------------------------------------
start:
mov ax,@code
mov ds,ax
mov es,ax
mov dx,offset mess1 ;提示输入
mov ah,9
int 21h
mov dx,offset fname
mov ah,10 ;输入文件名
int 21h
lea si,fname+2 ;键入的字符
lea di,n3
mov ch,0
mov cl,fname+1 ;实际键入的个数
rep movsb ;串传送文件名到n3
;----------------------------------------
mov dx,offset n2 ;路径名、文件名
mov al,0 ;只读
mov ah,3dh ;打开文件
int 21h
jnc let0
jmp erro ;打开出错,转erro
let0:
mov handle,ax ;保存文件句柄
mov bx,ax ;bx=文件句柄
mov ah,42h ;移动指针
mov cx,0 ;位移量=0
mov dx,0
mov al,2 ;移到尾部
int 21h
mov count,ax ;ax=长度
mov ah,42h
mov al,0 ;指针指向头部
int 21h
mov cx,count
mov dx,offset buff
mov ah,3fh ;从文件中读出cx字节→buff
int 21h
jc error ;读出错,转error
mov cx,ax ;实际读入的字符数送入cx
mov ah,2
mov dl,0ah ;换行
int 21h
mov bx,offset buff
let1:
mov dl,[bx] ;用2号功能循环显示文件内容
int 21h
inc bx
loop let1
mov bx,handle
mov ah,3eh
int 21h ;关闭文件
jnc out1 ;关闭无错,转到out1处返回dos
erro:
cmp ax,2
jnz err3
mov dx,offset emess2 ;错误2提示
mov ah,9
int 21h
jmp out1
err3:
cmp ax,3
jnz error
mov dx,offset emess3 ;错误3提示
mov ah,9
int 21h
jmp out1
error:
mov dx,offset emess1 ;读出错提示
mov ah,9
int 21h
out1:
mov ah,4ch
int 21h
end start
运行结果:
运行说明:从键盘输入的文件名不需要输入路径,文件应该是源程序或 ASCII 码文本文件。文件的大小不要超过 32KB(8000H)。
7.2 创建文件并写入
本例子为教材的示例 10-10。
设计目标
创建一个新文件 C:\HB\NEWFILE.ASM
,并写入文件内容。
设计思路
- (1) 用 3CH 号功能建立带有路径名的新文件;
- (2) 新文件的内容(一段汇编源程序)用字节单元定义;
- (3) 用 40H 号功能将该段源程序文本写入新文件中;
- (4) 利用 9-4.mac 宏库清屏、置光标;
- (5) 写入成功后将文件句柄设置为 1,再用 40H 号功能将文件内容显示出来。
实现代码
程序如下:
;10-10.asm 创建文件并写入文件内容
include 9-4.mac
data segment
filename db 'c:\hb\newfile.asm',0 ;创建的文件名
asmfile db ' .model small',0ah,0dh ;新文件的内容
db '.data',0ah,0dh
db 'infor db "create a new file.$" ',0ah,0dh
db '.code ',0ah,0dh
db 'start:',0ah,0dh
db 'mov ax,@data',0ah,0dh
db 'mov ds,ax',0ah,0dh
db 'mov dx,offset infor',0ah,0dh
db 'mov ah,9',0ah,0dh
db 'int 21h',0ah,0dh
db 'mov ah,4ch',0ah,0dh
db 'int 21h',0ah,0dh
db 'end start'
emess db 'error !$',0ah,0dh ;出错提示
message db 'ok ! newfile.asm: ',0ah,0dh,'$' ;创建成功后的提示
handle dw ? ;保存文件句柄
data ends
code segment
assume cs:code,ds:data,es:data
start:
mov ax,data
mov ds,ax
mov es,ax
mov dx,offset filename
mov cx,0 ;普通文件属性
mov ah,3ch ;创建文件
int 21h
jc error ;创建出错,转error处
mov handle,ax ;保存文件句柄
mov bx,ax
mov cx,emess-asmfile ;写入的字节数
mov dx,offset asmfile ;写入内容
mov ah,40h
int 21h
jc error ;写出错,转error处
mov bx,handle ;文件句柄
mov ah,3eh ;关闭文件
int 21h
jc error ;关闭文件出错,转error处
clearsc ;清屏宏
cursor 0,0 ;置光标宏
mov dx,offset message ;显示操作成功提示
mov ah,9
int 21h
;------------------
mov bx,1 ;句柄为1,写到显示器
mov cx,emess-asmfile ;字符个数
mov dx,offset asmfile ;显示的内容
mov ah,40h
int 21h
jmp out1
;-------------------
error:
mov dx,offset emess
mov ah,9
int 21h ;显示错误提示
out1:
mov ah,4ch
int 21h
code ends
end start
运行结果:
运行说明:示例 10-10 运行之后,也可以用示例 10-9 来打开 NEWFILE.ASM,检验一下文件的写入。
8. 综合实验题目
本节给出 8 个综合实验题目,通过综合实验的学习与训练,归纳、总结前面各章的知识,进一步提高汇编语言程序设计能力。
8.1 实验一:CMOS 时间和日期
实验目的
通过编写读取 CMOS 实时钟程序,加深对接口芯片的了解,掌握输入输出指令的用法。对比中断调用获取日期和时间,总结多种获取系统时间的方法,达到举一反三的目的。综合复习菜单程序,置光标、开窗口、颜色设置等屏幕功能。
实验内容
- 用 I / O 指令读取 CMOS 实时钟值,并清屏、置光标,在窗口中显示日期、时间
- 用 DOS 日期和时间功能调用提供修改时间和日期功能
- 设计一个 60 秒倒计时器
实验要求
- 编写出菜单,可对实验内容作选择
- 在不同窗口中显示日期、时间,修改日期、时间
- 能够显示出变化的时间
- 选做:60 秒倒计时器(带颜色),时间到响铃
设计思路
- 参考示例 10-1、示例 9-4 及 9.4.3 节
- 变化的时间。可在示例 10-1 中再加一层循环,达到重复显示。但要注意:由于指令执行时间非常快,需要在两次循环中加入延迟程序段或者按键控制,否则看不到时间的改变
- 60 秒倒计时器参考 9.3.3 节及示例 9-5
实验报告要求
- 写出设计思路、画出程序框图
- 列出源程序
- 用截图形式记录实验结果
- 写出实验结果分析
8.2 实验二:英文打字练习软件
实验目的
- 编写英文打字练习软件,综合复习字符输入和显示,置光标、开窗口、颜色设置等屏幕功能;
- 掌握分支程序中字符比较及统计的程序设计,循环及排序程序设计方法;
- 加入中断调用的计时功能。通过上述综合性训练,进一步加深对汇编语言的理解和提高程序设计技能。
实验内容
- 屏幕出现打字练习菜单(格式自定,字体、字号、颜色)
- 菜单项目为 4 项:照打,覆盖打,名次,退出
实验要求
- 屏幕显示一段文字,在下面照打。统计并显示打对和打错的个数以及正确率或成绩
- 显示一段文字,在原文上覆盖打,打错时该字反显并响铃。统计并显示打对和打错的个数以及正确率或成绩
- 选做:建立一数组,用于保存打字者的名字和成绩,并能显示目前打字者的名次
- 选做:上述操作可加入计时功能,时间显示在右上角
设计思路
- 在窗口内输入可参考示例 9-3,菜单程序参考示例 5-8
- 文字显示及打字参考示例 9-3
- 判断及统计参考示例 5-3、示例 6-3
- 名次排序参考示例 6-5、示例 7-6
- 计时参考示例 9-5
实验报告要求
- 写出设计思路、画出程序框图
- 列出源程序
- 用截图形式记录实验结果
- 写出实验结果分析
8.3 实验三:英文填字游戏软件
实验目的
- 编写英文填字游戏软件,增加趣味性游戏功能。
- 综合复习菜单程序,置光标、开窗口、颜色设置等屏幕功能。掌握字符串扫描、比较指令,分支循环程序设计方法以及中断调用的计时功能。
- 通过综合性编程训练,加深对汇编语言的理解,提高程序设计技能。
实验内容
1.屏幕出现英文填字游戏菜单
2.菜单项目为 4 项:填字,奖励,名次,退出
实验要求
- 设计菜单及彩色显示界面,在窗口内显示单词
- 每次给出缺了若干字母的英文单词,光标跳到空缺处,等待键入。如果填对了,跳到下一个空位置;全对,出现下一个单词。如果错了,统计并显示错误次数,三次为限。并给出正确答案。按 ESC 键退出并打印出正确的单词个数。
- 正确个数超过一定比例后,给予 n 个五星奖励,并有鼓励字样。
- 选做:填字后,按 F1 键可给出该单词的英文解释
- 选做:上述操作可加入计时功能,时间显示在右上角
设计思路
- 菜单程序参考示例 5-8
- 在窗口内文字显示及填字参考示例 9-3
- 查找空缺参考示例 6-4,调光标参考示例 9-4
- 判断对错及统计参考示例 6-3、示例 5-3
- 名次排序参考示例 6-5、示例 7-6
- 计时参考示例 9-5
实验报告要求
- 写出设计思路、画出程序框图
- 列出源程序
- 用截图形式记录 实验结果
- 写出实验结果分析
8.4 实验四:设计一个小计算器
实验目的
- 通过编写小计算器程序,复习十进制数的输入和输出,子程序设计,掌握中断程序调用和编写方法。
- 通过综合性训练,进一步加深对汇编语言的理解和提高程序设计技能。
实验内容
- 设计一个计算器,可做+、-、×、/ 加减乘除运算
- 清屏、开窗口,在窗口内计算
实验要求
- 从键盘输入一个多位十进制数,按加号“+”,再输入另一个十进制数;按等号“=”后显示结果
- 其余运算同上
- 结果为负时,显示成带负号“-”的十进制数形式
- 选做:除 0 出错处理,调用除零中断程序处理
- 选做:结果溢出处理,自编一个溢出中断,发生溢出时,显示提示信息后退出
设计思路
- 键盘输入十进制数、运算后显示十进制数,参考示例 7-7
- 显示带负号的十进制数,参考示例 8-4 和实验 7-2b
- 除 0 中断程序,参考示例 9-2
- 自编一个溢出中断,当溢出标志 OF=1,触发中断;参考示例 9-1
- 在窗口内显示和输入可参考示例 9-3
实验报告要求
- 写出设计思路、画出程序框图
- 列出源程序
- 用截图形式记录实验结果
- 写出实验结果分析
8.5 实验五:小学生算术练习软件
实验目的
通过编写算术练习软件,复习算术运算程序设计,子程序设计方法,中断调用获取计数值产生随机数,十进制数运算方法等,达到顺利完成综合性设计性实验目的。
实验内容
- 屏幕出现菜单选择项。包括两位数的加减运算、一位数的乘除运算
- 随机产生算式。判断输入的计算结果正确与否
实验要求
- 在屏幕上显示相关算式,等待键入计算结果
- 随机产生两个两位以内的十进制数用于加减运算
- 随机产生两个一位的十进制数用于乘除运算
- 判断计算结果是否正确,正确给出鼓励;错误重新计算,两次不对给出答案
- 选做:显示有色彩的计算时间值
设计思路
- 加减乘除计算程序参考示例 4-6、示例 7-7
- 产生随机数参考示例 9-6、示例 10-3
- 在窗口内显示和输入可参考示例 9-3
- 选作题,参考示例 9-4、示例 9-5
实验报告要求
- 写出设计思路、画出程序框图
- 列出源程序
- 用截图形式记录实验结果
- 写出实验结果分析
8.6 实验六:进制及编码转换工具
实验目的
进制转换、编码转换是汇编语言中的重要内容,自始至终贯穿在本书中。由于键盘输入、屏幕输出要用 ASCII 码;人们习惯用十进制表示,而 BCD 码就是替代品;二进制、十六进制又是机器的需求。因此几种进制、码制之间势必要做转换,这项工作系统没有提供,是需要编写程序实现的。进制、码制的转换程序在前几章中已经介绍了,通过本实验,将其综合起来,使之形成一个方便实用的小工具。
实验内容
- 设计菜单,可多次选择。
- 几种进制转换、编码转换
- 屏幕右上角开窗口显示日期和时间
实验要求
- 输入十进制,转换成二进制显示
- 输入十进制,转换成十六进制显示
- 输入带符号十进制,转换成十六进制补码显示
- 输入十六进制,转换成二进制显示
- 输入十六进制,转换成十进制显示
- 输入十六进制补码,转换成带符号十进制真值显示
- 输入二进制,转换成十进制显示
- 输入二进制,转换成十六进制显示
设计思路
- 参考示例 7-1、实验 7-2b、示例 7-7、示例 8-2、示例 8-4、实验 8-6.ASM
- 用 BCD 码表示十进制数,计算时要用十进制调整指令作调整
- BCD 码加上 30H 就是相应十进制数的 ASCII 码,可用于显示
- 键盘输入的数字去掉 30H,即将 ASCII 码变为二进制数
- 日期和时间参考示例 9-4,开窗口参考示例 9-5
实验报告要求
- 写出设计思路、画出程序框图
- 列出源程序
- 用截图形式记录实验结果
- 写出实验结果分析
8.7 实验七:绘制图形动画
实验目的
通过编写图形绘画程序,了解并掌握 BIOS 中断对屏幕显示模式的设置、利用像素点绘制线段的方法。
在文本模式下和图形模式下利用控制光标移动和字符消隐方法产生动画效果。
综合复习菜单程序,置光标、开窗口、颜色设置、图形绘制等功能。
实验内容
- 在文本模式下绘制大写字母 ASM,或者绘制学校 LOGO
- 在大写字母的下方从屏幕左右边分别移动出两行字符串
- 在图形模式下绘制一个一笔连线图形
- 在文本模式下先在屏幕第一行显示字符串,再让每个字符自由下落
实验要求
- 清屏、开窗口。在窗口内显示菜单
- 实验内容 1、2 在同一画面上
- 实验内容 3 画线时按一笔连线顺序画出
- 选作:字符下落。下落速度可更改
- 选作:键盘打字,如果键入的与下落字符相同,字符消失;否则不变
设计思路
- 参考示例 10-4、示例 10-5,示例 10-8,开窗口菜单参考示例 9-3
- 学校 LOGO 只选择可绘制部分,或者自选一个简单 LOGO
- 一笔连线图形任选;可以先画出原图,再用另一种颜色按一笔画形式描出
- 改变光标行位置控制字符下落,字符可按排列顺序下落也可随机选择下落
- 键盘输入可用 INT 21H 的 1 号功能,或者参考 9.3.2 节 BIOS 的键盘中断 INT 16H
实验报告要求
- 写出设计思路、画出程序框图
- 列出源程序
- 用截图形式记录实验结果
- 写出实验结果分析
8.8 实验八:磁盘文件
实验目的
磁盘文件管理是操作系统的重要功能,通过编写磁盘文件程序,了解文件句柄、文件指针、文件缓存区等概念,掌握文件最基本操作功能的 DOS 系统调用的用法。综合复习菜单程序,置光标、开窗口、颜色设置等功能。
实验内容
- 将从键盘输入的一串字符存入新建的文件 CHARKEY.TXT 中
- 打开 CHARKEY.TXT 文件,将其倒序写入另一文件中
- 打开示例 10-9 源程序,将其每次显示 20 行/页,按回车键显示下一页,直至结束
实验要求
- 编写出菜单窗口,可对实验内容作选择
- 能显示出倒序后的文件
- 分页显示的文件名从键盘输入
- 选做:清屏、开窗口后,在窗口内分页显示
设计思路
- 文件操作参考示例 10-10、开窗口参考 9.3.1 节
- 倒序文件可考虑移动指针,参考示例 10-9
- 分页显示可采用判断回车符 0DH,累计值为 20 次代表 20 行
- 开窗口菜单设置参考示例 9-3
实验报告要求
- 写出设计思路、画出程序框图
- 列出源程序
- 用截图形式记录实验结果
- 写出实验结果分析