1、问题的提出
在系统开发中采用RS485实现单片机与外围设备的通信,通信采用通用串行接口协议(uss),按照串行总线的主从通讯原理来确定访问的方法。uss规定了一套严格的通信规则,关于浮点数参数值,uss规定采用IEEE-754格式进行传送。例如,浮点数500.在通信中传送的是它的IEEE-754格式,即4字节的十六进制424800H。因此,单片机的C程序,在发送或接收外围设备的参数值时.需要解决如何实现浮点数与IEEE格式转换的问题。
2、IEEE浮点数的格式
在计算机中,浮点数的存储均采用4字节的IEEE-754格式。例如.浮点数50 0的IEEE表示形式如下:
二进制:
其中,最高位表示符号,“l”表示负,“0”表示正:第23_30位表示阶码。注意:阶码是以2为底的指数再加上偏移量127。第0~22位是尾数部分。尾数的整数部分永远为1.因此不予保存,但它是隐含存在的。
一个浮点数计算式为:(-1)s×2(n-27)×(1+m)。例如,前面绘出的浮点数的表示形式中.s=,n=132,m=(l/2+0/4+0/8+1/16+o/32+…).则计算结果为500。
3、浮点数与IEEE格式转换
在最初的C语言编程中,根据上面介绍的IEEE表示形式.采用移位计算的方法实现浮点数和IEEE格式转换。当接收到外围设备传来的4字节IEEE格式参数值时,依次将符号、阶码、尾数通过移位取出,然后按照IEEE计算规则计算出对应的浮点数。当需要发送给外围设备的浮点数时,按相反的方法将其转化为IEEE格式后再发送出去。
一直感觉上述方法太麻烦,而且效率太低。后来想到,既然在C语言中浮点数本身就是采用IEEE格式来存储的,能否利用C语言本身的机制来实现浮点数和IEEE格式的转换?经过尝试,发现利用union数据类型可以很好地完成这一工作,即只需定义下面这个umon类型:
umonPACket:
注意:类型定义的后面别忘了还有个符号“;”,union类型虽然有两个内部变量,但两个内部变量占用同一地址空间,它只占用4个字节。
内部float变量a(占用4个字节)和char数组b(同样占用4个字节)从同一个地址开始存放,并共享同一块内存空间。C语言中,对于单精度浮点数a.采用四个字节(IEEE格式1来存储,依次存储在四个连续的存储单元内,低字节存储在低地址存储单元,高字节存在高地址存储单元:
字符数组b也采用和a同样的存储方式。利用union数据类型,可以直接访问浮点数以IEEE格式存放在存储单元中的十六进制字节,通过直接读取或修改这些十六进制字节,便可以巧妙地实现浮点数与IEEE格式的转换。
(1)IEEE格式转换浮点数当单片机接收来自USS总线的数据时,只需将4个字节的数据放到内部变量b中,再访问内部变量a,即可实现转换。下面给出示意程序,供参考。
chari:floatdatum;unionpacketP;∥注意union数据类型的定义方式for(i=0;i<4;i++)p.b[i]=SBUF;//此处的SBUF为单片机的输入寄存器datium=p.a//通过此语句可实现IEEE格式向floar的转换。
(2)浮点数转换IEEE格式当单片机处理好数据后,需要把浮点型的数据转换成IEEE格式,输出给uss总线。只需把数据赋予内部变量a.再从内部变量b中取出对应的4个字节即可。
p.a=datum;∥注意union类型内部变量的访问方式for(i=O;i<4;i++)SBUF=p.b[i];∥此处的SBUF为单片机的输出寄存器此方法缩短了代码的长度,效率得到明显提高,在实际应用中效果非常好。