#96 Rotary Encoder Update - Stepless & Software Debounced

preview_player
Показать описание
A couple of recent comments on a previous video #19 (Rotary Encoders) made me think and ponder. So here's an update that looks at both the original sketch and stepped Rotary Encoder and also at a newer detentless (stepless) one, with the problems it potentially presents.

We also consider how best to debounce the signal in software and what happens if you change the way I originally did it with a Real World example of my car radio - yes, really!

I've included a link to a GitHub repository with the simple test sketches I used just so you can grab them and play about with them yourself, along with links to the stepless Rotary Encoder (rather more than I'd want to pay but it was supplied by a local supplier rather than a Far Eastern warehouse so would be more, of course).

--------------------------------
LINKS LINKS LINKS!
--------------------------------

Bourns Pro Audio Rotary Encoder Spec Sheet (generic)

Example eBay item for stepless rotary encoder
NOTE: The PEC-016 part number convention is that the second digit determines whether it is stepped or not.
Eg: PEC16-4020F-N0024 - it's the 4020F that is important - the second digit here (0) means STEPLESS
The next part, N0024 determine whether a SWITCH pin is included (N=NO, S=YES) and the 24 shows how many steps per revolution

Nick Gammon's web page on Interrupts:

The sketches used in the demo are in the repository. Just download as a zip file and unzip on your local machine.

If you like this video please give it a thumbs up, share it and if you're not already subscribed please do so :)

My channel is here:
------------------------------------------------------------------
------------------------------------------------------------------
How can I remember this? Memory tip: "See" Ralph Bacon, geddit?
Рекомендации по теме
Комментарии
Автор

Hi Ralph, I am still blown away about your original code, the simplicity, the use of that static variable and the speed and the responsiveness of the encoder in action. I have tried a few sketches and debouncing circuits, but your solution is absolutely the best! And these little boys are so very great to incorporate into our projects. So thanks very much :)

rolandberendonck
Автор

@Ralph thanks for this whole lesson and experiments. I have consulted several sources on how to debounce and make these cheap encoders more accurate... None of them reduced the lack of accuracy without slowing down the readings... I used the CLK falling ISR + a HW debounce with the 1nF / 100k RC filter and now it works like a consumer product. Thanks again!

leonardohomem
Автор

@7:48 that screwdriver scraping on the scope screen makes my teeth hurt X_X

RandallStephens
Автор

Hi again Ralf- thanks for another interesting and useful video. You have managed to fill an empty spot for all those that want to improve their knowledge with respect to what you teach and share. This is a great resource and I wanted to let you know it is much appreciated.

bikefarmtaiwan
Автор

I purchased a rotary encoder and it's doing the same thing. Seeing this video really helped me to understand what's going on. Thank you!

OneIdeaTooMany
Автор

Hmmm.. Old video, but hey, I couldn't help but notice that the change in code of lastInterruptTime changes to a "minimum time between pulses".. But contact-bounce _was_ taken care of by just "waiting around" for a TOTAL of 5ms.. A single contact bounce of 5 milliseconds sounds like a VERY long bounce to me. Usually the bounces are in the microseconds range. But there might be 10-20 bounces, thus a total wait of 5ms is "probably good".
But after moving it outside the if-clause, you could definitely reduce the time to make it more responsive, since every teeny bounce would reset the time.

arsenic
Автор

I had problems with a clicky rotary switch when I used them first. I learned you really need to debounce them or measure every edge change. If you handle all edge changes, you need usually no debounce, because then bouncing up signal is counted like up-down-up-down-up-down-up (which is same result as a single "up" because the up-down pairs are cancelled). If detents give you more than one count, just divide it with a suitable value. I found quickly too that with very fast turning you probably start missing pulses.
I think with every switch it is always very important to assume bouncing edges even if you have them or not. In future code may be pain to debug if you use different switch or you may get a buggy appliance by just replacing a broken rotary with another model that has debouncing you did not have before.
BTW, my favourite method of debouncing often was using a timer interrupt and tracking if you have enough similar readings in a row. If you read you may detect switch is probably stable 1 after several similar values. (and likewise must surely mean stable 0 for now). If you need a "push" event, just keep track of the stable value and as stable value changes (happens only once), register a push. (or like every n events if you want a repeating button effect).

hoggif
Автор

You mention that the Uno's and Nano 's don't like/do Interrupts on High - Is this also true for the Mega? Does this apply to the main INT pins or to all all the interrupts associated with the pins eg Int On Change.

Ray-ejjb
Автор

How much overhead does the serial.write affect the sensitivity of the resolver, or the perceived errors in the count? The interrupt may take too long or the serial.write may act as an additional interrupt when it is buffered.

terryschabert
Автор

Hi Ralph, I had this problem when I was designing a rope counter for measuring rope off a reel, I overcame the bounce issue by using a Schmitt trigger, but as you said you can only rotate a mechanical encoder so fast so I used an optical one in the end for my application. The use of a schmitt trigger gives you a lovely clean output signal though on a mechanical encoder.

loftos
Автор

Hello Ralph, thanks for sharing. I personally tries to do a strict separation between input, calculation and output. The shown method for decoding the rotary decoder volatile this. What i don't like is that the isr calculates a value. I think it's to limited and it throws away halve of the input information(the speed). I have made a decoding method that doesn't change a number but returns a value that give the direction and the time since the last puls. The calculation of the value that has to be changed is calculated in the sketch. That way i'm more flexible. This way i can add dynamics to the behavior. If the time is short the increment can be bigger.

spock
Автор

Hey Ralph. At about 6 minutes, you mentioned that the detent encoder has built-in pull up resistors. Would that be true of all detent encoders? That would explain why my works without needing to call a pull up in code. Thanks

KW-eipi
Автор

Nice info, thanks. I am currently working on a rotary encoder project.

jimbooth
Автор

thank you for exist. This video is so cool!

shalbsb
Автор

I have known Nick for 10 years plus(via forums) Nick and I were using Atmel chips for that time. Arduino is an Atmel micro. Nick knows arduino as all we had years ago was machine code for these devices. As a side note, memory was so small, that we had to use machine code rather than wastefull C. C even uses RAM for contants and string that don't change etc.

ismzaxxon
Автор

If you were using a micro-controller with more interrupt pins, could you use 2 to determine direction and count detents and another 2 to count pulses in between detents? That might allow you to simplify the code and reduce the likelihood of losing track of the direction.

jeffschroeder
Автор

One can get a 600 ppr optical rotary encoder from Ebay these days for as little as Aus$13.00 - $14.00 . I am about to look at using them in fact (as a counter) or rather as a dual counter for sync on a spindle to leadscrew and that is what brought me here.
This brings up another query you may be able to help me with, using 2 of these optical rotary encoders, one on the spindle and one on the leadscrew, if I am to use both interrupt pins, would any problem arise from missing pulses ? As I understand it only one interrupt can happen at a time.
Possible it is explained somewhere, ( need to look further) just thought I'd ask while I'm here.

jeffbluejets
Автор

Hi Ralph, could you explain line 34 a bit more as it appears max and min are reversed. I did a search of that particular line to see if I could understand it but nothing really came up.

jeffbluejets
Автор

Rising and Falling for iterrupts are fairly well defined. The logic in the microcontroller has a set point where a low becomes a high and vice versa. When the signal crosses that value, the 'rising' or 'falling' interrupt would be triggered. The 'change' interrupt is triggered no matter which way it goes. If your input were a slowly moving ramp signal, you could get some wacky readings, since the rising point will be different from the falling point, voltage-wise. But with an on/off signal like the encoder, we don't have to worry about that.
The code for using all four different states of a rotary encoder like this is fairly common. You need to read both pins on the change, and you need to know which one caused the interrupt. If pin A causes the Change interrupt and it's now High, it was rising. If pin B causes the interrupt and it's now low, it was falling. In the two separate ISR's, you have four states each: For the A interrupt: Pin A rising while B is low, or A rising while B is high. A falling / B high. A falling / B low. The B change interrupt would have similar states. If you study the timing diagram, you'll see that of these 8 states, four can only occur during clockwise rotation, and the other four can only occur during counterclockwise rotation. So you know immediately on getting the interrupt which way the encoder is turning, even if it skips due to being turned too fast. To halve the resolution, you could use Rising and Falling for A only, for example, and just ignore the other states. You'd only need to read B instead of both, since the interrupt already tells you A is Rising or Falling. This would be close to the code in the video, except you definitely know which way the encoder is turning. Taking it further, you could interrupt on one state - for example, A Rising. The ISR would only check B. If B is low, it's turning one way. High, it's the other.
It's important to note that the debounce time is effectively doubled if you check all states, since the interrupt will be called two times more than the original code. If you use only Rising or only Falling, it would be simply 5 ms, or half the original code. This is important because it will affect how fast you can turn the knob. If you check all states, you get really high resolution, but the ISR is busy ignoring you for 120 ms for every full rotation. It won't take much speed to miss a few ticks, especially if you get a noisy encoder and have to increase the time above 5 ms.
Most mechanical rotary encoders use wipers on a rotary disk with conductive fingers. It isn't a sprung contact pushed out of the way like a switch or relay - the wiper only has to move the thickness of the finger plating. The crossing does cause noise on the signal which will look like bounce, but it's much smaller than a sprung contact bounce. A 5 ms dead time wouldn't be long enough to debounce a sprung switch, but it works fine here, and even lower might be possible with a new encoder. Older ones get dirty and worn, of course, and will need more debounce time.

chrisw
Автор

Ralph,

Thanks for the update. Would you consider doing this with an ESP32? I'm using a ESP32 to control a Sous Vide cooker/PID loop. and would like to use the encoder to control a menu for time and temp changes and I'm not sure how to use an interrupt with the ESP32. I don't want to be sitting there checking the state of the encoder constantly. The program could be away from the PID loop for a second or two but it cannot be gone for any extended time or the temp will be way off.

I've switched most of my project MC work over to an ESP-8266 and now a ESP32 because of its additional features

williammiller