如何在 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();
}

迴圈內部沒有任何操作。

更新於:2021年7月24日

7000+ 次檢視

啟動您的 職業生涯

完成課程獲得認證

開始學習
廣告