Go Down

Topic: WIRING of KY-040 Rotary Encoder plus Demo Code (Read 41157 times) previous topic - next topic

arduinoaleman

May 24, 2014, 02:58 pm Last Edit: May 26, 2014, 01:35 am by arduinoaleman Reason: 1
  ROTARY ENCODER KY-040 on Arduino UNO    -   May 2014

  WIRING INFORMATION
  ===================
  Connect CLK to Pin 2 on Arduino Board  (CLK is Data Output 1 of KY-040)
  Connect DT  to Pin 3 on Arduino Board  (DT is Data Output 2 of KY-040)
  Connect SW  to Pin 4 on Arduino Board  (Switch - goes LOW when pressed)
  Connect GND to ground
  Connect +   to +5V  (this will pull up CLK and DT with 10 KiloOhm resistors)
  ----------------------------------------------------------------------------
  Connect a 0,47µ capacitor from ground to CLK   (debouncing)
  Connect a 0,47µ capacitor from ground to DT    (debouncing)
  Connect a 10 KiloOhm resistor from +5V to SW (no integrated pullup for SW !!)
  ----------------------------------------------------------------------------
  It is better NOT to use internal pull-up resistors on the Arduino, instead
  use the integrated pull-ups of KY-040 (this requires "+" to be connected to 5V).
  You can check if your version of the KY-040 has pull-up resistors on the bottom
  side ouf the printed circuit board.
  If not, use internal pull-ups from Arduino or external pull-ups.
  -----------------------------------------------------------------------------
  In the stopping positions the KY-040 has always HIGH signals on both CLK and DT.
  When you turn the encoder from one position to another, either CLK or DT goes LOW
  before the other signal goes LOW as well.
  The signal that goes LOW first determines if the encoder is turned left or right.
  Once you reach the next stopping position both signals will be HIGH again.

  If you press the push button, the current count can be reset to ZERO.

  For faster response you might increase the speed of the serial connection.
  (Make sure, that the Serial Monitor is also set to a higher speed,
   otherwise you will get no output).

  My rotary encoder came from china for 2 dollars, and after some debugging i found out, that it sometimes
  behaves strange (e.g. it gives a signal to the SW pin - although I did not press the button.)
  So for serious projects invest a dollar more and buy a quality product.
  ----------------------------------------------------------------------------------

Code: [Select]

volatile boolean TurnDetected;
volatile boolean up;

const int PinCLK=2;                   // Used for generating interrupts using CLK signal
const int PinDT=3;                    // Used for reading DT signal
const int PinSW=4;                    // Used for the push button switch

void isr ()  {                    // Interrupt service routine is executed when a HIGH to LOW transition is detected on CLK
 if (digitalRead(PinCLK))
   up = digitalRead(PinDT);
 else
   up = !digitalRead(PinDT);
 TurnDetected = true;
}


void setup ()  {
 pinMode(PinCLK,INPUT);
 pinMode(PinDT,INPUT);  
 pinMode(PinSW,INPUT);
 attachInterrupt (0,isr,FALLING);   // interrupt 0 is always connected to pin 2 on Arduino UNO
 Serial.begin (9600);
 Serial.println("Start");
}

void loop ()  {
 static long virtualPosition=0;    // without STATIC it does not count correctly!!!

 if (!(digitalRead(PinSW))) {      // check if pushbutton is pressed
   virtualPosition=0;              // if YES, then reset counter to ZERO
   Serial.print ("Reset = ");      // Using the word RESET instead of COUNT here to find out a buggy encoder
   
   Serial.println (virtualPosition);
 }  
 
 if (TurnDetected)  {    // do this only if rotation was detected
   if (up)
     virtualPosition++;
   else
     virtualPosition--;
   TurnDetected = false;          // do NOT repeat IF loop until new rotation detected
   Serial.print ("Count = ");  
   Serial.println (virtualPosition);
 }
}

   
If your questions are not precise, nobody can help you.

MAS3

Hi and welcome.

Did you read this (click !) ?
Don't answer that question, it's a truism, i already know you didn't.
Please do and edit your post accordingly.
That will make your post / example as useful as you hoped it would / meant it to be.
Have a look at "blink without delay".
Did you connect the grounds ?
Je kunt hier ook in het Nederlands terecht: http://arduino.cc/forum/index.php/board,77.0.html

poor_leno

Thank you @arduinoaleman

This has definitely helped me with my KY-040 encoders I've just received from eBay. I appreciate the post.

Cheers
Ben

cattledog

Code: [Select]
void isr ()  {                    // Interrupt service routine is executed when a HIGH to LOW transition is detected on CLK
  if (digitalRead(PinCLK))
    up = digitalRead(PinDT);
  else
    up = !digitalRead(PinDT);
  TurnDetected = true;
}



There is redundancy in your ISR because it is only triggered by FALLING. and the digitalRead of PinCLK (the interrupt pin) can not be HIGH.

This code works fine with the simplified ISR

Code: [Select]
void isr ()  {                    // Interrupt service routine is executed when a HIGH to LOW transition is detected on CLK
    up = !digitalRead(PinDT);
  TurnDetected = true;
}

Paul__B


This code works fine with the simplified ISR

And it just might, except that you will be in a world of pain "down the track" using interrupts inappropriately and trying to figure out how to debounce the thing which will be necessary for any serious use of this encoder given its construction.

Interrupts - and the glib tutorials detailing them - are a major trap for "newbies".  Rotary encoders for manual input should in almost all cases be polled using suitable debounce routines, not interrupts.

cattledog

Quote
Rotary encoders for manual input should in almost all cases be polled using suitable debounce routines, not interrupts.


Agreed. I probably should have commented upon the OP's approach as well as his specific code. 

To his credit, the OP did have his encoder debounced with hardware, and did not try and place debounce routines with millis() timers within the interrupt.

mihi88

Hi guys! Today I found in mailbox the encoder KY040 from China.

So I found this thread and copy/paste original code.
I found out that when you turn the encoder, Arduino always skip one step. That really irritates me.

So I must little bit change base code from first post.
I change interrupt mode from FALLING to CHANGE
Code: [Select]

  attachInterrupt (0,isr0,CHANGE);


modify isr routine
Code: [Select]

void isr0 ()  {
  up = (digitalRead(PinCLK) == digitalRead(PinDT));
  TurnDetected = true;
}


and correct little bug.
Code: [Select]

  if (!(digitalRead(PinSW)) && (Position != 0)) {


I haven't found a 0,47 uF capacitor, but with 1 uF it's working fine. Without bouncing.
Add one capacitor on the SW pin too.

arduinoaleman

#7
Feb 16, 2015, 04:10 am Last Edit: Feb 23, 2015, 11:13 pm by arduinoaleman
When it comes to time critical responses you should NOT use polling techniques.

In many cases software debouncing seems to be the more elegant solution. However, hardware debouncing saves you processing time and does not need any code. It requires just a couple of resistors and capacitors in most cases (this is why software people always go for software debouncing).

So there is NO GENERAL RULE when it comes to choosing between interrupts and polling.

It just depends on your project and if you can afford to lose some input signals. In most situations it is not critical to lose an input signal from a rotary encoder, because you simply have to turn it once more.

If you have any doubts please google for: "jeremy blum tutorial 10".
This tutorial is about HW debouncing and interrupts. Pretty good stuff.
You will like his other tutorials as well.

And please DO NOT use SW debouncing in combination with interrupts.
Otherwise - do whatever you want to do.
If your questions are not precise, nobody can help you.

JimboZA

@arduinolaleman.... please don't change the post's subject title. That made this thread get a new name (at least while your post was the latest) with no "Re:" in the list. It's my opinion, but that is really annoying. At least one member disagrees with me; at least one mod agrees with me.
Johannesburg hams call me: ZS6JMB on Highveld rep 145.7875 (-600 & 88.5 tone)
Dr Perry Cox: "Help me to help you, help me to help you...."
Your answer may already be here: https://forum.arduino.cc/index.php?topic=384198.0

Paul__B

That made this thread get a new name (at least while your post was the latest) with no "Re:" in the list. It's my opinion, but that is really annoying. At least one member disagrees with me; at least one mod agrees with me.
That is bizarre.

When I look in the index, I see only the original thread name.

JimboZA

That is bizarre.

When I look in the index, I see only the original thread name.

NOW you do yes, since it seems it reverts to the thread title once another post is made.

While the post that changes the title is the last post, the changed title is the one that appears in the list, no "Re:" and looking like a new thread.

So by the time you had seen my post, my post was of course the latest one, and the title had reverted.
Johannesburg hams call me: ZS6JMB on Highveld rep 145.7875 (-600 & 88.5 tone)
Dr Perry Cox: "Help me to help you, help me to help you...."
Your answer may already be here: https://forum.arduino.cc/index.php?topic=384198.0

Paul__B

Ahh, dear - you are just not getting the message!

I just ran a quick test and am vindicated.  Whatever I may change the title to, the "subject" field in the index does not change.

We know that, as we are so often telling "newbies" to change the subject line in their first post to include the term "Solved" so that is then indicated in the index because it is that subject that is used in the index.

What is confusing you, and on what I have been challenging you, is that you are not using the Category index, but some other listing - presumably the overall "Recent Posts" listing which is somewhere available and which you would have to customise to choose which particular categories you "follow".  And that is of course, your prerogative, but since that is not the general index, I see it differently.



Actually, you now cause me to research the matter.   ;)   It actually must be the "Unread posts" listing which is rather clever because it knows which categories I follow (in separate tabs on my "main" computer but not my wife's or the "Church" machine while I print CDs or burn CDs respectively, in quantity).

But I have a particularly elegant solution for you!  Since you know I may have altered a topic as it appears in that particular listing, then just do not read any topic where you see I was clearly listed as the most recent contributor, because it tells you that.

Dead easy really!   :smiley-lol:

JimboZA

I bow to your superior something or other.

I'm out.

Been meaning to leave the forum for ages.... now I just did,

Toodles everyone.
Johannesburg hams call me: ZS6JMB on Highveld rep 145.7875 (-600 & 88.5 tone)
Dr Perry Cox: "Help me to help you, help me to help you...."
Your answer may already be here: https://forum.arduino.cc/index.php?topic=384198.0

Laurent6012

#13
Apr 09, 2015, 03:11 am Last Edit: Apr 09, 2015, 03:46 am by Laurent6012
Hello arduinoaleman,

Your code work well, thank you for the explanations.
And for you have no regret. You say :

  "My rotary encoder came from china for 2 dollars, and after some debugging i found out, that it sometimes behaves strange (e.g. it gives a signal to the SW pin - although I did not press the button.).
  So for serious projects invest a dollar more and buy a quality product."

No worries about this, after i was get one kit on Amazon in France i was get my things from China.
Even the kit make the sensor an things less expensive that still more than in China, i think around 1,50€ a bit less than your.
And at last the rotary encoder from the kit a "Keyes" product don't work well, it have weird bounces, and respond in inverse ! The Chinese product work like a charm, and in more it's 0,95€.
Of course the both came from China, but Keyes is very knew and that's not a good deal sometime.

Regards.

Shorebird69

I am very new to this arduino, but am learning. I want to control a small stepper motor remotely wired to turn an air capacitor for a magnetic loop antenna. I figured using a rotary encoder to turn the motor at the same speed and movement as the encoder. does anyone have any insight to this and can point me in the right direction, thank you

Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy