基于STM32F103C8T6的MPU6050调试与数字运动处理器DMP
StrongerHangover
笔者之前也接触过MPU6050模块,但是并没有真正的去了解内部的通讯方式与内部的寄存器操作,况且之前接触的程序是基于51单片机的,笔者只是使用者并未自己书写。虽然说,不管是基于51单片机还是基于STM32单片机,它内部的通讯方式和寄存器配置依然相同,主要区别于操作方式有所区别。当然STM32单片机又分为基于寄存器版本和基于库函数版本的,笔者是基于固件库书写的MPU6050测试程序。笔者觉得MPU6050的程序主要分为I2C协议和MPU6050寄存器两部分(基于STM32有一定基础),我主要分为以下:
一、I2C通讯协议
二、MPU6050寄存器解析
三、MPU6050程序调试及Bug
一、 I2C通讯协议
简介:I2C是两线式串行总线。它是由数据线SDA和时钟SCL构成的串行总线,可发送和接收数据,一般这两条线是开漏和双向。在CPU与被控IC之间、IC与IC之间进行双向传送,高速IIC总线一般可达400kbps以上。IIC是半双工通信方式。
笔者将以下几点讲解I2C协议:
1)空闲状态:I2C总线的SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态。此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。 也就是说在没有数据传输时,SDA=1,和SCL=1。可以看下图1空闲状态下两条线都是高电平。
Photos 1
2)启动信号START:如上图,当SCL为高期间,SDA由高到低的跳变;启动信号是一种电平跳变时序信号,而不是一个电平信号。简单的说就是SCL=1,SDA=1-》SDA=0,意思就是在时钟到来之前把要传输的数据准备好,保证数据有效传输。就相当于,要做某一件事,那是不是要做一定的准备,以保证把这件事做好。一个好的开始嘛!
3)停止信号STOP:如上图,当SCL为高期间,SDA由低到高的跳变;停止信号也是一种电平跳变时序信号,而不是一个电平信号。简单的说就是SCL=1,SDA=0-》SDA=1,意思就是时钟线拉高,数据线才会拉高,如果时钟还在允许数据传输的状态下,数据线已经拉低,这样就可能会导致数据丢失,时钟线线拉高是保证数据有效传输。
4)应答信号ACK:发送器每发送一个字节,就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。 应答信号为低电平时,规定为有效应答位(ACK简称应答位),表示接收器已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。 对于反馈有效应答位ACK的要求是,接收器在第9个时钟脉冲之前的低电平期间将SDA线拉低,并且确保在该时钟的高电平期间为稳定的低电平。 如果接收器是主控器,则在它收到最后一个字节后,发送一个NACK信号,以通知被控发送器结束数据发送,并释放SDA线,以便主控接收器发送一个停止信号。简单的说就是你叫别人的名字,别人给你一个回应,就说明他听到你的呼应了,这就是有效应答,否则就是得不到回应,不知道别人没有听见你的呼应,这是就是无效应答。
Photos 2
5)数据有效性:I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。即:数据在SCL的上升沿到来之前就需准备好。并在在下降沿到来之前必须稳定。
Photos 3
6)数据传输:在I2C总线上传送的每一位数据都有一个时钟脉冲相对应(或同步控制),即在SCL串行时钟的配合下,在SDA上逐位地串行传送每一位数据。数据位的传输是边沿触发。简单的说就是第一个时钟脉冲来到时,取高位(MSB)传输,当高位被取走之后,数据就要左移,这样次高位的数据就会移到高位,等到下一个时钟脉冲进行数据传输,依次进行传输八位。
I2C总线的信号:
1.起始信号:当SCL保持高电平期间,SDA有高变低跳变,称为起始信号。
2.结束信号:当SCL保持高电平期间,SDA有低变高跳变,称为结束信号。
3.数据位: 当SCL保持高电平期间,SDA保持电平稳定有效性,称为有效数据位。
4.应答信号:当SCL保持高电平期间,当发送一个字节的数据后,必须要有对方的应答信号。
5.停止信号:当SCL保持低电平期间,SDA由低变高的跳变,称为停止信号。
I2C总线的写时序和读时序:在MPU6050中体现更好,
1.Write Time Series:START信号,哪一个设备地址,写地址,紧跟连续两个字节的数据:要写的地址,对方收到8bit地址后回应ACK,再8bit数据发给从设备,对方收到8bit数据后回应ACK,处理器写完后发送停止信号。
2.Read Time Series:读的过程:start信号,从设备地址,写待读取存储地址,再一个start信号,从设备地址,读8个时钟,从设备就把对应的数据反馈给处理器。
注意:读写时序要有相应的ACK信号。读写设备地址和数据时不一样,设备地址(小的)是七位地址,最后一位如果为0表示写,如果为1表示读。而数据寄存器的话,读写可能是先写一个读写的指令如0xA0等,然后直接写入8位的数据地址。
笔者觉得I2C通讯协议是非常有必要学习的,因为这一种通讯存在广泛应用,许多模块都是应用该通讯方式,就例如我们的MPU6050就是用I2C通讯协议,需要熟练的掌握该方式。学会看懂I2C的时序图,这是最基础的。在保证时序正确的情况,才能保证你使用该通讯方式获取正确的数据。
二、 MPU6050寄存器解析
简介:MPU6050是InvenSense公司推出的全球首款整合性6轴运动处理组件,内带3轴陀螺仪和3轴加速度传感器,并且含有一个第二IIC接口,可用于连接外部磁力传感器,利用自带数字运动处理器(DMP: Digital Motion Processor)硬件加速引擎,通过主IIC接口,可以向应用端输出完整的9轴姿态融合演算数据。有了DMP,我们可以使用InvenSense公司提供的运动处理资料库,非常方便的实现姿态解算,降低了运动处理运算对操作系统的负荷,同时大大降低了开发难度 。
MPU6050简介-MPU6050的特点:
1)自带数字运动处理( DMP: Digital Motion Processing ),可以输出6轴或9轴(需外接磁传感器)姿态解算数据。
2)集成可程序控制,测量范围为±250、±500、±1000与±2000°/sec 的3轴角速度感测器(陀螺仪)
3)集成可程序控制,范围为±2g、±4g、±8g和±16g的3轴加速度传感器
4)自带数字温度传感器
5)可输出中断(interrupt),支持姿势识别、摇摄、画面放大缩小、滚动、快速下降中断、high-G中断、零动作感应、触击感应、摇动感应功能
6)自带1024字节FIFO,有助于降低系统功耗
7)高达400Khz的IIC通信接口
8)超小封装尺寸:4x4x0.9mm(QFN)
Photos 4
MPU6050简介-MPU6050初始化:
1)初始化IIC接口:MPU6050采用IIC与STM32F1通信,需要先初始化与MPU6050 连接的SDA和SCL数据线。
2)复位MPU6050,由电源管理寄存器1(0X6B)控制。MPU6050内部所有寄存器恢复默认值,通过对电源管理寄存器1(0X6B)的bit7写1实现,复位后,电源管理寄存器1恢复默认值(0X40),然后必须设置该寄存器为 0X00,以唤醒 MPU6050,进入正常工作状态。
3)设置角速度传感器和加速度传感器的满量程范围。两个传感器的满量程范围(FSR),分别通过陀螺仪配置寄存器(0X1B)和加速度传感器配置寄存器(0X1C)设置。我们一般设置陀螺仪的满量程范围为±2000dps,加速度传感器的满量程范围为±2g。
4)设置其他参数。配置中断,由中断使能寄存器(0X38)控制;设置AUX IIC接口,由用户控制寄存器(0X6A)控制;设置FIFO,由FIFO使能寄存器(0X23)控制;陀螺仪采样率 ,由采样率分频寄存器(0X19)控制;设置数字低通滤波器,由配置寄存器(0X1A)控制。
5)设置系统时钟。由电源管理寄存器1(0X6B)控制。一般选择x轴陀螺PLL作为时钟源,以获得更高精度的时钟。
6)使能角速度传感器(陀螺仪)和加速度传感器。由电源管理寄存器2(0X6C)控制来设置,设置对应位为 0 即可开启。
初始化完成,即可读取陀螺仪、加速度传感器和温度传感器的数据了!!(原始数据)
MPU6050简介-寄存器介绍:
1) 电源管理寄存器1(0X6B):
Photos 5
该寄存器主要设置如下:1)
DEVICE_RESE=1,复位MPU6050,复位完成后,自动清零。
SLEEP=1,进入睡眠模式;SLEEP=0,正常工作模式。
TEMP_DIS,用于设置是否使能温度传感器,设置为0,则使能。
CLKSEL[2:0],用于选择系统时钟源,如右表所示:
CLKSEL[2:0] 时钟源
000 内部8M RC晶振
001 PLL,使用X轴陀螺作为参考(一般选X轴)
010 PLL,使用Y轴陀螺作为参考
011 PLL,使用Z轴陀螺作为参考
100 PLL,使用外部32.768Khz作为参考
101 PLL,使用外部19.2Mhz作为参考
110 保留
111 关闭时钟,保持时序产生电路复位状态
2)陀螺仪配置寄存器(0X1B):
Photos 6
该寄存器主要设置如下:
FS_SEL[1:0]这两个位用于设置陀螺仪的满量程范围:
0,±250°/S;
1,±500°/S;
2,±1000°/S;
3,±2000°/S;
一般设置为3,即±2000°/S,因为陀螺仪的ADC为16位分辨率,灵敏度为:65536/4000=16.4LSB/(°/S)。
3)加速度传感器配置寄存器(0X1C)
Photos 7
该寄存器主要设置如下:
AFS_SEL[1:0]这两个位,用于设置加速度传感器的满量程范围:
0,±2g;
1,±4g;
2,±8g;
3,±16g;
一般设置为0,即±2g,因为加速度传感器的ADC也是16位,灵敏度为:65536/4=16384LSB/g。
4)FIFO使能寄存器(0X23):
Photos 8
该寄存器主要设置如下:
该寄存器用于控制FIFO使能,在简单读取传感器数据的时候,可以不用FIFO,设置对应位为:0,即可禁止FIFO,设置为1,则使能FIFO。注意:加速度传感器的3个轴,全由1个位(ACCEL_FIFO_EN)控制,只要该位置1,则加速度传感器的三个通道都开启FIFO了。
5)陀螺仪采样率分频寄存器(0X19):
Photos 9
该寄存器主要设置如下:
设置 MPU6050 的陀螺仪采样频率,计算公式为:
采样频率 = 陀螺仪输出频率 / (1+SMPLRT_DIV)
陀螺仪的输出频率,是1Khz或者8Khz,与数字低通滤波器(DLPF)的设置有关,DLPF_CFG=0/7(说明一下:数字低通滤波器的DLPF_CFG有三个位控制,DLPF_CFG=0/7,是指000和111这两种配置下,陀螺仪的输出频率都是8Khz,其他配置下都是1Khz)的时候,频率为8Khz,其他情况是 1Khz。而且 DLPF滤波频率一般设置为采样率的一半。采样率,我们假定设置为50Hz,那么SMPLRT_DIV=1000/50-1=19。
6)配置寄存器(0X1A):
Photos 10
该寄存器主要设置如下:
数字低通滤波器(DLPF)的设置位,即:DLPF_CFG[2:0],加速度计和陀螺仪,都是根据这三个位的配置进行过滤的,如下表:
DLPF_CFG[2:0] 加速度传感器Fs=1Khz 角速度传感器(陀螺仪)
带宽(Hz) 延迟(ms) 带宽(Hz) 延迟(ms) Fs(Khz)
000 260 0 256 0.98 8
001 184 2.0 188 1.9 1
010 94 3.0 98 2.8 1
011 44 4.9 42 4.8 1
100 21 8.5 20 8.3 1
101 10 13.8 10 13.4 1
110 5 19.0 5 18.6 1
111 保留 保留 8
解析上表:Fs是指陀螺仪的输出频率,例如上面设置的采样频率为50Hz,那么贷款就是25Hz,DLPF_CFG =100符合要求,50=1000/(1+DIV),DIV=19,这也就是陀螺仪采样率分频寄存器写入的值。在陀螺仪采样率分频寄存器讲到DLPF_CFG值的设置,该表就是很好的证明,0000和111对应的陀螺仪输出频率都是8Khz,其他设置都是1Khz.
注意:带宽=1/2采样率。
7)电源管理寄存器2(0X6C)
Photos 11
该寄存器主要设置如下:
寄存器的LP_WAKE_CTRL用于控制低功耗时的唤醒频率,剩下的6位,分别控制加速度和陀螺仪的x/y/z轴是否进入待机模式,全部都不进入待机模式,全部设置为:0 。
8)加速度传感器数据输出寄存器(0X3B~0X40):
Photos 12
该寄存器主要设置如下:
加速度传感器数据输出寄存器总共由6个寄存器组成,输出X/Y/Z三个轴的加速度传感器值,高字节在前,低字节在后。
9)陀螺仪数据输出寄存器(0X43~0X48):
Photos 13
该寄存器主要设置如下:
陀螺仪数据输出寄存器总共由6个寄存器组成,输出X/Y/Z三个轴的陀螺仪传感器数据,高字节在前,低字节在后。
10)温度传感器数据输出寄存器(0X41~0X42):
Photos 14
该寄存器主要设置如下:
通过读取0X41(高8位)和0X42(低8位)寄存器得到,温度换算公式为:
Temperature = 36.53 + regval/340
其中,Temperature为计算得到的温度值,单位为℃,regval为从0X41和0X42读到的温度传感器值。
MPU6050的寄存器我们主要掌握着十个寄存器就差不多了,笔者在前面也讲过了初始化了,再针对每个寄存器都讲解了一遍该如何配置,这就根据自己需要来配置相应参数,以便获取可靠的数据。
注意:加速度传感器数据输出寄存器和陀螺仪数据输出寄存器获取的X/Y/Z轴的加速度和X/Y/Z轴的角速度是原始数据,并没进行姿态融合解算(四元数AHRS姿态解算),原始数据对于玩四轴之类的人来说并没有太大的意义。而对于玩四轴的笔者,更期望得到姿态数据,也就是欧拉角:航向角(yaw)、横滚角(roll)和俯仰角(pitch)。
要得到欧拉角数据,就得利用我们的原始数据,进行姿态融合解算,而MPU6050自带了数字运动处理器,即DMP,并且,InvenSense提供了一个MPU6050的嵌入式运动驱动库,结合MPU6050的DMP,可以将我们的原始数据,直接转换成四元数输出,而得到四元数之后,就可以很方便的计算出欧拉角,从而得到yaw、roll和pitch。
使用内置的DMP,可以大大简化代码设计,MCU不用进行姿态解算过程,大大降低了MCU的负担,从而有更多的时间去处理其他事件,提高系统实时性。
MPU6050 DMP输出的是姿态解算后的四元数,采用q30格式,也就是放大了2的30次方,我们要得到欧拉角,就得做一个转换,代码如下:
q0=quat[0] / q30; //q30格式转换为浮点数
q1=quat[1] / q30;
q2=quat[2] / q30;
q3=quat[3] / q30;
//计算得到俯仰角/横滚角/航向角
Pitch=asin(-2 * q1 * q3 + 2 * q0* q2)* 57.3; //俯仰角
Roll=atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2* q2 + 1)* 57.3;//横滚角
Yaw=atan2(2*(q1q2 + q0q3),q0q0+q1q1-q2q2-q3q3) * 57.3;//航向角
笔者对四元数AHRS姿态解算、、、、、、、、、、、、、、、、、、、、
三、 MPU6050程序调试及Bug
笔者主要是对MPU6050程序进行讲解,对I2C程序进行部分解析。笔者在对寄存器解析时已经大概讲了一下MPU6050初始化,想要获取MPU6050的数据就必须保证I2C通讯成功,这是前提条件;然后就是MPU6050的正确配置,这样获取数据就稳妥妥了(程序已正确)。
从I2C下手,配置相应的IO,主要有两条线时钟线SCL和数据线SDA,想必时钟线就不必详解了(时钟脉冲),将其配置为输出就可以了(笔者在程序中配置为通用推挽输出)。数据线SDA(笔者也将其配置为通用推挽输出,此部分只是在IO初始化时配置的)既有输入又有输出,那我们又该如何解决?这时我们就该对寄存器进行操作了,如图:
Photos 15
笔者基于 STM32_FLY 四旋翼无人机开发平台 Mini V1.0 进行学习,配置的IO口也是根据该开发平台定义的。笔者在宏定义中给数据线SDA配置了两种模式(SDA输入和SDA输出两种),也就是该IO既允许输入也允许输出,此处笔者直接对寄存器进行操作, 既然允许了输入输出,笔者则给其配置两种模式(输入和输出模式),直接对端口配置低寄存器进行操作,不管是使用什么模块,在使用之前应将其之前内容清空,然后在对应位置赋相应的值,笔者配置输入模式赋予的值是8(1000),输出模式配置的值是3(0011),此处笔者只配置低寄存器,并未配置高寄存器。如:
#define MPU_IIC_SDA PBout(0) //数据线输出
#define MPU_READ_SDA PBin(0) //数据线输入
#define MPU_SDA_IN() {GPIOB-》CRL&=0xfffffff0;GPIOB-》CRL|=8《《0;}
#define MPU_SDA_OUT() {GPIOB-》CRL&=0xfffffff0;GPIOB-》CRL|=3《《0;}
Photos 16
其实只要会看时序图,I2C的程序并不难写,重点在灵活应用于实际。笔者主要对两个函数进行解析,如图:
一个是发送函数,一个是接收函数。I2C每次发送的字节不受限制,此处笔者写的是发送一个字节函数和接收一个字节函数。笔者主要是说明i2c有定义字节格式,发送到SDA 线上的每个字节必须为8 位,每次传输可以发送的字节数量不受限制。每个字节后必须跟一个响应位。首先传输的是数据的最高位(MSB),如果从机要完成一些其他功能后(例如一个内部中断服务程序)才能接收或发送下一个完整的数据字节,可以使时钟线SCL保持低电平,迫使主机进入等待状态,当从机准备好接收下一个数据字节并释放时钟线SCL 后数据传输继续。意思是如果你发送0x01那么前面很多个0一定是第一个发送出去的(MSB),1是最后发送出去的(LSB)。如图:
基于STM32F103C8T6的MPU6050调试与数字运动处理器DMP
StrongerHangover
笔者之前也接触过MPU6050模块,但是并没有真正的去了解内部的通讯方式与内部的寄存器操作,况且之前接触的程序是基于51单片机的,笔者只是使用者并未自己书写。虽然说,不管是基于51单片机还是基于STM32单片机,它内部的通讯方式和寄存器配置依然相同,主要区别于操作方式有所区别。当然STM32单片机又分为基于寄存器版本和基于库函数版本的,笔者是基于固件库书写的MPU6050测试程序。笔者觉得MPU6050的程序主要分为I2C协议和MPU6050寄存器两部分(基于STM32有一定基础),我主要分为以下:
一、I2C通讯协议
二、MPU6050寄存器解析
三、MPU6050程序调试及Bug
一、 I2C通讯协议
简介:I2C是两线式串行总线。它是由数据线SDA和时钟SCL构成的串行总线,可发送和接收数据,一般这两条线是开漏和双向。在CPU与被控IC之间、IC与IC之间进行双向传送,高速IIC总线一般可达400kbps以上。IIC是半双工通信方式。
笔者将以下几点讲解I2C协议:
1)空闲状态:I2C总线的SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态。此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。 也就是说在没有数据传输时,SDA=1,和SCL=1。可以看下图1空闲状态下两条线都是高电平。
Photos 1
2)启动信号START:如上图,当SCL为高期间,SDA由高到低的跳变;启动信号是一种电平跳变时序信号,而不是一个电平信号。简单的说就是SCL=1,SDA=1-》SDA=0,意思就是在时钟到来之前把要传输的数据准备好,保证数据有效传输。就相当于,要做某一件事,那是不是要做一定的准备,以保证把这件事做好。一个好的开始嘛!
3)停止信号STOP:如上图,当SCL为高期间,SDA由低到高的跳变;停止信号也是一种电平跳变时序信号,而不是一个电平信号。简单的说就是SCL=1,SDA=0-》SDA=1,意思就是时钟线拉高,数据线才会拉高,如果时钟还在允许数据传输的状态下,数据线已经拉低,这样就可能会导致数据丢失,时钟线线拉高是保证数据有效传输。
4)应答信号ACK:发送器每发送一个字节,就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。 应答信号为低电平时,规定为有效应答位(ACK简称应答位),表示接收器已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。 对于反馈有效应答位ACK的要求是,接收器在第9个时钟脉冲之前的低电平期间将SDA线拉低,并且确保在该时钟的高电平期间为稳定的低电平。 如果接收器是主控器,则在它收到最后一个字节后,发送一个NACK信号,以通知被控发送器结束数据发送,并释放SDA线,以便主控接收器发送一个停止信号。简单的说就是你叫别人的名字,别人给你一个回应,就说明他听到你的呼应了,这就是有效应答,否则就是得不到回应,不知道别人没有听见你的呼应,这是就是无效应答。
Photos 2
5)数据有效性:I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。即:数据在SCL的上升沿到来之前就需准备好。并在在下降沿到来之前必须稳定。
Photos 3
6)数据传输:在I2C总线上传送的每一位数据都有一个时钟脉冲相对应(或同步控制),即在SCL串行时钟的配合下,在SDA上逐位地串行传送每一位数据。数据位的传输是边沿触发。简单的说就是第一个时钟脉冲来到时,取高位(MSB)传输,当高位被取走之后,数据就要左移,这样次高位的数据就会移到高位,等到下一个时钟脉冲进行数据传输,依次进行传输八位。
I2C总线的信号:
1.起始信号:当SCL保持高电平期间,SDA有高变低跳变,称为起始信号。
2.结束信号:当SCL保持高电平期间,SDA有低变高跳变,称为结束信号。
3.数据位: 当SCL保持高电平期间,SDA保持电平稳定有效性,称为有效数据位。
4.应答信号:当SCL保持高电平期间,当发送一个字节的数据后,必须要有对方的应答信号。
5.停止信号:当SCL保持低电平期间,SDA由低变高的跳变,称为停止信号。
I2C总线的写时序和读时序:在MPU6050中体现更好,
1.Write Time Series:START信号,哪一个设备地址,写地址,紧跟连续两个字节的数据:要写的地址,对方收到8bit地址后回应ACK,再8bit数据发给从设备,对方收到8bit数据后回应ACK,处理器写完后发送停止信号。
2.Read Time Series:读的过程:start信号,从设备地址,写待读取存储地址,再一个start信号,从设备地址,读8个时钟,从设备就把对应的数据反馈给处理器。
注意:读写时序要有相应的ACK信号。读写设备地址和数据时不一样,设备地址(小的)是七位地址,最后一位如果为0表示写,如果为1表示读。而数据寄存器的话,读写可能是先写一个读写的指令如0xA0等,然后直接写入8位的数据地址。
笔者觉得I2C通讯协议是非常有必要学习的,因为这一种通讯存在广泛应用,许多模块都是应用该通讯方式,就例如我们的MPU6050就是用I2C通讯协议,需要熟练的掌握该方式。学会看懂I2C的时序图,这是最基础的。在保证时序正确的情况,才能保证你使用该通讯方式获取正确的数据。
二、 MPU6050寄存器解析
简介:MPU6050是InvenSense公司推出的全球首款整合性6轴运动处理组件,内带3轴陀螺仪和3轴加速度传感器,并且含有一个第二IIC接口,可用于连接外部磁力传感器,利用自带数字运动处理器(DMP: Digital Motion Processor)硬件加速引擎,通过主IIC接口,可以向应用端输出完整的9轴姿态融合演算数据。有了DMP,我们可以使用InvenSense公司提供的运动处理资料库,非常方便的实现姿态解算,降低了运动处理运算对操作系统的负荷,同时大大降低了开发难度 。
MPU6050简介-MPU6050的特点:
1)自带数字运动处理( DMP: Digital Motion Processing ),可以输出6轴或9轴(需外接磁传感器)姿态解算数据。
2)集成可程序控制,测量范围为±250、±500、±1000与±2000°/sec 的3轴角速度感测器(陀螺仪)
3)集成可程序控制,范围为±2g、±4g、±8g和±16g的3轴加速度传感器
4)自带数字温度传感器
5)可输出中断(interrupt),支持姿势识别、摇摄、画面放大缩小、滚动、快速下降中断、high-G中断、零动作感应、触击感应、摇动感应功能
6)自带1024字节FIFO,有助于降低系统功耗
7)高达400Khz的IIC通信接口
8)超小封装尺寸:4x4x0.9mm(QFN)
Photos 4
MPU6050简介-MPU6050初始化:
1)初始化IIC接口:MPU6050采用IIC与STM32F1通信,需要先初始化与MPU6050 连接的SDA和SCL数据线。
2)复位MPU6050,由电源管理寄存器1(0X6B)控制。MPU6050内部所有寄存器恢复默认值,通过对电源管理寄存器1(0X6B)的bit7写1实现,复位后,电源管理寄存器1恢复默认值(0X40),然后必须设置该寄存器为 0X00,以唤醒 MPU6050,进入正常工作状态。
3)设置角速度传感器和加速度传感器的满量程范围。两个传感器的满量程范围(FSR),分别通过陀螺仪配置寄存器(0X1B)和加速度传感器配置寄存器(0X1C)设置。我们一般设置陀螺仪的满量程范围为±2000dps,加速度传感器的满量程范围为±2g。
4)设置其他参数。配置中断,由中断使能寄存器(0X38)控制;设置AUX IIC接口,由用户控制寄存器(0X6A)控制;设置FIFO,由FIFO使能寄存器(0X23)控制;陀螺仪采样率 ,由采样率分频寄存器(0X19)控制;设置数字低通滤波器,由配置寄存器(0X1A)控制。
5)设置系统时钟。由电源管理寄存器1(0X6B)控制。一般选择x轴陀螺PLL作为时钟源,以获得更高精度的时钟。
6)使能角速度传感器(陀螺仪)和加速度传感器。由电源管理寄存器2(0X6C)控制来设置,设置对应位为 0 即可开启。
初始化完成,即可读取陀螺仪、加速度传感器和温度传感器的数据了!!(原始数据)
MPU6050简介-寄存器介绍:
1) 电源管理寄存器1(0X6B):
Photos 5
该寄存器主要设置如下:1)
DEVICE_RESE=1,复位MPU6050,复位完成后,自动清零。
SLEEP=1,进入睡眠模式;SLEEP=0,正常工作模式。
TEMP_DIS,用于设置是否使能温度传感器,设置为0,则使能。
CLKSEL[2:0],用于选择系统时钟源,如右表所示:
CLKSEL[2:0] 时钟源
000 内部8M RC晶振
001 PLL,使用X轴陀螺作为参考(一般选X轴)
010 PLL,使用Y轴陀螺作为参考
011 PLL,使用Z轴陀螺作为参考
100 PLL,使用外部32.768Khz作为参考
101 PLL,使用外部19.2Mhz作为参考
110 保留
111 关闭时钟,保持时序产生电路复位状态
2)陀螺仪配置寄存器(0X1B):
Photos 6
该寄存器主要设置如下:
FS_SEL[1:0]这两个位用于设置陀螺仪的满量程范围:
0,±250°/S;
1,±500°/S;
2,±1000°/S;
3,±2000°/S;
一般设置为3,即±2000°/S,因为陀螺仪的ADC为16位分辨率,灵敏度为:65536/4000=16.4LSB/(°/S)。
3)加速度传感器配置寄存器(0X1C)
Photos 7
该寄存器主要设置如下:
AFS_SEL[1:0]这两个位,用于设置加速度传感器的满量程范围:
0,±2g;
1,±4g;
2,±8g;
3,±16g;
一般设置为0,即±2g,因为加速度传感器的ADC也是16位,灵敏度为:65536/4=16384LSB/g。
4)FIFO使能寄存器(0X23):
Photos 8
该寄存器主要设置如下:
该寄存器用于控制FIFO使能,在简单读取传感器数据的时候,可以不用FIFO,设置对应位为:0,即可禁止FIFO,设置为1,则使能FIFO。注意:加速度传感器的3个轴,全由1个位(ACCEL_FIFO_EN)控制,只要该位置1,则加速度传感器的三个通道都开启FIFO了。
5)陀螺仪采样率分频寄存器(0X19):
Photos 9
该寄存器主要设置如下:
设置 MPU6050 的陀螺仪采样频率,计算公式为:
采样频率 = 陀螺仪输出频率 / (1+SMPLRT_DIV)
陀螺仪的输出频率,是1Khz或者8Khz,与数字低通滤波器(DLPF)的设置有关,DLPF_CFG=0/7(说明一下:数字低通滤波器的DLPF_CFG有三个位控制,DLPF_CFG=0/7,是指000和111这两种配置下,陀螺仪的输出频率都是8Khz,其他配置下都是1Khz)的时候,频率为8Khz,其他情况是 1Khz。而且 DLPF滤波频率一般设置为采样率的一半。采样率,我们假定设置为50Hz,那么SMPLRT_DIV=1000/50-1=19。
6)配置寄存器(0X1A):
Photos 10
该寄存器主要设置如下:
数字低通滤波器(DLPF)的设置位,即:DLPF_CFG[2:0],加速度计和陀螺仪,都是根据这三个位的配置进行过滤的,如下表:
DLPF_CFG[2:0] 加速度传感器Fs=1Khz 角速度传感器(陀螺仪)
带宽(Hz) 延迟(ms) 带宽(Hz) 延迟(ms) Fs(Khz)
000 260 0 256 0.98 8
001 184 2.0 188 1.9 1
010 94 3.0 98 2.8 1
011 44 4.9 42 4.8 1
100 21 8.5 20 8.3 1
101 10 13.8 10 13.4 1
110 5 19.0 5 18.6 1
111 保留 保留 8
解析上表:Fs是指陀螺仪的输出频率,例如上面设置的采样频率为50Hz,那么贷款就是25Hz,DLPF_CFG =100符合要求,50=1000/(1+DIV),DIV=19,这也就是陀螺仪采样率分频寄存器写入的值。在陀螺仪采样率分频寄存器讲到DLPF_CFG值的设置,该表就是很好的证明,0000和111对应的陀螺仪输出频率都是8Khz,其他设置都是1Khz.
注意:带宽=1/2采样率。
7)电源管理寄存器2(0X6C)
Photos 11
该寄存器主要设置如下:
寄存器的LP_WAKE_CTRL用于控制低功耗时的唤醒频率,剩下的6位,分别控制加速度和陀螺仪的x/y/z轴是否进入待机模式,全部都不进入待机模式,全部设置为:0 。
8)加速度传感器数据输出寄存器(0X3B~0X40):
Photos 12
该寄存器主要设置如下:
加速度传感器数据输出寄存器总共由6个寄存器组成,输出X/Y/Z三个轴的加速度传感器值,高字节在前,低字节在后。
9)陀螺仪数据输出寄存器(0X43~0X48):
Photos 13
该寄存器主要设置如下:
陀螺仪数据输出寄存器总共由6个寄存器组成,输出X/Y/Z三个轴的陀螺仪传感器数据,高字节在前,低字节在后。
10)温度传感器数据输出寄存器(0X41~0X42):
Photos 14
该寄存器主要设置如下:
通过读取0X41(高8位)和0X42(低8位)寄存器得到,温度换算公式为:
Temperature = 36.53 + regval/340
其中,Temperature为计算得到的温度值,单位为℃,regval为从0X41和0X42读到的温度传感器值。
MPU6050的寄存器我们主要掌握着十个寄存器就差不多了,笔者在前面也讲过了初始化了,再针对每个寄存器都讲解了一遍该如何配置,这就根据自己需要来配置相应参数,以便获取可靠的数据。
注意:加速度传感器数据输出寄存器和陀螺仪数据输出寄存器获取的X/Y/Z轴的加速度和X/Y/Z轴的角速度是原始数据,并没进行姿态融合解算(四元数AHRS姿态解算),原始数据对于玩四轴之类的人来说并没有太大的意义。而对于玩四轴的笔者,更期望得到姿态数据,也就是欧拉角:航向角(yaw)、横滚角(roll)和俯仰角(pitch)。
要得到欧拉角数据,就得利用我们的原始数据,进行姿态融合解算,而MPU6050自带了数字运动处理器,即DMP,并且,InvenSense提供了一个MPU6050的嵌入式运动驱动库,结合MPU6050的DMP,可以将我们的原始数据,直接转换成四元数输出,而得到四元数之后,就可以很方便的计算出欧拉角,从而得到yaw、roll和pitch。
使用内置的DMP,可以大大简化代码设计,MCU不用进行姿态解算过程,大大降低了MCU的负担,从而有更多的时间去处理其他事件,提高系统实时性。
MPU6050 DMP输出的是姿态解算后的四元数,采用q30格式,也就是放大了2的30次方,我们要得到欧拉角,就得做一个转换,代码如下:
q0=quat[0] / q30; //q30格式转换为浮点数
q1=quat[1] / q30;
q2=quat[2] / q30;
q3=quat[3] / q30;
//计算得到俯仰角/横滚角/航向角
Pitch=asin(-2 * q1 * q3 + 2 * q0* q2)* 57.3; //俯仰角
Roll=atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2* q2 + 1)* 57.3;//横滚角
Yaw=atan2(2*(q1q2 + q0q3),q0q0+q1q1-q2q2-q3q3) * 57.3;//航向角
笔者对四元数AHRS姿态解算、、、、、、、、、、、、、、、、、、、、
三、 MPU6050程序调试及Bug
笔者主要是对MPU6050程序进行讲解,对I2C程序进行部分解析。笔者在对寄存器解析时已经大概讲了一下MPU6050初始化,想要获取MPU6050的数据就必须保证I2C通讯成功,这是前提条件;然后就是MPU6050的正确配置,这样获取数据就稳妥妥了(程序已正确)。
从I2C下手,配置相应的IO,主要有两条线时钟线SCL和数据线SDA,想必时钟线就不必详解了(时钟脉冲),将其配置为输出就可以了(笔者在程序中配置为通用推挽输出)。数据线SDA(笔者也将其配置为通用推挽输出,此部分只是在IO初始化时配置的)既有输入又有输出,那我们又该如何解决?这时我们就该对寄存器进行操作了,如图:
Photos 15
笔者基于 STM32_FLY 四旋翼无人机开发平台 Mini V1.0 进行学习,配置的IO口也是根据该开发平台定义的。笔者在宏定义中给数据线SDA配置了两种模式(SDA输入和SDA输出两种),也就是该IO既允许输入也允许输出,此处笔者直接对寄存器进行操作, 既然允许了输入输出,笔者则给其配置两种模式(输入和输出模式),直接对端口配置低寄存器进行操作,不管是使用什么模块,在使用之前应将其之前内容清空,然后在对应位置赋相应的值,笔者配置输入模式赋予的值是8(1000),输出模式配置的值是3(0011),此处笔者只配置低寄存器,并未配置高寄存器。如:
#define MPU_IIC_SDA PBout(0) //数据线输出
#define MPU_READ_SDA PBin(0) //数据线输入
#define MPU_SDA_IN() {GPIOB-》CRL&=0xfffffff0;GPIOB-》CRL|=8《《0;}
#define MPU_SDA_OUT() {GPIOB-》CRL&=0xfffffff0;GPIOB-》CRL|=3《《0;}
Photos 16
其实只要会看时序图,I2C的程序并不难写,重点在灵活应用于实际。笔者主要对两个函数进行解析,如图:
一个是发送函数,一个是接收函数。I2C每次发送的字节不受限制,此处笔者写的是发送一个字节函数和接收一个字节函数。笔者主要是说明i2c有定义字节格式,发送到SDA 线上的每个字节必须为8 位,每次传输可以发送的字节数量不受限制。每个字节后必须跟一个响应位。首先传输的是数据的最高位(MSB),如果从机要完成一些其他功能后(例如一个内部中断服务程序)才能接收或发送下一个完整的数据字节,可以使时钟线SCL保持低电平,迫使主机进入等待状态,当从机准备好接收下一个数据字节并释放时钟线SCL 后数据传输继续。意思是如果你发送0x01那么前面很多个0一定是第一个发送出去的(MSB),1是最后发送出去的(LSB)。如图:
举报