树莓派4+SenseHat用Pi4J读取I2C数据始终返回0求助
解决方案:正确读取SenseHat传感器的I2C数据
你的核心问题有两个:
- 错误地将设备I2C地址作为寄存器地址传入
readRegister方法 - 未先配置传感器的工作模式,直接读取数据
SenseHat上的两个温压/温湿度传感器分别是:
- 0x5c:LPS25H(气压+温度传感器)
- 0x5f:HTS221(湿度+温度传感器)
下面分别给出两个传感器的Java/Pi4J实现代码:
1. 读取LPS25H(0x5c)的温度和气压
步骤说明:
- 先写入控制寄存器,启用连续测量模式
- 读取温度/气压的原始数据(各2/3字节)
- 通过官方公式计算实际数值
代码示例:
package com.example; import com.pi4j.Pi4J; import com.pi4j.context.Context; import com.pi4j.io.i2c.I2C; import com.pi4j.io.i2c.I2CConfig; import com.pi4j.io.i2c.I2CProvider; public class LPS25HReader { // LPS25H设备地址 private static final int DEVICE_ADDR = 0x5c; // 控制寄存器1地址 private static final int CTRL_REG1 = 0x20; // 温度数据寄存器 private static final int TEMP_OUT_L = 0x2b; private static final int TEMP_OUT_H = 0x2c; // 气压数据寄存器 private static final int PRESS_OUT_L = 0x28; private static final int PRESS_OUT_M = 0x29; private static final int PRESS_OUT_H = 0x2a; public static void main(String[] args) { Context pi4j = Pi4J.newAutoContext(); I2CProvider i2CProvider = pi4j.provider("linuxfs-i2c"); I2CConfig i2cConfig = I2C.newConfigBuilder(pi4j) .id("LPS25H") .bus(1) .device(DEVICE_ADDR) .build(); try (I2C sensor = i2CProvider.create(i2cConfig)) { // 配置传感器:启用连续测量,输出速率1Hz sensor.writeRegister(CTRL_REG1, (byte) 0x90); // 等待传感器初始化 Thread.sleep(100); // 读取温度原始数据(16位有符号整数) byte tempL = sensor.readRegister(TEMP_OUT_L); byte tempH = sensor.readRegister(TEMP_OUT_H); int rawTemp = ((tempH & 0xFF) << 8) | (tempL & 0xFF); // 计算实际温度:公式来自LPS25H datasheet double temperature = 42.5 + (rawTemp / 480.0); // 读取气压原始数据(24位有符号整数) byte pressL = sensor.readRegister(PRESS_OUT_L); byte pressM = sensor.readRegister(PRESS_OUT_M); byte pressH = sensor.readRegister(PRESS_OUT_H); int rawPress = ((pressH & 0xFF) << 16) | ((pressM & 0xFF) << 8) | (pressL & 0xFF); // 计算实际气压:单位hPa double pressure = rawPress / 4096.0; System.out.printf("温度:%.2f °C,气压:%.2f hPa%n", temperature, pressure); } catch (Exception e) { e.printStackTrace(); } finally { pi4j.shutdown(); } } }
2. 读取HTS221(0x5f)的温度和湿度
步骤说明:
- 先读取校准寄存器(传感器出厂时写入的校准数据,用于数值计算)
- 配置控制寄存器,启用连续测量模式
- 读取温湿度原始数据
- 通过校准数据计算实际数值
代码示例:
package com.example; import com.pi4j.Pi4J; import com.pi4j.context.Context; import com.pi4j.io.i2c.I2C; import com.pi4j.io.i2c.I2CConfig; import com.pi4j.io.i2c.I2CProvider; public class HTS221Reader { // HTS221设备地址 private static final int DEVICE_ADDR = 0x5f; // 控制寄存器1地址 private static final int CTRL_REG1 = 0x20; // 校准寄存器地址 private static final int H0_RH_X2 = 0x30; private static final int H1_RH_X2 = 0x31; private static final int T0_DEGC_X8 = 0x32; private static final int T1_DEGC_X8 = 0x33; private static final int T1_T0_MSB = 0x35; private static final int H0_T0_OUT_L = 0x36; private static final int H0_T0_OUT_H = 0x37; private static final int H1_T0_OUT_L = 0x3a; private static final int H1_T0_OUT_H = 0x3b; private static final int T0_OUT_L = 0x3c; private static final int T0_OUT_H = 0x3d; private static final int T1_OUT_L = 0x3e; private static final int T1_OUT_H = 0x3f; // 数据寄存器地址 private static final int HUMIDITY_OUT_L = 0x28; private static final int HUMIDITY_OUT_H = 0x29; private static final int TEMP_OUT_L = 0x2a; private static final int TEMP_OUT_H = 0x2b; public static void main(String[] args) { Context pi4j = Pi4J.newAutoContext(); I2CProvider i2CProvider = pi4j.provider("linuxfs-i2c"); I2CConfig i2cConfig = I2C.newConfigBuilder(pi4j) .id("HTS221") .bus(1) .device(DEVICE_ADDR) .build(); try (I2C sensor = i2CProvider.create(i2cConfig)) { // 读取校准数据 byte h0RhX2 = sensor.readRegister(H0_RH_X2); byte h1RhX2 = sensor.readRegister(H1_RH_X2); byte t0DegCX8 = sensor.readRegister(T0_DEGC_X8); byte t1DegCX8 = sensor.readRegister(T1_DEGC_X8); byte t1T0Msb = sensor.readRegister(T1_T0_MSB); byte h0T0OutL = sensor.readRegister(H0_T0_OUT_L); byte h0T0OutH = sensor.readRegister(H0_T0_OUT_H); byte h1T0OutL = sensor.readRegister(H1_T0_OUT_L); byte h1T0OutH = sensor.readRegister(H1_T0_OUT_H); byte t0OutL = sensor.readRegister(T0_OUT_L); byte t0OutH = sensor.readRegister(T0_OUT_H); byte t1OutL = sensor.readRegister(T1_OUT_L); byte t1OutH = sensor.readRegister(T1_OUT_H); // 计算校准参数 double h0Rh = (h0RhX2 & 0xFF) / 2.0; double h1Rh = (h1RhX2 & 0xFF) / 2.0; int t0DegC = ((t1T0Msb & 0x03) << 8) | (t0DegCX8 & 0xFF); int t1DegC = ((t1T0Msb & 0x0C) << 6) | (t1DegCX8 & 0xFF); double t0 = t0DegC / 8.0; double t1 = t1DegC / 8.0; int h0T0Out = ((h0T0OutH & 0xFF) << 8) | (h0T0OutL & 0xFF); int h1T0Out = ((h1T0OutH & 0xFF) << 8) | (h1T0OutL & 0xFF); int t0Out = ((t0OutH & 0xFF) << 8) | (t0OutL & 0xFF); int t1Out = ((t1OutH & 0xFF) << 8) | (t1OutL & 0xFF); // 配置传感器:启用连续测量,输出速率1Hz sensor.writeRegister(CTRL_REG1, (byte) 0x81); Thread.sleep(100); // 读取湿度原始数据 byte humL = sensor.readRegister(HUMIDITY_OUT_L); byte humH = sensor.readRegister(HUMIDITY_OUT_H); int rawHum = ((humH & 0xFF) << 8) | (humL & 0xFF); // 计算实际湿度 double humidity = h0Rh + (rawHum - h0T0Out) * (h1Rh - h0Rh) / (h1T0Out - h0T0Out); // 读取温度原始数据 byte tempL = sensor.readRegister(TEMP_OUT_L); byte tempH = sensor.readRegister(TEMP_OUT_H); int rawTemp = ((tempH & 0xFF) << 8) | (tempL & 0xFF); // 计算实际温度 double temperature = t0 + (rawTemp - t0Out) * (t1 - t0) / (t1Out - t0Out); System.out.printf("温度:%.2f °C,湿度:%.2f %%RH%n", temperature, humidity); } catch (Exception e) { e.printStackTrace(); } finally { pi4j.shutdown(); } } }
关键注意事项:
- 寄存器地址≠设备地址:你的原始代码中,错误地将设备I2C地址(0x5c/0x5f)作为寄存器地址传入
readRegister,这是导致返回0的直接原因。必须传入传感器的寄存器地址(比如LPS25H的0x2b是温度低字节寄存器)。 - 必须配置传感器:这类I2C传感器默认可能处于休眠模式,需要写入控制寄存器启用连续测量后,才能读取有效数据。
- 多字节数据处理:温度、气压、湿度数据都是16或24位的,需要读取多个寄存器后组合成完整的原始数值,再通过官方公式计算实际值。
内容的提问来源于stack exchange,提问作者WondrousBread
相关产品推荐
相关产品推荐

