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

ATMega328pのSleepについて Sleep中も出力は保持する

Posted at

勘違いをしていたのでここに記録。

ATMega328PをSleepにした場合は、GPIOの出力が停止されるとなにかの
Webサイトで見たことがあったのでそう思っていたのだが、
実際には違っていた。

検証で使用したのは以下のプログラム

#include <avr/sleep.h>  // スリープライブラリ

#define WAKEUP 2  // スリープからの起動ピン
#define LED 3     // LEDピン

void setup() {
  delay(1000);

  pinMode(WAKEUP, INPUT_PULLUP);
  pinMode(LED, OUTPUT);

  delay(100);

  digitalWrite(LED, HIGH);  // LED on
  delay(3000);
  digitalWrite(LED, LOW);  // LED off
}


void loop() {
  //ATmegaスリープに入る
  digitalWrite(LED, HIGH);  // LED on
  // delay(200);
  interruptWDT(7, true);  // 2s & 割り込みのスリープを設定

  //スリープから復帰
  digitalWrite(LED, LOW);  // LED off
  delay(2000);  //後から消す

}


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

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

// 割り込みスリープ処理
// t=スリープ時間
// flag: true = WDTも起動 false = 外部割り込みのみ起動
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);
}

よく考えたら昔自分でもATMega328pでSleep中に出力していたのを
途中から思い出した・・・

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