> 技术文档 > STM32读取IMU(ICM-42688-P)数据(文末附源码)_icm42688

STM32读取IMU(ICM-42688-P)数据(文末附源码)_icm42688


一、ICM-42688参数

1.1 GYROSCOPE

ICM-42688-P 是一款专为车载和工业应用设计的高性能惯性测量单元(IMU),集成三轴 MEMS 速率陀螺仪、三轴 MEMS 加速度计((支持 20 位 FIFO 高分辨率数据,多量程可选),配备 I3CSM、I2C 和 SPI 通信接口,具备自检、时钟管理、FIFO 缓存、多类型中断触发等系统级功能,内置数字温度传感器用于温度补偿,支持出厂偏置校准和动态补偿。
陀螺仪量程
具有±15.625、±31.25、±62.5、±125、±250、±500、±1000、±2000八种测量范围。
陀螺仪零偏
典型值:±0.5°/s;
温度敏感性:零偏温漂系数为 ±0.005°/s/°C。Alt

1.2 ACCELEROMETER

陀螺仪量程
具有±2、±4、±8、±16四种测量范围。
陀螺仪零偏
典型值:±20mg;
温度敏感性:零偏温漂系数为 ±0.15mg/°C。
Alt

二、通信接口

ICM-42688-P 支持I3CSM、I2C 和 SPI 三种通信接口模式,本次数据读取使用SPI通信接口。ICM-4688-P使用SPI通信时,具有如下特性

  • 大端传输,即先传输MSB后传输LSB;
  • 数据在 SCLK 的上升沿被锁存;
  • 数据应在 SCLK 的下降沿进行转换;
  • SCLK 的最大频率为 24 MHz。
    Alt
    所以根据上述特性,需要注意SPI的频率以及CPOL和CPHA,即CPOL = 1/CPHA = 1。本次使用的MCU是STM32F103C8T6。在STM32CubeMX中的配置,如下图所示。
    Alt
    SPI 在读取或者写入时,第一个字节包含 SPI 地址,后面的字节包含 SPI 数据。第一个字节的第一位包含读(1)/写(0)位。
    Alt

三、参数寄存器配置和数据读取

3.1读取ID

使用STM32CubeMX配置好相关参数之后,先读取一下IMU的ID,查看一下通信是否正常,读取IMU的ID可以先不配置IMU的加速度和陀螺仪的相关参数。
Alt
ICM-42688 SPI读写函数

/* * SPI读写函数 * @param addr 寄存器地址 * @param pTxData 发送数据(写操作时有效,单字节) * @param pRxData 接收缓冲区指针(读操作时有效) * @param dataSize 数据大小(字节数) * @return 操作状态:0=成功,1=失败*/uint8_t SPI1_ReadWriteBytes(uint8_t addr, uint8_t pTxData, uint8_t *pRxData, uint16_t dataSize){uint16_t totalSize = dataSize + 1;uint8_t txBuffer[totalSize];uint8_t rxBuffer[totalSize];// 根据发送/接收缓冲区设置地址字节if (pRxData) {txBuffer[0] = addr | 0x80; // 读操作:地址最高位置1memset(&txBuffer[1], 0xFF, dataSize); // 读操作} else {txBuffer[0] = addr & 0x7F; // 写操作:地址最高位清0txBuffer[1] = pTxData; // 写数据}// 执行SPI传输ICM_CS(0);if (HAL_SPI_TransmitReceive(&hspi1, txBuffer, rxBuffer, totalSize, 0xFF) != HAL_OK){return 1;}ICM_CS(1);// 读取操作时,提取有效数据(跳过地址响应字节)if (pRxData) {memcpy(pRxData, &rxBuffer[1], dataSize);}return 0;}

读取ID函数

/** * 读取ICM-42688设备ID寄存器值 * @return 成功时返回设备ID(正常为0x47),失败时返回0 */uint8_t ICM_ReadID(void){uint8_t Temp; // 调用SPI传输函数读取设备ID寄存器(地址为ICM_DEVICE_ID,0x75) // 参数: 寄存器地址, 写数据(0表示无写操作), 接收缓冲区, 数据长度(1字节) // 返回值: 0表示SPI通信成功, 非0表示失败if(SPI1_ReadWriteBytes(ICM_DEVICE_ID,0,&Temp,1)){return 1;} return Temp;}

3.2初始化ICM

在初始化ICM时,可以参考数据手册配置相应寄存器参数。根据手册显示,ICM在软件复位后的默认值基本可用,只需设置相关寄存器即可开启加速度计和陀螺仪功能就可以读数了。默认配置下,加速度计量程为±16g,陀螺仪的量程范围则为±2000°/s。以下为简单的初始化配置步骤:
(1)软件复位
在DEVICE_CONFIG(0x11)寄存器中,将第0位置1使能软件复位
Alt
(2)开启陀螺仪和加速度计
在PWR_MGMT0(0x4E)寄存器中,将[1:0]置1,设置加速度计Low Noise (LN) Mode,将[3:2]置1,设置陀螺仪Low Noise (LN) Mode。

注意:“Gyroscope needs to be kept ON for a minimum of 45ms. When transitioning from OFF to any of the other modes, do not issue any register writes for 200µs.”
“When transitioning from OFF to any of the other modes, do not issue any
register writes for 200µs.”

Alt
ICM需要配置量程和ODR在寄存器GYRO_CONFIG0(0x4F)和ACCEL_CONFIG0(0x50),具体可见数据手册,此处使用默认的量程和ODR,分别为:
陀螺仪:GYRO_FS_SEL: ±2000dps,GYRO_ODR:1kHz;
加速度计:ACCEL_FS_SEL: ±16g,ACCEL_ODR: 1kHz。
此外ICM还可以设置相关滤波器,此处不介绍那么详细,具体可见数据手册。
初始化函数

/** * 初始化ICM-42688六轴传感器 * @return 状态码:0=成功,1=SPI通信失败 */uint8_t ICM_Init(void){uint8_t status;// 步骤1:发送软件复位命令(向设备配置寄存器1写入复位值) // ICM_SOFT_RESET(0x11)status = SPI1_ReadWriteBytes(ICM_DEVICE_CONFIG_1, ICM_SOFT_RESET, NULL, 1);Hal_Delay_ms(4);// 步骤2:配置工作模式(启用加速度计和陀螺仪) // ACCEL_GYRO_MODE = 0x0F(低噪声模式,所有轴启用) // [3:2]=11(陀螺仪 LN MODE),[1:0]=11(加速度计 LN MODE)status = SPI1_ReadWriteBytes(ICM_PWR_MGMT0, ACCEL_GYRO_MODE, NULL, 1);Hal_Delay_ms(100);if(status != 0) return 1;return 0;}

3.3数据读取

接下来可以读取加速度计和陀螺仪的数据寄存器数值了。
加速度和陀螺仪的数据寄存器的地址:0x1F-0x2A。
数据读取函数

/** * 读取ICM-42688的加速度计和陀螺仪原始数据 * @param data 存储传感器数据的结构体指针 */void ICM_ReadData(icm42688_data_t *data){uint8_t buf[12];// 从加速度计X轴高位寄存器开始,连续读取12字节数据 // 地址自动递增模式:ICM_ACCEL_DATA_X1 (0x1F) → ICM_GYRO_DATA_Z0 (0x2A)SPI1_ReadWriteBytes(ICM_ACCEL_DATA_X1, NULL, buf, 12);// 解析加速度计数据(高字节在前,16位有符号整数) data->accel_x = (buf[0] << 8) | buf[1]; data->accel_y = (buf[2] << 8) | buf[3]; data->accel_z = (buf[4] << 8) | buf[5]; // 解析陀螺仪数据(高字节在前,16位有符号整数) data->gyro_x = (buf[6] << 8) | buf[7]; data->gyro_y = (buf[8] << 8) | buf[9]; data->gyro_z = (buf[10] << 8) | buf[11];}

正常读取数据啦
STM32读取IMU(ICM-42688-P)数据(文末附源码)_icm42688
如果需要读取温度数据,读取数据寄存器的起始地址为0x1D就可以了。像这样:

 // 地址自动递增模式:ICM_TEMP_DATA1 (0x1D) → ICM_GYRO_DATA_Z0 (0x2A)SPI1_ReadWriteBytes(ICM_TEMP_DATA1, NULL, buf, 14);

四、FIFO读取

4.1初始化

初始化步骤
(1)在FIFO_CONFIG寄存器中设置Stream-to-FIFO Mode,关于这三种模式解释如下:
Bypass Mode:旁路模式(默认) 数据不经过 FIFO,直接输出,FIFO 功能禁用;
Stream-to-FIFO Mode:数据持续写入 FIFO,满时循环覆盖旧数据;
STOP-on-FULL Mode:FIFO 填满后停止写入,避免数据溢出,直到主机读取后恢复写入。
(2)在FIFO_CONFIG1寄存器中设使能温度、陀螺仪和加速度计数据包进入FIFO。
Alt
Alt
初始化函数
FIFO数据包格式为: Header(1byte) + Accel(6bytes) + Gyro(6bytes) + Temp(1byte) + Timestamp(2bytes)

/** * 从ICM-42688传感器的FIFO缓冲区读取并解析数据 * @param data 指向icm42688_FIFO_data_t结构体的指针,用于存储解析后的数据 */void ICM_ReadFIFOData(icm42688_FIFO_data_t *data){ uint16_t data_index = 0; // 检查输入参数 if (data == NULL) return; // 读取FIFO数据 if (SPI1_ReadWriteBytes(ICM_FIFO_DATA, NULL, data->fifo_buffer, 128) != 0){ printf(\"SPI read failed!\\n\"); } // 解析FIFO数据 - 根据ICM-42688的数据手册格式 // 数据格式为: Header(1byte) + Accel(6bytes) + Gyro(6bytes) + Temp(1byte) + Timestamp(2bytes) while(data_index < 128){ // 解析头部 data->fifo_header = data->fifo_buffer[data_index];data_index += 1; // 解析加速度数据 (16位有符号整数,高字节在前) data->accel_x = (data->fifo_buffer[data_index] << 8) | data->fifo_buffer[data_index + 1]; data->accel_y = (data->fifo_buffer[data_index + 2] << 8) | data->fifo_buffer[data_index + 3]; data->accel_z = (data->fifo_buffer[data_index + 4] << 8) | data->fifo_buffer[data_index + 5]; data_index += 6; // 解析陀螺仪数据 data->gyro_x = (data->fifo_buffer[data_index] << 8) | data->fifo_buffer[data_index+1]; data->gyro_y = (data->fifo_buffer[data_index+2] << 8) | data->fifo_buffer[data_index+3]; data->gyro_z = (data->fifo_buffer[data_index+4] << 8) | data->fifo_buffer[data_index+5]; data_index += 6; // 解析温度 data->temp = data->fifo_buffer[data_index];data_index += 1;// 解析时间戳 data->timeStamp = (data->fifo_buffer[data_index] << 8) | data->fifo_buffer[data_index+1];data_index += 2; // 打印解析结果 printf(\"Header: 0x%02X\\r\\n\", data->fifo_header); printf(\"Accel: X=%d, Y=%d, Z=%d\\r\\n\", data->accel_x, data->accel_y, data->accel_z); printf(\"Gyro: X=%d, Y=%d, Z=%d\\r\\n\", data->gyro_x, data->gyro_y, data->gyro_z); printf(\"Timestamp: %d\\r\\n\", data->timeStamp); printf(\"Temperature: %d\\r\\n\", data->temp); }}

ICM-42688的FIFO容量为2K,本次测试中每次仅读取128字节的数据。此读取量可根据实际需求灵活调整,也可通过配置FIFO_WM寄存器来设定FIFO的中断触发阈值,以实现高效的数据处理。结果如图所示:
Alt

五、数据可视化

匿名上位机接收上报数据并实现可视化呈现,匿名上位机的具体的通信协议可参见其官方文档。下面是匿名上位机数据帧格式:
Alt
匿名数据帧格式发送函数

uint8_t Ano_frame_format(uint8_t NID, uint8_t len, uint8_t *data) { uint8_t frame_buf[200]; // 定义数据帧缓存,最大支持200字节 uint8_t sumcheck = 0; // 用于存储求和校验 uint8_t addcheck = 0; // 用于存储加和校验 uint8_t res; // 存储串口发送结果 // 设置帧头和各字段 frame_buf[0] = AnoFrame_HEAD;  // 帧头标识 frame_buf[1] = AnoFrame_S_ADDR; // 源地址 frame_buf[2] = AnoFrame_D_ADDR; // 目标地址 frame_buf[3] = NID; // 节点ID frame_buf[4] = len; // 数据长度 frame_buf[5] = 0x00; // 数据长度高八位 // 复制数据部分 memcpy(&frame_buf[6], data, len); // 从索引6开始存储数据 // 计算校验和 for (uint8_t i = 0; i < (len + 6); i++) // 计算数据部分和头部信息的校验和 { sumcheck += frame_buf[i]; // 求和校验 addcheck += sumcheck;  // 加和校验 } // 将计算出的校验和写入数据帧 frame_buf[len + 6] = sumcheck; // 写入累加和校验 frame_buf[len + 7] = addcheck; // 写入最终加和校验 // 通过串口发送数据帧 res = HAL_UART_Transmit(&huart1, frame_buf, len + 8, 500); // 发送数据帧,含有帧头、数据和校验和 return res; // 返回串口发送结果}

Alt
程序源码:

源码下载地址

六、结语

ICM-42688的当前测试数据仅为基本读取功能。根据数据手册,该传感器还可配置更多功能,包括中断触发、时间同步、计步以及阈值检测等功能。