Arduino loop function stops working after 290 milliseconds

I have the following code, where I'm reading interruptions from an encoder and summing them, then everytime 300 ms have passed, I calculate the frequency of the motor. I also print all of that in an LCD. The problem is that it appears the code never runs beyond the 300 ms.

#include <LiquidCrystal.h>

// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 12, en = 11, d4 = 7, d5 = 6, d6 = 5, d7 = 4;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

#define encoderA 2
#define encoderB 3

const int potPin = A0;
float valor, Vmedida;
const float volt_ref = 4.93;
long oldPosition  = -999;
long newPosition;
long ticks = 0;
const int periodo = 300;  // tiempo de muestreo (ms)
int tiempoActual = 0;
float freqEncoder;
long listaEncoder[5000];
long listaHall[5000];
long contador = 0;


byte mas_menos[8] = {
  B00100,
  B00100,
  B11111,
  B00100,
  B00100,
  B00000,
  B11111,
};

byte ohms[8] = {
  B00000,
  B01110,
  B10001,
  B10001,
  B10001,
  B01010,
  B11011,
};

void setup() {
  Serial.begin(115200);

  lcd.createChar(0, mas_menos);
  lcd.createChar(1, ohms);
  lcd.begin(16, 2);
  
  pinMode(encoderA, INPUT);
  pinMode(encoderB, INPUT);
  attachInterrupt(digitalPinToInterrupt(encoderB), sumarTicks, RISING);
}

void loop() {
  /*
  if (digitalRead(encoderA) == 1) {
    ticks++;
  }
  */

  Serial.println(millis());

  if (millis()-tiempoActual >= periodo) {
    valor = analogRead(potPin);
    Vmedida = valor/1024.0*volt_ref;
    
    freqEncoder = ticks/(periodo/1000/60)/14;   // Convierto periodo (ms) a minutos, calculo ticks por minuto y divido entre 14 ticks por revolucion, asi obtengo rev/min
    listaEncoder[contador];

    mostrarLCD(freqEncoder, Vmedida);    
    Serial.print("Frecuencia del encoder: "); Serial.println(freqEncoder); 
    Serial.print("Resistencia: ("); Serial.print(Vmedida); Serial.print(" +- "); 
    //Serial.print(incertidumbre); 
    Serial.println(") Ohms");
    
    contador++;
    ticks = 0;
    lcd.clear();
    tiempoActual = millis();
  }

}

void mostrarLCD(float freqEncoder, float Vmedida) {   // agregar incertidumbre como parámetro cuando se tenga
  lcd.setCursor(0, 0);
  lcd.print("Ticks: ");
  lcd.print(ticks);
  lcd.setCursor(0, 1);
  lcd.print("Resistencia: ");
  lcd.print("(");
  lcd.print(Vmedida);
  lcd.print(" ");
  lcd.write(byte(0));
  lcd.print(" ");
  //lcd.print(incertidumbre);
  lcd.print(") ");
  lcd.write(byte(1));
}

void sumarTicks() {
  ticks++;
}

As you can see, I print millis() on the Serial monitor to see what's happening and it only prints until 293 and the program stops completely.
I tried not using interrupts and just manually summing every time the digital pin is detected as high, but the same happens.

Welcome to the forum

tiempoActual is declared as a signed integer. What is the largest positive value that it can hold ? What will happen to this comparison

    if (millis() - tiempoActual >= periodo)

when the value of tiempoActual goes negative as a result of

        tiempoActual = millis();

when millis() exceeds the maximum positive value that a signed int can hold ?

Consider using a variable type that can hold a much larger unsigned value as returned by millis()

4 Likes

I didn't think that tiempoActual could be negative, so thank you for that, however, I did the following redefinition of variables:

#define encoderA 2
#define encoderB 3
#define potPin A0

float valor, Vmedida;
const float volt_ref = 4.93;
unsigned int ticks = 0;
const int periodo = 300;  // tiempo de muestreo (ms)
unsigned long tiempoActual = 0;
float freqEncoder;
float listaEncoder[5000];
float listaHall[5000];
unsigned long contador = 0;

and it's still stuck on 293 ms. It doesn't ever get into the if statement.

There are obviously still problems but you have taken a step in the right direction by eliminating future problems

I am short of time but will look at your revised sketch later if I have time

1 Like

There is something wrong with this line

        freqEncoder = ticks / (periodo / 1000 / 60) / 14;  // Convierto periodo (ms) a minutos, calculo ticks por minuto y divido entre 14 ticks por revolucion, asi obtengo rev/min

Out of interest, comment it out. Does the code run without stopping ?

2 Likes

How did you spot that there was something wrong with that line? I commented it and it worked, then tested until finally with this change it worked:

freqEncoder = float(ticks) / (float(periodo) / 60000 ) / 14;

It's weird to me that there was no error displayed, it just didn't work.

I could pretend that it was my many years of experience coding in C++ that led me to the problem with that line, but in fact all I did was to comment out most of the code and add it back line by line until it failed

I do not know exactly what the problem was and don't have time to look at it further

unsigned int ticks = 0;
const int periodo = 300;
//some code
freqEncoder = ticks / (periodo / 1000 / 60) / 14;

(300/1000/60)/14
you've forced a particular evaluation order with the ( ).
It will always evaluate to 0, as they're all integers. In fact, the compiler probably will evaluate this part of the expression, decide it never changes, and insert 0.

So you divide by 0.
Oops.
Turn up the compiler warnings in Preferences - you may be being told about this, haven't time to try it.

IMHO the problem resides in automatic casting (data conversion) resulting in wrong values.
When you do:

freqEncoder = ticks / (periodo / 1000 / 60) / 14;

this expression is evaluated from top to bottom, so the first executed operation will be "periodo / 1000". The problem is it's always zero because both "periodo" and "1000" are integers, so 300/1000 is an integer operation that gives zero. You can test it by printing that result (instead of the original line):

  Serial.print(periodo / 1000); // prints 0

Do the same with the ".0" and see the difference:

  Serial.print(periodo / 1000.0); // prints 0.30

This causes a waterfall effect: you divide zero by 60 -still gives zero-, and lastly when dividing "ticks" per zero it will lock everything up (Arduino doesn't have any kind of "error try-catch" so a division by zero is not handled and locks in panic).
So you just need to force that first division to be a float:

freqEncoder = = ticks / (periodo / 1000.0 / 60) / 14;

With this syntax "periodo /1000.0" is a division between integer and a float, so the result will be float, and going on with floats till the end of the expression.
Anyway, when dealing with floats, I'm used to often explicitly input types/casts over all constants, to avoid any "bad partial" expression evaluation:

freqEncoder = = ticks / (periodo / 1000.0 / 60.0) / 14.0;

HTH

1 Like

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