Dual Rotary Encoder Issue

Hi Guys

New to this forum and a fairly Noob to programming to.

I am having an issue with some code. what i am trying to achieve is have two separate rotary encoders change two separate values on an 8 x 2 LCD.
I have found Ralph Bacon's Interrupt code and it works almost as i want it to but i have an issue where one encoder wont work unless i turn the other one click back or forward. Then the first encoder works fine, but if i try the second encoder, it wont work unless i do the same again to the first.

Here is the full code so far and i am currently using an UNO but will migrate to a MICRO for the final project.

would really appreciate any help and very keen to learn more about programming correctly.

// EEPROM Setup

#include <EEPROM.h>

// LCD Setup

#include <LiquidCrystal.h>

LiquidCrystal lcd(13, 12, 11, 10, 9, 8); // initialize the libary with the interface pins

//ENCODER Setup

//MM Encoder
const int MMPinA = 3; // Used for generating interrupts using CLK signal
const int MMPinB = 4;  // Used for reading DT signal
int MMlastCount; // Keep track of last rotary value
float MMdecLastCount; // sets last count number to a decimal
float MMcalc; // Sets calculated number to a decimal
volatile int MMvirtualPosition = EEPROM.read(1); // Updated by the ISR (Interrupt Service Routine)

//SPD Encoder
const int SPDPinA = 2; // Used for generating interrupts using CLK signal
const int SPDPinB = 5;  // Used for reading DT signal
int SPDlastCount; // Keep track of last rotary value
float SPDdecLastCount; // sets last count number to a decimal
float SPDcalc; // Sets calculated number to a decimal
volatile int SPDvirtualPosition = EEPROM.read(2); // Updated by the ISR (Interrupt Service Routine)

//Safety Switch Setup

const int safetyPin = A0; //Set Safety Pin to A0
int safeVal = 0; // Set initial value to 0

//Stepper Motor Setup

int motorEnable = 0; // Set stepper motor enable pin to Digital pin 0
int motorStep = 7; // Set stepper motor Step pin to Digital pin 7
int motorDir = 6; // Set stepper motor Direction pin to Digital pin 6

//Manual/Auto Switch Setup

const int manAutoPin = A1; //Ser Manual Auto pin to A1
int manAutoVal = 0; //Set initial value to 0

 
//INTERUPT Setup

void isr1 ()  
{ //MM Setup
  static unsigned long MMlastInterruptTime = 0;
  unsigned long MMinterruptTime = millis();

  if (MMinterruptTime - MMlastInterruptTime > 5) // If interrupts come faster than 5ms, assume it's a bounce and ignore
  {
    if (digitalRead(MMPinB) == LOW)
      {
        MMvirtualPosition-- ;
      }
    else
     {
       MMvirtualPosition++ ;
     }

          MMvirtualPosition = min(250, max(0, MMvirtualPosition)); // Restrict value from 0 to +250

          MMlastInterruptTime = MMinterruptTime;  // Keep track of when we were here last (no more than every 5ms)
  }
}
void isr2 ()
{ //SPD Setup
  
  static unsigned long SPDlastInterruptTime = 0;
  unsigned long SPDinterruptTime = millis();

  if (SPDinterruptTime - SPDlastInterruptTime > 5) // If interrupts come faster than 5ms, assume it's a bounce and ignore
  {
    if (digitalRead(SPDPinB) == LOW)
      {
        SPDvirtualPosition-- ;
      }
    else 
      {
        SPDvirtualPosition++ ;
      }

          SPDvirtualPosition = min(250, max(0, SPDvirtualPosition)); // Restrict value from 0 to +250

          SPDlastInterruptTime = SPDinterruptTime;  // Keep track of when we were here last (no more than every 5ms)
  }
}

void setup()
{
  //EPPROM setup
  
  EEPROM.read (1);
  MMvirtualPosition = EEPROM.read (1);
  EEPROM.read (2);
  SPDvirtualPosition = EEPROM.read (2);
  
  // LCD Setup
  
  lcd.begin(8,2); //set the LCD's number of columns and rows
  lcd.setCursor(0, 0); //Set cursor to column 0, row 0
  lcd.print("INTRFLUX"); //Display INTRFLUX on first line
  lcd.setCursor(1, 1); //Set cursor to column 1, row 1
  lcd.print("SWF 25"); //Display SWF 25 on Second line
  delay(3000); //Display above lines for 3 seconds
  lcd.clear(); //Clear the LCD
  delay(2000); //Wait 2 seconds before going to loop

  //Encoder Setup
   //####################Serial.begin(9600);  // Just whilst we debug, view output on serial monitor
   //Sets the encoder pins
  pinMode(MMPinA, INPUT);   // Rotary pulses are INPUTs
  pinMode(MMPinB, INPUT);
  attachInterrupt(digitalPinToInterrupt(MMPinA), isr1, LOW);  // Attach the routine to service the interrupts
  pinMode(SPDPinA, INPUT);   // Rotary pulses are INPUTs
  pinMode(SPDPinB, INPUT);
  attachInterrupt(digitalPinToInterrupt(SPDPinA), isr2, LOW);  // Attach the routine to service the interrupts
  //###################Serial.println("Start");  // Ready to go!
  
  //Safety Pin Setup
  
  pinMode (safetyPin, INPUT); //Set safety pin to an input
  digitalWrite (A0, HIGH); //Set safety pin HIGH

  //Manual Auto Switch Setup

  pinMode (manAutoPin, INPUT);
  digitalWrite (A1, HIGH);
 
}

void loop()//###DISPLAY SCREEN###
{
  safeVal = digitalRead(A0);
  //Serial.print(safeVal);
  //Safety Switch

 if (safeVal != 1) //If Safety Pin A0 is Low change screen to COVER OPEN
   
    {
    //lcd.clear();
    lcd.setCursor (0,0);
    lcd.print(" Cover  ");
    lcd.setCursor(0,1);
    lcd.print("  Open  ");
    delay(100);
    }
 
    //Encoder
  //{

else 
  { 
    //LCD
    lcd.setCursor(1, 0);
    lcd.print("MM:");
    lcd.setCursor(0, 1);
    lcd.print("Spd:");
    lcd.setCursor(4, 0);
      if (MMcalc < 10) lcd.print(" ");
    lcd.print(MMcalc,1); //from encoder calcMM value
    lcd.setCursor(4, 1);
      if (SPDcalc < 10) lcd.print(" ");
    lcd.print(SPDcalc,1); //from encoderSPD value   // If the current rotary switch position has changed then update everything

   
    MMlastCount = MMvirtualPosition ; // Keep track of this new value
    MMdecLastCount = MMvirtualPosition;
    MMcalc = (MMdecLastCount/10);
    EEPROM.write (1, MMvirtualPosition); //Save number to EEPROM position 1
    SPDlastCount = SPDvirtualPosition ; // Keep track of this new value
    SPDdecLastCount = SPDvirtualPosition;
    SPDcalc = (SPDdecLastCount/10);
    EEPROM.write (2, SPDvirtualPosition); //Save number to EEPROM position 1
}
  }

hello for your information I am new to arduino also but experienced a similar issue with encoders recently where first step on encoder quote did nothing ??? then second step worked as required I may be wrong but its to do with the type of encoder used mine was KY040 PCB mounted the first movement was / is to read direction of rotation the second step this may help in your project BTW there are incremental or continuous encoders and the code differs for each???(maybe)

but i have an issue where one encoder wont work unless i turn the other one click back or forward. Then the first encoder works fine, but if i try the second encoder, it wont work unless i do the same again to the first.

attachInterrupt(digitalPinToInterrupt(MMPinA), isr1, LOW);  // Attach the routine to service the interrupts
  attachInterrupt(digitalPinToInterrupt(SPDPinA), isr2, LOW);  // Attach the routine to service the interrupts

I think there is an issue with using LOW for the interrupt trigger condition. The "low level" interrupts are continuously checked, and they will keep firing, even after the interrupt has been called. That is, the ISR will exit, and then the interrupt will immediately fire again. See Gammon Forum : Electronics : Microprocessors : Interrupts

Try setting the interrupt trigger condition to FALLING.