STM32 HAL库编写MPU6050输出六轴原始数据, 移植DMP输出自身姿态角,欧拉角

--------------------------------------------------------- 记录自学过程 -------------------------------------------------------------
可能有些说明不对的地方,请大家提出来,共同解决 .共同学习 .共同进步.

| 程序链接(主函数读取版)
| 程序链接(主函数读取版)
| 程序链接(主函数读取版)


| 程序链接(主函数或者中断读取版)
| 程序链接(主函数或者中断读取版)
| 程序链接(主函数或者中断读取版)

一、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/°/s
		mpu_gyro_fsr_500s		= 0x01u,		//FSR: ±500°/s,  LSB: 65.5 LSB/°/s
		mpu_gyro_fsr_1000s		= 0x02u,		//FSR: ±1000°/s, LSB: 32.8 LSB/°/s
		mpu_gyro_fsr_2000s		= 0x03u,		//FSR: ±2000°/s, LSB: 16.4 LSB/°/s
	
		// 0x1C, 加速度计满量程范围
		mpu_acce_fsr_2g			= 0x00u,		//FSR: ±2g,  LSB: 16384 LSB/g
		mpu_acce_fsr_4g			= 0x01u,		//FSR: ±4g,  LSB: 8192  LSB/g
		mpu_acce_fsr_8g			= 0x02u,		//FSR: ±8g,  LSB: 4086  LSB/g
		mpu_acce_fsr_16g		= 0x03u			//FSR: ±16g, LSB: 2048  LSB/g

}mpu_fsr_t;

/* mpu6050传感器六轴数据 */
typedef struct
{
		//原始六轴数据
		int16_t mpu_acce[3];				//加速度		0x3B
		int16_t mpu_gyro[3];				//陀螺仪		0x43
		float	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;					//写入成功
	else
		return 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;					//写入成功
	else
		return 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.cinv_mpu.hinv_mpu_dmp_motion_driver.cinv_mpu_dmp_motion_driver.h

  • 将这几个文件添加到自己的工程项目中即可。

操作如下:

inv_mpu.c文件:
  • 这里因为官方的DMP是基于MSP430单片机,所以我们要改成我们stm32fxxx系
  • 首先是源文件,移植内容如下:
    • 把MSP430给预处理掉, 定义自己的芯片型号, 写上我们的内容就好

    • [注意IIC的读写函数格式]注意IIC的读写函数格式

    • 改成陀螺仪的地址,地址选择可在上面的mpu6050.h文件中选择在这里插入图片描述

    • mpu6050.h文件中陀螺仪地址选择在这里插入图片描述

inv_mpu.h文件:
  • 头文件,移植内容如下:

    • 把源文件定义好的型号加上去处理
      在这里插入图片描述
inv_mpu_dmp_motion_driver.c文件:
  • 这里因为官方的DMP是基于MSP430单片机,所以我们要改成我们stm32fxxx系
  • 跟上面的差不多,把MSP430给预处理掉, 定义自己的芯片型号, 写上我们的内容就好
    • [注意IIC的读写函数格式]
      在这里插入图片描述
inv_mpu_dmp_motion_driver.h文件:
  • 不需要什么的改动,基本都在源文件中
  • 移植DMP就到这里结束了,接下来就是编写DMP的初始化了

六、DMP初始化及方位的设置

DMP初始化:
  • 具体配置这个就不这里多说了,详细的看我下面写的demo

在这里插入图片描述

陀螺仪方位:
  • 根据矩阵方位和自身陀螺仪实际摆放来改动

在这里插入图片描述
在这里插入图片描述

七、输出欧拉角

  • 分别读取原始数据和欧拉角— == 主函数读取 ==
    在这里插入图片描述
  • 分别读取原始数据和欧拉角— == 中断读取 ==
    在这里插入图片描述

八、程序demo下载

  • 本节的配套程序可以在这里下载

HAL库编写MPU6050输出六轴原始数据,移植DMP输出自身姿态角(主函数版)

HAL库编写MPU6050输出六轴原始数据,移植DMP输出自身姿态角(主函数或者中断)

------------------------------------- 本节结束啦!!! -------------------------------------

  • 31
    点赞
  • 206
    收藏
    觉得还不错? 一键收藏
  • 38
    评论
评论 38
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值