正文
前陣子一朋友使用單片機(jī)與某外設(shè)進(jìn)行通信時(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ù)校驗(yàn)頭,后面三位是有效數(shù)據(jù),問我怎么從外設(shè)不斷返回的數(shù)據(jù)中取出有效的數(shù)據(jù)。 對(duì)于這種問題最容易想到的就是使用一個(gè)標(biāo)志位用于標(biāo)志當(dāng)前正解析到一幀數(shù)據(jù)的第幾位,然后判斷當(dāng)前接收的數(shù)據(jù)是否與校驗(yàn)數(shù)據(jù)一致,如果一致則將標(biāo)志位加一,否則將標(biāo)志位置0重新判斷,使用這種方法解析數(shù)據(jù)的代碼如下:
if(flag==0) { if(tempData==0xAA) flag++; else flag=0; } elseif(flag==1) { if(tempData==0xAA) flag++; else flag=0; } elseif(flag==2) { if(tempData==0x04) flag++; else flag=0; } elseif(flag==3) { if(tempData==0x80) flag++; else flag=0; } elseif(flag==4) { if(tempData==0x02) flag++; else flag=0; } elseif(flag==5||flag==6||flag==7) { data[flag-5]=tempData; flag=(flag==7)?0:flag+1; }使用上述方法是最容易想到的也是最簡單的方法了,百度了一下基本上也都是使用類似的方法進(jìn)行數(shù)據(jù)解析,但是使用這種方法有如下幾個(gè)缺點(diǎn):
1、 大量使用了判斷,容易導(dǎo)致出現(xiàn)邏輯混亂。
2、 代碼重復(fù)率高,抽象程度低。從上述代碼可以看到一大堆代碼僅僅是判斷的數(shù)據(jù)不同,其他代碼都完全一致。
3、 代碼可復(fù)用性差。寫好的代碼無法用在其他類似的外設(shè)上,如果有多個(gè)外設(shè)就需要編寫多份類似的代碼。
4、 可擴(kuò)展性低。如果外設(shè)還有一個(gè)數(shù)據(jù)校驗(yàn)尾需要校驗(yàn)或者數(shù)據(jù)校驗(yàn)頭發(fā)生改變,就需要再次寫多個(gè)判斷重新用于校驗(yàn),無法在原有的代碼上進(jìn)行擴(kuò)展。
5、 容易出現(xiàn)誤判 。
對(duì)此,這里提出了一種新的解決方案,可以通用與所有類似的數(shù)據(jù)解析,原理如下: 使用一個(gè)固定容量的隊(duì)列用來緩存接收到的數(shù)據(jù),隊(duì)列容量等于一幀數(shù)據(jù)的大小,每來一個(gè)數(shù)據(jù)就將數(shù)據(jù)往隊(duì)列里面加,當(dāng)完整接收到一幀數(shù)據(jù)時(shí)此時(shí)隊(duì)列中的全部數(shù)據(jù)也就是一幀完整的數(shù)據(jù),因此只需要判斷隊(duì)列是否是數(shù)據(jù)校驗(yàn)頭,隊(duì)列尾是否是數(shù)據(jù)校驗(yàn)尾就可以得知當(dāng)前是否已經(jīng)接收到了一幀完整的數(shù)據(jù),然后在將數(shù)據(jù)從隊(duì)列中取出即可。原理圖如下: 每來一個(gè)數(shù)據(jù)就往隊(duì)列里面加:
當(dāng)接收到一幀完整數(shù)據(jù)時(shí)隊(duì)列頭和數(shù)據(jù)校驗(yàn)頭重合:
此時(shí)只需要從隊(duì)列中取出有效數(shù)據(jù)即可。 如果有數(shù)據(jù)尾校驗(yàn),僅僅只需要添加一個(gè)校驗(yàn)尾即可,如下圖所示:
好,分析結(jié)束,開始編碼。 首先需要一個(gè)隊(duì)列,為了保證通用性,隊(duì)列底層使用類似于雙向鏈表的實(shí)現(xiàn)(當(dāng)然也可以使用數(shù)組實(shí)現(xiàn)),需要封裝的結(jié)構(gòu)有隊(duì)列容量、隊(duì)列大小、隊(duì)頭節(jié)點(diǎn)和隊(duì)尾節(jié)點(diǎn),需要實(shí)現(xiàn)的操作有隊(duì)列初始化、數(shù)據(jù)入隊(duì)、數(shù)據(jù)出隊(duì)、清空隊(duì)列和釋放隊(duì)列,具體代碼如下:
/*queue.h*/ #ifndef_QUEUE_H_ #define_QUEUE_H_ #ifndefNULL #defineNULL((void*)0) #endif typedefunsignedcharuint8; /*隊(duì)列節(jié)點(diǎn)*/ typedefstructNode { uint8data; structNode*pre_node; structNode*next_node; }Node; /*隊(duì)列結(jié)構(gòu)*/ typedefstructQueue { uint8capacity;//隊(duì)列總?cè)萘?uint8size;//當(dāng)前隊(duì)列大小 Node*front;//隊(duì)列頭節(jié)點(diǎn) Node*back;//隊(duì)列尾節(jié)點(diǎn) }Queue; /*初始化一個(gè)隊(duì)列*/ Queue*init_queue(uint8_capacity); /*數(shù)據(jù)入隊(duì)*/ uint8en_queue(Queue*_queue,uint8_data); /*數(shù)據(jù)出隊(duì)*/ uint8de_queue(Queue*_queue); /*清空隊(duì)列*/ voidclear_queue(Queue*_queue); /*釋放隊(duì)列*/ voidrelease_queue(Queue*_queue); #endif
/*queue.c*/ #include#include"parser.h" /** *初始化一個(gè)隊(duì)列 * *@_capacity:隊(duì)列總?cè)萘?*/ Queue*init_queue(uint8_capacity) { Queue*queue=(Queue*)malloc(sizeof(Queue)); queue->capacity=_capacity; queue->size=0; returnqueue; } /** *數(shù)據(jù)入隊(duì) * *@_queue:隊(duì)列 *@_data:數(shù)據(jù) **/ uint8en_queue(Queue*_queue,uint8_data) { if(_queue->sizecapacity) { 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ù)出隊(duì) * *@_queue:隊(duì)列 * *@return:出隊(duì)的數(shù)據(jù) */ uint8de_queue(Queue*_queue) { uint8old_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--; } returnold_data; } /** *清空隊(duì)列 * *@_queue:隊(duì)列 */ voidclear_queue(Queue*_queue) { while(_queue->size>0) { de_queue(_queue); } } /** *釋放隊(duì)列 * *@_queue:隊(duì)列 */ voidrelease_queue(Queue*_queue) { clear_queue(_queue); free(_queue); _queue=NULL; }
其次是解析器,需要封裝的結(jié)構(gòu)有解析數(shù)據(jù)隊(duì)列、數(shù)據(jù)校驗(yàn)頭、數(shù)據(jù)校驗(yàn)尾、解析結(jié)果以及指向解析結(jié)果的指針,需要實(shí)現(xiàn)的操作有解析器初始化、添加數(shù)據(jù)解析、獲取解析結(jié)果、重置解析器和釋放解析器,具體代碼如下:
/*parser.h*/ #ifndef_PARSER_H_ #define_PARSER_H_ #include"queue.h" typedefenum { RESULT_FALSE, RESULT_TRUE }ParserResult; /*解析器結(jié)構(gòu)*/ typedefstructDataParser { Queue*parser_queue;//數(shù)據(jù)解析隊(duì)列 Node*resule_pointer;//解析結(jié)果數(shù)據(jù)指針 uint8*data_header;//數(shù)據(jù)校驗(yàn)頭指針 uint8header_size;//數(shù)據(jù)校驗(yàn)頭大小 uint8*data_footer;//數(shù)據(jù)校驗(yàn)尾指針 uint8footer_size;//數(shù)據(jù)校驗(yàn)尾大小 uint8result_size;//解析數(shù)據(jù)大小 ParserResultparserResult;//解析結(jié)果 }DataParser; /*初始化一個(gè)解析器*/ DataParser*parser_init(uint8*_data_header,uint8_header_size,uint8*_data_footer,uint8_foot_size,uint8_data_frame_size); /*將數(shù)據(jù)添加到解析器中進(jìn)行解析*/ ParserResultparser_put_data(DataParser*_parser,uint8_data); /*解析成功后從解析器中取出解析結(jié)果*/ intparser_get_data(DataParser*_parser,uint8_index); /*重置解析器*/ voidparser_reset(DataParser*_parser); /*釋放解析器*/ voidparser_release(DataParser*_parser); #endif
/*parser.c*/ #include接下來編寫測試代碼測試一下:#include"parser.h" /** *初始化一個(gè)解析器 * *@_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) returnNULL; 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); } returnparser; } /** *將數(shù)據(jù)添加到解析器中進(jìn)行解析 * *@_parser:解析器 *@_data:要解析的數(shù)據(jù) * *@return:當(dāng)前解析結(jié)果,返回RESULT_TRUE代表成功解析出一幀數(shù)據(jù) */ ParserResultparser_put_data(DataParser*_parser,uint8_data) { uint8i; Node*node; if(_parser==NULL) returnRESULT_FALSE; en_queue(_parser->parser_queue,_data); /*校驗(yàn)數(shù)據(jù)尾*/ node=_parser->parser_queue->back; for(i=_parser->footer_size;i>0;i--) { if(node->data!=_parser->data_footer[i-1]) gotoDATA_FRAME_FALSE; node=node->pre_node; } /*校驗(yàn)數(shù)據(jù)頭*/ node=_parser->parser_queue->front; for(i=0;iheader_size;i++) { if(node->data!=_parser->data_header[i]) gotoDATA_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個(gè)數(shù)據(jù) * *@return:獲取解析成功的數(shù)據(jù),返回-1代表數(shù)據(jù)獲取失敗 */ intparser_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--; } returnnode->data; } /** *重置解析器 * *@_parser:解析器 */ voidparser_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:解析器 */ voidparser_release(DataParser*_parser) { if(_parser==NULL) return; release_queue(_parser->parser_queue); free(_parser); _parser=NULL; }
/*main.c*/ #include#include"parser.h" intmain() { uint8i; //數(shù)據(jù)頭 uint8data_header[]={0xAA,0xAA,0x04,0x80,0x02}; //要解析的數(shù)據(jù),測試用 uint8data[]={ 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 }; /** *初始化一個(gè)解析器 *第一個(gè)參數(shù)是數(shù)據(jù)頭 *第二個(gè)參數(shù)是數(shù)據(jù)頭長度 *第三個(gè)參數(shù)是數(shù)據(jù)尾指針 *第四個(gè)參數(shù)是數(shù)據(jù)尾大小 *第五個(gè)參數(shù)是一整幀數(shù)據(jù)的大小 */ DataParser*data_parser=parser_init(data_header,sizeof(data_header),NULL,0,8); //將要解析的數(shù)據(jù)逐個(gè)取出,添加到解析器中 for(i=0;i
測試結(jié)果如下:
從上面可以看出,解析的結(jié)果與目標(biāo)一致。
github地址:
https://github.com/528787067/DataFrameParser
審核編輯:湯梓紅
-
單片機(jī)
+關(guān)注
關(guān)注
6030文章
44497瀏覽量
632145 -
通信數(shù)據(jù)
+關(guān)注
關(guān)注
0文章
13瀏覽量
9950
原文標(biāo)題:可參考的通信數(shù)據(jù)接收解析方法
文章出處:【微信號(hào):最后一個(gè)bug,微信公眾號(hào):最后一個(gè)bug】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論