Rotatie encoder
Een rotatie encoder of rotatie sensor geeft het aantal stappen dat een asje heeft rondgedraaid vanaf een bepaald punt weer. De as mag meerdere malen rond gaan; je kunt gewoon doortellen. Er zijn bijzonder veel verschillende types. Sommige duurdere rotatie encoders kunnen ook de absolute hoek van de encoder weergeven. Als je een goedkope (maar minder betrouwbare) sensor voor een absolute hoek wilt hebben dan kun je een potentiometer aansluiten op 0 en 5 volt en de spanning op de middenpoot uitlezen en omrekenen naar een hoek. Ik heb inmiddels drie encoders getest. Later hopelijk meer.
Meting van rotatie (met een Keyes KY-040 of kloon)
Een KY-040 kloon
Dit soort rotatie encoders kun je vooral goed te gebruiken om een aantal menu's te doorlopen, waarbij je niet gebonden bent aan een maximum aantal. Je kunt bij zo'n menu gemakkelijk aan de knop heen en weer draaien tot je een bepaalde keuze hebt gevonden en dan op de knop van de encoder drukken om de keuze te bevestigen. Voor deze toepassing hoef je de hoekstand niet eens te kennen. In mijn testprogramma laat ik de hoek echter wel zien. In de seriële monitor zie je hoeveel graden de knop verdraaid is ten opzichte van de (willekeurige) startpositie of vanaf de stand waarop de knop is ingedrukt. Nog te doen: uitleggen hoe de encoder werkt. Nog te doen: voorbeeld van zo'n menu. Het is nog niet zo makkelijk om een goed programma te maken om de volgende redenen:
- Als je wilt dat de encoder ook in de praktijk goed werkt dan moet je interrupt functies gebruiken
- De uitgangsspanning maakt geen mooie stap, maar gaat even op en neer. Hiervoor moet je een oplossing verzinnen
- Er zijn verschillende systemen in oploop. Twee ervan worden veel gebruikt. De programma's voor deze twee types zijn net iets anders. Ik heb twee knoppen die uiterlijk identiek zijn, maar toch een ander systeem gebruiken. Het is wel mogelijk om dit op te meten (eventueel met een Arduino programma), maar handiger is om gewoon te proberen welk van onderstaande voorbeeld programma's werkt. Als je ontdekt dat de helft van de stappen niet goed gaat, dan heb je het tweede voorbeeldprogramma nodig; als je per stap een dubbele sprong krijgt dan heb je het eerste programma nodig.
De voorbeeldprogramma's werken in het algemeen goed als je niet te snel aan de knop draait. Bij knoppen van mindere kwaliteit zie je wel eens een verkeerde stap. Sluit de encoder als volgt aan: CLK gaat naar pin 2 (in het programma heet dit pinA), DT gaat naar pin 3 (in het programma heet dit pinB) en de schakelaar (SW) gaat naar pin 4. Je mag natuurlijk andere pinnen gebruiken, maar pinA moet een interrupt pin zijn. Het programma zal in vorm zoals het hier staat met vrijwel alle arduino's werken. Als je alleen een volgnummer wilt hebben verander dan in het eerste programma Hoek += 18;
dan door Hoek++;
en Hoek -= 18;
door Hoek--;
In het tweede programma kun je het getal achter #define Stap 12
veranderen...
Klik hier om het test programma voor type 1 te zien
// Programma getest met twee uitvoeringen van een 20 stappen rotary encoder
#define pinA 2
#define pinB 3
#define knop 4
int vorigeHoek = 0;
volatile int Hoek = 0; // volatile is nodig bij variabelen die binnen een interrupt functie veranderen
void setup() {
Serial.begin(9600);
pinMode(pinA, INPUT); pinMode(pinB, INPUT);
pinMode(knop, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(pinA), leesEncoder, LOW);
Serial.println("Encoder Test:");
}
void leesEncoder() {
static unsigned long vorigeTijd = 0; // Static: behoud waarde tussen twee aanroepen
if ( (millis() - vorigeTijd) < 5 ) return; // Dit interrupt komt te kort na het vorige: doe er niets mee
if ( digitalRead(pinB) == HIGH ) Hoek -= 18; // Rotatie tegen de klok in
else Hoek += 18; // Rotatie met de klok mee
vorigeTijd = millis();
}
void loop() {
if ( !digitalRead(knop) ) { // De knop is ingedrukt: doe iets, bijvoorbeeld zet op 0, of maak keuze }
Serial.println("De knop is ingedrukt (reset Hoek)"); Hoek = 0;
while ( !digitalRead(knop) ); // Wacht tot de knop niet meer is ingedrukt
}
if ( vorigeHoek != Hoek ) {
Serial.print("Hoek: "); Serial.print(Hoek); Serial.println(" graden");
vorigeHoek = Hoek;
}
}
Klik hier om het test programma voor type 2 te zien
// Programma getest met Keyes 30 stappen rotary encoder
#define pinA 2 // Gaat naar CLK
#define pinB 3 // Gaat naar DT
#define knop 4
#define Stap 12 // Zet hier de juiste waarde in, meestal 1, 12 of 18
int vorigeHoek = 0;
volatile int Hoek = 0; // volatile is nodig bij variabelen die binnen een interrupt functie veranderen
void setup() {
Serial.begin(9600);
pinMode(pinA, INPUT); pinMode(pinB, INPUT);
pinMode(knop, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(pinA), leesEncoder, CHANGE);
Serial.println("Encoder Test:");
}
void leesEncoder() {
static unsigned long vorigeTijd = 0; // Static: behoud waarde tussen twee aanroepen
if ( (millis() - vorigeTijd) < 10 ) return; // Dit interrupt komt te kort na het vorige: doe er niets mee
if ( digitalRead(pinB) == digitalRead(pinA) ) Hoek -= Stap; // Rotatie tegen de klok in
else Hoek += Stap; // Rotatie met de klok mee
vorigeTijd = millis();
}
void loop() {
if ( !digitalRead(knop) ) { // De knop is ingedrukt: doe iets, bijvoorbeeld zet op 0, of maak keuze }
Serial.println("De knop is ingedrukt (reset Hoek)"); Hoek = 0;
while ( !digitalRead(knop) ); // Wacht tot de knop niet meer is ingedrukt
}
if ( vorigeHoek != Hoek ) {
Serial.print("Hoek: "); Serial.print(Hoek); Serial.println(" graden");
vorigeHoek = Hoek;
}
}
Tip: afhankelijk van het doel van je programma, kan het nodig zijn om ook van de drukknop een interrupt functie te maken. Je moet (bij gebuik van de Arduino Uno) dan pinB en knop omwisselen, want alleen pin 3 is ook een interrupt pin.