霓虹灯显示程序设计
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
霓虹灯显示程序设计
………………………………………………………………………………………………..?
设计内容简介 (1)
霓虹灯显示程序设计 (2)
设计任务及要求 (2)
设计方案及程序流程图 (2)
主程序流程图 (2)
汉字显示闪烁子程序 (3)
2.2.3 程序结果显示 (6)
主要程序段与程序设计 (10)
程序中用到的DOS功能调用 (10)
程序中用到的BIOS内的中断功能 (10)
主要程序段分析.........................................................................11 程序调试说明. (16)
调试工具 (16)
调试过程 (16)
课程设计总结..............................................................................................17 参考文献. (1)
8 附录源程序清单与注释 (19)
霓虹灯是日常生活中最常见的灯饰,它装点了晚上,丰富了人们的生活。
通过汇编语言,
实现霓虹灯的显示与闪烁,可以很方便的达到想要的效果。
汇编语言的INT 10号中断提供了设置显示模式、设置颜色模式、设置光标位置、按指定属性显示字符等功能号,可以显示汉
字,同时也提供了初始化屏幕或滚屏等功能号,通过擦除子程序以及清屏子程序的配合运用,
从而达到让汉字闪烁的功能。
正确编排汉字组成点的坐标、颜色以及ASCII码值,就可以得到想要显示的汉字,合理运用INT 10号中断的功能号,正确调用擦除子程序和清屏子程序就
可以得到想要的闪烁效果。
:霓虹灯中断子程序闪烁显示
I
汇编语言是计算机提供给用户的最快最有效的语言,也是能过利用计算机所有硬件特性
并能直接控制硬件的唯一语言,是操作系统等其它核心课程的必要先修课。
汇编语言的应用
有很多,其中,图形文字的显示就是计算机的一项基本应用。
本次课程设计说明书在简单说
明课题的硬件设施工作原理后,采用BIOS的 INT 10H 显示功能调用,设置为AH=0,AL=4的320×200彩色图像显示方式,利用AH=12写点功能,通过写ASCII 码,来组成文字,其中ASCII码的位置可由行数与列数的二维坐标确定,从定义的区域内开始,行向下自增1,列向右自减1,逐列写ASCII码。
为了程序中代码的方便书写,须事先利用坐标纸将自己要
显示的字用ASCII码拼出来,同时设定ASCII码的颜色值。
程序中将所要显示的文字的位形
图写在数据段中,每行数据段定义文字的一个点,定义中包含组成点的ASCII 码对应的数值、颜色以及其对应的二维坐标。
文字的闪烁通过清屏程序和擦除程序同时作用来实现。
退出通
过检测输入数值与Q或q大小的比较来实现。
整个设计的重点在于数据段的编写以及清屏、
擦除子程序的合理调用。
1
本次微机课程设计是一道文本显示设计题,由任务书中容易得到要求大致如下:
1.用汇编语言编写一个霓虹灯的模拟显示程序;
2.在屏幕上显示你的中文名字或其它文字,按某种规律闪烁变化,按“q”键退出。
题设中给出的要求比较简单,容易知道,编写出的程序要达到两种效果:1、能够显示某些文字;2、显示的文字能够按照某种形式闪烁,闪烁的方式不限。
同时,在程序运行的时
候,如果输入Q或q,程序能够退出,返回运行前的界面。
本次设计的流程图由主程序流程图和子程序流程图组成。
设计思路为:数据段初始化
,,调用汉字显示子程序,显示汉字“大”调用条纹显示程
序,显示运动的条纹,,调用汉字子程序,显示汉字“小”判断是否有字符输入,没有的话
继续执行显示程序,,有字符输入时,判断输入字符是否为“Q”、”q” 不为“Q”、“q”时,
执行显示程序,为“Q”、“q”时,退出程序,等待程序继续执行。
根据设计思路得到本次课程设计的流程图如图1所示。
2
开始
数据段初始
化
调用汉字显示子程序,显
示汉字“大”
调用条纹显示子程序,显
示运动的条纹
调用汉字显示子程序,显
示汉字“小”
N
判断是否有
字符输入?
Y
N
输入字符是
否为Q、q ?
Y
结束
图1 霓虹灯显示主程序
本次课程设计显示的汉字比较简单,就设置为“大”、“小”,在颜色设置方面做了一些改变,同一个字中选用了两种颜色,闪烁的形式设定的为有一个V形的蓝色条纹,条纹扫过文字时,文字被覆盖,条纹扫过以后,文字重新出现。
待文字显示完毕后,V形蓝色条纹再次
扫过文字,重复上述过程,从而实现文字的隐现。
根据上述叙述,有文字的显示子程序、V形条纹的显示子程序、擦除子程序,对应的流程图分别如图2、3、4所示。
3
开始
寄存器入栈 Cx寄存器清零
保存组成点
的基本信息
Cx入栈
在指定坐标处
写第一个点
Cx出栈,保
存循环次数
Cx中内容自减1
N
判断cx中内
容是否为0?
Y
寄存器出栈
结束
图2 文字显示子程序流程图4
开始
寄存器入栈
Cx寄存器清零
保存组成点
的基本信息
Cx寄存器入栈
Y
判断是否到达
屏幕最左端?
N
在指定坐标处
写第一个点
Cx出栈,保
存循环次数
Y 判断指定坐标处
字符是否为@?
N
N
判断制定坐标处
字符是否为* ?
Y
将字符写11次
寄存器出栈
结束
图3 擦除蓝色V形条纹的子程序5
开始
保存组成点
的基本信息
判断是否到达 Y
屏幕最左端?
N
Y
判断指定位置处字符是否为@?N
N 判断指定位置
处字符是否为*?
Y
将字符写11个
将字符改为#
列坐标dl自减1
保存点的基
本信息
结束
图4 擦除子程序流程图
本次课程设计预期运行的结果为,显示汉字“大”、“小”,并按照某种形式进行闪烁。
文
字闪烁的过程分别如下所示。
6
程序运行之初,首先在屏幕上显示汉字“大”,如图5所示。
图5 运行初显示汉字“大”
汉字显示完以后,蓝色V形条纹开始从右向左行进,运动后留下“#”组成的蓝色条纹若干行,如图6所示。
图6 汉字显示后,V形条纹开始向左行进
蓝色V形条纹扫过文字“大”,同时将文字覆盖,如图7所示。
7
图7 蓝色条纹扫过文字并将其覆盖
蓝色V形条纹扫过文字,将文字覆盖,在屏幕上只留下“#”组成的蓝色条纹所干行,如图8所示。
图8 屏幕上留下“#”组成的蓝色条纹
在蓝色条纹将“大”字覆盖之后,在这些蓝色条纹衫上将显示文字“小”,“小”显示完之后,将显示“大”,如图9所示。
8
图9 蓝色条纹扫过后,汉字“小”、“大”先后显示
在这两个汉字显示之后,蓝色V形条纹将重新开始自右向左行进,将已经显示的汉字覆
盖,如图10所示。
图10 文字显示后蓝色V形条纹继续行进,覆盖文字
蓝色条纹最终将汉字全部覆盖,如图11所示。
9
图11 文字覆盖后的屏幕
文字的闪烁就是按照上述7幅图的形式重复进行的。
(1)01H号功能调用功能:从键盘输入一个字符
输入参数:无
输出参数:AL=ASCII码
(2)0BH号功能调用
功能描述:检查标准输入设备上是否有字符可读,该输入操作可被重定向入口参数:AH=0BH
出口参数:AL=00H——无字符可读;FFH——有字符可读(3)4CH号功能调用
功能:返回操作系统4CH
调用:MOV AH,4CH
INT 21H
(1)02H 号功能调用
10
功能:用文本坐标下设置光标位置入口参数: AH=02H
BH=显示页码
DH=行(Y坐标)
DL=列(X坐标)
出口参数:无
(2)08H 号功能调用
功能:读光标处的字符及其属性入口参数:AH=08H
BH=显示页码
出口参数:AH=属性
AL=字符
(3)09H 号功能调用
功能:在当前光标处按指定属性显示字符入口参数:AH=09H
AL=字符
BH=显示页码
BL=属性(文本模式)或颜色(图形模式)
CX=重复输出字符的次数出口参数:无
(4)0FH号功能调用
功能:读取显示器模式
入口参数:AH=0FH
出口参数:AH=屏幕字符的列数
AL=显示模式(参见功能00H中的说明)
BH=页码
(1)数据段
本次课程设计的中心就在于数据段的编写,数据段中的汉字可以直接运用字摸软件进行
11
取模来编写程序,也可运用写点的方式来实现。
在本次课程设计数据段的定义中,由组成点
的ASCII码值、颜色以及对应的X、Y坐标组成。
例如:jeep db 6
db 3dh,0eh,0,0
db 40h,0eh,1,-1
db 3dh,0eh,1,0
db 3ch,0eh,0,-1
db 02ah,0bh,-1,0
db 3ch,0eh,-1,0
这段程序是擦除蓝色V形条纹的位形图,其中3dh为条纹组成的第一个点的ASCII码值,
在屏幕上显示的为“=”, 0eh为颜色设置,为黄色,(0,0)为这个点的坐标,第一个为行坐标,第二个为列坐标,这个点为擦除蓝色V形条纹组成点的基准坐标。
其他的点的前两项设置与基准坐标一致,坐标设置按照矩阵的形式,向右则列自增1,像左则列自减1,向下则
行自增1,像上则行自减1,每写出一个点后,写出的点的坐标变回基准坐标(0,0),由此
类推,写出组成汉字所需要的所有点的坐标。
值得注意的是,本次课程设计的点的坐标,是
在选定基准坐标后,从上向下写第一个的点,随后从下向上写第二列的点,就按照这样的规
律,直至将所有的点的坐标写完为止。
(2)在屏幕上写点
屏幕上写点是本次程序的重点。
写点的过程以及程序大致如下,首先要将汉字位形图的
地址送给寄存器,程序如下所示:
lea di,D
mov dh,8
mov dl,22
其中,dh和dl分别对应于要写汉字的起始点在屏幕上显示时的第一个点的行列坐标。
随后要读取组成点的信息,程序如下所示:
mov char_cnt1,cx
mov pointer1,di
mov line_on1,dh
mov col_on1,dl
12
mov char,cx
程序中char_cnt1指字符,pointer1指颜色,line_on1为行坐标,col_on1为列坐标。
在子程序move_shape1、Amust_2、Amust_21中,写点的程序大致相同,程序如下:
add dh,[di+2]
add dl,[di+3]
mov ah,2
int 10h
mov al,[di]
mov bl,[di+1]
push cx
mov cx,1
mov ah,09
int 10h
pop cx
add di,4
值得指出的是,程序中将寄存器cx入栈随后又出栈的目的在于,入栈是为了保存cx中的数值,将寄存器cx空出来,作为计数用,随后的出栈则是重新将已经保存的cx中的值保存到cx中,作为循环次数用。
程序中一直到pop cx之前的程序都是写点的程序,而 add di,4则是为写下一个点做准备,只需要返回继续执行上面的程序则可以继续写点了。
(3)擦除蓝色V形条纹的形成
数据段中定义的组成点数不足以将汉字覆盖,因而要将db 40h,0eh,1,-1以及db 02ah,0bh,-1,0这两个点重复写11次,从而达到扩充条纹,形成条纹的目的,程序如下:
cmp al,40h
je Aexitx0
cmp al,02ah
je Aexitx0
Aexitx0: dec Acount0
jne Aplot_next
mov Acount0,11
13
在主程序中已经将 Acount0的值定义为11,在11个“@”写完之后,将给Acount0重
新赋值为11,在遇到02ah对应的字符时,将继续执行程序 Aexitx0,在将此字符重复写11
次。
(4)蓝色条纹的移动与屏幕的擦除
本次课程设计中,文字的闪烁是通过蓝色V形条纹的扫过覆盖文字来实现的。
程序如下
所示:
Aerase_next: add dh,[di+2]
add dl,[di+3]
cmp dl,2
je Aleft
mov ah,2
int 10h
mov ah,8
int 10h
cmp al,40h
je Aexitx2
cmp al,02ah
je Aexitx2
jmp Aexitx3
Aexitx2: dec Acount0
jne Aexitx3
mov Acount0,11
Aexitx3: mov al,'#'
mov bl,03h
push cx
mov cx,1
mov ah,9
int 10h
pop cx
14
cmp Acount0,11
jne Aerase_next
add di,4
loop Aerase_next
dec col_on1
程序中也同样涉及了@ 和* 的持续编写程序,以及寄存器cx的出栈入栈操作的编写程序,再此不做多的解释。
在每次写完擦除蓝色V形条纹后,dec col_on1实现了起始点列坐标的自减1,从而实现条纹的从右向左行进。
而屏幕的擦除则是通过比较V形条纹经过处的字符与#的比较,相同的话不做改变,不同的话将此字符改变为#来实现的。
(5)按Q、q退出程序
设计中要求程序在运行时,按下Q或是q,能够退出,程序如下:
mov ah,0bh
int 21h
cmp al,0
jz Aagain0
mov ah,1
int 21h
cmp al,'q'
jz exit
cmp al,'Q'
jz exit
exit: mov ax,4c00h
int 21h
程序先判断有没有字符输入,没有就返回执行Aagain0,有再将输入的字符与Q或q进
行判断,相等时则跳转至程序exit,返回DOS界面,实现运行程序的退出。
15
调试使用汇编语言调试器DEBUG进行调试。
DEBUG 程序是专门为汇编语言设计的一种调试工具。
它能给DOS提供有力的纠错、跟踪和运行功能,并能检查系统的各个数据。
该
工具可以通过单步、设置断点等方法为程序设计者提供一种有效的调试手段,其功能主要包
括以下几个方面:
1)直接输入、更改、跟踪、运行汇编语言源程序; 2)观察操作系统的内容;
3)查看BIOS的内容;
4)观察更改RAM内部的设置值;
5)以扇区或文件的形式读写磁盘数据。
本次课程设计中,在调试过程中曾出现不少问题。
首先是按下Q或q时程序无法退出,
检查后发现,在程序中虽然运用21H号中断中的1号功能,设置了在电脑上输入一个字符与Q或是q进行比较,却没有设置功能去判断是否输入了字符,从而造成错误。
调试过程中最
常见的错误是,不能生成OBJ文件,就算运行成功,显示的结果也并不是预期的效果,而程
序中给出的错误信息无法查出。
仔细分析程序之后,依旧未发现程序的错误之处,无意之中
在数据段中将每个组成汉字的点数定义之后,程序运行成功,分析原因是在程序中,要将汉
字的点数送给寄存器,作为程序中写点的循环次数,如果没有将其进行定义,则无法知道循
环次数,就会造成预期的汉字以乱码形式显示。
程序的数据段定义,也让我花费了诸多心思。
点的形状以及颜色还好定义,关键在于点
的行列坐标,不能有丝毫的错误,否则也会造成程序显示结果的错误。
16
课程设计是培养和锻炼学生在学习完本门课后综合应用所学理论知识解决实际工程设计
和应用问题的能力、进行工程实训的重要教学环节,它具有动手、动脑,理论联系实际的特
点,是培养在校工科大学生理论联系实际、敢于动手、善于动手和独立自主解决设计实践中
遇到的各种问题能力的一种较好方法。
《微机原理与接口技术》是一门应用性、综合性、实践性较强的课程,没有实际的有针对
性设计环节,学生就不能很好的理解和掌握所学的技术知识,更缺乏解决实际问题的能力。
所以通过有针对性的课程设计,使学生学会系统地综合运用所学的技术理论知识,提高学生
在微机应用方面的开发与设计本领,系统的掌握微机硬软件设计方法。
我此次《微机原理与接口技术》课程设计的题目是《霓虹灯显示程序设计》,即要求在屏
幕上显示自己的名字或是其他文字,同时让这些文字按照一定的规律进行闪烁。
由于本次课
程设计中用到的知识中,INT 10号中断为基础,而我所学的知识中,多用到的是INT 21 号
中断,因此在课程设计开始之初,我在网上以及图书馆查阅了大量资料,对INT 10号中断的
一些常用的功能有了一定的了解,同时掌握了一些通过写点、写ASCII码值或是写像素点的
方法在屏幕上显示自己想要显示的文字,运用INT 10号中断中的颜色设置,让文字呈现不同的颜色。
在本次课程设计中,我曾经遇到了不少问题。
虽然在网上找到了不少参考程序,但是均
不符合题意,因而只得在理解参考程序的基础之上,将它们便为己用。
起初,我是在不停的
修改数据段试图找出程序写点的方式,在费劲心思掌握方法之后,却又因为没有定义点的个
数同样导致失败,始终不能生成OBJ文件。
还好,这些问题都在同学的帮助以及自己查阅之
后的情况下得到了很好的解决。
通过课程设计实践,我不仅培养了自己的实际动手能力,检验自己对本门课学习的情况,
更培养了在实际的工程设计中查阅专业资料、工具书或参考书,掌握工程设计手段和软件工
具,并能以图纸和说明书表达设计思想和结果的能力,实现由学习知识到应用知识的初步过
渡,同时也形成事实求是和严肃认真的工作态度,为自己今后进入社会参加工作打下良好基
础。
17
[1]郑学坚、周斌.微型机算计原理及应用(第三版).北京:清华大学出版社,2003.6 [2]谭浩强.C程序设计(第二版).北京:清华大学出版社,2002.1
[3] [美]Harold J.Rood著,杜大鹏、龚小平等译.北京:中国水利水电出版社,2004.6 [4]周佩玲.微机原理与接口技术.北京:电子工业出版社,2006.6
[5]朱定华.微机原理、汇编与接口技术学习指导.北京:清华大学出版社,2004.7
18
data_seg segment ;定义数据段 jeep db 6 ;擦除V型条纹的位形图
db 3dh,0eh,0,0
db 40h,0eh,1,-1
db 3dh,0eh,1,0
db 3ch,0eh,0,-1
db 02ah,0bh,-1,0
db 3ch,0eh,-1,0 ;汉字“大”、“小”的位形图也用相同方法得到
char_cnt1 dw ?
pointer1 dw ?
line_on1 db ?
col_on1 db ?
char dw ?
Acount db ?
Acount0 db ?
Acount1 db ?
data_seg ends
code_seg segment
assume cs:code_seg,ds:data_seg
main proc far ;定义主函数
push ds ;寄存器入栈
sub ax,ax ;ax寄存器清零
sub cx,cx ;cx寄存器清零
push ax
push cx
mov ax,data_seg
mov ds,ax
mov Acount1,2
19
mov Acount0,11
Aagain0: lea di,D ;把汉字“大”的位形图地址送给di mov dh,8 ;组成汉字“大”的点的起始点的显示坐标
mov dl,22
call move_shape1 ;调用子程序move_shape1
call Amust_2 ;调用子程序Amust_2
lea di,jeep ;把jeep的地址送给di
mov dh,4 ;组成jeep的起始点的坐标
mov dl,75
call move_shape1 ;调用子程序move_shape1
call Amust_21 ;调用子程序Amust_21
lea di,X ;把汉字“小”的位形图地址送给di
mov dh,12 ;组成汉字“小”的起始点的显示坐标
mov dl,44
call move_shape1 ;调用子程序move_shape1
call Amust_2 ;调用子程序Amust_2
mov ah,0bh ;判断有没有字符输入
int 21h
cmp al,0
jz Aagain0 ;没有字符输入时返回执行Aagain0
mov ah,1
int 21h
cmp al,'q' ;输入字符为“Q”或是“q”时执行exit jz exit
cmp al,'Q'
jz exit
exit: mov ax,4c00h ;返回DOS界面
int 21h
move_shape1 proc near ;move_shape1子程序
20
push ax
push bx
push cx
push dx
push di
mov ah,0fh ;读取显示器模式
int 10h
sub ch,ch
mov cl,[di]
inc di
mov char_cnt1,cx
mov pointer1,di
mov line_on1,dh
mov col_on1,dl
mov char,cx
pop di
pop dx
pop cx
pop bx
pop ax
ret
move_shape1 endp ;move_shape1子程序结束Amust_2 proc near ;Amust_2子程序
push ax
push bx
push cx
push dx
push di
mov ah,0fh ;读取显示器模式
21
int 10h
sub cx,cx ;cx寄存器清零
mov cx,char_cnt1 ;读取位形图组成点的字符、颜色、横纵坐标信息mov di,pointer1
mov dh,line_on1
mov dl,col_on1
Aplot_next0: add dh,[di+2]
add dl,[di+3]
mov ah,2 ;设置光标位置
int 10h
mov al,[di]
mov bl,[di+1]
push cx
mov cx,1
mov ah,09
int 10h ;写第一个点
pop cx ;cx出栈,所存的为初始值,作为循环次数
add di,4 ;准备写下一个点
call dly_qrtr ; 调用延时子程序
loop Aplot_next0 ;返回执行Aplot_next0
pop di
pop dx
pop cx
pop bx
pop ax
ret
Amust_2 endp
Amust_21 proc near ;Amust_21子程序
push ax
22
push bx
push cx
push dx
push di ;寄存器入栈
mov ah,0fh
int 10h
mov Acount,20
Aexit1: call dly_qrtr
dec Acount
jne Aexit1 ;延时,延长时间为延时程序中的20倍Aexit5: sub cx,cx
mov cx,char_cnt1 ;读取位形图组成点的字符、颜色、横纵坐标信息
mov di,pointer1
mov dh,line_on1
mov dl,col_on1
Aplot_next: add dh,[di+2]
add dl,[di+3]
cmp dl,2
je Aexit4 ;判断是否到达屏幕最左端,是的话执行Aexit4: mov ah,2 int 10h
mov al,[di]
mov bl,[di+1]
push cx
mov cx,1
mov ah,09
int 10h ;在指定坐标处写第一个点
pop cx ;保存循环次数
cmp al,40h ; 将指定坐标处的字符与@进行比较
23
je Aexitx0 ;相同时候执行Aexitx0
cmp al,02ah ;将指定坐标处的字符与*进行比较
je Aexitx0 ;相同时候执行Aexitx0
jmp Aexitx1 ;与上边两种情况不同时执行Aexitx1
Aexitx0: dec Acount0 ;若制定坐标处字符为@或是*,则将此字符循环写11次
jne Aplot_next ;不同时返回执行Aplot_next mov Acount0,11
Aexitx1: add di,4 ;准备写第二个点
loop Aplot_next
call dly_qrtr
call dly_qrtr
call dly_qrtr ;调用延时子程序
call Aerase ;调用子程序Aerase
jmp Aexit5 ;返回Aexit5,读取点的信息
Aexit4: call Aerase
pop di
pop dx
pop cx
pop bx
pop ax
ret
Amust_21 endp
Aerase proc near
mov cx,char_cnt1 ;读取点的基本信息
mov di,pointer1
mov dh,line_on1
mov dl,col_on1
Aerase_next: add dh,[di+2]
add dl,[di+3]
24
cmp dl,2
je Aleft ;列坐标与2进行比较,相同的话执行Aleft
mov ah,2
int 10h
mov ah,8
int 10h ;设置光标位置同时读取位置处的字符以及其属性
cmp al,40h ; 将指定坐标处的字符与@进行比较
je Aexitx2 ;相同时候执行Aexitx2
cmp al,02ah ;将指定坐标处的字符与*进行比较
je Aexitx2 ;相同时候执行Aexitx2
jmp Aexitx3 ;与上边两种情况不同时执行Aexitx3
Aexitx2: dec Acount0 ;若制定坐标处字符为@或是*,则将此字符循环写11次
jne Aexitx3 ;不同时执行Aexitx3
mov Acount0,11
Aexitx3: mov al,'#'
mov bl,03h ;设置擦除条纹扫过后留下字符形状与颜色
push cx ;保存cx内容
mov cx,1
mov ah,9
int 10h ;显示一个字符
pop cx
cmp Acount0,11
jne Aerase_next
add di,4 ;准备写下一个字
loop Aerase_next
dec col_on1 ; 字符的列坐标自减1,实现从右向左运动mov cx,char_cnt1
mov di,pointer1
mov dh,line_on1
25
mov dl,col_on1
Aleft: ret
Aerase endp
dly_qrtr proc near ;延时子程序
push cx
push dx
mov dx,255
dll: mov cx,45530
dl2: loop dl2
dec dx
jnz dll
pop dx
pop cx
ret
dly_qrtr endp
code_seg ends
end main ;主函数结束26。