You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

树莓派4+SenseHat用Pi4J读取I2C数据始终返回0求助

解决方案:正确读取SenseHat传感器的I2C数据

你的核心问题有两个:

  1. 错误地将设备I2C地址作为寄存器地址传入readRegister方法
  2. 未先配置传感器的工作模式,直接读取数据

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 16:07:04