99精品伊人亚洲|最近国产中文炮友|九草在线视频支援|AV网站大全最新|美女黄片免费观看|国产精品资源视频|精彩无码视频一区|91大神在线后入|伊人终合在线播放|久草综合久久中文

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

可參考的通信數(shù)據(jù)接收解析方法

lilihe92 ? 來源:CSDN技術(shù)社區(qū) ? 作者: XR528787067 ? 2022-12-09 09:06 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

正文

前陣子一朋友使用單片機(jī)與某外設(shè)進(jìn)行通信時,外設(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ù)。 對于這種問題最容易想到的就是使用一個標(biāo)志位用于標(biāo)志當(dāng)前正解析到一幀數(shù)據(jù)的第幾位,然后判斷當(dāng)前接收的數(shù)據(jù)是否與校驗數(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ù)解析,但是使用這種方法有如下幾個缺點(diǎn):
1、 大量使用了判斷,容易導(dǎo)致出現(xiàn)邏輯混亂。
2、 代碼重復(fù)率高,抽象程度低。從上述代碼可以看到一大堆代碼僅僅是判斷的數(shù)據(jù)不同,其他代碼都完全一致。
3、 代碼可復(fù)用性差。寫好的代碼無法用在其他類似的外設(shè)上,如果有多個外設(shè)就需要編寫多份類似的代碼。
4、 可擴(kuò)展性低。如果外設(shè)還有一個數(shù)據(jù)校驗尾需要校驗或者數(shù)據(jù)校驗頭發(fā)生改變,就需要再次寫多個判斷重新用于校驗,無法在原有的代碼上進(jìn)行擴(kuò)展。
5、 容易出現(xiàn)誤判 。
對此,這里提出了一種新的解決方案,可以通用與所有類似的數(shù)據(jù)解析,原理如下: 使用一個固定容量的隊列用來緩存接收到的數(shù)據(jù),隊列容量等于一幀數(shù)據(jù)的大小,每來一個數(shù)據(jù)就將數(shù)據(jù)往隊列里面加,當(dāng)完整接收到一幀數(shù)據(jù)時此時隊列中的全部數(shù)據(jù)也就是一幀完整的數(shù)據(jù),因此只需要判斷隊列是否是數(shù)據(jù)校驗頭,隊列尾是否是數(shù)據(jù)校驗尾就可以得知當(dāng)前是否已經(jīng)接收到了一幀完整的數(shù)據(jù),然后在將數(shù)據(jù)從隊列中取出即可。原理圖如下: 每來一個數(shù)據(jù)就往隊列里面加:
51e6dfc4-7744-11ed-8abf-dac502259ad0.png

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

51f154cc-7744-11ed-8abf-dac502259ad0.png
此時只需要從隊列中取出有效數(shù)據(jù)即可。 如果有數(shù)據(jù)尾校驗,僅僅只需要添加一個校驗尾即可,如下圖所示:
51f8e57a-7744-11ed-8abf-dac502259ad0.png
好,分析結(jié)束,開始編碼。 首先需要一個隊列,為了保證通用性,隊列底層使用類似于雙向鏈表的實現(xiàn)(當(dāng)然也可以使用數(shù)組實現(xiàn)),需要封裝的結(jié)構(gòu)有隊列容量、隊列大小、隊頭節(jié)點(diǎn)和隊尾節(jié)點(diǎn),需要實現(xiàn)的操作有隊列初始化、數(shù)據(jù)入隊、數(shù)據(jù)出隊、清空隊列和釋放隊列,具體代碼如下:

/*queue.h*/

#ifndef_QUEUE_H_
#define_QUEUE_H_

#ifndefNULL
#defineNULL((void*)0)
#endif

typedefunsignedcharuint8;

/*隊列節(jié)點(diǎn)*/
typedefstructNode
{
uint8data;
structNode*pre_node;
structNode*next_node;
}Node;

/*隊列結(jié)構(gòu)*/
typedefstructQueue
{
uint8capacity;//隊列總?cè)萘?uint8size;//當(dāng)前隊列大小
Node*front;//隊列頭節(jié)點(diǎn)
Node*back;//隊列尾節(jié)點(diǎn)
}Queue;

/*初始化一個隊列*/
Queue*init_queue(uint8_capacity);
/*數(shù)據(jù)入隊*/
uint8en_queue(Queue*_queue,uint8_data);
/*數(shù)據(jù)出隊*/
uint8de_queue(Queue*_queue);
/*清空隊列*/
voidclear_queue(Queue*_queue);
/*釋放隊列*/
voidrelease_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;
returnqueue;
}

/**
*數(shù)據(jù)入隊
*
*@_queue:隊列
*@_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ù)出隊
*
*@_queue:隊列
*
*@return:出隊的數(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;
}

/**
*清空隊列
*
*@_queue:隊列
*/
voidclear_queue(Queue*_queue)
{
while(_queue->size>0)
{
de_queue(_queue);
}
}

/**
*釋放隊列
*
*@_queue:隊列
*/
voidrelease_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"

typedefenum
{
RESULT_FALSE,
RESULT_TRUE
}ParserResult;

/*解析器結(jié)構(gòu)*/
typedefstructDataParser
{
Queue*parser_queue;//數(shù)據(jù)解析隊列
Node*resule_pointer;//解析結(jié)果數(shù)據(jù)指針
uint8*data_header;//數(shù)據(jù)校驗頭指針
uint8header_size;//數(shù)據(jù)校驗頭大小
uint8*data_footer;//數(shù)據(jù)校驗尾指針
uint8footer_size;//數(shù)據(jù)校驗尾大小
uint8result_size;//解析數(shù)據(jù)大小
ParserResultparserResult;//解析結(jié)果
}DataParser;

/*初始化一個解析器*/
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"

/**
*初始化一個解析器
*
*@_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);

/*校驗數(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;
}

/*校驗數(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個數(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
};

/**
*初始化一個解析器
*第一個參數(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

測試結(jié)果如下:

520b181c-7744-11ed-8abf-dac502259ad0.png

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

github地址:

https://github.com/528787067/DataFrameParser

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 單片機(jī)
    +關(guān)注

    關(guān)注

    6067

    文章

    44989

    瀏覽量

    650339
  • 通信數(shù)據(jù)
    +關(guān)注

    關(guān)注

    0

    文章

    13

    瀏覽量

    10051

原文標(biāo)題:可參考的通信數(shù)據(jù)接收解析方法

文章出處:【微信號:最后一個bug,微信公眾號:最后一個bug】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點(diǎn)推薦

    請問gps接收數(shù)據(jù)是每接收一條解析一條嗎?

    請教下,gps 數(shù)據(jù)是每接收一條解析一條還是一次全部接收完成后再一起解析 ???
    發(fā)表于 11-02 08:49

    用中斷接收異步數(shù)據(jù)方法有哪些?

    處理接收到的數(shù)據(jù)包(只要是在緩沖區(qū)重寫之前進(jìn)行處理)。我希望緩沖區(qū)長度大于2個包長度。如果這是一種處理數(shù)據(jù)的典型方法,那么在溢出后,如何處理數(shù)據(jù)
    發(fā)表于 08-13 07:41

    stm32通過wifi方式進(jìn)行數(shù)據(jù)通信方法

    stm32通過wifi方式進(jìn)行數(shù)據(jù)通信時通常采用ESP8266模塊,最常用的方法就是通過AT指令與esp模塊進(jìn)行交互,本項目對常用的AT指令進(jìn)行封裝成協(xié)議,使用戶調(diào)用簡單的函數(shù)即可實現(xiàn)熱點(diǎn)連接
    發(fā)表于 12-06 07:22

    串口接收數(shù)據(jù)方法

    上一篇文章介紹了串口發(fā)送數(shù)據(jù)的優(yōu)化方法,使用中斷的方式發(fā)送數(shù)據(jù)可以提高系統(tǒng)實時性。這次介紹串口接收數(shù)據(jù)
    發(fā)表于 01-19 07:50

    使用stm32F10x單片機(jī)串口接收數(shù)據(jù)時,接收中斷只能按字節(jié)接收怎么解決

    一樣利用接收超時機(jī)制判斷無后續(xù)幀。(接收到一段數(shù)據(jù)后,不會立即退出接收,而是等超時時間到表示本輪接收完畢)mqtt 讀取到
    發(fā)表于 02-17 07:03

    RS485 232串口通信數(shù)據(jù)解析

    文章目錄(RS485 232串口通信數(shù)據(jù)解析實用干貨(1)生成一個適合你的列表創(chuàng)建一個表格設(shè)定內(nèi)容居中、居左、居右SmartyPants創(chuàng)建一個自定義列表如何創(chuàng)建一個注腳注釋也是必不可少的KaTeX
    發(fā)表于 02-22 07:14

    介紹一種簡單的數(shù)據(jù)解析方法

    JSON。? 下面我將介紹一種簡單的數(shù)據(jù)解析方法,通過編寫函數(shù),將字符串解析取得目標(biāo)數(shù)據(jù)。解析
    發(fā)表于 02-28 06:15

    有沒有相關(guān)通信協(xié)議可以使c與js之間傳輸解析數(shù)據(jù)?

    最近學(xué)習(xí)RTT,要做一個單片機(jī)接收傳感器數(shù)據(jù)整理后需要傳到柿餅派中,柿餅派也會向單片機(jī)發(fā)送操作指令,設(shè)備之間用串口通信,但單片機(jī)使用c開發(fā)而柿餅派的PersimUI使用JS開發(fā),有沒有相關(guān)通信
    發(fā)表于 10-26 14:31

    最詳盡的——解析串口通信數(shù)據(jù)

    最詳盡的——解析串口通信數(shù)據(jù)
    發(fā)表于 12-05 14:56 ?3次下載

    單片機(jī) MQTT 讀取數(shù)據(jù)問題(串口通信

    一樣利用接收超時機(jī)制判斷無后續(xù)幀。(接收到一段數(shù)據(jù)后,不會立即退出接收,而是等超時時間到表示本輪接收完畢)mqtt 讀取到
    發(fā)表于 12-20 19:35 ?9次下載
    單片機(jī) MQTT 讀取<b class='flag-5'>數(shù)據(jù)</b>問題(串口<b class='flag-5'>通信</b>)

    一種單片機(jī)數(shù)據(jù)解析方法

    對于這種問題最容易想到的就是使用一個標(biāo)志位用于標(biāo)志當(dāng)前正解析到一幀數(shù)據(jù)的第幾位,然后判斷當(dāng)前接收數(shù)據(jù)是否與校驗數(shù)據(jù)一致,如果一致則將標(biāo)志位
    的頭像 發(fā)表于 04-01 10:16 ?1045次閱讀

    如何高效接收解析單片機(jī)的通信協(xié)議幀

    為簡化系統(tǒng)設(shè)計,我們強(qiáng)烈建議您采用“狀態(tài)機(jī)”來解析UART數(shù)據(jù)幀,并且把解析工作放在ISR(中斷服務(wù)程序)完成,僅當(dāng)接收到最后一個字節(jié)(0x0D)時,再將整個
    的頭像 發(fā)表于 07-05 17:19 ?1787次閱讀

    單片機(jī)接收數(shù)據(jù)幀幀頭幀尾校驗數(shù)據(jù)解析

    單片機(jī)接收數(shù)據(jù)幀幀頭幀尾校驗數(shù)據(jù)解析
    的頭像 發(fā)表于 10-17 17:23 ?1653次閱讀
    單片機(jī)<b class='flag-5'>接收</b><b class='flag-5'>數(shù)據(jù)</b>幀幀頭幀尾校驗<b class='flag-5'>數(shù)據(jù)</b><b class='flag-5'>解析</b>

    labview串口接收數(shù)據(jù)怎么不丟幀

    時如何避免丟幀的方法。 首先,我們需要了解什么是丟幀。在串口通信中,丟幀指的是接收方無法正確解析發(fā)送方發(fā)送的數(shù)據(jù)幀,從而導(dǎo)致
    的頭像 發(fā)表于 01-08 11:38 ?3106次閱讀

    AUTOSAR通信協(xié)議解析 如何實現(xiàn)AUTOSAR通信

    通信協(xié)議棧是一個復(fù)雜的系統(tǒng),它涵蓋了多種通信方式和模塊,以實現(xiàn)車內(nèi)ECU之間的高效、可靠的數(shù)據(jù)交換。以下是對AUTOSAR通信協(xié)議的解析及實
    的頭像 發(fā)表于 12-17 14:54 ?2811次閱讀