Un exemple courant d'utilisation est le bouton d'un autoradio qui permet le réglage du volume mais aussi d'allumer et d'éteindre la radio. Il ressemble beaucoup à un potentiomètre mais contrairement à lui il n'est pas limité dans ça rotation et envoie un signal à chaque "crans". Il y a 30 crans par tour et l'on est capable de déterminer le sens de rotation de l'encodeur. Pour cela, l'encodeur nous envoie 2 signaux (on parlera du signal A et B) comme suit :
Source : Arduino UNO Tutorial 6 - Rotary Encoder |
Mise en place du hardware
Pour "capturer" la rotation nous utiliserons les "interruptions" disponibles sur les entrées 2 et 3 de l'arduino. L'Uno ne disposant que de 2 entrées avec gestion des interruptions, le switch sera géré dans la fonction "loop".Au niveau hardware, rien de compliqué :
- DT --> pin 2
- CLK --> pin 3
- SW --> pin 4
- rs (LCD pin 4) --> Arduino pin 12
- enable (LCD pin 6) --> Arduino pin 10
- LCD D4 --> Arduino pin 8
- LCD D5 --> Arduino pin 7
- LCD D6 --> Arduino pin 6
- LCD D7 --> Arduino pin 5
Le programme correspondant
On utiliser un "unsigned int" pour stocker un compteur que l'on incrémente ou décrémente suivant le sens de rotation de l'encodeur. Un appuis dessus remettra à 0 ce compteur.De part l'utilisation d'un "unsigned int", ce compteur est forcement compris entre 0 et 65535.
Dernier point important, ce type de bouton génère des rebonds aux niveaux des entrées de l'arduino. Il faut donc un système d'anti-rebond. il existe plusieurs possibilités, soit hardware en utilisant par exemple des condensateurs (0.1µF devrait être bon), soit logique via un peu de code. C'est cette dernière solution que j'ai utilisé.
include <liquidcrystal.h>
LiquidCrystal lcd(12, 11, 10, 8, 7,6,5);
// définition des pin pour le KY040
enum PinAssignments {
encoderPinA = 2, // right (DT)
encoderPinB = 3, // left (CLK)
clearButton = 4 // switch (SW)
};
volatile unsigned int encoderPos = 0; // un compteur
unsigned int lastReportedPos = 1; // gestion du changement
static boolean rotating=false; // gestion de l'anti-rebonds
// variable pour les routines d'interruption
boolean A_set = false;
boolean B_set = false;
boolean A_change = false;
boolean B_change= false;
void setup() {
lcd.begin(20,4);
lcd.clear();
pinMode(encoderPinA, INPUT_PULLUP); // utilisation du pullup
pinMode(encoderPinB, INPUT_PULLUP); // utilisation du pullup
pinMode(clearButton, INPUT_PULLUP); // utilisation du pullup
// activation de l'interruption 0 (pin 2)
attachInterrupt(0, doEncoderA, CHANGE);
// activation de l'interruption 1 (pin 3)
attachInterrupt(1, doEncoderB, CHANGE);
}
void loop(){
if (lastReportedPos != encoderPos) {
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Index: ");
lcd.print(encoderPos, DEC);
lastReportedPos = encoderPos;
lcd.setCursor(0,1);
lcd.print(digitalRead(encoderPinA));
lcd.print(digitalRead(encoderPinB));
lcd.print(digitalRead(clearButton));
}
lcd.setCursor(0,1);
lcd.print(digitalRead(encoderPinA));
lcd.print(digitalRead(encoderPinB));
lcd.print(digitalRead(clearButton));
if (digitalRead(clearButton) == LOW ) {
encoderPos = 0;
A_change = false;
B_change= false;
lcd.print(encoderPos);
}
delay (100);
}
// Interruption sur changement d'état de A
void doEncoderA(){
// debounce
if ( rotating ) delay (1); // attendre un petit peut
rotating = true; //activation de l'anti-rebond
// Confirmation du changement
if( digitalRead(encoderPinA) != A_set ) {
A_set = !A_set;
if (B_change) {
encoderPos += 1;
B_change = false;
} else
A_change = true;
rotating = false; //libération de l'anti-rebond
}
}
// Interruption sur changement d'etat de B
void doEncoderB(){
if ( rotating ) delay (1);
rotating = true;
if( digitalRead(encoderPinB) != B_set ) {
B_set = !B_set;
if (A_change) {
encoderPos -= 1;
A_change = false;
} else
B_change = true;
rotating = false;
}
}
Source : Arduino, Arduino UNO Tutorial 6 - Rotary Encoder, Using a Rotary Encoder with the Arduino
Aucun commentaire :
Enregistrer un commentaire