ISR and void loop not working simultaneously.

We have written a code for calculation of rpm using encoder motor. We have used two interrupts and made two interrupt service routines (ISR) for the same. The problem is in our code only one thing gets printed at a time on the serial monitor. Either left count or the right count. Both don't work together. Also, the code is not entering the void loop, which it should before entering the ISR's. Here's the code:

#include "digitalWriteFast.h"

// left motor pins
#define InAL            10                      // INA motor pin
#define InBL            11                      // INB motor pin
#define PWML            6                       // PWM motor pin
#define encodPinAL      2                       // encoder A pin
#define encodPinBL      3                       // encoder B pin

//right motor pins
#define InAR            12                      // INA motor pin
#define InBR            13                      // INB motor pin
#define PWMR            7                       // PWM motor pin
#define encodPinAR      18                       // encoder A pin
#define encodPinBR      19                       // encoder B pin

unsigned long start_Time = millis();
volatile int countLeft = 0;
volatile int countRight = 0;
volatile int left_prev_count = 0;
volatile int right_prev_count = 0;
volatile int left_RPM = 0;
volatile int right_RPM = 0;
int Leftoffset = 0;
int Rightoffset = 0;
float konstant = 11.11;


void setup() 
{
  // put your setup code here, to run once:
  pinMode(InAL, OUTPUT);
  pinMode(InBL, OUTPUT);
  pinMode(PWML, OUTPUT);
  pinMode(encodPinAL, INPUT_PULLUP);
  pinMode(encodPinBL, INPUT);
  digitalWrite(encodPinAL, HIGH);                      // turn on pullup resistor
  attachInterrupt(digitalPinToInterrupt(2), ISRL, CHANGE);

  pinMode(InAR, OUTPUT);
  pinMode(InBR, OUTPUT);
  pinMode(PWMR, OUTPUT);
  pinMode(encodPinAR, INPUT_PULLUP);
  pinMode(encodPinBR, INPUT);
  digitalWrite(encodPinAR, HIGH);                      // turn on pullup resistor
  attachInterrupt(digitalPinToInterrupt(18), ISRR, CHANGE);
  Serial.begin(19200);
  
}

void ISRL()
{
  int state = digitalReadFast(encodPinAL);
  if (digitalReadFast(encodPinBL))
  {
    state ? countLeft-- : countLeft++;
    
  }
  else
  {
    state ? countLeft++ : countLeft--;
  }
 }

void ISRR()
{
  int state = digitalReadFast(encodPinAR);
  if (digitalReadFast(encodPinBR))
    state ? countRight++ : countRight--;
  else
    state ? countRight-- : countRight++;}

void moveForward() {
  digitalWrite(InAL, HIGH);
  digitalWrite(InBL, LOW);
  digitalWrite(InAR, HIGH);
  digitalWrite(InBR, LOW);
}

void  moveBackward() {
  digitalWrite(InAL, LOW);
  digitalWrite(InBL, HIGH);
  digitalWrite(InAR, LOW);
  digitalWrite(InBR, HIGH);
}

void stopMotor(){
  digitalWrite(InAL, LOW);
  digitalWrite(InBL, LOW);
  digitalWrite(InAR, LOW);
  digitalWrite(InBL, LOW); 
}

void moveMotor(int Left, int Right)
{
  analogWrite(PWML,Left);
  analogWrite(PWMR,Right);
  
  if(Left>0 && Right>0){
    moveForward();
  }
  else if(Left<0 && Right<0){
    moveBackward();
  }

   else if(Left==0 || Right==0)
   {
    stopMotor();
  
  }

}

void loop() 
{
  moveMotor(255 + Leftoffset,255 + Rightoffset);
  if((millis()-start_Time)>20)
    {
      Serial.println("Entering loop()");
      start_Time = millis();
      left_RPM = countLeft*konstant;
      right_RPM = countRight*konstant;
      Serial.println(left_RPM);
      Serial.println(right_RPM);
      countLeft = 0;
      countRight = 0;
    }
 
}

ISRs act asynchronously. You have no control over when they get triggered - that is the usual reason for using an ISR.

I suggest you have each ISR set a flag variable - for example ISRleft = true or ISRright = true and then your code in loop() can check for those flags like this

if (ISRleft == true) {
  noInterrupts();
  leftCountCopy = countLeft;
  ISRleft = false;
  interrupts();
}

Note especially the use of noInterrupts() to pause the interrupts while you take a copy of the multi-byte variable from the ISR. If you don't do that the value could change between reading the first part of the value and second part.

Then the rest of your code in loop() should use the copied value.

The flag variable should be a boolean which is a single byte so it can be read directly without any risk of confusion.

...R

Hi,
If all you are doing is calculating speed, you only need to monitor ONE of the encoder outputs,
So use only ONE interrupt and count that.

If you need direction as well, then still use ONE interrupt and when servicing that interrupt, check the state of the other encoder output.
The state of the other encoder will tell you which direction the encoder is turning.

Tom.... :slight_smile:
PS, +karma for using code tags

Also, the code is not entering the void loop, which it should before entering the ISR's.

What does this mean? Can you explain more? How do you know this?

We have used two interrupts and made two interrupt service routines (ISR) for the same. The problem is in our code only one thing gets printed at a time on the serial monitor. Either left count or the right count. Both don't work together.

How fast are your motors rotating, and how many counts do you expect in 20 milliseconds?