STM32驱动MPU6050基于IIC协议

简介: 笔记

一. 简介


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 -》 应答 -》发送寄存器地址 -》 应答 -》 写入数据 -》 非应答(应答) -》 停止

20.png


(2). IIC读

IIC读数据要比IIC写数据要复杂一点,主要是步骤上多了几步,但是状态什么的都完全一样。


开始 -》 从机地址 + 0 -》 应答 -》发送读取寄存器地址 -》 应答 -》开始 -》 从机地址 + 1 -》 读取数据 -》应答 -》 停止可以看到,只要将这几个状态实现了,按照这个流程就可以很容易实现IIC的读和写。大概的时序图如下。21.png


三. 代码实现


根据上面的六个状态,定义出对应的六个函数,对应的只有五个,空闲态忽略,因为经过Stop后,IIC的时钟线和数据线都已经为高了。delay时间需要根据从机所能接受的最大速率来决定,不然的话,会出错,下面就来详细说明这几个函数。


22.png

(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为高的时候,接收数据。

然后将上面的这几个函数依次组合成读写两个函数



23.png

这里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之旅 获取相关资料

想要完整代码的,也可以在上面联系我,商务合作也咳哟

image.png


公众号:FPGA之旅

目录
相关文章
小巴陪你搞技术-STM32驱动1602时钟
小巴陪你搞技术-STM32驱动1602时钟
|
17天前
【STM32】通过RTThread驱动W25QXXX
【STM32】通过RTThread驱动W25QXXX
|
1月前
STM32F103驱动oled显示屏
STM32F103驱动oled显示屏
21 0
|
8月前
|
传感器
STM32(HAL库)驱动GY30光照传感器通过串口进行打印
STM32(HAL库)驱动GY30光照传感器通过串口进行打印
|
6月前
|
存储 机器人 芯片
嵌入式 STM32 步进电机驱动,干货满满,建议收藏
嵌入式 STM32 步进电机驱动,干货满满,建议收藏
嵌入式 STM32 步进电机驱动,干货满满,建议收藏
|
6月前
|
API 芯片
嵌入式 STM32 实现STemwin移植+修改其配置文件,驱动LCD显示文本 (含源码,建议收藏)
嵌入式 STM32 实现STemwin移植+修改其配置文件,驱动LCD显示文本 (含源码,建议收藏)
|
6月前
|
传感器 智能硬件
STM32cubemx配置驱动DHT11模块
STM32cubemx配置驱动DHT11模块
68 0