前回までに試作したリモコン送信器の省電力化を検討します。省電力を実現するためにレジスタの直接操作などを行うため、Arduinoの作法には反すると思いますが、組み込み用途のい場合はこういうこともありだと思います。
●ペリフェラルのパワーダウン
Arduinoに使われてるマイクロプロセッサのATmega328は、ADCやUARTなどペリフェラル毎にパワーダウンさせる機能があります。レジスタを直接操作することになりますが、簡単にできるので試しました。
前回までの構成(WSN283なし)でアイドル状態の消費電流は16mAでしたが、ペリフェラルをパワーダウンさせたところ14mAまで減りました。さらに、WSN282上の電源LEDを外したところ、11mAぐらい減りました。
レジスタの図を添付しておきます(ATMEL AVRマニュアルより引用)。
パワーダウンの方法は、初期化処理に以下のコードを追加するだけです。
// ペリフェラルのパワーダウン TIMER0とTIMER2を除く PRR = (1<<PRTWI) | (1<<PRTIM1) | (1<<PRSPI) | (1<<PRUSART0) | (1<<PRADC);
ここではTIMER0とTIMER2を除いて、TWI、SPI、TIMER1、USART、ADCをパワーダウンさせています。
そのほか、ディジタル入力時に使われるDigital input buffersは、使っていない入力ポートでdisableにすることができます。DIDR1、DIDR0で設定できますが、今回はとりあえず省略。たぶん、入力ポートに設定しないと、イネーブルにならないと思います。
●スリープモード
電池駆動のリモコン送信器では無操作時にスリープモードにするのは常識ですが、これが使えると手っ取り早く省電力化ができます。そこで、自作リモコン送信器でも試してみます。
スリープに移行するのは簡単なのですが、問題はキー操作でスムーズにウェイクアップできるかと言うことです。
とりあえず、アイドルモードにしてみました。スリープ(アイドルモード)にするには次のコードを実行します。
#include <avr/sleep.h> (中略) set_sleep_mode(SLEEP_MODE_IDLE); (中略) sleep_mode(); //ここでsleepに移行
しかし、この方法(アイドルモード)ではTIMER2のオーバフローでウェイクアップしてしまうため、今回のアプリではすぐにウェイクアップして使えませんでした。
MEMO:スリープに入る前にTIMER2を停止させればよいか?
MEMO:今回ワンショット出力のため、スイッチのチャタリングは無視できないか、その場合、TIMER2とスイッチ入力ドライバは不要では?
シャットダウンモードにすればスリープします。ただし、起動に外部割り込み(D2またはD3)が必要です。実際、スイッチがD2、D3につながっているので、とりあえずウェイクアップさせることができますが、他のキーでは起動できません。Arduinoのマニュアルによると、シャットダウンモードでウェイクアップできるのはこの外部割り込みだけのようです。
MEMO:全スイッチ入力をORして外部割込みに入れれば簡単なんだが
とりあえず、覚え書きとして該当部分のコードを記載しておきます。
(中略) // ハンドラ、モードの登録(初期化処理内で実行しておく) attachInterrupt(0,intSv, CHANGE); // D2 attachInterrupt(1,intSv, CHANGE); // D3 (中略) // 割り込みサービスルーチン void intSv(void) { }
AVRのディジタル入力ポートには、ポート毎に状態変化で割り込みを発生させる機能があり、それが使えるかもしれませんが、Arduonoではサポートされていないようです。この状態変化割り込みでもウェイクアップさせることができるとは思うのですが、現状ではペンディングです。
ちなみにPICでリモコン送信器を作ったときには、PORTBの任意の入力ポートで状態変化割り込みでスリープ状態からウェイクアップできたため、うまく作動しました。
●8MHz 3.3V仕様で
クリスタル8MHz版のWSN282を用意し、プログラムを少し修正して単三型エネループ2本で駆動したところ、電源電圧2.7V、アイドル時の消費電流 2.6mAまで下がりました(ペリフェラルOFFあり、スリープなし)。
詳細は次回掲載します。