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