嵌入式串口通信原理与UART驱动实战
1. 串口通信原理与嵌入式系统实现
串口通信作为嵌入式系统中最基础、最广泛使用的异步通信方式,其设计简洁性、电气鲁棒性及跨平台兼容性,使其在调试接口、传感器数据采集、模块间协同、固件升级等场景中持续发挥不可替代的作用。尽管高速接口如USB、以太网、PCIe在带宽上占据绝对优势,但串口凭借单信号线对(TX/RX)、无时钟线依赖、低功耗待机能力以及极简的物理层实现,在资源受限的MCU系统中仍为首选通信机制。本文将从通信本质出发,系统梳理串口的核心参数定义、电气特性、帧结构、工作模式,并结合典型ARM Cortex-M系列开发板的硬件连接与驱动实现路径,还原一个可复现、可验证、可迁移的串口工程实践闭环。
1.1 串行通信的本质与工程权衡
串行通信指数据按时间顺序逐位(bit)在单一信道上传输的方式。与并行通信需多根数据线同步传输多位数据不同,串行通信仅需一对差分线(RS-485/RS-422)或两根单端线(TTL/RS-232),显著降低PCB布线复杂度、EMI辐射强度及连接器成本。其核心工程价值体现在远距离、低干扰、低成本三重约束下的最优解:
- 远距离适配 :TTL电平(0V/3.3V或0V/5V)直连传输距离通常不超过1米;通过电平转换芯片(如MAX3232、SP3232)转为RS-232标准(±3V~±15V),可靠传输距离可达15米;采用RS-485差分驱动(A/B线),在100kbps速率下可延伸至1200米;
- 抗干扰能力 :差分信号(RS-485)天然抑制共模噪声,适用于工业现场;单端TTL虽易受干扰,但在板级短距通信中因信号完整性可控而被广泛采用;
- 资源占用极小 :无需专用高速PHY,MCU内部UART外设仅消耗少量门电路与RAM缓冲区,对Flash与SRAM资源压力远低于USB或TCP/IP协议栈。
必须明确的是,串口并非“低速”的代名词——现代Cortex-M系列MCU(如STM32H7、NXP i.MX RT)的UART外设支持高达12Mbps的波特率,足以满足多数传感器(如IMU、气压计)、音频控制指令、固件差分包传输等需求。其“低速”印象源于传统51单片机或早期ARM7的硬件限制,而非协议本身缺陷。
1.2 串口通信关键参数解析
串口通信的可靠性完全依赖于收发双方在四个核心参数上的严格一致。任何一项失配都将导致数据错乱或接收失败。这些参数并非抽象概念,而是直接映射到硬件寄存器配置与信号时序中。
1.2.1 波特率(Baud Rate)
波特率定义为每秒传输的符号(symbol)数量,单位为bps(bits per second)。在标准异步串口(NRZ编码)中,一个符号即一个bit,故波特率=比特率。其本质是收发双方对“每一位持续时间”的共同约定:
$$ \text{Bit Time} = \frac{1}{\text{Baud Rate}} $$
例如,9600bps对应位时间为104.17μs。MCU UART外设通过分频器将系统时钟(如72MHz)分频生成精确的采样时钟。以STM32F103为例,其USARTDIV寄存器计算公式为:
$$ \text{USARTDIV} = \frac{\text{f}_{\text{PCLK}}}{16 \times \text{BaudRate}} $$
其中$f_{\text{PCLK}}$为APB总线时钟频率。该公式隐含了16倍过采样机制——UART在每位中间位置连续采样16次,取多数值判定电平,有效抑制毛刺干扰。因此,波特率误差需控制在±3%以内(RS-232标准),否则采样点偏移将导致误判。实际工程中,应优先选用MCU参考手册中“标准波特率”表格内的值(如9600、115200),避免因分频余数引入累积误差。
1.2.2 数据位(Data Bits)
数据位指每个字符帧中有效数据的bit数,常见值为5、6、7、8位。现代嵌入式系统几乎统一采用 8位数据位 ,原因在于:
- 与字节(byte)天然对齐,简化软件处理(无需位操作拼接);
- 兼容ASCII、UTF-8等主流字符编码;
- MCU寄存器宽度(8/16/32位)与之匹配,读写效率最高。
5/6/7位主要用于老式电传打字机(TTY)或特定工业协议,当前新项目中已无应用必要。
1.2.3 停止位(Stop Bits)
停止位是字符帧末尾的高电平持续时间,典型值为1、1.5或2位。其核心作用有二:
- 帧边界标识 :明确标示一个字符的结束,为下一个起始位的到来提供识别窗口;
- 时钟容错补偿 :由于收发双方晶振存在微小偏差(±100ppm),长距离或多帧连续传输时,累计相位差可能导致采样点漂移。增加停止位长度(如1.5或2位)扩大了接收方检测起始位的“安全窗口”,提升异步通信鲁棒性。
在绝大多数MCU应用中, 1位停止位 是默认且推荐的选择。它在保证足够容错能力的同时,最大化传输效率(每10位中仅1位开销)。仅在极端恶劣电磁环境或老旧设备互联时,才考虑启用2位停止位。
1.2.4 校验位(Parity Bit)
校验位是一种简单有效的错误检测机制,位于数据位之后、停止位之前,取值由数据位奇偶性决定:
- 偶校验(Even Parity) :数据位中1的个数为偶数时,校验位为0;为奇数时,校验位为1,确保整个字符(数据+校验)中1的总数为偶数;
- 奇校验(Odd Parity) :逻辑相反,确保1的总数为奇数;
- 无校验(None) :不使用校验位,数据位后直接跟停止位。
校验位仅能检测 单bit翻转错误 (如0→1或1→0),对双bit错误完全失效,且无法纠正错误。在现代嵌入式系统中,其价值已被更可靠的机制取代:
- 硬件CRC校验 :UART外设(如STM32L4/L5)支持发送/接收帧附加CRC,检错能力远超奇偶校验;
- 应用层协议校验 :Modbus、CANopen等协议在数据包级加入CRC16/CRC32;
- 链路层重传机制 :如YMODEM协议在文件传输中自动请求重发错误块。
因此,除对接特定遗留设备外, 强烈建议关闭校验位(None) ,以降低协议开销并简化驱动逻辑。
1.3 串口通信工作模式与物理层
串口通信模式描述信息流向的时空关系,直接影响硬件接口设计与软件状态机实现。
| 模式 | 信号流向 | 硬件线数 | 典型应用 | MCU实现要点 |
|---|---|---|---|---|
| 单工 | 单向固定(A→B) | 1根TX | 广播式传感器输出 | 仅使能TX,RX引脚可悬空或复用 |
| 半双工 | 双向交替(A↔B,不同时) | 1根TX/RX | RS-485总线(需方向控制) | 需GPIO控制DE/RE引脚,严格时序管理 |
| 全双工 | 双向并发(A→B & B→A 同时) | 2根(TX,RX) | 调试口、MCU-PC通信 | 标准UART配置,TX/RX独立中断处理 |
当前主流开发板(如基于STM32F103C8T6的Blue Pill)默认采用
全双工TTL电平
,TX与RX引脚直连USB转串口芯片(CH340G、CP2102)。此设计允许开发人员在烧录程序的同时,实时查看
printf
调试信息,极大提升开发效率。其硬件连接本质是:
- MCU USART1_TX → CH340G TXD(MCU发送,CH340接收)
- MCU USART1_RX ← CH340G RXD(MCU接收,CH340发送)
- 共地(GND)提供参考电平
该连接方式下,CH340G扮演电平转换与USB协议桥接角色,对MCU而言,通信对象仍是标准UART外设,无需感知USB细节。
1.4 异步串口帧格式与时序分析
异步串口不依赖共享时钟线,其同步完全依靠帧结构中的起始位与停止位。一个标准8N1(8数据位、无校验、1停止位)帧格式如下:
[起始位] [D0] [D1] [D2] [D3] [D4] [D5] [D6] [D7] [停止位]
0 0 1 0 1 1 0 0 1 1
- 起始位(Start Bit) :强制为逻辑0,持续1位时间。接收方通过检测“高→低”跳变(下降沿)启动内部位定时器,开始采样;
- 数据位(Data Bits) :低位(LSB)在前,高位(MSB)在后。例如发送字符‘A’(ASCII 0x41 = 0b01000001),数据位序列为:0,1,0,0,0,0,0,1;
- 校验位(Parity Bit) :若启用,位于数据位之后;
- 停止位(Stop Bit) :强制为逻辑1,持续1/1.5/2位时间。标志本字符结束,并为下一字符起始位预留高电平间隔;
- 空闲位(Idle State) :线路上无数据传输时,保持高电平(逻辑1),与停止位电平一致,构成连续高电平状态。
关键时序要求:
- 起始位下降沿后,第1.5位时间处为 首次采样点 (16倍过采样下);
- 后续每位在中心位置(位时间的50%处)采样3次,取多数值;
- 接收方在检测到起始位后,必须在1位时间内完成采样点定位,否则后续位将全部错位。
1.5 开发板硬件接口与原理图解读
以典型Cortex-M3开发板(主控STM32F103C8T6)为例,其串口1(USART1)硬件连接具有高度代表性:
- 引脚复用 :PA9(USART1_TX)、PA10(USART1_RX)为USART1的默认功能引脚,通过AFIO(Alternate Function I/O)寄存器配置;
- 调试/下载复用 :该两引脚与SWD调试接口(SWDIO/SWCLK)及USB转串口芯片(CH340G)共用同一排针(如板载的“DEBUG”或“USB”端子)。当插入DAPLink或ST-Link仿真器时,SWD信号接管PA13/PA14;当插入USB线时,CH340G通过PA9/PA10与MCU通信;
- 电平匹配 :CH340G为3.3V TTL电平器件,与STM32F103C8T6的I/O电压(VDD=3.3V)完全兼容,无需额外电平转换电路;
- 上拉/下拉 :PA10(RX)通常外接10kΩ上拉电阻至3.3V,确保空闲态为高电平,避免浮空引入误触发;PA9(TX)为推挽输出,无需上拉。
原理图中关键元件:
- CH340G :USB转TTL串口桥接芯片,内置USB PHY与UART控制器;
- USB-B型接口 :提供5V电源(VBUS)及D+/D-数据线;
- 稳压电路 :AMS1117-3.3将USB 5V降压为3.3V,为MCU与CH340G供电;
- LED指示灯 :TXD/RXD旁的LED(常经限流电阻接至TX/RX线)直观显示数据活动。
此设计实现了“一端口、多功能”:同一物理接口既支持JTAG/SWD在线调试与程序下载,又支持运行时串口日志输出与命令交互,是嵌入式开发板的经典范式。
1.6 串口驱动软件实现流程
一个健壮的串口驱动需覆盖初始化、发送、接收三大核心环节,并处理中断、DMA、重定向等高级特性。以下以STM32标准外设库(StdPeriph)为例,阐述最小可行实现。
1.6.1 初始化配置
void USART1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
// 1. 使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);
// 2. 配置PA9(TX)为复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 3. 配置PA10(RX)为浮空输入(实际常加弱上拉)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 4. 配置USART1参数:115200bps, 8N1
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 8数据位
USART_InitStructure.USART_StopBits = USART_StopBits_1; // 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);
// 5. 使能USART1及接收中断
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // 接收非空中断
USART_Cmd(USART1, ENABLE);
}
1.6.2 中断接收与环形缓冲区
为避免数据丢失,接收端必须采用环形缓冲区(Ring Buffer)管理:
#define RX_BUFFER_SIZE 128
uint8_t rx_buffer[RX_BUFFER_SIZE];
volatile uint16_t rx_head = 0, rx_tail = 0;
// USART1中断服务函数
void USART1_IRQHandler(void)
{
uint8_t ch;
USART_TypeDef* USARTx = USART1;
if (USART_GetITStatus(USARTx, USART_IT_RXNE) != RESET) {
ch = (uint8_t)USART_ReceiveData(USARTx);
// 环形缓冲区写入
rx_buffer[rx_head] = ch;
rx_head = (rx_head + 1) % RX_BUFFER_SIZE;
if (rx_head == rx_tail) {
// 缓冲区满,丢弃最老数据(或触发告警)
rx_tail = (rx_tail + 1) % RX_BUFFER_SIZE;
}
}
}
// 从缓冲区读取一字节(非阻塞)
uint8_t USART1_ReadByte(void)
{
uint8_t data = 0;
if (rx_head != rx_tail) {
data = rx_buffer[rx_tail];
rx_tail = (rx_tail + 1) % RX_BUFFER_SIZE;
}
return data;
}
1.6.3 发送实现与重定向
发送可采用轮询(阻塞)或中断/DMA(非阻塞)方式。
printf
重定向需实现
fputc
:
// 重定向printf到USART1(使用轮询发送)
int fputc(int ch, FILE *f)
{
USART_SendData(USART1, (uint8_t) ch);
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) {
// 等待发送完成(Transmission Complete)
}
return ch;
}
// 使用示例
printf("System initialized at %d Hz\r\n", SystemCoreClock);
对于高吞吐量场景(如日志批量输出),应启用发送中断或DMA,避免CPU长时间等待。
1.7 BOM关键器件选型依据
| 器件 | 型号 | 关键参数 | 选型理由 |
|---|---|---|---|
| 主控MCU | STM32F103C8T6 | Cortex-M3, 72MHz, 64KB Flash | 成本低、生态成熟、UART外设稳定,满足学习与原型开发需求 |
| USB转串口芯片 | CH340G | 3.3V TTL, 支持Windows/Linux/macOS驱动 | 兼容性极佳,无需额外驱动(Win10+原生支持),成本低于FT232RL |
| LDO稳压器 | AMS1117-3.3 | 输入4.75-12V, 输出3.3V/1A | 低压差、高PSRR,有效滤除USB电源纹波,保障MCU与CH340G稳定工作 |
| 晶振 | 8MHz HC-49S | ±20ppm, 并联谐振 | 为MCU提供主时钟源,精度满足UART波特率误差要求(9600bps下±20ppm误差<0.2%) |
| LED | 0805绿色LED | 正向压降2.0V, 电流2mA | 低功耗指示,TX/RX活动时可见,不影响信号完整性 |
所有器件均采用工业级温度范围(-40°C~85°C)与标准封装(SOIC、SOT-23),确保批量生产可行性与长期可靠性。
1.8 实际调试与故障排查指南
在真实开发中,串口通信失败常源于可复现的硬件或配置问题:
-
现象:PC端无任何数据显示
- 检查USB线是否为数据线(非仅充电线);
- 在设备管理器中确认CH340G驱动是否正确安装(COM端口号);
- 用万用表测量PA9(TX)对地电压:空闲时应为3.3V,发送时应有波动;若恒为0V,检查PA9是否被配置为普通GPIO而非复用功能;
- 示波器观察PA9波形:应有清晰的起始位(低电平)与数据位,若为恒定高/低电平,检查USART是否使能或发送函数是否调用。
-
现象:数据显示乱码(如“烫烫烫”)
- 首要怀疑波特率不匹配 :确认MCU代码配置、串口调试助手设置、CH340G固件是否均为同一值(如115200);
- 检查系统时钟配置:若HSE未起振或PLL配置错误,导致APB1时钟非预期值,波特率将严重偏离;
- 排查电源噪声:用示波器观察VDD波形,若纹波过大(>100mV),可能引起MCU内部时钟抖动。
-
现象:接收数据丢失
- 检查接收中断是否使能且未被更高优先级中断屏蔽;
- 验证环形缓冲区大小是否足够(如115200bps下,100ms内最多接收1152字节);
-
若使用
printf重定向,确认fputc中未开启发送中断(轮询模式下TC标志必须等待)。
掌握这些底层原理与排查方法,工程师便能超越“调通即止”的初级阶段,真正理解串口在系统中的角色,并将其作为构建更复杂通信协议(如Modbus RTU、自定义二进制协议)的坚实基石。
openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐


所有评论(0)