Interrupt che si attiva

Ciao a tutti.
Sto costruendo una centralina per Apricancello con Uno R3 , utilizzando una scheda relè autocostruita
Utilizzo una routine di Debounce per testare la condizione di start e ho attivato l’interrupt 0 (pin 2) per bloccare il cancello.
Il pin 2 viene definito in INPUT e posto a HIGH; premendo il pulsante di blocco il pin 2 passa a LOW.
Mi succede che si attiva l’interrupts 0 anche se non premo il pulsante di blocco, in maniera casuale e ripetuta frequentemente.
La tensione sul pin 2 è 4,9V
La definizione dei pin è la seguente:

const int Start=9;  //  telecomando e chiave in apertura
const int StopKey=2;  //  stop da chiave
const int StopFTC=3;  // Stop da fotocellula

Nel setup() imposto l’interrupt con l’istruzione:

  pinMode(StopKey, INPUT);
  digitalWrite(StopKey, HIGH);
  attachInterrupt(0,iRoutInt0,FALLING);

nella routine RoutInt0 mi limito ad impostare ad 1 la variabile iStopKey dichiarata come VOLATILE
Nel loop() testo iStopKey e se è 1 lancio la routine Ferma().
ecco il codice:

void iRoutInt0()  // premuto tasto stop  attivata  da interrupt 0
{
  iStopKey=1;
}

 void loop()
 {
  if(iStopKey==1){     // Se vero attivato interrupt 0 Stop da chiave 
     Ferma();
     iStopKey=0;
  }

Osservazioni:
l’interrupts non si attiva quando siamo in attesa che venga premuto il tasto Start,
Non ho avuto problemi nella fase di test in breadboard, dove ho simulato i relè con dei Led
Franco

Apricancellox.ino (7.34 KB)

Me ne intendo poco di interrupt, ma vedendo il problema, mi viene da chiedere: sul pin 2 hai messo la resistenza di pullup?

La pull-up l'ha attivata:

 pinMode(StopKey, INPUT);
  digitalWrite(StopKey, HIGH);

Che comunque si può sostituire con una singola istruzione:

pinMode(StopKey, INPUT_PULLUP);

Mi chiedo una cosa, però. Perché nella ISR dell'interrupt non hai messo tutto il codice che hai messo in Ferma()? Essendo un interrupt importante (devi bloccare la discesa arrivato a fine corsa), non mi sembra logico impostare solo un flag e poi delegare il resto dell'operazione al programma principale. Se il programma principale per qualche motivo si blocca, anche il tuo fermo di sicurezza va a farsi benedire perché l'ISR imposta il flag ma il loop() non esegue il blocco della serranda ;)

Ciao, in effetti la routine Ferma() faceva parte dell'istruzione attachInterrupt(0,Ferma,FALLING); ma, quando le cose non funzionano si effettua la caccia alle streghe; visto che l'interrupt mi partiva da solo sono andato a rileggere quallo che hanno scritto gli altri e ho notato la raccomandazione di fare meno operazioni possibile all'interno di una routine di interrupt Qualche idea? Franco

P.S. Ho variato il prg per provare la centralina e metterla a punto: tolto 'interrupt ho messo un Debounce sul tasto StopKey all'inizio della routine loop(); funziona tutto ma l'interrupt mi servirebbe

Frankq_it:
visto che l’interrupt mi partiva da solo

Se partiva da solo vuol dire che vedeva il segnale basso sul pin. Sei sicuro che il sensore usato non desse sbalzi di tensione? Perché con FALLING tu fai partire l’interrupt sul fronte in discesa del segnale, anche se il segnale non si stabilizza su LOW.

sono andato a rileggere quallo che hanno scritto gli altri e ho notato la raccomandazione di fare meno operazioni possibile all’interno di una routine di interrupt

Questa è una raccomandazione dettata dal buon senso perché l’interrupt ferma il flusso principale del programma: più dura la ISR e più il programma principale resta sospeso.

Ma mettere tutto il codice che tu hai nella funzione Ferma() all’interno della ISR o chiamarla da fuori non cambia nulla. Casomai, attento al fatto che tu stampi con la seriale. La stampa seriale sull’Arduino è gestita da un interrupt, quindi quella è una cosa che può rallentare dato che finché non sei uscito dalla ISR dell’interrupt non parte la ISR che trasmette sulla seriale.

Ciao, Ho messo FALLING per semplicità, in quanto mettevo il pin 2 a HIGH e chiudendo il circuito và a massa LOW le condizioni di test sono queste: Arduino alimentato via USB, i BC547 che pilotano i relè a 12 V con alimentatore esterno, i rele comandano i motori a 220V. Mettendo sotto Debounce il tasto Stopkey non ho più interruzioni. Pensi che se inverto la logica (RISING al posto di FALLING) risolverei il problema? Franco

Credo che il problema sia nell'utilizzo di un pulsante con un interrupt. E' una cosa da non fare perché un pulsante spara una sequela di segnali da far paura, ed ogni segnale sarebbe una chiamata della ISR. Dovresti fare in modo, all'interno della ISR, di prendere per buono il primo segnale e basta, magari disattivando l'interrupt da dentro la ISR stessa e poi riattivandolo in seguito dal codice principale.

Ciao Leo La richiesta di fermare il cancello arriva o da un pulsante a chiave oppure dal telecomando. Posso e devo disabilitare l'interrupts nella routine Ferma() e poi riattivarlo una volta completata la procedura di stop + un delay da stabilire. Ma l'interrupts si attiva da solo durante l'esecuzione del prg. Premo il pulsante Start e nei 50 secondi che dura la sequenza parte l'interrupt 0.

attento al fatto che tu stampi con la seriale. La stampa seriale sull'Arduino è gestita da un interrupt, quindi quella è una cosa che può rallentare dato che finché non sei uscito dalla ISR dell'interrupt non parte la ISR che trasmette sulla seriale.

Nell'altro mio post segnalavo che il Serial monitor si blocca. Potrebbe verificarsi che Interrupts 0 e Serial.print vadino in conflitto Appena ho un attimo faccio delle prove. Franco

Ma l'interrupts si attiva da solo durante l'esecuzione del prg.

Se non lo hai attivato, no. Puoi attivarlo quando vuoi con attachInterrupt e disattivarlo con detachInterrupt. Se "stacchi" l'interrupt, il segnale in arrivo sul pin INT0 non fa più chiamare la ISR relativa.

Nell'altro mio post segnalavo che il Serial monitor si blocca. Potrebbe verificarsi che Interrupts 0 e Serial.print vadino in conflitto

Il compilatore avr-gcc di default rende tutte le ISR atomiche, ossia blocchi unici ininterrompibili da altre ISR. Siccome dall'IDE 1.0 la seriale invia e riceve i dati con interrupt, se tu sei nella ISR dell'INT0 la trasmissione e la ricezione dei dati si interrompe, e viceversa: nel momento in cui spedisci o ricevi un byte con la seriale, l'eventuale chiamata della ISR legata all'interrupt di INT0 viene registrata ma non eseguita finché non termini l'altra ISR della seriale.

A parte questo, mi pare di capire comunque che la strada per risolvere la cosa sia più semplice di quel che pareva inizialmente.

La richiesta di fermare il cancello arriva o da un pulsante a chiave oppure dal telecomando.

A questo punto io farei così. 1) soluzione con interrupt INT0 nella ISR metti solo ed esclusivamente l'assegnazione a true di una variabile booleana, togliendo tutto il resto. In questo modo puoi chiamare anche 100 volte la ISR, l'operazione è velocissima e non interferisce nè con sé stessa nè con altro codice: setti un flag e poi dal codice principale lo controlli, usando un semplice do..while per lo spostamento del cancello da cui esci o perché il flag è divenuto true oppure perché hai letto il telecomando oppure hai visto il rocchetto della chiave girato. 2) senza interrupt come sopra, ma mettendo una semplice lettura del pin del pulsante