Rotary encoders done right

I have been working for a while trying to get a rotary encoder to work somewhat reliably. I downloaded 4 different examples and all of them provided poor results with the encoder generating sporadic results.

I finally discovered this link and would recommend it to anyone trying to make an encoder work.

I would not say it is 100% effective, but it is very close. Almost all the spurious activity and multiple values from a single click are gone. It works well enough to use an encoder for tuning in my radio project.

PickyBiker:
I have been working for a while trying to get a rotary encoder to work somewhat reliably. I downloaded 4 different examples and all of them provided poor results with the encoder generating sporadic results.

I finally discovered this link and would recommend it to anyone trying to make an encoder work.
Buxtronix: Rotary encoders, done properly

I would not say it is 100% effective, but it is very close. Almost all the spurious activity and multiple values from a single click are gone. It works well enough to use an encoder for tuning in my radio project.

It is not the encoder problem, it is poorly written software.
Some of the attempts seen here did the decoding in loop().
Talking abut buggy, spaghetti code. .

Just curious - how do you adjust radio frequency with a device which has only four position in one rotation?
My optical encoder has 64 slots and I had a fun time decoding the speed of the rotation to the frequency steps - from band changing to fine tuning SSB signal.

I, too, get nervous when I see someone adds demo code as a comment where they use a Serial.println() call in their interrupt service routine. As to debouncing, I find it easier to add a 0.1uF cap from the clock and data lines to ground.

The serial print is for demo purposes.

The encoder is used to control a digital pot. That pot is what tunes the Si4844 Analog Tune Digital Display chip from Silicon Labs.

I agree that caps do help control noise on a mechanical encoder. Still, with the other four demos I tried, I got spurious activity even with caps on.

With this software and caps, I get near perfection.

With more recent versions of avr-gcc, I suspect that your original version is the better choice. At some point the compiler started using SREG / T for single bit operations.

The only other possibility that comes to mind is a pair of branch-on-set/clear instructions. Which usually cannot be reduced.

If I have time I will take a gander later tonight.

"You have a signed counter variable and you add or subtract from it depending on which way the encoder is turning. When you want to see how far it has moved somewhere in the code, you just read that variable and it gives you the magnitude of the difference and the direction as the sign. You could even have two separate counters and know how many steps in each direction instead of just the relative difference in position. "

Good idea , I'll try it.
My biggest challenge was reversing the "direction" reliably.

I wrote the code about one year ago and never connected the DDS to my aging Atlas radio, maybe this year.

Once again, the serial print is just to allow you a way to see that things are wired up correctly and working. Once you have confirmed that they would be removed in finished code. No crash, no problems.

I wish someone else would try this code and see if their results are anywhere near as good as mine.

Delta_G:
So it crashes in testing and you think it doesn't work when really it's the stupid Serial code locking it up? Demo or not, Serial.print NEVER belongs in an ISR.

i HAVE NO CLUE HOW THIS GOT HERE
PLEASE EXPLAIN.
IT IS OUT OF CONTEXT OF THE ORIGINAL DISCUSSION AND THUS MAKES NO SENSE BY ITSELF.
AND i DO NOT WANT TO GET REPLY - READ SERIAL BASIC EITHER!

OT

I did some snooping into HardwareSerial as implemented for SAM.
I need to go back to school and figure out how HardwareSerial is a "base class" for "Serial" and why
IRQ handler in HardwareSerial is "not to be used directly".
Today my question is - if HardwareSerial IRQ DETECTS the incoming data ( char - not ASCII anymore) why can't such detection be carried "up stream" to " IRQ Serial"?
I hope I said it right.
Basically HardwareSerial fills the "Serial" buffer and than such buffer has to be "analyzed" by "Serial.available()".
Something is just not right in such scheme.

Vaclav:
Basically HardwareSerial fills the "Serial" buffer and than such buffer has to be "analyzed" by "Serial.available()".
Something is just not right in such scheme.

Like what?

...R

What else would you have it do?

You got me there.

So we are back where we started - you cannot use "Serial.any function " inside another ISR even if "Serial IRQ " ONLY job is to fill Serial buffer with char received.
Still don't get it, this char is NOT "serial - RS232 " format, no timing analysis ( baud rate etc) is needed.

Is it because interrupts ( all of them) are disabled by "Serial" IRQ collecting data into buffer, hence another ISR cannot be entered?

Don't interrupt requests stack / queue up?

MAKES NO SENSE

why can't such detection be carried "up stream" to " IRQ Serial"?

Can't disagree.

Delta_G:
The problem is on the sending side. When you call Serial.print it puts info
(char )
into the buffer

Are there two buffers - one for TX and one for RX?

The receiving (circular) buffer is generally 64 bytes long, the TX buffer is 16 bytes - one wonders why?
(please no RAM limitation argument here - not relevant to discussion about interrupts )

and then the bytes are sent out one at a time.

Should it be more descriptive as SINGLE (parallel in memory ) "char" set as serial data bits?

When one finishes

passing he char out in serial mode, hence using some form of timing ( NOT related to baud rate - just to add more to think about) , as you said - a (timer?) interrupt

it fires an interrupt to tell it to get the next one.

If you call print and there's room in the buffer

see the note about two buffers

for the bytes you are sending then you are cool.

If you call print and there isn't enough room in the buffer then the print function blocks until enough characters have been sent out so there will be enough room. That sending action being dependent upon interrupts that are disabled during the ISR in question, the function will end up blocking forever waiting on an action that can't happen until after the blocking function returns and the ISR returns.

so back to "stacking" the interrupts which apparently has to be programmed ( interrupt priority?)

Vaclav, what is it you don't understand about the correct use of tags?

I'm fed up of sorting out your posts to make them legible.