| Author |
Message |
|
|
Posted: Apr 04, 2008 - 04:03 AM |
|

Joined: Jan 24, 2008
Posts: 65
|
|
I am working on a project that will ultimately be being built by other hobbyists, and it uses a rotary encoder with 2-bit gray code output.
I am having trouble reliably decoding the gray code. I think that the encoder has a lot of bounce. I really need to be able to support these cheap, crappy encoders though.
So far I have tried using rising/falling edge or pin change interrupt triggering, looped polling, timer based polling from 1khz up to 180khz, and various decoding methods such as checking B on fall of A, checking both A and B on every pin change. I also tried various methods of debouncing the inputs such as timers that are reset every time there is a change (thus requiring a certain amount of no-change time before inputs are read).
Nothing worked properly. The best I can do is count debounced pulses on A or B. No matter what I try, I can't determine which direction the shaft is rotating in.
I have spent hours searching the net, including these forums, but as far as I can see no-one has actually posted a working, robust and complete bit of code. Lots of theory, but nothing proven to work. Even the code people posted on these forums were just snippets, and I tried them all.
I'd really appreciate some help Does anyone actually have a working example of using a rotary encoder? C or asm, I don't care... |
|
|
| |
|
|
|
|
|
Posted: Apr 04, 2008 - 05:08 AM |
|

Joined: Jul 08, 2006
Posts: 504
Location: Sunnyvale, CA
|
|
If you are seeing a lot of bounce, I presume you are using a mechanical encoder? How fast is the encoder turning?
As far as encoders go, I have built a home-brew encoder with reflective optical sensors, and sampling on pin change interrupt worked OK. My code tolerated NOP transitions to current state and silently threw them out, so maybe there was bounce I wasn't seeing.
Anway, for mechanical switches, my favorite debouncer is to sample on 1 mSec or so interrupt and simply shift the sampled bit into a byte -- when I get 0x00 or 0xff it means I've seen 8 in a row the same, and I call it debounced. Have you tried debouncing each contact by itself, and then running the up/down counter off the debounced output? Which brings me back to the question of how fast you are turning the encoder -- maybe it is bouncing longer than it takes for you to get between sectors?
If you're feeling adventurous, the code below is how I would approach the problem.... warning: I haven't even tried to compile it.
Code:
// this runs on a suitable timer interrupt
bouncy0 = (bouncy0 << 1) | (PINX & Q0BIT ? 1 : 0);
bouncy1 = (bouncy1 << 1) | (PINX & Q1BIT ? 1 : 0);
if (bouncy0 == 0x00) enc &= 0x2;
if (bouncy0 == 0xff) enc |= 0x1;
if (bouncy1 == 0x00) enc &= 0x1;
if (bouncy1 == 0xff) enc |= 0x2;
switch (qstate)
{
case 0:
switch (enc)
case 0:
// ignore
break;
case 1:
++count;
break;
case 2:
--count;
break;
case 3:
// WTF?
break;
}
break;
case 1:
...
}
qstate = enc;
|
|
|
| |
|
|
|
|
|
Posted: Apr 04, 2008 - 05:12 AM |
|


Joined: Jun 21, 2002
Posts: 676
Location: Canberra, Australia
|
|
Because a gray code should only change one bit at a time, bounce will only be a problem it it lasts past the next bit change position. The effect will be dithering back and forward at the transition point. To get the true rotation direction, you need to consider more than two values
Code:
ideal A -> B -> C -> D forward
A -> D -> C -> B reverse
actual A B A B A B C B C B C B C B C D C D C D or similar forward
use A B C D
A D A D A D C D C D C D C B C B C B or similar reverse
use A D C B
ie. use the last 3 positions keeping the "next different" |
|
|
| |
|
|
|
|
|
Posted: Apr 04, 2008 - 05:12 AM |
|

Joined: Jul 08, 2006
Posts: 504
Location: Sunnyvale, CA
|
|
[massive edit]
Deleting double post -- the first one errored off, but appears to have posted anyway. |
|
|
| |
|
|
|
|
|
Posted: Apr 04, 2008 - 05:18 AM |
|

Joined: Jul 08, 2006
Posts: 504
Location: Sunnyvale, CA
|
|
|
Quote:
To get the true rotation direction, you need to consider more than two values
Good point. True even with a perfectly bounceless encoder. |
|
|
| |
|
|
|
|
|
Posted: Apr 04, 2008 - 05:30 AM |
|

Joined: Jul 08, 2006
Posts: 504
Location: Sunnyvale, CA
|
|
| Actually, that could be done with a simple direction state machine with three states: CCW, AMBIGUOUS, and CW, and one input for counting up or down. |
|
|
| |
|
|
|
|
|
Posted: Apr 04, 2008 - 06:38 AM |
|

Joined: Sep 03, 2005
Posts: 684
Location: Christchurch, NZ
|
|
Search the forum as there were a number of related threads last year, I know as I was struggling with the same issue.
Good luck |
|
|
| |
|
|
|
|
|
Posted: Apr 04, 2008 - 06:43 AM |
|


Joined: Feb 19, 2001
Posts: 19075
Location: Wisconsin USA
|
|
|
Quote:
I think that the encoder has a lot of bounce. I really need to be able to support these cheap, crappy encoders though.
You "think"? You need to "support" the device, but there is no 'scope in your organization to actually look at the signals? And once you see the situation, you have no supply of Rs and Cs to clean it up?
Lee |
|
|
| |
|
|
|
|
|
Posted: Apr 04, 2008 - 08:16 AM |
|

Joined: May 02, 2007
Posts: 1034
Location: Nieuwegein, Netherlands
|
|
| The R's should be there anyway(either internally in the AVR or externaly to either VCC or VDD), so he would only need C's in my opinion. |
_________________ Best friends:
1) Datasheet (and application notes)
2) AVR freaks forum( specially the tutorials
3) Fellow freaks, Can answer to problems that could not be answered by 1 or 2
|
| |
|
|
|
|
|
Posted: Apr 04, 2008 - 01:56 PM |
|


Joined: Sep 04, 2002
Posts: 13547
Location: Orlando Florida
|
|
| Is the encoder turned by a machine or by a human? This gives some idea of the max counts per sec that have to be measured. To catch a 'snatch' of 90 degrees on the knob which would be 4 counts on a 16 detent encoder... if the snatch took 50ms, thats only 12.5ms per count... an eternity for a 16mhz processor.... in addition of some carefully chosen caps that will eat bounces faster than a ms or two, reading the encoder every 5ms should get past the bounce, but not miss the next count. This all sounds logical, but gremlims do defy logic I have found. |
_________________ Imagecraft compiler user
|
| |
|
|
|
|
|
Posted: Apr 04, 2008 - 09:55 PM |
|

Joined: Jan 24, 2008
Posts: 65
|
|
Okay, thanks for the replies.
I am using a mechanical rotary encoder, and turning it by hand. I don't turn it particularly fast (normal hifi volume control speed).
dbc: Your code looks interesting, I'm going to try and implement it. At the moment I have been debouncing just the input that I sense change on. I too was using a counter of unchanged states, and assumed that the other line we have settled by then too.
Man, I own a t-shirt that says "assumption is the mother of screw-up"
c_hirst: I like your idea of considering more than one state to determine direction. I had been trying to do that but it was failing due to the amount of bounce. Based on your diagram, I might try a system of recording the order in which states are seen.
theusch: I don't have an "organisation", I'm just a hobbyist. I don't own a scope (might get one soon if I can find a good, relatively cheap PC scope that goes up to 20MHz) and I want the project to be buildable by other hobbyists, using easily available parts. Unfortunately crappy mechanical rotary encoders are common, where as nice optical ones are expensive and hard to get (at least here in the UK).
I don't know why you assume I don't have resistors and capacitors - of course I do. I am using the AVR's internal pull-up and currently don't have a cap.
I'll try and give these ideas a try today or tomorrow, thanks. |
|
|
| |
|
|
|
|
|
Posted: Apr 04, 2008 - 10:03 PM |
|


Joined: Oct 30, 2002
Posts: 3922
Location: The Netherlands
|
|
| I've interfaced a number of encoders, and with a series resistor and cap you get nice clean edges (albeit a tad slow but that's no problem). I found that usually one input will chatter rapidly when you move the knob around a detent in one particular direction slowly. This can't be solved by debouncing but needs to be solved in the detection logic. |
_________________ Free e-books
Modern Mechanix: Yesterday's Tommorow Today
|
| |
|
|
|
|
|
Posted: Apr 05, 2008 - 12:40 AM |
|


Joined: Sep 04, 2002
Posts: 13547
Location: Orlando Florida
|
|
| Some encoders have the detent right in the middle between the edges of A and B, others have the detent right in the middle of A, which is right on an edge of B, which will dither up and down if you rock it back and forth in the detent. The fix is dont count those... just look for the rising edge on A or the falling edge on A, and inc or dec the count based on the state of B. |
_________________ Imagecraft compiler user
|
| |
|
|
|
|
|
Posted: Apr 05, 2008 - 11:54 PM |
|


Joined: Dec 31, 2005
Posts: 642
|
|
Some encoders (with detend positions) have for example cycles like this.
AB: 00 10 11 01 00 -> CW
AB: 00 01 11 10 00 -> CCW
For good reliability you can make 3 or 4 switch buffers (could be done with a single register -> 4 * AB = a byte -> ABABABAB.)
So first debounce AB -> when steady, then if another value than 00 apears in AB (change) will be 10 or 01 -> buffer value, then next round 11 must appear, then 01 or 10, and back to detend 00. So if you read a value of 45 (10 11 01 = 101101 INC a counter or set flag, if value = 30 (011110) DEC a counter or clear flag & clear value in buffers.
Wrong direction is impossible, a skip still possible.
Waterproof codes for mechanical encoders are not simple, use an optical encoder, much easier codes, but more expensive.
 |
_________________ RES - http://www.attiny.com
|
| |
|
|
|
|
|
Posted: Apr 06, 2008 - 01:28 AM |
|

Joined: Jan 24, 2008
Posts: 65
|
|
|
RES wrote:
So first debounce AB -> when steady, then if another value than 00 apears in AB (change) will be 10 or 01 -> buffer value
I did try that method, but it never seemed to work reliably. Often at normal turning speed B did not seem to settle enough to make an accurate reading.
I think I am going to get another rotary encoder. |
|
|
| |
|
|
|
|
|
Posted: Apr 06, 2008 - 02:16 AM |
|

Joined: Jan 06, 2008
Posts: 356
|
|
|
mojo-chan wrote:
I did try that method, but it never seemed to work reliably. Often at normal turning speed B did not seem to settle enough to make an accurate reading.
I think I am going to get another rotary encoder.
If we take "normal turning speed" to be e.g. 1 revolution per second, on a 20-position encoder that's 50ms per position, so your B signal should have had 50ms to settle down. If it's still bouncing around after all that time you may very well have a bad encoder. I looked up some cheap ($3) encoders and they specified 2ms maximum bounce time at 1 rps. |
|
|
| |
|
|
|
|
|
Posted: Apr 06, 2008 - 06:18 PM |
|

Joined: Jan 24, 2008
Posts: 65
|
|
Okay, I have experimented some more, and so far all suggested solutions have failed
I am going to see about hacking an optical encoder out of a mouse. |
|
|
| |
|
|
|
|
|
Posted: Apr 06, 2008 - 06:49 PM |
|


Joined: May 30, 2004
Posts: 7801
Location: Cincinnati, Ohio
|
|
I have a variation of the following working in an interrupt driven servo motor control system.
I modified it, as applicable to a non-interrupt driven system.
See here http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=62118&start=20 for the current code. |
_________________ Carl W. Livingston, KC5OTL
microcarl@roadrunner.com
It's a fundamental law of nature... All things gravitate toward total chaos!!!
The original Dragon Slayer !
Long live the AVR!!!
Last edited by microcarl on Apr 12, 2008 - 11:36 PM; edited 2 times in total
|
| |
|
|
|
|
|
Posted: Apr 07, 2008 - 05:47 PM |
|

Joined: Jan 24, 2008
Posts: 65
|
|
I managed to get a scope on the encoder and it seems like it never ever stops bouncing when being rotated
The output is so noisy, I was shocked. Even just touching the shaft causes bounce. I'm going to chuck it and get an optical encoder.
I'm looking at buying a scope too. I see for about £100 you can get USB ones that claim up to 40MHz bandwidth. I can't find much info on them though. Any good? |
|
|
| |
|
|
|
|
|
Posted: Apr 07, 2008 - 05:51 PM |
|


Joined: Oct 30, 2002
Posts: 3922
Location: The Netherlands
|
|
|
|
|
|
|