Random problems with my code

Hi, I´m new on arduino world. My first project is take info from sensor added to my car. I´m trying to collect info about oil temperature, oil pressure and fuel pressure and print in an lcd. In addition I have added some alarms, that makes the printed numbers blink.

The problem is that, sometimes the screen is full of estrange characters and stop working fine. Then I have to reset the arduino. I have been searching for the cause but this behaviour is always random.

Here is my code, I hope you could help me understand what is going on. By the way I´m using a arduino mega.

Thanks a lot

#include <Ethernet.h>

#include <Arduino.h>
#include <math.h>
#include <LiquidCrystal_I2C.h>

//Crear el objeto lcd  dirección  0x3F y 16 columnas x 2 filas
LiquidCrystal_I2C lcd(0x27,20,4);  //

int sensorValue;

// These constants won't change. They're used to give names to the pins used:
const int oilPressInPin = A0;  // Sensor de Presion de Aceite
const int oilTempInPin = A1;  // Sensor de Temperatura de Aceite
const int fuelPressInPin = A2;  // Sensor de Presion de Gasolina

//rango presion aceite de 1.4 bar a 7.5 bar
//rango temperatura de 80 a 95 Cº
// rango presion combustible constante 3.5 - 4 bar  
float oilPress,oilTemp,fuelPress,oilPressMax=1,oilPressMin=1,fuelPressMax=1,fuelPressMin=1; 
int oilTempMax=18,oilTempMin=10;
boolean oilTempAlarm = false,oilPressAlarm = false,fuelPressAlarm = false;
uint32_t resistencia;

#define MaxSensorPresionAceite 10340 // miliBares
#define MaxSensorPresionGasolina 6890 // miliBares
// configurar el valor de la resistencia que va en serie con el termistor NTC en ohms
#define CONFIG_THERMISTOR_RESISTOR 3000
#define PAUSE  500
//#define DEBUG 1

/**
 * @brief Obtiene la resistencia del termistor resolviendo el divisor resistivo.
 * 
 * @param adcval Valor medido por el convertidor analógico a digital.
 * @return int32_t Resistencia electrica del termistor.
 */
int32_t thermistor_get_resistance(uint16_t adcval)
{
  // calculamos la resistencia del NTC a partir del valor del ADC
  return (CONFIG_THERMISTOR_RESISTOR * ((1023.0 / adcval) - 1));
}

/**
 * @brief Obtiene la temperatura en grados centigrados a partir de la resistencia
 * actual del componente.
 * 
 * @param resistance Resistencia actual del termistor.
 * @return float Temperatura en grados centigrados.
 */
float thermistor_get_temperature(int32_t resistance)
{
  // variable de almacenamiento temporal, evita realizar varias veces el calculo de log
  float temp;

  // calculamos logaritmo natural, se almacena en variable para varios calculos
  temp = log(resistance);

  // resolvemos la ecuacion de STEINHART-HART
  // http://en.wikipedia.org/wiki/Steinhart–Hart_equation
  temp = 1 / (0.0006114743282473224 + (0.0002559996393842654 * temp) + (-2.2622413719689033e-8 * temp * temp * temp));

  // convertir el resultado de kelvin a centigrados y retornar
  return temp - 273.15;
}
/**
 * clear txt function
 */
void Clear(int type, int col, int row){
  if (type == 0){
    lcd.setCursor(col, row);
    lcd.print("       ");    
  }else if (type == 1){
    lcd.setCursor(col, row);
    lcd.print("       ");  
  }else if (type == 2){
    lcd.setCursor(col, row);
    lcd.print("     ");  
  }
    
}
/**
 * blink txt function
 */
void FlashMessage(int value, int type, int col, int row, int repeat)
{
  char temp[] = "";   // Enough spaces to fill one display line

  lcd.setCursor(col, row);
  if (type == 0){
      lcd.print("OL");lcd.print((char) 223);lcd.print(":");lcd.print(value);
      for (int i = 0; i < repeat; i++) {
        lcd.setCursor(col, row);
        lcd.print("       ");
        delay(PAUSE);
        lcd.setCursor(col, row);
        lcd.print("OL");lcd.print((char) 223);lcd.print(":");lcd.print(value);
        delay(PAUSE);
      }
  }else if (type == 1){
      lcd.print("OLp");lcd.print(":");lcd.print(value);
      for (int i = 0; i < repeat; i++) {
        lcd.setCursor(col, row);
        lcd.print("      ");
        delay(PAUSE);
        lcd.setCursor(col, row);
        lcd.print("OILp");lcd.print(":");lcd.print(value);
        delay(PAUSE);
      }
  }else if (type == 2){
      lcd.print("GAS");lcd.print(":");lcd.print(value);
      for (int i = 0; i < repeat; i++) {
        lcd.setCursor(col, row);
        lcd.print("     ");
        delay(PAUSE);
        lcd.setCursor(col, row);
        lcd.print("GAS");lcd.print(":");lcd.print(value);
        delay(PAUSE);
      }
  }
}

void setup() {
  #ifdef DEBUG
    Serial.begin(9600);
  #endif
  // Inicializar el LCD
  lcd.init();
  //Encender la luz de fondo.
  lcd.backlight();
  // Escribimos el Mensaje en el LCD.
  lcd.print("Mazda Rx8 Sensor Map");
  delay(2000);
  lcd.clear();
}

void loop() {
  
  // Leemos sensor de Presion de Aceite
  sensorValue = analogRead(oilPressInPin);
  // Calculamos la Presion de Aceite
  oilPress = map(sensorValue, 0, 1023, 0, MaxSensorPresionAceite);
  //oilPress = (sensorValue*MaxSensorPresionAceite)/1023;
  // change the analog out value:
  oilPress=oilPress/1000; //mbar ->bar
  if (oilPressMax < oilPress) {oilPressMax = oilPress;}//max oil press
  if (oilPressMin > oilPress) {oilPressMin = oilPress;}//max oil press
  
  if (oilPress >= 5.60 || oilPress <= 2.50) { //alarm
    oilPressAlarm = true;
  }else{
    oilPressAlarm = false;  
  }
  #ifdef DEBUG
    Serial.println("oilPressAlarm: ");
    Serial.println(oilPressAlarm);
    Serial.println(oilPress);
  #endif

  // Leemos sensor de Presion de Gasolina
  sensorValue = analogRead(fuelPressInPin);
  // Calculamos la Presion de Aceite
  fuelPress = map(sensorValue, 0, 1023, 0, MaxSensorPresionGasolina);
  //fuelPress = (sensorValue*MaxSensorPresionGasolina)/1023;
  // change the analog out value:
  fuelPress=fuelPress/1000; //mbar ->bar
  if (fuelPressMax < fuelPress) {fuelPressMax = fuelPress;}//max fuel press
  if (fuelPressMin > fuelPress) {fuelPressMin = fuelPress;}//max fuel press
  
  if (fuelPress > 4.60 || fuelPress <= 3.40 ) { //alarm
    fuelPressAlarm = true;
  }else{
    fuelPressAlarm = false;  
  }
  #ifdef DEBUG
    Serial.println("fuelPressAlarm: ");
    Serial.println(fuelPressAlarm);
    Serial.println(fuelPress);
  #endif

  // Leemos sensor de temperatura de aceite
  // calcular la resistencia electrica del termistor usando la lectura del ADC
  resistencia = thermistor_get_resistance(analogRead(oilTempInPin));
  // luego calcular la temperatura segun dicha resistencia
  oilTemp = thermistor_get_temperature(resistencia);
  if (oilTempMax < oilTemp) {oilTempMax = round(oilTemp);}//max oil temp
  if (oilTempMin > oilTemp) {oilTempMin = round(oilTemp);}//max oil temp
  
  if (oilTemp >= 101 || oilTemp < 10 ) { //alarm
    oilTempAlarm = true;
  }else{
    oilTempAlarm = false;  
  }
  #ifdef DEBUG
    Serial.println("oilTempAlarm: ");
    Serial.println(oilTempAlarm);
    Serial.println(oilTemp);
  #endif
  
 //mostramos las lecturas en pantalla
 
  lcd.setCursor(0, 0);
  lcd.print("OIL");lcd.print((char) 223);lcd.print(":");
  lcd.print((float)oilTemp,1);
  //lcd.print(oilTemp);
  lcd.print(" M:");
  lcd.print(oilTempMax);
  lcd.print(" m:");
  lcd.print(oilTempMin);
  

  lcd.setCursor(0, 1);
  lcd.print("OILp");lcd.print(":");
  lcd.print((float)oilPress,1);
  lcd.print(" M:");
  lcd.print((float)oilPressMax,1);
  lcd.print(" m:");
  lcd.print((float)oilPressMin,1);
 

  lcd.setCursor(0, 2);
  lcd.print("GAS");lcd.print(":");
  lcd.print(fuelPress);
  lcd.print(" M:");
  lcd.print((float)fuelPressMax,1);
  lcd.print(" m:");
  lcd.print((float)fuelPressMin,1);
  

  if (oilTempAlarm){
    FlashMessage(round(oilTemp), 0, 0, 3, 5);
    #ifdef DEBUG
      Serial.println("Entra en pintar alarma oil temp");
    #endif
  }else{
    Clear(0, 0, 3);
    #ifdef DEBUG
      Serial.println("Elimina alarma oil");
    #endif
  }
   if (oilPressAlarm){
    FlashMessage(round(oilPress), 1, 8, 3, 5);
    #ifdef DEBUG
      Serial.println("Entra en pintar alarma oil press");
    #endif
  }else{
    Clear(1, 8, 3);
    #ifdef DEBUG
      Serial.println("Elimina alarma oil press");
    #endif
  }
  if (fuelPressAlarm){
    FlashMessage(round(fuelPress), 2, 15, 3, 5);
    #ifdef DEBUG
      Serial.println("Entra en pintar alarma fuel");
    #endif
  }else{
    Clear(2, 15, 3);
    #ifdef DEBUG
      Serial.println("Elimina alarma fuel");
    #endif
  }

  // wait 2 milliseconds before the next loop for the analog-to-digital
  // converter to settle after the last reading:
  delay(7500);
  //delay(1000);
}

your problem may well be hardware related. Do you have a schematic to show us?

did you add pullups to the I2C lines?
how is your arduino powered and shielded from the engine?

I only have this right now. But the schema is pretty simple. The only thing different is that I have to use a 3000 ohm combined with the temperature sensor. And lcd is connected following the instructions of the manufacturer.

oilPressureSensor : A0 and Ground
fuelPressureSensor: A2 and Ground
oilTemperatureSensor: A1 + 3000 resistor and Ground

May not be your issue, but you're nearing the limits of the regulator on the Uno. They're not really intended to power external devices, like your LCD. What's your input voltage? We can't see much from that photo, do you have an external supply plugged into the black power jack, or are you running off of USB power?

did you add pullups to the I2C lines?

No, I didn´t know that it was necessary

how is your arduino powered and shielded from the engine?

It is powered from the lighter plug (12V) and It is not shielded from the engine.

I am newbie, but I understand that maybe I have any kind of interference coming from the engine.

I´m using a usb female plug that is powered from the lighter plug wires.

usually it's not but I've had issues with some boards

I will try to take a photo of the complete setup install on the car.

Please tell me I'm misunderstanding - You're wiring 12V from the lighter into your USB port on your Arduino?

I would not be surprised if the 1602LCD + I2C backpack is not being affected by stray electric noise. Some backpacks are terminated on I2C line, some not.

Arduino I2C LCD Backpack Introductory Tutorial (electroschematics.com)

I suggest you use a quality DC-DC switching "buck" board to drop the 12V to 5V and put your prototype into an aluminum project box.

Review:
arduino - How to shield for electromagnetic interference (DIY level)? - Electrical Engineering Stack Exchange

More:
eliminate EMI noise + Arduino + Automotive at DuckDuckGo

These Lcd 1602/2004 type displays are prone to electrical interference effects because they do not recover themselves if there has been a glitch. The "weird" character effect is caused by a synchronisation error in the data stream to the display. 8 bit bytes to the display are usually sent as a pair of 4 bit nibbles and, in an error case, the wrong nibbles get joined together causing a corrupt display. Reissuing the "lcd.init()" command periodically can help but the best solution, as already mentioned, is to eliminate the sources of interference.

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