从Arduino到树莓派:手把手教你玩转UART、IIC、SPI通信(附代码)
从Arduino到树莓派:三大通信协议实战指南
在开源硬件领域,UART、IIC和SPI就像电子设备之间的三种"语言",让不同模块能够相互理解、协同工作。无论是Arduino Uno的简单易用,还是树莓派Pico/4B的强大性能,掌握这些通信协议都是硬件开发的必修课。本文将带您从接线到代码,亲手实现OLED显示、RFID读取和上下位机通信等实际项目,让抽象的理论变成看得见的成果。
1. UART通信:硬件界的通用语言
UART(Universal Asynchronous Receiver/Transmitter)是最基础的异步串行通信协议,几乎存在于所有微控制器中。它的魅力在于只需要两根线(TX和RX)就能建立设备间的对话。
1.1 硬件连接要点
在Arduino Uno上使用UART时,需要注意:
- 0号(RX)和1号(TX)引脚默认用于串口通信
- 与电脑通信时,板载USB转串口芯片会自动处理电平转换
- 与其他3.3V设备通信时,建议使用逻辑电平转换器
树莓派Pico的UART引脚配置更为灵活:
# Pico的UART0默认引脚 UART0_TX = GP0 UART0_RX = GP1 # UART1默认引脚 UART1_TX = GP4 UART1_RX = GP5注意:连接两个设备的UART时,切记TX要接RX,RX要接TX,这是新手最容易犯的错误。
1.2 代码实现对比
Arduino端的串口初始化非常简单:
void setup() { Serial.begin(115200); // 设置波特率为115200 } void loop() { if(Serial.available()) { String received = Serial.readString(); Serial.print("Echo: "); Serial.println(received); } }树莓派Pico使用MicroPython的实现:
from machine import UART, Pin import time uart = UART(0, baudrate=115200, tx=Pin(0), rx=Pin(1)) while True: if uart.any(): data = uart.read() print("Received:", data) uart.write(b"Echo: " + data) time.sleep(0.1)2. IIC协议:优雅的双线解决方案
IIC(Inter-Integrated Circuit)以其简洁的两线制(SDA和SCL)闻名,特别适合连接多个低速外设。以下是IIC的三大优势:
- 节省引脚:理论上可连接128个设备(通过7位地址)
- 内置冲突检测:多主机架构也不会导致总线混乱
- 广泛支持:从温度传感器到显示屏,各类模块都有IIC版本
2.1 OLED显示屏实战
以常见的SSD1306 OLED屏为例,接线非常简单:
| OLED引脚 | Arduino Uno | 树莓派Pico |
|---|---|---|
| VCC | 3.3V | 3V3 |
| GND | GND | GND |
| SCL | A5 | GP1 |
| SDA | A4 | GP0 |
Arduino驱动OLED的核心代码:
#include <Wire.h> #include <Adafruit_SSD1306.h> Adafruit_SSD1306 display(128, 64, &Wire); void setup() { Wire.begin(); display.begin(SSD1306_SWITCHCAPVCC, 0x3C); display.clearDisplay(); display.setTextSize(1); display.setTextColor(WHITE); display.setCursor(0,0); display.println("Hello Arduino!"); display.display(); }树莓派Pico的MicroPython实现:
from machine import Pin, I2C import ssd1306 i2c = I2C(0, scl=Pin(1), sda=Pin(0), freq=400000) oled = ssd1306.SSD1306_I2C(128, 64, i2c) oled.text("Hello Pico!", 0, 0) oled.show()2.2 IIC地址扫描技巧
当不确定设备地址时,可以使用扫描功能:
# 树莓派Pico扫描IIC设备 devices = i2c.scan() if len(devices) == 0: print("No I2C devices found!") else: print("I2C devices found:", [hex(x) for x in devices])3. SPI协议:高速数据传输之王
SPI(Serial Peripheral Interface)是三大协议中速度最快的,特别适合需要高速数据传输的场景,如SD卡、显示屏和无线模块。
3.1 SPI的四线制解析
SPI使用四条主线:
- SCK:时钟信号,由主机产生
- MOSI:主机输出,从机输入
- MISO:主机输入,从机输出
- SS/CS:片选信号,每个从机单独一条
Arduino Uno的默认SPI引脚:
- SCK - 13
- MOSI - 11
- MISO - 12
- SS - 10
树莓派Pico的SPI配置:
from machine import SPI spi = SPI(0, baudrate=1000000, polarity=0, phase=0, sck=Pin(2), mosi=Pin(3), miso=Pin(4))3.2 RFID模块实战
以MFRC522 RFID模块为例,典型接线如下:
| MFRC522引脚 | Arduino Uno | 树莓派Pico |
|---|---|---|
| SDA(SS) | 10 | GP5 |
| SCK | 13 | GP2 |
| MOSI | 11 | GP3 |
| MISO | 12 | GP4 |
| IRQ | 未连接 | 未连接 |
| GND | GND | GND |
| RST | 9 | GP1 |
| 3.3V | 3.3V | 3V3 |
Arduino读取RFID卡的代码片段:
#include <SPI.h> #include <MFRC522.h> #define RST_PIN 9 #define SS_PIN 10 MFRC522 mfrc522(SS_PIN, RST_PIN); void setup() { SPI.begin(); mfrc522.PCD_Init(); Serial.begin(115200); } void loop() { if(!mfrc522.PICC_IsNewCardPresent()) return; if(!mfrc522.PICC_ReadCardSerial()) return; Serial.print("UID:"); for(byte i=0; i<mfrc522.uid.size; i++) { Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "); Serial.print(mfrc522.uid.uidByte[i], HEX); } Serial.println(); }4. 协议对比与项目选择指南
三大通信协议各有特点,选择时需考虑以下因素:
| 特性 | UART | IIC | SPI |
|---|---|---|---|
| 线数 | 2(TX/RX) | 2(SDA/SCL) | 4(标准) |
| 速度 | 中等 | 慢 | 快 |
| 寻址方式 | 无 | 7/10位地址 | 片选信号 |
| 多设备支持 | 点对点 | 多从机 | 多从机 |
| 复杂度 | 简单 | 中等 | 较高 |
项目选择建议:
- 传感器数据采集 → IIC(节省引脚)
- 高速数据传输 → SPI(如摄像头、显示屏)
- 设备间简单通信 → UART(调试、日志输出)
- 长距离通信 → RS485(UART的工业级变种)
在实际项目中,我经常同时使用这三种协议。比如一个气象站可能这样配置:
- 使用IIC连接温湿度传感器(BME280)
- 通过SPI驱动无线模块(nRF24L01)
- 利用UART输出调试信息到电脑
调试通信问题时,逻辑分析仪是得力助手。它能直观显示时序波形,帮助定位波特率不匹配、信号干扰等问题。如果没有专业设备,也可以先用简单的串口打印调试信息。
