Interrupt e Sleep Mode per scheda Digispark (Attiny85)

Schema dei collegamenti tra scheda Digispark e pulsante

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.

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.

2 commenti su “Interrupt e Sleep Mode per scheda Digispark (Attiny85)”

  1. Buongiorno Ing. Paolo,
    ho visto che lei ha una discreta esperienza con le schede digispark.
    Mi chiedevo se per caso ha mai avuto occasione di collegare a queste schedine un sensore di distanza TOF VL53L0X sul I2C bus.
    Ci ho litigato parecchio ma senza uscirne. Sicuramente sbaglio qualcosa io che non ho esperienza con queste schedine..
    Ormai mi sono arreso e penso che al posto delle digispark userò , poichè avevo necessità di spazi ristretti, il chip Atmel328 con cui ho più esperienza e realizzato diversi circuiti, ma se dovesse venirle in mente qualcosa…
    Grazie e cordiali saluti

    1. Salve Massimo,
      sulla Digispark è possibile utilizzare il protocollo I2C sui pin P0 e P2.
      Però non mi è mai capitato di usarla con i sensori di distanza laser quindi non ho maggiori informazioni, potrebbe essere la libreria che non è compatibile con l’Attiny85.

Lascia un commento

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