Debounce Rotary Encoder

Car de nos Clients dans les derniers Temps, les Questions de mise en œuvre du Drehimpulsgebers numérique (Poti) ont été posées, nous présentons brièvement une Possibilité de montrer un Signal de Drehimpulsgebers à l'aide des Interruptions de dépenser. Ici dans l'Exemple, le Série du Moniteur:

Circuit:

Nomenclature:

 

Sketch Arduino:

/*
* le Rotary Encoder connected to a Microcontrôleur, compatible with Arduino Uno R3
*
* Codeur Pins: CLK, DT, SW, +, GND
* The encoder contains two pull-up resistors of 10k at CLK and DT
* All contacts are low-active
*
* Program based on logiciel by Stefan Nicolas
* https://www.nikolaus-lueneburg.de/2016/02/rotary-encoder/
* and important code written by rafbuff at http://playground.arduino.cc/Main/RotaryEncoders
* "Another Interruption Library THAT REALLY WORKS (the Encoder interruptions the processor
* and debounces like there is no tomorrow)."
*
* Les broches 2 and 3 are used because they support interrups !
* Debouncing works really great !!!
* Math.positive, compter: DT on 3, CLK on 2
* Horaire de comptage: DT on 2, CLK on 3
*
* les Modifications:
* - deleted 'unprintable' characters, modified {} and TABs
* - added the button detection for pin 4 "SW"
* - ajout de actionButton() and actionPosition(); here we can put down the
* code for further processing dans notre système.
*
* UKA 31.05.2018
*/


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


volatile unsigned int encoderPos = 0; // a counter for the dial
unsigned int lastReportedPos = 1; // change management
static boolean rotating = false; // debounce de la gestion

int bouton = LOW;
int old_button = LOW;

// routine de service d'interruption variable
boolean A_set = false;
boolean B_set = false;


void setup()
{
pinMode(encoderPinA, INPUT);
pinMode(encoderPinB, INPUT);

pinMode( SW, INPUT_PULLUP );


digitalWrite(encoderPinA, HIGH); // turn on pullup resistors
digitalWrite(encoderPinB, HIGH); // turn on pullup resistors

attachInterrupt(0, doEncoderA, CHANGE); // codeur broche on interruption 0 (broche 2)
attachInterrupt(1, doEncoderB, CHANGE); // codeur broche on interruption 1 (broche 3)

Serial.begin(9600); // output to PC Serial Monitor

}// --------------------- le programme d'installation --------------------------------



void loop()
{
rotating = true; // reset the debouncer

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


button = !digitalRead( SW );

if( button != old_button )
{
actionButton();
delay( 10 );
old_button = button;
}

}// --------------------------- boucle principale -----------------------


void actionButton()
{
Serial.print("Bouton ");
Serial.print ("button");
Serial.print (" | ");
Serial.println(encoderPos, DEC);
} // ------------------ actionButton --------------------------------


void actionPosition()
{
Serial.print("Position: ");
Serial.print(encoderPos, DEC);
Serial.print (" | ");
Serial.println ("button");
} // ------------------ actionPosition --------------------------------




// ------------- Interrupt Service Routine ------------------------------

// ISR Interruption on A changing state (Incrémenter le compteur de position)
void doEncoderA()
{
if ( rotating ) delay (1); // wait a little until the bouncing is done
if( digitalRead(encoderPinA) != A_set ) // debounce once more
{
A_set = !A_set;
// adjust compteur +1 if A leads B
if ( A_set && !B_set )
encoderPos += 1;
rotating = false; // no more debouncing until loop() hits again
}
}// ------------------- doEncoderA ----------------------------------------


// ISR Interruption on B changing state, same as above
void doEncoderB()
{
if ( rotating ) delay (1);
if( digitalRead(encoderPinB) != B_set )
{
B_set = !B_set;
ajuster le compteur -1 si B mène A
si (B_set et ! A_set )
encoderPos - 1;
rotation - faux;
}
-------------------- doEncoderB --------------------------------------

Nous espérons que notre blog d’aujourd’hui vous a aidé à résoudre votre problème et comme une source d’inspiration pour vos projets et nous attendons avec impatience vos commentaires. Jusqu’au prochain post de AZ-Delivery, votre expert en microélectronique!

 

Für arduinoSpecials

2 commentaires

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

Laisser un commentaire

Tous les commentaires sont modérés avant d'être publiés