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