[SOLVED] Rotary Encoder only increments

dougp:
Per the photo it doesn't look like the ground side of the resistor is connected to ground, maybe I'm not seeing well. Should you not also have a resistor to ground for channel B? What happens if you swap the blu/orn wires on the Arduino header?

Added to resistor to pin B as well, no change. Swaped the wires in the arduino PINs A and B, no change there either.

Southpark:
The wiring is not correct in this photo you provided. If you go back to the bread-board manual, and look at the internal wiring of the bread-board along that rail.... you will find that your resistor leg is connected to nothing.

Take a look at the red coloured arrow.

checked and for some reason i missed that. but i've correct it now, not thing noticeable change tho.

re: photo in post #11 - where is the resistor for channel B?

Can you try what @vinceherman described in reply #1 and create a sketch that outputs the pin states instead of counting.

i had removed since it did not make a difference.

Tried the test what vinceherman mentioned and all seems to go high only.

int PinA = 6;
int PinB = 7;
int val;
int Counter = 1;
int PinALastState = LOW;
int pinAState = LOW;

void setup() {
  pinMode (PinA, INPUT);
  pinMode (PinB, INPUT);
  Serial.begin (9600);
}

void loop() {
  pinAState = digitalRead(PinA);
  if ((PinALastState == LOW) && (pinAState == HIGH))
  {
    if (digitalRead(PinA) == LOW) {
      Serial.println(0);
    } else {
      Serial.println(1);
    }
    //Serial.println(Counter);
  }
  PinALastState = pinAState;
}

anishkgt:
i had removed since it did not make a difference.

Since both channels are (presumably) electrically identical, I'd wire them both the same way.

change

  pinMode (PinA, INPUT);
  pinMode (PinB, INPUT);

to

  pinMode (PinA, INPUT_PULLUP);
  pinMode (PinB, INPUT_PULLUP);

And wire the encoder the standard way:
common to GND,
channels to pinA and pinB, no other connections, no physical resistors.

Then you have the standard setup.

Then check that the pins are being read correctly:

void loop ()
{
  Serial.print (digitalRead (pinA)) ; Serial.print (",") ; Serial.println (digitalRead (pinB)) ;
}

You can also use a multimeter to check the voltages on the pins directly as the encoder is turned
slowly.

And if this produces the expected results, then go back to the encoder logic.

Proceed step by step, from the most basic, checking everything at each stage is as expected
before proceeding to the next. That way you are far less likely to get confused, or assume
something that you haven't actually checked.

Tire @MarkT suggestion

int PinA = 6;
int PinB = 7;
int val;
int Counter = 1;
int PinALastState = LOW;
int pinAState = LOW;

void setup() {
  pinMode (PinA, INPUT_PULLUP);
  pinMode (PinB, INPUT_PULLUP);
  Serial.begin (9600);
}

void loop() {
  pinAState = digitalRead(PinA);
  if ((PinALastState == LOW) && (pinAState == HIGH))
  {
    if (digitalRead(PinA) == LOW) {
      Counter--;
    } else {
      Counter++;
    }
    Serial.print (digitalRead (PinA)) ; Serial.print (",") ; Serial.println (digitalRead (PinB)) ;
    //Serial.println(Counter);
  }
  PinALastState = pinAState;
}

The output is
1,0
1,0
1,1
1,1
1,1
1,1
1,1
1,1
1,1
1,0
1,0
1,0
1,0
1,1

Sifting through old posts last night I saw a thread - can't remember which topic - where the encoder itself was defective, IIRC it was made in a large country in the Orient. As a final check I suppose you could remove the Arduino connections and test the encoder in isolation. Wire up an LED and associated resistor to the channel B pin and see if there's any change when rotated.

anishkgt:

void loop() {

pinAState = digitalRead(PinA);
 if ((PinALastState == LOW) && (pinAState == HIGH))
 {
    // (... counter stuff ...)
    Serial.print (digitalRead (PinA)) ; Serial.print (",") ; Serial.println (digitalRead (PinB)) ;
   //Serial.println(Counter);
 }

You have put that line inside the "if ((PinALastState == LOW) && (pinAState == HIGH)) {}"
so it is normal that it only logs when pinA goes high.
But at least you can see that pinB is sometimes low and sometimes high when this happens,
presumably/hopefully depending on the turn direction.

Have you got a second or a third spare encoder to try? For comparison?

I had two but one of its lead came off.

So i just checked it with an LED and both seems to light up when connected. One turns off when i turn CW and the other CCW. I guess the encoder seems to be working then. am i correct ?

So one sketch that worked is

#define outputA 6
 #define outputB 7

 int counter = 0; 
 int aState;
 int aLastState;  

 void setup() { 
   pinMode (outputA,INPUT);
   pinMode (outputB,INPUT);
   
   Serial.begin (9600);
   // Reads the initial state of the outputA
   aLastState = digitalRead(outputA);   
 } 

 void loop() { 
   aState = digitalRead(outputA); // Reads the "current" state of the outputA
   // If the previous and the current state of the outputA are different, that means a Pulse has occured
   if (aState != aLastState){     
     // If the outputB state is different to the outputA state, that means the encoder is rotating clockwise
     if (digitalRead(outputB) != aState) { 
       counter ++;
     } else {
       counter --;
     }
     Serial.print("Position: ");
     Serial.println(counter);
   } 
   aLastState = aState; // Updates the previous state of the outputA with the current state
 }

here the wiring is different. The common is connected to the +5v and the pins A and B are connected in series with a 1k resitor.

Would appreciate if somebody could help with the previous code as in wiring the common to ground way as @MarkT had advised.

anishkgt:

     if (digitalRead(outputB) != aState) {

Since you compare B to A and not to HIGH or to LOW, I believe this should work regardless of whether you have common to +5 or to GND. (Otherwise you would have to swap the counter++ and counter--, or change != to ==)

anishkgt:

   // If the previous and the current state of the outputA are different, that means a Pulse has occured

if (aState != aLastState){

Also, since you act on every state change of A, not just rising or just falling, this will probably give you 2 counts per click. Most encoders go through 4 changes per click:

   AB     AB 
1  00 -> 01
2  01 -> 11
3  11 -> 10
4  10 -> 00

Your code will do a count on transitions 2 and 4.

Ok guess am getting somewhere

int PinA = 6;
int PinB = 7;
int val;
int Counter = 0;
int PinALastState = LOW;
int pinAState = LOW;

void setup() {
  pinMode (PinA, INPUT_PULLUP);
  pinMode (PinB, INPUT_PULLUP);
  Serial.begin (9600);
}

void loop() {
  pinAState = digitalRead(PinA);
  if (pinAState != PinALastState)
  {
    if (digitalRead(PinB) != pinAState) {
      Counter++;
    } else {
      Counter--;
    }
    Serial.println(Counter);
  }
  PinALastState = pinAState;
}

All works well but increments and decrements by 2 values.

anishkgt:
All works well but increments and decrements by 2 values.

Then just use (Counter>>1) whenever you want the position.
[ common pitfall: don't use (Counter/2), its not well behaved when the sign changes ]

MarkT:
Then just use (Counter>>1) whenever you want the position.
[ common pitfall: don't use (Counter/2), its not well behaved when the sign changes ]

well that did it. Seems to be ok now.

And now........ for the (optional) sequel ...... consider setting up interrupt pins and interrupt channels to detect a transition (like a high-to-low) transition of one of your encoder signals. And when a transition is detected.....read the values of the two encoder signals. Then get the program to make a decision (or do something) based on those readings.

Eg....when an interrupt occurs (when a falling edge of one signal is detected)..... one signal level maybe be low, while the other is high.... so increment. And, for a different condition....if one signal level is low and the other signal level is low.... decrement.

Well never knew i would really start that Sequel and i already have.

:slight_smile: :slight_smile: :slight_smile: