色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

一種單片機數據解析方法

GReq_mcu168 ? 來源:CSDN ? 作者:CSDN ? 2022-04-01 10:16 ? 次閱讀

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

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 是數據校驗頭,后面三位是有效數據,問我怎么從外設不斷返回的數據中取出有效的數據。

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

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;
}

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

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

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

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

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

5、 容易出現誤判 。

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

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

每來一個數據就往隊列里面加:

3b5c029a-b145-11ec-aa7f-dac502259ad0.png

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

3b6e2ed4-b145-11ec-aa7f-dac502259ad0.png

此時只需要從隊列中取出有效數據即可。

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

3b93d3dc-b145-11ec-aa7f-dac502259ad0.png

好,分析結束,開始編碼。

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

/*queue.h*/

#ifndef_QUEUE_H_
#define_QUEUE_H_

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

typedefunsignedcharuint8;

/*隊列節點*/
typedefstructNode
{
uint8data;
structNode*pre_node;
structNode*next_node;
}Node;

/*隊列結構*/
typedefstructQueue
{
uint8capacity;//隊列總容量
uint8size;//當前隊列大小
Node*front;//隊列頭節點
Node*back;//隊列尾節點
}Queue;

/*初始化一個隊列*/
Queue*init_queue(uint8_capacity);
/*數據入隊*/
uint8en_queue(Queue*_queue,uint8_data);
/*數據出隊*/
uint8de_queue(Queue*_queue);
/*清空隊列*/
voidclear_queue(Queue*_queue);
/*釋放隊列*/
voidrelease_queue(Queue*_queue);

#endif
/*queue.c*/

#include
#include"parser.h"

/**
*初始化一個隊列
*
*@_capacity:隊列總容量
*/
Queue*init_queue(uint8_capacity)
{
Queue*queue=(Queue*)malloc(sizeof(Queue));
queue->capacity=_capacity;
queue->size=0;
returnqueue;
}

/**
*數據入隊
*
*@_queue:隊列
*@_data:數據
**/
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;
}

/**
*數據出隊
*
*@_queue:隊列
*
*@return:出隊的數據
*/
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;
}

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

/*parser.h*/

#ifndef_PARSER_H_
#define_PARSER_H_

#include"queue.h"

typedefenum
{
RESULT_FALSE,
RESULT_TRUE
}ParserResult;

/*解析器結構*/
typedefstructDataParser
{
Queue*parser_queue;//數據解析隊列
Node*resule_pointer;//解析結果數據指針
uint8*data_header;//數據校驗頭指針
uint8header_size;//數據校驗頭大小
uint8*data_footer;//數據校驗尾指針
uint8footer_size;//數據校驗尾大小
uint8result_size;//解析數據大小
ParserResultparserResult;//解析結果
}DataParser;

/*初始化一個解析器*/
DataParser*parser_init(uint8*_data_header,uint8_header_size,uint8*_data_footer,uint8_foot_size,uint8_data_frame_size);
/*將數據添加到解析器中進行解析*/
ParserResultparser_put_data(DataParser*_parser,uint8_data);
/*解析成功后從解析器中取出解析結果*/
intparser_get_data(DataParser*_parser,uint8_index);
/*重置解析器*/
voidparser_reset(DataParser*_parser);
/*釋放解析器*/
voidparser_release(DataParser*_parser);

#endif
/*parser.c*/

#include
#include"parser.h"

/**
*初始化一個解析器
*
*@_data_header:數據頭指針
*@_header_size:數據頭大小
*@_data_footer:數據尾指針
*@_foot_size:數據尾大小
*@_data_frame_size:一幀完整數據的大小
*
*@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;
}

/**
*將數據添加到解析器中進行解析
*
*@_parser:解析器
*@_data:要解析的數據
*
*@return:當前解析結果,返回RESULT_TRUE代表成功解析出一幀數據
*/
ParserResultparser_put_data(DataParser*_parser,uint8_data)
{
uint8i;
Node*node;

if(_parser==NULL)
returnRESULT_FALSE;

en_queue(_parser->parser_queue,_data);

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

/*校驗數據頭*/
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;

}

/**
*解析成功后從解析器中取出解析結果
*
*@_parser:解析器
*@_index:解析結果集合中的第_index個數據
*
*@return:獲取解析成功的數據,返回-1代表數據獲取失敗
*/
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;
//數據頭
uint8data_header[]={0xAA,0xAA,0x04,0x80,0x02};
//要解析的數據,測試用
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
};

/**
*初始化一個解析器
*第一個參數是數據頭
*第二個參數是數據頭長度
*第三個參數是數據尾指針
*第四個參數是數據尾大小
*第五個參數是一整幀數據的大小
*/
DataParser*data_parser=parser_init(data_header,sizeof(data_header),NULL,0,8);

//將要解析的數據逐個取出,添加到解析器中
for(i=0;isizeof(data);i++)
{
//解析數據,返回RESULT_TRUE代表成功解析出一組數據
if(parser_put_data(data_parser,data[i])==RESULT_TRUE)
{
printf("成功解析出一幀數據...
");

/*一位一位取出解析后的數據*/
printf("第一個數據是:0x%x
",parser_get_data(data_parser,0));
printf("第二個數據是:0x%x
",parser_get_data(data_parser,1));
printf("第三個數據是:0x%x


",parser_get_data(data_parser,2));
}
}

//當不再需要解析器時,應該把解析器釋放掉,回收內存,避免造成內存泄漏
parser_release(data_parser);

return0;
}

測試結果如下:

3bb3cb9c-b145-11ec-aa7f-dac502259ad0.png

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

github地址:

https://github.com/528787067/DataFrameParser

審核編輯 :李倩


聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 單片機
    +關注

    關注

    6037

    文章

    44563

    瀏覽量

    635848
  • 數據
    +關注

    關注

    8

    文章

    7067

    瀏覽量

    89107

原文標題:一種單片機數據解析方法

文章出處:【微信號:mcu168,微信公眾號:硬件攻城獅】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    單片機調試常見問題與解決方法

    燒錄到單片機時,燒錄軟件顯示無法與單片機通信。 解決方法: 檢查單片機的電源是否正常,確保電源電壓在規定的范圍內。 檢查燒錄線的連接是否正確,包括
    的頭像 發表于 11-01 14:11 ?904次閱讀

    如何實現51單片機與PC的串行通信

    的詳細步驟和方法。 硬件連接 首先,我們需要將51單片機與PC的串行接口連接起來。通常,我們使用RS-232接口進行連接。RS-232接口是一種常用的串行通信接口,它使用9個引腳進行
    的頭像 發表于 10-21 11:35 ?1012次閱讀

    單片機的中斷機制

    單片機的中斷機制是一種重要的處理方式,它允許單片機在執行主程序的過程中,能夠暫停當前任務,轉而處理外部或內部緊急事件。這種機制極大地提高了系統的響應速度和處理能力,使得單片機在各種應用
    的頭像 發表于 10-17 18:03 ?758次閱讀

    單片機io口的四工作狀態

    )是單片機與外部世界進行數據交換的接口。每個I/O口可以配置為輸入或輸出狀態,或者同時具備這兩功能。I/O口的狀態可以通過編程來控制,以滿足不同的應用需求。 2. 單片機I/O口的工
    的頭像 發表于 09-14 14:24 ?1618次閱讀

    單片機的三總線結構

    單片機的三總線結構包括地址總線(Address Bus, AB)、數據總線(Data Bus, DB)和控制總線(Control Bus, CB)。這三總線在
    的頭像 發表于 09-10 11:32 ?3108次閱讀

    文讀懂什么單片機:組成結構與應用

    歡迎來到單片機的世界,這是一種微小(但功能強大)的設備,改變了嵌入式系統的面貌。在本文中,您將了解單片機些基本知識、單片機的結構以及微處
    的頭像 發表于 08-09 11:49 ?1729次閱讀
    <b class='flag-5'>一</b>文讀懂什么<b class='flag-5'>單片機</b>:組成結構與應用

    藍牙模塊如何實現單片機和手機端數據互傳

    藍牙模塊實現單片機和手機端數據互傳的過程可以分為以下幾個步驟: 硬件準備 : 確保你有個支持藍牙通信的單片機開發板,如Arduino、Raspberry Pi等。 準備
    的頭像 發表于 07-24 17:59 ?2561次閱讀
    藍牙模塊如何實現<b class='flag-5'>單片機</b>和手機端<b class='flag-5'>數據</b>互傳

    數字電路仿真軟件單片機怎么用

    數字電路仿真軟件是一種用于模擬和測試數字電路設計的工具。其中,單片機仿真軟件是一種專門針對單片機進行仿真的工具。這種軟件能夠提供個類似真實
    的頭像 發表于 04-21 10:28 ?1081次閱讀

    單片機是什么?單片機編程如何入門?

    單片機其實是一種很早的叫法了,最開始我們的前輩叫單板機或者叫單片機,因為那個時候單片機的處理能力還沒有很強,現在我們所用的基本都是微型處理單元,也叫為控制器也稱之為MCU
    的頭像 發表于 03-28 08:03 ?1945次閱讀
    <b class='flag-5'>單片機</b>是什么?<b class='flag-5'>單片機</b>編程如何入門?

    FH8A1?8A是一種io型,完全靜態,基于otp的控制器8位MCU單片機

    FH8A1?8A是一種io型,完全靜態,基于otp的控制器8位MCU單片機
    的頭像 發表于 03-25 17:35 ?591次閱讀

    單片機抗干擾措施有哪些?

    電磁干擾(EMI)問題日益成為影響單片機穩定性與可靠性的主要障礙。因此,探討和實施有效的抗干擾措施對于提高單片機系統的性能至關重要。下面為大家簡單介紹一種單片機抗干擾措施
    的頭像 發表于 03-15 16:36 ?2556次閱讀
    <b class='flag-5'>單片機</b>抗干擾措施有哪些?

    單片機中斷功能及其應用

    單片機中斷功能及其應用? 單片機中斷是指在程序執行過程中,根據特定的條件或事件自動暫時中斷當前程序的執行,轉而執行特定的中斷服務程序。中斷是一種能提高單片機系統效率的重要技術,能夠實現
    的頭像 發表于 01-30 14:45 ?5514次閱讀

    單片機怎么能夠與手機實現遠程通訊呢?

    單片機怎么能夠與手機實現遠程通訊呢? 隨著物聯網的快速發展,單片機作為物聯網應用中最常見的控制器,與手機實現遠程通訊已成為一種趨勢。通過單片機與手機的遠程通訊,可以實現智能家居、智能農
    的頭像 發表于 01-15 14:59 ?3263次閱讀

    單片機原理及應用是什么

    單片機(Microcontroller)是一種集成電路(IC)芯片,其中包括了中央處理器(CPU)、存儲器和輸入/輸出(I/O)設備等功能模塊。它是一種小型計算機系統,具有獨立的工作能力和完整的計算
    的頭像 發表于 01-12 15:28 ?2173次閱讀

    單片機如何讀取鍵盤數據

    單片機作為一種嵌入式系統,往往需要與外部設備進行交互。其中之的重要環節就是通過鍵盤讀取輸入的數據。在本文中,我們將詳細介紹如何使用單片機
    的頭像 發表于 01-04 17:09 ?1867次閱讀
    主站蜘蛛池模板: 欧美s00老人| 亚洲AV噜噜88| 免费无码一区二区三区蜜桃大| 交换娇妻呻吟声不停中文字幕| 巨爆乳中文字幕爆乳区| 日本69xxxx| 亚洲精品美女久久777777| 97亚洲狠狠色综合久久久久| 国产伦精品一区二区三区| 久久伊人电影| 亚洲精品国偷拍电影自产在线 | 国产精品亚洲高清一区二区| 日本高清无吗| 无限资源日本2019版免费| 259luxu高跟黑色丝袜系列| 国产精品婷婷久青青原| 卫生间被教官做好爽HH视频| 99久久国语露脸精品国产| 花蝴蝶免费版高清版| 亚洲综合香蕉在线视频| 国产精品99re6热在线播放| 男男高H啪肉Np文多攻多一受| 97caopeng| 美女扒开尿口直播| 亚洲中久无码永久在线| 国产精品永久AV无码视频| 小柔的性放荡羞辱日记| 绑着男军人的扒开内裤| 久久这里只有精品无码3D| 最近中文字幕在线中文高清版| 果冻传媒妈妈要儿子| 午夜A级理论片左线播放| 国精品产露脸偷拍视频| 依人青青青在线观看| 狠狠色狠狠色88综合日日91| 四虎一级片| 国产69精品久久久久APP下载| 日本精品久久久久中文字幕2 | 挺进老师的紧窄小肉六电影完整版 | 亚洲综合视频| 九九黄色大片|