☰
串行通信三剑客:UART/I2C/SPI面试考点与实战避坑全汇总
2026/10/18 1:03:56 网站建设 项目流程

串行三剑客:UART / I2C / SPI 面试高频考点全汇总

UART、I2C、SPI这三兄弟,几乎是嵌入式面试里绕不开的固定环节。不管你是面MCU开发、驱动工程师,还是 linux 底层方向,面试官大概率都会从这三个串行协议里挑一个往深里问。我这些年面试别人、也被别人面试,一个很深的感受是:能背出“UART异步、I2C半双工、SPI全双工”的人很多,但能把握手时序画出来、能把波特率误差算出来、能把 I2C 总线死锁恢复步骤讲清楚的人,寥寥无几。

这篇不是教科书复读,也不是把数据手册翻译一遍。我会结合真实面试场景,把三个协议的高频考点、容易翻车的细节、还有面试官追问背后真正想考察的东西,一条一条拆开讲。无论你是准备校招、跳槽,还是单纯想把这些底层通信协议吃透,这篇文章都值得收藏下来慢慢看。

1. 串行三剑客:先搞懂它们各自活在不同世界的底层逻辑

1.1 同步/异步、全双工/半双工:面试第一个分水岭

面试官问“你讲讲 UART / I2C / SPI 的区别”,如果只是列引脚、列速率,那只能算及格分。真正拉开差距的,是从底层的同步/异步、双工方式、时钟由谁提供这几个维度去展开。

我习惯用一张表把这几个核心差异讲透:

特性UARTI2CSPI
同步/异步异步同步同步
双工方式全双工半双工全双工
时钟来源双方各自约定主机产生SCL主机产生SCLK
引脚数TX + RX(+ 地)SDA + SCLMOSI + MISO + SCLK + CS/SS
数据帧起始位 + 数据位 + 校验位 + 停止位地址 + 数据,以字节为单位无固定帧格式,按位收发
速率量级通常 9600 ~ 1Mbps100k / 400k / 1M / 3.4M bps从几百k到几十MHz
可挂设备数点对点多设备(7位地址最多127个)一主多从,每个从机一条CS线
有无应答无有ACK/NACK无应答机制

这里要特别强调一个容易混淆的概念:UART 虽然叫“异步”,但双方必须对波特率达成一致,它只是不传时钟信号,并不代表不需要时序约束。而 I2C 和 SPI 都有专用时钟线,从机跟着主机时钟走,所以速率可以做得更高、更灵活。

1.2 为什么面试官总爱让你“说人话解释”这三个协议

我面试过不少候选人,简历上写着“精通 UART/I2C/SPI”,可一问“I2C 为什么需要上拉电阻?”就开始支支吾吾,或者是“因为开漏”就没了。其实面试官要的不只是名词,而是你能不能把一个复杂机制说得让外行也听懂。

我自己常用的三个类比:

  • UART 像两个对讲机:两个人都知道“说完一句要等一下”,各自按自己那块手表的节奏说话,不需要额外同步线。但前提是两块表必须走得一样快,这就是波特率。
  • I2C 像一条公交线路:所有设备挂在同一根线上,每个站点(设备)有唯一门牌号(地址),公交车(主机)喊站名,被喊到的站点才响应。同一时间只能有一个说话的人,否则就撞车(仲裁)。
  • SPI 像老板给每个下属单独拉一根专线:老板(主机)想联系哪个下属,就单独拉一下那根呼叫线(CS),然后用统一的节拍器(SCLK)带着对方收发数据,速度快、实时性好,但线多。

能够用这种类比去做通俗解释,同时又能马上切回专业术语描述时序细节,这是面试里非常加分的表达方式。

1.3 面试开场的三个定制问题(自检清单)

很多公司面试官习惯用“你最近做的项目里用到了哪些通信接口”作为开场。与其被动等问,不如主动带着结论去讲。这里我整理三个高频的“开场式追问”,建议你在准备面试时对着自测:

  1. “你项目里为什么用 I2C 而不用 SPI?”——考察选型能力,不是考记忆。
  2. “这个设备用 UART 通信,波特率你设多少?为什么?”——考察计算能力和工程经验。
  3. “如果 SPI 的时钟频率提不上去,你会从哪里排查?”——考察真实调试能力。

这三个问题没有标准答案,但都有最优回答路径。后续章节我会把对应的底层计算和排查方法详细展开。

2. 逐剑拆招:UART 的高频考点与实战坑位

2.1 帧格式与波特率误差计算:不能只背公式,要会手算

UART 一帧数据的结构是:空闲时保持高电平,一帧开头拉低 1 位作为起始位,然后是 5~8 位数据位(通常 8 位),可选校验位,最后是 1~2 位停止位(停止位必须是高电平)。所以最常用的 8N1 格式,完整一帧是 10 bit(起始 1 + 数据 8 + 停止 1)。

面试里最常见的一个考法是:给你一个晶振频率(比如 12 MHz)和期望波特率(比如 9600),让你选波特率寄存器分频值,并计算误差。

参考类似常见 MCU 的 UART 分频公式:分频值 BRR = f_CLK / (16 × 波特率) - 1,然后取整。

以 12 MHz 晶振、目标 9600 为例:

  • 理论分频值 = 12000000 / (16 × 9600) - 1 = 77.125
  • 取整数分频值 77,则实际波特率 = 12000000 / (16 × (77 + 1)) = 9615.38 bps
  • 误差 = (9615.38 - 9600) / 9600 ≈ 0.16%

1552 这个误差完全没问题。但如果你的分频值是 78,那么实际波特率 = 12000000 / (16 × 79) = 9493.67 bps,误差 ≈ -1.11%,在要求不高的场合勉强能用,但接某些苛刻模块时可能就乱码了。

然后把晶振换成 11.0592 MHz:分频值 = 11059200 / (16 × 9600) - 1 = 71.0,整数,实际波特率恰好 9600,误差为 0。这就是工业级应用中为什么大量使用 11.0592 MHz 晶振的底层原因。面试能把这个“为什么”讲清楚,就能甩开一大半背概念的人。

注意:串口通信允许的波特率误差通常是 ±2%~±3%(取决于对端采样时刻和位宽),但这只是“上限”,实际工程里要留余量。尤其多设备互连、环境温度变化时,晶振漂移会导致误差进一步扩大。

2.2 校验位、DMA 与中断处理的时机选择

UART 的校验位有奇校验、偶校验、无校验三种。面试官经常问“校验位能不能发现所有错误?”答案是不能。奇偶校验只能检测奇数个 bit 翻转,如果数据里有两位同时翻转,校验结果仍然正确,错误就漏掉了。如果项目要求高可靠性,必须叠加 CRC 校验或数据帧重传机制,这是我在做传感器采集通信时被现实教育过的。

还有个高频追问是“你什么时候用中断接收,什么时候用 DMA?”这里我的经验是:

  • 数据量小、接收不定长,用“空闲中断 + 字节中断”或按帧解析,处理逻辑简单。
  • 数据量大(比如一次几百字节)、波特率高(比如 921600),必须用 DMA,否则高频中断会挤占 CPU 时间。
  • 用 DMA 时不要忽略环形缓冲区的设计,否则 DMA 覆盖旧数据时你会排查一整天。

2.3 UART 面试追问:乱码排查的标准路径

面试官很喜欢给这样一个场景:“嵌入式设备通过 UART 连调试口,收到的是乱码,你怎么定位?”标准回答路径应该是由层到点的排查思路:

  1. 先查波特率。这是乱码最常见的原因,确认双方是否都是 9600 或 115200,最好用示波器抓一下 TX 脚波形,量一下位宽是否匹配波特率。
  2. 查电平标准。UART 有 TTL 电平(0~3.3V/5V)和 RS232 电平(-12V~+12V),如果 TTL 设备接 RS232 口,绝无可能正常通信。没有转换芯片,波形都对不上。
  3. 查 RX/TX 是否交叉接反。两个设备的 TX 要接对方的 RX,不少新手直接 TX 接 TX,结果当然收不到数据。
  4. 查共地。串口通信是单端信号,两边必须共地,否则电压基准不同,数据会乱码,还可能烧器件。
  5. 查干扰。如果线长、波特率高,要考虑线材屏蔽、降低波特率或加隔离芯片。

这条路径本身就是面试官想看到的“结构化思维”。你可以现场用示波器波形图结合排查顺序去答,会显得非常有实战经验。

3. I2C:总线仲裁、开漏与死锁恢复是真正的试金石

3.1 开漏结构与上拉电阻怎么选?从波形角度理解

I2C 的 SDA 和 SCL 都是开漏输出,意味着引脚只能主动拉低,不能主动输出高电平。高电平全靠外部上拉电阻提供。这设计的好处是:多个设备可以“线与”在总线上,谁拉低谁就输出了低电平;高电平时谁都不驱动,总线自然为高。

关于上拉电阻的取值,面试官要么问定性,要么让你定量。我在实践中用的是这两个边界公式:

最小上拉电阻取决于低电平输出能力和总线电压:

  • Rp_min = (VCC - Vol_max) / Iol,其中 Vol_max 通常 0.4V,Iol 规范值标准模式 3mA、快速模式 20mA。

最大上拉电阻取决于总线电容和允许的上升时间:

  • Rp_max = tr / (0.8473 × Cb),其中 tr 为标准模式 1000ns、快速模式 300ns(以常见规格举例)。

举个例子:快速模式总线电容 200pF,则 Rp_max = 300ns / (0.8473 × 200pF) ≈ 1.77kΩ。如果实际选了个 10kΩ 的电阻,上升沿会超过时序要求,高频通信时很可能出现数据判读错误。总线长度每增加一点,电容就大一点,这也是为什么长线 I2C 必须降速、换更小的上拉电阻。

实操提醒:不要只凭“I2C 一般用 4.7kΩ”这句话行走江湖。3.3V 短距离用 4.7kΩ 通常没问题,但 400k 快速模式、多个从机、线长超过 20cm 时,最好按公式算一遍,再用示波器检查上升沿。

3.2 时钟同步与仲裁:两个主机同时抢总线怎么办

多主机模式是 I2C 面试的重灾区。很多人的理解只停留在“多主机就是多个主机轮流用总线”,但面试官想要的答案是仲裁机制和时钟同步的位级原理。

时钟同步:多个主机同时发起传输时,SCL 低电平时间由“拉低持续时间最长”的主机决定,高电平时间由“先释放高电平”的主机决定。也就是说,所有主机在 SCL 低电平时都要同步自己的时钟,谁最后释放,谁决定高电平起始时刻。这样多个主机虽然在跑各自的时钟,但最后 SCL 波形是统一的。

数据仲裁:在 SDA 上,如果在主机发送一位数据的时刻,它往总线上写高电平,但读到的却是低电平,说明还有另一个主机也在发送且它发了低电平,此时当前主机立刻退出竞争(“线与”导致先低者胜)。这就是为什么 I2C 仲裁遵循“低电平优先”的原则,一开始比较的是地址字节,从机地址小的主机通常赢得仲裁。

面试中如果能顺手画出“两个主机同时发 START 时 SCL/SDA 的波形交汇图”,直接就是满分回答。

3.3 总线死锁与恢复:9 个时钟脉冲为什么有效

I2C 最常见的现场故障是:SDA 一直被拉低,总线卡死,程序里 i2c 写操作超时。原因是某个从机处于错误状态,正在等待一个完整的字节传输,而没有时钟它无法完成状态转移。

标准恢复流程是:

  1. 主机主动翻转 9 个 SCL 时钟脉冲(CLK 信号给从机)。
  2. 在第 9 个脉冲的 ACK 位时刻释放 SDA。
  3. 然后主机发送 STOP 信号。

为什么是 9 个?因为 I2C 数据传输以字节为单位,每个字节 8 位后紧跟一位 ACK/NACK,一共 9 个时钟。从机在接收完 8 位后,会在第 9 个时钟上释放 SDA,让主机发送 ACK/NACK。如果从机因为某种原因卡死,漏掉了 1 个或者几个位,9 个时钟能让它从当前位流位置走到字节边界,从而恢复状态机。

需要注意的是:只能用做“尝试恢复”,不能保证 100% 成功。我在实际调试时还见过总线卡死是因为主机代码本身错误(比如中断里重复调用了 I2C 启动,产生了错误的起始/停止信号),这种情况恢复脉冲也只是暂时解套,根因还是要回到代码上排查。

3.4 I2C 面试追问:7 位地址 vs 10 位地址 vs 无地址设备

大部分简单传感器(如温度传感器、EEPROM)用 7 位地址,一个总线上理论上可挂 112 个不同地址的设备(保留地址除外)。10 位地址是扩展寻址能力用的,实际项目用得不多,但面试你可能只需要知道它的起始条件后面紧跟头字节的高 5 位为 11110 即可。

更常见的追问是:如果总线上有两个设备地址相同怎么办?标准做法是用 I2C 多路复用器(如 TCA9548A 之类的开关芯片),给每组设备单独分一条子总线,物理隔离后就可以解决地址冲突。我在一个项目里就曾接了 8 个相同地址的传感器,最终就是靠 8 路 I2C 开关解决的。

4. SPI:四个模式、片选管理和高速传输的暗坑

4.1 CPOL/CPHA 四模式不是背的,是推出来的

SPI 的四种模式是面试必考,很多教程让你死记:模式 0:CPOL=0, CPHA=0;模式 1:CPOL=0, CPHA=1……背了基本就忘,而且面试现场容易慌。更靠谱的办法是理解两个参数的本质:

  • CPOL(Clock Polarity):空闲时 SCLK 是高电平(CPOL=1)还是低电平(CPOL=0)。
  • CPHA(Clock Phase):数据在第一个边沿采样(CPHA=0)还是在第二个边沿采样(CPHA=1)。

以最常用的模式 0 为例:空闲 SCLK 为低,主机在 SCLK 下降沿改变数据、在上升沿采样数据。从机跟在同一个时钟下,它在上升沿时从 MOSI 上抓数据。只要你对齐了“数据何时建立,何时采样”,四个模式自然就推出来了。

模式CPOLCPHA空闲电平数据输出边沿(主机侧)数据采样边沿(从机侧)
000低下降沿上升沿
101低上升沿下降沿
210高下降沿上升沿
311高上升沿下降沿

注意这张表在实际实现时因不同芯片会有“按寄存器移位寄存器的边沿差一个”的小问题,但面试答这个逻辑顺一遍,比背表格强得多。

面试官接着会问:“主从机的模式必须完全一致,如果 CS 拉低后才发现 SCLK 空闲电平不对,会发生什么?”答案是:第一个位可能直接采错,整个字节错位,而且这种错误很难通过示波器一眼看出,因为波形看起来“差不多”。

4.2 典型 SPI 面试追问:为什么 SPI 没有应答机制

SPI 没有 ACK、没有地址总线,一次传输由 CS 选通决定发送给谁。这个设计让 SPI 协议简单、吞吐高,但也带来了两个经典面试题:

  • “SPI 从机收到一个错误数据怎么办?”从机没有能力自发报告错误,要么靠主机回读校验,要么靠额外的 GPIO 中断线(比如从机拉一个 INT 脚通知主机)做带外反馈。
  • “为什么 SPI 从机比较多的时候要小心?”每个从机占一条 CS 线,主机引脚不够时可以用 GPIO 扩展器,但 CS 信号频繁切换会引入时序抖动;从机太多也会拉高总线负载,影响信号质量。

我常用的扩展方式是“菊花链”(Daisy Chain),即把多个从机的数据线串起来形成链式移位,这样只用一个 CS。但菊花链在面试里属于加分项,需要记住它的核心约束:每个从机必须支持“无论 CS 是否选中,都级联转发数据”的模式,总延时等于所有从机移位延时的叠加。

4.3 高速 SPI 的实操心法:布线、串阻、信号完整性

SPI 跑到 10MHz 以上就不能再“随便飞线”了。几个实实在在的坑:

  • 上拉/下拉电阻配合 CS 空闲电平:CS 在空闲时必须被拉到确定电平(由 CPOL 决定空闲电平),否则浮空输入会导致从机误触发。
  • 串联匹配电阻:在 MOSI、SCLK 线上串 22~33Ω 电阻可以降低振铃,代价是上升沿变缓。这个值需要示波器实测调整。
  • 走线等长与回路面积:高速 SPI 的 SCLK 和数据线尽量等长并靠近地平面,减少环路面积。工业现场还有“包地”处理的做法。
  • CS 提前拉低时序:主机必须在发出第一个 SCLK 边沿之前就把 CS 拉低至少几个 ns,给从机命令解析留时间。很多国产从机芯片有“CS setup time”要求,忽略它会导致首字节丢位。

5. 开放题进阶:把三剑客放进真实系统里比较

5.1 场景选型:什么设备用 I2C、SPI 还是 UART?

面试官很喜欢拿一个具体场景问你“这个传感器你会选哪个接口”,这是综合考察协议特性的经典套路。我用下面这张表概括了我在真实项目里的选型经验:

典型设备推荐接口理由
温湿度传感器(低速率、小数据量)I2C引脚少、多设备共线、休眠功耗低
陀螺仪/加速度计(高速采样)SPI/ I2C高速模式用 SPI(如 10kHz 输出率),普通模式 I2C 够用
EEPROM / Flash 存储I2C/SPI容量小而频繁读写用 I2C;大量连续读写、高速用 SPI
LCD 显示屏(刷新率高)SPI需要快速刷大量像素数据,引脚也足够
SD 卡SDIO/SPI低速调试用 SPI,量产设备用 SDIO 提升吞吐
GPS/蓝牙模块(数据流/AT 命令)UART天然是字符流协议,AT 命令交互简单

选型逻辑不外乎三点:数据量、速率要求、引脚资源,再叠加上“是否需要多设备共用总线、是否需要低成本隔离、是否有时钟同步要求”。只要在回答里把这四点都覆盖到,就已经是很好的答案了。

5.2 总线拓扑:I2C 多设备地址规划与 SPI 片选分配

I2C 多设备规划的核心是地址表:先查每个芯片可配置的地址引脚(A0/A1/A2),用硬件拨码或焊接方式错开;如果地址实在冲突,才用 I2C 开关。另外要注意总线上从上电到复位完成期间,某些从机可能响应默认地址,主机上电扫描时要做延时保护。

SPI 多设备规划的核心则是片选分配:优先把相同工作频率的设备挂在同一组 SCLK/MOSI 上;不同速率的设备尽量分开,否则 SPI 总线频率只能按最慢设备来定。如果确实混挂,用独立的 SPI 外设或者软件跟随模式来切换时钟速率,每次 CS 切换时要重新初始化波特率分频器。

6. 手写软件模拟协议:面试“show code”的关键套路

6.1 软件模拟 I2C:start/stop/ack 的时序模板

有些面试让现场手写软件模拟 I2C。核心不是代码多漂亮,而是你是否清楚每一位的时序约束。我提供一个经过大量项目验证的模板思路:

// 定义 IO 操作 #define SCL_H() gpio_write(SCL_PORT, SCL_PIN, 1) #define SCL_L() gpio_write(SCL_PORT, SCL_PIN, 0) #define SDA_H() gpio_write(SDA_PORT, SDA_PIN, 1) #define SDA_L() gpio_write(SDA_PORT, SDA_PIN, 0) #define SDA_IN() gpio_set_mode(SDA_PORT, SDA_PIN, GPIO_MODE_INPUT) #define SDA_OUT() gpio_set_mode(SDA_PORT, SDA_PIN, GPIO_MODE_OUTPUT) #define READ_SDA() gpio_read(SDA_PORT, SDA_PIN) // 起始条件:SCL 高电平期间,SDA 由高变低 void i2c_start(void) { SDA_OUT(); SDA_H(); SCL_H(); delay_us(5); // tSU;STA: 建立时间 >= 4.7us SDA_L(); delay_us(4); // tHD;STA: 保持时间 >= 4.0us SCL_L(); } // 停止条件:SCL 高电平期间,SDA 由低变高 void i2c_stop(void) { SDA_OUT(); SDA_L(); SCL_H(); delay_us(5); SDA_H(); delay_us(4); SCL_L(); } // 等待从机 ACK:主机释放 SDA,从机拉低表示 ACK uint8_t i2c_wait_ack(void) { SDA_IN(); SCL_H(); delay_us(5); uint8_t ack = (READ_SDA() == 0); SCL_L(); delay_us(4); SDA_OUT(); return ack; }

注意这几个细节:SDA 只有在 SCL 为低电平时才可以改变,否则会产生错误的起始/停止条件;延时参数参考标准模式下的 4.7µs/4.0µs,快速模式可以缩到 0.6µs/0.6µs,但如果从机不强求速度,保守一点无妨。此外,每一帧发送时,发送 8 位数据后要释放 SDA 再等 ACK,这个“释放”很容易被忽略,一旦漏写,从机永远不会应答。

6.2 软件模拟 SPI:为什么比 I2C 简单这么多

SPI 模拟的核心是移位寄存器换向。模式 0 下,主机在 SCLK 下降沿输出数据,在上升沿采样 MISO,写入一个字节的逻辑如下:

uint8_t sw_spi_transfer_byte(uint8_t dat) { uint8_t recv = 0; for (uint8_t i = 0; i < 8; i++) { // 先设 MOSI 电平 if (dat & 0x80) MOSI_H(); else MOSI_L(); dat <<= 1; // SCLK 上升沿,从机采样 MOSI,同时主机采样 MISO SCLK_H(); recv <<= 1; if (READ_MISO()) recv |= 0x01; // SCLK 下降沿,主机和从机都改变数据输出 SCLK_L(); } return recv; }

代码本身不难,但要记得 CS 管理和时钟边沿方向。面试时能把这段代码画个时序图配套讲解,就已经把 SPI 的最高频考点覆盖了大半。

7. 面试官爱问的 20 个追问与参考答案速查

整理了一批高频追问,你可以直接拿来当模拟题练:

  1. 为什么 UART 的停止位必须为高?——为了区分空闲和结束,高电平是空闲电平。
  2. UART 能不能一发多收?——标准 UART 是点对点,广播式监听只有单发一小部分应用上用,物理层没做多地址寻址。
  3. 波特率 115200 下,1 秒传多少字节?——约 11520 字节(按 8N1 每帧 10bit)。
  4. 为什么 I2C 要开漏?——实现线与、多设备总线共连、避免总线冲突烧毁。
  5. I2C 上拉电阻选大了会怎样?——上升沿变缓、时序超标、可能误码。
  6. 上拉电阻选小了呢?——低电平灌电流过大,可能触发过流保护或损坏引脚;但上升沿变快。
  7. I2C 为什么从机不能主动发数据?——从机必须等主机分配总线,除非用主机主动读的方式。
  8. SCL 上为什么会自动产生时钟?——因为从机需要时钟驱动的字节边界,不能自行完成状态转换。
  9. SPI 的 MISO 能不能复用一根线?——硬件上可以,但必须有 CS 隔离,否则多个从机同时驱动 MISO 必打架。
  10. SPI 从机最高频率由谁决定?——由从机内部移位寄存器和输入建立/保持时间决定,主机只能适配。
  11. CS 信号在 SPI 模式 0 中空闲是高还是低?——依从机而定,多数是低有效,即空闲为高。
  12. 全双工 SPI 中同时收发,MISO 数据什么时候有效?——在 SCLK 的采样边沿有效,必须与主机时钟匹配。
  13. I2C 的地址位是 7 位,为什么能挂很多外设?——因为保留地址之外还有广播地址和软件可配置地址引脚。
  14. I2C 仲裁失败后,主机会重发吗?——不会自动重发,软件要检测仲裁失败标志并重试。
  15. UART 用 DMA 接收时怎么处理空闲?——用 UART 空闲中断,或帧超时定时器判断整帧结束。
  16. SPI 只有一个从机时,CS 能不能接地?——硬件上可以,但要注意没有 CS 意味着无法复位从机状态机。
  17. 为什么 I2C 的速度比 SPI 慢?——I2C 协议开销大(地址、ACK、开漏上拉慢),且半双工。
  18. 多设备 I2C 通信时,设备地址如何确定?——查数据手册 A0/A1/A2 引脚,再结合软件设置。
  19. SPI 模式 2 和模式 3 的差别?——CPOL 不同,空闲电平高;而 CPHA 决定采样沿在第几个边沿。
  20. 你如何用万用表判断 I2C 总线是否卡死?——测 SDA 电平是否恒为低、SCL 是否还有翻转,低且无翻转即为死锁。

当然,问题能答出来是一回事,能在现场用波形图辅助讲解、能结合项目里踩过的坑去讲,又是另一回事。

8. 实际踩过的坑与备考心法

8.1 三个让我印象深刻的翻车现场

第一个翻车现场是 SPI 模式选错。当时我调一个 LCD 屏,初始化代码照搬参考例程,屏幕一直花屏。用示波器抓 SCLK 和 MOSI 波形,怎么看都对,后来才发现参考例程用的是模式 2(CPOL=1、CPHA=0),而屏的 datasheet 默认推荐模式 0。CS 拉低时,SCLK 空闲电平不一致,第一个采样边沿直接吃到了半个无效位。那次之后我再也不背模式表了,每次都是先看 datasheet 上的时序图,自己推一遍 CPOL/CPHA。

第二个是 I2C 总线死锁恢复。项目里一块从机板在上电时序异常时经常把 SDA 拉死,主控频繁超时。我最初在应用层加了一个“复位后延时重试”,但没用。后来在底层加了一个“死锁检测 + 9 时钟恢复 + 重新初始化”的状态机,才算根治。这个经历让我意识到:协议层面的问题要用协议手段解决,不能只靠应用层重启。

第三个是 UART 波特率误差。一个模块要求 57600 波特率,我用的晶振是 12MHz,计算后发现理论误差已经有 0.16%,看起来不大。但模块对端用的 RC 振荡器本身偏差 ±1.5%,两边误差叠加后,长帧数据持续出错,偶尔一个字节正常。后来我把晶振换成了 11.0592MHz,误差归零,通信立刻稳定。

8.2 备考建议:不要背概念,要能现场推导

面试备考最忌讳逐字背诵答案。UART 波特率分频公式、I2C 上拉电阻边界公式、SPI 四个模式推导,这些你都要做到能时刻从零推出来,而不是“我记得好像是某某知识点”。面试官只要一变具体数值、一变场景设备,背答案的人立刻露馅。

另外强烈建议你把三个协议用在同一个项目里实践一遍:比如一块主控板上同时挂 I2C 传感器、SPI 屏、UART 模块,然后强迫自己在没有现成库的情况下,用寄存器或模拟 GPIO 把三套收发都调通。这个过程遇到的每一个波形反着走、每一帧错位,都比你在面试题库里刷十倍题更管用。

我在实际带人时还有个小习惯:把每个协议最核心的一张时序图亲手画在纸上,标出所有建立时间、保持时间、采样边沿,然后合上讲给自己听。能连续三遍完整讲清楚,才说明你是真懂了。等到面试现场,你不会慌,因为你已经把协议的底层逻辑焊死在了脑子里。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询