1.顺序程序设计
顺序程序又称简单程序,是指顺序执行的程序。在这种程序中,没有分支、循环或子程序。顺序结构程序虽然比较简单,但也能完成一定的功能,是构成复杂程序的基础。
【例3.25】两个8位无符号数相加,和仍为8位。
假设两个无符号数X1、X2分别存放于内部RAM的60H、61H单元中,求和送入62H单元。程序如下:
MOV R0,#60H ;设R0为数据指针
MOV A,@R0 ;取X1
INC R0
ADD A,@R0 ;X1+X2
INC R0
MOV @R0,A ;保存结果
2.分支程序设计
分支结构程序通常是利用条件转移指令来实现的。即根据条件对程序的执行情况进行判断,满足条件则转移,否则顺序执行。用于判断分支转移的指令有:JZ、JNZ、JC、JNC、JB、JNB、JBC、CJNE和DJNZ。另外,在该类分支程序的设计中,要设置好判断测试对象、程序转移方向及转移的标志地址。在MCS-51指令系统中,把这些指令结合在一起使用,就可以完成多种条件判断,如正负判断、溢出判断、大小判断等。
(1)利用条件转移指令实现程序分支。
【例3.26】比较内部RAM的40H和50H单元中两个无符号数的大小,使得40H存放大数,50H单元存放小数
程序流程图如图3.4所示。
图3.4 比较两个无符号数的大小
程序如下:
ORG 2000H
START:CLR C
MOV A,40H
SUBB A,50H
JNC DONE ;若无借位,即(40H)≥(50H)时转移
MOV A,40H
XCH A,50H ;有借位,即(40H)<(50H)时交换
MOV 40H,A
DONE:SJMP
上面的程序中,用减法指令SUBB来比较两数的大小。由于这是一条带借位的减法指令,所以在执行该指令前,先要把进位位清零。用减法指令通过借位(CY)的值来判断两数的大小,是比较两个无符号数大小的常用方法。执行JNC指令后,形成了程序分支。
(2)利用比较转移指令实现程序分支。
【例3.27】用CJNE指令实现车速自动控制。检测车速V存放到R7中,与标准车速相比较,标准车速在V1~V2之间(V1<V2),分别存放在BUF1、BUF2单元内。若V介于V1、V2之间,汽车正常行驶;若V>V2,汽车减速;若V<V1,汽车加速。该程序段编写如下:
MOV A,R7
CJNE A,BUF1,CON1
AJMP KEEP ;KEEP为保持车速程序段
CON1:JC UP ;UP为加速程序段
CJNE A,BUF2,CON2
AJMP KEEP
CON2:JNC DOWN ;DOWN为减速程序段
AJMP KEEP
KEEP:…
UP:…
DOWN:…
3.循环程序设计
在应用程序中,有时需要重复执行某一段程序,这时可采用循环程序。循环程序是指当某种条件满足时,能够重复执行某一段程序的程序结构。采用循环程序可使程序结构紧凑、节省存储单元。
循环程序一般由以下5部分组成:
①初始化部分:这是循环程序的准备部分,如给循环次数计数器、地址指针和某些地址变量赋初值。
②处理部分:为反复执行的程序段,这是循环程序的实体。
③修改部分:每执行一次处理部分后,对地址指针作一次修改,使指针指向下一数据所在位置,为进入下一轮处理作准备。
④控制部分:根据循环次数计数器的值(即循环变量值)或其它循环条件,确定循环是否继续进行。若循环次数未达规定值或循环条件满足,继续循环;否则退出循环。
⑤结束部分:分析、处理及存放程序执行结果。
循环程序的结构一般有两种形式:
①先进入处理部分,再控制循环,如图3.5a所示。这种结构至少执行一次循环体。
②先控制循环,后进入处理部分,如图3.5b所示。这种结构根据判断结果,控制循环的执行与否,有时可能不进入循环体就退出了循环。
循环程序不论是先处理后判断,还是先判断后处理,其关键是控制循环的次数。循环次数的控制方法根据实际情况而定:循环次数已知的,可以用计数器来控制;循环次数未知的,可以用某种条件控制。
图3.5 循环程序结构类型(www.xing528.com)
a)设置计数器实现已知循环次数的循环程序。
【例3.28】将首地址为STA的100个外部RAM单元清零。
该例题为循环次数已知(循环100次)的循环程序,设置R0为控制循环的计数器。
程序如下:
START:MOV R0,#64H ;设置计数器初值
MOV DPTR,#STA ;设置地址指针初值
CLR A ;累加器A清零
LOOP:MOVX @DPTR,A ;清外部RAM单元
INC DPTR ;修改地址指针
DJNZ R0,LOOP ;循环控制
SJMP
b)利用条件转移指令控制循环次数未知的循环程序。
【例3.29】设某以“$”为结束标志的字符串存放在内部RAM以STA为首地址的连续单元中(字符总数不超过256个)。统计该字符串的长度,并存放到内部RAM的LEN单元。
程序如下:
ORG 1000H
MOV R2,#STA ;设置地址指针
MOV B,#00H ;设置计数器
LOOP:MOV A,@R2
CJNE A,“$”,NEXT ;判断是否结束
MOV LEN,B ;存数据结果
SJMP DONE
NEXT:INC B ;修改计数器
INC R2 ;修改地址指针,准备下一次循环
SJMP LOOP
DONE:END
4.子程序调用设计
在实际程序编制中,往往会多次进行一些相同的计算或操作,如乘除运算、数码转换、延时等等。如果每次都重新编制一段程序,不仅麻烦,而且浪费存储空间。因此,对于一些常用的程序段,可将它们从程序中独立出来,以便由其它程序随时调用。这种独立的有一定功能的程序称为子程序。调用子程序的源程序称为主程序。
当主程序在运行中需要用子程序时,只要执行调用子程序的指令,使程序转到子程序。子程序执行完毕,依靠最后一条指令——返回指令自动返回主程序,继续其后的操作。在MCS-51指令系统中,提供了两条调用子程序指令ACALL、LCALL以及一条返回主程序的指令RET。
一个子程序在其运行过程中,还可以调用其它的子程序,这称为子程序嵌套。MCS-51对子程序嵌套的层数没有限制,但要为堆栈容量所允许。在编制子程序时,要注意以下几点:
(1)子程序的首地址必须要用标号,此标号也就是该子程序的名称。子程序的最后一定要设置一条返回指令。
(2)尽可能编成浮动地址程序,使用相对转移而不用绝对转移指令,以便于存放在存储区的任意位置。
(3)为了便于使用,每个子程序要有使用说明。其内容包括:
①子程序功能的简要说明。
②入口条件。就是指运行该子程序所需要的一些参数及其存放处。
③出口条件。这是指该子程序运行完毕后给出的结果及其存放处。
④所占用的寄存器和存储单元。
用户在调用子程序时,要注意以下两个问题:
(1)子程序的入口条件和出口条件。主程序要根据子程序的入口条件提供所需的数据,放到指定的寄存器或存储单元;根据出口条件取得该子程序的运行结果。
(2)现场保护。主程序在调用子程序时,虽已对断点作了保护,但对子程序中所用到的寄存器的内容未作保护。因此,对于在主程序和子程序中都要用到的那些寄存器,在转向子程序之前的主程序中或在子程序的起始部分,应将其内容压入堆栈,在子程序返回时再恢复。
【例3.30】单字节二进制数转换为BCD码子程序SBTOD。
功能:将单字节二进制数转换为三位BCD码。
入口:R2中存放要转换的二进制数。
出口:(R0)给出百位BCD码的存放地址。(R0)+1给出十位和个位BCD码的存放地址,高半字节放十位,低半字节放个位。
占用寄存器:A,B,R0,R2。
程序如下:
SBTOD:MOV A,R2 ;取数
MOV B,#64H
DIV AB ;除以100后,A中为百位数
MOV @R0,A ;存入(R0)单元
MOV A,#0AH
XCH A,B ;余数B送A
DIV A,B ;除以10,得十位和个位
SWAP A ;十位数放于高半字节
ADD A,B ;个位数放于低半字节
INC R0
MOV @R0,A ;十位、个位存入(R0)+1单元
RET
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。