0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

UART接收数据和解析的常见方式

strongerHuang 来源:strongerHuang 2023-04-19 14:31 次阅读

UART串口是嵌入式开发常见的一种通信方式,但还是有不少人不知道怎么使用串口。

今天就来围绕串口,简单分享几点内容:

串口接收方式

处理接收数据

通信协议解析

串口接收方式

串口接收(通信另一端)的数据,常见的方式:

轮询(查询)接收寄存器

中断接收数据

轮询,就是间隔一定时间(一般ms,甚至us)去查询一下接收寄存器是否有数据,如果有数据,就处理接收到的数据。

中断,平时没有数据接收时,CPU干自己的事。当有接收数据时,UART串口控制器会响应中断,通知CPU有事干了。

轮询方式,大家想过有哪些弊端吗?

效率低:CPU大部分时间都是去做查询的工作;

响应不实时:如果短时间内有多个接收数据,CPU正在处理一件相对耗时的事情(比如:发送一个数据包),没来得及查询接收到的数据,此时,数据就可能丢失。(特别是早些年串口没有FIFO功能的时候)

所以,不管是UART串口,还是I2C、 SPI、 CAN等串行通信,用的最多,最常见的还是中断接收,很少有用轮询的方式。

我之前维护一个老代码(坑),CLI串口用轮询方式,出现丢数据、溢出错误等众多问题,让我还加了好几个班。。。

处理接收数据

中断有数据来了,大家怎么处理接收到的数据?

我见过有些小项目,直接在中断函数里面做一些应用的情况。比如:串口中断接收一个传感器发过来的数据,显示数据并做一些响应的动作。

中断函数,代码能少尽少,耗时能少尽少,不能处理太多耗时的复杂的逻辑、应用等。

中断有数据来了,一般是通过FIFO方式处理。

1.简单的数组接收、应用解析并处理

比如:

static uint8_t gRxCnt = 0;
static uint8_t gRxBuf[10];


void USART1_IRQHandler(void)
{
  //...
  gDgus_RxBuf[gRxCnt] = (uint8_t)USART_ReceiveData(USART1);
  gRxCnt++;
  //...
  
}


void App(void)
{
  //...
  if(0 < gRxCnt)
  {
    //拷贝接收到的数据
    gRxCnt = 0;
    //解析接收数据并处理
  }
}

2.中断函数接收一帧完整数据再处理

比如:

void USART1_IRQHandler(void)
{
  static uint8_t RxCnt = 0;                      //计数值
  static uint8_t RxNum = 0;                      //数量


  if((USART1->SR & USART_FLAG_RXNE) == USART_FLAG_RXNE)
  {
    gDgus_RxBuf[RxCnt] = (uint8_t)USART_ReceiveData(USART1);
    RxCnt++;


    /* 判断帧头 */
    if(gDgus_RxBuf[0] != DGUS_FRAME_HEAD1)       //接收到帧头1
    {
      RxCnt = 0;
      return;
    }
    if((2 == RxCnt) && (gDgus_RxBuf[1] != DGUS_FRAME_HEAD2))
    {
      RxCnt = 0;
      return;
    }


    /* 确定一帧数据长度 */
    if(RxCnt == 3)
    {
      RxNum = gDgus_RxBuf[2] + 3;
    }


    /* 接收完一帧数据 */
    if((6 <= RxCnt) && (RxNum <= RxCnt))
    {
      RxCnt = 0;
      OSMboxPost(EventMBox_Touch, gDgus_RxBuf);  //发送消息邮箱(执行触控操作)
    }
  }
}

中断函数解析完一帧数据,可以通过标志位通知应用(裸机时),也可以通过消息队列、邮箱等方式发送到应用(RTOS时)。

3.RTOS队列、邮箱接收

比如:

void DEBUG_COM_IRQHandler(void)
{
  static uint8_t Data;


  if(USART_GetITStatus(DEBUG_COM, USART_IT_RXNE) != RESET)
  {
    Data = USART_ReceiveData(DEBUG_COM);
CLI_RcvDateFromISR(Data);//下面把这个函数分离出来了
  }
}


void CLI_RcvDateFromISR(uint8_t RcvData)
{
  static portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;


  if(xCLIRcvQueue != NULL)
  {
    xQueueSendFromISR(xCLIRcvQueue, &RcvData, &xHigherPriorityTaskWoken);
  }
}

中断来一字节数据,就通过消息队列发送一个字节数据,如果没有及时出来这个数据,也是存储在队列中。

通信协议解析

像上面第2种,简单通信协议,项目相对较小的情况下,可以直接在中断函数里面处理。

但是,如果项目相对较大、复杂一点,协议也先对复杂一点,上面第2种在函数内部出来方式就不可取。

1.裸机环境

裸机的情况下,建议用第一种:中断数组缓存数据(FIFO),应用解析通信协议。

2.RTOS环境

RTOS情况下,建议用第三种方式:消息队列、邮箱等方式接收数据,然后发送(通知)应用解析协议。

当然,以上说的都只是常见的方式,具体还需要结合你项目实际情况。

同时,其它类似I2C、CAN等通信,如有协议解析,也是类似。

比如之前给大家分享的MavLink,我就用CAN实现过:

void CAN_RX_IRQHandler(void)
{
  static CanRxMsg RxMessage;
  static MAVRCV_QUEUE_TypeDef MAVRcvQueue_Union;


  CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);
                                                 //拷贝长度、 数据
  MAVRcvQueue_Union.MAVRcvStruct.MAVLink_Len = RxMessage.DLC;
  memcpy(&MAVRcvQueue_Union.MAVRcvStruct.MAVLink_Buf[0], &RxMessage.Data[0], RxMessage.DLC);


  MAVLink_RcvDateFromISR(&MAVRcvQueue_Union.MAVLinkRcv_Queue[0]);
}

最后,以上内容,仅提供思路,代码不一定适合项目。

审核编辑 :李倩

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 寄存器
    +关注

    关注

    30

    文章

    5042

    浏览量

    117819
  • uart
    +关注

    关注

    22

    文章

    1159

    浏览量

    100019
  • 嵌入式开发
    +关注

    关注

    18

    文章

    979

    浏览量

    46983

原文标题:UART接收数据和解析的常见方式

文章出处:【微信号:strongerHuang,微信公众号:strongerHuang】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    介绍内部EEPROM数据读取和解析

    EEPROM数据读取和解析上一篇我们简单介绍了热成像传感器德国海曼的HTPA 32x32d,本文主要进一步介绍内部EEPROM数据读取和解析。存储结构一览在说海曼这个传感器之前,我们先
    发表于 12-07 12:14

    stm32 uart1如何通过DMA方式发送和接收数据

    stm32 uart1如何通过DMA方式发送和接收数据
    发表于 12-08 07:05

    如何去实现Stm32 Uart用DMA的方式接收数据

    DMA有何用途?如何去实现Stm32 Uart用DMA的方式接收数据呢?
    发表于 12-14 07:37

    如何使用查询方式通过UART接收数据

    使用查询方式通过UART接收数据实验目的本节实验目的为实现串口发送和接收。这一节计划采取查询的方式
    发表于 02-17 06:26

    常见数据发送接收处理方式

    文章目录目的发送缓存数据接收解析总结目的发送缓存数据接收解析总结
    发表于 02-17 07:34

    uart pdma方式接收不定长数据如何解决?

    目前测试过用uart接收超时中断在pdma方式接收时不起作用,那么有其他方式来解决接收不定长
    发表于 08-23 08:25

    请问如何接收和解析单片机串口的数据,怎么防止丢失和断贞?

    请问大家如何接收和解析单片机串口的数据,怎么防止丢失和断贞呢?
    发表于 11-08 07:57

    光耦隔离的4种常见方法对比

    光耦隔离的4种常见方法对比
    发表于 05-31 11:06 13.1w次阅读
    光耦隔离的4种<b class='flag-5'>常见方</b>法对比

    STC单片机串口接收一帧数据全为0的原因和解决办法

    STC单片机串口接收一帧数据全为0的原因和解决办法typedef unsigned char BYTE;void UART_RX_DATA_JX(void){ volatile BYT
    发表于 12-03 19:06 16次下载
    STC单片机串口<b class='flag-5'>接收</b>一帧<b class='flag-5'>数据</b>全为0的原因<b class='flag-5'>和解</b>决办法

    K210应用5-使用查询方式通过UART接收数据

    使用查询方式通过UART接收数据实验目的本节实验目的为实现串口发送和接收。这一节计划采取查询的方式
    发表于 12-20 19:37 10次下载
    K210应用5-使用查询<b class='flag-5'>方式</b>通过<b class='flag-5'>UART</b><b class='flag-5'>接收</b><b class='flag-5'>数据</b>

    MCU批量生产下载程序的几种常见方

    MCU批量生产下载程序的几种常见方
    的头像 发表于 10-24 17:22 1024次阅读
    MCU批量生产下载程序的几种<b class='flag-5'>常见方</b>法

    使用UART IDLE中断接收不定长数据

    使用UART IDLE中断接收不定长数据
    的头像 发表于 09-18 15:41 608次阅读
    使用<b class='flag-5'>UART</b> IDLE中断<b class='flag-5'>接收</b>不定长<b class='flag-5'>数据</b>

    无功补偿的原理、作用及常见方式

    无功补偿的原理、作用及常见方式  无功补偿是电力系统中的一项重要技术措施,用于改善电力质量和提高能源利用效率。本文将详细介绍无功补偿的原理、作用以及常见的补偿方式。 一、无功补偿的原理 无功功率
    的头像 发表于 01-19 14:19 1114次阅读

    常见UART收发方式

    这种方式适合大多数单片机,只要有中断就行。使用UART Write发送数据时,数据并不是直接写入到UART发送器,而是放进了一个环形缓冲区中
    的头像 发表于 02-19 16:23 451次阅读

    如何采用“状态机”解析UART数据

    如果一个系统接收上述“不定长度”的协议帧,将会有一个挑战--如何高效接收解析。 为简化系统设计,我们强烈建议您采用“状态机”来解析UART
    的头像 发表于 03-25 14:29 199次阅读
    如何采用“状态机”<b class='flag-5'>解析</b><b class='flag-5'>UART</b><b class='flag-5'>数据</b>帧