嵌入式 UART 协议面试题及参考答案
UART 是什么?它的英文全称是什么?
UART 即通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),是一种广泛应用于嵌入式系统的串行通信接口。它为不同设备之间的数据传输提供了一种简单且高效的方式,在微控制器、计算机主板以及各种电子设备中都能看到其身影。
从功能角度来看,UART 主要负责处理串行数据的发送和接收。在发送数据时,它会将并行数据转换为串行数据,逐位通过传输线发送出去;而在接收数据时,则把接收到的串行数据重新转换为并行数据,供设备内部使用。这种并行 - 串行和串行 - 并行的转换功能,使得 UART 能够适配不同设备之间的数据传输需求。
在硬件层面,UART 通常以芯片或集成电路的形式存在,集成在微控制器或其他设备中。它一般具有两根数据线,即发送线(TX)和接收线(RX),通过这两根线就可以实现全双工通信,意味着设备可以同时进行数据的发送和接收。
UART 的应用场景十分广泛。在工业控制领域,它可以用于连接传感器、执行器等设备,实现数据的采集和控制指令的传输;在通信设备中,如调制解调器、蓝牙模块等,UART 也发挥着重要作用,负责与其他设备进行数据交互。此外,在消费电子领域如智能手表、智能家居网关等设备中,UART 也常用于调试日志输出或与主控芯片进行底层配置交互。
UART 核心通信参数
在实际开发中,理解以下参数至关重要:
- 波特率(Baud Rate):表示每秒传输的符号数。对于 UART,通常波特率等于比特率。常见的波特率有 9600, 115200 等。通信双方必须设置相同的波特率。
- 数据位(Data Bits):通常为 8 位,也可设置为 7 位。
- 停止位(Stop Bits):表示一个数据包结束的标志,可以是 1 位、1.5 位或 2 位。
- 校验位(Parity Bit):用于错误检测,可选无校验(None)、奇校验(Odd)、偶校验(Even)。
常见面试题与参考答案
Q1: UART 通信需要几根线?如何连接?
答: 最基本的 UART 通信只需要两根信号线:TX(发送)和 RX(接收)。连接时需要交叉连接,即设备的 TX 接对方的 RX,设备的 RX 接对方的 TX。如果涉及流控制,可能还需要 RTS 和 CTS 线,但在大多数简单应用中仅使用 TX/RX。
Q2: 什么是波特率?为什么通信双方波特率必须一致?
答: 波特率是指每秒钟传输的二进制位数。UART 是异步通信,没有时钟信号同步,因此接收方必须依靠预设的波特率来采样发送方的数据位。如果波特率不一致,采样点会偏移,导致数据解析错误。
Q3: UART 支持流控制吗?如何实现?
答: 支持。硬件流控制通常使用 RTS(请求发送)和 CTS(清除发送)引脚。当接收缓冲区即将溢出时,接收方拉低 CTS 信号通知发送方暂停发送。软件流控制则使用 XON/XOFF 字符序列。
Q4: 轮询方式与中断方式读取 UART 数据有什么区别?
答:
- 轮询方式:CPU 不断检查状态寄存器是否有新数据。优点是逻辑简单,缺点是占用 CPU 资源,效率低,无法实时响应突发数据。
- 中断方式:当接收到完整数据或发送缓冲空时触发中断。优点是 CPU 效率高,可实时响应,适合高负载场景。缺点是需要处理中断服务程序,代码复杂度稍高。
Q5: 如何在 C 语言中初始化 UART?
答: 通常需要配置 GPIO 复用功能为 UART 模式,设置波特率发生器分频系数,配置数据位、停止位和校验位,最后使能 UART 外设。以下是一个基于 STM32 的示例框架:
void UART_Init(void) {
// 1. 开启 GPIO 和 USART 时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = ;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_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);
USART_Cmd(USART1, ENABLE);
}

