Shop OBEX P1 Docs P2 Docs Learn Events
Grey code — Parallax Forums

Grey code

wb7076wb7076 Posts: 29
edited 2010-03-14 18:20 in Propeller 1
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

  • JackBakJackBak Posts: 45
    edited 2010-03-01 20:27
    Are you perhaps referring to the little grey code encoder from Sparkfun? If yes my stumbling point was that I didn't realize that encoder goes through
    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
    
    
  • JackBakJackBak Posts: 45
    edited 2010-03-01 20:33
    Oh, yeah, forgot. I pulled the two lines up with 10K resistors and then debounced the lines with 10nF caps from the lines to ground. Bad ASCII follows.

    3.3v
    ----
    |
    \
    / 10K
    \
    +
    Output from encoder
    |
    ----
    ---- 10nF cap
    |
    |
    ---
    - Gnd
  • wb7076wb7076 Posts: 29
    edited 2010-03-02 21:15
    That helps alot thanks. i hacked a encoder from a sony dvd player. it was just what i needed. but the code tossed me for loop.
    800 x 600 - 129K
  • wb7076wb7076 Posts: 29
    edited 2010-03-03 00:40
    I tried no dice.very eratic up downs lots of runaway digits; need to turn knob slightly for any felling of control. any way to read a whole turn before advancing or subtracting the value. I cant figure this out. I just order 10 knobs for my project....
  • VIRANDVIRAND Posts: 656
    edited 2010-03-03 04:56
    Grey code is not supposed to have that problem and should debounce by inertia.

    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
  • wb7076wb7076 Posts: 29
    edited 2010-03-04 00:26
    Its been a long time but I am ordering the book today. I don't get what you wrote without a code for example. I am not that good with the Programing math yet, cant see it in my head. You got any other good reading, so i can learn more on programing tips and ticks or functions used for solving things problems or methods ?
    Ill keep re-reading this maybe ill get it....
  • VIRANDVIRAND Posts: 656
    edited 2010-03-04 07:53
    grey code indicates motion by changing only one bit at a time.
    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
  • JackBakJackBak Posts: 45
    edited 2010-03-04 13:42
    My comments are not wrong for the Sparkfun encoder as I mentioned in my first post.
    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.
  • wb7076wb7076 Posts: 29
    edited 2010-03-04 18:46
    E is for electronics not emotions. When i have two opinions that gives me a much better chance at learning how to solve my problems. I get to scale where i am between both of your opinions and with that figure. I see how far i got to go to reach my goal.

    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
  • JackBakJackBak Posts: 45
    edited 2010-03-04 19:25
    wb7076 said...
    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?
  • wb7076wb7076 Posts: 29
    edited 2010-03-06 09:39
    okay just got new encoders from mouser... what do you know . my test encoder was the problem. as soon as i hooked up the new encoder it worked . iam guessing,the test encoder, is not a normal encoder. thanks
  • JackBakJackBak Posts: 45
    edited 2010-03-06 16:33
    Great! We now know of at least two encoder's that aren't normal.
  • JonnyMacJonnyMac Posts: 9,234
    edited 2010-03-06 18:00
    That may not be the case, Jack. I started looking at graycode encoders for a project and found this data sheet...

    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
  • VIRANDVIRAND Posts: 656
    edited 2010-03-06 20:08
    Apparently there are knobs that are not gray encoders, which are simply two buttons,
    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.
  • JackBakJackBak Posts: 45
    edited 2010-03-06 20:09
    Hey Jon,

    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.
  • JackBakJackBak Posts: 45
    edited 2010-03-07 00:37
    I realized my last example may have left too much to fill in for all readers, here I hope is a better general example.
    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
  • JonnyMacJonnyMac Posts: 9,234
    edited 2010-03-07 15:31
    Jack (and others),

    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
  • mmottemmotte Posts: 1
    edited 2010-03-14 17:18
    jon,

    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
  • JonnyMacJonnyMac Posts: 9,234
    edited 2010-03-14 18:20
    @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
Sign In or Register to comment.