Use of 4 interrupt pins i.e. 2,3,19 and 20 in Arduino Mega for Rotary encoder

Hello;
I am working on a project in which there are two rotary encoder. I need to display RPM of both encoder on serial monitor. But the RPM of only encoder connected to pin 2 & 3 is displayed and RPM of encoder connected to pin 20 & 21 is sowing 0.00. The code is as follows:

int encoderPin1 = 2;
int encoderPin2 = 3;
int encoderPin3 = 20;
int encoderPin4 = 21;

volatile int lastEncoded = 0;
volatile int lastEncoded2 = 0;
volatile long encoderValue = 0;
volatile long encoderValue2 = 0;
long lastencoderValue = 0;
long lastencoderValue2 = 0;
int lastMSB = 0;
int lastLSB = 0;

long previousMillis = 0;
long currentMillis = 0;

void setup() {
  Serial.begin (9600);
  pinMode(encoderPin1, INPUT);
  pinMode(encoderPin2, INPUT);
  pinMode(encoderPin3, INPUT);
  pinMode(encoderPin4, INPUT);
  digitalWrite(encoderPin1, HIGH);
  digitalWrite(encoderPin2, HIGH);
  digitalWrite(encoderPin3, HIGH);
  digitalWrite(encoderPin4, HIGH);

  attachInterrupt(encoderPin1, updateEncoder, CHANGE);
  attachInterrupt(encoderPin2, updateEncoder, CHANGE);
  attachInterrupt(encoderPin3, updateEncoder2, CHANGE);
  attachInterrupt(encoderPin4, updateEncoder2, CHANGE);
}
void loop() {

  currentMillis = millis();
  if (currentMillis - previousMillis > 1000) {
    previousMillis = currentMillis;

    float rpm = (encoderValue * 60.00 / 1600.00);
    float rpm2 = (encoderValue2 * 60.00 / 1600.00);

    Serial.print(rpm);
    Serial.print("          ");
    Serial.print(rpm2);
    Serial.println();

    encoderValue = 0;
    encoderValue2 = 0;

  }
}
void updateEncoder() {
  int MSB = digitalRead(encoderPin1);
  int LSB = digitalRead(encoderPin2);
  int encoded = (MSB << 1) | LSB;

  int sum = (lastEncoded << 2) | encoded;

  if (sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011)
    encoderValue ++;
  if (sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000)
    encoderValue --;
  lastEncoded = encoded;
}

void updateEncoder2() {
  int MSB2 = digitalRead(encoderPin3);
  int LSB2 = digitalRead(encoderPin4);
  int encoded2 = (MSB2 << 1) | LSB2;

  int sum = (lastEncoded2 << 2) | encoded2;

  if (sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011)
    encoderValue2 ++;
  if (sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000)
    encoderValue2 --;
  lastEncoded2 = encoded2;
}

Please suggest the necessary correction.

from SoftwareSerial library
Not all pins on the Mega and Mega 2560 boards support change interrupts, so only the following can be used for RX: 10, 11, 12, 13, 14, 15, 50, 51, 52, 53, A8 (62), A9 (63), A10 (64), A11 (65), A12 (66), A13 (67), A14 (68), A15 (69).

I am not using change interrupts because Mega 2560 board already has 06 interrupt pins i.e 2,3,18,19,20,21. My problem is why the value of pin 20 & 21 sowing 0.

Read the reference on how this instruction works.

You are not using the instruction correctly.

Thanks @Grumpy_Mike. It works now.

Can you suggest me that how can i use 4 interrupt pins on arduino nano because it has only 2 i.e. D2 & D3.

Timer-interrupt based encoder-reading

As all coders give their library the same name
encoder.h / encoder.cpp
you have to make sure that your IDE is using the correct encoder-library

here is a demo-sketch that shows how to use two encoders on non-state-change-interrupt-capable IO-pins

//timer-interrupt based encoder-reading for 2 encoders
// MACRO-START * MACRO-START * MACRO-START * MACRO-START * MACRO-START * MACRO-START *
// a detailed explanation how these macros work is given in this tutorial
// https://forum.arduino.cc/t/comfortable-serial-debug-output-short-to-write-fixed-text-name-and-content-of-any-variable-code-example/888298

#define dbg(myFixedText, variableName) \
  Serial.print( F(#myFixedText " "  #variableName"=") ); \
  Serial.println(variableName);

#define dbgi(myFixedText, variableName,timeInterval) \
  { \
    static unsigned long intervalStartTime; \
    if ( millis() - intervalStartTime >= timeInterval ){ \
      intervalStartTime = millis(); \
      Serial.print( F(#myFixedText " "  #variableName"=") ); \
      Serial.println(variableName); \
    } \
  }

#define dbgc(myFixedText, variableName) \
  { \
    static long lastState; \
    if ( lastState != variableName ){ \
      Serial.print( F(#myFixedText " "  #variableName" changed from ") ); \
      Serial.print(lastState); \
      Serial.print( F(" to ") ); \
      Serial.println(variableName); \
      lastState = variableName; \
    } \
  }

#define dbgcf(myFixedText, variableName) \
  { \
    static float lastState; \
    if ( lastState != variableName ){ \
      Serial.print( F(#myFixedText " "  #variableName" changed from ") ); \
      Serial.print(lastState); \
      Serial.print( F(" to ") ); \
      Serial.println(variableName); \
      lastState = variableName; \
    } \
  }
// MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END *

#include <Encoder.h>

const byte enc1PinA = 4;
const byte enc1PinB = 7;
const byte enc1Btn  = A1;

const byte enc2PinA = 10;
const byte enc2PinB = 11;
const byte enc2Btn  = A2;

long position = 0;
long position2 = 0;

int delta;
int delta2;

// create encoder objects initialized with their pins
Encoder encoder1( enc1PinA, enc1PinB, enc1Btn );
Encoder encoder2( enc2PinA, enc2PinB, enc2Btn );

Encoder *encoderArray[] = { &encoder1, &encoder2 };


void PrintFileNameDateTime() {
  Serial.println( F("Code running comes from file ") );
  Serial.println( F(__FILE__) );
  Serial.print( F("  compiled ") );
  Serial.print( F(__DATE__) );
  Serial.print( F(" ") );
  Serial.println( F(__TIME__) );
}


// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - startOfPeriod >= TimePeriod ) {
    // more time than TimePeriod has elapsed since last time if-condition was true
    startOfPeriod = currentMillis; // a new period starts right here so set new starttime
    return true;
  }
  else return false;            // actual TimePeriod is NOT yet over
}

unsigned long MyTestTimer = 0;                   // Timer-variables MUST be of type unsigned long
const byte    OnBoard_LED = 13;


void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
  static unsigned long MyBlinkTimer;
  pinMode(IO_Pin, OUTPUT);

  if ( TimePeriodIsOver(MyBlinkTimer, BlinkPeriod) ) {
    digitalWrite(IO_Pin, !digitalRead(IO_Pin) );
  }
}


void setup() {
  Serial.begin(115200);
  Serial.println("Setup-Start");
  PrintFileNameDateTime();
  EncoderInterrupt.begin( encoderArray, 2 );
}


void loop() {
  BlinkHeartBeatLED(OnBoard_LED, 250);

  delta = encoder1.delta(); 
  //dbgc("e1:",delta);
  position += delta;
  // dbgc print only ONCE if value has changed 
  dbgc("pos", position);

  delta2 = encoder2.delta();
  //dbgc("e2:",delta2);
  position2 += delta2;
  // dbgc print only ONCE if value has changed 
  dbgc("pos2", position2);
}

best regards Stefan

True it only has two so you can't use more. If you want to use a library then this one:-
Rotary Library
from Encoder Library, for Measuring Quadarature Encoded Position or Rotation Signals
Allows you to use just one interrupt per rotary encoder.

Otherwise look into the "pin change" interrupt process. It is slightly more complex in that you have to do a bit of work to find out what pin on what channel caused the interrupt.

google is your friend

https://tttapa.github.io/Arduino-Helpers/Doxygen/d6/dd2/Pin-Change-Interrupt-Encoders_8ino-example.html

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