stm32 mpu6050 模拟i2c实例实现

    欢迎大家访问我的github:https://github.com/Iamttp

    最近准备一个比赛,所以正在加紧学习stm32,这篇文章就结合mpu6050分析一下利用i2c实现芯片之间的通信。

    首先可以在原有的LED文件或显示屏(OLED)的文件基础上,新建一个HANDWARE,在其中加入mpu6050.c和mpu6050.h(名字自定)。

stm32 mpu6050 模拟i2c实例实现_第1张图片

    首先是在C文件中加入基本的I2C通信函数

    1.I2C的GPIO端口初始化SDA、SCL设置为推挽输出。

    2.然后是i2c_start();i2c_stop();函数,根据时序图设置SCL、SDA的高低电平变化。

    3.之后加入主机ack的响应函数和ack的等待响应函数i2c_wait_ack();i2c_ack();i2c_waitack();。

    4.最后加入IIC_Send_Byte();和IIC_Read_Byte();

    具体实现可以参考其他文章,这里重点讲解mpu6050的通信实现。

    (

        读者可以参考我上传到github的I2C代码实现:

        https://github.com/Iamttp/STM32_CODE/blob/master/mpu6050/HARDWARE/MPU6050/mpu6050.c

    )

    上面部分的一个难点在于GPIO口的模式转化,因为SDA的输入输出在变化,所以可以使用寄存器操作的宏定义来改变IO口的模式,使用位操作来控制SDA、SCL的高低电平。其中在wait_ack中设置SDA为输入,可以通过SDA_w的设置达到输入的上拉、下拉的设置,具体参考下面的端口位配置表。

#define SDA_IN()  {GPIOB->CRH&=0XFFFFFFF0;GPIOB->CRH|=8<<0;}
#define SDA_OUT() {GPIOB->CRH&=0XFFFFFFF0;GPIOB->CRH|=3<<0;}

//IO操作函数	 
#define SCL    PBout(9) 		//SCL
#define SDA_w    PBout(8) 		//SDA	 
#define SDA_r  PBin(8) 		//输入SDA 

stm32 mpu6050 模拟i2c实例实现_第2张图片

 

完成上面的I2C函数,就可以根据I2C函数完成mpu6050函数的编写了。

 

对于具体芯片,有具体的时序分析。这部分也可以参考其他文章,这里列出MPU6050的IIC实例。

u8 MPU_Write_Byte(u8 reg, u8 data) {
    i2c_start();
    IIC_Send_Byte((MPU_ADDR << 1) | 0);  //发送器件地址+写命令
    if (i2c_wait_ack())                  //等待应答
    {
        i2c_stop();
        return 1;
    }
    IIC_Send_Byte(reg);   //写寄存器地址
    i2c_wait_ack();       //等待应答
    IIC_Send_Byte(data);  //发送数据
    if (i2c_wait_ack())   //等待ACK
    {
        i2c_stop();
        return 1;
    }
    i2c_stop();
    return 0;
}

u8 MPU_Read_Byte(u8 reg) {
    u8 res;
    i2c_start();
    IIC_Send_Byte((MPU_ADDR << 1) | 0);  //发送器件地址+写命令
    i2c_wait_ack();                      //等待应答
    IIC_Send_Byte(reg);                  //写寄存器地址
    i2c_wait_ack();                      //等待应答
    i2c_start();
    IIC_Send_Byte((MPU_ADDR << 1) | 1);  //发送器件地址+读命令
    i2c_wait_ack();                      //等待应答
    res = IIC_Read_Byte(0);              //读取数据,发送nACK
    i2c_stop();                          //产生一个停止条件
    return res;
}

    

    1.针对mpu6050写出具体的字节发送、读取函数,mpu6050主要用到了MPU_Read_Byte,MPU_Write_Byte,MPU_Read_Len(连续读函数)。

    2.mpu6050的初始化函数MPU_Init(),其中会向芯片的指定寄存器传入参数,所以可以在.h文件中加入寄存器的宏定义。

    3.根据需要定义向指定寄存器读取数值的函数,mpu6050可以读取陀螺仪值、加速度值、温度值。

    其中加速度计通过重力加速度分解(利用atan2)可以得到倾角,而陀螺仪则可以测得角速度。但是这两类数据都不准确,需要数据融合。

这里给出一个互补滤波的算法。

    Angle = (0.98) * (Angle + gyro * dt) + (0.02) *(acc); 

    利用这个算法可以得到较精确的值。

       

欢迎大家评论指正,也欢迎大家提出相关代码的重难点,博主会第一时间回复处理!

你可能感兴趣的:(硬件相关)