STM32F407的串口接收不定长数据两种方式HAL库

概要

我的博客:https://hahaxiong0204.github.io
STM32的串口接收不定长数据,最近在看超子说物联网,感觉太麻烦了不适合直接上手,然后我自己总结了两种方法:
1、不利用DMA
2、利用DMA方式

整体架构流程

这个HAL整起来是方便,但是HAL整体来说对于细节很到位就是逻辑很强逻辑,也就很繁琐,效率又不高,还缺胳膊少腿的。好用,就比如说这个串口接收,没有专门的方法调用。搞的就很麻烦,我第一次接触就是这感觉哈,大佬除外。

然后我看到超子说物联网可以用这个串口的空闲中断来搞这个串口的不定长接收。

大致的原理是:在接收每一段数据帧之后就会放开这个串口,产生了这个串口的空闲中断(IDLE),然后我们可以捕捉这个UART_FLAG_IDLE这个标志位,然后这个标志位被置位了,我们就可以说这段数据被接收完成了。

我们使用STM32F407给大家做一下,大概流程

不用DMA的方式

先选择SYS
在这里插入图片描述
在这里插入图片描述

使能串口1
在这里插入图片描述
开启中断
在这里插入图片描述
配置时钟
在这里插入图片描述
在这里插入图片描述
生成工程
在这里插入图片描述
进入代码打开usart.c的MX_USART1_UART_Init这个函数在后面加上开启中断的代码

开启串口接收和串口的空闲中断之后就是一直等待 ,等待串口接收到数据,一旦接收数据就触发串口中断进入USART1_IRQHandler函数

void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */
  /* USER CODE END USART1_Init 0 */
  /* USER CODE BEGIN USART1_Init 1 */
  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */
  __HAL_UART_ENABLE_IT(&huart1,UART_IT_RXNE);    // 开启接收中断
  __HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);      // 开启串口的空闲中断
  /* USER CODE END USART1_Init 2 */

}

在stm32f4xx_it.c中,分别判断是否是接收中断还是空闲中断,如果是接收中断调用HAL_UART_Receive去接收一个数组,当一个数据帧接受完,就触发了空闲中断,以为串口接不到数据了,就直接放开串口,进入空闲中断后操作。

// 定义变量
uint8_t rx_buffer[100];//接收数组
uint8_t rx_len = 0; //接收到的数据长度
/**
  * @brief This function handles USART1 global interrupt.
  */
void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
  uint8_t res;
  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */
 
  if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_RXNE) != RESET)   // 接收中断的标志位
  {
    HAL_UART_Receive(&huart1,&res,1,1000);
    if(rx_len>=100)
    {
        rx_len = 0;    //防止串口被刷爆  就是防止越界
    }
    rx_buffer[rx_len++] = res;
    __HAL_UART_CLEAR_FLAG(&huart1,UART_FLAG_RXNE);
  }
  
  if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE) != RESET)    // 空闲中断的标志位
  {
    HAL_UART_Transmit(&huart1,rx_buffer,rx_len,1000);
    rx_len = 0;
    __HAL_UART_CLEAR_IDLEFLAG(&huart1);      // 清除空闲中断的标志位
  }
  
  /* USER CODE END USART1_IRQn 1 */
}

在这里插入图片描述

使用DMA方式

在创建工程的时候方法一样只需要在

在这里插入图片描述
在这里插入图片描述
还是在usart.c的MX_USART1_UART_Init这个函数在后面加上开启中断的代码,开启DMA的接收

void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */
  HAL_UART_Receive_DMA(&huart1,rx_buffer,100);    // 开启DMA接收
  __HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);      // 开启串口的空闲中断
  /* USER CODE END USART1_Init 2 */

}

进入中断函数

#define MAX 100
uint8_t rx_buffer[MAX];//接收数组
uint8_t rx_len = 0; //接收到的数据长度
void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */

  if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE) != RESET)    // 空闲中断的标志位
  {
    HAL_UART_DMAStop(&huart1);                               //停止接收
    rx_len = MAX - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);    // 计算接收的数据长度
    HAL_UART_Transmit(&huart1,rx_buffer,rx_len,1000);
    HAL_UART_Receive_DMA(&huart1,rx_buffer,100);         // 开启DMA继续接收
    __HAL_UART_CLEAR_IDLEFLAG(&huart1);
  }
  
  /* USER CODE END USART1_IRQn 1 */
}

在这里插入图片描述

小结

简单来说,就是利用接收数据后,数据的空闲时间来做有些事情把这些数据保存起来。

  • 12
    点赞
  • 67
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论
STM32 HAL库中,串口接收不定数据方式可以通过使用中断实现。以下是一些基本步骤: 1. 配置串口工作模式为中断模式 ``` UART_HandleTypeDef huart; huart.Instance = USARTx; huart.Init.BaudRate = 115200; huart.Init.WordLength = UART_WORDLENGTH_8B; huart.Init.StopBits = UART_STOPBITS_1; huart.Init.Parity = UART_PARITY_NONE; huart.Init.Mode = UART_MODE_TX_RX; huart.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart.Init.OverSampling = UART_OVERSAMPLING_16; huart.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; huart.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; HAL_UART_Init(&huart); /* Enable UART RX interrupt */ __HAL_UART_ENABLE_IT(&huart, UART_IT_RXNE); ``` 2. 实现串口接收中断服务函数 ``` void USARTx_IRQHandler(void) { uint32_t isrflags = READ_REG(huart.Instance->SR); if (isrflags & USART_SR_RXNE) { /* Read data from the USART RX register */ uint8_t rx_data = (uint8_t)(huart.Instance->DR & 0xFF); /* Process the received data */ // ... } } ``` 3. 在中断服务函数中处理接收的数据 在中断服务函数中,读取接收数据寄存器中的数据,并进行处理。处理方式可以根据具体应用场景而定。例如,可以将接收的数据存储到一个缓冲区中,直到达到特定条件时再进行处理。 注意事项: - 在中断服务函数中,要根据实际情况判断接收到的数据是否已经达到预期度,防止缓冲区溢出等问题。 - 在处理接收数据时,要注意保护共享资源的安全,例如使用互斥锁等机制。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哈哈啊哈h

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值