I2C 读取返回零(RPi 4、SenseHat、Pi4J)

问题描述 投票:0回答:1

我正在使用 Raspberry Pi 4 和 Sense Hat 开发一个项目。我正在尝试从 Java 的帽子获取温度、湿度和气压读数。我不想在这里使用 Python 或其他语言,因为稍后我会将其集成到 Spring Boot 项目中。

每当我从 I2C 地址读取温度/压力/湿度时,我都会得到返回值 0。

根据https://pinout.xyz/pinout/sense_hat,I2C地址如下:

压力/温度:0x5c 湿度/温度:0x5f

我正在使用 Pi4j,我使用的代码是他们的 I2C 示例的修改版本

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 App 
{

    static final int tempAddress = 0x5c;

    public static void main( String[] args )
    {

        Context pi4j = Pi4J.newAutoContext();
        I2CProvider i2CProvider = pi4j.provider("linuxfs-i2c");
        I2CConfig i2cConfig = I2C.newConfigBuilder(pi4j).id("TEMP").bus(1).device(tempAddress).build();
        try (I2C temp = i2CProvider.create(i2cConfig)) {

            byte temperature = (byte) temp.readRegister(tempAddress);
            
            System.out.println(temperature);
            
        }
        
        
    }
}

代码编译并运行,但我总是在控制台上打印 0。我已经尝试了上述两个地址并得到相同的结果。有趣的是,如果我使用地址 0x6a(应该是磁力计),我会得到 -95 的输出。

当我在终端中运行 i2cdetect 时,我得到以下信息:

chris@raspberrypi:~ $ sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:                         -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- 1c -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- 39 -- -- -- -- -- -- 
40: -- -- -- -- -- -- 46 -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- 5c -- -- 5f 
60: -- -- -- -- -- -- -- -- -- -- 6a -- -- -- -- -- 
70: -- -- -- -- -- -- -- --                         
chris@raspberrypi:~ $ 



所以看起来我使用的寄存器是正确的,但我的实现有问题。

我确实找到了有人面临同样的问题,但解决方案尚不清楚。看起来在该用户的情况下,设备可能需要在读取之前写入一些内容(?),但我找不到 Sense Hat 的任何内容来详细记录 i2c。官方文档大多只是展示Python函数的用法,而不是直接从i2c总线读取。

任何建议都值得赞赏,谢谢。

java raspberry-pi i2c raspberry-pi4
1个回答
0
投票

在发帖后的第二天我又做了一些工作,并解决了我的问题。

首先,我对 i2c 寻址工作方式的理解是错误的。 0x5c是读取压力/温度的芯片的地址,但那是整个芯片的地址。温度读数是通过读取芯片中的两个特定寄存器,然后对它们进行一些附加操作来找到的。更正后的代码将类似于以下内容:


/**
* I2C registers where data is read from the chips
*/
static final int LPS25H_TEMP_OUT_H_REGISTER = 0x2c;
static final int LPS25H_TEMP_OUT_L_REGISTER = 0x2b;

public static double getTempFromPressure(){
        double temperature = 0;

        I2C tempI2C = getI2C("TEMPFROMPRESSURE", LPS25H_ADDRESS);
        
        try  {

            if(!initializeLPS25H(tempI2C)){
                //Add proper exception-handling here later
                System.out.println("Error initializing LPS25H");
            }

            //Get the temperature readings from the registers and store them as Strings
            String tempStringHigh = Integer.toBinaryString(tempI2C.readRegister(LPS25H_TEMP_OUT_H_REGISTER));
            String tempStringLow = Integer.toBinaryString(tempI2C.readRegister(LPS25H_TEMP_OUT_L_REGISTER));
            
            //The readings from the registers represent 8 bit values. Add zeroes to the left hand side until the values are 8 bits
            tempStringHigh = fillEightBit(tempStringHigh);
            tempStringLow = fillEightBit(tempStringLow);

            //Concatenate the two strings to get the 16 bit value for the temperature
            String tempString = tempStringHigh + tempStringLow;

            double cycles;

            /**
             * If the leading bit is a zero, convert from twos-complement. 
             * 
             * Otherwise simply convert to an integer
             * 
             * (Cycles is the nomenclature in LPS25H docs, so I am keeping it consistent here)
             */
            if(tempString.charAt(0) == '1'){
                cycles = fromTwosComplement(tempString);
            }else{
                cycles = Integer.parseInt(tempString, 2); 
            }

            //Temperature offset is cycles/480, relative to a base number of 42.5 degrees Celsius
            temperature = 42.5 + (cycles/480);
        } catch (Exception e){
            System.out.println(e);
        }
        

        return temperature;
    }

另外,我发现芯片上的一些寄存器需要通过写入某些值来手动设置。所以在读取之前用下面的方法初始化一次芯片:


public static boolean initializeLPS25H(I2C tempI2C){
            try{
                //Set CTRL_REG1. Enable output, set data rate to 25Hz, don't update output registers until MSB and LSB update
                tempI2C.writeRegister(0x20, 0xc4); 
                //Set RES_CONF. Set temp internal avereage to 16, pressure internal average to 32
                tempI2C.writeRegister(0x10, 0x05);
                //Set FIFO_CTRL. Set FIFO to generate a running average filtered pressure
                tempI2C.writeRegister(0x2E, 0xc0);
                //Set CTRL_REG4. Unclear what this does in RTIMU, doing it here until I can test.
                tempI2C.writeRegister(0x23, 0x40);

                return true;
            } catch (Exception e){
                System.out.println(e);
                return false;
            }


    }

如上所述,这要归功于 RTIMU 的创建者。我通过阅读芯片文档学到了很多上述内容,但设置这些初始值是我通过阅读 Github 上提供的 RTIMU 代码学到的。

添加所有不同的 Pi HAT 功能后,我将开源上述所有代码。我正在考虑在完成后将其制作成一个简单的库,以便其他人稍后可以轻松导入它。

© www.soinside.com 2019 - 2024. All rights reserved.