北京邮电大学 微机原理软件实验3.docx
《北京邮电大学 微机原理软件实验3.docx》由会员分享,可在线阅读,更多相关《北京邮电大学 微机原理软件实验3.docx(20页珍藏版)》请在冰点文库上搜索。
北京邮电大学微机原理软件实验3
北京邮电大学
微机原理软件实验·第三次实验
题目一:
一、实验目的
1、初步掌握中断程序的设计方法;
2、初步掌握修改DOS系统中断,以适应实际使用的方法。
二、实验内容
编一程序,在显示器上显示时、分、秒。
借用计数器8253的Timer0作为中断源,通过8259A向CPU发中断,每10ms产生一次中断。
在中断服务程序中管理刷新时、分、秒。
要求:
1、输入文件名(如:
CLK)后清屏后显示:
2、Currenttimeis:
xx:
xx:
xx(时分秒键盘输入)
3、打回车,时、分、秒开始计时。
时钟不停的刷新。
4、当键入CTRL+C时,停止计时,返回系统,且系统正常运行不死机。
提示:
8253的初始化程序段可借用。
口地址为40H、41H、42H、43H,控制字为36H=00110110B,时间常数TC=11932:
1.1932MHz/11932=100Hz,输出方波频率为100Hz,其周期为1000/100=10ms。
三、设计思路
1、程序流程图
2、中断子程序流程图
3、可能用到的指令
1STI置中断允许位.
CLI清中断允许位.
格式:
CLISTI
功能:
开关中断允许标志,用于在程序中防止中断嵌套,设置中断。
2STOS(STOreintoString)存入串指令
格式:
STOSDST
STOSB//存放字节串(DI)=AL
STOSW//存放字串(DI)=AX
执行操作:
把AL或AX中的内容存放由DI指定的附加段的字节或字单元中,并根据DF值修改及数据类型修改DI的内容。
字节操作:
((DT))←(AL),(DI)←(DI)±1
字操作:
((DI))←(AX),(DI)←(DI)±2无条件转移指令
3IN输入指令
长格式为:
INAL,PORT(字节)
INAX,PORT(字)
执行的操作:
(AL)<-(PORT)(字节)
(AX)<-(wPORT+1,PORT)(字)
短格式为:
INAL,DX(字节)
INAX,DX(字)
4OUT输出指令
长格式为:
OUTPORT,AL(字节)
OUTPORT,AX(字)
执行的操作:
(PORT)<-(AL)(字节)
(PORT+1,PORT)<-(AX)(字)
短格式为:
OUTDX,AL(字节)
OUTDX,AX(字)
执行的操作:
((DX))<-(AL)(字节)
((DX)+1,(DX))<-AX(字)
5设置中断向量
格式:
moval,8
movah,25h
int21h
DS:
DX=中断向量
AL=中断类型号
6查看中断向量
格式:
moval,8
movah,35h
AL=中断类型
ES:
BX=中断向量
4、计数器芯片8253简介
1初始化
使用8253前,要进行初始化编程。
初始化编程的步骤是:
A向控制寄存器端口写入控制字对使用的计数器规定其使用方式等。
B向使用的计数器端口写入计数初值。
28253控制字
D7D6=00:
使用0号计数器,D7D6=01:
使用1号计数器
D7D6=10:
使用2号计数器,D7D6=11:
无效
D5D4=00:
锁存当前计数值
D5D4=01:
只写低8位(高8位为0),读出时只读低8位
D5D4=10:
只写高8位(低8位为0),读出时只读高8位
D5D4=11:
先读/写低8位,后读/写高8位计数值
D3D2D1=000:
选择方式0,D3D2D1=001:
选择方式1
D3D2D1=X10:
选择方式2,D3D2D1=X11:
选择方式3
D3D2D1=100:
选择方式4,D3D2D1=101:
选择方式5
D0=0:
计数初值为二进制,D0=1:
计数初值为BCD码数
四、源程序
datasegment
count100db100
;100个10ms=1s,此处count100起计数作用
msg1db'Pleaseenterthecurrenttime(XX:
XX:
XX)!
(PressENTERtousedefaulttime)$'
msg2db'Sorry,yourdateenteredincorrectly,pleasetryagain!
$'
msg3db'Now,thetimeis:
',0ah,'(PressCtrl+CtoEXIT.)',0ah,'(PressEntertouseasaStopwatch.)',0ah,'(PressSorstosetcurrenttimeagain.)(XX:
XX:
XX)$'
msg4db0ah,'ProgramEXITnormally.$'
tenhourdb'0';小时十位数
hourdb'0',':
';小时个位数
tenmindb'0';分钟十位数
minutedb'0',':
';分钟个位数
tensecdb'0';秒十位数
seconddb'0’;秒个位数
dataends
stacksegmentstack'stack'
db256dup(0)
stackends
codesegment
assumecs:
code,ds:
data,es:
data
start:
movax,segdata
moves,ax
movds,ax
cli;使中断标志IF=0
moval,8;保存源中断向量
movah,35h
int21h
pushes
pushbx
movax,0
moves,ax;es置零,这是准备中断向量的写入
movdi,20h
movax,offsettimer;中断子程序timer的偏移量
stows
;字符串填充,将AX的内容
;(timer偏移量)存入di所指向的单元,
;di的增减取决于DF,默认段基址总是ES
movax,cs
stosw;timer端基址
moval,36h
out43h,a;设置8253控制字为36H
movbx,11932
;分频系数为11932,分频结
;果1.1932MHz/11932=100Hz,10ms变化一次
moval,bl;分两次设置分频系数
out40h,al
moval,bh
out40h,al
moval,0fch;主PIC端口设置为0fch
out21h,al
sti;开中断,允许外部中断
movax,segdata
moves,ax
movds,ax
movdx,offsetmsg1;打印提示信息1
movah,09h
int21h
movdl,0ah
movah,02h
int21h
settime:
movsi,offsettenhour;设定时间
movah,01h
int21h
cmpal,0dh
jzforever1
cmpal,'0'
jcerror2;如果输入不合法,报错
cmpal,'3'
jncerror2
mov[si],al
incsi
cmpal,'2'
jzershi
movah,01h
;如果小时高位为1,
;低位可以设置0~9
int21h
cmpal,0dh
jzforever1
cmpal,'0'
jcerror2
cmpal,'9'+1
jncerror2
mov[si],al
incsi
jmpfen
ershi:
movah,01h
;如果小时高位为2,低位可以设置0~4
int21h
cmpal,0dh
jzforever1
cmpal,'0'
jcerror2
cmpal,'4'
jncerror2
mov[si],al
incsi
jmpfen
fen:
movah,01h;分高位可设置0~5
int21h
cmpal,0dh
jzforever1
cmpal,':
'
jnzerror1
mov[si],al
incsi
movah,01h
int21h
cmpal,0dh
jzforever1
cmpal,'0'
jcerror1
cmpal,'6'
jncerror1
mov[si],al
incsi
zcy4:
movah,01h;分低位0~9
int21h
cmpal,0dh
jzforever1
cmpal,'0'
jcerror1
cmpal,'9'+1
jncerror1
mov[si],al
incsi
jmpzcy
settime2:
jmpsettime;用来跳转接力
error2:
jmperror1
forever1:
jmpnext2
zcy:
movah,01h;秒高位可设置0~5
int21h
cmpal,0dh
jzforever1
cmpal,':
'
jnzerror1
mov[si],al
incsi
movah,01h
int21h
cmpal,0dh
jzforever1
cmpal,'0'
jcerror1
cmpal,'6'
jncerror1
mov[si],al
incsi
movah,01h;秒低位可设置0~9
int21h
cmpal,0dh
jzforever1
cmpal,'0'
jcerror1
cmpal,'9'+1
jncerror1
mov[si],al
incsi
jmpnext2
error1:
movdl,0ah;用来报错:
设置时间不合法
movah,02h
int21h
movdx,offsetmsg2;打印提示信息2
movah,09h
int21h
movdl,0ah
movah,02h
int21h
jmpsettime
settime3:
jmpsettime2;跳转接力
next2:
MOVAX,0003H;做时钟显示初始化
INT10H;清屏显示
movdl,0ah
movah,02h
int21h
movdx,offsetmsg3;打印提示信息3
movah,09h
int21h
movdl,0ah
movah,02h
int21h
forever:
movbx,offsettenhour
;这个程序段循环执行
movcx,8
cmptenhour,'2';如果超过24点,置为0点
jnzdispclk
cmphour,'4'
jnzdispclk
movtenhour,'0'
movhour,'0'
dispclk:
movdl,[bx];用来显示当前时间
calldispchar
incbx
loopdispclk
;调用显示子程序,显示初始状态时间,
;比如”11:
11:
11"
movdl,0dh;输出一个换行
calldispchar
xoral,al;读键盘缓冲区
movah,0bh
int21h
cmpal,0FFH
jnznext3
movah,08h;取其字符
int21h
cmpal,03h;Ctrl+C退出
jzstop
cmpal,'s';S/s设定时间
jzsettime3
cmpal,'S'
jzsettime3
cmpal,0dh
jnznext3
movdl,0ah;回车则使用秒表功能
movah,02h
int21h
jmpforever
next3:
moval,second
next:
cmpal,second;判断second是否发生变化
jenext;如果没有,循环比较
jmpforever;如果有变化,刷新输出
stop:
movdx,offsetmsg4;打印提示信息4
movah,09h
int21h
movdl,0ah
movah,02h
int21h
popdx;恢复中断向量
popds
moval,8
movah,25h
int21h
movah,4ch
int21h
timerprocfar;中断程序timer
pushax
deccount100;计数100次
jnztimerx;如果计数小于100,跳出中断
movcount100,100
;否则重置count100<=100
;1s已经到达
incsecond;加一秒
cmpsecond,'9'
;判断大小,用于进位,以下原理相同
jletimerx
movsecond,'0'
inctensec
cmptensec,'6'
jltimerx
movtensec,'0'
incminute
cmpminute,'9'
jletimerx
movminute,'0'
inctenmin
cmptenmin,'6'
jltimerx
movtenmin,'0'
inchour
cmphour,'9'
jaadjhour
cmphour,'3'
jnztimerx
cmptenhour,'1'
jnztimerx
movhour,'1'
movtenhour,'0'
jmpshorttimerx;段内短转移
adjhour:
inctenhour
movhour,'0'
timerx:
moval,20h
out20h,al;主PIC口地址
popax;出栈恢复
iret;中断返回
timerendp
dispcharprocnear;显示子函数
pushbx
movbx,0
movah,02h
int21h;DOS功能调用,输出DL内容
popbx
ret
dispcharendp
codeends
endstart
五、实验结果(反色)
这幅图是运行程序之后,设定时间,输入的时间不合法的截图。
当输入不合法的字符时,对弹出一条错误信息,然后要求重新输入时间。
这幅图是输入一个合法字符串后,时钟被设定为该值,并且正常计数的程序截图。
这幅图是在时钟运行的过程中,按下Enter键,进入秒表模式的截图。
秒表模式,会将按下Enter的时间保存下来。
这幅图是在时钟运行的过程中,按下S键,进入设定模式的截图。
该截图输入字符串不合法。
当输入合法的字符串后,程序将清屏,这是截图和正常计时状态一样。
这幅图是按下Ctrl+C,程序正常退出的截图。
程序正常退出后,与之前的运行情况完全一样,程序运行不死机。
六、实验总结:
这次微原实验是我设计比较大型的汇编程序,从如何使用8253/8255开始,到程序被完整调通为止,这个实验带给我的是对于课本第七章、第八章的知识更加清晰的认识与了解,和对于微机运行的原理的进一步认识。
在这次实验中,我都要求自己先做整体思路规划,再去做代码实现,这样节省了我大量时间。
也给我带来了很多收获。
整体的思路规划:
我认识到,相比于直接闷头就上的编程方法,有一个好的整体思路规划,会节省很多后期的力气,对于任务的完成大有裨益。
严谨认真的代码风格:
汇编语言的编译器不如C++等高级语言,当程序出错时,并不会给出错误。
我们要有严谨的代码风格,才能保证效率。
学会调试:
汇编语言的编译器较差,当程序出错时,我们要善用DEBUG工具,去认真地分析程序的每一部动向,找到问题所在。
回归课本基本概念:
在编程的过程中,曾经出过一个bug,总是无法正常的进入计时中断Timer。
经过我查阅课本,发现是8253的控制字设置有问题。
这说明我对课本的内容掌握的还不够好,应该多多回归课本基本概念,才可以顺利的编程。