串行通信是嵌入式系统中最基础也最关键的通信技术之一。作为最常用的异步串行接口,UART通过灵活的波特率配置和寄存器控制实现了广泛的数据传输应用。而在UART基础上扩展的IrDA红外通信和CIR消费电子红外控制功能,则为设备提供了无线通信能力。
UART模块通过MDR1_REG[2:0]的MODE_SELECT字段实现多种工作模式的切换。这个3位字段决定了模块将作为标准UART、IrDA还是CIR接口工作,同时也控制了UART的不同波特率生成方式。
在配置模式选择时,必须严格遵守一个关键操作顺序:先禁用模块(MODE_SELECT=0x7),再设置目标模式。这个顺序看似简单,但却是许多工程师容易忽视的"坑"。我曾在一个车载娱乐系统项目中,因为忽略了这一步,导致整个UART模块工作异常,花了整整两天时间才排查出问题。
模式选择的具体编码如下:
| 值 | 模式 | 适用模块 |
|---|---|---|
| 0x0 | UART 16x模式 | 所有UART |
| 0x1 | SIR模式 | 仅UART3 |
| 0x2 | UART 16x自动波特率 | 所有UART |
| 0x3 | UART 13x模式 | 所有UART |
| 0x4 | MIR模式 | 仅UART3 |
| 0x5 | FIR模式 | 仅UART3 |
| 0x6 | CIR模式 | 仅UART3 |
重要提示:在初始化或修改时钟参数控制寄存器(DLH_REG/DLL_REG)之前,必须先将MODE_SELECT设为禁用状态(0x7)。违反这一规则可能导致模块行为异常。
UART模式下可用的寄存器根据工作状态(配置模式A/B或操作模式)有所不同。这种设计既保证了配置灵活性,又避免了误操作关键寄存器。
DLL_REG/DLH_REG:波特率分频值寄存器,共同组成14位分频器。DLL存储低8位,DLH存储高6位。
波特率计算公式:
LCR_REG:线路控制寄存器,控制数据格式:
EFR_REG:增强功能寄存器,控制硬件流控:
MCR_REG:调制解调器控制寄存器:
UART模块有三种寄存器访问模式,每种模式下寄存器的读写行为可能不同:
| 偏移地址 | 寄存器名称 | 配置模式A | 操作模式 |
|---|---|---|---|
| 0x000 | DLL_REG | 读写分频值低字节 | 只读接收保持寄存器 |
| 0x004 | DLH_REG | 读写分频值高字节 | 只写中断使能寄存器 |
| 0x008 | IIR_REG/FCR_REG | 中断标识/ FIFO控制 | 不同功能 |
这种设计使得同一物理地址在不同模式下可以复用为不同功能的寄存器,既节省了地址空间,又保持了功能清晰。
IrDA模式仅在UART3上可用,它扩展了标准UART功能,支持红外通信的三种速率标准:
IrDA模式的时钟生成比UART复杂,不同模式使用不同的分频系数:
波特率计算公式:
IrDA模式引入了一些专用寄存器来控制红外特有的功能:
IrDA模式下,数据以帧为单位传输,帧控制是重点。有两种帧结束方式:
在实际项目中,帧长度法更适合固定长度的协议帧,而EOT位法则更适合变长数据。我曾在一个医疗设备项目中,因为混淆了这两种模式,导致红外通信不稳定,后来统一使用帧长度法解决了问题。
CIR(Consumer Infrared)模式专为消费电子红外遥控设计,它在寄存器使用上更为精简,主要特点包括:
CIR模式下,MDR1_REG[3:0]的更多位被用于控制载波生成和脉冲解码参数,这与UART和IrDA模式有明显区别。
UART模块使用48MHz基准时钟,通过可编程分频器生成所需的波特率时钟。分频值计算是UART初始化的关键步骤。
UART通常使用16倍过采样的16x模式,但在高速(≥460.8kbps)时,为降低分频比,可采用13x模式:
| 波特率 | 推荐模式 | 分频值 | 实际波特率 | 误差 |
|---|---|---|---|---|
| 460.8kbps | 13x | 8 | 461.54kbps | +0.16% |
| 921.6kbps | 13x | 4 | 923.08kbps | +0.16% |
| 1.843Mbps | 13x | 2 | 1.846Mbps | +0.16% |
从表中可以看出,虽然理论计算存在微小误差,但在实际应用中,这种误差通常可以接受。我在工业控制器项目中测试过,即使连续传输8小时,这种误差也不会导致数据错位。
自动波特率模式(MODE_SELECT=0x2)是UART的一个实用功能,它能自动检测输入数据的波特率。该模式通过识别"AT"命令序列来确定通信参数:
自动波特率的一个限制是不支持7位字符加空格校验的组合。在启用自动波特率时,需要注意:
IrDA模式的波特率生成更为复杂,不同速率标准采用不同的编码方式:
SIR采用3/16编码,即每个bit周期内,逻辑1对应3/16周期的光脉冲,逻辑0无脉冲。这种编码保证了足够的空闲时间,便于接收端同步。
典型SIR波特率配置示例(48MHz时钟):
| 目标波特率 | 分频值 | 实际波特率 | 脉冲宽度 |
|---|---|---|---|
| 115.2kbps | 26 | 115.38kbps | 1.62μs |
| 57.6kbps | 52 | 57.692kbps | 3.25μs |
| 9.6kbps | 312 | 9.6153kbps | 19.5μs |
MIR采用1/4编码,使用41或42分频,实现更高的数据传输速率:
| 目标波特率 | 分频值 | 实际波特率 | 脉冲宽度 |
|---|---|---|---|
| 1.152Mbps | 1 | 1.1511Mbps | 208ns |
| 0.576Mbps | 2 | 0.5756Mbps | 416ns |
MIR模式下的分频值较小,时钟抖动对通信稳定性的影响更为明显,因此在实际应用中需要更高精度的时钟源。
FIR模式固定使用4PPM(4脉冲位置调制)编码,波特率固定为4Mbps,不依赖DLL/DLH分频器。FIR的每个符号周期为250ns,通过脉冲在四个可能位置中的出现与否来表示数据。
UART的数据帧格式通过LCR_REG寄存器配置,主要包括以下要素:
校验位配置较为灵活,支持多种模式:
| PARITY_EN | PARITY_TYPE1 | PARITY_TYPE2 | 校验类型 |
|---|---|---|---|
| 0 | X | X | 无校验 |
| 1 | 0 | 0 | 奇校验 |
| 1 | 1 | 0 | 偶校验 |
| 1 | 0 | 1 | 强制1 |
| 1 | 1 | 1 | 强制0 |
在工业通信中,奇偶校验是常见的错误检测手段。但我在实际测试中发现,在高噪声环境中,仅靠奇偶校验是不够的,通常需要结合更高层的校验机制如CRC。
硬件流控制通过RTS/CTS信号自动管理数据流,可显著降低软件开销。UART模块支持两种硬件流控制机制:
自动RTS的工作流程:
这种机制确保了接收端有足够缓冲区时才请求发送数据,避免了FIFO溢出。
自动CTS的工作流程:
自动CTS和自动RTS通常配合使用,实现全双工的硬件流控制。在医疗设备等高可靠性应用中,这种机制可以防止数据丢失。
软件流控制通过特殊字符(XON/XOFF)控制数据流,由EFR_REG配置。与硬件流控相比,它不需要额外的信号线,但增加了协议复杂度。
软件流控支持多种组合方式:
| EFR_REG[3:2] | 发送流控字符 | EFR_REG[1:0] | 接收比较字符 |
|---|---|---|---|
| 00 | 无 | 00 | 无 |
| 10 | XON1/XOFF1 | 10 | XON1/XOFF1 |
| 01 | XON2/XOFF2 | 01 | XON2/XOFF2 |
| 11 | XON1,XON2/XOFF1,XOFF2 | 11 | XON1,XON2/XOFF1,XOFF2 |
XON/XOFF字符可自定义,通常使用ASCII控制字符DC1(0x11)和DC3(0x13)。在跨平台通信中,需要确保两端使用相同的流控字符定义。
UART模块支持多种中断源,按优先级从高到低排列:
每种中断都有独立的使能位(IER_REG)和标识位(IIR_REG)。在实际编程中,合理配置中断优先级和处理程序对系统性能影响很大。
UART模块能检测多种传输错误,通过LSR_REG反映:
在高速通信中,错误处理尤为关键。我的经验是:对于OE错误,应适当增大FIFO触发阈值;对于PE/FE错误,则需要检查波特率配置和线路质量。
IrDA模式除了常规错误外,还有特有的错误类型:
IrDA的错误信息存储在状态FIFO中,需要读取SFLSR_REG获取。在DMA传输中,可以设置状态FIFO的触发水平,减少中断频率。
正确的初始化序列对UART稳定工作至关重要。以下是经过验证的初始化步骤:
在步骤1和步骤6之间,应加入足够的延时,确保模块完全复位。我在智能家居项目中曾遇到因延时不足导致的初始化失败问题,加入10ms延时后解决。
分频值计算:使用无符号整数运算,避免浮点误差
c复制// 16x模式分频值计算示例
#define UART_CLK 48000000
uint16_t div16x = (UART_CLK + (baudrate * 8)) / (baudrate * 16); // 四舍五入
误差评估:实际波特率误差应小于3%,最好小于1%
c复制float actual_baud = (float)UART_CLK / (16 * div16x);
float error = (actual_baud - baudrate) / baudrate * 100; // 误差百分比
高速模式选择:≥460.8kbps时优先使用13x模式,降低分频比
FIFO能有效减轻CPU负担,合理配置触发水平很关键:
接收FIFO:
发送FIFO:
在DMA传输中,可以将触发水平设为1,配合DMA请求实现最高效率。
无通信:
数据错误:
流控失效:
在多年的开发中,我发现90%的UART问题都源于配置错误。使用逻辑分析仪捕获实际波形,对照寄存器配置分析,是快速定位问题的有效方法。