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

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

/**
* @brief 写寄存器,这是提供给上层的接口
* @param slave_addr: 从机地址
* @param reg_addr: 寄存器地址
* @param len:写入的长度
* @param data_ptr: 指向要写入的数据
* @retval 正常为 0,不正常为非 0
*/
int Sensors_I2C_WriteRegister(unsigned char slave_addr,unsigned char reg_addr,unsigned short len,unsigned char *data_ptr){HAL_StatusTypeDef status = HAL_OK;status = HAL_I2C_Mem_Write(&I2C_Handle,slave_addr,reg_addr,I2C_MEMADD_SIZE_8BIT,data_ptr,len,I2Cx_FLAG_TIMEOUT);if(status != HAL_OK){}while (HAL_I2C_GetState(&I2C_Handle) != HAL_I2C_STATE_READY) {}/* 检查 SENSOR 是否就绪进行下一次读写操作 */while (HAL_I2C_IsDeviceReady(&I2C_Handle, slave_addr,I2Cx_FLAG_TIMEOUT, I2Cx_FLAG_TIMEOUT) == HAL_TIMEOUT);/* 等待传输结束 */while (HAL_I2C_GetState(&I2C_Handle) != HAL_I2C_STATE_READY) {}return status;
}/**
* @brief 读寄存器,这是提供给上层的接口
* @param slave_addr: 从机地址
* @param reg_addr: 寄存器地址
* @param len:要读取的长度
* @param data_ptr: 指向要存储数据的指针
* @retval 正常为 0,不正常为非 0
*/
int Sensors_I2C_ReadRegister(unsigned char slave_addr,unsigned char reg_addr,unsigned short len,unsigned char *data_ptr){HAL_StatusTypeDef status = HAL_OK;status =HAL_I2C_Mem_Read(&I2C_Handle,slave_addr,reg_addr,I2C_MEMADD_SIZE_8BIT,data_ptr,len,I2Cx_FLAG_TIMEOUT);if (status != HAL_OK) {/* 检查通讯状态 */}while (HAL_I2C_GetState(&I2C_Handle) != HAL_I2C_STATE_READY) {}/* 检查 SENSOR 是否就绪进行下一次读写操作 */while (HAL_I2C_IsDeviceReady(&I2C_Handle, slave_addr,I2Cx_FLAG_TIMEOUT, I2Cx_FLAG_TIMEOUT) == HAL_TIMEOUT);/* 等待传输结束 */while (HAL_I2C_GetState(&I2C_Handle) != HAL_I2C_STATE_READY) {}return status;
}

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

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

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

初始化MPU6050芯片

/*** @brief 写数据到 MPU6050 寄存器* @param reg_add: 寄存器地址* @param reg_data: 要写入的数据* @retval*/
void MPU6050_WriteReg(uint8_t reg_add,uint8_t reg_dat){Sensors_I2C_WriteRegister(MPU6050_ADDRESS,reg_add,1,&reg_dat);
}
/*** @brief 从 MPU6050 寄存器读取数据* @param reg_add: 寄存器地址* @param Read:存储数据的缓冲区* @param num:要读取的数据量* @retval*/
void MPU6050_ReadData(uint8_t reg_add,unsigned char* Read,uint8_t num){Sensors_I2C_ReadRegister(MPU6050_ADDRESS,reg_add,num,Read);
}
/*** @brief 初始化 MPU6050 芯片* @param* @retval*/
void MPU6050_Init(void){//在初始化之前要延时一段时间,若没有延时,则断电后再上电数据可能会出错HAL_Delay(100);//解除休眠状态MPU6050_WriteReg(MPU6050_RA_PWR_MGMT_1, 0x00);//陀螺仪采样率MPU6050_WriteReg(MPU6050_RA_SMPLRT_DIV , 0x07);MPU6050_WriteReg(MPU6050_RA_CONFIG , 0x06);//配置加速度传感器工作在 16G 模式MPU6050_WriteReg(MPU6050_RA_ACCEL_CONFIG , 0x01);//陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s)MPU6050_WriteReg(MPU6050_RA_GYRO_CONFIG, 0x18);HAL_Delay(200);
}
/*** @brief 读取 MPU6050 的 ID* @param* @retval 正常返回 1,异常返回 0*/
uint8_t MPU6050ReadID(void){unsigned char Re = 0;MPU6050_ReadData(MPU6050_RA_WHO_AM_I,&Re,1); //读器件地址if (Re != 0x68) {printf("检测不到 MPU6050 模块,请检查模块与开发板的接线,------%d\r\n",Re);return 0;} else {printf("MPU6050 ID = %d\r\n",Re);return 1;}
}

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

/*** @brief 读取 MPU6050 的加速度数据* @param* @retval*/
void MPU6050ReadAcc(short *accData){uint8_t buf[6];MPU6050_ReadData(MPU6050_ACC_OUT, buf, 6);accData[0] = (buf[0] << 8) | buf[1];accData[1] = (buf[2] << 8) | buf[3];accData[2] = (buf[4] << 8) | buf[5];
}
/*** @brief 读取 MPU6050 的角加速度数据* @param* @retval*/
void MPU6050ReadGyro(short *gyroData){uint8_t buf[6];MPU6050_ReadData(MPU6050_GYRO_OUT,buf,6);gyroData[0] = (buf[0] << 8) | buf[1];gyroData[1] = (buf[2] << 8) | buf[3];gyroData[2] = (buf[4] << 8) | buf[5];
}
/*** @brief 读取 MPU6050 的原始温度数据* @param* @retval*/
void MPU6050ReadTemp(short *tempData){uint8_t buf[2];MPU6050_ReadData(MPU6050_RA_TEMP_OUT_H,buf,2); //读取温度值*tempData = (buf[0] << 8) | buf[1];
}
/*** @brief 读取 MPU6050 的温度数据,转化成摄氏度* @param* @retval*/
void MPU6050_ReturnTemp(float*Temperature){short temp3;uint8_t buf[2];MPU6050_ReadData(MPU6050_RA_TEMP_OUT_H,buf,2); //读取温度值temp3= (buf[0] << 8) | buf[1];*Temperature=((double) (temp3 /340.0))+36.53;
}

********然后就是重头戏了——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就行。

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

MPL_LOG_NDEBUG=1
EMPL,MPU6050
EMPL_TARGET_STM32F4

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

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

创建bsp_mpu6050_dmp.h和bsp_mpu6050_dmp.c

#ifndef __BSP_MPU6050_DMP_H__
#define __BSP_MPU6050_DMP_H__#include "stm32f4xx.h"
#include <stdio.h>
#include <i2c.h>void gyro_data_ready_cb(void);int get_tick_count(unsigned long *count);uint8_t mpu_dmp_init(void);uint8_t mpu_dmp_get_data(float *pitch,float *roll,float *yaw);int fputcc(int ch);#endif
#include "bsp_mpu6050_dmp.h"#include "usart.h"
#include "i2c.h"
#include "gpio.h"
#include "main.h"#include "inv_mpu.h"
#include "inv_mpu_dmp_motion_driver.h"
#include "invensense.h"
#include "invensense_adv.h"
#include "eMPL_outputs.h"
#include "mltypes.h"
#include "mpu.h"
#include "log.h"
#include "packet.h"/* Private typedef -----------------------------------------------------------*/
/* Data read from MPL. */
#define PRINT_ACCEL     (0x01)
#define PRINT_GYRO      (0x02)
#define PRINT_QUAT      (0x04)
#define PRINT_COMPASS   (0x08)
#define PRINT_EULER     (0x10)
#define PRINT_ROT_MAT   (0x20)
#define PRINT_HEADING   (0x40)
#define PRINT_PEDO      (0x80)
#define PRINT_LINEAR_ACCEL (0x100)
#define PRINT_GRAVITY_VECTOR (0x200)volatile uint32_t hal_timestamp = 0;
#define ACCEL_ON        (0x01)
#define GYRO_ON         (0x02)
#define COMPASS_ON      (0x04)#define MOTION          (0)
#define NO_MOTION       (1)/* Starting sampling rate. */
#define DEFAULT_MPU_HZ  (100)#define FLASH_SIZE      (512)
#define FLASH_MEM_START ((void*)0x1800)#define PEDO_READ_MS    (1000)
#define TEMP_READ_MS    (500)
#define COMPASS_READ_MS (100)#define q30  1073741824.0fstatic signed char gyro_orientation[9] = { 1, 0, 0,0, 1, 0,0, 0, 1};int get_tick_count(unsigned long *count)
{*count = HAL_GetTick();return 0;
}int fputcc(int ch)
{printf("%c",ch);
//  HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, 0xFF);return 0;
}uint8_t run_self_test(void)
{int result;long gyro[3], accel[3];result = mpu_run_self_test(gyro, accel);if (result == 0x07) {                   //返回0x03为MPU6050六轴,只要通过该if语句,就可以实现零偏自动校准/* Test passed. We can trust the gyro data here, so let's push it down* to the DMP.*/float sens;unsigned short accel_sens;mpu_get_gyro_sens(&sens);           //读取当前陀螺仪的状态gyro[0] = (long)(gyro[0] * sens);gyro[1] = (long)(gyro[1] * sens);gyro[2] = (long)(gyro[2] * sens);dmp_set_gyro_bias(gyro);            //根据读取的状态进行校准mpu_get_accel_sens(&accel_sens);    //读取当前加速度计的状态accel[0] *= accel_sens;accel[1] *= accel_sens;accel[2] *= accel_sens;dmp_set_accel_bias(accel);          //根据读取的状态进行校准printf("setting bias succesfully ......\r\n");return 0;}elsereturn 1;
}//mpu6050,dmp初始化
//返回值:0,正常
//    其他,失败
uint8_t mpu_dmp_init(void)
{uint8_t res=0;struct int_param_s int_param;//这个没什么用,就是为了能给他实参调用起来if(mpu_init(&int_param)==0) //初始化MPU6050{    res=mpu_set_sensors(INV_XYZ_GYRO|INV_XYZ_ACCEL);//设置所需要的传感器if(res)return 1; res=mpu_configure_fifo(INV_XYZ_GYRO | INV_XYZ_ACCEL);//设置FIFOif(res)return 2; res=mpu_set_sample_rate(DEFAULT_MPU_HZ);  //设置采样率if(res)return 3; res=dmp_load_motion_driver_firmware();     //加载dmp固件if(res)return 4; res=dmp_set_orientation(inv_orientation_matrix_to_scalar(gyro_orientation));//设置陀螺仪方向if(res)return 5; res=dmp_enable_feature(DMP_FEATURE_6X_LP_QUAT|DMP_FEATURE_TAP|    //设置dmp功能DMP_FEATURE_ANDROID_ORIENT|DMP_FEATURE_SEND_RAW_ACCEL|DMP_FEATURE_SEND_CAL_GYRO|DMP_FEATURE_GYRO_CAL);if(res)return 6; res=dmp_set_fifo_rate(DEFAULT_MPU_HZ); //设置DMP输出速率(最大不超过200Hz)if(res)return 7;   res = run_self_test();       //自检if(res)return 8;    res=mpu_set_dmp_state(1);  //使能DMPif(res)return 9;     }return 0;
}//得到dmp处理后的数据(注意,本函数需要比较多堆栈,局部变量有点多)
//pitch:俯仰角 精度:0.1°   范围:-90.0° <---> +90.0°
//roll:横滚角  精度:0.1°   范围:-180.0°<---> +180.0°
//yaw:航向角   精度:0.1°   范围:-180.0°<---> +180.0°
//返回值:0,正常
//    其他,失败
uint8_t mpu_dmp_get_data(float *pitch,float *roll,float *yaw)
{float q0=1.0f,q1=0.0f,q2=0.0f,q3=0.0f;unsigned long sensor_timestamp;short gyro[3], accel[3], sensors;unsigned char more;long quat[4]; if(dmp_read_fifo(gyro, accel, quat, &sensor_timestamp, &sensors,&more))return 1;     /* Gyro and accel data are written to the FIFO by the DMP in chip frame and hardware units.* This behavior is convenient because it keeps the gyro and accel outputs of dmp_read_fifo and mpu_read_fifo consistent.**//*if (sensors & INV_XYZ_GYRO )send_packet(PACKET_TYPE_GYRO, gyro);if (sensors & INV_XYZ_ACCEL)send_packet(PACKET_TYPE_ACCEL, accel); *//* Unlike gyro and accel, quaternions are written to the FIFO in the body frame, q30.* The orientation is set by the scalar passed to dmp_set_orientation during initialization. **/if(sensors&INV_WXYZ_QUAT) {q0 = quat[0] / q30;   //q30格式转换为浮点数q1 = quat[1] / q30;q2 = quat[2] / q30;q3 = quat[3] / q30; //计算得到俯仰角/横滚角/航向角*pitch = asin(-2 * q1 * q3 + 2 * q0* q2)* 57.3;    // pitch*roll  = atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2* q2 + 1)* 57.3;  // roll*yaw   = atan2(2*(q1*q2 + q0*q3),q0*q0+q1*q1-q2*q2-q3*q3) * 57.3; //yaw}else return 2;return 0;
}

然后就是把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我是按照这篇文章移植的。在此特别感谢两位作者。

MPU6050(读取原数据、移植DMP、stm32f4、HAL库、KEIL5)相关推荐

  1. STM32F4 HAL库开发 -- 串口

    一.串口介绍 串口设置包含:开启串口时钟.设置响应的IO口模式.设置波特率.数据位长度.奇偶校验位.DMA等信息. 具体参看:STM32开发 – 串口详解 二.函数 1.串口参数初始化,并使能串口. ...

  2. STM32F4 HAL库开发 -- 温度传感器(DS18B20)

    参看:<嵌入式-STM32开发指南>第三部分 外设篇 - 第2章 温度传感器DS18B20 这篇文章讲的非常详细了. 一.简介 1.概述 DS18B20 是 DALLAS 最新单线数字温度 ...

  3. STM32F4 HAL库开发 -- 工程模板解读

    一.关键文件介绍 1.HAL库关键文件 stm32f4xx_hal_ppp.c/.h 基本外设的操作API,ppp代表任意外设.其中stm32f4xx_hal_cortex.c/.h比较特殊,它是一些 ...

  4. STM32F103C8移植uCOSIII(HAL库)

    少年 一.随笔 二.uCOSIII源码 三.项目导入文件整理 四.导入文件和增加头函数路径 五.代码改动 六.参考资料 一.随笔 移植一个嵌入式系统用了一天时间,只能说不愧是我,在不了解的情况下还是少 ...

  5. STM32F4 HAL库开发 -- 独立看门狗(IWDG)

    之前讲过看门狗,参看:STM32开发 – 看门狗详解 一.HAL库配置独立看门狗步骤 1.取消寄存器写保护,设置看门狗预分频系数和重装载值. 首先我们必须取消 IWDG_PR和 IWDG_RLR寄存器 ...

  6. STM32F4 HAL库开发 -- RTC

    一.STM32F407 RTC时钟简介 STM32F407的RTC,是一个独立的BCD定时器/计数器.RTC提供了一个日历时钟(包含年月日时分秒信息).两个可编程闹钟(ALARM A和ALARM B) ...

  7. STM32F4 HAL库开发 -- DMA

    一.DMA简介 DMA之前有讲过,参看:STM32开发 – DMA详解 DMA,全称为Direct Memory Access,即直接存储器访问.DMA传输方式无需CPU直接控制传输,也没有中断处理方 ...

  8. STM32F4 HAL库开发 --时钟使能和配置

    在STM32F4的HAL库中,外设时钟使能操作都是在RCC相关固件库文件头文件stm32f4xx_hal_rcc.h 定义的.外设时钟使能在HAL库中都是通过宏定义标识符来实现.首先,我们来看看GPI ...

  9. STM32F4 HAL库开发 -- 新建基于 HAL 库的工程模板

    一.STM32CubeF4 固件包下载 下载:STM32CubeF4 MCU Firmware Package 二.新建基于 HAL 库的工程模板 1.新建文件夹 建立一个文件夹为 Template. ...

最新文章

  1. python软件下载手机版-Learn Python中文版app
  2. Struts2的核心文件
  3. Zuul:Cookie和动态路由
  4. 小姐姐为你解析马爸爸是怎么用大数据“宰你”的
  5. linux 内核定时器精度_linux使用select实现精确定时器详解
  6. 方舟编译器的安装和编译Helloword(2)
  7. 微博办公李国庆:急招副总裁,提请股权激励,希望俞渝同意
  8. 解决新版本Vivado打开老工程IP锁住的问题
  9. 【OpenCV学习笔记】【函数学习】十二(cvCanny()函数及其阈值设置的比较)
  10. 九度oj题目amp;吉大考研11年机试题全解
  11. VTD学习记录——八大进程概括(一)
  12. #Geek Founders# 蒋涛的 CES 2016 感受 - Day 4 (总结版)
  13. Android 之AS项目,无法编译,Make Project(小锤子)、Rebuild Project、Clean Project都无效
  14. 图片存档和通信系统(PACS)的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
  15. 微信小程序 修改 顶部电量 时间的颜色
  16. 兼容QQ浏览器,UC浏览器滚动到底部
  17. 华为链路聚合(路由器和交换机)
  18. 2020年数二真题(重点题讲解)
  19. Android 获得app的应用签名
  20. python下载抖音视频_抖音好看的视频你想下载吗?

热门文章

  1. 2021年高考成绩查询宜春昌黎,2021年宜春中考志愿设置
  2. IIC16bit数据读
  3. lesson5-week2
  4. koch雪花python_基于python绘制科赫雪花
  5. 经典智力题:药丸污染问题
  6. 运算放大器使用的一些经验
  7. 电商后台产品设计:订单拆单
  8. MT6575 平板模式 camera 预览拉伸的问题
  9. angular引用swiper插件绘制中间大两边依次缩小的轮播图
  10. python自带的框架是什么_Python Django框架是什么?Python学习入门!