使用 Arduino UNO R4 上 Qwiic 接口的小技巧

Arduino 最新版经典外形板载了 Qwiic 接口。图 1 显示了 Arduino UNO R4 WiFi 的 Qwiic 接口连接到一块 Adafruit 3966 气压传感器的示意图。

如果你是 Qwiic 的新手,可以点击这个链接快速了解它的基本介绍。

简要说明:带有 Qwiic 接口的 Arduino 为测试新硬件提供了一种便捷方式。但需要注意的是,UNO R4 WiFi 引入了一个全新的 I2C 硬件接口,这改变了我们对 I2C 的传统理解。

:white_check_mark: 特别提示:如果你的 Qwiic 模块无法正常工作,可能需要将代码中用到的 Wire 对象更改为 Wire1 对象,以正确地使用 Qwiic 接口。

请继续阅读完整的解释与示例。

图 1:Arduino UNO R4 WiFi 连接 Adafruit BMP388(型号 3966)传感器的照片。所有部件都安装在 Arduino 的 Plug and Make 基座上。

如何快速上手 Arduino 与 Qwiic?

最简单的方式之一是购买 Arduino 的 Plug and Make 套件。这篇文章介绍了该套件作为软件探索 Arduino 编程与传感器的理想起点。

Plug and Make 套件配备了多种匹配的 Qwiic 板(称为 Modulino),包括:

为什么推荐使用 modulino 板?

Modulino 板从物理和软件上都专为 UNO R4 WiFi 设计匹配。

  • 如图 2 所示,所有 modulino 板均设计成可彼此拼接,并可固定在 Plug and Make 基座上,为项目提供稳定的基础。

  • Modulino 板附带了完善的软件库,其中包括使用方式非常简单的示例代码,就像我们最熟悉的 “Blinky LED” 程序一样,能帮助学习者迅速掌握 Arduino 编程,从而聚焦于更高层级的应用逻辑。秉承 Arduino 的传统,这种方式让学习者能够迅速实现相对复杂的行为,激发兴趣。

  • 这些软件库已支持 UNO R4 上的 32 位高级特性,特别是使用了连接 Qwiic 接口的第二个 I2C 通道 —— Wire1。

技术小贴士: 虽然 Arduino 强调“简单上手”,但深入理解微控制器的工作原理同样重要。新版 Arduino IDE 支持直接跳转 .h 和 .cpp 源文件,便于查看底层库的实现。

图 2:Arduino Plug and Make 套件中四个 modulino 板以菊花链方式连接的照片。

修复 Arduino UNO R4 WiFi 无法识别 Qwiic 传感器的问题

最常见的问题是使用了错误的 Wire 对象。我们习惯性地使用 Wire(传统 I2C 接口),但在使用 Qwiic 时,应该使用 Wire1 对象。以下内容假设你使用的是支持 Qwiic 的模块。

背景:Wire 与 Wire1 对象有什么区别?

首先需要了解,早期版本的 UNO 使用的是 8 位的 Atmel(现 Microchip)ATMega328 AVR 微控制器。而最新的 Arduino R4 则基于先进的 32 位 Renesas RA4M1 芯片。因此,它具备多个通信外设等更强大的功能。

  • ATMega328 只配备了一个基于硬件的 I2C 模块,这个模块被识别为 Wire 对象,使用 Wire.begin()、Wire.write() 和 Wire.end() 等方法访问。从物理引脚来看,这组 I2C 被映射到 D18(SDA)和 D19(SCL)。大多数“Arduino”库都基于这一硬件接口以实现更高通信速度。

  • 而 RA4M1 拥有两个可用的 I2C 通信外设。其中一个是刚才提到的 D18 和 D19,另一个是新的 Qwiic 接口,对应引脚为 RA4M1 的 P401(SDA)和 P400(SCL)。这个第二个 I2C 接口就是 Wire1 对象。

示例:将 Wire 对象更换为 Wire1 的实际应用

图 1 展示了 UNO R4 WiFi 连接到 Adafruit 参数传感器的情况。该传感器板原生支持 Qwiic,可通过 modulino 使用的相同连接线轻松连接到 R4。

实际操作如下:

  • 按照 Adafruit 提供的示例加载了示例程序

  • 安装了 Adafruit 库

  • 编译并下载 I2C 示例代码到 UNO R4

  • 系统无法识别传感器

不推荐的快速修改方式

一种快速但不推荐的解决方法是直接修改 Adafruit_BMP3XX.h 文件中的 Wire 对象指向,将其改为 Wire1。

修改方法很简单,如下代码所示,只需将 Wire 改成 Wire1:

public:
  Adafruit_BMP3XX();
  bool begin_I2C(uint8_t addr = BMP3XX_DEFAULT_ADDRESS,
                 TwoWire *theWire = &Wire1);

我们称之为“脏”修改,因为这会在不易察觉的情况下破坏 Adafruit 库。举例来说,如果你之后在 UNO R3 上使用相同传感器库,该代码将无法编译,因为 ATmega328 生态中没有 Wire1 对象。

推荐的“干净”修改方式

更好的做法是在用户自己的草图(sketch)中修改调用方式,而不是破坏库文件。也就是说,从外部传入 Wire1 对象地址。例如:

if (!bmp.begin_I2C(BMP3XX_DEFAULT_ADDRESS, &Wire1)){

最后

Arduino 相比将 Qwiic 接口并联到原有 I2C 总线上,他们将其设计为独立接口,这极大提升了灵活性。