一、MPU6050的简介
MPU6050是全球首例 9 轴运动处理传感器。它集成了 3 轴 MEMS 陀螺仪,3 轴 MEMS 加速度计,以及一个可扩展的数字运动处理器 DMP(Digital Motion Processor),可用 I2C 接口连接一个第三方的数字传感器,比如磁力计。扩展之后就可以通过其 I2C 或 SPI 接口 输出一个 9 轴的信号(SPI 接口仅在 MPU-6000 可用)。MPU-60X0 也可以通过其 I2C 接口 连接非惯性的数字传感器,比如压力传感器。
MPU-60X0 对陀螺仪和加速度计分别用了三个 16 位的 ADC,将其测量的模拟量转化 为可输出的数字量。为了精确跟踪快速和慢速的运动,传感器的测量范围都是用户可控的, 陀螺仪可测范围为±250,±500,±1000,±2000°/秒(dps),加速度计可测范围为±2,±4, ±8,±16g。
一个片上 1024 字节的 FIFO,有助于降低系统功耗。
和所有设备寄存器之间的通信采用 400kHz 的 I2C 接口或 1MHz 的 SPI 接口(SPI 仅 MPU-6000 可用)。对于需要高速传输的应用,对寄存器的读取和中断可用 20MHz 的 SPI。 另外,片上还内嵌了一个温度传感器和在工作环境下仅有±1%变动的振荡器。
芯片尺寸 4×4×0.9mm,采用 QFN 封装(无引线方形封装),可承受最大 10000g 的冲 击,并有可编程的低通滤波器。
关于电源,MPU-60X0 可支持 VDD 范围 2.5V±5%,3.0V±5%,或 3.3V±5%。另外 MPU-6050 还有一个 VLOGIC 引脚,用来为 I2C 输出提供逻辑电平。VLOGIC 电压可取 1.8±5%或者 VDD。
二、MPU6050框图
三、模块的初始化工作
1.初始化IIC接口
MPU6050的通信方式就是IIC,所以初始时应先初始化IIC。
2.复位MPU6050
主要目的是使MPU6050内部所有寄存器恢复默认值,然后通过对电源管理寄存器1(0X6B)的第七位写1实现,及向MPU6050写入0x80使其复位。复位完成,电源管理寄存器1恢复默认值位0x40。通过寄存器手册可以知道此时为低功耗模式(SLEEP被置1),如果我们想正常使用陀螺仪,所以我们还得设置该寄存器为0x00来唤醒MPU6050,使其进入到正常工作状态。代码如下:
MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X80); //复位MPU6050
delay_ms(100);
MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X00); //唤醒MPU6050
其中延时100ms是为了确保复位完成。
3.设置角速度(0X1B)和加速度传感器(0X1C)满量程范围以及采样率(0X19)
MPU_Write_Byte(MPU_GYRO_CFG_REG,0X18);//设置陀螺仪满量程范围
MPU_Write_Byte(MPU_ACCEL_CFG_REG,0x00);//设置加速度传感器满量程范围
MPU_Set_Rate(50); //设置采样率50Hz
0X1B寄存器如下:设置量程范围为第3、4位,0,±250°/S;1,±500°/S;2,±1000°/S;3,±2000°/S;我们设置为3,即±2000°/S,也就是0x18。
0X1C寄存器如下:设置量程范围为AFS_SEL[1:0]这两个位,0,±2g;1,±4g;2,±8g;3,±16g;我们一般设置为0,即±2g,也就是0x00。
0X19寄存器如下:采样频率计算公式为:采样频率 = 陀螺仪输出频率 / (1+SMPLRT_DIV)。
则SMPLRT_DIV = 陀螺仪输出频率/采样频率 - 1;阅读寄存器说明手册可知,MPU6050的陀螺输出频率可达8kHz,加速度计为1kHz,而且可以通过分频来降低频率。采样频率就是通过陀螺仪输出频率分频得到的。陀螺仪采样率通过采样率分频寄存器(0x19)控制。如果要得到50Hz的采样率,当我们要设定50Hz时,SMPLRT_DIV = 1000/50 -1 = 19,那么分频值就是19。只要设置寄存器的值为19,就可以使得DMP以50Hz来更新寄存器中的数据,只要按时读取寄存器就可以了。
数字低通滤波器(DLPF)则通过配置寄存器(0x1A)设置,一般设置 DLPF 为带宽的 1/2 即可。
//设置MPU6050的采样率(假定Fs=1KHz)
//rate:4~1000(Hz)
//返回值:0,设置成功
// 其他,设置失败
u8 MPU_Set_Rate(u16 rate)
{
u8 data;
if(rate>1000)rate=1000;
if(rate<4)rate=4;
data=1000/rate-1;
data=MPU_Write_Byte(MPU_SAMPLE_RATE_REG,data); //设置数字低通滤波器
return MPU_Set_LPF(rate/2); //自动设置LPF为采样率的一半
}
最终代码也就如上。
4.4.设置其他参数
我们还需要配置的参数有:
- 关闭中断
- 关闭 AUX IIC 接口
- 禁止 FIFO
- 设置陀螺仪采样率
- 设置数字低通滤波器(DLPF)等。
中断的关闭:我们不用中断方式读取数据,所以可以关闭中断。寄存器地址(0X38)
在寄存器手册上可以看见,要想使能中断,则相应为置1,否则为0,故我们写0x00。
MPU_Write_Byte(MPU_INT_EN_REG,0X00); //关闭所有中断
AUX IIC接口的关闭:
我们也没用到 AUX IIC 接口外接其他传感器,所以也关闭这个接口。如下所示,分别通过用户控制寄存器(0x6A)控制。和中断一样,为1则使能,故置0;
MPU_Write_Byte(MPU_USER_CTRL_REG,0X00); //I2C主模式关闭
禁止FIFO:
MPU6050 可以使用 FIFO 存储传感器数据,由于我们没有使用,所以关闭所有 FIFO 通道。如下所示,通过 FIFO 使能寄存器(0x23)控制,默认都是 0(即禁止 FIFO),所以用默认值就可以了。
MPU_Write_Byte(MPU_FIFO_EN_REG,0X00); //关闭FIFO
而数字低通滤波器:数字低通滤波器(DLPF)则通过配置寄存器(0x1A)设置,一般设置 DLPF 为带宽的 1/2 即可。上面也设置了。最后总体代码如下:
u8 MPU_Init(void)
{
u8 res;
MPU_IIC_Init();//初始化IIC总线
MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X80); //复位MPU6050
delay_ms(100);
MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X00); //唤醒MPU6050
MPU_Set_Gyro_Fsr(3); //陀螺仪传感器,±2000dps
MPU_Set_Accel_Fsr(0); //加速度传感器,±2g
MPU_Set_Rate(50); //设置采样率50Hz
MPU_Write_Byte(MPU_INT_EN_REG,0X00); //关闭所有中断
MPU_Write_Byte(MPU_USER_CTRL_REG,0X00); //I2C主模式关闭
MPU_Write_Byte(MPU_FIFO_EN_REG,0X00); //关闭FIFO
MPU_Write_Byte(MPU_INTBP_CFG_REG,0X80); //INT引脚低电平有效
res=MPU_Read_Byte(MPU_DEVICE_ID_REG);
if(res==MPU_ADDR)//器件ID正确
{
MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X01); //设置CLKSEL,PLL X轴为参考
MPU_Write_Byte(MPU_PWR_MGMT2_REG,0X00); //加速度与陀螺仪都工作
MPU_Set_Rate(50); //设置采样率为50Hz
}else return 1;
return 0;
}
下一章继续讲解MPU6050。这里附上IIC代码:
mpuiic.c
#include "mpuiic.h"
#include "delay.h"
//MPU IIC 延时函数
void MPU_IIC_Delay(void)
{
delay_us(2);
}
//初始化IIC
void MPU_IIC_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//先使能外设IO PORTC时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9; // 端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIO
GPIO_SetBits(GPIOB,GPIO_Pin_8|GPIO_Pin_9); //PB8,PB9输出高
}
//产生IIC起始信号
void MPU_IIC_Start(void)
{
MPU_SDA_OUT(); //sda线输出
MPU_IIC_SDA=1;
MPU_IIC_SCL=1;
MPU_IIC_Delay();
MPU_IIC_SDA=0;//START:when CLK is high,DATA change form high to low
MPU_IIC_Delay();
MPU_IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
}
//产生IIC停止信号
void MPU_IIC_Stop(void)
{
MPU_SDA_OUT();//sda线输出
MPU_IIC_SCL=0;
MPU_IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
MPU_IIC_Delay();
MPU_IIC_SCL=1;
MPU_IIC_SDA=1;//发送I2C总线结束信号
MPU_IIC_Delay();
}
//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
u8 MPU_IIC_Wait_Ack(void)
{
u8 ucErrTime=0;
MPU_SDA_IN(); //SDA设置为输入
MPU_IIC_SDA=1;MPU_IIC_Delay();
MPU_IIC_SCL=1;MPU_IIC_Delay();
while(MPU_READ_SDA)
{
ucErrTime++;
if(ucErrTime>250)
{
MPU_IIC_Stop();
return 1;
}
}
MPU_IIC_SCL=0;//时钟输出0
return 0;
}
//产生ACK应答
void MPU_IIC_Ack(void)
{
MPU_IIC_SCL=0;
MPU_SDA_OUT();
MPU_IIC_SDA=0;
MPU_IIC_Delay();
MPU_IIC_SCL=1;
MPU_IIC_Delay();
MPU_IIC_SCL=0;
}
//不产生ACK应答
void MPU_IIC_NAck(void)
{
MPU_IIC_SCL=0;
MPU_SDA_OUT();
MPU_IIC_SDA=1;
MPU_IIC_Delay();
MPU_IIC_SCL=1;
MPU_IIC_Delay();
MPU_IIC_SCL=0;
}
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void MPU_IIC_Send_Byte(u8 txd)
{
u8 t;
MPU_SDA_OUT();
MPU_IIC_SCL=0;//拉低时钟开始数据传输
for(t=0;t<8;t++)
{
MPU_IIC_SDA=(BitAction)((txd&0x80)>>7);
txd<<=1;
MPU_IIC_SCL=1;
MPU_IIC_Delay();
MPU_IIC_SCL=0;
MPU_IIC_Delay();
}
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
u8 MPU_IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
MPU_SDA_IN();//SDA设置为输入
for(i=0;i<8;i++ )
{
MPU_IIC_SCL=0;
MPU_IIC_Delay();
MPU_IIC_SCL=1;
receive<<=1;
if(MPU_READ_SDA)receive++;
MPU_IIC_Delay();
}
if (!ack)
MPU_IIC_NAck();//发送nACK
else
MPU_IIC_Ack(); //发送ACK
return receive;
}
mpuiic.h
#ifndef __MPUIIC_H
#define __MPUIIC_H
#include "sys.h"
//IO方向设置
#define MPU_SDA_IN() {GPIOB->CRH &= 0XFFFFFF0F;GPIOB->CRH |= (u32)8<<4;}
#define MPU_SDA_OUT() {GPIOB->CRH &= 0XFFFFFF0F;GPIOB->CRH |= (u32)3<<4;}
//IO操作函数
#define MPU_IIC_SCL PBout(8) //SCL
#define MPU_IIC_SDA PBout(9) //SDA
#define MPU_READ_SDA PBin(9) //输入SDA
//IIC所有操作函数
void MPU_IIC_Delay(void); //MPU IIC延时函数
void MPU_IIC_Init(void); //初始化IIC的IO口
void MPU_IIC_Start(void); //发送IIC开始信号
void MPU_IIC_Stop(void); //发送IIC停止信号
void MPU_IIC_Send_Byte(u8 txd); //IIC发送一个字节
u8 MPU_IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
u8 MPU_IIC_Wait_Ack(void); //IIC等待ACK信号
void MPU_IIC_Ack(void); //IIC发送ACK信号
void MPU_IIC_NAck(void); //IIC不发送ACK信号
#endif