- バッテリー駆動をさせるためにArduinoの消費電力を抑えたい
- 短いコードで、とりあえずスリープモードを使いたい
- モードによる消費電力の違いを知りたい
Arduinoのプログラムを停止する際に「delay()」などを使うと思います。
これは内部のタイマーを動かして時間をカウントしているため、Arduino内でタイマーをカウントするループをしています。
そのため、何もしていないのに電力を消費します。
Arduinoをバッテリーなどで長期運用したいときには痛い電力消費になります。
そこでスリープモードを使って、できるだけ消費電力を抑えて、Arduinoを運用していく方法を勉強していきたいと思います。
- スリープモードとは
- スリープモードの種類
- 作成するプログラムの流れ
- プログラム作成
- モードごとの消費電力
スリープモードとは
スリープモードは、Arduinoを停止(スリープ)させておくモードです。Arduinoの動作を必要最小限にして、消費電力を節約できます。
スリープモードの種類
Arduinoでスリープ機能を使うためのライブラリは複数あるようですが、今回は「avr/sleep.h」を使いたいと思います。
「avr/sleep.h」では6種類のスリープモードがあります。
モードの種類 | コード |
アイドルモード | SLEEP_MODE_IDLE |
ADCノイズ低減モード | SLEEP_MODE_ADC |
パワーダウンモード | SLEEP_MODE_PWR_DOWN |
パワーセーブモード | SLEEP_MODE_PWR_SAVE |
スタンバイモード | SLEEP_MODE_STANDBY |
EXTスタンバイモード | SLEEP_MODE_EXT_STANDBY |
詳しい違いについてはArduinoに搭載されているPIC「ATmega328P」のデータシートに書いてあります。
実際に各モードを動かしてみて、どのくらい消費電力に差が出るのか、試してみたいと思います。
作成するプログラムの流れ
今回使用するプログラムの流れを図にしました。
プログラム作成
1 2 3 4 |
#include <avr/sleep.h> int SleepModePin = 12; //Sleep_Modeピン int valsleep = 0; // 後にSleep_Modeピンの値を格納する変数 int WakeUpPin = 2; //復帰ピン |
ライブラリ「avr/sleep.h」の読み込みをします。また、使用するピンにわかりやすい名前を付けました。12ピンをスリープモードにするためのピン、2ピンを復帰するためのピンとしています。
1 2 3 4 5 |
void setup(){ pinMode(SleepModePin, INPUT_PULLUP); pinMode(WakeUpPin, INPUT_PULLUP); set_sleep_mode(SLEEP_MODE_PWR_DOWN); } |
先ほど指定した2及び12ピンのピンモードを設定します。2つとも信号を受ける側なので「INPUT」とし、「PULLUP」しておくことで、何もしていないときは「HIGH」にしておきます。
また、スリープモードの設定もここで行っています。set_sleep_mode(SLEEP_MODE_●●●)の赤字の部分にモードの種類に応じたコードを入れることで好きなスリープモードにできます。
※アイドルモードについての注意事項を後に記載
1 2 3 4 5 6 |
void loop(){ valsleep = digitalRead(SleepModePin); if (valsleep == LOW){ interrupt(); } } |
12ピン「SleepModePin」を読み込み、「LOW」の場合は「interrupt()」の部分で復帰のための割込み関数を読み出します。
1 2 3 4 5 |
void interrupt(){ attachInterrupt(0,WakeUp, LOW); sleep_mode(); detachInterrupt(0); } |
この部分では先ほど読み込んだ割込み関数「interrupt()」の設定を行います。「attachInterrupt()」にて割込み時の処理を指定します。入力するパラメータとしては3つになります。左から
1 | 割込み信号を受取るためのピン UNOの場合は2ピンと3ピン 2ピンで受けたい場合は「0」、3ピンで受けたい場合は「1」にする |
2 | 割込み時に呼び出す関数 |
3 | 割込みを発生させるトリガー 4種類あり LOW:ピンがLOWのとき発生 →本コードで使用しているトリガー CHANGE:ピンの状態が変化したときに発生 RISING:ピンの状態がLOWからHIGHに変わったときに発生 FALLING:ピンの状態がHIGHからLOWに変わったときに発生 |
割込み信号を受取るためのピンに割込みを発生させるトリガーの値が入った場合、割込み時に呼び出す関数が動きをします。
違った場合は何も発生せずに次の行の「sleep_mode()」を読むためスリープモードになります。
1 2 |
void WakeUp(){ } |
割込み時に呼び出す関数に復帰時の処理を入れます。 何も無ければ空欄でOKですが、関数自体は作らなければ「attachInterrupt()」が使えませんので必要不可欠です。
下記にすべてをまとめとプログラムを掲載します。
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 |
#include <avr/sleep.h> int SleepModePin = 12; //Sleep_Modeピン int valsleep = 0; // 後にSleep_Modeピンの値を格納する変数 int WakeUpPin = 2; //復帰ピン void setup(){ pinMode(SleepModePin, INPUT_PULLUP); pinMode(WakeUpPin, INPUT_PULLUP); set_sleep_mode(SLEEP_MODE_PWR_DOWN); } void loop(){ valsleep = digitalRead(SleepModePin); if (valsleep == LOW){ interrupt(); } } void interrupt(){ attachInterrupt(0,WakeUp, LOW); sleep_mode(); detachInterrupt(0); } void WakeUp(){ } |
※アイドルモード
アイドルモードについては8bitタイマーを停止する必要があります。
停止していないとスリープと復帰を繰り返すような動作をします。
スリープ前に8bitタイマーを停止するコードを、復帰時は8bitタイマーを起動させるコードが必要になります。
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 |
#include <avr/sleep.h> int SleepModePin = 12; //Sleep_Modeピン int valsleep = 0; // 後にSleep_Modeピンの値を格納する変数 int WakeUpPin = 2; //復帰ピン void setup(){ pinMode(SleepModePin, INPUT_PULLUP); pinMode(WakeUpPin, INPUT_PULLUP); set_sleep_mode(SLEEP_MODE_IDLE); } void loop(){ valsleep = digitalRead(SleepModePin); if (valsleep == LOW){ interrupt(); } } void interrupt(){ attachInterrupt(0,WakeUp, LOW); PRR = PRR | 0b00100000; //8bitタイマー停止 sleep_mode(); detachInterrupt(0); } void WakeUp(){ PRR = PRR & 0b00000000; //8bitタイマー起動 } |
モードごとの消費電力とまとめ
配線は上の写真のように行いました。電源は5VのACアダプタから取っております。赤いタクトスイッチは2ピンへ、青いタクトスイッチは12ピンに繋がっています。
青いタクトスイッチを押すと12ピンはGNDに繋がるためスリープモードとなり、その後赤いタクトスイッチを押すと2ピンがGNDに繋がるためArduinoは復帰します。
これでタクトスイッチでスリープモードと復帰を自由に制御できます。
各モードの消費電力を計測してみました。
モード | 電流mA | 電力W |
スリープ未使用 | 30 | 0.15 |
アイドルモード | 25 | 0.125 |
ADCノイズ低減モード | 23 | 0.115 |
パワーダウンモード | 20 | 0.1 |
パワーセーブモード | 21 | 0.105 |
スタンバイモード | 20 | 0.1 |
EXTスタンバイモード | 21 | 0.105 |
データシート上ではパワーダウンモードが一番機能制限がかかるので消費電力が低いと思われます。特に理由がなければパワーダウンモードを使っていきたいと思います。