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 如何选型?我的“三板斧”
很多新手问我:到底该用哪个协议?我的回答是:看需求,别跟风。我总结了三步走:
- 看速度需求:如果数据量小(比如温度传感器每秒读一次),I2C或UART都行。如果数据量大(比如摄像头图像),必须上SPI。
- 看设备数量:如果只连一个设备,UART最简单。如果连多个设备,I2C最省线。如果多个设备都需要高速,SPI+多路CS。
- 看硬件资源:有些MCU的UART、I2C、SPI外设数量有限。我建议优先用硬件外设,别用GPIO模拟——模拟的时序不稳定,还占CPU。
我的经验:如果项目初期不确定用哪个协议,优先选I2C。它兼容性好,调试工具多(逻辑分析仪一抓就能看),而且大多数传感器都支持I2C。等后期确定需求了,再优化成SPI或UART。
1.5 知识体系总览:一张图看懂本章内容
下面这张图展示了本章的核心知识结构。你可以把它当作整个课程的“地图”。
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外设。
好了,第一章就到这里。记住一句话:通信协议没有的好坏,只有合不合适的场景。后面的章节,我会带大家逐个深入,从原理到代码,把每个协议吃透。