modificare una variabile con encoder

ciao a tutti ragazzi leggo molto sul forum e mi sono documentato il più possibile riguardo questa cosa.
sono scarso nel campo dell'elettronica e della programmazione ma sono riuscito ad elaborare questo sketch per gestire una variabile tramite la rotazione di un encoder di quelli meccanici, tipo potenziometro.

/* interrupt routine 


   The average rotary encoder has three pins, seen from front: A C B
   rotazione oraria A(on)->B(on)->A(off)->B(off)
   antioraria B(on)->A(on)->B(off)->A(off)

   

*/

// ground pin in the middle
enum PinAssignments {
  encoderPinA = 2,   // right (labeled DT on our decoder, yellow wire)
  encoderPinB = 3,   // left (labeled CLK on our decoder, green wire)
  clearButton = 8    // switch (labeled SW on our decoder, orange wire)
// connect the +5v and gnd appropriately
};

volatile unsigned int encoderPos = 0;  
unsigned int lastReportedPos = 1;   
static boolean rotating=false;      


boolean A_set = false;              
boolean B_set = false;


void setup() {

  pinMode(encoderPinA, INPUT_PULLUP); // new method of enabling pullups
  pinMode(encoderPinB, INPUT_PULLUP); 
  pinMode(clearButton, INPUT);
 

//  interrupt 0 (pin 2)
  attachInterrupt(0, doEncoderA, HIGH);
  //  interrupt 1 (pin 3)
  attachInterrupt(1, doEncoderB, HIGH);

  Serial.begin(9600);  // output
}


void loop() { 
  rotating = true;  // reset  debounce

  if (lastReportedPos != encoderPos) {
    Serial.print("Index:");
    Serial.println(encoderPos, DEC);
    lastReportedPos = encoderPos;
  }
  if (digitalRead(clearButton) == HIGH )  {
    encoderPos = 0;
  }
}

// Interrupt on A changing state
void doEncoderA(){
  // debounce
  if ( rotating ) delay (1);  

   
  if( digitalRead(encoderPinA) != A_set ) { 
    A_set = !A_set;

    // +1 se a precede b
    if ( A_set && !B_set ) 
      encoderPos ++;

    rotating = false;  }}



void doEncoderB(){
  if ( rotating ) delay (1);
  if( digitalRead(encoderPinB) != B_set ) {
    B_set = !B_set;
    //  - 1 se b precede a
    if( B_set && !A_set ) 
      encoderPos --;

    rotating = false;
  }}

l'encoder che sto utilizzando è il seguente http://it.rs-online.com/web/p/encoder-ottici-rotativi/7816815/?searchTerm=781-6815&relevancy-data=636F3D3126696E3D4931384E525353746F636B4E756D6265724D504E266C753D656E266D6D3D6D61746368616C6C26706D3D5E5C647B337D5B5C732D2F255C2E2C5D5C647B332C347D2426706F3D313426736E3D592673743D52535F53544F434B5F4E554D424552267573743D3738312D363831352677633D4E4F4E4526

il mio problema è che la variabile in questione viene incrementata o decrementata ogni due scatti percepiti dall'encoder, non ogni scatto.
inoltre io ho acquistato l'encoder dato come 12 impulsi a giro....e in effetti con lo sketch che ho scritto la variabile aumenta o diminuisce di 12 unità ogni giro...ma l'encoder ha 24 possibili posizioni, cioè, in un giro manualmente percepisco 24 scatti.

secondo voi è posssibile che mandi 12 impulsi e faccia 24 scatti?
se io faccio uno scatto avanti e uno indietro a monitor mi stampa -1, quindi lo scatto in avanti deve averlo percepito...

Tu hai un Arduino DUE?

Sí i sintomi sono quelli che hai programmato.

Tu incrementi la variabile con la fase A e decrementi con la fase B

Se vuoi avere 24 Impulsi per rotazione allora usa l' interrupt in modalitá CHANGE di uno dei 2 canali e usa un codice molto piú semplice:

void doEncoderA(){
    encoderPos += (-1 +2*digitalRead(encoderPinB));
}

Il debounce lo devi fare via Hardware come descritto nel http://docs-europe.electrocomponents.com/webdocs/1273/0900766b81273a19.pdf "Suggested Filter Circuit" a pagina 2 in basso a destra.

Ciao Uwe

no, possiedo una scheda arduino UNO....
stasera provo con il codice che hai postato, ma basta che lo sostituisco alla funzione doEncoderA che avevo creato io?
appena trovo dei condensatori così piccoli faccio il debounce hardware
grazie

serventino:
...
secondo voi è posssibile che mandi 12 impulsi e faccia 24 scatti?
...

Hai 24 "scatti" meccanici ?

Quegli encoder sono in genere usati su roba audio, e letti in modo diverso ... il sistema potrebbe leggere gli scatti basandosi su entrambi i canali, quindi avresti in pratica 24 fronti da contare ... oppure avere uno scatto per ogni transizione di entrambi i canali (quindi avresti meccanicamente 24 passi, ma leggendo solo un canale avresti solo 12 fronti positivi, uno ogni 2 scatti)

Ovviamente, se fosse cosi, leggendolo in quel modo avresti un'errore, perche' come dici tu, facendo uno scatto avanti ed uno indietro, non leggerebbe "+1 ... -1", ma solo il fronte del "-1" (oppure l'opposto, dipende dalla posizione da cui si inizia) ... la cosa piu corretta, in quel caso, sarebbe ignorare la transizione "1->0" di entrambi i canali, e contare invece le transizioni "0->1" di entrambi ... o viceversa ... dipende da come sono posizionati gli "scatti" rispetto alla transizione dei contatti ...

Collegando all'encoder due led con le loro resistenze, quello che ottieni in uscita sui led avanzando di uno scatto alla volta, e' piu simile ad una sequenza tipo: 11-01-00-10-11-01-... oppure tipo: 11-00-11-00-11-... ?

https://code.google.com/p/arduino-rotary-encoder-with-velocity/source/browse/RotaryEncoder.h

scarica lo zip
cè un uno scketc di esempio VelocityTest.ino

la riga RotaryEncoder encoder(A0,A2,5,6,3000); A0 e A2 sono i pin dell'encoder (oltre la massa) 3000 e la "velocita"
ovviamente puoi modificare i pin e la velocita

le righe
val = min (val,4095);
val = max (val,0);

indicano il valore minimo e massimo che possono prendere anche valori negativi tipo

val = min (val, -99);

val = max (val, 99);

se vuoi proprio pochi scatti a giro puoi mettere val = val/10 ; :wink:
insomma puoi aggiustartelo come più ti aggrada

serventino:
no, possiedo una scheda arduino UNO....

Te l' ho chiesto perché l' opzone "HIGH" nel
"attachInterrupt(0, doEncoderA, HIGH);"
é consentito solo per Arduino DUE.
Ciao Uwe

Etemenanki:

serventino:
...
secondo voi è posssibile che mandi 12 impulsi e faccia 24 scatti?
...

Hai 24 "scatti" meccanici ?

Quegli encoder sono in genere usati su roba audio, e letti in modo diverso ... il sistema potrebbe leggere gli scatti basandosi su entrambi i canali, quindi avresti in pratica 24 fronti da contare ... oppure avere uno scatto per ogni transizione di entrambi i canali (quindi avresti meccanicamente 24 passi, ma leggendo solo un canale avresti solo 12 fronti positivi, uno ogni 2 scatti)

Ovviamente, se fosse cosi, leggendolo in quel modo avresti un'errore, perche' come dici tu, facendo uno scatto avanti ed uno indietro, non leggerebbe "+1 ... -1", ma solo il fronte del "-1" (oppure l'opposto, dipende dalla posizione da cui si inizia) ... la cosa piu corretta, in quel caso, sarebbe ignorare la transizione "1->0" di entrambi i canali, e contare invece le transizioni "0->1" di entrambi ... o viceversa ... dipende da come sono posizionati gli "scatti" rispetto alla transizione dei contatti ...

Collegando all'encoder due led con le loro resistenze, quello che ottieni in uscita sui led avanzando di uno scatto alla volta, e' piu simile ad una sequenza tipo: 11-01-00-10-11-01-... oppure tipo: 11-00-11-00-11-... ?

si, l'encoder ha 24 scatti meccanici.
provo a spiegare cosa noto collegando i led all'encoder:
girando molto lentamente la manopola, i led si accendono e spengono in questa sequenza :11 (entrambi accesi), giro la manopola in senso orario, 01,00,10,11
lo scatto meccanico si avverte in posizione 11 & 00, se giro velocemente la manopola le transizioni con uno solo dei due led accesi non si notano neanche
purtroppo non ho ancora reperito i condensatori per il debounce hardware.
grazie a tutti, ora provo con lo sketch suggeritomi da elrospo anche se vorrei capire io, con il vostro aiuto, dove sta l'inghippo

Quindi gli scatti sono solo nelle posizioni "11" e "00" , non anche in quelle intermedie .. allora la cosa si semplifica un po dal punto di vista del software (se fossero state anche in quelle intermedie, c'era da incasinare un po di piu per evitare gli errori dovuti ad "uno scatto avanti ed uno indietro" ...

Cosi, ti basta leggere le transizioni e sommare o sottrarre in base a quale delle due accade prima (se lo giri molto velocemente potrebbe saltare qualche passo, ma dipende dalla velocita' dello sketch e da quante altre istruzioni deve fare nel frattempo) ...

Prova una cosa del genere nel loop, senza interrupts, se vuoi (occhio che non l'ho testata, non posso adesso, e la sto scrivendo al volo, quindi potrebbero esserci errori) ... cosi in teoria dovrebbe cambiarti lo stato di encoderVal ogni passo (quindi 24 cambi ogni giro), se ne vuoi solo 12 elimina le due istruzioni di controllo nel secondo ciclo if di rilevazione dello stato ... encoderAprec e' una variabile in piu che devi dichiarare, per effettuare un confronto fra stati, in modo che lo sketch senta solo il cambio dello stato e non lo stato in se ...

	if ((encoderA != encoderAprec) && (encoderAprec == 0)) //se canale A cambia stato
	{
		encoderAprec = encoderA;
		if (encoderB == 1) {encoderVal++;} //incrementa
		else {encoderVal--;}	//decrementa	 
	}
	if ((encoderA != encoderAprec) && (encoderAprec == 1))
	{
		encoderAprec = encoderA;
		if (encoderB == 0) {encoderVal++;} //se vuoi solo 12 passi
		else {encoderVal--;}		       //elimina queste due righe 
	}
int encoderA=2;
int encoderB=3;
int encoderAprec=0;
int encoderVal=0;

void setup(){
  pinMode(encoderA, INPUT);
  pinMode(encoderB, INPUT);
  digitalWrite(encoderA,HIGH);
  digitalWrite(encoderB,HIGH);
Serial.begin(9600);}
void loop(){
  encoderA=digitalRead(2);
  encoderB=digitalRead(3);
if ((encoderA != encoderAprec) && (encoderAprec == 0)) //se canale A cambia stato
	{
		encoderAprec = encoderA;
		if (encoderB == 1) {encoderVal++;} //incrementa
		else {encoderVal--;}	//decrementa	 
Serial.println(encoderVal);
	}
	if ((encoderA != encoderAprec) && (encoderAprec == 1))
	{
		encoderAprec = encoderA;
		if (encoderB == 0) {encoderVal++;} //se vuoi solo 12 passi
		else {encoderVal--;}//elimina queste due righe 
	Serial.println(encoderVal);}
}

l'ho ricopiato così....funziona così e così, effettivamente perde passi se girato velocemente, c'è da dire che magari influisce un po anche il fatto che non ho ancora sistemato il circuito con debounce hardware, oggi comunque mi sono arrivati i condensatori e stasera riprovo lo sketch

Io ho smontato da un mouse un'encoder ottico. Posso usare lo stesso codice?

Intendi quello sulla rotellina, con gli scatti ? ... se gli scatti corrispondono alle posizioni "11" e "00", credo di si ... se non ha scati, invece, bisogna modificarlo perche' il mezzo passo avanti e indietro darebbe letture sbagliate, quindi e' necessario gestire entrambe le uscite, anche se la cosa raddoppia gli scatti ...