前言

  1. 本文目标:从零完成 MPU6050/ICM20608 六轴原始加速度、陀螺仪数据读取;
  2. 开发环境:STM32CubeMX、Keil MDK5、HAL 库、I2C 通信;
  3. 阅读说明:正文只贴核心功能代码,CubeMX 自动生成的底层初始化代码省略,完整工程仓库链接放文末。

1. 硬件准备(表格最简)

表格

器件 用途
STM32F407VET6 主控 飞控核心
ICM20608 六轴传感器 获取原始六轴数据
USB-TTL 串口打印调试数据

2. STM32CubeMX配置

  1. 打开stm32CubeMX,创建新项目:

        

     2. 选择芯片STM32F407VET6:

     3. 手动配置RCC,选择Crystal/Ceramic Resonator:

     4. 手动配置I2C1,选择I2C:

     5. 手动配置USART1,选择Asynchronous:

     6. 进入右侧的System view界面,点击下方的GPIO,找到弹出窗口中的PB6,PB7手动设置为高电平Pull-up

     7. 手动设置外部晶振Input frequency 为 8MHz,PLL Source Mux 调为HES,HCKLK调为168MHz,最后点击回车键完成自动配置

     8. 进入Project Manager界面,找到Toolchain /IDE 手动设置为 MDK-ARM,然后输入项目名称,点击右上方的GENERATE CODE

    9. 弹窗选择Open Project,随后系统会自动打开keil,生成对应配置的代码

3,keil相应配置

     1. 点击左上方魔法棒

     2. 选择ARM Compiler型号:version 6,勾选Use MicroLIB,点击OK,配置完成,打开main.c工程文件

4,源码分段解析

     1. 传感器寄存器宏定义
#define ICM20608_ADDR        0x68    // ICM20608 7位I2C地址
#define ICM20608_PWR_MGMT_1  0x6B    // 电源管理寄存器1(唤醒传感器)
#define ICM20608_WHO_AM_I    0x75    // 设备ID寄存器,用于校验硬件是否存在
#define DEV_ID_ICM20608     0x74    // ICM20608固定设备识别ID

#define ACCEL_XOUT_H  0x3B  // X轴加速度高字节
#define ACCEL_YOUT_H  0x3D  // Y轴加速度高字节
#define ACCEL_ZOUT_H  0x3F  // Z轴加速度高字节

#define GYRO_XOUT_H   0x43  // X轴陀螺仪高字节
#define GYRO_YOUT_H   0x45  // Y轴陀螺仪高字节
#define GYRO_ZOUT_H   0x47  // Z轴陀螺仪高字节

解析要点:

  1. I2C 通信时设备地址需要左移 1 位,即 ICM20608_ADDR << 1原理:I2C 传输一字节中高 7 位为设备地址,最低 1 位读写标志位(0 写 / 1 读),HAL 库要求传入移位后的 8 位完整地址。
  2. 传感器硬件特性:读取高字节后会自动锁存对应低字节,必须一次性连续读取 2 字节,否则高低字节采样不同步,数据剧烈跳变;
  3. 0x6B 上电默认休眠,写入 0x00 即可唤醒传感器,同时切换内部 8M 晶振作为时钟;未唤醒时读取所有寄存器均为 0;
  4. 读取 WHO_AM_I 的数值与 0x74 对比,可判断传感器接线、地址是否正常;
  5. AD0 引脚逻辑:引脚接地 / 悬空地址 0x68,拉高 3.3V 地址切换为 0x69;
  6. 0x3B 起始连续 6 个寄存器,依次存放三轴加速度、三轴陀螺仪 16 位原始数据。
     2. I2C 读写底层驱动
单字节寄存器读取(带重试抗干扰)
//单字节寄存器读取 ICM20608_ReadReg
uint8_t ICM20608_ReadReg(uint8_t reg)
{
    uint8_t val = 0;
    uint8_t retry = 3;
    HAL_StatusTypeDef ret;
    
    while(retry--)
    {
        ret = HAL_I2C_Mem_Read(&hi2c1, ICM20608_ADDR << 1, reg,
                              I2C_MEMADD_SIZE_8BIT, &val, 1, 1000);
        if(ret == HAL_OK) break;
        HAL_Delay(10);
    }
    return val;
}

功能说明:读取传感器单个 8 位寄存器;增加 3 次重试机制,解决 I2C 总线干扰、上电时序不稳问题,是飞控硬件基础抗干扰写法;读取成功直接退出循环,失败延时 10ms 重试。

读取 16 位高低字节合并数据
//16 位传感器数据读取 MPU_Read_Data
int16_t ICM_Read_Data(uint8_t reg)
{
    uint8_t buf[2];
    HAL_I2C_Mem_Read(&hi2c1, ICM20608_ADDR << 1, reg,
                     I2C_MEMADD_SIZE_8BIT, buf, 2, 1000);
    return (int16_t)((buf[0] << 8) | buf[1]);
}

功能说明:一次性读取一组高低字节,拼接为 16 位有符号原始数据;buf [0] 高 8 位,buf [1] 低 8 位;高字节左移 8 位后与低字节按位或,组合完整数值;强制转换 int16_t 有符号短整型:加速度、陀螺仪存在正负方向,无符号 uint16_t 会造成负数数据溢出错乱。

单字节寄存器写入函数
//单字节寄存器写入 ICM20608_WriteReg
void ICM20608_WriteReg(uint8_t reg, uint8_t data)
{
    HAL_I2C_Mem_Write(&hi2c1, ICM20608_ADDR << 1, reg,
                      I2C_MEMADD_SIZE_8BIT, (uint8_t*)&data, 1, 500);
}

HAL 库 I2C 寄存器写入接口,向指定寄存器写入 1 字节配置数据。
 寄存器 0x6B 写入0x00除了唤醒,还会选择内部8M振荡器作为传感器时钟;如果不唤醒,所有寄存器读取全部返回0,识别不到设备。

注意:

 HAL_I2C_Mem_Write(&hi2c1, ICM20608_ADDR << 1, reg,
                      I2C_MEMADD_SIZE_8BIT, (uint8_t*)&data, 1, 500)
  1. 函数参数逐位解释:

  2. &hi2c1:指定使用 I2C1 外设总线;
  3. ICM20608_ADDR << 1:移位后的 8 位设备通信地址;
  4. reg:目标操作的传感器内部寄存器编号;
  5. I2C_MEMADD_SIZE_8BIT:传感器寄存器为 8 位地址;
  6. (uint8_t*)&data:数据缓存区,写入接口存放待发送数据;
  7. 1:单次传输字节长度;
  8. 500:通信超时时间,单位 ms,超时直接退出防止程序卡死。
     3.main 主循环采集打印逻辑
int main(void)
{
  // CubeMX自动生成初始化代码省略
  MPU6050_Init(); 

  uint8_t whoami = ICM20608_ReadReg(ICM20608_WHO_AM_I);
  printf("WHO_AM_I = 0x%02X\r\n", whoami);

  if(whoami == DEV_ID_ICM20608)
  {
    printf("ICM20608 Device Detect SUCCESS!\r\n");
  }
  else{
    printf("Device Detect ERROR!\r\n");
  }

  while (1)
  {
    int16_t ax, ay, az;
    int16_t gx, gy, gz;

    ax = ICM_Read_Data(ACCEL_XOUT_H);
    ay = ICM_Read_Data(ACCEL_YOUT_H);
    az = ICM_Read_Data(ACCEL_ZOUT_H);

    gx = ICM_Read_Data(GYRO_XOUT_H);
    gy = ICM_Read_Data(GYRO_YOUT_H);
    gz = ICM_Read_Data(GYRO_ZOUT_H);

    printf("ACC: %d %d %d | GYRO: %d %d %d\r\n", ax, ay, az, gx, gy, gz);
    HAL_Delay(200);
  }
}

循环定时读取传感器数据,通过串口打印方便调试观察

5,结尾总结

文实现了 STM32F407 搭配 ICM20608 读取六轴原始数据完整流程,覆盖 CubeMX 引脚时钟配置、Keil 工程设置、I2C 驱动封装、传感器 ID 校验、实时数据打印全套内容,同时梳理了 AD0 地址切换、寄存器读写、数据拼接等高频踩坑点。

原始六轴数据是四轴飞控开发最基础的前置步骤,拿到原始数值后,后续可延伸数据滤波、欧拉角 / 四元数姿态解算、PID 姿态控制等核心飞控内容。我后续会更新姿态解算相关实操文章,感兴趣可以收藏持续关注。

调试过程遇到读不到传感器、数据乱跳、串口无输出等问题,都可以在评论区留言交流。

完整 CubeMX 工程、全部驱动源码已整理,仓库地址:https://gitee.com/iiddoo/flight-control-embedded-system,下载后打开.ioc 文件重新生成工程即可直接编译运行。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐