LoginSignup
1
0
記事投稿キャンペーン 「2024年!初アウトプットをしよう」

ATMega328PのSleep消費電力を調べてみた!WDTの比較

Posted at

今回はとある案件でSleepのウォッチドッグタイマを使用した場合と
使用しなかった場合の消費電力を調査する必要があったため
その記録をここに記載しておきます。

ハードウェア構成

写真だけですみません。
image.png

ソフトウェア

ウォッチドッグタイマを使用しないコード

#include <avr/sleep.h>  // スリープライブラリ #include  <avr/wdt.h>             // ウォッチドッグタイマー ライブラリ

const int led = 8;       // LEDピン
const int PUSH_PIN = 2;  // 外部入力割込みピン

void setup() {
  //pin set
  pinMode(led, OUTPUT);
  pinMode(PUSH_PIN, INPUT_PULLUP);
}

void loop() {
  digitalWrite(led, LOW);  // LED off
  interrupt();             // 割り込みのスリープを設定
  // 通常モードに復帰
  digitalWrite(led, HIGH);  // LED on
  delay(1000);              // 普通のdelay(比較用)
}

// 外部入力割込みによる起動処理
void wakeUp() {
  //外部入力割込みの際に行いたい処理を記載
}

// 割り込みスリープ処理
void interrupt() {
  Serial.flush();   // シリアルバッファが空になるまで待つ

  // ADCを停止(消費電流 147→27μA)
  ADCSRA &= ~(1 << ADEN);

  set_sleep_mode(SLEEP_MODE_PWR_DOWN);  // パワーダウンモード指定
  attachInterrupt(0, wakeUp, LOW);      // Lowになった時にwakeUp関数起動
  sleep_enable();

  // BODを停止(消費電流 27→6.5μA)
  MCUCR |= (1 << BODSE) | (1 << BODS);            // MCUCRのBODSとBODSEに1をセット
  MCUCR = (MCUCR & ~(1 << BODSE)) | (1 << BODS);  // すぐに(4クロック以内)BODSSEを0, BODSを1に設定

  asm("sleep");  // 3クロック以内にスリープに入る sleep_mode();では間に合わなかった

  sleep_disable();        // 割り込みででここから動作再開
  ADCSRA |= (1 << ADEN);  // ADCの電源をON(BODはハードウエアで自動再開される)
  detachInterrupt(0);     //外部割込み停止
}

結果

Sleep中
image.png
約0.16uA

ウォッチドッグタイマを使用したコード

#include <avr/sleep.h>  // スリープライブラリ #include  <avr/wdt.h>             // ウォッチドッグタイマー ライブラリ

const int led = 8;       // LEDピン
const int PUSH_PIN = 2;  // 外部入力割込みピン

void setup() {
  //pin set
  pinMode(led, OUTPUT);
  pinMode(PUSH_PIN, INPUT_PULLUP);
}

void loop() {
  digitalWrite(led, LOW);  // LED off
  interruptWDT(9,true);             // 割り込みのスリープを設定
  // 通常モードに復帰
  digitalWrite(led, HIGH);  // LED on
  delay(1000);              // 普通のdelay(比較用)
}

// 外部入力割込みによる起動処理
void wakeUp() {
  //外部入力割込みの際に行いたい処理を記載
}

// WDTがタイムアップした時に実行される処理
ISR(WDT_vect) {                         
  //ウォッチドッグの際に行いたい処理を記載
}

// 割り込みスリープ処理
void interruptWDT(unsigned long t, bool flag) {
  Serial.flush();  // シリアルバッファが空になるまで待つ
  if (flag == true) {
    delayWDT_setup(t);  // ウォッチドッグタイマー割り込み条件設定
  }
  // ADCを停止(消費電流 147→27μA)
  ADCSRA &= ~(1 << ADEN);

  set_sleep_mode(SLEEP_MODE_PWR_DOWN);  // パワーダウンモード指定
  attachInterrupt(0, wakeUp, LOW);      // Lowになった時にwakeUp関数起動
  sleep_enable();

  // BODを停止(消費電流 27→6.5μA)
  MCUCR |= (1 << BODSE) | (1 << BODS);            // MCUCRのBODSとBODSEに1をセット
  MCUCR = (MCUCR & ~(1 << BODSE)) | (1 << BODS);  // すぐに(4クロック以内)BODSSEを0, BODSを1に設定

  asm("sleep");  // 3クロック以内にスリープに入る sleep_mode();では間に合わなかった

  sleep_disable();        // 割り込みででここから動作再開
  ADCSRA |= (1 << ADEN);  // ADCの電源をON(BODはハードウエアで自動再開される)
  detachInterrupt(0);     //外部割込み停止
}

void delayWDT_setup(unsigned int ii) {  // ウォッチドッグタイマーをセット。
  // 引数はWDTCSRにセットするWDP0-WDP3の値。設定値と動作時間は概略下記
  // 0=16ms, 1=32ms, 2=64ms, 3=128ms, 4=250ms, 5=500ms
  // 6=1sec, 7=2sec, 8=4sec, 9=8sec
  byte bb;
  if (ii > 9) {  // 変な値を排除
    ii = 9;
  }
  bb = ii & 7;       // 下位3ビットをbbに
  if (ii > 7) {      // 7以上(7.8,9)なら
    bb |= (1 << 5);  // bbの5ビット目(WDP3)を1にする
  }
  bb |= (1 << WDCE);

  MCUSR &= ~(1 << WDRF);  // MCU Status Reg. Watchdog Reset Flag ->0
  // start timed sequence
  WDTCSR |= (1 << WDCE) | (1 << WDE);  // ウォッチドッグ変更許可(WDCEは4サイクルで自動リセット)
  // set new watchdog timeout value
  WDTCSR = bb;  // 制御レジスタを設定
  WDTCSR |= _BV(WDIE);
}

結果

Sleep中
image.png
約6.4uA

総括

WDTを未使用だと0.16uAとかなりの低消費だということがわかりました。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0