Using Multiple Rotary Encoders with one board

Hello!
I have been trying to attach two CALT GHW38 Rotary Encoders to my Arduino MEGA2560, my Rotary Encoder is 600 PPR.
I have been trying to modify this code in order to accept another interrupt over pin 18/19 for my second encoder, however, I have been running into issues with the second coder not reading at all.

unsigned long start;
const byte encoderPinA = 2;//A pin -> interrupt pin 2
const byte encoderPinB = 3;//B pin -> digital pin 3
volatile long pulse;
volatile bool pinB, pinA, dir;
const byte upDatesPerSec = 10;
unsigned short ppr = 600;
const int fin = 1000 / upDatesPerSec;
const float konstant = 60.0 * upDatesPerSec / (ppr * 2);
int rpm;


void setup() {
  Serial.begin(9600);
  attachInterrupt(0, readEncoder, CHANGE);
  pinMode(encoderPinA,INPUT);
  pinMode(encoderPinB,INPUT);
}

void loop() {
  if(millis() - start > fin)
  {
    start = millis();
    rpm = pulse * konstant;
    Serial.print("RPM: ");
    Serial.println(rpm);
    pulse = 0;
  }
}

void readEncoder()
{
  pinA = bitRead(PIND,encoderPinA);
  pinB = bitRead(PIND,encoderPinB);
  dir = pinA ^ pinB;          // if pinA & pinB are the same
  dir ? --pulse : ++pulse;    // dir is CW, else CCW
}

My first attempt was along the lines of this

unsigned long start;
const byte encoderPinA = 2;//A pin -> interrupt pin 2
const byte encoderPinB = 3;//B pin -> digital pin 3
const byte encoderPinA2 = 18;
const byte encoderPinB2 = 19;
volatile long pulse;
volatile long pulse2;
volatile bool pinB, pinA, dir;
volatile bool pinB2, pinA2, dir2;
const byte upDatesPerSec = 10;
unsigned short ppr = 600;
const int fin = 1000 / upDatesPerSec;
const float konstant = 60.0 * upDatesPerSec / (ppr * 2);
int rpm;
int rpm2;


void setup() {
  Serial.begin(9600);
  attachInterrupt(2, readEncoder, CHANGE);
  pinMode(encoderPinA,INPUT);
  pinMode(encoderPinB,INPUT);
  pinMode(encoderPinA2,INPUT);
  pinMode(encoderPinB2,INPUT);
}

void loop() {
  if(millis() - start > fin)
  {
    start = millis();
    rpm = pulse * konstant;
    rpm2 = pulse2 * konstant;
    
    Serial.print("A RPMS: ");
    Serial.println(rpm);
    Serial.print("B RPMS: ");
    Serial.println(rpm2);
    
    pulse = 0;
    pulse2 = 0;
  }
}

void readEncoder()
{
  pinA = bitRead(PIND,encoderPinA);
  pinB = bitRead(PIND,encoderPinB);
  pinA2 = bitRead(encoderPinA2);
  pinB2 = bitRead(encoderPinB2);
  
  dir = pinA ^ pinB;          // if pinA & pinB are the same
  dir ? --pulse : ++pulse;    // dir is CW, else CCW
  dir2 = pinA2 ^ pinB2;
  dir2 ? --pulse2 : ++pulse2;
}

However, this code breaks obviously as my bitRead(x,n) is missing a call and a few other glaring mistakes. I am getting confused with the port manipulation needed for such fast processes and using interrupts it seems and any ideas/guidance would be greatly appreciated.
In the end I want to be able to measure the difference between two rotating shafts in terms of acceleration and RPM's among other things which is why I want both rotary encoders feeding into one Arduino.
Thanks for taking the time.

You might get some ideas here: GitHub - gfvalvo/NewEncoder: Rotary Encoder Library
See the MultipleEncoders example.

attachInterrupt(2, readEncoder, CHANGE);

Use this recommended syntax for the interrupt. I do not think you are using the correct interrupt number.

attachInterrupt(digitalPinToInterrupt(pin), ISR, mode)

You are going to want two different interrupt service routines-- one for each encoder.

Get started with digitalRead() to begin with, and convert to faster methods when things are working correctly at lower speeds.

unsigned long start;
const byte encoderPinA = 2;//A pin -> interrupt pin 2
const byte encoderPinB = 3;//B pin -> digital pin 3
const byte encoderPinA2 = 18;
const byte encoderPinB2 = 19;
volatile long pulse;
volatile long pulse2;
volatile bool pinB, pinA, dir;
volatile bool pinB2, pinA2, dir2;
const byte upDatesPerSec = 10;
unsigned short ppr = 600;
const int fin = 1000 / upDatesPerSec;
const float konstant = 60.0 * upDatesPerSec / (ppr * 2);
int rpm;
int rpm2;


void setup() {
  Serial.begin(9600);
  attachInterrupt(0, readEncoder, CHANGE);
  pinMode(encoderPinA,INPUT);
  pinMode(encoderPinB,INPUT);
  
  attachInterrupt(18, readEncoder2, CHANGE);
  pinMode(encoderPinA2, INPUT);
  pinMode(encoderPinB2, INPUT);
}

void loop() {
  if(millis() - start > fin)
  {
    start = millis();
    rpm = pulse * konstant;
    rpm2 = pulse2 * konstant;
    Serial.print("A RPM: ");
    Serial.println(rpm);
    Serial.print("B RPM: ");
    Serial.println(rpm2);
    pulse = 0;
    pulse2 = 0;
    
  }
}

void readEncoder()
{
  pinA = bitRead(PIND,encoderPinA);
  pinB = bitRead(PIND,encoderPinB);
  dir = pinA ^ pinB;          // if pinA & pinB are the same
  dir ? --pulse : ++pulse;    // dir is CW, else CCW
}

void readEncoder2()
{
  pinA2 = digitalRead(encoderPinA2);
  pinB2 = digitalRead(encoderPinB2);
  dir2 = pinA2 ^ pinB2;
  dir2 ? --pulse2 : ++pulse2;
}

Something like this? it seems to be still giving me 0s when using digital read in this instance

I tested the encoder and its getting data so the problem has to be in my code or how im doing the interrupts I think

attachInterrupt(18, readEncoder2, CHANGE);

No.

attachInterrupt(digitalPinToInterrupt(18), readEncoder2, CHANGE);

that fixed it! thanks for the help cattledog

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.