我們經常在各種開發板的介紹中看見,支持UART,SPI,IIC,CAN通信等等,這些協議在單片機的應用里面非常簡單,可能是一個簡單的函數:SPI.transfer(),Wire.write()就解決了問題。但是那么這些函數在硬件層次到底是如何實現的呢?想了解這個,首先要了解一些關於單片機對於電路的控制方式。
控制器的輸入輸出口通常只能輸出高低電平。所謂高低電平也就是用高電平代表1(輸出口有正電壓),低電平代表0(通常電壓為0)。
通信協議的作用是什么?
高低電平的變換對應的0和1,可以組成一組二進制數,這組二進制數就可以傳遞信息,收到高電平就當作收到1,收到低電平就當作收到0,於是這個時候接收這個信號的芯片就好像在做一個電報接收員一樣把一連串的010101信號對應着一個信號表翻譯成具體的指令。說到這里就有了一個問題,如果要連續發送2個0信號怎么發?
有兩個解決辦法:
1
、限定每個信號的時間,比如規定高低電平持續時間為1ms,那么2ms低電平就代表2個0. (UART基本是用的這個原理)
2
、多添加一個信號線,當這個信號線上的電平發生變化的時候讀入之前信號線上的信號(后來這個新加的信號線就叫時鍾線,大部分協議都是用的這種方式)
這兩種方式各有利弊,第一種只需要1根線,同樣由於只有一根線,那么為了減少誤傳輸只能降低傳輸速度,第二個需要2根線,但可以以很快的速度進行數據傳輸。也可以再加一組線組成全雙工模式(發送數據的同時還可以接收數據)。
什么是IIC
IIC是以上述第二種方式運行的一套協議。他由3根線組成分別叫SDA,SCL,GND。SDA為數據線,SCL為時鍾線,GND為參考電平,就是0電平,這個線的主要功能是提供一個參考的電壓,告訴IC到底多少為0V電勢(通常我們說的多少V是說的電勢差及電壓)。
先說下為
什么要使用協議,有人可能會想,按照之前所說,當時鍾線上電平發生改變(我們形象的稱之為上升沿和下降沿)時讀入數據線的0或1不就好了,為什么還要什么協議呢?
說說我個人理解,之所以有協議是為了更加穩定也更加的可靠。舉個例子,家里敲門,大家可能都有這樣的經歷,有時候聽到敲門然后出門,發現門外並沒有人,這就有2個可能,一個是外部原因:外面有什么人或者物不小心敲到了門。或者是內因:自己不小心聽錯了。無論是什么原因,都造成了我們信息的錯誤獲取(認為有人敲門),所以我們想到一個方法,以后每次敲門都先敲1下,然后連續敲3下,以此表示我要進來這個信號,這樣里面的人聽到有人敲門后再聽到3次短促的敲門才去開門,這樣外因或者內因產生的錯誤都將大大減少,我認為這是發明協議的最初原因。
下面說說什么叫IIC協議:
這種總線類型是由飛利浦半導體公司在八十年代初設計出來的,主要是用來連接整體電路,IIC是一種多向控制總線,也就是說多個芯片可以連接在一起,同時每個芯片都可以對其他的芯片進行數據傳輸。這種方式簡化了信號傳輸總線。但是這種方式也增加了一個傳送數據的步驟,就是需要對信號線上的每個芯片定義一個邏輯地址,讓芯片知道這個信息是發給他的(類似電話號碼的功能)。
IIC
協議包含開始信號:START(類似於第一下敲門)、應答信號:ACK(里面的人給予回應)、無應答:NACK(另一種回答)、停止信號:STOP(表示數據發送結束) 這幾個東西,當然還少不了普通的數據發送。盡管協議中規定START必須,其他幾個非必須,但實際上其他三個仍舊非常重要。
IIC的具體形式
IIC
發送數據是8位數據(即8個0或1,也就是一個字節)。整個協議發送的順序如下:
通常我們為了方便把設備分為主設備和從設備,我的划分方法是誰控制時鍾線(即控制SCL的電平高低變換),誰就是主設備。
- 主發從收:主機發送 START 信號-> 主機發送地址 -> 從機發送ACK應答 -> (主機發送數據 -> 從機發送ACK應答 (循環)) -> 主機發送STOP信號 或 主機發送 START 信號啟動下一次傳輸
- 主收從發:主機發送 START 信號-> 從機發送發地址 -> 主機發送ACK應答 -> (從機發送數據 -> 主機發送ACK應答 (循環)) -> 接受至最后一個字節時,主機發送NACK -> 主機發送 STOP 信號或 主機發送START信號 啟動下一次傳輸
看下面一段Arduino的代碼:
Wire.beginTransmission(0x04); Wire.write(0xaa); Wire.endTransmission();
0x
代表的是16進制數轉換為2進制為 0x04=0100b 0xaa=10101010b
以上是一段主發從收的代碼。
Wire.beginTransmission(0x04);//執行了3步 主機發送 START信號 -> 主機發送地址-> 從機發送 ACK應答 后面的0x04就是從機的地址 Wire.write(0xaa);// 執行了2步 主機發數據 -> 從機發送ACK應答 (循環) 參數0xaa就是發送的數據 Wire.endTransmission(); // 執行了最后一步 主發送STOP信號
IIC底層原理
1:STTART&STOP
我們要往底層走一步,每個數據的發送,START ACK NACK STOP到底是怎么以電平變化的方式發送的呢?請看下面這個圖:
這個圖在工程上我們叫他時序圖,這個圖講的正是START,和STOP的發送方式。
看一個虛線的地方我們很容易的看到所謂START其實就是在SCL,SDA都為高的時候把SDA變為低電平(拉低)嘛,和敲門一樣的道理。
同樣第二個虛線的地方,STOP就是在SDA為低,SCL為高的時候把SDA變為高電平(拉高)。
2、DATA INPUT
下面我們可以來看看IIC協議是如何傳輸數據的,如下圖
在IIC協議中數據傳輸也很簡單,IIC在SCL(時鍾線)為高電平時對SDA進行讀取(digitalRead,即采樣)讀到高電平即收到一個1,讀到低即收到一個0。現在只剩下應答信號ACK NACK,了解了這2個就算是完全了解了IIC協議。
3、ACK&NACK
所謂應答就是告訴發送數據的一方,我收到了數據。所以說到底,應答也是一種數據,說白了就是0或者1,只不過換了一個發送方。具體地說就是就是A對B發送了8位數據之后,這時B會給A返回一個1位的數據,非0則1,當返回0在IIC協議里稱為ACK,返回1稱為NACK,但是請注意這里與發送數據有一點不同的地方,即發送的時候SCL,SDA的信號都是有發送方(主機)控制的,但是在ACK的時候SCL是主機控制的,SDA接收方(從機)控制的,所以反應在程序上,你所做的是等!當你控制MCU拉低SCL之后,需要不斷讀取SDA的值,直到其被從機拉低,才可以認為從機發送了ACK信號。
至此關於IIC的介紹已經全部完成了,下面給大家一個圖,讓大家對於IIC能有一個更加直觀的認識:
