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

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

## ハードウェア構成
写真だけですみません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/68752d92-43fc-fe71-1757-2b53c4d515b1.png)

## ソフトウェア
### ウォッチドッグタイマを使用しないコード
```c
#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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/cda76a82-510b-4002-7466-99a8708ca981.png)
約0.16uA


### ウォッチドッグタイマを使用したコード
```c
#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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/3e7c69b1-12c8-07ce-16f1-bc894d20596a.png)
約6.4uA

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