Digital Readout X & Y axis, attachInterupt issue "ai0 not in the scope"

I an working on this adding a readout to a microscope X & Y stage. It does have stepper motors but I am not utilizing them, just using it manually. I am connected to the 1000 pulse encoders, one on each axis. I started with a base program from online and have built it up from there. I started with the Y axis and have it working the way I want. I am now trying to incorporate the X axis into the program and keep getting hung up on how to code it to work. I tried coping the "Y" code and change the need variables but it returns with "aiO not in the scope" when it gets to the "X" counter section near the end. I have been working on it all weekend and just can't get it. I have become confused from all the examples and this I have read about the interrupt commands. I always try to figure things out myself but I have thrown the towel in to hopefully get some guidance.

Thank you in advance!!!!
Tom

Here is a 30sec. Youtube video showing the project to hopefully better understand what I am doing:

#include <LiquidCrystal.h>
LiquidCrystal lcd(1, 2, 4, 5, 6, 7);
volatile long tempX, counterX = 0; //This variable will increase or decrease depending on the rotation of encoder
volatile long tempY, counterY = 0; //This variable will increase or decrease depending on the rotation of encoder
int buttonxPin = 13; //used to ZERO out X axis
int buttonyPin = 12; //used to ZERO out Y axis
int buttonxRead;
int buttonyRead;


void setup() {
  float counterX;
  float counterY;
  pinMode(buttonxPin, INPUT_PULLUP); //X axis ZEROing pin
  pinMode(buttonyPin, INPUT_PULLUP); //Y axis ZEROing pin

  //----------------------------------------------------------------------------------
  //THE PROBLEMS ARISE FROM BELOW HERE AND I'M NOT SURE OF THE CORRECT CODING
  //----------------------------------------------------------------------------------
  //Setting up interrupt for Y axis
  //Y axis- A rising pulse from encodenren activated ai0(). AttachInterrupt 0 is DigitalPin int2(pin 21).
  attachInterrupt(2, ai0, RISING);

  //Y axis_ B rising pulse from encodenren activated ai1(). AttachInterrupt 1 is DigitalPin int3(pin 20).
  attachInterrupt(3, ai1, RISING);

  //Setting up interrupt for X axis
  //X axis- A rising pulse from encodenren activated ai0(). AttachInterrupt 0 is DigitalPin int4(pin 19).
  attachInterrupt(4, ai0, RISING);

  //X axis_ B rising pulse from encodenren activated ai1(). AttachInterrupt 1 is DigitalPin int5(pin 18).
  attachInterrupt(5, ai1, RISING);
  //----------------------------------------------------------------------------------
  //THE PROBLEMS ARISE FROM ABOVE HERE AND I'M NOT SURE OF THE CORRECT CODING
  //----------------------------------------------------------------------------------


  lcd.begin(16, 2);

  //X axis cursor set and ZEROing readout for X
  lcd.setCursor(0, 0);
  lcd.print("X 0.0000   ");
  lcd.setCursor(10, 0);
  lcd.print("000.00");

  //Y axis cursor set and ZEROing readout for Y
  lcd.setCursor(0, 1);
  lcd.print("Y 0.0000   ");
  lcd.setCursor(10, 1);
  lcd.print("000.00");
}

//-----------------------------------------------------
// Y axis start
//----------------------------------------------------

void loop() {

  //if "Y Zero" button pushed (int buttonyPin = 12), counterY=0, display "0.000
  buttonyRead = digitalRead(buttonyPin);
  if (buttonyRead == 0) {
    lcd.setCursor(2, 1);
    lcd.print ("0.0000   ");
    lcd.setCursor(10, 1);
    lcd.print("000.00");
    counterY = 0;
    delay(10);
  }


  //if "X Zero" button pushed (int buttonxPin = 13), counterY=0, display "0.000
  buttonxRead = digitalRead(buttonxPin);
  if (buttonxRead == 0) {
    lcd.setCursor(2, 1);
    lcd.print ("0.0000   ");
    lcd.setCursor(10, 1);
    lcd.print("000.00");
    counterX = 0;
    delay(10);
  }


  // Send the value of counterY
  lcd.setCursor(1, 1);
  if ( counterY != tempY ) {
    if (0 < (counterY * .001 * .03937))
    {
      lcd.print(" ");
      lcd.print (counterY * .001 * .03937, 4); //convert counterY pulses to inches, 1000 per revolution
      lcd.setCursor(10, 1);
      lcd.print (counterY * .001, 3); //convert counterY pulses to milimeters, 1000 per revolution
      lcd.print(" ");
    }
    else {
      lcd.print (counterY * .001 * .03937, 4); //convert counterY pulses to inches, 1000 per revolution
      lcd.setCursor(9, 1);
      lcd.print (counterY * .001, 3); //convert counterY pulses to milimeters, 1000 per revolution
      lcd.print(" ");
    }
    tempY = counterY;

  }
  //-----------------------------------------------------
  // Y axis end
  //----------------------------------------------------

  //-----------------------------------------------------
  // X axis start
  //----------------------------------------------------



  // Send the value of counterX
  lcd.setCursor(1, 1);
  if ( counterX != tempX ) {
    if (0 < (counterX * .001 * .03937))
    {
      lcd.print(" ");
      lcd.print (counterX * .001 * .03937, 4); //convert counterY pulses to inches, 1000 per revolution
      lcd.setCursor(10, 1);
      lcd.print (counterX * .001, 3); //convert counterY pulses to milimeters, 1000 per revolution
      lcd.print(" ");
    }
    else {
      lcd.print (counterX * .001 * .03937, 4); //convert counterY pulses to inches, 1000 per revolution
      lcd.setCursor(9, 1);
      lcd.print (counterX * .001, 3); //convert counterY pulses to milimeters, 1000 per revolution
      lcd.print(" ");
    }
    tempX = counterX;

  }
}


// counter for Y axis
void ai0() {
  // ai0 is activated if DigitalPin nr 2 is going from LOW to HIGH
  // Check pin 3 to determine the direction
  if (digitalRead(20) == LOW) {
    counterY++;
  } else {
    counterY--;
  }
}

void ai1() {
  // ai0 is activated if DigitalPin nr 3 is going from LOW to HIGH
  // Check with pin 2 to determine the direction
  if (digitalRead(21) == LOW) {
    counterY--;
  } else {
    counterY++;
  }
}

//----------------------------------------------------------------------------------
//I GET AN ERROR BELOW HERE, "ai0 not in the scope"
//----------------------------------------------------------------------------------
// counter for X axis
void ai0() {
  // ai0 is activated if DigitalPin nr 2 is going from LOW to HIGH
  // Check pin 3 to determine the direction
  if (digitalRead(18) == LOW) {
    counterX++;
  } else {
    counterX--;
  }
}

void ai1() {
  // ai0 is activated if DigitalPin nr 3 is going from LOW to HIGH
  // Check with pin 2 to determine the direction
  if (digitalRead(19) == LOW) {
    counterX--;
  } else {
    counterX++;
  }
}
//-----------------------------------------------------
// x axis end
//----------------------------------------------------

You have two functions named ai0() and two functions named ai1()

You may only use a name once.

And your code in loop() is not getting the data from the interrupt routines correctly. counterY and counterX are multi-byte variables so you need to briefly suspend interrupts when you read the value in case they change while you are reading them. Like this ...

void loop() {
   noInterrupts();
      copyOfCounterX = counterX;
      copyOfCounterY = counterY;
   interrupts();
 
   // rest of your code

then the rest of your code should use the copies.

You need a similar approach if you want to change the values of counterX or counterY

...R

Robin2,

Thank you for the input, the program works great now!

I kinda knew the ai0 and ai1 needed to be different but I was changing the number. I renamed them to aix0, aix1, aiyo and aiy1-no problems.

I don't fully have my head wrapped around this part you gave me and exactly what it's doing, especially with the "copyOfCounterX(Y)" but, I will continue to read up and study it more.

void loop() {
   noInterrupts();
      copyOfCounterX = counterX;
      copyOfCounterY = counterY;
   interrupts();
 
   // rest of your code

Thank you again!
Tom

tpreb6:
I don't fully have my head wrapped around this part you gave me and exactly what it's doing, especially with the "copyOfCounterX(Y)" but, I will continue to read up and study it more.

void loop() {

noInterrupts();
      copyOfCounterX = counterX;
      copyOfCounterY = counterY;
  interrupts();

// rest of your code

The idea is to pause interrupts while you take a copy of the value in the variables that are updated by the ISR. Once you have the copies then allow the interrupts to continue.

For the rest of the calculations in loop() anywhere that you need the value from the ISR use the relevant copy.

If that is not clear then please explain your confusion and I will try to help.

...R

The main reason is that you're using an eight bit microcontroller, and a "long" variable occupies 32 bits, or four bytes.
The processor cannot handle 32 bits in a single operation, so it possible that while you're loading such a variable into registers, the processor could be interrupted and the variable incremented or decremented.
If this involves a single byte over- or under-flow, your variable could look very wrong indeed.