返回

Pico 多协议演示:RP2040 上的串行、I2C、SPI 与 ADC

引言

欢迎来到 Pico 多协议演示!在本教程中,我们将探索如何让 Raspberry Pi Pico (RP2040) 同时通过多种协议进行通信:串行I2CSPIADC。这是一个高级示例,汇集了嵌入式开发的几项关键技能。我们将在 Velxio 模拟器中搭建电路、编写代码,并逐步讲解每个部分。

Velxio 模拟器画布上的 pico-multi-protocol 电路图

电路讲解

让我们来看看组件和接线。该电路使用了一块 Raspberry Pi Pico (Nano RP2040 Connect) 和几个外设:

所有 LED 共享一个公共地。电位器由 3.3V 电源轨供电。接线很简单,但请注意我们使用了 Pico 内置的 I2C 和 SPI 外设(虽然在原理图中没有明确显示,但代码假定它们位于默认引脚上)。

代码讲解

代码使用 Arduino C++ 编写,并使用了 WireSPI 库。让我们逐节分析。

设置

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(115200);
  delay(500);

  Serial.println("==============================");
  Serial.println(" Pico Multi-Protocol Demo");
  Serial.println("==============================");
  Serial.println();

我们首先初始化内置 LED 和串行通信,波特率设为 115200。延迟是为了给串行监视器连接留出时间。

1. I2C 扫描器

  Wire.begin();
  Serial.println("[I2C] Scanning bus...");
  int found = 0;
  for (byte addr = 1; addr < 127; addr++) {
    Wire.beginTransmission(addr);
    if (Wire.endTransmission() == 0) {
      found++;
      Serial.print("  Found device at 0x");
      if (addr < 16) Serial.print('0');
      Serial.println(addr, HEX);
    }
  }
  Serial.print("  Total devices: "); Serial.println(found);
  Serial.println();

这段代码扫描所有可能的 I2C 地址(1-126),并报告任何响应的设备。在模拟器中,你可能会看到地址为 0x50 (EEPROM) 和 0x68 (RTC) 的虚拟设备。

2. I2C EEPROM 读写

  Serial.println("[I2C] EEPROM test at 0x50...");
  Wire.beginTransmission(0x50);
  Wire.write(0x00); // register 0
  Wire.write(0x42); // data
  Wire.endTransmission();
  delay(5);

  Wire.beginTransmission(0x50);
  Wire.write(0x00);
  Wire.endTransmission();
  Wire.requestFrom(0x50, 1);
  if (Wire.available()) {
    byte val = Wire.read();
    Serial.print("  Wrote 0x42, Read 0x");
    Serial.print(val, HEX);
    Serial.println(val == 0x42 ? " — OK" : " — FAIL");
  }
  Serial.println();

我们将值 0x42 写入地址为 0x50 的 EEPROM 的寄存器 0,然后读回以验证。这测试了基本的 I2C 读写功能。

3. I2C RTC

  Serial.println("[I2C] Reading DS1307 RTC at 0x68...");
  Wire.beginTransmission(0x68);
  Wire.write(0x00);
  Wire.endTransmission();
  Wire.requestFrom(0x68, 3);
  if (Wire.available() >= 3) {
    byte sec = ((Wire.read() & 0x7F) >> 4) * 10 + (Wire.read() & 0x0F);
    byte min2 = Wire.read();
    (void)sec; (void)min2;
    Serial.println("  RTC responded OK");
  }
  Serial.println();

这里我们尝试从地址为 0x68 的 DS1307 RTC 读取时间寄存器。代码读取了三个字节(秒、分钟、小时),但只检查了设备是否响应。

4. SPI 回环

  Serial.println("[SPI] Loopback test...");
  SPI.begin();
  SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
  byte tx = 0xAB;
  byte rx = SPI.transfer(tx);
  Serial.print("  TX: 0x"); Serial.print(tx, HEX);
  Serial.print("  RX: 0x"); Serial.println(rx, HEX);
  SPI.endTransaction();
  Serial.println();

这执行了一个简单的 SPI 回环测试:发送 0xAB 并读回接收到的数据。在模拟器中,MISO 和 MOSI 没有外部连接,因此接收到的值可能是 0xFF 或其他值。这测试了 SPI 硬件。

5. ADC

  Serial.println("[ADC] Reading analog channels...");
  analogReadResolution(12);
  int a0 = analogRead(A0);
  Serial.print("  A0 (GP26): "); Serial.println(a0);
  Serial.println();

我们将 ADC 分辨率设置为 12 位,并从 A0 (GP26) 读取值。读取电位器滑臂的电压,得到一个介于 0 到 4095 之间的值。

6. GPIO 闪烁

  Serial.println("[GPIO] Blinking LED...");
  for (int i = 0; i < 3; i++) {
    digitalWrite(LED_BUILTIN, HIGH);
    delay(200);
    digitalWrite(LED_BUILTIN, LOW);
    delay(200);
  }
  Serial.println("  3 blinks done");
  Serial.println();

  Serial.println("=== All protocol tests complete ===");
}

最后,我们让内置 LED 闪烁三次,表示设置完成。

主循环

void loop() {
  // Heartbeat
  static unsigned long last = 0;
  if (millis() - last >= 3000) {
    last = millis();
    Serial.print("[Heartbeat] ");
    Serial.print(millis() / 1000);
    Serial.println("s");
  }
}

主循环每 3 秒 打印一次心跳消息,以显示程序仍在运行。

关键概念

常见陷阱与调试技巧

建议的扩展

亲自尝试!

准备好实验了吗?在 Velxio 中打开实时示例并运行模拟。你可以修改代码、添加组件,并立即看到结果。

在 Velxio 上启动 Pico 多协议演示

带有编译和运行控件的 Velxio 编辑器工具栏

模拟视口上方的 Velxio 画布工具栏

按类别浏览部件的 Velxio 组件选择器弹窗

祝你编程愉快!


分享到:
David Montero

作者

David Montero

Creator of Velxio, the open-source circuit and Arduino simulator.

GitHub velxio.dev

相关文章


上一篇
Velxio 与 Wokwi、Tinkercad、Proteus 和 Fritzing 的坦诚对比
下一篇
在树莓派Pico上使用Velxio读取模拟传感器