在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

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

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

3天內不再提示

一種單片機數據解析方法

STM32嵌入式開發 ? 來源:CSDN-XR528787067 ? 2023-05-18 09:34 ? 次閱讀

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

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



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

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

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

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

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

5、 容易出現誤判 。

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

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

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

769cb4b8-f4af-11ed-90ce-dac502259ad0.png ?

當接收到一幀完整數據時隊列頭和數據校驗頭重合:
76aad64c-f4af-11ed-90ce-dac502259ad0.png ????
此時只需要從隊列中取出有效數據即可。

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

76b1e68a-f4af-11ed-90ce-dac502259ad0.png ? ??

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

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


/* queue.h */
 
#ifndef _QUEUE_H_
#define _QUEUE_H_
 
#ifndef NULL
#define NULL ((void *)0)
#endif
 
typedef unsigned char uint8;
 
/* 隊列節點 */
typedef struct Node
{
 uint8 data;
 struct Node *pre_node;
 struct Node *next_node;
} Node;
 
/* 隊列結構 */
typedef struct Queue
{
 uint8 capacity;     // 隊列總容量
 uint8 size;         // 當前隊列大小
 Node *front;        // 隊列頭節點
 Node *back;         // 隊列尾節點
} Queue;
 
/* 初始化一個隊列 */
Queue *init_queue(uint8 _capacity);
/* 數據入隊 */
uint8 en_queue(Queue *_queue, uint8 _data);
/* 數據出隊 */
uint8 de_queue(Queue *_queue);
/* 清空隊列 */
void clear_queue(Queue *_queue);
/* 釋放隊列 */
void release_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;
 return queue;
}
 
/**
 * 數據入隊
 *
 * @_queue: 隊列
 * @_data: 數據
 **/
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;
}
 
/**
 * 數據出隊
 *
 * @_queue: 隊列
 *
 * @return: 出隊的數據
 */
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;
}

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


/* parser.h */
 
#ifndef _PARSER_H_
#define _PARSER_H_
 
#include "queue.h"
 
typedef enum
{
    RESULT_FALSE,
    RESULT_TRUE
} ParserResult;
 
/* 解析器結構 */
typedef struct DataParser
{
    Queue *parser_queue;   // 數據解析隊列
    Node *resule_pointer;   // 解析結果數據指針
    uint8 *data_header;    // 數據校驗頭指針
    uint8 header_size;    // 數據校驗頭大小
    uint8 *data_footer;    // 數據校驗尾指針
    uint8 footer_size;    // 數據校驗尾大小
    uint8 result_size;    // 解析數據大小
    ParserResult parserResult;  // 解析結果
} DataParser;
 
/* 初始化一個解析器 */
DataParser *parser_init(uint8 *_data_header, uint8 _header_size, uint8 *_data_footer, uint8 _foot_size, uint8 _data_frame_size);
/* 將數據添加到解析器中進行解析 */
ParserResult parser_put_data(DataParser *_parser, uint8 _data);
/* 解析成功后從解析器中取出解析結果 */
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: 數據頭指針
 * @_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)
        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;
}
 
/**
 * 將數據添加到解析器中進行解析
 *
 * @_parser: 解析器
 * @_data: 要解析的數據
 *
 * @return: 當前解析結果,返回 RESULT_TRUE 代表成功解析出一幀數據
 */
ParserResult parser_put_data(DataParser *_parser, uint8 _data)
{
    uint8 i;
    Node *node;
 
 if(_parser == NULL)
  return RESULT_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])
            goto DATA_FRAME_FALSE;
        node = node->pre_node;
 }
 
 /* 校驗數據頭 */
    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;
 
}
 
/**
 * 解析成功后從解析器中取出解析結果
 *
 * @_parser: 解析器
 * @_index: 解析結果集合中的第 _index 個數據
 *
 * @return: 獲取解析成功的數據,返回 -1 代表數據獲取失敗
 */
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;
    // 數據頭
    uint8 data_header[] = {0xAA, 0xAA, 0x04, 0x80, 0x02};
    // 要解析的數據,測試用
    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
    };
 
    /**
     * 初始化一個解析器
     * 第一個參數是數據頭
     * 第二個參數是數據頭長度
     * 第三個參數是數據尾指針
     * 第四個參數是數據尾大小
     * 第五個參數是一整幀數據的大小
     */
    DataParser *data_parser = parser_init(data_header, sizeof(data_header), NULL, 0, 8);
 
    // 將要解析的數據逐個取出,添加到解析器中
    for(i = 0; i < sizeof(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);
 
    return 0;
}

測試結果如下:

76b94812-f4af-11ed-90ce-dac502259ad0.png

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

github地址:

https://github.com/528787067/DataFrameParser

審核編輯:湯梓紅

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

    關注

    6044

    文章

    44627

    瀏覽量

    638962
  • 數據
    +關注

    關注

    8

    文章

    7169

    瀏覽量

    89694
  • 代碼
    +關注

    關注

    30

    文章

    4836

    瀏覽量

    69121
  • 數據解析
    +關注

    關注

    0

    文章

    14

    瀏覽量

    3526

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

文章出處:【微信號:c-stm32,微信公眾號:STM32嵌入式開發】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    一種可用于單片機的中斷高效處理與事件機制方法

    一種可用于單片機的中斷高效處理與事件機制方法
    的頭像 發表于 10-17 15:08 ?797次閱讀

    單片機與PC之間并行通訊的一種實現方法

    單片機與PC之間并行通訊的一種實現方法
    發表于 08-17 23:14

    介紹一種簡單的數據解析方法

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

    單片機并行通訊的一種方法

    摘 要:單片機通訊般采用串行總線方式,但在通訊距離短,通訊數據量大,通訊速率高的場合也會用到多并行通訊。本文介紹
    發表于 10-28 15:51 ?119次下載

    單片機軟件產生高頻方波的一種方法

    單片機軟件產生高頻方波的一種方法
    發表于 05-15 14:00 ?50次下載

    AVR 單片機SPI 通信的一種抗干擾方法

    AVR 單片機SPI 通信的一種抗干擾方法
    發表于 05-15 16:03 ?44次下載

    用VB6.0數字示波單片機實時監測數據一種方法

    本文介紹利用VB6.0數字動態圖形顯示單片機實時檢測數據一種方法,該顯示方法符合人們看圖習慣,視覺效果好且數值顯示精確。關鍵詞:VB6.0, 數字動態圖形顯示,
    發表于 08-05 16:03 ?33次下載

    一種PC與單片機RS232串口通信設計

    摘要:針對傳統的PC與單片機串口通信會使多個單片機接收無效數據的缺陷。介紹了一種串口通信的方法
    發表于 08-18 18:05 ?0次下載

    一種基于單片機的電子密碼鎖的設計

    一種基于單片機的電子密碼鎖的設計,有需要的下來看看。
    發表于 02-17 16:47 ?46次下載

    一種簡單多功能單片機系統設計

    一種簡單多功能單片機系統設計
    發表于 01-14 22:41 ?10次下載

    PC單片機串行通信的一種方法

    PC單片機串行通信的一種方法
    發表于 09-04 14:20 ?4次下載
    PC<b class='flag-5'>機</b>與<b class='flag-5'>單片機</b>串行通信的<b class='flag-5'>一種</b>新<b class='flag-5'>方法</b>

    一種單片機系統RAM的低功耗測試方法

    介紹了單片機系統RAM測試的方法,并在原有的MARCH-G算法的基礎上進行了更深入的研究,提出了一種低功耗的改進方法
    發表于 06-24 10:23 ?16次下載

    一種單片機數據解析方法

    對于這種問題最容易想到的就是使用個標志位用于標志當前正解析一幀數據的第幾位,然后判斷當前接收的數據是否與校驗數據
    的頭像 發表于 04-01 10:16 ?898次閱讀

    一種單片機通信系統的設計

    電子發燒友網站提供《一種單片機通信系統的設計.pdf》資料免費下載
    發表于 10-30 11:11 ?0次下載
    <b class='flag-5'>一種</b><b class='flag-5'>單片機</b>多<b class='flag-5'>機</b>通信系統的設計

    單片機解析g代碼的方法

    單片機一種完整的計算機系統,它集成了處理器、存儲器、輸入輸出接口等基本的計算機組成部分。單片機應用廣泛,可以用于控制各種電子設備。在單片機中,G代碼是
    的頭像 發表于 12-22 14:15 ?1977次閱讀
    主站蜘蛛池模板: 又大又粗进出白浆直流动态图 | 国产gav成人免费播放视频 | 黄色网址你懂得 | 日本黄色大片网站 | 亚洲色图综合图片 | 一区二区三区电影 | 一本二卡三卡四卡乱码二百 | 欧美高清一级 | 综合久色| 国产三级精品最新在线 | 天天色影 | 国产亚洲人成网站观看 | www.av片| 操她视频网站 | 日韩免费视频一区二区 | 一二三区乱码一区二区三区码 | 91激情在线 | 一级特黄aaa大片在线观看 | 手机午夜视频 | 久久国产香蕉视频 | 性做久久久久 | 日本wwwwwwwww| 成人丁香婷婷 | 94久久国产乱子伦精品免费 | 天天摸天天操天天射 | 欧美在线视频二区 | 色先锋av资源中文字幕 | 日韩在线一区二区 | 免费四虎永久在线精品 | 欧美特黄一免在线观看 | 亚洲免费三级 | bt天堂网在线www资源 | 日本在线看小视频网址 | 69女poren18女| 欧美zooz人禽交免费观看 | 四虎影库在线播放 | 精品国产第一国产综合精品gif | 一区二区三区四区无限乱码在线观看 | 久久免 | 日本一区二区免费看 | 国产美女久久久 |