Quadrature Encoder: wrong counting of pulses per revolution

Hello,

I'm trying to count pulses with my Arduino Due card. I'm using a DC motor with an encoder (400 PPR according to the datasheets) but the Arduino card counts 10 000 pulses/revolution. When I change the speed of rotation, the PPR remain the same, which is normal. I can't explain the difference between the two values of PPR, I assume I don't control the Arduino card the right way, do you have any clue?

// PWM 
const int enable = 7;

//direction of rotation
const int in1 = 2;
const int in2 = 4;

#define c_EncoderPinA 52
#define c_EncoderPinB 40

volatile bool _EncoderASet;
volatile bool _EncoderBSet;
volatile bool _EncoderAPrev;
volatile bool _EncoderBPrev;
volatile long _EncoderTicks = 0;



void setup ()  {
  
  //encoder
  pinMode(c_EncoderPinA, INPUT);
  digitalWrite (c_EncoderPinA, HIGH);
  attachInterrupt(digitalPinToInterrupt(c_LEncoderPinA), pulseRead, RISING);

  pinMode(c_LeftEncoderPinB, INPUT);
  digitalWrite (c_LeftEncoderPinB, HIGH);
  attachInterrupt(digitalPinToInterrupt(c_EncoderPinB),pulseRead, RISING);
  
  //Motor
  pinMode(enable, OUTPUT);
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);

  //Starting the motor
  analogWrite(enable, 200);
  digitalWrite(in1, LOW);
  digitalWrite(in2, HIGH);

  Serial.begin (115200);   

}



void loop ()  {

  delay(20);
  Serial.println(_EncoderTicks);

  if(_EncoderTicks>50000)
  {analogWrite(enable, 0);}
}

  



// Interrupt service routines for the motor's quadrature encoder

void pulseRead(){
  // Test transition;
  _EncoderBSet = digitalRead(c_EncoderPinB);
  _EncoderASet = digitalRead(c_EncoderPinA);
  
  _EncoderTicks++;
  _EncoderAPrev = _EncoderASet;
  _EncoderBPrev = _EncoderBSet;
}

chaisepliante: Hello,

I'm trying to count pulses with my Arduino Due card. I'm using a DC motor with an encoder (400 PPR according to the datasheets) but the Arduino card counts 10 000 pulses/revolution. When I change the speed of rotation, the PPR remain the same, which is normal. I can't explain the difference between the two values of PPR, I assume I don't control the Arduino card the right way, do you have any clue?

// PWM 
const int enable = 7;

//direction of rotation const int in1 = 2; const int in2 = 4;

define c_EncoderPinA 52

define c_EncoderPinB 40

volatile bool _EncoderASet; volatile bool _EncoderBSet; volatile bool _EncoderAPrev; volatile bool _EncoderBPrev; volatile long _EncoderTicks = 0;

void setup ()  {    //encoder  pinMode(c_EncoderPinA, INPUT);  digitalWrite (c_EncoderPinA, HIGH);  attachInterrupt(digitalPinToInterrupt(c_LEncoderPinA), pulseRead, RISING);

 pinMode(c_LeftEncoderPinB, INPUT);  digitalWrite (c_LeftEncoderPinB, HIGH);  attachInterrupt(digitalPinToInterrupt(c_EncoderPinB),pulseRead, RISING);    //Motor  pinMode(enable, OUTPUT);  pinMode(in1, OUTPUT);  pinMode(in2, OUTPUT);

 //Starting the motor  analogWrite(enable, 200);  digitalWrite(in1, LOW);  digitalWrite(in2, HIGH);

 Serial.begin (115200);  

}

void loop ()  {

 delay(20);  Serial.println(_EncoderTicks);

 if(_EncoderTicks>50000)  {analogWrite(enable, 0);} }

 

// Interrupt service routines for the motor's quadrature encoder

void pulseRead(){  // Test transition;  _EncoderBSet = digitalRead(c_EncoderPinB);  _EncoderASet = digitalRead(c_EncoderPinA);    _EncoderTicks++;  _EncoderAPrev = _EncoderASet;  _EncoderBPrev = _EncoderBSet; }

In my experience, the code to use an 'A', 'B' rotation encoder needs to detect each transition on the encoder lines, your RISING declaration should be CHANGE and the code needs to be different.

volatile bool _EncoderASet;
volatile bool _EncoderBSet;
volatile int _EncoderTicks;
int _EncoderRange=400; // 400 ppm 

void ISR_A(){
_EncoderAset = digitalRead(c_EncoderPinA);

if(_EncoderASet == _EncoderBSet) {// 'A' is following 'B',   Therefore CCW
  _EncoderTicks = (_EncoderTicks + _EncoderRange -1); // the +_EncoderRange keeps % from producing
  //unexpected results.
  }
else _EncoderTicks++;

EncoderTicks = EncoderTicks % _EncoderRange; // limit encoder value to 0..(EncoderRange-1);
}

void ISR_B(){
_EncoderBSet = digitalRead(c_EncoderPinB);
if(_EncoderASet == _EncoderBSet) {// 'B' is following 'A',   Therefore CW
  _EncoderTicks ++;
  }
else _EncoderTicks = (_EncoderTicks + _EncoderRange -1);

EncoderTicks = EncoderTicks % _EncoderRange; // limit encoder value to 0..(EncoderRange-1);
}

void setup(){
  //encoder
  pinMode(c_EncoderPinA, INPUT);
  digitalWrite (c_EncoderPinA, HIGH);
  attachInterrupt(digitalPinToInterrupt(c_LEncoderPinA), ISR_A, CHANGE);

  pinMode(c_LeftEncoderPinB, INPUT);
  digitalWrite (c_LeftEncoderPinB, HIGH);
  attachInterrupt(digitalPinToInterrupt(c_EncoderPinB), ISR_B, CHANGE);
}

Now, if you want EncoderTicks to be an absolute position remove the modula function.

change both ISR to simple Increment and Decrement.

void ISR_A(){
_EncoderASet = digitalRead(c_EncoderPinA);

if(_EncoderASet == _EncoderBSet) {// 'A' is following 'B',   Therefore CCW
  _EncoderTicks--;
  }
else _EncoderTicks++;
}

Chuck.