Drehimpulsgeber KY-040

Autoren: Marc Ebmeyer, Prof. Dr.-Ing. Schneider
Einleitung
Der KY-040 ist ein inkrementaler Drehimpulsgeber (Engl. rotary encoder), der Drehbewegungen in digitale Signale umwandelt. Er dient zur Erfassung von Drehwinkel, Drehrichtung und Anzahl der Umdrehungen und wird häufig in Mikrocontroller-Projekten (z. B. mit Arduino oder Raspberry Pi) eingesetzt.
Der KY-040 besteht aus:
- Mechanischem Encoder mit Rastungen (20 Schritte pro Umdrehung)
- Taster (SW) – durch Drücken der Achse betätigt
Beim Drehen der Achse erzeugen die Signale CLK und DT eine quadraturkodierte Folge (A und B um 90° phasenverschoben).
- Drehrichtung: Bestimmt durch die Phasenlage von A und B
- Drehschritte: Jeder Signalwechsel entspricht einer Rasterposition
In Mikrocontroller- oder Simulink-Anwendungen kann der KY-040 zur:
- Menü-Navigation (Drehgeber als Eingabegerät)
- Positions- oder Geschwindigkeitsmessung
- Einstellwertregelung (z. B. Sollwert-Drehknopf)
Technische Übersicht
| Eigenschaft | Daten |
|---|---|
| Spannungsversorgung | 3thinsp;V -5 V DC |
| Schritte pro Umdrehung | 20 |
| Signalart | Digital, quadraturkodiert |
| Abmessungen | 32x20x30 mm |
| Gewicht |
8 g |
| Schalterbelastung | max. 5 V / 10 mA |
Pinbelegung
| # | Pin | Funktion | Beschreibung |
|---|---|---|---|
| 1 | CLK | Signal A | Erster Ausgang (Quadratimpuls) |
| 2 | DT | Signal B | Zweiter Ausgang, phasenverschoben |
| 3 | SW | Schalter | Kontakt beim Drücken der Achse |
| 4 | + | Versorgung (3,3 V – 5 V) | |
| 5 | GND | Masse | Bezugspotential |
Prinziperklärung
Die unter der Platine befindlichen drei Widerstände (siehe Abb.6) sind Pullup Widerstände für die zwei Encoder und den Taster. Der KY-040 ist ein Inkrementalgeber. Je nach dem ob man rechts oder links herum dreht, wird erst der Pin A oder der Pin B high, da beide versetzt auf der Drehencoderscheibe sitzen (siehe Abb.3). Damit bekommt man einen Gray-Code am Ausgang vom Signalausgang A und B. Gray-code ähneld dem Binär-Code nur wird bei ihm bei jedem Sprung nach oben oder unten jeweils nur ein Wert verändert. Damit bekommen wir die Drehrichtung, den Drehwinkel und die Drehgeschwindigkeit.
Geht zum Beispiel erst CLK auf high und dann DT, dann drehen wir rechts rum. Geht erst der DT Pin auf high und dann der CLK Pin, dann drehen wir links rum.
Teilen wir die Anzahl an CLK durch die vorhandene Inkremente und durch die Zeitspanne der Messung, bekommen wir die Drehzahl.


Bezug zur Prinzipskizze?
| Zahlenwert | Binär-Code | Gray-Code |
|---|---|---|
| 0 | 00 | 00 |
| 1 | 01 | 01 |
| 2 | 10 | 11 |
| 3 | 11 | 10 |
Messung


Demo
Die beiden Demos basieren auf den oben genanten Prinzip. Drückt man den Taster (Achsentaster), dann wird der Nullpunkt neu gesetzt, diese Änderung wird dann aber erst beim weiterdrehen angezeigt.
const byte SW_u8 = 4; // Pin zum Messen vom Schalter
const byte DT_u8 = 2; // Pin zum Messen Interrupt PIN
const byte CLK_u8 = 3; // Pin zum Messen des Taktes Interrupt pin
const unsigned int Pos_u16 = 40; // Anzahl an Positionen des Drehencoders
volatile int CLK_pos_alt_s16; // letzte Position von CLK
volatile int CLK_pos_neu_s16;
volatile bool drehtimUhr_bit; // dreht der Drehencoder im Uhrzeigersinn? true =ja
volatile int PosZaehler_s16 =0; // Zähler der Position
volatile float WinkelZaehler_f32 =0.0;// Winkel Zähler initialisieren Startposition= o
volatile bool drehtsich_bit =false;
//-------------------------------------------------------------------------------------------------------
void alarm_DT()
{
CLK_pos_neu_s16 = digitalRead(CLK_u8); // auslesen der Position von CLK und zwischen speichern in Hilfsvariable
if (CLK_pos_neu_s16 != CLK_pos_alt_s16)// Drehencoder dreht sich
{
if (digitalRead(DT_u8) != CLK_pos_neu_s16) // Drehrichtungserkennung
{ // CLK ändert sich zuerst -
PosZaehler_s16 ++; // hoch zählen da im Uhrzeigersinn
drehtimUhr_bit = true; //mit dem Uhrzeigersinn
}
else // DT ändert sich zuerst wodurch wir uns gegen dem Uhrzeigersinn drehen
{
drehtimUhr_bit = false; // gegen dem Uhrzeigersinn
PosZaehler_s16 --; // runterzählen
}
}
drehtsich_bit =true; //AusgabeBit setzen das der Drehencoder sich dreht
}
//-------------------------------------------------------------------------------------------------------
void alarm_CLK()
{
CLK_pos_neu_s16 = digitalRead(CLK_u8); // auslesen der Position von CLK und zwischen speichern in Hilfsvariable
if (CLK_pos_neu_s16 != CLK_pos_alt_s16)// Drehencoder dreht sich
{
if (digitalRead(DT_u8) != CLK_pos_neu_s16) // Drehrichtungserkennung
{ // CLK ändert sich zuerst -
PosZaehler_s16 ++; // hoch zählen da im Uhrzeigersinn
drehtimUhr_bit = true; //mit dem Uhrzeigersinn
}
else // DT ändert sich zuerst wodurch wir uns gegen dem Uhrzeigersinn drehen
{
drehtimUhr_bit = false; // gegen dem Uhrzeigersinn
PosZaehler_s16 --; // runterzählen
}
}
drehtsich_bit =true; //Ausgabe Bit setzen das der Drehencoder sich dreht
}
//-------------------------------------------------------------------------------------------------------
void setup() //definition von Serieller Schnittstelle und der Pins als Eingang
{
Serial.begin(115200); //Übertragungsrate und initialisieren der seriellen Schnittstelle
pinMode(SW_u8, INPUT); // Definition als Eingang
pinMode(DT_u8, INPUT_PULLUP); // Definition als Eingang
pinMode(CLK_u8, INPUT_PULLUP); // Definition als Eingang
CLK_pos_alt_s16=digitalRead(CLK_u8); // einlesen damit Wert vorhanden
attachInterrupt(digitalPinToInterrupt(DT_u8), alarm_DT, CHANGE);// Interrupt 0 auf Pin 2
attachInterrupt(digitalPinToInterrupt(CLK_u8), alarm_CLK, CHANGE);// // Interrupt 1 auf Pin 3
CLK_pos_neu_s16 = digitalRead(CLK_u8); // auslesen der Position von CLK und zwischen speichern in Hilfsvariable
}
//-------------------------------------------------------------------------------------------------------
void loop()
{
if(digitalRead(SW_u8)==false) // Wenn taster gedrückt wird Winkel auf null gesetzt
{
PosZaehler_s16=0;
}
if (drehtsich_bit)
{
float WinkelZaehler_f32= ((float ) PosZaehler_s16/ Pos_u16 )* 360;// teilen der Position durch die Anzahl an Positionen am Drehencoder und Umrechnen auf 360 Grad
Serial.print ("es dreht sich :-): ");//Ausgabe der Ergebnisse
if (drehtimUhr_bit) //Drehrichtungsausgabe
{
Serial.print ("mit dem Uhrzeiger");
}
else
{
Serial.print("gegen den Uhrzeiger");
}
Serial.print("Position: "); // Positionsausgabe
Serial.print(PosZaehler_s16);
Serial.print(" Winkel: "); // Positionsausgabe
Serial.println(WinkelZaehler_f32);
drehtsich_bit=false;
}
else
{
//Serial.println ("es dreht sich nicht ;-(: ");//Ausgabe der Ergebnisse
}
CLK_pos_alt_s16 = CLK_pos_neu_s16; //neuer Messwert wird u altem Messwert für den nächsten Durchlauf
}
DemoDrehencoderKY_040_interrupt.ino
|
Hardwareaufbau


Datenblätter
Literatur
Weiterführende Artikel
→ zurück zum Hauptartikel: HSHL-Mechatronik-Baukasten