This is yet another Arduino library for controlling rotary encoders with an optional pushbutton. It supports both full cycle and half cycle encoders. Probably the most common is a full cycle encoder where both signals switch on and off for every click. A half cycle encoder has an additional click half-way, which means that the signals don't have a fixed idle state.
Various signal names are used for encoders but this library refers to them as A and B, where the A signal switches before the B signal when you turn the encoder clockwise. If your encoder behaves differently, just swap the pins.
The code doesn't require any debouncing circuitry, debouncing is done with "logical hysteresis" where the value is only changed after two edges in the same direction. Two edges on either A or B for a full cycle encoder, or edges on both A end B for a half cycle encoder.
The library can use interrupts or polling. By default, one or more
pin change interrupts are used to track the position of an encoder.
When the GPIO pins you configure for an encoder don't support pin
change interrupts, the code falls back to polling mode. You can also
force polling mode in the call to begin(). In polling mode, you need
to call the poll() function every couple of milliseconds yourself,
for instance from a timer interrupt handler.
For a full cycle encoder, either the A or B pin should support a pin change interrupt. A half cycle encoder requires pin change interrupts for both the A and B pins.
There are member functions to change the value of the encoder or set limits and optionally enable a wraparound mode.
For more complex scenarios, such as for instance progressive resolution, you can install a callback function that is called for every left or right click.
There is also a function to poll the state of the pushbutton, using a simple time-based debouncing method. You can retrieve the time between the two last button changes to check how long the button was pressed (or released).
On platforms supporting attachInterruptArg() such as ESP32 and ESP8266,
the object instance can be passed as an argument to the interrupt handler.
On other platfoms, a compromise is used to keep the implementation relatively simple. The four possible interrupt handlers are shared by all encoder objects. An objects is added to one or two linked lists corresponding to the interrupt handlers it uses and each interrupt handler will service all objects on its list.
This means that when multiple encoder objects use the same interrupt handler an interrupt may be serviced unnecessarily when an input pin of another encoder changes. In practice this is usually not an issue as the number of available hardware interrupts on these platforms is limited anyway. And by cleverly allocating the input pins you can limit the length of these lists, in many cases to just a single object. For instance, when there are two pins that support a pin change interrupt, you can use one for pin A of encoder 1 and the other one for pin B of encoder 2.
YetAnotherRotaryEncoder(int a_pin, int b_pin, int button_pin=0, int pinmode=INPUT_PULLUP, bool type=FULL_CYCLE, bool idle=HIGH);
- Specify the pin numbers for A, B and the optional button switch.
- Use
pinmodeINPUTwhen you have external pull-ups or bounce filters orINPUT_PULLUPfor a bare encoder. - The
typeparameter can be eitherFULL_CYCLEorHALF_CYCLE. - The
idleparameter should beHIGHwhen pull-ups are used,LOWfor pull-downs.
bool begin(bool polling=false);
- Start this instance, returning
truewhen the encoder is interrupt driven. It will try to use interrupts by default, but you can force polling mode with thepollingparameter.
void end();
- Stop this instance.
void poll();
- Polling function, to be used when interrupts are not enabled.
int getValue();
- Get the encoder value.
void setValue(int value);
- Set the encoder value.
void setLimits(int low, int high, bool wrap=false);
- Set encoder value limits to the range [low,high) and define the wraparound behavior.
void setCallback(Callback func, int id=0);
- Install a callback for encoder value updates.
The
idparameter is passed as the first argument to the callback function. The second argument is the delta value: -1 or +1.
bool buttonDown();
- Poll the button state with debouncing.
unsigned long buttonTime();
- Return the time between the two last button state changes (msec).
YetAnotherRotaryEncoder is free software, licensed under the terms of the GNU General Public License as published by the Free Software Foundation.