第十三章 常用软件设计
13.1与软件结构相关的散转、查表程序设计
一、查表程序设计
单片机应用系统中,查表程序是一种常用程序,它广泛使用于LED显示器控制,打印机打印以及数据补偿、计算、转换等功能程序中。
查表,就是根据变量x在表格中查找y,使y=f(x)。
x有各种结构,如有时x可取小于n(n为定值)的自然数子集;有时,x取值范围较大,并且不会取到该范围中的所有值,即对某些x,f(x)无定义,例如x为不定长的字符串或x为某些ASCII字符等。
y也有各种结构,如有时y可取定字长的数,但不是所有该字长的数都有对应的x;有时y可取小于m(m为定值)的自然数子集。
对于表格本身,也有许多不同的结构。以存放顺序分,有有序表与无序表,以存放地点 分,有的表格存放在程序存储器中(用MOVC指令访问),有的表格存放在数据存储器中(用MOVX指令访问)。表格的存放内容也各有不同,有的只存放y值,有的只存放x值;有的表格中还包括含有几个子表;表格中的每一项的长度也各有不同,有的是定长,有的为不定长。其它还有多维表格等情况。下面介绍几种常见类型查表程序和这些表格的构成方法。
(一)x可取小于等于n的自然数的全体,y为定字长。
由于xi取值为自然数0,l,2,3,…,n有序等差排列,而yi又为定字长,故可以简化表格,在表中只存放yi的值。
例1 设有一个巡回检测报警装置,需对16路输入值进行比较,当每一路输入值超过该路的报警值时,实现报警。下面根据这一要求,编制一个查表程序。
x为路数,查表时xi按0,1,2,…,15(n=15)取数,yi为报警值,二字节数,依xi顺序列成表格放在TABl中。进入查表程序前,路数xi放在R2中,查表后的最大值放在R3、R4中。
查表程序如下:
TB1: MOV A,R2 ;路数xi→R2
ADD A,R2 ;R2·2→A
MOV R3,A ;保存路数xi值
ADD A,#TAB(rel) ;加上表首偏移量
MOVC A,@A+PC ;查第一字节
XCH A,R3 ;第一字节→R3
ADD A,#TAB(rel)+1 ;加上表首偏移量
MOVC A,@A+PC ;查第二字节
MOV R4,A ;第二字节入R4
RET
TAB: DW 05F0H,0E89H,0A695H,1BAAH;报警值表
DW 0D9BH,7F93H,0378H,26D7H
DW 2710H,9B3FH,1A66H,22B3H
DW 1174H,16EFH,3aB4H9,0CA0H
上述查表程序使用MOVC A,@A+PC,因此,表格偏移不得超过255个字节。当表
格偏移大于255个字节时,使用MOVC A,@A十DPTR查表指令。
例2 在一个温度测量装置中,测量的电压与温度为非线性关系,需对它进行线性化处理。如测得值为10位二进制数(占两个字节),采用表格方法实现线性化处理时,可将所测出不同温度下的输入值(共有1024个数)数据构成一个表,表中存放温度值为yi,电压值为x(为了减少测量数据,也可用插值法求出其它数据)。设测量输入值放在R2、R3中,采用以下程序可以把它转换成线性温度值,然后再放回到R2、R3中。表TAB2可放在64k程序存储器中任何地方。
LTB2: MOV DPTR,#TAB2
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
CLR A
MOVC A,@A+DPTR
MOV R2,A
CLR A
INC DPTR
MOVC A,@A+DPTR
MOV R3,A
RET
TAB2: DW … ;温度数值麦
二、散转程序设计
散转程序是一种并行分支程序。它是根据某种输入或运算结果,分别转向各个处理程序。在MCS-51单片机中,散转指令为JMP @A+DPTR。它按照程序运行时决定的地址执行间接转移指令。该指令把累加器的8位无符号内容与16位数据指针的内容相加后装入程序计数器,实现程序的转移。A的内容不同,散转的入口地址不同。
下面介绍几种不同的散转程序
(一)使用转移指令表的散转程序
在不少场合下,需要根据某一单元的内容是0,1,2,…,n时分别转向分支处理程序0,1,2,…,n。可直接使用散转指令JMP @A+DPTR。由于A可容纳的字节数只有256个,在DPTR为首地址的256个程序存储单元一般不可能容纳n个分支处理程序。因此,可只将这个区域中作为n个分支处理程序的转移指令表。采用AJMP转移指令需占用二个字节,而采用LJMP转移指令需占空间为三个字节。
例5 根据R2的内容,转向各个处理程序
(R2)=0,转向 PRG0
(R2)=1,转向 PRGl
……
(R2)=n,转向 PRGn
程序清单
JMPl: MOV DPTR,#TBJ1 ;转移指令表(转移指令入口地址)
MOV A,R2 ;给每个转移指令空出二个字节车间
ADD A,R2
JNC NADD
INC DPH ; R2·2>256时表空间增加一面
NADD: JMP @A+DPTR
TBJ1: AJMP PRG0
AJMP PRGl
AJMP PRG2
……
AJMP PRGn
PRG0: ……
……
PRG1: ……
……
PRG2: ……
……
……
PRGn: ……
……
这个散转程序由于在分支转移指令表中使用AJMP指令,其寻址范围为2k字节,如果n个散转分支程序长度超过2k字节时,可改用64k寻址的LJMP指令。这时,上述程序中应给每个转移指令空出三个字节空间。
对于散转分支程序超过256个时,即n>255,一个字节存放不下,这时,可用两个字节,并利用对DPTR进行加法运算的方法,直接修改DPTR;然后再用JMP @A+DPTR实现散转。
三、子程序调用时的参数传递方法
在MCS-51应用程序中,完成子程序调用的指令为ACALL和LCALL,子程序返回指令为RET。
在功能上子程序与中断服务程序有相似之处。但中断请求是随机的,转向中断处理的时刻与主程序无直接关系,故一定要有现场保护与现场恢复,而对于子程序来说,它的调用安排是由主程序设定,故现场不一定要加以保护,可按实际情况灵活处理。
子程序调用时有个参数传递问题,即在子程序调用时,主程序应先把有关参数放到某些约定的位置,子程序在运行时,可以从约定位置得到有关参数,同样,子程序起运行结束前,也应把运算结果送到约定位置。在返回主程序后,主程序从约定的位置上得到所需要的结果。
子程序调用时,可采用以下几种常用的参数传递方法。
1.用工作寄存器或累加器传递参数
这种方法是将输入参数或结果参数放在工作寄存器或累加器中。使用这种方法程序简单,运算速度也高。是最常使用的参数传递方法,其缺点是传递参数不能太多。
2.用指针寄存器来传递参数
由于数据一般存放在存储器中,故可用指针来指示数据的位置,这样可大大节省传递数据的工作量,并可实现变长度运算。如果参数在内部RAM中,可用R0、R1作指针;参数在外部RAM或程序存储器中,可用DPTR作指针。可变长度运算时,可用一个寄存器来指出数据长度,也可在数据中设置结束标记。