当前位置: 首页 > news >正文

基于stm32的四旋翼飞行器:MPU6050讲解 · 上(参数读取)

大伙早上好,不知道大伙有没有飞行器情结,就是学习嵌入式就想做一个能飞的东西。小白兔不才,小白兔有啊,所以最近准备做一个简单的飞行器出来,如果失败了,那么这个系列就只能烂尾了,如果成功了,那大伙也都会拥有一个自己的飞行器了。

在这里插入图片描述

文章目录

  • 前言
  • MPU6050 详细说明
    • 概述
    • 核心特性
      • 传感器性能
      • 通信接口
    • 硬件接口
    • 工作原理
      • 加速度计
      • 陀螺仪
      • 数据融合
        • 这部分内容我们下一期里会详细讲解。
  • 寄存器介绍
    • PWR_MGMT_1 寄存器
      • 功能概述
    • GYRO_CONFIG 寄存器
      • 功能概述
    • ACCEL_CONFIG 寄存器
      • 功能概述
    • PWR_MGMT_2 寄存器
      • 功能概述
  • 数据读取代码编写
    • MPU6050.h
    • MPU6050.c
    • MPU6050_Reg.h
    • main.c
  • 结语
  • 感谢大伙观看,别忘了三连支持一下
  • 大家也可以关注一下我的其它专栏,同样精彩喔~
  • 下期见咯~

前言

这个系列我们志在做出一个四旋翼飞行器,然后按照我现在的了解,我将这个项目分成了三个大步骤进行制作学习。

  1. 首先是 MPU6050 学习,我们需要通过 陀螺仪加速度器 获取飞行器的 pitch(俯仰角)、yaw(偏航角)、roll(横滚角) 三个参数,以此为凭据通过更改旋翼让飞行器保持平衡和行动。这部分我们也是分为三期进行,具体的大伙看下去就知道了。
  2. 然后第二步是飞行器的模型设计,包括飞行器的 3D模型,PCB设计 等。
  3. 最后就是代码编写,这部分应该是比较麻烦的一个任务了,但是可以参考网上大佬的例程,

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
SCLI2C 时钟线
SDAI2C 数据线
AD0I2C 地址选择位
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

感谢大伙观看,别忘了三连支持一下

大家也可以关注一下我的其它专栏,同样精彩喔~

下期见咯~

请添加图片描述

相关文章:

  • C语言中,sizeof关键字(详细介绍)
  • java Servlet Session 本身局限性解决方案
  • 【libuv】基于libuv的exe链接错误
  • Kubernetes(k8s)学习笔记(四)--入门基本操作
  • AI 采用金字塔(Sohn‘s AI Adoption Pyramid)
  • Linux操作系统从入门到实战(五)详细讲解Linux权限概念
  • Python Django基于小波变换的数字水印技术实现系统【附源码、文档说明】
  • Docker —— 技术架构的演进
  • Linux实验课二(重点:动态链接库,makefile使用)
  • 经典算法 求解台阶问题
  • 【RocketMQ NameServer】- NettyEventExecutor 处理 Netty 事件
  • 软件测试 - 绪论
  • 【计算机网络-应用层】解析HTTP会话保持:Cookie与Session的原理与实践
  • 昇腾的昇思MindSpore是什么?跟TensorFlow/PyTorch 等第三方框架有什么区别和联系?【浅谈版】
  • 机器学习中的分类和回归问题
  • 网络安全系列--《文章1:网络安全基础与核心概念》
  • LeetCode Hot100题解
  • Dubbo(92)如何在微服务架构中应用Dubbo?
  • 电脑RGB888P转换为JPEG方案 ,K230的RGB888P转换为JPEG方案
  • 【C++重载操作符与转换】赋值操作符
  • 长三角铁路今日预计发送旅客398万人次,客流持续保持高位运行
  • 客场不敌蓉城遭遇联赛首败,申花争冠需要提升外援能力
  • 媒体:机票盲盒值不值得开?年轻人正用行为博弈的逻辑重构规则
  • 新华每日电讯头版聚焦上海:科创高地向未来
  • 美国经济萎缩意味着什么?关税政策如何反噬经济?
  • “上博号”彩绘大飞机今日启航:万米高空传播中国古代文化