I2C(Inter-Integrated Circuit)總線是由PHILIPS公司開發的兩線式串行總線,用於連接微控制器及其外圍設備。是微電子通信控制領域廣泛採用的一種總線標準。它是同步通信的一種特殊形式,具有接口線少,控制方式簡單,器件封裝形式小,通信速率較高等優點。
只要求兩條總線線路:一條串行數據線SDA,一條串行時鐘線SCL;串行的8 位雙向數據傳輸位速率在標準模式下可達100kbit/s,快速模式下可達400kbit/s,高速模式下可達3.4Mbit/s;每個連接到總線的器件都可以通過唯一的地址和一直存在的簡單的主機/從機關係軟件設定地址,主機可以作爲主機發送器或主機接收器; 它是一個真正的多主機總線,如果兩個或更多主機同時初始化,數據傳輸可以通過沖突檢測和仲裁防止數據被破壞;
I2C的使用實際上是嚴格遵循I2C總線協議進行的,下面我們結合STM32F051一一進行分析:
首先看I2C總線硬件:
硬件準備:
重新開始信號:它本質上是一個開始信號,信號電平和開始信號一樣,是在連續傳輸信號時進行使用。
應答信號:接收數據的IC在接收到8位數據後,會向主設備發出一個特定的低電平脈衝,這就是應答信號。應答信號一般在第9個週期出現,每位信號必須跟一位應答信號,表示數據已經接收。
如下圖所示:
上面兩個圖表示了數據連續傳輸的基本格式,那麼下面我們就來學習如何通過I2C對24c02進行讀寫。
軟件準備:
採樣庫函數編寫程序,工程配置如下圖所示,用戶需要調用stm32f0xx_i2c.c庫函數。需要編寫i2c_eeprom.c驅動文件和主函數main.c。
首先是開始信號,然後發送從機地址,寫選通,給一個應答信號。然後寫入要訪問的地址。
再次應答。從新開始信號,發送從機地址,從機地址是外掛總線地址。然後讀選通,主機等待從機的應答信號,當接收應答後,開始讀取數據。
而24C02寫和讀是按照頁進行。而按頁寫最大頁面不超過8個字節,超過後會發送覆蓋。此時採用緩衝進行處理和分配,下面幾個函數就是寫緩衝和寫頁面:
1
|
uint32_t
sEE_ReadBuffer(uint8_t* pBuffer, uint16_t ReadAddr, uint16_t* NumByteToRead); |
讀緩衝函數:uint8_t* pBuffer:緩衝指針。
uint16_t ReadAddr:讀的地址。
uint16_t* NumByteToRead:讀字節數
1
|
uint32_t
sEE_WritePage(uint8_t* pBuffer, uint16_t WriteAddr, uint8_t* NumByteToWrite); |
寫頁函數:uint8_t* pBuffer, 緩衝指針
uint16_t WriteAddr, 寫的地址
uint8_t* NumByteToWrite 寫字節數
1
|
void
sEE_WriteBuffer(uint8_t* pBuffer, uint16_t WriteAddr, uint16_t NumByteToWrite); |
寫緩衝函數:uint8_t* pBuffer, 緩衝指針
uint16_t WriteAddr, 寫的地址
uint8_t* NumByteToWrite 寫字節數
1
|
uint32_t
sEE_WaitEepromStandbyState( void ); |
等待EEPROM待機狀態
主函數首先向24c02寫入一個數據,然後讀出這個數據。對比兩個數據是否一樣,判斷讀寫是否正確:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
uint8_t
temp1[]= "qfstm32" ; uint8_t
temp2[]; int
main( void ) { SystemInit(); LCD_init();
//
液晶顯示器初始化 LCD_Clear(WHITE);
//
全屏顯示白色 POINT_COLOR
= BLACK; //
定義筆的顏色爲黑色 BACK_COLOR
= WHITE; //
定義筆的背景色爲白色 I2C_EE_Init(); SPI_FLASH_Init(); LCD_DrawRectage(0,
0, 320, 20, DARKBLUE); //
畫一個深藍色邊框的矩形 LCD_ShowString(2,2, "實驗十一" ); LCD_ShowString(100,2, "i2c讀24c02實驗" ); sEE_WriteBuffer(temp1,
0x050, 8); LCD_ShowString(2,40, "24c02寫入值:" ); LCD_ShowString(100,40,temp1); NumDataRead=8; sEE_ReadBuffer(temp2,
0x050,(uint16_t *)(&NumDataRead)); LCD_ShowString(2,60, "24c02讀出值:" ); LCD_ShowString(100,60,temp2); if (*temp1
!= *temp2) { LCD_ShowString(50,80, "讀取EEROR" ); } else { LCD_ShowString(50,80, "讀取sccess" ); } while (1) {} } |