MPU6050模块是一款由InvenSense公司生产的数字运动处理器,它集成了三轴陀螺仪和三轴加速度计,采用MEMS技术,可以通过I2C接口与其他微控制器进行通信。
MPU6050模块中的加速度计和陀螺仪分别测量物体在三个轴上的加速度和角速度。加速度计的输出被称为加速度,而陀螺仪的输出被称为角速度。经过一些复杂的数学运算和算法,可以将这些数据转换为物体的姿态、位置和移动方向等信息。
除了加速度计和陀螺仪之外,MPU6050还具有许多其他功能。例如,它内置了一个温度传感器,可以测量环境温度并输出一个温度值;另外,它还包含一个数字低通滤波器,可用于去除高频噪声和干扰。此外,MPU6050还具有两个可编程中断引脚和一些可编程GPIO引脚,使其能够适应不同的应用场景。
MPU6050模块的输出数据可以通过I2C接口传输给其他微控制器或单片机,如Arduino或树莓派等。但是,由于其集成了多种传感器和计算功能,因此对于一些复杂的应用程序而言,这些外部处理器可能无法完成所有的计算任务。为了解决这个问题,MPU6050还支持数字运动处理器(DMP)功能,可以在芯片内部进行一些姿态计算和滤波操作,并将结果输出给外部微控制器或应用程序。
总之,MPU6050模块是一款非常实用的惯性传感器模块,具有高精度、低功耗、多种功能和易于编程等特点。它被广泛应用于机器人、遥控器、运动追踪器、智能家居和其他需要精确运动控制的应用领域。
可以用于设置数字低通滤波器的截止频率、加速度计和角速度计的初始采样率和选择外部同步信号的触发方式。
DLPF_CFG[2:0]: 数字低通滤波器配置位,用于设置数字低通滤波器的截止频率、加速度计和角速度计初始采样率,加速度计采样率在1KHz时才能有效配置数字低通滤波器截止频率。可选值包括:
需要注意的是,数字低通滤波器的截止频率越高,输出数据的带宽越宽,但也越容易受到高频干扰,数据的噪声也会增加。
EXT_SYNC_SET[2:0]:外部同步信号触发位,用于选择外部同步信号的触发方式。可选值包括:
DLPF_CFG 和 EXT_SYNC_SET 的设置还可以结合使用,以实现更加精细的滤波和同步控制。具体来说,可以根据不同的需求将数字低通滤波器和外部同步信号结合使用,实现以下功能:
需要注意的是,数字低通滤波器和外部同步信号的设置需要根据具体的应用场景和需求进行选择,以达到最优的效果。同时,在进行设置时还需要考虑采样率和带宽的匹配问题,以保证输出数据的准确性和稳定性。
用于配置加速度计的量程范围、自检和高通滤波器等功能。
AFS_SEL[1:0]:加速度计量程位,用于设置加速度计的量程范围,可选值包括:
ACCEL_HPF[2:0]: 高通滤波器截止频率配置位。可选值包括:
说明:相比加速度计的测量值,陀螺仪的测量值通常受到低频振动的影响较小,因此在 MPU6050 中没有对陀螺仪进行高通滤波器配置。
XA_ST、YA_ST、ZA_ST:加速度计自检使能位,用于加速度计的自检功能,这三个位分别对应X、Y、Z轴。当设置为1时,加速度计将进行自检,自检时需要将加速度计放在静止的表面上。自检完成后,这些位将自动清除。正常使用时,这些位应该设置为0。
用于配置角速度计的量程范围和自检测功能等。
FS_SEL[1:0]: 陀螺仪量程选择位,用于设置陀螺仪的量程范围。可选值包括:
需要注意的是,量程范围越大,陀螺仪可以测量的角速度范围也越大,但精度也会相应降低。
XG_ST, YG_ST, ZG_ST: 陀螺仪自检测使能位,用于启用或禁用陀螺仪自检测功能。当这些位被置为 1 时,陀螺仪会进行自检测,通过比较自检测前后的输出数据来检测陀螺仪是否正常工作。这些位域的具体含义如下:
需要注意的是,陀螺仪自检测功能只适用于陀螺仪,不适用于加速度计。
举例:
如果要将陀螺仪的量程范围设置为±500°/s,并启用 X 轴的自检测功能,可以将 GYRO_CONFIG 寄存器设置为 0x88=1000 1000,其中:
提前创建一个文件夹,用来存放工程(文件夹路径建议全英文)
打开STM32CubeMX,选择芯片(这里选择STM32F103ZET6),配置Debug,ST-LINK选择Serial Wire。
使能HSE和LSE,配置时钟频率为72M。
由于要使用OLED模块显示采集到的加速度、角速度和温度数据,因此配置硬件IIC,这里使能IIC1,对应STM32F103ZET6引脚为PB6和PB7。
对STM32CubeMX驱动OLED有疑问的点击这里(内含OLED驱动源码提取方式)
因为MPU6050常用通信协议为IIC,因此使能IIC2,对应STM32F103ZET6引脚为PB10和PB11。
创建工程名,配置编译环境。
这里用keil5编译,因此选择MDK-ARM-V5。
点击配置代码生成器并生成代码。
点击GENERATE CODE即可生成代码。
打开工程存放的位置。
移植MPU6050相关的.h和.c文件到工程中。
相关文件提取方式:
关注微信公众号:码上芯路人
私信:模块驱动
说明:MPU6050.h中是一些宏定义和MPU6050相关的函数声明,MPU6050.c中是MPU6050相关函数的定义。
将MPU6050.h、oled.h和oledfont.h文件复制到工程文件目录MPU6050_test\Core\Inc中
将oled.c和MPU6050.c文件复制到工程文件目录MPU6050_test\Core\Src中
双击打开MPU6050_test\MDK-ARM目录中UVPROJX文件,按下图提示操作。
编译后oled.h和oledfont.h将被包含在oled.c目录下,MPU6050.h将被包含在MPU6050.c目录下。
下面介绍驱动函数。
函数的定义见MPU6050.c文件
函数定义如下:
/*
@brief 写入MPU6050寄存器数据
@param mpu6050: MPU6050设备结构体指针
@param regAddr: 要写入的寄存器地址
@param data: 要写入的数据
@retval 返回HAL库操作状态
*/
static HAL_StatusTypeDef MPU6050_WriteReg(MPU6050_t* mpu6050, uint8_t regAddr, uint8_t data)
{
return HAL_I2C_Mem_Write(mpu6050->hi2c, mpu6050->devAddr, regAddr, I2C_MEMADD_SIZE_8BIT, &data, 1, 1000);
}
/*
@brief 读取MPU6050寄存器数据
@param mpu6050: MPU6050设备结构体指针
@param regAddr: 要读取的寄存器地址
@param pData: 存储读取数据的缓冲区指针
@param size: 要读取的数据长度(字节)
@retval 返回HAL库操作状态
*/
static HAL_StatusTypeDef MPU6050_ReadReg(MPU6050_t* mpu6050, uint8_t regAddr, uint8_t* pData, uint16_t size)
{
return HAL_I2C_Mem_Read(mpu6050->hi2c, mpu6050->devAddr, regAddr, I2C_MEMADD_SIZE_8BIT, pData, size, 1000);
}
/*
@brief 初始化MPU6050设备
@param mpu6050: MPU6050设备结构体指针
@param hi2c: I2C句柄
*/
这两个函数的作用即向MPU6050写入/读取寄存器数据。
这两个函数实际上是调用了 HAL 库提供的 I2C 读写函数 HAL_I2C_Mem_Write(),HAL_I2C_Mem_Read() 进行 I2C 通信。其中,HAL_I2C_Mem_Write() 用于向 I2C设备的指定地址写入数据,HAL_I2C_Mem_Read() 用于从 I2C 设备的指定地址读取数据。
这两个函数一般在其它函数中嵌套使用。
函数声明如下:
void MPU6050_Init(MPU6050_t* mpu6050, I2C_HandleTypeDef* hi2c);
函数声明如下:
void MPU6050_SetLPF(MPU6050_t* mpu6050, MPU6050_LPF_CUTOFF_FREQ_t lpf_cutoff_freq);
函数内部定义一个8位的变量data,使用switch-case语句,不同的lpf_cutoff_freq对应的data即为对应要写入寄存器CONFIG的数据,默认禁用外部同步信号。需要开启外部同步信号时参照芯片手册修改函数。
/* 数字低通滤波器截止频率配置 */
typedef enum {
LPF_CUTOFF_FREQ_5HZ = 0, //截止频率5HZ 初始采样率1KHZ
LPF_CUTOFF_FREQ_10HZ, //截止频率10HZ 初始采样率1KHZ
LPF_CUTOFF_FREQ_21HZ, //截止频率21HZ 初始采样率1KHZ
LPF_CUTOFF_FREQ_44HZ, //截止频率44HZ 初始采样率1KHZ
LPF_CUTOFF_FREQ_94HZ, //截止频率94HZ 初始采样率1KHZ
LPF_CUTOFF_FREQ_184HZ, //截止频率184HZ 初始采样率1KHZ
LPF_CUTOFF_FREQ_260HZ, //截止频率260HZ 初始采样率8KHZ
LPF_CUTOFF_FREQ_3600HZ //禁用低通滤波器 初始采样率8KHZ
} MPU6050_LPF_CUTOFF_FREQ_t;
函数声明如下:
void MPU6050_SetSampleRate(MPU6050_t* mpu6050, MPU6050_SAMPLE_RATE_t sample_rate);
函数内部定义一个8位的变量data,使用switch-case语句,不同的sample_rate对应的data即为对应要写入寄存器SMPRT_DIV的分频数据。
/* 采样率配置 */
typedef enum {
SAMPLE_RATE_DIV0 = 0, //0分频
SAMPLE_RATE_DIV2, //2分频
SAMPLE_RATE_DIV4, //4分频
SAMPLE_RATE_DIV8, //8分频
SAMPLE_RATE_DIV16, //16分频
SAMPLE_RATE_DIV32, //32分频
SAMPLE_RATE_DIV64, //64分频
SAMPLE_RATE_DIV128 //128分频
} MPU6050_SAMPLE_RATE_t;
函数声明如下:
void MPU6050_SetAccelFS(MPU6050_t* mpu6050, MPU6050_ACCEL_FS_SEL_t accel_fs_sel);
函数内部定义一个8位的变量data,使用switch-case语句,不同的accel_fs_sel对应的data即为对应要写入寄存器ACCEL_CONFIG的数据,默认关闭高通滤波器和自检,需要使用时参照芯片手册修改。
/* 加速度计灵敏度配置 */
typedef enum {
ACCEL_FS_SEL_2G = 0, // ±2g
ACCEL_FS_SEL_4G, // ±4g
ACCEL_FS_SEL_8G, // ±8g
ACCEL_FS_SEL_16G // ±16g
} MPU6050_ACCEL_FS_SEL_t;
说明:量程越大,灵敏度相应越低。
函数声明如下:
void MPU6050_SetGyroFS(MPU6050_t* mpu6050, MPU6050_GYRO_FS_SEL_t gyro_fs_sel);
函数内部定义一个8位的变量data,使用switch-case语句,不同的gyro_fs_sel对应的data即为对应要写入寄存器GYRO_CONFIG的数据,默认关闭自检,需要使用自检时参照芯片手册修改。
/* 陀螺仪灵敏度配置 */
typedef enum {
GYRO_FS_SEL_250DPS = 0, // ±250dps
GYRO_FS_SEL_500DPS, // ±500dps
GYRO_FS_SEL_1000DPS, // ±1000dps
GYRO_FS_SEL_2000DPS // ±2000dps
} MPU6050_GYRO_FS_SEL_t;
说明:量程越大,灵敏度相应越低。
函数声明如下:
void MPU6050_ReadAccel(MPU6050_t* mpu6050, float* ax, float* ay, float* az);
函数声明如下:
void MPU6050_ReadGyro(MPU6050_t* mpu6050, float* gx, float* gy, float* gz);
函数声明如下:
float MPU6050_ReadTemp(MPU6050_t* mpu6050);
先将模块静止在桌面,然后晃动模块,最后用体温对芯片进行热传递,观察OLED显示的加速度值、角速度值和温度值变化。
主函数内容如下:
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "i2c.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "oled.h"
#include "MPU6050.h"
#include "stdio.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
uint8_t accelX_buff[16]={0},accelY_buff[16]={0},accelZ_buff[16]={0};
uint8_t gyroX_buff[16]={0},gyroY_buff[16]={0},gyroZ_buff[16]={0};
uint8_t temp_buff[16]={0};
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
// 定义一个MPU6050结构体
MPU6050_t mpu6050
= {
.hi2c=&hi2c2,
.devAddr = 0xD0, // 设备地址
.initialized = 0 // 设备是否已初始化
};
float ax, ay, az, gx,gy,gz,temp;
/* 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();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
MX_I2C2_Init();
/* USER CODE BEGIN 2 */
OLED_Init();
OLED_Clear();
MPU6050_Init(&mpu6050, &hi2c2);
if (mpu6050.initialized)
{
OLED_ShowString(0,0,"MPU6050 initialized successfully!",16);
}
else
{
OLED_ShowString(0,0,"MPU6050 initialization failed.",16);
return -1;
}
OLED_Clear();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
/* 读取加速度计数据 */
MPU6050_ReadAccel(&mpu6050, &ax, &ay, &az);
/* 读取加速度计数据 */
MPU6050_ReadGyro(&mpu6050, &gx, &gy, &gz);
/* 读取温度数据 */
temp = MPU6050_ReadTemp(&mpu6050);
/* 打印数据到串口 */
sprintf((char*)accelX_buff,"AccelX:%-.3f ",ax);
OLED_ShowString(0,0,accelX_buff,8);
sprintf((char*)accelY_buff,"AccelY:%-.3f ",ay);
OLED_ShowString(0,1,accelY_buff,8);
sprintf((char*)accelZ_buff,"AccelZ:%-.3f ",az);
OLED_ShowString(0,2,accelZ_buff,8);
sprintf((char*)gyroX_buff,"Gyro X:%-.3f ",gx);
OLED_ShowString(0,3,gyroX_buff,8);
sprintf((char*)gyroY_buff,"Gyro Y:%-.3f ",gy);
OLED_ShowString(0,4,gyroY_buff,8);
sprintf((char*)gyroZ_buff,"Gyro Z:%-.3f ",gz);
OLED_ShowString(0,5,gyroZ_buff,8);
sprintf((char*)temp_buff,"Temp :%-.3f ",temp);
OLED_ShowString(0,6,temp_buff,8);
}
/* USER CODE END 3 */
}
效果如下:
MPU6050_实验