HAL库串口接收不定长数据,并使用环形队列处理每一帧数据

简介

以USART2接受数据为例,环形队列可以循环使用缓冲区的空间,并且可以处理到每一帧数据,适合收发数据比较频繁的场景

正文

初始化后利用中断接受一字节数据
在这里插入图片描述

void USART2_IRQHandler(void)
{
  HAL_UART_IRQHandler(&huart2);
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  if(huart->Instance ==USART2)
  {
    HAL_UART_Transmit(&huart2,&rx_data,1,0xffff);   /*将接收到的数据发送出去*/
    HAL_UART_Receive_IT(&huart2,&rx_data,1);        /*接受下一字节数据*/
  }
}

顺利的话我们就能把接受到的数据原封不动的发送出去,之后进行下一步

下面是串口通信使用环形队列的一种方式

usart.h文件

#define UART2_RX_BUF_SIZE 200
#define RING_BUF_DATA_TYPE     unsigned char
uint8_t ring_buf_read(RING_BUF_DATA_TYPE* pdata);

usart.c文件

uint8_t rx_data = 0;
typedef struct {
  RING_BUF_DATA_TYPE uart1_rx_data[UART2_RX_BUF_SIZE];
  uint16_t data_len;
  uint16_t read_index; 
}RING_BUF_TYPEDEF;
RING_BUF_TYPEDEF ring_buf={0};

/*初始化环形缓冲区*/
uint8_t ring_buf_init(RING_BUF_TYPEDEF* r_buf)
{
  r_buf->data_len =0;
  r_buf->read_index = 0;
  return 0;
}
/*环形缓冲区为空或者数据已经被读完*/
uint8_t ring_buf_is_empty()
{
  if(ring_buf.data_len == ring_buf.read_index)
  {
    return 1;/*环形缓冲区为空返回1*/
  }
  return 0;
}
/*环形缓冲区爆满*/
uint8_t ring_buf_is_fill()
{
  if(ring_buf.data_len == ring_buf.read_index - 1)
  {
    return 1;/*环形缓冲区爆满返回1*/
  }
  return 0;
}
/*往环形缓冲区中写数据*/
uint8_t ring_buf_write(RING_BUF_DATA_TYPE data)
{
  if(ring_buf_is_fill() == 0)/*环形缓冲区未满*/
  {
    if(ring_buf.data_len==UART2_RX_BUF_SIZE)
    {
      ring_buf.data_len = 0;
    }
    ring_buf.uart1_rx_data[ring_buf.data_len]=data;
    ring_buf.data_len++;
    return 1; /*写成功*/
  }
  return 0;   /*写失败*/
}
/*从环形缓冲区中读数据*/
uint8_t ring_buf_read(RING_BUF_DATA_TYPE* pdata)
{
  int16_t i = 1000;
  while(ring_buf_is_empty() != 0 && i >= 0)//接受可能过快等一段时间
  {
    i--;
  }
  if(ring_buf_is_empty()==0)  /*环形缓冲区非空*/
  {
    if(ring_buf.read_index == UART2_RX_BUF_SIZE)
    {
      ring_buf.read_index = 0;
    }
    *pdata= ring_buf.uart1_rx_data[ring_buf.read_index];
    ring_buf.read_index++;
    return 1; /*读成功*/
  }
  return 0;   /*读失败*/
}

main.c文件

void main()
{
  /*省略.....*/
  while (1)
  {
    /* USER CODE END WHILE */
		if(ring_buf_read(&temp8))
    {
      printf("%c",temp8);
    }
    HAL_Delay(100);
    /* USER CODE BEGIN 3 */
  }
}

最后效果,只要保证缓冲区不出现饱满,的情况可以每隔较长时间处理每一帧数据
在这里插入图片描述

下面是一个应用,假设以16进制 AA BB CC 为指定命令。

void main()
{
  /*省略......*/
  while (1)
  {
    if(ring_buf_read(&temp8)==0) continue;
    if(temp8 == 0xAA)
    {
      if(ring_buf_read(&temp8)==0) continue;
      if(temp8 == 0xBB)
      {
        if(ring_buf_read(&temp8)==0) continue;
        if(temp8==0xCC)
        {
          printf("接收到指定命令\r\n");
        }
      }
    }
  }
}

在这里插入图片描述

  • 13
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值