1 顺序结构程序
顺序结构程序是按程序顺序一条指令紧接一条指令执行的程序。顺序结构程序是所有程序设计中最基本的程序结构,是应用最普遍的程序结构。它是实际编写程序的基础。
例3-37:设计一个顺序结构程序,将内部RAM的30H中的数据送到内RAM的40H和外RAM的40H中,再将内RAM的30H和31H的数据相互交换。设(30H)=16H,(31H)=28H。
解:汇编语言程序如下:
ORG 0000H
SJMP STAR
ORG 0030H
STAR:MOV 30H,#16H
MOV 31H,#28H
MOV A,30H;(A)←(30H)
MOV 40H,A;(40H)←(A),(A)=16H
MOV R0,#40H;(R0)←40H
MOV P2,#00H;(P2)←00H
MOVX @R0,A;外(0040H)←(A)
XCH A,31H;(A)与(31H)数据互换
MOV 30H,A;(30H)←(A)
SJMP $
END
结果:(40H)=16H,(0040H)=16H,(30H)=28H,(31H)=16H。
2 选择结构程序(分支程序)
选择结构程序是程序执行过程中,依据条件选择执行不同分支程序的程序。所以又称“分支程序”。为实现程序分支,编写选择结构程序时要合理选用具有判断功能的指令,如条件转移指令、比较转移指令和位转移指令等。分支程序结构分为有条件转移和无条件转移。有条件分支转移程序又可分为单分支转移和多分支转移。
间接转移指令JMP @A+DPTR由数据指针DPTR决定多分支转移程序的首地址,由A的内容选择对应分支。CJNE四条比较转移指令能对两个欲比较的单元内容进行比较,当不相等时,程序实现相对转移;若两者相等,则顺序往下执行。
简单的分支转移程序的设计,常采用逐次比较法,就是把所有不同的情况一个一个地进行比较,发现符合就转向对应的处理程序。缺点是程序太长,有n种可能的情况,就需有n个判断和转移。在实际应用中,典型例子就是当单片机系统中的键盘按下时,就会得到一个键值,根据不同的键值,跳向不同的键处理程序入口。此时,可用直接转移指令(LJMP或AJMP指令)组成一个转移表,然后把该单元的内容读入累加器A,转移表首地址放入DPTR中,再利用间接转移指令实现分支转移。
例3-38:根据寄存器R2的内容转向各处理程序PRGX(X=0~n),(R2)=0,转PRG0;(R2)=1,转PRG1;…;(R2)=n,转PRGn。
解:程序段如下:
JMP:MOV DPTR,#TAB50;转移表首地址送DPTR
MOV A,R2;分支转移参量送A
MOV B,#03H;乘数3送B
MUL AB;分支转移参量乘3
MOV R6,A;乘积的低8位暂存R6
MOV A,B;乘积的高8位送A
ADD A,DPH;乘积的高8位加到DPH中
MOV DPH,A
MOV A,R6
JMP @A+DPTR;多分支转移选择
TAB50:LJMP PRG0
LJMP PRG1
…
LJMP PRGn
例3-39:设计比较两个无符号8位二进制数的大小,并将较大数存入高地址中的程序。设两数分别存入30H和31H中,并设(30H)=42H,(31H)=30H。
解:汇编语言程序如下:
ORG 0000H
LJMP STAR
ORG 0200H
STAR:MOV 30H,#42H;(30H)←42H
MOV 31H,#30H;(31H)←30H
CLR;C←0
MOV A,30H;(A)←(30H)
SUBB A,31H;做减法比较两数
JC NEXT;(31H)≥(30H)转
MOV A,30H
XCH A,31H;大数存入31H中
MOV 30H,A;小数存入30H中
NEXT:SJMP $
END
结果:(31H)=42H,(30H)=30H。
例3-40:已知X、Y均为8位二进制数,分别存在R0、R1中,试编制能实现下面函数的程序,结果送入R1中。
解:程序设计流程图如图3-18所示,为选择结构程序中的有嵌套的分支程序。
汇编语言程序如下:设X=-6(补码为FAH)。
ORG 0000H
MOV R0,#0FAH;X数赋给R0
CJNE R0,#00H,MP1;R0≠0转MP1
MOV R1,#00H;(R0)=0,则(R1)=0
SJMP MP3;转程序尾
MP1:MOV A,R0;(A)←(R0)
JB ACC.7,MP2;A的符号位=1转MP2,表明(A)<0
MOV R1,#01H;A的符号位=0,则(R1)=1
SJMP MP3;转程序尾
MP2:MOV R1,#0FFH;送-1的补码0FFH到R1
MP3:SJMP $
END
结果:(R1)=FFH。
选择结构程序允许嵌套,即一个程序的分支又由另一个分支程序所组成,从而形成多级
选择程序结构。汇编语言本身并不限制嵌套的层数,但过多的嵌套将使程序的结构变得十分复杂,以致造成逻辑上的混乱,因此应尽量避免过多的嵌套。
3 循环结构程序
循环程序按结构形式,有单重循环与多重循环。在多重循环中,只允许外重循环嵌套内重循环。不允许循环相互交叉,也不允许从循环程序的外部跳入循环程序的内部。
循环程序的结构主要由以下4部分组成:
(1)循环初始化(赋初值)
完成循环前的准备工作。例如,在进入循环体之前需给用于循环过程的工作单元设置初值,循环控制计数初值的设置、地址指针起始地址的设置、为变量预置初值等。它们是保证循环程序正确执行所必需的。
(2)循环处理(循环体)
完成实际的处理工作,反复循环执行的部分,故又称循环体。它是循环结构的核心部分。在循环体中,有的还包括改变循环变量、地址指针等有关修改循环参数部分。
(3)循环控制
在重复执行循环体的过程中,不断修改循环控制变量,直到符合结束条件就结束循环程序的执行。是控制循环与结束的部分,通过循环变量和结束条件进行控制。
(4)循环结束
这部分是对循环程序执行的结果进行分析、处理和存放。
循环处理程序的结束条件不同,相应的控制部分的实现方法也不一样,分为计数循环控制法和条件控制法。判断是否符合结束条件,若符合就结束循环程序的执行。有的修改循环参数和判断结束条件由一条指令完成,如DJNZ指令。经常使用的延时程序便是其中的典型。
1)计数循环控制结构。依据计数器的值来决定循环次数,一般为减1计数器,计数器减到0时,结束循环。计数器初值在初始化时设定。MCS-51系列单片机的指令系统提供了功能极强的循环控制指令。
DJNZ Rn,rel;以工作寄存器作控制计数器
DJNZ direct,rel;以直接寻址单元作控制计数器
计数控制只有在循环次数已知的情况下才适用。循环次数未知,不能用循环次数来控制,往往需要根据某种条件来判断是否应该终止循环。
例3-41:在内RAM的40H开始存放了一串单字节数,串长度为8,编程求其中最大值并送R7中。对数据块中的数逐一两两相比较,较大值暂存于A中,直到整串比完,A中的值就为最大值。
解:程序如下。
MOV R0,#40H;数据块首址送地址指针R0
MOV R2,#7;循环次数送R2
MOV A,@R0;取第一个数,当作极大值
LOOP:INC R0;修改地址指针
MOV B,@R0;暂存B中
CJNE A,B,$+3;比较后产生标志(Cy),$+3为下条指令的地址
JNC NEXT;Cy=0?
MOV A,@R0;更大数送A
NEXT:NOP
DJNZ R2,LOOP;循环次数结束?
MOV R7,A;存最大值
SJMP $
2)条件控制结构。在该循环控制中,设置一个条件,判断是否满足该条件,若满足,则循环结束,若不满足该条件,则循环继续。
例3-42:一串字符依次存放在内部RAM从30H单元开始的连续单元中,字符串以0AH为结束标志,测试字符串长度。
采用逐个字符依次与0AH比较(设置的条件)的方法。如果字符与0AH不等,则长度计数器和字符串指针都加1;如果比较相等,则表示该字符为0AH,字符串结束,计数器值就是字符串的长度。
解:程序段如下。
MOV R4,#0FFH;长度计数器初值送R4
MOV R1,#2FH;字符串指针初值送R1
NEXT:INC R4
INC R1
CJNE @R1,#0AH,NEXT;比较,不等则进行下一字符比较
END
最常见的多重循环是由DJNZ指令构成的软件延时程序。
例3-43:50ms延时程序。
解:软件延时程序与指令执行时间有很大的关系。在使用12MHz晶振频率时,一个机器周期为1μs,执行一条DJNZ指令的时间为2μs,可用双重循环方法的延时50ms程序。
DEL:MOV R7,#200;本指令执行时间1μs
DEL1:MOV R6,#125;本指令执行时间1μs
DEL2:DJNZ R6,DEL2;执行内循环125次,共125×2μs=250μs
DJNZ R7,DEL1;指令执行时间2μs,执行外循环共200次
RET;指令执行时间2μs
它的延时时间为[1+(1+250+2)×200+2]μs=50.603ms
注意,用软件实现延时程序不允许有中断,否则将严重影响定时的准确性。对于延时更长的时间,可采用多重的循环。
多重循环就是循环的嵌套,即一个循环程序包含了其他循环程序,也就是循环内套循环的结构形式,也称多重循环。一般内层循环完成后,外层才执行一次,然后再逐次类推,层次分明。
例3-44:设在外RAM的TAB处开始有一个ASCII字符串,该字符串以0结尾,编程把它们从P1口输出。
解:程序如下:
ORG 0000H
MOV DPTR,#TAB;设字符串首地址指针
STOUT:MOVX A,@DPTR;取字符
JZ NEXT;整串结束则转跳
MOV P1,A;
INC DPTR;修改地址指针
SJMP STOUT;没结束继续取数发送
NEXT:…;结束处理
ORG 2000H
TAB:DB XXH,XXH,…;定义ASCII字符串
DB XXH,XXH,…,00H;以0结尾
END
4 子程序结构
将那些需多次应用的、完成相同的某种基本运算或操作的程序段从整个程序中独立出来,单独编制成一个程序段,需要时进行调用,这样的程序段称为子程序。其优点是可使程序结构简单,缩短程序的设计时间,减少占用的程序存储空间。
子程序是可在主程序中通过LCALL、ACALL等指令调用的程序段,该程序段的第一条指令地址称为子程序入口地址,它的最后一条指令必须是RET返回指令,即返回到主程序中调用子程序指令的下一条指令。
(1)子程序的设计原则
1)子程序的入口地址,子程序首条指令前必须有标号。
2)主程序调用子程序,是通过调用指令来实现。
4)子程序返回主程序时,最后一条指令必须是RET指令,其功能是把堆栈中的断点地址弹出送入PC指针中,从而实现子程序返回后能从主程序断点处继续执行主程序。
5)子程序可以嵌套,即主程序可以调用某子程序,该子程序又可调用另外的子程序。(www.xing528.com)
(2)子程序设计应注意的问题
1)参数的传递:在调用子程序前,主程序应先把有关参数(即入口参数)放到某些约定的位置,子程序在运行结束返回前,也应该把运算结果(出口参数)送到约定的位置/单元。可以用Rn或A传参数;用指针传参数,如DPTR、R0、R1;用堆栈传参数,如PUSH、POP指令。
2)信息的保护(现场的恢复和保护)。
利用堆栈:
PUSH ACC
PUSH PSW
PUSH B
POP B
POP PSW
POP ACC
(3)子程序的基本结构
典型的子程序的基本结构如下:
MAIN: ;MAIN为主程序入口标号
LCALL SUB;调用子程序SUB
SUB:PUSH PSW;现场保护
PUSH ACC;子程序处理程序段
POP ACC;现场恢复,注意要先进后出
POP PSW
RET;最后一条指令必须为RET
注意:在上述子程序结构中,现场保护与现场恢复不是必需的,要根据实际情况而定。
例3-45:设计一程序,由它的主程序循环调用子程序SHY。子程序SHY使连接到单片机P1口上的8个LED灯中的某个闪烁5次。主程序中的指令RL A将确定某个LED灯闪烁。
解:程序段如下:
ORG 0000H
MOV A,#0FEH;灯亮初值
STAR:ACALL SHY;调用闪烁子程序
RL A;左移
SJMP STAR;短跳到STAR,循环以上程序段为主程序,
;以下程序段为子程序,标号SHY为其入口
SHY:MOV R2,#5;闪烁子程序,闪烁5次计数
SHY1:MOV P1,A;点亮
NOP;延时
MOV P1,#0FFH;熄灭
NOP;延时
DJNZ R2,SHY1;循环
RET;子程序返回
END
本例中的子程序入口地址是标号SHY地址,子程序返回指令是RET,主程序调用该子程序的调用指令是ACALL SHY。为观察到LED灯的闪烁,要求状态时钟信号频率低,为此,单片机可采用频率很低的外部振荡器信号。
子程序内主要是一个循环结构程序,很简单。实际应用中,大多数子程序的结构具有复杂程度不等的结构。主程序调用的子程序运行时有可能改变主程序中某些寄存器的内容,PSW、A、B、工作寄存器等。这样就必须先用PUSH指令将相应寄存器内容压入堆栈保护起来(保护现场),然后再用POP指令将压入堆栈的内容弹回到相应的寄存器中(恢复现场)。一般地,保护、恢复现场方法有两种:①调用前由主程序保护,返回后由主程序恢复;②在子程序开头保护现场,在子程序末尾恢复。
5 查表程序
查表程序是一种常用程序,可避免复杂的运算或转换过程,可完成数据补偿、修正、计算、转换等各种功能,具有程序简单、执行速度快等优点。
查表是根据自变量x,在表格寻找y,使y=f(x)。在单片机中,数据表格存放于程序存储器内,在执行查表指令时,发出读程序存储器选通脉冲。两条极为有用的查表指令如下:①MOVC A,@A+DPTR;②MOVC A,@A+PC。
例3-46:设计一子程序,功能是根据累加器A中的数x(0~9之间)查x的平方表y,即根据x的值查出相应的平方值y。本例中的x和y均为单字节数。
解:使用指令MOVC A,@A+DPTR时不必计算偏移量,表格可以设在64KB程序存储器空间内的任何地方,而不像MOVC A,@A+PC那样只设在PC下面的256个单元中。
程序指令可以用如下形式:
PUSH DPH;保存DPH
PUSH DPL;保存DPL
MOV DPTR,#TAB
MOVC A,@A+DPTR
POP DPL;恢复DPL
POP DPH;恢复DPH
RET
TAB:DB 00H,01H,04H,09H,10H;平方表
DB 19H,24H,31H,40H,51H
说明:如果DPTR已被使用,则在查表前必须保护DPTR,且结束后恢复DPTR。实际查表程序设计中,有时x为单字节数,y为双字节数,也有时x和y都是双字节数,如下例所示。
例3-47:以STC89C52为核心的温度控制器,温度传感器输出的电压与温度为非线性关系,传感器输出的电压已由A-D转换为10位二进制数。测得不同温度下的电压值数据构成一个表,表中温度值为y(双字节无符号数),x(双字节无符号数)为电压值数据。设测得电压值x放入R2、R3中,根据电压值x查找对应的温度值y,仍放入R2、R3中。
解:参考程序段如下:
LTB:MOV DPTR,#TAB1
MOV A,R3
CLR C
RLC A
MOV R3,A
XCH A,R2
RLC A
XCH R2,A
ADD A,DPL
MOV DPL,A
MOV A,DPH
ADDC A,R2
MOV DPH,A;(R2R3)+(DPTR)→(DPTR)
CLR A
MOVC A,@A+DPTR;查第一字节
MOV R2,A;第一字节存入R2中
CLR A
INC DPTR
MOVC A,@A+DPTR;查第二字节
MOV R3,A;第二字节存入R3中
RET
TAB1:DW;温度值表
例3-48:将1位十六进制数转换为ASCII码。设1位十六进制数放在R0的低4位,转换为ASCII后再送回R0。(用查表法设计程序,使用查表指令MOVC A,@A+DPTR)
解:设计程序如下:
ORG 0000H
MOV R0,#0BH;设(R0)=BH
MOV A,R0;读数据
ANL A,#0FH;屏蔽高4位
MOV DPTR,#TAB;置表格首地址
MOVC A,@A+DPTR;查表
MOV R0,A;回存
SJMP $
ORG 0050H
TAB:
DB 30H,31H,32H,33H,34H,35H,36H,37H,38H,39H;0~9的ASCII码
DB 41H,42H,43H,44H,45H,46H;A~F的ASCII码
END
结果:用查表法查得1位十六进制数B的ASCII码为42H。
6 延时程序
在单片机应用系统中,延时程序是经常使用的程序,一般设计成具有通用性的循环结构延时子程序。在设计延时子程序时,延时的最小单位为机器周期,所以要注意晶振频率。
例3-49:当晶振频率为12MHz时,设计延时20ms的子程序。
解:为便于理解调用子程序过程和子程序的通用性,将程序设计为主程序中调用子程序方式。
程序设计如下:
ORG 0000H
LCALL YASH20;调用延时20ms子程序
SJMP $
YASH20:MOV R7,#100;延时20ms子程序
AA0:MOV R6,#49
AA1:NOP
NOP
DJNZ R6,AA1
NOP
DJNZ R7,AA0
NOP
RET;子程序返回
END
结果:经Keil软件运行测得延时20.006ms。
7 码制转换程序
在单片机应用程序的设计中,经常涉及各种码制的转换问题。在单片机系统内部进行数据计算和存储时,多采用二进制码。二进制码具有运算方便、存储量小的特点。在输入/输出中,按照人的习惯多采用代表十进制数的BCD码(用4位二进制数表示的十进制数)表示。
(1)二进制(或十六进制)数转换成BCD码
十进制数常用BCD码表示。而BCD码又有两种形式:一种是1个字节放一位BCD码,它适用于显示或输出;另一种是压缩的BCD码,即1个字节放两位BCD码,高4位、低4位各存放一个BCD码,可以节省存储单元。
单字节二进制(或十六进制)数在0~255之间,设单字节数在累加器A中,转换结果的百位数放在R3中,十位和个位同时放入A中。除法指令完成的操作为:A除以B的商放入A中,余数放入B中。
例3-50:将单字节二进制数转换成BCD码。
解:设计程序如下:
ORG 0000H
MOV A,#89H;十六进制数89H送A中
MOV B,#100;100作为除数送入B中
DIV AB;十六进制数除以100
MOV R3,A;百位数送R3,余数在B中
MOV A,#10;分离十位和个位数
XCH A,B;余数送入A中,除数10在B中
DIV AB;分离出十位在A中个位在B中
SWAP A;十位数交换到A中的高4位
ADD A,B;将个位数送入A中的低4位
SJMP $
END
结果:(R3)=1,(A)=37H,89H的BCD码为137。
(2)BCD码转换成二进制(或十六进制)数
例3-51:将两位压缩BCD码按其高、低4位分别转换为二进制数。
解:设计程序如下,将两位压缩BCD码存放在R2中,将其高、低4位分别转换为二进制数,并存于R3中。
STAR:MOV R2,#89H;表示BCD码为89
MOV A,R2;(A)←(R2)
ANL A,#0F0H;屏蔽低4位
SWAP A;高4位与低4位交换
MOV B,#10;乘数
MUL AB;相乘
MOV R3,A;(R3)←(A)
MOV A,R2;(A)←(R2)
ANL A,#0FH;屏蔽高4位
ADD A,R3;(A)←(A)+(R3)
MOV R3,A;(R3)←(A)
SJMP $
END
结果:BCD码89,转换为十六进制为59H,放在R3中。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。