如何在 Arduino 中使用 PROGMEM 存储大型不可变数据?
PROGMEM 是一个关键字,当您希望将数据存储在程序内存(Flash)而不是 SRAM 中时使用。虽然您可以将 PROGMEM 用于单个变量,但这并没有多大意义。毕竟,SRAM 的空间足以容纳您的单个变量,并且访问存储在 SRAM 中的变量速度更快。
PROGMEM 主要用于大型数据块(主要是数组),这些数据块可能会占用 SRAM 的大量空间(SRAM 的大小通常远小于 Flash 内存,但访问速度更快)。将数据存储在 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 存储在 Flash 内存中的数据,可以使用专用函数:
**strlen_P(arrayName)** - 此函数返回数组 **arrayName** 的长度。
**pgm_read_byte_near(address)** - 此函数返回位于 address 位置的一个字节的值。
**pgm_read_word_near(address)** - 此函数返回从 address 位置开始的一个字(在大多数微控制器上为 2 个字节)的值。
下面示例将阐明这些函数的用法。这些并不是唯一可与 PROGMEM 一起使用的函数。您可以在这里找到其他一些函数:这里。
示例
让我们从示例开始。我们将使用 Arduino 文档中提供的示例。
我们将查看第一个示例。如您所见,在 PROGMEM 中定义了两个数组,一个是 16 位整数数组(16 位 = Arduino Uno 上的一个字),另一个是字符数组(每个字符为 8 位或 1 字节)。
// save some unsigned ints const PROGMEM uint16_t charSet[] = { 65000, 32796, 16843, 10, 11234}; // save some chars const char signMessage[] PROGMEM = {"I AM PREDATOR, UNSEEN COMBATANT. CREATED BY THE UNITED STATES DEPART"};
随后,定义了两个全局变量,稍后将使用。
unsigned int displayInt; char myChar;
在 **setup** 中,我们初始化 **Serial**。然后,我们一次读取一个字,打印 charset 数组的整数。请注意,我们如何使用 **charSet + k** 作为我们要读取的地址。您可能还记得,数组的名称也是其第一个元素的指针。这里使用了相同的属性。
void setup() { Serial.begin(9600); while (!Serial); // wait for serial port to connect. Needed for native USB // put your setup code here, to run once: // read back a 2-byte int for (byte k = 0; k < 5; k++) { displayInt = pgm_read_word_near(charSet + k); Serial.println(displayInt); } Serial.println();
然后,我们从 **signMessage** 数组中一次读取一个字节并将其打印到串口监视器。请注意,我们使用 **strlen_P** 函数获取数组的长度,以确定 **for** 循环的终止条件。
// read back a char for (byte k = 0; k < strlen_P(signMessage); k++) { myChar = pgm_read_byte_near(signMessage + k); Serial.print(myChar); } Serial.println(); }
循环内部没有任何操作。