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;
}}
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...
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-... ?
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 ;
insomma puoi aggiustartelo come più ti aggrada
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
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 ...