问题:
编程:在屏幕中间显示绿色,绿底红色,白底蓝色的字符串’welcome to masm!’
解析:
在DOS中有一个80*25的彩色字符模式缓冲区,即25行,每行有80个字符,总计4000个字符,内存地址为B8000H~BFFFF。在这个区域上写入的数据会立刻出现在显示器上。
用e指令定位 B800:0200的内存地址,写入一个41.可以在屏幕的上方看到一个A字符,41其实是ASCII码,41正好对应A字母;
然后我们在紧接着输入 02 数字 ,可以看到字母变成了绿色的;
- 我们不妨假设,这两个字节的掌握着一个字符的形态,第一个字节存放字符数据,第二个字节存放字符的属性(颜色)。
- 第一个字节对应低位字节,第二个字节对应高位字节
- 低位字节(寄存器低位)存储ASCII码,高位字节(寄存器高位)存储字符的属性
- 验证得知,确实是这样的
也可以看作:偶地址存放字符,奇地址存放字符的颜色属性
关于颜色
- 在屏幕上显示的字符,具有前景色(字符色)和背景色(底色)两种颜色,还可以以高亮度和闪烁的形式显示
- 属性字节的格式:
- 比如:红底蓝字 :0100 0001 B
- 红底闪烁绿字:1100 0010B
- 白底闪烁高亮绿字:1111 1010B
本题要求的其颜色:
绿色: 00000010B
绿底红色:00100100B
白底蓝色:01110001B
实现代码
基本框架:
- 定义数据段:把要操作的字符串数据提前存放在cs数据段中,并且紧随着保存三种颜色属性
- 定义栈段:定义一个栈用于控制临时数据的保存与返回
assume cs:code
data segment ;数据段
db 'welcome to masm!' ;保存字符串
db 00000010B,00100100B,01110001B ;保存三种颜色形式
data ends
stack segment ;栈段
db 128 dup(0)
stack ends
code segment
start: ;在此编写代码
mov ax,4c00H
int 21h
code ends
end start
一步一步来
1.创建段: 首先ds和ss的创建,用es来控制打印到屏幕上的位置,在B8000~BFFFFh之间的内存单元,
2. 确定偏移地址:si和di分别控制数据段中字符串和属性的偏移地址,bx控制输出到屏幕上的偏移地址,用dx寄存器来保存数据及格式,注意:高字节(dh)存放属性,低字节(dl)存放数据
3. 开始一次循环:循环16次,首先dl读取8位数据,dx送到es寄存器(直接显示在屏幕上),一个字符输出完成,随后字符递增,输出位置更新,开始下一次打印。
assume cs:code
data segment ;数据段
db 'welcome to masm!' ;保存字符串
db 00000010B,00100100B,01110001B ;保存三种颜色形式
data ends
stack segment ;栈段
db 128 dup(0)
stack ends
code segment
start: mov ax,data
mov ds,ax ;ds指向数据段
mov ax,stack
mov ss,ax
mov sp,128 ;创建栈段
mov ax,0B800H
mov es,ax ;es控![在这里插入图片描述](https://img-blog.csdnimg.cn/c4fd5d9556464d01a7e3de392726265c.png)
制打印的屏幕
mov si,0 ;si控制字符串数据的起始位置
mov di,0010h ;di控制颜色属性的起始位置
mov bx,160*10+30*2 ;bx控制打印在屏幕上的位置
mov cx,16 ;一次打印循环次数
mov dh,ds:[di] ;高位字节存放属性,dh八位寄存器存放颜色属性
s: mov dl,ds:[si] ;低位字节存放数据,dl八位寄存器存放数据
mov es:[bx],dx ;dx16位寄存器存放了数据和属性,送到屏幕上
inc si ;字符数据移动
add bx,2 ;一个字符打印在屏幕上占两个字节,要加2
loop s
mov ax,4c00H
int 21h
code ends
end start
显示:
栈返回操作
至此,我们已经完成了第一个字符串的形式的打印,还剩下两个,我们很容易的想到,再来两个循环,再打印两遍字符串。
这确实是一个办法,但是当我们打印完一个字符串后,在打印第二遍,你可以想到,其中有很多变量不一定需要改变,比如控制字符串位置的si,重复的操作只会让程序更加复杂,我们可以使用栈,来实现打印多个。
- 外层循环控制打印的行数,每次bx加160实现换行,颜色属性ci偏移地址也要改变,看代码吧,不想写了。。。。
assume cs:code
data segment ;数据段
db 'welcome to masm!' ;保存字符串
db 00000010B,00100100B,01110001B ;保存三种颜色形式
data ends
stack segment ;栈段
db 128 dup(0)
stack ends
code segment
start: mov ax,data
mov ds,ax ;ds指向数据段
mov ax,stack
mov ss,ax
mov sp,128 ;创建栈段
mov ax,0B800H
mov es,ax ;es控制打印的屏幕
mov si,0 ;si控制字符串数据的起始位置
mov di,0010h ;di控制颜色属性的起始位置
mov bx,160*10+30*2 ;bx控制打印在屏幕上的位置
mov cx,3
;入栈,保存每个变量
s0: push di
push si
push cx
push bx
mov cx,16 ;一次打印循环次数
mov dh,ds:[di] ;高位字节存放属性,dh八位寄存器存放颜色属性
s: mov dl,ds:[si] ;低位字节存放数据,dl八位寄存器存放数据
mov es:[bx],dx ;dx16位寄存器存放了数据和属性,送到屏幕上
inc si ;字符数据移动
add bx,2 ;一个字符打印在屏幕上占两个字节,要加2
loop s
;注意出栈顺序,相反
pop bx
pop cx
pop si
pop di
add bx,160 ;屏幕的打印位置换行,加160,因为一行有160个字节
inc di ;颜色属性递增,实现换色
loop s0
mov ax,4c00H
int 21h
code ends
end start