3、UART硬件设计要点:CMS32串口引脚分配、电平转换电路与硬件流控设计

做嵌入式开发这么多年,我有个很深的体会:软件上的bug顶多让你多调几天,硬件上的坑往往让你直接重做一版PCB。串口通信看似简单,但引脚分配错了、电平没匹配、流控没接对——板子回来就是废的。这一节,我把CMS32上UART硬件设计的几个关键点掰开揉碎了讲清楚。

3.1 CMS32串口引脚分配:别踩复用功能的坑

CMS32系列单片机的UART外设,通常有多个可选引脚组。我见过不少新手,拿到原理图就开始画,结果发现UART2的TX和某个SPI的SCK冲突了——这种问题在布局阶段就该规避。

以CMS32L051为例,它的UART0、UART1、UART2分别对应不同的GPIO组。我习惯在项目初期就做一张引脚分配表,把功能、复用号、备注列清楚:

UART模块 TX引脚 RX引脚 复用功能号 注意事项
UART0 PA9 PA10 AF1 与I2C0_SCL共用,注意不要同时使能
UART1 PB6 PB7 AF2 与TIM1_CH1共用,PWM输出时慎用
UART2 PC0 PC1 AF3 与SPI0_NSS共用,注意片选信号
⚠ 我曾经踩过的坑: 有一次做多机通信,我选了UART2,结果PC0/PC1在PCB上被拉到了排针,但没注意到SPI0_NSS默认也是这两个脚。SPI初始化时把引脚模式改了,UART直接哑火。排查了两天才发现是复用功能冲突。所以我的建议是:原理图阶段就把所有外设的引脚分配列一张总表,交叉检查冲突。

3.2 电平转换电路:TTL、RS232、RS485怎么选?

说白了,CMS32的UART引脚输出的是3.3V TTL电平。但你的设备可能要跟PC的DB9串口通信,或者要在工业现场拉几百米线——这时候电平转换就是必须的。

3.2.1 TTL转RS232

PC的RS232串口用±12V电平,而CMS32是3.3V。直接连?烧IO都是轻的。你需要一颗电平转换芯片,比如MAX3232或SP3232。

我常用的电路结构是这样的:

CMS32_TX  →  MAX3232_T1IN  →  MAX3232_T1OUT  →  DB9 Pin2 (RX)
CMS32_RX  ←  MAX3232_R1OUT ←  MAX3232_R1IN  ←  DB9 Pin3 (TX)
GND       →  DB9 Pin5 (GND)
💡 个人经验: MAX3232的VCC引脚旁边,一定要放两个0.1μF+10μF的去耦电容,紧贴芯片放置。我见过有人为了省空间只放了一个电容,结果通信距离超过5米就开始丢包。另外,MAX3232内部有电荷泵,需要外接4个0.1μF的电容,别用错容值。

3.2.2 TTL转RS485

工业现场用得最多的就是RS485。它用差分信号传输,抗干扰能力强,最远能到1200米。常用的芯片有MAX3485(3.3V供电)或SP3485。

这里有个关键点:RS485是半双工的,发送和接收不能同时进行。你需要用CMS32的一个GPIO来控制收发使能。

// 伪代码示例:RS485收发切换
#define RS485_DE_RE   PB0   // 控制使能引脚

void RS485_Send_Enable(void) {
    GPIO_SetBits(RS485_DE_RE);   // DE=1, RE=1,进入发送模式
}

void RS485_Receive_Enable(void) {
    GPIO_ResetBits(RS485_DE_RE); // DE=0, RE=0,进入接收模式
}
⚠ 注意: 收发切换之间要加一点延时。我遇到过的情况是:发送完最后一个字节立刻切到接收,结果最后一个字节的停止位还没发完,总线冲突了。建议在切换前等待发送移位寄存器真正空(检查TC标志位),再加10μs左右的余量。

3.3 硬件流控设计:RTS/CTS到底用不用?

很多人觉得流控是可有可无的东西。但如果你做过高速串口通信(比如921600bps以上),或者跟蓝牙模块、4G模块对接过,你就会知道——没有流控,丢数据是家常便饭。

3.3.1 什么是RTS/CTS?

简单说,就是两个设备之间握手:

  • RTS(Request To Send):发送方告诉接收方“我要发数据了,你准备好了吗?”
  • CTS(Clear To Send):接收方回复“我准备好了,你发吧”或者“我忙不过来,你等等”。

在CMS32上,UART的硬件流控通常由外设自动管理。你只需要把RTS和CTS引脚连好,配置好寄存器就行。

3.3.2 什么时候必须用流控?

我总结了几种场景:

场景 是否建议用流控 原因
波特率 ≤ 115200,短距离(<1m) 可选 CPU处理速度足够,软件缓冲能应付
波特率 ≥ 460800 强烈建议 CPU来不及处理中断,硬件流控可以自动暂停发送
对接蓝牙/WiFi模块 建议 模块内部缓冲有限,流控可以防止溢出
多机通信(RS485总线) 不适用 RS485是半双工,流控由软件控制DE/RE引脚实现

3.3.3 CMS32硬件流控配置示例

CMS32的UART外设支持自动RTS/CTS。配置起来其实不复杂:

// 假设使用UART1,RTS=PB4,CTS=PB5
void UART1_HwFlowCtrl_Init(void) {
    // 1. 使能UART1时钟
    RCC_APB2PeriphClockCmd(RCC_APB2PERIPH_UART1, ENABLE);
    
    // 2. 配置GPIO复用功能
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource4, GPIO_AF_UART1); // RTS
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource5, GPIO_AF_UART1); // CTS
    
    // 3. 配置UART参数,使能硬件流控
    UART_InitTypeDef uart_init;
    uart_init.UART_BaudRate = 115200;
    uart_init.UART_WordLength = UART_WORDLENGTH_8B;
    uart_init.UART_StopBits = UART_STOPBITS_1;
    uart_init.UART_Parity = UART_PARITY_NONE;
    uart_init.UART_Mode = UART_MODE_TX_RX;
    uart_init.UART_HardwareFlowControl = UART_HWCONTROL_RTS_CTS; // 使能硬件流控
    UART_Init(UART1, &uart_init);
    
    // 4. 使能UART
    UART_Cmd(UART1, ENABLE);
}
💡 我的习惯: 如果硬件流控引脚不够用,或者对方设备不支持RTS/CTS,我会用软件流控(XON/XOFF)作为替代方案。但说实话,软件流控在高速场景下效率很低——它需要在数据流中插入特殊字符,处理起来很麻烦。所以,能用硬件流控就别用软件。

3.4 本章知识结构图

下面这张图把UART硬件设计的三个核心维度串起来了。你可以把它当作设计检查清单:

UART硬件设计知识结构图 UART硬件设计 引脚分配 • 检查复用功能冲突 • 避免与SPI/I2C/TIM共用 • 原理图阶段做交叉表 电平转换 • TTL→RS232:MAX3232 • TTL→RS485:MAX3485 • RS485需GPIO控制收发 • 去耦电容紧贴芯片 硬件流控RTS/CTS • 高速场景(≥460800)必用 • 对接蓝牙/WiFi模块建议用 • RS485不适用硬件流控 • 配置UART_HWCONTROL_RTS_CTS 设计原则:先规划、再布线、后调试

核心要点回顾:

  • 引脚分配:先做交叉表,再画原理图,避免复用功能冲突
  • 电平转换:根据通信距离和接口类型选择RS232或RS485,去耦电容不能省
  • 硬件流控:高速场景和模块对接时强烈建议使用,RS485用软件控制收发使能