单片机开发教程3——串口发送MPU6050姿态角
文章目录
- 1. 简介
- 1.1 模块原理图
- 1.2 引脚说明
- 1.3 接线方式
- 2. IIC通信
- 2.1 IIC介绍
- 2.2 例程讲解
- 3. 姿态解算
- 3.1 欧拉角
- 3.2 解算方法
- 3.3 一阶互补滤波
- 4. 串口通信
- 4.1 概念
- 4.2 串口显示姿态角
- 4.3 接线图
1. 简介
MPU6050 是 InvenSense 公司推出的整合性 6 轴运动处理组件,其内部整合了 3 轴陀螺仪和 3 轴加速度传感器,并且含有一个IIC 接口, 可用于连接外部磁力传感器,并利用自带的数字运动处理器(DMP: Digital Motion Processor) 硬件加速引擎,通过主 IIC 接口,向应用端输出完整的 9 轴融合演算数据。
InvenSense 公司提供了一套基于DMP的运动处理驱动库,可大大降低单片机对动处理运算的负荷,同时也大大降低了编程难度。该模块广泛运用于飞控、计步等电子产品中。
1.1 模块原理图
1.2 引脚说明
序号 | 引脚 | 说明 |
---|---|---|
1 | VCC | 3.3V/5V |
2 | GND | 地线 |
3 | SCL | 作为从机时 IIC 时钟线 |
4 | SDA | 作为从机时 IIC 数据线 |
5 | XDA | 作为主机时 IIC 数据线 |
6 | XCL | 作为主机时 IIC 时钟线 |
7 | AD0 | 作为从机时 IIC 地址 |
8 | INT | 中断输出引脚 |
XDA和XCL是在MPU6050作为主机时的信号线,在与单片机的IIC通信中,MPU6050作为从机,所以用不到
AD0 是从 IIC 接口(接 MCU)的地址控制引脚,该引脚控制IIC 地址的最低位。由原理图可知,AD0 接了 GND,所以 MPU6050 的 IIC 地址默认为:0X68
INT也用不到,当模块需要输出数据时,可以通过该引脚给单片机中断信号,一般都不需要
1.3 接线方式
单片机 —— MPU6050
5V <——> VCC
GND <——> GND
Px.x <——> SCL
Px.x <——> SDA
2. IIC通信
如果你学过一段时间单片机,你或多或少会听说过IIC通信(也写作I2C,通常读作:I方C),这是硬件开发里很常见、很常用的一种通信协议。
其实协议并不是听上去的那么高不可攀,它终究是人为定义的一个标准而已,我们只需遵循这个标准就可以了。
这里面的协议层会涉及到时序,如果你还不是“老司机”,暂且可以放下不去专研,因为这些都会被封装为函数,使用格式也非常固定,完全不必担心。比如通信中最频繁的 读写操作 ,会被封装成 IIC读/写函数 ,而读写只能算是最基础的操作,还可以利用它进一步封装成各种设置函数和数据采集函数。
2.1 IIC介绍
I2C(Inter-Integrated Circuit)总线是由 PHILIPS 公司开发的两线式串行总线,用于连接微控制器及其外围设备。是微电子通信控制领域广泛采用的一种总线标准。它是 同步通信的一种特殊形式,具有接口线少,控制方式简单, 器件封装形式小,通信速率较高等优点。 I2C 总线 只有 两根双向信号线 。一根是 数据线 SDA ,另一根是 时钟线 SCL 。由于其管脚少,硬件实现简单,可扩展性强等特点,因此被广泛的使用在各大集成芯片内。
2.2 例程讲解
开发资料中的例程代码虽然很多,但最后在main函数里对MPU6050操作的只有两个函数,其他函数大多作为这两个函数的内容。其实,对于这种不小的工程项目,我们往往会写成多个文件,方便查看和使用,这就涉及到了工程项目的管理,后续可能还会出一篇教程 (>﹏<)
// 初始化MPU6050
void InitMPU6050()
{Single_WriteI2C(PWR_MGMT_1, 0x00); // #define PWR_MGMT_1 0x6BSingle_WriteI2C(SMPLRT_DIV, 0x07); // #define SMPLRT_DIV 0x19Single_WriteI2C(CONFIG, 0x06); // #define CONFIG 0x1ASingle_WriteI2C(GYRO_CONFIG, 0x18); // #define GYRO_CONFIG 0x1BSingle_WriteI2C(ACCEL_CONFIG, 0x01);// #define ACCEL_CONFIG 0x1C
}// 合成数据
int GetData(uchar REG_Address)
{uchar H,L;H=Single_ReadI2C(REG_Address); // 相应寄存器地址L=Single_ReadI2C(REG_Address+1);return ((H<<8)+L);
}
InitMPU6050 可以初始化模块,函数里对MPU6050的各个寄存器写入参数,从而实现初始化的功能,如果你想了解寄存器内部的配置原理,可以根据寄存器地址找到它的数据手册上对应的说明
GetData 可以返回采集的数据,值得注意的是这里得到数据不是角度,还需要进一步融合数据才能解算出姿态角
3. 姿态解算
3.1 欧拉角
欧拉角是最直观的一种姿态描述方式,所以在谈到姿态时,我们往往会使用欧拉角表达
一个坐标系到另一个坐标系的变换,可以通过绕不同坐标轴的3次连续转动来实现。这三次的转动角度统一称之为欧拉角
偏航角(Yaw)
机体系x轴投影到水平面与参考系x轴的夹角,顺时针旋转为正。俯仰角(Pitch)
机体系x轴与水平面的夹角,抬头为正。横滚角(Roll)
机体坐标系z轴与通过机体系x轴的铅垂面间的夹角,机体右旋为正。
3.2 解算方法
上面得到数据只是10位原始数据,我们需要把原始数据融合成与姿态有关的
欧拉角
这里有两种方法:
第一种是自己添加滤波算法,常用的有一阶互补滤波、二阶互补滤波和卡尔曼滤波等
第二种是直接使用MPU6050内部的DMP
DMP 是什么意思? DMP 就是指 MPU6050 内部集成的处理单元,可以直接运算出四元数和姿态,而不再需要另外进行数学运算。DMP 的使用大大简化了四轴的代码设计。DMP 是数字运动处理器的缩写,顾名思义 mpu6050 并不单单是一款传感器,其内部还包含了可以独立完成姿态解算算法的处理单元。如在设计中使用 DMP 来实现传感器融合算法优势很明显。首先,invensense 官方提供的姿态解算算法应该比像我们自己写的要可靠得多。其次,由 DMP 实现姿态解算算法将单片机从算法处理的压力中解放出来,单片机所要做的是等待DMP 解算完成后产生的外部中断,在外部中断里去读取姿态解算的结果。这样单片机有大量的时间来处理其他任务,提高了系统的实时性
经过 DMP 你就可以得到四元数,四元数就是 4 个数,可以表征姿态,经过几个数学公式之后就可以得出姿态,姿态包括 pitch,roll,yaw
下面介绍的是第一种方法的一阶互补滤波,因为51单片机对DMP的几个库函数不太兼容,或许后面会尝试解决并出教程 ╮(╯_╰)╭ ,而第一种算法网上有不少案例,实际使用上,两种方法对于初学者的难度都差不多
3.3 一阶互补滤波
需要注意的是,以下代码只能得到俯仰和滚转的数据,偏航角(Yaw)由于偏差太大没有输出值
以下代码不是完整的,还需要使用开发资料中的例程
//*******************************************************************************************************
//主程序
//*******************************************************************************************************
void main()
{ unsigned int time; // 保存定时器计数值float halfT; // 每次采样的时间int Ax,Ay,Az,Gx,Gy,Gz; // 加速度计和陀螺仪的原始数据 unsigned long Gravity;float AngleX1,AngleY1,AngleZ1,AngleX2,AngleY2,AngleZ2=0,dx,dy,dz;float Filter;Filter=0.8; //互补滤波系数delay(500); //上电延时init_uart();InitMPU6050(); 初始化MPU6050delay(150);while(1){Ax=GetData(ACCEL_XOUT_H);Ay=GetData(ACCEL_YOUT_H);Az=GetData(ACCEL_ZOUT_H);Gx=GetData(GYRO_XOUT_H);Gy=GetData(GYRO_YOUT_H);Gz=GetData(GYRO_ZOUT_H);TR0 = 0;time = (TH0<<8)|TL0;halfT = (time/1000000.)*(12/11.0592);// Display10BitData((int)(halfT*1000000)); //显示采样时间TH0 = 0;TL0 = 0;TR0 = 1;Gravity=sqrt((float)Ax*Ax+(float)Ay*Ay+(float)Az*Az); //Ax*Ax+Ay*Ay+Az*AzAngleX1=acos((float)Ax/Gravity)*180.0/3.14-90;;AngleY1=acos((float)Ay/Gravity)*180.0/3.14-90;AngleZ1=acos((float)Az/Gravity)*180.0/3.14;dy=halfT*Gx/-16.4; //陀螺仪测的转角ydx=halfT*Gy/16.4; //陀螺仪测的转角xdz=halfT*Gz/16.4; //陀螺仪测的转角z//x和y轴数据是融合加速度计和陀螺仪数据, z轴只采用陀螺仪数据AngleX2=Filter*(AngleX2+dx)+(1-Filter)*AngleX1; AngleY2=Filter*(AngleY2+dy)+(1-Filter)*AngleY1; // z轴数据有两种方式,一种是只使用陀螺仪的数据,舍弃z轴加速度(z轴零飘严重):AngleZ2=AngleZ2+dz; // 注意MPU6050必须芯片正面朝上SeriPushSend(0x20);SeriPushSend('X'); SeriPushSend(':');Display10BitData((int)AngleX2); //显示X轴角度SeriPushSend(0x20);SeriPushSend('Y'); SeriPushSend(':');Display10BitData((int)AngleY2); //显示Y轴角度SeriPushSend(0x20);SeriPushSend('Z'); SeriPushSend(':');Display10BitData((int)AngleZ2); //显示Z轴角度SeriPushSend(0x0d); SeriPushSend(0x0a);//换行,回车delay(500); // 控制采样频率}
}
4. 串口通信
4.1 概念
串行通讯是指仅用一根接收线和一根发送线就能将数据以位进行传输的一种通讯方式。尽管串行通讯的比按字节传输的并行通信慢,但是串口可以在仅仅使用两根线的情况下就能实现数据的传输
典型的串口通信使用3根线完成,分别是地线、发送、接收。由于串口通信是异步的,所以端口能够在一根线上发送数据同时在另一根线上接收数据。串口通信最重要的参数是波特率、数据位、停止位和奇偶的校验。对于两个需要进行串口通信的端口,这些参数必须匹配,这也是能够实现串口通讯的前提
我们使用的STC89C516RD+内部集成有一个串行通信口,使用时只需配置波特率、工作方式和中断开关,因为这块内容比较吃单片机前面的中断和定时器的基础,所以没掌握也无须担心,这些都有比较固定的初始化模板,直接使用例程提供的函数即可
4.2 串口显示姿态角
代码下载到单片机内之后,使用串口助手显示数据
4.3 接线图
上电时,MPU6050的绿色电源指示灯亮起,程序下载完成后,串口模块会有LED一直闪烁,表示串口通信正在工作
单片机开发教程3——串口发送MPU6050姿态角相关推荐
- 单片机开发教程4——多文件编程
文章目录 前言 文件结构 创建工程 多文件编程 头文件 源文件 全局变量 示例代码 main.c sys.c sys.hh iic.c iic.h mpu6050.c mpu6050.h uart.c ...
- 单片机开发教程1——开发环境的搭建
文章目录 开发环境介绍 Keil安装教程 下载安装包 安装keil 运行注册机 STC-ISP 单片机型号 串口驱动 串口助手 开发环境介绍 51单片机的开发只需要用到两个软件--keil和stc-i ...
- 单片机传输浮点数给android,请问单片机怎么接收从串口发送过来的浮点数?
如题,单片机接收串口发送的浮点数,然后进行处理,我想的是建立一个二维数组,想把浮点数一位一位的存到数组里,因为要接收多个浮点数所以用了二维数组,可是实际发现是不可行的,请问到底应该怎么接收啊.以下是我 ...
- 51单片机 Proteus仿真 时钟 串口 发送时钟 整点报时
#include "reg52.h" #include <intrins.h> #include <string.h> #include <stdio ...
- 51单片机:电脑向串口发送数据并控制LED灯
电脑向串口发送数据后,控制LED灯,并返回发送的数据 程序如下 #include"regx52.h" #include"intrins.h" unsigned ...
- 单片机开发教程5——51单片机驱动TFT彩屏
文章目录 代码例程 TFT模块 介绍 使用要点 减少刷新像素 坐标系 游戏设计 对象 VS Code 代码例程 TFT.zip 开发资料中的例程有些瑕疵,上面是整理后的例程,修改了一些参数,也添加了不 ...
- 辉芒微单片机开发教程_辉芒微单片机笔记004:IO寄存器配置,点亮一只LED
刚开始对开发软件环境和仿真器的使用还不算很熟,先点亮一只LED看一下软硬件的操作有没有问题.电子芯片 在点亮LED之前,要弄懂二个寄存器的工作原理: 1.TRISA方向寄存器. 2.PORTA控制寄存 ...
- 新手入门上位机开发 C#语言:PC串口发送数据
题目概述: VS2017开发环境 PC串口发送数据 编程: namespace _004_7_28 { public partial class Form1 : Form {public Form1( ...
- ❤️微信小程序 云开发 教程合集(视频+图文)免费❤️
一.视频版 微信小程序云开发视频教程上线啦 二.图文版 (1)预备知识 1. 怎么注册开通个人微信小程序 2. 微信小程序云开发教程-互联网软件的运作模式 3.微信小程序云开发教程-云开发对微信小程序 ...
最新文章
- Google Chrome的CSS hack写法
- Google 翻译的妙用
- mysql触发器错误信息_MySQL 触发器错误_MySQL
- 同一表单内设置两个或两个以上的提交按钮 Two submit buttons in one form
- 电大计算机机考excel,中央电大计算机应用机考excel电子表格模板题库存(118页)-原创力文档...
- vs 堆栈保留大小_新娘妆前vs妆后!看过就知道化妆师的重要性了!
- Vue使用Axios Ajax封装渲染页面
- 【python】中 type dtype astype辨析
- java零基础从入门到精通(全)
- 【HMS core】【push kit】【FAQ】华为推送服务 手机未收到推送消息/消息延迟/息屏通知 问题合集
- Fast RTPS原理与代码分析(2):动态发现协议之参与者发现协议PDP
- (二)动态白盒测试(含逻辑覆盖例子)
- 关于硬件批量贴片焊接流程
- “汇新杯”新兴科技成果专项赛介绍
- ie浏览器样式兼容写法_浏览器兼容性以及写法
- bzoj1597: 土地购买
- 无限循环小数四则运算_无限循环小数不能进行四则运算
- 小女子做销售 四大温柔手段
- EVE-NG模拟器教程(四)——常用镜像导入和使用
- ..NET程序破解仅需三步
热门文章
- [leetcode] 72.Edit Distance 编辑距离-史前最简明清晰的解答
- 乒乓RAM基本原理和操作介绍
- 云钱袋 网上报案流程分享 云钱袋逾期处理
- 涂鸦智能全功能智慧植物生长系统(展示)
- 我们会被低代码取代吗?
- 虚拟机连接服务器出现网络错误,winscp连接VM虚拟机出现网络错误连接超时
- c++11新特性之完美转发(std::foward)
- oneinstack_Oneinstack环境安装,更优的网站环境一键安装包
- java环境教程_java环境配置的详细教程(图文)
- MYsql备份数据库如何导入到新数据库!