65.9K
CodeProject 正在变化。 阅读更多。
Home

在不修改草图的情况下,在 Arduino 上实现更快、更高效的 GPIO

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.90/5 (15投票s)

2016年8月14日

CPOL

3分钟阅读

viewsIcon

21504

downloadIcon

349

我介绍一种新的 Arduino GPIO 函数实现,它比原始函数更快更高效。

引言

Arduino 配备了内置的 GPIO 函数,可以很好地实现其目的。但是,在我们将它们的性能与其他更高效的实现进行比较之后,很明显这些函数体积庞大且速度慢。支持这些效率低下的函数的常见论点是,它们主要供爱好者使用,而爱好者通常更看重易用性而不是效率。

在这里,我没有介绍最快的实现,而是介绍一种高效且保持与原始 Arduino 函数相同易用性的实现。

背景

几年前,我在大学时做了一项研究,旨在提高 Arduino 库的效率。虽然我确实成功了,但它从未在实验室外使用过。但现在我清理了代码,使其更容易使用。

Using the Code

使用此代码非常简单。您所要做的就是将 *FastIO.h* 和 *FastIO.c* 复制到 Arduino 核心目录(*[Arduino Folder]\hardware\arduino\avr\cores\arduino*),并在您的草图中包含头文件。

#include <FastIO.h>

工作原理

Arduino 上的每个引脚都连接到 AVR 微控制器的引脚。这些引脚分布在不同的端口中。这些端口在 AVR 的内存中以不同的地址进行内存映射。为了操作这些引脚,我们必须写入这些特定的内存区域。

那么,Arduino 如何仅使用引脚编号来访问其引脚呢?实际上,Arduino 已将所有必需的信息保存到其内存中。因此,当您在特定引脚上调用 `digitalWrite` 时,Arduino 软件会在其内存中搜索所需的信息(引脚所属端口的地址及其在端口上的位置)。Arduino 软件还需要一些关于引脚是否也连接到定时器的额外信息,如果是,则是哪个定时器以及在哪个位置。

所有这些开销使得 Arduino 的内置函数非常慢。我的实现试图通过使所有必需的信息易于函数使用来减轻这种开销。这样,该函数就可以在调用后立即开始操作引脚,而不是搜索信息。

它的工作原理是将信息存储在一个 4 字节的数组中。

  • 第一个字节包含引脚在特定端口上的位置。
  • 第二个字节包含引脚所属端口的地址。
  • 如果引脚还连接了定时器,那么第三个字节包含控制引脚功能的定时器引脚。
  • 第四个字节包含连接到引脚的定时器的地址。

如果引脚没有连接定时器,则第三个和第四个字节都将等于零。

在函数调用时,此数组的引用会传递给函数,而不是简单地传递引脚编号。

基准测试

内置的 `digitalWrite` 函数大约需要 5us 才能改变引脚状态,这对于以 16MHz(62.5ns 周期)运行的微控制器来说非常慢。我的实现通过将时间减少到大约 250ns,使此函数速度提高了 20 倍。所有这些性能提升都是在不更改草图代码的情况下实现的,这也是此实现的主要目标。

作为奖励,使用我的代码时,编译后的草图大小也更小(一举两得)。

正如您在此处看到的,无需对草图进行任何更改即可实现接近原生速度。

限制

目前,此代码与基于 Arduino mega 的板不兼容。这是因为我在引脚定义数组中仅为端口地址保留了一个字节,但在 Atmega2560 中,某些端口位于大于 0xFF 的地址处。通过为端口地址和定时器地址保留 2 个字节,可以轻松避免此限制。这些更改将在后续版本中进行,一旦我的实现在基于 Atmega8/168/328P 的板上经过彻底测试。

© . All rights reserved.