天天看點

stm32 mpu6050 模拟i2c執行個體實作

    歡迎大家通路我的github:https://github.com/Iamttp

    最近準備一個比賽,是以正在加緊學習stm32,這篇文章就結合mpu6050分析一下利用i2c實作晶片之間的通信。

    首先可以在原有的LED檔案或顯示屏(OLED)的檔案基礎上,建立一個HANDWARE,在其中加入mpu6050.c和mpu6050.h(名字自定)。

stm32 mpu6050 模拟i2c執行個體實作

    首先是在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執行個體實作

完成上面的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); 

    利用這個算法可以得到較精确的值。

歡迎大家評論指正,也歡迎大家提出相關代碼的重難點,部落客會第一時間回複處理!

繼續閱讀