当前位置: 首页 > news >正文

从Arduino到树莓派:手把手教你玩转UART、IIC、SPI通信(附Python/C++代码示例)

从Arduino到树莓派:三大通信协议实战指南

在开源硬件领域,UART、IIC和SPI如同三位性格迥异的老朋友——UART随性自由、IIC严谨有序、SPI雷厉风行。当Arduino Uno遇上树莓派Pico,这三种通信协议便成为硬件对话的通用语言。本文将带您跨越理论迷雾,直接进入实战环节,用OLED屏幕显示数据、用温湿度传感器采集环境信息、用GPS模块获取位置数据,在真实项目中感受每种协议的特性。

1. UART:异步串行的自由派

1.1 硬件连接与基础配置

UART通信只需两根线(TX/RX)即可建立连接,但需要注意电平匹配问题。Arduino Uno使用5V逻辑电平,而树莓派Pico采用3.3V系统,直接连接可能损坏树莓派GPIO。推荐以下两种解决方案:

  • 电平转换模块:使用TXB0104等双向电平转换芯片
  • 电阻分压电路:对Arduino的TX信号进行分压(1.8kΩ+3.3kΩ组合)

典型接线示例(Arduino Uno与树莓派Pico):

Arduino Uno TX -> 电平转换 -> 树莓派Pico RX (GPIO1) Arduino Uno RX <- 电平转换 <- 树莓派Pico TX (GPIO0)

1.2 双平台代码实现

Arduino端发送数据(C++)

void setup() { Serial.begin(115200); // 设置波特率 } void loop() { Serial.println("Hello Raspberry Pi!"); delay(1000); }

树莓派端接收数据(Python)

import serial ser = serial.Serial('/dev/ttyACM0', 115200, timeout=1) while True: if ser.in_waiting > 0: line = ser.readline().decode('utf-8').rstrip() print(f"Received: {line}")

注意:实际设备路径可能是/dev/ttyUSB0或其他,可通过ls /dev/tty*命令查看

1.3 项目实战:GPS数据采集系统

使用NEO-6M GPS模块通过UART传输数据时,典型数据格式如下:

$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47

解析关键字段的Python代码片段:

def parse_gpgga(sentence): if not sentence.startswith('$GPGGA'): return None parts = sentence.split(',') return { 'time': parts[1][:2] + ":" + parts[1][2:4] + ":" + parts[1][4:6], 'latitude': float(parts[2][:2]) + float(parts[2][2:])/60, 'longitude': float(parts[4][:3]) + float(parts[4][3:])/60, 'altitude': float(parts[9]) }

2. IIC:优雅的双线制协议

2.1 协议特性与物理连接

IIC协议的精妙之处在于用两根线(SDA/SCL)实现多设备通信。以下是典型IIC设备地址表:

设备类型默认地址地址范围
OLED SSD13060x3C0x3C-0x3D
BMP280气压传感器0x760x76-0x77
AT24C32 EEPROM0x500x50-0x57

连接多个IIC设备时,SCL和SDA线需要并联,每个设备通过唯一地址识别。树莓派上启用IIC接口的命令:

sudo raspi-config # 选择 Interface Options -> I2C -> Yes

2.2 OLED屏幕驱动实战

Arduino驱动SSD1306(使用Adafruit库)

#include <Wire.h> #include <Adafruit_SSD1306.h> Adafruit_SSD1306 display(128, 64, &Wire, -1); void setup() { Wire.begin(); display.begin(SSD1306_SWITCHCAPVCC, 0x3C); display.display(); delay(2000); display.clearDisplay(); } void loop() { display.setTextSize(1); display.setCursor(0,0); display.print("Temp: 25.6C"); display.display(); }

树莓派Python版本

from board import SCL, SDA import busio from PIL import Image, ImageDraw, ImageFont import adafruit_ssd1306 i2c = busio.I2C(SCL, SDA) display = adafruit_ssd1306.SSD1306_I2C(128, 64, i2c, addr=0x3C) image = Image.new("1", (128, 64)) draw = ImageDraw.Draw(image) draw.text((0, 0), "Hello I2C World!", fill=255) display.image(image) display.show()

2.3 多设备通信技巧

当总线上挂载多个IIC设备时,可能会遇到地址冲突问题。解决方案包括:

  • 使用地址可配置的模块(如某些传感器有ADDR引脚)
  • 添加IIC多路复用器(如TCA9548A)
  • 软件实现虚拟IIC总线

扫描IIC总线上所有设备的Python代码:

import board import busio i2c = busio.I2C(board.SCL, board.SDA) while not i2c.try_lock(): pass devices = i2c.scan() print("I2C devices found:", [hex(x) for x in devices]) i2c.unlock()

3. SPI:高速同步通信专家

3.1 硬件连接与时钟配置

SPI协议采用主从架构,需要四线制连接:

信号线作用备注
SCLK时钟信号由主设备产生
MOSI主设备输出从设备输入数据发送通道
MISO主设备输入从设备输出数据接收通道
SS/CS片选信号每个从设备需要独立片选线

树莓派SPI接口启用命令:

sudo raspi-config # 选择 Interface Options -> SPI -> Yes

3.2 双平台SPI通信对比

Arduino作为主设备(使用SPI库)

#include <SPI.h> void setup() { SPI.begin(); pinMode(SS, OUTPUT); } void sendData(byte data) { digitalWrite(SS, LOW); SPI.transfer(data); digitalWrite(SS, HIGH); }

树莓派Python实现(使用spidev)

import spidev spi = spidev.SpiDev() spi.open(0, 0) # 打开SPI总线0,设备0 spi.max_speed_hz = 1000000 # 设置时钟频率1MHz def send_data(data): resp = spi.xfer2([data]) # 发送并接收数据 return resp[0]

3.3 高速数据采集项目

以ADS1115模数转换器为例,演示SPI高速数据采集:

接线示意图:

树莓派 ADS1115 GPIO11 (SCLK) -> SCLK GPIO10 (MOSI) -> MOSI GPIO9 (MISO) <- MISO GPIO8 (CE0) -> CS

配置ADS1115的Python代码:

import time import spidev class ADS1115: def __init__(self, bus=0, device=0): self.spi = spidev.SpiDev() self.spi.open(bus, device) self.spi.max_speed_hz = 4000000 def read_channel(self, channel): config = 0x8583 | (channel << 12) # 单端输入,±4.096V,128SPS msg = [(config >> 8) & 0xFF, config & 0xFF] resp = self.spi.xfer2(msg) return ((resp[0] << 8) | resp[1]) * 4.096 / 32767

4. 协议对比与选型指南

4.1 关键参数对比表

特性UARTIICSPI
通信方式异步同步同步
数据线数量2 (TX/RX)2 (SDA/SCL)4 (标准)
最大速率3Mbps3.4Mbps50Mbps+
寻址方式7/10位地址片选信号
典型应用场景调试终端传感器网络高速外设
硬件复杂度

4.2 项目选型建议

  • 选择UART当

    • 需要简单的点对点通信
    • 设备间距较远(配合RS485可达千米级)
    • 对实时性要求不高
  • 选择IIC当

    • 需要连接多个同类设备
    • PCB空间受限(只需两根线)
    • 通信速率要求适中
  • 选择SPI当

    • 需要高速数据传输(如显示屏、ADC)
    • 不介意增加布线复杂度
    • 需要全双工通信

4.3 混合使用案例

智能环境监测站设计示例:

[BME280传感器] --IIC--> [树莓派] | [GPS模块] ----UART------+ | [OLED显示屏] --SPI------+

系统整合Python代码框架:

class EnvironmentMonitor: def __init__(self): self.i2c = busio.I2C(SCL, SDA) self.spi = busio.SPI(SCLK, MOSI, MISO) self.uart = serial.Serial('/dev/ttyAMA0', 9600) self.bme = adafruit_bme280.Adafruit_BME280_I2C(self.i2c) self.oled = SSD1306_SPI(128, 64, self.spi, dc=7, rst=24, cs=8) def update_display(self): # 综合显示所有传感器数据 image = Image.new("1", (128, 64)) draw = ImageDraw.Draw(image) draw.text((0, 0), f"Temp: {self.bme.temperature:.1f}C", fill=255) draw.text((0, 16), f"GPS: {self.read_gps()}", fill=255) self.oled.image(image) self.oled.show()
http://www.cnnetsun.cn/news/2907983.html

相关文章:

  • 冥想第一千九百零九天
  • MC9S08QE128内存管理与寄存器映射实战:从原理到高效嵌入式开发
  • 符合消防专项要求玻璃防火门多场景合规落地应用研究摘要
  • MC68341定时器与QSPI模块深度解析:从寄存器原理到实战调试
  • 腾讯AI,有自己的坐标
  • 如何打造终极iOS漫画阅读体验:E-Hentai Viewer完全指南 [特殊字符]
  • yolov26改进 | 损失函数改进篇 | 最新ShapeIoU、InnerShapeIoU损失助力细节涨点(含三十余种损失函数改进方法)
  • 3步掌握d2s-editor:零基础玩转暗黑破坏神2存档修改
  • 如何快速掌握AI图层分离:5步提升设计效率的完整指南
  • 什么是 supremum pseudo-record?
  • FLEXPART模式实战:如何用后向轨迹分析锁定污染源(附Python后处理脚本)
  • 别再手动PS了!用Python+OpenCV给论文配图加局部放大镜,5分钟搞定
  • 第1章:架构基础
  • 如何免费获取抖音无水印高清视频:douyin-downloader完整指南
  • 生产级机器学习系统:防御性设计与系统性风险治理
  • 从零样本到思维分支:LLM推理增强的工业级落地路径
  • Docker分层构建缓存原理详解:零基础快速吃透镜像加速机制
  • MCU模拟比较器与DAC实战:低功耗监控与自动波形生成
  • SPI驱动非标准字长外设:硬件打包与软件模拟方案详解
  • BERTScore深度解析:为什么这个文本评估指标能碾压传统方法?
  • 小红书无水印下载终极指南:3分钟掌握批量采集技巧
  • 嵌入式定时器与DAC实战:从抗噪滤波到自动波形生成
  • 别再只用qemu-img了!QEMU快照的两种玩法(磁盘/检查点)与实战避坑指南
  • 终极指南:在Linux上安装Realtek 8922AE WiFi 7网卡驱动的完整教程
  • 抖音下载器开源项目实战教程:从零搭建24小时自动采集系统完整指南
  • 深入解析MC56F81xxxL中断与eDMA:从原理到实战配置指南
  • i.MX21 SSI接口AC97模式详解:寄存器配置与多通道音频驱动开发
  • 深入解析NXP LS1046A SEC队列接口与错误处理寄存器
  • 3步精通:开源工具高效下载MOOC课程
  • SAP UI5 没有 NgModule,但有自己的装配秩序