當前位置:首頁 > 公眾號精選 > 嵌入式大雜燴
[導讀]前陣子一朋友使用單片機與某外設(shè)進行通信時,外設(shè)返回的是一堆格式如下的數(shù)據(jù)。

來源 | 網(wǎng)絡(luò)

前陣子一朋友使用單片機與某外設(shè)進行通信時,外設(shè)返回的是一堆格式如下的數(shù)據(jù):

AA AA 04 80 02 00 02 7B AA AA 04 80 02 00 08 75 AA AA 04 80 02 00 9B E2 AA AA 04 80 02 00 F6 87 AA AA 04 80 02 00 EC 91

其中 AA AA 04 80 02 是數(shù)據(jù)校驗頭,后面三位是有效數(shù)據(jù),問我怎么從外設(shè)不斷返回的數(shù)據(jù)中取出有效的數(shù)據(jù)。

對于這種問題最容易想到的就是使用一個標志位用于標志當前正解析到一幀數(shù)據(jù)的第幾位,然后判斷當前接收的數(shù)據(jù)是否與校驗數(shù)據(jù)一致,如果一致則將標志位加一,否則將標志位置0重新判斷,使用這種方法解析數(shù)據(jù)的代碼如下:

if(flag == 0)
{ if(tempData == 0xAA)
  flag++; else flag = 0;
} else if(flag == 1)
{ if(tempData == 0xAA)
  flag++; else flag = 0;
} else if(flag == 2)
{ if(tempData == 0x04)
  flag++; else flag = 0;
} else if(flag == 3)
{ if(tempData == 0x80)
  flag++; else flag = 0;
} else if(flag == 4)
{ if(tempData == 0x02)
  flag++; else flag = 0;
} else if(flag == 5 || flag == 6 || flag == 7)
{
 data[flag-5] = tempData;
 flag = (flag == 7) ? 0 : flag+1;
}

使用上述方法是最容易想到的也是最簡單的方法了,百度了一下基本上也都是使用類似的方法進行數(shù)據(jù)解析,但是使用這種方法有如下幾個缺點:

1、 大量使用了判斷,容易導致出現(xiàn)邏輯混亂。

2、 代碼重復率高,抽象程度低。從上述代碼可以看到一大堆代碼僅僅是判斷的數(shù)據(jù)不同,其他代碼都完全一致。

3、 代碼可復用性差。寫好的代碼無法用在其他類似的外設(shè)上,如果有多個外設(shè)就需要編寫多份類似的代碼。

4、 可擴展性低。如果外設(shè)還有一個數(shù)據(jù)校驗尾需要校驗或者數(shù)據(jù)校驗頭發(fā)生改變,就需要再次寫多個判斷重新用于校驗,無法在原有的代碼上進行擴展。

5、 容易出現(xiàn)誤判  。

對此,這里提出了一種新的解決方案,可以通用與所有類似的數(shù)據(jù)解析,原理如下:

使用一個固定容量的隊列用來緩存接收到的數(shù)據(jù),隊列容量等于一幀數(shù)據(jù)的大小,每來一個數(shù)據(jù)就將數(shù)據(jù)往隊列里面加,當完整接收到一幀數(shù)據(jù)時此時隊列中的全部數(shù)據(jù)也就是一幀完整的數(shù)據(jù),因此只需要判斷隊列是否是數(shù)據(jù)校驗頭,隊列尾是否是數(shù)據(jù)校驗尾就可以得知當前是否已經(jīng)接收到了一幀完整的數(shù)據(jù),然后在將數(shù)據(jù)從隊列中取出即可。原理圖如下:

每來一個數(shù)據(jù)就往隊列里面加:

當接收到一幀完整數(shù)據(jù)時隊列頭和數(shù)據(jù)校驗頭重合:

此時只需要從隊列中取出有效數(shù)據(jù)即可。

如果有數(shù)據(jù)尾校驗,僅僅只需要添加一個校驗尾即可,如下圖所示:

好,分析結(jié)束,開始編碼。

首先需要一個隊列,為了保證通用性,隊列底層使用類似于雙向鏈表的實現(xiàn)(當然也可以使用數(shù)組實現(xiàn)),需要封裝的結(jié)構(gòu)有隊列容量、隊列大小、隊頭節(jié)點和隊尾節(jié)點,需要實現(xiàn)的操作有隊列初始化、數(shù)據(jù)入隊、數(shù)據(jù)出隊、清空隊列和釋放隊列,具體代碼如下:

/* queue.h */ #ifndef _QUEUE_H_ #define _QUEUE_H_ #ifndef NULL #define NULL ((void *)0) #endif typedef unsigned char uint8; /* 隊列節(jié)點 */ typedef struct Node { uint8 data; struct Node *pre_node; struct Node *next_node; } Node; /* 隊列結(jié)構(gòu) */ typedef struct Queue { uint8 capacity; // 隊列總?cè)萘?/span> uint8 size; // 當前隊列大小 Node *front; // 隊列頭節(jié)點 Node *back; // 隊列尾節(jié)點 } Queue; /* 初始化一個隊列 */ Queue *init_queue(uint8 _capacity); /* 數(shù)據(jù)入隊 */ uint8 en_queue(Queue *_queue, uint8 _data); /* 數(shù)據(jù)出隊 */ uint8 de_queue(Queue *_queue); /* 清空隊列 */ void clear_queue(Queue *_queue); /* 釋放隊列 */ void release_queue(Queue *_queue); #endif 
/* queue.c */ #include  #include "parser.h" /**
 * 初始化一個隊列
 *
 * @_capacity: 隊列總?cè)萘?
 */ Queue *init_queue(uint8 _capacity) {
 Queue *queue = (Queue *)malloc(sizeof(Queue)); queue->capacity = _capacity; queue->size = 0; return queue;
} /**
 * 數(shù)據(jù)入隊
 *
 * @_queue: 隊列
 * @_data: 數(shù)據(jù)
 **/ uint8 en_queue(Queue *_queue, uint8 _data) { if(_queue->size < _queue->capacity)
 {
  Node *node = (Node *)malloc(sizeof(Node));
  node->data = _data;
  node->next_node = NULL; if(_queue->size == 0)
        {
            node->pre_node = NULL;
            _queue->back = node;
            _queue->front = _queue->back;
        } else {
            node->pre_node = _queue->back;
 
            _queue->back->next_node = node;
            _queue->back = _queue->back->next_node;
        }
  _queue->size++;
 } else {
  Node *temp_node = _queue->front->next_node;
  _queue->front->pre_node = _queue->back;
  _queue->back->next_node = _queue->front;
  _queue->back = _queue->back->next_node;
  _queue->back->data = _data;
  _queue->back->next_node = NULL;
  _queue->front = temp_node;
 } return _queue->size-1;
} /**
 * 數(shù)據(jù)出隊
 *
 * @_queue: 隊列
 *
 * @return: 出隊的數(shù)據(jù)
 */ uint8 de_queue(Queue *_queue) {
    uint8 old_data = 0; if(_queue->size > 0)
    {
        old_data = _queue->front->data; if(_queue->size == 1)
        { free(_queue->front);
            _queue->front = NULL;
            _queue->back = NULL;
        } else {
            _queue->front = _queue->front->next_node; free(_queue->front->pre_node);
            _queue->front->pre_node = NULL;
        }
        _queue->size--;
    } return old_data;
} /**
 * 清空隊列
 *
 * @_queue: 隊列
 */ void clear_queue(Queue *_queue) { while(_queue->size > 0)
    {
        de_queue(_queue);
    }
} /**
 * 釋放隊列
 *
 * @_queue: 隊列
 */ void release_queue(Queue *_queue) {
    clear_queue(_queue); free(_queue);
    _queue = NULL;
}

其次是解析器,需要封裝的結(jié)構(gòu)有解析數(shù)據(jù)隊列、數(shù)據(jù)校驗頭、數(shù)據(jù)校驗尾、解析結(jié)果以及指向解析結(jié)果的指針,需要實現(xiàn)的操作有解析器初始化、添加數(shù)據(jù)解析、獲取解析結(jié)果、重置解析器和釋放解析器,具體代碼如下:

/* parser.h */ #ifndef _PARSER_H_ #define _PARSER_H_ #include "queue.h" typedef enum {
    RESULT_FALSE,
    RESULT_TRUE
} ParserResult; /* 解析器結(jié)構(gòu) */ typedef struct DataParser { Queue *parser_queue; // 數(shù)據(jù)解析隊列 Node *resule_pointer; // 解析結(jié)果數(shù)據(jù)指針 uint8 *data_header; // 數(shù)據(jù)校驗頭指針 uint8 header_size; // 數(shù)據(jù)校驗頭大小 uint8 *data_footer; // 數(shù)據(jù)校驗尾指針 uint8 footer_size; // 數(shù)據(jù)校驗尾大小 uint8 result_size; // 解析數(shù)據(jù)大小 ParserResult parserResult; // 解析結(jié)果 } DataParser; /* 初始化一個解析器 */ DataParser *parser_init(uint8 *_data_header, uint8 _header_size, uint8 *_data_footer, uint8 _foot_size, uint8 _data_frame_size); /* 將數(shù)據(jù)添加到解析器中進行解析 */ ParserResult parser_put_data(DataParser *_parser, uint8 _data); /* 解析成功后從解析器中取出解析結(jié)果 */ int parser_get_data(DataParser *_parser, uint8 _index); /* 重置解析器 */ void parser_reset(DataParser *_parser); /* 釋放解析器 */ void parser_release(DataParser *_parser); #endif 
/* parser.c */ #include  #include "parser.h" /**
 * 初始化一個解析器
 *
 * @_data_header: 數(shù)據(jù)頭指針
 * @_header_size: 數(shù)據(jù)頭大小
 * @_data_footer: 數(shù)據(jù)尾指針
 * @_foot_size: 數(shù)據(jù)尾大小
 * @_data_frame_size: 一幀完整數(shù)據(jù)的大小
 *
 * @return: 解析器
 */ DataParser *parser_init(uint8 *_data_header, uint8 _header_size, uint8 *_data_footer, uint8 _foot_size, uint8 _data_frame_size) { if((_header_size+_foot_size) > _data_frame_size || (_header_size+_foot_size) == 0) return NULL;
 
    DataParser *parser = (DataParser *)malloc(sizeof(DataParser));
    parser->parser_queue = init_queue(_data_frame_size);
    parser->resule_pointer = NULL;
    parser->data_header = _data_header;
    parser->header_size = _header_size;
 parser->data_footer = _data_footer;
 parser->footer_size = _foot_size;
    parser->result_size = _data_frame_size - parser->header_size - parser->footer_size;
    parser->parserResult = RESULT_FALSE; while(_data_frame_size-- > 0)
    {
        en_queue(parser->parser_queue, 0);
    } return parser;
} /**
 * 將數(shù)據(jù)添加到解析器中進行解析
 *
 * @_parser: 解析器
 * @_data: 要解析的數(shù)據(jù)
 *
 * @return: 當前解析結(jié)果,返回 RESULT_TRUE 代表成功解析出一幀數(shù)據(jù)
 */ ParserResult parser_put_data(DataParser *_parser, uint8 _data) {
    uint8 i;
    Node *node; if(_parser == NULL) return RESULT_FALSE;
 
    en_queue(_parser->parser_queue, _data); /* 校驗數(shù)據(jù)尾 */ node = _parser->parser_queue->back; for(i = _parser->footer_size; i > 0; i--)
 { if(node->data != _parser->data_footer[i-1]) goto DATA_FRAME_FALSE;
        node = node->pre_node;
 } /* 校驗數(shù)據(jù)頭 */ node = _parser->parser_queue->front; for(i = 0; i < _parser->header_size; i++)
    { if(node->data != _parser->data_header[i]) goto DATA_FRAME_FALSE;
        node = node->next_node;
    } if(_parser->resule_pointer == NULL && _parser->result_size > 0)
        _parser->resule_pointer = node; if(_parser->parserResult != RESULT_TRUE)
     _parser->parserResult = RESULT_TRUE; return _parser->parserResult;
 
DATA_FRAME_FALSE: if(_parser->resule_pointer != NULL)
        _parser->resule_pointer = NULL; if(_parser->parserResult != RESULT_FALSE)
        _parser->parserResult = RESULT_FALSE; return _parser->parserResult;
 
} /**
 * 解析成功后從解析器中取出解析結(jié)果
 *
 * @_parser: 解析器
 * @_index: 解析結(jié)果集合中的第 _index 個數(shù)據(jù)
 *
 * @return: 獲取解析成功的數(shù)據(jù),返回 -1 代表數(shù)據(jù)獲取失敗
 */ int parser_get_data(DataParser *_parser, uint8 _index) {
    Node *node; if(_parser == NULL || _parser->parserResult != RESULT_TRUE
    || _index >= _parser->result_size
    || _parser->resule_pointer == NULL) return -1;
    node = _parser->resule_pointer; while(_index > 0)
    {
        node = node->next_node;
        _index--;
    } return node->data;
} /**
 * 重置解析器
 *
 * @_parser: 解析器
 */ void parser_reset(DataParser *_parser) {
 uint8 _data_frame_size; if(_parser == NULL) return;
 
 _data_frame_size = _parser->parser_queue->size; while(_data_frame_size-- > 0)
    {
        en_queue(_parser->parser_queue, 0);
    }
    _parser->resule_pointer = NULL;
    _parser->parserResult = RESULT_FALSE;
} /**
 * 釋放解析器
 *
 * @_parser: 解析器
 */ void parser_release(DataParser *_parser) { if(_parser == NULL) return;
    release_queue(_parser->parser_queue); free(_parser);
    _parser = NULL;
}

接下來編寫測試代碼測試一下:

/* main.c */ #include  #include "parser.h" int main() {
    uint8 i; // 數(shù)據(jù)頭 uint8 data_header[] = {0xAA, 0xAA, 0x04, 0x80, 0x02}; // 要解析的數(shù)據(jù),測試用 uint8 data[] = { 0xAA, 0xAA, 0x04, 0x80, 0x02, 0x00, 0x02, 0x7B, 0xAA, 0xAA, 0x04, 0x80, 0x02, 0x00, 0x08, 0x75, 0xAA, 0xAA, 0x04, 0x80, 0x02, 0x00, 0x9B, 0xE2, 0xAA, 0xAA, 0x04, 0x80, 0x02, 0x00, 0xF6, 0x87, 0xAA, 0xAA, 0x04, 0x80, 0x02, 0x00, 0xEC, 0x91, 0xAA, 0xAA, 0x04, 0x80, 0x02, 0x01, 0x15, 0x67, 0xAA, 0xAA, 0x04, 0x80, 0x02, 0x01, 0x49, 0x33, 0xAA, 0xAA, 0x04, 0x80, 0x02, 0x00, 0xE7, 0x96, 0xAA, 0xAA, 0x04, 0x80, 0x02, 0x00, 0x68, 0x15, 0xAA, 0xAA, 0x04, 0x80, 0x02, 0x00, 0x3C, 0x41, 0xAA, 0xAA, 0x04, 0x80, 0x02, 0x00, 0x66, 0x17, 0xAA, 0xAA, 0x04, 0x80, 0x02, 0x00, 0xA5, 0xD8, 0xAA, 0xAA, 0x04, 0x80, 0x02, 0x01, 0x26, 0x56, 0xAA, 0xAA, 0x04, 0x80, 0x02, 0x01, 0x73, 0x09, 0xAA, 0xAA, 0x04, 0x80, 0x02, 0x01, 0x64, 0x18, 0xAA, 0xAA, 0x04, 0x80, 0x02, 0x01, 0x8B, 0xF1, 0xAA, 0xAA, 0x04, 0x80, 0x02, 0x01, 0xC6, 0xB6, 0xAA, 0xAA, 0x04, 0x80, 0x02, 0x01, 0x7B, 0x01, 0xAA, 0xAA, 0x04, 0x80, 0x02, 0x00, 0xCB, 0xB2, 0xAA, 0xAA, 0x04, 0x80, 0x02, 0x00, 0x2C, 0x51, 0xAA, 0xAA, 0x04, 0x80, 0x02, 0xFF, 0xE5, 0x99 }; /**
     * 初始化一個解析器
     * 第一個參數(shù)是數(shù)據(jù)頭
     * 第二個參數(shù)是數(shù)據(jù)頭長度
     * 第三個參數(shù)是數(shù)據(jù)尾指針
     * 第四個參數(shù)是數(shù)據(jù)尾大小
     * 第五個參數(shù)是一整幀數(shù)據(jù)的大小
     */ DataParser *data_parser = parser_init(data_header, sizeof(data_header), NULL, 0, 8); // 將要解析的數(shù)據(jù)逐個取出,添加到解析器中 for(i = 0; i < sizeof(data); i++)
    { // 解析數(shù)據(jù),返回 RESULT_TRUE 代表成功解析出一組數(shù)據(jù) if(parser_put_data(data_parser, data[i]) == RESULT_TRUE)
        { printf("成功解析出一幀數(shù)據(jù)...\n"); /* 一位一位取出解析后的數(shù)據(jù) */ printf("第一個數(shù)據(jù)是:0x%x\n", parser_get_data(data_parser, 0)); printf("第二個數(shù)據(jù)是:0x%x\n", parser_get_data(data_parser, 1)); printf("第三個數(shù)據(jù)是:0x%x\n\n\n", parser_get_data(data_parser, 2));
        }
    } // 當不再需要解析器時,應該把解析器釋放掉,回收內(nèi)存,避免造成內(nèi)存泄漏 parser_release(data_parser); return 0;
}

測試結(jié)果如下:

從上面可以看出,解析的結(jié)果與目標一致。

github地址:

https://github.com/528787067/DataFrameParser

免責聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關(guān)機構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫毥谦F公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務能7×24不間斷運行,同時企業(yè)卻面臨越來越多業(yè)務中斷的風險,如企業(yè)系統(tǒng)復雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會上,華為常務董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機 衛(wèi)星通信

要點: 有效應對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅持高質(zhì)量發(fā)展策略,塑強核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運營商 數(shù)字經(jīng)濟

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術(shù)學會聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(shù)(集團)股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉