1. 项目概述与UART核心价值在嵌入式开发的世界里设备间的“对话”是项目成败的关键。无论是让主控芯片读取传感器数据还是将调试信息打印到电脑都需要一个可靠、高效的通信桥梁。在众多通信协议中UART通用异步收发器以其简单、成熟、无需时钟线的特点成为了工程师们最信赖的“老伙计”。它不追求极致的速度但胜在稳定可靠几乎每一款微控制器MCU都将其作为标准配置。这次我们把目光聚焦在德州仪器TI的CC26x0和CC13x0系列无线微控制器上。这两款芯片在低功耗物联网领域大名鼎鼎其内置的UART模块远不止一个简单的串口那么简单。它集成了深度可调的FIFO缓冲区、灵活的硬件流控制、与DMA控制器无缝协作的能力以及精细的中断管理机制。理解并熟练配置这些寄存器意味着你能从“能用”串口跃升到“精通”串口能榨干硬件性能设计出更稳定、更高效、更省电的通信链路。对于从事蓝牙、Zigbee、Sub-1GHz等无线应用开发的工程师来说这是绕不开的基本功。本文就将带你深入CC26x0/CC13x0的UART模块内部从原理到寄存器手把手拆解配置要点和避坑指南。2. UART通信基础与CC26x0模块架构解析2.1 异步串行通信的本质在开始摆弄寄存器之前我们必须先统一“语言”。UART通信是异步的这意味着通信双方没有共享的时钟信号来同步每一位数据。那么接收方如何知道从哪里开始读、读多快呢答案就在于预先约定好的帧格式和波特率。一个标准的UART数据帧就像一列火车起始位Start Bit是车头永远是一个逻辑低电平0它告诉接收方“注意数据要来了”。紧接着是5到8个数据位Data Bits承载着实际信息通常从最低有效位LSB开始发送。数据位之后是可选的校验位Parity Bit用于最简单的错误检测如奇校验、偶校验。最后是停止位Stop Bit一个或多个逻辑高电平1标志着本帧数据的结束并为下一帧的起始位留出准备时间。波特率Baud Rate定义了这列“火车”的运行速度即每秒传输的符号数。对于UART一个符号就是一位所以115200的波特率意味着每秒传输115200位。发送和接收双方必须严格使用相同的波特率、数据位、停止位和校验位设置否则通信就会乱码就像两个人用不同的语言和语速对话根本无法理解彼此。2.2 CC26x0/CC13x0 UART模块亮点CC26x0/CC13x0的UART模块可以看作一个高度集成的“通信管家”它基于经典的16C550架构思想但寄存器并不兼容拥有许多现代化增强特性高性能波特率发生器支持高达3 Mbps的通信速率足以应对大多数高速数据采集或固件升级场景。深度缓冲的FIFO独立的32x8位发送FIFO和32x12位接收FIFO。接收FIFO多出的4位用于存储每字节数据的错误状态帧错误、奇偶校验错误、溢出错误、Break错误。FIFO能显著减少CPU处理中断的频率提升系统效率。可编程FIFO触发水位中断并非来一个字节就触发一次。你可以设置FIFO填充到1/8、1/4、1/2、3/4、7/8时再产生中断让CPU批量处理数据进一步优化性能。灵活的帧格式数据位5-8位、停止位1或2位、校验位奇、偶、固定、无均可自由配置。硬件流控制RTS/CTS通过RTS请求发送和CTS清除发送信号线实现收发双方的速度匹配防止缓冲区溢出导致数据丢失这是实现可靠通信的关键。强大的中断系统可独立屏蔽发送、接收、接收超时、调制解调器状态、各类错误等多种中断源并提供原始和掩码后两种中断状态查询。μDMA微直接内存访问支持为发送和接收提供了独立的DMA通道可以将CPU从繁重的数据搬运工作中彻底解放出来实现高效的数据吞吐。注意在配置任何UART功能寄存器之前必须先通过清除UART_CTL寄存器的UARTEN位来禁用UART模块。否则在UART使能状态下修改关键配置如波特率、帧格式可能导致不可预测的行为或通信失败。这是一个非常容易踩坑的地方。3. 核心寄存器详解与配置实战手册里寄存器列表看起来令人望而生畏但实际常用、需要重点关注的也就那么十来个。我们按功能分组并结合一个具体的配置实例来讲解。3.1 波特率配置精度与同步的艺术波特率配置是通信的基石。CC26x0的波特率发生器由一个22位的分频器驱动包括16位整数部分UART_IBRD和6位小数部分UART_FBRD。这种设计允许它生成非常精确的标准波特率。计算公式如下BRD UART_CLK / (16 * 期望的波特率)其中UART_CLK是供给UART模块的时钟频率例如PERDMACLK通常为48MHz或24MHz。BRD的结果是一个浮点数其整数部分写入IBRD小数部分乘以64再加0.5用于四舍五入后取整写入FBRD。实战配置115200波特率时钟24MHz计算BRD:24,000,000 / (16 * 115200) 13.0208333整数部分IBRD 13(0xD)小数部分计算:FBRD integer(0.0208333 * 64 0.5) integer(1.83333 0.5) integer(2.33333) 2因此我们需要向UART_IBRD写入13向UART_FBRD写入2。关键陷阱IBRD、FBRD和UART_LCRH线路控制寄存器共同构成一个内部30位锁存器。这个锁存器只有在写入UART_LCRH时才会被更新这意味着更改波特率必须遵循正确的顺序顺序A写IBRD- 写FBRD- 写LCRH顺序B写FBRD- 写IBRD- 写LCRH顺序C写IBRD- 写LCRH仅改整数部分顺序D写FBRD- 写LCRH仅改小数部分最常见的错误是只写了IBRD和FBRD却忘了随后“触发”一下LCRH的写操作即使LCRH的值没变也需要写一次导致新波特率不生效。3.2 帧格式与FIFO控制UART_LCRH寄存器UART_LCRH寄存器是UART的“面貌塑造师”它决定了数据帧长什么样以及FIFO如何工作。WLEN(Bits 6:5)数据位长度。005位016位107位118位。绝大多数应用使用8位0x60。FEN(Bit 4)FIFO使能位。必须置1才能启用32字节的深度缓冲这是发挥该UART性能优势的关键。复位后默认为0禁用此时FIFO退化为1字节的保持寄存器。STP2(Bit 3)停止位数量。01个停止位12个停止位。EPS,PEN,SPS(Bits 2:1:0)共同控制校验位。PEN使能校验EPS选择奇偶0奇校验1偶校验SPS选择粘性校验通常为0。如果要配置为8位数据、无校验、1停止位、使能FIFO则UART_LCRH应写入0x70(二进制0111 0000)。3.3 核心控制与状态UART_CTL与UART_FR寄存器UART_CTL是总开关。UARTEN(Bit 0)UART模块总使能。在完成所有初始化波特率、帧格式、GPIO映射等后最后置1。TXE,RXE(Bits 8, 9)分别使能发送器和接收器。通常两者都使能。LBE(Bit 7)回环模式使能。置1后TX引脚输出 internally loopback 到RX引脚输入用于自测试无需外部连线。CTSEN,RTSEN(Bits 15, 14)硬件流控制使能。具体配置见下文硬件流控制部分。UART_FR是状态指示器主要用于查询轮询模式。TXFF,TXFE发送FIFO满、发送FIFO空。RXFF,RXFE接收FIFO满、接收FIFO空。BUSY(Bit 3)忙碌标志位。这是一个非常重要的位。当发送FIFO非空或移位寄存器正在发送时该位为1。它只有在发送FIFO完全清空且最后一个字符包括停止位已完全移出后才会变为0。因此在准备关闭UART或进入低功耗模式前不能仅仅检查TXFE还必须等待BUSY位变为0以确保所有数据都已物理发送完毕。3.4 数据收发UART_DR寄存器UART_DR寄存器是数据进出的门户。读操作返回一个12位的值低8位是数据高4位Bits 11:8分别是OE溢出错误、BEBreak错误、PE奇偶校验错误、FE帧错误状态位。写操作则向发送FIFO写入8位数据。操作心得在启用FIFO的情况下你可以连续向UART_DR写入多达32个字节而无需等待。同样读取时也可以一次读取多个字节并同时检查其错误状态。这比传统的单字节查询效率高得多。3.5 中断系统深度配置CC26x0的中断系统设计得非常精细目的是让CPU只在必要时被唤醒。1. 中断水位设置 (UART_IFLS) 这个寄存器决定了FIFO填充到什么程度时触发中断。例如设置接收中断水位为1/4那么当接收FIFO中累积了8个字节32 * 1/4时才会产生接收中断。这对于处理数据包非常有用你可以设置水位略高于预期数据包长度让一个中断处理一整个包。2. 中断掩码与状态 (UART_IMSC,UART_RIS,UART_MIS,UART_ICR)UART_IMSC中断掩码设置/清除寄存器。你想让哪种事件触发中断就把对应的位置1。UART_RIS原始中断状态寄存器。无论掩码如何只要事件发生对应位就置1。UART_MIS被掩码后的中断状态寄存器。只有UART_IMSC中使能了的事件其状态才会出现在这里。在中断服务程序ISR中通常读取这个寄存器来判断中断源。UART_ICR中断清除寄存器。向某个位写1可以清除UART_RIS和UART_MIS中对应的中断状态位。注意有些中断如接收中断在读取FIFO数据使其低于触发水位后也会自动清除。中断处理流程示例void UART0_IRQHandler(void) { uint32_t mis HWREG(UART0_BASE UART_O_MIS); // 读取被掩码的中断状态 if (mis UART_INT_RX) { // 接收中断 // 1. 循环读取UART_DR直到UART_FR.RXFE为1FIFO空 // 2. 处理读取到的数据 // 3. 接收中断会自动清除当FIFO水位低于阈值 } if (mis UART_INT_TX) { // 发送中断 // 1. 检查是否还有数据要发送 // 2. 如果有写入UART_DR直到FIFO满或数据写完 // 3. 如果发完了可以在UART_IMSC中屏蔽发送中断避免空触发 // 4. 发送中断在向FIFO写入数据使其超过水位后会自动清除 } if (mis UART_INT_RT) { // 接收超时中断 // 当FIFO非空但超过32个位时间没有新数据时触发 // 这是处理“数据包尾”或“短帧”的绝佳时机立即读取FIFO中剩余的数据 HWREG(UART0_BASE UART_O_ICR) UART_INT_RT; // 需要手动写ICR清除 } if (mis UART_INT_OE) { // 溢出错误 // 严重错误数据已丢失。需要读取UART_RSR或UART_DR获取错误状态并复位接收逻辑 HWREG(UART0_BASE UART_O_ECR) 0xFF; // 写ECR清除所有错误标志 } // ... 处理其他错误中断 }4. 高级功能实现硬件流控制与DMA传输4.1 硬件流控制RTS/CTS实战硬件流控制是保证高速或大数据量通信不丢数据的“保险丝”。它通过UART0_RTS输出和UART0_CTS输入两根信号线实现。RTS (Request To Send)本设备告诉对方“我的接收缓冲区快满了请你暂停发送”。当接收FIFO空间达到预设水位例如快满时RTS信号会变为无效高电平通知对方停止发送。CTS (Clear To Send)本设备接收对方指令“对方允许我发送数据”。只有当CTS信号有效低电平时本设备的发送器才会工作。如果CTS变高发送会暂停在当前字符发送完后直到CTS再次变低。在CC26x0上配置硬件流控制GPIO配置将两个GPIO引脚分别配置为UART0_RTS和UART0_CTS功能。控制寄存器配置在UART_CTL寄存器中同时设置RTSEN和CTSEN位为1使能完整的RTS/CTS流控制。理解模式手册中提到UART可作为DTE或DCE信号定义会反转。在大多数嵌入式设备作为终端设备的场景下我们通常将其配置为DTE模式即UART0_RTS是我们的输出请求发送UART0_CTS是我们的输入清除发送。连接时本设备的RTS接对端设备的CTS本设备的CTS接对端设备的RTS交叉连接。重要提示务必在使能UART (UARTEN1)之前通过IOC模块正确配置GPIO的复用功能。如果先使能UART再配置GPIOUART模块可能会在引脚状态不稳定时检测到错误的起始位或信号跳变导致通信紊乱或无法启动。4.2 DMA传输配置解放CPU的利器对于需要连续、高速传输数据的应用如通过串口上传大量传感器数据或下载固件使用DMA是必不可少的优化手段。配置步骤使能UART的DMA功能设置UART_DMACTL寄存器的TXDMAE位使能发送DMA和/或RXDMAE位使能接收DMA。配置μDMA控制器为UART发送和接收分配独立的DMA通道例如Channel 1用于发送Channel 2用于接收。设置通道的源地址对于发送是内存数据地址对于接收是UART_DR寄存器地址和目标地址对于发送是UART_DR寄存器地址对于接收是内存缓冲区地址。配置传输模式通常使用“基本模式”Basic也可以使用Ping-Pong模式实现双缓冲。设置传输数据量仲裁大小。理解UART的DMA请求UART会向DMA控制器发出两种请求单次请求Single Request和突发请求Burst Request。发送当发送FIFO有空间时发出请求。单次请求对应有1个空位突发请求对应空位达到FIFO触发水位。接收当接收FIFO有数据时发出请求。单次请求对应有1个数据突发请求对应数据量达到FIFO触发水位。在DMA控制器的通道配置中你需要选择响应哪种请求通常选择突发请求以提高效率。连接与清除如图19-3所示UART的DMA请求清除信号需要连接到DMA控制器的“通道活跃”DMA active信号。这确保了在DMA传输期间UART不会重复产生请求。TI的驱动库通常会帮你处理好这些底层连接。DMA配置示例片段概念性代码// 假设使用TI DriverLib // 1. 配置UART DMA使能 HWREG(UART0_BASE UART_O_DMACTL) | (UART_DMACTL_TXDMAE | UART_DMACTL_RXDMAE); // 2. 配置μDMA发送通道例如通道1 uDMAChannelControlSet(UDMA_CHANNEL_UART0_TX | UDMA_PRI_SELECT, UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_8); uDMAChannelTransferSet(UDMA_CHANNEL_UART0_TX | UDMA_PRI_SELECT, UDMA_MODE_BASIC, txBuffer, (void *)(UART0_BASE UART_O_DR), bufferSize); // 3. 配置μDMA接收通道例如通道2 uDMAChannelControlSet(UDMA_CHANNEL_UART0_RX | UDMA_PRI_SELECT, UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_8); uDMAChannelTransferSet(UDMA_CHANNEL_UART0_RX | UDMA_PRI_SELECT, UDMA_MODE_BASIC, (void *)(UART0_BASE UART_O_DR), rxBuffer, bufferSize); // 4. 使能DMA通道 uDMAChannelEnable(UDMA_CHANNEL_UART0_TX); uDMAChannelEnable(UDMA_CHANNEL_UART0_RX);配置完成后当你需要发送数据时只需将数据放入txBuffer然后启动DMA传输CPU就可以去处理其他任务了。数据会自动从内存搬运到UART的发送FIFO并发出。接收亦然。5. 完整初始化流程、常见问题与调试技巧5.1 一个完整的UART初始化流程结合以上所有知识点一个稳健的UART0初始化流程如下使能外设时钟通过PRCM模块使能UART0所在的外设时钟域运行、睡眠模式。使用函数PRCMPeripheralRunEnable(PRCM_PERIPH_UART0)。加载时钟设置调用PRCMLoadSet()使能时钟生效。配置GPIO引脚复用通过IOC模块将目标GPIO引脚配置为UART0_RXD、UART0_TXD功能。如果需要硬件流控制还要配置UART0_RTS和UART0_CTS。禁用UART写UART_CTL寄存器清除UARTEN位。配置波特率计算并写入UART_IBRD和UART_FBRD寄存器。配置帧格式和FIFO写入UART_LCRH寄存器设置数据位、停止位、校验位并务必置位FEN以启用FIFO。这一步也锁存了步骤5的波特率设置。可选配置中断设置UART_IFLS选择中断触发水位设置UART_IMSC使能所需的中断源在NVIC中使能UART0中断。可选配置硬件流控制如果需要在UART_CTL中设置RTSEN和CTSEN。可选配置DMA如果需要设置UART_DMACTL并配置μDMA通道。最后使能UART置位UART_CTL寄存器的UARTEN位。如果需要同时置位TXE和RXE。5.2 常见问题排查速查表现象可能原因排查步骤与解决方案完全无通信TX引脚无波形1. UART模块时钟未使能。2. GPIO引脚复用功能未正确配置。3.UARTEN位未使能。4.TXE位被禁用。1. 检查PRCM配置代码。2. 用万用表或示波器检查引脚电压或用IO口功能测试程序验证。3. 确认UART_CTL寄存器值。4. 确认UART_CTL寄存器值。能发送但不能接收或反之1.RXE或TXE位未使能。2. 线路连接错误RX/TX接反。3. 对方设备故障或配置错误。1. 检查UART_CTL寄存器。2. 交换RX和TX线缆测试。3. 用USB转串口工具等已知良好的设备交叉验证。通信乱码1.波特率不匹配最常见。2. 数据位、停止位、校验位配置不匹配。3. 系统时钟源如HF晶振精度不够导致波特率偏差过大。1. 双方设备使用示波器测量位宽度计算实际波特率。2. 仔细核对双方UART_LCRH配置。3. 检查芯片时钟树配置确保UART时钟源稳定准确。高波特率时丢数据1. 未使用FIFOCPU处理中断不及时。2. 未使用硬件流控制缓冲区溢出。3. 中断优先级太低被其他中断阻塞。4. DMA配置错误或未使用。1. 确认UART_LCRH.FEN1。2. 检查并连接RTS/CTS线确认UART_CTL中已使能。3. 提高UART中断优先级。4. 检查DMA通道配置和传输大小。发送完成后系统挂起或复位在发送FIFO未完全清空、BUSY位仍为1时关闭了UART模块时钟或进入了深度睡眠。在关闭UART或进入低功耗前循环检查UART_FR寄存器直到TXFE和BUSY位同时为0。中断不触发或频繁触发1. 中断未在NVIC中使能。2.UART_IMSC中未屏蔽对应中断源。3.UART_IFLS触发水位设置不合理如接收水位为1/8则每4字节就中断一次。4. 中断服务程序ISR中未清除中断标志。1. 检查NVIC配置。2. 检查UART_IMSC寄存器值。3. 根据数据包大小调整UART_IFLS。4. 对于需要手动清除的中断如接收超时RT、错误中断确保在ISR中写UART_ICR。DMA传输卡住或数据不全1. DMA通道未使能或配置错误源/目标地址、传输大小。2. UART的DMA使能位TXDMAE/RXDMAE未设置。3. DMA传输完成中断未处理或未重新配置下一次传输。1. 单步调试检查DMA通道控制寄存器配置。2. 检查UART_DMACTL寄存器。3. 实现DMA传输完成中断并在其中重新装填缓冲区或处理数据。5.3 调试心得与高级技巧活用回环模式在硬件连接前先将UART_CTL.LBE置1进入内部回环模式。然后自发自收数据。这是验证UART底层驱动代码波特率计算、数据读写是否正确的最快方法无需连接任何外部设备。善用状态寄存器当通信异常时第一时间读取UART_FR标志寄存器和UART_RSR/UART_DR高4位错误状态。FE帧错误往往意味着波特率严重失配或线路干扰OE溢出错误意味着你的程序读取速度跟不上接收速度需要优化代码或启用流控制/DMA。接收超时中断的妙用RT接收超时中断在处理不定长数据包时非常有用。设置一个合理的超时时间例如对应4-8个字符的时间当一帧数据发送完毕线路空闲超过这个时间就会触发此中断。在ISR中读取FIFO里剩余的数据即可完整获取一帧。这比依赖特定结束符更可靠。低功耗设计考虑在CC26x0这种低功耗设备上UART通信期间外设域是活动的。通信间隙如果没有数据应让CPU进入睡眠。此时可以将UART中断唤醒CPU。更高级的做法是配合DMA设置DMA传输完成中断让CPU只在数据块准备好时才被唤醒一次最大化睡眠时间。计算波特率误差波特率误差是通信距离和可靠性的隐形杀手。使用公式误差(%) (|实际波特率 - 目标波特率| / 目标波特率) * 100%计算你的配置产生的误差。对于常用的115200波特率误差最好控制在2%以内长距离或高速通信则要求更严。CC26x0的分数分频器能让误差变得非常小。