FOC之定点小数运算

描述

许多MCU 芯片只支持整数运算,如果要在这些芯片上进行小数运算,定点运算应该是最佳选择了;此外即使芯片支持浮点数,定点小数运算也是最佳的速度选择。所谓定点小数运算,就是将小数点位置固定,用整数的方式来进行运算;由于小数点的位置是固定的,所以就没有必要储存它。既然没有储存小数点的位置,那么计算机当然就不知道小数点的位置,所以这个小数点的位置是我们写程序的人自己需要牢记的。那么,如何将小数表示成整数呢?

处理器整数以二进制形式存储,首先要了解如何将小数转换成二进制!假定MCU 是16位,因最高位是符号位,那么有效位就只有15位(不考虑符号则16位)。即小数点之后可以有0~15 位。我们把小数点之后有n位叫做Qn,例如小数点之后有12位叫做Q12 格式的定点小数,而Q0就是我们所说的整数:

FOC

以Q12 格式为例,Q12 的正数的最大值是0111.111111111111,第一个0是符号位,后面的数都是1,那么这个数是十进制的多少呢? 请看下面的运算:

FOC

FOC

FOC

对于Qn格式的定点小数的表达的数值就它的整数值除以2^Qn。在计算机中还是以整数来运算,我们把它想象成实际所表达的值的时候,进行这个运算。反过来把一个实际所要表达的值x 转换Qn 型的定点小数的时候,就是x*(2^ Qn)了。例如0.2 的Q12 型定点小数为:0.2*(2^12) =819.2,由于这个数要用整数储存, 所以是819 即0x0333。因为舍弃了小数部分,所以0x0333 不是精确的0.2,实际上它是819/2^12=0.199951171875,非常接近0.2 了。

因此我们可以归纳出一个公式,假定x 表示实际的小数, q表示这小数在MCU 中的Qn 型定点小数,则有:

FOC

由以上公式我们可以很快得出定点小数运算法则:

FOC

加减法和一般的整数运算相同,而乘除法的时候,为了使得结果的小数点位不移动,对数值进行了移动(乘除2^Qn实际是将被乘除数左或右移动n位):

q3 = q1 * q2 / (2^Qn) ---> q3 = (q1 * q2 )>>Qn

用c语言来写定点小数的乘法就是:

short q1,q2,q3;

....

q3=((long q1) * (long q2)) >> n;

由于/ 2^Qn 和* 2^Qn可以简单的用移位来计算,所以定点小数的运算比浮点小数要快得多。下面我们用一个例子来验证一下上面的公式:用Q12来计算2.1 * 2.2,先把2.1, 2.2转换为Q12 定点小数:

2.1 * 2^12 = 8601.6 = 8602

2.2 * 2^12 = 9011.2 = 9011

(8602 * 9011) >> 12 = 18923

18923 的实际值是18923/(2^12) = 4.619873046875 和实际的结果4.62相差0.000126953125,对于一般的计算已经足够精确了。好了,话不投机半句多,说了这么多,最终还是要用实例代码来形象的指出如何实现定点运算。

MCU 实例

用硕呈16BIT-MCU 实现一组数据乘以0.492,这组数据是:

100*0.492=49.2

105*0.492=51.66

147*0.492=72.324

350*0.492=172.2

860*0.492=423.12

458*0.492=225.336

步骤一,先确定小数,0.492属于小于“1”的小数;且乘数与被乘数符号都为正,为了提高精度,可以考虑使用Q16 格式;因此将0.492转换成定点小数有:

FOC

步骤二,编写如下代码:

FOC

FOC

在地址0x00F0 处,设定运算为无符号乘以无符号运算。

地址0x00F1 处,将Q16 小数送入MX 寄存器。

地址0x00f4~0x00f8 处,利用循环计算出_MUL_表格中列出的数据,并将结果存到I0指向的缓冲中(MR1 是计算结果的整数位,MR0 是计算结果的小数低位)。

计算结果请查阅以下表格:

FOC

如果运算不需要小数部分(即运算结果取整),则"MCU 运算结果"中的数值均需要向右移动16位去掉小数部分;在代码中,用户可以直接取MR1的数字做为整数结果(假如不考虑四舍五入)。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分