要特別說明下:所有的數據位包括應答位都需要主設備產生時鐘脈沖。如果從設備沒有應答意味著將沒有更多的數據要傳送或者設備沒有準備好傳送。這時,主設備要么產生停止信號,要么重新發出開始條件。

圖 7_6 應答信號
n I2C的7-bit地址:
上面說過每一個從設備都應該具有唯一的地址,這樣主設備才能準確的尋址到每一個設備,而這些地址被統一規定為7比特。但是上面講過I2C總線傳輸數據都是8比特傳送,地址7比特豈不是少一位!其實緊跟地址還有一位用來表示是讀操作還是寫操作的標志位。如果該位為0表示主設備將要向從設備寫數據,否則表示主設備將要從從設備讀數據。在這8比特被發送后主設備能夠持續地進行讀或者寫。如果主設備想和其他從設備進行通信,只要再次發送一個新的開始信號就可以而不必發送終止信號。

圖 7_7 一個完整的數據讀寫操作
8 、MPU6050驅動設計
至此,我們基本上已經將I2C的知識學完了,下面將結合MPU6050的驅動進一步講解其原理(該部分的代碼參見工程的mpu6050.c部分)。我們首先來看一下它的頭文件mpu6050.h:從第6到25行上來就是一大串內部地址的定義,對于初學者可能一頭霧水!如果樓主再引入寄存器等數字電路的知識可能又要說幾頁了,于是這里準備只用一個簡單的例子闡述下這些地址的作用。
#include“i2c.h”
//-----------------------------------------
// 定義MPU6050內部地址
//-----------------------------------------
#define SMPLRT_DIV 0x19 //陀螺儀采樣率,典型值:0x07(125Hz)
#define CONFIG 0x1A //低通濾波頻率,典型值:0x06(5Hz)
#define GYRO_CONFIG 0x1B //陀螺儀自檢及測量范圍,典型值:0x18(不自檢,2000deg/s)
#define ACCEL_CONFIG 0x1C //加速計自檢、測量范圍及高通濾波頻率,典型值:0x01(不自檢,2G,5Hz)
#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 TEMP_OUT_H 0x41
#define TEMP_OUT_L 0x42
#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 //電源管理,典型值:0x00(正常啟用)
#define WHO_AM_I 0x75 //IIC地址寄存器(默認數值0x68,只讀)
#define SlaveAddress 0xD0 //IIC寫入時的地址字節數據,+1為讀取
//-----------------------------------------
// 通過I2C和MPU6050通信的函數
//-----------------------------------------
void Single_WriteI2C(uchar REG_Address,uchar REG_data);//向I2C設備寫入一個字節數據
uchar Single_ReadI2C(uchar REG_Address); //從I2C設備讀取一個字節數據
void InitMPU6050(); //初始化MPU6050
int GetData(uchar REG_Address); //合成數據
上面講到在I2C總線中主設備可以通過固定的7-bit地址尋找到相應的從設備(這里的7-bit地址為第26行的SlaveAddress,想必大家也能夠理解后面注釋的意義了吧~不加1表示緊跟著地址的一位為0,表示向該設備寫數據;加1則表示緊跟著的一位為1,表示主設備從從設備讀數據)。雖然采用這種方式能夠準確找到從設備,但是從設備里面又有比較多的寄存器。這就好比你知道了某個要找的東西在具體的某個大柜子里,但是來到大柜子前又發現有許多小抽屜。這里的7-bit地址就好像指明了哪個柜子,而從第6到25行的內部地址就像柜子上的抽屜編號,而不一樣之處是位于mpu6050內的“小抽屜”一部分存放著其采集的實時數據,另一部分等著外部放一些數據來設置其采樣屬性。
這樣,如上面的第6行的SMPLRT_DIV(0x19)是用來設置陀螺儀采樣率的寄存器地址,只要向該地址所指的寄存器寫入相應的值則可以設置陀螺儀采樣率。因此下面MPU6050初始化函數就是調用封裝的I2C寫函數向相應的小抽屜內寫屬性數據,設置MPU6050采樣屬性。
//------------------------------------------------
//初始化MPU6050
//------------------------------------------------
void InitMPU6050()
{
Single_WriteI2C(PWR_MGMT_1, 0x00); //解除休眠狀態
Single_WriteI2C(SMPLRT_DIV, 0x07);
Single_WriteI2C(CONFIG, 0x06);
Single_WriteI2C(GYRO_CONFIG, 0x18);
Single_WriteI2C(ACCEL_CONFIG, 0x01);
}
再如第10~11行的ACCEL_XOUT_H、ACCEL_XOUT_L是用來存放最新的陀螺儀X極的數值,因為采用16位ADC所以這里需要用兩個寄存器。所以下面合成數據函數負責連續讀取REG_Address開始的兩字節數據組成一個16位數據。當函數的參數為ACCEL_XOUT_H時,則獲取的是實時的陀螺儀X極的數值,同樣地可以獲得實時的6軸數據。
//------------------------------------------------
//合成數據
//------------------------------------------------
int GetData(uchar REG_Address)
{
uchar H,L;
H=Single_ReadI2C(REG_Address);
L=Single_ReadI2C(REG_Address+1);
return (H《《8)+L; //合成數據
}
電子發燒友App





評論