PROGMEM

説明

データをSRAMではなく、フラッシュ(プログラム)メモリに配置する。Arduinoボードで利用可能なさまざまな種類のメモリの詳細説明がある。

PROGMEMは変数の修飾子である。 “pmgspace.hで定義されたデータ型に対してだけ利用すること。通常変数を配置するSRAMではなく、フラッシュメモリに変数を配置するようコンパイラに対して指示を出す。

PROGMEMはpmgspace.hライブラリの一部である。新しいバージョンのIDEでは、自動的にインクルードされる。しかし、1.0(2011)未満のIDEを使っている場合は、以下のように、スケッチの最初の方でライブラリをインクルードする必要がある。

#include <avr/pgmspace.h>

PROGMEMは(配列ではない)一つの変数に対しても利用できる。しかし、実際には大きなデータブロックを利用しなければならないときに有用であり、それを利用する簡単で一般的な方法は配列である(今まで議論していないC++言語のデータ構造もあるかもしれないが)。

PROGMEMの利用は2段階からなる。まず、データをフラッシュメモリに配置し、その後、pgmspace.hに定義された特別なメソッド(関数)を使って、データをフラッシュメモリからSRAMに読み出す。このようにすることでPROGMEMを有効に利用することができる。

書式

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

PROGMEMは変数の修飾子なので、どこに記述するかの明確な規則はない。Arduinoコンパイラは以下の定義をすべて受け付ける。これらはすべて同じ意味である。しかし、多くのバージョンのArduino(GCCのバージョンに関係する)での経験上、PROGMEMはある場所に記述したときは動作するが、他の場所では動作しないこともある。Arduino13での文字列テーブルでの例では、以下が動作することがわかっている。古いバージョンのIDEでは、PROGMEMが変数名の後ろにあるほうがいい。

1
2
3
const dataType variableName[] PROGMEM = {}; // use this form
const PROGMEM dataType variableName[] = {}; // or this one
const dataType PROGMEM variableName[] = {}; // not this one

引数

dataType任意の変数のデータ型。
variableNameデータの配列の名前。

使用例

以下のコードは、PROGMEMにchar(1バイト)とint(2バイト)のデータを読み書きする。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 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;


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();

  // 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();
}

void loop() {
  // put your main code here, to run repeatedly:
}

文字列の配列

LCDディスプレイを利用したプロジェクトなどにおいて文字列の配列を設定するときなど、大量の文字を利用する場合に有用である。文字列自身が配列なので、これは2次元配列の実際の例である。

これらは大きな構造になることが多いので、プログラムメモリに配置することが望ましい。以下のコードでは考え方を示す。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/*
  PROGMEM string demo
  How to store a table of strings in program memory (flash),
  and retrieve them.

  Information summarized from:
  http://www.nongnu.org/avr-libc/user-manual/pgmspace.html

  Setting up a table (array) of strings in program memory is slightly complicated, but
  here is a good template to follow.

  Setting up the strings is a two-step process. First define the strings.
*/

#include <avr/pgmspace.h>
const char string_0[] PROGMEM = "String 0"; // "String 0" etc are strings to store - change to suit.
const char string_1[] PROGMEM = "String 1";
const char string_2[] PROGMEM = "String 2";
const char string_3[] PROGMEM = "String 3";
const char string_4[] PROGMEM = "String 4";
const char string_5[] PROGMEM = "String 5";


// Then set up a table to refer to your strings.

const char *const string_table[] PROGMEM = {string_0, string_1, string_2, string_3, string_4, string_5};

char buffer[30];  // make sure this is large enough for the largest string it must hold

void setup() {
  Serial.begin(9600);
  while (!Serial);  // wait for serial port to connect. Needed for native USB
  Serial.println("OK");
}


void loop() {
  /* Using the string table in program memory requires the use of special functions to retrieve the data.
     The strcpy_P function copies a string from program space to a string in RAM ("buffer").
     Make sure your receiving string in RAM  is large enough to hold whatever
     you are retrieving from program space. */


  for (int i = 0; i < 6; i++) {
    strcpy_P(buffer, (char *)pgm_read_word(&(string_table[i])));  // Necessary casts and dereferencing, just copy.
    Serial.println(buffer);
    delay(500);
  }
}

注意

PROGMEMを動作させるためには、変数は大域変数にするか、staticキーワードをつけて定義する必要がある。

以下のコードは、関数の中に記載されたときには動作しない。

1
const char long_str[] PROGMEM = "Hi, I would like to tell you a bit about myself.\n";

以下のコードは、関数の中に記載されても動作する。

1
const static char long_str[] PROGMEM = "Hi, I would like to tell you a bit about myself.\n"

F()マクロ

以下のようなコードが使われたときには、表示される文字列はRAMに格納される。

1
Serial.print("Write something on  the Serial Monitor");

シリアルモニタに大量の文字を表示するときには、簡単にRAMを満杯にしてしまう。FLASHメモリの領域が余っているときには、以下のようなコードを使って、簡単にFLASHメモリを利用することができる。

1
Serial.print(F("Write something on the Serial Monitor that is stored in FLASH"));

参照

利用例 Types of memory available on an Arduino board

定義 配列

定義 string(文字の配列)

オリジナルのページ

https://www.arduino.cc/reference/en/language/variables/utilities/progmem/

Last Revision: 2022/07/07

最終更新日

January 4, 2024

inserted by FC2 system