Quadrature Encoder too fast for arduino uno to read

#include <digitalWriteFast.h> // gamit ani para mas paspas ang pag toggle
#define encoderA 2
#define encoderB 3
#define uplus 8
#define uminus 9
#define vplus 10
#define vminus 11
#define wplus 12
#define wminus 13
#define PINP A0

int phase = 1;
int sped = 0;

int pulses = 0;
int deg = 0;
int pulsesChanged = 0;




unsigned long previousMillis = 0;
unsigned long previous_print_Millis = 0;

void ccs1() {
  digitalWriteFast(uminus, HIGH);
  digitalWriteFast(uplus, LOW);
  digitalWriteFast(vplus, HIGH);
  digitalWriteFast(vminus, LOW);
  digitalWriteFast(wminus, HIGH);
  digitalWriteFast(wplus, LOW);
}

void ccs2() {
  digitalWriteFast(wplus, HIGH);
  digitalWriteFast(wminus, LOW);
}

void ccs3() {
  digitalWriteFast(vminus, HIGH);
  digitalWriteFast(vplus, LOW);
}

void ccs4() {
  digitalWriteFast(uplus, HIGH);
  digitalWriteFast(uminus, LOW);
}

void ccs5() {
  digitalWriteFast(wminus, HIGH);
  digitalWriteFast(wplus, LOW);
}

void ccs6() {
  digitalWriteFast(vplus, HIGH);
  digitalWriteFast(vminus, LOW);
}

void cs1() {
  digitalWriteFast(uplus, HIGH);
  digitalWriteFast(uminus, LOW);
  digitalWriteFast(vplus, HIGH);
  digitalWriteFast(vminus, LOW);
  digitalWriteFast(wminus, HIGH);
  digitalWriteFast(wplus, LOW);
}

void cs2() {
  digitalWriteFast(vminus, HIGH);
  digitalWriteFast(vplus, LOW);
}

void cs3() {
  digitalWriteFast(wplus, HIGH);
  digitalWriteFast(wminus, LOW);
}

void cs4() {
  digitalWriteFast(uminus, HIGH);
  digitalWriteFast(uplus, LOW);
}

void cs5() {
  digitalWriteFast(vplus, HIGH);
  digitalWriteFast(vminus, LOW);
}

void cs6() {
  digitalWriteFast(wminus, HIGH);
  digitalWriteFast(wplus, LOW);
}
void stahp() {
  digitalWriteFast(uminus, HIGH);
  digitalWriteFast(wplus, HIGH);
  digitalWriteFast(vplus, HIGH);
  digitalWriteFast(vminus, HIGH);
  digitalWriteFast(uplus, HIGH);
  digitalWriteFast(wminus, HIGH);

}
void A_CHANGE() {
  if ( digitalReadFast(encoderB) == 0 ) {
    if ( digitalReadFast(encoderA) == 0 ) {
      // A fell, B is low
      pulses--; // moving reverse
    } else {
      // A rose, B is low
      pulses++; // moving forward
    }
  } else {
    if ( digitalReadFast(encoderA) == 0 ) {
      // A fell, B is high
      pulses++; // moving forward
    } else {
      // A rose, B is high
      pulses--; // moving reverse
    }
  }
  // Make sure the pulses are between 0 and 359
  if (pulses > 359) {
    pulses = pulses - 360;
  } else if (pulses < 0) {
    pulses = pulses + 360;
  }

  // tell the loop that the pulses have changed
  pulsesChanged = 1;
}

void B_CHANGE() {
  if ( digitalReadFast(encoderA) == 0 ) {
    if ( digitalReadFast(encoderB) == 0 ) {
      // B fell, A is low
      pulses++; // moving forward
    } else {
      // B rose, A is low
      pulses--; // moving reverse
    }
  } else {
    if ( digitalReadFast(encoderB) == 0 ) {
      // B fell, A is high
      pulses--; // moving reverse
    } else {
      // B rose, A is high
      pulses++; // moving forward
    }
  }
  // Make sure the pulses are between 0 and 359
  if (pulses > 359) {
    pulses = pulses - 360;
  } else if (pulses < 0) {
    pulses = pulses + 360;
  }

  // tell the loop that the pulses have changed
  pulsesChanged = 1;
}
void setup() {

  Serial.begin(115200);
  pinModeFast(encoderA, INPUT);
  pinModeFast(encoderB, INPUT);

  pinModeFast(uplus, OUTPUT);
  pinModeFast(uminus, OUTPUT);
  pinModeFast(wplus, OUTPUT);
  pinModeFast(wminus, OUTPUT);
  pinModeFast(vplus, OUTPUT);
  pinModeFast(vminus, OUTPUT);
  pinModeFast(PINP, INPUT);

  attachInterrupt(0, A_CHANGE, CHANGE);
  attachInterrupt(1, B_CHANGE, CHANGE);



  previousMillis = millis();
}

void loop() {

  unsigned long currentMillis = millis();
  //Serial.println(sped);
  if (currentMillis - previousMillis >= sped) {
    previousMillis += sped;
    if (pulsesChanged != 0) {
      pulsesChanged = 0;
      Serial.println(pulses);
    }
    switch (phase) {
      case 1:
        cs1();
        break;
      case 2:
        cs2();
        break;
      case 3:
        cs3();
        break;
      case 4:
        cs4();
        break;
      case 5:
        cs5();
        break;
      case 6:
        cs6();
        break;
    }
    int z = constrain(analogRead(PINP), 0, 1023);
    sped = map(z, 0, 1023, 5, 50);
    if (phase < 6) {
      phase = phase + 1;;
    }
    else {
      phase = 1;
    }
  }
}

Is there something i can do such that i can read quadrature encoder vales with my arduino uno without skipping huge values?

Do i need much fastor arduino such that it can catch encoder values without skipping? or i need to use port manipulation?

Please help me.

Result of code above:
202
196
396
5
7
100

Try an interrupt driven library :

or

#define PINP A0
int z = constrain(analogRead(PINP), 0, 1023);
sped = map(z, 0, 1023, 5, 50);
unsigned long currentMillis = millis();
  //Serial.println(sped);
  if (currentMillis - previousMillis >= sped) {
    previousMillis += sped;

What is connected to A0, and do you see the same inconsistency in the output if you use a fixed value for sped?

How many pulses per revolution is the encoder? How fast is the system rotating? What number of counts are you expecting over what period? Do the counts go in both direction?

These variables are changed within the ISR, and should be declared volatile. pulsesChanged should be a byte as it is only 0 or 1.

 volatile int pulses = 0;
volatile byte pulsesChanged = 0;

When you access the value for pulses in loop, you should disable and re enable interrupts and make a protected copy to guarantee an reading when the number is not changing.

if (pulsesChanged != 0) {
      pulsesChanged = 0;
      noInterrupts();
      int copy_pulses = pulses;
      interrupts();
      Serial.println(copy_pulses);//work with copy_pulses
    }

cattledog:

#define PINP A0

int z = constrain(analogRead(PINP), 0, 1023);
sped = map(z, 0, 1023, 5, 50);






unsigned long currentMillis = millis();
  //Serial.println(sped);
  if (currentMillis - previousMillis >= sped) {
    previousMillis += sped;




What is connected to A0, and do you see the same inconsistency in the output if you use a fixed value for sped?

How many pulses per revolution is the encoder? How fast is the system rotating? What number of counts are you expecting over what period? Do the counts go in both direction?


These variables are changed within the ISR, and should be declared volatile. pulsesChanged should be a byte as it is only 0 or 1.


volatile int pulses = 0;
volatile byte pulsesChanged = 0;




When you access the value for pulses in loop, you should disable and re enable interrupts and make a protected copy to guarantee an reading when the number is not changing.



if (pulsesChanged != 0) {
      pulsesChanged = 0;
      noInterrupts();
      int copy_pulses = pulses;
      interrupts();
      Serial.println(copy_pulses);//work with copy_pulses
    }

good evening sorry for my very late reply , 5k potentiometer is attached to the A0, its purpose is to control the speed of the motor.

Output is still inconsistent even if i stay the speed of the motor not varying it.

Regarding the specs of the encoder attached to the motor, i dont know about it, all i know is the unit number of the motor Panasonic MSM021A2UE because i cannot find any datasheet online about this motor. all i know now is that i can mange to run the motor in the code about 5 milliseconds fast if less than the value of 5 the motor will not turn and it is just vibrate, correct me if i am wrong. 1/0.005 seconds = 200Hz. that the thing i assume about the motor using the cod above.

Thank you very much for your response, this is a very big help to me in completing this project of mine. until now i am still looking for ideas, codes and other related things about motor with encoder.

The encoder library by Paul Stoffregen is highly optimized for speed. Try it instead.

pinModeFast(encoderA, INPUT);
  pinModeFast(encoderB, INPUT);

Most encoders are open collector output, and require pullup resistors on the outputs. Are you using any? If not, make the pinMode INPUT_PULLUP which will engage the internal pullups of the Arduino pins.

Result of code above:
202
196
396
5
7
100

These results would appear impossible given this

}
  // Make sure the pulses are between 0 and 359
  if (pulses > 359) {
    pulses = pulses - 360;
  } else if (pulses < 0) {
    pulses = pulses + 360;
  }

I would forget about trying to constrain the pulse count like this. Until you work you stability issues out, I would

  1. run the motor in the direction where the pulse count increases.
    2)run the moter at a fixed speed without using the analogRead() and mapping.
  2. change the variable type for pulses to volatile unsigned int.
  3. report the difference between the pulse count values
if (pulsesChanged != 0) {
      pulsesChanged = 0;
      noInterrupts();
      unsigned int last_copy_pulses = copy_pulses;
      unsigned int copy_pulses = pulses;
      interrupts();
      Serial.println(copy_pulses - last_copy_pulses);//work with copy_pulses
    }