【官方原创】如何在STM32CubeMX2中使用UART

摘要

本文简要介绍如何通过STM32CubeMX2开启并配置UART(universal asynchronous receiver transmitter,通用异步收发器)。本教程基于NUCLEO-C562RE开发板,覆盖以下UART功能:

  • polling mode(轮询模式)

  • 中断

  • DMA(direct memory access,直接存储器访问)


简介

USART/UART(universal synchronous / asynchronous receiver transmitter,通用同步/异步收发器)可与外部设备进行全双工数据交互,采用业界标准NRZ(non-return-to-zero,不归零)异步串行数据格式。

USART通过可编程波特率发生器支持多种波特率;同时支持同步单向通信、半双工单线通信以及多处理器通信。

其他支持功能包括:本地互联网络(local interconnect network,LIN)、智能卡协议、红外SIR编解码、调制解调器硬件流控(CTS/RTS)。借助DMA多缓冲区配置可以实现高速数据传输,UART也可配合中断方式工作。


前置准备

本教程使用硬件:NUCLEO-C562RE开发板。


1. STM32CubeMX2工程创建与基础配置

按照以下步骤创建NUCLEO-C562RE应用工程,完成一个简单USART示例程序。

++1.1 创建工程++

打开STM32CubeMX2,在Home页点击MCU新建工程。

在MCU名称搜索框输入STM32C562RE,选中芯片,点击Continue。

填写工程名称与保存路径,点击Automatically Download,Install \& Create Project完成工程创建。

点击Launch Project打开工程。

++1.2 引脚与外设配置++

在STM32CubeMX2 界面进入Peripherals外设区域,选择Connectivity连接外设,选择异步模式使能UART。

按图示配置USART2外设:

NUCLEO板载VCOM虚拟串口桥接电路使用USART2_TX、USART2_RX,对应引脚PA2、PA3,但软件默认选中引脚不一定是这一组。可以在下方滚动修改TX/RX对应的GPIO引脚。

切换到Pinout视图,添加用户LED。右键PA5,配置为GPIO引脚

再点击齿轮图标,在GPIO配置页,标签设置为USER_LED,引脚模式配置为推挽输出。

++1.3 生成代码++

生成代码操作:

  • 点击Project settings工程设置图标,选择目标IDE。
  • 点击Generate按钮生成工程代码。

2. 在 Visual Studio Code中配置工程

打开VS Code并打开工程文件夹。弹出配置选择框则直接选择;未弹出则按下Ctrl+Shift+P,输入CMake:Select Configure Preset,选择调试配置。

编译工程确认环境无误,之后进行代码开发。

++2.1 代码编辑++

VS Code打开生成的工程后修改main.c。该示例将C库printf、getchar重定向到UART外设,使用HALUART轮询收发接口,在串口终端工具(Tera Term或者VS Code内置终端)实现回显功能。

复制代码
/** ****************************************************************************** * file :main.c * brief :Main program body * Calls target system initialization then loop in main. ****************************************************************************** * * Copyright (c) 2025 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** *//* Includes ------------------------------------------------------------------*/#include "main.h"#include <stdio.h> /* C library input/output functions */#include <string.h> /* importing memcmp and memset functions */
/* Private typedef -----------------------------------------------------------*//* Private define ------------------------------------------------------------*/#define RX_TIMEOUT 10000U#define TX_TIMEOUT 1000U#define MAX_BUFFER_SIZE 26U
/* Private macro -------------------------------------------------------------*//* Private variables ---------------------------------------------------------*/uint8_t RxBuffer[MAX_BUFFER_SIZE]; /* Reception buffer *//* Private functions prototype -----------------------------------------------*//** ----------------------------------------------------------- * Definitions of C library functions re-targeted to the UART. * ----------------------------------------------------------- */
int __io_getchar(void) { uint8_t ch = 0; HAL_UART_Receive(mx_usart2_uart_gethandle(), (uint8_t *)&ch, 1, 10000); return ch;}
int __io_putchar(int ch) { HAL_UART_Transmit(mx_usart2_uart_gethandle(), (uint8_t *)&ch, 1, 100); return ch;}
/** * brief: The application entry point. * retval: none but we specify int to comply with C99 standard */int main(void) { /** System Init: this code placed in targets folder initializes your system. * It calls the initialization (and sets the initial configuration) of the * peripherals. You can use STM32CubeMX to generate and call this code or not * in this project. It also contains the HAL initialization and the initial * clock configuration. */ if (mx_system_init() != SYSTEM_OK) { return (-1); } else { /* * You can start your application code here */ printf("USART2 echo example\r\n"); /** System Init: this generated code placed in targets folder initializes * your system. It calls the initialization (and sets the initial * configuration) of the peripherals. You can use STM32CubeMX to generate * and call this code or not in this project. It also contains the HAL * initialization and the initial clock configuration. */setvbuf(stdin, NULL, _IONBF, 0); while (1) { int idx = 0; int ch; printf("Input: "); // prompt before typing // Receive chars until '\n', '\r' or '\b' while (1) { ch = getchar(); // uses HAL_UART_Receive in polling if (ch == '\n' || ch == '\r' || ch == '\b') { break; } if (idx < (MAX_BUFFER_SIZE - 1)) { RxBuffer[idx++] = (char)ch; } }RxBuffer[idx] = '\0'; // Echo received data printf("\n Echo: %s\r\n", RxBuffer); for (idx = 0; idx < MAX_BUFFER_SIZE; idx++) { RxBuffer[idx] = 0; } } }} /* end main */

++2.2 功能验证++

编译完成后,点击Run and Debug图标,调试会话选择STM32Cube: STLINK GDB Server。

按下Ctrl+Shift+P,输入Open Serial>COMXY(STMicroelectronics)> 115200


3. UART中断方式使用

本固件示例替换getchar函数,使用硬件中断实现响应式回显,无数据处理时CPU可以保持空闲。系统初始化完成打印欢迎信息后,程序进入空死循环;通信采用事件驱动:每收到一个字符,硬件触发回调函数,将收到字符回显至终端;检测到回车键时追加换行符,最后重新开启中断接收。

在STM32CubeMX2的USART2配置页面向下找到System系统选项,或者快捷菜单点击NVIC。

重新生成工程。

提示:可以通过高级设置指定工程重新生成策略,例如备份上一版示例工程。

下面是中断示例完整main.c代码:

复制代码
/** ****************************************************************************** * file :main.c * brief : Main program body * Calls target system initialization then loop in main. ****************************************************************************** * * Copyright (c) 2025 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** *//* Includes ------------------------------------------------------------------*/#include "main.h"#include <stdio.h> /* C library input/output functions */#include <string.h> /* importing memcmp and memset functions */
/* Private typedef -----------------------------------------------------------*//* Private define ------------------------------------------------------------*/#define RX_TIMEOUT 10000U#define TX_TIMEOUT 1000U#define MAX_BUFFER_SIZE 2U
/* Private macro -------------------------------------------------------------*//* Private variables ---------------------------------------------------------*/uint8_t RxBuffer[MAX_BUFFER_SIZE]; /* Reception buffer */
/* Private functions prototype -----------------------------------------------*//** ----------------------------------------------------------- * Definitions of C library functions re-targeted to the UART. * ----------------------------------------------------------- */ int __io_putchar(int ch) { HAL_UART_Transmit(mx_usart2_uart_gethandle(), (uint8_t *)&ch, 1, 100); return ch;}
void HAL_UART_RxCpltCallback(hal_uart_handle_t *huart, uint32_t size_byte,hal_uart_rx_event_types_t rx_event) { HAL_UART_Transmit(mx_usart2_uart_gethandle(), RxBuffer, 1, 10); if (RxBuffer[0] == '\r') { uint8_t newline = '\n'; HAL_UART_Transmit(mx_usart2_uart_gethandle(), &newline, 1, 10); } HAL_UART_Receive_IT(mx_usart2_uart_gethandle(), RxBuffer, 1);}
/** * brief: The application entry point. * retval: none but we specify int to comply with C99 standard */int main(void) { /** System Init: this code placed in targets folder initializes your system. * It calls the initialization (and sets the initial configuration) of the * peripherals. You can use STM32CubeMX to generate and call this code or not * in this project. It also contains the HAL initialization and the initial * clock configuration. */ if (mx_system_init() != SYSTEM_OK) { return (-1); } else { /* * You can start your application code here */ printf("USART2 RX IT echo example\r\n"); HAL_UART_Receive_IT(mx_usart2_uart_gethandle(), RxBuffer, 1); while (1) { } }} /* end main */

编译工程,完成调试配置后,按下Ctrl+Shift+P,输入Open Serial,选择COM40(STMicroelectronics),波特率115200。

此时程序正常运行,终端保持本地回显。


4. UART DMA方式使用

该示例不再使用中断,改用DMA传输预设数据;等待收到10字节数据块后触发接收回调,无数据处理时CPU保持空闲。

进入STM32CubeMX2的USART2配置页,向下找到System系统选项,或者快捷菜单点击DMA。

开启DMA发送与DMA接收,展开下拉选项完成配置。

重新生成工程,在IDE打开项目。

本示例配置STM32使用DMA异步处理UART通信,CPU可以并行处理其他任务。上电后后台立刻开启接收器等待接收数据。

主循环每10秒发送一次ASCII字符串"ABCDEFGHIJ";当收到恰好10字节数据时触发回调函数。回调内部自动重新使能接收,保证开发板可以接收下一组数据,不会打断周期性发送。

main.c代码片段:

复制代码
/** ****************************************************************************** * file :main.c * brief : Main program body * Calls target system initialization then loop in main. ****************************************************************************** * * Copyright (c) 2025 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** *//* Includes ------------------------------------------------------------------*/#include "main.h"#include <stdio.h> /* C library input/output functions */#include <string.h> /* importing memcmp and memset functions *//* Private typedef -----------------------------------------------------------*//* Private define ------------------------------------------------------------*/#define RX_TIMEOUT 10000U#define TX_TIMEOUT 1000U#define MAX_BUFFER_SIZE 10U
/* Private macro -------------------------------------------------------------*//* Private variables ---------------------------------------------------------*/uint8_t RxBuffer[MAX_BUFFER_SIZE]; /* Reception buffer *//* Buffer used for transmission */uint8_t TxBuffer[]={65,66,67,68,69,70,71,72,73,74}; //ABCDEFGHIJ in ASCII code/* Private functions prototype -----------------------------------------------*//** ----------------------------------------------------------- * Definitions of C library functions re-targeted to the UART. * ----------------------------------------------------------- */int __io_putchar(int ch) { HAL_UART_Transmit(mx_usart2_uart_gethandle(), (uint8_t *)&ch, 1, 100); return ch;}
void HAL_UART_RxCpltCallback(hal_uart_handle_t *huart, uint32_t size_byte, hal_uart_rx_event_types_t rx_event) { HAL_UART_Transmit_DMA(mx_usart2_uart_gethandle(), RxBuffer, MAX_BUFFER_SIZE); HAL_UART_Receive_DMA(mx_usart2_uart_gethandle(), RxBuffer, MAX_BUFFER_SIZE);}
/** * brief: The application entry point. * retval: none but we specify int to comply with C99 standard */
 int main(void) { /** System Init: this code placed in targets folder initializes your system. * It calls the initialization (and sets the initial configuration) of the * peripherals. You can use STM32CubeMX to generate and call this code or not * in this project. It also contains the HAL initialization and the initial * clock configuration. */ if (mx_system_init() != SYSTEM_OK) { return (-1); } else { /* * You can start your application code here */ printf("USART2 RX IT echo example\r\n"); HAL_UART_Receive_DMA(mx_usart2_uart_gethandle(), RxBuffer, MAX_BUFFER_SIZE); while (1) { HAL_UART_Transmit_DMA(mx_usart2_uart_gethandle(), TxBuffer, MAX_BUFFER_SIZE); HAL_Delay(10000); } }} /* end main */

编译工程,调试步骤完成后,按下Ctrl+Shift+P,输入Open Serial,选择COM40(STMicroelectronics),波特率115200。
程序正常运行:粉色下划线代表DMA传输,蓝色为输入本地回显,绿色为DMA回发的接收数据。


总结

本文介绍基于STM32CubeMX2 + VS Code在NUCLEO-C562RE上搭建UART通信,详细说明了HAL2硬件抽象层配置、工程结构。分别演示轮询、中断、DMA三种通信模式,展现STM32C5系列UART外设的灵活性。开发者可以从简单阻塞式调试控制台,逐步升级到高效率非阻塞数据传输方案。

相关推荐
辛迪聊物业数字化6 小时前
物业费收缴率从68%提升到97%落地复盘:中小物业收费系统选型避坑指南
人工智能·嵌入式硬件·物联网·网络协议·系统架构
白搞电子6 小时前
ESP-Mosaico 轮滑动画编排台:拍点吸附、完整动作编辑与工程保存
单片机·嵌入式硬件·电脑
玄芯散人7 小时前
【元婴·114】SD卡和FatFS文件系统:数据持久化
stm32·sd卡·fatfs
恒锐丰科技林技术员7 小时前
EG2106L 高压半桥驱动芯片解析:高性价比 600V 栅极驱动方案
经验分享·嵌入式硬件·硬件工程
cu1437 小时前
细谈IT6653的具体功能与其应用
c语言·c++·单片机·嵌入式硬件
夏虫不可与之言冰8 小时前
RMT 与 WS2812 灯带:可寻址 RGB 全彩控制
c语言·c++·单片机·物联网·visual studio
额额额对了8 小时前
【项目实战】从IMX6ULL环境监测到N647 AI视觉加速
linux·开发语言·嵌入式硬件
三佛科技-134163842129 小时前
微针美容仪数显方案开发案例,微针美容仪方案单片机选择(FT62F23X,FT62F288-LRB,FT32A072)
单片机·嵌入式硬件·物联网·智能家居·pcb工艺
天空'之城9 小时前
单片机基础核心知识点汇总(四十九)
单片机·嵌入式硬件