1. 通信协议概述:嵌入式系统中通信的重要性,I2C/SPI/UART的对比与选型

各位同学,咱们今天正式开课。先聊点实在的——为什么嵌入式系统里通信协议这么重要?

你想想看,一个MCU再厉害,它也就是个孤立的芯片。你要接传感器、连显示屏、挂存储器、跟其他板子交换数据,总得有个“说话”的渠道吧?这个渠道,就是通信协议。

我刚开始做嵌入式那会儿,接过一个项目,需要在两个MCU之间传数据。当时图省事,随便拉了根线,用GPIO模拟了个简单的串口。结果呢?数据丢包、时序错乱、调试到凌晨三点……嗯,从那以后我再也不敢轻视通信协议的设计了。

1.1 为什么通信协议是嵌入式系统的“血管”

嵌入式系统里,通信协议承担着三个核心任务:

  • 数据搬运:把传感器采集到的温度、压力、加速度等物理量,从外设搬到MCU内部。
  • 设备协同:让多个芯片(比如主控+蓝牙模块+电机驱动)按照统一的节奏工作。
  • 系统扩展:通过标准总线,你可以随时挂载新的外设,而不需要重新设计硬件。

说白了,没有通信协议,你的MCU就是个“哑巴”。再强的算力也发挥不出来。

核心观点:选对通信协议,项目就成功了一半。选错了,后面全是坑。

1.2 三大主流协议:I2C、SPI、UART 的“性格”差异

咱们课程主要讲这三种。它们各有各的脾气,我一个个说。

1.2.1 UART——最“老派”但最通用的串行通信

UART(Universal Asynchronous Receiver/Transmitter)是异步通信的典型代表。它只需要两根线:TX(发送)和RX(接收)。

特点:

  • 异步:不需要时钟线,双方约定好波特率就行。
  • 全双工:可以同时收发数据。
  • 点对点:只能两个设备之间通信,不能挂多个从机。

我在项目中遇到过最典型的场景:用UART连接GPS模块和MCU。GPS模块每秒输出一次NMEA格式的定位数据,波特率设成9600,简单可靠。但要注意,如果两个设备的波特率偏差超过2%,数据就会出错。我曾经因为晶振精度不够,9600波特率下跑了一天,突然丢包……后来换成了带自动波特率检测的MCU才解决。

1.2.2 I2C——两线制“总线”,适合多设备挂载

I2C(Inter-Integrated Circuit)是飞利浦(现NXP)发明的同步通信协议。两根线:SCL(时钟)和SDA(数据)。

特点:

  • 同步:有专门的时钟线,时序由主机控制。
  • 多主机多从机:理论上可以挂载上百个设备,每个设备有唯一的地址。
  • 半双工:数据线在同一时刻只能单向传输。
  • 速度较慢:标准模式100kHz,快速模式400kHz,高速模式3.4MHz。

我个人习惯在需要连接多个传感器(比如温度、湿度、气压)时优先用I2C。每个传感器一个地址,一根总线搞定。但要注意总线电容问题——线太长或者挂的设备太多,信号会变形。我曾经在一条I2C总线上挂了8个设备,结果最后一个设备死活不响应。后来加了总线缓冲器才搞定。

1.2.3 SPI——速度之王,适合大数据量传输

SPI(Serial Peripheral Interface)是Motorola推出的同步通信协议。它需要四根线:SCLK(时钟)、MOSI(主机输出从机输入)、MISO(主机输入从机输出)、CS(片选)。

特点:

  • 同步:时钟由主机控制,速度可以很高(几十MHz甚至更高)。
  • 全双工:MOSI和MISO独立,可以同时收发。
  • 一主多从:每个从机需要一根独立的CS线。
  • 硬件开销大:每增加一个从机,就要多一根CS线。

我建议在需要高速传输数据的场景(比如LCD显示、SD卡读写、ADC采样)时用SPI。记得有一次做高速数据采集系统,用I2C读ADC,速度死活上不去。换成SPI后,采样率直接从100kHz飙到了10MHz。但SPI也有坑——没有标准的应答机制,数据发出去后,从机有没有收到,主机并不知道。所以我在SPI通信中通常会加一个简单的校验和。

1.3 三大协议对比:一张表看懂

特性 UART I2C SPI
通信方式 异步 同步 同步
线数 2(TX/RX) 2(SCL/SDA) 4(SCLK/MOSI/MISO/CS)
传输模式 全双工 半双工 全双工
拓扑结构 点对点 多主机多从机(总线) 一主多从(星型)
速度 通常115200bps~1Mbps 100kHz~3.4MHz 几MHz~几十MHz
硬件开销 低 中(需上拉电阻) 高(每从机需独立CS)
典型应用 调试口、GPS、蓝牙模块 传感器、EEPROM、RTC LCD、SD卡、ADC/DAC

1.4 如何选型?我的“三板斧”

很多新手问我:到底该用哪个协议?我的回答是:看需求,别跟风。我总结了三步走:

  1. 看速度需求:如果数据量小(比如温度传感器每秒读一次),I2C或UART都行。如果数据量大(比如摄像头图像),必须上SPI。
  2. 看设备数量:如果只连一个设备,UART最简单。如果连多个设备,I2C最省线。如果多个设备都需要高速,SPI+多路CS。
  3. 看硬件资源:有些MCU的UART、I2C、SPI外设数量有限。我建议优先用硬件外设,别用GPIO模拟——模拟的时序不稳定,还占CPU。

我的经验:如果项目初期不确定用哪个协议,优先选I2C。它兼容性好,调试工具多(逻辑分析仪一抓就能看),而且大多数传感器都支持I2C。等后期确定需求了,再优化成SPI或UART。

1.5 知识体系总览:一张图看懂本章内容

下面这张图展示了本章的核心知识结构。你可以把它当作整个课程的“地图”。

嵌入式通信协议知识体系 MCU通信协议 UART I2C SPI UART特性 • 异步,无时钟线 • 全双工,点对点 • 速度:115200~1Mbps I2C特性 • 同步,2线制 • 多主机多从机 • 速度:100kHz~3.4MHz SPI特性 • 同步,4线制 • 全双工,一主多从 • 速度:几MHz~几十MHz 选型建议:看速度 → 看设备数 → 看硬件资源 图1-1 嵌入式通信协议知识体系总览

1.6 避坑指南:我踩过的那些坑

最后,分享几个我亲身经历的教训,希望能帮你少走弯路。

坑1:UART波特率不匹配

我曾经用两个不同品牌的MCU做UART通信,一个用16MHz晶振,一个用8MHz晶振。波特率都设成115200,但实际误差一个+0.5%,一个-0.8%。累计误差超过1.3%,数据偶尔出错。后来我改用带自动波特率检测的UART外设,或者用更高精度的晶振。

坑2:I2C总线电容过大

有一次我在一条I2C总线上挂了6个设备,线长加起来超过50cm。结果SCL和SDA的上升沿变得很缓,信号逻辑混乱。解决办法:降低I2C速度(从400kHz降到100kHz),或者加总线缓冲器(如PCA9517)。

坑3:SPI的CS信号毛刺

SPI的片选信号(CS)如果控制不好,会在上电瞬间产生毛刺,导致从机误触发。我建议在CS引脚上加一个10kΩ上拉电阻,并且在软件中先拉高CS,再初始化SPI外设。

好了,第一章就到这里。记住一句话:通信协议没有绝对的好坏,只有合不合适的场景。后面的章节,我会带大家逐个深入,从原理到代码,把每个协议吃透。