[其他] STM32 姿态传感器mpu6050的使用

[复制链接]
1705|34
 楼主| 略略u 发表于 2022-8-29 22:55 | 显示全部楼层 |阅读模式
特性
MPU6050 ,能同时检测三轴加速度、 三轴陀螺仪(三轴角速度)的运动数据以及温度数据。利用其内部的 DMP 模块(Digital Motion Processor 数字运动处理器) ,可对传感器数据进行滤波、融合处理,直接通过 IIC 接口向主控器输出姿态解算后的数据,降低主控器的运算量。其姿态解算频率最高可达 200Hz

评论

———————————————— 版权声明:本文为CSDN博主「为了维护世界和平_」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/WANGYONGZIXUE/article/details/121503215  发表于 2022-8-29 22:57
 楼主| 略略u 发表于 2022-8-29 23:01 | 显示全部楼层
 楼主| 略略u 发表于 2022-8-29 23:01 | 显示全部楼层
引脚说明
42911630cd4cae4b86.png
 楼主| 略略u 发表于 2022-8-29 23:02 | 显示全部楼层
备注:SDA/SCL、 XDA/XCL 通讯引脚分别为两组 I2C 信号线;当模块与外部主机通讯时, 使用 SDA/SCL,如与 STM32 芯片通讯; 而 XDA/XCL 则用于 MPU6050 芯片与其它I2C 传感器通讯时使用,但一般不这样使用。
 楼主| 略略u 发表于 2022-8-29 23:03 | 显示全部楼层
模块引脚与单片机连接
22641630cd5123e6ee.png
 楼主| 略略u 发表于 2022-8-29 23:03 | 显示全部楼层
编程要点
(1) 初始化 STM32 的 I2C(软件模拟);
(2) 使用 I2C 向 MPU6050 写入控制参数;
(3) 定时读取加速度、角速度及温度数据;
 楼主| 略略u 发表于 2022-8-29 23:04 | 显示全部楼层
使用I2C软件,驱动mpu6050
  1. #define GPIO_PORT_I2C        GPIOB                        /* GPIO端口*/
  2. #define RCC_I2C_PORT         RCC_APB2Periph_GPIOB                /* GPIO时钟*/
  3. #define I2C_SCL_PIN                GPIO_Pin_6                        /* 连接SCL的GPIO */
  4. #define I2C_SDA_PIN                GPIO_Pin_7                        /* 连接SDL的GPIO */

  5. #define I2C_SCL_1()  GPIO_SetBits(GPIO_PORT_I2C, I2C_SCL_PIN)                /* SCL = 1 */
  6. #define I2C_SCL_0()  GPIO_ResetBits(GPIO_PORT_I2C, I2C_SCL_PIN)                /* SCL = 0 */

  7. #define I2C_SDA_1()  GPIO_SetBits(GPIO_PORT_I2C, I2C_SDA_PIN)                /* SDA = 1 */
  8. #define I2C_SDA_0()  GPIO_ResetBits(GPIO_PORT_I2C, I2C_SDA_PIN)                /* SDA = 0 */

  9. #define I2C_SDA_READ()  GPIO_ReadInputDataBit(GPIO_PORT_I2C, I2C_SDA_PIN)        /*读SDA数据 */

  10. static void i2c_Delay(void)
  11. {
  12.         uint8_t i;
  13.         for (i = 0; i < 10; i++);
  14. }

  15. //当SCL高电平时,SDA出现一个下跳沿表示I2C总线启动信号
  16. void i2c_Start(void)
  17. {
  18.     /*    _____
  19.      *SDA      \_____________
  20.      *    __________
  21.      *SCL           \________
  22.      */
  23.         I2C_SDA_1();
  24.         I2C_SCL_1();
  25.         i2c_Delay();
  26.         I2C_SDA_0();
  27.         i2c_Delay();
  28.         I2C_SCL_0();
  29.         i2c_Delay();
  30. }

  31. //当SCL高电平时,SDA出现一个上跳沿表示I2C总线停止信号
  32. void i2c_Stop(void)
  33. {
  34.     /*               _______
  35.      *SDA __________/
  36.      *          ____________
  37.      *SCL _____/
  38.      */
  39.         I2C_SDA_0();
  40.         I2C_SCL_1();
  41.         i2c_Delay();
  42.         I2C_SDA_1();
  43. }

  44. /*CPU向I2C总线设备发送8bit数据

  45. */
  46. void i2c_SendByte(uint8_t _ucByte)
  47. {
  48.         uint8_t i;

  49.         /* 先发送高7位,*/
  50.         for (i = 0; i < 8; i++)
  51.         {               
  52.                 if (_ucByte & 0x80)
  53.                 {
  54.                         I2C_SDA_1();//发送的1
  55.                 }
  56.                 else
  57.                 {
  58.                         I2C_SDA_0();//发送的0
  59.                 }
  60.                 i2c_Delay();
  61.                 I2C_SCL_1();
  62.                 i2c_Delay();       
  63.                 I2C_SCL_0();
  64.                 if (i == 7)
  65.                 {
  66.                          I2C_SDA_1(); //释放总线
  67.                 }
  68.                 _ucByte <<= 1;        /*左移一个 bit */
  69.                 i2c_Delay();
  70.         }
  71. }

  72. /*
  73. CPU从I2C设备读取8bit数据
  74. */
  75. uint8_t i2c_ReadByte(u8 ack)
  76. {
  77.         uint8_t i;
  78.         uint8_t value;

  79.         /* 读取到第一个bit为数据的bit7 */
  80.         value = 0;
  81.         for (i = 0; i < 8; i++)
  82.         {
  83.                 value <<= 1;
  84.                 I2C_SCL_1();
  85.                 i2c_Delay();
  86.                 if (I2C_SDA_READ())
  87.                 {
  88.                         value++;
  89.                 }
  90.                 I2C_SCL_0();
  91.                 i2c_Delay();
  92.         }
  93.         if(ack==0)
  94.                 i2c_NAck();
  95.         else
  96.                 i2c_Ack();
  97.         return value;
  98. }

  99. /*
  100. CPU产生一个时钟,并读取器件的ACK应答信号
  101. */
  102. uint8_t i2c_WaitAck(void)
  103. {
  104.         uint8_t re;

  105.         I2C_SDA_1();        /* CPU释放SDA总线 */
  106.         i2c_Delay();
  107.         I2C_SCL_1();        /* CPU驱动SCL = 1, 此器件会返回ACK应答 */
  108.         i2c_Delay();
  109.         if (I2C_SDA_READ())        /* CPU读取SDA口状态 */
  110.         {
  111.                 re = 1;
  112.         }
  113.         else
  114.         {
  115.                 re = 0;
  116.         }
  117.         I2C_SCL_0();
  118.         i2c_Delay();
  119.         return re;
  120. }

  121. /*
  122. CPU产生一个ACK信号

  123. */
  124. void i2c_Ack(void)
  125. {

  126.     /*           ____
  127.      *SCL ______/    \______
  128.      *    ____         _____
  129.      *SDA     \_______/
  130.      */
  131.         I2C_SDA_0();        /* CPU驱动SDA = 0 */
  132.         i2c_Delay();
  133.         I2C_SCL_1();        /* CPU产生1个时钟 */
  134.         i2c_Delay();
  135.         I2C_SCL_0();
  136.         i2c_Delay();
  137.         I2C_SDA_1();        /* CPU释放SDA总线 */
  138. }

  139. /*
  140. CPU产生1个NACK信号
  141. */
  142. void i2c_NAck(void)
  143. {
  144.     /*           ____
  145.      *SCL ______/    \______
  146.      *    __________________
  147.      *SDA
  148.      */
  149.         I2C_SDA_1();        /* CPU驱动SDA = 1 */
  150.         i2c_Delay();
  151.         I2C_SCL_1();        /* CPU产生一个时钟 */
  152.         i2c_Delay();
  153.         I2C_SCL_0();
  154.         i2c_Delay();       
  155. }

  156. /*
  157. 配置I2C总线的GPIO
  158. */
  159. void i2c_GPIO_Config(void)
  160. {
  161.         GPIO_InitTypeDef GPIO_InitStructure;

  162.         RCC_APB2PeriphClockCmd(RCC_I2C_PORT, ENABLE);        //时钟

  163.         GPIO_InitStructure.GPIO_Pin = I2C_SCL_PIN | I2C_SDA_PIN;
  164.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  165.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; //开漏输出
  166.         GPIO_Init(GPIO_PORT_I2C, &GPIO_InitStructure);

  167.         //停止信号,复位I2C总线上的所有设备
  168.         i2c_Stop();
  169. }

  170. /*
  171. CPU发送设备地址,然后读取设备应答是否有设备
  172. */
  173. uint8_t i2c_CheckDevice(uint8_t _Address)
  174. {
  175.         uint8_t ucAck;

  176.         i2c_GPIO_Config();                /* 配置GPIO */
  177.        
  178.         i2c_Start();                /*I2C开始信号*/

  179.         /* 发送设备地址和读写控制bit(0=写,1=读)bit7位先传 */
  180.         i2c_SendByte(_Address|I2C_WR);
  181.         ucAck = i2c_WaitAck();        /*检测设备应答 */

  182.         i2c_Stop();                        /* I2C结束信号 */

  183.         return ucAck;
  184. }
 楼主| 略略u 发表于 2022-8-29 23:31 | 显示全部楼层
mp6050使用软件I2C读写数据写

  1. void MPU6050_WriteReg(u8 reg_add,u8 reg_dat)
  2. {
  3.         i2c_Start();
  4.         i2c_SendByte(MPU6050_SLAVE_ADDRESS);
  5.         i2c_WaitAck();
  6.         i2c_SendByte(reg_add);
  7.         i2c_WaitAck();
  8.         i2c_SendByte(reg_dat);
  9.         i2c_WaitAck();
  10.         i2c_Stop();
  11. }

  12. void MPU6050_ReadData(u8 reg_add,unsigned char*Read,u8 num)
  13. {
  14.         unsigned char i;
  15.        
  16.         i2c_Start();
  17.         i2c_SendByte(MPU6050_SLAVE_ADDRESS);
  18.         i2c_WaitAck();
  19.         i2c_SendByte(reg_add);
  20.         i2c_WaitAck();
  21.        
  22.         i2c_Start();
  23.         i2c_SendByte(MPU6050_SLAVE_ADDRESS+1);
  24.         i2c_WaitAck();
  25.        
  26.         for(i=0;i<(num-1);i++){
  27.                 *Read=i2c_ReadByte(1);
  28.                 Read++;
  29.         }
  30.         *Read=i2c_ReadByte(0);
  31.         i2c_Stop();
  32. }
 楼主| 略略u 发表于 2022-8-29 23:32 | 显示全部楼层
手册中寄存器描述
1、电源管理寄存器
53079630cdbefd6e72.png
描述:这个寄存器允许用户配置电源模式和时钟源。它也提供1位重置整个设备,和1位使能温度传感器
SLEEP 设置1时,设备进入低功耗休眠模式;TEMP_DIS用于设置是否使能温度传感器,0 则使能
 楼主| 略略u 发表于 2022-8-29 23:32 | 显示全部楼层
CLKSEL[2:0]时钟源如下,
16095630cdc1944029.png
内部8M RC晶振精度不高,一般选择X/Y/Z轴陀螺作为参考PLL的时钟源,设置CLKSEL=001
 楼主| 略略u 发表于 2022-8-29 23:33 | 显示全部楼层
2、陀螺仪寄存器
该寄存器用于触发陀螺仪自检并配置陀螺仪的量程范围。
42519630cdc4ae0912.png
FS_SEL[1:0]的取值:0,±250° /S; 1,±500° /S; 2,±1000° /S; 3,±2000° /S;
一般设置为3,±2000dps,因为陀螺仪的ADC为16位分辨率,所以得到灵敏度为65536/4000 = 16.4LSB(°/S)
 楼主| 略略u 发表于 2022-8-29 23:34 | 显示全部楼层
3、加速度传感器
该寄存器用于触发加速计自检并配置加速计满标度范围。该寄存器还配置数字高通滤波器(DHPF)。
315630cdc62c01b8.png
AFS_SEL[1:0]选择范围:0, ±2g; 1,±4g; 2,±8g; 3,±16g;
一般设置为0,±2g ,灵敏度为65536/4=16384 LSB/g
 楼主| 略略u 发表于 2022-8-29 23:34 | 显示全部楼层
4、 采样率
该寄存器指定用于生成MPU-60X0采样率的陀螺仪输出速率的除法器。
10321630cdc9b82f36.png
传感器寄存器输出、FIFO输出和DMP采样均基于采样率。

在这陀螺仪的输出频率是1Khz或者8Khz,与数字低通滤波器(DLPF)的设置有关。
公式 采样频率 = 陀螺仪输出频率 / (1+SMPLRT_DIV)

当 DLPF_CFG=0/7 的时候,频率为 8Khz,其他情况是 1Khz。而且 DLPF 滤波频率一般设置
为采样率的一半。

例如:采样率,假设为125HZ,那么 SMPLRT_DIV=1000/125 - 1 = 7
 楼主| 略略u 发表于 2022-8-29 23:35 | 显示全部楼层
5、 配置寄存器
该寄存器配置陀螺仪和加速度计的外部帧同步(FSYNC)引脚采样和数字低通滤波器(DLPF)设置。
32811630cdcc4e79b4.png
 楼主| 略略u 发表于 2022-8-29 23:36 | 显示全部楼层
其中,DLPF_CFG 配置低通滤波如下
2983630cdcf208881.png
 楼主| 略略u 发表于 2022-8-29 23:37 | 显示全部楼层
一般我们设置角速度传感器的带宽为其采样率的一半, 如前面所说的,如果设置采样率为 125Hz,那么带宽就应该设置为 62Hz,取近似值 44Hz, 就应该设置 DLPF_CFG=011
 楼主| 略略u 发表于 2022-8-29 23:37 | 显示全部楼层
MPU6050初始化的步骤:
复位MPU6050,让MPU6050内部的所有寄存器恢复默认值
必须设置该寄存器位0x00,以唤醒MPU6050,进入正常工作状态,一般选择x轴陀螺PLL作为时钟源,以获得更高精度的时钟。
陀螺仪配置寄存器(0x1B)
加速度传感器配置寄存器(0x1C)
陀螺仪采样率,由采样率分频寄存器(0x19)控制;
设置数字低通滤波器,由配置寄存器(0x1A)控制;
DLPF位设置,即DLPF_CFG[2:0],加速度技和陀螺仪,都是根据这三个位的配置进行过滤的,
 楼主| 略略u 发表于 2022-8-29 23:38 | 显示全部楼层
初始化程序
  1. #define MPU6050_RA_SMPLRT_DIV       0x19
  2. #define MPU6050_RA_CONFIG           0x1A
  3. #define MPU6050_RA_GYRO_CONFIG      0x1B
  4. #define MPU6050_RA_ACCEL_CONFIG     0x1C

  5. #define MPU6050_RA_PWR_MGMT_1       0x6B
  6. #define MPU6050_RA_PWR_MGMT_2       0x6C

  7. #define MPU6050_WHO_AM_I        0x75
  8. #define MPU6050_SMPLRT_DIV      0  //8000Hz  fix me
  9. #define MPU6050_DLPF_CFG        0  //fix me
  10. #define MPU6050_GYRO_OUT        0x43     //MPU6050陀螺仪数据寄存器地址
  11. #define MPU6050_ACC_OUT         0x3B     //MPU6050加速度数据寄存器地址

  12. void MPU6050_Init(void)
  13. {
  14.   int i=0,j=0;
  15.   for(i=0;i<1000;i++)
  16.   {
  17.     for(j=0;j<1000;j++);
  18.   }
  19.         MPU6050_WriteReg(MPU6050_RA_PWR_MGMT_1, 0x01);
  20.         MPU6050_WriteReg(MPU6050_RA_SMPLRT_DIV , 0x07);        //值得设置
  21.         MPU6050_WriteReg(MPU6050_RA_CONFIG , 0x03);//值得设置
  22.         MPU6050_WriteReg(MPU6050_RA_ACCEL_CONFIG , 0x00);
  23.         MPU6050_WriteReg(MPU6050_RA_GYRO_CONFIG, 0x18);
  24. }
 楼主| 略略u 发表于 2022-8-29 23:39 | 显示全部楼层
数据读取
1、 陀螺仪数据输出寄存器
通过读取这6个寄存器,就可以读到陀螺仪 x/y/z 轴的值,比如 x 轴的数据,可以通过读取 0X43(高 8 位)和 0X44(低 8 位)寄存器得到,其他轴以此类推
  1. void MPU6050ReadGyro(short *gyroData)
  2. {
  3.     u8 buf[6];
  4.     MPU6050_ReadData(MPU6050_GYRO_OUT,buf,6);
  5.     gyroData[0] = (buf[0] << 8) | buf[1];
  6.     gyroData[1] = (buf[2] << 8) | buf[3];
  7.     gyroData[2] = (buf[4] << 8) | buf[5];
  8. }
 楼主| 略略u 发表于 2022-8-29 23:40 | 显示全部楼层
2、加速度传感器数据输出寄存器
通过读取这6个寄存器,就可以读到加速度传感器 x/y/z 轴的值,比如读 x 轴的数据,可以通过读取0X3B(高 8 位)和0X3C(低8位)寄存器得到,其他轴以此类推
  1. void MPU6050ReadAcc(short *accData)
  2. {
  3.     u8 buf[6];
  4.     MPU6050_ReadData(MPU6050_ACC_OUT, buf, 6);
  5.     accData[0] = (buf[0] << 8) | buf[1];
  6.     accData[1] = (buf[2] << 8) | buf[3];
  7.     accData[2] = (buf[4] << 8) | buf[5];
  8. }
您需要登录后才可以回帖 登录 | 注册

本版积分规则

84

主题

666

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部