尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

CC13x2/CC26x2 UART驱动开发:从波特率计算到DMA配置的实战指南

CC13x2/CC26x2 UART驱动开发:从波特率计算到DMA配置的实战指南
📅 发布时间:2026/7/26 12:58:07

1. 项目概述

在嵌入式开发的世界里,UART(通用异步收发器)就像一位沉默寡言但极其可靠的老朋友。无论你是调试代码、打印日志,还是连接GPS模块、蓝牙透传芯片,UART总是那个最基础、最直接的通信桥梁。它不需要复杂的握手协议,仅凭两根线(TX和RX)就能建立起设备间的对话,这种简洁和高效是其他总线难以比拟的。

这次我们聚焦于德州仪器(TI)的CC13x2和CC26x2系列无线微控制器(MCU)。这两款芯片在物联网和低功耗无线领域名声显赫,而它们内置的UART模块,远不止是一个简单的串口。它支持高达3 Mbps的波特率,拥有独立的收发FIFO,集成了硬件流控制和DMA接口,甚至可以通过分数波特率发生器实现精准的时钟分频。对于开发者而言,这意味着你可以用更少的CPU干预,实现更稳定、更高效的数据吞吐,尤其是在电池供电的无线传感节点中,这种效率直接关系到设备的续航能力。

然而,官方技术手册往往侧重于寄存器位的描述,对于如何将这些功能模块组合成一个稳定、高效的驱动,以及在实际项目中可能遇到的“坑”,却着墨不多。我经历过不少因为波特率计算偏差导致的通信乱码,也调试过因FIFO触发级别设置不当而丢失的数据包。这篇文章,我将结合手册内容和多年的实战经验,带你从原理到寄存器,再到代码实践,彻底吃透CC13x2/CC26x2的UART模块。无论你是刚接触嵌入式的新手,还是想优化现有通信协议的老手,相信都能从中找到有价值的细节。

2. UART核心原理与CC13x2/CC26x2模块架构

2.1 异步串行通信的本质

要驾驭一个外设,首先要理解它工作的基本逻辑。UART通信是异步的,这意味着通信双方没有共享的时钟线来同步每一位数据。那么,接收方如何知道一位数据的开始和结束呢?答案就在于起始位和停止位,以及一个预先约定好的速度——波特率。

一个标准的UART数据帧以一位低电平的起始位开始,这就像跑步比赛时的发令枪,告诉接收方:“数据要来了,准备好采样!”紧接着是5到8位的数据位(通常为8位),从最低有效位(LSB)开始发送。数据位之后是可选的奇偶校验位,用于简单的错误检测。最后,以一位或多位高电平的停止位结束,标志着本次传输的终止,并确保线路恢复到空闲(高电平)状态。

这里的关键在于,发送和接收双方必须使用完全相同的波特率。波特率定义为每秒传输的符号数,对于UART,一个符号就是一位。如果双方波特率有微小偏差,在传输大量数据后,采样点就会逐渐漂移,最终导致帧错误。CC13x2/CC26x2的UART模块通过一个22位的分数波特率发生器(16位整数 + 6位小数)来精确匹配所需的波特率,这是其高可靠性的基础。

2.2 CC13x2/CC26x2 UART模块功能全景

CC13x2/CC26x2的UART模块可以看作一个高度集成的通信引擎,其功能远不止简单的串并转换。我们来看看它的核心组件:

  1. 双缓冲FIFO:独立的32x8位发送FIFO和32x12位接收FIFO。接收FIFO多出的4位用于存储每个字节对应的状态信息(帧错误、奇偶校验错误、溢出错误、线路中断)。FIFO的引入极大地减轻了CPU负担。你可以配置FIFO的触发水位(如1/2满),只有当数据量达到这个阈值时才产生中断,让CPU能批量处理数据,而不是每收到一个字节就被打断一次。
  2. 灵活的帧格式控制:通过UART:LCRH寄存器,你可以自由定义数据位长度(5-8位)、停止位数量(1或2位)、奇偶校验类型(奇校验、偶校验、固定1、固定0或无校验)。这种灵活性使其能够适配从老式设备到现代传感器的各种通信协议。
  3. 硬件流控制(RTS/CTS):这是实现可靠高速通信的关键。当接收方FIFO快满时,可以通过拉低RTS(请求发送)信号通知发送方暂停发送;反之,发送方在检测到CTS(清除发送)信号有效(低电平)后才开始发送。这避免了因接收端处理不及时而导致的数据溢出(Overrun)。模块的UART:CTL寄存器可以独立启用CTS和RTS流控制。
  4. 强大的中断系统:模块可以针对多种事件产生中断:发送FIFO空、接收FIFO达到触发水平、接收超时、帧错误、奇偶校验错误、溢出错误、线路中断以及调制解调器状态变化。所有中断源在逻辑上“或”起来产生一个总的中断请求给CPU,你需要在中断服务程序(ISR)中读取UART:MIS(屏蔽后中断状态)寄存器来判别具体是哪个事件触发了中断。
  5. μDMA(微直接内存访问)集成:这是提升系统效率的利器。UART模块为发送和接收分别提供了独立的DMA请求信号(单次请求和突发请求)。启用DMA后,数据可以在UART FIFO和系统内存之间直接搬运,完全无需CPU参与。例如,在接收大量数据时,你可以配置DMA在接收FIFO达到半满时,自动将32字节的数据块搬移到指定的内存缓冲区,仅在DMA传输完成时产生一个中断通知CPU处理。这显著降低了CPU负载和中断延迟。

理解这个整体架构后,我们再深入各个功能模块的配置细节,就会清晰很多。这个模块的设计思想很明确:把能硬件化的任务都交给硬件,让CPU专注于应用逻辑。

3. 关键功能深度解析与配置要点

3.1 波特率计算:精度与误差控制

波特率配置是UART通信的第一步,也是最容易出错的一步。CC13x2/CC26x2的波特率发生器公式如下:

BRD = UART_Ref_Clk / (16 * Desired_Baud_Rate)

其中,BRD是一个22位的数值,高16位是整数部分(IBRD.DIVINT),低6位是小数部分(FBRD.DIVFRAC)。UART_Ref_Clk通常是外设时钟PERDMACLK,例如24 MHz或48 MHz。

计算示例:假设PERDMACLK = 24 MHz,目标波特率为115200。

  1. 计算理论BRD:24,000,000 / (16 * 115,200) ≈ 13.02083333
  2. 整数部分IBRD = 13(0xD)
  3. 小数部分计算:FBRD = integer(0.02083333 * 64 + 0.5) = integer(1.83333) = 1

这里有一个非常重要的细节:对UART:FBRD寄存器的写入必须遵循特定的顺序。手册指出,UART:IBRD、UART:FBRD和UART:LCRH寄存器共同构成一个内部的30位锁存器。这个锁存器只有在写入UART:LCRH时才会更新。因此,正确的配置顺序必须是:

  • 先写UART:IBRD
  • 再写UART:FBRD
  • 最后写UART:LCRH(即使LCRH的值没有改变,也必须执行一次写操作来锁存新的波特率除数)

如果顺序错误,新的波特率将不会生效。这是一个常见的陷阱。

实操心得:在实际项目中,我习惯使用一个计算函数来生成配置值,并封装一个波特率设置函数,确保顺序正确。同时,对于非常见波特率(如非整数的自定义速率),要计算实际产生的波特率与目标值的误差。误差计算公式为:误差 = (实际波特率 - 目标波特率) / 目标波特率。通常要求误差小于2%(很多串口芯片的容限在3%以内),但为了稳定性,最好控制在1%以下。对于24MHz时钟和115200波特率,实际波特率为24e6 / (16 * (13 + 1/64)) ≈ 115207,误差仅为0.006%,完全可以忽略。

3.2 FIFO与中断协同工作策略

FIFO和中断的配置直接决定了UART驱动的效率和实时性。UART:IFLS(中断FIFO级别选择)寄存器是这里的控制核心。

  • 接收中断触发点(RXSEL):决定接收FIFO中积累了多少数据后才触发接收中断。选项有1/8, 1/4, 1/2, 3/4, 7/8满。默认是1/2满。
  • 发送中断触发点(TXSEL):决定发送FIFO空到什么程度时触发发送中断(请求更多数据)。选项有7/8, 3/4, 1/2, 1/4, 1/8空。默认是1/2空。

配置策略分析:

  • 低延迟、小数据量场景(如交互式命令):可以将接收触发点设为1/8或1/4。这样一两个字节到达就能立刻触发中断处理,响应迅速。但频繁的中断会增加CPU开销。
  • 高吞吐、大数据块场景(如固件升级、文件传输):应将接收触发点设为1/2或更高,发送触发点设为1/2或更低。这样让FIFO积累更多数据再处理,减少中断次数,提高批量传输效率。配合DMA使用效果更佳。
  • 流控场景:当启用硬件流控(RTS/CTS)时,RTS信号(指示本机接收状态)会在接收FIFO达到“满”阈值(非中断触发阈值)时自动置位(低电平有效,表示“不要发”),在FIFO空出一定空间后自动清除。这个阈值是硬件固定的,与IFLS设置无关。你需要确保发送方能正确响应这个流控信号。

中断服务程序(ISR)编写要点: 进入UART ISR后,第一件事是读取UART:MIS寄存器,确定中断源。常见处理流程如下:

void UART0_IRQHandler(void) { uint32_t mis = HWREG(UART0_BASE + UART_O_MIS); // 读取屏蔽后中断状态 if (mis & UART_MIS_RXMIS) { // 接收中断 // 循环读取UART_DR,直到接收FIFO为空或低于触发水平 while (!(HWREG(UART0_BASE + UART_O_FR) & UART_FR_RXFE)) { uint32_t data = HWREG(UART0_BASE + UART_O_DR); uint8_t rxByte = data & 0xFF; // 提取数据 uint8_t errors = (data >> 8) & 0xF; // 提取错误位(FE, PE, BE, OE) // 处理接收到的字节和错误 processRxByte(rxByte, errors); } // 清除接收中断(可选,读DR也可清除) HWREG(UART0_BASE + UART_O_ICR) = UART_ICR_RXIC; } if (mis & UART_MIS_TXMIS) { // 发送中断 // 检查发送FIFO是否还有空间(TXFF位为0) while (!(HWREG(UART0_BASE + UART_O_FR) & UART_FR_TXFF)) { if (txBufferHasData()) { uint8_t byteToSend = getNextTxByte(); HWREG(UART0_BASE + UART_O_DR) = byteToSend; } else { // 没有更多数据要发送,可以禁用发送中断以避免空循环 HWREG(UART0_BASE + UART_O_IMSC) &= ~UART_IMSC_TXIM; break; } } HWREG(UART0_BASE + UART_O_ICR) = UART_ICR_TXIC; } // 处理错误中断(OEIM, BEIM, PEIM, FEIM) if (mis & (UART_MIS_OEMIS | UART_MIS_BEMIS | UART_MIS_PEMIS | UART_MIS_FEMIS)) { // 读取RSR或DR的高位获取具体错误,并写入ECR清除错误标志 uint32_t rsr = HWREG(UART0_BASE + UART_O_RSR); handleUartErrors(rsr); HWREG(UART0_BASE + UART_O_ECR) = 0xFF; // 写任何值到ECR即可清除错误标志 } }

注意事项:务必在ISR中清除相应的中断标志(通过写UART:ICR寄存器),否则会立即再次触发中断,导致系统锁死。对于接收中断,通过读取UART:DR寄存器将数据从FIFO中取出,当FIFO数据量低于触发水平时,中断标志会自动清除,但显式清除是个好习惯。

3.3 硬件流控制(RTS/CTS)实战配置

硬件流控制是保证高速、大数据量通信不丢包的“保险丝”。CC13x2/CC26x2的UART0支持完整的RTS/CTS流控。

连接方式: 你的设备(DTE,如MCU)的UART0_RTS(输出)应连接到对方设备(DCE,如模组)的CTS(输入)。你的UART0_CTS(输入)应连接到对方的RTS(输出)。注意,RTS和CTS都是低电平有效。

寄存器配置步骤:

  1. 引脚复用:通过IOC模块(IOCFGn寄存器)将对应的GPIO引脚配置为UART0_RTS和UART0_CTS功能。务必在使能UART模块之前完成此配置,否则初始的引脚状态抖动可能会被UART误认为是有效的流控信号。
  2. 使能流控:在UART:CTL寄存器中,设置CTSEN位和RTSEN位为1,同时使能RTS和CTS流控。
  3. 理解自动行为:
    • CTS流控:当你的UART0_CTS输入引脚为低电平时(对方允许你发送),你的发送器才能工作。如果CTS变高,发送器会暂停,直到CTS再次变低。这一切由硬件自动完成,无需软件干预。
    • RTS流控:当你的接收FIFO达到“满”阈值(硬件固定)时,UART0_RTS输出引脚会自动变为低电平(通知对方“我快满了,请暂停发送”)。当FIFO中的数据被读取,空出足够空间后,RTS会自动恢复高电平(“可以继续发送”)。这个阈值与FIFO深度有关,通常是接近满的位置。

调试技巧: 在调试流控时,最容易出现的问题是“通信卡死”。一个常见的错误是只连接了TX/RX,而RTS/CTS引脚悬空或未正确配置。悬空的输入引脚状态不确定,可能导致CTS始终为高(禁止发送)或RTS始终为低(一直请求对方暂停)。我的建议是,在初始化阶段,先用万用表或逻辑分析仪确认这四个引脚的电平状态。如果暂时不需要流控,确保在软件中禁用CTSEN和RTSEN,并将对应的GPIO配置为通用输入(带上拉)以避免干扰。

3.4 DMA配置与高效数据传输

对于需要连续、高速传输数据的应用(如通过串口传输音频采样数据、图像数据块),使用DMA可以解放CPU。CC13x2/CC26x2的UART与μDMA控制器紧密集成。

DMA请求类型:

  • 单次请求(SREQ):当FIFO中有数据(接收)或有空间(发送)时立即触发。适合零散、非连续的数据传输。
  • 突发请求(BREQ):当FIFO中的数据量达到你在UART:IFLS中设置的触发水平时触发。适合批量数据传输,能最大化总线利用率。

配置流程:

  1. 使能UART的DMA功能:设置UART:DMACTL寄存器中的RXDMAE(接收DMA使能)和/或TXDMAE(发送DMA使能)位。
  2. 配置μDMA控制器:这通常通过TI的DriverLib库函数或直接配置DMA控制表来完成。你需要为UART的发送和接收分别设置一个DMA通道。
    • 源地址/目标地址:对于发送DMA,源地址是内存中的数据缓冲区,目标地址是UART:DR寄存器。对于接收DMA,源地址是UART:DR寄存器,目标地址是内存中的接收缓冲区。
    • 传输大小:设置一次DMA传输需要搬运的数据量(字节数)。
    • 仲裁大小:定义每次DMA突发传输的数据量。为了匹配UART FIFO的触发水平,通常将其设置为与FIFO触发水平对应的字节数(例如,接收触发水平为1/2,则仲裁大小可设为16字节)。
    • 请求类型:选择单次请求或突发请求。
  3. 连接DMA完成中断:当DMA完成一次设定的传输总量后,会产生完成中断。你可以在中断中重新填充发送缓冲区或处理接收到的数据块,然后重新启动DMA传输。

一个典型的DMA接收示例: 假设你需要连续接收不定长数据包。一个高效的做法是:设置接收FIFO触发水平为1/2满(16字节),使能接收DMA突发请求。配置DMA通道为“Ping-Pong”模式或使用两个交替的缓冲区。当FIFO中数据达到16字节时,触发DMA突发传输,将16字节数据搬移到缓冲区A。同时,CPU可以处理之前已满的缓冲区B的数据。这样实现了数据搬运和处理的并行,几乎没有数据丢失的风险。

避坑指南:启用DMA时,务必注意DMAONERR位(位于UART:DMACTL寄存器)。如果此位置1,当发生任何UART错误(奇偶、帧错误等)时,DMA请求会被自动禁用。这可以防止错误数据被DMA盲目地搬移到内存。在错误处理ISR中,你需要检查错误状态,清除错误标志,并可能需要重新使能DMA。

4. 从零开始:UART模块初始化与驱动实现

4.1 引脚复用与时钟使能

在操作任何外设之前,时钟和引脚是基础。CC13x2/CC26x2的UART信号需要通过IOC模块映射到具体的GPIO引脚上。

步骤详解:

  1. 使能外设时钟:UART模块位于外设电源域,需要先使能其运行时钟。使用TI的DriverLib库函数最为便捷:

    #include <ti/drivers/pin/PINCC26XX.h> #include <ti/drivers/power/PowerCC26XX.h> #include <driverlib/prcm.h> #include <driverlib/ioc.h> // 1. 使能UART0的外设时钟(运行、睡眠、深度睡眠模式) PRCMPeripheralRunEnable(PRCM_PERIPH_UART0); PRCMPeripheralSleepEnable(PRCM_PERIPH_UART0); PRCMPeripheralDeepSleepEnable(PRCM_PERIPH_UART0); // 加载时钟设置 PRCMLoadSet();

    这一步确保了UART模块在任何功耗模式下都有时钟供给。

  2. 配置GPIO引脚:假设我们使用DIO2作为UART0_TX,DIO3作为UART0_RX。

    // 配置DIO2为UART0 TX功能,输出 IOCPinTypeUart(UART0_BASE, IOID_2, PIN_MODE_7); // PIN_MODE_7 通常是UART TX // 配置DIO3为UART0 RX功能,输入 IOCPinTypeUart(UART0_BASE, IOID_3, PIN_MODE_6); // PIN_MODE_6 通常是UART RX // 如果需要硬件流控,还需配置RTS和CTS引脚 // IOCPinTypeUart(UART0_BASE, IOID_4, PIN_MODE_?); // RTS // IOCPinTypeUart(UART0_BASE, IOID_5, PIN_MODE_?); // CTS

    IOCPinTypeUart函数内部会设置IOCFGn寄存器的IOMODE字段,将引脚功能切换到UART模式,并配置正确的上下拉和驱动强度。务必查阅具体芯片的数据手册,确认每个引脚支持的模式编号。

4.2 寄存器级初始化流程

在时钟和引脚就绪后,我们开始配置UART模块本身。遵循手册推荐的步骤至关重要。

标准初始化序列:

// 假设 PERDMACLK = 24MHz, 目标波特率 = 115200 #define UART0_BASE 0x40001000 #define SYSTEM_CLOCK_FREQ 24000000 #define BAUDRATE 115200 void UART0_Init(void) { // 步骤1: 禁用UART (UARTEN = 0) HWREG(UART0_BASE + UART_O_CTL) &= ~(UART_CTL_UARTEN); // 步骤2: 计算并设置波特率除数BRD // BRD = SysClk / (16 * BaudRate) = 24e6 / (16 * 115200) = 13.02083333 uint32_t brd = (SYSTEM_CLOCK_FREQ * 64) / (BAUDRATE * 16); // 先乘以64,保留小数精度 uint32_t ibrd = brd / 64; // 整数部分 uint32_t fbrd = ((brd % 64) * 64 + 32) / 64; // 小数部分,四舍五入 HWREG(UART0_BASE + UART_O_IBRD) = ibrd; // 写入整数部分 HWREG(UART0_BASE + UART_O_FBRD) = fbrd; // 写入小数部分 // 步骤3: 配置线路控制寄存器 (数据位、停止位、奇偶校验、FIFO) uint32_t lcrh = 0; lcrh |= UART_LCRH_WLEN_8; // 8位数据位 lcrh |= UART_LCRH_FEN; // 使能FIFO // lcrh |= UART_LCRH_STP2; // 2位停止位 (默认1位) // lcrh |= UART_LCRH_PEN; // 使能奇偶校验 // lcrh |= UART_LCRH_EPS; // 偶校验 (与PEN一起使用) HWREG(UART0_BASE + UART_O_LCRH) = lcrh; // 此写入操作同时锁存了步骤2的波特率设置! // 步骤4: 配置中断FIFO触发水平 (可选) HWREG(UART0_BASE + UART_O_IFLS) &= ~(UART_IFLS_RX_MASK | UART_IFLS_TX_MASK); HWREG(UART0_BASE + UART_O_IFLS) |= UART_IFLS_RX1_2 | UART_IFLS_TX1_2; // RX/TX均为1/2 // 步骤5: 使能所需的中断 (可选) // 先清除所有挂起的中断 HWREG(UART0_BASE + UART_O_ICR) = 0x7FF; // 写入1清除所有中断标志 // 使能接收中断和接收超时中断 HWREG(UART0_BASE + UART_O_IMSC) |= UART_IMSC_RXIM | UART_IMSC_RTIM; // 注意:发送中断通常在需要发送数据时再临时使能 // 步骤6: 配置DMA (可选) // HWREG(UART0_BASE + UART_O_DMACTL) |= UART_DMACTL_RXDMAE; // 使能接收DMA // 步骤7: 配置硬件流控制 (可选) // HWREG(UART0_BASE + UART_O_CTL) |= UART_CTL_CTSEN | UART_CTL_RTSEN; // 步骤8: 最后,使能UART模块 HWREG(UART0_BASE + UART_O_CTL) |= UART_CTL_UARTEN | UART_CTL_RXE | UART_CTL_TXE; }

这段代码清晰地展示了从禁用模块、配置波特率、设置帧格式,到最后使能模块的完整流程。步骤3中写入LCRH是激活波特率设置的关键。

4.3 发送与接收的基础操作

初始化完成后,就可以进行数据收发了。

阻塞式发送(轮询): 最简单的方式是查询UART_FR_TXFF标志(发送FIFO满)。这种方式会占用CPU,只适合在初始化或极低频率的调试输出中使用。

void UART0_SendBytePolling(uint8_t data) { // 等待发送FIFO有空间 while (HWREG(UART0_BASE + UART_O_FR) & UART_FR_TXFF) { // 可在此处加入超时机制 } HWREG(UART0_BASE + UART_O_DR) = data; } void UART0_SendStringPolling(const char *str) { while (*str) { UART0_SendBytePolling(*str++); } }

中断驱动发送: 高效的方式是使用中断。通常维护一个发送环形缓冲区。

  1. 用户调用发送函数,将数据填入缓冲区。
  2. 如果发送器空闲(TXFF为0且发送中断未使能),则直接启动第一次发送(写DR),并使能发送中断(UART_IMSC_TXIM)。
  3. 在发送中断服务程序(ISR)中,检查发送FIFO是否还有空间(TXFF为0),如果有,则从环形缓冲区取出下一个字节写入UART:DR。
  4. 当环形缓冲区为空时,在ISR中禁用发送中断,避免无意义的中断。

中断驱动接收: 接收通常完全由中断驱动。在接收ISR中,循环读取UART:DR直到FIFO为空(RXFE为1)。每次读取会得到一个32位值,低8位是数据,高8位中的某些位是错误状态(FE, PE, BE, OE)。必须检查这些错误位,并进行相应处理(如丢弃错误数据、记录错误计数等)。

DMA驱动收发: 配置好DMA后,发送和接收几乎不需要CPU参与。对于发送,你只需要将数据放入DMA源缓冲区,启动DMA传输,然后等待DMA完成中断。对于接收,你设置好DMA目标缓冲区,启动接收DMA,数据就会自动填充缓冲区,并在达到指定传输量或接收超时(如果使能了超时中断)时产生中断通知CPU。

5. 高级应用与调试技巧

5.1 回环测试与自检

在硬件连接前或怀疑硬件有问题时,回环测试(Loopback)是极佳的诊断工具。CC13x2/CC26x2的UART支持内部数字回环。

操作方法:

  1. 在初始化序列的最后一步(使能UARTEN之前),将UART:CTL寄存器的LBE(回环使能)位置1。
  2. 正常使能UART。
  3. 此时,芯片内部将UART_TXD输出直接连接到UART_RXD输入。你发送的任何数据都会被自己接收回来。
  4. 编写测试代码:发送一串已知的数据(如0x00, 0x55, 0xAA, 0xFF等),然后在接收端验证收到的数据是否完全一致。

这个测试可以验证UART模块本身的软硬件配置(波特率、数据格式、FIFO、中断逻辑)是否正确,排除了外部线路和对方设备的影响。

5.2 低功耗模式下的UART操作

CC13x2/CC26x2是低功耗MCU,UART模块在睡眠模式下如何工作是需要考虑的。

  • 睡眠模式:如果UART时钟在睡眠模式下保持使能(通过PRCMPeripheralSleepEnable),并且UART模块本身使能,它可以在接收到数据时产生中断,将CPU从睡眠中唤醒。这常用于由外部设备触发唤醒的场景。
  • 深度睡眠模式:大多数高速时钟在深度睡眠下会被关闭,UART无法工作。如果需要在深度睡眠下维持极低速率的串口监听,可能需要依赖GPIO边沿中断结合软件模拟的“唤醒”机制,唤醒后再初始化UART进行通信。这不是UART模块的标准功能,需要精心设计。

最佳实践:在进入低功耗模式前,确保所有UART数据传输已经完成,并根据需求决定是否保持UART时钟和模块使能。如果不需要在睡眠时接收,最好禁用UART以节省功耗。

5.3 常见问题排查速查表

在实际开发中,UART通信失败是家常便饭。下面这个表格总结了我遇到过的典型问题及排查思路:

现象可能原因排查步骤与解决方案
完全无通信,TX引脚无波形1. UART模块时钟未使能。
2. GPIO引脚未正确复用为UART功能。
3. UART模块未使能(UARTEN=0)。
4. 发送器被禁用(TXE=0)。
1. 检查PRCM相关寄存器,确认UART外设时钟已开启并加载。
2. 用逻辑分析仪或示波器检查TX引脚,确认其已不是高阻态,并有正确的UART输出波形(如果没有,检查IOC配置)。
3. 确认UART:CTL寄存器的UARTEN和TXE位为1。
有波形但数据错误(乱码)1.波特率不匹配(最常见)。
2. 数据格式不匹配(数据位、停止位、奇偶校验)。
3. 双方电平标准不匹配(如3.3V vs 5V)。
1.双查波特率计算:确认系统时钟频率、BRD整数和小数部分计算无误,且写入顺序正确(IBRD->FBRD->LCRH)。用逻辑分析仪测量实际位宽,反推波特率。
2. 核对双方LCRH设置(WLEN, STP2, PEN, EPS)。
3. 检查硬件电平转换电路。
通信不稳定,偶尔丢数据1. 未使用流控,且接收端处理速度跟不上发送端。
2. 中断服务程序处理时间过长,导致FIFO溢出。
3. 系统中断被长时间关闭。
4. 电源噪声或地线问题。
1. 考虑启用硬件RTS/CTS流控。
2. 优化ISR:只做最必要的操作(如将数据移入缓冲区),将处理任务交给主循环。增大接收FIFO触发水平,减少中断频率。
3. 检查代码中是否有长时间关中断的操作。
4. 检查PCB布局,确保UART线路远离噪声源,并做好滤波。
只能发送,不能接收1. RX引脚配置错误(应为输入)。
2. 接收器被禁用(RXE=0)。
3. 接收中断未使能,且采用轮询方式时未检查RXFE标志。
4. 对方设备TX未正确连接或损坏。
1. 确认RX引脚的IOC配置为UART输入模式。
2. 确认UART:CTL的RXE位为1。
3. 如果使用中断,检查UART:IMSC的RXIM位;如果轮询,检查UART:FR的RXFE位。
4. 交换TX/RX线进行交叉测试。
使能DMA后数据混乱1. DMA源/目标地址或传输大小配置错误。
2. DMA和CPU同时访问同一缓冲区,未做同步。
3.DMAONERR导致错误后DMA被禁用。
1. 仔细检查DMA控制表的配置,特别是地址递增模式和数据大小。
2. 使用双缓冲区或标志位进行CPU和DMA的同步。
3. 在UART错误中断中检查并重新使能DMA。
硬件流控无效1. RTS/CTS引脚未正确配置或连接。
2.CTSEN/RTSEN位未使能。
3. 对方设备不支持或不响应流控。
1. 用示波器同时测量TX和CTS信号。当CTS为高时,TX应暂停发送。
2. 测量RTS信号,当本机FIFO快满时,RTS应变低。
3. 确认对方设备手册,了解其流控行为。

5.4 性能优化与资源权衡

在资源受限的嵌入式系统中,需要在性能、功耗和代码复杂度之间取得平衡。

  • 中断 vs 轮询:对于低速、间歇性通信(如配置命令),轮询足够简单高效。对于连续数据流,中断是必须的。但过于频繁的中断(如FIFO触发水平设得太低)会成为系统负担。
  • 中断 vs DMA:如果数据包较大(例如大于32字节)或传输非常频繁,DMA的优势巨大。它几乎零CPU开销,且能保证确定的延迟。缺点是设置稍复杂,且会占用DMA通道资源。
  • FIFO深度利用:32字节的FIFO是宝贵资源。对于发送,可以在启动传输前,尽可能多地将数据写入FIFO(直到TXFF置位),以减少中断次数。对于接收,设置合理的触发水平,让一次中断能处理更多数据。
  • 功耗考虑:如果通信是间歇性的,可以在空闲时关闭UART模块和时钟以省电。需要通信时再重新初始化。TI的驱动库通常提供了相应的低功耗接口。

最后,再分享一个调试“笨”办法但极其有效:使用一个USB转UART调试器连接到你的MCU。用PC端的串口助手(如Putty、Tera Term)发送数据,同时用逻辑分析仪抓取MCU的TX/RX引脚波形。对比PC发送的数据、逻辑分析仪捕获的波形、以及MCU程序实际接收到的数据,任何不一致都能帮你迅速定位问题是在软件配置、硬件连接还是时序方面。嵌入式开发,很多时候就是一场与细节的较量,而UART正是这场较量中最基础的战场之一。把它摸透了,其他更复杂的通信协议也就有了扎实的根基。

相关新闻

  • 如何利用OrionCMS构建响应式管理后台:Bootstrap与Materialize主题全攻略
  • LangChain框架:快速构建大语言模型应用
  • 本人不能到场出售夫妻共同房产,委托公证书当天能出吗? - 跑政通

最新新闻

  • 华硕笔记本硬件控制指南:GHelper开源工具深度解析
  • Django毕设选题推荐:基于 Django 的数字化教学在线考核测评系统开发与实践 面向高校的多功能在线考试服务平台【附源码、mysql、文档、调试+代码讲解+全bao等】
  • 【2026 许昌奢侈品回收选购指南】劳力士、欧米茄、LV闲置变现避坑与门店参考 - 你就像风一样
  • 高效健康160自动挂号脚本:医疗预约难题的技术解决方案
  • DankDroneDownloader:大疆无人机固件自由下载的终极指南
  • 5分钟掌握Obfuscapk:彻底告别Android应用反编译风险的专业级混淆方案

日新闻

  • 大连理工大学与东京大学联手打造的“主动型AI助手“
  • 170.2026年国家级科研瓶颈:超精密单点金刚石切削(SPDT)光学表面生成
  • SongBloom:革命性歌曲生成框架深度解析——如何通过交织自回归与扩散模型创作完整音乐

周新闻

  • 大连理工大学与东京大学联手打造的“主动型AI助手“
  • 170.2026年国家级科研瓶颈:超精密单点金刚石切削(SPDT)光学表面生成
  • SongBloom:革命性歌曲生成框架深度解析——如何通过交织自回归与扩散模型创作完整音乐

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号