|
|

楼主 |
发表于 2014-4-13 11:59:24
|
显示全部楼层
本帖最后由 Super169 于 2014-4-13 13:06 编辑
maxims 发表于 2014-4-13 08:21 
谢谢了,终于有人系统的讲了一下这些!不过,我还有个问题!
对方以十六进制发送数据,我接收处理也用十 ...
不好意思, 我不太肯定 "十六进制发送", 及 "十六进制处理" 的具體意思.
我猜測, 基本上說 十六进制发送" 的話, 應該是指以數值傳出去 (例如 0x1A 的一個 byte代表 26), 不會是指 十六进字符 ("1A") 吧. 或者我對兩個方法也說說吧.
如果是以 數值發送 (就是一個數值, 一個個 byte 傳出去, 沒有十六進或十進的分別, 直接說是二進的發出去, 因為最基本單位是每次去一個 bit 以 高低位訊號發送)
基本上, 最簡單就是用一個 uint8_t / byte 的變數去接收資料 (當然 int 之類亦可, 但 int 在不同機種會有不同的長度, 所以一舨用指定大小的如 uint8_t, byte, uint16_t 之類比較安全一點), 然後直接處理.
比如通訊協定如下 (有三個指令):
- 0x01 <data> <data>
- 0x02 <data> <data> <data>
- 0x03 <data>
先用 uint8_t code = Serial.read(); 接收了一個 code, 之後再按照不同的 code, 接收餘下的資料進行處理就可以了. 接收方式看需要而定, 簡單的可設定一個足夠不同指令的 array, 把資料放進去. 又或有不同的地方去接收 (例如 0x01 的是一個 16bit 的數, 就合成一個 uint16_t 放到 var1, 0x02 就是三個獨立的數放入 uint8_t var2[3] 中, 而 0x03 是一個 char 就放入 char var3 之中.) 沒有絕對, 最重要是看通訊協定處理.
此外, 當中每個資料接收之間, 最好加入一點 delay. 原因是接收時, 處理的速度可能比傳送快很多.
如果用 9600bps, 每一個 byte 最少也要 8/9600 約 1ms 的時間去傳送, 但程式處理接收的速度相對很快. 當你完成一個 read() 之後, 可能少於 0.5ms 就會進行下一次 available() 的檢測, 如果下一個 data 還未送到, 就可能會出現錯誤判定為資料發送完結.
因此, 每次 read 之後, 在下一次 available() 檢測之前, 加入一點延遲, 如 delay(2); 之類, 只是浪費一丁點時間, 但對 available() 的檢測會較準確. 另外為免因為傳送受到干擾, 而收到錯誤資料, 一般會在資料後加一個 checksum, 最簡單的方法, 可以把整串資料的數值加起來, 取低位的一個 byte 傳出去 (你可能會發覺, 把 1,2,3 發成 3,1,2 也會被判定為正確. 但不要想得太複雜, 只是作簡單的檢測, 總不能把資料發兩次去檢測吧. 現實中有很多大同的檢測方法, 越準確對應的檢測碼也會比較長, 對單片機而言, 不可能用一串長長的檢測碼吧. 用一個 byte 的已可以了, 如有需要可以加上不同的計算, 例如加權的方式, 甚至用 2 個或以上的檢測碼, 但不要把檢測碼弄得太長..否則, 乾脆發兩次作比對算了.)
如果傳送協定是以 字符的形式進行 (例如 32路串口航舵控制板之類), 資料的長度可能不是固定的, 例如 要傳送一個 0 - 255 的值時, 用 數值的方式, 就會固定是一個 byte, 但用字符時, 一般不會補零, 就可能會出現 1 至 3 byte 長度的可能了 (例如 "3" 是一個 byte, "123" 是三個 byte 了).
一般用字符傳送的, 都會有一些分隔符號, 以便決定資料的長度. 否則, 就要用固長度的方式傳送.
例如要送出三個 0-255 的數值, 如沒有任何分隔, 亦沒有固定長度, 當發送出 "123","12","3"後, 接收的一方收到了 "123123" 的資料, 就可能出現不同的可能:
- "1", "23", "123"
- "1", "231", "23"
- "12", "3", "123"
- "12", "31", "23"
- "123", "1", "23"
- "123", "12", "3"
不同的數值, 更可能出現更大的變化.
所以, 一般會加入分隔或轉為固定長度
例如:
- 用"#"作開始, ";"分隔每個數, "$"作結束: "#123;12;3$"
- 用固定三個字: "123012003" 亦可轉成 16 進發出 "7B0C03"
接收的也可以準確分拆資料使用 (通常串口都會是加入分隔符號, 如用固定長度, 多會是16進的, 但亦有可能是十進, 最重要是看通訊協定)
由於以字符傳送, 資料的長度可能不能確定, 如果直接處理, 程序會比較複雜, 一般會設定一個 char[] 或 String, 先把一次的資料收下來, 再對資料進行分析.
注意, 如果用 char[] 的時候, 要確保有足夠的空間存放一次的資料. 例如用分隔符號的例子中, 傳送三個數值, 就要預留 3 x 3 + 4 = 13 個字符的空位 (或者除去開始及結束的不用再處理, 也要 11 個字符).
當然, 有可能出現資料受干擾而收到錯亂數據, 在接收時, 資料或會長度改變了.
例如: #123;3#123;31;234$", 第一個傳送可能出了問題, 程式中需要加入在中途對開始碼的檢測, 以為超出預定長度時的處理. 否則, 如果用 char buffer[13] 去接收, 當接收了 "#123;3#123;31" 後, 再收到 ";" 而放進 buffer[13] 中時, 就會把其他資料改變了, 後果難以估計.
最後還是一句, 接收方式不會是固定的, 不要奢望同一套方法可以完全通行, 最重要是根據通訊協定去處理.
|
|