如何在 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(); }
迴圈內部沒有任何操作。