【STM32】HAL库教程-USART串口通信

使用工具和依赖

  • 芯片:STM32F103ZET6、USB转TTL模块(CH340)
  • 代码初始化软件:STM32CUBEMX
  • IDE:MDK-ARM Keil5
  • 依赖:stm32c0xx hal库

接收空闲中断

在这一节中,我们将重点讲解HAL_UARTEx_ReceiveToIdle_DMA这个函数的作用与正确用法。

主要解决的问题

传统 HAL_UART_Receive_DMA() 需要你预先知道固定长度,或者等DMA满缓冲区才算“一帧完成”。而实际串口通信经常是变长帧(例如上位机一次发 7 字节、下一次发 23 字节),此时最常用的帧结束判据就是 UART IDLE(空闲线):接收线上在收到若干字节后,出现“一个字节时间以上无数据”,就认为这一帧结束。

HAL_UARTEx_ReceiveToIdle_DMA() 做的事情就是:

  • 启动 DMA循环/非循环接收(取决于HAL内部配置方式,常见是DMA正常模式 + 每次事件后重启)
  • 同时使能 IDLE中断
  • 当发生以下任一事件时,HAL会触发“接收事件”机制并最终进入回调:
    • IDLE事件:本次收到的字节数为“从启动到空闲出现的字节数”
    • DMA半传输/全传输(取决于你是否使能HT中断、缓冲区大小、是否希望流式处理)

函数原型与关键参数

1
2
3
4
5
HAL_StatusTypeDef HAL_UARTEx_ReceiveToIdle_DMA(
UART_HandleTypeDef *huart,
uint8_t *pData,
uint16_t Size
);
  • pData:DMA写入的缓冲区首地址

  • Size:缓冲区容量(最大能接收多少字节)

  • 该函数返回 HAL_OK 仅表示“成功启动接收流程”,并不表示收到了数据。

代码示例

首先须在CubeMX软件中配置USART的模式(Mode)为异步(Asynchronous),打开RX和TX两路通道的DMA,设置DMA的模式(Mode)为普通(Normal). 在main.c函数中加入以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/* main.c */
#include "main.h"
#include "dma.h"
#include "usart.h"
#include "gpio.h"

#define RX_BUF_LEN 64
uint8_t rx_buf[RX_BUF_LEN];
uint8_t msg[] = "UART DMA Test \r\n";

void SystemClock_Config(void);

int main(void)
{
HAL_Init();
SystemClock_Config();

MX_GPIO_Init();
MX_DMA_Init();
MX_USART2_UART_Init();

// 配置并启动 UART RX 的 DMA 传输
HAL_UARTEx_ReceiveToIdle_DMA(&huart2, rx_buf, RX_BUF_LEN);

while (1)
{

}

}

/* USER CODE BEGIN 4 */
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
if (huart->Instance != USART2) return;
if (Size == 0) return;

HAL_UART_Transmit_DMA(huart, msg, (uint16_t)(sizeof(msg) - 1));

HAL_UARTEx_ReceiveToIdle_DMA(huart, rx_buf, RX_BUF_LEN);
}
/* USER CODE END 4 */