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:
- I am getting stuck in the "if (lcdStatus == 1)" loop (which makes no sense)
- 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);
}
}
}