当前位置:   article > 正文

MPU6050(读取原数据、移植DMP、stm32f4、HAL库、KEIL5)_mpu6050 dmp库

mpu6050 dmp库

记录一下自己遇到的问题及解决方法,希望能帮助到一些人。

第一步,读取芯片的原始数据。需要注意两点:1、对HAL库提供的IIC读取写入函数进行再包装。(千万不要觉的这步多此一举,后面移植DMP时用得到)

  1. /**
  2. * @brief 写寄存器,这是提供给上层的接口
  3. * @param slave_addr: 从机地址
  4. * @param reg_addr: 寄存器地址
  5. * @param len:写入的长度
  6. * @param data_ptr: 指向要写入的数据
  7. * @retval 正常为 0,不正常为非 0
  8. */
  9. int Sensors_I2C_WriteRegister(unsigned char slave_addr,
  10. unsigned char reg_addr,
  11. unsigned short len,
  12. unsigned char *data_ptr){
  13. HAL_StatusTypeDef status = HAL_OK;
  14. status = HAL_I2C_Mem_Write(&I2C_Handle,slave_addr,reg_addr,
  15. I2C_MEMADD_SIZE_8BIT,data_ptr,len,I2Cx_FLAG_TIMEOUT);
  16. if(status != HAL_OK){
  17. }
  18. while (HAL_I2C_GetState(&I2C_Handle) != HAL_I2C_STATE_READY) {
  19. }
  20. /* 检查 SENSOR 是否就绪进行下一次读写操作 */
  21. while (HAL_I2C_IsDeviceReady(&I2C_Handle, slave_addr,
  22. I2Cx_FLAG_TIMEOUT, I2Cx_FLAG_TIMEOUT) == HAL_TIMEOUT);
  23. /* 等待传输结束 */
  24. while (HAL_I2C_GetState(&I2C_Handle) != HAL_I2C_STATE_READY) {
  25. }
  26. return status;
  27. }
  28. /**
  29. * @brief 读寄存器,这是提供给上层的接口
  30. * @param slave_addr: 从机地址
  31. * @param reg_addr: 寄存器地址
  32. * @param len:要读取的长度
  33. * @param data_ptr: 指向要存储数据的指针
  34. * @retval 正常为 0,不正常为非 0
  35. */
  36. int Sensors_I2C_ReadRegister(unsigned char slave_addr,
  37. unsigned char reg_addr,
  38. unsigned short len,
  39. unsigned char *data_ptr){
  40. HAL_StatusTypeDef status = HAL_OK;
  41. status =HAL_I2C_Mem_Read(&I2C_Handle,slave_addr
  42. ,reg_addr,I2C_MEMADD_SIZE_8BIT,data_ptr,len,I2Cx_FLAG_TIMEOUT);
  43. if (status != HAL_OK) {/* 检查通讯状态 */
  44. }
  45. while (HAL_I2C_GetState(&I2C_Handle) != HAL_I2C_STATE_READY) {
  46. }
  47. /* 检查 SENSOR 是否就绪进行下一次读写操作 */
  48. while (HAL_I2C_IsDeviceReady(&I2C_Handle, slave_addr,
  49. I2Cx_FLAG_TIMEOUT, I2Cx_FLAG_TIMEOUT) == HAL_TIMEOUT);
  50. /* 等待传输结束 */
  51. while (HAL_I2C_GetState(&I2C_Handle) != HAL_I2C_STATE_READY) {
  52. }
  53. return status;
  54. }

2、芯片的地址(这里面有俩坑)第一就是,芯片的 I2C 设备地址可通过 AD0 引脚的电平控制,当 AD0 接地时,设 备地址为 0x68(七位地址),当 AD0 接电源时,设备地址为 0x69(七位地址)。第二就是,用HAL库需要将地址向左移一位,也就是0x68<<1,0x69<<1。

  1. // MPU6050, Standard address 0x68
  2. #define MPU6050_ADDRESS 0x68<<1

然后就没啥问题了,下面是我的代码

初始化MPU6050芯片

  1. /**
  2. * @brief 写数据到 MPU6050 寄存器
  3. * @param reg_add: 寄存器地址
  4. * @param reg_data: 要写入的数据
  5. * @retval
  6. */
  7. void MPU6050_WriteReg(uint8_t reg_add,uint8_t reg_dat){
  8. Sensors_I2C_WriteRegister(MPU6050_ADDRESS,reg_add,1,&reg_dat);
  9. }
  10. /**
  11. * @brief 从 MPU6050 寄存器读取数据
  12. * @param reg_add: 寄存器地址
  13. * @param Read:存储数据的缓冲区
  14. * @param num:要读取的数据量
  15. * @retval
  16. */
  17. void MPU6050_ReadData(uint8_t reg_add,unsigned char* Read,uint8_t num){
  18. Sensors_I2C_ReadRegister(MPU6050_ADDRESS,reg_add,num,Read);
  19. }
  20. /**
  21. * @brief 初始化 MPU6050 芯片
  22. * @param
  23. * @retval
  24. */
  25. void MPU6050_Init(void){
  26. //在初始化之前要延时一段时间,若没有延时,则断电后再上电数据可能会出错
  27. HAL_Delay(100);
  28. //解除休眠状态
  29. MPU6050_WriteReg(MPU6050_RA_PWR_MGMT_1, 0x00);
  30. //陀螺仪采样率
  31. MPU6050_WriteReg(MPU6050_RA_SMPLRT_DIV , 0x07);
  32. MPU6050_WriteReg(MPU6050_RA_CONFIG , 0x06);
  33. //配置加速度传感器工作在 16G 模式
  34. MPU6050_WriteReg(MPU6050_RA_ACCEL_CONFIG , 0x01);
  35. //陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s)
  36. MPU6050_WriteReg(MPU6050_RA_GYRO_CONFIG, 0x18);
  37. HAL_Delay(200);
  38. }
  39. /**
  40. * @brief 读取 MPU6050 的 ID
  41. * @param
  42. * @retval 正常返回 1,异常返回 0
  43. */
  44. uint8_t MPU6050ReadID(void){
  45. unsigned char Re = 0;
  46. MPU6050_ReadData(MPU6050_RA_WHO_AM_I,&Re,1); //读器件地址
  47. if (Re != 0x68) {
  48. printf("检测不到 MPU6050 模块,请检查模块与开发板的接线,------%d\r\n",Re);
  49. return 0;
  50. } else {
  51. printf("MPU6050 ID = %d\r\n",Re);
  52. return 1;
  53. }
  54. }

读取加速度、角加速度、温度的原始数据,并转化为摄氏度

  1. /**
  2. * @brief 读取 MPU6050 的加速度数据
  3. * @param
  4. * @retval
  5. */
  6. void MPU6050ReadAcc(short *accData){
  7. uint8_t buf[6];
  8. MPU6050_ReadData(MPU6050_ACC_OUT, buf, 6);
  9. accData[0] = (buf[0] << 8) | buf[1];
  10. accData[1] = (buf[2] << 8) | buf[3];
  11. accData[2] = (buf[4] << 8) | buf[5];
  12. }
  13. /**
  14. * @brief 读取 MPU6050 的角加速度数据
  15. * @param
  16. * @retval
  17. */
  18. void MPU6050ReadGyro(short *gyroData){
  19. uint8_t buf[6];
  20. MPU6050_ReadData(MPU6050_GYRO_OUT,buf,6);
  21. gyroData[0] = (buf[0] << 8) | buf[1];
  22. gyroData[1] = (buf[2] << 8) | buf[3];
  23. gyroData[2] = (buf[4] << 8) | buf[5];
  24. }
  25. /**
  26. * @brief 读取 MPU6050 的原始温度数据
  27. * @param
  28. * @retval
  29. */
  30. void MPU6050ReadTemp(short *tempData){
  31. uint8_t buf[2];
  32. MPU6050_ReadData(MPU6050_RA_TEMP_OUT_H,buf,2); //读取温度值
  33. *tempData = (buf[0] << 8) | buf[1];
  34. }
  35. /**
  36. * @brief 读取 MPU6050 的温度数据,转化成摄氏度
  37. * @param
  38. * @retval
  39. */
  40. void MPU6050_ReturnTemp(float*Temperature){
  41. short temp3;
  42. uint8_t buf[2];
  43. MPU6050_ReadData(MPU6050_RA_TEMP_OUT_H,buf,2); //读取温度值
  44. temp3= (buf[0] << 8) | buf[1];
  45. *Temperature=((double) (temp3 /340.0))+36.53;
  46. }

********然后就是重头戏了——DMP的移植!!!(真是恶心坏我了)

第一步,把官方文档中motion_driver_6.12\arm\STM32F4_MD6\Projects\eMD6\core的四个文件夹全复制过来,一个也不能少。

 然后再去官方文档motion_driver_6.12\mpl libraries\arm\Keil,解压你需要的静态库,我选的是第四个。(第四个和第五个有区别,具体问百度吧,我忘了)

 然后把解压好的静态库libmpllib.lib复制到刚才那四个文件夹中的mpl文件夹中,再把这个文件夹里面的libmpllib.a给删了。

然后打开Keil5,把刚才复制的.c文件全部加进来,包括静态库。不用分,直接搞一个group就行。

 接着把下面这三个宏定义加进去,并添加头文件路径。

  1. MPL_LOG_NDEBUG=1
  2. EMPL,MPU6050
  3. EMPL_TARGET_STM32F4

 接下来就是最恶心的——修改程序

  1. inv_mpu.c
  2. #include "i2c.h"
  3. #include "main.h"
  4. #include "log.h"
  5. //#include "board-st_discovery.h"//*****************
  6. //这两个文件是我创建的
  7. #include "bsp_i2c.h"//这个里面是讲HAL库中的IIC写入读取封装成Sensors_I2C_WriteRegister、Sensors_I2C_ReadRegister
  8. #include "bsp_mpu6050_dmp.h"//这里面有get_tick_count函数,还有MPU6050带DMP的初始化,以及四元数的读取函数
  9. #define i2c_write Sensors_I2C_WriteRegister
  10. #define i2c_read Sensors_I2C_ReadRegister
  11. #define delay_ms HAL_Delay//***************
  12. #define get_ms get_tick_count
  13. #define log_i printf//***************
  14. #define log_e printf//***************
  15. #define min(a,b) ((a<b)?a:b)
  1. inv_mpu_dmp_motion_driver.c
  2. #include "i2c.h"
  3. #include "main.h"
  4. //#include "board-st_discovery.h"//******************
  5. #include "bsp_i2c.h"
  6. #include "bsp_mpu6050_dmp.h"
  7. #define i2c_write Sensors_I2C_WriteRegister
  8. #define i2c_read Sensors_I2C_ReadRegister
  9. #define get_ms get_tick_count

创建bsp_mpu6050_dmp.h和bsp_mpu6050_dmp.c

  1. #ifndef __BSP_MPU6050_DMP_H__
  2. #define __BSP_MPU6050_DMP_H__
  3. #include "stm32f4xx.h"
  4. #include <stdio.h>
  5. #include <i2c.h>
  6. void gyro_data_ready_cb(void);
  7. int get_tick_count(unsigned long *count);
  8. uint8_t mpu_dmp_init(void);
  9. uint8_t mpu_dmp_get_data(float *pitch,float *roll,float *yaw);
  10. int fputcc(int ch);
  11. #endif
  1. #include "bsp_mpu6050_dmp.h"
  2. #include "usart.h"
  3. #include "i2c.h"
  4. #include "gpio.h"
  5. #include "main.h"
  6. #include "inv_mpu.h"
  7. #include "inv_mpu_dmp_motion_driver.h"
  8. #include "invensense.h"
  9. #include "invensense_adv.h"
  10. #include "eMPL_outputs.h"
  11. #include "mltypes.h"
  12. #include "mpu.h"
  13. #include "log.h"
  14. #include "packet.h"
  15. /* Private typedef -----------------------------------------------------------*/
  16. /* Data read from MPL. */
  17. #define PRINT_ACCEL (0x01)
  18. #define PRINT_GYRO (0x02)
  19. #define PRINT_QUAT (0x04)
  20. #define PRINT_COMPASS (0x08)
  21. #define PRINT_EULER (0x10)
  22. #define PRINT_ROT_MAT (0x20)
  23. #define PRINT_HEADING (0x40)
  24. #define PRINT_PEDO (0x80)
  25. #define PRINT_LINEAR_ACCEL (0x100)
  26. #define PRINT_GRAVITY_VECTOR (0x200)
  27. volatile uint32_t hal_timestamp = 0;
  28. #define ACCEL_ON (0x01)
  29. #define GYRO_ON (0x02)
  30. #define COMPASS_ON (0x04)
  31. #define MOTION (0)
  32. #define NO_MOTION (1)
  33. /* Starting sampling rate. */
  34. #define DEFAULT_MPU_HZ (100)
  35. #define FLASH_SIZE (512)
  36. #define FLASH_MEM_START ((void*)0x1800)
  37. #define PEDO_READ_MS (1000)
  38. #define TEMP_READ_MS (500)
  39. #define COMPASS_READ_MS (100)
  40. #define q30 1073741824.0f
  41. static signed char gyro_orientation[9] = { 1, 0, 0,
  42. 0, 1, 0,
  43. 0, 0, 1};
  44. int get_tick_count(unsigned long *count)
  45. {
  46. *count = HAL_GetTick();
  47. return 0;
  48. }
  49. int fputcc(int ch)
  50. {
  51. printf("%c",ch);
  52. // HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, 0xFF);
  53. return 0;
  54. }
  55. uint8_t run_self_test(void)
  56. {
  57. int result;
  58. long gyro[3], accel[3];
  59. result = mpu_run_self_test(gyro, accel);
  60. if (result == 0x07) { //返回0x03为MPU6050六轴,只要通过该if语句,就可以实现零偏自动校准
  61. /* Test passed. We can trust the gyro data here, so let's push it down
  62. * to the DMP.
  63. */
  64. float sens;
  65. unsigned short accel_sens;
  66. mpu_get_gyro_sens(&sens); //读取当前陀螺仪的状态
  67. gyro[0] = (long)(gyro[0] * sens);
  68. gyro[1] = (long)(gyro[1] * sens);
  69. gyro[2] = (long)(gyro[2] * sens);
  70. dmp_set_gyro_bias(gyro); //根据读取的状态进行校准
  71. mpu_get_accel_sens(&accel_sens); //读取当前加速度计的状态
  72. accel[0] *= accel_sens;
  73. accel[1] *= accel_sens;
  74. accel[2] *= accel_sens;
  75. dmp_set_accel_bias(accel); //根据读取的状态进行校准
  76. printf("setting bias succesfully ......\r\n");
  77. return 0;
  78. }
  79. else
  80. return 1;
  81. }
  82. //mpu6050,dmp初始化
  83. //返回值:0,正常
  84. // 其他,失败
  85. uint8_t mpu_dmp_init(void)
  86. {
  87. uint8_t res=0;
  88. struct int_param_s int_param;//这个没什么用,就是为了能给他实参调用起来
  89. if(mpu_init(&int_param)==0) //初始化MPU6050
  90. {
  91. res=mpu_set_sensors(INV_XYZ_GYRO|INV_XYZ_ACCEL);//设置所需要的传感器
  92. if(res)return 1;
  93. res=mpu_configure_fifo(INV_XYZ_GYRO | INV_XYZ_ACCEL);//设置FIFO
  94. if(res)return 2;
  95. res=mpu_set_sample_rate(DEFAULT_MPU_HZ); //设置采样率
  96. if(res)return 3;
  97. res=dmp_load_motion_driver_firmware(); //加载dmp固件
  98. if(res)return 4;
  99. res=dmp_set_orientation(inv_orientation_matrix_to_scalar(gyro_orientation));//设置陀螺仪方向
  100. if(res)return 5;
  101. res=dmp_enable_feature(DMP_FEATURE_6X_LP_QUAT|DMP_FEATURE_TAP| //设置dmp功能
  102. DMP_FEATURE_ANDROID_ORIENT|DMP_FEATURE_SEND_RAW_ACCEL|DMP_FEATURE_SEND_CAL_GYRO|
  103. DMP_FEATURE_GYRO_CAL);
  104. if(res)return 6;
  105. res=dmp_set_fifo_rate(DEFAULT_MPU_HZ); //设置DMP输出速率(最大不超过200Hz)
  106. if(res)return 7;
  107. res = run_self_test(); //自检
  108. if(res)return 8;
  109. res=mpu_set_dmp_state(1); //使能DMP
  110. if(res)return 9;
  111. }
  112. return 0;
  113. }
  114. //得到dmp处理后的数据(注意,本函数需要比较多堆栈,局部变量有点多)
  115. //pitch:俯仰角 精度:0.1° 范围:-90.0° <---> +90.0°
  116. //roll:横滚角 精度:0.1° 范围:-180.0°<---> +180.0°
  117. //yaw:航向角 精度:0.1° 范围:-180.0°<---> +180.0°
  118. //返回值:0,正常
  119. // 其他,失败
  120. uint8_t mpu_dmp_get_data(float *pitch,float *roll,float *yaw)
  121. {
  122. float q0=1.0f,q1=0.0f,q2=0.0f,q3=0.0f;
  123. unsigned long sensor_timestamp;
  124. short gyro[3], accel[3], sensors;
  125. unsigned char more;
  126. long quat[4];
  127. if(dmp_read_fifo(gyro, accel, quat, &sensor_timestamp, &sensors,&more))return 1;
  128. /* Gyro and accel data are written to the FIFO by the DMP in chip frame and hardware units.
  129. * This behavior is convenient because it keeps the gyro and accel outputs of dmp_read_fifo and mpu_read_fifo consistent.
  130. **/
  131. /*if (sensors & INV_XYZ_GYRO )
  132. send_packet(PACKET_TYPE_GYRO, gyro);
  133. if (sensors & INV_XYZ_ACCEL)
  134. send_packet(PACKET_TYPE_ACCEL, accel); */
  135. /* Unlike gyro and accel, quaternions are written to the FIFO in the body frame, q30.
  136. * The orientation is set by the scalar passed to dmp_set_orientation during initialization.
  137. **/
  138. if(sensors&INV_WXYZ_QUAT)
  139. {
  140. q0 = quat[0] / q30; //q30格式转换为浮点数
  141. q1 = quat[1] / q30;
  142. q2 = quat[2] / q30;
  143. q3 = quat[3] / q30;
  144. //计算得到俯仰角/横滚角/航向角
  145. *pitch = asin(-2 * q1 * q3 + 2 * q0* q2)* 57.3; // pitch
  146. *roll = atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2* q2 + 1)* 57.3; // roll
  147. *yaw = atan2(2*(q1*q2 + q0*q3),q0*q0+q1*q1-q2*q2-q3*q3) * 57.3; //yaw
  148. }else return 2;
  149. return 0;
  150. }

然后就是把log_stm32.c中的所有fputc(...)替换成fputcc(...)。

 然后就是,inv_mpu_dmp_motion_driver.c中,有一个__no_operation(); 直接注释掉(我也不知道这个是干啥的)

然后是修改MPU6050 的地址, 去inv_mpu.c中,直接搜“hw_s hw”就能找到

 接下来就是修改main函数,调用mpu_dmp_get_data,编译运行了

 注意还需要定义float pitch;float roll;float yaw;这仨变量。

最后,可能会出现mpu_dmp_init没问题,但mpu_dmp_get_data函数里的dmp_read_fifo函数出现了问题,解决方法见https://blog.csdn.net/liusenyon/article/details/119333722https://blog.csdn.net/liusenyon/article/details/119333722

stm32f4 移植 mpu6050 md6.12步骤_Scarlett29的博客-CSDN博客_emd 6.12z我是按照这篇文章移植的。在此特别感谢两位作者。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/467200
推荐阅读
相关标签
  

闽ICP备14008679号