Debounce hardware per encoder rotativo

Salve a tutti, per il mio progetto prevedo l'utilizzo di un encoder rotatativo (e del relativo pulsante) per la navigazione fra i menu e la selezione delle varie voci.
Mi sto facendo una cultura sui debouncer hardware (dai semplici RC ad integrati ecc) ma la confusione regna sovrana... l'encoder sarà gestito da uno degli interrupt del Mega2560 (solo la rotazione, non il click perché non penso mi serva un interrupt per questo)... mi chiedo se per la rotazione sia effettivamente necessario un debouncer hardware... per il click ne metterò in piedi uno software... che ne dite? il mio problema è che non ho in casa condensatori ne' ho negozi di elettronica nelle vicinanze per cui comprare uno stock di condensatori online che costano più di spedizione che altro, beh, se posso evitare....
che mi dite?
come sempre grazie
Andrea

Se usi gli interrupt non è che hai tanta scelta... devi usare la soluzione hardware quella software è esclusa con gli interrupt, per il click puoi fare come meglio credi quindi anche software può andar bene

fabpolli:
Se usi gli interrupt non è che hai tanta scelta… devi usare la soluzione hardware quella software è esclusa con gli interrupt, per il click puoi fare come meglio credi quindi anche software può andar bene

Stavo valutando che tutto sommato anche il discorso degli interrupt tenendo conto della “bassa” velocità di commutazione forse non è nemmeno così importante, che ne dici?

Ho trovato questa libreria che permette di gestire un rotary encoder: GitHub - brianlow/Rotary: Rotary encoder library for Arduino

Che ha come esempio questo:

/*
    Rotary Encoder - Interrupt Example
    
    The circuit:
    * encoder pin A to Arduino pin 2
    * encoder pin B to Arduino pin 3
    * encoder ground pin to ground (GND)
*/

#include <Rotary.h>

Rotary r = Rotary(2, 3);

void setup() {
  Serial.begin(9600);
  PCICR |= (1 << PCIE2);
  PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);
  sei();
}

void loop() {

}

ISR(PCINT2_vect) {
  unsigned char result = r.process();
  if (result == DIR_NONE) {
    // do nothing
  }
  else if (result == DIR_CW) {
    Serial.println("ClockWise");
  }
  else if (result == DIR_CCW) {
    Serial.println("CounterClockWise");
  }
}

Pensavo di provarlo…

the_dragonlord:
1. Stavo valutando che tutto sommato anche il discorso degli interrupt tenendo conto della "bassa" velocità di commutazione forse non è nemmeno così importante, che ne dici?

2. Ho trovato questa libreria che permette di gestire un rotary encoder: GitHub - brianlow/Rotary: Rotary encoder library for Arduino

... emmm ... le due cose sono leggermente in contraddizione visto che quella libreria fa proprio uso degli interrupts ::slight_smile:

Guglielmo

gpb01:
… emmm … le due cose sono leggermente in contraddizione visto che quella libreria fa proprio uso degli interrupts ::slight_smile:

Guglielmo

Sì sì, scusa Gugliemo hai ragione, ho dato sfogo a due ragionamenti in parallelo facendo partire le mani prima del cervello, volevo dire che ho trovato questa libreria che mi gestisce gli interrupt ma mi stavo anche contemporaneamente interrogando sulla necessità o meno di utilizzarli…anche perchè io ODIO usare cose “prefabbricate” senza capire cosa faccio e la sintassi:

    PCICR |= (1 << PCIE2);
  PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);

Non la capisco, nel senso che ho visto che PCICR, PCIE1 ecc. sono delle costanti predefinite ma, purtroppo, non ho ancora capito cosa sono e a cosa servono…purtroppo come sempre il materiale in rete è infinito e per chi è alle prime armi la confuzione (e mal di testa) sono una costante…da quello che ho capito quelle due istruzioni servono per “confugurare” l’interrupt, però non capisco il legame fra PCICE2 ed i pin 2 o 3…poi su PCIMT18 e PCINT19 proprio sono andato alla deriva…riesci a farmi un po’ di chiarezza o ad indicarmi qualcosa da studiare in proposito che sia abbordabile?

Grazie
Andrea

E' programmazione a "basso livello" utilizzando direttamente i "registri" interni della MCU. E' tutto ampiamente descritto nel datasheet del ATmega328P e i nomi dei registri sono gli stessi che trovi li.

Esempio:
PCICR: Pin Change Interrupt Control Register
PCIE2: è il bit 2 di detto registro, Pin Change Interrupt Enable 2
... e così via. Ovviamnete, senza studiare il datasheet e senza capire il funzionamneto HW delle varie cose ... è impossibile capire cosa fanno quelle righe.

Ah ... NON sono esattamente cose per chi si avvicina ad Arduino ed è "alle prime armi" ... ::slight_smile:

Guglielmo

Edit: ... nota che non sta usando i classici interrupt che conosci sui due pin di Arduno, sta utilizzando i "Pin Change Interrupt" che si possono attivare anche su altri pin.

gpb01:
E' programmazione a "basso livello" utilizzando direttamente i "registri" interni della MCU. E' tutto ampiamente descritto nel datasheet del ATmega328P e i nomi dei registri sono gli stessi che trovi li.

Esempio:
PCICR: Pin Change Interrupt Control Register
PCIE2: è il bit 2 di detto registro, Pin Change Interrupt Enable 2
... e così via. Ovviamnete, senza studiare il datasheet e senza capire il funzionamneto HW delle varie cose ... è impossibile capire cosa fanno quelle righe.

Ovviamente NON sono esattamente cose per chi si avvicina ad Arduino ed è "alle prime armi" ... ::slight_smile:

Guglielmo

Edit: ... nota che non sta usando i classici interrupt che conosci sui due pin di Arduno, sta utilizzando i "Pin Change Interrupt" che si possono attivare anche su altri pin.

Grazie! Mi ci metto d'impegno a studiare allora

Guarda che stai parlando di un'encoder ruotato a mano per cambiare i menu, non di un'encoder da motore a 200 o piu passi per giro ... a quelle velocita', anche un solo interrupt sarebbe piu che sufficente ... ci colleghi uno dei due pin e lo agganci al corretto cambio di stato (rising se il pin chiude a VCC, falling se chiude a massa), poi nella ISR controlli lo stato dell'altro, se e' alto stai girando in un senso, se e' basso stai girando nell'altro, sempre ...

Come debounce basta un condensatorino da 10n o valori simili fra il pin e massa, anche per il click ... puoi pure recuperarli da qualche scheda, se non hai un negozio a portata di mano ...

Etemenanki:
Come debounce basta un condensatorino da 10n o valori simili fra il pin e massa, anche per il click ... puoi pure recuperarli da qualche scheda, se non hai un negozio a portata di mano ...

Grazie, purtroppo anche il discorso di reperire una scheda da cui smontare non è proponibile, proverò a vedere cosa riesco a trovare....10nF quindi poliestere o ceramico, giusto?

Si ... o un qualsiasi altro valore simile ... dato che serve per pilotare un'interrupt, i soliti 100n potrebbero essere troppi, ma qualsiasi cosa fra 4.7n e 47n dovrebbe andare ... o comunque aiutare ad eliminare eventuali disturbi da rimbalzo ...

Etemenanki:
Si ... o un qualsiasi altro valore simile ... dato che serve per pilotare un'interrupt, i soliti 100n potrebbero essere troppi, ma qualsiasi cosa fra 4.7n e 47n dovrebbe andare ... o comunque aiutare ad eliminare eventuali disturbi da rimbalzo ...

eccellente, grazie, quindi solo un condensatore fra pin e massa, non un RC

Dipende, se l'encoder chiude a massa, puoi attivare le pullup interne e risparmiarti le resistenze di pullup esterne, se invece chiude a VCC, servono per forza le resistenze di pulldown verso massa, perche' la MCU internamente non le prevede ... poi certo sarebbe piu corretto se ci fossero anche le resistenze da 100 ohm in serie ai contatti, ma quelle si possono anche evitare ...

Etemenanki:
Dipende, se l'encoder chiude a massa, puoi attivare le pullup interne e risparmiarti le resistenze di pullup esterne, se invece chiude a VCC, servono per forza le resistenze di pulldown verso massa, perche' la MCU internamente non le prevede ... poi certo sarebbe piu corretto se ci fossero anche le resistenze da 100 ohm in serie ai contatti, ma quelle si possono anche evitare ...

L'encoder è questo: http://www.ebay.it/itm/Modulo-encoder-rotativo-2-canali-con-pulsante-arduino-pic-ART-CR10/331712061894?ssPageName=STRK%3AMEBIDX%3AIT&_trksid=p2057872.m2749.l2649
Purtroppo non c'è scritto se chiude verso massa....

Chiude a massa e ha gia' a bordo le resistenze di PullUp

Gli encoder meccanici non hanno una polarità, semplicemente sono due contatti che vengono chiusi ciclicamente, sfasati di 90°, girando l'alberino, hanno un comune, che si può collegare a piacere a GND o al 5V, due uscite per i contatti, nel modello specifico è presente una terza uscita per il pulsante centrale.
Nella parte inferiore del pcb sono visibili due resistenze da 10k, più il posto per una terza che non è montata, ovvero sono giù presenti le resistenze di pullup, i contatti sono da interpretare come GND per il comune degli switch, + per il 5V delle pullup, volendo si può lasciare libero e si attivano le pullup integrate nei AVR su i pin, DT e CLK sono le uscite dei due contatti, ovvero il canale A e B del encoder, SW l'uscita del contatto dello switch a pressione.

Ho anche io esattamente quegli encoder, e li ho usati con la libreria, non ho mai avuto particolari problemi di debounce (forse la libreria fa di suo qualcosa), comunque ho da parte uno schema che avevo trovato e che mi riproponevo di implementare alla prima occasione, vedete se per voi possa essere di aiuto:

docdoc:
Ho anche io esattamente quegli encoder, e li ho usati con la libreria, non ho mai avuto particolari problemi di debounce (forse la libreria fa di suo qualcosa), comunque ho da parte uno schema che avevo trovato e che mi riproponevo di implementare alla prima occasione, vedete se per voi possa essere di aiuto:

Io ho un Mega2560 e non c'è modo che riesca a far funzionare l'esempio che ho allegato collegando l'encoder ai pin 2 e 3...

the_dragonlord:
Io ho un Mega2560 e non c'è modo che riesca a far funzionare l'esempio che ho allegato collegando l'encoder ai pin 2 e 3...

Si ma prova anche con lo schema che ho postato e facci sapere...

docdoc:
Si ma prova anche con lo schema che ho postato e facci sapere...

Alla fine non voglio fare un ordine di 10 euro per 2 condensatori....ho provato ad usare l'esempio in polling invece che con interrupt della libreria e tutto funziona più che alla meraviglia senza incertezze o quant'altro per cui per il momento lo tengo così...

Grazie a tutti!
Andrea

docdoc:
Si ma prova anche con lo schema che ho postato e facci sapere…

Ciao, sono duvuto tornare sul discorso degli interrupt perchè la gestione in polling dell’encoder non mi va bene…non riesco in nessun modo a far funzionare gli interrupt sul Mega…non solo non riesco con nessuno degli esempi presenti nelle librerie sopra citate, ma nemmeno con l’esempio di Mauro Alfieri:

int encoderPin1 = 2;
int encoderPin2 = 3;

volatile int lastEncoded = 0;
volatile long encoderValue = 0;

long lastencoderValue = 0;

int lastMSB = 0;
int lastLSB = 0;

void setup() {
	Serial.begin(9600);

	pinMode(encoderPin1, INPUT_PULLUP);
	pinMode(encoderPin2, INPUT_PULLUP);

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

}

void loop() {
	Serial.println(encoderValue);
	delay(1000);
}

void updateEncoder() {
	int MSB = digitalRead(encoderPin1); //MSB = most significant bit
	int LSB = digitalRead(encoderPin2); //LSB = least significant bit
	int encoded = (MSB << 1) | LSB; //converting the 2 pin value to single number
	int sum = (lastEncoded << 2) | encoded; //adding it to the previous encoded value

	if (sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011)
		encoderValue++;
	if (sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000)
		encoderValue--;

	lastEncoded = encoded; //store this value for next time
}

Da notare che su UNO funziona tutto per cui non è un problema dell’encoder…cosa mi sfugge??? Ah, naturalmente l’encoder è collegato ai PIN digitali 2 e 3

HELPPPPP!
Andrea