You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

PSoC 5LP搭载ICM-42688-P时加速度计读数固定、姿态检测失效的问题求助

PSoC 5LP搭载ICM-42688-P时加速度计读数固定、姿态检测失效的问题求助

各位大佬好,我现在在做PSoC 5LP搭配MikroE的6DOF IMU 14 Click(核心IC是ICM-42688-P)的项目,遇到了一个卡壳的问题,想请大家帮忙排查下:

问题现象

  • I2C通信基本正常:传感器地址设为0x68,读取WHO_AM_I寄存器(0x75)能正确返回预期值0x47,说明传感器可以被正常检测到。
  • 但加速度计数据完全不随姿态变化:不管怎么倾斜、翻转传感器,软件始终判定板子处于“平放”状态,对应的两个LED会同时亮起(硬件上两灯同亮显示黄色),哪怕把板子垂直竖起来也是这个结果。

已做的排查

  1. 核对了ICM-42688-P的 datasheet,确认非FIFO模式下的加速度计寄存器地址是正确的;
  2. 验证了I2C单字节读取逻辑,WHO_AM_I能正确返回,说明基本读写流程没问题;
  3. 初始化时向PWR_MGMT0寄存器写入0x0F,试图唤醒加速度计和陀螺仪;
  4. 检查了LED的控制逻辑,代码里的状态判断和LED输出对应关系是对的。

完整项目代码

#include "project.h"
#include <stdlib.h>

// -----------------------------------------------------------
// ICM-42688-P 寄存器定义
// -----------------------------------------------------------
#define IMU_ADDR 0x68
#define WHO_AM_I_REG 0x75
#define WHO_AM_I_VALUE 0x47

// 非FIFO模式下的加速度计寄存器
#define ACCEL_X_H 0x1F
#define ACCEL_X_L 0x20
#define ACCEL_Y_H 0x21
#define ACCEL_Y_L 0x22
#define ACCEL_Z_H 0x23
#define ACCEL_Z_L 0x24

#define REG_PWR_MGMT0 0x4E // 电源管理寄存器:控制加速度计/陀螺仪使能

// -----------------------------------------------------------
// I2C 读取辅助函数
// -----------------------------------------------------------
uint8_t IMU_Read8(uint8_t reg) {
    uint8_t v;
    I2C_1_MasterSendStart(IMU_ADDR, I2C_1_WRITE_XFER_MODE);
    I2C_1_MasterWriteByte(reg);
    I2C_1_MasterSendRestart(IMU_ADDR, I2C_1_READ_XFER_MODE);
    v = I2C_1_MasterReadByte(I2C_1_NAK_DATA);
    I2C_1_MasterSendStop();
    return v;
}

int16_t IMU_Read16(uint8_t regH, uint8_t regL) {
    uint8_t hi = IMU_Read8(regH);
    uint8_t lo = IMU_Read8(regL);
    return (int16_t)((hi << 8) | lo);
}

// -----------------------------------------------------------
// 传感器初始化
// -----------------------------------------------------------
void IMU_Init(void) {
    I2C_1_MasterSendStart(IMU_ADDR, I2C_1_WRITE_XFER_MODE);
    I2C_1_MasterWriteByte(REG_PWR_MGMT0);
    I2C_1_MasterWriteByte(0x0F); // 尝试开启加速度计和陀螺仪
    I2C_1_MasterSendStop();
    CyDelay(100);
}

// -----------------------------------------------------------
// WHO_AM_I 传感器检测
// -----------------------------------------------------------
uint8_t DetectIMU(void) {
    return (IMU_Read8(WHO_AM_I_REG) == WHO_AM_I_VALUE);
}

// -----------------------------------------------------------
// MAIN 主函数
// -----------------------------------------------------------
int main(void) {
    CyGlobalIntEnable;
    I2C_1_Start();
    
    LED_Write(1);  // 初始状态:绿灯灭
    LED2_Write(1); // 初始状态:红灯灭
    CyDelay(200);

    // 传感器检测失败则红灯闪烁告警
    if (!DetectIMU()) {
        while(1) {
            LED2_Write(0);
            CyDelay(150);
            LED2_Write(1);
            CyDelay(150);
        }
    }

    IMU_Init();

    // -----------------------------
    // 滤波与状态变量(平滑水平检测)
    // -----------------------------
    float ax_f = 0, ay_f = 0, az_f = 0;
    float alpha = 0.08f; // 低通滤波系数
    uint8_t stable = 0;  // 1=平放状态,0=倾斜状态
    uint8_t counter = 0;

    while(1) {
        // 读取原始加速度计数据
        int16_t ax_raw = IMU_Read16(ACCEL_X_H, ACCEL_X_L);
        int16_t ay_raw = IMU_Read16(ACCEL_Y_H, ACCEL_Y_L);
        int16_t az_raw = IMU_Read16(ACCEL_Z_H, ACCEL_Z_L);

        // -----------------------------
        // 低通滤波(数据平滑处理)
        // -----------------------------
        ax_f += alpha * (ax_raw - ax_f);
        ay_f += alpha * (ay_raw - ay_f);
        az_f += alpha * (az_raw - az_f);

        // -----------------------------
        // 水平状态判定逻辑(Z轴向上为参考)
        // -----------------------------
        // 平放条件:X/Y轴加速度接近0,Z轴加速度接近+1g
        uint8_t is_flat_now = (abs((int)ax_f) < 3500) && (abs((int)ay_f) < 3500) && (az_f > 8000);
        // 注:这里8000是我预估的0.5g对应值,可能需要根据传感器量程调整

        // -----------------------------
        // 迟滞逻辑(避免状态频繁切换)
        // -----------------------------
        if (is_flat_now) {
            counter++;
            if (counter > 5) { // 连续5次检测稳定则判定为平放
                stable = 1;
                counter = 0;
            }
        } else {
            counter++;
            if (counter > 5) { // 连续5次检测稳定则判定为倾斜
                stable = 0;
                counter = 0;
            }
        }

        // -----------------------------
        // LED状态控制
        // -----------------------------
        if (stable) {
            LED_Write(0);  // 平放:绿灯亮
            LED2_Write(1); // 平放:红灯灭
        } else {
            LED_Write(1);  // 倾斜:绿灯灭
            LED2_Write(0); // 倾斜:红灯亮
        }

        CyDelay(30);
    }
}

我的疑问点

  1. 加速度计寄存器地址我核对过datasheet是对的,但为什么读数完全不随姿态变化?会不会是传感器没真正唤醒?
  2. 初始化PWR_MGMT0寄存器时写0x0F是否正确?有没有可能这个值并没有真正开启加速度计的正常工作模式?
  3. I2C读取16位数据时,我是分两次读高/低字节,会不会这个流程不符合ICM-42688-P的要求?比如应该连续读取两个字节?
  4. 滤波逻辑或者水平判定的阈值设置有没有问题?

麻烦各位大佬帮忙看看哪里可能出了问题,谢谢大家!🙏

火山引擎 最新活动