マイコン全般に言えることですが、スリープさせると大分消費電力は抑えられます。
車載とか電池とかで使うときには必要な事だと思います。
ウォッチドッグタイマによる復帰についてはJean Rabault website - UiO-Using the Arduino Uno watchdog、
外部割り込みによる復帰はplayground.arduino.cc--Sleepに詳しく書かれています。
#ちょっと説明
- Arduinoのボードをそのまま使用すると省電力は望めません。AVR単体で動作させてください。
- 16Mhzでの動作となりますので、8Mhzで動作させるときは考慮してください。
- スリープ中はウォッチドッグタイマのオーバーフロー時のリセットを無効にして、割り込みのみでの使用となります。
#include <avr/wdt.h>
#include <avr/sleep.h>
//LED_PIN
#define LED_PIN (13)
//interrupt pin
#define ACC_IN (2)
volatile int sleep_flg=0;
volatile int counter;
int count_max=15;//4second * 15 = 60 second
int wait_minutes=1;//wait_time (minutes)
//arduino wakeup interrupt
void wakeUp()
{
//wdt_reset();
//sleep end
sleep_flg = 0;
//counter reset
counter = 0;
}
//watch dog timer setup
void wdt_set()
{
wdt_reset();
cli();
MCUSR = 0;
WDTCSR |= 0b00011000; //WDCE WDE set
WDTCSR = 0b01000000 | 0b100000;//WDIE set |WDIF set scale 4 seconds
sei();
}
//watch dog timer unset
void wdt_unset()
{
wdt_reset();
cli();
MCUSR = 0;
WDTCSR |= 0b00011000; //WDCE WDE set
WDTCSR = 0b00000000; //status clear
sei();
}
//watch dog timer call
ISR(WDT_vect)
{
//wdt_reset();
if(sleep_flg == 1)
{
counter++;
if( counter >= (count_max * wait_minutes))
{
//sleep end
sleep_flg = 0;
//counter reset
counter = 0;
}
}
else
{
}
}
//status reset
void init_status()
{
counter=0;
}
//sleep arduino
void sleep()
{
wdt_set(); //watch dog timer set
sleep_flg=1; //enable on sleep flag
set_sleep_mode(SLEEP_MODE_PWR_DOWN); //set sleep mode
attachInterrupt(0,wakeUp, RISING); //set level interrupt
while(sleep_flg){
noInterrupts(); //cli();
sleep_enable();
interrupts(); //seii();
sleep_cpu(); //cpu sleep
sleep_disable();
}
wdt_unset(); //watch dog timer unset
detachInterrupt(0); //unset level interrupt
}
//set up
void setup()
{
init_status();
pinMode(LED_PIN,OUTPUT);
pinMode(ACC_IN, INPUT);
}
//main loop
void loop()
{
digitalWrite(LED_PIN,HIGH);
delay(5000);
if(!digitalRead(ACC_IN))
{
digitalWrite(LED_PIN,LOW);
sleep(); //sleep
}
}
- 単体で動作と言いつつ思いっきりArduino unoをそのまま使ってますが、検証はこっちのが良いと思います。
- 割り込みのトリガになるのは2番ピンへの入力なので、適当な抵抗(1K~10KΩとか)を介してプルダウンしておきます。
- 起動後に5秒ほど本体の緑色のLEDが点灯してから消灯、スリープに移行します。
- スリープから復帰後は、ウォッチドッグタイマを無効にしていますが、本来の使い方ではここでウォッチドッグタイマのオーバーフロー時のリセットを有効にして、ループ内でタイマのリセットを行い、ハングした時にリセットが掛かるようすべきだと思います。
■割り込み
トリガピンに5Vの電圧が掛かるとスリープから解放されLEDが点灯します。トリガピンの入力がなくなると再びスリープへ
■ウォッチドッグタイマ
スリープの間隔ですが、基本となるスリープの時間が4秒程度(最大8秒)としているため、ウォッチトドッグタイマ復旧時に呼ばれるISR内でカウンタを使用しています。
スリープは割り込みが無くても(4152=)120秒毎にスリープから復帰してLEDが5秒点灯します。
`count_max`
変数と`wait_minutes`
変数で時間を合わせてます。
検証した所、数秒ラグがあります。
#メモ
ウォッチドッグタイマのインターバルの設定
WDTCSR = 0b01000000 | 0b100000; ← これの右側の値で設定します。
インターバルタイム | セットビット |
---|---|
16 ms | 0b000000 |
500 ms | 0b000101 |
1 second | 0b000110 |
2 seconds | 0b000111 |
4 seconds | 0b100000 |
8 seconds | 0b100001 |
##レジスタ
###MCUSR
MCUがどの要因によってリセットされたかの情報が格納されているレジスタ。
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|
---- | ---- | ---- | ---- | WDRF | BORF | EXTRF | PORF |
WDRF ウォッチドッグシステムリセット
BORF ブラウンアウトリセット
EXTRF 外部リセット
PORF パワーオンリセット
###WDTCSR
ウォッチドッグタイマの設定を行うレジスタ
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|
WDIF | WDIE | WDP3 | WDCE | WDE | WDP2 | WDP1 | WDP0 |
WDP0~3 ウォッチドッグタイマーインターバル(分周比)セット
WDCE ウォッチドッグ変更許可
WDE ウォッチドッグ・システムリセット許可
WDIE ウォッチドッグ・割込み許可
WDIF ウォッチドッグ・割込みフラグ