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