跳转到主内容
Knowledgebase
Home
Renesas Electronics China - Knowledgebase

查表及补偿处理(用于78K0模式的程序示例。其它适用于整个系列。)

最新更新:2011年10月 06日

Question:

查表及补偿处理(用于78K0模式的程序示例。其它适用于整个系列。)

Answer:

当微控制器用于控制时,通常是处理输入信息(使用输入信息进行计算),然后输出由输入信息得到的控制变量。



[引言]
微控制器顺序执行控制操作所需的计算处理过程,根据应用的不同而不同,从非常容易到极其复杂。如果在给定的时间内处理复杂的计算,则要求微控制器有极高的计算能力。为了处理复杂计算而提高计算能力是不实用的。因此作为一种实用的方法可以使用查表的 方式。

[查表的概念]
查表是提前计算给定输入(x)的结果,并将计算结果记录在表中。计算本身是很烦琐的,因为必须在明确的输入值范围内执行计算,但是使用PC或其它计算机就很容易。



创建表时,表的容量要重点考虑。如果象上例中输出格式是重复的,就没必要覆盖输入值的整个范围来建表;仅在表示重复部分的范围建表就足够了。然后根据输入值除以循环周期和其它参数得到的余数和商查表。
[使用查表]
在查表时,基于输入数据计算表起始地址到目标地址之间的差(该值称为偏移量)。 如果需要的数据是一个字节,则可以把输入数据看作偏移量。如果数据长度为16位,则把输入数据的两倍作为偏移量。如果把该偏移量与表的起始地址相加,就可 以得到所需数据存储的地址。从存储器中读取该地址的内容,就可以得到所需的计算结果。


 
75X系列4位微控制器有专门用于查表的指令(如MOVT XA, @PCDE和MOVT XA, @PCXA),但是78K0没有查表指令。那么78K0就不能查表吗?实际上,78K0无需使用专门的查表指令,因为ROM和RAM都在同一个存储空间。 基于变址寻址的指令可用于查表。这些指令包括MOV A, [HL+B]和MOV A, [HL+C],把表的起始地址赋给HL寄存器,偏移量赋给B或C寄存器,这样偏移量和起始地址相加,得到一个地址,读取该地址所在存储单元的内容,赋给A 寄存器。

[查表注意事项]
创建表时,计算的精确度和准备的数据的个数会产生一个问题。如果精确度太高,表就很大,会占据太多的存储空间。不要每件事情都采用查表的方式处理,而是在最后进行补偿处理 ,可以减小表的大小。如需了解详细信息,可参考下面关于补偿处理的描述。

[补偿处理]
补偿包括通过查表获得大致的结果,并通过简单的比例计算得到的详细结果。既然在很大的间隔内足以准备数据,那么就可以大幅度减少表的容量。



例如,为了把数据量降到所需量的1/16,仅将低4位为0000的数据设置在表中。 通过执行以下处理过程来完成补偿。
使用仅为输入数据的1/16(4位右移)的偏移量进行查表。在上图中,可以获得A点的数据。
接下来计算该数据与表中下一个数据(上图中的数据B)的差。
差值除以16,再乘以输入数据的低4位。这样可以得到A点的增量。(如果按这样的顺序执行计算,会出现舍入错误。因此必须改变计算顺序,先进行乘法。)
将上述增量累加到从表中得到的A点值中。

上述处理过程确实可以在相当短的时间内完成,因为,基本上只需要加法、乘法和移位操作。但是由于 中存在带符号数的计算,后面的计算过程是很烦琐的。因此实际的处理过程中,获得加权平均数更容易。等价的处理能够转化为以下表达式,其中m是除数,n是输入数据的低位 所表示的数值。



从最后一个表达式可以很明显看出,如果从表中得到的数据A乘以除数,减去输入数据的低位部分,再加上输入数据乘以表中下一个数据B(已除以除数)所得数据的低位部分,得到的结果是相同的。
在上述例子中,表中下一个数据B仅与偏移量(由低4位指示)相加,数据的A部分和剩余部分相加,再除以16。

下面是一个程序示例, 把表中的数据压缩到1/32。通常数据不会压缩这么多,仅压缩到1/2即可。如果把数据压缩到1/2,使用所给数据之前和之后的数据的简单平均值就可以执 行补偿处理。这样可以简化程序,提高处理速度。总的存储容量比仅使用查表时要少得多。但是随着表中数据量的增加,可以不考虑1/2压缩的情况。
 
补偿误差
考虑一下补偿处理中的错误。在这个例子中,执行计算的范围是sin0 ~ sin/2(精确度达10位(除以1024)),结果最大可达1023 (= sin/2)。略去详细的计算结果,最大误差是:
0.005,当2位补偿时除以256
0.019,当3位补偿时除以128
0.077,当4位补偿时除以64
0.31,当5位补偿时除以32

在所有情况中,精确度达10位时误差都很小(不大于0.5位)。当使用精确度达10位的表时,需要2048字节的存储容量。然而,即使容量只有64字节,也能得到足够的精确度。

[程序举例]
下面是一个程序示例,计算sin0 ~ sin/2,可以精确到10位。输入值,范围是0 ~/2,除以1024,用10位表示(0~1023)。如果从输入参数计算偏移量并与#00111110b进行AND运算的部分被修改为#01111110b,而且 如果扩展了表,那么就可以支持多达11位的精度(0 ~ 2047),并且可以获得sin0~sin的值。在下面的程序中,使用16位变量(CONVDATA)存储输入参数和结果,并使用8位变量(WORK1)用于处理过程。这些变量都分配在短直接寻址区域。
WORK00          DSEG    SADDRP
CONVDATA:
        DS      2               ;返回输入参数和结果的区域
WORK01          DSEG    SADDR
WORK1:  DS      1

该程序是一个子例程,由四个主要部分组成(三个部分是程序主体,一部分是内部子例程)

(1) 第一部分是根据输入参数查表。在表中,存储的数据被压缩到1/32。因此,为了获取表的偏移量,将输入数据压缩到原来的1/32,由于数据长度是10位所 以输入数据要加倍,这样就需要2个字节。也就是说输入参数除以16就可以得到查表的偏移量。在这个例子里,输入参数中只有低10位是有用的。因此,使用 78K0的数字循环指令(ROR4 [HL])把输入参数右移4位,即可压缩到原来的1/16。忽略输入参数的高4位。将表的起始地址和用上述方法得到的偏移量(不大于8位的值)相加,就可 以获得表中数据 的地址。如果表是从低地址部分00开始定位,如200H,则不需要把起始地址和偏移量相加,这样只需用偏移量代替低地址部分就可以进行处理(在这个例子中 通过把起始地址和偏移量相加获取表中的数据地址)。这部分 与除用于1/16压缩处理外的查表是相同的。
CONVSUB:
        PUSH    AX
        PUSH    HL
        MOVW    AX,CONVDATA     ;输入数据的高字节部分赋给A, 低字节部分赋给X
        MOVW    HL,#CONVDATA
        ROR4    [HL]            ;A和[HL]的低4位除以16
        MOV     A,[HL]
        AND     A,#00111110b    ;获取偏移量
        ADD     A,#LOW TABLE    ;计算低位部分地址
        MOV     L,A
        MOV     A,#0
        ADDC    A,#HIGH TABLE   ;计算高位部分地址
        MOV     H,A             ;HL指向目标表
        MOV     A,[HL]          ;读取低字节
        MOV     CONVDATA,A      ;设置为低字节的初始值
        MOV     A,[HL+1]
        MOV     CONVDATA+1,A    ;设置高字节

(2) 程序的第二部分是补偿计算。在这部分程序中,把表中查到的值和下一个值相加,使用权值计算加权平均值。如果不需要补偿,那么由于已经将查表结果设置在输出 参数中,所以处理过程即可完成。为了执行补偿处理,下一个数据 需要重复多次加运算,加运算的次数与补偿数据的个数相同(实际上就是下一个数据乘以补偿数据),表中数据多次进行加运算,次数为32减去补偿数据的个数。 实际计算过程由子例程完成。在这个例子中,要准备计算所需的参数,并根据需要多次调用子例程。由于是完成16位x8位+16位的运算,所以要把所需的参数 装入堆栈以简化处理过程,并使用HL寄存器作为整个数据的索引。计算结果在16位以内,但另外需要一个字节用于通用处理。 这个字节(WORK1)作为数据没有具体意义但要赋初值为0。
        MOV     A,X
        AND     A,#00011111b    ;获取补偿数据
        BZ      $EXITS          ;如果不需要补偿就结束
;
;       补偿前的准备
;       (加权平均值) (把需要计算的数据装入堆栈)
;
        MOV     WORK1,#0        ;初始化数据的高位部分
        MOV     X,A             ;将补偿数据设置到X寄存器
        MOV     A,[HL+3]        ;在表中设置下一个数据的高字节部分
        PUSH    AX              ;保存计算后的数据
        MOV     A,[HL+2]        ;在表中设置下一个数据的低字节部分
        PUSH    AX              ;保存计算后的数据
        MOV     A,#31
        SUB     A,X             ;计算32的余数
        MOV     X,A
        MOV     A,[HL+1]        ;设置表中参考数据的高字节部分
        PUSH    AX              ;保存计算后的数据
        MOV     A,[HL]          ;设置表中参考数据的低字节部分
        MOVW    HL,#CONVDATA    ;设置指针
;
;       表中的参考数据汇总
;
        CALL    !SEKIWA         ;汇总数据的低位部分
        POP     AX
        INCW    HL
        CALL    !SEKIWA         ;汇总数据的高位部分 
;
;       表中下一个数据汇总
;
        POP     AX
        DECW    HL
        CALL    !SEKIWA
        POP     AX
        INCW    HL
        CALL    !SEKIWA

(3) 总数除以32,便得到最终计算结果。这样,计算结果与10位和5位的乘法相同,结果不超过16位。用舍入代替截取,加上与总数的1/2的等价值,然后执行 1/32的处理过程。该处理过程中,用HL表示CONVDATA+1,作为处理结果。为了将数据压缩到原来的1/32,通过字节 移位将数据左移4位,这样就可以将数据压缩到原来的1/16,然后执行1/2处理。
        MOV     A,CONVDATA      ;装载结果的低位部分
        ADD     A,#00010000b    ;加0.5,舍入
        BNC     $NEXT
        INC     CONVDATA+1      ;进位到高位部分
NEXT:   AND     A,#11100000b    ;屏蔽未使用位
        ROR     A,1             ;结果写入低4位
        ROR     A,1             ;A=00XXX000丄CY=0
        ROR     A,1             ;A=000XXX00丄CY=0
        ROR     A,1             ;A=0000XXX0丄CY=0
        ROL4    [HL]            ;结果除以16
        RORC    A,1             ;得到的结果再除以2
        XCH     A,[HL]          ;高3位与低位部分交换
        RORC    A,1             ;低位部分也除以2
        MOV     CONVDATA,A      ;保存结果

EXITS:  POP     HL
        POP     AX
        RET

(4) 下面是一个内部子例程,执行乘积和操作,用于汇总。将乘数和被乘数分别设置在A和X寄存器中,调用子例程,数据汇总在HL中。A和X寄存器内容相乘结果存于[HL]和[HL+1]中。
;       8位乘积和操作
;     (结果应该用16位表示)
;
SEKIWA:
        MULU    X               ;计算权
        XCH     A,X             ;高位部分的结果和低位部分的结果交换
        ADD     A,[HL]          ;低位部分汇总
        MOV     [HL],A          ;保存结果
        MOV     A,X             ;取结果的高位部分
        ADDC    A,[HL+1]        ;高位部分的进位参与计算
        MOV     [HL+1],A        ;保存字节的高位部分
        RET

(5) 这是对应0(0) ~ 1024 (=/2)的表。该表没有1024个数据项,但是数据被压缩为原来的1/32 (每次取出32个数据项的数据)。
把目标范围扩展到0(0) ~ 2048(=)。
TAREA   CSEG    AT      200H
;
;       当sin0~sin/2除以32再乘以1023时表中的值

TABLE:  DW      0,      50,     100,    150
        DW      200,    249,    297,    345
        DW      392,    437,    482,    526
        DW      568,    609,    649,    687
        DW      723,    758,    791,    822
        DW      851,    877,    902,    925
        DW      945,    963,    949,    992
        DW      1003,   1012,   1018,   1022
        DW      1023

支持2048 (=)或以上个数据
使用表或屏蔽偏移量不能支持 或更多的数据。这是因为需要检查结果值(怎样表示负值)的范围。该程序可以处理的结果范围为0 ~ 1023。因此sin/2 ~ sin 3 /2必须表示为0 ~ 1023。规定1(=sin/2)表示为1023,0(=sin)表示为512,以及-1(=sin3/2)表示为1。
由于该程序不支持负值处理,不能将负值表示为 2的补偿,因此必须添加外部处理过程,用于带符号数据(0减去数的表示)。
Suitable Products