• 串口數據包解析代碼分析

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

    簡單的小的總結,上述幾種方法都還是較為常(cháng)用(yòng)的,在具體的實現(xiàn)上,可以根據具體的實際情況,設計出具(jù)體的通訊協議。數據校驗位,有時候感覺不出來(lái)其重要性,但(dàn)是(shì)一定要加上,對數據進行一個相關(guān)的驗證還是必要(yào)的。現(xiàn)在很在MCU都帶有FIFO,DMA等(děng)功能,所以有時候利用上這些特性,可以設計出更(gèng)好的通訊方式。有的(de)人問在接受串口數據時候是應該中斷一次接收(shōu)一個,還是進入中斷後接(jiē)收一段數據呢(ne),我認為應該中(zhōng)斷(duàn)接收一個,因為CPU是很快的,至少對於串口是這樣(yàng),在接受每個數據的間隔期間,處理器還(hái)是可以做些其他工(gōng)作的。這是在裸機下的模型(xíng)。在多線程中,那就可以直接建立一(yī)個數據接收線程。


    密桃直播-密桃直播手机版下载-蜜桃直播app下载安装-蜜桃直播官方版下载