Switch and Encoder Interfacing With Arduino - DevBhoomi Robots

Home Top Ad

Responsive Ads Here

Post Top Ad

Your Ad Spot

Monday, September 17, 2018

Switch and Encoder Interfacing With Arduino

rotary_encoderI like using rotary encoders for user input as they can provide very precise control over settings. The built-in switch is also very convenient and makes it easy to implement the push button functionality I described in a previous post. Altogether, rotary encoders have a ‘modern’ feel that makes projects seem more professional.
There is one shortcoming of these devices, though, that I have recently worked to overcome.

The downside became obvious in a recent project where the encoder was being used to select a frequency between 1Hz and 10MHz. Seven orders of magnitude is quite a range and wholly unsuitable for the ‘standard’ method of one encoder click per value – it would have simply take too long to cover the range. However, I also did not want to lose the ability to move by 1 step value if that was needed.
Somehow the user needed to express how the encoder should work by how it was being used. The most obvious way was to sense how fast the encoder was being rotated and vary the step size accordingly – precise small steps for slow turning and bigger movement steps for faster turning.
I changed my rotary encoder library (MD_REncoder) to measure a ‘speed’ parameter measured in clicks per second. I found that could get counts of 1 to around 50 with normal use of the encoder, but this was still not providing large enough steps for a good user exeperience.
I needed a logarithmic increment to give the ‘kick’ needed at faster speeds. I turned the linear readings from the encoder into a logarithmic step size by applying the formula
step = 10^(int(speed/10))

ExponentialThis meant that speed readings of 0-10 resulted in step size 1 (ie, 10^0), 10-20 step 10 (ie, 10^1), … , 40-50 step 10,000 (ie, 10^4). Given the large range to be covered this work fantastically well.
A bonus of this algorithm is that the responsiveness of the system can be tuned to requirements.
For starters, the base for the exponential does not have to be 10.  5, 3, 2 (or numbers larger than 10) can be used depending on how ‘amplified’ the steps need to be. The table on the right shows how the step size varies for each exponent base (click the chart to enlarge).
The divisor for the speed value can also be varied to give larger or smaller index values – experimentation will allow you to pick numbers that give the desired response for the particular application.
I think this is one algorithm that I will be using more in future.

Update 30 May 2017

A more efficient expression for logarithmic increments on a base 2 system (ie, a computer) is:

step = 1 << (int(speed / 10))



KeySwitchThe humble switch is one of the major ways that users can interact with Arduino based code. Often the input comes from some variation of the momentary-on push switch, like the tact switch on the left, connected to an input on the microcontroller.
Users of modern GUIs will be familiar with being able to express themselves through a keyboard and a mouse. So user interface elements like double-clicks, long clicks and keyboard auto-repeat are familiar.
However, a lot of microcontroller code simply restricts the use of these switches to on/off functionality. Arduino programmers often don’t understand how to provide more features, even though a single switch can be made to do much more for a user.

Some time ago I wrote a utility library (MD_KeySwitch) that has become a mainstay in my own coding. This is a small library that reliably provides all the functionality I need to implement complex user interfaces using switch inputs – simple press, double press, long press and an auto repeat function. All but the simple press can be disabled and the library provides configurable timing for most of the functions.
The basis for the library is understanding the heirarchy of how the keypress can be processed – a key concept is that an event has to end before it can be reported. The initial press of a key is the start of the process and all timing values – from there we should be able to detect the following press sequences:
  • release after a short time for a simple press
  • release then press and release for a double press. In this case we really should not be detecting the initial press until we are sure that we don’t have a double!
  • release after a long time for a long press
  • once the switch has been held active for a time, auto repeat simple presses
I won’t be discussing the need for switch debouncing in this article. There are a number of references that cover this subject well. The best one I have is found here as web pages and here as a pdf. In this library debouncing is done using a timer long enough to allow the input to settle.
How do we detect all the different states and make sure the right type of switch press is detected? Using a Finite State Machine, of course! The FSM for the library, without the complications created by optional functionality, is shown and explained below.
KeySwitch_States
The FSM starts in the IDLE state, where it watches the configured input for the switch to be in active state (LOW if configured with pull-up resistors, HIGH for pull-down). The next immediate state is DEBOUNCE1 to wait through a timeout period of a few milliseconds for switch debouncing. If the switch is no longer active after this time then the FSM just retuns to IDLE state and nothing is detected.
However if the switch is active, then we could be detecting any of the possible events so the FSM moves to the PRESS state and starts a timing process. One of a two outcomes could occur:
  1. The switch could be released. This means that we definitely have a simple press but we could also have a double press coming, so move on to DPRESS state.
  2. The switch is not released for longer then the long press threshold time. In this case move the FSM to the LPRESS state – we can either have a long press of we could be heading towards auto repeat.
The DPRESS state waits for a new press within a double press timeout period. If it detects a new switch active state, it moves to DEBOUNCE2 (similar to the IDLE to DEBOUNCE1 transition). If the switch remains active at the end of the debounce period, then we have detected a double press. At this point we need to allow the user let go of the switch, which is what the WAIT state does. Once the switch is inactive WAIT move back to IDLE, assuring that the IDLE state will start with an inactive switch.
If the switch was not active at the end of DEBOUNCE2, then all we can decide is that we detected a single press and the FSM returns to IDLE.
If in step 2 above we went to the LPRESS state, then we could have one of 2 outcomes:
  1. The switch becomes inactive before the auto repeat threshold time is reached. In this scenario we detect a long press and reset back to IDLE.
  2. The switch is still active when the auto repeat threshold has expired. In this case we enter REPEAT state.
REPEAT state is simply a timer that waits for the repeat period to expire and then returns a simple press. This continues at the configured repeat rate (time period) until the switch becomes inactive.
Clearly, adding configurable items complicates the path of the FSM. and this is reflected in the code. However, the way of thinking about the problem is the same.
Once this type of utility library code is code is written, it can be reused again and again, simplifying this aspect of any future project.

Post Top Ad

Your Ad Spot