Da von unseren Kunden in letzter immer wieder Fragen zur Implementierung des Drehimpulsgebers (digitales Poti) gestellt wurden m'chten wir hier kurz eine M'glichkeit zeigen, ein sauberes Signal des Drehimpulsgebers mithilfe von interrupts ausge. Hier im Beispiel am Seriellen Monitor:
Schaltung:
St'ckliste:
Schizzo Arduino:
/*
- Rotary Encoder collegato a un Microcontroller, compatibile con Arduino Uno R3
*
Pin encoder: CLK, DT, SW,
L'encoder contiene due pull-up-resistors di 10k a CLK e DT
Tutti i contatti sono bassi-attivi
*
Programma basato su software di Stefan Nikolaus
- https://www.nikolaus-lueneburg.de/2016/02/rotary-encoder/
- e codice importante scritto da rafbuff al http://playground.arduino.cc/Main/RotaryEncoders
"Un'altra libreria di interrupt che REALMENTE (l'encoder interrompe il processore
- e si pronuncia come se non ci sia un domani)."
*
I Pin 2 e 3 sono utilizzati perché supportano gli interrup!
" Debouncing funziona davvero molto !!!
Conteggio Math.positive: DT su 3, CLK su 2
Conteggio in senso orario: DT su 2, CLK su 3
*
- Modifiche:
- eliminati i caratteri 'non stampabili', modificati e TAB
- aggiunto il rilevamento dei pulsanti per il pin 4 "SW"
- aggiunto actionButton() e actionPosition(); qui possiamo mettere giù il
codice per un'ulteriore elaborazione nel nostro sistema.
*
UKA 31.05.2018
*/
#define codificatorePinA 2
#define codificatorePinB 3
SW #define 4
volatile unsigned int encoderPos - 0; un contatore per il quadrante
unsigned int lastReportedPos - 1; gestione del cambiamento
rotazione booleana statica : false; denunciare la gestione
Tasto int - LOW;
int old_button - LOW;
interrompere le variabili di routine di servizio
A_set booleane: false;
B_set booleani: false;
void setup()
{
pinMode(encoderPinA, INPUT);
pinMode(encoderPinB, INPUT);
pinMode( SW, INPUT_PULLUP );
digitalWrite(encoderPinA, HIGH); accendere i resistori pullup
digitalWrite(encoderPinB, HIGH); accendere i resistori pullup
attachInterrupt(0, doEncoderA, CHANGE); pin encoder sull'interrupt 0 (pin 2)
attachInterrupt(1, doEncoderB, CHANGE); pin dell'encoder sull'interrupt 1 (pin 3)
Serial.begin(9600); uscita su PC Serial Monitor
-------------------------------- di configurazione ---------------------
void loop()
{
rotazione : true; azzerare il debouncer
if (lastReportedPos !
{
actionPosition();
lastReportedPos - encoderPos;
}
pulsante : !digitalRead( SW );
if( Button ! old_button )
{
actionButton();
ritardo( 10 );
old_button ;
}
// --------------------------- ----------------------- del ciclo principale
void actionButton()
{
Serial.print("Pulsante: ");
Serial.print ( pulsante );
Serial.print (" : ");
Serial.println(encoderPos, DEC);
// ------------------ -------------------------------- actionButton
void actionPosition()
{
Serial.print("Posizione: ");
Serial.print(encoderPos, DEC);
Serial.print (" : ");
Serial.println ( pulsante );
// ------------------ -------------------------------- actionPosition
------------------------------ di routine del servizio di interruzione di -------------
Interrupt ISR su uno stato di modifica (contatore di posizione di incremento)
void doEncoderA()
{
se ( rotazione ) ritardo (1); aspettare un po 'fino a quando il rimbalzo è fatto
if( digitalRead(encoderPinA) ! A_set ) // pronuncia ancora una volta
{
A_set ! A_set;
regolare il contatore 1 se A conduce B
if ( A_set && ! B_set )
codificatorePos 1;
rotazione : false; non più debouncing fino a loop() colpisce di nuovo
}
---------------------------------------- doEncoderA -------------------
ISR Interrupt su B che cambia stato, come A sopra
void doEncoderB()
{
se ( rotazione ) ritardo (1);
if( digitalRead(encoderPinB) B_set !
{
B_set ! B_set;
regolare il contatore -1 se B conduce A
if( B_set && ! A_set )
codificatorePos - 1;
rotazione : false;
}
-------------------- -------------------------------------- doEncoderB
Speriamo che il nostro post sul blog oggi ti abbia aiutato a risolvere il tuo problema e come ispirazione di pensiero per i tuoi progetti e non vediamo l'ora di ricevere i tuoi commenti. Fino al prossimo post da A-Delivery, il tuo esperto di microelettronica!
3 commenti
Steven
https://github.com/ownprox/Rotary_Encoder_KY-040_Fixed
0 Jumping, use one with resistors built in and no need to add extra and you do not need to add a capacitor
Stefan Andres
Mit dem ESP32 (Arduino IDE) hatte ich viele Probleme den KY-040 vernünftig zum laufen zu bringen.
Ich habe einige Lib’s und Lösungen versucht, vergebens.
Der Grund: Es ist ein analoges Signal und der Interrupt wird, beim Eintreffen von CLK, mehrfach ausgelöst. Manchmal sogar einige 100 mal. Ein “debouncing” mit delay(x) bringt auch nicht wirklich eine Lösung. Kondensatoren gegen GND genau so wenig.
Nach einigen Versuchen habe ich eine Lösung mittels Schmitt Trigger gefunden:
Das Signal (clk) vom KY-040, zum Unterdrücken von Schwingungen mit einem Kondenstator (0,1µF) gegen GND an den Eingang des Schmitt Trigger (A) legen. Den Ausgang (Y) dann auf den Interrupt PIN. Damit wird die Interrupt Routine ebenfalls sehr einfach:
Nun noch einen Interrupt auf CLK Flanke “FALLING”. In der Routine brauch man nur noch DT abfragen.:
Code Auszug:
…….
volatile int16_t count=0;
uint8t clkPin;
uint8t _dtPin;
portMUX_TYPE mux = portMUX_INITIALIZERUNLOCKED;
void IRAM_ATTR ISR_ROTATION() {
portENTER_CRITICAL_ISR(&(mux));
if (digitalRead(dtPin)) _count++; //CW
else count—; // CCW
portEXIT_CRITICAL_ISR(&(mux));
}
KY040::KY040(uint8_t clkPin, uint8t dtPin, uint8t swPin) {
// constructor code
_clkPin = clkPin;
_dtPin = dtPin;
swPin = swPin;
pinMode(clkPin, INPUT);
pinMode(dtPin, INPUT);
pinMode(swPin, INPUT);
attachInterrupt(digitalPinToInterrupt(clkPin), ISRROTATION , FALLING);
….
}
…..
int16t KY040::readEncoder() {
uint16t c = _count;
_count = 0;
return c;
}
Analog habe ich auch den Switch gegen Prellen geschützt.
Walter van Boer
/*
Walter van Boer 12.06.2018 Further modifications: - writing error: actionposition() actionbutton() in void loop() - should be actionPosition(), actionButton() - should be: if (A_set && !B_set) in ISR void doEncoderA() -This sketch works great!*/