串口協議以及串口二進製(zhì)整數據包解析(xī)
以串口作(zuò)為傳輸媒(méi)介,介紹下怎樣來發送接收一個完整的(de)數(shù)據包。過程涉及(jí)到封包與解(jiě)包。設計一個良好的包(bāo)傳輸機製很有利(lì)於數(shù)據(jù)傳輸的穩定性以(yǐ)及正確性。串(chuàn)口隻是一種傳輸媒介,這種(zhǒng)包機製同時(shí)也(yě)可以(yǐ)用於SPI,I2C的總(zǒng)線(xiàn)下的數據傳輸。在單片機通信係統(多機通信以及PC與單片機通信)中,是很常(cháng)見的問題(tí)。
一、根據幀頭幀尾或(huò)者幀長檢測一個數據幀
1、幀頭+數據+校(xiào)驗+幀尾
這是一(yī)個典型的方案,但是對幀頭與幀尾在設計的時候都要(yào)注意,也就(jiù)是說幀頭、幀尾不能在所傳輸的數據域中出現(xiàn),一旦出現可能就被誤判。如果用(yòng)中斷來接(jiē)收的(de)話,程序基本可以這麽實現:
unsigned char recstatu;//表示是否(fǒu)處於一個正在接收數據包的狀態(tài)
unsigned char ccnt; //計數
unsigned char packerflag;//是否接收到一(yī)個完整的數據包標誌
unsigned char rxbuf[100];//接收數據的緩衝區
void UartHandler()
{
unsigned char tmpch;
tmpch = UARTRBR;
if(tmpch 是包頭) //檢測(cè)是否是包頭
{
recstatu = 1;
ccnt = 0 ;
packerflag = 0;
return ;
}
if(tmpch是包尾(wěi)) //檢(jiǎn)測是(shì)否(fǒu)是包尾
{
recstatu = 0;
packerflag = 1; //用於告知係統已經接收到一個完整的數據包
return ;
}
if(recstatu ==1) //是(shì)否處於接收數(shù)據包狀態
{
rxbuf[ccnt++] = tmpch;
}
}
上(shàng)麵也就是接收(shōu)一個數據包,但是再次提(tí)醒,包頭和包尾不能在數據域中出現,一旦出現將會出現誤判。另外一個。數據的校驗算法是很必要(yào)的,在(zài)數據傳輸中,由於受到幹擾,很難免有時出(chū)現數據錯誤,加上(shàng)校驗(yàn)碼可在發現(xiàn)數據傳輸錯誤時,可以要求數據的另一方重新發送,或是進行簡單的丟(diū)棄處理。校驗算法不一定(dìng)要很(hěn)複雜,普(pǔ)通的加和,異或,以及循環冗餘都是可以(yǐ)的。我上麵的接收程序在接收數據時,已經將包頭和包尾去掉,這些可以根據自己的需求加上,關鍵是要(yào)理解原理(lǐ)。
上述包(bāo)協議出現了以下(xià)的幾種變種:
1.1 幀頭+數據長度+數據+校驗值
1.2包長+校驗(yàn)值
上麵兩種(zhǒng)其實都是知道了數據包的長度,然後根據接收字節的長度來判斷一個完整的數據包。例如,定義一個數據包的長度為256字節,那(nà)我們就可(kě)以一直接收,直到接收到256個字節,就認為是一個數據包。但是,會不會存在問題(tí)呢?比如說從機向主機發送數據,發送(sòng)了(le)一半,掉電(diàn),重(chóng)啟(qǐ),開機後繼續發(fā)送,這(zhè)很明顯(xiǎn)接收到(dào)的數據就不(bú)對了,所(suǒ)以此時很有必要定義(yì)一個超限時間,比如我們可以維(wéi)護下麵這樣的一個結(jié)構體。
struct uartrd{
char rd[ 256];
unsigned int timeout;
}
成員(yuán)變量rd用來存放(fàng)接收到的數據字節;成員變量timeout用(yòng)來維(wéi)護超時值,這裏主(zhǔ)要討論這個。這個數(shù)值怎麽(me)維護呢,可以用一(yī)個定時器(qì)來維護,以可以(yǐ)放在普通的滴答中斷(duàn)裏麵來維(wéi)護,也(yě)可以根據係統運行一條指令的(de)周期,在自己的循環中來維(wéi)護,給其設置個初值,比如說100,當有第一個(gè)數(shù)據到來以後,timeout在指定的時間就(jiù)會減少1,減少到0時,就認為超時(shí),不論是否接(jiē)收到足夠(gòu)的數據,都(dōu)應該拋棄。
二、根據接收超時來(lái)判斷一個數據包
2.1 數(shù)據+校驗
核心(xīn)思想是如果在達到一(yī)定的時間(jiān)沒有接受到數據,就認為數據包接(jiē)收完成(chéng)。modbus協議裏就有通(tōng)過時間間隔來判斷幀結束的(de)。具體實現是要使用一(yī)個定時(shí)器,在接(jiē)收(shōu)到第一個數據時候,開啟定時器,在接收到(dào)一個數據時候(hòu),就將定時器清零,讓定時器重新開始計時,如果設定的(de)超(chāo)時時間到(超時時間(jiān)長度(dù)可以設置為5個(gè)正常接收的周期),則認為在(zài)這一段時間內沒有接受到新的數據,就認為接收到一個完整的(de)數據包了(le)。
進行一個簡單的小的總結,上述幾種方法都還是(shì)較為常用的,在具體的實現上,可(kě)以根(gēn)據具體的實際(jì)情況,設計出具體的通訊協議。數據校驗位(wèi),有時候感覺不出來其重要性,但是(shì)一定要加上,對數據進行一個相關的驗證還是必要的。現在很在MCU都帶(dài)有FIFO,DMA等功能,所以有時候(hòu)利用上這些特性,可以設計出更好的(de)通訊方式。有(yǒu)的人問在接受串口數(shù)據時候是應該(gāi)中斷(duàn)一次接收一個(gè),還是進入中斷後接收一段數據(jù)呢,我認(rèn)為應該中斷接收一個,因為CPU是很快的,至少對(duì)於串口是這樣,在接受每個數(shù)據的間隔期間,處理器還是可以做些其他(tā)工作的。在多線程中,那就可(kě)以直接建立(lì)一個數(shù)據接收線程。
- 上一(yī)篇:串口通信(xìn)的MPU姿態傳感器數據包解析技(jì)術 2018/1/19
- 下一篇:Valve拆開賣HTC Vive的雙跟蹤基站,HTC失去絕對 2017/12/15
