先說說廢話,第一篇博客文章,文中有不足之處或者有錯誤的地方還望指正。
IIC 總線(AT24C02)
一、先了解了解IIC總線協議基本知識
1.IIC協議是二線制,信號線包含SDA和SCL,且信號線是雙向的,開路結構,需要通過上拉電阻到VCC,具體的電阻值影響的是信號反應速度和驅動能力。
2.IC傳輸時,要保持SCL為高電平不變,SDA保持穩定;IIC開始的條件:SCL保持高電平,SDA從高電平跳躍到低電平,IIC停止通訊的條件:SCL保持高電平,SDA從低電平跳躍到高電平。
3.串行的8位雙向數據傳輸位速率在標准模式下可達100kbit/s,快速模式下可達400kbit/s,高速模式下可達3.4Mbit/s(一般不用考慮)。
單片機一般最高使用到400KBit/s(具體查看數據手冊可知),可知IIC的時鍾周期可以設置為:2.5us - 10us。
二、以下是此次學習IIC通訊協議,調試過程中一些要點
1.只有當SCL為高電平時,SDA線上的數據才有效,且在SCL電平升高前,SDA電平要保持穩定。
2.SCL,SDA為高電平時,總線為空閑狀態。
3.在主機讀數據前,應把SDA拉高,釋放SDA,交由從機控制。
4.要注意每種功能實現時總線的時序性(比如:start -> write - ack)。
5.要注意寫數據周期不能超過write cycle time(byte or page),查看數據手冊可知。
6.在寫完數據后讀取數據時,需做延時,否則會讀取不到數據(具體時間和設置時鍾周期有關)。
7.在接收ACK時,應先釋放SDA,在SCL為高電平時接收(與第3點一樣)。
三、調試過程:先看數據手冊時序圖
1.啟動、停止IIC
啟動過程:拉高SCL,SDA (延時)-->拉低SDA(延時) -->拉低SCL(延時),最后拉低SCL是為了控制總線為忙狀態
停止過程:拉高SDA(延時) -->拉高SCL(延時) -->拉高SDA(延時)
void IIC_START(void) { SDA_H; SCL_H; delay_us(5); SDA_L; delay_us(5); SCL_L; //控制總線為忙狀態 delay_us(5); }
void IIC_STOP(void) { // SCL_L;// SDA_L; delay_us(5); SCL_H; delay_us(5); SDA_H; delay_us(5); }
2.寫數據、讀數據
這里需要特別注意,讀數據時,需先將SDA拉高,釋放控制權,交由從機控制。
寫數據:先將數據准備好(SDA拉高、或拉低)-->拉高SCL(延時)(此時從機讀取SDA的電平) -->拉低SCL(延時)(等待下一位數據,即DATA CHANG)
讀數據:拉高SDA(延時) -->拉高SCL(延時) -->讀取數據 -->拉低SCL(延時)(等待下一位數據,即DATA CHANG)
void IIC_Write_Byte(u8 ucdata) { u8 i = 8; // SCL_L;// while(i--) { if(ucdata & 0x80) { // 1.先准備數據,從機在SCL為高電平時讀入數據 SDA_H; } else { SDA_L; } delay_us(5); SCL_H; // 2.拉高SCL,從機讀取穩定數據 delay_us(5); SCL_L; // 3.拉低SCL,等待下一位數據 ucdata <<= 1; } }
u8 IIC_Read_Byte(void) { u8 i = 8, ucdata = 0x00; // SCL_L;// SDA_H; // 1.先拉高SDA,釋放SDA總線 delay_us(5); while(i--) { SCL_H; // 2.再拉高SCL,從機在SCL為高電平時輸出穩定的數據 delay_us(5); ucdata <<= 1; if(Read_SDA) { //讀數據 ucdata = ucdata | 0x01; } SCL_L; // 3.拉低SCL,等待下一位數據 delay_us(5); } return ucdata; }
3.獲取應答、回復應答
在讀數據或寫數據,在第9個時鍾周期回復應答或獲取應答,即讀取8bit數據或寫8bit數據后應答。其實這里與讀數據,寫數據是一樣的,只是這個過程只有一個周期。
回復應答(寫數據),獲取應答(讀數據)。
u8 IIC_Get_ACK(void) { u8 wait_tiem,ack; ack = 0; SDA_H; // 1.先拉高SDA,釋放SDA控制,交給從機控制 delay_us(5); SCL_H; // 2.再拉高SCL,從機輸出穩定數據 delay_us(5); while(Read_SDA) { //主機讀取數據 wait_tiem++; if(wait_tiem > 10) { ack = 1; break; } } delay_us(5); SCL_L; // 3.拉低SCL,完成一個時鍾周期 return ack; }
void IIC_Set_ACK(u8 ack) { if(ack) { SDA_H; // 1.先准備數據 } else { SDA_L; } // SCL_L; delay_us(5); SCL_H; // 2.拉高SCL,從機讀取穩定的數據 delay_us(5); SCL_L; // 3.拉低SCL,完成一個時鍾周期 }
IIC總線協議底層程序完成,接下來是寫芯片應用程序,讀寫過程一定要嚴格按照芯片數據手冊的時序。
4.應用(AC24C02)
①.首先要知道設備地址,數據存儲地址(個人理解)。AT24C02芯片是一個2K 大小的EEPROM存儲芯片,2 * 1024 = 2048 字節,總共256個數據。
設備地址由固定的“1010” + 三位硬件選擇位(與硬件連接有關) + 一位讀/寫命令位;
數據存儲地址:0 - 255(0x00 - 0xFF)。
②寫數據,可以單次寫8位(字節寫),或多次寫8位(頁寫);1K/2K的EEPROM的芯片以8位數據(即一個字節)為一頁。
byte write:啟動 --> 寫設備地址+寫命令 -->獲取應答(ack) -->寫位置地址 -->獲取應答 -->寫數據 -->獲取應答 --> 停止
page write:與byte write 過程一樣,寫完一頁數據獲取到從機應答后繼續寫數據,直到寫完最后一個數據獲取到應答后發送停止。
/*************************** **函數名稱:IIC_Write_Data **參 數:DeviceAddr:設備地址 WordAddr:數據存儲地址 *Data :需要寫的數據 num :寫個數 **作 用:隨機寫數據,返回值為1:寫數據成功;返回值為0:寫數據失敗 **日 期:2020.2.17 **作 者:Yangyang ****************************/ u8 IIC_Write_Data(u8 DeviceAddr,u16 WordAddr,u8 *Data,u8 num) { u8 AddrTemp, i; IIC_START(); //啟動 IIC_Write_Byte(DeviceAddr & 0xfe); //設備地址 + 寫命令 if(IIC_Get_ACK()) { IIC_STOP(); return 0; } AddrTemp = (WordAddr & 0xff); //存儲數據地址 IIC_Write_Byte(AddrTemp); if(IIC_Get_ACK()) { IIC_STOP(); return 0; } for(i = 0; i < num; i++) { IIC_Write_Byte(*(Data + i));//寫數據 if(IIC_Get_ACK()) { IIC_STOP(); return 0; } } IIC_STOP(); delay_ms(3);//最少需延時2ms,在寫完數據后讀數據,不延時會讀取數據失敗(也可以函數外部延時) return 1; }
③讀數據,讀數據可分為當前地址讀數據、隨機地址讀數據和順序地址讀數據(此處就不說當前地址讀數據,基本不用)
隨機讀數據:啟動 --> 先寫設備地址 + 寫命令 -->獲取應答 --> 寫讀取數據的位置 -->獲取應答 --> 再啟動 --> 寫設備地址 + 讀命令 --> 獲取應答 --> 讀取數據 --> 回復不應答 --> 停止
順序讀數據:讀取方式與隨機讀數據相似,在讀取數據后是回復應答,當讀到最后一個數據后再回復不應答:....讀取數據n-1 --> 回復應答 -->讀取數據n --> 回復不應答 --> 停止
/*************************** **函數名稱:IIC_Read_Data **參 數:DeviceAddr: 設備地址 WordAddr: 數據存儲地址 *Data : 讀取的數據 num : 讀取個數 **作 用:隨機讀取數據,順序讀取數據,返回值為1:讀取數據成功;返回值為0:讀取數據失敗 **日 期:2020.2.17 **作 者:Yangyang ****************************/ u8 IIC_Read_Data(u8 DeviceAddr,u16 WordAddr,u8 *Data,u8 num) { u8 AddrTemp, i; IIC_START(); //啟動 IIC_Write_Byte(DeviceAddr & 0xfe); //設備地址 + 寫命令 if(IIC_Get_ACK()) { IIC_STOP(); //Internally organized with 32 pages of 8 byteseach, return 0; //the 2K requires an 8-bit data word address for random word addressing. } //此說明在數據手冊可知 AddrTemp = (WordAddr & 0xff); //地址可取0 - 255 IIC_Write_Byte(AddrTemp); if(IIC_Get_ACK()) { IIC_STOP(); return 0; } delay_us(100); IIC_START(); //再啟動 IIC_Write_Byte(DeviceAddr | 0x01); //設備地址 + 讀命令 if(IIC_Get_ACK()) { // IIC_STOP(); return 0; } for(i = 0; i < num; i++) { *(Data + i) = IIC_Read_Byte(); //讀數據 if(i < num - 1) { IIC_Set_ACK(0); //接收N-1個數據后應該從機 } else { //接收最后一個數據時不應答從機 IIC_Set_ACK(1); } } IIC_STOP(); //停止 return 1; }
④測試
使用硬件:STM32F103 + AT24C02
#define at24c02_byte_num 8
u8 IIC_ref_data[at24c02_byte_num] = {0};
u8 IIC_ref_data2[at24c02_byte_num] = {0};
u8 IIC_write_data[at24c02_byte_num] = {0x20,0x20,0x02,0x29,0x21,0x51,0x55,0x55}
u8 Test_IIC(void) { u8 i = 0; IIC_Write_Data(0xa0,0,IIC_write_data,at24c02_byte_num); // delay_ms(3); i = IIC_Read_Data(0xa0,0,IIC_ref_data2,at24c02_byte_num); return i; }