最近使用keil5和stm32f103cb在调试一个BMI088 IMU芯片时,读出来三轴加速度数据后要转换成相应的加速度值,使用了以下代码:
#define GRAVITY_EARTH (9.80665f)//地球重力加速度值,常数 //该函数将整型数据转成相应的浮点加速度数据 static float lsb_to_mps2(int16_t val, int8_t g_range, uint8_t bit_width) { double power = 2; float half_scale = (float)((pow((double)power, (double)bit_width) / 2.0f)); return (GRAVITY_EARTH * val * g_range) / half_scale; } //以下是main函数代码 main() { ...... BMI088a_Reset(); BMI088a_Init(); BMI088a_GetData(&bmi08_accel);//读取三轴加速度值 x = lsb_to_mps2(bmi08_accel.x, 6, 16);//读取X轴数据并转成加速度值 y = lsb_to_mps2(bmi08_accel.y, 6, 16);//读取Y轴数据并转成加速度值 z = lsb_to_mps2(bmi08_accel.z, 6, 16);//读取Z轴数据并转成加速度值 usb_printf("%5d, %5d, %5d, %4.2f, %4.2f, %4.2f\n",bmi08_accel.x,bmi08_accel.y,bmi08_accel.z,x,y,z); usb_printf("\r\n\r\n");//插入换行 }
因为代码是直接从别的工程拷贝过来的,就直接使用了,经过调试发现,串口助手能收到原始加速度bmi08_accel.x,bmi08_accel.y,bmi08_accel.z的值,但浮点化的加速度值x,y,z全是0。
后来经过单步调试,发现函数lsb_to_mps2第二句half_scale的值是0,如下图所示。
最后定位到是由于没有包含math.h头文件,包含后就好了。另外经验证,和勾选microlib也没关系。
然后,我对比了一下正确的map文件和错误的map文件。左侧是包含math.h的文件,右侧是没有包含math.h的文件。
可以看到左侧是引用了__aeabi_d2f和__aeabi_ddiv等double除法函数和double转float函数,而右侧没有,只引用了浮点乘法fmul和除法fdiv。
经过查询资料https://bbs.21ic.com/icview-3447122-1-1.html,ARM Cortex-M处理器中计算浮点数的方式有软件和硬件两种。对于不带 FPU 的处理器,ARM提供了一个「浮点支持软件库」用于计算浮点数:fplib。fplib提供的 API 以__aeabi开头,比如:
__aeabi_fadd:计算两个float型浮点数(float占4个字节,32位)
__aeabi_dadd:计算两个double型浮点数(double占8个字节,64位)
__aeabi_f2d:float型转为double型
__aeabi_d2f:double型转为float型
估计就是double处理时出错引起的计算错误。
但为啥包含math.h就引用了,没有包含math.h就不引用就不得而知了,可能编译器哪些选项对这个起作用吧。
关键很最奇怪的是,没有包含math.h竟然没有报错,连报警告都没有,让人很费解。