如何設計一種串列通信協議(基於RS232/RS485埠)?
問題設計太廣了,設計到認證、安全和負載,不是一兩句話能說清楚的這個問題標準回答應該很長。還需要很多圖,用的是手機,邊走邊答,就簡化一下說。
你用的是RS232這樣的介面,標準協議有串口協議,可以自行參考。如果想自定義,可以繼續往下看。
你選定了RS232,因此不可能是高速串列介面,因此也不需要時鐘同步,非同步握手,編碼均衡等等麻煩的事情,同樣考慮到可實現性,我假定你使用的是串口的通用PHY器件,這樣各種電氣方面的問題都不管啦,然後只點對點通訊,也不允許熱插拔,也不需要枚舉,沒有橋,HUB,路由這碼子事。不廣播,不允許休眠,不檢測設備故障。OK,我們只關注通訊內容本身。
這裡假定你是需要設計一個板間通信用,距離不太長,比如小於1m,速度低,比如400k,通信線纜各方面都很理想,工作環境也很理想,不會有雷擊,不會有強靜電,磁場等等,然後通信可靠性要求不高,通信包類型只有單個讀,單個寫,中斷(控制包就不算了,不然寫不完)三種,有主從要求,無需配置,默認連接很好,連不好也不管,埠永遠有電從不關閉,由此導致的問題統統不管。(是不是很魂淡)。好,假定的差不多了,遺漏的也不管了。
通信的目的是為了交流信息,通信協議是交流的模版。既然定了主從,那這種交流就變為主告訴從(寫),主問,從答(讀)。還有就是從有急事,比如"我尿急!"(中斷)。我前面約定了單個讀寫,也就是說一次只干一件事。一件事情沒幹完,絕不做下一件事。
根據以上的思路,第一要確定,最多有多少事情需要通訊,也就是命令字或者事務的地址空間有多大。
吃個早飯先
人之間的通信靠語言,命令字或者事務列表就是單詞表。具體執行哪條就靠地址來標識。定了地址空間後,就確定了串列匯流排通訊包前段的地址長度。
第二,由於只有3種包,因此需要2個bit來進行標識,比如0為讀,1為寫,2為中斷,或者沒有中斷包等等,具體看需求。
第三,設定命令字的內容,比如,你每個命令最多有16種操作,那至少數據位寬4bit。當然不可能所有操作都是等位寬的。如果希望通過位寬不等來提高通信效率,還需要一個包長控制位,避免麻煩,這裡就默認等長了。同樣,你的通訊內容不能只有命令,還應該有數據等,因此之前說的地址空間應該分2部分,命令空間和數據空間。命令空間定義一些協議約定的控制字,並將地址保護起來。同時留一些用戶可自定義的命令空間,數據空間為傳輸的數據。同樣由於前面假設,搬數據的時候就一個一個搬吧,(50%的帶寬留給地址,雖然浪費,但是協議簡單)
第四,同步,前面假定了不做時鐘內嵌協議,而且用了串口的通用phy,因此同步模式使用串口的約定波特率的方法,省掉前期訓練同步的過程。但是考慮到板間通訊,可能時鐘不保證同源,在邊界以及累積情況下有風險,因此需加包頭包尾,一方面同步,一方面便於複位,一方面便於超時判斷
第五,中斷。中斷類似小朋友課堂舉手的機制。老師(主)給小朋友(從)講課(寫),也提問題(讀)。有時候小朋友主動舉手(中斷),老師問啥事(查詢中斷)。尿尿(中斷事務),去吧(中斷處理)。為了完成以上操作,需要對中斷進行定義,比如用包頭為10表示中斷包,後面帶上中斷向量(表示中斷內容,直接喊我要尿尿),也可以只將上行線拉高一陣子(舉個手),然後讓主設備查 。具體怎麼定看應用場景,反正只要和其他區別開就行。
第六 錯誤校驗。校驗當然靠校驗碼啦,最簡單的校驗是沒有校驗,錯就錯。複雜一點靠長度或包頭校驗,然後是奇偶校驗,然後crc,反正很多種,挑一個或者不嫌麻煩自己設計一個。錯誤包丟棄之後再根據需要設計個重發機制,可以對重發加權,就是有的包重發,有的不重複發,有的重發很多遍,有的包錯了要重發一系列包。具體看需要啦。然後還要有超時機制,根據系統需求,設計每個包之間間隔下限和上限,每個包最大長度和最小長度。每次響應的最長時間間隔和最小間隔。超時後的處理方法(重發還是放棄,是否報錯等)
第7 兼容性。你設計個協議總有實現載體吧,特別自由的有fpga,特別不自由的有各種cpu。你總要有個東西來跑這個協議。要保證在你選型的器件上可以跑,要規划下,比如8bit單片機操作,最好規定我整個包可以拆成一個個8bit來發送,如果是fpga則無所謂。
第8 可靠性 雖然可靠性已經體現在前7點了,但是就像降龍第18掌一樣,還要再打一遍。成熟合理的協議需要實際在場景中經歷種種壓力測試才能商用,實際環境遠比自己拍腦袋想得要複雜。沒打過戰的新兵不算兵。所以如果有合適的現成協議,盡量不要自己來,不經濟.
隨手寫的,有遺漏,莫當真
同意 @bort kaluoy 這個答案設計確實太廣了,即使你加了基於232/485的限制,但依然是一個學科性的問題。寫本書都夠了。
簡單的說要做一個協議,首先要考慮你的匯流排拓撲形式。是點對點的方式傳輸(是一主一從,還是兩個為對等的節點),還是一個主機下掛了多個從節點(節點和主機如何鏈接,是星形鏈接、樹形鏈接,還是匯流排型連接)。
如果是一主一從的點對點那是最簡單的。如果是兩個對等的節點或者一對多匯流排節點,那就需要考慮匯流排競爭、衝突、地址設計、超時處理等問題。
那最簡單的主從點對點來說(封閉式網路,即設備節點數確定,且非相設備協議不相同無法接入該網路)。
首先你的波特率設置,最好是所有節點都定一個波特率,有人做過不同波特率通信的,反正我沒玩過。而且波特率的大小要從你匯流排的數據量開銷、處理器/控制器的速度、應用的環境中電磁複雜程度、硬體設備的帶寬(頻率高了會不會受影響,導致丟包率增大,或影響其他設備)然後一個幀開頭應該帶有幀標識,讓對方判斷收到的是數據幀還是應答幀。點對點通信,最少應該具備一個數據命令幀和應答幀。數據命令幀是包含主要設信息的,應答幀是告訴對方是正確否收到數據,如沒有,請重發。另外如果收的幀標識都不是這兩種的,就說明可能匯流排出現問題/受干擾/接入其他未知設備。其次考慮你傳輸的數據量有多大,是否需要數據包定長。如果傳輸的數據時而多(十幾/幾十個個位元組),時而少(不到一個位元組),那就不能定長。這樣的話就需要在第二第三個位元組(放幀標識的位元組前後)加上包/幀的長度信息。然後是地址,雖然只有兩個點在面對面對話通信,但建議加上源地址和目標地址。這個只是建議,在點對點通信中可選。之後應該加上一個序列號,用以表示為第幾次發送。比如說,我發了一次Hello給你,下一次應該發一個World給你,但你反饋應答幀說沒收到或者收到錯誤,然後我再發一次Hello給你,這時的Hello這幀中的序列號應為2了。接下來是數據內容……最後是校驗,CRC ……異或……什麼的,對前面所有的數據從幀頭到幀尾的位做數據校驗。防止傳輸過程中,任何一個bit出錯。現在想到的就是這麼點。吐個槽,記得當年我們一組人做鐵路信號設備的協議,研究院的人看了我們兩周想出來的協議後(基於RS485),說:協議是這麼簡單就搞出來的么!沒試驗個一年的工夫都不敢說整出一個安全的強壯的協議來。
推薦閱讀:
※如何自學通信原理?
※如何評價NB-IOT核心協議凍結的影響?是否標誌物聯網大規模產業化時代到來?
※I2C協議(中)——硬體I2C的簡單讀寫實驗
※室內OFDM信道測試?