2018年1月26日金曜日

スリープでATTiny85の消費電力を抑える

低い電力消費プロジェクトを作るために、
ATTiny85というマイクロコントローラーを勉強しています。

消費電力を抑えるためには、
マイクロコントローラーをスリープさせ、
インタラプトでマイクロコントローラーを起こすのが鍵です。

でも、ATTiny85は一つのピンインタラプトしかありません。
複数のピンで反応させるには、pin change interruptという方法が必要です。
Pin change interruptを可能にすれば、
ピンの電圧が変わると、インタラプトが発生します。

今回の例は二つのスイッチ(PB0とPB2につないである)によって、
どっちかがオープンになればLEDを点灯します。

まずは
GIMSK |= _BV(PCIE);
でpin change interruptを可能にします。

そして、インタラプトに使いたいピンを設定します。
PCMSK |= _BV(PCINT0);  // PB0
PCMSK |= _BV(PCINT2);  // PB2

次は使わないADCをオフに、スリープのモード()完全にパワーダウン)を設定します。
ADCSRA &= ~_BV(ADEN);
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sei();

そして、実際にスリープをさせます。
sleep_cpu();

で、起きたら、もとへ戻します。
cli();
PCMSK &= ~_BV(PCINT0);
PCMSK &= ~_BV(PCINT2);
sleep_disable();
ADCSRA |= _BV(ADEN);
sei();

サンプルコードはこれです。
#include <avr/sleep.h>
#include <avr/interrupt.h>

const int switchPin1                     = 0;
const int switchPin2                     = 2;
const int statusLED                     = 1;

void setup() 
{

    pinMode(switchPin1, INPUT);
    pinMode(switchPin2, INPUT);
    digitalWrite(switchPin1, HIGH);
    digitalWrite(switchPin2, HIGH);
    pinMode(statusLED, OUTPUT);
}

void sleep()
{

    GIMSK |= _BV(PCIE);  // Enable Pin Change Interrupts
    PCMSK |= _BV(PCINT0);  // Use PB0 as interrupt pin
    PCMSK |= _BV(PCINT2);  // Use PB2 as interrupt pin
    ADCSRA &= ~_BV(ADEN);  // ADC off
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    sleep_enable();  // Sets the Sleep Enable bit
    sei();  // Enable interrupts
    sleep_cpu();  // sleep

    cli();  // Disable interrupts
    PCMSK &= ~_BV(PCINT0);  // Turn off PB0 as interrupt pin
    PCMSK &= ~_BV(PCINT2);  / Turn off PB2 as interrupt pin
    sleep_disable();  // Clear SE bit
    ADCSRA |= _BV(ADEN); // ADC on

    sei();  // Enable interrupts
}

ISR(PCINT0_vect) {
}

void loop()
{
    sleep();
    if(digitalRead(switchPin1) == HIGH) {
        digitalWrite(statusLED, HIGH);
        delay(1000);
        digitalWrite(statusLED, LOW);
    }
    else
        digitalWrite(statusLED, LOW);
    if(digitalRead(switchPin2) == HIGH) {
        digitalWrite(statusLED, HIGH);
        delay(2000);
        digitalWrite(statusLED, LOW);
    }
    else
        digitalWrite(statusLED, LOW);
}


0 件のコメント:

コメントを投稿