HELP WITH INTERRUPTS :( code stops working

Please help, I am working with an encoder and dc motor, i have to find the RPM's, I found this code online:

/*
   Ejemplo como usar encoder rotativo con arduino
*/
const int channelPinA = 2;

int PPR = 20;
volatile int ISRCounter = 0;
unsigned int pulsos = 0;
unsigned long Time = 0; 
unsigned int RPM = 0;

void setup()
{ 
  pinMode(channelPinA, INPUT_PULLUP);
  
  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(channelPinA), doEncode, CHANGE);
  Time = millis();
  
}

void loop()
{
  if(millis() - Time >=1000)
  {
    
    pulsos = ISRCounter;
    RPM = 60 * pulsos/PPR;
    
    Serial.print("Pulsos por segundo:");
    Serial.println(pulsos);

    Serial.print("Revoluciones por minuto:");
    Serial.println(RPM);
    //se reestablecen los valores
    ISRCounter = 0;
    pulsos = 0;
    Time = millis();
    
  }
}

void doEncode()
{
  ISRCounter++;  
}

I am trying to add other calculations and the code stops working, nothing prints out! WHAT IS IT ! help :frowning:

#include <Wire.h>
#include <LiquidCrystal.h>

//rs, en, d4, d5, d6, d7
LiquidCrystal lcd(A0, A1, A2, A3, A4, A5); //pins in the arduino
#define RotationalDirection 9
#define Pot A12
#define encoder A13
#define btnTemp A15
#define tempSensor A14
#define pot A12
#define pin2 4
#define pin1 3
#define vel 5


int steps = 0;
int motorSpeed = 0;
int ppr = 20;

float Speed = 0;
float RPMin = 0;
float RPMs = 0;
float RPMout = 0;

unsigned long pi = 3.14159265359;
unsigned long currentTime = 0;
unsigned long btnTime = 0;
unsigned long startTime = millis();
unsigned long tiempoSeg = 0;
unsigned long tiempo1 = 0;
unsigned long timePeriod = 0;

unsigned long start_time = 0;
unsigned long end_time = 0;

float oldPulses=0;
float rps=0;
float tempValue;
float tempC;
float tempActual = 0;
float tempActualBtn = 0;

int lastButtonState = 0;
int oldState =0;
int state = 1;
int btnState;
int pulses=0;
int cont = 0;

bool buttonPress = false;
bool first = true;
bool second = true;

const int channelPinA = 2 ;

int PPR = 20;
volatile int ISRCounter = 0;
unsigned int pulsos = 0;
unsigned long Time = 0; 
unsigned int RPM = 0;


void setup()
{ 
  pinMode(channelPinA, INPUT_PULLUP);
  
  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(channelPinA), doEncode, CHANGE);
  Time = millis();
  
}

void loop()
{
  if(millis() - Time >2000)
  {
    
    pulsos = ISRCounter;
    RPMin = (60 * pulsos/PPR)/(1/48);
    RPMout =(60 * pulsos/PPR);

    Serial.println(RPMin);
 Serial.println(RPMout);
    //se reestablecen los valores
    ISRCounter = 0;
    Time = millis();
    
  }
}

void doEncode()
{
  ISRCounter++;  
}

This is a really interesting problem... :thinking:

I cut down your code a line at a time to a bare minimum, to try and isolate the issue. In the code below the problem still exists.

volatile int  ISRCounter = 0;
float         RPMin = 0;
unsigned long Time = millis();


void setup()
{
  Serial.begin(115200);
  Serial.println("Start");
}


void loop()
{
  Serial.println(millis());

  if (millis() - Time > 2000)
  {
    Serial.println("2 seconds");
      
    delay(50);                                 // To allow serial prints to complete before the crash...
    
    RPMin = (60 * ISRCounter / 20) / (1 / 48);   // Simpler calculations seem to work.

    Serial.println(RPMin);                     // This never returns.
  }
}

The issue seems to be related to the calculation of RPMin, and then trying to display it... kills the Serial interface. Nothing gets printed after the attempt to print RPMin.

Also of note is that the problem does not occur if ISRCounter is not declared as "volatile".

I do not know why this is occurring, but now that the issue is a lot narrower someone on here may be able to explain what is happening.

thankyou very much! i gave up and decided to change it to not use interrupts, but I hope someone will find it useful for other problems! :smiley:

1. Your sketch of post #1 is working fine which I have tested injecting 5-Hz interrupting signal at INT0-pin of the NANO. The process is nicely detecting changes in the properties of the interrupting signal (HIGH to LOW and LOW to HIGH; because the triggering mode is: CHNAGE).

OUTPUT:

11:37:56.361 -> Pulsos por segundo:10
11:37:56.361 -> Revoluciones por minuto:30
11:37:57.366 -> Pulsos por segundo:10
11:37:57.366 -> Revoluciones por minuto:30

2. Describe in Text what addition function(s) you want to add with the original sketch that you have collected from online. It is difficult to know from the codes you have provided.

This will cause a division by zero. (1/48) == 0 because C performs integer division when the values are integer.

Why that causes a problem with serial printing, I don't know. I thought it would just print "0".

Try

RPMin = 48 * 60 * pulsos/PPR;

Yes I agree, that is definitely the trigger, but still weird that...

  • If no attempt is made to print the variable it runs ok.
  • If variable is not declared as volatile it runs ok.

An even simpler example

volatile int x = 0;  // If not volatile runs ok.
  
void setup()
{
  Serial.begin(115200);

  Serial.println("Start");
  delay(100);

  float f = x / 0;

  Serial.println("Before");
  delay(100);
  
  Serial.println(f);  // If comment this print runs ok.
  delay(100);
  
  Serial.println("After");
}


void loop()
{}

I'm running on an Uno.

Is it a valid code?

We do divide an integer by 0 by mistake; here, the operation is being done knowingly.

Some processors except the TAmega328P have overflow interrupts to handle such kind of situations.

What result/output is being expected?

I think you have missed the point of this post ?

Divide by zero in the example is not a mistake... what it is trying to demonstrate is the odd behaviour that occurs in this sketch as a result of the invalid divide by zero.

Specifically...

  • Serial.print causes the sketch to freeze.
  • Defining x as volatile cause the sketch to freeze.

Try the sketch above with an Uno.

1 Like

@red_car I repeated your experiment (same results, of course) and did some tinkering.

When you get your version to run, it prints 0.00 as the answer, which is wrong.

By changing the computation to

   float f = x / 0.0;

the code prints nan as the answer, "not a number", which is correct.

Furthermore, there is no need to eliminate the volatile qualifier to get this correct answer and not wire off into the blue somehow.

I do not know what this means.

a7

1 Like

Which Arduino? Which encoder, post datasheet?

This post isn't really about the encoder. The odd behaviour reported in post #6 was run on an Uno (ATMEGA328P).

@red_car:
My post was not aimed at you, I clicked the green reply block at the bottom.
I would like to know which encoder with 20 PPM driven with a DC motor. :face_with_raised_eyebrow:

1 Like

If ISRcounter is not declared as volatile, it is equal to 0.
The compiler might then derive that 0/something is 0.
In this case that is not really the case as something is also zero...
Without Serial.print, the value of ISRcounter is never used. So calculation is simply not implemented ...
And hence no crash.

1 Like

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