Arduino Mega unresponsive (after turning off LCD backlight with IF statement)

I am building a battery voltage monitor for my travel trailer. The monitor will sound an alarm when the battery voltage drops below 11v, letting me know that I need to start the generator and charge the battery. (I may eventually auto-start the generator when needed, but that would be a second phase...)

Because the Arduino (which is a Mega, BTW) will be powered from the battery that I am monitoring (and am trying to reduce my re-charge cycles), I'm trying to turn off the LCD when not needed in order to conserve power. I have a momentary button that, when pressed, will turn the LCD backlight on for 5 seconds to show the battery voltage and then turn the LCD backlight back off.

The code below works as expected, except that the display will turn on once when the button is pressed (and turns off as expected) before becoming unresponsive. The alarm functions as expected before the LCD turns on and also while the LCD is on. As soon as the LCD turns off (which happens in the "if (lcdStatus == 1)" loop), the alarm stops working and the LCD will not turn back on a second time. It appears to be "stuck" or "unresponsive" or "crashed".

I suspect that one of the following is happening:

  1. I am getting stuck in the "if (lcdStatus == 1)" loop (which makes no sense)
  2. The Arduino is crashing after the "if (lcdStatus == 1)" loop (which I also don't understand).

I also searched to see if there was something in the "LiquidCrystal_I2C" library that would gracefully shut off the LCD, but didn't see anything. The LCD is a 20x4 with an 4-wire I2C backpack.

I am struggling with what's going on. Does anyone have any ideas?

Thanks in advance!

  • Chip
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <SPI.h>
 
#define BACKLIGHT_PIN     13
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address -- NEW LCD

//DEFINE VARIABLES

  // Switches
    int switch1Ground = 8;        // Set Internal Pullup Resistor for Buttons
    const byte buttonOne = 9;
    int switch2Ground = 10;        // Set Internal Pullup Resistor for Buttons
    const byte buttonTwo = 11;

  // Voltage Sensor(s)
    int analogInput = A0; // voltage sensor input
    int sensorGround = A7;
    float svalue = 0; //do not change
    float Bat1 = 0;  // Voltage for Battery #1;

  // Alarm
    int alarmPos = 6;  //Will likely feed the alarm directly (not through the arduino)
    int alarmTrig = 7;  //alarm signal pin
    unsigned long AlarmStart;  //Time current alarm sounds
    unsigned long AlarmLast;  //Time of last alarm
    int Valarm = 11;  //Low voltage arlarm trigger

 //Smoothing
    const int numReadings = 25;
    int readings[numReadings];      // the readings from the analog input
    int readIndex = 0;              // the index of the current reading
    float total = 0;                  // the running total
    float average = 0;                // the average

  //LCD Switching
    unsigned long lcdOn;
    int lcdStatus = 0;


void setup()
{
// initialize alarm/buzzer
  pinMode(alarmPos, OUTPUT); 
  digitalWrite(alarmPos, LOW);
  pinMode(alarmTrig, OUTPUT);
  digitalWrite(alarmTrig, LOW);

// initialize voltage sensor
  pinMode(analogInput, INPUT);
  pinMode (sensorGround, OUTPUT);
  digitalWrite(sensorGround, LOW);  
  
// initialize lcd
  pinMode ( BACKLIGHT_PIN, OUTPUT);
  digitalWrite ( BACKLIGHT_PIN, LOW);
  //lcd.begin(20,4);                          //uncomment this line when switching BACKLIGHT_PIN to HIGH (to have LCD on my default)

// Assign pinmodes for buttons
  pinMode (switch1Ground, OUTPUT);
  digitalWrite(switch1Ground, LOW);                  //Set switchGround to "Ground"
  pinMode (buttonOne, INPUT_PULLUP);  
  pinMode (switch2Ground, OUTPUT);
  digitalWrite(switch2Ground, LOW);                  //Set switchGround to "Ground"
  pinMode (buttonTwo, INPUT_PULLUP); 


// Initialize Smoothing
  for (int thisReading = 0; thisReading < numReadings; thisReading++) {
    readings[thisReading] = 0;
  }
}

void loop()
{

// Check for button press   
    if (digitalRead (buttonOne) == LOW)          // check to see if button is pressed
       {digitalWrite (BACKLIGHT_PIN, HIGH);      // turn on LCD
       lcd.begin(20,4);                          // initialize LCD
       lcdOn = millis();                         // start timer
       lcdStatus = 1;                            // change status to "1" (used for turning it back off)
       delay (200);                              // Debounce button presses
       }
    if (lcdStatus == 1)                          // Check to see if the LCD is currently on
      {if (millis() > (lcdOn + 5000))            // Check to see if the LCD has been on for > 5000ms
      {digitalWrite (BACKLIGHT_PIN, LOW);        // Turn LCD off 
       lcdStatus = 0;                            // Set status back to "0" so that it won't re-enter this loop 
      }
      }
    
// Read voltage from sensor, add to array
    total = total - readings[readIndex];  // subtract the last reading
    readings[readIndex] = analogRead(analogInput);// read from the sensor
    total = total + readings[readIndex];// add the reading to the total
    readIndex = readIndex + 1;// advance to the next position in the array
    if (readIndex >= numReadings) {  // if we're at the end of the array...
      readIndex = 0;// ...wrap around to the beginning:
  }
    average = total / numReadings;// calculate the average

// Convert sensor reading to voltage
  Bat1 = ((0.0237*average)+0.2727);
 
//PRINT TO LCD:
//Print sensor values:  
  lcd.setCursor(0,0);               // (Horizontal, Vertical)
  lcd.print("Battery 1: ");
  lcd.setCursor(11,0);              // clear previous value
  lcd.print("     ");               // clear previous value
  lcd.setCursor(11,0);
  lcd.print(Bat1,1);

// ALARM
  if (Bat1 < Valarm){
   AlarmStart = millis();
   if (AlarmStart >= (AlarmLast + 5000)){
     digitalWrite(alarmPos, HIGH);
     tone(alarmTrig, 2000, 500);                  // sound alarm (frequency, duration(ms))
     AlarmLast = millis();   
   }  
   if (millis() >= (AlarmLast + 500)){          // leave buzzer + on long enough for alarm to complete
     digitalWrite(alarmPos, LOW);
   }
  }
}

Add some debugging using Serial.println so you can see what it's doing.

I don't like the idea of running lcd.begin repeatedly, but I wouldn't expect that to cause your symptoms.

What are you controlling with BACKLIGHT_PIN?

The initialization of the LCD implies that the backlight is controlled through the LiquidCrystal_I2C library.

I think the others found the problem, but there are more problems.

wildbill:
I don't like the idea of running lcd.begin repeatedly

Use lcd.begin() only in the setup() function.

david_2018:
What are you controlling with BACKLIGHT_PIN?
The initialization of the LCD implies that the backlight is controlled through the LiquidCrystal_I2C library.

That seems to be the problem. Are you trying to turn on and off the complete LCD display with a output pin of the Arduino board ? That makes no sense, the Arduino Mega 2560 board requires more current than the display. Only the backlight requires more current. Can you show us a schematic and a photo ?

The Arduino Mega 2560 and the LCD display need 5.0V. Both start to have problems with 4.5V or lower. Can you measure the voltage of the 5V pin of the Arduino and the 5V of the display ?

The use of millis() is wrong. That will become a problem after 50 days.
Never add a value to something that has to do with millis().
I have an example for a single shot timer.