PROGMEMの使い方 (Arduino)
OLEDを使った小さなオシロ作りはソフトとハードまで出来て、あとは適当なケースを探す段階まで進みました。久しぶりに新しい物を作ることに取り組んでみたのですが、その過程でいくつか発見がありました。
そんなことで、発見と言うほど大袈裟なものではありませんが、気付いた点について記事にまとめておきたいと思います。まずはタイトルの通り PROGMEM です。なお、以下の情報はこの記事を書いた時点(2019/2/15)のもので今後変わる可能性がある点はご注意ください。
1.PROGMEMの使い方が判らない
PROGMEMはデーターの保存先をRAMからフラッシュメモリーに移動させることで、RAMの空き容量を拡げる機能です。詳しい説明はネットにいっぱい書かれているのでここでは省略します。問題はその使い方、というかプログラムの書き方です。
ネットにはPROGMEMの使い方について解説した記事がいっぱいあります。また、Arduinoの日本語リファレンスにも書かれているので、そういうのを見れば済むと思っていたら、なんだか変です。ちゃんと動かないどころか、例として掲載されているプログラムすらコンパイラが通りません。
2.PROGMEMの仕様が変わっていた
おかしいな、と思って調べてみると、どうも2017年頃にPROGMEMの使い方に仕様変更があったようです。変更の前後で互換性は無いので、古い仕様で書かれたプログラムは動かなくなっていました。
ネットには新旧の仕様の情報が混在していて、どちらかと言うと古い仕様で描かれた情報の方が多いようです。ということで、そういう状況になっていることを知らないと、問題解決のために無駄な時間を使うことになります。(私がそうでした)
3.PROGMEMの使い方についてのお勧めのサイト
上に書いたような状況になるのは実は日本語のリファレンスのページを読んだ場合で、本家の英語のサイトにはPROGMEMの使い方の正しい情報が記載されています。そんなことで本家のサイトを読むようにしましょう、と書けば済むのですが、やはり日本語で書かれた情報の方が断然読み易いです。
ということで改めて探してみると、jumbleatさんのブログの、PROGMEMを使うと言う記事がすごく判り易かったので、これを読むことをお勧めします。
4.PROGMEMのプログラム例
OLEDオシロの記事中でPROGMEMを使ったプログラムを公開していますが、説明用にPROGMEMの部分だけ取り出して書き直したのが以下のプログラムです。
なんでこんなに面倒なの?と思うくらいごちゃごちゃしています。また、ポインターを使っていて判り難いです。ともかく、こういうものだと思って、あまり考えずに使うのが良いと思います。8行目が const char * const string_table[] PROGMEM = となっていて、* (アスタリスク)の前後に意味不明なスペースが入っていますが、これも気にしないことにします。
◆まとめ
ともかくこれでPROGMEMの使い方が判ったので、ミニオシロのプログラムを完成形まで持って行くことが出来ました。 判り易い情報を開示していただいた iumbleatさんに感謝します。実はRAMが足らなくなって、すごく困ってました。
PROGMEMでは、文字を扱っているのにbyteでは無くword (pgm_read_word) という単語が出てきたリ、数値の扱いでは far や near なんて単語が出て来て面くらいます。前者は、フラッシュメモリーのデーター幅が16ビットなので word と呼ばれているのでしょう。また far/near は参照ページの内外を表しているようなんですが、いずれにしても違う文化の風に当たったみたいで、面白いです。
参考:Arduinoの日本語のレファレンスのPROGMEMのページ
武蔵野電波さんのArduino 日本語リファレンスの、PROGMEMとFマクロのページ
garretlabさんの、PROGMEMのページ
変数の宣言で、prog_char などとなっていたら古い仕様なので、その先は読んでも無駄です。
そんなことで、発見と言うほど大袈裟なものではありませんが、気付いた点について記事にまとめておきたいと思います。まずはタイトルの通り PROGMEM です。なお、以下の情報はこの記事を書いた時点(2019/2/15)のもので今後変わる可能性がある点はご注意ください。
1.PROGMEMの使い方が判らない
PROGMEMはデーターの保存先をRAMからフラッシュメモリーに移動させることで、RAMの空き容量を拡げる機能です。詳しい説明はネットにいっぱい書かれているのでここでは省略します。問題はその使い方、というかプログラムの書き方です。
ネットにはPROGMEMの使い方について解説した記事がいっぱいあります。また、Arduinoの日本語リファレンスにも書かれているので、そういうのを見れば済むと思っていたら、なんだか変です。ちゃんと動かないどころか、例として掲載されているプログラムすらコンパイラが通りません。
2.PROGMEMの仕様が変わっていた
おかしいな、と思って調べてみると、どうも2017年頃にPROGMEMの使い方に仕様変更があったようです。変更の前後で互換性は無いので、古い仕様で書かれたプログラムは動かなくなっていました。
ネットには新旧の仕様の情報が混在していて、どちらかと言うと古い仕様で描かれた情報の方が多いようです。ということで、そういう状況になっていることを知らないと、問題解決のために無駄な時間を使うことになります。(私がそうでした)
3.PROGMEMの使い方についてのお勧めのサイト
上に書いたような状況になるのは実は日本語のリファレンスのページを読んだ場合で、本家の英語のサイトにはPROGMEMの使い方の正しい情報が記載されています。そんなことで本家のサイトを読むようにしましょう、と書けば済むのですが、やはり日本語で書かれた情報の方が断然読み易いです。
ということで改めて探してみると、jumbleatさんのブログの、PROGMEMを使うと言う記事がすごく判り易かったので、これを読むことをお勧めします。
4.PROGMEMのプログラム例
OLEDオシロの記事中でPROGMEMを使ったプログラムを公開していますが、説明用にPROGMEMの部分だけ取り出して書き直したのが以下のプログラムです。
// PROGMEM 使用例 2019/02/14 ラジオペンチここではフラッシュ領域に文字列(オシロの縦軸レンジの表示名)を保存し、それをstrcpy_Pで取り出してシリアルに表示するまでの手順を示しています。
// #include <avr/pgmspace.h> // PROGMEMを使うために使用(たぶんインクルード不要)
const char Name[10][5] PROGMEM = {
"A50V", "A 5V", " 50V", " 20V", " 10V", " 5V", " 2V", " 1V", "0.5V", "0.2V"
}; // 縦軸表示文字の定義(10項目、5文字(\0含んだ文字数が必要))
const char * const string_table[] PROGMEM = {
Name[0], Name[1], Name[2], Name[3], Name[4], Name[5], Name[6], Name[7], Name[8], Name[9]
}; // アクセス用のテーブルの定義
char chrBuff[8]; // 文字列操作バッファ
void setup() {
Serial.begin(115200);
}
void loop() {
for (int i = 0; i <= 9; i++) {
// strcpy_Pによりテーブル番号の文字列をchrBuffに取り出し
strcpy_P(chrBuff, (char*)pgm_read_word(&(string_table[i])));
Serial.println(chrBuff);
}
while (1) {}
}
なんでこんなに面倒なの?と思うくらいごちゃごちゃしています。また、ポインターを使っていて判り難いです。ともかく、こういうものだと思って、あまり考えずに使うのが良いと思います。8行目が const char * const string_table[] PROGMEM = となっていて、* (アスタリスク)の前後に意味不明なスペースが入っていますが、これも気にしないことにします。
◆まとめ
ともかくこれでPROGMEMの使い方が判ったので、ミニオシロのプログラムを完成形まで持って行くことが出来ました。 判り易い情報を開示していただいた iumbleatさんに感謝します。実はRAMが足らなくなって、すごく困ってました。
PROGMEMでは、文字を扱っているのにbyteでは無くword (pgm_read_word) という単語が出てきたリ、数値の扱いでは far や near なんて単語が出て来て面くらいます。前者は、フラッシュメモリーのデーター幅が16ビットなので word と呼ばれているのでしょう。また far/near は参照ページの内外を表しているようなんですが、いずれにしても違う文化の風に当たったみたいで、面白いです。
参考:Arduinoの日本語のレファレンスのPROGMEMのページ
武蔵野電波さんのArduino 日本語リファレンスの、PROGMEMとFマクロのページ
garretlabさんの、PROGMEMのページ
変数の宣言で、prog_char などとなっていたら古い仕様なので、その先は読んでも無駄です。