微机程序设计代码例题.docx
《微机程序设计代码例题.docx》由会员分享,可在线阅读,更多相关《微机程序设计代码例题.docx(21页珍藏版)》请在冰豆网上搜索。
![微机程序设计代码例题.docx](https://file1.bdocx.com/fileroot1/2023-4/29/9b33226d-7508-43da-a355-6b4f8a36e74e/9b33226d-7508-43da-a355-6b4f8a36e74e1.gif)
微机程序设计代码例题
一、简单程序设计
简单程序设计是没有分支,没有循环的直线运行程序,程序执行按照IP内容自动增加的顺序进行。
例1利用查表法计算平方值。
已知0~9的平方值连续存在以SQTAB开始的存储区域中,求SUR单元内容X的平方值,并放在DIS单元中。
假定0≤X≤9且为整数。
分析:
建立平方表,通过查表完成。
STACKSEGMENT
DB100DUP(?
)
STACKENDS
DATASEGMENT
SURDB?
DISDB?
SQTABDB0,1,4,9,16,25,36,49,64,81;0~9的平方表
DATAENDS
CODESEGMENT
ASSUMECS:
CODE,DS:
DATA,SS:
STACK,ES:
DATA
BEGIN:
PUSHDS
MOVAX,0
PUSHAX;保证返回DOS,
MOVAX,DATA
MOVDS,AX;为DS送初值
LEABX,SQTAB;以下程序部分完成查表求平方值
MOVAH,0;亦可用查表指令完成(如下程序段)
MOVAL,SUR;AL=XLEABX,SQTAB
ADDBX,AX;MOVAL,SUR
MOVAL,[BX];XLAT
MOVDIS,AL;MOVDIS,AL
CODEENDS
ENDBEGIN
例2已知Z=(X+Y)-(W+Z),其中X,Y,Z,W均为用压缩BCD码表示的数,写出程序。
分析:
这也是一种典型的直线程序,在这里要注意是BCD数相加,要进行十进制调整。
具体程序如下:
MOVAL,Z
MOVBL,W
ADDAL,BL
DAA
MOVBL,AL;BL=(W+Z)
MOVAL,X
MOVDL,Y
ADDAL,DL;AL=(X+Y)
DAA;十进制调整
SUBAL,BL;AL=(X+Y)-(Z+W)
DAS;十进制调整
MOVZ,AL;结果送Z
表3-2子程序R1—R8的入口地址表
P1
子程序R1的入口偏移地址
P2
子程序R2的入口偏移地址
P3
子程序R3的入口偏移地址
……
……
…….
……
P7
子程序R7的入口偏移地址
P8
子程序R8的入口偏移地址
例2利用表实现分支
根据AL中各位被置位情况,控制转移到8个子程序P1~P8之一中去。
转移表的结构如表3-2所示。
分析:
对于这种程序关键要找出每种情况的转移地址,从图中可见
表地址=表基地址+偏移量,而偏移量可由AL各位所在位置*2求得。
流程图见图3-3。
DATASEGMENT
BASEDWSR0,SR1,SR2,SR3,
SR4,SR5,SR6,SR7
DATAENDS
CODESEGMENT
ASSUMECS:
CODE,DS:
DATA,ES:
DATA
BEGIN:
PUSHDS
XORAX,AX
PUSHAX
MOVAX,DATA图3-3流程图
MOVDS,AX
LEABX,BASE;表头送BX
INAL,PORT
GETBIT:
RCRAL,1;右移一位
JCGETAD;移出位是1?
INCBX
INCBX;修改指针
JMPGETBI
GETAD:
JMPWORDPTR[BX];实现散转
CODEENDS
ENDBEGIN
根据跳转表构成方法不同,实现分支的方法也有所改变,下面有三个问题希望大家思考:
(1)若跳转表地址由段值和偏移量四个字节构成,程序应如何实现?
(2)若跳转表中的内容由JMPOPRD指令构成,表的结构应如何组织、程序如何实现?
(3)上述程序若不用间接跳转指令,而改为直接跳转,程序如何变动?
例3将内存中某一区域的原数据块传送到另一区域中。
分析:
这种程序若源数据块与目的数据块之间地址没有重叠,则可直接用传送或串操作实现;若地址重叠,则要先判断源地址+数据块长度是否小于目的地址,若是,则可按增量方式进行,否则要修改指针指向数据块底部,采用减量方式传送。
程序如下:
DATASEGMENT
STRDB1000DUP(?
)
STR1EQUSTR+7
STR2EQUSTR+25
STRCOUNTEQU50
DATAENDS
STACKSEGMENTPARASTACK‘STACK’
STAPNDB100DUP(?
)
STACKENDS
CODESEGMENT
ASSUMECS:
CODE,DS:
DATA,ES:
DATA,SS:
STACK
GOOPROC
PUSHDS
SUBAX,AX;将AX清零
PUSHAX
MOVAX,DATA
MOVDS,AX
MOVES,AX
MOVAX,STACK
MOVSS,AX
MOVCX,STRCOUNT
MOVSI,STR1
MOVDI,STR2
CLD;将DF置0确定地址修改方向
PUSHSI;将源首地址入栈
ADDSI,STRCOUNT-1;判断源地址+数据块长度是否小
CMPSI,DI;于目的地址
POPSI;将源首地址弹出堆栈,赋给SI
JLOK;如果源地址+数据;块长度小于目的地址,直接传送数据
STD;如果大于目的地址,将DF置1改变地址修改方向
ADDSI,STRCOUNT-1;从最后一个存储单元传送数据,以免
ADDDI,STRCOUNT-1;把源数据中最后几个单元的数据覆盖
OK:
REPMOVSB
RET
GOOENDP
CODEENDS
ENDGOO
例4设内存BUFF开始的单元中依次存放着30个8位无符号数,求它们的和并放在SUM单元中,试编写程序。
分析:
这是一个求累加的程序。
(设计思想同C语言)程序如下:
MOVSI,BUFF;设地址指针
MOVCX,30;设计数初值
XORAX,AX;设累加器初值
AGAIN:
ADDAL,[SI]
ADCAH,0
INCSI
DECCX
JNZAGAIN;循环累加
MOVSUM,AX
例4在给定个数的16位数串中,找出大于零、等于零和小于零的个数,并紧跟着原串存放。
分析:
这是一个统计问题,须设定三个计数器分别统计三种情况下的结果。
程序如下:
DATASEGMENT
BUFFDWX1,X2,X3,……,Xn
COUNTEQU$-BUFF;此时,COUNT的值为BUFF所占的字节数
PLUSEDB?
ZERODB?
MINUSDB?
DATAENDS
CODESEGMENT
ASSUMECS:
CODE,DS:
DATA
ASSUMEES:
DATA,SS:
STACK
BEGIN:
MOVAX,DATA
MOVDS,AX
MOVCX,COUNT
SHRCX,1;相当于除2,正好为BUFF中的数据个数
MOVDX,0;设定计数器初值
MOVAX,0;设定计数器初值
LEABX,BUFF
AGAIN:
CMPWORDPTR[BX],0
JAEPLU;大于等于0,则转PIU
INCAH;<0,则统计
JMPNEXT
PLU:
JZZER;=0,则转ZER
INCDL;>0,则统计
JMPNEXT
ZER:
INCDH;=0,则统计
NEXT:
INCBX
INCBX
LOOPAGAIN
MOVPLUS,DL
MOVZERO,DH
MOVMINUS,AH
MOVAX,4C00H
INT21H
CODEENDS
ENDBEGIN
第七章
8259A的应用举例
例1.IBMPC机中,只有一片8259A,可接受外部8级中断。
在I/O地址中,分配8259A的端口地址为20H和21H,初始化为:
边沿触发、缓冲连接、中断结束采用EOI命令、中断优先级采用完全嵌套方式,8级中断源的中断类型分别为08H—0FH,初始化程序为:
MOVDX,20H
MOVAL,00010011B
OUTDX,AL;写入ICW1
MOVDX,21H
MOVAL,08H
OUTDX,AL;写入ICW2
MOVAL,00001101B
OUTDX,AL;写入ICW4
XORAL,AL
OUTDX,AL;写入OCW1
。
。
。
。
。
。
STI
。
。
。
。
。
。
例2.进入和退出特殊屏蔽方式的流程图。
假定,初始化之后,8259A工作于完全嵌套方式,要求对于IR3的中断级,
能够允许任何级别的中断中断其中断服务程序,即8259A按特殊屏蔽方式工作。
因而在响应IR3而执行IR3的中断服务程序时,在A处,写入OCW1以屏蔽IR3,然后写入OCW3使ESMM=SMM=1,于是从A处开始,8259A进而特殊屏蔽方式,此后继续执行IR3的中断服务程序。
在中断服务结束之前,再向8259A写入OCW3使ESMM=1,SMM=0,结束特殊屏蔽方式,返回到完全嵌套方式,接着写入OCW1,撤消对IR3的屏蔽,最后写入OCW2,向8259A发出EOI命令。
此例,说明在IR3的中断服务程序的A处至B处,允许任何级别的中断源中断IR3的服务程序。
(除本身之外)
。
。
。
IR3中断服务程序入口
STI保护现场
。
。
。
STI开中断
MOVAL,00001000B服务程序
OUT21H,AL;OCW1写入OCW1,使IM3=1
MOVAL,01101000B写入OCW3,使ESMM=SMM=1
OUT20H,AL;OCW3继续服务
。
。
。
写入OCW3,使ESMM=1,SMM=0
MOVAL,01001000B写入OCW1,使IM3=0
OUT20H,AL;OCW3写入OCW2,普通的EOI命令
MOVAL,00H中断返回
OUT21H,AL;OCW1
MOVAL,00100111B
OUT20H,AL;OCW3
OUT21H,AL;OCW3EOI命令
例3.读8259A相关寄存器的内容。
设8259A的端口地址为20H、21H,请读入IRR、ISR、IMR寄存器的内容,
并相继保存在数据段2000H开始的内存单元中;若该8259A为主片,请用查询
方式,查询哪个从片有中断请求。
解:
MOVAL,xxx01010B发OCW3,欲读取IRR的内容
OUT20H,AL
INAL,20H读入并保存IRR的内容
MOV(2000H),AL
MOVAL,xxx01011B发OCW3,欲读取ISR的内容
OUT20H,AL
INAL,20H读入并保存ISR的内容
MOV(2001H),AL
INAL,21H读入并保存ISR的内容
MOV(2002H),AL
MOVAL,xxx0110xB发OCW3,欲查询是否有中断请求
OUT20H
INAL,20H读入相应状态,并判断最高位是否为1
TESTAL,80H
JZDONE
ANDAL,07H判断中断源的编码
…………
DONE:
HLT
第八章
接口应用举例
例4将上例中8255A的工作方式改为方式1,采用中断方式将BUFF开始的缓冲区中的100个字符从打印机输出。
(假设打印机接口仍采用Centronics标准)
分析:
仍用PC0作为打印机的选通,打印机的
作为8255A的A口,
8255A的中断请求信号(PC3)接至系统中断控制器8259A的IR3,其它硬件连线同上例,如图7-15所示。
图7-15中断方式硬件连线
8255A的控制字为:
1010XXX0
PC0置位:
00000001即01H
PC0复位:
00000000即00H
PC6置位:
00001101即0DH,允许8255A的A口输出中断
由硬件连线可以分析出,8255A的4个口地址分别为:
00H,01H,02H,03H。
假设8259A初始化时送ICW2为08H,则8255AA口的中断类型码是0BH,此中断类型码对应的中断向量应放到中断向量表从2CH开始的4个单元中。
主程序:
MAIN:
MOVAL,0A0H
OUT03H,AL;设置8255A的控制字
MOVAL,01H;使选通无效
OUT03H,AL
XORAX,AX
MOVDS,AX
MOVAX,OFFSETROUTINTR
MOVWORDPTR[002CH],AX
MOVAX,SEGROUTINTR
MOVWORDPTR[002EH],AX;送中断向量
MOVAL,0DH
OUT03H,AL;使8255AA口输出允许中断
MOVDI,OFFSETBUFF;设置地址指针
MOVCX,99;设置计数器初值
MOVAL,[DI]
OUT00H,AL;输出一个字符
INCDI
MOVAL,00H
OUT03H,AL;产生选通
INCAL
OUT03H,AL;撤消选通
STI;开中断
NEXT:
HLT;等待中断
LOOPNEXT;修改计数器的值,指向下一个要输出的字符
HLT
中断服务子程序如下:
ROUTINTR:
MOVAL,[DI]
OUT00H,AL:
从A口输出一个字符
MOVAL,00H
OUT03H,AL:
产生选通
INCAL
MOV03H,AL;撤消选通
INCDI:
修改地址指针
IRET:
中断返回
五.8251A应用举例
1.异步模式下的初始化程序举例
设8251A工作在异步模式,波特率系数(因子)为16,7个数据位/字符,偶校验,2个停止位,发送、接收允许,设端口地址为00E2H和00E4H。
完成初始化程序。
分析:
根据题目要求,可以确定模式字为:
11111010B即FAH
而控制字为:
00110111B即37H
则初始化程序如下:
MOVAL,0FAH;送模式字
MOVDX,00E2H
OUTDX,AL;异步方式,7位/字符,偶校验,2个停止位
MOVAL,37H;设置控制字,使发送、接收允许,清出错标志,使
、
OUTDX,AL;有效
2.同步模式下初始化程序举例
设端口地址为52H,采用内同步方式,2个同步字符(设同步字符为16H),偶校验,7位数据位/字符。
分析:
根据题目要求,可以确定模式字为:
00111000B即38H
而控制字为:
10010111B即97H。
它使8251A对同步字符进行检索;同时使状态寄存器中的3个出错标志复位;此外,使8251A的发送器启动,接收器也启动;控制字还通知8251A,CPU当前已经准备好进行数据传输。
具体程序段如下:
MOVAL,38H;设置模式字,同步模式,用2个同步字符,
OUT52H,AL;7个数据位,偶校验
MOVAL,16H
OUT52H,AL;送同步字符16H
0UT52H,AL
MOVAL,97H;设置控制字,使发送器和接收器启动
OUT52H,AL
3.利用状态字进行编程的举例
下面的程序段先对8251A进行初始化,然后对状态字进行测试,以便输入字符。
本程序段可用来输入80个字符。
分析:
8251A的控制和状态端口地址为52H,数据输入和输出端口地址为50H。
字符输入后,放在BUFFER标号所指的内存缓冲区中。
具体的程序段如下:
MOVAL,0FAH;设置模式字,异步方式,波特率因子为16,
OUT52H,AL;用7个数据位,2个停止位,偶校验
MOVAL,35H;设置控制字,使发送器和接收器启动,
OUT52H,AL;并清除出错指示位
MOVDI,0;变址寄存器初始化
MOVCX,80;计数器初始化,共收取80个字符
BEGIN:
INAL,52H;读取状态字,测试RXRDY位是否为1,如为0,
TESTAL,02H;丢示未收到字符,故继续读取状态字并测试
JZBEGIN
INAL,50;读取字符
MOVDX,OFFSETBUFFER
MOV[DX+DI],AL
INCDI;修改缓冲区指针
INAL,52H;读取状态字
TESTAL,38H;测试有无帧校验错,奇/偶校验错和
JZERROR;溢出错,如有,则转出错处理程序
L00PBEGIN;如没错,则再收下一个字符
JMPEXIT;如输入满足80个字符,则结束
ERROR:
CALLERR-0UT;调出错处理
EXIT:
……
8253的初始化编程
要使用8253,必须首先进行初始化编程,初始化编程包括设置通道控制字和送通道计数初值两个方面,控制字写入8253的控制字寄存器,而初始值则写入相应通道的计数寄存器中。
初始化编程包括如下步骤:
(1).写入通道控制字,规定通道的工作方式
(2).写入计数值,若规定只写低8位,则高8位自动置0,若规定只写高8位,则低8位自动置0。
若为16位计数值则分两次写入,先写低8位,后写高8位。
D0:
用于确定计数数制,0,二进制;1,BCD码
例1:
设8253的端口地址为:
04H~07H,要使计数器1工作在方式0,仅用8位二进制计数,计数值为128,进行初始化编程。
控制字为:
01010000B=50H
初始化程序:
MOVAL,50H
OUT07H,AL
MOVAL,80H
OUT05H,AL
例2:
设8253的端口地址为:
F8H~FBH,若用通道0工作在方式1,按二――十进制计数,计数值为5080H,进行初始化编程。
控制字为:
00110011B=33H
初始化程序:
MOVAL,33H
OUT0FBH,AL
MOVAL,80H
OUT0F8H,AL
MOVAL,50H
OUT0F8H,AL
例3:
设8253的端口地址为:
04H~07H,若用通道2工作在方式2,按二进制计数,计数值为02F0H,进行初始化编程。
(P164 例3)
控制字为:
10110100B=0B4H
初始化程序:
MOVAL,0B4H
OUT07H,AL
MOVAL,0F0H
OUT06H,AL
MOVAL,02H
OUT06H,AL
2.读取8253通道中的计数值
8253可用控制命令来读取相应通道的计数值,由于计数值是16位的,而读取的瞬时值,要分两次读取,所以在读取计数值之前,要用锁存命令,将相应通道的计数值锁存在锁存器中,然后分两次读入,先读低字节,后读高字节。
当控制字中,D5、D4=00时,控制字的作用是将相应通道的计数值锁存的命令,锁存计数值在读取完成之后,自动解锁。
如要读通道1的16位计数器,编程如下:
地址F8H~FBH。
MOVAL,40H;
OUT0FBH,AL;锁存计数值
INAL,0F9H
MOVCL,AL;低八位
INAL,0F9H;
MOVCH,AL;高八位
六、8253的编程应用
例1在IBMPC/XT中,8253作为定时计数器电路,它的三个通道的作用分别为:
计数器0编程为方式3,GATE0固定为高电平,OUT0作为中断请求信号接至8259A中断控制器的第0级IRQ0。
这个定时中断(约55ms)用于报时时钟的时间基准。
计数器1编程为方式2,GATE1固定为高电平,OUT1的输出经过一个D触发器后作为8237A-5DMA控制器通道0的DMA请求DREQ0,用于定时(约15us)启动刷新动态RAM,这样在2ms内可以有132次刷新,大于128次(128次是系统的最低要求)。
计数器2编程为方式3,1KHZ的方波输出,通过滤波,去除高频分量后送扬声器,GATE2是8255的PB0,OUT输出经一与门控制,控制信号为8255的PB1,这样利用PB0、PB1同时为高的时间来控制发长音还是发短音。
时钟频率F为1.19MHZ,T=1/F
8253-5的地址为040H~043H,ROM-BIOS对8253-5的编程如下:
计数器0用于定时中断。
MOVAL,0011 0110B;0011 0110――二进制
OUT43H,AL
MOVAL,0;计数初值为0000,即为
OUT40H,AL
OUT40H,AL;定时为:
,即频率为
――每秒产生
次
时钟中断(CLK周期为:
)
计数器1用于定时DMA请求。
MOVAL,0101 0100B;0101 0100――二进制
OUT43H,AL
MOVAL,12H;计数初值为18D,定时:
OUT41H,AL
计数器2用于产生1KHZ的方波送至扬声器发声,声响子程序为BEEP,入口地址为FFA08H。
BEEP PROC NEAR
MOVAL,1011 0110B;1011 0110――二进制
OUT43H,AL
MOVAX,0533H;计数初值为1331
OUT42H,AL
MOVAL,AH
OUT42H,AL
INAL,61H;取8255B端口
MOVAH,AL;存在AH
ORAL,03H;使
OUT61H,AL;输出至82255的B端口,使扬声器发声
SUBCX,CX;循环计数
G7:
LOOPG7
MOVBH,0
DECBX;BL的值为控制长短声,BL=6(长),BL=1(短)
JNZG7
MOVAL,AH;恢复8255B端口值,停止发声
OUT61H,AL
RET
BEEPENDP
例2:
CPU为8088,用8253的CH0(通道0),每隔2ms输出一个负脉冲,设CLK为2MHZ,完成软件设计。
分析:
时间常数的计算:
已知时钟频率F及定时时间t,求计数初值N:
设用方式2,时间常数:
控制字:
0011 0100――――二进制
端口地址:
CH0――00H;控制端口――03H
初始化编程:
MOVAL,34H;0011 0100B
OUT03H,AL
MOVAX,4000
OUT00H,AL;先送低八位
MOVAL,AH
MOVAL,02H
OUT00H,AL;再送高八位