I2C 总线协议初探 - STM32 I2C 接口外设学习笔记
前言
早在大一和班上大神談理想的時候就聽過 I2C,那時我還在用 51 點燈,而他調了一星期 I2C,還把 I2C 念成 「I幫C」,我愣是沒聽懂。現在終于也到了我調 I2C 的時候,還是用著一款新接觸的單片機 —— STM32。這幾天看了一下?I2C 協議手冊,經歷了從懵逼到略懂的過程。那么,I2C 到底是個什么東西?
見名知意
好的名字對于一個概念的理解起到了良好輔助作用,使人在腦海中形成直觀的第一印象,而 I2C 這個名字卻讓人莫名其妙。I2C 全名?Inter-Integrated Circuit?,由集成電路的英文 integrated circuit (即我們常說的IC)加上?Inter-?(互聯/相互)前綴構成,直譯過來就是「集成電路間」、「集成電路際」或者「互聯集成電路」,當然我們不會這么說,它其實是I2C Bus簡稱,所以中文應該叫集成電路總線(事實上它念 「I方C」)。由此可以了解到 I2C 所連接對象是 IC 集成電路,它實現的既不是兩臺終端設備之間的通信,也不是兩個進程之間的通信,而是一塊電路板上兩片 IC 之間的通信。
更進一步講,I2C 是一種使用多主從架構的串行通信總線,作為串行通信協議,I2C 只需要兩根線——數據線(SDA)和時鐘線(SCL)即可工作,眾多主機、從機就是掛載在這兩根線上,通過總線上的高低起伏的電平變化進行尋址、握手、仲裁和數據傳輸等功能,麻雀雖小五臟俱全——僅僅兩根線就能玩出這么多花樣,不得不佩服設計協議的工程師們。
除此之外,I2C 總線還有三種數據傳輸速率可供選擇,分別是標準模式(可達 100 kbit/s)、快速模式(可達 400 kbit/s)和高速模式(可達 3.4 Mbit/s)。
開漏輸出與上拉電阻
關于總線連接的物理特性,官方文檔中還有這樣的介紹:
SDA 和 SCL 都是雙向線路都通過一個電流源或上拉電阻連接到正的電源電壓。當總線空閑時,這兩條線路都是高電平 連接到總線的器件輸出級必須是漏極開路或集電極開路才能執行線與的功能 。注意到這樣一句話:「連接到總線的器件輸出級必須是漏極開路或集電極開路才能執行線與的功能 」,這里就涉及到「漏極/集電極開路」、「上拉電阻」和「線與」兩個概念,而這絕對可以算得上是實現 I2C 總線協議的關鍵所在。
在芯片中,當一個輸出級為漏極/集電極開路時(開漏輸出),它只能輸出低電平和高阻態,低電平我們了解,那「高阻態」又是個什么東西?高阻態可理解為通過很大的電阻把輸出引腳與 MCU 芯片內部隔開,近似開路的狀態(電阻非常大)。這時芯片無法控制輸出的電平,引腳的電平不確定,可被外部電平輕松改變。開漏輸出可以簡單理解為輸出處接一個開關,閉合時接低電平,斷開時懸空(啥也不接)。下圖的中間部分電路就很好地說明這種狀態。
資料來源:單片機I/O口推挽輸出與開漏輸出的區別(轉) - xiaoweiboy的專欄 - 博客頻道 - CSDN.NET
正是由于開漏輸出的「要么拉低要么放手」的特性,使得總線只受輸出端低電平的影響(同樣,設備也只能通過輸出低電平來使用總線),從而實現了「線與」的功能。和「邏輯與」一樣,「線與」所表達的意思是 —— 當總線上只要有一個設備輸出低電平,整條總線便處于低電平狀態,這時候的總線被稱為占用狀態。
然而 I2C 總線電路的真正主角,是連接總線到 VCC 的兩個上拉電阻。根據前面的分析我們知道,輸出端只能輸出低電平或高阻態,是不能把總線拉高的,自然而然就需要通過其他方式為總線提供高電平,上拉電阻就擔負了這個重任 ——?當輸出端輸出高阻態時且沒有其他設備拉低總線(占用總線)時,總線被外部的上拉電阻拉高、呈現出高電平狀態,這不正是我們的「線與」功能么。
不僅如此,利用「線與」特性還可以實現總線的仲裁、時鐘的同步,更牛逼的是,在整個過程中數據完全不會丟失。我甚至覺得 I2C 協議相對于其他串行通信協議最大的優勢就是通過「開漏輸出」和「上拉電阻」兩個物理特性大大簡化了協議整體的設計和實現。
上拉電阻阻值對 I2C 協議的影響
需要補充說明的一點是,兩個上拉電阻的大小并不是隨便用的,涉及到通信速率與功耗的取舍。協議層對電平的變化時間有著嚴格的要求與限制,而電平的變化受總線電氣特性的影響。
對總線而言,上拉電阻越大,信號的上升時間就越長,通信速率就越低,反之亦然。但電阻也并不是越小越好,阻值過小的話,總線低電平時電阻上的大電流會增加電路的功耗。此外,電容也會影響信號的上升時間,于是就有了 I2C 總線總電容 400 pf 的限制,這直接關系到總線上可掛載設備的數目。
I2C 總線基本術語
主機和從機都可作為發送器和接收器,于是每個 I2C 設備可有下面四種工作模式:
- 主發送器
- 主接收器
- 從發送器
- 從接收器
通信流程
和串口一樣,I2C 的最終目的還是為了傳數據(通信),每種通信協議都有自己傳數據的規矩,這些規矩包括了「先發什么后發什么」、「什么時候發」等細節,通信雙方只要嚴格按照約定好的規矩來,就能實現數據的收發。
值得注意的是,I2C 通信雙方是分為主機與從機的,兩者是一種「不平等」的從屬關系,主機是老大,地位比從機高。一次數據的傳輸,無論傳輸方向如何,都是由主機發起和結束的,主機有著本次傳輸的絕對控制權,不像串口那樣雙方能夠對等傳輸。
完整的數據傳輸
以「主發送器」工作方式為例,在開始數據傳輸前,主機會發送一個起始信號,緊接著發送目標從機地址,從機被尋址后產生響應信號,接著主機開始發送數據,從機接收數據并產生響應信號,在數據傳輸完畢時主機發送結束信號,通訊結束。這就是 I2C 通訊的大致流程。
起始、結束信號
I2C 協議通過 SCL 與 SDA 兩根線上的電平狀態組合來定義不同的傳輸信號。SCL 為高電平時 SDA 由高到低變化表示起始信號(START condition),SCL 為高電平時 SDA 由低到高變化表示結束信號(STOP condition)。給我的感覺像是「跳進坑里,通信開始」、「跳出坑外,通信結束」。每次數據傳輸都是始于起始信號止于結束信號,期間總線處于占用狀態。
重復起始信號
在通信過程中若要改變目的從機或者數據傳輸方向,可以不發送結束信號直接再發送一次起始信號,緊接著發送新的從機地址或傳輸方向,這個起始信號稱為「重復起始信號(Sr)」,本質上和普通起始信號相同,但避免了結束、起始信號反復多次發送。在多主機的總線中使用重復起始信號可保持主機對總線的控制權,避免結束信號臨時釋放總線造成控制權丟失。
從機地址、數據傳輸方向
在發送完起始信號后,主機緊接著需要發送一個字節(10 地址模式下兩個字節)的地址信息,包括?7 位的從機地址以及一位傳輸方向控制位,「0」表示發送(寫) 「1」表示請求數據(讀)。
數據有效性
I2C 協議規定了 SDA 線上的數據只在 SCL 為高電平時有效,在 SCL 為低電平時可進行數據的切換,即設備只在 SCL 線為高電平時才會對 SDA 上的信號進行采樣。這里指的數據包括傳輸數據、從機地址等二進制數據。
根據數據傳輸的特點,可以通過改變 SCL 時鐘信號的占空比靈活調整數據的采集和切換時間。
響應信號
在從機被尋址或者主機/從機接收一字節數據后,都要在地址或數據后產生一個響應信號。響應信號包括「應答(ACK)」和「非應答(NACK)」兩種信號。所謂的作出應答就是在 SCL 線電平升高前設備將 SDA 線拉低,而產生非應答信號,設備只要在這時什么也不干,釋放總線即可。所以在使用 STM32 I2C 接口時不一定要等到數據接收完成后才使能非應答信號,實際上在前一次應答信號發出后就可以干這事了。
I2C 基本讀寫過程
在用單片機作為主機進行 I2C 通信控制外設時,根據數據傳輸方向可將 I2C 數據傳輸模式分為三類:
主機發送模式
在主機發送模式下,同一次通信過程中數據傳輸只由主機到從機,報文格式如下圖:
在產生起始信號后,主機發送包含 7 位地址以及「寫」控制位的一個字節數據,隨后開始逐字節傳輸數據,并接收從機對各字節的響應信號。當從機響應非應答信號時,主機產生結束信號終止通信。當然,因為主機是「大佬」,也可以隨時產生結束信號終止通信。
主機接收模式
在主機接收模式下,同一次通信過程中數據傳輸只由從機到主機,報文格式如下圖:
在產生起始信號后,主機發送包含 7 位地址以及「讀」控制位的一個字節數據,隨后開始逐字節接收從機數據,并產生對各字節的響應信號。數據接收完畢時,主機產生非應答響應信號時,隨后產生結束信號終止通信。要注意主機在發送結束信號前先要產生非應答響應信號。
復合模式
前面兩種模式中的數據傳輸方向都是固定的 —— 只由主機到從機或只由從機到主機,而在復合模式下,主機可以通過重新發送起始信號改變數據傳輸方向,即同一次通信過程中存在兩個數據傳輸方向,報文格式如下圖:
復合模式結合了前兩種模式的特點,主機通過發送重復起始信號改變數據傳輸方向,實現讀/寫切換。同樣的,接收數據的主機要想改變方向或者終止通信,在發送重復起始信號和結束信號前都要先產生非應答響應信號。
復合模式可以實現主機數據的「先發送后接收」,最典型的應用是通過 I2C 總線控制 EEPROM 讀數據 —— 主機(MCU)先發送要讀取數據在 EEPROM 內的地址,隨后切換模式接收 EEPROM 返回的數據。
STM32 中使用 I2C
了解 I2C 總線協議的基本規定后,可以發現所謂的 XXX 協議,不過就是根據一個標準進行總線上高低電平的變化而已。這種電平變化無論是用單片機C語言軟件實現、還是眾多 IC 固化的硬件接口實現,甚至把兩條總線通過撥碼開關接到 VCC/GND 進行純手動操作(你可以想象在快速模式 I2C 下,極客的手指以 400 Hz 的頻率在「抽搐」,只為了實現真正的「人機交互」),理論上只要能產生符合協議規范的「特征電平」信號,兩個 I2C 設備就能通信,于是就有了我們常說的「一個協議的兩種實現方式」 —— 「軟件模擬」和「硬件實現」。
軟件模擬
軟件模擬是通過編程語言(C 啊匯編什么的)控制單片機 I/O 口的電平來產生通信協議的各種信號。因為每一個電平變化都是碼農一下下敲出來的(類似于「LED = 0;」這樣的代碼),給人一種「一切盡在掌握之中」的感覺,軟件模擬方式會讓人有一種久違的「安全感」,具體表現為可控性高、靈活性強的優點,但同時也要付出代價,很顯然,MCU 監控或查詢總線的次數越多,用于執行自己功能的時間越少。
硬件實現
隨著時代的發展,單片機上的外設越來越多、越來越強大,與串口、定時器、I/O口一樣,I2C 也可以固化為 MCU 外設,協議各種信號的發送/接收都可以由硬件自動完成,并通過眾多寄存器給 MCU 開發者提供使用接口,碼農們只需要「面向寄存器編程」。
使用 STM32 的 I2C 接口外設時,要發送就往外設的數據寄存器扔數據,要接收就從外設的數據寄存器讀數據,各種控制信號的產生也可以通過寫相應的外設控制寄存器位完成。或許你覺得就這樣「放手硬件」有點不放心,萬一被硬件坑了怎么辦?別怕,STM32 還有一堆的狀態寄存器供你判斷外設工作狀態。另外,硬件還為通信過程中的各種情況實現了中斷,這些都是用軟件模擬法所沒有的福利。
只是隨便寫點 I2C,STM32 部分不具體描述,詳見參考手冊
總結
以上是生活随笔為你收集整理的I2C 总线协议初探 - STM32 I2C 接口外设学习笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 编制网站首页的基本原则
- 下一篇: jupyter怎么安装jieba_记录