x86汇编语言之显存操控屏幕输出
操控显存输出字符串
前面咱们介绍过使用中断的方式输出字符串, 今天我们学习一种不使用中断的方式实现字符串的打印
在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
作者:乱码三千
链接:https://juejin.cn/post/7028744851805978638