STM32开发之UART串口编程从入门到实战:协议与标准外设库实现详解
1. 什么是串口UART串口是嵌入式开发中最常用的通信接口之一。UARTUniversal Asynchronous Receiver/Transmitter通用异步收发传输器是一种异步串行通信协议它通过一根数据线逐位bit地传输数据实现设备之间的信息交换。在 STM32 开发中串口承担着极其重要的角色它既是调试输出的“窗口”也是与上位机、传感器模块、无线模块如蓝牙、WiFi通信的桥梁。理解 UART 的工作原理是掌握 STM32 编程的基础能力之一。2. UART 与 USART 的区别在 STM32 数据手册中我们经常同时看到 UART 和 USART 两个术语它们之间有什么区别呢UART通用异步收发传输器仅支持异步通信模式即收发双方不需要共享时钟信号。USART通用同步异步收发传输器在 UART 的基础上增加了同步通信能力可以额外输出时钟信号SCLK支持 SPI 等同步模式。简单来说USART 是 UART 的“增强版”。在绝大多数串口通信场景下我们使用的是异步模式此时两者的用法基本一致。STM32 系列芯片通常同时集成多个 USART 和 UART 外设编程时需根据实际需求选择。3. 串口通信关键概念3.1 TX 与 RX串口通信至少需要两根数据线TXTransmit发送数据线用于向外发送数据。RXReceive接收数据线用于接收外部传入的数据。需要注意的是两个设备连接时遵循“交叉连接”原则设备 A 的 TX 接设备 B 的 RX设备 A 的 RX 接设备 B 的 TX。这样才能保证一方发送、另一方接收。3.2 全双工通信UART 支持全双工通信即发送和接收可以同时进行。这是因为 TX 和 RX 是两条独立的数据线互不干扰。与之相对的概念是半双工如 RS-485 总线和单工如仅发送的广播。3.3 串行数据传输串行通信的特点是逐位传输数据。与并行通信一次传输多位相比串行通信虽然单次传输的数据量小但只需要很少的引脚非常适合引脚资源有限的单片机系统。UART 的数据帧就是按照起始位、数据位、校验位、停止位的顺序逐位发送的。3.4 上位机与下位机在串口通信的语境中常提到“上位机”和“下位机”两个概念下位机通常指嵌入式设备本身如 STM32 单片机负责采集数据、控制执行器。上位机通常指 PC 端的应用程序如串口调试助手、自研上位机软件负责发送指令、接收并显示数据。上位机与下位机通过串口通常借助 USB 转 TTL 模块建立连接实现人机交互和数据监控。4. UART 数据传输UART 的传输过程可以概括为“帧”的发送与接收。一个完整的 UART 数据帧包含以下部分空闲状态数据线保持高电平。起始位发送方将数据线拉低一个位时间通知接收方“数据要开始了”。数据位通常为 8 位也可配置为 5、6、7、9 位按低位在前、高位在后的顺序逐位发送。校验位可选用于简单的错误检测常见的有奇校验、偶校验。停止位数据线恢复高电平通常为 1 位或 2 位表示一帧数据结束。收发双方必须约定相同的波特率每秒传输的位数单位 bps才能正确解析每一位数据。常见的波特率有 9600、115200 等。波特率不一致是串口通信乱码的最常见原因。5. 物理层标准UART 协议定义了数据帧的格式但实际传输时还需要依赖具体的物理层标准来决定电平、距离和连接方式。常见的物理层标准有 TTL、RS-232、RS-485 和 RS-422它们各有特点适用于不同的应用场景。5.1 TTL 电平TTLTransistor-Transistor Logic电平是单片机系统中最常用的串口电平标准。STM32 的 UART 引脚直接输出的就是 TTL 电平。逻辑 1高电平通常为 3.3VSTM32或 5V部分 5V 单片机。逻辑 0低电平通常为 0V。特点电平范围窄抗干扰能力较弱传输距离一般不超过 1 米。TTL 电平适合板级通信例如 STM32 与传感器模块、蓝牙模块之间的短距离连接。当需要与 PC 通信时通常借助 USB 转 TTL 模块完成电平转换。5.2 RS-232 标准RS-232 是早期 PC 串口COM 口使用的标准采用负逻辑电平抗干扰能力比 TTL 强。逻辑 1负电平范围为 -3V 到 -15V。逻辑 0正电平范围为 3V 到 15V。特点传输距离可达 15 米左右但只能点对点通信且速率相对较低。STM32 的 TTL 电平不能直接连接 RS-232 设备需要经过 MAX3232 等电平转换芯片。如今 PC 上 RS-232 接口已逐渐被 USB 取代但在工业设备和老式仪器中仍常见。5.3 RS-485 标准RS-485 是一种差分信号标准广泛应用于工业现场总线支持多点通信和长距离传输。差分信号使用 A、B 两根线传输通过两线电压差表示逻辑 0 和 1抗干扰能力强。多点通信一条总线上最多可挂接 32 个节点标准负载下。传输距离可达 1200 米适合远距离工业场景。半双工同一时刻只能一方发送需要收发切换控制。STM32 通过 SP3485、MAX485 等收发器芯片将 TTL 电平转换为 RS-485 差分信号。RS-485 常用于 Modbus 协议、楼宇自控、工厂设备联网等场景。5.4 RS-422 标准RS-422 与 RS-485 类似也采用差分信号但它是全双工通信需要 4 根线两对差分线。全双工发送和接收各用一对差分线可同时收发。多点通信支持一主多从但接收端数量有限通常最多 10 个。传输距离与 RS-485 相当可达 1200 米。RS-422 适合需要同时收发且距离较远的场景例如某些工业设备之间的双向通信。由于 RS-485 在半双工场景下更常用RS-422 的应用相对较少。5.5 四种标准对比标准电平方式通信模式传输距离节点数典型应用TTL单端 3.3V/5V全双工约 1 米点对点板级模块通信RS-232单端 ±12V全双工约 15 米点对点PC 串口、工业仪表RS-485差分半双工约 1200 米最多 32 个Modbus、工业总线RS-422差分全双工约 1200 米最多 10 个远距离双向通信在实际项目中应根据传输距离、通信节点数和是否需要全双工来选择物理层标准。STM32 的 UART 外设本身不区分这些标准只需通过对应的收发器芯片完成电平转换即可。6. UART 协议UART 协议本身只定义了物理层和数据链路层的基础帧格式并不规定数据内容的含义。但在实际工程中为了让通信更可靠、更易解析通常会在 UART 帧之上再封装一层“应用层协议”。下面介绍几种常见的做法。6.1 基础帧格式一个典型的自定义串口协议帧可以设计为帧头(2字节) 数据长度(1字节) 数据(N字节) 校验(1字节) 帧尾(1字节)帧头固定值如 0xAA 0x55用于接收方识别一帧数据的开始。数据长度指明后续数据字段的字节数。数据实际要传输的有效信息。校验常用累加和校验或 CRC 校验用于检测传输过程中是否出现错误。帧尾固定值如 0x0D 0x0A标志一帧结束。6.2 数据解析流程接收方解析一帧数据的典型流程如下逐字节接收数据检测是否匹配帧头。匹配帧头后继续接收长度字节确定本帧总长度。按长度接收完整数据并同步计算校验值。校验通过且帧尾正确则判定为一帧有效数据交给上层处理。校验失败则丢弃本帧重新等待帧头。6.3 常见波特率与配置参数常见取值说明波特率9600 / 115200115200 常用于调试9600 常用于低速传感器数据位8最常用配置校验位无 / 奇 / 偶一般选择无校验以简化处理停止位1最常用配置在 STM32 的 HAL 库中上述参数通过UART_InitTypeDef结构体配置初始化后调用UART_Init()即可完成串口外设的启动。7. STM32F4xx 串口控制器前面介绍了 UART 的协议和物理层标准本节从 STM32F4xx 芯片内部的角度深入讲解串口控制器的核心组成。理解这些寄存器、引脚和状态标志是编写高效串口驱动的基础。7.1 整体结构STM32F4xx 的 USART 控制器由发送器Transmitter、接收器Receiver、波特率发生器Baud Rate Generator以及一组控制/状态寄存器组成。控制器通过 TX 引脚发送数据通过 RX 引脚接收数据并借助硬件流控制引脚RTS、CTS实现流量管理。发送器将并行数据转换为串行比特流按起始位、数据位、停止位的顺序从 TX 引脚发出。接收器从 RX 引脚采样串行比特流重新组装为并行数据并存入接收数据寄存器。波特率发生器根据系统时钟和分频配置产生收发双方约定的位时钟。控制/状态寄存器用于配置工作模式、使能中断并反映收发状态如 TXE、TC、RXNE。7.2 TX 与 RXTXTransmit Data和 RXReceive Data是串口通信的两根核心数据线在 STM32F4xx 中它们被映射到多个 GPIO 引脚可通过复用功能AF配置选择。TX 引脚发送数据输出空闲时为高电平。发送时按帧格式逐位输出数据。RX 引脚接收数据输入用于采样外部传入的串行信号。引脚复用例如 USART1 的 TX/RX 可映射到 PA9/PA10 或 PB6/PB7通过 GPIO 复用功能配置选择。在标准外设库SPL中通过GPIO_InitTypeDef将引脚配置为复用推挽输出TX和复用浮空输入RX再调用USART_Init()完成初始化。下面给出基于 SPL 的 GPIO 复用配置示例/* GPIO 复用配置USART1 的 TXPA9、RXPA10标准外设库 SPL */ void GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; /* 使能 GPIOA 和 USART1 时钟 */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); /* TX复用推挽输出 */ GPIO_InitStructure.GPIO_Pin GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, GPIO_InitStructure); /* RX复用浮空输入 */ GPIO_InitStructure.GPIO_Pin GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, GPIO_InitStructure); /* 将 PA9、PA10 连接到 USART1 复用功能 */ GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1); GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1); } /* USART1 初始化115200、8 数据位、1 停止位、无校验、无流控SPL */ void USART1_Config(void) { USART_InitTypeDef USART_InitStructure; USART_InitStructure.USART_BaudRate 115200; USART_InitStructure.USART_WordLength USART_WordLength_8b; USART_InitStructure.USART_StopBits USART_StopBits_1; USART_InitStructure.USART_Parity USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART1, USART_InitStructure); USART_Cmd(USART1, ENABLE); }7.3 硬件流控制当通信双方速率不匹配或接收缓冲区即将溢出时需要一种机制来协调发送节奏这就是硬件流控制。STM32F4xx 的 USART 支持 RTS 和 CTS 两根流控引脚。RTSRequest To Send接收方输出用于通知发送方“我可以接收数据”。当接收缓冲区满时RTS 拉高请求对方暂停发送。CTSClear To Send发送方输入用于检测接收方是否允许发送。CTS 为低电平时发送方可以继续发送CTS 为高电平时发送方暂停。启用硬件流控制后发送器在 CTS 有效前不会启动发送接收器在缓冲区满时通过 RTS 通知对方暂停从而避免数据丢失。在 HAL 库中通过UART_InitTypeDef的HwFlowCtl字段配置可选UART_HWCONTROL_NONE、UART_HWCONTROL_RTS、UART_HWCONTROL_CTS或UART_HWCONTROL_RTS_CTS。7.4 关键状态标志STM32F4xx 的 USART 状态寄存器USART_SR中TXE、TC、RXNE 是编程中最常用的三个标志位它们直接决定了收发流程的推进。TXETransmit Data Register Empty发送数据寄存器为空表示可以写入下一个待发送字节。写数据寄存器USART_DR后 TXE 自动清零。TCTransmission Complete一帧数据已完整发送完毕包括停止位。TC 置位表示数据真正从引脚发出适合在关闭串口或进入低功耗前等待。RXNERead Data Register Not Empty接收数据寄存器已收到一帧数据表示可以读取。读 USART_DR 后 RXNE 自动清零。这三个标志位既可以轮询查询也可以触发中断。例如发送时先等待 TXE 置位再写入数据接收时通过 RXNE 中断及时读取避免数据覆盖。7.5 轮询与中断收发流程基于上述标志位串口收发有两种典型实现方式轮询方式发送时循环等待 TXE 置位后写入数据接收时循环等待 RXNE 置位后读取数据。实现简单但会占用 CPU。中断方式使能 TXE 或 RXNE 中断在中断服务函数中完成数据搬运。CPU 利用率高适合实时性要求较高的场景。在标准外设库SPL中轮询方式通过USART_SendData()和USART_ReceiveData()配合状态标志实现中断方式则通过使能USART_IT_RXNE中断并在中断服务函数中读取数据完成。更高效的 DMA 方式将在后续文章中介绍。下面给出一个基于标准外设库SPL的完整示例将轮询发送与中断接收整合在一起上电后通过轮询方式发送欢迎信息随后使能 RXNE 中断接收数据并在中断服务函数中把收到的数据原样回显。/* main.c —— SPL 库串口轮询发送 中断接收示例 */ #include stm32f4xx.h uint8_t rx_buffer[64]; /* 接收缓冲区 */ uint8_t rx_index 0; /* 当前接收位置 */ uint8_t rx_complete 0; /* 一帧接收完成标志 */ /* GPIO 复用配置USART1 的 TXPA9、RXPA10SPL */ void GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; /* 使能 GPIOA 和 USART1 时钟 */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); /* TX复用推挽输出 */ GPIO_InitStructure.GPIO_Pin GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, GPIO_InitStructure); /* RX复用浮空输入 */ GPIO_InitStructure.GPIO_Pin GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, GPIO_InitStructure); /* 将 PA9、PA10 连接到 USART1 复用功能 */ GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1); GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1); } /* USART1 初始化115200、8 数据位、1 停止位、无校验、无流控SPL */ void USART1_Config(void) { USART_InitTypeDef USART_InitStructure; USART_InitStructure.USART_BaudRate 115200; USART_InitStructure.USART_WordLength USART_WordLength_8b; USART_InitStructure.USART_StopBits USART_StopBits_1; USART_InitStructure.USART_Parity USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART1, USART_InitStructure); /* 使能 USART1 接收中断 */ USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); /* 配置 NVICUSART1 中断优先级 */ NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority 0; NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE; NVIC_Init(NVIC_InitStructure); USART_Cmd(USART1, ENABLE); } /* 主函数 */ int main(void) { GPIO_Config(); /* 配置 GPIO 复用 */ USART1_Config(); /* 初始化串口并开启中断 */ /* 轮询方式发送欢迎信息 */ uint8_t welcome[] STM32 UART SPL Demo Ready\r\n; uint8_t i; for (i 0; i sizeof(welcome) - 1; i) { /* 等待 TXE 置位后写入数据 */ while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) RESET); USART_SendData(USART1, welcome[i]); } while (1) { if (rx_complete) { /* 轮询方式回显整帧数据 */ uint8_t j; for (j 0; j rx_index; j) { while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) RESET); USART_SendData(USART1, rx_buffer[j]); } /* 复位接收状态准备接收下一帧 */ rx_index 0; rx_complete 0; } } } /* USART1 中断服务函数每收到一字节自动调用 */ void USART1_IRQHandler(void) { uint8_t ch; if (USART_GetITStatus(USART1, USART_IT_RXNE) ! RESET) { /* 读取数据寄存器同时清除 RXNE 标志 */ ch USART_ReceiveData(USART1); /* 收到换行符认为一帧结束 */ if (ch \n) { rx_complete 1; } else { rx_buffer[rx_index] ch; if (rx_index sizeof(rx_buffer)) { rx_index 0; /* 缓冲区溢出保护 */ } } } }上述示例的运行流程可以概括为系统初始化完成后通过USART_SendData()配合 TXE 标志轮询发送欢迎信息验证发送通路正常。初始化时使能USART_IT_RXNE中断每收到一字节自动进入USART1_IRQHandler()中断服务函数。中断服务函数中判断是否收到换行符未收到则存入缓冲区收到则置位rx_complete标志。主循环检测到rx_complete后将整帧数据回显并复位状态重新开始接收。7.6 小结STM32F4xx 串口控制器的核心在于 TX/RX 引脚、RTS/CTS 硬件流控制以及 TXE、TC、RXNE 三个状态标志。掌握这些底层机制才能写出稳定、高效的串口驱动并为后续的中断接收、DMA 传输打下基础。8. STM32F4xx 串口编程流程前面几节分别介绍了串口控制器的结构、引脚、状态标志和收发流程本节把这些知识点串起来给出一个基于标准外设库SPL的完整串口编程流程。整个流程可以概括为六个步骤GPIO 配置、UART 配置、中断配置、使能串口、接收数据和发送数据。下面以 USART1TXPA9、RXPA10为例逐一展开。8.1 核心步骤基于 SPL 的串口编程核心步骤如下GPIO 配置使能 GPIOA 和 USART1 时钟将 PA9 配置为复用推挽输出TXPA10 配置为复用浮空输入RX并通过GPIO_PinAFConfig()把引脚连接到 USART1 复用功能。UART 配置填充USART_InitTypeDef结构体设置波特率、数据位、停止位、校验位、硬件流控制和收发模式调用USART_Init()完成初始化。中断配置使能USART_IT_RXNE接收中断并配置 NVIC 中断优先级使能 USART1 中断通道。使能串口调用USART_Cmd(USART1, ENABLE)启动串口外设。接收数据在USART1_IRQHandler()中断服务函数中通过USART_ReceiveData()读取数据并存入缓冲区。发送数据等待 TXE 标志置位后通过USART_SendData()逐字节发送数据。8.2 GPIO 配置GPIO 配置是串口编程的第一步。STM32F4xx 的 USART1 引脚默认不是串口功能必须通过复用功能AF配置才能连接到 USART1。具体来说需要完成三件事使能 GPIOA 时钟、使能 USART1 时钟、将 PA9/PA10 配置为复用功能并连接到 USART1。/* 8.2 GPIO 配置USART1 的 TXPA9、RXPA10SPL */ void GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; /* 使能 GPIOA 和 USART1 时钟 */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); /* TXPA9复用推挽输出 */ GPIO_InitStructure.GPIO_Pin GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, GPIO_InitStructure); /* RXPA10复用浮空输入 */ GPIO_InitStructure.GPIO_Pin GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, GPIO_InitStructure); /* 将 PA9、PA10 连接到 USART1 复用功能 */ GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1); GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1); }这里有两个关键点需要说明时钟使能GPIOA 挂在 AHB1 总线上所以用RCC_AHB1PeriphClockCmd()USART1 挂在 APB2 总线上所以用RCC_APB2PeriphClockCmd()。两者缺一不可。复用功能映射GPIO_PinAFConfig()的作用是把 PA9、PA10 的复用功能选择寄存器AFRL/AFRH配置为 USART1这一步决定了引脚最终连接到哪个外设。8.3 UART 配置GPIO 配置完成后接下来配置 USART 外设本身。通过USART_InitTypeDef结构体设置通信参数再调用USART_Init()写入寄存器。常用的配置是 115200 波特率、8 数据位、1 停止位、无校验、无硬件流控、收发模式。/* 8.3 UART 配置115200、8 数据位、1 停止位、无校验、无流控SPL */ void USART1_Config(void) { USART_InitTypeDef USART_InitStructure; USART_InitStructure.USART_BaudRate 115200; USART_InitStructure.USART_WordLength USART_WordLength_8b; USART_InitStructure.USART_StopBits USART_StopBits_1; USART_InitStructure.USART_Parity USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART1, USART_InitStructure); }各字段含义如下USART_BaudRate波特率收发双方必须一致否则会出现乱码。USART_WordLength数据位长度最常用 8 位。USART_StopBits停止位常用 1 位。USART_Parity校验位一般选择无校验以简化处理。USART_HardwareFlowControl硬件流控制本例不使用。USART_Mode工作模式这里同时使能发送和接收。8.4 中断配置如果采用中断方式接收数据还需要配置 USART 中断和 NVIC。首先通过USART_ITConfig()使能 RXNE 接收中断然后配置 NVIC 中断优先级使能 USART1 的中断通道。/* 8.4 中断配置使能 RXNE 中断并配置 NVICSPL */ void NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; /* 使能 USART1 接收中断RXNE */ USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); /* 配置 NVICUSART1 中断优先级 */ NVIC_InitStructure.NVIC_IRQChannel USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority 0; NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE; NVIC_Init(NVIC_InitStructure); }NVIC 配置中抢占优先级和子优先级的具体数值取决于工程的分组设置NVIC_PriorityGroupConfig()。在简单应用中两者都设为 0 即可满足需求。8.5 使能串口以上配置完成后最后一步是调用USART_Cmd()使能串口外设。这一步不能省略否则前面的配置不会生效。/* 8.5 使能串口SPL */ void USART_Enable(void) { USART_Cmd(USART1, ENABLE); }使能串口后USART1 就开始按照配置的波特率和帧格式工作TX 引脚进入空闲高电平状态RX 引脚开始监听外部数据。8.6 接收数据接收数据采用中断方式。当 RX 引脚收到一字节数据时RXNE 标志置位并触发中断程序自动进入USART1_IRQHandler()中断服务函数。在中断服务函数中通过USART_ReceiveData()读取数据寄存器同时清除 RXNE 标志。/* 8.6 接收数据USART1 中断服务函数SPL */ uint8_t rx_buffer[64]; /* 接收缓冲区 */ uint8_t rx_index 0; /* 当前接收位置 */ uint8_t rx_complete 0; /* 一帧接收完成标志 */ void USART1_IRQHandler(void) { uint8_t ch; if (USART_GetITStatus(USART1, USART_IT_RXNE) ! RESET) { /* 读取数据寄存器同时清除 RXNE 标志 */ ch USART_ReceiveData(USART1); /* 收到换行符认为一帧结束 */ if (ch \n) { rx_complete 1; } else { rx_buffer[rx_index] ch; if (rx_index sizeof(rx_buffer)) { rx_index 0; /* 缓冲区溢出保护 */ } } } }这里采用换行符作为一帧结束的标志是一种简单实用的做法。在实际工程中也可以使用帧头 帧尾 校验的方式这在第 6 节已经介绍过。8.7 发送数据发送数据采用轮询方式。发送前先等待 TXE 标志置位表示发送数据寄存器为空可以写入下一个字节然后调用USART_SendData()写入数据。逐字节循环即可完成整帧数据的发送。/* 8.7 发送数据轮询方式发送字符串SPL */ void USART_SendString(uint8_t *str) { while (*str ! \0) { /* 等待 TXE 置位表示发送数据寄存器为空 */ while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) RESET); /* 写入一个字节到发送数据寄存器 */ USART_SendData(USART1, *str); } /* 等待最后一帧发送完成包括停止位 */ while (USART_GetFlagStatus(USART1, USART_FLAG_TC) RESET); }发送完成后还可以等待 TCTransmission Complete标志置位确保数据真正从引脚发出这在关闭串口或进入低功耗前尤为重要。8.8 主函数整合最后把以上各个步骤整合到main()函数中形成完整的串口收发流程/* 8.8 主函数整合完整串口流程SPL */ int main(void) { /* 1. GPIO 配置 */ GPIO_Config(); /* 2. UART 配置 */ USART1_Config(); /* 3. 中断配置 */ NVIC_Config(); /* 4. 使能串口 */ USART_Enable(); /* 5. 发送数据发送欢迎信息 */ USART_SendString((uint8_t *)STM32 UART SPL Demo Ready\r\n); while (1) { /* 6. 接收数据检测到一帧接收完成 */ if (rx_complete) { /* 回显接收到的数据 */ USART_SendString(rx_buffer); /* 复位接收状态准备接收下一帧 */ rx_index 0; rx_complete 0; } } }整个流程可以概括为先配置 GPIO 和 USART再配置中断并使能串口然后通过轮询方式发送数据、通过中断方式接收数据。主循环中检测到一帧数据接收完成后将其原样回显实现简单的串口收发演示。8.9 小结本节基于标准外设库SPL完整梳理了 STM32F4xx 串口编程的六个核心步骤GPIO 配置、UART 配置、中断配置、使能串口、接收数据和发送数据。掌握这套流程就可以在此基础上扩展出更复杂的串口应用例如自定义协议解析、DMA 传输和环形缓冲区等。9. 小结本文围绕 STM32 的 UART 串口编程从基础概念到实际代码系统梳理了完整的知识链路。下面回顾全文的核心要点串口基础UART 是一种异步串行通信协议通过 TX/RX 两根数据线实现全双工通信USART 是 UART 的增强版额外支持同步模式。设备连接遵循交叉连接原则收发双方必须约定相同的波特率。物理层标准TTL 适合板级短距离通信RS-232 用于点对点远距离RS-485 支持半双工多点通信RS-422 支持全双工多点通信。实际项目中应根据传输距离、节点数和通信模式选择合适的标准并通过收发器芯片完成电平转换。UART 协议基础帧由起始位、数据位、校验位、停止位组成工程中通常在其上封装自定义应用层协议通过帧头、长度、校验和帧尾保证数据可靠解析。串口控制器STM32F4xx 的 USART 由发送器、接收器、波特率发生器和控制/状态寄存器组成核心状态标志 TXE、TC、RXNE 直接决定收发流程的推进。编程流程基于标准外设库SPL的串口编程可概括为 GPIO 配置、UART 配置、中断配置、使能串口、接收数据和发送数据六个步骤轮询方式适合简单场景中断方式适合实时性要求较高的场景。掌握以上内容就具备了 STM32 串口开发的基础能力。后续可以在此基础上继续深入串口中断接收的进阶用法、DMA 传输以及环形缓冲区等话题进一步提升串口通信的效率和稳定性。

相关新闻

STM32开发之IIC通信详解:从协议基础到FM24CL04实战

STM32开发之IIC通信详解:从协议基础到FM24CL04实战

1. IIC概述IIC(Inter-Integrated Circuit,集成电路间总线)是一种由飞利浦公司(现恩智浦半导体)开发的两线式串行通信总线,广泛应用于微控制器与各类外设(如 EEPROM、传感器、RTC 时钟芯片等&…

2026/10/12 4:48:50 阅读更多 →
一篇文章教会你:用“经纬度思维”看懂比特币链上所有数据

一篇文章教会你:用“经纬度思维”看懂比特币链上所有数据

一、为什么你需要“经纬度思维”?很多人看比特币链上数据,第一反应是“太复杂了”。地址、区块、交易、手续费、活跃地址、算力……几十个指标堆在一起,越看越乱。其实,链上数据就像一张地图。地图上有经度和纬度,帮你…

2026/10/12 4:48:50 阅读更多 →
agent-skills实践:打造可复用、可校验的Agent技能系统

agent-skills实践:打造可复用、可校验的Agent技能系统

开头这几年做大模型应用开发,大家应该都感觉到了:单纯的 Prompt 工程已经撑不起复杂业务,真正难的是让 Agent 在真实环境里稳定地干活。“agent-skills”这个项目就是冲着这个痛点来的——它把 Agent 的能力拆解成一个个可复用、可管理、可验…

2026/10/12 4:47:50 阅读更多 →

最新新闻

【xilem0.4基础语法学与练】第33课 text_input 文本输入框

【xilem0.4基础语法学与练】第33课 text_input 文本输入框

前言 参考官方文档:https://docs.rs/xilem/latest/xilem/view/fn.text_input.html 版本:Xilem 0.4 一、text_input基础概念 text_input 是可编辑文本输入框组件,接收用户键盘输入字符串。 区分三个文本组件: label :只…

2026/10/12 5:30:14 阅读更多 →
Maven 配置全流程详解:从 JDK、环境变量到 IDEA 关联

Maven 配置全流程详解:从 JDK、环境变量到 IDEA 关联

不夸张地说,Maven 配置是 Java 开发路上第一个让新手挠头、让老手也偶尔翻车的环节。IDEA 自带的 Maven 能建项目,换个电脑就跑不动;命令行输入 mvn -v 有输出,一拉依赖却卡在原地;明明照着教程写了 mirror 镜像&#…

2026/10/12 5:30:14 阅读更多 →
【xilem0.4基础语法学与练】第32课 prose 可选择文本

【xilem0.4基础语法学与练】第32课 prose 可选择文本

前言 参考官方文档:https://docs.rs/xilem/latest/xilem/view/fn.prose.html 版本:Xilem 0.4 一、prose基础概念 prose 是可鼠标选中复制的段落文本组件。 label 文本不可选中复制;prose支持鼠标拖拽选中文本、CtrlC复制,适合日志…

2026/10/12 5:30:14 阅读更多 →
软件测试基础全解析:从用例设计到缺陷管理的完整路径

软件测试基础全解析:从用例设计到缺陷管理的完整路径

干这行这么多年,经常被问到一句话:"软件测试基础篇这东西,是不是就学学怎么点点点?" 说实话,我入行前也是这么以为的,以为测试就是照着用例点按钮、提bug、催开发修。真正在项目里滚过几轮之后才…

2026/10/12 5:30:14 阅读更多 →
Paperclip 与 OpenClaw 互相成就:智能体「运行时 + 编排」生态成型记

Paperclip 与 OpenClaw 互相成就:智能体「运行时 + 编排」生态成型记

Paperclip 与 OpenClaw 互相成就:智能体「运行时 编排」生态成型记 【免费下载链接】paperclip The open-source app everyone uses to manage agents at work 项目地址: https://gitcode.com/GitHub_Trending/papercl/paperclip 2026 年,开源智…

2026/10/12 5:30:14 阅读更多 →
Adobe认证报考全流程指南:从报名到拿证一次讲透

Adobe认证报考全流程指南:从报名到拿证一次讲透

做设计这行,Adobe认证是常被问起的一个东西。不管是刚毕业的学生、想转行的职场新人,还是已经在接私活的自由设计师,总会有人来问:这套认证到底怎么考、怎么报名、多久能拿证、证书有没有用。我前前后后帮团队里几个新人梳理过整套…

2026/10/12 5:29:14 阅读更多 →

日新闻

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

在数码相机、高清显示屏与现代矢量图形技术高度发达的今天,画面可以做到绝对的锐利、平滑与无瑕。然而,当一张秋日手账插画或拍立得照片过于“平整无瑕”时,往往会散发出一种冰冷生硬的“数码塑料感(Digital Plasticity&#xff0…

2026/10/12 0:00:59 阅读更多 →
活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

在现代网页与移动端设计中,横排(Horizontal Layout)早已经成为了绝对的主流。然而,当我们翻开泛黄的线装古籍、宋版木刻诗集,或是欣赏一张茶道雅集的手写便签时,那种**自上而下纵向书写、自右向左逐列铺展&…

2026/10/12 0:00:59 阅读更多 →
周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

每到周日的晚上八点到十点,很多人心里都会悄悄亮起一盏警示灯。 在心理学上,这种现象有一个专门的称谓——“周日夜晚焦虑症(Sunday Scaries)”。明天又是周一,闹钟又要重新在七点响彻卧房;脑海里仿佛有一个…

2026/10/12 0:00:59 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/12 0:16:30 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/12 0:16:43 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 10:45:37 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:53 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:54 阅读更多 →