「这是我参与11月更文挑战的第10天,活动详情查看:2021最后一次更文挑战」。
操控显存输出字符串
前面咱们介绍过使用中断的方式输出字符串, 今天我们学习一种不使用中断的方式实现字符串的打印
在8086的内存地址结构中,B8000H~BFFFFH这部分的内存区域为显存区域,一旦向这个地址空间写入数据,cpu会从0号偏移地址开始读取数据然后显示输出, (每写入一次数据就从0开始读取一次)
代码尝试:
start:
mov ax,0B800H
mov ds,ax
mov dl,'a'
mov ds:[0],dl
end start
在这块区域中,每个字符固定占用两个字节的空间,也就是ds:[0]和ds:[1]存放一个字符的信息,前者存放字符具体的内容,后者存放字符对应的颜色
比如:
start:
mov ax,0B800H
mov ds,ax
mov dl,'a'
mov ds:[0],dl
mov dl,00000100B ;让字符以红色显示
mov ds:[1],dl
end start
字符颜色的设置规则:
0 0 0 0 0 0 0 0 ;用8个二进制位表示字符属性
从高往低数,第一个二进制位表示是否显示闪烁痕迹
start:
mov ax,0B800H
mov ds,ax
mov dl,'a'
mov ds:[0],dl
mov dl,10000000B ;保留字符闪烁痕迹
mov ds:[1],dl
end start
第234个二进制位表示字符背景颜色 分别代表:RGB,即red、green、blue
start:
mov ax,0B800H
mov ds,ax
mov dl,'a'
mov ds:[0],dl
mov dl,01000000B ;背景颜色设为红色
mov ds:[1],dl
end start
第5个二进制位表示字符是否高亮
start:
mov ax,0B800H
mov ds,ax
mov dl,'a'
mov ds:[0],dl
mov dl,00001100B ;字符颜色设置为红色 并且高亮显示
mov ds:[1],dl
end start
第678个二进制位表示字符本身的颜色 分别代表:RGB,即red、green、blue
start:
mov ax,0B800H
mov ds,ax
mov dl,'a'
mov ds:[0],dl
mov dl,00000111B ;背景颜色设为白色 系统默认颜色是白色
mov ds:[1],dl
end start
由于cpu会从0号偏移地址开始读取数据然后显示输出,因此假如你直接在6号偏移地址写入字符数据, 那么前面三个数据会以占位形式存在
start:
mov ax,0B800H
mov ds,ax
mov dl,'a'
mov ds:[0],dl
mov dl,00000111B
mov ds:[6],dl ;输出结果为" a"
end start
字符串打印
data segment
str db 'hello pangshu'
endstr db ''
data ends
code segment
start:
mov ax,data
mov ds,ax
mov ax,0B800H
mov es,ax
mov cx ,offset endstr-str
mov bx,0
mov si,0
print:
mov dl,ds:[si]
mov es:[bx],dl
mov dl,00000111B ;背景颜色设为白色 系统默认颜色是白色
mov es:[bx+1],dl
inc si
add bx,2
loop print
code ends
end start
借助字符不断刷新显示的特性,可用让字符动画显示
;让字符从左往右移动
code segment
start:
mov ax,0B800H
mov es,ax
mov bx,0
mov cx,30
print:
mov es:[bx],' '
mov dl,'a'
mov es:[bx+2],dl
add bx,2
loop print
code ends
end start
屏幕默认显示80x25个字符,全屏显示106x38个字符,那么可以根据这个特性,让字符上下移动
;让字符从上往下移动
code segment
start:
mov ax,0B800H
mov es,ax
mov bx,0
mov cx,25
print:
mov es:[bx],'a'
mov dl,' '
mov es:[bx-160],dl
add bx,160 ;为什么是160而不是80 以内一个字符占两个字节的空间, 80个字符总共偏移了160
loop print
code ends
end start
;让字符从下往上移动
code segment
start:
mov ax,0B800H
mov es,ax
mov bx,160*24
mov cx,25
print:
mov es:[bx],'a'
mov dl,' '
mov es:[bx+160],dl
sub bx,160 ;为什么是160而不是80 以内一个字符占两个字节的空间, 80个字符总共偏移了160
loop print
code ends
end start
另外, 让字符斜着移动
;让让字符斜着移动
code segment
start:
mov ax,0B800H
mov es,ax
mov bx,0
mov cx,25
print:
mov es:[bx],'a'
mov dl,' '
mov es:[bx-161],dl
add bx,161 ;向右斜加偏移量 向左斜减偏移量
loop print
code ends
end start
补充: 在8086中系统提供了一个显示服务(Video Service)中断供我们使用,使用10H这个中断码也可以打印带有颜色属性的字符串
;示例1:
mov ah,2 ;放置光标
mov bh,0 ;第0页
mov dh,5 ;行号
mod dl,12 ;列号
int 10H
;示例2:
mov ah,9 ;在光标的位置显示字符
mov al,'a' ;字符
mov bl,11001010B ;颜色
mov bh,0 ;第0页
mov cx,3 ;重复显示3次
int 10H
使用键盘输入控制字符移动
使用16号中断码
;使用键盘控制字符移动
code segment
start:
mov ax,0B800H
mov es,ax
mov bx,0
mov cx,30
scan:
mov ah, 00H
int 16H
cmp al,61H ;判断两个值是否相等
jne scan2 ;jmp not equal 如果两者不相等 则跳转到scan2 否则往下执行
call left
jmp scan
scan2:
cmp al,64H
jne scan3
call right
jmp scan
scan3:
cmp al,77H
jne scan4
call top
jmp scan
scan4:
cmp al,73H
jne scan
call down
jmp scan
right:
mov es:[bx],' '
mov dl,'a'
mov es:[bx+2],dl
add bx,2
ret
left:
mov es:[bx],' '
mov dl,'a'
mov es:[bx-2],dl
sub bx,2
ret
top:
mov es:[bx],' '
mov dl,'a'
mov es:[bx-160],dl
sub bx,160
ret
down:
mov es:[bx],' '
mov dl,'a'
mov es:[bx+160],dl
add bx,160
ret
code ends
end start