\ AmazonにてArduino UNO R4 発売中!! /

Arduino 入門 番外編 13 【スリープモードによる消費電力の低減】

arduino-extra-edition-13-00 Arduino番外編
記事に広告(アフィリエイト広告)が含まれています。
スポンサーリンク

Arduino 入門
番外編 13
【スリープモードによる消費電力の低減】

こんにちは管理人のomoroyaです。

本記事は、「Arduino 入門 番外編 13 【スリープモードによる消費電力の低減】」です。

arduino 入門 番外編はarduinoの基本的なことを書いていく方向性にしたいと考えています。

 

Arduinoで遊んでいるとわかりますが、Arduinoには終了という概念がありません。

入門編にあるサンプルコードを見てみてください。

ひたすらループ内を実行しているだけです。

では、終了させるためにはどうしたら良いか?

電源を落とすしかないわけです・・・。

しかし、このままではバッテリー駆動している場合など困ります。

必要な場合のみ、電力を消費するようにしたいと思ったときに電源を落とす、入れるという動作を外部にさせる必要が生じます。

それを外部にさせようと思うと結構手間ですよね・・・。

そんな手間を省くために、スリープモード機能を利用するという手があります。

完全にOFFさせてしまうと、復帰が難しい。

そこで、低消費電力状態を作り出し、復帰は自分自身でできる状態にするといった具合です。

 

ということで本記事では、Arduinoのスリープモードによる消費電力低減について解説していきます。

 

 

Arduinoに供給される、電圧、電流、電力の確認にはUSBテスターを使用しています。

 

Arduinoをこれから始めたい、という方は下記の入門編からお読みください。

 

Lessonの入門編で使用しているArduinoは互換品です。

互換品とは言え、Arduinoはオープンソースであり複製して販売するのもライセンス的に問題なし。

そのため互換品の品質も悪くなく、それでいて値段は安いです。

正規品本体の値段で豊富な部品が多数ついています。

 

スポンサーリンク

Arduino スリープ機能ライブラリ

Arduinoのスリープ機能を使用するためにはライブラリを使用する必要があります。

スリープに関する主なライブラリは下記2つのようです。

  1.  avr/sleep.h
  2.  Narcoleptic.h

 

項目1は標準で実装されていますので#includeすれば使えます。

項目2は標準で実装されていませんので、ライブラリをインストールする必要があります。

 

本記事はで、項目1の標準実装されている「avr/sleep.h」について解説します。

Narcoleptic.hについては、別記事にて解説予定です。

 

上記以外にも消費電力を低減できるライブラリ、方法があります。

こちらに関しては、私も勉強中のため学習しながら記事をアップしていきます。

 

Arduino スリープ機能について

スリープ機能はおおまかに以下3つが考えられます。

 

・トリガーを利用したスリープ

例えば、「トリガー発生までスリープ⇒処理」を繰り返すことを想定。

 

・一定時間を指定したスリープ

例えば、「指定した時間スリープ⇒処理」を繰り返すことを想定。

 

・トリガースリープと一定時間スリープの併用

 

使用するライブラリによってできることが異なります。

必要に応じたライブラリを使用する必要があります。

 

sleep.h ライブラリの機能について

コード内での使い方は以下となります。

set_sleep_mode(mode);

 

modeの指定には以下の機能があります。

モード名
mode
内容
アイドル
SLEEP_MODE_IDLE
システムクロックは停止。
周辺回路へのクロックは供給。
復帰方法:
外部割込、ウオッチドックタイマー、ADC変化、RESETピン
ADCノイズ低減
SLEEP_MODE_ADC
ADC変換ノイズ低減。
パワーダウン
SLEEP_MODE_PWR_DOWN
外部発振器停止。
復帰方法:
外部割込、ウオッチドックタイマー、RESETピン
※もっとも消費電力が少ないモード
パワーセーブ
SLEEP_MODE_PWR_SAVE
タイマー用の外部発振器は動作。
復帰方法:
外部割込、ウオッチドックタイマー、RESETピン
スタンバイ
SLEEP_MODE_STANDBY
外部発振器が動作。
上記以外はパワーダウンと同じ。
パワーダウン
+外部割込み復帰
SLEEP_MODE_EXT_STANDBY
外部発振器が動作。
上記以外はパワーセーブと同じ。
本記事では割愛します。

 

より、詳細なスリープ機能と復帰条件がAVRマイコンのデータシートに記載されています。

arduino-extra-edition-13-01

 

データシートは下記サイトにて確認することができます。

Access Denied

 

スリープモード コマンド

#include <avr/sleep.h>で使用できるコマンドを解説します。

コマンド名 説明
set_sleep_mode(mode) スリープモードの選択。
SLEEP_MODE_IDLE※下記注意点参照
SLEEP_MODE_ADC
SLEEP_MODE_PWR_DOWN
SLEEP_MODE_PWR_SAVE
SLEEP_MODE_STANDBY
SLEEP_MODE_EXT_STANDBY
sleep_enable() スリープモードの許可
sleep_disable() スリープモード禁止
sleep_cpu() スリープモード実行
cli() 割込み禁止
sei() 割込み許可
sleep_mode() sleep_enable()
sleep_disable()
sleep_cpu()
を実行する。

 

SLEEP_MODE_IDLE 使用時の注意点
8bitタイマーを止めること!
このタイマーは復帰動作に関わるため、タイマーを止めないと・・・
IDLE⇒復帰⇒IDLE⇒復帰・・・
を繰り返すことになります。

SLEEP_MODE_IDLEだけ機能しない!

これに気づくのに、かなりの時間を要しました。

 

8bitタイマーを止める方法を以下に示します。

sleepモードに入る前にPRRを設定することでタイマーを止めることができます。

PRR = PRR | 0b00100000; //8bit タイマーの停止
sleep_mode();           //スリープモードの設定

PRRは「Power Reduction Register」と呼ばれているものです。

Arduinoの公式ページにも下記の記載があります。

When using SLEEP_MODE_IDLE, care must be taken to ensure that the 8-bit timer is disabled if you’re using the arduino layer. The timer can be disabled before entering sleep using the PRR = PRR | 0b00100000; statement and subsequently re-enabled once out of sleep using PRR = PRR & 0b00000000; .

https://playground.arduino.cc/Learning/ArduinoSleepCode/
より引用

 

Arduino スリープからの復帰について

Arduinoのスリープからの復帰について解説します。

 

復帰するためにはsleepライブラリの説明にある復帰方法を実行する必要があります。

例えば、外部割込、ウオッチドックタイマー、ADC変化、RESETピンなどです。

 

何も考えないで済むのは「RESETピン」です。

Arduinoの「RESETピン」を押せば復帰します。

 

それだと、あまりにも安直ですし、Arduinoで遊んでいる感じがないですよね・・・。

ということで、外部割込を使ってコードで対応します。

そのコマンドが下記の2つ。

attachInterrupt(interrupt, function, mode)
外部割込みが発生した時に実行する関数を指定。
detachInterrupt(interrupt)
指定した割り込みを停止。

 

引数パラメータは以下となります。

interrupt:割込み番号(ピン番号の割り当て)
function:割込み発生時に呼び出す関数
mode:割込みを発生させるトリガ

 

ピンの割り当てはボードによって異なります。

UNOに割り当てられている有効な割込み番号は以下となります。

デジタルピン2(int.0)
デジタルピン3(int.1)

 

modeに割り当てられるトリガは以下となります。

LOW:ピンがLOWのときに発生
CHANGE:ピンの状態が変化した時に発生
RISING:ピンの状態がLOWからHIGHに変わったとに発生
FALLING:ピンの状態がHIGHからLOWに変わったときに発生

 

では、これらをふまえてさっそく回路とコード作成です。

 

スリープモード サンプル回路図

回路はGNDとデジタルの2番ピン、プッシュボタンスイッチのみの単純なものです。

プッシュボタンスイッチを押すと、2番ピンがGNDに接続されるようにします。

 

回路図がこちら。

arduino-extra-edition-13-02

 

ブレッドボード図がこちら。

arduino-extra-edition-13-03

 

スリープモード サンプルコード

次に、スリープモードを実行するためのサンプルコードを作成していきます。

今回はスリープモードのテストのため、動作中は特に電子部品をつないで動作させていません。

割込みのためのデジタル入力の2番ピンはプルアップ指定をしておきます。

Switchを押すことで「GND」、スイッチが押されていないときは「VDD」となります。

//Arduino 番外編13 スリープモード編
//https://omoroya.com

#include <avr/sleep.h>
int wakePin = 2; //割り込み用のピン番号

void setup()
{
pinMode(wakePin, INPUT_PULLUP); //割込み用のピンを入力のプルアップあり指定
Serial.begin(9600);             //シリアルポートの指定
Serial.println("-- Sleep Test Start --");
}

void loop()
{
if (Serial.available()) {        //シリアルモニターからの入力の受け取り
int val = Serial.read();         //val変数に格納

if (val == 'i') {                //"i"が入力された場合 SLEEP_MODE_IDLE
Serial.println(" MODE <- IDLE"); //モニタに表示
standBy();                       //スタンバイ突入調整関数読み出し
set_sleep_mode(SLEEP_MODE_IDLE); //スリープモードの設定
interrupt();                     //割込み関数の呼び出し
}
if (val == 'a') {                //"a"が入力された場合 SLEEP_MODE_ADC
Serial.println(" MODE <- ADC");  //モニタに表示
standBy();                       //スタンバイ突入調整関数読み出し
set_sleep_mode(SLEEP_MODE_ADC);  //スリープモードの設定
interrupt();                     //割込み関数の呼び出し
}
if (val == 'd') {                //"d"が入力された場合 SLEEP_MODE_PWR_DOWN
Serial.println(" MODE <- DOWN"); //モニタに表示
standBy();                       //スタンバイ突入調整関数読み出し
set_sleep_mode(SLEEP_MODE_PWR_DOWN); //スリープモードの設定
interrupt();                     //割込み関数の呼び出し
}
if (val == 's') {                //"s"が入力された場合 SLEEP_MODE_PWR_SAVE
Serial.println(" MODE <- SAVE"); //モニタに表示
standBy();                       //スタンバイ突入調整関数読み出し
set_sleep_mode(SLEEP_MODE_PWR_SAVE); //スリープモードの設定
interrupt();                     //割込み関数の呼び出し
}
if (val == 'b') {                //"b"が入力された場合 SLEEP_MODE_STANDBY
Serial.println(" MODE <- STANDBY"); //モニタに表示
standBy();                       //スタンバイ突入調整関数読み出し
set_sleep_mode(SLEEP_MODE_STANDBY); //スリープモードの設定
interrupt();                     //割込み関数の呼び出し
}
}

Serial.println("In operation."); //モニタに動作中を表示
delay(500);
//何か動作させたい場合はここにコードを追加
//例えばLEDを点灯させるなど。
//setup関数での設定もお忘れなく!
}

//スタンバイ突入調整関数
void standBy(){
Serial.println("Arduino is standby."); //モニタ表示
delay(100);                            //時間調整
}

//割込み関数
void interrupt(){
attachInterrupt(0,wakeUp, LOW); //割り込み処理の設定、2番ピンがLowで復帰
PRR = PRR | 0b00100000;         //8bitタイマーdisable
sleep_mode();                   //スリープモードを有効にする
detachInterrupt(0);             //割り込み処理を解除する
}

void wakeUp(){
Serial.println("Wake up from standby."); //復帰時にシリアルモニターに表示
PRR = PRR & 0b00000000;                  //8bitタイマーenable
delay(30000);                            //時間調整
}

では、さっそく動かしてみましょう!

 

スリープモード 動作確認

全体回路がこちらとなります。

arduino-extra-edition-13-04

 

実際にコードを書き込んで動かしてみた結果がこちら。

mode 電流値
動作時 arduino-extra-edition-13-05
SLEEP_MODE_IDLE arduino-extra-edition-13-06
SLEEP_MODE_ADC arduino-extra-edition-13-07
SLEEP_MODE_PWR_DOWN arduino-extra-edition-13-08
SLEEP_MODE_PWR_SAVE arduino-extra-edition-13-09
SLEEP_MODE_STANDBY arduino-extra-edition-13-10

 

仕様書によるとSLEEP_MODE_PWR_DOWNが一番低電流になると見込んでいました。

一応、その通りとなりました。

 

しかし、思ったほど低電流となりません・・・。

他にも、色々と止める必要があったり、本記事では触れていないライブラリを使ったりすることでさらに低減できると考えます。

さらに学習して、低消費電力を目指したいと考えます。

 

まとめ

Arduino 入門 番外編 13 【スリープモードによる消費電力の低減】

いかがだったでしょうか?

バッテリーなどを使って、Arduinoを動かしたいと考えると動作していないときの待機電力を抑えたいものです。

 

本記事だけでは、まだまだ勉強不足だなと感じました。

まだ、学習していない低電力モードにも挑戦したいと思います。

 

冒頭でもお伝えしましたが、Arduinoに供給される電圧、電流、電力のモニターにはUSBテスターが便利です。

 

次回の番外編も、Arduinoの基本的なことについて情報を発信したいと考えています。

 

最後に

疑問点、質問などありましたら気軽にコメントください。

この電子部品の解説をしてほしい!などなどなんでもOKです。

リンク切れ、間違いなどあればコメントいただけると助かります。

 

Arduino入門編、番外編、お役立ち情報などなどサイトマップで記事一覧をぜひご確認ください。

 

Arduino入門編で使用しているUNOはAmazonにて購入可能です。

互換品とは言え、Arduinoはオープンソース。

複製して販売するのもライセンス的に問題なし。

 

そのため互換品の品質も悪くなく、それでいて値段は安いです。

正規品本体の値段程度で豊富な部品が多数ついています。

 

学習用、遊び用、お試し用には安価な互換品がおすすめです。

 

 

上記のものでも十分に多数の部品が入っていますが、最初からもっと多数の部品が入っているこちらもお勧めです。

 

Amazonでお得に買う方法

Amazonでお得に購入するなら、Amazonギフト券がおすすめです。

現金でチャージするたびに、チャージ額に応じたポイントが付与されます。

最大2.5%!!!(Amazonプライム会員ならさらにお得)

チャージ額(一回分) 一般 プライム会員
5,000円~19,999円 0.5% 1.0%
2,0000円~39,999円 1.0% 1.5%
40,000円~89,999円 1.5% 2.0%
90,000円~ 2.0% 2.5%

さらに、初回チャージで1000ポイントもらえるキャンペーンも実施中!

\Amazonギフト券 1000ポイントキャンペーン/
Amazonチャージ 初回購入で1000ポイントキャンペーン

 

補足情報
コンビニ・ATM・ネットバンクが対象
購入は1円単位で可能

コメント

  1. 匿名 より:

    はじめまして。
    ボード上のLEDの消費電流が結構大きいので、スリープの実験で消費電流の変化を見るならマイコンチップのATMEGA328Pと16MHzの水晶、水晶用のコンデンサ2個の最小構成で試した方がいいと思います。

    • omoroya omoroya より:

      コメントありがとうございます。
      消費電流の低減について深堀ができていないので、時間をみつけて色々と試してみたいと思います。

  2. まさき より:

    こんにちは
    ウォッチドッグタイマー等を使用した,スリープ時間を制御できる方法が知りたいです。

    • omoroya omoroya より:

      コメントありがとうございます。
      すみません、色々と立て込んでおりまして時間がありましたら検討します。

  3. 匿名 より:

    こんにちは。いつも記事拝見させていただいております。
    ウォッチドックタイマー等を使って,スリープ時間を制御できるようなプログラムについての解説が見たいです。

  4. iseda より:

    バッテリ駆動のディスペンサーを作っているのですが、省エネしたく、貴殿のスケッチを参考にして作ったのですが、どうしてもstandByでエラーになります。’standBy’ was not declared in this scope と出ます。このstandByというのは?なにものでしょう。対策ありませんでしょうか?

    //Arduino 番外編13 スリープモード編
    //https://omoroya.com

    #include
    Servo myservo1;
    const int IR_Sensor =2;
    int IR=0;

    #include
    #include

    void setup()
    {

    pinMode(IR_Sensor,INPUT);
    myservo1.attach(3);

    }

    void loop()
    {
    IR=digitalRead(IR_Sensor);
    myservo1.write(0);

    if (IR_Sensor == 0) { //”d”が入力された場合 SLEEP_MODE_PWR_DOWN
    SLEEP_MODE_PWR_DOWN
    standBy(); //スタンバイ突入調整関数読み出し
    set_sleep_mode(SLEEP_MODE_PWR_DOWN); //スリープモードの設定
    interrupt(); //割込み関数の呼び出し
    }

    }

    delay(500);
    //何か動作させたい場合はここにコードを追加
    //例えばLEDを点灯させるなど。
    //setup関数での設定もお忘れなく!
    myservo1.write(110);
    delay(1000);
    myservo1.write(0);

    }

    //スタンバイ突入調整関数
    void standBy(){

    delay(100); //時間調整
    }

    //割込み関数
    void interrupt(){
    attachInterrupt(0,wakeUp, 0); //割り込み処理の設定、2番ピンがLowで復帰
    PRR = PRR | 0b00100000; //8bitタイマーdisable
    sleep_mode(); //スリープモードを有効にする
    detachInterrupt(0); //割り込み処理を解除する
    }

    void wakeUp(){

    PRR = PRR & 0b00000000; //8bitタイマーenable
    delay(30000); //時間調整
    }

    • omoroya omoroya より:

      コメントありがとうございます。
      void loop(){
      }
      の{}の数がおかしいためと考えます。
      {}が対になっているか確認ください。

      下記1つ余計では?
      }
      } ← いらない。
      delay(500);

      上記を消して、defineなどが定義されていればエラーは出ませんでした。

タイトルとURLをコピーしました