[项目]基于FreeRTOS的STM32四轴飞行器: 十一.MPU6050配置与读取

news2025/3/31 3:26:20

基于FreeRTOS的STM32四轴飞行器: 十一.MPU6050

  • 一.芯片介绍
  • 二.配置I2C
  • 三.编写驱动
  • 四.读取任务的测试
  • 五.MPU6050六轴数据的校准

一.芯片介绍

芯片应该放置在PCB中间,X Y轴原点,敏感度131表示范围越小越灵敏。理想状态放置在地面上X,Y,Z轴为0,即使地面极平有可能锡膏导致芯片倾斜。
在这里插入图片描述
在这里插入图片描述
AD0接地和接电源地址不一样:
在这里插入图片描述
寄存器介绍:
在这里插入图片描述
在这里插入图片描述

二.配置I2C

观察原理图:
在这里插入图片描述
CubeMX中配置I2C1,配置Master Features 速度为高速,400KHz,占空比33%。
在这里插入图片描述
配置PB3为下拉输入模式:
在这里插入图片描述

三.编写驱动

I2C协议中,地址需要左移1位,最低位表示读写方向
0 表示写操作,1 表示读操作,直接将查好寄存器的代码直接移植。
在这里插入图片描述
写入寄存器和读取寄存器函数:

/**
 * @description: 向指定的寄存器写入一个字节
 * @param {uint8_t} reg
 * @param {uint8_t} byte
 * @return {*}
 */
void Inf_MPU6050_WriteReg(uint8_t reg, uint8_t byte)
{
    HAL_I2C_Mem_Write(&hi2c1,
                      MPU6050_ADDR_W,
                      reg,
                      I2C_MEMADD_SIZE_8BIT,
                      &byte,
                      1,
                      2000);
}

/**
 * @description: 从指定的寄存器startReg写入多个字节
 * @param {uint8_t} startReg 开始寄存器地址
 * @param {uint8_t} *bytes 写的字节数据
 * @param {uint8_t} len 多少个字节
 * @return {*}
 */
void Inf_MPU6050_WriteRegs(uint8_t startReg, uint8_t *bytes, uint8_t len)
{
    HAL_I2C_Mem_Write(&hi2c1,
                      MPU6050_ADDR_W,
                      startReg,
                      I2C_MEMADD_SIZE_8BIT,
                      bytes,
                      len,
                      2000);
}

/**
 * @description: 从指定的寄存器读取一个字节
 * @param {uint8_t} reg
 * @return {*}
 */
uint8_t Inf_MPU6050_ReadReg(uint8_t reg)
{
    uint8_t rByte = 0;
    HAL_I2C_Mem_Read(&hi2c1,
                     MPU6050_ADDR_R,
                     reg,
                     I2C_MEMADD_SIZE_8BIT,
                     &rByte,
                     1,
                     2000);
    return rByte;
}

/**
 * @description: 从指定的寄存器读取多个字节
 * @param {uint8_t} startReg
 * @param {uint8_t} *bytes
 * @param {uint8_t} len
 * @return {*}
 */
void Inf_MPU6050_ReadRegs(uint8_t startReg, uint8_t *bytes, uint8_t len)
{
    HAL_I2C_Mem_Read(&hi2c1,
                     MPU6050_ADDR_R,
                     startReg,
                     I2C_MEMADD_SIZE_8BIT,
                     bytes,
                     len,
                     2000);
}

根据数据手册MPU6050初始化流程配置:
在这里插入图片描述
低通滤波器:
数据输出速率1kHz。
在这里插入图片描述
采样率:
采样率是多少的时候,才能正确的反应模拟。
香农定律(麦克斯韦定律):采样率 >= 2 * 最高的频率
这时候可以根据数字信号还原出模拟信号了。
采样频率 = 陀螺仪输出频率 / (1 + SMPLRT_DIV)
500Hz = 1000Hz / (1 + x)
x = 1
因为飞控任务调度周期是4ms,意味着1S执行250次,这时采样频率为500Hz可以1S将数据转换500次,转换多读取少没问题,不能低于250Hz。
在这里插入图片描述
加速度和陀螺仪是否进入待机模式:
在这里插入图片描述
读取角速度:
在这里插入图片描述
读取加速度:
在这里插入图片描述
初始化:

/**
 * @description: mpu6050初始化函数
 * @return {*}
 */
void Inf_MPU6050_Init(void)
{
    /* 1. 复位MPU6050:   复位->休眠200ms->唤醒 */
    Inf_MPU6050_WriteReg(MPU_PWR_MGMT1_REG, 1 << 7);
    HAL_Delay(200);
    Inf_MPU6050_WriteReg(MPU_PWR_MGMT1_REG, 0);
    /* 2. 设置量程 */
    /* 2.1 角速度的量程  +-2000°/s */
    Inf_MPU6050_WriteReg(MPU_GYRO_CFG_REG, 3 << 3);
    /* 2.2 加速度的量程  +2g  */
    Inf_MPU6050_WriteReg(MPU_ACCEL_CFG_REG, 0);
    /* 3. 关闭中断、关闭 第2 IIC 接口、禁止 FIFO */
    Inf_MPU6050_WriteReg(MPU_INT_EN_REG, 0);
    Inf_MPU6050_WriteReg(MPU_USER_CTRL_REG, 0);
    Inf_MPU6050_WriteReg(MPU_FIFO_EN_REG, 0);

    /* 4. 设置陀螺仪采样率和低通滤波器
        低通滤波器:  数据输出速率时 1kHz

        采样率: 采样率是多少的时候,才能正确的反应模拟信号
            香浓定律(奈奎斯特定律): 采样率 >= 2 * 信号中最高的频率

            采样频率 = 陀螺仪输出频率 / (1 + SMPLRT_DIV)
            500Hz = 1000Hz / (1 + x)
            x = 1
     */

    Inf_MPU6050_WriteReg(MPU_SAMPLE_RATE_REG, 1); /*  采样率 */
    Inf_MPU6050_WriteReg(MPU_CFG_REG, 1 << 0);    /* 低通滤波器 */

    /* 5. 配置系统时钟源 */
    Inf_MPU6050_WriteReg(MPU_PWR_MGMT1_REG, 1);

    /* 6. 使能角速度传感器和加速度传感器   进入工作模式 (禁用待机模式)*/
    Inf_MPU6050_WriteReg(MPU_PWR_MGMT2_REG, 0);

    /* 校准6轴数据 */
    Inf_MPU6050_Calibrate();
}

读取角速度和加速度:

/**
 * @description: 读取角速度
 * @param {Gyro_Struct} *gyro
 * @return {*}
 */
void Inf_MPU6050_ReadGyro(Gyro_Struct *gyro)
{
    uint8_t data[6] = {0};
    Inf_MPU6050_ReadRegs(MPU_GYRO_XOUTH_REG, data, 6);

    gyro->gyroX = (int16_t)((data[0] << 8) | data[1]);
    gyro->gyroY = (int16_t)((data[2] << 8) | data[3]);
    gyro->gyroZ = (int16_t)((data[4] << 8) | data[5]);
}

/**
 * @description: 读取加速度
 * @param {Accel_Struct} *accel
 * @return {*}
 */
void Inf_MPU6050_ReadAccel(Accel_Struct *accel)
{
    uint8_t data[6] = {0};
    Inf_MPU6050_ReadRegs(MPU_ACCEL_XOUTH_REG, data, 6);
    accel->accelX = (int16_t)((data[0] << 8) | data[1]);
    accel->accelY = (int16_t)((data[2] << 8) | data[3]);
    accel->accelZ = (int16_t)((data[4] << 8) | data[5]);
}

/**
 * @description: 读取角速度和加速度
 * @param {GyroAccel_Struct} *gyroAccel
 * @return {*}
 */
void Inf_MPU6050_ReadGyroAccel(GyroAccel_Struct *gyroAccel)
{
    Inf_MPU6050_ReadGyro(&gyroAccel->gyro);
    Inf_MPU6050_ReadAccel(&gyroAccel->accel);
}

四.读取任务的测试

飞行模块中初始化MPU6050:
在这里插入图片描述
编写打印角速度加速度数据的函数:
在这里插入图片描述
观察打印数据,角速度和加速度都有误差值,应该尽量让前5个值为0。
在这里插入图片描述

五.MPU6050六轴数据的校准

在读取时使用HAL_Delay延时3ms,可以让读取的速度变慢,保证读取的值有意义。

得到需要校准的值:

/**
 * @description: 在水平平面静止状态下校准6轴数据
 *  1.确认飞机处于静止
 *      多次测量3轴数据(角速度),本次与上次对比,如果变化小于某个阈值,则认为飞机处于静止状态
 *  2.多次测量计算偏移
 *
 *
 * @return {*}
 */
void Inf_MPU6050_Calibrate(void)
{
    /* 1.确认静止  */
    uint8_t          cnt = 30;
    GyroAccel_Struct current;
    GyroAccel_Struct last;
    debug_printfln(" 陀螺仪: 等待静止");
    while(cnt)
    {
        Inf_MPU6050_ReadGyroAccel(&current);
        if(abs(current.gyro.gyroX - last.gyro.gyroX) <= 10 &&
           abs(current.gyro.gyroY - last.gyro.gyroY) <= 10 &&
           abs(current.gyro.gyroZ - last.gyro.gyroZ) <= 10)
        {
            cnt--;
        }

        last = current; /* 上次的结构体执行这次 */
        HAL_Delay(3);
    }
    debug_printfln(" 陀螺仪: 已经静止");

    debug_printfln(" 陀螺仪: 开始校准");
    int32_t  sumBuff[6] = {0};
    uint16_t sumCount   = 255;
    for(uint16_t i = 0; i < sumCount; i++)
    {
        Inf_MPU6050_ReadGyroAccel(&gyroAccel);
        sumBuff[0] += gyroAccel.gyro.gyroX - 0;
        sumBuff[1] += gyroAccel.gyro.gyroY - 0;
        sumBuff[2] += gyroAccel.gyro.gyroZ - 0;
        sumBuff[3] += gyroAccel.accel.accelX - 0;
        sumBuff[4] += gyroAccel.accel.accelY - 0;
        sumBuff[5] += gyroAccel.accel.accelZ - 16383;

        HAL_Delay(3);
    }

    offsetGyroAccel.gyro.gyroX   = sumBuff[0] / sumCount;
    offsetGyroAccel.gyro.gyroY   = sumBuff[1] / sumCount;
    offsetGyroAccel.gyro.gyroZ   = sumBuff[2] / sumCount;
    offsetGyroAccel.accel.accelX = sumBuff[3] / sumCount;
    offsetGyroAccel.accel.accelY = sumBuff[4] / sumCount;
    offsetGyroAccel.accel.accelZ = sumBuff[5] / sumCount;

    // Com_Config_PrintGyroAccel("cal", &offsetGyroAccel);
    debug_printfln(" 陀螺仪: 结束校准");
}

需要在读取角速度和角速度后减去需要校准的值
在这里插入图片描述
校准后数据如下:

void Inf_MPU6050_ReadGyroAccelCalibrated(GyroAccel_Struct *gyroAccel)
{
    /* 获取原始数据 */
    Inf_MPU6050_ReadGyroAccel(gyroAccel);

    /* 减去校准值 */
    gyroAccel->gyro.gyroX -= offsetGyroAccel.gyro.gyroX;
    gyroAccel->gyro.gyroY -= offsetGyroAccel.gyro.gyroY;
    gyroAccel->gyro.gyroZ -= offsetGyroAccel.gyro.gyroZ;
    gyroAccel->accel.accelX -= offsetGyroAccel.accel.accelX;
    gyroAccel->accel.accelY -= offsetGyroAccel.accel.accelY;
    gyroAccel->accel.accelZ -= offsetGyroAccel.accel.accelZ;
}

观察发现数据仍然有些许波动,需编写滤波算法进行滤波
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2323029.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

后端学习day1-Spring(八股)--还剩9个没看

一、Spring 1.请你说说Spring的核心是什么 参考答案 Spring框架包含众多模块&#xff0c;如Core、Testing、Data Access、Web Servlet等&#xff0c;其中Core是整个Spring框架的核心模块。Core模块提供了IoC容器、AOP功能、数据绑定、类型转换等一系列的基础功能&#xff0c;…

【赵渝强老师】在Docker中运行达梦数据库

Docker是一个客户端服务器&#xff08;Client-Server&#xff09;架构。Docker客户端和Docker守护进程交流&#xff0c;而Docker的守护进程是运作Docker的核心&#xff0c;起着非常重要的作用&#xff08;如构建、运行和分发Docker容器等&#xff09;。达梦官方提供了DM 8在Doc…

Python电影市场特征:AR模型时间序列趋势预测、热图可视化评分影响分析IMDb数据|附数据代码

原文链接&#xff1a;https://tecdat.cn/?p41214 分析师&#xff1a;Zhiheng Lin 在数字时代&#xff0c;电影产业的数据分析已成为洞察市场趋势与用户偏好的重要工具。本专题合集聚焦印度电影市场&#xff0c;通过IMDb数据集&#xff08;IMDb Movies Dataset&#xff09;的深…

扭蛋机小程序开发,潮玩娱乐消费风口下的机遇

随着Z世代消费能力的提升和盲盒经济的火爆&#xff0c;扭蛋文化正迎来爆发式增长。 扭蛋机作为一种充满惊喜感的消费模式&#xff0c;正从线下走向线上&#xff0c;并借助移动互联网实现了数字化转型。线上扭蛋机小程序不仅延续了传统扭蛋的趣味性&#xff0c;还通过数字化手段…

各类神经网络学习:(五)LSTM 长短期记忆(上集),结构详解

上一篇下一篇RNN&#xff08;下集&#xff09;待编写 LSTM&#xff08;长短期记忆&#xff09; 参考知乎文章《人人都能看懂的LSTM介绍及反向传播算法推导&#xff08;非常详细&#xff09; - 知乎》&#xff0c;部分图片也进行了引用。 参考视频教程《3.结合例子理解LSTM_哔哩…

计算机网络-2 物理层

【考纲内容】 &#xff08;一&#xff09;通信基础 信道、信号、带宽、码元、波特、速率、信源与信宿等基本概念&#xff1b; 奈奎斯特定理与香农定理&#xff1b;编码与调制&#xff1b; 电路交换、报文交换与分组交换&#xff1b;数据报与虚电路① 视频讲解 &#xff08;二…

Redis集群哨兵相关面试题

目录 1.Redis 主从复制的实现原理是什么? 详解 补充增量同步 replication buffer repl backlog buffer 2.Redis 主从复制的常见拓扑结构有哪些? 3.Redis 复制延迟的常见原因有哪些? 4.Redis 的哨兵机制是什么? 主观下线和客观下线 哨兵leader如何选出来的&#x…

Shopify Checkout UI Extensions

结账界面的UI扩展允许应用开发者构建自定义功能&#xff0c;商家可以在结账流程的定义点安装&#xff0c;包括产品信息、运输、支付、订单摘要和Shop Pay。 Shopify官方在去年2024年使用结账扩展取代了checkout.liquid&#xff0c;并将于2025年8月28日彻底停用checkout.liquid…

MOSN(Modular Open Smart Network)-04-TLS 安全链路

前言 大家好&#xff0c;我是老马。 sofastack 其实出来很久了&#xff0c;第一次应该是在 2022 年左右开始关注&#xff0c;但是一直没有深入研究。 最近想学习一下 SOFA 对于生态的设计和思考。 sofaboot 系列 SOFAStack-00-sofa 技术栈概览 MOSN&#xff08;Modular O…

Softmax 回归 + 损失函数 + 图片分类数据集

Softmax 回归 softmax 回归是机器学习另外一个非常经典且重要的模型&#xff0c;是一个分类问题。 下面先解释一下分类和回归的区别&#xff1a; 简单来说&#xff0c;分类问题从回归的单输出变成了多输出&#xff0c;输出的个数等于类别的个数。 实际上&#xff0c;对于分…

【C++】内存模型分析

在 C 语言中&#xff0c;程序运行时的内存通常被划分为以下几个区域&#xff1a; 代码区&#xff08;Text Segment&#xff09;常量区&#xff08;Constant Segment&#xff09;全局/静态区&#xff08;Data Segment&#xff0c;包含静态数据段和 BSS 段&#xff09;堆区&…

Vue2+OpenLayers携带请求头加载第三方瓦片数据

目录 一、案例截图 二、安装OpenLayers库 三、代码实现 一、案例截图 在对接一些第三方GIS地图的时候,需要携带请求头来验证身份,从而获取相应的瓦片数据,这时候我们需要改造一下WMTS服务的调用方式,效果如图所示: 二、安装OpenLayers库 npm install ol 三、代码实现…

智能汽车图像及视频处理方案,支持视频实时拍摄特效能力

在智能汽车日新月异的今天&#xff0c;美摄科技作为智能汽车图像及视频处理领域的先行者&#xff0c;凭借其卓越的技术实力和前瞻性的设计理念&#xff0c;为全球智能汽车制造商带来了一场视觉盛宴的革新。美摄科技推出智能汽车图像及视频处理方案&#xff0c;一个集高效性、智…

数据结构--顺序表(实现增删改查)

三个文件&#xff08;Mytest.c 、MySeqList.c 、 MySeqList.h&#xff09; Mytest.c测试函数 MySeqList.c 函数定义 MySeqList.h函数声明 增删改查的步骤&#xff1a; 初始化 增加元素 • 尾插&#xff1a;先检查顺序表空间是否足够&#xff0c;若不足则进行扩容&#x…

【android】补充

3.3 常用布局 本节介绍常见的几种布局用法&#xff0c;包括在某个方向上顺序排列的线性布局&#xff0c;参照其他视图的位置相对排列的相对布局&#xff0c;像表格那样分行分列显示的网格布局&#xff0c;以及支持通过滑动操作拉出更多内容的滚动视图。 3.3.1 线性布局Linea…

说说MyBatis一、二级缓存和Spring一二级缓存有什么关系?

大家好&#xff0c;我是锋哥。今天分享关于【说说MyBatis一、二级缓存和Spring一二级缓存有什么关系&#xff1f;】面试题。希望对大家有帮助&#xff1b; 说说MyBatis一、二级缓存和Spring一二级缓存有什么关系&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源…

蓝桥杯题型分布2

蓝桥杯 蓝桥杯题型分类2素数孪生素数素数个数朴素筛法求素数线性筛法求素数 因数分解试除法分解质因数 等差素数列梅森素数组素数素数环找素数(分段筛&#xff09;连续素数和小明的素数对疑似素数质数拆分纯质数超级质数质数日期质数游戏2魔法阵的能量阿坤老师切割年糕阶乘分解…

vue响应式原理剖析

一、什么是响应式? 我们先来看一下响应式意味着什么?我们来看一段代码: m有一个初始化的值,有一段代码使用了这个值; 那么在m有一个新的值时,这段代码可以自动重新执行; let m = 20 console.log(m) console.log(m * 2)m = 40上面的这样一种可以自动响应数据变量的代码机…

Element UI实现表格全选、半选

制作如图所示的表格全选、半选&#xff1a; 父组件 <template><div id"app"><SelectHost :hostArray"hostArray" /></div> </template><script> import SelectHost from ./components/SelectHost.vue export default…