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会同时亮起(硬件上两灯同亮显示黄色),哪怕把板子垂直竖起来也是这个结果。
已做的排查
- 核对了ICM-42688-P的 datasheet,确认非FIFO模式下的加速度计寄存器地址是正确的;
- 验证了I2C单字节读取逻辑,WHO_AM_I能正确返回,说明基本读写流程没问题;
- 初始化时向
PWR_MGMT0寄存器写入0x0F,试图唤醒加速度计和陀螺仪; - 检查了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); } }
我的疑问点
- 加速度计寄存器地址我核对过datasheet是对的,但为什么读数完全不随姿态变化?会不会是传感器没真正唤醒?
- 初始化
PWR_MGMT0寄存器时写0x0F是否正确?有没有可能这个值并没有真正开启加速度计的正常工作模式? - I2C读取16位数据时,我是分两次读高/低字节,会不会这个流程不符合ICM-42688-P的要求?比如应该连续读取两个字节?
- 滤波逻辑或者水平判定的阈值设置有没有问题?
麻烦各位大佬帮忙看看哪里可能出了问题,谢谢大家!🙏




