Strange problem reading rotary encoder

Hi all,

So I'm facing this strange problem, I desoldered a rotary encoder from a mouse:

and there is 3 pins, from the left to right, GND, signal 1 and signal 2.

int led = 13;
int pin1 = 5;
int pin2 = 6;
int val1 = 0;
int val2 = 0;
void setup() {                
  Serial.begin(9600);
  pinMode(led, OUTPUT);
  pinMode(pin1, INPUT);  
  pinMode(pin2, INPUT); 
}


void loop() {
 
  val1 = digitalRead(pin1);
  val2 = digitalRead(pin2);
  Serial.print("P1:");
  Serial.print(val1);  
  Serial.print("P2:"); 
  Serial.println(val2); 
  delay(100);
}

Using this simple code, I wanted to get a feed back from the encoder 1-1, 0-1... and so on.
and I get them but the problem is the lag, freezing in serial monitor, when I turn it cw and ccw
I get the data but after a while the serial monitor keeps displaying values but not the right ones.

For example:
cw 1-0, 1-1 after that turning one click ccw I should get back 1-0 and I do but for few moments
doing it for testing purposes constantly, it freezes at a value 1-0 (keeps displaying) and after like 5sec
unfreezes, doing it like all the time.

Circuit:

Any ideas are appreciated.

BR,
D60

You're not going to effectively read an encoder with a 100ms delay in your loop. Part of the deal with encoders is that you have to catch every pulse or you end up reading it wrong. Normally it is done with an interrupt.

Delta_G

Could you give me an example if possible.
My goal is to read the encoder really fast like at least 30 times per second so read speed is necessary for me.

My goal is to read the encoder really fast like at least 30 times per second

Then don't use delay(). The loop() function, with no delays, executes tens to hundreds of thousands of times per second.

It is hard to see how your circuit could work, regardless of whether the 10K resistor is connected to Vcc or ground. Please study the Arduino button example to learn how to read a switch.

You might find this useful:
https://playground.arduino.cc/Main/RotaryEncoders
Beside technical explanation and examples, it lists a number of encoder libraries.

Domino60:
Delta_G

Could you give me an example if possible.
My goal is to read the encoder really fast like at least 30 times per second so read speed is necessary for me.

If speed is an issue then why the hell do you have a delay 100 in your loop. You do know what that line does right?

You don't read an encoder at some specified rate. You have to react when it gives you a pulse. The pulses don't last long and if you miss one you read wrong.

There is tons written on encoders. You don't need an example just for you. You are capable of searching.

Also, serial prints are very slow.

What you really want for encoders is the transitions -- high to low or low to high. if you want to experiment and see what it's doing, you should build an array to put timestamps when those transitions happen. The pin change interrupts would be perfect for that. Or you could just have it fill up the array in the loop() function until it gets full, and then serial print the entire thing.

And yeah, you hooked up the resistor wrong.

Using this code and the “circuit” I use it’s working now but as mentioned in the URL I took the code, it’s not high precision so turning fast the encoder it loses sense of direction, sadly for me that’s a problem.

I need the encoder to spin fast sometimes and losing direction that’s not an option.

int val;
int PinA = 3;
int PinB = 4;
int encoder0Pos = 0;
int encoder0PinALast = LOW;
int n = LOW;

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

void loop() {
    n = digitalRead(PinA);
  if ((encoder0PinALast == LOW) && (n == HIGH)){
    if (digitalRead(PinB) == LOW){
      encoder0Pos--;} 
    else{
      encoder0Pos++;}
    Serial.print (encoder0Pos);
    Serial.print ("/");
  }
  encoder0PinALast = n;  
}

Domino60:
I need the encoder to spin fast sometimes and losing direction that’s not an option.

Then you need more than the simple-minded approach you’re trying to use.

As mentioned, you want to be working with transitions of the switch states, not their value every time through the loop. If you have to print out status on Serial, only do it when position changes, not every time through loop (again transitions).

As also mentioned, real speed with an encoder requires use of interrupts. Look at the “Encoder” library (by PJRC). It’s the first one listed on the page I linked in Reply #4.

Thanks for the info and help, it was useful and informative but it's too much time wasted and work.

I think I will build a personal encoder which will find easier the direction and better in speed using 2 step
IR Leds/reflectors

For a normal click encoder , you need to poll the pins every 10ms, if encoder resolution is very high, 5ms or even 1ms.

Regardless of mechanical or optical, the principals of rotary encoder operation are the same.

Domino60:
Thanks for the info and help, it was useful and informative but it’s too much time wasted and work.

I think I will build a personal encoder which will find easier the direction and better in speed using 2 step
IR Leds/reflectors

It’s not hard or a lot of work. An encoder really should run on an interrupt.

volatile int encoderCount = 0;
unsigned int printInterval = 500;


void setup() {
  Serial.begin(115200);

  attachInterrupt(0, ISR_pinA, CHANGE);
  attachInterrupt(1, ISR_pinB, CHANGE);

  Serial.println();
  Serial.println("Starting :");

}

void loop() {
  cli();
  int tempCount = encoderCount;
  sei();
  Serial.print("Count = ");
  Serial.println(tempCount);

}


// Encoder should have one data pin to pin 2 and one to pin 3 and the
// ground pin connected to ground.  
// Encoder should probably be debounced with hardware
// For example 100nF caps between each data line and ground. 


//  Pin A will be on pin 2 so we want third bit of PORTD  0x04
//  Pin B will be on pin 3 so it will be fourth bit of PORTD    0x08
//This code is for UNO / Nano / 328P
//If you have other fix the ports

void ISR_pinA() {
  //  If the pins don't read the same
  if (((PORTD & 0x04) << 1) ^ (PORTD & 0x08)) {
    encoderCount++;
  }
  else {
    encoderCount--;
  }
}


void ISR_pinB() {
  //  If the pins don't read the same
  if (((PORTD & 0x04) << 1) ^ (PORTD & 0x08)) {
    encoderCount--;
  }
  else {
    encoderCount++;
  }
}

Actually, I’m not sure if it is better to write this:

if (((PORTD & 0x04) << 1) ^ (PORTD & 0x08)) {

or this

if ((!!(PORTD & 0x04)) != (!!(PORTD & 0x08))) {

But the end result is the same