折腾加速度芯片的过程中的一些记录,
相关数据和依据来源于以下两个官方文档:
AD输出位数:
加速度的值经过AD转换后以数字形式输出,这里首先要搞清楚,AD转换后的数据是多少位的,官方英文版的手册给出的说明是:
不同的工作模式、有效数据位数不同。
低功耗是8位、高分辨是12、普通10位。这个由两个寄存器的位来控制。上表总最后一列中说明不同位(工作模式)时,在满量程为 ± 2g的时候,最小一个数值代表多少mg,也就是一个单位表示重力加速度的值的千分之几。一般情况下用到的加速度测量都不大,为了更高的分辨率都选±2g量程。
中文版给了一个例子,其中的BLE是寄存器【CTRL_REG4 (23h)】中一位,但是只有在高分辨模式下才能设置。否则只能是默认值 == 0;
并且给了相应的说明
通过上面的解释可以得知:这个例子是 高分辨模式、12bitAD、。
如果不修改BLE保持默认,那么是小端模式。我们一般读寄存器的时候都是连续读的,所以RAW[0]中是OUT_X_L 也就是0x28的值。因为是12位,就需要两个8位拼接成一个16位。小端模式 ,得到的16位数值应该是 RAW[1]<<8 | RAW[0] == 0x15E0
由于左对齐,12位有效,最后4位无用,右移4位
B 0001 0101 1110 0000 右移4位 0000 0001 0101 1110
转换为十六进制 0x 01 5E 转为 10进制 == 350
那么怎么表示 -350呢,
用补码表示,首先将350二进制的最高位变为1,剩下的位都取反、然后再加一;
这个是12位的,变成16位需要左移4位,后面补4个0.
最后将这个转为十六进制就是 0xEA20
28h == 20h 29h ==EA
其实说了这么多,就是要理解下面这个 0xF000,为什么最高4位全是1。
int16_t pdata[3] = {0, 0, 0};
uint8_t regValue[6] = {0, 0, 0, 0, 0, 0};
IIC_read_len(m_device_address,(LIS3DH_REG_OUT_X_L | 0x80),regValue,6);
/* Format the data. */
for(uint8_t i=0;i<3;i++)
{
if(regValue[2*i+1] & 0x80) symbol[i] = 0xF000;
else symbol[i] = 0x0000;
}
pdata[0] =symbol[0] | ((( ( ( int16_t )regValue[1] ) << 8 ) + ( int16_t )regValue[0] ) >> 4);
pdata[1] =symbol[1] | ((( ( ( int16_t )regValue[3] ) << 8 ) + ( int16_t )regValue[2] ) >> 4);
pdata[2] =symbol[2] | ((( ( ( int16_t )regValue[5] ) << 8 ) + ( int16_t )regValue[4] ) >> 4);
NRF_LOG_INFO("\t\tX:%d\t\t Y:%d\t\t Z:%d\t\t\n\r",pdata[0],pdata[1],pdata[2]);
原始整数,12位,右对齐,高位4个0;
转为负值,高位4个1;
AD数值,左对齐,先要右移4位,然后将高位全部置为1
int16 有符号数,直接赋值,OK!
补码、大小端、AD位数、数据对齐;
这些对于我们这些非计算机专业的来说,还是有点难的。
纯属个人兴趣;若文中有错误的地方欢迎留言指正,不胜感激。
参考以下文章,感谢原作者:
《lis3dh调试心得,读取正确的加速度值》
文末评论:
你好,三轴加速度的数据在寄存器中好像是以原码的形式存在的,而并非是补码的形式,所以你的LIS3DH_Get_AccRaw()计算是有问题的,而且你在结果上或上0xf000,导致最高四位全为1,这样的话拿到的结果肯定是会偏大的。请知悉
是不对的,数值确实是补码方式存储的,高4位全是1,这个没关系,因为是补码。