Skip to content
  • MySensors
  • OpenHardware.io
  • Categories
  • Recent
  • Tags
  • Popular
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Brand Logo
  1. Home
  2. Hardware
  3. KY-40 rotary encoder

KY-40 rotary encoder

Scheduled Pinned Locked Moved Hardware
10 Posts 5 Posters 4.4k Views 5 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • L Offline
    L Offline
    LastSamurai
    Hardware Contributor
    wrote on last edited by
    #1

    I bought the rotary encoder/switch that is linked in the store as I wanted to get such a combo to control my led strips (button = on/off, rotation = brightness or color). I did some googling but couldn't find any good and working code. Did anyone of you already use this device?

    My goal is to use that with a battery driven sensor, so it needs to sleep a lot which means relying on interrupts.

    What I think I got so far:

    • SW seems to be active high (also mine is missing the pullup resistor it seems)
    • DT and CLK are the rotation pins. Both are active low, one goes low first and indicates the direction of the rotation
    • Some additional hardware debouncing might be needed

    All the code I found is either not really working or requires and infinite loop and busy waiting (bad for the battery). My idea was to attach SW to one interrupt

    attachInterrupt(1, push, FALLING);
    
    void push ()  {
      delay(5); // debouncing?
      if (!digitalRead(PinSW))
        Serial.println("Pushed");
    }
    

    and one of the others to the other interrupt

    attachInterrupt(0, rotate, FALLING);
    
    void rotate ()  {
      delay(5);
      if (!digitalRead(PinDT)) {
        virtualPosition = virtualPosition + 1;
        Serial.println("Position " + virtualPosition);
      }
      else {
        virtualPosition = virtualPosition - 1;
        Serial.println("Position " + virtualPosition);
      } // isr
    
    }
    

    That doesn't seem to be working yet though. Any ideas from you guys?

    YveauxY vladimirV 2 Replies Last reply
    0
    • L LastSamurai

      I bought the rotary encoder/switch that is linked in the store as I wanted to get such a combo to control my led strips (button = on/off, rotation = brightness or color). I did some googling but couldn't find any good and working code. Did anyone of you already use this device?

      My goal is to use that with a battery driven sensor, so it needs to sleep a lot which means relying on interrupts.

      What I think I got so far:

      • SW seems to be active high (also mine is missing the pullup resistor it seems)
      • DT and CLK are the rotation pins. Both are active low, one goes low first and indicates the direction of the rotation
      • Some additional hardware debouncing might be needed

      All the code I found is either not really working or requires and infinite loop and busy waiting (bad for the battery). My idea was to attach SW to one interrupt

      attachInterrupt(1, push, FALLING);
      
      void push ()  {
        delay(5); // debouncing?
        if (!digitalRead(PinSW))
          Serial.println("Pushed");
      }
      

      and one of the others to the other interrupt

      attachInterrupt(0, rotate, FALLING);
      
      void rotate ()  {
        delay(5);
        if (!digitalRead(PinDT)) {
          virtualPosition = virtualPosition + 1;
          Serial.println("Position " + virtualPosition);
        }
        else {
          virtualPosition = virtualPosition - 1;
          Serial.println("Position " + virtualPosition);
        } // isr
      
      }
      

      That doesn't seem to be working yet though. Any ideas from you guys?

      YveauxY Offline
      YveauxY Offline
      Yveaux
      Mod
      wrote on last edited by
      #2

      @LastSamurai Try this library and connect the DT & CLK (horrible names btw) signals to interrupt pins, as described on this page.
      Works like a charm for me in combination with an UNO.

      http://yveaux.blogspot.nl

      1 Reply Last reply
      1
      • L Offline
        L Offline
        LastSamurai
        Hardware Contributor
        wrote on last edited by
        #3

        @Yveaux Thanks. I tried it out with this example code

        #include <Encoder.h>
        
        // Change these two numbers to the pins connected to your encoder.
        //   Best Performance: both pins have interrupt capability
        //   Good Performance: only the first pin has interrupt capability
        //   Low Performance:  neither pin has interrupt capability
        Encoder myEnc(3, 5);
        //   avoid using pins with LEDs attached
        
        void setup() {
          Serial.begin(9600);
          Serial.println("Basic Encoder Test:");
        }
        
        long oldPosition  = -999;
        
        void loop() {
          long newPosition = myEnc.read();
          if (newPosition != oldPosition) {
            oldPosition = newPosition;
            Serial.println(newPosition);
          }
        }
        

        using one interrupt pin (need the other one for the button) and it doesn't really work. I get 0 -1 0 -1... when I rotate it and -2 when I push the switch. I also added 4.7uF caps between ground and the 2 pins which got rid off the "spam" of values but doesn't change the values themselves. Also I don't see a way with that library to sleep until some motion of the switch is detected.

        1 Reply Last reply
        0
        • L Offline
          L Offline
          LastSamurai
          Hardware Contributor
          wrote on last edited by
          #4

          Ok I found this code from the arduino page on rotary encoders. This seems to work perfectly (beside always needing 2 clicks to register a change). Still have no idea how to use this with sleep though... guess I need to keep experimenting.

          /* interrupt routine for Rotary Encoders
             tested with Noble RE0124PVB 17.7FINB-24 http://www.nobleusa.com/pdf/xre.pdf - available at pollin.de
             and a few others, seems pretty universal
          
             The average rotary encoder has three pins, seen from front: A C B
             Clockwise rotation A(on)->B(on)->A(off)->B(off)
             CounterCW rotation B(on)->A(on)->B(off)->A(off)
          
             and may be a push switch with another two pins, pulled low at pin 8 in this case
             raf@synapps.de 20120107
          
          */
          
          // usually the rotary encoders three pins have the ground pin in the middle
          enum PinAssignments {
            encoderPinA = 2,   // right
            encoderPinB = 3,   // left
            clearButton = 5    // another two pins
          };
          
          volatile unsigned int encoderPos = 0;  // a counter for the dial
          unsigned int lastReportedPos = 1;   // change management
          static boolean rotating=false;      // debounce management
          
          // interrupt service routine vars
          boolean A_set = false;              
          boolean B_set = false;
          
          
          void setup() {
          
            pinMode(encoderPinA, INPUT); 
            pinMode(encoderPinB, INPUT); 
            pinMode(clearButton, INPUT);
           // turn on pullup resistors
            digitalWrite(encoderPinA, HIGH);
            digitalWrite(encoderPinB, HIGH);
            digitalWrite(clearButton, HIGH);
          
          // encoder pin on interrupt 0 (pin 2)
            attachInterrupt(0, doEncoderA, CHANGE);
          // encoder pin on interrupt 1 (pin 3)
            attachInterrupt(1, doEncoderB, CHANGE);
          
            Serial.begin(9600);  // output
          }
          
          // main loop, work is done by interrupt service routines, this one only prints stuff
          void loop() { 
            rotating = true;  // reset the debouncer
          
            if (lastReportedPos != encoderPos) {
              Serial.print("Index:");
              Serial.println(encoderPos, DEC);
              lastReportedPos = encoderPos;
            }
            if (digitalRead(clearButton) == LOW )  {
              encoderPos = 0;
            }
          }
          
          // Interrupt on A changing state
          void doEncoderA(){
            // debounce
            if ( rotating ) delay (1);  // wait a little until the bouncing is done
          
            // Test transition, did things really change? 
            if( digitalRead(encoderPinA) != A_set ) {  // debounce once more
              A_set = !A_set;
          
              // adjust counter + if A leads B
              if ( A_set && !B_set ) 
                encoderPos += 1;
          
              rotating = false;  // no more debouncing until loop() hits again
            }
          }
          
          // Interrupt on B changing state, same as A above
          void doEncoderB(){
            if ( rotating ) delay (1);
            if( digitalRead(encoderPinB) != B_set ) {
              B_set = !B_set;
              //  adjust counter - 1 if B leads A
              if( B_set && !A_set ) 
                encoderPos -= 1;
          
              rotating = false;
            }
          }
          
          YveauxY 1 Reply Last reply
          0
          • L LastSamurai

            Ok I found this code from the arduino page on rotary encoders. This seems to work perfectly (beside always needing 2 clicks to register a change). Still have no idea how to use this with sleep though... guess I need to keep experimenting.

            /* interrupt routine for Rotary Encoders
               tested with Noble RE0124PVB 17.7FINB-24 http://www.nobleusa.com/pdf/xre.pdf - available at pollin.de
               and a few others, seems pretty universal
            
               The average rotary encoder has three pins, seen from front: A C B
               Clockwise rotation A(on)->B(on)->A(off)->B(off)
               CounterCW rotation B(on)->A(on)->B(off)->A(off)
            
               and may be a push switch with another two pins, pulled low at pin 8 in this case
               raf@synapps.de 20120107
            
            */
            
            // usually the rotary encoders three pins have the ground pin in the middle
            enum PinAssignments {
              encoderPinA = 2,   // right
              encoderPinB = 3,   // left
              clearButton = 5    // another two pins
            };
            
            volatile unsigned int encoderPos = 0;  // a counter for the dial
            unsigned int lastReportedPos = 1;   // change management
            static boolean rotating=false;      // debounce management
            
            // interrupt service routine vars
            boolean A_set = false;              
            boolean B_set = false;
            
            
            void setup() {
            
              pinMode(encoderPinA, INPUT); 
              pinMode(encoderPinB, INPUT); 
              pinMode(clearButton, INPUT);
             // turn on pullup resistors
              digitalWrite(encoderPinA, HIGH);
              digitalWrite(encoderPinB, HIGH);
              digitalWrite(clearButton, HIGH);
            
            // encoder pin on interrupt 0 (pin 2)
              attachInterrupt(0, doEncoderA, CHANGE);
            // encoder pin on interrupt 1 (pin 3)
              attachInterrupt(1, doEncoderB, CHANGE);
            
              Serial.begin(9600);  // output
            }
            
            // main loop, work is done by interrupt service routines, this one only prints stuff
            void loop() { 
              rotating = true;  // reset the debouncer
            
              if (lastReportedPos != encoderPos) {
                Serial.print("Index:");
                Serial.println(encoderPos, DEC);
                lastReportedPos = encoderPos;
              }
              if (digitalRead(clearButton) == LOW )  {
                encoderPos = 0;
              }
            }
            
            // Interrupt on A changing state
            void doEncoderA(){
              // debounce
              if ( rotating ) delay (1);  // wait a little until the bouncing is done
            
              // Test transition, did things really change? 
              if( digitalRead(encoderPinA) != A_set ) {  // debounce once more
                A_set = !A_set;
            
                // adjust counter + if A leads B
                if ( A_set && !B_set ) 
                  encoderPos += 1;
            
                rotating = false;  // no more debouncing until loop() hits again
              }
            }
            
            // Interrupt on B changing state, same as A above
            void doEncoderB(){
              if ( rotating ) delay (1);
              if( digitalRead(encoderPinB) != B_set ) {
                B_set = !B_set;
                //  adjust counter - 1 if B leads A
                if( B_set && !A_set ) 
                  encoderPos -= 1;
            
                rotating = false;
              }
            }
            
            YveauxY Offline
            YveauxY Offline
            Yveaux
            Mod
            wrote on last edited by
            #5

            @LastSamurai I'm sure that if you would use two interrupt-pins to connect the encoder, the suggested library will also work just fine.
            You're changing your requirements along the way ;-)

            http://yveaux.blogspot.nl

            L 1 Reply Last reply
            0
            • hekH Offline
              hekH Offline
              hek
              Admin
              wrote on last edited by
              #6

              Well, I created this example way back for the KY-40:

              https://github.com/mysensors/MySensorsArduinoExamples/blob/master/examples/DimmableLightWithRotaryEncoderButton/DimmableLightWithRotaryEncoderButton.ino

              1 Reply Last reply
              0
              • YveauxY Yveaux

                @LastSamurai I'm sure that if you would use two interrupt-pins to connect the encoder, the suggested library will also work just fine.
                You're changing your requirements along the way ;-)

                L Offline
                L Offline
                LastSamurai
                Hardware Contributor
                wrote on last edited by
                #7

                @Yveaux I am sure it works then but I am not changing requirements ;) Perhaps I wasn't clear enough though.

                My goal is to get the arduino to correctly read values from the button/encoder (works with the libraries/codes) but to also sleep most of the time when noone uses the encoder as I want this to be a seperate battery powered "sensor" if possible. Perhaps I am missing something here but the only way to wake up from sleep when something is used are interrupts. So if the library uses them but doesn't provide any hooks into the "wake up call" I can't use it for this usecase.

                YveauxY 1 Reply Last reply
                0
                • L LastSamurai

                  @Yveaux I am sure it works then but I am not changing requirements ;) Perhaps I wasn't clear enough though.

                  My goal is to get the arduino to correctly read values from the button/encoder (works with the libraries/codes) but to also sleep most of the time when noone uses the encoder as I want this to be a seperate battery powered "sensor" if possible. Perhaps I am missing something here but the only way to wake up from sleep when something is used are interrupts. So if the library uses them but doesn't provide any hooks into the "wake up call" I can't use it for this usecase.

                  YveauxY Offline
                  YveauxY Offline
                  Yveaux
                  Mod
                  wrote on last edited by
                  #8

                  @LastSamurai said:

                  @Yveaux I am sure it works then but I am not changing requirements ;) Perhaps I wasn't clear enough though.

                  I meant first you don't use two interrupts to connect the sensor and then with some other code you do. Anyway, never mind it :expressionless:

                  My goal is to get the arduino to correctly read values from the button/encoder (works with the libraries/codes) but to also sleep most of the time when noone uses the encoder as I want this to be a seperate battery powered "sensor" if possible. Perhaps I am missing something here but the only way to wake up from sleep when something is used are interrupts. So if the library uses them but doesn't provide any hooks into the "wake up call" I can't use it for this usecase.

                  Apart from reworking parts of the library I see some options:

                  • Use a wired-OR to combine both encoder signals and connect that to an interrupt input. This will trigger the ATmega to wakeup, after which the regular encoder code can determine the new encoder value.
                  • Use the pushbutton of the encoder to wake the ATmega (so connect it to an interrupt pin), then the regular encoder code can determine the new encoder value.

                  IMHO, sleep, wake, decode, send a message and go to sleep again is quite tricky to get it right without loosing pulses.
                  For a good user experience it's probably best to stay awake for a while after waking up, giving your software time to process any more incoming pulses. When no new pulses have been detected for some time, you can go back to sleep again.

                  http://yveaux.blogspot.nl

                  1 Reply Last reply
                  0
                  • L LastSamurai

                    I bought the rotary encoder/switch that is linked in the store as I wanted to get such a combo to control my led strips (button = on/off, rotation = brightness or color). I did some googling but couldn't find any good and working code. Did anyone of you already use this device?

                    My goal is to use that with a battery driven sensor, so it needs to sleep a lot which means relying on interrupts.

                    What I think I got so far:

                    • SW seems to be active high (also mine is missing the pullup resistor it seems)
                    • DT and CLK are the rotation pins. Both are active low, one goes low first and indicates the direction of the rotation
                    • Some additional hardware debouncing might be needed

                    All the code I found is either not really working or requires and infinite loop and busy waiting (bad for the battery). My idea was to attach SW to one interrupt

                    attachInterrupt(1, push, FALLING);
                    
                    void push ()  {
                      delay(5); // debouncing?
                      if (!digitalRead(PinSW))
                        Serial.println("Pushed");
                    }
                    

                    and one of the others to the other interrupt

                    attachInterrupt(0, rotate, FALLING);
                    
                    void rotate ()  {
                      delay(5);
                      if (!digitalRead(PinDT)) {
                        virtualPosition = virtualPosition + 1;
                        Serial.println("Position " + virtualPosition);
                      }
                      else {
                        virtualPosition = virtualPosition - 1;
                        Serial.println("Position " + virtualPosition);
                      } // isr
                    
                    }
                    

                    That doesn't seem to be working yet though. Any ideas from you guys?

                    vladimirV Offline
                    vladimirV Offline
                    vladimir
                    wrote on last edited by
                    #9

                    @lastsamurai Hello!
                    Did you manage to implement this node?

                    korttomaK 1 Reply Last reply
                    1
                    • vladimirV vladimir

                      @lastsamurai Hello!
                      Did you manage to implement this node?

                      korttomaK Offline
                      korttomaK Offline
                      korttoma
                      Hero Member
                      wrote on last edited by
                      #10

                      @vladimir there is an example for using rotary encoder on this page:

                      https://www.mysensors.org/build/dimmer

                      • Tomas
                      1 Reply Last reply
                      0
                      Reply
                      • Reply as topic
                      Log in to reply
                      • Oldest to Newest
                      • Newest to Oldest
                      • Most Votes


                      20

                      Online

                      11.7k

                      Users

                      11.2k

                      Topics

                      113.1k

                      Posts


                      Copyright 2025 TBD   |   Forum Guidelines   |   Privacy Policy   |   Terms of Service
                      • Login

                      • Don't have an account? Register

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • MySensors
                      • OpenHardware.io
                      • Categories
                      • Recent
                      • Tags
                      • Popular