1、什么是通訊協(xié)議
如果按照百度百科里面的定義,那么通訊協(xié)議的解釋如下:
通信協(xié)議又稱通信規(guī)程,是指通信雙方對(duì)數(shù)據(jù)傳送控制的一種約定。約定中包括對(duì)數(shù)據(jù)格式, 同步方式,傳送速度,傳送步驟,檢糾錯(cuò)方式以及控制字符定義等問題做出統(tǒng)一規(guī)定,通信雙方 必須共同遵守,它也叫做鏈路控制規(guī)程。 好吧,如果抄襲到這里,我肯定不會(huì)收到讀者的鮮花,而是板磚和臭雞蛋。文抄公誰不會(huì)做?那么,對(duì)于業(yè)余電子愛好者而言,如何來快速而又簡(jiǎn)單地理解通訊協(xié)議?其實(shí),我們可以簡(jiǎn)單地這么來理解,對(duì)于人類世界來說,在中國(guó)范圍內(nèi),那么我們可以將普通話看成是一個(gè)通訊協(xié)議。也就是說,當(dāng)有一個(gè)人懂得漢語的人要對(duì)另外一個(gè)懂得漢語的人表達(dá)自己意見的時(shí)候,他可 以使用“普通話”這個(gè)通訊協(xié)議和另外一個(gè)懂得普通話的人進(jìn)行溝通。同樣的,我們也可以將英語看成人類世界的另外一個(gè)版本的通訊協(xié)議。而在電子世界中,我們通常所謂的通訊協(xié)議都是數(shù)字通訊協(xié)議,在數(shù)字通訊協(xié)議中,小到 各種電子零件,大到電腦,它們之間互相溝通其實(shí)都是通過 0 或者 1 兩個(gè)電位水平來進(jìn)行通訊的(當(dāng) 然,還有別的表達(dá)方式,如差分電位,這里不細(xì)表,作為愛好者,我們將且這么認(rèn)為罷)。
大家知道,當(dāng)我們采用 0,1 來進(jìn)行信息表達(dá)的時(shí)候,如果只表達(dá)一次,即每次只說 1 或者 0 。那么這次表達(dá)只能夠蘊(yùn)含兩個(gè)意思,或者你說了 0,這就表示“沒有”,或者你說了 1,這就表示“有”。但是,我們總該知道,這個(gè)世界哪里這么簡(jiǎn)單?比如你女友問你現(xiàn)在溫度是多少度,你卻 回答說“沒有”或者“有”,我相信,你的女友少不得給你來一記九陰白骨抓。幸好,我們并沒有走到絕路,其實(shí),如果你有一個(gè)比較耐得住性子且愿意陪你搞怪的女友。那么我們可以這樣來解決“問溫度”的問題:我們這樣設(shè)想,如果你事先和女朋友約定如下:
如果她問你溫度,如果并且她會(huì)有足夠的耐心會(huì)反復(fù)這樣問:現(xiàn)在的溫度是 0 ?如果對(duì)了,你回答“是”,如果不對(duì),你回答“否”如果回答了否,她就將上次問的溫度增加一度重新問你。(如第二次就該問是否是 1 )直到你回答了“是”。也就是說,當(dāng)你回答了“是”的時(shí)候,你的女友也就知道了現(xiàn)在溫度。
好吧,恭喜你,盡管這個(gè)例子非常地?zé)o聊。但是,你和你的女友已經(jīng)共同創(chuàng)造了一種全新的“通 訊協(xié)議”。當(dāng)然,我們不能想得這么簡(jiǎn)單,這個(gè)世界非常復(fù)雜,所以,我們需要進(jìn)行復(fù)雜的表達(dá)。比如說,你女友正在問你溫度問題的時(shí)候,你忽然發(fā)現(xiàn)她老娘在背后看著你們倆發(fā)傻,我 相信,明智的你肯定不會(huì)繼續(xù)這樣傻干下去了。這個(gè)時(shí)候,你肯定得想辦法打個(gè)哈哈蒙混過關(guān), 諸如“阿姨,您怎么親自來了?”什么的。人類世界的溝通,可以用語言來進(jìn)行復(fù)雜的表達(dá),而語言由于其音節(jié)音調(diào)的多樣性。所以 可以進(jìn)行復(fù)雜的表達(dá)。普通話中的“你”“我”“他”三個(gè)字,有三種發(fā)音,聽者肯定可以區(qū)分三者的含義。但是,在電子的數(shù)字通訊世界里,只有 0 和1這兩個(gè)基本元素。就如前面提到的,它只能在一個(gè)時(shí)刻里面只表達(dá)一次。怎么辦?解決的方法是,我們用一組 0 和 1 的組合來進(jìn)行復(fù)雜意義的表達(dá)。如,我們可以用 00001 表示現(xiàn)在溫度是 1 ,00010 表示現(xiàn)在是 2 ,00011 表示現(xiàn)在是 3 。 當(dāng)然,這種表達(dá)的方法是二進(jìn)制的(關(guān)于二進(jìn)制,八進(jìn)制,十進(jìn)制等數(shù)學(xué)進(jìn)制的概念和互相轉(zhuǎn)換, 請(qǐng)參考網(wǎng)上的文檔)。所以,簡(jiǎn)而言之,在電子的世界里面,所謂的通訊協(xié)議,其實(shí)就是一個(gè)事先規(guī)定的規(guī)則, 我發(fā)送什么樣的 0 和 1 的組合代表什么意思。你如果事先了解了這個(gè)規(guī)則,這就是所謂的你“兼容”這個(gè)通訊協(xié)議。如果不了解,那 就是所謂的“不兼容”。
2、一個(gè)通訊協(xié)議涉及到的關(guān)鍵要素
一個(gè)通訊協(xié)議包含哪些要素呢?在此羅列如下:
A、電壓規(guī)范。
處于一個(gè)通訊網(wǎng)絡(luò)下的各個(gè)電子零件在進(jìn)行通訊的時(shí)候,首先必須要采用共同的電壓 水平。因?yàn)?數(shù)字通訊的基本規(guī)則就是 LOW(通常是 0V,當(dāng)然還有別的電壓水平,如果是 0V,這個(gè)電壓并非指確定的 0V,而是大約在 0V 左右)表示 0,表示“沒有”。HIGH(事先 約定的高電平,如 3.3V,5V,12V 等。如果是 3.3V,那么這個(gè)值并非是確定的 3.3V 等,而 是電壓高到大約 3.3V 左右)表示 1,表示“有”。
試想一下,如果兩個(gè)電子零件相互之間連基本的工作電壓都不一致,你還妄圖讓它們進(jìn) 行通訊,那么除了冒煙或者是通訊失敗,你幾乎得到什么別的結(jié)果。
舉個(gè)例子,如你手頭的一個(gè)零件 A,輸出 0V 表示開關(guān)閉合,輸出 5V 表示開關(guān)打開?,F(xiàn) 在另外一個(gè)零件 B,它認(rèn)為 -12V 表示開關(guān)閉合,0V 代表開關(guān)打開。姑且不去討論會(huì)不會(huì)燒掉 電路的問題。那么不管 A 發(fā)送什么電壓給 B,B 會(huì)永遠(yuǎn)都認(rèn)為 A 是處于開關(guān)打開的狀態(tài),因?yàn)?不管是 0V 還是 5V 都已經(jīng)高于了 0V 這個(gè)限度。
繼續(xù)舉一個(gè)例子,如,你和你的女友約定,如果你拿手指頭點(diǎn)點(diǎn)她的額頭表示你現(xiàn)在很無奈(你的手指很溫暖,女友很幸福)。如果你拿著一把燒紅的烙鐵打算點(diǎn)點(diǎn)她的額頭,這還 會(huì)讓她認(rèn)為你打算讓她認(rèn)為你很無奈嗎?不過,需要注意的一點(diǎn)是:通常情況下,我們?cè)诰W(wǎng)上可以下載到的各種 IEEE 的通訊協(xié)議 標(biāo)準(zhǔn)規(guī)范里面都不會(huì)對(duì)電壓進(jìn)行直接的規(guī)定。其實(shí),這也很好理解,我們只需要保證處于通訊中的雙方采用同樣的電壓就行了。這就好像,如果你和你的女友是超人和女超人,那么你拿個(gè)烙鐵點(diǎn)她的額頭,她還是會(huì)理 解為你是在表達(dá)你的無奈。實(shí)際上的例子則是:在實(shí)際應(yīng)用中,如 canbus 總線,有的總線的通訊電壓是 3.3V,有的 在是 5V,甚至還有使用 12V。而之所以在此提出這一點(diǎn)。是因?yàn)橛泻芏嗟男氯藧酆谜咴谑褂脭?shù)字傳感器的時(shí)候,往往不 會(huì)去考察它的通訊電壓。而這往往會(huì)導(dǎo)致通訊失敗,甚至燒毀電路元器件。
B、幀長(zhǎng)度
所謂的幀長(zhǎng)度就是:到底一個(gè)信息用了多少個(gè) 0 和 1 來組成。這個(gè)好理解,因?yàn)槭遣捎靡淮?0 和 1 的組合來代表意義,那么我們?cè)O(shè)想,信息的發(fā)送方 如果沒有預(yù)定多少個(gè)用 0-1 來表示一個(gè)完整的組合。那么假設(shè)我們按照如下的方式發(fā)送信息呢:一次性發(fā)送:0101001011100101001010100如果拆分成 4 個(gè)一組呢?: 0101-0010-1100-1010-0101-0100顯然,前者你根本就不知道是什么意思。你哪里知道是多少個(gè)數(shù)字代表一個(gè)信息?而后者,你雖然不知道意思,但是好歹,知道發(fā)送了 6 個(gè)信息過來。在幀長(zhǎng)度的實(shí)際應(yīng)用中,有些通訊協(xié)議采用了停止位的方法,而所謂的停止位,類似于上 面的 0101-0010 之間的“-”,通常的做法是使用一個(gè)較長(zhǎng)的低電平或者高電平。而有些的通 訊協(xié)議則是,事先約定了多少個(gè) 0-1 組合就是表示一個(gè)信息。也就是發(fā)送方一旦開始發(fā)送,接 收方直接照著固定的個(gè)數(shù),自行將一整個(gè)的 0-1 序列拆分。 無奈(你的手指很溫暖,女友很幸福)。如果你拿著一把燒紅的烙鐵打算點(diǎn)點(diǎn)她的額頭,這還 會(huì)讓她認(rèn)為你打算讓她認(rèn)為你很無奈嗎?
我們常見的序列長(zhǎng)度有 8 個(gè) 0-1,16 個(gè),32 個(gè),64 個(gè)??匆幌?正好是 2 的倍數(shù)。當(dāng)然,前言 8 個(gè)的最常見,8 個(gè) 0-1 序列就可以排出 256 個(gè)可能。而我們必須要接觸到的 ASCII 編碼,其 基本的 0-1 序列長(zhǎng)度就是 8 位。
C、通訊速率
關(guān)于這一點(diǎn),我們可以使用一個(gè)簡(jiǎn)單的實(shí)驗(yàn)來得到體現(xiàn)。我們?cè)?Arduino 中輸入如下的 代碼:
void setup(){Serial.begin(9600);}void loop(){Serial.println(“Hello!”);delay(1000);}
如果在電腦中打開串口監(jiān)視器,除非我們選擇的波特率是 9600,否則,我們?cè)诖诒O(jiān)視 器中將只能看到一堆的亂碼。
我們打一個(gè)比方:好吧,你和你的女友郎情妾意,她在給你喂飯。如果你當(dāng)時(shí)感到幸福,于是閉上了眼感覺 自己徜徉在幸福的海洋中,而女友也感到幸福,于是也閉眼享受和你一樣的幸福。如果她這個(gè) 時(shí)候還給你繼續(xù)喂飯呢?你知道她什么時(shí)候會(huì)喂給你,而你恰好張開嘴?于是飯勺子很可能就 直接戳你嘴皮上了。
當(dāng)然,如果你們兩個(gè)都具有大哲學(xué)家的冷靜,事先約定了:
“親,你每 5 秒給我喂一次哦”
那么上面煞風(fēng)景的事情就不會(huì)發(fā)生。 這是因?yàn)?你們約定了喂飯的頻率。
其實(shí),處于通訊兩端的兩個(gè)電子零件也相當(dāng)于這么一對(duì)閉眼享受幸福還要秀恩愛喂飯的男 女,一個(gè)在發(fā)送信息(喂飯)一個(gè)在接收信息(張嘴吃飯)。如果通訊雙方不事先約定好頻率, 那么就會(huì)出現(xiàn)信息丟失的現(xiàn)象。
D、校驗(yàn)
如果說,兩個(gè)人互相之間是在扯談,比如像我現(xiàn)在正在干的事情。那么說過了也就罷了, 沒啥大問題。但是,如果是在非常重要和嚴(yán)肅的場(chǎng)合呢?萬一聽的人聽錯(cuò)了,那肯定會(huì)出大問 題。在軍事指揮中,有這么一種方法來防止出問題:命令復(fù)述。也就是指揮官下重要命令的時(shí)候, 聽從命令者必須復(fù)述指揮官的命令以做確認(rèn)。同樣的,在電子世界的通訊中,因?yàn)橥ㄐ啪€路的干擾,信息發(fā)送方和接收方可能出偶爾的 問題,那么也會(huì)面臨同樣的問題—信息發(fā)送出現(xiàn)了失誤(術(shù)語叫誤碼)。這個(gè)時(shí)候,我們就必 須想辦法來解決。當(dāng)然,如果接收方在接收到信息之后原封不動(dòng)的反饋給發(fā)送方,發(fā)送方比對(duì),如果對(duì)了就 回復(fù)確認(rèn);如果錯(cuò)了就回復(fù)錯(cuò)誤,然后重新發(fā)送,這種方法可以確保絕對(duì)的正確。但是,這種 方法顯然是相當(dāng)無效率的,除非是非常重要的,一點(diǎn)錯(cuò)都不能出的通訊場(chǎng)合,否則這種檢驗(yàn)方 法很少會(huì)被采用。
幸好專家們想到了更有效率的方法,即所謂的校驗(yàn)。通常的校驗(yàn)方法有所謂的奇偶校驗(yàn), 和值校驗(yàn)等等。如奇偶校驗(yàn),則是在發(fā)送信息的同時(shí)在末尾再帶上這次發(fā)送信息的 0-1 中的 0 的個(gè)數(shù)或者 1 的個(gè)數(shù)的模值。
如前面的數(shù)據(jù)列
>0101-0010-1100-1010-0101-0100
如果為了確保信息發(fā)送的完全。我們可以采用在每個(gè)4位數(shù)的后面再加上一個(gè)奇偶校驗(yàn)位, 即一次性發(fā)送 5 個(gè)。
如果我們采用耦校驗(yàn)位,那么我們的上面的序列就變成了如下的串列:
>0101(0)-0010(1)-1100(0)-1010(0)-0101(0)-0100(1)
括號(hào)里面的 0-1 就是所謂的校驗(yàn)字(注:事實(shí)上,括號(hào)是不存在的)
采用數(shù)學(xué)的方法。如第一串 0101(0) 我們可以根據(jù)校驗(yàn)字來判斷,前面的 0101 是否正確。
如果發(fā)生了錯(cuò)誤,我們?cè)敬蛩惆l(fā)送 0101,但是因?yàn)橥ㄓ嵆隽藛栴},結(jié)果只接收成了0001,那么我們可以發(fā)現(xiàn),這個(gè)時(shí)候的校驗(yàn)位卻是 0 的話,顯然,0001 絕對(duì)是錯(cuò)誤的值。那 么這個(gè)串列就可以簡(jiǎn)單拋棄,然后要求重發(fā)了。 當(dāng)然,在實(shí)際過程中。如 TTL 串口通訊。如果你要求不是那么高,那大可以不搞什么校驗(yàn)。 而如果你對(duì)奇偶校驗(yàn)有跟多的興趣,可以參考維基百科。
E、握手
這個(gè)概念非常好理解。如果你在圖書館聚精會(huì)神地讀書,忽然坐你邊上的人開始說話,我 相信,你的第一反應(yīng)肯定不會(huì)認(rèn)為那個(gè)家伙是在對(duì)你說話,并且你幾乎記不住那個(gè)家伙剛剛在 說什么。但是,如果那個(gè)家伙先用手肘碰碰你,然后說:“喂”。等你抬頭看著他,他再和你嘰里 呱啦的時(shí)候,你肯定可以聽到他對(duì)你說了什么。
在電子通訊世界里面也是如此,兩個(gè)或者多個(gè)需要進(jìn)行互相通訊的電子零件可能正在執(zhí)行 各自的工作。結(jié)果,接收方正在進(jìn)行某個(gè)工作的處理,結(jié)果發(fā)送方忽然發(fā)送了一大段的信息過去。 很有可能的結(jié)果就是接收方?jīng)]法接受到這個(gè)信息。解決這個(gè)問題的方法有幾種。一種是采用所謂的握手信號(hào),有的是一個(gè)專門的電路,如 Arduino 中的 SPI 通訊,發(fā)送方 會(huì)使用 CS 引腳發(fā)送一個(gè)高電平,告訴接受方,我要開始和你通訊了。
還有一種類似于老師在課堂上點(diǎn)名回答問題,參與通訊的各個(gè)電子元件事先都規(guī)定好了各 自的 ID,當(dāng)發(fā)送方發(fā)送信息的時(shí)候在開頭的時(shí)候發(fā)送這個(gè) ID。那么具有這個(gè) ID 的接受者就會(huì) 根據(jù) ID 判斷這個(gè)信息是否是發(fā)送給自己的。這類似于在信封上面寫地址一樣。再有就是沒有握手信號(hào)。純粹雙方都具有專門的發(fā)送和接收的模塊。如 Arduino 上的 RS232 中的 RX 端口,它是相對(duì)獨(dú)立于 Arduino 的 CPU 的,一旦 Arduino 上電,它就會(huì)隨時(shí) 監(jiān)聽來自于電線上的信號(hào)。一旦收到就立即存儲(chǔ)起來供 CPU 調(diào)用。這就好像一個(gè)老板給自己配 了一個(gè)電話秘書,隨時(shí)替老板接收電話,然后把電話內(nèi)容記錄下來供老板隨時(shí)瀏覽。
F、并行通訊和串行通訊
關(guān)于這個(gè),其實(shí)很好理解,如果只有一根導(dǎo)線,那么我們一次只能發(fā)送 0 或者 1。如果我 們要發(fā)送 0101,那么我們就需要按照先后順序連續(xù)發(fā)送四次。這就是所謂的串行通訊。但是, 如果我們?cè)谕ㄓ嵉碾p方連接 4 條導(dǎo)線呢?那么一次性我們就可以把 0101 中的第一位的 0 通過 第一根導(dǎo)線,第一位的 1 通過第二根,第三位的 0 通過第三根,第四位的 1 通過第四根一次性 地發(fā)送出去。 串行通訊的速度相對(duì)較慢,但是這節(jié)省連接電路,也就是說省錢。并行通訊速度相對(duì)較快, 但是這相對(duì)來說非常不省錢。并且,隨著連接電路的數(shù)量增多,它的可靠性也成級(jí)數(shù)往下降。所以, 選擇哪種通訊方式,這在于速度 VS 可靠和經(jīng)濟(jì)的權(quán)衡。 通常情況下,遠(yuǎn)距離、低速的通訊通常都是串行的。而近距離、高速的通訊通常都是并行的。
G、單工,半雙工,全雙工。
這三個(gè)概念也比較簡(jiǎn)單。單工就是發(fā)送方只能發(fā)送,接收方只能接受。這種方式在現(xiàn)實(shí)的世界中比如說廣播、電視。 這些就是單工。半雙工則是,雙方都能夠發(fā)送和接收,但是如果是發(fā)送信息,那么它在同一個(gè)時(shí)刻下只能 發(fā)送或者接收。無法在同一個(gè)時(shí)刻下同時(shí)干兩件事情。如 Arduino 上的 IIC 總線(TWI)就是 半雙工通訊。比較形象的就是步話機(jī)。
全雙工則是,雙方不僅能夠發(fā)送和接收,而且發(fā)送和接收可以同時(shí)進(jìn)行。在 Arduino 上 的 SPI 總線和 TTL RS232 都屬于全雙工。而現(xiàn)實(shí)中的例子如電話,互聯(lián)網(wǎng)連接等。
3、了解這些對(duì)于應(yīng)用 Arduino 的意義。
1、了解了關(guān)于電平的概念,那么我們?cè)谖磥磉B接電路的時(shí)候就不會(huì)出現(xiàn)隨便拿一個(gè)數(shù)字 傳感器就往 Arduino 上接的低級(jí)錯(cuò)誤。好歹我們得注意看一下,它的通訊電壓是多少的。當(dāng)然, 還有一些特例,如 CMOS 電平和 TTL 電平兼容,這些是后來的升級(jí)概念。我們這兒不做延伸說明。2、了解了關(guān)于通訊速率的概念,那么我們就明白了,為什么需要設(shè)定 Serial.begin()。3、了解了奇偶校驗(yàn),那么我們?cè)谖磥碜x取數(shù)字傳感器的發(fā)來的數(shù)字的時(shí)候就會(huì)應(yīng)用這 個(gè)位來判定讀數(shù)值正確與否。4、了解串行和并行通訊,其實(shí),是為了讓我們理解 shiftout() 函數(shù)。5、了解握手的概念,這樣我們才會(huì)理解為何 IIC 需要設(shè)定一個(gè) ID 去發(fā)送或者接收,而 TTL RS232 和 SPI 則不需要。6、了解了單工,半雙工,全雙工。好吧,這個(gè)概念貌似對(duì)于 Arduino 的初級(jí)應(yīng)用的確沒啥用。 只是純粹為了補(bǔ)齊概念和湊字?jǐn)?shù)。
很多的時(shí)候,很多的愛好者往往不清楚這些概念,所以總是會(huì)犯一些讓業(yè)內(nèi)人士嘲笑的 低級(jí)錯(cuò)誤。但是,這些錯(cuò)誤正是因?yàn)槿狈A(chǔ)知識(shí)才會(huì)發(fā)生的錯(cuò)誤。如何避免?難道要像那些 業(yè)內(nèi)人士一樣老老實(shí)實(shí)地抱著專業(yè)書開啃?但是,我們真的只是愛好者,我們只需要搞清楚大概的理論框架就行了。所以,才 有了這個(gè)水煮通訊協(xié)議的扯談篇。希望能夠給有需要的讀者以幫助