问题:

编程:在屏幕中间显示绿色,绿底红色,白底蓝色的字符串’welcome to masm!’

解析:

在DOS中有一个80*25的彩色字符模式缓冲区,即25行,每行有80个字符,总计4000个字符,内存地址为B8000H~BFFFF。在这个区域上写入的数据会立刻出现在显示器上。

用e指令定位 B800:0200的内存地址,写入一个41.可以在屏幕的上方看到一个A字符,41其实是ASCII码,41正好对应A字母;

汇编语言实验9(详解)多种颜色打印字符串_c++

然后我们在紧接着输入 02 数字 ,可以看到字母变成了绿色的;

汇编语言实验9(详解)多种颜色打印字符串_c++_02

  • 我们不妨假设,这两个字节的掌握着一个字符的形态,第一个字节存放字符数据第二个字节存放字符的属性(颜色)
  • 第一个字节对应低位字节,第二个字节对应高位字节
  • 低位字节(寄存器低位)存储ASCII码,高位字节(寄存器高位)存储字符的属性
  • 验证得知,确实是这样的汇编语言实验9(详解)多种颜色打印字符串_c++_03
    也可以看作:偶地址存放字符,奇地址存放字符的颜色属性

关于颜色

  • 在屏幕上显示的字符,具有前景色(字符色)背景色(底色)两种颜色,还可以以高亮度闪烁的形式显示
  • 属性字节的格式:
    汇编语言实验9(详解)多种颜色打印字符串_开发语言_04
  • 比如:红底蓝字 :0100 0001 B
  • 红底闪烁绿字:1100 0010B
  • 白底闪烁高亮绿字:1111 1010B

本题要求的其颜色:
绿色: 00000010B
绿底红色:00100100B
白底蓝色:01110001B

实现代码

基本框架:

  1. 定义数据段:把要操作的字符串数据提前存放在cs数据段中,并且紧随着保存三种颜色属性
  2. 定义栈段:定义一个栈用于控制临时数据的保存与返回
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

显示:
汇编语言实验9(详解)多种颜色打印字符串_java_05

栈返回操作

至此,我们已经完成了第一个字符串的形式的打印,还剩下两个,我们很容易的想到,再来两个循环,再打印两遍字符串。
这确实是一个办法,但是当我们打印完一个字符串后,在打印第二遍,你可以想到,其中有很多变量不一定需要改变,比如控制字符串位置的si,重复的操作只会让程序更加复杂,我们可以使用栈,来实现打印多个。

  1. 外层循环控制打印的行数,每次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

汇编语言实验9(详解)多种颜色打印字符串_ide_06