大家好我正在研究加速度计bma220,它的数据表说数据是2的补码形式。所以我要做的就是在任何8位有符号字符中获取8位数据并完成。 bma220有一个8位寄存器,其中前6位是数据,后两位是零。
void properdata(int16_t *msgData)
{
printf("\nin proper data\n");
int16_t temp, i;
for(i=0; i<3; i++)
{
temp = *(msgData + i);
printf("temp = %d sense = %d\n", temp, sense);
temp = temp >> 2; // only 6 bits data
temp = temp / sense; //decimal value * .0625 = value in g
printf("temp = %d\n", temp);
}
}
在这个程序中,我在无符号变量msgdata中获取数据并对有符号变量进行所有计算。我只需要知道这是否是转换数据的正确方法?
经过一些建议后,我将代码更改为
void properdata(uint16_t *msgData)
{
int arr[3];
arr[0] = msgData[0];
arr[1] = msgData[1];
arr[2] = msgData[2];
arr[0] = arr[0]/4;
arr[1] = arr[1]/4;
arr[2] = arr[2]/4;
printf("x = %d y = %d z = %d\n", arr[0], arr[1], arr[2]);
}
现在处于静止状态我得到61,60和17的数据。如果我认为数据应该在31到-32的范围内,但是这里它超出了范围?
答案 0 :(得分:2)
在这个程序中我正在使用无符号变量msgdata
中的数据
不,你不是。 msgdata是一个签名变量。
我只需要知道这是否是转换数据的正确方法?
对已签名变量使用逐位运算符几乎总是一个错误。您对已签名变量执行右移,这是实现定义的行为,符号位将发生什么取决于编译器。
答案 1 :(得分:2)
我在你的代码中看到两个问题:
1)正如Lundin所说,将负值向右移动是危险的,因为行为是编译器特定的。
2)根据数据表,加速剂的范围是1.94 ...- 2.00 g。您尝试将值存储为普通整数。这里至少需要定点算术(或浮点数)。或者你的结果只有1,0,-1或-2。
以下代码应考虑这些要点(未经测试):
int16_t raw; // the 8 bit raw value from the chip
int32_t accel; // acceleration in mg
raw = (int16_t) read_value_from_chip(); // get 8 bits raw value from chip
accel = (int32_t)(raw / 4) * 625; // to avoid to shift to right, use division here
if ( accel >= 0 )
accel = ( accel + 5 ) / 10;
else
accel = ( accel - 5 ) / 10;
printf("%ld\n", accel);
说明:
根据数据表,分辨率为62.5毫克,最重要的6位保留有符号原始值。
为避免在将位置于位置时明确处理符号,此处使用除法而不是右移。使用除以4代替&gt;&gt;这样就可以根据需要保留标志。
如果编译器/ MCU在负值向右移位时设置左侧1的位,则优化编译器将通过位移替换该除法。如果编译器/ MCU不支持,则使用除法。
* 625用于获得所需分辨率为1/10 mg的加速度(1位数为0.1 mg)。 625是0.0625 * 10000的缩写形式。(更新)
为了得到毫克,加速度除以10(我这里这样做只是因为mg比0.1毫克更方便)。要正确舍入,必须根据分割前的符号加上/减去一半的被除数,这里是10/2 = 5.
现在的结果是mg。
如果要避免除法,则必须在将有效位置于适当位置时明确处理负值/正值。
答案 2 :(得分:0)
通常,规格表将有一个或两个示例转换。它可能显示值0000 0000(二进制)为零,0100 0000为47.25 g。通过代码运行示例值进行验证。