UART、SPI、I2C、RS232、RS422、RS485、DB接口概念傻傻分不清楚,一篇文章以初学者的角度告诉你

当然可以!下面是一篇专为初学者设计的详细讲解 ,用最通俗的语言、生活化的比喻和清晰的图示(文字描述),帮你彻底搞懂 UART 和 RS422 到底是什么、有什么区别、怎么配合使用


🌟 UART 与 RS422 完全入门指南(给嵌入式新手)

适合人群 :刚学单片机、第一次接触串口通信、看到"UART""RS422"就头晕的新手
目标:读完后你能回答------

  • UART 是协议还是电线?
  • RS422 跟普通串口有什么不同?
  • 为什么我的开发板要加一个"转换芯片"才能连电脑?

一、先说结论(一句话记住)

  • UART 是一种 通信规则(协议),规定数据怎么打包、怎么发送。
  • RS422 是一种 物理电平标准,规定用多少电压、几根线来传输信号。
  • 它们的关系UART 是"说什么语言",RS422 是"用什么嗓门喊"

就像:

  • 你说中文(UART 协议)
  • 但你可以小声说(TTL 电平),也可以用喇叭喊(RS422 电平)

二、UART 是什么?------ 通信的"语法"

1. 全称

U niversal A synchronous R eceiver/T ransmitter

(通用异步收发器)

2. 核心特点

特点 解释
异步 没有时钟线!靠双方提前约定"语速"(波特率)
串行 数据一位一位地传(像排队过独木桥)
全双工 有两条线:一条发(TX),一条收(RX),能同时说话和听

3. 一帧数据长什么样?

UART 把每个字节(8 位)包装成一个"数据帧":

复制代码
[起始位] [数据位] [校验位] [停止位]
   0     D0~D7     (可选)     1

举个例子:发送字母 'A'(ASCII = 65 = 01000001

  • 起始位:0(表示"我要开始说话了!")
  • 数据位:从最低位开始发1 0 0 0 0 0 1 0
  • 停止位:1(表示"我说完了!")

关键:发送方和接收方必须约定好:

  • 波特率(每秒发多少位,如 9600)
  • 数据位(通常是 8 位)
  • 有没有校验位
  • 停止位是 1 位还是 2 位

这就是常说的 "8N1" 配置:

  • 8 位数据
  • N = No parity(无校验)
  • 1 位停止位

三、UART 的"电平问题"------ 为什么不能直接连电脑?

1. 芯片内部的 UART 用的是 TTL 电平

  • 逻辑 0 = 0V
  • 逻辑 1 = 3.3V 或 5V

⚠️ 问题来了:

这种电压只能传很短距离 (< 0.5 米),而且抗干扰能力差

工厂里电机一开,电磁干扰一大,信号就乱了!

2. 传统电脑串口用的是 RS232 电平

  • 逻辑 0 = +3V ~ +15V
  • 逻辑 1 = -3V ~ -15V

❗ 注意:RS232 是负逻辑 !高电压反而是 0!

而且它用正负电压,是为了抗干扰、传得远(可达 15 米)。

但 RS232 也有缺点:

  • 只能点对点(1 对 1)
  • 速度慢(最高约 115kbps)
  • 现在新电脑都没串口了(被 USB 取代)

四、RS422 是什么?------ 工业级的"大声喊话"

1. 为什么需要 RS422?

为了解决 TTL 传不远、RS232 速度慢的问题,工程师发明了 差分信号

2. 什么是"差分信号"?

不用一根线传 0/1,而是用两根线

  • A 线:发原始信号
  • B 线:发相反的信号
逻辑值 A 线 B 线 电压差 (A - B)
1 +2V ~ +6V
0 -2V ~ -6V

好处

外界干扰(比如电机噪声)会同时影响 A 和 B 线 ,但电压差不变

所以接收端只看"差值",就能准确判断是 0 还是 1。

3. RS422 的优势

特性 RS422 TTL / RS232
传输距离 最长 1200 米 < 15 米
传输速率 最高 10 Mbps < 115 kbps
抗干扰 极强(差分) 弱(单端)
连接方式 1 发多收(最多 10 个设备) 仅 1 对 1

4. 接线方式

RS422 需要 4 根线(全双工):

  • TX+、TX-(核心板发)
  • RX+、RX-(核心板收)
  • GND(共地,很重要!)

💡 实际使用中,常通过 RS422 转 USB 模块 连到电脑。


五、UART 和 RS422 怎么配合?------ "翻译官"芯片

你的 TMS320C6678 芯片内部有 UART 模块 ,但它输出的是 TTL 电平(0V/3.3V)

而你要连的是 RS422 设备(用差分信号)。

所以中间需要一个 "翻译官" ------ RS422 收发器芯片,比如:

  • SN65HVD72
  • MAX3080
  • ADM2587

工作流程:

复制代码
C6678 (UART-TTL) 
    → [RS422 芯片] 
    → (差分信号: TX+, TX-, RX+, RX-) 
    → 工业设备 / 电脑(通过转接器)

🔧 芯片作用

  • 把 TTL 的 0/3.3V 转成 RS422 的 ±2V~±6V 差分信号
  • 把收到的差分信号转回 TTL 电平给 C6678

六、一张表总结所有概念

名称 类型 作用 电平 距离 速度 线数
UART 通信协议 规定数据帧格式、波特率等 不定义(依赖物理层) - - 2(TX/RX)
TTL 电平标准 芯片间短距离通信 0V / 3.3V 或 5V < 0.5m 高(>1Mbps) 2
RS232 电平标准 老式电脑串口 ±3V~±15V(负逻辑) ≤15m ≤115kbps 3(TX/RX/GND)
RS422 电平标准 工业长距离通信 差分 ±2V~±6V ≤1200m ≤10Mbps 4(TX±, RX±)+GND

记住

  • UART 是"软件协议",存在于代码和寄存器配置中
  • TTL/RS232/RS422 是"硬件电平",决定你用什么芯片、怎么接线

七、实际应用举例

场景 1:调试你的 C6678 开发板

  • 板子上 UART 引脚(TTL 电平) → 接 USB 转 TTL 模块(如 CH340) → 电脑
  • 你在串口助手看到 printf("Hello") ------ 这就是 UART + TTL

场景 2:工业现场连接 PLC

  • C6678 的 UART → 接 RS422 芯片 → 用双绞线连到 100 米外的 PLC
  • 即使旁边有大电机,通信依然稳定 ------ 这就是 UART + RS422

八、常见误区澄清

误区 1 :"UART 就是串口"

✅ 正解:UART 是串口的一种实现方式(还有 SPI、I2C 也是串口,但不是 UART)

误区 2 :"RS422 是一种协议"

✅ 正解:RS422 只是物理层标准,它上面跑的还是 UART 协议!

误区 3 :"RS422 和 RS485 一样"

✅ 正解:

  • RS422:全双工,1 发多收(不能多个设备同时发)
  • RS485:半双工,多设备可轮流发(更常用在 Modbus 总线)

九、给初学者的建议

  1. 先掌握 UART 协议:理解起始位、数据位、波特率
  2. 再学电平转换:知道 TTL 传不远,工业要用 RS422/RS485
  3. 动手接一次线:用 USB 转 RS422 模块连开发板,亲眼看到数据
  4. 别怕看芯片手册:找一个 RS422 芯片(如 SN65HVD72),看它的引脚图和典型电路

十、总结(终极记忆法)

  • UART = "怎么说话"(语法:先说"你好",再说内容,最后说"再见")
  • RS422 = "用喇叭喊"(嗓门大、传得远、不怕吵)
  • 没有 RS422 芯片,UART 只能在板子上"悄悄说话"
  • 有了 RS422,UART 就能在工厂里"大声广播"

现在,你再也不用混淆 UART 和 RS422 了!🎉


如果你正在用 TMS320C6678 做项目,记住:
写代码配 UART,画电路加 RS422 芯片,接线别忘 GND ------ 通信稳如泰山!

那么spi和I2c又是什么?

Qwen3-Max

太好了!你已经理解了 UART 和 RS422 ,现在我们来认识另外两种在嵌入式系统中极其常用 的串行通信协议:SPII²C(读作 "I-squared-C" 或 "I-two-C")

下面这篇讲解专为初学者设计,用生活化比喻、清晰对比和实际例子,帮你彻底搞懂它们是什么、怎么工作、有什么区别,以及什么时候该用哪个。


🌟 SPI 与 I²C 完全入门指南(给嵌入式新手)

适合人群 :刚学单片机、第一次接触传感器/存储器通信的新手
目标:读完后你能回答------

  • SPI 和 I²C 是用来干什么的?
  • 它们需要几根线?谁更快?谁更省引脚?
  • 为什么我的 OLED 屏用 I²C,而 SD 卡用 SPI?

一、先说结论(一句话记住)

  • SPI工厂流水线:高速、全双工、一对一"点名"通信。
  • I²C会议室圆桌讨论:低速、半双工、靠"地址"喊人。

✅ 它们都是 同步串行通信协议 (有主设备提供时钟),用于芯片之间短距离通信,比如:

  • 单片机 ↔ 温度传感器
  • MCU ↔ EEPROM 存储器
  • 主控 ↔ OLED 显示屏

二、SPI 是什么?------ "高速流水线"

1. 全称

S erial P eripheral I nterface

(串行外设接口)

2. 核心特点

特性 说明
同步 由主设备提供时钟(SCLK),收发双方严格同步
全双工 能同时发送和接收数据(像对讲机)
主从架构 1 个主设备(Master),可带多个从设备(Slave)
无地址 靠"片选线"(CS)直接选中某个从设备

3. 需要几根线?

最少 4 根(标准 SPI):

信号线 全称 方向(从主设备看) 作用
SCLK Serial Clock 输出 时钟信号,由主设备产生
MOSI Master Out Slave In 输出 主设备 → 从设备 的数据线
MISO Master In Slave Out 输入 从设备 → 主设备 的数据线
CS/SS Chip Select / Slave Select 输出 片选信号,低电平有效

⚠️ 关键 :每增加一个从设备,就要多一根 CS 线

比如接 3 个传感器,就需要 3 根 CS 线(共 6 根线:SCLK+MOSI+MISO+CS1+CS2+CS3)

4. 工作流程(以读取 Flash 为例)

  1. 主设备拉低 Flash 的 CS 线 → "你,准备干活!"
  2. 主设备通过 SCLK 打拍子 ,同时在 MOSI 发送"读命令"
  3. Flash 在 MISO 上返回数据(同时 MOSI 可继续发地址)
  4. 通信结束,主设备拉高 CS → "干完了,休息!"

5. 优点 vs 缺点

优点 缺点
✅ 速度极快(可达 10~100 Mbps) ❌ 引脚多(每从机需独立 CS)
✅ 协议简单,无复杂握手 ❌ 不支持多主设备
✅ 全双工,效率高 ❌ 通信距离短(< 0.5 米)

6. 典型应用

  • SD 卡、Flash 存储器(高速读写)
  • TFT/OLED 显示屏(快速刷屏)
  • 高速 ADC/DAC(模数转换器)

三、I²C 是什么?------ "地址喊话会议"

1. 全称

I nter-I ntegrated C ircuit

(集成电路间总线)

2. 核心特点

特性 说明
同步 由主设备提供时钟(SCL)
半双工 同一时间只能单向传输(像对讲机按住说话)
多主多从 支持多个主设备(但通常只用一个)
地址寻址 每个从设备有唯一地址(7 位或 10 位)

3. 需要几根线?

只需要 2 根

信号线 全称 作用
SDA Serial Data 双向数据线(所有设备共享)
SCL Serial Clock 时钟线(由主设备控制)

优势 :无论接多少设备,都只用这 2 根线!

(当然,每个设备还需接电源和地)

4. 工作流程(以读取温度传感器为例)

  1. 主设备发出 起始信号(SCL 高时,SDA 从高→低)
  2. 主设备发送 从设备地址 + 读写位 (如 0x90 表示写)
  3. 对应地址的从设备 拉低 SDA 回应 ACK(确认收到)
  4. 主设备发送寄存器地址(如 0x00
  5. 主设备再发 重复起始 ,然后发 0x91(读)
  6. 传感器通过 SDA 返回温度值
  7. 主设备发 停止信号(SCL 高时,SDA 从低→高)

5. 关键机制

  • 起始/停止条件:界定一次通信的开始和结束
  • ACK/NACK:每传 1 字节,接收方必须回应确认
  • 开漏输出 + 上拉电阻:避免多个设备同时驱动总线冲突

💡 为什么需要上拉电阻?

因为 I²C 设备只能"拉低"总线,不能"输出高电平"。

所以靠外部 上拉电阻 把 SDA/SCL 拉到高电平,实现"线与"逻辑。

6. 优点 vs 缺点

优点 缺点
✅ 引脚极少(仅 2 根线) ❌ 速度较慢(标准 100kbps,快模式 400kbps)
✅ 支持多设备(靠地址区分) ❌ 协议复杂(起始/停止/ACK/仲裁)
✅ 适合连接大量低速传感器 ❌ 总线负载有限(设备太多会失败)

7. 典型应用

  • 温湿度传感器(DHT20, SHT30)
  • 实时时钟(DS1307)
  • 小容量 EEPROM(AT24C02)
  • IO 扩展芯片(PCF8574)

四、SPI vs I²C 终极对比表

特性 SPI I²C
线数 ≥4 根(SCLK, MOSI, MISO, CS×N) 仅 2 根(SCL, SDA)
速度 极快(10~100 Mbps) 较慢(100kbps ~ 3.4Mbps)
通信方式 全双工(同时收发) 半双工(同一时间单向)
设备选择 硬件片选(CS 拉低) 软件地址(广播地址)
主从结构 单主多从 多主多从(支持仲裁)
协议复杂度 简单(无起始/停止/ACK) 复杂(需处理 ACK、仲裁等)
引脚占用 多(每从机需 1 根 CS) 极少(所有设备共享 2 线)
典型应用 SD卡、显示屏、高速ADC 传感器、RTC、EEPROM

五、生活化比喻(加深理解)

🏭 SPI = 工厂流水线

  • 主设备是 厂长
  • SCLK 是 流水线节拍器
  • MOSI 是 厂长发指令:"装轮胎!"
  • MISO 是 工人回话:"装好了!"
  • CS 是 点名器:"3号工位,准备干活!"

✅ 优点:效率高、速度快

❌ 缺点:工位越多,点名线越长(引脚多)

🪑 I²C = 圆桌会议

  • 主设备是 主持人
  • SCL 是 敲钟:"下一个发言!"
  • SDA 是 唯一麦克风(所有人共用)
  • 每个设备有 工号(地址)
  • 主持人喊:"0x50号,请报温度!"
  • 对应设备拿起麦克风回答,其他人沉默

✅ 优点:节省麦克风(引脚少)

❌ 缺点:不能抢话,速度慢


六、如何选择?------ 一句话口诀

🔥 高速选 SPI,设备多选 I²C

  • 你要连 OLED 屏、SD 卡、Flash ? → 用 SPI
  • 你要连 10 个温湿度传感器、RTC、EEPROM ? → 用 I²C
  • 引脚紧张? → 优先 I²C
  • 要传大量数据(如图像)? → 必须 SPI

七、常见问题解答(FAQ)

Q1:SPI 有没有地址?

A:没有!靠 CS 线硬件选中。所以不能"广播"。

Q2:I²C 地址冲突怎么办?

A:每个 I²C 芯片出厂有固定地址,部分支持通过引脚修改(如 A0/A1)。务必查 datasheet!

Q3:能不能用 GPIO 模拟 SPI/I²C?

A:可以!叫"软件模拟"(bit-banging),但速度慢。硬件 SPI/I²C 更高效。

Q4:为什么 I²C 需要上拉电阻,SPI 不需要?

A:I²C 用开漏输出,靠上拉提供高电平;SPI 用推挽输出,能自己输出高低电平。


八、总结

协议 本质 适用场景
UART 异步串口(无时钟) 调试打印、连蓝牙/WiFi 模块
SPI 同步高速全双工 显示屏、存储器、高速外设
I²C 同步低速地址总线 传感器、RTC、多设备低速通信

✅ 记住:

  • UART:连电脑、调程序
  • SPI:要速度、不怕线多
  • I²C:省引脚、接一堆小设备

现在,你已经掌握了嵌入式三大串行通信协议的核心思想!🎉

下次看到电路板上的传感器,你就知道它大概率是用 I²C 还是 SPI 了!


💡 动手建议

用 Arduino 或 STM32 开发板,分别试试:

  • I²C 读取一个温湿度传感器(如 DHT20)
  • SPI 驱动一个 OLED 屏幕

眼见为实,一试就懂!

他们的代码有什么区别?

Qwen3-Max

这是一个非常关键的问题!UART、SPI 和 I²C 的代码区别 ,本质上反映了它们通信机制的根本不同 。下面我将用 清晰的对比 + 简化代码示例(基于 STM32 风格伪代码) ,从初始化、发送、接收 三个维度,为你逐行解析它们的代码差异,并解释为什么这样写

前提说明

  • 所有代码均为简化教学版,省略错误处理和寄存器细节
  • 假设使用硬件外设(非 GPIO 模拟)
  • 目标平台:STM32(但逻辑适用于大多数 MCU)

一、核心差异速览表

特性 UART SPI I²C
同步/异步 异步(无时钟线) 同步(主设备提供 SCLK) 同步(主设备提供 SCL)
数据线 TX, RX(独立) MOSI, MISO(独立) SDA(双向共享)
设备选择 无(点对点) CS 片选(硬件控制) 地址(软件发送)
通信流程 发就完事 先拉低 CS → 发数据 → 拉高 CS 起始 → 地址 → 数据 → 停止
典型函数 uart_send(data) spi_write(addr, data) i2c_write(slave_addr, reg, data)

二、代码对比详解

📌 场景设定

我们要向一个外设写入一个字节 0x55

  • UART:直接发给串口助手(点对点)
  • SPI:写入 Flash 芯片的某个寄存器
  • I²C:写入 EEPROM 的某个地址

1. 初始化代码对比

🔹 UART 初始化
复制代码
void uart_init(void) {
    // 1. 使能时钟(GPIO + USART)
    RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
    
    // 2. 配置 TX/RX 引脚为复用推挽
    GPIOA->CRH &= ~0xFF0;          // 清除 PA9, PA10 配置
    GPIOA->CRH |= 0x4B0;           // PA9=AF_PP, PA10=IN_FLOATING
    
    // 3. 设置波特率(115200)、8N1
    USART1->BRR = 0x271;           // 72MHz / 16 / 115200 ≈ 39 = 0x27
    USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; // 使能收发
}

关键点

  • 只需配置波特率(双方必须一致)
  • 无时钟线,所以不涉及 SCLK/SCL
  • 引脚方向固定:TX 输出,RX 输入

🔹 SPI 初始化
复制代码
void spi_init(void) {
    // 1. 使能时钟(GPIO + SPI)
    RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
    
    // 2. 配置 SCLK/MOSI/MISO 为复用推挽(PA5/6/7)
    GPIOA->CRL &= ~0xFFF00000;
    GPIOA->CRL |= 0xB4400000;      // SCK=AF_PP, MISO=IN_FLOAT, MOSI=AF_PP
    
    // 3. 配置 CS 引脚(PA4)为普通推挽输出
    GPIOA->CRL &= ~0xF0000000;
    GPIOA->CRL |= 0x30000000;      // PA4=OUT_PP
    GPIOA->BSRR = GPIO_BSRR_BS4;   // 默认拉高(不选中)
    
    // 4. 配置 SPI 主机模式、时钟极性等
    SPI1->CR1 = SPI_CR1_MSTR |     // 主机模式
                 SPI_CR1_BR_1 |    // 分频 fPCLK/8
                 SPI_CR1_SSM |     // 软件管理 NSS
                 SPI_CR1_SSI;      // 内部 NSS 高
    SPI1->CR1 |= SPI_CR1_SPE;      // 使能 SPI
}

关键点

  • 必须配置 SCLK 时钟参数(分频、极性 CPOL/相位 CPHA)
  • CS 引脚由 GPIO 控制(不是 SPI 外设自动管)
  • MOSI/MISO 方向固定

🔹 I²C 初始化
复制代码
void i2c_init(void) {
    // 1. 使能时钟(GPIO + I2C)
    RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
    
    // 2. 配置 SCL/SDA 为开漏输出 + 上拉
    GPIOB->CRH &= ~0xFF000000;
    GPIOB->CRH |= 0x88000000;      // PB6/7 = AF_OD (开漏)
    // 注意:外部需接上拉电阻!
    
    // 3. 配置 I2C 时钟频率(100kHz)
    I2C1->CR2 = 36;                // PCLK1 = 36MHz
    I2C1->CCR = 180;               // 标准模式: T_low = T_high = 5us
    I2C1->TRISE = 37;              // 最大上升时间 = 1000ns
    
    // 4. 使能 I2C
    I2C1->CR1 |= I2C_CR1_PE;
}

关键点

  • 必须配置时钟频率(通过 CCR/TRISE 计算)
  • GPIO 必须设为 开漏(Open-Drain)
  • 依赖外部上拉电阻(代码无法体现,但硬件必须有)

2. 发送数据代码对比

🔹 UART 发送(最简单)
复制代码
void uart_send(uint8_t data) {
    while (!(USART1->SR & USART_SR_TXE)); // 等待发送缓冲区空
    USART1->DR = data;                    // 写入数据,自动发送
}
// 使用:uart_send(0x55);

特点

  • 无需握手,写入即发
  • 无目标地址(默认发给对方)

🔹 SPI 发送(需控制 CS)
复制代码
void spi_write(uint8_t data) {
    while (!(SPI1->SR & SPI_SR_TXE)); // 等待发送缓冲区空
    SPI1->DR = data;                  // 写入数据
    while (SPI1->SR & SPI_SR_BSY);    // 等待传输完成
}

// 完整写操作(以 Flash 为例)
void flash_write_enable(void) {
    GPIOA->BRR = GPIO_BRR_BR4;  // 拉低 CS(选中 Flash)
    spi_write(0x06);            // 发送 "Write Enable" 命令
    GPIOA->BSRR = GPIO_BSRR_BS4; // 拉高 CS(结束通信)
}
// 使用:flash_write_enable();

特点

  • 必须手动控制 CS(拉低开始,拉高结束)
  • 全双工:每发一个字节,MISO 也会返回一个字节(即使不用)

🔹 I²C 发送(需起始/地址/ACK/停止)
复制代码
void i2c_start(void) {
    I2C1->CR1 |= I2C_CR1_START;        // 产生起始条件
    while (!(I2C1->SR1 & I2C_SR1_SB)); // 等待起始完成
}

void i2c_stop(void) {
    I2C1->CR1 |= I2C_CR1_STOP;         // 产生停止条件
}

uint8_t i2c_write_byte(uint8_t data) {
    I2C1->DR = data;                   // 写入数据
    while (!(I2C1->SR1 & I2C_SR1_BTF)); // 等待传输完成
    return I2C1->SR1 & I2C_SR1_AF ? 1 : 0; // 检查 ACK(0=ACK, 1=NACK)
}

// 完整写操作(以 EEPROM 为例)
void eeprom_write(uint8_t slave_addr, uint8_t reg, uint8_t data) {
    i2c_start();
    i2c_write_byte(slave_addr << 1);   // 发送 7 位地址 + 写标志(bit0=0)
    i2c_write_byte(reg);               // 发送寄存器地址
    i2c_write_byte(data);              // 发送数据
    i2c_stop();
}
// 使用:eeprom_write(0xA0, 0x00, 0x55);

特点

  • 必须发送从设备地址(7 位左移 + R/W 位)
  • 每字节后需检查 ACK(硬件自动处理,但可读状态)
  • 起始/停止条件是协议核心

三、为什么代码会这样设计?------ 回到协议本质

协议 代码特点 原因
UART 直接写 DR 寄存器 异步通信,无时钟、无地址、点对点
SPI 手动控制 CS + 全双工收发 同步通信,靠 CS 选设备,MOSI/MISO 独立
I²C 起始/地址/ACK/停止 共享总线,靠地址寻址,需仲裁和确认

四、总结:一眼识别代码类型

当你看到一段通信代码,可以这样判断:

  • 如果只有 send(data),没有地址、没有 CS、没有起始信号UART
  • 如果有 CS_LOW() / CS_HIGH() 包裹发送函数SPI
  • 如果函数里有 start()stop()addr<<1、检查 ACKI²C

五、给初学者的建议

  1. 先掌握 UART:代码最简单,用于调试,建立信心。
  2. 再学 SPI:理解"片选"概念,适合驱动显示屏、SD卡。
  3. 最后攻克 I²C:重点理解"起始/停止"和"地址",多看波形图。
  4. 善用逻辑分析仪:亲眼看到 SDA/SCL 或 MOSI/MISO 的波形,代码瞬间变直观!

💡 记住
代码是协议的影子

理解了 UART/SPI/I²C 的物理连接和时序图,代码自然就懂了!

希望这篇对比能帮你彻底分清三者的代码差异!如有具体芯片(如 STM32、ESP32、Arduino)的代码需求,也可以告诉我,我可以给出更针对性的例子。

还有can协议呢?

Qwen3-Max

太好了!你已经掌握了 UART、SPI、I²C ,现在我们来认识工业与汽车电子领域的"通信王者"------CAN 协议(Controller Area Network)

下面这篇讲解专为初学者设计,用清晰的逻辑、生活化比喻和代码对比,帮你彻底搞懂:

  • CAN 是什么?为什么汽车和工厂都用它?
  • 它和 UART/SPI/I²C 有什么本质区别?
  • CAN 的代码长什么样?为什么更复杂?

🌟 CAN 协议完全入门指南(给嵌入式新手)

适合人群 :学过 UART/SPI/I²C,想了解工业/汽车通信的新手
目标:读完后你能回答------

  • CAN 为什么比 UART 更可靠?
  • "ID 不是地址"是什么意思?
  • 为什么 CAN 代码要配"滤波器"和"邮箱"?

一、先说结论(一句话记住)

CAN 不是点对点通信,而是一个"广播会议"

所有设备都在听,但只处理自己关心的消息。

消息用 ID 标识优先级 (不是地址),自动仲裁 + 错误重传,确保关键数据永不丢失!


二、为什么需要 CAN?------ UART 的致命缺陷

想象一辆汽车:

  • 发动机 ECU 要发"当前转速"给仪表盘
  • ABS 系统要发"车轮打滑"给车身控制模块
  • 空调要发"温度设定"给中控

如果用 UART

  • 需要无数根线(发动机→仪表、ABS→车身...)
  • 如果一根线断了,整个系统瘫痪
  • 多个设备同时发?数据冲突!

CAN 的解决方案

  • 所有设备挂到同一对双绞线(CAN_H / CAN_L)
  • 所有消息广播发送
  • 每个消息带一个 ID(如 0x201)
  • ID 越小,优先级越高(0x100 比 0x200 先发)
  • 自动检测错误并重发

结果

  • 线少、成本低
  • 抗干扰强(差分信号)
  • 关键消息(如刹车)永远优先

三、CAN 的核心特点(vs UART/SPI/I²C)

特性 UART SPI I²C CAN
拓扑 点对点 星型(主从) 总线(多从) 总线(多主)
地址 CS 片选 7/10 位地址 ID = 优先级(非地址)
同步 异步 同步 同步 异步(但有位同步)
错误处理 ACK/NACK CRC + 自动重传 + 故障隔离
物理层 TTL/RS232 单端 开漏+上拉 差分(CAN_H/CAN_L)
典型速率 ≤115kbps ≤100Mbps ≤3.4Mbps ≤1Mbps(经典 CAN)

🔥 最大区别

  • UART/SPI/I²C:"我要发给谁"
  • CAN:"这是什么类型的消息"(所有节点自己判断要不要)

四、CAN 帧结构(以标准帧为例)

一帧 CAN 数据包含:

复制代码
[SOF] [ID(11bit)] [RTR] [IDE] [DLC] [Data(0~8字节)] [CRC] [ACK] [EOF]
字段 说明
SOF 帧起始(1 位显性)
ID 11 位标识符(决定优先级,数值越小优先级越高)
RTR 远程请求位(0=数据帧,1=请求数据)
DLC 数据长度(0~8 字节)
Data 实际数据(最多 8 字节!)
CRC 15 位校验码(硬件自动生成/校验)
ACK 接收方应答(正确接收则拉低)

关键限制每帧最多 8 字节数据

(所以不适合传大文件,但非常适合传传感器状态、控制指令)


五、CAN 代码 vs UART/SPI/I²C ------ 为什么更复杂?

📌 场景:发送一条"车速 = 60 km/h"的消息

🔹 UART 代码(简单粗暴)
复制代码
uart_send(60); // 直接发,对方必须知道这是车速
🔹 SPI 代码(需选设备)
复制代码
cs_low();
spi_write(CMD_SET_SPEED);
spi_write(60);
cs_high();
🔹 I²C 代码(需地址)
复制代码
i2c_write(0x50, SPEED_REG, 60);
🔹 CAN 代码(完整流程)
复制代码
// 1. 定义消息头(重点:ID 和 DLC)
CAN_TxHeaderTypeDef tx_header;
tx_header.StdId = 0x201;        // 车速消息 ID(行业约定)
tx_header.IDE = CAN_ID_STD;     // 标准帧(11位ID)
tx_header.RTR = CAN_RTR_DATA;   // 数据帧
tx_header.DLC = 1;              // 1字节数据

// 2. 准备数据
uint8_t data = 60;

// 3. 发送到发送邮箱(硬件自动处理总线仲裁)
uint32_t mail_box;
if (HAL_CAN_AddTxMessage(&hcan, &tx_header, data, &mail_box) != HAL_OK) {
    Error_Handler(); // 发送失败(邮箱满等)
}

关键差异

  • 不指定"发给谁" ,只指定 "这是什么消息"(ID=0x201)
  • 硬件自动处理:仲裁、CRC、ACK、重传
  • 发送成功 ≠ 对方收到(因为是广播)

📌 接收代码:靠"滤波器"筛选消息

CAN 节点会收到所有消息 ,但通常只关心几类。

所以需要配置 硬件滤波器,避免 CPU 被无关消息打扰。

复制代码
// 配置滤波器:只接收 ID=0x201(车速)和 0x202(油量)的消息
CAN_FilterTypeDef filter;
filter.FilterBank = 0;
filter.FilterMode = CAN_FILTERMODE_IDMASK;      // ID + 掩码模式
filter.FilterScale = CAN_FILTERSCALE_32BIT;
filter.FilterIdHigh = ((0x201 << 5) & 0xFFFF);  // ID 左移 5 位(STM32要求)
filter.FilterMaskIdHigh = ((0x7FF << 5) & 0xFFFF); // 掩码:全匹配
filter.FilterFIFOAssignment = CAN_RX_FIFO0;
filter.FilterActivation = ENABLE;

HAL_CAN_ConfigFilter(&hcan, &filter);

// 启动接收中断
HAL_CAN_Start(&hcan);
HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING);

// 回调函数(当收到匹配消息时触发)
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) {
    CAN_RxHeaderTypeDef rx_header;
    uint8_t rx_data[8];
    
    // 从 FIFO 读取消息
    HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rx_header, rx_data);
    
    if (rx_header.StdId == 0x201) {
        printf("收到车速: %d km/h\n", rx_data[0]);
    }
}

为什么需要滤波器?

想象总线上有 100 个设备,每秒发 1000 条消息。

如果不滤波,CPU 会被中断打爆!
硬件滤波器在数据进 RAM 前就过滤掉无关消息,极大减轻 CPU 负担。


六、CAN 的独特机制(代码背后的原理)

1. 非破坏性仲裁

  • 多个节点同时发?ID 小的胜出
  • 仲裁过程中,输的一方自动停止发送,转为接收
  • 无数据冲突,且高优先级消息零延迟

2. 错误检测与恢复

  • 每个节点监控总线
  • 发现错误(位错误、CRC 错误等)→ 发送 错误帧
  • 发送方自动重发,直到成功

3. 故障封闭

  • 如果某个节点持续出错,会被自动离线(Bus Off)
  • 不影响其他节点通信

七、CAN vs 其他协议 ------ 何时使用?

场景 推荐协议
调试打印、连电脑 UART
高速读写 Flash/SD卡 SPI
连多个传感器(温湿度、RTC) I²C
汽车电子、工业控制、多节点实时通信 ✅ CAN

💡 记住

  • 高可靠、多节点、抗干扰 → 选 CAN
  • 传大量数据 → CAN 不合适(只有 8 字节/帧),考虑 CAN FD (64 字节)或 Ethernet

八、总结:CAN 代码的核心思想

概念 说明
ID 不是地址 是消息类型 + 优先级
广播通信 所有节点都能收到,靠滤波器筛选
硬件处理底层 仲裁、CRC、ACK 由 CAN 控制器自动完成
邮箱/FIFO 发送用"邮箱",接收用"FIFO 队列"
滤波器必备 避免 CPU 被无关消息淹没

九、给初学者的建议

  1. 先理解"ID 优先级"和"广播"概念,再看代码
  2. 用 CAN 分析仪或逻辑分析仪看真实波形(显性/隐性电平)
  3. 从 STM32 HAL 库示例入手 (如 CAN_Networking
  4. 不要试图用 GPIO 模拟 CAN(时序要求太高,必须用硬件控制器)

🚗 终极比喻

  • UART = 两个人打电话
  • SPI = 老板对员工下命令(点名)
  • I²C = 会议室按工号发言
  • CAN = 工厂广播系统
    "注意!生产线紧急停机(ID=0x100)!" ------ 所有工人都听到,但只有产线工人行动!

现在,你已经掌握了嵌入式四大串行通信协议(UART/SPI/I²C/CAN)的核心思想!🎉

下次看到汽车或工业设备,你就知道它们内部是如何"对话"的了!

rs232,rs485,rs422。还有uart,spi,i2c,can。我全部弄混了

Qwen3-Max

别担心!这是嵌入式通信初学者最常遇到的困惑。你不是一个人------几乎所有工程师都曾把它们搞混过。

下面我用一张 终极对比表 + 一句话口诀 + 生活化比喻 ,帮你彻底理清这 7 个概念(RS232/485/422 + UART/SPI/I2C/CAN) 的关系,从此不再混淆!


🌟 一、先划重点:它们根本不在一个"维度"上!

UART、SPI、I2C、CAN 是「通信协议」 (规定数据怎么打包、怎么传输)

RS232、RS485、RS422 是「物理电平标准」(规定用多少电压、几根线传信号)

🔑 关键理解:

  • UART 是协议 ,但它需要物理层 来传输 → 可以用 TTL 电平 (板内),也可以用 RS232/RS422/RS485 电平(远距离)
  • SPI/I2C/CAN 通常只用 TTL 电平(短距离板内通信),但 CAN 也有自己的差分物理层

💡 类比

  • 协议 = 语言(中文、英语)
  • 电平 = 嗓门/工具 (小声说、用喇叭喊、用手语)
    你可以说中文(UART),但可以用普通声音(TTL),也可以用扩音器(RS485)

📊 二、终极对比表(按用途分类)

类型 名称 本质 典型用途 线数 距离 速度 特点
串行协议 UART 异步串行协议 调试打印、连蓝牙/WiFi 2~3 <15m (TTL) ≤1200m (RS485) ≤115kbps 点对点,简单
SPI 同步全双工协议 Flash、SD卡、显示屏 ≥4 <0.5m ≤100Mbps 高速,引脚多
I2C 同步半双工总线 传感器、RTC、EEPROM 2 <0.5m ≤3.4Mbps 引脚少,地址寻址
CAN 多主广播总线 汽车、工业控制 2(差分) ≤1km ≤1Mbps 高可靠,自动仲裁
物理电平 TTL 芯片电平 板内芯片互联 - <0.5m 0V/3.3V
RS232 单端高电压 老式电脑串口 3 ≤15m ≤115kbps ±12V,负逻辑
RS422 差分全双工 工业长距离通信 4+GND ≤1200m ≤10Mbps 抗干扰强,1发多收
RS485 差分半双工 Modbus、PLC网络 2+GND ≤1200m ≤10Mbps 多点通信,最常用

记住

  • RS422 和 RS485 都是差分,抗干扰强,适合工业
  • RS485 比 RS422 更常用(支持多主,成本低)

🧩 三、它们如何组合使用?

场景 1:你的开发板调试

复制代码
STM32 (UART协议 + TTL电平) 
    → [USB转TTL模块] 
    → 电脑

✅ 这就是最常见的 printf 调试

场景 2:工业设备通信

复制代码
PLC (UART协议 + RS485电平) 
    ↔ 双绞线 
    ↔ 传感器 (UART协议 + RS485电平)

✅ 虽然底层是 UART 协议,但用了 RS485 电平传得远

场景 3:汽车内部通信

复制代码
发动机ECU (CAN协议 + CAN差分电平) 
    ↔ 双绞线 
    ↔ 仪表盘 (CAN协议 + CAN差分电平)

✅ CAN 协议自带差分物理层,不依赖 RSxxx


🗣️ 四、一句话口诀(背下来!)

"协议四兄弟:UART 异步,SPI 快,I2C 省线,CAN 最稳;
电平三剑客:RS232 老,RS422 全双工,RS485 最通用。"


🏙️ 五、生活化比喻(彻底分清)

协议/电平 比喻 为什么?
UART + TTL 两个人面对面小声说话 距离近,简单直接
UART + RS232 用老式电话线打电话 距离中等,但线粗笨重
UART + RS485 对讲机群聊(轮流说话) 多人可用,声音大传得远
SPI 工厂流水线(老板一对一指挥) 高速高效,但每人需专线
I2C 会议室按工号发言 省麦克风(引脚),但要排队
CAN 消防警报系统 所有人都听,火警(高优先级)插队播报

❓ 六、常见混淆点澄清

❌ 混淆 1:"RS232 就是串口"

✅ 正解:

  • "串口"是统称,UART 是串口的一种实现
  • RS232 是 UART 在老电脑上的物理接口标准

❌ 混淆 2:"RS485 是一种协议"

✅ 正解:

  • RS485 只是电平标准 ,上面跑的还是 UART 协议(或自定义协议)
  • 真正的协议是 Modbus RTU(基于 UART)

❌ 混淆 3:"CAN 和 RS485 一样"

✅ 正解:

  • RS485:物理层,需上层协议(如 Modbus)
  • CAN:完整协议栈(含仲裁、错误处理),自带物理层

🛠️ 七、实际选型建议

你的需求 推荐方案
调试程序、打印日志 UART + USB转TTL
连 OLED 屏、SD 卡 SPI
接 5 个温湿度传感器 I2C
工厂里连 10 台设备(距离 100 米) UART + RS485
汽车、机器人、高可靠性系统 CAN
老设备对接(如 90 年代仪器) UART + RS232

✅ 八、总结:一张图理清所有关系

复制代码
                     ┌───────────────┐
                     │   通信协议    │
                     └───────────────┘
                            │
        ┌───────────────────┼───────────────────┐
        │                   │                   │
┌───────▼───────┐   ┌───────▼───────┐   ┌───────▼───────┐
│    UART       │   │     SPI       │   │     I2C       │
└───────┬───────┘   └───────────────┘   └───────────────┘
        │
        ▼
┌───────────────┐
│ 物理电平层    │
└───────────────┘
        │
        ├─ TTL (0V/3.3V) → 板内短距离
        ├─ RS232 (±12V) → 老设备
        ├─ RS422 (差分) → 1发多收,全双工
        └─ RS485 (差分) → 多点通信,半双工(最常用)

┌───────────────┐
│     CAN       │ ← 自带差分物理层,不依赖 RSxxx
└───────────────┘

现在,你应该能清晰回答:

  • UART 是什么? → 异步串行通信协议
  • RS485 是什么? → 差分电平标准,用于延长 UART 通信距离
  • SPI 和 I2C 区别? → SPI 快但费引脚,I2C 慢但省引脚
  • CAN 为什么特殊? → 它是唯一自带"交通规则"(仲裁+错误处理)的协议

💪 记住
协议决定"说什么",电平决定"怎么喊"

理解了这个核心,你就再也不会混淆了!

如果还有不清楚的地方,欢迎继续问!比如:"我想连一个 Modbus 传感器,该用什么?" ------ 我可以给你具体接线和代码建议 😊

相关推荐
gugugu.8 小时前
Redis 字符串类型完全指南:从原理到实战应用
数据库·redis·缓存
杨云龙UP8 小时前
MySQL 自动备份与覆盖恢复实战:一套脚本搞定全库/按库备份恢复
linux·运维·数据库·sql·mysql
workflower9 小时前
PostgreSQL 数据库优化
数据库·团队开发·数据库开发·时序数据库·数据库架构
计算机毕设VX:Fegn089510 小时前
计算机毕业设计|基于springboot + vue服装商城系统(源码+数据库+文档)
数据库·vue.js·spring boot·课程设计
WX-bisheyuange11 小时前
基于Spring Boot的智慧校园管理系统设计与实现
java·大数据·数据库·毕业设计
JavaGuide11 小时前
对标MinIO!全新一代分布式文件系统诞生!
数据库·后端
快乐非自愿11 小时前
数据库如何处理大量的交易流水记录
数据库·oracle
IvorySQL12 小时前
瀚高硬核助力 PG 社区:Postgres 19 迎来并行 TID 范围扫描,速度提升 3 倍
数据库·postgresql·开源
ServBay12 小时前
MongoDB 的文档模型与 CRUD 实战
数据库·后端·mongodb
ITMr.罗12 小时前
深入理解EF Core更新机制(开发中因为省事遇到的问题)
服务器·数据库·c#·.net