はじめに
本記事ではATtiny202のスリープ機能について、自分なりに使い方をまとめてみました。タクトスイッチ1個を使い、スリープ状態への移行と復帰を制御するような具体例で試してみます。以前の記事に引き続き、少しでも参考になりましたら幸いです。
開発環境
- Windows 11 Home 22H2
- Arduino IDE 1.8.19
- megaTinyCore 2.6.10
回路構成
PA6にLED、PA7にタクトスイッチを接続しました。書き込み方法などは以前の記事でも解説しているため、今回は割愛します。
クロック周波数
クロック周波数はデフォルトだと20MHzに設定されているため、低電圧検出機能が4.2V付近で作動します。今回は乾電池2本で駆動することを想定しているため、このままだと正しく動作しません。そこで、閾値を最小値の1.8Vにまで下げてみたところ、クロック周波数も5MHz以下にまで落とす必要がありました。なお、設定した項目を適用するためにはヒューズビットを書き換える必要があります。Arduino開発環境を利用している場合はブートローダの書き込みを実行するだけなので簡単です。
クロック周波数は動作時の消費電流に影響します。しかし、スリープ時はCPUも停止するため、スリープ時の消費電流とは無関係です。
スリープ機能
以下の表で示すようにモードとしては3種類が用意されているみたいです。今回は最も消費電流が小さくなるモードを選択しました。RTCなど、ほとんどの機能は停止します。また、スリープ状態から復帰する手段としては3種類の中から選べます。今回は外部割り込みを選択しました。ピン状態の立ち下がり、立ち上がり、その両方を含む変化、あるいはローレベルのいずれかを検出できます。ATtiny202では全ての入出力ピンが外部割り込みに使用できますが、注意としては非同期で検出できる入出力ピンがPA2とPA6に限られている点です。つまり、その他はピン状態の変化、あるいはローレベルしか検出できません。
復帰に要する時間はオシレータの起動に要する時間とペリフェラルへ供給されるクロック信号6回に要する時間との合計です。
プログラム
タクトスイッチを1秒くらい押し続けるとスリープ状態に移行します。そして、タクトスイッチを再び押すとPA7がローレベルとなり、外部割り込みが発生してスリープ状態から復帰します。押し続ける時間により判定しているため、条件分岐を増やせば複数の機能を割り当てることも可能です。
#include <avr/sleep.h>
#define PIN_LED PIN_PA6
#define PIN_BUTTON PIN_PA7
//the interrupt is handled after waking up here
ISR(PORTA_PORT_vect) {
PORTA.INTFLAGS = PORT_INT7_bm; //clear the interrupt flag on PA7
}
void sleep() {
set_sleep_mode(SLEEP_MODE_PWR_DOWN); //select the power down sleep mode
noInterrupts(); //disable all interrupts
sleep_enable();
interrupts(); //enable all interrupts
PORTA.PIN7CTRL = PORT_PULLUPEN_bm | PORT_ISC_LEVEL_gc; //pull up PA7, trigger on low level
sleep_cpu(); //actually go to sleep here
//the program will continue after waking up from here
sleep_disable();
PORTA.PIN7CTRL = PORT_PULLUPEN_bm; //pull up PA7, turn off the pin change interrupt
}
void setup() {
pinMode(PIN_LED, OUTPUT);
pinMode(PIN_BUTTON, INPUT_PULLUP); //pull up PA7
//pull up unused pins to minimize current consumption
pinMode(PIN_PA1, INPUT_PULLUP);
pinMode(PIN_PA2, INPUT_PULLUP);
pinMode(PIN_PA0, INPUT_PULLUP);
pinMode(PIN_PA3, INPUT_PULLUP);
digitalWrite(PIN_LED, HIGH); //turn on the LED
}
void loop() {
static unsigned long lastTime;
static int lastState = HIGH;
int state = digitalRead(PIN_PA7); //read the state of the button
//detect the state change
if (state != lastState) {
if (state == LOW) { //the button is pressed
lastTime = millis();
} else { //the button is released
unsigned long interval = millis() - lastTime;
//the button is pressed for more than 1 second
if (interval > 1000) {
digitalWrite(PIN_LED, LOW); //turn off the LED
sleep(); //go to sleep
digitalWrite(PIN_LED, HIGH); //turn on the LED
}
}
}
lastState = state;
delay(10);
}
未使用ピンは内部プルアップを有効化し、電位を固定することで意図しない発振を防ぎ、より消費電流を抑えることができます。
検証
まずは動作時の消費電流を測定してみたところ、約2.735mAとなりました。LEDには約1.630mAの電流が流れていたのでATtiny202には差し引き約1.105mAの電流が流れていた計算となります。クロック周波数は5MHzです。また、検証時は単3形の乾電池2本を電源として使用し、電圧は約2.478Vでした。
次にスリープ時の消費電流を測定してみたところ、なんと約0.1uAとなりました。
このように消費電流を大幅に抑えることができました。起動時間も短く、非常に優秀だと思います。
おわりに
例えばLR44など、容量が100mAhくらいの小型なボタン電池2個で駆動することを仮定した場合、理論上は約114年も持つ計算となります。もちろん、動作時の消費電流を減らしていく工夫は必要ですが、スリープ時の消費電流は無視できるくらい小さいことが検証できました。活用の幅も広がりそうです。