disabilitare interrupt

La cosa sembrava semplicissima, ed invece non riesco a risolvere.

In pratica un interruttore rotativo (encoder) collegato al pin 3 di arduino nano scatena un interrupt, il problema è che l'interruttore rotativo come tutti gli interruttori del resto, ha un rimbalzo delle lamelle interne, che quindi genera una serie di impulsi nell'arco di qualche millisecondo.

Questo causa una serie di interrupt consecutivi, la soluzione doveva essere semplice, basta disabilitare l'interrupt dopo che si è scatenato, e riabilitarlo dopo una decina di millisecondi.

Problema non mi riesce di fare questa cosa, posto un codice di esempio utilizzato:

const byte interruptPin = 3;


void setup() {
  
  pinMode(interruptPin, INPUT_PULLUP);  
  attachInterrupt(digitalPinToInterrupt(interruptPin), test, FALLING);
  Serial.begin(9600);
}

void loop() {
  
}

void test()
{
detachInterrupt(digitalPinToInterrupt(interruptPin))
delay(1000);
Serial.println("interrupt");
attachInterrupt(digitalPinToInterrupt(interruptPin), test, FALLING);
 
}

Per provare ho appositamente impostato un tempo altissimo di 1 secondo, questo il risultato sul monitor seriale:

20:13:41.804 -> interrupt
20:13:41.804 -> interrupt
20:13:41.852 -> interrupt
20:13:41.852 -> interrupt

Non gli e ne frega nulla del detachInterrupt che dovrebbe disabilitare l'interrupt, l'interrupt viene generato 4 volte nell'arco di 5 millisecondi

Ma come è possibile?
E soprattutto come risolvo?

non so se c'è soluzione hardware...a livello software metterei una if nella ISR che verifica una flag...se false la metto true e faccio quello che devo fare e salvo micros() in una altra variabole...e nel loop verifico la flag e micros()...se variabile true e passato tot tempo resetto la flag

Oltre a usare il debounce hardware, tieni conto che delay() non funziona dentro l'interrupt handler.

Ciao, Ale.

GianlucaB: Come ti è stato detto, quando si tratta di segnali che riguardano gli interrupt, si DEVE fare il debouncing via hardware (... cosa che, in realtà, sarebbe bene fare SEMPRE e non solo nel caso degli interrupt) e non cercare di trovare alternative software che creano solo problemi.

Quindi ... tanti bei circuitini RC su pin d'ingresso di Arduino e passa la paura.

Guglielmo

Grazie a tutti, per adesso sembra che abbia risolto (forse) in un modo abbastanza semplice.
Se è vero che il delay non funziona all'interno della ISR, allora dentro alla ISR disabilito solo l'interrupt il resto del codice lo eseguo dentro al loop.

const byte interruptPin = 3;
bool flag=false;


void setup() {
  
  pinMode(interruptPin, INPUT_PULLUP);  
  attachInterrupt(digitalPinToInterrupt(interruptPin), test, LOW);
  Serial.begin(9600);
}

void loop() {
  if(flag)
  {
    delay(50);
    Serial.println("interrupt");
    attachInterrupt(digitalPinToInterrupt(interruptPin), test, LOW);
    flag=false;
    
  }
  
}

void test()
{
detachInterrupt(digitalPinToInterrupt(interruptPin));
flag=true;
 
}

Beh, insomma, non è proprio il modo migliore, hai solo spostato la polvere sotto al tappeto... :wink:

Metti 100nF tra ciascuna uscita dell'encoder e il comune e risolvi ogni problema. Se vuoi essere pignolo e/o l'encoder verrà usato moltissimo, metti 100 ohm in serie a ciascun condensatore per limitare la corrente alla chiusura dei contatti.
La regola è sempre la stessa: non mandare robaccia al microcontrollore demandando a lui l'ingrato compito di ripulire i segnali (salvo che tu abbia ordine di risparmiare fino all'ultimo centesimo per una produzione di 1000000 di pezzi... :slight_smile: ).

Non avrei voluto utilizzare ulteriori componenti, ma credo che abbiate ragione, un resistenza + condensatore per un antirimbalzo, e fine dei problemi.

GianlucaB:
Non avrei voluto utilizzare ulteriori componenti

Puoi anche saldare i due condensatori da 100 nF direttamente sui pin del rotary encoder, tanto sono molto piccoli: 30 secondi e risolvi.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.