Debounced Rotory Encoder - AZ-Delivery

Da von unseren Kunden in letzter Zeit 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 auszugeben. Hier im Beispiel am Seriellen Monitor:

Schaltung:

St-ckliste:

 

Arduino Sketch:

/*
* Codificador giratorio conectado a un microcontrolador, compatible con Arduino Uno R3
*
* Pines del codificador: CLK, DT, SW, +, GND
* El codificador contiene dos resistencias pull-up de 10k en CLK y DT
* Todos los contactos son de baja actividad
*
* Programa basado en software de Stefan Nikolaus
* https://www.nikolaus-lueneburg.de/2016/02/rotary-encoder/
* y código importante escrito por rafbuff en http://playground.arduino.cc/Main/RotaryEncoders
* "Otra biblioteca de interrupciones que realmente funciona (el codificador interrumpe el procesador
* y debounces como si no hubiera un mañana)."
*
* Pines 2 y 3 se utilizan porque soportan interrumps !
* Debouncing funciona muy bien !!!
* Recuento de Matemáticas positivas: DT en 3, CLK en 2
* Conteo en el sentido de las agujas del reloj: DT en 2, CLK en 3
*
* Modificaciones:
* - caracteres 'no imprimibles' eliminados, modificados y TABs
* - se ha añadido la detección de botones para el pin 4 "SW"
* - añadido actionButton() y actionPosition(); aquí podemos poner el
* Código para su posterior procesamiento en nuestro sistema.
*
* UKA 31.05.2018
*/


#define encoderPinA 2
#define encoderPinB 3
#define SW 4


volatile unsigned encoderPos - 0; un contador para la esfera
unsigned int lastReportedPos ? 1; gestión del cambio
booleano estático rotativo - false; gestión de bounce

Botón int - BAJO;
int old_button - BAJO;

interrumpir las variables rutinarias de servicio
booleano A_set - false;
booleano B_set - false;


configuración del vacío()
{
pinMode(encoderPinA, INPUT);
pinMode(encoderPinB, INPUT);

pinMode( SW, INPUT_PULLUP );


digitalWrite(encoderPinA, HIGH); activar las resistencias pullup
digitalWrite(encoderPinB, HIGH); activar las resistencias pullup

attachInterrupt(0, doEncoderA, CHANGE); Pin del codificador en la interrupción 0 (pin 2)
attachInterrupt(1, doEncoderB, CHANGE); Pin del codificador en la interrupción 1 (pin 3)

Serial.begin(9600); salida al monitor serie de PC

•// --------------------- -------------------------------- de configuración



void loop()
{
rotación de la strue; restablecer el debouncer

if (lastReportedPos !- encoderPos)
{
actionPosition();
lastReportedPos - encoderPos;
}


botón !digitalRead( SW );

botón if(!- old_button )
{
actionButton();
delay( 10 );
old_button botón;
}

•// --------------------------- ----------------------- de bucle principal


void actionButton()
{
Serial.print("Botón: ");
Serial.print ( botón );
Serial.print ("a ");
Serial.println(encoderPos, DEC);
• // ------------------ actionButton --------------------------------


void actionPosition()
{
Serial.print("Posición: ");
Serial.print(encoderPos, DEC);
Serial.print ("a ");
Serial.println (botón );
• // ------------------ actionPosición --------------------------------




------------- ------------------------------ de rutinas de servicio de interrupción

Interrupción ISR en un estado cambiante (contador de posición de incremento)
void doEncoderA()
{
si (rotación ) retardo (1); esperar un poco hasta que el rebote se hace
if( digitalRead(encoderPinA) !- A_set ) // debounce una vez más
{
A_set ! A_set;
ajustar contador +1 si A conduce B
si ( A_set && ! B_set )
encoderPos + 1;
rotación: falso; no más debouncing hasta loop() golpea de nuevo
}
•// ------------------- ---------------------------------------- doEncoderA


Interrupción del ISR en el estado cambiante B, lo mismo que A arriba
void doEncoderB()
{
si (rotación ) retardo (1);
if( digitalRead(encoderPinB) !- B_set )
{
B_set ! B_set;
ajustar el contador -1 si B lleva A
if( B_set && ! A_set )
encoderPos - 1;
rotación: falso;
}
-------------------- -------------------------------------- doEncoderB

Esperamos que nuestra entrada de blog de hoy le haya ayudado a resolver su problema y como una inspiración de pensamiento para sus proyectos y esperamos sus comentarios. ¡Hasta el próximo post de AZ-Delivery, tu experto en microelectrónica!

 

Für arduinoSpecials

3 comentarios

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

Deja un comentario

Todos los comentarios son moderados antes de ser publicados