dimircea / REncoder

Rotary Encoder with and without builtin Switch implementation for Arduino UNO/MEGA/DUE and many others, inclusive Seeeduino XIAO.
Other
3 stars 1 forks source link

What is REncoder ?

REncoder is a simple Rotary Encoder and Switch Button implementation for Adruino and compatible boards. While working on a Home Automation project, I got in the need of using an Rotary Encoder with a builtin Switch, to be more specific, the Keyes KY-040 one.

At first, I was thinking: of course there are tons of such libraries !, so i've done my homework and do some search. Soon (well, after a few hours...) I just realized that while there are some libraries here and there that practically are doing that in one way or the other, none of them really worked good (if at all!) on all the boards I needed them to work: the Arduino UNO, Arduino MEGA and the Seeeduino XIAO.

In addition, I wanted to be able to control some things, like if IRQs must be used or not, if the push of the switch is detected continuously or requires a release before the next push, to set limits on the maximum and minimum value of the encoder rotation, to be able to use more than one encoder at once, and so on. While some of these features were (partially) available in some other libraries, I wasn't satisfied with the results, so it was the time to get to work and write some C/C++ code. A couple of hours and two medium cups of caffe later, I come up with the REncoder library.

Some basic tests shown that the library itself, with just one instance, had a footprint of about 30 Bytes RAM and 1200 Bytes FLASH when no IRQ and no Switch was used. This depends on the board (the above are for on an Arduino UNO) and used compiler, and your own code will of course add up on top of that.

How to install REncoder

Rencoder is basicaly just another Arduino library. To use it, you have a multitude of choices, such as:

Configure the library

This library is configurable. The configuration parameters are available in the REncoderConfig.h file. Due to the way on how the compilation works, you can't simply just define these parameters as part of your own code, i.e., inside your own sketch file. The parameters affects the compilation - multiple parts of the code are compiled differently on some of these parameters. The main reason for this, was to keep the usage of the RAM / FLASH resources as low as possible...these are anyway very limited in some boards.

The following parameters / flags are available:

Usage examples

In the examples folder you'll find a set of basic examples. The code comments (in particular, check the header files) may also help in special cases.

In addition, here are some relevant use cases that shall give you the feeling on how you can use the library and what it can do.

Example 1 - Simple Encoder: no IRQ and no Switch

For this examples, all the library parameters, available in the REncoderConfig.h configuration file are switched off.

    #include "REncoder.h"

    REncoder rEncoder(
        3, // the CLK Pin 
        4  // the DT 
    );

    void setup() {
      rEncoder.setMinEncoderPosition(-2);
      rEncoder.setMaxEncoderPosition(3);
    }

    void loop() {

      REncoder::Event encoderEvent = rEncoder.reState();

      switch (encoderEvent) {
        case REncoder::Event::REncoder_Event_Rotate_CW: 
          // use rEncoder.getPosition() to get the current position
          // This is the case when the encoder is rotated Clock Wise
          // Here add code for what you'll like to happen in this case...
        break;

        case REncoder::Event::REncoder_Event_Rotate_CCW: 
          // use rEncoder.getPosition() to get the current position
          // This is the case when the encoder is rotated Counter Clock Wise
          // Here add code for what you'll like to happen in this case...
        break;
      }
    }

Example 2 - Enabling the Switch

For this example, only the RENCODER_ENABLE_SWITCH parameter, available in the REncoderConfig.h configuration file is switched on. The extra code, by comparison with Example 1 is marked as bold.


    #include "REncoder.h"

    REncoder rEncoder(
        3, // the CLK Pin 
        4, // the DT Pin 
        2 // the SW Pin 
    );

    void setup() {
      rEncoder.setMinEncoderPosition(-2);
      rEncoder.setMaxEncoderPosition(3);
    }

    void loop() {

      REncoder::Event encoderEvent = rEncoder.reState();

      switch (encoderEvent) {
        case REncoder::Event::REncoder_Event_Rotate_CW: 
          // This is the case when the encoder is rotated Clock Wise
          // Here add code for what you'll like to happen in this case...
          // NOTE: you can use rEncoder.getPosition() to get the current encoder position
        break;

        case REncoder::Event::REncoder_Event_Rotate_CCW:  
          // This is the case when the encoder is rotated Counter Clock Wise
          // Here add code for what you'll like to happen in this case...
          // NOTE: you can use rEncoder.getPosition() to get the current encoder position
        break;

        case REncoder::Event::REncoder_Event_Switch_Pushed: 
          // The switch was activated / the button was pressed
          // // Here add code for what you'll like to happen in this case...
        break;
      }
    }

Example 3 - Use IRQ(s)

For this example the following parameters were enabled: RENCODER_ENABLE_SWITCH, RENCODER_ENABLE_SWITCH_IRQ and RENCODER_ENABLE_ENCODER_IRQ. All these parameters are available in the REncoderConfig.h configuration file. Notice how the call to rEncoder.reState() is now missing. It is also important to notice that one can still use IRQ for the switch but not for the encoder, and the other way around. All this is possible by enabling and/or disabling the following two parameters: RENCODER_ENABLE_SWITCH_IRQ and RENCODER_ENABLE_ENCODER_IRQ.


    #include "REncoder.h"

    REncoder rEncoder(
        3, // the CLK Pin 
        4, // the DT Pin 
        2 // the SW Pin 
    );

    void setup() {
      rEncoder.attachSwitchHandler([]() {
        // here add your code to be executed when the switch is pressed
      });

      rEncoder.attachEncoderHandler(
        [](REncoderWithoutSwitch::Event encoderEvent, int16_t encPos) {

        switch (encoderEvent) {
          case REncoder::Event::REncoder_Event_Rotate_CW: 
            // here add your code to be executed when the encoder is rotated Clock Wise
            // The current value of the rotation is provided by the encPos parameter
          break;

          case REncoder::Event::REncoder_Event_Rotate_CCW: 
            // here add your code to be executed when the encoder is rotated Counter Clock Wise
            // The current value of the rotation is provided by the encPos parameter
          break;
        }
      });
    }

    void loop() {}

Some Special features

One of the features that I wanted to have and no other library provided it, was to allow to rotate the encoder when the switch was pushed. This feature only works when the button does not use an IRQ and it is enabled by default. It can be controlled by calling the method enableEncoderWhenSwitchPushed with true to enable it and false to disable it.


    #include "REncoder.h"

    REncoder rEncoder(
        3, // the CLK Pin 
        4, // the DT Pin 
        2 // the SW Pin 
    );

    void setup() {
      // ... some code ...

      // disable the encoder when the switch is kept pressed
      rEncoder.enableEncoderWhenSwitchPushed(false) 

      // ... some code ...
    }

    void loop () {...}

Another feature that I wanted to have, was to be able to keep the button pressed and to get the event continuously. This was needed to be able to use the encoder with a user interface. This feature only works when the button does not use an IRQ and it is disabled by default. It can be controlled by calling the method enableContinuousSwitchDetection with true to enable it and false to disable it.


    #include "REncoder.h"

    REncoder rEncoder(
        3, // the CLK Pin 
        4, // the DT Pin 
        2 // the SW Pin 
    );

    void setup() {
      // ... some code ...

      // enable the continuous detection of the switch pressed event
      rEncoder.enableContinuousSwitchDetection(true) 

      // ... some code ...
    }

    void loop () {...}

MIT License - free to use at your own risk