我正在尝试从 STC3100 电池监控器 IC 读取值,但我得到的值不正确。数据表的内容:
The temperature value is coded in 2’s complement format, and the LSB value is 0.125° C.
REG_TEMPERATURE_LOW, address 10, temperature value, bits 0-7
REG_TEMPERATURE_HIGH, address 11, temperature value, bits 8-15
这是数据表:http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATASHEET/CD00219947.pdf
我的代码中有什么:
__u8 regaddr = 0x0a; /* Device register to access */
__s32 res_l, res_h;
int temp_value;
float temperature;
res_l = i2c_smbus_read_word_data(myfile, regaddr);
regaddr++;
res_h = i2c_smbus_read_word_data(myfile, regaddr);
if (res_l < 0) {
/* ERROR HANDLING: i2c transaction failed */
} else {
temp_value = (res_h << 8)+res_l;
temperature = (float)temp_value * 0.125;
printf("Temperature: %4.2f C\n", temperature);
}
我做错了什么?这不是我应该如何将 2 的补码值复制到 int 中吗?
最佳答案
i2c_smbus_read_word_data()
将从设备上指定的寄存器开始读取 16 位,因此单个 i2c_smbus_read_word_data()
将读取您有兴趣使用的两个寄存器单个 i2c 事务。
i2c_smbus_read_word_data()
将从设备读取的 16 位作为无符号数返回 - 如果出现错误,i2c_smbus_read_word_data()
的返回值为负。您应该能够像这样读取温度传感器:
__u8 regaddr = 0x0a; /* Device register to access */
__s32 res;
int temp_value;
float temperature;
res = i2c_smbus_read_word_data(myfile, regaddr);
if (res < 0) {
/* ERROR HANDLING: i2c transaction failed */
} else {
temp_value = (__s16) res;
temperature = (float)temp_value * 0.125;
printf("Temperature: %4.2f C\n", temperature);
}
解决评论中的问题:
如果没有错误,i2c_smbus_read_word_data()
函数将从 i2c 总线获取的 16 位数据作为无符号 16 位值返回。函数返回的 32 位 int 可以很容易地表示 16 位无符号值,因此根据定义,16 位数据不能为负数。当且仅当出现错误时,res
才会为负。
将 16 位值解释为(可能为负的)二进制补码值由 res
的 (__s16)
转换处理。这会获取 res
中的值并将其转换为带符号的 16 位 int
表示形式。严格来说,它是关于此转换如何处理负数的实现定义的。我相信在 Linux 实现中,这将始终简单地将 res
的低 16 位视为二进制补码。
如果您担心 (__s16)
转换的实现定义方面,您可以通过使用算术而不是 caf 的答案中的转换来避免它:
temp_value = (res > 0x7fff) ? res - (0xffff + 1) : res;
即使您碰巧在一个补码机器上运行,它也会执行正确的负值转换(Linux 甚至支持在这样的机器上运行吗?)。
另请注意,上面发布的代码假定您在小端机器上运行 - 在将数据转换为负值之前,您需要在大端机器上适本地交换字节,应该执行以下操作然而, objective-c PU 表示整数值(大/小,一个或两个)的技巧:
__u16 data = __le16_to_cpu( (__u16) res);
// convert negative two's complement values to native negative value:
int temp_value = (data > 0x7fff) ? data - (0xffff + 1) : data;
关于c - 如何将两个寄存器的 2 的补码值读入一个 int,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11920411/