Grey code
i can read the binary grey code output but i cant figure how to make it work. i would like to turn the knob and raise and lower a value. like a temp i can do it with buttons but cant figure out how to do it with grey code...
Comments
all of the states for each detent position, thank you logic analyzer. Here is my code for that encoder
PUB read_gray_code | tmp tmp := ina[noparse][[/noparse]GRAY_CODE_B..GRAY_CODE_A] case tmp %00: return 0 'in between detents %01: return 1 'CW rotation %10: return -1 'CCW rotation %11: return 3 'quiescent state
3.3v
----
|
\
/ 10K
\
+
Output from encoder
|
----
---- 10nF cap
|
|
---
- Gnd
The sequence goes around a square in either direction and only changes of value should register as increment,
don't accept the value as repeating.
00 <----> 01 A A | | V V 10 <------>11 clockwise 00>01>11>10>00 counterclockwise 00<01<11<10<00
I don't think these things jitter unless they are worn out and bad contacts.
Only one bit changes indicating an increment in a direction.
If you XOR one bit with the other , maybe using b:=((a&2)/2)^(a),
then the cycle of b would be
0123 for clockwise (0132 in gray a)
3210 for counterclockwise (2310 in gray a)
and the direction would be something like (b - previous_b)&3
-1 or for counterclockwise
0 for none
+1 for clockwise
(+3 counterclockwise and -3 for clockwise indicates my direction math is missing something,
so this should either be ignored or fixed with b := -(4-b)
The whole point of graycode is minimum transition so
if its unstable then the encoder is dirty or
your code is looking for the numbers and getting repeats
instead of looking for changes to adjacent states
This is like a 4 phase motor driven by AC sine and cosine (90' out of phase) but with squarewaves,
It is also like a quadrature phase shift in QPSK, QAM, FM, Phase Modulation, or Sideband detection.
(I assume you read the ham radio books and periodicals though.)
Ball mouses have two gray encoders, one for each axis.
Post Edited (VIRAND) : 3/3/2010 5:09:06 AM GMT
Ill keep re-reading this maybe ill get it....
the order of 2-bit numbers determines which way you are going.
you haven't gone anywhere when the number doesn't change.
you haven't gone anywhere if the number changes and then changes back.
but you can only know if you went one way or the other when the code changes.
JackBak's comments on the meaning of the code are either wrong or only useful for his encoder.
This is the order of gray code which repeats four 2-bit numbers
00
01
11
10
Forget about math, there is none. It isn't a code about numbers and math.
if you turn the encoder one way, you get the number above it on the list
if you turn the encoder the other way, you get the number below it on the list
if there is no number there, it will be the number at the other end of the list.
The encoder tells you when you moved it by changing the number
The encoder tells you which way you went by whether the new number is above or below it on the list.
The square really makes more sense than the list.
Maybe you didn't understand my arrows using A and V the way < and > are arrows like ---->
I used arrows like this <----> to make a MAP of how the numbers change in a circle as you turn the encoder.
JackBak's code is not normal for decoding encoders. He commented the gray code with wrong meaning.
Gray code doesn't have a meaning. It just indicates motion and direction.
Post Edited (VIRAND) : 3/4/2010 8:07:20 AM GMT
I have no idea why that particular encoder goes through all the states for each detent position
and then ends at open-open (so with my pull ups the prop sees 11).
This is the difference between worrying about what something "should be" and making it work.
so i need to..
1. sample the inputs.
2. compare them
3. Advance, stay or decrement a (var ) based on the comparison
4. repeat
my thing is knob and program are out of sync. some times when turning the knob up to fast or slow the code thinks its suddenly changed direction.
By the way both of you guys sound like great engineers and iam not naming any kids after either one of you ..lol
Good lord NO don't name anyone JackBak ... now VIRAND it's got a ring don't you think?
www.bitechnologies.com/pdfs/en11.pdf
... that shows the detents landing on the "off" state of the switches. Perhaps this is in fact the norm with detented encoders. It seems to me it would be a little more work to write a driver for this type, and if you wanted each "click" to have a delta of one then you'd reduce your rotary resolution down to 25%.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Jon McPhalen
Hollywood, CA
with a wedge between them that does two things:
-Make a detent stop position by wedging itself between teeth of a gear on the knob.
-Push the button that is on the side of it (the wedge) to indicate which way the knob is being turned,
before slipping over the gear tooth (with a click or snap noise) and holding the next detent position.
That knob mechanism is great as a direct substitute for UP/DOWN Channel select buttons,
but would not withstand continuous duty in machine applications for a useful amount of time.
Yeah, that data sheet is closer to what mine is really doing, from Sparkfun
www.sparkfun.com/datasheets/Components/TW-700198.pdf
Note their vertical dashed lines don't seem to correspond to your data sheet's vertical dashed detent lines.
Apparently from the user comments this Sparkfun encoder has given folks a challenge - I would guess
based on the data sheet I sited. When looking at the output of this encoder with my logic analyzer it is
much more similar to your data sheet in that the quiescent state is off-off and all 2-bit gray code states are
transitioned from detent to detent.
Don't quite understand your comment about reduced resolution of the encoder, but note that for each detent
position my code returns 1 for CW rotation and -1 for CCW rotation. thus,
GRAY_CODE_A = 20 'encoder pin assignments GRAY_CODE_B = 21 ENCODER_MASK = 1<<GRAY_CODE_A | 1<<GRAY_CODE_B ENCODER_QS = ENCODER_MASK .... repeat ... temp += read_gray_code waitpeq(ENCODER_QS, ENCODER_MASK, 0) ...
would give you an accurate total taking into account CW or CCW rotation.
Remember I have pulled up the A and B pins on the Sparkfun encoder while the C pin is grounded.
[b]CON[/b] [b]_CLKMODE[/b] = [b]XTAL1[/b] + [b]PLL16X[/b] 'Set to ext crystal, 4x PLL [b]_XINFREQ[/b] = 5_000_000 'Frequency on XIN pin is 5.00 MHz GRAY_CODE_A = 20 'assigned pins for encoder GRAY_CODE_B = 21 ENCODER_MASK = 1<<GRAY_CODE_A | 1<<GRAY_CODE_B ENCODER_QS = ENCODER_MASK [b]PUB[/b] Main | temp, val ' 'setup code for Main goes here ' [b]repeat[/b] 'loop forever '... more application specific code temp := read_gray_code 'call method to read encoder and return a value [b]if[/b] temp <> 3 'user has done something with the encoder dial val += temp val <#= 255 'don't let val go above 255 for some reason specific to app val #>= 0 'and don't let it go negative either, presumably we are tweaking something 'based on this while the user spins the encoder dial '... more specific code [b]waitpeq[/b](ENCODER_QS, ENCODER_MASK, 0) 'wait for encoder to return to quiescent state '... more app code [b]PUB[/b] read_gray_code | tmp tmp := [b]ina[/b][noparse][[/noparse]*GRAY_CODE_B..GRAY_CODE_A] [b]case[/b] tmp %00: [b]return[/b] 0 'in between detents %01: [b]return[/b] 1 'CW rotation %10: [b]return[/b] -1 'CCW rotation %11: [b]return[/b] 3 'quiescent state
Here Main is just looping forever reading the encoder and doing something with it.
Hope that helps.
-Jack
As I have a need for these encoders myself but don't have them on hand, WB and I have been working offline. I have a pasm driver working that allows you to specify whether your encoder is detented or not. If it is the range (which you specify, low and high values) is expanded by four, and when you read the value back it is divided by four -- this gives you one unit change per detent. I'll post as soon as WB confirms the final version.
[noparse][[/noparse]Edit] Wayne (wb7076) confirmed that the driver works so I'm going to post my demo here. Once I have my own hardware I'm going to write create a dual-encoder version as well -- when that's working I'll post the works in ObEx.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Jon McPhalen
Hollywood, CA
Post Edited (JonnyMac) : 3/8/2010 3:30:21 PM GMT
your jm_grayenc_demo worked great for the mechanical encoder that I was using,
But I wanted to be able to change the range of the values returned. so I added a pub routine to it
i.e. sometimes I want a value 1to5 for menus and sometimes 0-59 for clock
pub chgrange(lo, hi, preset) ' new sub- 3/12/2010 if detent lolimit := lo << 2 hilimit := hi << 2 encoder := preset << 2 else lolimit := lo hilimit := hi encoder := preset
which seems to work because it sets the starting value but as soon as i move the encoder the range flips back to the initialized range.
I am brand new to prop but not to programming. Maybe there is something I need to know?
thanks,
mike
Your routine doesn't work because you're attempting to set values that are now running in another cog -- the init() method changes these before the cog is launched; you can't do it after.
Go ahead and set the encoder to 0 to 59. When in menu mode, do a bit of math on the value:
menupos := (encoder.read // 5) + 1
The modulus operator (//) will return 0 to 4 with a divisor of 5, adding 1 bumps the final result to your desired range (1 to 5).
Remember, you can use the .set() method to put the value where you want it when changing modes in your program. For menu mode you need to subtract one as it gets added using the above formula.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Jon McPhalen
Hollywood, CA
Post Edited (JonnyMac) : 3/14/2010 6:25:38 PM GMT