嵌入式面试:一个字节从 UART 发出去,中间经过了哪些环节
- 时间
- 2026-10
- 来源
- 牛客网
《面试题目》
- 做过 UART 吗?
- 从发一个字节到线上电平变化,中间经过了哪些环节?
- 工程能配起来,但复位后到 main 之间发生了什么,能说清吗?
- 用过队列和信号量,阻塞、唤醒和超时怎么选?
- 写过 UART、SPI、I2C,时序、错误处理和 DMA 是怎么处理的?
- 项目里写了「实时」,最坏路径和优先级是怎么设计的?
- Demo 能跑,需求一改,你从内存、时序还是并发入手排查?
《参考解析》
一个字节的完整路径
按数据流讲,分五段:应用层调用 write/HAL_UART_Transmit,把数据和长度交给驱动;驱动把字节写进发送缓冲(裸机常见一个环形队列,RTOS 下可能是一个消息队列或流缓冲),然后判断发送寄存器是否空闲;硬件侧 CPU 把字节写进 UART 的数据寄存器(DR/TDR),这一写入会进入发送 FIFO;控制器按配置的波特率对总线时钟分频,产生移位节拍,把字节按「起始位 + 数据位(低位先发)+ 可选校验位 + 停止位」串行移出到 TX 引脚,电平随之变化;最后一个停止位发完后置位发送完成标志(TC),如果开了发送寄存器空中断(TXE)就会继续取下一个字节,队列空了就关中断。
面试官追问时通常往三个方向走:为什么不能连续写 DR(发送寄存器只有一个,上一字节没移出就覆盖会丢数据,所以要看 TXE/TC 标志或用 FIFO 深度);波特率怎么算(baud = f_pclk / (16 × USARTDIV) 之类,分频值有小数部分,误差超过约 2%~3% 就会误码);出错怎么处理(帧错误、噪声、溢出 ORE——ORE 的典型成因是中断里没及时读数据,处理方式是读 SR 再读 DR 清标志,必要时丢弃整帧)。能答到「ORE 是因为软件没跟上」这一层,基本就把「用过」和「讲得清」分开了。
中断、DMA 和任务并发
单字节靠中断、连续大块数据靠 DMA,这是常见取舍:中断每次都要进上下文,字节率高时 CPU 全耗在进出中断上;DMA 让控制器自己搬,CPU 只在半传输/传输完成中断里处理,代价是要处理缓冲复用——DMA 正在写的缓冲区不能同时被应用读,常见做法是双缓冲或半满/全满两个中断。临界区的边界要能说清:环形队列的头尾指针在多任务下要么加锁、要么单生产者单消费者配合原子操作;中断上下文不能阻塞,所以不能在中断里等信号量、不能 malloc。
内存与指针
volatile 用在会被硬件或中断改变的变量上(寄存器映射、中断里置位的标志),它只保证每次都从内存读,不保证原子性;结构体对齐影响的不只是内存占用,还影响协议解析——用 #pragma pack 或按字段手工拼包,否则对端按字节偏移解析会错位;局部数组不能返回,函数返回后栈帧失效;指针的生命周期和它指向的存储区(栈、静态区、堆)要分开讲。
启动、链接和故障定位
复位后的顺序是:从向量表取初始 MSP 和 Reset_Handler 地址 → 关中断、初始化时钟 → 把 .data 从 Flash 的加载地址拷到 RAM 的运行地址 → 把 .bss 清零 → 调 SystemInit、__libc_init_array(C++ 全局构造)→ main。HardFault 的定位套路:先看 LR 判断是从线程还是中断里挂的,再取栈帧里的 PC 找到出错指令,结合 CFSR/HFSR 判断是非法访问、非对齐还是除零。这类问题的准备方式不是背流程,而是在自己板子上真跑一遍、把栈帧打印出来看过。
按追问链准备,而不是从头背教材
这套面试的真正考点是「解释取舍」。每个知识点按五个问题过一遍:这个机制解决什么问题、不用它会怎样、用错了会出现什么现象、出了 bug 从哪里查、项目里哪段代码能对应上。比如信号量,除了「PV 操作」还要能说:为什么用信号量而不是全局标志(唤醒机制与优先级继承)、超时设为 0 和设为 portMAX_DELAY 分别是什么语义、在中断里该用哪个 API。能顺着这条链讲到项目代码,才算接得住追问。