首先,抱歉标题令人困惑。这里已经很晚了,我无法想出一个更好的。
所以,我有一个 I2C 温度传感器,可以将当前温度输出为 16 位字。从左到右读取,第 1 位是 MSB,第 13 位是 LSB,所以 13 位是有效载荷,最后 3 位是零。我想用 Raspberry Pi 读出那个传感器并转换数据。
第一个字节(8 位)是当前温度的整数部分。当且仅当温度为负时,必须构建整个单词的二进制补码。
第二个字节是必须乘以 0.03125 的小数部分。
因此,仅举几个例子(TEMP DIGITAL OUTPUT (Binary) / DIGITAL OUTPUT (Hex),取自此处的数据表http://datasheets.maximintegrated.com/en/ds/DS1624.pdf)
+125˚C | 01111101 00000000 | 7D00h
+25.0625˚C | 00011001 00010000 | 1910h
+½˚C | 00000000 10000000 | 0080h
0˚C | 00000000 00000000 | 0000h
-½˚C | 11111111 10000000 | FF80h
-25.0625˚C | 11100110 11110000 | E6F0h
-55˚C | 11001001 00000000 | C900h
由于字节序的不同,读取传感器时字节顺序会颠倒,这不是问题。例如,第一行将变为 0x007D 而不是 0x7D00,0xE6F0 变为 F0E6,依此类推......
但是,一旦我为负值建立了二进制补码,我就无法提出正确的转换。
我想出的(不适用于负值)是:
import smbus
import time
import logging
class TempSensor:
"""
Class to read out an DS1624 temperature sensor with a given address.
DS1624 data sheet: http://datasheets.maximintegrated.com/en/ds/DS1624.pdf
Usage:
>>> from TempSensor import TempSensor
>>> sensor = TempSensor(0x48)
>>> print "%02.02f" % sensor.get_temperature()
23.66
"""
# Some constants
DS1624_READ_TEMP = 0xAA
DS1624_START = 0xEE
DS1624_STOP = 0x22
def __init__(self, address):
self.address = address
self.bus = smbus.SMBus(0)
def __send_start(self):
self.bus.write_byte(self.address, self.DS1624_START);
def __send_stop(self):
self.bus.write_byte(self.address, self.DS1624_STOP);
def __read_sensor(self):
"""
Gets the temperature data. As the DS1624 is Big-endian and the Pi Little-endian,
the byte order is reversed.
"""
"""
Get the two-byte temperature value. The second byte (endianness!) represents
the integer part of the temperature and the first byte the fractional part in terms
of a 0.03125 multiplier.
The first byte contains the value of the 5 least significant bits. The remaining 3
bits are set to zero.
"""
return self.bus.read_word_data(self.address, self.DS1624_READ_TEMP)
def __convert_raw_to_decimal(self, raw):
# Check if temperature is negative
negative = ((raw & 0x00FF) & 0x80) == 0x80
if negative:
# perform two's complement
raw = (~raw) + 1
# Remove the fractional part (first byte) by doing a bitwise AND with 0x00FF
temp_integer = raw & 0x00FF
# Remove the integer part (second byte) by doing a bitwise AND with 0XFF00 and
# shift the result bits to the right by 8 places and another 3 bits to the right
# because LSB is the 5th bit
temp_fractional = ((raw & 0xFF00) >> 8) >> 3
return temp_integer + ( 0.03125 * temp_fractional)
def run_test(self):
logging.basicConfig(filename='debug.log', level=logging.DEBUG)
# Examples taken from the data sheet (byte order swapped)
values = [0x7D, 0x1019, 0x8000, 0, 0x80FF, 0xF0E6, 0xC9]
for value in values:
logging.debug('value: ' + hex(value) + ' result: ' + str(self.__convert_raw_to_decimal(value)))
def get_temperature(self):
self.__send_start();
time.sleep(0.1);
return self.__convert_raw_to_decimal(self.__read_sensor())
如果你运行 run_test() 方法,你会明白我的意思。所有负值都是错误的。
我得到的结果是:
DEBUG:root:value: 0x7d result: 125.0
DEBUG:root:value: 0x1019 result: 25.0625
DEBUG:root:value: 0x8000 result: 0.5
DEBUG:root:value: 0x0 result: 0.0
DEBUG:root:value: 0x80ff result: 1.46875
DEBUG:root:value: 0xf0e6 result: 26.03125
DEBUG:root:value: 0xc9 result: 55.96875
所以,我在这个问题上花了好几个小时,但似乎我缺乏按位操作的基础知识。我认为问题在于当值为负时使用逻辑 AND 进行屏蔽。
编辑:网络上有几个实现。它们都不适用于负温度。我通过将传感器实际放入冰水中进行了尝试。我还没有尝试过 Arduino C++ 版本,但是从查看源代码看来它根本没有构建两者的补码,所以也没有负温度(https://github.com/federico-galli/Arduino -i2c-温度传感器-DS1624/blob/master/DS1624.cpp)。