Interrupt e Sleep Mode per scheda Digispark (Attiny85)

Lo Sleep Mode, come dice il nome stesso, è una modalità di funzionamento dei microcontrollori a bassissimo consumo di corrente.
È una modalità che viene generalmente usata nei sistemi alimentati a batteria in modo da preservarne la carica per il tempo più lungo possibile.

Il risveglio del microcontrollore può avvenire tramite un reset oppure tramite un interrupt, interno, ad esempio tramite il Watchdog oppure esterno tramite il cambio di stato di un pin.

Vedremo alcuni esempi di uso dello Sleep Mode e risveglio proprio tramite cambio di stato di un pin.

Il circuito che utilizzeremo è molto semplice ed il suo funzionamento è il seguente: ad ogni pressione del pulsante cambierà lo stato del led a bordo della scheda.
Tra un cambio di stato e il successivo il sistema entrerà in Sleep Mode per ridurre la corrente consumata.

Schema dei collegamenti tra scheda Digispark e pulsante

Il programma è il seguente:

 #include <avr/sleep.h>
 #include <avr/power.h>

 const byte LED = 1;  // D1 / pin 6
 const byte SWITCH = 2; // D2 / pin 7 / PCINT2

 volatile byte last_sw_state = HIGH;
 volatile byte led_state = HIGH;

 // Interrupt Service Request. Executed when the state of the pin changes
 ISR(PCINT0_vect)
 {
   byte sw_state;
   sw_state = digitalRead(SWITCH); // or faster: (PINB >> PINB2) & 1
   if (last_sw_state==HIGH && sw_state==LOW) { // Falling edge
     led_state = !led_state;
   }
   last_sw_state = sw_state;
 }

 void setup()
 {
   pinMode (LED, OUTPUT);
   pinMode (SWITCH, INPUT_PULLUP);

   cli(); // Disable interrupt
   // Pin change interrupt
   PCMSK  |= bit (PCINT2);  // D2 / pin 7
   GIFR   |= bit (PCIF);    // Clear any outstanding interrupts
   GIMSK  |= bit (PCIE);    // Enable pin change interrupts
   sei(); // Enable interrupt
 }

 void loop()
 {
   digitalWrite (LED, led_state);
   enter_sleep ();
 }

 void enter_sleep ()
 {
   // Enter sleep
   set_sleep_mode(SLEEP_MODE_PWR_DOWN);
   ADCSRA = 0; // Turn off ADC
   power_all_disable (); // Power off ADC, Timer 0 and 1, serial interface
   sleep_enable();
   sleep_cpu();

   // …zzz

   // Wake up
   sleep_disable();
   power_all_enable(); // Power everything back on
 }

Oppure possiamo cambiare la logica di funzionamento e far sì che il led cambi di stato solo in seguito alla pressione del pulsante per almeno un secondo:

#include <avr/sleep.h>
#include <avr/power.h>

const byte LED = 1;  // D1 / pin 2
const byte SWITCH = 2; // D2 / pin 6 / PCINT2
volatile byte last_sw_state = HIGH;
volatile byte led_state = LOW;
volatile long last_sw_change_millis = 0;
byte sw_state = HIGH;
long sw_read_millis = 0;

 // Interrupt Service Request. Executed when the state of the pin changes
 ISR(PCINT0_vect)
 {
 }
 
void setup()
{
  pinMode (LED, OUTPUT);
  pinMode (SWITCH, INPUT_PULLUP);

  cli(); // Disable interrupt
  // Pin change interrupt
  PCMSK  |= bit (PCINT2);  // D2 / pin 7
  GIFR   |= bit (PCIF);    // Clear any outstanding interrupts
  GIMSK  |= bit (PCIE);    // Enable pin change interrupts
  sei(); // Enable interrupt
}

void loop()
{
  sw_state = digitalRead(SWITCH); // or faster: (PINB >> PINB2) & 1
  sw_read_millis = millis();
  if (last_sw_state==HIGH && sw_state==LOW) { // Falling edge
      last_sw_change_millis = sw_read_millis;
  }
  if (last_sw_state==LOW && sw_state==LOW &&
      sw_read_millis-last_sw_change_millis>1000) {
    led_state = !led_state;    
    digitalWrite (LED, led_state);
    enter_sleep ();
  }
  last_sw_state = sw_state; 
}

void enter_sleep ()
{
  // Enter sleep
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  ADCSRA = 0; // Turn off ADC
  power_all_disable (); // Power off ADC, Timer 0 and 1, serial interface
  sleep_enable();
  sleep_cpu();

 // …zzz

 // Wake up
  sleep_disable();
  power_all_enable(); // Power everything back on
}

Un po’ di misure

Nelle mie prove la corrente assorbita dall’intera scheda senza Sleep Mode è di circa 15 mA con il led spento e di circa 17 mA con il led acceso.
Attivando lo Sleep Mode i consumi calano a circa 5 mA con il led spento e circa 7 mA con il led acceso.

Ovviamente la scheda Digispark con cui ho fatto le prove ha un secondo led sempre acceso (che indica la presenza di alimentazione) e diversi altri componenti passivi che impediscono di scendere sotto certi consumi ma il datasheet dell’Attiny85 indica, per il solo microcontrollore, consumi dell’ordine di qualche µA quando è in Sleep Mode.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *