Go Down

Topic: Evil Genius getEncoderTurn() Discarding some aPin and bPin Transitions? (Read 628 times) previous topic - next topic

FoxcodeBob

Greetings all,

Regarding getEncoderTurn() first appearing in the listing for Project 11:

int getEncoderTurn()
{
  // return -1, 0, or +1
  static int oldA = LOW;
  static int oldB = LOW;
  int result = 0;
  int newA = digitalRead(aPin);
  int newB = digitalRead(bPin);
  if (newA != oldA || newB != oldB)
  {
    // something has changed
    if (oldA == LOW && newA == HIGH)
    {
      result = -(oldB * 2 - 1);
    }
  }
  oldA = newA;
  oldB = newB;
  return result;
}

I'm clear once we test to see if a change has occurred [if (newA != oldA || newB != oldB)], but it seems to me that we then only calculate a result for the case when we are transitioning from Phase 2--->Phase 3 or Phase 1--->Phase4 [if (oldA == LOW && newA == HIGH)]. This ignores valid transitions when aPin goes from HIGH to LOW and transitions where aPin stays the same and bPin goes HIGH to LOW or LOW to HIGH, all of which are valid state changes that in this code will result in result being 0, incorrectly signalling no change in the rotary encoder at all.

I think this code drops 75% of the state transition cases, but it's possible I've lost the plot here!

Can anyone shed some light? Many thanks,
Bob

olikraus

Without a state diagram it is usually difficult to understand such code... Due to this fact, i draw the complete graph some months ago and derived the code from it.



From: http://code.google.com/p/m2tklib/wiki/rotenc

Sorry for not giving you more specific help.

Oliver

FoxcodeBob

#2
Dec 31, 2012, 04:19 pm Last Edit: Dec 31, 2012, 04:27 pm by FoxcodeBob Reason: 1
Thank you Oliver. Your state diagram is very helpful and shows my point - I've marked (*) the CW and CCW transitions which would be triggered by the IF conditional in the source code; all others would be ignored by the conditional, and result in a "no change" return value of 0.

retrolefty

#3
Dec 31, 2012, 04:48 pm Last Edit: Dec 31, 2012, 04:50 pm by retrolefty Reason: 1
Encoder manufactures usually specify their encoders by "steps per revolution" where steps means four complete transitions of the A and B in the gray code quadrature.

So you have a choice of how to count 'steps' when using an arduino. If the encoders is rated at say 256 steps per/rev:

Count just one edge condition, say A signal rising and you will measure 256 steps/rev
Count two edge conditions, say either A or B rising and you will measure 512 steps/rev
Count all four edge condition, any change on A or B, and you will measure 1024 steps/rev

So the choice is yours to make and will dictate the decoding algorithm you use.

Lefty

dc42

You can find the code I use to drive rotary encoders at https://github.com/dc42/arduino. You need to call the poll() function at least every 2ms to avoid missing transitions when the encoder is turned quickly. I normally call it from a tick interrupt or from a task scheduled to run every 2ms. When you want to know how far the encoder has moved, call getChange(). The code allows for the unfortunate tendency of some encoders to be in either of 2 states when in a detent.
Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

Go Up