MPU6050驱动配置
1、MPU6050传感器
1)加速度计传感器
可以用于测量向某个方向的加速度力,在重力的影响下,也可以测量当前的俯仰角度
(1)传感器原理
下图中左侧在XYZ轴上的是加速度力的作用力示意图,右侧是加速度计内部的一个模拟示意图

当小车向前行驶时,就向Y轴施加了一个水平的加速度力时,
由于内部的惯性,小球会被往反方向施加一个反作用力,如此一来就MPU6050就采集到了向Y轴施加的加速度力。

(2)重力影响
加速度计三轴的数值由于重力影响,即使是静止状态下,依然会有一个向Z轴方向的加速度力,所以加速度计的参数不会为0,0,0

(3)俯仰角计算
就是根据重力作用在XYZ三轴上关于加速度力的向量参数,使用三角函数,计算出倾斜的角度

2)陀螺仪传感器
可以用于测量物体向一个方向转动的力度或速度
(1)传感器原理
下图中左侧围绕着XYZ轴作用的力就是科里奥利力,右侧是陀螺仪内部的一个模拟示意图

当陀螺仪静止状态,小球会沿着竖直方向反复震荡
当陀螺仪按红色箭头旋转的时候,会有沿着蓝色虚线方向作用的科里奥利力,也就是陀螺仪采集的数据

(2)角速度计算
2、MPU6050数据手册

根据MPU6050数据手册的目录,可以看到有四个章节,
第一章节是MPU6050的历史修订记录;
第二章节介绍MPU6050的作用和测量的范围;
第三章节是MPU6050中所有的寄存器的地址总览;
第四章节详细介绍了每个寄存器的作用和地址,以及使用的方法(着重分析)
1)寄存器分析
(1)寄存器13-16(设置自检参数)

用于设置陀螺仪和加速度计的自检功能,需要通过数据手册的计算公式,写入数值,详细介绍看手册

(2)寄存器25(设置采样分频系数)

用于设置传感器的采样频率,采样频率为传感器输出速率除以分频系数加一

(3)寄存器26(滤波功能配置寄存器)




(4)寄存器27(配置陀螺仪传感器)

[3:4]位,用于设置陀螺仪检测范围,[5:7]用于陀螺仪对应XYZ轴的自检使能


(5)寄存器28(配置加速度计传感器)


(6)寄存器31(设置运动检测阈值)

设置运动检测阈值,当运动参数超过阈值时,就会触发"运动中断"

(7)寄存器35(对应缓冲区使能)

用于设置哪些参数写入缓存区,使用时需要将缓冲区使能,将FIFO_EN设为1,FIFO中的数据读写时遵循先进先出原则。

(8)~(14)寄存器36-54(设置主从机模式)
当需要MPU6050为主机,于其他从机通讯时使用,这里不做介绍
(15)~(17)寄存器55-58(配置中断触发)
由于我使用的开发板上,没有连接MPU6050的中断信号引脚,所以我使用不了这个功能,也不做介绍
(18)寄存器59-64(采集到的加速度计数据)

ACCEL_XOUT[15:8]为数据高位,ACCEL_XOUT[7:0]为数据低位


(19)寄存器65-66(采集到的温度数据)


(20)寄存器67-72(采集到的陀螺仪数据)



(21)寄存器73-96(存储获取从机数据)

共24个寄存器,可以用存储,MPU6050作为主机时,从四个从机获取到的陀螺仪/加速度计数据。
(22)寄存器99(从机0获取到的数字量数据)

(23)寄存器100(从机1获取到的数字量数据)

(24)寄存器101(从机2获取到的数字量数据)

(25)寄存器102(从机3获取到的数字量数据)

(26)寄存器103(设置从机延时使能)

用于降低从机设备的采样速率

(27)寄存器104(传感器复位寄存器)

用于将模数转换器和滤波器重置到初始状态

(28)寄存器105(设置唤醒延时时间)

用于设置唤醒时的时长,默认时间是4ms,在此基础上加上设置的二进制参数,那么也就是说唤醒延时时间最短为4ms最长为7ms

(29)寄存器106(用户配置寄存器)

该寄存器的主要功能,使能缓冲区,设置是否使用SDA和SCL主导通讯,设置MPU6000是使用IIC协议还是使用SPI协议,MPU6050只能使用IIC协议

(30)寄存器107(电源管理寄存器1)

该寄存器的功能:将整个设备复位,进入/退出休眠模式,设置时钟信号源,温度采集屏蔽


(31)寄存器108(电源管理寄存器2)

该寄存器功能:设置陀螺仪或加速度计的XYZ轴中的任意轴为待机模式,设置低功耗模式下的加速度计唤醒频率
如何设置低功耗模式
1. 设置MPU6050_PWR_MGMT_1[5] CYCLE为1
2. 设置MPU6050_PWR_MGMT_1[6] SLEEP为0
3. 设置MPU6050_PWR_MGMT_1[3] TEMP_DIS为1
4. 设置MPU6050_PWR_MGMT_2[0-2] 为1,使陀螺仪待机


(32)寄存器114-115(缓冲区计数寄存器)


(33)寄存器116(缓冲区读写寄存器)


(34)寄存器117(身份证明寄存器)

2)从机地址
可以查找产品手册,查找从机地址,也可以根据第34节关于寄存器177的介绍得知从机地址默认为0x68,根据电路图上AD0引脚的值,确定从机地址的最后一位,因此当AD0为0时从机地址为0x68,当AD0为1时,从机地址为0x69。

3、HAL库编写驱动代码
1)MPU6050的初始化流程
- 将设备复位重置,复位需要执行100ms(向PWR_MGMT_1写入0x80)
- 关闭休眠模式,默认状态是休眠模式(向PWR_MGMT_1写入0x40)
- 设置设备时钟信号源,并屏蔽温度采集(向PWR_MGMT_1写入0x05)
- 写入陀螺仪检测范围(向GYRO_CONFIG写入0x10)
- 写入加速度计检测范围(向ACCEL_CONFIG写入0x00)
- 配置滤波参数以及陀螺仪采样频率(向CONFIG写入0x00)
- 设置时钟分频系数(向CONFIG写入0x4F)
2)示例源码
(1)mpu6050.h
#ifndef __MPU6050_H__ #define __MPU6050_H__#include "main.h" #include "i2c.h"#define MPU6050_Device_Address 0x69 #define MPU6050_Device_Address_R ((MPU6050_Device_Address<<1) | 1) #define MPU6050_Device_Address_W ((MPU6050_Device_Address<<1) | 0)//1. 配置时钟源 //2. 配置陀螺仪和加速度计传感器量程 //3. 配置噪声滤除参数 //4. 配置MPU6050时钟分频器 //5. 配置自检使能 //6. 对应参数的缓冲区使能//自检参数寄存器地址(4.1) //陀螺仪传感器自检参数寄存器地址 #define MPU6050_XG_TEST_Addr 0x0D //寄存器中[0-4]位 #define MPU6050_YG_TEST_Addr 0x0E //寄存器中[0-4]位 #define MPU6050_ZG_TEST_Addr 0x0F //寄存器中[0-4]位 //加速度传感器自检参数寄存器地址低位 #define MPU6050_XA_TEST_L_Addr 0x10 //寄存器中[0-1]位(表示数据位[0-1]位) #define MPU6050_YA_TEST_L_Addr 0x10 //寄存器中[2-3]位(表示数据位[0-1]位) #define MPU6050_ZA_TEST_L_Addr 0x10 //寄存器中[4-5]位(表示数据位[0-1]位) //加速度传感器自检参数寄存器地址高位 #define MPU6050_XA_TEST_H_Addr 0x0D //寄存器中[5-7]位(表示数据位[2-4]位) #define MPU6050_YA_TEST_H_Addr 0x0E //寄存器中[5-7]位(表示数据位[2-4]位) #define MPU6050_ZA_TEST_H_Addr 0x0F //寄存器中[5-7]位(表示数据位[2-4]位)//MPU6050工作频率分频器寄存器地址(4.2) #define MPU6050_SMPRRT_DIV_Addr 0x19 //寄存器中[0-7]位(表示数据位[0-7]位)//MPU6050滤波模式配置寄存器地址(4.3) #define MPU6050_CONFIG_Addr 0x1A //寄存器中的[0-2]位,配置陀螺仪/加速度传感器的滤波频率(滤除噪声) //寄存器中的[3-5]位,直接写入000,因为FSYNC引脚被接地了,无法获取校验值//陀螺仪传感器自检配置寄存器(4.4) #define MPU6050_GYRO_CONFIG_Addr 0x1B //寄存器中的[3-4]位,配置检测的范围 //第[5]位陀螺仪Z轴自检使能位,第[6]位陀螺仪Y轴自检使能位,第[7]位陀螺仪X轴自检使能位//加速度传感器自检配置寄存器(4.5) #define MPU6050_ACCEL_CONFIG_Addr 0x1C //寄存器中的[3-4]位,配置检测的范围 //第[5]位加速度计Z轴自检使能位,第[6]位加速度计Y轴自检使能位,第[7]位加速度计X轴自检使能位//缓冲区使能位(4.7) #define MPU6050_FIFO_EN_Addr 0x23 //[0]SLV0_FIFO_EN,[1]SLV0_FIFO_EN,[2]SLV0_FIFO_EN //[3]ACCEL_FIFO_EN //[4]ZG_FIFO_EN,[5]YG_FIFO_EN,[6]XG_FIFO_EN //[7]TEMP_FIFO_EN//存储加速度数据的寄存器(4.18) //连续读六次读取完整的加速度XYZ数据 #define MPU6050_ACCEL_Data_Addr 0x3B //加速度传感器的各个存储数据寄存器地址 #define MPU6050_XA_Data_H_Addr 0x3B #define MPU6050_XA_Data_L_Addr 0x3C #define MPU6050_YA_Data_H_Addr 0x3D #define MPU6050_YA_Data_L_Addr 0x3E #define MPU6050_ZA_Data_H_Addr 0x3F #define MPU6050_ZA_Data_L_Addr 0x40//存储温度数据的寄存器(4.19) #define MPU6050_TEMP_Data_Addr 0x41 #define MPU6050_TEMP_Data_H_Addr 0x41 #define MPU6050_TEMP_Data_L_Addr 0x42//存储陀螺仪数据的寄存器(4.20) //连续读六次读取完整的陀螺仪XYZ数据 #define MPU6050_GYRO_Data_Addr 0x43 //陀螺仪传感器的各个存储数据寄存器地址 #define MPU6050_XG_Data_H_Addr 0x43 #define MPU6050_XG_Data_L_Addr 0x44 #define MPU6050_YG_Data_H_Addr 0x45 #define MPU6050_YG_Data_L_Addr 0x46 #define MPU6050_ZG_Data_H_Addr 0x47 #define MPU6050_ZG_Data_L_Addr 0x48//陀螺仪、加速度、温度传感器的信号路径复位重置寄存器地址(4.27) #define MPU6050_PATH_RESET_Addr 0x68 //[0]复位温度、[1]复位加速度、[2]复位陀螺仪//唤醒延迟寄存器(4.28) #define MPU6050_MOT_DETECT_CTRL_Addr 0x69 //[4-5]写入增加的延迟时间,单位毫秒,最少延时4ms//MPU6050用户的各种功能使能操作寄存器(4.29) #define MPU6050_USER_CTRL_Addr 0x6A //[0]MPU6050所有传感器重置位,为1时触发 //[1]MPU6050主机功能重置位,为0时触发 //[2]MPU6050缓冲区重置位,当缓冲区未被使能(FIFO_EN为0时)时,当前位为1触发 //[4]MPU6050通讯接口控制位,为1时使用SPI通讯,为0时使用IIC通讯(默认为IIC通讯) //[5]MPU6050主从机控制位,为1时MPU6050为主机,为0时MPU6050为从机 //[6]MPU6050的缓冲区使能位,为1时使能缓冲区,为0时禁用缓冲,被禁用时才可以被复位//MPU6050设备管理寄存器1地址(4.30) #define MPU6050_PWR_MGMT_1_Addr 0x6B //[0-2]选择MPU6050的时钟信号源,推荐使用陀螺仪x轴作为时钟源,写入001 //[3]温度传感器屏蔽位,设置为1时,屏蔽温度传感器功能 //[5]循环激活位,当不处于睡眠模式时,设置为1,MPU6050会每秒激活一次MPU6050 //[6]睡眠使能位,设置为1时,MPU6050进入睡眠 //[7]设备重置位,设置为1时,会将MPU6050所有寄存器全部复位重置//如何设置低功耗模式 //1. 设置MPU6050_PWR_MGMT_1[5] CYCLE为1 //2. 设置MPU6050_PWR_MGMT_1[6] SLEEP为0 //3. 设置MPU6050_PWR_MGMT_1[3] TEMP_DIS为1 //4. 设置MPU6050_PWR_MGMT_2[0-2] 为1,使陀螺仪待机//MPU6050设备管理寄存器2地址(4.31) //1. 可以设置加速度和陀螺仪传感器进入待机模式 //2. 可以设置MPU6050低功耗模式下的工作频率 #define MPU6050_PWR_MGMT_2_Addr 0x6C //[0-2]加速度传感器待机位,[3-5]陀螺仪传感器待机位 //[6-7]低功耗模式工作频率选择位//MPU6050的缓冲区计数寄存器地址(4.32)(必须先读取高位地址才会刷新计数值) #define MPU6050_FIFO_COUNT_Addr 0x72 //缓冲区的各个存储数据寄存器地址 #define MPU6050_FIFO_COUNT_H_Addr 0x72 #define MPU6050_FIFO_COUNT_L_Addr 0x73//缓冲区读写寄存器(4.33) #define MPU6050_FIFO_R_W 0x74 //当写入数据时,会将该寄存器中的地址按照缓冲区寄存器编号顺序从低到高添加到缓冲区中//MPU6050从机地址校验位(4.34)(存储从机地址的上6位) #define MPU6050_Device_Addr 0x75/*** 功能:MPU6050初始化* 参数:无* 返回值:无*/ void MPU6050_Init(void); /*** 功能:获取MPU6050采集参数* 参数:获取的目标寄存器地址* 返回值:返回读取到的uint16_t参数的数组*/ int16_t* MPU6050_Get_Data(uint8_t register_addr,int16_t* Buf_data); /*** 功能:转换MPU6050采集的参数* 参数:获取到的uint16_t参数* 返回值:返回读取到的uint16_t参数的数组*/ #define GYRO 1 #define ACCEL 2 int16_t* MPU6050_Digital_to_Analog(int16_t* Digital_data,uint8_t Mode); int16_t* GYRO_Digital_to_Analog(int16_t* Digital_Data); int16_t* ACCEL_Digital_to_Analog(int16_t* Digital_Data);#define MPU6050_GYRO_RANGE 0x10#if !(MPU6050_GYRO_RANGE^0x00) #define GYRO_RANGE 250 #elif !(MPU6050_GYRO_RANGE^0x04) #define GYRO_RANGE 500 #elif !(MPU6050_GYRO_RANGE^0x10) #define GYRO_RANGE 1000 #elif !(MPU6050_GYRO_RANGE^0x14) #define GYRO_RANGE 2000 #endif#define MPU6050_ACCEL_RANGE 0x00#if !(MPU6050_ACCEL_RANGE^0x00) #define ACCEL_RANGE 2 #elif !(MPU6050_ACCEL_RANGE^0x04) #define ACCEL_RANGE 4 #elif !(MPU6050_ACCEL_RANGE^0x10) #define ACCEL_RANGE 8 #elif !(MPU6050_ACCEL_RANGE^0x14) #define ACCEL_RANGE 16 #endif#endif
(2)mpu6050.c
#include "mpu6050.h"/*** 功能:MPU6050初始化* 参数:无* 返回值:无*/ void MPU6050_Init(void) {uint8_t Buf[2]={};//将MPU6050复位Buf[0] = MPU6050_PWR_MGMT_1_Addr;Buf[1] = 0x80;HAL_I2C_Master_Transmit(&hi2c1,MPU6050_Device_Address_W,Buf,2,10);HAL_Delay(100);//关闭休眠模式Buf[0] = MPU6050_PWR_MGMT_1_Addr;Buf[1] = 0x40;//关闭休眠模式HAL_I2C_Master_Transmit(&hi2c1,MPU6050_Device_Address_W,Buf,2,10);//设置时钟源Buf[0] = MPU6050_PWR_MGMT_1_Addr;Buf[1] = 0x05;//屏蔽温度采集,设置陀螺仪X轴为时钟源HAL_I2C_Master_Transmit(&hi2c1,MPU6050_Device_Address_W,Buf,2,10);//写入陀螺仪检测范围Buf[0] = MPU6050_GYRO_CONFIG_Addr;Buf[1] = 0x10;HAL_I2C_Master_Transmit(&hi2c1,MPU6050_Device_Address_W,Buf,2,10);//写入加速度计检测范围Buf[0] = MPU6050_ACCEL_CONFIG_Addr;Buf[1] = 0x00;HAL_I2C_Master_Transmit(&hi2c1,MPU6050_Device_Address_W,Buf,2,10);//配置噪音滤波参数及陀螺仪采样频率Buf[0] = MPU6050_CONFIG_Addr;Buf[1] = 0x00;HAL_I2C_Master_Transmit(&hi2c1,MPU6050_Device_Address_W,Buf,2,10);//设置时钟分频系数Buf[0] = MPU6050_SMPRRT_DIV_Addr;Buf[1] = 0x4F;HAL_I2C_Master_Transmit(&hi2c1,MPU6050_Device_Address_W,Buf,2,10); }/*** 功能:获取MPU6050采集参数* 参数:获取的目标寄存器地址* 返回值:返回读取到的uint16_t参数的数组*/ int16_t* MPU6050_Get_Data(uint8_t register_addr,int16_t* Buf_data) {uint8_t Buf[6] = {};Buf[0] = register_addr;HAL_I2C_Master_Transmit(&hi2c1,MPU6050_Device_Address_W,Buf,1,10);HAL_I2C_Master_Receive(&hi2c1,MPU6050_Device_Address_R,Buf,6,10);Buf_data[0] = (Buf[0] << 8) | Buf[1];Buf_data[1] = (Buf[2] << 8) | Buf[3];Buf_data[2] = (Buf[4] << 8) | Buf[5];return Buf_data; }/*** 功能:转换MPU6050采集的参数* 参数:获取到的uint16_t参数* 返回值:返回读取到的uint16_t参数的数组*/ int16_t* MPU6050_Digital_to_Analog(int16_t* Data,uint8_t Mode) {switch(Mode){case 1:Data=GYRO_Digital_to_Analog(Data);break;case 2:Data=ACCEL_Digital_to_Analog(Data);break;}return Data; }int16_t* GYRO_Digital_to_Analog(int16_t* Data) {int16_t i=0;for(i=0;i<3;i++){Data[i] = (Data[i] * GYRO_RANGE) / 32768;}return Data; }int16_t* ACCEL_Digital_to_Analog(int16_t* Data) {int16_t i=0;for(i=0;i<3;i++){Data[i] = (Data[i] * ACCEL_RANGE*1000) / 32768;}return Data; }
(3)main.c
/* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "i2c.h" #include "icache.h" #include "usart.h" #include "gpio.h" #include "mpu6050.h" #include "stdio.h" #include "math.h"/*** @brief The application entry point.* @retval int*/ int main(void) {/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* Configure the System Power */SystemPower_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_I2C1_Init();MX_ICACHE_Init();MX_USART1_UART_Init();/* USER CODE BEGIN 2 */MPU6050_Init();int16_t Data_Buf[3] = {};uint16_t i = 0;/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){MPU6050_Get_Data(MPU6050_GYRO_Data_Addr,Data_Buf);MPU6050_Digital_to_Analog(Data_Buf,GYRO);printf("XG=%d\t",Data_Buf[0]);printf("YG=%d\t",Data_Buf[1]);printf("ZG=%d\n",Data_Buf[2]);MPU6050_Get_Data(MPU6050_ACCEL_Data_Addr,Data_Buf);MPU6050_Digital_to_Analog(Data_Buf,ACCEL);printf("XA=%d\t",Data_Buf[0]);printf("YA=%d\t",Data_Buf[1]);printf("ZA=%d\n",Data_Buf[2]);printf("/***********************/\n");HAL_Delay(1000);/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */ }
