Arduinoファームウェアの基礎 - PROGMEM

提供:MochiuWiki - SUSE, Electronic Circuit, PCB
ナビゲーションに移動 検索に移動

概要

PROGMEMキーワードは変数修飾子であり、SRAMの代わりにフラッシュメモリにデータを格納する。

PROGMEMキーワードは、pgmspace.hファイルで定義されたデータ型でのみ使用される。

Arduino IDEが古い場合は、以下のようにライブラリをインクルードする必要がある。

 #include <avr/pgmspace.h>



使用方法

PROGMEMキーワードの使用方法は、2ステップに分かれている。

  1. まず、データをフラッシュメモリに格納する。
  2. 次に、プログラムメモリからSRAMにデータを読み戻す(使用する)には、avr/pgmspace.hファイルで定義されているPROGMEM専用の関数を使用する。


以下に、PROGMEMキーワードのシンタックスを示す。

 const <データ型> <変数名または配列変数名> PROGMEM = {data0, data1, data3 ...};
 // または
 const PROGMEM <データ型> <変数名または配列変数名> = {data0, data1, data3 ...};


以下の例では、PROGMEMキーワードを使用したchar型とuint16_t型の配列を読み書きしている。

 // save some unsigned int
 const PROGMEM uint16_t charSet[] = {65000, 32796, 16843, 10, 11234};
 
 // save some char
 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を使用して大量のテキストを扱う場合、文字列配列を設定すると便利なことが多い。
このような配列はサイズが大きくなりがちなため、フラッシュメモリ上に格納することが望ましい場合がある。
以下は、その例である。

 /*
  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キーワードを使用する必要があることに注意する。

以下の例は、関数内では動作しない。

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


以下の例は、関数内に定義されていても動作する。

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



F()マクロ

以下のようなSerial.print()を使用する場合、表示される文字列はRAMに保存される。

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


シリアルモニタに多くのものを表示する場合、RAMが不足する可能性がある。
この時、フラッシュメモリの空き容量がある場合は、F()マクロを使用して、文字列をフラッシュメモリに保存することができる。

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