mfc如何将一个数组中的字节数据用串口发送出去_[翻译] 串口通信的帧(frame)...
在串口通信中,只傳輸一個字節(jié)是簡單的,但是如果要傳送一個幀(多個字節(jié)),將面臨以下問題:
- receiver從串口接收的是字節(jié)流,那它是如何知道幀的開始或結(jié)束呢?它又是如何知道這個幀有多長?
- 真實的物理硬件是充滿噪音和干擾的,由于電噪聲,某些字節(jié)的位可能被翻轉(zhuǎn),字節(jié)甚至整個幀都可能會丟失。
要解決這些問題,首先需要了解下計算機網(wǎng)絡(luò)中數(shù)據(jù)鏈路層的基礎(chǔ)知識。
基于一個可以在設(shè)備之間傳輸信號的物理層,數(shù)據(jù)鏈路層的工作(粗略地說)就是傳輸整個數(shù)據(jù)幀,其中一些方法可以確保數(shù)據(jù)的完整性(減少錯誤)。當我們使用socket通過TCP或UDP進行網(wǎng)絡(luò)通信時,幀在硬件層面得到了很好的處理,以至于上層甚至都感覺不到。但是,在串口通信中,我們必須自己處理幀和數(shù)據(jù)錯誤。
處理幀有以下幾種方法:
方法1和2僅適用于硬件實現(xiàn)的數(shù)據(jù)鏈路層。當涉及多層軟件(比如在Windows上運行)時,確保計時非常困難。
方法3的意思是在幀頭中指定幀中的字節(jié)數(shù)。這樣做的問題是計數(shù)可能因傳輸錯誤而出現(xiàn)亂碼。在這種情況下,“重新同步”會非常困難,因而這種方法很少使用。
方法4和5有些相似。在本文中,我將重點關(guān)注4,因為5不適合串口通信。
帶字節(jié)填充的標志字節(jié)
讓我們從先一個簡單的想法開始,然后逐步將其發(fā)展成一個完整,強大的方案。flag bytes是特殊字節(jié)值,表示幀何時開始和結(jié)束。假設(shè)我們希望能夠發(fā)送任意長度的幀。特殊的start flag bytes表示幀的開始,end flag bytes表示幀的結(jié)束。
那么問題來了。假設(shè)end flag的值是0x98,如果0x98又正好出現(xiàn)在data的某處,協(xié)議將混淆并認為這個幀到data里的這個0x98就結(jié)束了。這個問題有一個簡單的解決辦法,所有熟悉字符串轉(zhuǎn)義引號和特殊字符的程序員都應(yīng)該能想到。它被稱為字節(jié)填充,或簡單地轉(zhuǎn)義,具體方法如下:
每當數(shù)據(jù)中出現(xiàn)一個flag byte(開始或結(jié)束)時,我們將在它之前插入一個特殊的轉(zhuǎn)義字節(jié)(比如ESC)。 當receiver看到ESC時,它知道忽略它并且不將其插入到接收的實際數(shù)據(jù)中。每當ESC本身必須出現(xiàn)在數(shù)據(jù)中時,另一個ESC就會被置于其前面。Receiver移除第一個但保留第二個。
這里有一些示例:
此外,我們還需要某種錯誤檢查,比如checksum,或者更好的CRC。這通常是幀的最后一個字節(jié),檢查范圍包括幀中的所有字節(jié)(以其未填充的形式)。
這種方案是穩(wěn)健的:任何丟失的字節(jié)(無論是標志,轉(zhuǎn)義,數(shù)據(jù)字節(jié)還是校驗和字節(jié))都會導(dǎo)致receiver僅丟失一幀,之后它將重新同步到下一幀的start flag。
PPP協(xié)議
事實上,這種方法可以算是點對點協(xié)議(PPP)的簡化版,在PPP中:
- 開始和結(jié)束的flag byte都是0x7E
- 轉(zhuǎn)義字節(jié)為0x7D
- 只要消息中出現(xiàn)標志或轉(zhuǎn)義字節(jié),它就會被0x7D轉(zhuǎn)義,字節(jié)本身與0x20進行異或運算,例如0x7E變?yōu)?x7D 0x5E,0x7D變?yōu)?x7D 0x5D。Receiver取消轉(zhuǎn)義轉(zhuǎn)義字節(jié)并再次使用0x20對下一個字節(jié)進行異或,以獲得原始數(shù)據(jù)。
讓我們用一個完整的例子來演示它是如何工作的。
假設(shè)我們定義以下協(xié)議:
start flag:0x12 end flag:0x13 轉(zhuǎn)義字節(jié):0x7D并且sender想要發(fā)送以下數(shù)據(jù)消息。原始數(shù)據(jù)在(a)中:
數(shù)據(jù)包含兩個需要轉(zhuǎn)義的標志,位置2的0x13(對,從0開始計數(shù)),以及位置4的0x7D。
Sender的數(shù)據(jù)鏈路層會將數(shù)據(jù)轉(zhuǎn)換為(b)中所示的幀。
接下來讓我們看看receiver如何處理這樣的幀。 為了演示,假設(shè)receiver從串口獲取的第一個字節(jié)不是消息的真實部分(我們想看看它如何處理這種情況)。 在下圖中,receiver state是接收字節(jié)后receiver的狀態(tài),data buffer是接收數(shù)據(jù)的緩沖區(qū),用于之后將數(shù)據(jù)傳遞到上層應(yīng)用程序。
有幾點需要注意:
- 忽略start flag之前的“雜散”字節(jié):根據(jù)協(xié)議,每個幀必須以start flag開頭,因此這不是幀的一部分。
- start flag和end flag本身不會進入數(shù)據(jù)緩沖區(qū)。
- 轉(zhuǎn)義字節(jié)由一特殊狀態(tài)AFTER_ESC處理。
- 當幀以end flag結(jié)束時,receiver擁有了一個可以往上層程序傳遞的幀,并且返回等待start flag,或者說等待一個新的幀。
最后,上層應(yīng)用程序看到收到的消息正是發(fā)送的消息,所有協(xié)議細節(jié)(標志,轉(zhuǎn)義等)都由數(shù)據(jù)鏈路層透明地處理掉了。
本文翻譯自 https://eli.thegreenplace.net/2009/08/12/framing-in-serial-communications
原創(chuàng)翻譯,轉(zhuǎn)載請注明出處。
總結(jié)
以上是生活随笔為你收集整理的mfc如何将一个数组中的字节数据用串口发送出去_[翻译] 串口通信的帧(frame)...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: boolean类型_JS核心理论之《数据
- 下一篇: m3u8文件在手机上用什么软件看_如何用