--------------------------------------------------------- 记录自学过程 -------------------------------------------------------------
可能有些说明不对的地方,请大家提出来,共同解决 .共同学习 .共同进步.
| 程序链接(主函数读取版)
| 程序链接(主函数读取版)
| 程序链接(主函数读取版)
| 程序链接(主函数或者中断读取版)
| 程序链接(主函数或者中断读取版)
| 程序链接(主函数或者中断读取版)
目录
- 一、mpu6050的通信方式
- 二、CubeMX的配置
- 三、宏定义MPU6050需要用到的寄存器
- 四、编写 mpu6050的读写函数
- 五、开始移植官方DMP解算
- 加载DMP文件
- inv_mpu.c文件:
- inv_mpu.h文件:
- inv_mpu_dmp_motion_driver.c文件:
- inv_mpu_dmp_motion_driver.h文件:
- 六、DMP初始化及方位的设置
- DMP初始化:
- 陀螺仪方位:
- 七、输出欧拉角
- 八、程序demo下载
一、mpu6050的通信方式
- MPU6050采用IIC通讯
一种简单、双向、二线制、同步串行总线,
IIC总线一共有四根线,分别是VCC,GND,SCL,SDA。SCL的为时钟线,SDA为数据线。I2C总线上的主设备与从设备之间以字节(8位)为单位进行双向的数据传输,
二、CubeMX的配置
下面以stm32F407IG为例(大疆开发板C型)
1. - 配置时钟
2. - 配置debug调试接口
3 - 配置时钟树
4. - 配置I2C接口
5. - 这里配置串口,为了后面的DMP里移植的需要用到
6. - 配置堆栈大小, 可选配置
7. - 最后CubeMX生成代码,CubeMX就配置到这里
三、宏定义MPU6050需要用到的寄存器
代码如下:
- 需要用到的寄存器都在这,还有些另外的寄存器看自己的需求
/******************************************************************************* @Author : WangJing(王晶)* @contact : QQ: 2991386492* @DateCreated : 2020.11.28* @board : RM开发板C型* @consult : 参考 MPU6000 & MPU6050各类芯片手册, 普中, 原子, csdn博客等开源资料
*****************************************************************************/
#ifndef _MPU6050_H
#define _MPU6050_H
#include "main.h"
#include "i2c.h"
#include "usart.h"
//内置DMP的头文件哎
#include "inv_mpu.h" //没用到DMP可以注释掉
#include "inv_mpu_dmp_motion_driver.h" //没用到DMP可以注释掉
#include "stm32f4xx.h"#define MPU_I2C_HANDLE hi2c2 //mpu6050 I2C句柄
#define MPU_I2C_GPIO_INIT MX_I2C2_Init() //mpu6050 I2C的gpio端口配置/* ------------------------------ 选择mpu6050的ADO引脚接法, 从而确定IIC地址 -------------------------------------------- */
#define MPU6050_ADO_JOIN_GND
//#define MPU6050_ADO_JOIN_VCC/* ------------------------------ 根据mpu6050的ADO引脚接法, 从而确定的设备地址 ----------------------------------------- */
/* ADO引脚接GND */
#if defined MPU6050_ADO_JOIN_GND//AD0接GND,IIC地址为0X68#define _MPU_ADDRESS 0x68 //mpu6050_i2c地址, W: 0x68<<1 -->> 0xD0, R: 0x68<<1 + 1 -->> 0xD1//AD0接GND#define _MPU_WRITE 0xD0 //mpu6050地址, I2C设备7位地址值,HAL库用8位整字节写入,所以在数据表中必须在调用接口前左移一位 (( 0xD0>>1 )=0x68)#define _MPU_READ 0xD1#endif/* ADO引脚接VCC */
#if defined MPU6050_ADO_JOIN_VCC//AD0接VCC,IIC地址为0X69#define _MPU_ADDRESS 0x69 //mpu6050_i2c地址, W: 0x69<<1 -->> 0xD2, R: 0x69<<1 + 1 -->> 0xD3//AD0接VCC#define _MPU_WRITE 0xD2 //mpu6050地址, I2C设备7位地址值,HAL库用8位整字节写入,所以在数据表中必须在调用接口前左移一位 (( 0xD2>>1 )=0x69)#define _MPU_READ 0xD3 #endif/* ------------------------------------------------------ MPU6050各个寄存器定义 --------------------------------------------------------------- *//* mpu6050传感器各个状态 */
typedef enum
{mpu_ok = 0x00U, //成功mpu_err = 0x01U, //错误mpu_busy = 0x02U, //忙碌mpu_id_err = 0x03U, //ID错误mpu_timeout = 0x04U, //超时mpu_init_err = 0x05U //初始化错误}mpu_state_t;/* mpu6050传感器电源管理1 */
typedef enum
{//电源管理1寄存器配置mpu_pwr_mgmt_1_rouse = 0x00, //唤醒mpu_pwr_mgmt_1_reset = 0x80, //Bit7该位置 1, 重启内部寄存器到默认mpu_pwr_mgmt_1_sleep = 0x40, //Bit6该位置 1, MPU-60X0 进入睡眠模式mpu_pwr_mgmt_1_cycle = 0x20, //Bit5该位置 1, 且当失能 SLEEP, MPU-60X0 进入循环模式。 在循环模式, 设备在睡眠模式和唤醒模式间循环, 根据 LP_WAKE_CTRL(寄存器 108->电源管理2)设定的速率从加速度计采集样品数据mpu_pwr_mgmt_1_temp_disble = 0x10, //Bit3该位置 1, 失能温度传感器//Bit[2:0]
// mpu_pwr_mgmt_1_clksel_osc = 0x000, //设备的系统时钟 与 内部8 MHZ振荡器(唤醒)mpu_pwr_mgmt_1_clksel_x = 0x01, //设备的系统时钟 与 X轴陀螺仪参考。mpu_pwr_mgmt_1_clksel_y = 0x02, //设备的系统时钟 与 Y轴陀螺仪参考。mpu_pwr_mgmt_1_clksel_z = 0x03, //设备的系统时钟 与 Z轴陀螺仪参考。mpu_pwr_mgmt_1_clksel_32 = 0x04, //PLL 与 外部32.768kHz参考mpu_pwr_mgmt_1_clksel_19 = 0x05, //PLL 与 外部19.2MHz参考mpu_pwr_mgmt_1_clksel_reserved = 0x06, //保留mpu_pwr_mgmt_1_clksel_stop = 0x07
}mpu_pwr_mgmt_1_t;/* mpu6050传感器满量程范围 */
typedef enum
{// 0x1B, 加速度计、陀螺仪满量程范围配置mpu_gyro_fsr_250s = 0x00u, //FSR: ±250°/s, LSB: 131 LSB/°/smpu_gyro_fsr_500s = 0x01u, //FSR: ±500°/s, LSB: 65.5 LSB/°/smpu_gyro_fsr_1000s = 0x02u, //FSR: ±1000°/s, LSB: 32.8 LSB/°/smpu_gyro_fsr_2000s = 0x03u, //FSR: ±2000°/s, LSB: 16.4 LSB/°/s// 0x1C, 加速度计满量程范围mpu_acce_fsr_2g = 0x00u, //FSR: ±2g, LSB: 16384 LSB/gmpu_acce_fsr_4g = 0x01u, //FSR: ±4g, LSB: 8192 LSB/gmpu_acce_fsr_8g = 0x02u, //FSR: ±8g, LSB: 4086 LSB/gmpu_acce_fsr_16g = 0x03u //FSR: ±16g, LSB: 2048 LSB/g}mpu_fsr_t;/* mpu6050传感器六轴数据 */
typedef struct
{//原始六轴数据int16_t mpu_acce[3]; //加速度 0x3Bint16_t mpu_gyro[3]; //陀螺仪 0x43float mpu_temperature; //温度 0x41}mpu_msg_t;/* mpu自身姿态数据 */
typedef struct
{//mpu欧拉角float pitch; //俯仰角 --> (绕 'X轴' 旋转)float roll; //翻滚角 --> (绕 'Y轴' 旋转)float yaw; //偏航角 --> (绕 'Z轴' 旋转)}pose_msg_t;/* ------------------------------------------------ 查MPU60x0数据手册 ------------------------------------------------ *//* 注意:MPU6000 & MPU6050设备在'上电时'会进入'睡眠模式' */
/* 注意:MPU6000 & MPU6050设备在'上电时'会进入'睡眠模式' */
/* 注意:MPU6000 & MPU6050设备在'上电时'会进入'睡眠模式' *//* 自检寄存器 */
#define _MPU_SELF_TEST_X_REG 0x0D //自检寄存器X
#define _MPU_SELF_TEST_Y_REG 0x0E //自检寄存器Y
#define _MPU_SELF_TEST_Z_REG 0x0F //自检寄存器Z
#define _MPU_SELF_TEST_A_REG 0x10 //自检寄存器A/* 采样频率分频寄存器 */
#define _MPU_SAMPLE_RATE_DIVIDER_REG 0x19 //采样频率分频寄存器
/* 配置寄存器 */
#define _MPU_CONFIG_REG 0x1A //配置寄存器
#define _MPU_GYRO_CONFIG_REG 0x1B //陀螺仪配置寄存器(自检和满量程范围)
#define _MPU_ACCE_CONFIG_REG 0x1C //加速度计配置寄存器(自检和满量程范围)/* mpu6050中断寄存器 */
#define _MPU_INT_BP_CFG_REG 0X37 //INT引脚/旁路有效使能配置寄存器
#define _MPU_INT_ENABLE_REG 0X38 //中断使能寄存器
#define _MPU_INT_STATE_REG 0X3A //中断状态寄存器/* 传感器原始数据 */
#define _MPU_RAW_DATA_REG 0x3B //传感器数据输出第一位寄存器
/* mpu6050加速度值 */
#define _MPU_ACCE_XOUT_H_REG 0x3B //加速度值, X轴高8位寄存器
#define _MPU_ACCE_XOUT_L_REG 0x3C //加速度值, X轴低8位寄存器
#define _MPU_ACCE_YOUT_H_REG 0x3D //加速度值, Y轴高8位寄存器
#define _MPU_ACCE_YOUT_L_REG 0x3E //加速度值, Y轴低8位寄存器
#define _MPU_ACCE_ZOUT_H_REG 0x3F //加速度值, Z轴高8位寄存器
#define _MPU_ACCE_ZOUT_L_REG 0x40 //加速度值, Z轴低8位寄存器/* mpu6050温度值 */
#define _MPU_TEMP_OUT_H_REG 0x41 //温度值, 高8位寄存器
#define _MPU_TEMP_OUT_L_REG 0x42 //温度值, 低8位寄存器/* mpu6050陀螺仪值 */
#define _MPU_GYRO_XOUT_H_REG 0x43 //陀螺仪值, X轴高8位寄存器
#define _MPU_GYRO_XOUT_L_REG 0x44 //陀螺仪值, X轴低8位寄存器
#define _MPU_GYRO_YOUT_H_REG 0x45 //陀螺仪值, Y轴高8位寄存器
#define _MPU_GYRO_YOUT_L_REG 0x46 //陀螺仪值, Y轴低8位寄存器
#define _MPU_GYRO_ZOUT_H_REG 0x47 //陀螺仪值, Z轴高8位寄存器
#define _MPU_GYRO_ZOUT_L_REG 0x48 //陀螺仪值, Z轴低8位寄存器#define _MPU_USER_CTRL 0x6A //用户配置
#define _MPU_PWR_MGMT_1 0x6B //电源管理1
#define _MPU_PWR_MGMT_2 0x6C //电源管理2/* "WHO AM I" */
#define _MPU_DEVICE_ID 0x75 //设备ID, "WHO AM I"寄存器
四、编写 mpu6050的读写函数
代码如下:
mpu的读写函数
/* ------------------------------------------------ mpu写入一个Byte ------------------------------------------------------------ */
/*** @brief mpu_write_byte() IIC写一个字节.* @param reg_addr 寄存器地址.* @param w_data 需要写入的数据.* @note 传入需要写的寄存器地址, 后面是往这个寄存器写入的一个字节的数据.* @retval HAL status mpu_ok/hal_error*/
mpu_state_t w_mpu_write_byte(uint8_t reg_addr, uint8_t w_data)
{uint8_t w_data_byte = w_data; //放入要写入的数据if( HAL_I2C_Mem_Write(&MPU_I2C_HANDLE, _MPU_WRITE, reg_addr, I2C_MEMADD_SIZE_8BIT, &w_data_byte, 1, 0xfff) == HAL_OK)return mpu_ok; //写入成功elsereturn mpu_err; //写入失败}/* ------------------------------------------------ mpu读取一个Byte ------------------------------------------------------------ */
/*** @brief mpu_read_byte() IIC读取一个字节.* @param reg_addr 读取的寄存器地址.* @note 传入需要读取的寄存器地址* @retval HAL status r_data_byte/mpu_busy*/
uint8_t w_mpu_read_byte(uint8_t reg_addr)
{static uint8_t r_data_byte = 0x00u; //存放读取一个Byte的数据if( HAL_I2C_Mem_Read(&MPU_I2C_HANDLE, _MPU_READ, reg_addr, I2C_MEMADD_SIZE_8BIT, &r_data_byte, 1, 0xfff) == HAL_OK)
// HAL_Delay(50);return r_data_byte; //返回读取的数据else
return mpu_busy; //iic忙碌(0x02/0x2)return mpu_err;}/* ------------------------------------------------ mpu连续写入多个Byte ------------------------------------------------------------ */
/*** @brief mpu_write_byte() IIC连续写入多个Byte.* @param reg_addr 寄存器地址.* @param *w_data_buf 需要写入的数据缓冲区.* @param len 数据缓冲区的长度.* @note 传入需要写的寄存器地址, 后面是往这个寄存器写入的的一组数据, 确定数据长度* @retval HAL status mpu_ok/hal_error*/
mpu_state_t w_mpu_write_byte_len(uint8_t reg_addr, uint8_t *w_data_buf, uint8_t len)
{if( HAL_I2C_Mem_Write(&MPU_I2C_HANDLE, _MPU_WRITE, reg_addr, I2C_MEMADD_SIZE_8BIT, w_data_buf, len, 0xfff) == HAL_OK)return mpu_ok; //写入成功elsereturn mpu_err; //写入失败}/* ------------------------------------------------ mpu连续读取多个Byte ------------------------------------------------------------ */
/*** @brief mpu_read_byte() IIC连续读取多个Byte.* @param reg_addr 读取的寄存器地址.* @param *r_data_buf 需要读取的数据缓冲区.* @param len 数据缓冲区的长度.* @note 传入需要读取的寄存器地址, 后面是读取到的数据放入这个数组buff中, 确定这组数据的长度* @retval HAL status mpu_ok/hal_error*/
mpu_state_t w_mpu_read_byte_len(uint8_t reg_addr, uint8_t *r_data_buf, uint8_t len)
{if( HAL_I2C_Mem_Read(&MPU_I2C_HANDLE, _MPU_READ, reg_addr, I2C_MEMADD_SIZE_8BIT, r_data_buf, len, 0xfff) == HAL_OK)
// HAL_Delay(50);return mpu_ok; //读取完成else
// return mpu_busy; //iic忙碌return mpu_err;}**
五、开始移植官方DMP解算
步骤如下:
加载DMP文件
- 首先到官网下载DMP运动解算的压缩包
- 解压后找到文件core \ driver \ eMPL,的目录下,4个mpu文件分别如下:
inv_mpu.c, inv_mpu.h, inv_mpu_dmp_motion_driver.c, inv_mpu_dmp_motion_driver.h
- 将这几个文件添加到自己的工程项目中即可。
操作如下:
inv_mpu.c文件:
- 这里因为官方的DMP是基于MSP430单片机,所以我们要改成我们stm32fxxx系
- 首先是源文件,移植内容如下:
-
把MSP430给预处理掉, 定义自己的芯片型号, 写上我们的内容就好
-
[注意IIC的读写函数格式]
-
改成陀螺仪的地址,地址选择可在上面的mpu6050.h文件中选择
-
mpu6050.h文件中陀螺仪地址选择
-
inv_mpu.h文件:
-
头文件,移植内容如下:
- 把源文件定义好的型号加上去处理
- 把源文件定义好的型号加上去处理
inv_mpu_dmp_motion_driver.c文件:
- 这里因为官方的DMP是基于MSP430单片机,所以我们要改成我们stm32fxxx系
- 跟上面的差不多,把MSP430给预处理掉, 定义自己的芯片型号, 写上我们的内容就好
- [注意IIC的读写函数格式]
- [注意IIC的读写函数格式]
inv_mpu_dmp_motion_driver.h文件:
- 不需要什么的改动,基本都在源文件中
- 移植DMP就到这里结束了,接下来就是编写DMP的初始化了
六、DMP初始化及方位的设置
DMP初始化:
- 具体配置这个就不这里多说了,详细的看我下面写的demo
陀螺仪方位:
- 根据矩阵方位和自身陀螺仪实际摆放来改动
七、输出欧拉角
- 分别读取原始数据和欧拉角— == 主函数读取 ==
- 分别读取原始数据和欧拉角— == 中断读取 ==
八、程序demo下载
- 本节的配套程序可以在这里下载
HAL库编写MPU6050输出六轴原始数据,移植DMP输出自身姿态角(主函数版)
HAL库编写MPU6050输出六轴原始数据,移植DMP输出自身姿态角(主函数或者中断)
------------------------------------- 本节结束啦!!! -------------------------------------