2、硬件接口入门:GPIO、I2C、SPI、UART通信协议原理与区别,树莓派/ESP32引脚图解读

好,咱们今天聊点硬核的。很多朋友刚开始接触嵌入式,看到板子上密密麻麻的引脚就头大。我当年也一样,拿着树莓派和ESP32的引脚图,愣是看了半天没敢下手。

其实没那么玄乎。你想想看,传感器和主控芯片之间怎么说话?靠的就是这些硬件接口。今天我就把GPIO、I2C、SPI、UART这四种最常用的协议,掰开了揉碎了讲清楚。

2.1 GPIO:最基础的“开关”

GPIO,全称是General Purpose Input Output,通用输入输出口。说白了,它就是芯片上的一个引脚,你可以控制它输出高电平(3.3V或5V)或低电平(0V),也可以读取它当前的电平状态。

我在项目中遇到过最典型的场景:用GPIO控制一个LED灯。代码里写pin.write(1),灯就亮了;写pin.write(0),灯就灭了。就这么简单。

核心要点:

  • 输出模式:控制引脚输出高/低电平
  • 输入模式:读取引脚当前电平(0或1)
  • 上拉/下拉:防止引脚悬空时电平不稳定

我的小技巧:GPIO驱动能力有限,一般只能输出几毫安电流。想驱动大功率设备(比如电机),必须加驱动芯片或三极管。我曾经直接拿GPIO推一个继电器,结果芯片烧了……嗯,学费交得有点贵。

2.2 UART:最古老的“串口”

UART,Universal Asynchronous Receiver/Transmitter,通用异步收发器。这是最古老的通信方式之一,但至今仍在大量使用。

它只需要两根线:TX(发送)和RX(接收)。注意,设备A的TX要接设备B的RX,交叉连接。我刚开始做的时候,经常把TX和TX接一起,结果啥反应没有,还以为是代码写错了。

UART的通信参数有四个:波特率、数据位、停止位、校验位。最常见的是9600波特率、8数据位、1停止位、无校验,简写为9600-8-N-1。

避坑指南:我曾经在调试一个GPS模块时,怎么都收不到数据。折腾了两小时,最后发现是波特率设错了。模块默认是115200,我代码里写的是9600。所以,拿到新模块第一件事:看数据手册,确认默认波特率。

2.3 I2C:多设备“总线”

I2C,Inter-Integrated Circuit,集成电路间总线。它最大的特点是:只用两根线(SDA数据线、SCL时钟线),就能挂载多个设备。

每个I2C设备都有一个唯一的地址,比如7位地址范围是0x00到0x7F。主设备通过地址来寻址,想跟谁说话就叫谁。

我特别喜欢I2C的一点:它支持多主设备。不过实际项目中,我基本只用单主设备模式,省心。

I2C通信流程:

  1. 主设备发送起始信号
  2. 主设备发送从设备地址+读写位
  3. 从设备应答(ACK)
  4. 数据传输(每字节后跟一个ACK)
  5. 主设备发送停止信号

我的经验:I2C总线上需要上拉电阻,一般4.7kΩ或10kΩ。如果距离较长或设备较多,可以适当减小上拉电阻值。我有个项目挂了8个传感器,上拉电阻从10k换到4.7k才稳定。

2.4 SPI:高速“全双工”

SPI,Serial Peripheral Interface,串行外设接口。它比I2C快得多,而且支持全双工通信(可以同时收发数据)。

SPI需要四根线:

  • SCLK:时钟线,由主设备产生
  • MOSI:主设备输出,从设备输入
  • MISO:主设备输入,从设备输出
  • SS/CS:片选线,每个从设备一根

你想想看,SPI的片选线是独立的,所以每增加一个设备,就要多占用一个GPIO。这也是SPI的缺点——设备多了,引脚不够用。

注意:SPI有四种模式(CPOL和CPHA的组合),不同设备可能要求不同模式。我踩过这个坑:一个LCD屏幕死活不显示,后来发现是SPI模式设错了。数据手册上写的是Mode 0,我代码里配的是Mode 3。

2.5 四种协议对比

特性 GPIO UART I2C SPI
引脚数 1根 2根 2根 4根+
通信方式 并行 异步串行 同步串行 同步串行
速度 取决于软件 慢(最高约1Mbps) 中(最高约3.4Mbps) 快(最高几十Mbps)
设备数量 1对1 1对1 多设备(地址区分) 多设备(片选区分)
典型应用 按键、LED GPS模块、蓝牙 温湿度传感器、OLED SD卡、LCD屏

2.6 树莓派和ESP32引脚图解读

好了,理论讲完了,咱们看看实物。树莓派和ESP32的引脚图,我建议你打印出来贴在桌上,调试时随时看。

树莓派(以Pi 4 Model B为例)

树莓派的40针GPIO排针,布局很规整。我个人习惯把板子USB口朝下,这样左上角就是3.3V,右上角是5V。

  • 物理引脚1和17:3.3V
  • 物理引脚2和4:5V
  • 物理引脚6、9、14、20、25、30、34、39:GND
  • I2C:物理引脚3(SDA)、5(SCL)
  • SPI:物理引脚19(MOSI)、21(MISO)、23(SCLK)、24(CE0)、26(CE1)
  • UART:物理引脚8(TX)、10(RX)

注意:树莓派的GPIO编号有两种:物理引脚编号(1-40)和BCM编号(GPIO0-GPIO27)。编程时用BCM编号,但接线时看物理引脚。我刚开始经常搞混,后来养成习惯:代码里写BCM编号,接线时看物理引脚图。

ESP32(以ESP32-DevKitC为例)

ESP32的引脚比树莓派更灵活,很多引脚可以复用。但也正因为灵活,容易踩坑。

  • ADC:GPIO32-GPIO39(注意GPIO34-39只能输入,不能输出)
  • DAC:GPIO25、GPIO26
  • I2C:默认GPIO21(SDA)、GPIO22(SCL),但可以任意指定
  • SPI:默认VSPI(GPIO23 MOSI、GPIO19 MISO、GPIO18 SCLK、GPIO5 CS)
  • UART:UART0(GPIO1 TX、GPIO3 RX),UART1(GPIO10 TX、GPIO9 RX),UART2(GPIO17 TX、GPIO16 RX)

ESP32特别提醒:

  • GPIO6-GPIO11连接了Flash芯片,不要乱用
  • GPIO0在启动时拉低会进入下载模式
  • GPIO2在启动时拉高才能正常启动

我曾经在GPIO0上接了一个按键,结果每次上电都进入下载模式,折腾了半天才发现问题。

2.7 实战建议:如何选择通信协议?

好了,四种协议都讲完了。你可能会问:那我该用哪个?

我的建议很简单:

  • 控制单个设备(LED、继电器):用GPIO
  • 简单数据传输(GPS、蓝牙):用UART
  • 挂载多个低速传感器(温湿度、气压):用I2C
  • 高速数据传输(摄像头、SD卡、LCD):用SPI

嗯,其实没有绝对的好坏。我在一个项目里同时用了I2C和SPI:I2C挂温湿度传感器和气压计,SPI接SD卡存数据。各取所长,才是王道。

下一章,咱们就动手写代码,让树莓派和ESP32真正跑起来。到时候你会觉得,这些协议其实没那么神秘。