Encoder rotativo e velocità lettura

Ciao a tutti,
ho un problema con un encoder rotativo meccanico(EC11K della Alps), ho collegato i pin A e B agli ingressi 2 e 3 dell'arduino, per poterlo gestire tramite interrupt e il pin C dell'encoder a GND; questo encoder al momento fa aumentare un counter ad ogni scatto della rotazione in un senso e lo decrementa se ruotato nell'altro.

Il tutto funziona perfettamente finchè l'encoder viene ruotato lentamente o comunque non troppo velocemente, se lo ruoto più velocemente invece "perde scatti" o addirittura torna indietro di uno o due valori nonostante stia ruotando nel senso dell'incremento del counter.

Ho provato a cercare sia qui sul forum che online e ho provato ad aggiungere due condensatori sulle uscite per il "debouncing" dei segnali ma il problema non è cambiato, credo sia un problema di velocità di lettura degli interrupt che oltre un certo valore non riescono più a tenere il passo con i segnali in ingresso.

Qualcuno ha già avuto esperienza in merito?
Cambiare encoder mettendone uno con meno scatti può avere senso o esistono modi via codice più semplici per ovviare al problema?

Allego qui il codice che sto utilizzando

#define outA 2
#define outB 3

volatile int counter=0;
volatile int aState, lastState;

void setup(){
  pinMode(outA, INPUT_PULLUP);
  pinMode(outB, INPUT_PULLUP);

  Serial.begin(9600);

  attachInterrupt(0, updateEncoder, CHANGE);
  attachInterrupt(1, updateEncoder, CHANGE);

}

void loop(){
  
}


void updateEncoder(){
  aState=digitalRead(outA);
  if(aState != lastState){
    if(digitalRead(outB) != aState){
      counter++;
    }else{
      counter--;
    }
    Serial.println(counter);
      }
  lastState = aState;
}

Grazie a tutti

Luca

Inizia con il togliere il Serial.print dall'interrupt, mettilo casomai nel loop.

Ciao, Ale.

Poi, scusa, perche' usi due interrupt ? ... la serie EC11K non ha i click meccanici ? ... se si, ti basta un solo interrupt, su una sola uscita, in "falling" ... poi nella ISR controlli solo lo stato dell'altra uscita, se e' alto incrementi, se e' basso decrementi (o viceversa, come serve a te), tutto qui ... :wink:

Etemenanki:
Poi, scusa, perche' usi due interrupt ? ... la serie EC11K non ha i click meccanici ? ... se si, ti basta un solo interrupt, su una sola uscita, in "falling" ... poi nella ISR controlli solo lo stato dell'altra uscita, se e' alto incrementi, se e' basso decrementi (o viceversa, come serve a te), tutto qui ... :wink:

Verissimo, grazie per la correzione dell'inutile rindondanza e avere un'interrupt libero mi fa comodo!!

la vera svolta nella lettura l'ho avuta grazie a questo

ilguargua:
Inizia con il togliere il Serial.print dall'interrupt, mettilo casomai nel loop.

quindi innanzi tutto grazie mille, avevo inserito la Serial.print() nell'ISR perchè mi serve la stampa del valore quando viene girato e volevo evitare inutili controlli nel loop, ora è così:

void loop(){
  if(counter!= lastCounter){
    Serial.println(counter);
    
    lastCounter=counter;
  }
}

per caso, per mio eccesso di zelo, sai dirmi come mai la stampa sulla seriale all'interno dell'ISR genera problemi alla lettura?

Grazie mille, siete stati davvero utili!!

Luca

La buona norma generale è che le isr siano più brevi possibili, cioè devono fare il minimo indispensabile e tutto il resto deve essere fatto fuori.

Questo perchè quando si verifica un dato evento, la normale esecuzione viene interrotta per eseguire la isr, mentre durante l'esecuzione dell'isr no.
Quindi tutti gli eventi che si verificano durante l'esecuzione del'isr vengono persi.
La gestione della seriale è un'operazione tendenzialmente lenta, per cui c'è il rischio che durante la stampa su seriale arrivino altre isr che se la Serial.print è nel loop principale, vengono intercettate, se invece è nella isr vengono perse.

Ci sono casi in cui gli eventi non vengono persi ma vengono messi in coda, ma in questo caso, quando vengono eseguiti, la situazione potrebbe essere ulteriormente cambiata, ad es. l'encoder potrebbe aver fatto altri avanzamenti e quindi si perdono passi.

Se la Serial.print è nel loop principale, magari tra una stampa e l'altra non conterai un singolo avanzamento ma anche più di uno, perchè la stampa non è stata sufficientemente veloce, ma l'isr sarà scattata e avrà contato tutti i passi correttamente, quindi la print successiva riporterà il conteggio giusto anche se non ne avrà stampato qualcuno nel mezzo.

Maurizio

Perfetto, super esaustivo.

Grazie davvero!

Luca

>lucamenny: Quando si quota un post, NON è necessario riportarlo (inutilmente) tutto; bastano poche righe per far capire di cosa si parla ed a cosa ci si riferisce, inoltre, se si risponde al post immediatamente precedente, normalmente NON è necessario alcun "quote" dato che è sottinteso. :slight_smile:

Gli utenti da device "mobile" (piccoli schermi) ringrazieranno per la cortesia :wink:

Guglielmo

P.S.: Ho eliminato io il "quote" dal tuo post qui sopra :wink:

Chiedo scusa,
grazie per il suggerimento!

Luca