Debounced Rotory Encoder - AZ-Delivery

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!

 

Für arduinoSpecials

3 commenti

Steven

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

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;
uint8
t clkPin;
uint8
t _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, uint8
t dtPin, uint8
t swPin) {
// constructor code
_clkPin = clkPin;
_dtPin = dtPin;
swPin = swPin;
pinMode(clkPin, INPUT);
pinMode(dtPin, INPUT);
pinMode(swPin, INPUT);
attachInterrupt(digitalPinToInterrupt(
clkPin), ISR
ROTATION , FALLING);
….
}
…..
int16
t KY040::readEncoder() {
uint16
t c = _count;
_count = 0;
return c;
}

Analog habe ich auch den Switch gegen Prellen geschützt.

Walter van Boer

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!
*/

Lascia un commento

Tutti i commenti vengono moderati prima della pubblicazione