obsidian-notes/代码/状态机接收不定长数据.md
2024-06-20 08:45:57 +08:00

143 lines
4.5 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
tags:
- 代码块
- 源码
- 串口
- 不定长
- 解析
- 状态机
---
# 如何高效解析不定长度的协议帧?
嵌入式应用研究院 _2022-02-20 21:16_
通信设计中考虑协议的灵活性经常把协议设计成“不定长度”。一个实例如下图锐米LoRa终端的通信协议帧。
![[Pasted image 20240618084710.png]]
如果一个系统接收上述“不定长度”的协议帧,将会有一个挑战--如何高效接收与解析。
为简化系统设计我们强烈建议您采用“状态机”来解析UART数据帧并且把解析工作放在ISR中断服务程序完成仅当接收到最后一个字节0x0D再将整个数据帧提交给进程处理。该解析状态机的原理如下图所示
![[Pasted image 20240618084749.png]]
那么ISR处理这个状态机来得及吗答案是so easy因为它只有3个动作运算量十分小
比较接收数据 -> 更新状态变量 -> 存储接收数据C语言仅3条语句翻译成机器指令也不超过10条。
更多信息与源代码下载请链接:
> http://www.rimelink.com/nd.jsp?id=38&_np=105_315
代码清单如下:
```c
/**
* @brief  Status of received communication frame
*/
typedef enum
{
    STATUS_IDLE = (uint8_t)0,
    STATUS_HEAD, /* Rx Head=0x3C */
    STATUS_TYPE, /* Rx Type */
    STATUS_DATA, /* Data filed */
    STATUS_TAIL, /* Tail=0x0D */
    STATUS_END, /* End of this frame */
} COMM_TRM_STATUS_TypeDef;
/**
* @brief  Data object for received communication frame
*/
typedef struct
{
    uint8_t    byCnt; /* Count of 1 field */
    uint8_t    byDataLen; /* Length of data field */
    uint8_t    byFrameLen; /* Length of frame */
    COMM_TRM_STATUS_TypeDef    eRxStatus;
    uint8_t    a_byRxBuf[MAX_LEN_COMM_TRM_DATA];
} COMM_TRM_DATA;
/**
* @brief  Data object for received communication frame.
* @note  Prevent race condition that accessed by both ISR and process.
*/
static COMM_TRM_DATA    s_stComm2TrmData;
/**
  * @brief  Put a data that received by UART into buffer.
  * @note  Prevent race condition this called by ISR. 
  * @param  uint8_t byData: the data received by UART.
  * @retval  None
  */
void comm2trm_RxUartData(uint8_t byData)
{
    /* Update status according to the received data */
    switch (s_stComm2TrmData.eRxStatus)
    {
        case STATUS_IDLE:
            if (COMM_TRM_HEAD == byData) /* Is Head */
            {
                s_stComm2TrmData.eRxStatus = STATUS_HEAD;
            }
            else
            {
                goto rx_exception;
            }
            break;
        case STATUS_HEAD:
            if (TYPE_INVALID_MIN < byData && byData < TYPE_INVALID_MAX) /* Valid type */
            {
                s_stComm2TrmData.eRxStatus = STATUS_TYPE;
            }
            else
            {
                goto rx_exception;
            }
            break;
        case STATUS_TYPE:
            if (byData <= MAX_LEN_UART_FRAME_DATA) /* Valid data size */
            {
                s_stComm2TrmData.eRxStatus = STATUS_DATA;
                s_stComm2TrmData.byDataLen = byData;
            }
            else
            {
                goto rx_exception;
            }
            break;
        case STATUS_DATA:
            if (s_stComm2TrmData.byCnt < s_stComm2TrmData.byDataLen)
            {
                ++s_stComm2TrmData.byCnt;
            }
            else
            {
                s_stComm2TrmData.eRxStatus = STATUS_TAIL;
            }
            break;
        case STATUS_TAIL:
            if (COMM_TRM_TAIL == byData)
            {
                /* We received a frame of data, now tell process to deal with it! */
                process_poll(&Comm2TrmProcess);
            }
            else
            {
                goto rx_exception;
            }
            break;
        default:
            ASSERT(!"Error: Bad status of comm2trm_RxUartData().\r\n");
            break;
    }
    /* Save the received data */
    s_stComm2TrmData.a_byRxBuf[s_stComm2TrmData.byFrameLen++] = byData;
    return;
rx_exception:
    ClearCommFrame();
    return;
}
```
****原文:https://blog.csdn.net/jiangjunjie_2005/article/details/50619884****