在STM32中编写串口通信数据收发有三种方式:轮询模式(阻塞方式),中断模式(非阻塞方式)以及DMA模式。

一. 串口通信(DMA模式)

    打开STM32CubeMX,前部分配置流程如串口数据收发基础(三)节里一样。配置好USART1的基本参数,开启定时器中断后,接下来就要开启USART1的DMA。 设置好之后,设置存储路径,选择所用IDE,然后点击GENERATE CODE创建工程,open project打开工程进行全局编译。

二. HAL库中串口收发的重要函数(DMA模式)

  1. DMA模式下发送数据函数:HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

@简介 以DMA模式发送一定数量的数据。

@参数 huart,指向UART_HandleTypeDef结构体的指针,该结构体包含指定UART模块的配置信息。

@参数 pData,待发送数据缓冲区的指针。

@参数 Size,待发送数据的字节数。

@返回值 函数执行状态。

  2. DMA模式下接收数据函数: HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

@简介 在DMA模式下接收一定数量的数据

@参数 huart,指向UART_HandleTypeDef结构体的指针,该结构体包含指定UART模块的配置信息。

@参数 pData,待接收接收数据缓冲区的指针。

@参数 Size,待接收数据的字节数。

@注意 当UART奇偶校验使能(PCE = 1)时,接收的数据包含奇偶校验位。

@返回值 函数执行状态。

  3. DMA模式下接收不定长数据函数: HAL_UARTEx_ReceiveToIdle_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

HAL_StatusTypeDef HAL_UARTEx_ReceiveToIdle_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

@简介 在DMA模式下接收一定数量的数据,直到接收到预期数量的数据或发生IDLE事件。

@注意 接收数据由这个函数调用发起。DMA服务实现了接收数据的进一步进展,在用户接收缓冲区中自动传输接收到的数据元素,并在接收传输过半/完成时调用回

调函数。UART IDLE事件也用于将接收阶段视为结束。在所有情况下,回调执行将指示接收到的数据元素的数量。

@参数 huart 指向UART_HandleTypeDef结构体的指针,该结构体包含指定UART模块的配置信息。

@参数 pData 待接收接收数据缓冲区的指针。

@参数 Size 待接收数据的字节数。

@返回值 函数执行状态。

  4. DMA模式数据传输完成回调函数:HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size);

__weak void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)

{

UNUSED(huart);

UNUSED(Size);

}

@简介 接收事件回调(使用高级接收服务后调用的Rx事件通知)。

@参数 huart UART handle

@参数 Size,应用程序接收缓冲区中可用数据的数量(表示接收缓冲区中数据可用的位置)

@返回值 空

  5.禁用指定的DMA通道中断函数:__HAL_DMA_DISABLE_IT(HANDLE, INTERRUPT) (CLEAR_BIT((HANDLE)->Instance->CCR , (INTERRUPT)));

#define __HAL_DMA_DISABLE_IT(__HANDLE__, __INTERRUPT__) (CLEAR_BIT((__HANDLE__)->Instance->CCR , (__INTERRUPT__)))

@简介 禁用指定的DMA通道中断。

@参数 __HANDLE__: DMA处理

@参数 __INTERRUPT__: 指明要启用或者禁用的DMA中断源

该参数可以是下列值的任意组合:

@arg DMA_IT_TC: 传输完成中断屏蔽

@arg DMA_IT_HT: 过半传输完成中断屏蔽

@arg DMA_IT_TE: 传输错误中断屏蔽

@返回值 空

以上提及的函数可在stm32f1xx_hal_uart.c 和 stm32f1xx_hal_dma.h中,在这些文件中找到

三. 实现串口定长收发通信(DMA模式)

 在main.c文件中的Private variables下的USER CODE BEGIN PV注释对中写入以下代码

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

unsigned char String_1[] = "hello world!!!\r\n";

unsigned char rx[16];

/* USER CODE END PV */

 在main.c文件中的Private function prototypes下的USER CODE BEGIN PFP注释对中写入以下代码

/* Private function prototypes -----------------------------------------------*/

void SystemClock_Config(void);

/* USER CODE BEGIN PFP */

// dma模式

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){

if(huart == &huart1){ // 将上位机发来的数据完整的返回回去

HAL_UART_Transmit_DMA(&huart1,rx,sizeof(rx));

HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_4);

HAL_UART_Receive_DMA(&huart1,rx,sizeof(rx));

}

}

/* USER CODE END PFP */

 在main.c文件中的main函数下USER CODE BEGIN 2 注释对写入以下代码

/* USER CODE BEGIN 2 */

HAL_UART_Transmit_IT(&huart1,String_1,sizeof(String_1));

HAL_UART_Receive_DMA(&huart1,rx,sizeof(rx));

/* USER CODE END 2 */

实现的效果是在当开发板通过USB转TTL模块与电脑上的串口调试助手相连后,上位机向开发板发送的数据。开发板接收到上位机发来的数据后,翻转PB4引脚上的LED灯亮灭,随后将接收到的数据原封不动的再返回给上位机。

四. 实现串口不定长收发数据通信(DMA模式)

 在main.c文件中的Private function prototypes下的USER CODE BEGIN PFP注释对中写入以下代码

/* Private function prototypes -----------------------------------------------*/

void SystemClock_Config(void);

/* USER CODE BEGIN PFP */

// dma模式

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size){

if(huart == &huart1){ // 将上位机发来的数据完整的返回回去

HAL_UART_Transmit_DMA(&huart1,rx,Size);

HAL_UARTEx_ReceiveToIdle_DMA(&huart1,rx,sizeof(rx));

}

}

/* USER CODE END PFP */

 在main.c文件中的main函数下USER CODE BEGIN 2 注释对写入以下代码

/* USER CODE BEGIN 2 */

HAL_UART_Transmit_IT(&huart1,String_1,sizeof(String_1));

HAL_UARTEx_ReceiveToIdle_DMA(&huart1,rx,sizeof(rx));

/* USER CODE END 2 */

实现的效果是在当开发板通过USB转TTL模块与电脑上的串口调试助手相连后,上位机向开发板发送的数据。开发板接收到上位机发来的数据后,随后将接收到的数据原封不动的再返回给上位机。 如下图可以发现依次发送不定长的数据给开发板后,开发板都完整的返回了。 但是当我们一次发送过多的数据后,返回的数据竟然不完整了。 这是因为在发送数据的时候,当我们接收的数据量达到设置的最大值的一半的时候 也就是这个 ,就会触发HAL_UARTEx_RxEventCallback回调函数。 为了解决这个问题,我们可以使用关闭“DMA传输过半中断”的函数,也就是__HAL_DMA_DISABLE_IT()函数。将其写入到HAL_UARTEx_RxEventCallback回调函数中 注意:如果编译出错为 **error: #20: identifier “hdma_usart1_rx” is undefined **时,说明标识符“hdma_usart1_rx”未定义。可以证明解决。 在usart.h中的USER CODE BEGIN Private defines注释对中添加extern DMA_HandleTypeDef hdma_usart1_rx; 编译,运行,串口调试助手,启动!!! 这个时候可以发现数据终于实现了正常的不定长收发了(只要不要写过我们的先前设定的rx数组长度就好了)

精彩内容

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: