我试图在屏幕中央显示x
,然后将控制台的背景颜色更改为蓝色。我有以下代码来完成除更改背景颜色之外的所有内容:
TITLE screen1.ASM
.MODEL SMALL
.STACK 0100h
.DATA
.CODE
start:
MOV AX,@DATA
MOV DS,AX
MOV AX,0600h
MOV BH,07h
MOV CX,0000h
MOV DX,184Fh
INT 10h
MOV AH,02h
MOV BH,00h
MOV DH,0Ch
MOV DL,28h
INT 10h
MOV AH,02h
MOV DL,'x'
INT 21h
MOV AX,4C00h
INT 21h
END start
代码清除屏幕,在dosbox窗口的中心显示x
并将控制权交还给DOS。我试图找出将窗口(不是文本)的背景颜色更新为蓝色所需的更改。
答案 0 :(得分:3)
清除屏幕时,移动bh=17h
而不是07h
TITLE screen1.ASM
.MODEL SMALL
.STACK 0100h
.DATA
.CODE
start:
MOV AX,@DATA
MOV DS,AX
MOV AX,0600h
MOV BH,17h
MOV CX,0000h
MOV DX,184Fh
INT 10h
MOV AH,02h ;settin cursor position
MOV BH,00h ;page number
MOV DH,0Ch ;row
MOV DL,28h ;column
INT 10h
MOV AH,02h
MOV DL,'x'
INT 21h
MOV AX,4C00h
INT 21h
END start
答案 1 :(得分:2)
我对您的代码的第一印象,以及促使我第一次评论的原因是您可能使用了错误的前景色和背景色。你有:
MOV BH,07h
黑色为浅灰色。蓝色的白色本来就是:
MOV BH,1fh
可以找到有关BIOS颜色属性的信息here。
您的问题不明确,但此示例中的代码将更新当前文本模式的背景颜色,但保留前景色和字符。在运行screen1
之前,我假设文本模式为80x25。
该程序直接更新显示内存。文本模式的第0页通常从物理地址0xB8000开始。我将 ES 设置为0xB800来进行视频更新,因为0xB800:0x0000 segment:offset pair与物理地址相同(0xB800<< 4)+ 0x0000 = 0xB8000。
屏幕上的每个字符占用2个字节(或一个16位字)。 80x25文本模式是2000个单元(每个2个字节)或总共4000个字节的视频RAM。字符位于第一个字节中,属性位于第二个字节中。您可以获得有关此视频布局here的更多信息。
以下代码读取屏幕上每个字符的每个属性,清除背景颜色(高4位),然后将高4位设置为新的背景颜色。 0x01是蓝色。更新背景颜色后,代码会将新属性写回视频内存。
TITLE screen1.ASM
.MODEL SMALL
.STACK 0100h
.DATA
.CODE
start:
MOV AX,@DATA
MOV DS,AX
MOV AX,0B800h
MOV ES,AX ; Set ES to text video memory segment
MOV SI,1 ; Attributes are on odd addresses
MOV CX,2000 ; 2000 2-byte cells on an 80x25 display
L1:
MOV AL,ES:[SI] ; Get cell attribute
AND AL,0Fh ; Clear the current background
OR AL,10h ; Set the background to 1 (1=blue)
MOV ES:[SI],AL ; Update the attribute on screen with new background color
ADD SI,2 ; Go to next cell's attribute
DEC CX
JNZ L1 ; Loop for entire display
MOV AH,02h
MOV BH,00h
MOV DH,0Ch
MOV DL,28h
INT 10h ; Set cursor
MOV AH,02h
MOV DL,'x'
INT 21h ; Write character at cursor using the current
; foreground and background colors at that position
MOV AX,4C00h
INT 21h ; Exit Program
END start
运行此程序前的屏幕示例:
之后:
在更新背景颜色时保留所有文本(和前景色)。
执行背景颜色更新的代码中的循环也可以写为:
MOV AX,0B800h
MOV ES,AX ; Set ES to text video memory segment
MOV SI,4000 ; 4000 bytes with each screen cell on an 80x25 display
; taking 2 bytes each. 80*25*2 = 4000
L1:
MOV AL,ES:[SI-1] ; Get cell attribute
AND AL,0Fh ; Clear the current background color bits
OR AL,10h ; Set the background color bits to 1 (1=blue)
MOV ES:[SI-1],AL ; Update the attribute with new background color
SUB SI,2 ; Go to next cell (move backwards)
JG L1 ; Loop for entire display
如果您不熟悉x86程序集,我原始示例中的代码可能更容易理解。
如果您不需要为屏幕上的每个字符保留前景色,则只需使用新值更新属性,并保留现有字符。我的第一个代码示例中的循环可以修改为:
MOV AX,0B800h
MOV ES,AX ; Set ES to text video memory segment
MOV SI,4000 ; 2000 2-byte cells on an 80x25 display
L1:
MOV BYTE PTR ES:[SI-1],01Fh
; Set attribute to 1F (1=blue background, F=white foreground)
SUB SI,2 ; Go to next attribute(backwards)
JG L1 ; Loop for entire display
这会将屏幕上的所有字符更改为蓝色的白色,并显示如下:
为了完整起见,还可以使用角色清除整个屏幕。 space 字符有效地充当了清晰的字符。我们可以使用REP STOSW更新字符和属性。我们希望使用 STOSW 向前移动内存,因此我们使用CLD向前设置方向标记。 STD会在内存中向后移动。 STOSW 被描述为:
REP STOS m16 Fill (E)CX words at ES:[(E)DI] with AX.
用蓝色背景和白色前景清除屏幕的代码可以这样做:
MOV AX,0B800h
MOV ES,AX ; Set ES to text video memory segment
XOR DI,DI ; Starting offset = 0 for STOSW
MOV CX,2000 ; 2000 2-byte (16-bit WORD) cells on an 80x25 display
MOV AX,1F20h ; 20h = ASCII value for space character
; 1Fh = attribute (white on blue)
CLD ; Set direction flag forward (used by STOSW etc)
REP STOSW ; Copy AX (attribute and char) to ES:DI, Repeat CX (2000) times
此代码与您使用视频BIOS服务的代码相同:
MOV AX,0600h
MOV BH,1Fh
MOV CX,0000h
MOV DX,184Fh
INT 10h
上面带有此代码的程序输出如下所示:
答案 2 :(得分:1)
您必须手动设置每个字符的颜色。使用INT 0x10 / AH=0x09
,或直接写入屏幕缓冲区(B800:xxxx
)。
屏幕缓冲区中的每个字符占用两个字节,低字节包含字符,高字节是颜色属性。
答案 3 :(得分:-1)
要更改背景并显示x,请检查此资源http://ss64.com/nt/color.html。我希望它有所帮助