你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

基于STM32的驱动MPU6050输出欧拉角经验分享

[复制链接]
攻城狮Melo 发布时间:2023-3-18 12:25
一.MPU6050介绍
1.MPU6050与陀螺仪、加速度计的关系:

MPU6050是InvenSense公司推出的一款全球首款的整合性9轴运动处理传感器,其最大的特色就是:消除了陀螺仪和加速度计的误差,将陀螺仪和加速度计组合在一起,而且缩小了空间。

2.整体概括

MPU6050内部整合了三轴MEMS陀螺仪、三轴MEMS加速度计以及一个可扩展的数字运动处理器DMP,而且还可以连接一个第三方数字传感器(比如:磁力计),这样的话,就可以通过IIC接口输出一个9轴信号。
更加方便的是,有了DMP,可以结合InvenSense公司提供的运动处理资料库,实现姿态解算。通过自带的DMP,可以通过IIC接口输出9轴融合演算的数据,大大降低了运动处理运算对操作系统的负荷,同时也降低了开发难度。

特点
① 以数字形式输出 6 轴或 9 轴(需外接磁传感器)的旋转矩阵、四元数(quaternion)、欧
拉角格式(Euler Angle forma)的融合演算数据(需 DMP 支持)
② 具有 131 LSBs/° /sec 敏感度与全格感测范围为±250、±500、±1000 与±2000° /sec
的 3 轴角速度感测器(陀螺仪)
③ 集成可程序控制,范围为±2g、±4g、±8g 和±16g 的 3 轴加速度传感器
④ 移除加速器与陀螺仪轴间敏感度,降低设定给予的影响与感测器的飘移
⑤ 自带数字运动处理(DMP: Digital Motion Processing)引擎可减少 MCU 复杂的融合演算
数据、感测器同步化、姿势感应等的负荷
⑥ 内建运作时间偏差与磁力感测器校正演算技术,免除了客户须另外进行校正的需求
⑦ 自带一个数字温度传感器
⑧ 带数字输入同步引脚(Sync pin)支持视频电子影相稳定技术与 GPS
⑨ 可程序控制的中断(interrupt),支持姿势识别、摇摄、画面放大缩小、滚动、快速下降
中断、 high-G 中断、零动作感应、触击感应、摇动感应功能
⑩ VDD 供电电压为 2.5V±5%、 3.0V±5%、 3.3V±5%; VLOGIC 可低至 1.8V± 5%
⑪ 陀螺仪工作电流: 5mA,陀螺仪待机电流: 5uA; 加速器工作电流: 500uA,加速器省
电模式电流: 40uA@10Hz
⑫ 自带 1024 字节 FIFO,有助于降低系统功耗
⑬ 高达 400Khz 的 IIC 通信接口
⑭ 超小封装尺寸: 4x4x0.9mm(QFN)

其检测轴如图所示:

20200215154932517.png


3.引脚说明

20200215160046383.jpg

如图,MPU6050一共有8个引脚,实际上输出六轴数据时,只用了5个:VCC、GND、SCL、SDA、AD0。下面介绍一下引脚:
VCC:供电,3.3V即可
GND:接地
SCL:连接MCU的IIC时钟接口
SAD:连接MCU的IIC数据接口
XCL:连接外部设备的IIC时钟接口
XAD:连接外部设备的IIC数据接口
AD0:地址控制引脚(控制地址的最低位)
INT:中断触发接口(不用)
XCL、XDA只有在连接外部设备(比如磁力计的时候才用),AD0用来控制MPU6050的地址,如果AD0低电平,地址就是0X68;如果AD0高电平,地址就是0X69。

4.基本配置及相关寄存器
MCU与MPU6050的通信是建立在IIC通信机制上的,在IIC的基础上,可以实现对MPU6050的寄存器的操作,而MPU6050的运作就是过对寄存器进行读写。所以,了解相关的寄存器和对寄存器的操作是很有必要的。MPU6050的寄存器相关资料都可以在数据手册中查到,下面介绍一下几个重要的寄存器:

电源管理寄存器1
地址:0X68


20200215163434244.png

主要位的功能:
DEVICE_RESET:控制复位,1表示复位,复位后会自动清零;
SLEEP:控制MPU6050工作模式,1表示睡眠模式,0表示正常工作模式,复位后改位为1,要手动将改位清零;
TEMP_DIS:使能温度传感器位,0代表使能;
CLKSEL[2:0]:选择系统时钟源,一般采用PLL_X轴陀螺作为参考,具体的时钟源选择及相应位的值如图:


20200215164457650.png

陀螺仪配置寄存器
地址:0X1B

20200215164757727.png

主要位的功能:
FS_SEL[1:0]:设置陀螺仪满量程范围:为0代表±250° /S、为1代表±500° /S、为2代表±1000° /S为3代表±2000° /S;

陀螺仪的分辨率是16位,所以在最大量程下灵敏度为: 65536/4000=16.4LSB/(° /S)。

加速度计配置寄存器
地址:0X1C

20200215165411152.png

主要位的功能:
AFS_SEL[1:0]:设置加速度计满量程范围:为 0代表±2g、为1代表±4g、为 2代表±8g、为 3代表±16g;

FIFO使能寄存器
地址:0X23

20200215165816272.png

用来控制FIFO功能,相应位对应着相应的传感器FIFO功能,为0代表禁止,为1代表使能。注意:加速度传感器的三个轴的FIFO功能由一个位ACCEL_FIFO_EN控制。在简单读取传感器数据的情况下可以不使用FIFO。

陀螺仪采样率分频寄存器
地址:0X19

20200215170242372.png

改寄存器用来设置MPU6050陀螺仪的采样频率,与之相关的是陀螺仪的输出频率,俩者关系是:采样频率 = 陀螺仪输出频率 / (1+SMPLRT_DIV)
陀螺仪输出频率与数字低通滤波器(DLPF)有关,DLPF滤波频率一般设置为采样率的一半。

温度传感器寄存器
地址:高八位0X41、低八位0X42
直接通过读取寄存器中的值来得到温度数据,温度换算公式为:
Temperature = 36.53 + regval/340

二.代码详解
1.框架

我是用STM32驱动MPU6050,MPU6050输出原始的六轴数据,经过DMP处理(有库)得到四元数,再由四元数算出欧拉角:yaw、roll、pitch。由串口打印在电脑屏幕上。
首先,要做底层的IIC驱动,用来和MPU6050建立通信,我在mpu_iic.c中实现了;
然后,有了底层的驱动,就要写一些函数来与MPU6050交流了(通过读写寄存器),还可以写入命令、配置MPU6050、读取原始数据等等,这些操作我都写在mpu6050.c中,当然在mpu6050.h头文件中还包含了MPU各寄存器地址和相关指令。
通过mpu6050.c的实现,就可以读出原始六轴数据,下一步就是通过DMP将原始数据转换为四元数,这一步的DMP算法我水平有限,只能移植InvenSense公司提供的例程。关于移植DMP算法,由于DMP算法本质也是对MPU6050的操作,所以我们只需要向移植过来的算法提供:对MPU6050寄存器执行读和写的函数接口即可,最后通过移植过来的函数直接读出四元数!
然后,就是将四元数转换为欧拉角了,这个比较简单,一个函数就可以实现。
最后,打印串口到屏幕。

下面给出各函数文件

2.mpu_iic.c/mpu_iic.h
mpu_iic.h
主要是宏定义对引脚电平的操作和进行函数声明。
  1. #ifndef __MPU_IIC_H
  2. #define __MPU_IIC_H

  3. #include "stm32f10x.h"
  4. #include "delay.h"

  5. /* 宏定义引脚电平操作函数 */
  6. #define MPU_SDA_IN()  {GPIOB->CRH&=0XFFFF0FFF;GPIOB->CRH|=8<<12;}
  7. #define MPU_SDA_OUT() {GPIOB->CRH&=0XFFFF0FFF;GPIOB->CRH|=3<<12;}  


  8. #define MPU_IIC_SDA_1() GPIO_SetBits( GPIOB, GPIO_Pin_11 )
  9. #define MPU_IIC_SDA_0() GPIO_ResetBits( GPIOB, GPIO_Pin_11 )

  10. #define MPU_IIC_SCL_1() GPIO_SetBits( GPIOB, GPIO_Pin_10 )
  11. #define MPU_IIC_SCL_0() GPIO_ResetBits( GPIOB, GPIO_Pin_10 )

  12. #define MPU_IIC_AD0_1() GPIO_SetBits( GPIOA, GPIO_Pin_15 )
  13. #define MPU_IIC_AD0_0() GPIO_ResetBits( GPIOA, GPIO_Pin_15 )

  14. #define MPU_IIC_SDA_READ() GPIO_ReadInputDataBit( GPIOB, GPIO_Pin_11 )

  15. #define MPU_IIC_Delay() delay_us(2)

  16. /* 函数声明 */
  17. void MPU_IIC_Init( void );
  18. void MPU_IIC_Start( void );
  19. void MPU_IIC_Stop( void );
  20. uint8_t MPU_IIC_Wait_Ack( void );
  21. void MPU_IIC_Ack( void );
  22. void MPU_IIC_NAck( void );
  23. void MPU_IIC_Send_Byte( uint8_t data );
  24. uint8_t MPU_IIC_Read_Byte( uint8_t ack );

  25. #endif

复制代码

mpu_iic.c
通过软件模拟IIC的代码,没什么好说的。
  1. #include "mpu_iic.h"
  2. #include "usart.h"

  3. /*
  4. IIC接口引脚配置
  5. SDA:PB11
  6. SCL:PB10
  7. AD0:PB2
  8. */
  9. void MPU_IIC_Init( void )
  10. {
  11.         GPIO_InitTypeDef  GPIO_InitStruct;
  12.        
  13.         RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );
  14.        
  15.         GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  16.         GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
  17.         GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11;
  18.         GPIO_Init( GPIOB, &GPIO_InitStruct );
  19.        
  20.         MPU_IIC_SDA_1();
  21.         MPU_IIC_SCL_1();

  22. }


  23. void MPU_IIC_Start( void )
  24. {
  25.         MPU_SDA_OUT();
  26.        
  27.         MPU_IIC_SDA_1();
  28.         MPU_IIC_SCL_1();
  29.         delay_us(2);
  30.         MPU_IIC_SDA_0();
  31.         delay_us(2);
  32.         MPU_IIC_SCL_0();
  33. }

  34. void MPU_IIC_Stop( void )
  35. {
  36.         MPU_SDA_OUT();
  37.        
  38.         MPU_IIC_SDA_0();
  39.         MPU_IIC_SCL_1();
  40.         delay_us(2);
  41.         MPU_IIC_SDA_1();
  42.         MPU_IIC_SCL_1();
  43.         delay_us(2);
  44.        
  45. }

  46. /* 由从设备在SCL为高电平的时候拉低SDA作为应答
  47. 返回值:1:未应答
  48.         0:已应答
  49. */
  50. uint8_t MPU_IIC_Wait_Ack( void )
  51. {
  52.         uint8_t count;
  53.         MPU_SDA_IN();
  54.        
  55.         MPU_IIC_SCL_1();
  56.         delay_us(2);
  57.         MPU_IIC_SDA_1();
  58.         delay_us(2);
  59.        
  60.         while( MPU_IIC_SDA_READ()==1 )
  61.         {
  62.                 count++;
  63.                 if( count>250 )
  64.                 {
  65.                         MPU_IIC_Stop();
  66.                         return 1;
  67.                 }
  68.         }       
  69.         MPU_IIC_SCL_0();
  70.         return 0;
  71. }


  72. void MPU_IIC_Ack( void )
  73. {
  74.        
  75.         MPU_IIC_SCL_0();
  76.         MPU_SDA_OUT();
  77.         MPU_IIC_SDA_0();
  78.         delay_us(2);
  79.         MPU_IIC_SCL_1();
  80.         delay_us(2);
  81.         MPU_IIC_SCL_0();
  82.        
  83. }


  84. void MPU_IIC_NAck( void )
  85. {
  86.        
  87.        
  88.         MPU_IIC_SCL_0();
  89.         MPU_SDA_OUT();
  90.         MPU_IIC_SDA_1();
  91.         delay_us(2);
  92.         MPU_IIC_SCL_1();
  93.         delay_us(2);
  94.         MPU_IIC_SCL_0();
  95. }


  96. /* 发送一个字节数据,高位先行 */
  97. void MPU_IIC_Send_Byte( uint8_t data )
  98. {
  99.         uint8_t t;
  100.         MPU_SDA_OUT();
  101.        
  102.         MPU_IIC_SCL_0();
  103.         for( t=0;t<8;t++ )
  104.         {
  105.                 if( ((data&0x80)>>7)==1 )
  106.                         MPU_IIC_SDA_1();
  107.                 else
  108.                         MPU_IIC_SDA_0();
  109.                 data<<=1;
  110.                 MPU_IIC_SCL_1();
  111.                 delay_us(2);
  112.                 MPU_IIC_SCL_0();
  113.                 delay_us(2);
  114.         }
  115. }


  116. /* 读取一个字节,ack=1时,读取完成后主机发送应答 */
  117. uint8_t MPU_IIC_Read_Byte( uint8_t ack )
  118. {
  119.         uint8_t t,data=0;
  120.         MPU_SDA_IN();
  121.         for( t=0;t<8;t++ )
  122.         {
  123.                 MPU_IIC_SCL_0();
  124.                 delay_us(2);//等待SDA的变化
  125.                 MPU_IIC_SCL_1();
  126.                
  127.                 data<<=1;//必须在读取前面,因为之后一位读取后就不再移位
  128.                 if( MPU_IIC_SDA_READ()==1 )
  129.                         data++;
  130.                
  131.                 delay_us(2);//等待SDA的变化
  132.                
  133.         }

  134.         if( !ack )
  135.                 MPU_IIC_NAck();//发送nACK
  136.     else
  137.         MPU_IIC_Ack(); //发送ACK
  138.         return data;
  139. }


复制代码

3.mpu6050.c/mpu6050.h
mpu6050.h
主要是定义MPU相关寄存器的地址,和进行函数声明。
  1. #ifndef __MPU6050_H
  2. #define __MPU6050_H

  3. #include "stm32f10x.h"
  4. #include "mpu_iic.h"


  5. /* AD0接地,MPU6050的IIC地址为0x68   接3.3V就为0x69*/
  6. #define MPU_ADDR                                0X68

  7. /************** MPU6050相关寄存器地址 *********************/
  8. #define MPU_ACCEL_OFFS_REG                0X06        //accel_offs寄存器,可读取版本号,寄存器手册未提到
  9. #define MPU_PROD_ID_REG                        0X0C        //prod id寄存器,在寄存器手册未提到
  10. #define MPU_SELF_TESTX_REG                0X0D        //自检寄存器X
  11. #define MPU_SELF_TESTY_REG                0X0E        //自检寄存器Y
  12. #define MPU_SELF_TESTZ_REG                0X0F        //自检寄存器Z
  13. #define MPU_SELF_TESTA_REG                0X10        //自检寄存器A
  14. #define MPU_SAMPLE_RATE_REG                0X19        //采样频率分频器
  15. #define MPU_CFG_REG                                0X1A        //配置寄存器
  16. #define MPU_GYRO_CFG_REG                0X1B        //陀螺仪配置寄存器
  17. #define MPU_ACCEL_CFG_REG                0X1C        //加速度计配置寄存器
  18. #define MPU_MOTION_DET_REG                0X1F        //运动检测阀值设置寄存器
  19. #define MPU_FIFO_EN_REG                        0X23        //FIFO使能寄存器
  20. #define MPU_I2CMST_CTRL_REG                0X24        //IIC主机控制寄存器
  21. #define MPU_I2CSLV0_ADDR_REG        0X25        //IIC从机0器件地址寄存器
  22. #define MPU_I2CSLV0_REG                        0X26        //IIC从机0数据地址寄存器
  23. #define MPU_I2CSLV0_CTRL_REG        0X27        //IIC从机0控制寄存器
  24. #define MPU_I2CSLV1_ADDR_REG        0X28        //IIC从机1器件地址寄存器
  25. #define MPU_I2CSLV1_REG                        0X29        //IIC从机1数据地址寄存器
  26. #define MPU_I2CSLV1_CTRL_REG        0X2A        //IIC从机1控制寄存器
  27. #define MPU_I2CSLV2_ADDR_REG        0X2B        //IIC从机2器件地址寄存器
  28. #define MPU_I2CSLV2_REG                        0X2C        //IIC从机2数据地址寄存器
  29. #define MPU_I2CSLV2_CTRL_REG        0X2D        //IIC从机2控制寄存器
  30. #define MPU_I2CSLV3_ADDR_REG        0X2E        //IIC从机3器件地址寄存器
  31. #define MPU_I2CSLV3_REG                        0X2F        //IIC从机3数据地址寄存器
  32. #define MPU_I2CSLV3_CTRL_REG        0X30        //IIC从机3控制寄存器
  33. #define MPU_I2CSLV4_ADDR_REG        0X31        //IIC从机4器件地址寄存器
  34. #define MPU_I2CSLV4_REG                        0X32        //IIC从机4数据地址寄存器
  35. #define MPU_I2CSLV4_DO_REG                0X33        //IIC从机4写数据寄存器
  36. #define MPU_I2CSLV4_CTRL_REG        0X34        //IIC从机4控制寄存器
  37. #define MPU_I2CSLV4_DI_REG                0X35        //IIC从机4读数据寄存器

  38. #define MPU_I2CMST_STA_REG                0X36        //IIC主机状态寄存器
  39. #define MPU_INTBP_CFG_REG                0X37        //中断/旁路设置寄存器
  40. #define MPU_INT_EN_REG                        0X38        //中断使能寄存器
  41. #define MPU_INT_STA_REG                        0X3A        //中断状态寄存器

  42. #define MPU_ACCEL_XOUTH_REG                0X3B        //加速度值,X轴高8位寄存器
  43. #define MPU_ACCEL_XOUTL_REG                0X3C        //加速度值,X轴低8位寄存器
  44. #define MPU_ACCEL_YOUTH_REG                0X3D        //加速度值,Y轴高8位寄存器
  45. #define MPU_ACCEL_YOUTL_REG                0X3E        //加速度值,Y轴低8位寄存器
  46. #define MPU_ACCEL_ZOUTH_REG                0X3F        //加速度值,Z轴高8位寄存器
  47. #define MPU_ACCEL_ZOUTL_REG                0X40        //加速度值,Z轴低8位寄存器

  48. #define MPU_TEMP_OUTH_REG                0X41        //温度值高八位寄存器
  49. #define MPU_TEMP_OUTL_REG                0X42        //温度值低8位寄存器

  50. #define MPU_GYRO_XOUTH_REG                0X43        //陀螺仪值,X轴高8位寄存器
  51. #define MPU_GYRO_XOUTL_REG                0X44        //陀螺仪值,X轴低8位寄存器
  52. #define MPU_GYRO_YOUTH_REG                0X45        //陀螺仪值,Y轴高8位寄存器
  53. #define MPU_GYRO_YOUTL_REG                0X46        //陀螺仪值,Y轴低8位寄存器
  54. #define MPU_GYRO_ZOUTH_REG                0X47        //陀螺仪值,Z轴高8位寄存器
  55. #define MPU_GYRO_ZOUTL_REG                0X48        //陀螺仪值,Z轴低8位寄存器

  56. #define MPU_I2CSLV0_DO_REG                0X63        //IIC从机0数据寄存器
  57. #define MPU_I2CSLV1_DO_REG                0X64        //IIC从机1数据寄存器
  58. #define MPU_I2CSLV2_DO_REG                0X65        //IIC从机2数据寄存器
  59. #define MPU_I2CSLV3_DO_REG                0X66        //IIC从机3数据寄存器

  60. #define MPU_I2CMST_DELAY_REG        0X67        //IIC主机延时管理寄存器
  61. #define MPU_SIGPATH_RST_REG                0X68        //信号通道复位寄存器
  62. #define MPU_MDETECT_CTRL_REG        0X69        //运动检测控制寄存器
  63. #define MPU_USER_CTRL_REG                0X6A        //用户控制寄存器
  64. #define MPU_PWR_MGMT1_REG                0X6B        //电源管理寄存器1
  65. #define MPU_PWR_MGMT2_REG                0X6C        //电源管理寄存器2
  66. #define MPU_FIFO_CNTH_REG                0X72        //FIFO计数寄存器高八位
  67. #define MPU_FIFO_CNTL_REG                0X73        //FIFO计数寄存器低八位
  68. #define MPU_FIFO_RW_REG                        0X74        //FIFO读写寄存器
  69. #define MPU_DEVICE_ID_REG                0X75        //器件ID寄存器




  70. /* 函数声明 */
  71. uint8_t MPU_Read_Byte( uint8_t reg );
  72. uint8_t MPU_Write_Byte( uint8_t reg, uint8_t data );
  73. uint8_t MPU_Read_Continue( uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf );
  74. uint8_t MPU_Write_Continue( uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf );

  75. uint8_t MPU_Init( void );


  76. uint8_t MPU_Set_Gyro_Fsr( uint8_t fsr );
  77. uint8_t MPU_Set_Accel_Fsr( uint8_t fsr );
  78. uint8_t MPU_Set_LPF( uint16_t lpf );
  79. uint8_t MPU_Set_Rate( uint16_t rate );
  80. short MPU_Get_Temperature( void );
  81. uint8_t MPU_Get_Gyroscope( short *gx, short *gy, short *gz );
  82. uint8_t MPU_Get_Accelerometer( short *ax, short *ay, short *az );

  83. #endif

复制代码

mpu6050.c
最为重要的一部分代码,包括了对MPU6050的一系列基本配置和读取原始数据的操作,代码都注解的很详细了。
AD0引脚用了PA15,所以要GPIO_Remap_SWJ_JTAGDisable,换个引脚也可以。
  1. #ifndef __MPU6050_H
  2. #define __MPU6050_H

  3. #include "stm32f10x.h"
  4. #include "mpu_iic.h"


  5. /* AD0接地,MPU6050的IIC地址为0x68   接3.3V就为0x69*/
  6. #define MPU_ADDR                                0X68

  7. /************** MPU6050相关寄存器地址 *********************/
  8. #define MPU_ACCEL_OFFS_REG                0X06        //accel_offs寄存器,可读取版本号,寄存器手册未提到
  9. #define MPU_PROD_ID_REG                        0X0C        //prod id寄存器,在寄存器手册未提到
  10. #define MPU_SELF_TESTX_REG                0X0D        //自检寄存器X
  11. #define MPU_SELF_TESTY_REG                0X0E        //自检寄存器Y
  12. #define MPU_SELF_TESTZ_REG                0X0F        //自检寄存器Z
  13. #define MPU_SELF_TESTA_REG                0X10        //自检寄存器A
  14. #define MPU_SAMPLE_RATE_REG                0X19        //采样频率分频器
  15. #define MPU_CFG_REG                                0X1A        //配置寄存器
  16. #define MPU_GYRO_CFG_REG                0X1B        //陀螺仪配置寄存器
  17. #define MPU_ACCEL_CFG_REG                0X1C        //加速度计配置寄存器
  18. #define MPU_MOTION_DET_REG                0X1F        //运动检测阀值设置寄存器
  19. #define MPU_FIFO_EN_REG                        0X23        //FIFO使能寄存器
  20. #define MPU_I2CMST_CTRL_REG                0X24        //IIC主机控制寄存器
  21. #define MPU_I2CSLV0_ADDR_REG        0X25        //IIC从机0器件地址寄存器
  22. #define MPU_I2CSLV0_REG                        0X26        //IIC从机0数据地址寄存器
  23. #define MPU_I2CSLV0_CTRL_REG        0X27        //IIC从机0控制寄存器
  24. #define MPU_I2CSLV1_ADDR_REG        0X28        //IIC从机1器件地址寄存器
  25. #define MPU_I2CSLV1_REG                        0X29        //IIC从机1数据地址寄存器
  26. #define MPU_I2CSLV1_CTRL_REG        0X2A        //IIC从机1控制寄存器
  27. #define MPU_I2CSLV2_ADDR_REG        0X2B        //IIC从机2器件地址寄存器
  28. #define MPU_I2CSLV2_REG                        0X2C        //IIC从机2数据地址寄存器
  29. #define MPU_I2CSLV2_CTRL_REG        0X2D        //IIC从机2控制寄存器
  30. #define MPU_I2CSLV3_ADDR_REG        0X2E        //IIC从机3器件地址寄存器
  31. #define MPU_I2CSLV3_REG                        0X2F        //IIC从机3数据地址寄存器
  32. #define MPU_I2CSLV3_CTRL_REG        0X30        //IIC从机3控制寄存器
  33. #define MPU_I2CSLV4_ADDR_REG        0X31        //IIC从机4器件地址寄存器
  34. #define MPU_I2CSLV4_REG                        0X32        //IIC从机4数据地址寄存器
  35. #define MPU_I2CSLV4_DO_REG                0X33        //IIC从机4写数据寄存器
  36. #define MPU_I2CSLV4_CTRL_REG        0X34        //IIC从机4控制寄存器
  37. #define MPU_I2CSLV4_DI_REG                0X35        //IIC从机4读数据寄存器

  38. #define MPU_I2CMST_STA_REG                0X36        //IIC主机状态寄存器
  39. #define MPU_INTBP_CFG_REG                0X37        //中断/旁路设置寄存器
  40. #define MPU_INT_EN_REG                        0X38        //中断使能寄存器
  41. #define MPU_INT_STA_REG                        0X3A        //中断状态寄存器

  42. #define MPU_ACCEL_XOUTH_REG                0X3B        //加速度值,X轴高8位寄存器
  43. #define MPU_ACCEL_XOUTL_REG                0X3C        //加速度值,X轴低8位寄存器
  44. #define MPU_ACCEL_YOUTH_REG                0X3D        //加速度值,Y轴高8位寄存器
  45. #define MPU_ACCEL_YOUTL_REG                0X3E        //加速度值,Y轴低8位寄存器
  46. #define MPU_ACCEL_ZOUTH_REG                0X3F        //加速度值,Z轴高8位寄存器
  47. #define MPU_ACCEL_ZOUTL_REG                0X40        //加速度值,Z轴低8位寄存器

  48. #define MPU_TEMP_OUTH_REG                0X41        //温度值高八位寄存器
  49. #define MPU_TEMP_OUTL_REG                0X42        //温度值低8位寄存器

  50. #define MPU_GYRO_XOUTH_REG                0X43        //陀螺仪值,X轴高8位寄存器
  51. #define MPU_GYRO_XOUTL_REG                0X44        //陀螺仪值,X轴低8位寄存器
  52. #define MPU_GYRO_YOUTH_REG                0X45        //陀螺仪值,Y轴高8位寄存器
  53. #define MPU_GYRO_YOUTL_REG                0X46        //陀螺仪值,Y轴低8位寄存器
  54. #define MPU_GYRO_ZOUTH_REG                0X47        //陀螺仪值,Z轴高8位寄存器
  55. #define MPU_GYRO_ZOUTL_REG                0X48        //陀螺仪值,Z轴低8位寄存器

  56. #define MPU_I2CSLV0_DO_REG                0X63        //IIC从机0数据寄存器
  57. #define MPU_I2CSLV1_DO_REG                0X64        //IIC从机1数据寄存器
  58. #define MPU_I2CSLV2_DO_REG                0X65        //IIC从机2数据寄存器
  59. #define MPU_I2CSLV3_DO_REG                0X66        //IIC从机3数据寄存器

  60. #define MPU_I2CMST_DELAY_REG        0X67        //IIC主机延时管理寄存器
  61. #define MPU_SIGPATH_RST_REG                0X68        //信号通道复位寄存器
  62. #define MPU_MDETECT_CTRL_REG        0X69        //运动检测控制寄存器
  63. #define MPU_USER_CTRL_REG                0X6A        //用户控制寄存器
  64. #define MPU_PWR_MGMT1_REG                0X6B        //电源管理寄存器1
  65. #define MPU_PWR_MGMT2_REG                0X6C        //电源管理寄存器2
  66. #define MPU_FIFO_CNTH_REG                0X72        //FIFO计数寄存器高八位
  67. #define MPU_FIFO_CNTL_REG                0X73        //FIFO计数寄存器低八位
  68. #define MPU_FIFO_RW_REG                        0X74        //FIFO读写寄存器
  69. #define MPU_DEVICE_ID_REG                0X75        //器件ID寄存器




  70. /* 函数声明 */
  71. uint8_t MPU_Read_Byte( uint8_t reg );
  72. uint8_t MPU_Write_Byte( uint8_t reg, uint8_t data );
  73. uint8_t MPU_Read_Continue( uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf );
  74. uint8_t MPU_Write_Continue( uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf );

  75. uint8_t MPU_Init( void );


  76. uint8_t MPU_Set_Gyro_Fsr( uint8_t fsr );
  77. uint8_t MPU_Set_Accel_Fsr( uint8_t fsr );
  78. uint8_t MPU_Set_LPF( uint16_t lpf );
  79. uint8_t MPU_Set_Rate( uint16_t rate );
  80. short MPU_Get_Temperature( void );
  81. uint8_t MPU_Get_Gyroscope( short *gx, short *gy, short *gz );
  82. uint8_t MPU_Get_Accelerometer( short *ax, short *ay, short *az );

  83. #endif

复制代码

4.DMP相关代码
要想使用DMP求欧拉角的代码,包含下面这几个文件即可,下面列出接口函数,到时候使用时直接使用接口函数即可。

20200215175340295.png

向DMP算法提供的接口宏定义
只需要提供:对MPU6050的读写操作函数和延时函数即可
  1. #define i2c_write   MPU_Write_Continue
  2. #define i2c_read    MPU_Read_Continue
  3. #define delay_ms    delay_ms
复制代码

DMP初始化
  1. //mpu6050,dmp初始化
  2. //返回值:0,正常
  3. //    其他,失败
  4. uint8_t mpu_dmp_init(void)
  5. {
  6.         uint8_t res=0;
  7.         MPU_IIC_Init();         //初始化IIC总线
  8.         if(mpu_init()==0)        //初始化MPU6050
  9.         {         
  10.                 res=mpu_set_sensors(INV_XYZ_GYRO|INV_XYZ_ACCEL);//设置所需要的传感器
  11.                 if(res)return 1;
  12.                 res=mpu_configure_fifo(INV_XYZ_GYRO|INV_XYZ_ACCEL);//设置FIFO
  13.                 if(res)return 2;
  14.                 res=mpu_set_sample_rate(DEFAULT_MPU_HZ);        //设置采样率
  15.                 if(res)return 3;
  16.                 res=dmp_load_motion_driver_firmware();                //加载dmp固件
  17.                 if(res)return 4;
  18.                 res=dmp_set_orientation(inv_orientation_matrix_to_scalar(gyro_orientation));//设置陀螺仪方向
  19.                 if(res)return 5;
  20.                 res=dmp_enable_feature(DMP_FEATURE_6X_LP_QUAT|DMP_FEATURE_TAP|        //设置dmp功能
  21.                     DMP_FEATURE_ANDROID_ORIENT|DMP_FEATURE_SEND_RAW_ACCEL|DMP_FEATURE_SEND_CAL_GYRO|
  22.                     DMP_FEATURE_GYRO_CAL);
  23.                 if(res)return 6;
  24.                 res=dmp_set_fifo_rate(DEFAULT_MPU_HZ);        //设置DMP输出速率(最大不超过200Hz)
  25.                 if(res)return 7;   
  26.                 res=run_self_test();                //自检
  27.                 if(res)return 8;   
  28.                 res=mpu_set_dmp_state(1);        //使能DMP
  29.                 if(res)return 9;     
  30.         }else return 10;
  31.         return 0;
  32. }
复制代码

获取欧拉角
  1. //得到dmp处理后的数据(注意,本函数需要比较多堆栈,局部变量有点多)
  2. //pitch:俯仰角 精度:0.1°   范围:-90.0° <---> +90.0°
  3. //roll:横滚角  精度:0.1°   范围:-180.0°<---> +180.0°
  4. //yaw:航向角   精度:0.1°   范围:-180.0°<---> +180.0°
  5. //返回值:0,正常
  6. //    其他,失败
  7. uint8_t mpu_dmp_get_data(float *pitch,float *roll,float *yaw)
  8. {
  9.         float q0=1.0f,q1=0.0f,q2=0.0f,q3=0.0f;
  10.         unsigned long sensor_timestamp;
  11.         short gyro[3], accel[3], sensors;
  12.         unsigned char more;
  13.         long quat[4];
  14.         if(dmp_read_fifo(gyro, accel, quat, &sensor_timestamp, &sensors,&more))return 1;         
  15.         /* Gyro and accel data are written to the FIFO by the DMP in chip frame and hardware units.
  16.          * This behavior is convenient because it keeps the gyro and accel outputs of dmp_read_fifo and mpu_read_fifo consistent.
  17.         **/
  18.         /*if (sensors & INV_XYZ_GYRO )
  19.         send_packet(PACKET_TYPE_GYRO, gyro);
  20.         if (sensors & INV_XYZ_ACCEL)
  21.         send_packet(PACKET_TYPE_ACCEL, accel); */
  22.         /* Unlike gyro and accel, quaternions are written to the FIFO in the body frame, q30.
  23.          * The orientation is set by the scalar passed to dmp_set_orientation during initialization.
  24.         **/
  25.         if(sensors&INV_WXYZ_QUAT)
  26.         {
  27.                 q0 = quat[0] / q30;        //q30格式转换为浮点数
  28.                 q1 = quat[1] / q30;
  29.                 q2 = quat[2] / q30;
  30.                 q3 = quat[3] / q30;
  31.                 //计算得到俯仰角/横滚角/航向角
  32.                 *pitch = asin(-2 * q1 * q3 + 2 * q0* q2)* 57.3;        // pitch
  33.                 *roll  = atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2* q2 + 1)* 57.3;        // roll
  34.                 *yaw   = atan2(2*(q1*q2 + q0*q3),q0*q0+q1*q1-q2*q2-q3*q3) * 57.3;        //yaw
  35.         }else return 2;
  36.         return 0;
  37. }

复制代码

5.mian()函数
主函数中对MPU6050进行初始化后,对DMP也进行初始化,然后就可以直接使用mpu_dmp_get_data()获取欧拉角,还可以获取温度值。
  1. #include "stm32f10x.h"   
  2. #include "usart.h"
  3. #include "delay.h"
  4. #include "mpu6050.h"
  5. #include "inv_mpu.h"
  6. #include "inv_mpu_dmp_motion_driver.h"

  7. int main(void)
  8. {
  9.         uint8_t x=0;
  10.         float pitch,roll,yaw;                 //欧拉角
  11.         short aacx,aacy,aacz;                //加速度传感器原始数据
  12.         short gyrox,gyroy,gyroz;        //陀螺仪原始数据
  13.         short temp;                                        //温度
  14.        
  15.         NVIC_PriorityGroupConfig( 2 );
  16.         delay_init();
  17.         USART1_Init(115200);       
  18.         printf("程序开始\n");
  19.        
  20.         if( MPU_Init()!=0 )
  21.         {
  22.                 printf("MPU6050初始化错误!\n");
  23.                 return 0;
  24.         }
  25.                
  26.         if( mpu_dmp_init() )
  27.         {
  28.                 printf("DMP初始化错误!\n");
  29.                 return 0;
  30.         }
  31.         while(1)
  32.         {
  33.                 if(mpu_dmp_get_data(&pitch,&roll,&yaw)==0)
  34.                 {
  35.                         temp=MPU_Get_Temperature();        //得到温度值
  36.                         MPU_Get_Accelerometer(&aacx,&aacy,&aacz);        //得到加速度传感器数据
  37.                         MPU_Get_Gyroscope(&gyrox,&gyroy,&gyroz);        //得到陀螺仪数据
  38.                 }
  39.                 delay_ms(100);
  40.                 printf("pitch:%02f  roll:%02f  yaw:%02f\n",pitch,roll,yaw);
  41.         }

  42. }
复制代码

这就是我理解的MPU6050,后续做平衡小车的时候要读取欧拉角,先总结一下
————————————————
版权声明:Aspirant-GQ
如有侵权请联系删除


收藏 评论0 发布时间:2023-3-18 12:25

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版