我正在尝试从 LIS3DH 加速度计获取读数,我正在获取随机数

I'm trying to get readings from the LIS3DH accelerometer and I'm getting random numbers

我将 LIS3DH 加速度计与 i2c 连接,当我 运行 脚本时,它应该打印出 x、y、z 值,我得到随机数。

我在 C++ 中使用 i2csmbus 库,它们是 Linux 内核的一部分。
这是加速度计的(数据表)[https://cdn-shop.adafruit.com/datasheets/LIS3DH.pdf]。

我试过更改寄存器地址。
我试过 __s16 而不是 __s32.
我不确定我是否遗漏了在读取读数之前应该发生的事情。不知道是否需要写入其他寄存器。我对底部函数中到底发生了什么以及从寄存器返回的位和值一无所知。我想学。

extern "C" {
    #include <linux/i2c-dev.h>
    #include <i2c/smbus.h>
}
#include <sys/ioctl.h>
#include <fcntl.h>    /* For O_RDWR */
#include <unistd.h> 
#include <iostream>
using namespace std;

int file;
int adapter_nr = 1;
const char* filename = "/dev/i2c-8";
int initialize_mpu(int file);
__s32 high;
__s32 low;
__s32 value;
int read_raw_data(int file, __u8 addr);

int main() {
    file = open(filename, O_RDWR);
    if (file < 0) {
        exit(1);
    }
    int addr = 0x18;

    if (ioctl(file, I2C_SLAVE, addr) < 0) {
         exit(1);
    }

    __u8 res;

    __s32 accel_x;
    __s32 accel_y;
    __s32 accel_z;
    
    __s32 accel_x_register_high = 0x29;
    __s32 accel_y_register_high = 0x2B;
    __s32 accel_z_register_high = 0x2D;
    
    char buf[10];
    
    res = i2c_smbus_write_byte_data(file, addr, 0);

    if (res < 0) {
      /* ERROR HANDLING: i2c transaction failed */
    } else {
      /* res contains the read word */
    }
    
    buf[1] = 0x02;
    buf[2] = 0x03;
    if (write(file, buf, 3) != 3) {
      /* ERROR HANDLING: i2c transaction failed */
    }
    initialize_mpu(file);

    while (1) {
        
        accel_x = read_raw_data(file, accel_x_register_high) / 131.0;
        accel_y = read_raw_data(file, accel_y_register_high) / 131.0;
        accel_z = read_raw_data(file, accel_z_register_high) / 131.0;

        cout << accel_x <<" " << accel_y << " " << accel_z << " " << endl;

        usleep(100000);
    }
}


int initialize_mpu(int file) {
    i2c_smbus_write_byte_data(file, 0x20, 0xA7); //Write A7h into CTRL_REG1;      // Turn on the sensor, enable X, Y, Z axes with ODR = 100Hz normal mode.
    i2c_smbus_write_byte_data(file, 0x21, 0x09); //Write 09h into CTRL_REG2;      // High-pass filter (HPF) enabled
    i2c_smbus_write_byte_data(file, 0x22, 0x40); //Write 40h into CTRL_REG3;      // ACC AOI1 interrupt signal is routed to INT1 pin.
    i2c_smbus_write_byte_data(file, 0x23, 0x00); //Write 00h into CTRL_REG4;      // Full Scale = +/-2 g
    i2c_smbus_write_byte_data(file, 0x24, 0x08); //Write 08h into CTRL_REG5;      // Default value is 00 for no latching. Interrupt signals on INT1 pin is not latched.
    // configurations for wakeup and motionless detection
    i2c_smbus_write_byte_data(file, 0x32, 0x10); //Write 10h into INT1_THS;          // Threshold (THS) = 16LSBs * 15.625mg/LSB = 250mg.
    i2c_smbus_write_byte_data(file, 0x33, 0x00); //Write 00h into INT1_DURATION;     // Duration = 1LSBs * (1/10Hz) = 0.1s.
    //readRegister();  //Dummy read to force the HP filter to set reference acceleration/tilt value
    i2c_smbus_write_byte_data(file, 0x30, 0x2A); //Write 2Ah into INT1_CFG;          // Enable XLIE, YLIE, ZLIE interrupt generation, OR logic.
}


// Read the data of two 8-bit registers and compile into one 16-bit value
// register_address is the first (high) register, register_address-1 is the low register
// E.g., if the two registers contain the 8-bit values 0x01 and 0x02, this
// function returns the value 0x0102
int read_raw_data(int file, __u8 register_address) {
    high = i2c_smbus_read_byte_data(file, register_address);
    low = i2c_smbus_read_byte_data(file, register_address-1);
 
    value = (high << 8 | low);
 
    // This converts it from an unsigned 0-63355 value
    // to a signed value between -32769 and 32768
     if (value > 32768)
         value = value - 65536;
 
    return value;
}

我使用的 initialize_mpu 寄存器地址有误。

this datasheet 中隐藏了一些配置选项。我申请了一个,现在我得到了很多读数。

extern "C" {
    #include <linux/i2c-dev.h>
    #include <i2c/smbus.h>
}
#include <sys/ioctl.h>
#include <fcntl.h>    /* For O_RDWR */
#include <unistd.h> 
#include <iostream>
using namespace std;

int file;
int adapter_nr = 1;
const char* filename = "/dev/i2c-8";
int initialize_mpu(int file);

__s32 high;
__s32 low;
__s32 value;

int read_raw_data(int file, __u8 addr);

int main() {
    file = open(filename, O_RDWR);
    if (file < 0) {
        exit(1);
    }
    int addr = 0x18;

    if (ioctl(file, I2C_SLAVE, addr) < 0) {
         exit(1);
    }

    __u8 res;

//     __s32 whoami;
    __s32 accel_x2;
    __s32 accel_x;
    __s32 accel_y;
    __s32 accel_z;
    
    __s32 accel_x_register_high = 0x29;
    __s32 accel_y_register_high = 0x2B;
    __s32 accel_z_register_high = 0x2D;
    
    res = i2c_smbus_write_byte_data(file, addr, 0);

    if (res < 0) {
      /* ERROR HANDLING: i2c transaction failed */
    } else {
      /* res contains the read word */
    }


               
    initialize_mpu(file);
    
    
    

    while (1) {

        accel_x = read_raw_data(file, accel_x_register_high) / 133.0;
        accel_y = read_raw_data(file, accel_y_register_high) / 133.0;
        accel_z = read_raw_data(file, accel_z_register_high) / 133.0;

        cout << accel_x <<" " << accel_y << " " << accel_z << " " << endl;

        usleep(150000);
    }
}


int initialize_mpu(int file) {
    i2c_smbus_write_byte_data(file, 0x20, 0x57);
    i2c_smbus_write_byte_data(file, 0x21, 0x00);
    i2c_smbus_write_byte_data(file, 0x22, 0x40);
    i2c_smbus_write_byte_data(file, 0x23, 0x00);
    i2c_smbus_write_byte_data(file, 0x24, 0x08);
    i2c_smbus_write_byte_data(file, 0x32, 0x10);
    i2c_smbus_write_byte_data(file, 0x33, 0x00);
    i2c_smbus_write_byte_data(file, 0x30, 0x0A);
}

// Read the data of two 8-bit registers and compile into one 16-bit value
// register_address is the first (high) register, register_address-1 is the low register
// E.g., if the two registers contain the 8-bit values 0x01 and 0x02, this
// function returns the value 0x0102
int read_raw_data(int file, __u8 register_address) {
    high = i2c_smbus_read_byte_data(file, register_address);
    low = i2c_smbus_read_byte_data(file, register_address-1);
 
    value = (high << 8 | low);
 
//     This converts it from an unsigned 0-63355 value
//     to a signed value between -32769 and 32768
     if (value > 32768)
         value = value - 65536);
 
    return value;
}