これまでの例では、常に記録されたデータを処理し、必要に応じてすぐに再出力することを目的としていましたが、今回の例では、記録されたデータを処理して、必要に応じてすぐに再出力することを目的としています。しかし場合によっては、情報を永久に保存することが必要な場合もあります。例えば、ユーザー設定が関与している場合や、センサの読み取り値をより長い期間にわたって記録する必要がある場合などです。また記録されたデータは、Arduinoの速度やメモリ容量に制限があるため、より処理能力の高いデバイス(例えばPC)で評価してもらう必要があるかもしれません。
不揮発性メモリ
コンピュータ技術の黎明期には、データの永久保存が課題となっていました。バイナリデータの中間記憶用の回路はすでに開発されていましたが、一定の電圧供給に依存し、電源に接続し続けないとデータが失われてしまいます。Arduinoのメインメモリも同じような挙動を示しています。
大容量のデータを回転ディスクに永久保存することを可能にした最初のハードディスクの開発と並行して、EPROM(Erasable Programmable Read-Only-Memory)が開発されました。これらの部品は、ハードディスクよりも記憶容量が小さいですが、コンピュータのボード上に直接インストールしてスペースを節約することができました。電源が入っていなくても、データはそのままです。欠点としては、電子的にモジュールに書き込めますが、消去のために外部から紫外線を照射する必要がありました。
その後、EPROMを発展させたEEPROM(Electrically Erasable Programmerable Read-Only-Memory)により、ようやくデータの読み書きが電子的に行われるようになりました。EEPROMは他のチップに組み込めるようになったので、マイクロコントローラに組み込まれていることが多く、初期値設定等の保存のために使用されています。
内部 EEPROM
Arduinoマイクロコントローラは、1024バイトのサイズの内部EEPROMを持っています。以下の例では、ユーザが設定した調光可能なLEDの明るさを永続的に保存するために使用します。すなわち、電源ON/OFFしてもユーザが設定したデータを失うことはありません。
そのために、2つのボタンで操作可能な制御システムをプログラムします。片方のボタンで明るさを上げ、もう片方のボタンで明るさを下げます。電源電圧を遮断し、後に再接続した場合、プログラムが最後に設定した明るさに戻す必要があります。 内部EEPROMを使用するには、EEPROM.hというライブラリが必要です。
#define BUTTON1 9 #define BUTTON2 8 #define LED 6 #include "EEPROM.h" byte Brightness; long Timer; void setup() { pinMode(BUTTON1,INPUT_PULLUP); pinMode(BUTTON2,INPUT_PULLUP); pinMode(LED,OUTPUT); Brightness = EEPROM.read(0); //(1) analogWrite(LED, Brightness); } void loop() { if(!digitalRead(BUTTON1)) { if(Brightness < 255) Brightness++; analogWrite(LED, Brightness); Timer = millis() + 1000; while(!digitalRead(BUTTON1)) //(2) { if(millis() > Timer) { if(Brightness < 255) Brightness++; analogWrite(LED, Brightness); delay(10); } } EEPROM.write(0,Brightness); //(3) } if(!digitalRead(BUTTON2)) //(4) { if(Brightness > 0) Brightness--; analogWrite(LED, Brightness); Timer = millis() + 1000; while(!digitalRead(BUTTON2)) { if(millis() > Timer) { if(Brightness > 0) Brightness--; analogWrite(LED, Brightness); delay(10); } } EEPROM.write(0,Brightness); } }
(1) ライブラリは、オブジェクトEEPROMを自動的に作成します。関数 read() を使用すると、EEPROM から特定のバイトを読み出すことができます。合計で1024バイトあるので、引数は0から1023までの範囲でなければなりません。戻り値は常にバイト(または char)型です。
(2) ここでは、これまでのプログラムよりも一歩進んで入力クエリを実行します。これまでは、空の実行処理文(条件文ではない)でwhileループを使ってキーが離されるのを待っていましたが、キーを長押しすることでより速く値を変更できるようにしたいと考えています。したがって、ループの直前には、変数timerに1秒先の値を設定します。ループ実行中にこの時点に到達した場合は、最大(255)まで連続的に明るさを増加させます。ボタン1つで輝度を1段階上げたり、ボタンを長押しして素早く値を変更したりできるようになりました。
(3) 輝度値を変更した後、EEPROM に書き込まれ、次のプログラム開始時に使用可能になります。関数 write() は、引数として渡すメモリアドレス (0 ~ 1023) と格納する8 ビットの値 (byte型またはchar型の変数)を求めます。
(4) LEDの輝度を下げるために、先ほどのプログラム部分を複製し、それに合わせて調整しました。関数 write() は 8 ビットの変数しか処理できないという条件から、ある種の制限が生じています。8 ビットより大きなデータ(intや文字列など)を格納する場合は、その大きさに応じていくつかの8ビットの値に分割しなければなりません。例えば、16ビットの変数aを以下のように分割し、後で再び組み合せられます。
... int a = 12345; EEPROM.write(0,a/256); //最上位ビット8bitを書き込みします。 EEPROM.write(1,a%256); //最下位8ビットを書き込みします。 ... a=EEPROM.read(0)*256+EEPROM.read(1); //EEPROMから読み込み、16bitとして併合させる ...
コメントを残す