• 
    

    
    

      99热精品在线国产_美女午夜性视频免费_国产精品国产高清国产av_av欧美777_自拍偷自拍亚洲精品老妇_亚洲熟女精品中文字幕_www日本黄色视频网_国产精品野战在线观看 ?

      一種基于SLIP 協(xié)議的串行數(shù)據(jù)解析方法

      2019-07-22 07:37:58李逸楠孫麗君所玉君
      科技與創(chuàng)新 2019年12期
      關(guān)鍵詞:鏈表字符解碼

      李逸楠,孫麗君,王 欣,所玉君

      (1.天津津航計算技術(shù)研究所,天津 300308;2.天津市航空電子綜合顯示控制重點實驗室,天津 300308;3.天津航海技術(shù)研究所,天津 300131)

      1 背景

      在嵌入式系統(tǒng)中,分系統(tǒng)間最常用的數(shù)據(jù)傳輸方式是采用各種串口進(jìn)行通訊,比如RS232/RS422/RS485等[1-3]。拋開底層硬件設(shè)計的不同,通常在鏈路層通過一些協(xié)議來保證發(fā)送方與接收方數(shù)據(jù)的一致性。

      SLIP協(xié)議是一種常用的鏈路層通訊協(xié)議,規(guī)定了幀頭、幀尾、在幀頭幀尾之間如果出現(xiàn)幀頭或幀尾字符,則按照一定的規(guī)則進(jìn)行替換,保證發(fā)送方在幀頭幀尾間不會出現(xiàn)幀頭幀尾對應(yīng)的字符[4];接收方收到數(shù)據(jù)后,也需要按照幀頭幀尾把數(shù)據(jù)解析出來,再按照替換規(guī)則把有效數(shù)據(jù)還原。這時得到的數(shù)據(jù)就可以按照上層協(xié)議進(jìn)一步解析,得到有意義的數(shù)據(jù)。不同的項目有具體的上層協(xié)議,解析的方法不盡相同,但基本思路是一致的。本文涉及到的協(xié)議及硬件可返回的數(shù)據(jù)如下。

      1.1 SLIP協(xié)議

      以0xc0為幀頭,0xc0為幀尾,幀頭幀尾間如果出現(xiàn)0xc0,則以連續(xù)兩個字符0xdb和0xdc取代;如果幀頭幀尾間出現(xiàn)0xdb,那么就用連續(xù)兩個字符0xdb和0xdd替代;接收方也按照這個規(guī)則還原接收到的數(shù)據(jù)。

      1.2 上層協(xié)議

      經(jīng)SLIP協(xié)議解析后的數(shù)據(jù)為一個完整的數(shù)據(jù)幀,格式如表1所示。

      表1 消息幀格式

      1.3 可從硬件獲取的信息

      UINT16 ReciveCοunt:自硬件上電以來收取到的所有字符數(shù),數(shù)據(jù)類型為UINT16,無符號的16位整型。

      UINT8 DataRev[2048]:數(shù)據(jù)接收緩存,硬件接收到數(shù)據(jù)之后會按順序記錄在緩存中,最多可存放2 048個字節(jié),當(dāng)超過2 048個字節(jié),新數(shù)據(jù)從頭開始存放。

      2 需求分析

      根據(jù)背景說明,可以分析出數(shù)據(jù)解析具體需求有以下幾點:①需要根據(jù)硬件提供的信息計算出每周期接收到的新數(shù)據(jù)個數(shù),并從數(shù)據(jù)緩存中取出新數(shù)據(jù);②需要按照SLIP協(xié)議解析出原始數(shù)據(jù),并將接收方回復(fù)的數(shù)據(jù)按照SLIP協(xié)議處理后發(fā)送;③如果一個周期內(nèi)未接收到一個完整的數(shù)據(jù)幀,需要將不完整的數(shù)據(jù)幀存儲起來,待下一個周期接收到數(shù)據(jù)之后,進(jìn)行數(shù)據(jù)拼接,保證數(shù)據(jù)的完整性;④需要將解析出的原始數(shù)據(jù)整理為上述數(shù)據(jù)幀格式。一個周期內(nèi)如果有多條數(shù)據(jù)幀,則都需要保存起來。

      3 模塊設(shè)計

      按照上述需求分析,采用模塊化的設(shè)計思想設(shè)計出以下幾個軟件模塊。數(shù)據(jù)解析過程的總流程如圖1所示。

      3.1 不完整數(shù)據(jù)保存模塊Save422Data()

      該模塊用來判斷一個周期內(nèi)收取到的數(shù)據(jù)中是否存在不完整的數(shù)據(jù)幀,如果存在,則給出需要保存的數(shù)據(jù)個數(shù),并將需保存的數(shù)據(jù)存儲在全局?jǐn)?shù)組中。算法的關(guān)鍵是如何判斷是否存在不完整的數(shù)據(jù)幀。本文采用的方法如下:判斷接收到的數(shù)據(jù)中最后一個c0是否就是本次接收到的最后一個數(shù)據(jù),如果是,說明本次接收的是一幀完整的數(shù)據(jù);如果最后一個c0不是最后一個數(shù)據(jù),說明本次接收到了不完整的數(shù)據(jù),需要將最后一個c0之后的數(shù)據(jù)保存起來。

      需要特別注意的是,主要有以下兩種情況需要單獨處理:①本周期內(nèi)就只收到了一個數(shù)據(jù),而這個數(shù)據(jù)恰好就是c0。如果按照之前的條件判斷,不會把這單獨的c0認(rèn)為是一個不完整的數(shù)據(jù)幀,就不會保存這個c0,導(dǎo)致下一周期收取的數(shù)據(jù)沒有幀頭或幀尾,解析數(shù)據(jù)就會出錯。正確的做法是遇到僅有一個c0的情況,要把這個c0保存起來,在下一周期拼接在收到數(shù)據(jù)之前。②收到數(shù)據(jù)不止一個,且最后一個c0確實也是本周期收到數(shù)據(jù)的最后一個,但這個c0之前還是個c0。如果按照最開始的條件判斷,會誤認(rèn)為這是一幀完整的數(shù)據(jù),而事實上,連著的兩個c0前者是上一幀數(shù)據(jù)的結(jié)尾,后者是下一幀數(shù)據(jù)的開頭。正確的做法是當(dāng)遇到最后一個c0就是最后一個數(shù)據(jù)的情況,還需要額外判斷這個c0之前是否是c0。如果不是,則說明確實是完整的數(shù)據(jù),無需保存數(shù)據(jù);如果是,則說明恰好收到了下一幀數(shù)據(jù)的開頭,需要把這個c0保存起來,在下一周期拼接在收到數(shù)據(jù)之前。經(jīng)過以上分情況處理,就可以保證不會漏掉一幀不完整的數(shù)據(jù)。程序控制流如圖2所示。

      圖1 數(shù)據(jù)解析過程

      3.2 底層收數(shù)模塊px_422recive()

      該模塊負(fù)責(zé)判斷何時有新數(shù)據(jù)傳來,并從硬件緩存中取出新數(shù)據(jù)。基本思路是設(shè)計兩個全局變量,一個用來存放當(dāng)前周期的ReciveCοunt值(num),一個用來存放上一個周期的ReciveCοunt值(numοld)。如果當(dāng)前值等于上周期值,則表明無新數(shù)據(jù)傳來,如果當(dāng)前值大于上周期值,則表明有新數(shù)據(jù),需要從硬件內(nèi)存中取出數(shù)據(jù)。新數(shù)據(jù)為從DataRev[numοld]開始到 DataRev[numοld+(num-numοld-1)]的數(shù)據(jù)。上述規(guī)律在ReciveCοunt小于2 048個數(shù)據(jù)時成立;當(dāng)ReciveCοunt大于2 048個數(shù)據(jù)時,新數(shù)據(jù)將保存在緩存區(qū)的開頭,這時情況稍顯復(fù)雜。因為物理內(nèi)存只有2 048 Byte,首先應(yīng)將ReciveCοunt值對2 048取余,這樣就將ReciveCοunt換為2 048以內(nèi)的數(shù)值。則一旦數(shù)據(jù)超過2 048從頭開始時,前述取數(shù)規(guī)律又可以使用。需要分情況討論的就只剩上一周期數(shù)據(jù)(numοld)小于2 048,而當(dāng)前周期數(shù)據(jù)大于2 048的情況了。由于取余處理,當(dāng)前周期的ReciveCοunt實際值為余數(shù)(num),如果一個周期數(shù)據(jù)量不超過2 048個,則一定有num小于numοld。此條件可作為特殊情況的判斷條件,這時新數(shù)據(jù)應(yīng)該是內(nèi)存尾部DataRev[numοld]開始到DataRev[numοld+(2048-numοld-1)]的數(shù)據(jù)與內(nèi)存頭部DataRev[0]開始到DataRev[num-1]的數(shù)據(jù)拼接而成。程序控制流程如圖3所示。

      圖2 不完整數(shù)據(jù)保存模塊控制流程圖

      3.3 鏈表數(shù)據(jù)插入模塊ListInsert()

      在SLIP協(xié)議解析過程中,需要根據(jù)規(guī)則,在數(shù)據(jù)中指定位置插入特定的數(shù)據(jù)。例如“如果幀頭幀尾間出現(xiàn)0xdb,那么就用連續(xù)兩個字符0xdb和0xdd替代”這一條規(guī)則其實就是在0xdb之后插入一個0xdd。為滿足這個需求,設(shè)計了一種鏈表類型結(jié)構(gòu)體,結(jié)構(gòu)體設(shè)計如下:

      typedef struct

      {

      UINT8RevBuf[MAXSIZE];

      int charnum;

      }SqList;

      該結(jié)構(gòu)體由一個字符數(shù)組和一個整型變量組成,字符數(shù)組用來存放消息數(shù)據(jù),整型變量用來存放消息包含的字符個數(shù),MAXSIZE為數(shù)據(jù)最大長度,由實際傳輸數(shù)據(jù)最大長度確定。

      鏈表數(shù)據(jù)插入模塊的操作對象就是這種鏈表數(shù)據(jù),輸入一個待操作的鏈表,待插入的數(shù)據(jù),以及插入的位置,鏈表數(shù)據(jù)插入模塊輸出插入數(shù)據(jù)之后的鏈表,并自動更新數(shù)據(jù)長度。程序控制流如圖4所示。

      圖3 底層收數(shù)模塊程序流程

      3.4 鏈表數(shù)據(jù)刪除模塊ListDelete()

      在SLIP協(xié)議解析過程中,需要根據(jù)規(guī)則,刪除數(shù)據(jù)中指定位置的數(shù)據(jù)。例如“幀頭幀尾間如果出現(xiàn)0xc0,則以連續(xù)兩個字符0xdb和0xdc取代”這條規(guī)則需要刪掉不是幀頭幀尾的0xc0,然后利用上一小節(jié)設(shè)計的鏈表數(shù)據(jù)插入模塊在刪掉的位置依次插入0xdc,0xdb。刪除指定位置數(shù)據(jù)之后,其后數(shù)據(jù)依次向前移動一位,并讓數(shù)據(jù)長度減1。程序控制流如圖5所示。

      3.5 協(xié)議解碼模塊Decode422data()

      協(xié)議解碼模塊的輸入為兩個,一是待解碼的數(shù)據(jù)長度,二是待解碼的數(shù)據(jù)緩存區(qū);輸出為消息幀結(jié)構(gòu)體數(shù)組,返回值為解析出的消息個數(shù)。簡單介紹輸出的消息幀結(jié)構(gòu)體為:

      typedef struct

      {

      UINT16 DataID;

      UINT16 DataLen;

      UINT8 DataItem[80];

      UINT16 CheckSum;

      }MessageRev;

      該結(jié)構(gòu)體與表1所述數(shù)據(jù)幀結(jié)構(gòu)一致,DataID代表數(shù)據(jù)ID,DataLen代表數(shù)據(jù)長度,DataItem[80]代表有物理意義的數(shù)據(jù)內(nèi)容(假設(shè)數(shù)據(jù)內(nèi)容不會超過80個字符),CheckSum表示校驗和。假設(shè)一個周期內(nèi)傳來的消息不會超過10幀,則需創(chuàng)建一個可存儲10幀消息的結(jié)構(gòu)體數(shù)組MessageRev Message[10]。

      圖4 鏈表數(shù)據(jù)插入模塊

      圖5 鏈表數(shù)據(jù)刪除模塊

      解碼主要分為三個步驟:①從待解碼的數(shù)據(jù)緩存區(qū)中把兩個c0之間的數(shù)據(jù)取出,存放在上述鏈表結(jié)構(gòu)中,同時記錄好數(shù)據(jù)長度,并記錄下解析出的消息幀條數(shù);②如果解析出消息幀條數(shù)大于0,就按照SLIP協(xié)議的規(guī)則,把每一條消息幀中該刪除的刪掉,該插入的插入,得到解析后的數(shù)據(jù)幀;③從解析好的數(shù)據(jù)中提取出MessageRev結(jié)構(gòu)體所需的各變量,按順序存放在Message[10]結(jié)構(gòu)體數(shù)組中,有幾幀消息就占用數(shù)組中的前幾個;返回消息幀條數(shù),這樣就把原始數(shù)據(jù)解析為可以直接用來判斷處理的上層協(xié)議幀格式。

      程序流程如圖6所示。

      圖6 協(xié)議解碼模塊

      3.6 協(xié)議編碼模塊Incode422data()

      待發(fā)送數(shù)據(jù)需要根據(jù)SLIP協(xié)議要求進(jìn)行編碼,調(diào)用ListDelete模塊將需要替換的字符刪除,調(diào)用ListInsert模塊插入規(guī)定的字符。全部替換完畢后,調(diào)用ListInsert模塊在待發(fā)送數(shù)據(jù)開始和結(jié)尾分別插入0xc0,完成數(shù)據(jù)的SLIP協(xié)議編碼。具體流程如圖7所示。

      圖7 協(xié)議編碼模塊

      4 實驗及結(jié)果

      首先測試底層接收數(shù)據(jù)功能是否正確,測試設(shè)備通過232串口向本設(shè)備發(fā)送數(shù)據(jù),波特率460.8 Kbps,測試設(shè)備向本設(shè)備發(fā)送1 247 030個字節(jié),在本設(shè)備讀取記錄的接收字節(jié)數(shù)也是1 247 030,說明基本的接收數(shù)據(jù)功能正常。

      測試設(shè)備接著向本設(shè)備發(fā)送不同類型的數(shù)據(jù),包括周期性數(shù)據(jù)與事件性數(shù)據(jù),不同消息幀發(fā)送與接收到的幀計數(shù)如表2所示。

      表2 消息幀解析實驗結(jié)果

      根據(jù)實驗結(jié)果可以看到,周期性消息不同ID的數(shù)據(jù)幀接收到的個數(shù)是一致的,且發(fā)送與接收到的幀計數(shù)相同,說明周期性數(shù)據(jù)幀接收與解析功能正確。在周期性數(shù)據(jù)發(fā)送過程中中隨機(jī)的發(fā)送事件性消息,可以看到發(fā)送幀計數(shù)與接收幀計數(shù)相同,說明隨機(jī)的事件性數(shù)據(jù)幀也可以完整接收并解析出來。具體的幀內(nèi)容,如果消息ID解析正確,則容易根據(jù)項目協(xié)議解析出來,不再贅述。

      5 結(jié)論

      本文給出了一種基于SLIP協(xié)議的串行數(shù)據(jù)解析方法,對解析過程中的各個模塊進(jìn)行了詳細(xì)描述。特別描述了數(shù)據(jù)幀不完整情況下數(shù)據(jù)的存儲與拼接方法。將各個模塊集成為完整的數(shù)據(jù)解析軟件并經(jīng)過大量數(shù)據(jù)測試,結(jié)果表明數(shù)據(jù)接收無丟數(shù)現(xiàn)象,數(shù)據(jù)幀解析完整,不論周期性數(shù)據(jù)和事件性數(shù)據(jù)均無丟幀現(xiàn)象。本方法可適用于大多數(shù)串行通訊過程,具有適用面廣、解析方法簡單可靠之優(yōu)點。

      猜你喜歡
      鏈表字符解碼
      《解碼萬噸站》
      尋找更強(qiáng)的字符映射管理器
      字符代表幾
      解碼eUCP2.0
      中國外匯(2019年19期)2019-11-26 00:57:32
      一種USB接口字符液晶控制器設(shè)計
      電子制作(2019年19期)2019-11-23 08:41:50
      基于二進(jìn)制鏈表的粗糙集屬性約簡
      跟麥咭學(xué)編程
      NAD C368解碼/放大器一體機(jī)
      Quad(國都)Vena解碼/放大器一體機(jī)
      消失的殖民村莊和神秘字符
      洞口县| 招远市| 泰州市| 哈尔滨市| 扎赉特旗| 大城县| 尤溪县| 鹰潭市| 泾阳县| 土默特右旗| 定边县| 宣武区| 乐安县| 开化县| 龙游县| 都江堰市| 三江| 成武县| 泰宁县| 阳高县| 盖州市| 公主岭市| 瑞丽市| 南和县| 四子王旗| 沧州市| 桑植县| 昌乐县| 通城县| 临猗县| 九寨沟县| 阜城县| 福建省| 吉木乃县| 嵩明县| 迭部县| 体育| 长治市| 汕头市| 淳化县| 承德市|