如何在 Arduino 中使用 PROGMEM 存储大量不可变数据?

PROGMEM 是您希望将数据存储在程序存储器(闪存)而不是 SRAM 中时使用的关键字。虽然您可以将 PROGMEM 用于单个变量,但这样做没有多大意义。毕竟,SRAM 将有足够的空间来容纳您的单个变量,并且访问存储在 SRAM 中的变量会更快。

PROGMEM 主要用于大块数据(主要是数组),它可以压倒 SRAM(它的大小通常比闪存小得多,但访问速度更快)。在 PROGMEM 中存储一些东西的含义是它不能在运行时动态修改。因此,人们一般使用 PROGMEM 来存储大型的不可变文本或数据。

如果您使用的是低于 1.0 的 Arduino IDE 版本(为什么?),那么您需要包括

#include <avr/pgmspace.h>

在代码顶部使用 PROGMEM 关键字。对于 Arduino >= 1.0 的版本,您可以直接使用 PROGMEM 关键字而无需任何包含。

请注意,PROGMEM 仅适用于全局变量或使用 static 关键字定义的变量。

语法

语法如下 -

const dataType arrayName[] PROGMEM = {data0, data1, data3…};

datatype 允许任何变量类型,arrayName是数组的名称。

为了使用 PROGMEM 访问存储在闪存中的数据,您可以使用专门的功能 -

  • strlen_P(arrayName)− 此函数返回数组arrayName的长度。

  • pgm_read_byte_near(address) − 此函数返回位于地址的一个字节的值。

  • pgm_read_word_near(address) − 此函数返回一个字的值(大多数微控制器上为 2 个字节),位置从地址开始。

这些函数的用法将在下面的示例中一目了然。这些不是与 PROGMEM 一起使用的唯一函数。还有其他几个,你可以在这里找到。

示例

让我们从示例开始。我们将使用 Arduino 文档中给出的示例。

我们将看第一个例子。如您所见,PROGMEM 中定义了两个数组,一个是 16 位整数数组(在 Arduino Uno 上为 16 位 = 1 个字),而第二个是字符数组(每个字符为 8 位或1 字节长)

// save some unsigned ints
const PROGMEM uint16_t charSet[] = { 65000, 32796, 16843, 10, 11234};
// 保存一些字符
const char signMessage[] PROGMEM = {"I AM PREDATOR, UNSEEN COMBATANT.
CREATED BY THE UNITED STATES DEPART"};

后面定义了两个全局变量,后面会用到。

unsigned int displayInt;
char myChar;

setup 中,我们初始化Serial。稍后,我们一次读取一个单词,以打印字符集数组的整数。注意我们如何使用charSet + k作为我们想要读取的地址。您可能还记得数组的名称也是指向其第一个元素的指针。此处使用了相同的属性。

void setup() {
   Serial.begin(9600);
   while (!Serial); //等待串口连接。本机 USB 需要
   // 把你的设置代码放在这里,运行一次:
   // 读回一个 2 字节的 int
   for (byte k = 0; k < 5; k++) {
      displayInt = pgm_read_word_near(charSet + k);
      Serial.println(displayInt);
   }
   Serial.println();

稍后,我们从signMessage数组中读取每个字节并将其打印到串行监视器。请注意,我们使用strlen_P函数来获取数组的长度,以确定for循环的终止条件。

   // 读回一个字符
   for (byte k = 0; k < strlen_P(signMessage); k++) {
      myChar = pgm_read_byte_near(signMessage + k);
      Serial.print(myChar);
   }
   Serial.println();
}

循环内什么也没有发生。