單芯片解決方案,開啟全新體驗——W55MH32 高性能以太網單片機
W55MH32是WIZnet重磅推出的高性能以太網單片機,它為用戶帶來前所未有的集成化體驗。這顆芯片將強大的組件集于一身,具體來說,一顆W55MH32內置高性能Arm? Cortex-M3核心,其主頻最高可達216MHz;配備1024KB FLASH與96KB SRAM,滿足存儲與數據處理需求;集成TOE引擎,包含WIZnet全硬件TCP/IP協議棧、內置MAC以及PHY,擁有獨立的32KB以太網收發緩存,可供8個獨立硬件socket使用。如此配置,真正實現了All-in-One解決方案,為開發者提供極大便利。
在封裝規格上,W55MH32 提供了兩種選擇:QFN68和QFN100。
W55MH32Q采用QFN68封裝版本,尺寸為8x8mm,它擁有36個GPIO、3個ADC、12通道DMA、17個定時器、2個I2C、3個串口、2個SPI接口(其中1個帶I2S接口復用)、1個CAN以及1個USB2.0。在保持與同系列其他版本一致的核心性能基礎上,僅減少了部分GPIO以及SDIO接口,其他參數保持一致,性價比優勢顯著,尤其適合網關模組等對空間布局要求較高的場景。緊湊的尺寸和精簡化外設配置,使其能夠在有限空間內實現高效的網絡連接與數據交互,成為物聯網網關、邊緣計算節點等緊湊型設備的理想選擇。 同系列還有QFN100封裝的W55MH32L版本,該版本擁有更豐富的外設資源,適用于需要多接口擴展的復雜工控場景,軟件使用方法一致。更多信息和資料請進入http://www.w5500.com/網站或者私信獲取。
此外,本W55MH32支持硬件加密算法單元,WIZnet還推出TOE+SSL應用,涵蓋TCP SSL、HTTP SSL以及MQTT SSL等,為網絡通信安全再添保障。
為助力開發者快速上手與深入開發,基于W55MH32Q這顆芯片,WIZnet精心打造了配套開發板。開發板集成WIZ-Link芯片,借助一根USB C口數據線,就能輕松實現調試、下載以及串口打印日志等功能。開發板將所有外設全部引出,拓展功能也大幅提升,便于開發者全面評估芯片性能。
若您想獲取芯片和開發板的更多詳細信息,包括產品特性、技術參數以及價格等,歡迎訪問官方網頁:http://www.w5500.com/,我們期待與您共同探索W55MH32的無限可能。

第十六章 I2C
1 I2C簡介
I2C(Inter-Integrated Circuit)總線是一種由 PHILIPS 公司開發的兩線式串行總線,用于連接微控制器以及其外圍設備。它是由數據線 SDA 和時鐘線 SCL 構成的串行總線,可發送和接收數據,在 CPU 與被控 IC 之間、IC 與 IC 之間進行雙向傳送。
I2C 總線有如下特點:
?總線由數據線 SDA 和時鐘線 SCL 構成的串行總線,數據線用來傳輸數據,時鐘線用來同步數據收發。
?總線上每一個器件都有一個唯一的地址識別,所以我們只需要知道器件的地址,根據時序就可以實現微控制器與器件之間的通信。
?數據線 SDA 和時鐘線 SCL 都是雙向線路,都通過一個電流源或上拉電阻連接到正的電壓,所以當總線空閑的時候,這兩條線路都是高電平。
?總線上數據的傳輸速率在標準模式下可達 100kbit/s 在快速模式下可達 400kbit/s 在高速模式下可達 3.4Mbit/s。
總線支持設備連接。在使用 I2C 通信總線時,可以有多個具備 I2C 通信能力的設備掛載在上面,同時支持多個主機和多個從機,連接到總線的接口數量只由總線電容 400pF 的限制決定。I2C 總線掛載多個器件的示意圖,如下圖所示:

I2C 總線掛載多個器件
下面來學習I2C 總線協議,I2C 總線時序圖如下所示:

I2C 總線時序圖
為了便于大家更好的了解 I2C 協議,我們從起始信號、停止信號、應答信號、數據有效性、數據傳輸以及空閑狀態等 6 個方面講解。
① 起始信號
當 SCL 為高電平期間,SDA 由高到低的跳變。起始信號是一種電平跳變時序信號,而不是一個電平信號。該信號由主機發出,在起始信號產生后,總線就處于被占用狀態,準備數據傳輸。
② 停止信號
當 SCL 為高電平期間,SDA 由低到高的跳變。停止信號也是一種電平跳變時序信號,而不是一個電平信號。該信號由主機發出,在停止信號發出后,總線就處于空閑狀態。
③ 應答信號
發送器每發送一個字節,就在時鐘脈沖 9 期間釋放數據線,由接收器反饋一個應答信號。應答信號為低電平時,規定為有效應答位(ACK 簡稱應答位),表示接收器已經成功地接收了該字節;應答信號為高電平時,規定為非應答位(NACK),一般表示接收器接收該字節沒有成功。
觀察上圖標號③就可以發現,有效應答的要求是從機在第 9 個時鐘脈沖之前的低電平期間將 SDA 線拉低,并且確保在該時鐘的高電平期間為穩定的低電平。如果接收器是主機,則在它收到最后一個字節后,發送一個 NACK 信號,以通知被控發送器結束數據發送,并釋放SDA 線,以便主機接收器發送一個停止信號。
④ 數據有效性
I2C 總線進行數據傳送時,時鐘信號為高電平期間,數據線上的數據必須保持穩定,只有在時鐘線上的信號為低電平期間,數據線上的高電平或低電平狀態才允許變化。數據在 SCL的上升沿到來之前就需準備好。并在下降沿到來之前必須穩定。
⑤ 數據傳輸
在 I2C 總線上傳送的每一位數據都有一個時鐘脈沖相對應(或同步控制),即在 SCL 串行時鐘的配合下,在 SDA 上逐位地串行傳送每一位數據。數據位的傳輸是邊沿觸發。
⑥ 空閑狀態
I2C 總線的 SDA 和 SCL 兩條信號線同時處于高電平時,規定為總線的空閑狀態。此時各個器件的輸出級場效應管均處在截止狀態,即釋放總線,由兩條信號線各自的上拉電阻把電平拉高。
了解前面的知識后,下面介紹一下 I2C 的基本的讀寫通訊過程,包括主機寫數據到從機即寫操作,主機到從機讀取數據即讀操作。下面先看一下寫操作通訊過程圖。

寫操作通訊過程
主機首先在 I2C 總線上發送起始信號,那么這時總線上的從機都會等待接收由主機發出的數據。主機接著發送從機地址+0(寫操作)組成的 8bit 數據,所有從機接收到該 8bit 數據后,自行檢驗是否是自己的設備的地址,假如是自己的設備地址,那么從機就會發出應答信號。
主機在總線上接收到有應答信號后,才能繼續向從機發送數據。
注意:I2C 總線上傳送的數據信號是廣義的,既包括地址信號,又包括真正的數據信號。
接著講解一下 I2C 總線的讀操作過程,先看一下讀操作通訊過程圖。

讀操作通訊過程圖
主機向從機讀取數據的操作,一開始的操作與寫操作有點相似,觀察兩個圖也可以發現,都是由主機發出起始信號,接著發送從機地址+1(讀操作)組成的 8bit 數據,從機接收到數據驗證是否是自身的地址。 那么在驗證是自己的設備地址后,從機就會發出應答信號,并向主機返回 8bit 數據,發送完之后從機就會等待主機的應答信號。假如主機一直返回應答信號,那么從機可以一直發送數據,也就是圖中的(n byte + 應答信號)情況,直到主機發出非應答信號,從機才會停止發送數據。
2 I2C從模式
默認情況下,I2C 接口總是工作在從模式。從從模式切換到主模式,需要產生一個起始條件。為了產生正確的時序,必須在 I2C_CR2 寄存器中設定該模塊的輸入時鐘。輸入時鐘的頻率必須至少是:
標準模式下為:2MHz
快速模式下為:4MHz
一旦檢測到起始條件,在 SDA線上接收到的地址被送到移位寄存器。然后與芯片自己的地址 OAR1和 OAR2(當 ENDUAL=1)或者廣播呼叫地址(如果 ENGC=1)相比較。
注:在 10 位地址模式時,比較包括頭段序列(11110xx0),其中的 xx 是地址的兩個最高有效位。頭段或地址不匹配:I2C 接口將其忽略并等待另一個起始條件。
頭段匹配(僅 10 位模式):如果 ACK 位被置'1',I2C 接口產生一個應答脈沖并等待 8 位從地址。地址匹配:I2C 接口產生以下時序:
如果 ACK 被置'1',則產生一個應答脈沖硬件設置 ADDR 位;如果設置了 ITEVFEN 位,則產生一個中斷如果 ENDUAL=1,軟件必須讀 DUALF 位,以確認響應了哪個從地址。在 10 位模式,接收到地址序列后,從設備總是處于接收器模式。在收到與地址匹配的頭序列并且最低位為'1'(即 11110xx1)后,當接收到重復的起始條件時,將進入發送器模式。在從模式下 TRA 位指示當前是處于接收器模式還是發送器模式。
從發送器
在接收到地址和清除 ADDR 位后,從發送器將字節從 DR 寄存器經由內部移位寄存器發送到 SDA 線上。
從設備保持 SCL 為低電平,直到 ADDR 位被清除并且待發送數據已寫入 DR 寄存器。(見下圖中的EV1 和 EV3)。當收到應答脈沖時:TxE 位被硬件置位,如果設置了 ITEVFEN 和 ITBUFEN 位,則產生一個中斷。
如果 TxE 位被置位,但在下一個數據發送結束之前沒有新數據寫入到 I2C_DR 寄存器,則 BTF 位被置位,在清除 BTF 之前 I2C 接口將保持 SCL 為低電平;讀出 I2C_SR1 之后再寫入 I2C_DR 寄存器將清除 BTF 位。

從發送器的傳送序列圖
說明:S=Start(起始條件),S,=重復的起始條件,P=Stop(停止條件),A=應,NA=非響應 EVx=事件(ITEVFEN=1 時產生中斷)
EV1:ADDR=1,讀 SR1 然后讀 SR2 將清除該事件。
EV3-1:TxE=1,移位寄存器空,數據寄存器空,寫 DR。
EV3:TxE=1,移位寄存器非空,數據寄存空,寫 DR 將清除該事件。
EV3-2:AF=1,在 SR1 寄存器的 AF 位寫'0'可清除 AF 位。
注:
1-EV1 和 EV3 1 事件拉長 SCL 低的時間,直到對應的軟件序列結束。
2-EV3 的軟件序列必須在當前字節傳輸結束之前完成。
從接收器
在接收到地址并清除 ADDR 后,從接收器將通過內部移位寄存器從 SDA 線接收到的字節存進 DR 寄存器。I2C 接口在接收到每個字節后都執行下列操作:
如果設置了 ACK 位,則產生一個應答脈沖硬件設置 RxNE=1。如果設置了 ITEVFEN 和 ITBUFEN 位,則產生一個中斷。
如果 RxNE 被置位,并且在接收新的數據結束之前 DR 寄存器未被讀出,BTF 位被置位,在清除BTF 之前 I2C 接口將保持 SCL 為低電平;讀出 I2C_SR1 之后再寫入 I2C_DR 寄存器將清除 BTF 位。

從接收器的傳送序列圖
說明:S=Start(起始條件),S,=重復的起始條件,P=Stop(停止條件),A=響應,NA=非響應,EVx=事件(ITEVFEN=1 時產生中斷)
EV1:ADDR=1,讀 SR1 然后讀 SR2 將清除該事件。
EV2:RxNE=1,讀 DR 將消除該事件。
EV4:STOPF=1,讀 SR1 然后寫 CR1 寄存器將清除該事件。
注:
1.EV1 事件拉長 SCL 低的時間,直到對應的軟件序列結束。
2.EV2 的軟件序列必須在當前字節傳輸結束之前完成。關閉從通信在傳輸完最后一個數據字節后,主設備產生一個停止條件,I2C 接口檢測到這一條件時:
?設置 STOPF=1,如果設置了 ITEVFEN 位,則產生一個中斷。然后 I2C 接口等待讀 SR1 寄存器,再寫 CR1 寄存器。
3 I2C主模式
在主模式時,I2C 接口啟動數據傳輸并產生時鐘信號。串行數據傳輸總是以起始條件開始并以停止條件結束。當通過 START 位在總線上產生了起始條件,設備就進入了主模式。
以下是主模式所要求的操作順序:
1.在 I2C_CR2 寄存器中設定該模塊的輸入時鐘以產生正確的時序
2.配置時鐘控制寄存器
3.配置上升時間寄存器
4.編程 I2C_CR1 寄存器啟動外設
5.置 I2C_CR1 寄存器中的 START 位為 1,產生起始條件
6.I2C 模塊的輸入時鐘頻率必須至少是:
7.標準模式下為:2MHz
8.快速模式下為:4MHz
9.起始條件
當 BUSY=0 時,設置 START=1,I2C 接口將產生一個開始條件并切換至主模式(M/SL 位置位)。
注:在主模式下,設置 START 位將在當前字節傳輸完后由硬件產生一個重開始條件。一旦發出開始條件:
SB 位被硬件置位,如果設置了 ITEVFEN 位,則會產生一個中斷。然后主設備等待讀 SR1 寄存器,緊跟著將從地址寫入 DR 寄存器。
從地址的發送
從地址通過內部移位寄存器被送到 SDA 線上。
?在 10 位地址模式時,發送一個頭段序列產生以下事件:
······ADD10 位被硬件置位,如果設置了 ITEVFEN 位,則產生一個中斷。然后主設備等待讀 SR1 寄存器,再將第二個地址字節寫入 DR 寄存器。
ADDR 位被硬件置位,如果設置了 ITEVFEN 位,則產生一個中斷。隨后主設備等待一次讀 SR1 寄存器,跟著讀 SR2 寄存器。
?在 7 位地址模式時,只需送出一個地址字節。
······一旦該地址字節被送出:
? ADDR 位被硬件置位,如果設置了 ITEVFEN 位,則產生一個中斷。
隨后主設備等待一次讀 SR1 寄存器,跟著讀 SR2 寄存器。根據送出從地址的最低位,主設備決定進入發送器模式還是進入接收器模式。
?在 7 位地址模式時
······? 要進入發送器模式,主設備發送從地址時置最低位為'0'。
······? 要進入接收器模式,主設備發送從地址時置最低位為'1'。
?在 10 位地址模式時
? 要進入發送器模式,主設備先送頭字節(11110xx0),然后送最低位為'0'的從地址。(這里 xx代表 10 位地址中的最高 2 位。)
? 要進入接收器模式,主設備先送頭字節(11110xx0),然后送最低位為'1'的從地址。然后再重新發送一個開始條件,后面跟著頭字節(11110xx1)(這里 xx 代表 10 位地址中的最高 2位。)
TRA 位指示主設備是在接收器模式還是發送器模式。
主發送器
在發送了地址和清除了 ADDR 位后,主設備通過內部移位寄存器將字節從 DR 寄存器發送到 SDA 線上。
主設備等待,直到 TxE 被清除。當收到應答脈沖時:
TxE 位被硬件置位,如果設置了 INEVFEN 和 ITBUFEN 位,則產生一個中斷。如果 TxE 被置位并且在上一次數據發送結束之前沒有寫新的數據字節到 DR 寄存器,則 BTF 被硬件置位,在清除 BTF 之前 I2C 接口將保持 SCL 為低電平;讀出 I2C_SR1 之后再寫入 I2C_DR 寄存器將清除 BTF 位。
關閉通信
在 DR 寄存器中寫入最后一個字節后,通過設置 STOP 位產生一個停止條件,然后 I2C 接口將自動回到從模式(M/S 位清除)。
注: 當 TxE 或 BTF 位置位時,停止條件應安排在出現 EV8_2 事件時。

主發送器傳送序列圖
說明:S=Star(起始條件),S;=重復的起始條件,P=Stop(停止條件),A=響應,NA=非響應,EVx=事件(ITEVFEN=1 時產生中斷)。
EV5:SB=1,讀 SR1 然后將地址寫入 DR 寄存器將清除該事件。
EV6:ADDR=1,讀 SR1 然后讀 SR2 將清除該事件。
EV8 1:TxE=1,移位寄存器空,數據寄存器空,寫 DR 寄存器。
EV8:TxE=1,移位寄存器非空,數據寄存器空,寫入 DR 寄存器將清除該事件。
EV8 2:TxE=1,BTF=1,請求設置停止位。TxE 和 BTF 位由硬件在產生停止條件時清除。
EV9:ADDR10=1,讀 SR1 然后寫入 DR 寄存將清除該事件。
注:1-EV5、EV6、EV9、EV8 1 和 EV8 2 事件拉長 SCL 低的時間,直到對應的軟件序列結束。
主接收器
在發送地址和清除 ADDR 之后,I2C 接口進入主接收器模式。在此模式下,I2C 接口從 SDA 線接收數據字節,并通過內部移位寄存器送至 DR 寄存器。在每個字節后,I2C 接口依次執行以下操作:
如果 ACK 位被置位,發出一個應答脈沖。
硬設置 RxNE=1, 如果設置了 INEVFEN 和 ITBUFEN 位,則會產生一個中斷。
如果 RxNE 位被置位,并且在接收新數據結束前,DR 寄存器中的數據沒有被讀走,硬件將設置BTF=1,在清除 BTF 之前 I2C 接口將保持 SCL 為低電平;讀出 I2C_SR1 之后再讀出 I2C_DR 寄存器將清除 BTF 位。
關閉通信
主設備在從從設備接收到最后一個字節后發送一個 NACK。接收到 NACK 后,從設備釋放對 SCL 和SDA 線的控制;主設備就可以發送一個停止/重起始條件。為了在收到最后一個字節后產生一個 NACK 脈沖,在讀倒數第二個數據字節之后(在倒數第二個 RxNE 事件之后)必須清除 ACK 位。為了產生一個停止/重起始條件,軟件必須在讀倒數第二個數據字節之后(在倒數第二個 RxNE事件之后)設置 STOP/START 位。只接收一個字節時,剛好在 EV6 之后(EV6_1 時,清除 ADDR 之后)要關閉應答和停止條件的產生位。在產生了停止條件后,I2C 接口自動回到從模式(M/SL 位被清除)。

主接收器傳送序列圖
說明:S=Start(起始條件),S:=重復的起始條件,P=Stop(停止條件),A=響應,NA=非響應,EVx=事件(ITEVFEN=1 時產生中斷)EV5:SB=1,讀 SR1 然后將地址寫入 DR 寄存器將除該事件。EV6:ADDR=1,讀 SR1 然后讀 SR2 將清除該事件。在 10位主接收模式下,該事件后應設置 CR2的 START=1.EV6 1:沒有對應的事件標志,只適于接收 1 個字節的情況。恰好在 EV6 之后(即清除了 ADDR 之后),要潔除響應和停止條件的產生。
EV7:RxNE=1,讀 DR 寄存器清除該事件。
EV7 1:RXNE=1,讀 DR 寄存器清除該事件。設置 ACK=0 和 STOP 請求。
EV9:ADDR10=1,讀 SR1 然后寫入 DR 寄存將清除該事件。
1. 如果收到一個單獨的字節,則是 NA。
2. EV5、EV6 和 E事件拉長 SCL 低電平,直到對應的軟件序列結束。
3. EV7 的軟件序列必須在當前字節傳輸結束前完成。
EV6_1 或 EV7_1 的軟件序列必須在當前傳輸字節的 ACK 脈沖之前完成。
4 SDA/SCL線控制
如果允許時鐘延長:
?發送器模式:如果 TxE=1 且 BTF=1:I2C 接口在傳輸前保持時鐘線為低,以等待軟件讀取SR1,然后把數據寫進數據寄存器(緩沖器和移位寄存器都是空的)。
?接收器模式:如果 RxNE=1 且 BTF=1:I2C 接口在接收到數據字節后保持時鐘線為低,以等待軟件讀 SR1,然后讀數據寄存器 DR(緩沖器和移位寄存器都是滿的)。
?如果在從模式中禁止時鐘延長:
?如果 RxNE=1,在接收到下個字節前 DR 還沒有被讀出,則發生過載錯。接收到的最后一個字節丟失。
?如果 TxE=1,在必須發送下個字節之前卻沒有新數據寫進 DR,則發生欠載錯。相同的字節將被重復發出。
不控制重復寫沖突。
5 I2C中斷請求
下圖列出了所有的 I2C 中斷請求:
中斷事件 | 事件標志 | 開啟控制位 |
起始位已發送 (主) | SB | ITEVFEN |
地址已發送 (主) 或地址匹配 (從) | ADDR | ITEVFEN |
10 位頭段已發送 (主) | ADD10 | ITEVFEN |
已收到停止 (從) | STOPF | ITEVFEN |
數據字節傳輸完成 | BTF | ITEVFEN |
接收緩沖區非空 | RxNE | ITEVFEN 和 ITBUFEN |
發送緩沖區空 | TxE | ITEVFEN 和 ITBUFEN |
總線錯誤 | BERR | ITERREN |
仲裁丟失 (主) | ARLO | ITERREN |
響應失敗 | AF | ITERREN |
過載 / 欠載 | OVR | ITERREN |
PEC 錯誤 | PECERR | ITERREN |
超時 / Tlow 錯誤 | TIMEOUT | ITERREN |
SMBus 提醒 | SMBALERT | - |
注:
1.SB、ADDR、ADD10、STOPF、BTF、RxNE 和 TxE 通過邏輯或匯到同一個中斷通道中。
2.BERR、ARLO、AF、OVR、PECERR、TIMEOUT 和 SMBALERT 通過邏輯或匯到同一個中斷通道中。

I2C 中斷映射圖
6 例程設計
6.1 IIC_IntTransmit例程
1.UART 模塊:配置 USART1,將printf輸出重定向到該串口,用于與用戶交互和輸出調試信息。
2.I2C 配置模塊:使能 GPIOB 和 I2C1 時鐘,配置引腳,初始化 I2C1,設置工作模式、時鐘速度等參數。
void IIC_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1 | RCC_APB1Periph_I2C2, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//Enable internal pull-up function
GPIO_ForcePuPdCmd(GPIOB, ENABLE);
GPIO_ForcePullUpConfig(GPIOB, GPIO_Pin_6);
GPIO_ForcePullUpConfig(GPIOB, GPIO_Pin_7);
I2C_DeInit(I2C1);
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_OwnAddress1 = 0xA0;
I2C_InitStructure.I2C_ClockSpeed = 100000;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_Init(I2C1, &I2C_InitStructure);
I2C_Cmd(I2C1, ENABLE);
}
3.主設備測試模塊:填充發送緩沖區,生成 I2C 起始信號,發送從設備地址和數據,最后生成停止信號。
void IIC_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1 | RCC_APB1Periph_I2C2, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//Enable internal pull-up function
GPIO_ForcePuPdCmd(GPIOB, ENABLE);
GPIO_ForcePullUpConfig(GPIOB, GPIO_Pin_6);
GPIO_ForcePullUpConfig(GPIOB, GPIO_Pin_7);
I2C_DeInit(I2C1);
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_OwnAddress1 = 0xA0;
I2C_InitStructure.I2C_ClockSpeed = 100000;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_Init(I2C1, &I2C_InitStructure);
I2C_Cmd(I2C1, ENABLE);
}
4.從設備測試模塊:使能 I2C 中斷,進入循環等待接收數據。若接收完成,打印數據并比較是否與發送數據一致。
void IIC_SlaveTest(void)
{
FillData();
I2C_ITConfig(I2C1, I2C_IT_EVT | I2C_IT_BUF, ENABLE);
I2C_ITConfig(I2C1, I2C_IT_ERR, ENABLE);
while (1)
{
if (RecvFlag == 1)
{
DataPrintf(RecvBuff, BUFF_SIZE);
if (memcmp(RecvBuff, SendBuff, BUFF_SIZE) == 0)
{
printf("IIC slave int receive data successn");
}
memset(RecvBuff, 0, BUFF_SIZE);
RecvFlag = 0;
}
}
}
5.NVIC 配置模塊:配置 I2C1 的事件和錯誤中斷優先級,使能相應中斷通道。
6.數據處理模塊:包含數據填充、打印和獲取命令等功能。
6.2 IIC_Software例程
該例程通過軟件模擬I2C協議與EEPROM芯片通信,驗證I2C驅動的正確性。程序首先初始化系統時鐘并通過串口輸出SYSCLK/HCLK/PCLK1/PCLK2/ADCCLK頻率信息,隨后配置I2C所需GPIO引腳(SCL/SDA),調用`ee_Test()`執行EEPROM測試:向指定地址寫入256字節數據塊,讀取數據并校驗正確性,同時測試多字節讀寫及錯誤處理以驗證通信穩定性。主循環保持程序運行,確保測試持續進行。工作流程如下:
1.初始化系統:配置串口(波特率 115200)輸出系統時鐘頻率(SYSCLK/HCLK/PCLK1/PCLK2/ADCCLK)。
2.I2C 配置:通過i2c_CfgGpio()初始化 I2C 所需 GPIO 引腳(如 SCL/SDA)。
// main函數中的I2C GPIO配置調用
int main(void)
{
// ...(初始化代碼略)...
i2c_CfgGpio(); // 初始化I2C所需的GPIO引腳(如SCL/SDA)
ee_Test(); // 執行EEPROM測試
while (1);
}
// 假設i2c_CfgGpio()函數實現(示例,實際在bsp_i2c_gpio.h中)
void i2c_CfgGpio(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // 假設I2C使用GPIOB引腳
// 配置SCL和SDA引腳為開漏輸出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; // 假設SCL=PB6,SDA=PB7
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; // 開漏輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// 上拉電阻使能(根據硬件設計選擇)
GPIO_SetBits(GPIOB, GPIO_Pin_6 | GPIO_Pin_7);
}
3.EEPROM 測試:調用ee_Test()執行軟件 I2C 與 EEPROM 的通信測試(可能包括讀寫驗證)。
// main函數中的EEPROM測試調用
int main(void)
{
// ...(初始化代碼略)...
ee_Test(); // 執行EEPROM讀寫測試
while (1);
}
// 假設ee_Test()函數實現(示例,實際在bsp_i2c_ee.h中)
void ee_Test(void)
{
uint8_t write_buf[BUFF_SIZE] = {0};
uint8_t read_buf[BUFF_SIZE] = {0};
uint16_t i;
// 初始化數據緩沖區
for (i = 0; i < BUFF_SIZE; i++)
{
write_buf[i] = i % 256; // 寫入測試數據(0~255循環)
}
// 通過I2C寫入EEPROM
i2c_WriteBytes(EEPROM_ADDR, 0x00, write_buf, BUFF_SIZE);
// 延時等待寫入完成(EEPROM寫入需要時間)
delay_ms(10);
// 通過I2C讀取EEPROM數據
i2c_ReadBytes(EEPROM_ADDR, 0x00, read_buf, BUFF_SIZE);
// 驗證數據一致性(示例:打印前10字節)
printf("EEPROM Test: ");
for (i = 0; i < 10; i++)
{
printf("%02X ", read_buf[i]);
}
printf("n");
}
4.主循環:保持程序運行,維持測試狀態。
7 下載驗證
7.1 IIC_IntTransmit例程
程序啟動
?串口輸出系統時鐘頻率信息,可確認時鐘配置是否正確。
?顯示測試提示,告知用戶可通過輸入 m 或 r 選擇主設備發送或從設備接收測試模式。
主設備發送測試(輸入 m)
?串口輸出確認信息。
?顯示即將發送的十六進制數據。
程序控制 I2C 總線完成起始信號、地址及數據發送,最后發送停止信號。
從設備接收測試(輸入 r)
?串口輸出確認信息。
?使能 I2C 中斷并進入等待。
?接收到 256 字節數據后,顯示接收到的十六進制數據。
?比較接收和發送數據,若一致則輸出成功信息,清空接收緩沖區并重置標志位。
7.2 IIC_Software例程
程序運行后,先完成延時與串口初始化,接著通過串口輸出系統時鐘頻率信息,包括SYSCLK、HCLK、PCLK1、PCLK2和ADCCLK頻率,并提示進行IIC軟件測試。隨后進行I2C所需GPIO引腳初始化,調用函數執行與EEPROM的通信測試,可能包含向指定地址寫入數據塊、讀取數據并校驗以及測試通信穩定性等操作。若測試正常,可認為I2C驅動功能正確;若有異常,可能會在后續測試流程中體現出來。最后程序進入無限循環,維持當前運行狀態:

WIZnet 是一家無晶圓廠半導體公司,成立于 1998 年。產品包括互聯網處理器 iMCU?,它采用 TOE(TCP/IP 卸載引擎)技術,基于獨特的專利全硬連線 TCP/IP。iMCU? 面向各種應用中的嵌入式互聯網設備。
WIZnet 在全球擁有 70 多家分銷商,在香港、韓國、美國設有辦事處,提供技術支持和產品營銷。
香港辦事處管理的區域包括:澳大利亞、印度、土耳其、亞洲(韓國和日本除外)。
審核編輯 黃宇
-
單片機
+關注
關注
6063文章
44915瀏覽量
646751 -
I2C
+關注
關注
28文章
1533瀏覽量
126985 -
SDA
+關注
關注
0文章
125瀏覽量
28693 -
SCL
+關注
關注
1文章
243瀏覽量
17453
發布評論請先 登錄
I2C讀寫時序分析和實現思路

視頻詳解:上海尤老師verilog入門到實戰第十六課
I2C Guid I2C指南
單片機c語言教程第十六章--C51指針的使用

一文看懂I2C協議

一文看懂I2C協議

評論