aiuto sleep mode

Ciao a tutti :) , sto realizzando un semplice rilevatore di gas con display nel quale impostare alcune cosette carine. Fin qui non ci sono problemi, ora però sto pensando di aumentare il risparmio energetico ma sorgono alcuni dubbi. (so che l'mq5 consuma circa 150mah e avrebbe poco senso risparmiare quei 20/30 mah dell'arduino però lo prendo come spunto per impare cose nuove).

Ho pensato di usare la pwr_down il problema è che l'mq5 mi restituisce un valore analogico che non posso usare per creare l'interrupt che mi risveglia l'atmega. Come posso fare? Esiste un modo, ad esempio tramite un trimmer nel quale imposto il valore di attivazione, per trasformare il valore analogico in digitale?

Prova a guardare QUI e le rispettive versioni che trove aggiornate su GitHub, QUI e QUI.

Puoi leggere anche QUI.

Guglielmo

cerca bene negli interrupt dell’avr, perché gli ADC possono generare un interrupt quando superano una soglia.
Hanno anche un comparatore interno…
scarica il datasheet e leggi.

Vi ringrazio per la risposta ma purtroppo non sono riuscito a farlo funzionare :sweat_smile: Altri consigli?

Purtroppo so già che il consiglio non ti piacerà ... è simile a quello di VB ... ... scaricati il datasheet e [u]STUDIA[/u] come funziona lo sleep (pag. 39 e seguenti) ed i timers (pag. 93 e seguenti) !

Guglielmo

P.S.: Per l'Analog Comparator ... pag. 234 e seguenti.

P.P.S.: Comunque proprio per studiare ... perché mettere in sleep la MCU su un Arduino non risparmia praticamente nulla (tutta la circuiteria introno comunque consuma), ed anche cercare di risparmiare quando si una un MQ5 ... è abbastanza inutile.

Ora provo a studiarmi un po il datasheet anche se la vedo un pò dura avendo scarse conoscenze in elettronica. Ho cercato su interent, nel forum in inglese ma niente, non sono riuscito a trovare niente che fa al caso mio…

Per la circuteria lo sò già che consuma parecchio, infatti ho costruito l’arduino su breadboard così da evitare regolatore di tensione e cose varie :D.

Per l’MQ5 mi rendo conto che è abbastanza inutile risparmiare quei 20/30 mah ma lo prendo come spunto per imparare qualcosa di nuovo. Se trovo qualcosa di buono vi tengo aggiornati, per ora vi ringrazio :wink:

Ragazzi buongiorno e buona domenica, ho studiato un pò il datasheet e da quello che ho capito dalla PWR_DOWN si può uscire solo con un reset esterno, Watchdog System Reset, Watchdog Interrupt, tramite un external level interrupt su INT0 or INT1, oppure con un pin change interrupt che penso sia proprio ciò che cerco. Così ho fatto qualche ricerca in rete, ho studiato un pò come funziona il tutto e sono arrivato a questo esempio di risveglio:

#include <avr/sleep.h>

const byte LEDLOOP = 8;
const byte LEDWAKE = 9;

ISR (PCINT1_vect)
 {
 // IMPOSTO IL PIN CHANGE INTERRUPT PER I PIN DA A0 AD A5
 
 // toggle LED
 digitalWrite (LEDWAKE, !digitalRead (LEDWAKE));
 }  // FINE PCINT1_vect

void setup () 
  {
  pinMode (LEDWAKE, OUTPUT);
  pinMode (LEDLOOP, OUTPUT);
  digitalWrite (A0, HIGH);  // IMPOSTO A0 COME PULL-UP
  
  // pin change interrupt
  PCMSK1 |= bit (PCINT8);  //  pin A0
  PCIFR  |= bit (PCIF1);   
  PCICR  |= bit (PCIE1);   // ABILITO PIN CHANGE INTERRUPT DA A0 AD A5
  
  }  // FINE SETUP

void loop () 
{
  
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);  
  sleep_mode ();  

//I LED LAMPEGGIANO DOPO IL RISVEGLIO

  digitalWrite (LEDLOOP, HIGH);
  delay (100);
  digitalWrite (LEDLOOP, LOW);
  delay (100);
  
  } // FINE loop

Il problema è che a me non funziona :sob: Ho anche provato a togliere la sleep dal codice ma vedo che non abilita proprio l’interrupt :(. Come posso fare?

P.S. ho collegato un semplice pulsante con GND ad un lato e l’altro al pin A0,visto che è già attiva tramite codice la resistenza di pull up.

... invece di impazzire con i vari registri (... dato che ancora non hai troppa esperienza), credo che sia meglio che ti studi ed usi la libreria EnableInterrupt che fa il "lavoro sporco" per te ;)

Guglielmo

P.S.: Nella cartella "examples" ci sono parecchi esempi d'uso ...

Ti ringrazio per il suggerimento ma ho risolto così:

#include <avr/sleep.h>

const byte LEDLOOP = 8;
const byte LEDWAKE = 9;

ISR (PCINT1_vect)
 {
 // IMPOSTO IL PIN CHANGE INTERRUPT PER I PIN DA A0 AD A5
 
 // toggle LED
 digitalWrite (LEDWAKE, !digitalRead (LEDWAKE));
 }  // FINE PCINT1_vect

void setup () 
  {
  Serial.begin(9600);
  pinMode (LEDWAKE, OUTPUT);
  pinMode (LEDLOOP, OUTPUT);
  //digitalWrite (A0, HIGH);  // IMPOSTO A0 COME PULL-UP
  
  // pin change interrupt
  PCMSK1 |= bit (PCINT8);  //  pin A0
  PCIFR  |= bit (PCIF1);   
  PCICR  |= bit (PCIE1);   // ABILITO PIN CHANGE INTERRUPT DA A0 AD A5
  
  }  // FINE SETUP

void loop () 
{
  Serial.println(analogRead(A0));
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);  
  sleep_mode ();  

//I LED LAMPEGGIANO DOPO IL RISVEGLIO
  Serial.println(analogRead(A0));
  digitalWrite (LEDLOOP, HIGH);
  delay (100);
  digitalWrite (LEDLOOP, LOW);
  delay (100);
  
  } // FINE loop

ho risolto disattivo semplicemente il pull up :sweat_smile: :sweat_smile:

Ho trovato invece anche un modo per farlo risvegliare tramite l’ADC con la libreria analogComp.h, in pratica sull’AIN0 imposto il valore di riferimento, se sull’AIN1 si supera si crea l’interrupt… Con questo però posso solo usare la PWR_IDLE e quindi il risparmio energetico sarà veramente minimo. Posto cmq il codice nel caso possa essere utile a qualcuno:

#include <avr/sleep.h>    //libreria indispensabile 
#include <avr/power.h>    
#include "analogComp.h"

//global variables
const byte LED13 = 8; //DEFINISCO IL LED
boolean enableLed = false; 

void wake() {}

void setup() {
    pinMode(LED13, OUTPUT); //LED COME OUTPUT
    analogComparator.setOn(INTERNAL_REFERENCE, AIN1);// IMPOSTO IL COMPARATORE    
}

//main loop
void loop() {
  sleep();//AVVIO LA FUNZIONE SLEEP
    if (enableLed) {// SE C'è L'INTERRUPT ENABLE LED DIVENTA ==1 E IL LED LAMPEGGIA
        digitalWrite(LED13, HIGH);
        delay(200);
        digitalWrite(LED13, LOW);
        enableLed = false;
    }
}

//interrupt to be raised by the analog comparator
void changeStatus() {
    enableLed = true; //let's inform the main loop that the condition has been reached by the analog comparator
}

void sleep(){
  analogComparator.enableInterrupt(changeStatus, CHANGE);// ABILITA L'INTERRUPT AL CAMBIAMENTO DI AIN1
  delay(100);

  set_sleep_mode(SLEEP_MODE_IDLE); //MANDA IN SLEEP
  sleep_enable();//ABILITAZIONE SLEEP
  sleep_mode();//METTE IN SLEEP
  //QUI RICOMINCIA IL CODICE DOPO IL RISVEGLIO
  sleep_disable(); //DISABILITA LO SLEEP
}

Per ora penso di aver risolto, appena mi arriverà il sensore farò ulteriori prove, ti ringrazio :slight_smile: