ATtiny202小さいのでプラモデルに組み込みやすいのでボタン電池で動かしたいですよね。LED光らせる等の電力をあまり消費しない回路ならSleepモードを活用して電池を長持ちさせてみましょう。
目的
- 電池を長持ちさせる
- LEDを一定時間光らせて消す
- タクトスイッチで再度LEDを光らせる
実装の大枠
一定時間LEDをゆっくり光らせたら、スリープモードに入れて電力消費を抑える。スイッチをおしたら割り込みでまたLEDを光らせる。という具合です。
情報収集
古い製品群のATtinyはこちらの情報が有用です。
ATtiny202等の情報はこちらが有用です。
ATtiny202のデータシートではこちらの章を読むといいでしょう。
https://akizukidenshi.com/goodsaffix/attiny202-402.pdf
上記PDF のSleep Controller (SLPCTRL)辺りを読むと理解が深まると思います。
回路図
ソースコード
/* 10秒でスリープしてボタンで割り込みして再度光らせる
*/
#include <avr/sleep.h>
// Arduino pins
const int ledPin = 1; // PA7 LED pin
const int Button = 4; // PA3 pushbutton
const int Unused2 = 2; // PA1
const int Unused3 = 3; // PA2
const int Unused5 = 5; // PA0/UPDI
const int Unused6 = 0; // PA6
// Constants
const unsigned long sleep10Sec = 10000; // led sleep in 10 sec
ISR(PORTA_PORT_vect) {
PORTA.INTFLAGS = PORT_INT3_bm; // Clear PA3 interrupt flag
}
void setup() {
pinMode(ledPin, OUTPUT);
PORTA.PIN3CTRL = PORT_PULLUPEN_bm; // Same as pinMode(Button, INPUT_PULLUP);
// Don't leave unused pins floating
pinMode(Unused2, INPUT_PULLUP);
pinMode(Unused3, INPUT_PULLUP);
pinMode(Unused5, INPUT_PULLUP);
pinMode(Unused6, INPUT_PULLUP);
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
}
void loop () {
unsigned long StartTime = millis();
static unsigned int duty = 255;
while (millis() - StartTime < sleep10Sec) {
analogWrite(ledPin, duty--); //change the duty cycle
if (!duty) {
duty = 255;
}
delay(10);
}
// sleep in 10 sec
digitalWrite(ledPin, LOW);
delay(500);
PORTA.PIN3CTRL = PORT_PULLUPEN_bm | PORT_ISC_LEVEL_gc; // Pullup + Trigger on low level
sleep_cpu();
// Continue after interrupt
PORTA.PIN3CTRL = PORT_PULLUPEN_bm; // Turn off pin sense interrupt
}
ポイント
ATtinyのsleepライブラリをインクルード
#include <avr/sleep.h>
使用しないピンはプルアップで電圧の揺れを防止するとともに省電力化
SLEEP_MODE_PWR_DOWNにモード設定
- SLEEP_MODE_IDLE :Idle with all peripherals running for immediate wake-up
- SLEEP_MODE_STANDBY :Configurable operation of selected peripherals SleepWalking peripherals
- SLEEP_MODE_PWR_DOWN :with full data retention
sleep_enable() スリープモードを利用可能としています。
const int Unused2 = 2; // PA1
const int Unused3 = 3; // PA2
const int Unused5 = 5; // PA0/UPDI
const int Unused6 = 0; // PA6
void setup() {
.
.
.
// Don't leave unused pins floating
pinMode(Unused2, INPUT_PULLUP);
pinMode(Unused3, INPUT_PULLUP);
pinMode(Unused5, INPUT_PULLUP);
pinMode(Unused6, INPUT_PULLUP);
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
}
PA3のピン制御ポート(PORTA.PIN3CTRL)にプルアップとレベル割り込みを設定しています。
割り込みピンPA3をスイッチにしているので、スイッチを内部プルアップしてグランドに接続された時に割り込みが発生する!という意味です。
割り込みの種類はの四種類
- 両エッジ BOTHEEDGES
- 上昇感知エッジ RISING
- 落下感知エッジ FALLING
- 低レベルエッジ LEVEL
PORT_ISC_LEVEL_gc のLEVEL部分を上記に置き換えて指定します。
PORTA.PIN3CTRL = PORT_PULLUPEN_bm | PORT_ISC_LEVEL_gc; // Pullup + Trigger on low level
指定したスリープモードでスリープさせます。
sleep_cpu();
タクトスイッチを押した時の割り込み時にINTFLAGSをクリアするためのメソッド
この辺りはレジスタのオンオフなのでとりあえずこれで覚えておきましょう。
ISR(PORTA_PORT_vect) {
PORTA.INTFLAGS = PORT_INT3_bm; // Clear PA3 interrupt flag
}
sleep_cpu()でスリープに入った後に、タクトスイッチを押して割り込み発生させたらsleep_cpu()直後から再開されるので、すかさず制御ポートを元に戻しておきましょう。
sleep_cpu();
// Continue after interrupt
PORTA.PIN3CTRL = PORT_PULLUPEN_bm; // Turn off pin sense interrupt
電流実測
スリープ時の電流を測定してみましょう。電池のプラスとATtiny202のVCCの間にマルチメータを差し込んで
簡単ですが全体の電流を測定すると。
0.1μA かなり低電流になっており十分低い値となっています。
コメント