
各位做嵌入式的朋友应该都有体会通讯协议是嵌入式开发中绕不开的核心知识。无论是驱动一个传感器、连接一块屏幕还是搭建一整套控制系统MCU 与外设之间、板卡与板卡之间都要靠各种通讯协议来完成数据传输。更重要的是通讯协议几乎是嵌入式面试的必考内容很多公司在技术面时都会围绕 UART、I2C、SPI、CAN 这些协议反复提问从基本原理问到项目中的实际应用再问到异常排查。本文是“嵌入式八股”系列的第三篇围绕通讯协议这个主题做一次系统梳理。我会从通讯协议的基本概念讲起逐一拆解嵌入式开发中最常用的几种协议包括它们的物理层特点、数据传输机制、优缺点和适用场景然后整理一批面试中高频出现的通讯协议问题与回答思路最后给出一些实用的工程建议。不管是正在准备嵌入式面试还是想在项目中选型通讯方案这篇文章都可以作为一份比较完整的参考资料。1. 通讯协议到底在解决什么问题1.1 通讯协议的本质通讯协议的本质是通讯双方约定好的一套“语言规则”。单片机本身只知道高低电平而高低电平本身没有意义必须通过协议把它们组织成有意义的“帧”“字节”“位”。协议里至少要约定以下几件事电平标准多高的电压算高电平多低的电压算低电平还是用差分信号传输。时序关系时钟线何时采样数据线何时变化起始位、停止位、应答位如何排列。数据格式一个字节包含多少位先传高位还是低位有没有校验位。通讯模式是全双工、半双工还是单工。寻址方式如果总线上挂着多个设备如何区分数据是发给谁的。可以说通讯协议是嵌入式系统内部各模块之间、系统与外部设备之间交换信息的“共同语言”。没有协议硬件上即使连接在一起数据也无法被正确理解。1.2 为什么嵌入式开发必须掌握通讯协议嵌入式开发几乎不可能脱离通讯协议单独存在。常见场景包括读取传感器数据温湿度传感器 SHT30 用 I2C 通讯陀螺仪 MPU6050 用 I2C 或 SPI气压计 BMP280 用 I2C/SPI。驱动显示与存储设备LCD 屏幕用 SPI 或 RGB 接口Flash 芯片用 SPIEEPROM 用 I2C。板间通讯设备之间长距离传输数据时常用 CAN 总线或 RS485 总线。与上位机通讯调试时通过 USART 转 USB 与 PC 交互工业场景中通过 Modbus 协议与 PLC、触摸屏通讯。而这些场景中的协议恰恰是面试官最喜欢深入追问的内容。因为通讯协议能同时考察一个人的硬件基础、C 语言功底、时序理解能力和项目实战经验。1.3 通讯方式的分类从不同维度看通讯方式可以分成几组分类维度类型典型代表传输方向单工、半双工、全双工单工红外遥控半双工I2C、RS485全双工UART、SPI时钟方式同步、异步同步I2C、SPI异步UART数据传输方式串行、并行串行绝大多数总线并行并口屏、并口 Flash信号形式单端、差分单端UART、I2C、SPI差分CAN、RS485、USB理解这些分类非常重要因为在面试中经常会出现“I2C 是什么类型的通讯”这类问题如果你能直接说出“同步、半双工、串行通讯”就能给面试官一个专业的第一印象。2. 串行通讯的基础知识点2.1 串行与并行的区别串行通讯指数据按位依次传输每次只传输一位因此只需要较少的数据线。并行通讯则一次传输多位数据需要多根数据线同时传输。串行通讯的优点是引脚少、布线简单、成本低、抗干扰能力容易做得好缺点是相同时钟频率下传输速率比并行低。并行通讯的优点是速度快但占用引脚多布线复杂高速时容易产生信号串扰。在实际项目中MCU 与外设的长距离通讯几乎全部采用串行方式。并行通讯多用于内部总线或者对速度要求极高的存储接口例如并口 NOR Flash。2.2 同步通讯与异步通讯同步通讯会单独提供一根时钟线。发送方和接收方都按照这根时钟线的节拍来传输数据接收方在时钟的上升沿或下降沿采样数据线。典型的同步协议有 I2C、SPI、I2S。异步通讯没有时钟线。通讯双方必须约定相同的波特率即每秒传输多少位接收方靠起始位来对齐数据的边界。典型的异步协议是 UART。同步通讯的优点是时序明确、速率可以做得更高缺点是需要额外的时钟线。异步通讯的优点是不需要时钟线、接线少缺点是通讯双方必须保证波特率一致且波特率误差过大时数据会出错。2.3 单端信号与差分信号单端信号使用一根信号线电平参考 GND。UART、I2C、SPI 都属于单端信号。单端信号实现简单但抗干扰能力相对较弱距离长了容易受到共模干扰。差分信号使用两根线传输一路信号接收端比较两根线的电压差来判断电平。CAN、RS485、USB 都属于差分信号。差分信号抗干扰能力强适合长距离、高可靠的工业现场。面试中如果被问到“RS485 为什么能传上千米”核心答案就是差分信号带来的抗干扰能力。3. 常用通讯协议逐个拆解3.1 UART最基础的异步串行通讯UART 全称 Universal Asynchronous Receiver/Transmitter通用异步收发器。它是嵌入式开发中最常用、最简单的通讯协议之一。硬件上只需要两根线TX发送和 RX接收。两个设备之间的 TX 接对方的 RX。通讯双方共地。UART 的数据帧格式为起始位数据位校验位可选停止位1 位低电平5~8 位常用 8 位奇校验/偶校验/无校验1 位或 2 位高电平发送开始时总线先拉低一个位时间这就是起始位。接收方检测到这个下降沿后就知道数据开始了。之后按约定的波特率依次采样数据位最后是停止位。面试中与 UART 相关的常见知识点波特率比如 9600、115200表示每秒传输的位数。波特率误差通讯双方的波特率必须足够接近一般误差不能超过 2%~3%。起始位、停止位的作用起始位用于对齐数据停止位用于保证帧间隔。流控有硬件流控RTS/CTS和软件流控XON/XOFF但裸机开发中常用无流控模式。UART 本身只定义了数据帧格式并没有定义电平标准。我们通常说的 TTL 电平 UART、RS232、RS485本质上是 UART 数据在不同物理层上的传输方式。3.2 I2C两线制同步半双工通讯I2C 全称 Inter-Integrated Circuit由飞利浦公司现恩智浦提出是一种广泛用于连接低速外设的两线制同步串行总线。I2C 只需要两根线SCLSerial Clock时钟线由主机产生。SDASerial Data数据线双向传输数据。I2C 支持一主多从或多主通讯每个从设备都有一个唯一的地址。主机通过地址来选择与哪个从设备通讯。I2C 的关键机制起始条件SCL 为高电平时SDA 产生一个下降沿。停止条件SCL 为高电平时SDA 产生一个上升沿。应答机制每传输 8 位数据后接收方需要拉低 SDA 表示应答ACK不应答则释放 SDANACK。地址帧通常主机先发送 7 位从机地址加 1 位读写标志位。速率模式标准模式 100kbit/s快速模式 400kbit/s高速模式 3.4Mbit/s。I2C 的上拉电阻问题也是面试常考点。因为 I2C 总线使用开漏输出所以 SCL 和 SDA 上必须接上拉电阻。上拉电阻的取值需要平衡功耗和上升沿速度。I2C 的优点是引脚少、支持多设备挂载、接线简单非常适合连接传感器、EEPROM、RTC 等低速设备。缺点是速率相对 SPI 较低且没有类似 SPI 的片选信号多设备靠地址区分。3.3 SPI高速全双工同步通讯SPI 全称 Serial Peripheral Interface串行外设接口由摩托罗拉公司提出。SPI 需要四根线SCLK时钟线由主机产生。MOSIMaster Out Slave In主机输出、从机输入。MISOMaster In Slave Out主机输入、从机输出。CS/SSChip Select / Slave Select片选线低电平有效。SPI 是真正意义上的全双工通讯主机和从机可以同时发送和接收数据。它的核心机制是移位寄存器每产生一个时钟脉冲主机和从机各移出一位数据同时各移入一位数据。SPI 没有地址机制依靠 CS 片选线来选择从机。这也是 SPI 和 I2C 最直观的区别之一。SPI 的四种工作模式由 CPOL时钟极性和 CPHA时钟相位决定模式CPOLCPHA数据采样时机模式 000上升沿采样模式 101下降沿采样模式 210下降沿采样模式 311上升沿采样其中模式 0 是最常用的。如果通讯双方配置的 SPI 模式不一致接收到的数据就会错位。所以在写 SPI 驱动时必须先查阅从设备数据手册确认设备要求的是哪种模式。SPI 的优点是速率高、全双工、数据吞吐量大适合 Flash、屏幕、SD 卡等需要用大量数据交互的场景。缺点是需要至少 4 根线且每个从机都需要单独的 CS 引脚设备多了以后布线压力比较大。3.4 CAN高可靠多主差分通讯CAN 全称 Controller Area Network控制器局域网由博世公司开发最早用于汽车电子现在已经是工业控制、机器人、医疗设备中主流的现场总线之一。CAN 使用两根差分线CAN_H 和 CAN_L。逻辑电平分为显性电平Dominant和隐性电平Recessive。显性电平对应逻辑 0隐性电平对应逻辑 1。当总线上多个节点同时发送时显性电平会覆盖隐性电平这个特性是 CAN 总线仲裁的基础。CAN 总线的物理层要求两端各接一个 120Ω 终端电阻用于消除信号反射。CAN 的关键机制多主通讯总线上任何节点都可以主动发起通讯。报文仲裁多个节点同时发送时ID 小的报文优先发送也就是显性位优先。帧类型数据帧、远程帧、错误帧、过载帧最常用的是数据帧。标准帧与扩展帧标准帧 ID 为 11 位扩展帧 ID 为 29 位。错误处理CAN 节点具备完善的错误检测和处理机制包括位错误、填充错误、CRC 错误、格式错误、应答错误。CAN 的波特率与位时序相关。每个位时间由同步段、传播段、相位缓冲段 1、相位缓冲段 2 组成采样点就位于相位缓冲段 1 和 2 的交界处。实际项目中采样点通常设置在 75%~87.5% 左右具体取决于总线速率和线缆长度。CAN 的主要优点可靠性高抗干扰能力强。支持多主节点之间可以自由通讯。总线利用率高仲裁机制避免了数据碰撞。支持错误检测和自动重发。CAN 的缺点是协议相对复杂配置难度比 UART、SPI 高普通 MCU 通常需要外接 CAN 收发器芯片如 TJA1050、SN65HVD230。3.5 RS485 与 Modbus工业现场的经典组合RS485 是电气层标准定义的是差分信号的电气特性不规定具体的数据帧格式。因此 RS485 可以承载 UART 协议数据也可以承载 Modbus 协议数据。RS485 的特点差分信号抗干扰能力强。支持多点通讯一条总线上最多可以挂接 32 个节点标准负载条件下。半双工工作同一时刻只能有一个节点发送。传输距离远1200m 以上仍可正常工作与波特率相关。需要加终端电阻通常在总线两端各接一个 120Ω 匹配电阻。Modbus 是应用层协议在很多工业设备中物理层采用 RS485数据链路层和应用层采用 Modbus RTU。Modbus RTU 的报文格式为从站地址功能码数据区CRC 校验1 字节1 字节N 字节2 字节常用的功能码包括0x01读线圈0x02读离散输入0x03读保持寄存器0x04读输入寄存器0x05写单个线圈0x06写单个寄存器0x0F写多个线圈0x10写多个寄存器Modbus 是主从协议主机发起请求从机响应。从机不能主动向主机发送数据。面试中如果被问到 Modbus 和 RS485 的关系回答思路是RS485 解决的是“电信号怎么传”Modbus 解决的是“数据怎么组织、指令怎么定义”两者可以组合使用。3.6 其他常见协议简述除了上面几种协议嵌入式开发中还经常接触到USB差分信号支持热插拔、枚举、多种传输类型。复杂但通用性极强。以太网工业以太网、EtherCAT、PROFINET 等衍生协议覆盖面很广。SDIO用于 SD 卡、WiFi 模块等设备。1-Wire单总线协议典型应用是 DS18B20 温度传感器。LIN汽车领域低成本的局域互联网络CAN 的补充。面试中通常会先考察 UART、I2C、SPI、CAN 这四大协议因为这些协议覆盖面最广项目中出现概率最高。4. 常用协议特性对比面试中经常要求横向对比不同协议下面这张表建议熟练掌握特性UARTI2CSPICAN信号线2 根TX/RX2 根SCL/SDA4 根SCLK/MOSI/MISO/CS2 根CAN_H/CAN_L通讯模式全双工半双工全双工半双工同步/异步异步同步同步同步信号形式单端单端单端差分多设备支持不支持点对点支持多从机靠地址支持多从机靠片选支持多主速率一般 ≤ 几 Mbit/s最高 3.4Mbit/s高速模式几十 Mbit/s最高 1Mbit/s经典 CAN传输距离较短较短较短很长抗干扰能力弱弱弱强典型应用调试、GPS、蓝牙模块传感器、EEPROM、RTCFlash、屏幕、SD 卡汽车、工业控制这个表不需要死记硬背而是要通过理解协议的工作原理自然推导出来。比如“SPI 为什么是全双工”因为 MOSI 和 MISO 是独立的两根线可以同时数据双向传输。“I2C 为什么是半双工”因为 SDA 是双向数据线同一时刻只能一个方向传输数据。5. 通讯协议面试高频题目与回答思路5.1 UART 面试题问题 1UART 通讯中起始位和停止位的作用是什么回答思路起始位用于标识一帧数据的开始接收方在检测到起始位高电平变为低电平的下降沿后开始采样停止位用于标识一帧数据的结束同时也保证了两个连续数据帧之间有一段高电平间隔避免起始位检测混乱。问题 2两个设备 UART 通讯波特率不一致会怎样回答思路接收方采样时机和数据实际位置出现偏差采到的数据位不对最终出现乱码。波特率误差较小时一般 2% 以内可能勉强可以通讯误差大了必然出错。问题 3为什么有时候 UART 传输距离很短回答思路UART 属于单端信号参考地是 GND在长距离传输时容易受到共模干扰且信号电平摆幅固定线缆的分布电容也会导致波形变差。因此 UART 适合板级短距离通讯远距离传输应改用 RS232、RS485 或者 CAN 等物理层方案。5.2 I2C 面试题问题 1I2C 为什么需要上拉电阻回答思路I2C 的 SCL 和 SDA 是开漏输出结构只能主动拉低电平不能主动输出高电平。所以必须通过上拉电阻将电平拉高。上拉电阻的阻值会影响功耗和通讯速率阻值太小功耗大阻值太大上升沿变缓高速通讯容易出错。问题 2I2C 一主多从时如何区分不同设备回答思路每个 I2C 从设备都有唯一的器件地址。主机在起始条件后先发送从机地址加读写标志位只有地址匹配的从机会产生应答其他从机则不参与后续通讯。问题 3如果 I2C 总线上某个从机不回应答可能是什么原因回答思路地址错误、从机供电异常、SDA 或 SCL 线序接反、上拉电阻缺失、从机地址冲突或者从机正处于复位状态。排查时先用示波器或逻辑分析仪抓取总线波形确认起始条件、地址帧和应答位是否存在。5.3 SPI 面试题问题 1SPI 和 I2C 的区别有哪些回答思路物理层上 SPI 需要 4 根线I2C 只需要 2 根线SPI 全双工I2C 半双工SPI 依靠 CS 选择从机I2C 依靠地址选择从机SPI 速率通常高于 I2CSPI 没有应答机制I2C 有 ACK/NACK 应答。问题 2SPI 的四种模式怎么区分回答思路由 CPOL 和 CPHA 两个参数决定。CPOL 决定空闲时时钟电平为高还是低CPHA 决定数据在第几个边沿采样。两个设备必须工作在相同的模式下才能正常通讯。问题 3SPI 模式配置错了会出现什么现象回答思路主机和从机的采样边沿不匹配导致数据移位错乱读到的数据出现位错位或字节错位甚至完全无法通讯。一般表现为读寄存器值异常或者设备完全不应答。5.4 CAN 面试题问题 1CAN 总线为什么需要终端电阻回答思路CAN 属于高速差分总线信号在总线末端会发生反射。终端电阻可以吸收反射能量保证信号质量。标准要求总线两端各接一个 120Ω 电阻总等效电阻约 60Ω。问题 2CAN 的仲裁机制是怎样的回答思路CAN 总线上的显性电平逻辑 0可以覆盖隐性电平逻辑 1。多个节点同时发送时每个节点在发送过程中监督总线电平如果自己发送隐性位但总线上是显性位就说明有更高优先级ID 更小的报文在发送该节点立即停止发送转为接收状态。问题 3CAN 标准帧和扩展帧有什么区别回答思路标准帧 ID 是 11 位扩展帧 ID 是 29 位。扩展帧 ID 是 11 位基础 ID 加 18 位扩展 ID。两者在帧格式上不同但仲裁机制和错误机制相同。问题 4CAN 能传输多远的距离回答思路与波特率有关。波特率越低传输距离越长。比如 1Mbit/s 时可以达到约 40m125kbit/s 时可以达到约 500m 以上50kbit/s 时可以达到 1000m 左右。具体还需要考虑线缆质量、总线节点数和终端电阻配置。5.5 RS485/Modbus 面试题问题 1RS485 为什么传输距离远、抗干扰能力强回答思路RS485 采用差分信号传输接收端比较 A/B 两线电压差来判断逻辑值共模干扰对差分信号的干扰会被抵消。因此抗干扰能力强传输距离远。问题 2RS485 通讯中 A/B 线接反会怎样回答思路逻辑电平反相接收到的数据取反上位机或 MCU 收到的数据乱码或完全不对。很多 RS485 收发器也有 A/B 接反保护但更稳妥的做法是严格按照 A 接 A、B 接 B 来接线。问题 3Modbus RTU 的一帧报文由哪些部分组成回答思路从站地址1 字节、功能码1 字节、数据区N 字节、CRC16 校验2 字节。CRC 校验低位在前高位在后。5.6 综合性设计题这一类问题是面试中难度较高的通常没有标准答案考察的是综合能力。问题 1如果让你设计一个多设备通讯系统你会怎么选型回答思路先分析需求通讯距离、数据量、实时性、节点数量、成本、可靠性和抗干扰要求。短距离小数据量选 I2C大数据量高速率选 SPI长距离多节点选 RS485 或 CAN汽车或工业现场选 CAN低成本点对点选 UART。问题 2如何判断一个新的通讯协议芯片是否工作正常回答思路先用示波器或逻辑分析仪确认时钟线是否有时钟输出确认/CS 片选电平是否正确拉低确认 MOSI 发送的数据是否与寄存器配置一致。再检查 MISO 返回数据必要时先用已知设备验证主机配置是否正确。问题 3通讯数据出现乱码一般怎么排查回答思路从物理层到协议层逐步排查。先确认波特率或时钟极性配置再测量波形看电平幅值是否正常是否有毛刺然后检查数据帧格式、地址、校验最后检查软件逻辑比如缓冲区处理、中断优先级等。6. 实战代码示例下面用 STM32 HAL 库给出几个常见协议的初始化与读写示例。代码以思路演示为主具体引脚以实际板卡为准。6.1 UART 收发示例// 文件路径uart_demo.c #include main.h extern UART_HandleTypeDef huart1; uint8_t rx_buffer[1]; uint8_t tx_data[] Hello UART\r\n; void UART_Demo_Init(void) { // 使能串口接收中断单字节接收 HAL_UART_Receive_IT(huart1, rx_buffer, 1); } void UART_Demo_Send(void) { HAL_UART_Transmit(huart1, tx_data, sizeof(tx_data) - 1, 1000); } void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if (huart-Instance USART1) { // 收到一字节数据原样回显 HAL_UART_Transmit(huart1, rx_buffer, 1, 100); // 重新使能接收 HAL_UART_Receive_IT(huart1, rx_buffer, 1); } }关键点UART 接收中断必须在每次接收完一帧或一字节后重新使能否则后续数据无法触发中断。实际项目中建议使用空闲中断加 DMA 的方式处理不定长数据。6.2 I2C 读传感器示例// 文件路径i2c_demo.c #include main.h extern I2C_HandleTypeDef hi2c1; // 以 SHT30 温湿度传感器为例设备地址 0x44 1 #define SHT30_ADDR (0x44 1) #define SHT30_CMD_MEASURE 0x2C06 uint8_t recv_data[6]; void SHT30_Read(float *temperature, float *humidity) { uint8_t cmd[2]; cmd[0] (SHT30_CMD_MEASURE 8) 0xFF; cmd[1] SHT30_CMD_MEASURE 0xFF; // 发送测量命令 HAL_I2C_Master_Transmit(hi2c1, SHT30_ADDR, cmd, 2, 1000); // 等待测量完成 HAL_Delay(20); // 读取 6 字节数据 HAL_I2C_Master_Receive(hi2c1, SHT30_ADDR, recv_data, 6, 1000); // 温度前两个字节为数据第三个字节为 CRC uint16_t temp_raw (recv_data[0] 8) | recv_data[1]; *temperature -45.0f 175.0f * (float)temp_raw / 65535.0f; // 湿度后两个字节为数据 uint16_t hum_raw (recv_data[3] 8) | recv_data[4]; *humidity 100.0f * (float)hum_raw / 65535.0f; }关键点I2C 读设备时地址最后一位是读写标志。HAL 库的地址参数已经帮我们处理了移位注意传入时地址要左移一位。从设备收到命令后可能需要延时等待处理完成不能立刻读数据。6.3 SPI 读写 Flash 示例// 文件路径spi_demo.c #include main.h extern SPI_HandleTypeDef hspi1; #define FLASH_CS_LOW() HAL_GPIO_WritePin(FLASH_CS_GPIO_Port, FLASH_CS_Pin, GPIO_PIN_RESET) #define FLASH_CS_HIGH() HAL_GPIO_WritePin(FLASH_CS_GPIO_Port, FLASH_CS_Pin, GPIO_PIN_SET) uint8_t spi_tx_buf[8]; uint8_t spi_rx_buf[8]; // 读取 Flash 的 JEDEC ID用于验证 SPI 通讯是否正常 void Flash_Read_JEDEC_ID(void) { uint8_t tx_cmd[4] {0x9F, 0x00, 0x00, 0x00}; uint8_t rx_data[4] {0}; FLASH_CS_LOW(); HAL_SPI_TransmitReceive(hspi1, tx_cmd, rx_data, 4, 1000); FLASH_CS_HIGH(); // rx_data[1] 为 Manufacturer IDrx_data[2] 为 Memory Typerx_data[3] 为 Capacity }关键点SPI 时序中CS 片选必须在整个读写过程中保持拉低操作完成后拉高。主机发送数据的同时必须接收数据因为 SPI 是全双工发送即使只读数据也要发送填充字节来产生时钟。6.4 CAN 发送示例// 文件路径can_demo.c #include main.h extern CAN_HandleTypeDef hcan1; void CAN_SendMessage(uint32_t id, uint8_t *data, uint8_t len) { CAN_TxHeaderTypeDef tx_header; uint32_t tx_mailbox; tx_header.IDE CAN_ID_STD; // 标准帧 tx_header.RTR CAN_RTR_DATA; // 数据帧 tx_header.DLC len; // 数据长度 tx_header.StdId id; // 标准帧 ID HAL_CAN_AddTxMessage(hcan1, tx_header, data, tx_mailbox); } void CAN_Init_Filter(void) { CAN_FilterTypeDef filter; filter.FilterBank 0; filter.FilterMode CAN_FILTERMODE_IDMASK; filter.FilterScale CAN_FILTERSCALE_32BIT; filter.FilterIdHigh 0x0000; filter.FilterIdLow 0x0000; filter.FilterMaskIdHigh 0x0000; filter.FilterMaskIdLow 0x0000; filter.FilterFIFOAssignment CAN_RX_FIFO0; filter.FilterActivation ENABLE; HAL_CAN_ConfigFilter(hcan1, filter); }关键点CAN 发送前必须调用HAL_CAN_Start启动 CAN 外设接收报文前必须先配置滤波器否则中断不会触发。每发送一帧数据后要检查邮箱发送完成状态。7. 通讯协议调试经验与工具推荐7.1 常见调试工具工具用途逻辑分析仪抓取 I2C、SPI、UART 时序分析波形和数据帧示波器测量电平、毛刺、上升沿时间检查物理层信号质量USB 转 TTL 串口模块调试 UART查看嵌入式设备打印日志USB 转 RS485 模块调试 RS485/Modbus 通讯CAN 分析仪抓取 CAN 报文分析 ID、数据、错误帧多功能协议分析工具部分工具支持 UART/I2C/SPI/CAN 自动解码7.2 调试建议首先确认物理连接TX/RX 是否交叉、I2C 上拉电阻是否焊接、RS485 A/B 是否正确、CAN 终端电阻是否匹配。很多通讯问题都不是软件问题而是硬件连接问题。然后确认配置参数UART 的波特率、I2C 的地址、SPI 的模式和速率、CAN 的波特率这些参数任何一个不匹配通讯都会失败。再用逻辑分析仪抓波形。通过波形可以直接看到起始位、数据位、应答位、片选信号是否正常比在代码里加打印日志高效得多。最后做数据校验。先发送固定字节或者 Read ID 命令确认链路是否通再处理复杂业务数据。7.3 一个代表性的排查案例场景I2C 读取温湿度传感器始终返回错误数据或超时。排查过程先用万用表测量 SCL 和 SDA 电压正常待机时应该被上拉到 3.3V。如果电压为 0检查上拉电阻是否焊接、传感器是否供电。用逻辑分析仪抓取起始条件、设备地址、ACK 位。发现 SDA 上完全没有 ACK 信号进一步确认是设备地址左移/合并错误修正后正常。这个案例说明排查通讯问题时要按照“电平 → 波形 → 协议 → 软件”的顺序逐层缩小范围不要一开始就翻代码。8. 通讯协议工程建议与注意事项8.1 协议选型建议选型时不要盲目追求“高速”或“功能强”而要从项目需求反推节点数量只有两三个设备且距离很近UART 或 I2C 足够。数据量大量数据块传输优先考虑 SPI 或并口。节点数量多且距离远考虑 RS485 或 CAN。环境恶劣、抗干扰要求高RS485 或 CAN 优于 UART/I2C/SPI。需要多主机同时通讯CAN 是最合理的方案。成本敏感UART 硬件成本最低I2C 外设成本低。8.2 驱动代码编写建议通讯驱动是嵌入式系统中频繁使用的模块建议封装成独立接口层。将协议驱动和业务逻辑解耦后续更换芯片或调整引脚时只需要修改底层实现不需要改动上层代码。// 抽象通讯接口示例 typedef struct { int (*init)(void); int (*read)(uint8_t reg, uint8_t *buf, uint16_t len); int (*write)(uint8_t reg, uint8_t *buf, uint16_t len); } bus_ops_t;将 UART、I2C、SPI 各自的读写函数封装成统一接口上层应用面向接口编程这样代码的可维护性和可移植性都会好很多。8.3 需要注意的坑以下问题在嵌入式通讯开发中非常常见未处理总线上无应答、超时等异常情况导致程序卡死在等待状态。中断优先级配置不合理导致通讯数据丢失。波特率误差过大尤其在高波特率下容易偶发乱码。I2C 上没有上拉电阻或上拉电阻阻值不合适。SPI 模式和速率不匹配通讯出现偶发错误。CAN 过滤器配置错误导致接收不到报文。RS485 半双工收发切换不及时导致最后一个字节被截断。写代码时建议给所有通讯接口增加超时机制和错误处理避免在无应答时无限等待。8.4 从面试角度准备的建议准备通讯协议相关面试题时不要只背概念。面试官更看重你能不能结合项目经验说明问题。比如你说自己用过 I2C就要能说清楚设备地址怎么确定、上拉电阻阻值选多少、实测波形什么样、有没有遇到过总线锁死的问题以及你是如何解决的。以下复习方向建议优先准备每个协议的物理层电平特性、引脚定义。每个协议的时序图能自己画出来并解释每一步。每个协议的数据帧格式能写出关键字段。每个协议的优缺点和适用场景。项目中实际用过哪些协议遇到了什么坑。经典对比题如 I2C 与 SPI、RS485 与 CAN、UART 与 RS485。嵌入式面试中通讯协议是最容易体现项目深度的话题之一。基础原理大家都懂但能把原理和项目经验结合起来讲清楚的人并不多。建议你在准备面试时把自己做过的每一个用到通讯协议的项目单独整理成“项目背景 协议选型原因 关键配置参数 遇到的坑 解决方案”的结构这样不管面试官问到哪个层次你都能有条理地回应。通讯协议的知识体系比较庞杂建议以 UART、I2C、SPI、CAN 四个协议为核心深入学习RS485/Modbus 作为补充USB 和以太网按需了解。先把四类主流协议吃透再结合实际项目反复调试和复盘这些知识就会逐渐变成自己的工程经验。本文整理的内容可以作为一份复习资料建议收藏备用面试前过一遍会有很大帮助。