Domanda su Interrupt e funzione millis()

Ciao a tutti,
oggi mi sono messo a "giocare" con gli interrupt, ho riprodotto lo sketch del pulsante che attiva l'interrupt e fa accendere il led... ho letto sulle Reference che all'interno di un ISR la funzione millis() non funziona... io ho provato ad inserirla per gestire il rimbalzo del pulsante...e funziona.
Ho provato a stampare il contatore millis sul monitor seriale, ed effettivamente il contatore incrementa ad ogni pressione del pulsante, ma allora...esattamente cos'è che non viene incrementato o non gestito?
In basso il codice:

const byte LedPin = 4; //pin del led
const byte PulsanteInterrupt = 2; // connessione sul pin di Interrupt, nel Mega ce ne sono diversi rispetto ad Arduino Uno (2,3)...
volatile bool Stato = 0; // variabile di Stato per gestire l'Interrupt...
volatile unsigned long LastContatore = 0;
int Delay = 200;


void setup()
{
  Serial.begin(9600);
  pinMode(LedPin, OUTPUT);
  pinMode(PulsanteInterrupt, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(2), Cambio, FALLING);
  Serial.begin(9600);



}

void loop()
{


  digitalWrite (LedPin, Stato);
  Serial.println(LastContatore);


}



void Cambio()  //funzione richiamata dall'interrupt....
{

  volatile unsigned long Contatore = millis();

  if ((Contatore - LastContatore) > Delay)
  {

    Stato = !Stato;  //ogni volta che viene richiamata la funzione, si cambia lo stato di "Stato"...
    LastContatore = Contatore;


  }
}

Firestarter83:
che all'interno di un ISR la funzione millis() non funziona... io ho provato ad inserirla per gestire il rimbalzo del pulsante...e funziona

Sembra funzionare perché ti limiti a leggere il contatore. Ma il contatore avanza a sua volta tramite una ISR avviata dall'interrupt di un timer. Siccome viene gestita una sola ISR alla volta, se la tua ISR dura troppo a lungo il contatore rimane bloccato allo stesso valore.

>Firestarter83: ti ricordo che in conformità al regolamento, punto 7, devi editare il tuo post (quindi NON scrivendo un nuovo post, ma utilizzando il bottone More → Modify che si trova in basso a destra del tuo post) e racchiudere il codice all’interno dei tag CODE (… sono quelli che in edit inserisce il bottone con icona fatta così: </>, tutto a sinistra).

In pratica, tutto il tuo codice dovrà trovarsi racchiuso tra due tag: [code] _il _tuo_ codice_ [/code] così da non venire interpretato e non dare adito alla formazione di caratteri indesiderati o cattiva formattazione del testo. Grazie.

Guglielmo

>Claudio_FF: Claudio, cortesemente NON rispondere a chi prima non rispetta il regolamento. Grazie :wink:

Scusate per l’errore, non scrivo spesso sul forum, ho corretto.

Ciao Claudio, grazie per la risposta.
Si, la ISR usa il timer millis, quindi di fatto io sto leggendo il suo timer...? Perché il contatore millis lo vedo incrementarsi ogni qualvolta premo il pulsante... per capire: se volessi replicare il blocco del valore come potrei fare? Salvo il millis in un secondo contatore?

All'interno di una ISR vengono automaticamente disabilitati gli interupt finché non si esce.

Il contatore che viene restituito dalla funzione millis() è un contatore che viene incrementato, tramite un interrupt, sull'overflow di Timer0 ... è ovvio che se gli interrupt sono disabilitati, il contatore NON avanza.

Quindi, al di fuori della ISR, il contatore cammina, dentro una ISR il contatore è fermo.

Guglielmo

E’proprio questo che non e’chiaro Guglielmo: io la funzione millis l’ho inserita di proposito nella ISR, non nel loop, ed avanza...mi sfugge qualcosa...

Attento, nella ISR la puoi leggere, ho detto che NON avanza se resti nella ISR, ma se entri, la leggi, fai un confronto, e riesci ... ovviamente quando sei fuori avanza.

Leggi bene la tua ISR ...

void Cambio()  //funzione richiamata dall'interrupt....
{
  volatile unsigned long Contatore = millis();
  if ((Contatore - LastContatore) > Delay)
  {
    Stato = !Stato;  //ogni volta che viene richiamata la funzione, si cambia lo stato di "Stato"...
    LastContatore = Contatore;
  }
}

... entri, leggi il valore di millis() e lo metti in contatore (millis() in questo momento è congelato, ma tu leggi l'ultimo valore), fai un confronto, fai qulello che devi fare e ESCI ... ovvio che quando rientri millis() ha camminato !

Guglielmo

Grazie Guglielmo per il chiarimento, era questo il punto, l’incremento che vado a leggere e’quello che avanza al di fuori dell’ISR...quindi per dire, se mettessi un ciclo While che non si concretizza mai all’interno della ISR, e andassi a leggere il contatore, in questo caso mi accorgerei che il contatore non avanza... giusto?

Si, all'interno della ISR millis() NON avanza. Nota che, invece, micros() che NON usa interrupt, continua ad avanzare :slight_smile:

In ogni caso la regola è che una ISR DEVE essere la più breve possibilie e quindi NON si devono fare cicli di attesa al suo interno. La cosa migliore è alzare una flag per indicare che la ISR è scattata e poi, nel loop() verificare che tale flag e alzata e fare ciò che si deve fare :slight_smile:

Guglielmo

P.S.: Per una completa trattazione su ciò che si può fare e no, e sul meccansimo degli interrupt, ti consiglio QUESTA lettura.

Chiarissimo, grazie Guglielmo, leggero’ con attenzione l’articolo che mi hai suggerito.
Grazie
Giorgio