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.
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
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.