一. 简介
MPU6050是一款六轴陀螺仪,可以通过IIC协议输出三个方向上的加速度和角速度,在平衡车和飞控中较为常见。一般情况下,模块有用的引脚只有四个(其它的不常用),即VCC,GND,SDA和SCL。操作它的第一步,即编写IIC协议。
二. IIC协议
作为三大常用协议之一,掌握它是非常有必要的。IIC为主从协议,分为主机和从机。IIC协议要比SPI要简单那么一点,没有像SPI那样还有模式的配置。下面就简单说说IIC协议。
SDA: IIC的数据线
SCL:IIC的时钟线
空闲态: SDA和SCL都为高电平。
起始态: 主机将SDA拉低
数据传输: 在SCL为低电平的时候,将数据输出,在SCL为高电平的时候,将数据输入。
应答态:在SCL为高电平的时候,检测到SDA为低电平。
非应答态:在SCL为高电平的时候,检测到SDA为高电平。
停止态:在SCL为高电平的时候,将SDA由低拉高。
IIC协议一共可以分为这六种状态,接下来将简要说明如何将这六种状态组成一个完整的IIC协议,来驱动MPU6050。
(1). IIC写
数据输出是以一个byte为单位的,从机地址一般为七位,与读写标志一起组成一个byte。0为写,1为读。
开始 -》 从机地址 + 0 -》 应答 -》发送寄存器地址 -》 应答 -》 写入数据 -》 非应答(应答) -》 停止
(2). IIC读
IIC读数据要比IIC写数据要复杂一点,主要是步骤上多了几步,但是状态什么的都完全一样。
开始 -》 从机地址 + 0 -》 应答 -》发送读取寄存器地址 -》 应答 -》开始 -》 从机地址 + 1 -》 读取数据 -》应答 -》 停止可以看到,只要将这几个状态实现了,按照这个流程就可以很容易实现IIC的读和写。大概的时序图如下。
三. 代码实现
根据上面的六个状态,定义出对应的六个函数,对应的只有五个,空闲态忽略,因为经过Stop后,IIC的时钟线和数据线都已经为高了。delay时间需要根据从机所能接受的最大速率来决定,不然的话,会出错,下面就来详细说明这几个函数。
(1) MPU6050IICDelay(void)
这就不用说明什么了
void MPU6050IICDelay(void) { uint16_t i = 250; while(i--); }
(2) MPU6050IICStart(void)
将SDA配置为输出模式。然后将SCL和SDA全部拉高,dealy后,将SDA拉低,就ok了。
void MPU6050IICStart(void) { SetSDAOut(); SCLHigh(); SDAHigh(); MPU6050IICDelay(); SDALow(); MPU6050IICDelay(); }
(3) MPU6050IICACK(void)
这里只包含了从机应答。
void MPU6050IICACK(void) { SCLLow(); MPU6050IICDelay(); SetSDAIn(); MPU6050IICDelay(); SCLHigh(); MPU6050IICDelay(); SDARead(); MPU6050IICDelay(); SCLLow(); }
(4) MPU6050IICStop(void)
停止位这里,需要先将SCL和SDA都拉低,然后先将SCL拉高,后将SDA拉高,
void MPU6050IICStop(void) { SetSDAOut(); MPU6050IICDelay(); SCLLow(); MPU6050IICDelay(); SDALow(); MPU6050IICDelay(); SCLHigh(); MPU6050IICDelay(); SDAHigh(); MPU6050IICDelay(); }
(5) MPU6050IICWrite(void)
void MPU6050IICWrite(uint8_t data) { uint8_t i; SetSDAOut(); MPU6050IICDelay(); for(i = 0 ; i < 8; i++) { SCLLow(); MPU6050IICDelay(); if(data & 0x80) SDAHigh(); else SDALow(); data = data << 1; MPU6050IICDelay(); SCLHigh(); MPU6050IICDelay(); } }
(6) MPU6050IICRead(void)
uint8_t MPU6050IICRead(void) { uint8_t i; uint8_t data = 0; SetSDAIn(); MPU6050IICDelay(); for(i = 0;i < 8; i++) { SCLLow(); MPU6050IICDelay(); SCLHigh(); MPU6050IICDelay(); if(SDARead()) data = data | 0x01; else data = data | 0x00; data = data << 1; MPU6050IICDelay(); } return data; }
读写数据,可以搭配时序图来,都是将SCL为低的时候,将数据送出去。在SCL为高的时候,接收数据。
然后将上面的这几个函数依次组合成读写两个函数
这里IIC驱动编写完成。
四. MPU6050 初始化
初始化的实质就是对寄存器进行配置,这就要查看芯片手册,了解每一个寄存器的作用了,以及初始化的时候寄存器配置的顺序。
这里将重要的寄存器列举出来了
#define MPU6050Addr 0xD0 #define ACCEL_XOUT_H 0x3B #define ACCEL_XOUT_L 0x3C #define ACCEL_YOUT_H 0x3D #define ACCEL_YOUT_L 0x3E #define ACCEL_ZOUT_H 0x3F #define ACCEL_ZOUT_L 0x40 #define GYRO_XOUT_H 0x43 #define GYRO_XOUT_L 0x44 #define GYRO_YOUT_H 0x45 #define GYRO_YOUT_L 0x46 #define GYRO_ZOUT_H 0x47 #define GYRO_ZOUT_L 0x48 #define PWR_MGMT_1 0x6B #define PWR_MGMT_2 0x6C #define SMPLRT_DIV 0x19 #define MPU_CONFIG 0x1A #define GYRO_CONFIG 0x1B #define ACCEL_CONFIG 0x1C #define MPU6050ID 0x75
(1). 初始化
/*MPU6050初始化*/ void MPU6050Init(void) { MPU6050GPIOInit(); MPU6050IICWriteRegister(MPU6050Addr,PWR_MGMT_1,0x80); rt_thread_mdelay(100); MPU6050IICWriteRegister(MPU6050Addr,PWR_MGMT_1,0x00); MPU6050IICWriteRegister(MPU6050Addr,SMPLRT_DIV,0x00); MPU6050IICWriteRegister(MPU6050Addr,MPU_CONFIG,0x03); MPU6050IICWriteRegister(MPU6050Addr,GYRO_CONFIG,0x18);// gyro scale :+-2000°/s MPU6050IICWriteRegister(MPU6050Addr,ACCEL_CONFIG,0x10);// Accel scale :+-8g (65536/16=4096 LSB/g) MPU6050IICWriteRegister(MPU6050Addr,0x6B,0x01); }
(2)验证
通过读取芯片的ID,可以确定IIC是否有问题。
/*读取MPU6050的ID*/ uint8_t MPU6050GetId(void) { return MPU6050IICReadRegister(MPU6050Addr,MPU6050ID); }
分享一个成果图
欢迎关注 微信公众号 FPGA之旅 获取相关资料
想要完整代码的,也可以在上面联系我,商务合作也咳哟
公众号:FPGA之旅