STM32HAL-快速入门十八UART-编程一-查询方式实现串口收发
STM32HAL 快速入门(十八):UART 编程(一)—— 查询方式实现串口收发
前言
大家好,这里是 Hello_Embed。上一篇我们拆解了 STM32 UART 的硬件结构,理解了寄存器配置、数据收发的底层流程。本篇将进入实战环节,先用最基础的 “查询方式” 实现串口通信 —— 完成 “单片机发送字符串到电脑”“电脑发送字符,单片机接收后加一返回” 两个功能,同时明确查询方式的优缺点,为下一篇 “中断方式” 和后续 “DMA 方式” 铺垫。
一、实战准备:硬件连接与驱动安装
在编程前,需先完成硬件连接、驱动安装和串口工具配置,确保单片机与电脑能正常通信。
1. 硬件连接:TX 与 RX 交叉对接
需使用 “USB-TTL 转接器” 连接单片机与电脑,核心原则是 “发送接接收,接收接发送”:
- 转接器的 TXD → 单片机的 PA10(USART1_RX);
- 转接器的 RXD → 单片机的 PA9(USART1_TX);
- 转接器的 GND → 单片机的 GND(共地,避免信号干扰)。
实际连接可借助面包板,确保引脚接触可靠,转接器实物示意:
2. 驱动安装与 COM 口确认
- 安装 USB-TTL 转接器驱动(如 CH340 驱动,可在 B 站搜索安装教程,此处不展开);
- 驱动安装完成后,将转接器插入电脑 USB 口,打开 “设备管理器→端口”,确认串口对应的 COM 号(本文为 COM9),后续串口工具需匹配此 COM 口:
二、UART 三种编程方式对比
结合 UART 硬件结构,常用编程方式有三种,核心区别在于 “CPU 参与度” 和 “效率”:
编程方式 | 核心逻辑 | 优点 | 缺点 | 适用场景 |
---|---|---|---|---|
查询方式 | CPU 轮询状态寄存器(SR),判断收发时机 | 逻辑简单,代码量少 | 占用 CPU 资源,数据不及时读取易丢失 | 简单调试、低速率小数据量通信 |
中断方式 | 硬件触发中断,CPU 仅在中断时处理收发 | 不占用 CPU 资源,响应快 | 逻辑稍复杂,需处理中断回调 | 中速率数据通信,需兼顾其他任务 |
DMA 方式 | DMA 替 CPU 完成寄存器与内存的数据搬运 | 完全不占用 CPU 资源 | 配置复杂,需理解 DMA 硬件逻辑 | 高速、大数据量通信(如 LCD 显示 + 串口收发) |
本篇聚焦 “查询方式”,后续两篇将分别讲解中断和 DMA 方式,三种方式的核心函数参考:
三、CubeMX 配置 UART(USART1)
查询方式的配置非常简单,只需使能 UART 异步模式并确认基础参数:
- 选择 UART 外设:
进入 “Connectivity→USART1”,设置 “Mode” 为 “Asynchronous”(异步模式),系统会默认分配 PA9(TX)和 PA10(RX),无需修改引脚: - 确认通信参数:
进入 “Parameter Settings”,检查基础参数是否符合默认配置(与电脑串口工具需一致):
- 波特率(Baud Rate):115200(常用速率,兼顾速度与稳定性);
- 数据位(Word Length):8 Bits;
- 校验位(Parity):None(无校验);
- 停止位(Stop Bits):1 Bit;
无需修改其他配置(中断、DMA 暂不启用):
- 生成工程:
配置完成后生成代码,工程中会自动添加 USART 相关文件(如stm32f1xx_hal_usart.c
),并在main.c
中生成初始化函数MX_USART1_UART_Init()
。
四、查询方式代码实现
查询方式的核心是 “CPU 通过轮询状态寄存器,判断是否可收发数据”,主要使用 HAL 库的HAL_UART_Transmit
(发送)和HAL_UART_Receive
(接收)函数。
1. 串口发送:单片机→电脑
目标:单片机循环发送字符串 “Hello_Embed !\r\n” 到电脑,通过串口工具查看。
- 定义发送数据:
在main.c
的 “USER CODE BEGIN 2” 区域定义要发送的字符串:
/* USER CODE BEGIN 2 */
char *str = "Hello_Embed !\r\n"; // 要发送的字符串,\r\n是换行符
/* USER CODE END 2 */
- 调用发送函数:
在while(1)
循环中调用HAL_UART_Transmit
,函数参数解析如下:
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout)
*huart
:UART 句柄指针,此处为&huart1
(CubeMX 自动定义的 USART1 句柄);*pData
:发送数据缓冲区指针,此处为(uint8_t *)str
(字符串强转为字节指针);Size
:发送数据长度,用strlen(str)
获取字符串实际长度(不含结束符 ‘\0’);Timeout
:超时时间(ms),设为 1000(1 秒内未发送完成则返回超时错误)。
完整发送代码:
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
// 发送字符串到电脑
HAL_UART_Transmit(&huart1, (uint8_t *)str, strlen(str), 1000);
HAL_Delay(500); // 延时500ms,避免数据发送过快
/* USER CODE END 3 */
}
- 实验结果:
打开串口工具(本文用 “纸飞机”),选择 COM9、波特率 115200,烧录程序后,工具会持续收到字符串,证明发送成功:
2. 串口接收与返回:电脑→单片机→电脑
目标:电脑发送一个字符,单片机接收后加 1 返回(如发送 ‘1’ 返回 ‘2’,发送 ‘a’ 返回 ‘b’)。
- 定义接收相关变量:
/* USER CODE BEGIN 2 */
char *str1 = "Please enter a char : \r\n"; // 提示用户输入
char c; // 存储接收的字符
/* USER CODE END 2 */
- 接收与返回逻辑:
在while(1)
中先发送提示信息,再等待接收电脑发送的字符,接收成功后加 1 返回:
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
// 1. 发送提示信息
HAL_UART_Transmit(&huart1, (uint8_t *)str1, strlen(str1), 1000);
// 2. 等待接收电脑发送的1个字符(超时100ms,循环等待直到接收成功)
while (HAL_OK != HAL_UART_Receive(&huart1, (uint8_t *)&c, 1, 100));
// 3. 字符加1(ASCII码递增)
c = c + 1;
// 4. 返回加1后的字符,加换行符便于查看
HAL_UART_Transmit(&huart1, (uint8_t *)&c, 1, 1000);
HAL_UART_Transmit(&huart1, (uint8_t *)"\r\n", 2, 1000); // \r\n占2个字节
/* USER CODE END 3 */
}
- 关键说明:
HAL_UART_Receive
参数:接收 1 个字符(Size=1
),超时 100ms;用while
循环等待HAL_OK
(接收成功),避免提示信息不停发送;- 字符加 1 原理:字符在计算机中以 ASCII 码存储,如 ‘1’ 的 ASCII 码是 0x31,加 1 后变为 0x32(对应 ‘2’),‘a’(0x61)加 1 后变为 ‘b’(0x62)。
- 实验结果:
电脑发送 ‘1’,单片机返回 ‘2’;发送 ‘a’,返回 ‘b’;用 HEX 模式发送 0x31(即 ‘1’ 的 ASCII 码),返回 0x32(即 ‘2’),符合预期:
五、查询方式的缺陷
虽然查询方式实现简单,但存在明显不足:数据不及时读取易丢失。例如,电脑快速发送 “12345”,单片机因轮询等待,可能只接收到部分字符(如仅收到 ‘1’ 和 ‘3’),无法完整返回 “23456”—— 这是因为 CPU 在处理前一个字符时,后一个字符已被新数据覆盖。
要解决数据丢失问题,需采用 “中断方式” 让硬件主动通知 CPU 接收数据,这正是下一篇笔记的重点。
结尾
本文用查询方式实现了 UART 的基础收发功能,理解了 HAL 库HAL_UART_Transmit
和HAL_UART_Receive
的用法,同时明确了查询方式的适用场景与缺陷。下一篇我们将学习 “UART 中断方式”,通过中断回调函数高效处理收发,彻底解决数据丢失问题。
Hello_Embed 继续带你从基础到进阶,逐步掌握 UART 的高效编程技巧,敬请期待~