基于stm32的UART高效接收DMA+IDLE编程HAL库

发布于:2024-04-23 ⋅ 阅读:(183) ⋅ 点赞:(0)

基于stm32的UART高效接收DMA+IDLE编程HAL库

本文目标:基于stm32的UART高效接收DMA+IDLE编程HAL库

按照本文的描述,应该可以在对应的硬件上通实验并举一反三。

先决条件:拥有C语言基础,装有编译和集成的开发环境,比如:Keil uVision5

使用外设:USART2、GPIO

HAL库版本:STM32F1xx HAL Driver version number 1.8.5

STMCubeMX版本:6.10.0

Keil uVision5版本:V5.38.0.0

实验目的

新手学习UART实验,使用串口的DMA+IDLE空闲中断进行接收数据。

使用场景原理图

在我的应用场景中,设计一个实验进行自发的实验,其中我这里使用串口2进行实验

在这里插入图片描述

其中涉及使用的HAL库API如下:

//查询方式:
//发送:
HAL_UART_Transmit
//接收: 
HAL_UART_Receive
    
//中断方式:
//发送:
HAL_UART_Transmit_IT
HAL_UART_TxCpltCallback 
//接收: 
HAL_UART_Receive_IT
HAL_UART_RxCpltCallback
    
//DMA方式:
//发送:
HAL_UART_Transmit_DMA
HAL_UART_TxHalfCpltCallback
HAL_UART_TxCpltCallback
//接收: 
HAL_UART_Receive_DMA
HAL_UART_RxHalfCpltCallback
HAL_UART_RxCpltCallback
    
// 错误
HAL_UART_ErrorCallback
HAL_UART_ErrorCallback
  

IDLE

IDLE,空闲的定义是:总线上在一个字节的时间内没有再接收到数据。UART 的 IDLE 中断何时发生?RxD 引脚一开始就是空闲的啊,难道 IDLE 中断一直产生?不是的。当我们使能 IDLE 中断后,它并不会立刻产生,而是:至少收到 1 个数据后,发现在一个字节的时间里,都没有接收到新数据,才会产生 IDLE 中断。我们使用 DMA 接收数据时,确实可以提高 CPU 的效率,但是“无法预知要接收多少数据”,而我们想尽快处理接收到的数据。怎么办?比如我想读取 100 字节的数据,但是接收到 60 字节后对方就不再发送数据了,怎么办?我们怎么判断数据传输中止了?可以使用IDLE 中断。在这种情况下,DMA 传输结束的条件有 3:

① 接收完指定数量的数据了,比如收到了 100 字节的数据了,HAL_UART_RxCpltCallback被调用

② 总线空闲了:HAL_UARTEx_RxEventCallback 被调用

③ 发生了错误:HAL_UART_ErrorCallback 被调用

使用 IDLE 状态来接收的函数有:

//查询方式:
//接收: 
HAL_UARTEx_ReceiveToIdle
//回调函数:
//根据返回参数 RxLen 判断是否接收完毕,还是因为空闲而返回
    
//中断方式:
//接收: 
HAL_UARTEx_ReceiveToIdle_IT
//回调函数:
完毕:HAL_UART_RxCpltCallback
因为空闲而中止:
HAL_UARTEx_RxEventCallback

//DMA方式:
//接收: 
HAL_UARTEx_ReceiveToIdle_DMA
//回调函数:
传输一半:
HAL_UART_RxHalfCpltCallback
完毕:
HAL_UART_RxCpltCallback
因为空闲而中止:
HAL_UARTEx_RxEventCallback

// 错误
HAL_UART_ErrorCallback

程序设计

① 使用 DMA+IDLE 中断的方式接收数据,使用全局的数组来进行接收;

② main函数中将接收到的数据发回上位机。

串口配置

打开配置工具,进行串口配置

在这里插入图片描述

配置中断

在这里插入图片描述

配置DMA

在这里插入图片描述

代码片段

按照上述的配置进行底层配置之后,我们写点代码,进行接收数据,我们简单粗暴的写点函数,如下的代码片段

// 接收完成进入
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if (huart == &huart2)
	{
		g_uart2_rx_complete = 1;
		Uart2ReciveDataSize = UART2_RECIVE_MAX;
		HAL_UART_Receive_DMA(&huart2,Uart2ReciveBuff,UART2_RECIVE_MAX);  // 重新启动接收
	}	
}
// 空闲中断进入
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
	if (huart == &huart2)
	{
		g_uart2_rx_complete = 1;
		Uart2ReciveDataSize = Size;
		/* re-start DMA+IDLE rx */
		HAL_UARTEx_ReceiveToIdle_DMA(&huart2, Uart2ReciveBuff, UART2_RECIVE_MAX);
	}	
}

接收错误进入

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
	if (huart == &huart2)
	{
		/* re-start DMA+IDLE rx */
		HAL_UARTEx_ReceiveToIdle_DMA(&huart2, Uart2ReciveBuff, UART2_RECIVE_MAX);
	}
}

main函数中代码片段

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART1_UART_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */
  HAL_UART_Receive_DMA(&huart2,Uart2ReciveBuff,UART2_RECIVE_MAX);  // 开启接收
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
	if(g_uart2_rx_complete == 1)
	{
		g_uart2_rx_complete = 0;
		HAL_UART_Transmit_DMA(&huart2,Uart2ReciveBuff,Uart2ReciveDataSize);  // 将接收的数据进行回显
	}
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

编译、烧写、运行,可以看到开发板的上的串口能成功接收数据,将接收到的数据进行回显,实验设计成功。

在这里插入图片描述

工程实验成功,后续将会继续记录项目中的实验,感谢关注。

本文中使用的测试工程

https://download.csdn.net/download/weixin_44317448/89208845


网站公告

今日签到

点亮在社区的每一天
去签到