摘要:協(xié)議物理層原理總體特征協(xié)議層起始和停止條件數(shù)據(jù)有效性響應(yīng)應(yīng)答尋址讀數(shù)據(jù)寫數(shù)據(jù)單片機通訊軟件模擬硬件外設(shè)一物理層原理總線,分別由串行數(shù)據(jù)線和串行時鐘線及上拉電阻組成。第八步,主機發(fā)送一個校驗碼,此校驗值為步數(shù)據(jù)產(chǎn)生的校驗碼。
I2C 總線,分別由SDA(串行數(shù)據(jù)線)和SCL(串行時鐘線)及上拉電阻組成。
通信原理是通過對SCL和SDA線高低電平時序的控制,來 產(chǎn)生I2C總線協(xié)議所需要的信號進行數(shù)據(jù)的傳遞。在總線空閑狀態(tài)時,這兩根線一般被上面所接的上拉電阻拉高,保持著高電平。
? 連接到總線的器件輸出級必須是漏極開路或集電極開路才能執(zhí)行線與的功能。
? I2C 總線上的每一個設(shè)備都可以作為主設(shè)備或者從設(shè)備,而且每一個設(shè)備都會對應(yīng)一個唯一的地址(可以從I2C器件的數(shù)據(jù)手冊得知),主從設(shè)備之間就通過這 個地址來確定與哪個器件進行通信。
? I2C 總線上數(shù)據(jù)的傳輸速率在標(biāo)準(zhǔn)模式下可達 100kbit/s ,在快速模式下可達 400kbit/s ,在高速模式下可達 3.4Mbit/s ,連接到總線的接口數(shù)量只由總線電容是 400pF 的限制決定。
? I2C 總線上的主設(shè)備與從設(shè)備之間以字節(jié)(8位)為單位進行雙向的數(shù)據(jù)傳輸。
I2C協(xié)議規(guī)定,總線上數(shù)據(jù)的傳輸必須以一個起始信號作為開始條件,以一個結(jié)束信號作為傳輸?shù)耐V箺l件。
起始和結(jié)束信號總是由主設(shè)備產(chǎn)生。
SDA線上的數(shù)據(jù)必須在SCL的高電平時保持穩(wěn)定。
SDA線的高或低電平狀態(tài)只有在 SCL 線的時鐘信號是低電平時才能改變。
發(fā)送到 SDA 線上的每個字節(jié)必須為 8 位,每次傳輸可以發(fā)送的字節(jié)數(shù)量不受限制 ,每個字節(jié)后必須跟一個響應(yīng)位 ,首先傳輸?shù)氖菙?shù)據(jù)的最高位(見下圖MSB )
如果從機要完成一些其他功能后(如中斷)才能接收或發(fā)送下一個完整的數(shù)據(jù)字節(jié) ,可以使時鐘線 SCL 保持低電平迫使主機進入等待狀態(tài) ,當(dāng)從機準(zhǔn)備好接收下一個數(shù)據(jù)字節(jié)時釋放時鐘線 SCL, 數(shù)據(jù)傳輸繼續(xù)。
數(shù)據(jù)傳輸必須帶響應(yīng),相關(guān)的響應(yīng)SCL時鐘脈沖由主機產(chǎn)生,在響應(yīng)的時鐘脈沖期間,發(fā)送器釋放 SDA 線(輸出高阻態(tài)使SDA線被上拉電阻拉高)。在響應(yīng)的時鐘脈沖期間,接收器必須將 SDA 線拉低,使它在這個時鐘脈沖的高電平期間保持穩(wěn)定的低電平。 必須考慮建立和保持時間。
在起始條件 S 后 ,發(fā)送了一個從機地址SLAVE ADDRESS, 這個地址共有 7 位,緊接著的第 8 位是數(shù)據(jù)方向位[R/W], 0 表示寫,1表示讀。接下來的一個bit是應(yīng)答位NACK/ACK,當(dāng)這個幀中前面8bits發(fā)送完后,接收端獲得SDA控制權(quán),此時接收設(shè)備應(yīng)該在第9個時鐘脈沖之前回復(fù)一個ACK(將SDA拉低)以表示接收正常,如果接收設(shè)備沒有將SDA拉低,則說明接收設(shè)備可能沒有收到數(shù)據(jù)(如尋址的設(shè)備不存在或設(shè)備忙)或無法解析收到的消息,如果是這樣,則由master來決定如何處理(stop或repeated start condition)。
10 位從機地址是由在起始條件 S 或重復(fù)起始條件 Sr 后的頭兩個字節(jié)組成。
第一個字節(jié)的頭 7 位是 11110XX 的組合 ,其中:最后兩位 XX 是 10 位地址的兩個最高位 MSB
第一個字節(jié)的第 8 位是 R/ W 位, 決定了報文的方向 :0 表示寫, 1 表示讀。
如果 R/ W 位是 0 則下一個字節(jié)是 10 位從機地址剩下的 8 位;
如果 R/ W 位是 1 則下一個字節(jié)是從機發(fā)送給主機的數(shù)據(jù)。
仲裁過程
主機只能在總線空閑的時侯啟動傳輸。兩個或多個主機可能在起始條件的最小持續(xù)時間內(nèi)產(chǎn)生一個起始條件,結(jié)果在總線上產(chǎn)生一個規(guī)定的起始條件。
當(dāng) SCL 線是高電平時,仲裁在 SDA 線發(fā)生。這樣,在其他主機發(fā)送低電平時,發(fā)送高電平的主機將退出競爭, 因為總線上的電平與它自己的電平不相同。
仲裁可以持續(xù)多位。第一個階段是比較地址位,如果每個主機都嘗試尋址相同的器件,當(dāng)主機作發(fā)送器時仲裁會繼續(xù)比較數(shù)據(jù)位,當(dāng)主機作接收器時仲裁會繼續(xù)比較響應(yīng)位。
IIC總線的地址和數(shù)據(jù)信息由贏得仲裁的主機決定,因此在仲裁過程中不會丟失信息。
丟失仲裁的主機可以產(chǎn)生時鐘脈沖,直到丟失仲裁的該字節(jié)末尾。
可以看到在起始信號的第3個時鐘周期低電平時,DATA1的SDA輸出高電平,而DATA2向SDA輸出低電平,SDA總線保持低電平,仲裁給到DATA2,即DATA1的主機退出競爭,不再發(fā)送數(shù)據(jù)。DATA1主機贏得仲裁,SDA總線已傳送的數(shù)據(jù)和DATA1發(fā)送的數(shù)據(jù)保持一致。
7位尋址為例 CPU作為主接收器
第一步,主機發(fā)送一個起始信號S。
第二步,主機發(fā)送7bit從機地址。此處需要注意,發(fā)送數(shù)據(jù)時,無法發(fā)送7bit數(shù)據(jù),此處發(fā)送了7bit地址+1bit讀寫選擇位,即發(fā)送7bit+R/W。最低位為1表示讀,為0表示寫。
第三步,從機產(chǎn)生一個ACK應(yīng)答信號。
//第四步,主機發(fā)送寄存器地址。
//第五步,從機產(chǎn)生一個ACK應(yīng)答信號。
//第六步,主機再次發(fā)送一個起始信號。
//第七步,主機發(fā)送7bit從機地址,即7bit+R/W。最低位為1表示讀,為0表示寫。
//第八步,從機產(chǎn)生一個ACK應(yīng)答信號。
第九步,主機讀取一個字節(jié)(8bit)的數(shù)據(jù)(相當(dāng)于從機發(fā)送一個字節(jié))。
第十步,CPU產(chǎn)生一個ACK應(yīng)答信號。
//第十一步,讀取一個CRC校驗碼。
第十二步,CPU產(chǎn)生一個NACK無應(yīng)答信號。
第十三步,主機產(chǎn)生一個停止信號。
常規(guī)的使用就是第一、二、三、九、十、十二、十三步。
注釋掉的是單片機集成的硬件IIC配置通信的整個完整的通訊過程。
CPU作為主發(fā)送器
第一步,主機發(fā)送一個起始信號。
第二步,發(fā)送7bit從機地址。此處需要注意,發(fā)送數(shù)據(jù)時,無法發(fā)送7bit數(shù)據(jù),此處發(fā)送了7bit地址+1bit讀寫選擇位,即發(fā)送7bit+R/W。最低位為1表示讀,為0表示寫。
第三步,從機產(chǎn)生一個ACK應(yīng)答信號。
//第四步,主機發(fā)送寄存器地址,8bit數(shù)據(jù)。
//第五步,從機產(chǎn)生一個ACK應(yīng)答信號。
第六步,主機發(fā)送一個字節(jié)(8bit)數(shù)據(jù)。
第七步,從機產(chǎn)生一個ACK應(yīng)答信號。
//第八步,主機發(fā)送一個CRC校驗碼,此CRC校驗值為2、4、6步數(shù)據(jù)產(chǎn)生的校驗碼。
第九步,從機既可以發(fā)送一個應(yīng)答信號,也可以發(fā)送一個無應(yīng)答信號。
第十步,主機發(fā)送一個停止信號。
CPU與EEPROM通訊為例
相關(guān)函數(shù):
void I2C_Delay(void); //延時,以防單片機速度太快void I2C_Start(void); //起始信號void I2C_Stop(void); //終止信號u8 I2C_SendByte(u8 data); //寫一個字節(jié)u8 I2C_ReadByte(void); //讀一個字節(jié)void EEPROM_Write(u8 address, u8 data); //往EEPROM的一個地址寫一個數(shù)據(jù)u8 EEPROM_Read (u8 address); //讀EEPROM的一個地址的數(shù)據(jù)
stm32軟件模擬配置流程:
初始化GPIO
void I2c_Init(void); //初始化GPIO
模擬總線SDA, SCL ,GPIO引腳開漏輸出
寫起始信號函數(shù)
void I2C_Start(void); //起始信號
SDA, SCL拉高 , 延時
SDA = 1; SCL = 1; delay();
SDA由高變低 , 延時
SDA = 0; delay();
SCL拉低,延時等待發(fā)送/接收
SCL = 0; delay();
寫終止信號函數(shù)
void I2C_Stop(void); //終止信號
SCL拉低后將SDA拉低 (SCL低電平時SDA可變),延時
SCL = 0; SDA = 0; delay();
SCL拉高 , 延時
SCL = 1; delay();
SDA由低變高 , 延時
SDA = 1; delay();
等待應(yīng)答信號函數(shù)
u8 I2C_WaitToAck(void); //讀取器件ACK應(yīng)答
產(chǎn)生/不產(chǎn)生ACK應(yīng)答
void I2C_Ack(void);
void I2C_NoAck(void);
寫一個字節(jié)
讀一個字節(jié)
//延時static void I2c_Delay(void){ /*CPU主頻72MHz 10: SCL頻率205KHz 7: SCL頻率347KHz,高電平1.5us,低電平2.87us; 5: SCL頻率421KHz,高電平1.25us,低電平2.375us;*/ u8 i; for(i = 0; i < 10; i++);}//起始信號void I2C_Start(void){ I2C_SDA_High(); //SDA=1 I2C_SCL_High(); //SCL=1 I2C_Delay(); I2C_SDA_Low(); I2C_Delay(); I2C_SCL_Low(); I2C_Delay();}//終止信號void I2C_Stop(void){ I2C_SDA_Low(); I2C_SCL_High(); I2C_Delay(); I2C_SDA_High(); I2C_Delay();}//寫一個字節(jié)u8 I2C_SendByte(uint8_t Byte){ uint8_t i; /* 先發(fā)送高位字節(jié) */ for(i = 0 ; i < 8 ; i++) { if(Byte & 0x80) { I2C_SDA_High(); } else { I2C_SDA_Low(); } I2C_Delay(); I2C_SCL_High(); I2C_Delay(); I2C_SCL_Low(); I2C_Delay(); if(i == 7) { I2C_SDA_High(); /* 釋放SDA總線 */ } Byte <<= 1; /* 左移一位 */ I2C_Delay(); }} //讀取一個字節(jié)u8 I2C_ReadByte(void){ uint8_t i; uint8_t value; /* 先讀取最高位即bit7 */ value = 0; for(i = 0 ; i < 8 ; i++) { value <<= 1; I2C_SCL_High(); I2C_Delay(); if(I2C_SDA_READ()) { value++; } I2C_SCL_Low(); I2C_Delay(); } return value;}//產(chǎn)生一個ACK應(yīng)答信號void I2C_Ack(void){ I2C_SDA_Low(); I2C_Delay(); I2C_SCL_High(); //cpu產(chǎn)生一個時鐘 I2C_Delay(); I2C_SCL_Low(); I2C_Delay(); I2C_SDA_High();}//產(chǎn)生一個非ACK信號void I2C_NoAck(void){ I2C_SDA_High(); I2C_Delay(); I2C_SCL_High(); //cpu產(chǎn)生一個時鐘 I2C_Delay(); I2C_SCL_Low(); I2C_Delay();}//產(chǎn)生時鐘讀取器件ACK應(yīng)答信號u8 I2C_WaitToAck(void){ u8 redata; I2C_SDA_High(); //CPU釋放SDA總線 I2C_Delay(); I2C_SCL_High(); //SCL=1此時器件會返回ACK應(yīng)答 I2C_Delay(); if(I2C_SDA_READ()) //CPU讀取SDA口線狀態(tài) { redata = 1; } else { redata = 0; } I2C_SCL_Low(); I2C_Delay(); return redata;}
與EEPROM通訊為例
typedef struct{ uint32_t I2C_ClockSpeed; //設(shè)置SCL時鐘頻率 <40,000 uint32_t I2C_Mode; //工作模式 I2C模式或SMBUS模式 uint32_t I2C_DutyCycle; //指定時鐘占空比 低/高=2/1或16/9 uint32_t I2C_OwnAddress1; //指定自身的I2C設(shè)備地址 uint32_t I2C_Ack; //使能或關(guān)閉響應(yīng)(一般使能) uint32_t I2C_AcknowledgedAddress; //指定地址長度 7位/10位} I2C_InitTypeDef;
參考:
原理:《IIC總線協(xié)議中文版》
代碼實現(xiàn):博客園
學(xué)習(xí):野火、正點原子、普中科技
部分圖片來源于網(wǎng)站,侵刪
修改時間:2021年09月27日
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/121624.html
摘要:如圖所示在了解起始條件和停止條件后,我們再來看看在這個過程中數(shù)據(jù)的傳輸是如何進行的。四參考資料通過接口實現(xiàn)溫濕度的采集硬件和軟件區(qū)別 stm32通過I2C接口實現(xiàn)...
摘要:從設(shè)備使能信號,由主設(shè)備控制,只有該信號為預(yù)先規(guī)定的使能信號,對該芯片的操作才有效,這就允許再統(tǒng)一總線上連接多個設(shè)備。點對點通信中,接口不需要進行尋址操作,但是沒有指定的流控制,沒有應(yīng)答機制確認(rèn)是否接收到數(shù)據(jù)。 1、GPIO 通用可編程IO接口,對于簡單的外圍設(shè)備或者電路,需要CPU為之提供...
摘要:使用庫讀寫環(huán)境光照度傳感器本文將教大家如何快速使用庫讀取光照度數(shù)據(jù)。五實驗樣機測試展示通過之前配置好的面板,通過涂鴉智能進行配網(wǎng)實時采集光照度傳感器的數(shù)據(jù)。 使用STM32 HAL庫讀寫環(huán)境光照度傳感器(BH1750) 本文將教大家如何快速使用STM32HAL庫讀取光照度數(shù)據(jù)。 實現(xiàn)功能:通...
摘要:問你是否用過什么操作系統(tǒng),,等,這個是加分項,然后會問一些的協(xié)議,進程與線程區(qū)別,還有一些電機算法,或者視覺等等。 大家好,我是Q3。我是一名2022屆的一名電氣工程及其自動化的學(xué)生,學(xué)校是二本就不說啦。 ??我今天主要是來淺談一下我的面試經(jīng)驗以及一些遇到的問題。 ??首先我來聊一下我的學(xué)習(xí)...
摘要:帶中文字庫的是一種具有位位并行線或線串行多種接口方式,內(nèi)部含有國標(biāo)一級二級簡體中文字庫的點陣圖形液晶顯示模塊其顯示分辨率為。貼片按鍵模塊支持標(biāo)準(zhǔn)的協(xié)議,完整的協(xié)議棧。以最低成本提供最大實用性,為功能嵌入其他系統(tǒng)提供無限可能。 項目簡介 開發(fā)環(huán)境: Keil5.14,CubeMX6.0.1,主...
閱讀 2984·2023-04-25 19:45
閱讀 2700·2021-11-19 09:40
閱讀 707·2021-10-14 09:49
閱讀 2721·2021-09-30 09:47
閱讀 2251·2021-09-26 09:55
閱讀 1240·2021-09-22 16:01
閱讀 2823·2019-08-30 14:19
閱讀 716·2019-08-29 16:44