基于stm32的四旋翼飞行器:MPU6050讲解 · 上(参数读取)
大伙早上好,不知道大伙有没有飞行器情结,就是学习嵌入式就想做一个能飞的东西。小白兔不才,小白兔有啊,所以最近准备做一个简单的飞行器出来,如果失败了,那么这个系列就只能烂尾了,如果成功了,那大伙也都会拥有一个自己的飞行器了。
文章目录
- 前言
- MPU6050 详细说明
- 概述
- 核心特性
- 传感器性能
- 通信接口
- 硬件接口
- 工作原理
- 加速度计
- 陀螺仪
- 数据融合
- 这部分内容我们下一期里会详细讲解。
- 寄存器介绍
- PWR_MGMT_1 寄存器
- 功能概述
- GYRO_CONFIG 寄存器
- 功能概述
- ACCEL_CONFIG 寄存器
- 功能概述
- PWR_MGMT_2 寄存器
- 功能概述
- 数据读取代码编写
- MPU6050.h
- MPU6050.c
- MPU6050_Reg.h
- main.c
- 结语
- 感谢大伙观看,别忘了三连支持一下
- 大家也可以关注一下我的其它专栏,同样精彩喔~
- 下期见咯~
前言
这个系列我们志在做出一个四旋翼飞行器,然后按照我现在的了解,我将这个项目分成了三个大步骤进行制作学习。
- 首先是 MPU6050 学习,我们需要通过 陀螺仪 和 加速度器 获取飞行器的 pitch(俯仰角)、yaw(偏航角)、roll(横滚角) 三个参数,以此为凭据通过更改旋翼让飞行器保持平衡和行动。这部分我们也是分为三期进行,具体的大伙看下去就知道了。
- 然后第二步是飞行器的模型设计,包括飞行器的 3D模型,PCB设计 等。
- 最后就是代码编写,这部分应该是比较麻烦的一个任务了,但是可以参考网上大佬的例程,
MPU6050 详细说明
概述
MPU-6050 是 InvenSense(现属 TDK)推出的 六轴运动处理传感器,集成了 三轴陀螺仪、三轴加速度计 和 温度传感器,支持通过 I2C 接口 与主控通信。其内置的 DMP(Digital Motion Processor) 可直接解算姿态数据(四元数/欧拉角),大幅减轻主控计算负担。该传感器广泛用于无人机、平衡车、VR设备等运动控制场景。
核心特性
传感器性能
陀螺仪:量程 ±250°/s、±500°/s、±1000°/s、±2000°/s
加速度计:量程 ±2g、±4g、±8g、±16g
温度传感器:范围 -40°C 至 +85°C
分辨率:16位ADC,陀螺仪灵敏度最高 131 LSB/°/s
通信接口
I2C 接口:默认地址 0x68(AD0=0)或 0x69(AD0=1)
硬件接口
引脚 | 功能说明 |
---|---|
VCC | 电源 (3.3V-5V) |
GND | 地 |
SCL | I2C 时钟线 |
SDA | I2C 数据线 |
AD0 | I2C 地址选择位 |
INT | 中断输出(数据就绪/运动检测) |
工作原理
加速度计
基于 MEMS 电容式检测,测量 X/Y/Z 轴线性加速度。
公式:加速度值 = 原始值 / 灵敏度(灵敏度由量程决定,如 ±2g 对应 16384 LSB/g)。
陀螺仪
基于科里奥利力原理,测量角速度。
公式:角速度值 = 原始值 / 灵敏度(如 ±250°/s 对应 131 LSB/°/s)。
数据融合
使用 互补滤波 或 卡尔曼滤波 结合加速度计与陀螺仪数据,解算姿态角(Roll/Pitch/Yaw)。
这部分内容我们下一期里会详细讲解。
寄存器介绍
PWR_MGMT_1 寄存器
功能概述
该寄存器用于系统电源管理、时钟源配置及设备复位控制。关键位域定义如下:
位域 | 功能描述 |
---|---|
DEVICE_RESET | 置1触发全局复位操作,所有寄存器恢复默认值。复位完成后自动清零(典型耗时50μs)。 |
SLEEP | 置1使能低功耗睡眠模式,传感器模块停止采样,维持最小功耗(典型值5μA)。 |
CYCLE | 置1使能循环工作模式,配合SLEEP=0时,器件按LP_WAKE_CTRL(寄存器108)设定周期唤醒进行加速度采样(低功耗应用场景)。 |
TEMP_DIS | 置1关闭温度传感器,降低系统功耗(默认使能)。 |
CLKSEL[2:0] | 时钟源选择:000=内部8MHz RC振荡器; 001=PLL(X轴陀螺时钟); 010=PLL(Y轴陀螺时钟); 011=PLL(Z轴陀螺时钟); 100=外部32.768kHz晶振; 101=外部19.2MHz晶振 |
GYRO_CONFIG 寄存器
功能概述
该寄存器控制陀螺仪量程配置与轴自检功能,关键参数如下:
位域 | 功能描述 |
---|---|
XG_ST/YG_ST/ZG_ST 置1分别触发X/Y/Z轴陀螺仪自检。自检通过内部激励MEMS结构,验证机械与电气特性(需结合SELF_TEST寄存器分析响应值)。 | |
FS_SEL[1:0] 陀螺仪满量程配置: | |
00=±250°/s(灵敏度131 LSB/°/s) | |
01=±500°/s(65.5 LSB/°/s) | |
10=±1000°/s(32.8 LSB/°/s) | |
11=±2000°/s(16.4 LSB/°/s) |
ACCEL_CONFIG 寄存器
功能概述
该寄存器控制加速度计量程配置与轴自检功能,关键参数如下:
位域 | 功能描述 |
---|---|
XA_ST/YA_ST/ZA_ST | 置1分别触发X/Y/Z轴加速度计自检。自检通过内部施加静电力,验证传感器输出线性度与偏置。 |
AFS_SEL[1:0] | 加速度计满量程配置:00=±2g(灵敏度16384 LSB/g); 01=±4g(8192 LSB/g); 10=±8g(4096 LSB/g); 11=±16g(2048 LSB/g) |
PWR_MGMT_2 寄存器
功能概述
该寄存器控制传感器轴级功耗管理与低功耗模式唤醒频率,关键位域定义如下:
位域 | 功能描述 |
---|---|
LP_WAKE_CTRL[1:0] | 低功耗模式唤醒频率配置:00=1.25Hz; 01=5Hz; 10=20Hz; 11=40Hz(仅加速度计工作时生效) |
STBY_XA/YA/ZA | 置1分别使X/Y/Z轴加速度计进入待机模式(停止数据采集,降低功耗)。 |
STBY_XG/YG/ZG | 置1分别使X/Y/Z轴陀螺仪进入待机模式(若当前时钟源为对应陀螺轴,将自动切换至内部8MHz振荡器)。 |
数据读取代码编写
本期代码不涉及欧拉角,只是将MPU6050的参数读取出来。
这里我们采用软件I2C来读取数据:
使用 PB10 作为 SCL
使用 PB11 作为 SDA
本期里就不讲解 I2C 的相关内容了,下面就不呈现 I2C 的代码,大伙如果有需要,可以到另一期的文章里学习:stm32教程:软件I2C通信协议 & 代码模板提供
MPU6050.h
#ifndef __MPU6050_H
#define __MPU6050_Hvoid MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data);
uint8_t MPU6050_ReadReg(uint8_t RegAddress);void MPU6050_Init(void);
uint8_t MPU6050_GetID(void);
void MPU6050_GetData(int16_t *AccX, int16_t *AccY, int16_t *AccZ, int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ);#endif
MPU6050.c
#include "stm32f10x.h" // Device header
#include "MyI2C.h"
#include "MPU6050_Reg.h"#define MPU6050_ADDRESS 0xD0 //MPU6050的I2C从机地址void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
{MyI2C_Start(); //I2C起始MyI2C_SendByte(MPU6050_ADDRESS); //发送从机地址,读写位为0,表示即将写入MyI2C_ReceiveAck(); //接收应答MyI2C_SendByte(RegAddress); //发送寄存器地址MyI2C_ReceiveAck(); //接收应答MyI2C_SendByte(Data); //发送要写入寄存器的数据MyI2C_ReceiveAck(); //接收应答MyI2C_Stop(); //I2C终止
}uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{uint8_t Data;MyI2C_Start(); //I2C起始MyI2C_SendByte(MPU6050_ADDRESS); //发送从机地址,读写位为0,表示即将写入MyI2C_ReceiveAck(); //接收应答MyI2C_SendByte(RegAddress); //发送寄存器地址MyI2C_ReceiveAck(); //接收应答MyI2C_Start(); //I2C重复起始MyI2C_SendByte(MPU6050_ADDRESS | 0x01); //发送从机地址,读写位为1,表示即将读取MyI2C_ReceiveAck(); //接收应答Data = MyI2C_ReceiveByte(); //接收指定寄存器的数据MyI2C_SendAck(1); //发送应答,给从机非应答,终止从机的数据输出MyI2C_Stop(); //I2C终止return Data;
}void MPU6050_Init(void)
{MyI2C_Init(); //先初始化底层的I2C/*MPU6050寄存器初始化,需要对照MPU6050手册的寄存器描述配置,此处仅配置了部分重要的寄存器*/MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01); //电源管理寄存器1,取消睡眠模式,选择时钟源为X轴陀螺仪MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00); //电源管理寄存器2,保持默认值0,所有轴均不待机MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09); //采样率分频寄存器,配置采样率MPU6050_WriteReg(MPU6050_CONFIG, 0x06); //配置寄存器,配置DLPFMPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18); //陀螺仪配置寄存器,选择满量程为±2000°/sMPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18); //加速度计配置寄存器,选择满量程为±16g
}uint8_t MPU6050_GetID(void)
{return MPU6050_ReadReg(MPU6050_WHO_AM_I); //返回WHO_AM_I寄存器的值
}void MPU6050_GetData(int16_t *AccX, int16_t *AccY, int16_t *AccZ, int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ)
{uint8_t DataH, DataL; //定义数据高8位和低8位的变量DataH = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H); //读取加速度计X轴的高8位数据DataL = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L); //读取加速度计X轴的低8位数据*AccX = (DataH << 8) | DataL; //数据拼接,通过输出参数返回DataH = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H); //读取加速度计Y轴的高8位数据DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L); //读取加速度计Y轴的低8位数据*AccY = (DataH << 8) | DataL; //数据拼接,通过输出参数返回DataH = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H); //读取加速度计Z轴的高8位数据DataL = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L); //读取加速度计Z轴的低8位数据*AccZ = (DataH << 8) | DataL; //数据拼接,通过输出参数返回DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H); //读取陀螺仪X轴的高8位数据DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L); //读取陀螺仪X轴的低8位数据*GyroX = (DataH << 8) | DataL; //数据拼接,通过输出参数返回DataH = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H); //读取陀螺仪Y轴的高8位数据DataL = MPU6050_ReadReg(MPU6050_GYRO_YOUT_L); //读取陀螺仪Y轴的低8位数据*GyroY = (DataH << 8) | DataL; //数据拼接,通过输出参数返回DataH = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H); //读取陀螺仪Z轴的高8位数据DataL = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L); //读取陀螺仪Z轴的低8位数据*GyroZ = (DataH << 8) | DataL; //数据拼接,通过输出参数返回
}
MPU6050_Reg.h
#ifndef __MPU6050_REG_H
#define __MPU6050_REG_H#define MPU6050_SMPLRT_DIV 0x19
#define MPU6050_CONFIG 0x1A
#define MPU6050_GYRO_CONFIG 0x1B
#define MPU6050_ACCEL_CONFIG 0x1C#define MPU6050_ACCEL_XOUT_H 0x3B
#define MPU6050_ACCEL_XOUT_L 0x3C
#define MPU6050_ACCEL_YOUT_H 0x3D
#define MPU6050_ACCEL_YOUT_L 0x3E
#define MPU6050_ACCEL_ZOUT_H 0x3F
#define MPU6050_ACCEL_ZOUT_L 0x40
#define MPU6050_TEMP_OUT_H 0x41
#define MPU6050_TEMP_OUT_L 0x42
#define MPU6050_GYRO_XOUT_H 0x43
#define MPU6050_GYRO_XOUT_L 0x44
#define MPU6050_GYRO_YOUT_H 0x45
#define MPU6050_GYRO_YOUT_L 0x46
#define MPU6050_GYRO_ZOUT_H 0x47
#define MPU6050_GYRO_ZOUT_L 0x48#define MPU6050_PWR_MGMT_1 0x6B
#define MPU6050_PWR_MGMT_2 0x6C
#define MPU6050_WHO_AM_I 0x75#endif
main.c
#include "stm32f10x.h" // Device header
#include "OLED.h"
#include "Delay.h"
#include "Timer.h"
#include "MyI2C.h"
#include "MPU6050.h"uint8_t ID; //定义用于存放ID号的变量
int16_t AX, AY, AZ, GX, GY, GZ; //定义用于存放各个数据的变量int main()
{/*模块初始化*/OLED_Init(); //OLED初始化MyI2C_Init();MPU6050_Init(); //MPU6050初始化/*显示ID号*/OLED_ShowString(0, 0, "ID:", OLED_6X8);ID = MPU6050_GetID(); //获取MPU6050的ID号OLED_ShowHexNum(18, 0, ID, 5, OLED_6X8);OLED_Update();while (1){MPU6050_GetData(&AX, &AY, &AZ, &GX, &GY, &GZ); //获取MPU6050的数据OLED_ShowSignedNum(0, 8, AX, 5, OLED_6X8); //OLED显示数据OLED_ShowSignedNum(0, 16, AY, 5, OLED_6X8);OLED_ShowSignedNum(0, 24, AZ, 5, OLED_6X8);OLED_ShowSignedNum(0, 32, GX, 5, OLED_6X8);OLED_ShowSignedNum(0, 40, GY, 5, OLED_6X8);OLED_ShowSignedNum(0, 48, GZ, 5, OLED_6X8);OLED_Update();Delay_ms(500);}
}
结语
大伙可以从下面的网盘链接来下载本期的代码:
链接:小白兔的礼物—— MPU6050
提取码:k2kv