When operating the relay and buttons the LCD timer and Serial Print cease working.
I previously used delays and caused the same issue. I thought the solution was in millis and still believe it is. However, clearly my application is not work the way I would like.
I am using Wokwi to help design which has been mostly helpful.
Could you please review the code and provide advice on how to resolve the clock ceasing?
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
unsigned long previousMillis;
const unsigned long interval = 1000; // 1 second
int hours, minutes, seconds;
// Relay Controls
int rt = 1000;
const int RELAY_PIN = 3;
// ON & OFF Time 1
int OnRelayHour = 05;
int OnRelayMin = 00;
int OffRelayHour = 05;
int OffRelayMin = 01;
int x = OffRelayMin - OnRelayMin;
int y = 0;
// Button Int
const int pushbtn1 = 9; // LCD Backlight
const int pushbtn2 = 5; // Manual Relay activation
int btnstate1; // LCD Backlight
int btnstate2; // Manual Relay activation
void setup()
{
Wire.begin();
pinMode(pushbtn1, INPUT); // Green LCD Back light
pinMode(pushbtn2, INPUT); // Blue Manual Relay activation
pinMode(3, OUTPUT); // Manual Relay activation
Serial.begin( 9600);
Serial.setTimeout( 100); // 100ms timeout for serial input
Serial.println( "Set the new time in hh:mm:ss format");
// LCD Code 26 Dec 2022
lcd.init();
lcd.backlight();
lcd.setCursor(1, 0);
}
void loop()
{
// LCD Backlight Button
if(digitalRead(9)==HIGH)
{
lcd.backlight();
}
if(digitalRead(9)==LOW)
{
lcd.noBacklight();
}
// Manual Relay Activation
digitalWrite(3,digitalRead(5));
// Relay on and off time
if(hours == OnRelayHour && minutes == OnRelayMin)
for (y= 0; y <x*60/7; y++)
{
digitalWrite(RELAY_PIN, HIGH);
delay(rt);
digitalWrite(RELAY_PIN, LOW);
delay(rt);
}
{
delay(rt);
digitalWrite(RELAY_PIN, LOW);
}
unsigned long currentMillis = millis();
if( Serial.available() > 0)
{
delay( 100); // wait 100ms to get whole line
int h, a, m, b, s;
h = Serial.parseInt(); // get integer with timeout
a = Serial.read(); // get character, no timeout
m = Serial.parseInt(); // get integer with timeout
b = Serial.read(); // get character, no timeout
s = Serial.parseInt(); // get integer with timeout
if( a == ':' && b == ':') // check for right format
{
hours = constrain( h, 0, 23);
minutes = constrain( m, 0, 59);
seconds = constrain( s, 0, 59);
}
else
{
Serial.println( "New time not accepted");
}
// Clear remaining characters from the serial input buffer.
while( Serial.available() > 0)
{
Serial.read();
}
}
if( currentMillis - previousMillis >= interval)
{
// When previousMillis would be set to currentMillis,
// then a delay in the code would delay the clock.
// When previousMillis is incremented with 1 second,
// then it stays synchronized.
previousMillis += interval; // increment with 1 second
seconds++;
if( seconds >= 60)
{
seconds = 0;
minutes++;
if( minutes >= 60)
{
minutes = 0;
hours++;
if( hours >= 24)
{
hours = 0;
}
}
}
// Update the time to the serial monitor.
// The format is hh:mm:ss.
// For example 09:30:55
if( hours < 10)
Serial.print( "0");
Serial.print( hours);
Serial.print( ":");
if( minutes < 10)
Serial.print( "0");
Serial.print( minutes);
Serial.print( ":");
if( seconds < 10)
Serial.print( "0");
Serial.print( seconds);
Serial.println();
// LCD code
lcd.setCursor(1,1);
if( hours < 10)
lcd.print("0");
lcd.print(hours);
lcd.print(":");
if( minutes < 10)
lcd.print( "0");
lcd.print( minutes);
lcd.print( ":");
if( seconds < 10)
lcd.print( "0");
lcd.print( seconds);
lcd.println();
// Attempt of On Off Code
}
}
Could this unconditional 1 second delay() in loop() be a problem, to say nothing of the multiple 1 second delays in the for loop just before it and the multiple parseInt() calls each with a 100 milisecond timeout ?
Yep. Probably is the issue here. However I want to isolate the 'clock function' from the delay.
Do you have a recommendation on further learning regarding this matter?
I learnt from this example but it wasn't enough for my particular application.
In the Wokwi "Library Manager" tab, you have three libraries for the display. Please use just one. A good library is the hd44780 library (https://github.com/duinoWitchery/hd44780). You don't have to upload the "hd44780" library, it is part of the known libraries, search for the name "hd44780". You also don't have to add the "Wire" library "Library Manager" tab, because the "Wire" library is already included by the Arduino software.
I suggest to print a message to the Serial Monitor in setup(), so you know that the sketch has started.
You don't have to use the 'enum' to make a variable, when you already have created a type of that kind.
This is an extensive example - thank you.
However after reading - I find it difficult to apply to my application setting.
Do you have anything that will help with this?
I uploaded your code into Wokwi as a practical example also.
I have managed to get it working again but had to keep library
LiquidCrystal I2C
in the library manager.
I have also added the start up display as per your recommendation.
However the problem remains when activating the the relay there is a delay and then the shutoff timer does not register within the expect timeframe. Thoughts?
Lastly, I have just realised there is a different code between the Wokwi and the code I have posted. Apologies - I will also fix this.
#include <Wire.h>
#include <hd44780.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
unsigned long previousMillis;
const unsigned long interval = 1000; // 1 second
int hours, minutes, seconds;
// Relay Controls
int rt = 1000;
const int RELAY_PIN = 3;
// ON & OFF Time 1
int OnRelayHour = 05;
int OnRelayMin = 00;
int OffRelayHour = 05;
int OffRelayMin = 01;
int x = OffRelayMin - OnRelayMin;
int y = 0;
// Button Int
const int pushbtn1 = 9; // LCD Backlight
const int pushbtn2 = 5; // Manual Relay activation
int btnstate1; // LCD Backlight
int btnstate2; // Manual Relay activation
void setup()
{
Wire.begin();
pinMode(pushbtn1, INPUT); // Green LCD Back light
pinMode(pushbtn2, INPUT); // Blue Manual Relay activation
pinMode(3, OUTPUT); // Manual Relay activation
Serial.begin( 9600);
Serial.setTimeout( 100); // 100ms timeout for serial input
Serial.println( "Starting...");
// LCD Code 26 Dec 2022
lcd.init();
lcd.backlight();
lcd.setCursor(1, 0);
lcd.print( "Starting...");
delay(1000);
lcd.clear();
}
void loop()
{
// LCD Backlight Button
if(digitalRead(9)==HIGH)
{
lcd.backlight();
}
if(digitalRead(9)==LOW)
{
lcd.noBacklight();
}
// Manual Relay Activation
digitalWrite(3,digitalRead(5));
// Relay on and off time
if(hours == OnRelayHour && minutes == OnRelayMin)
for (y= 0; y <x*60/7; y++)
{
digitalWrite(RELAY_PIN, HIGH);
delay(rt);
digitalWrite(RELAY_PIN, LOW);
delay(rt);
}
{
delay(rt);
digitalWrite(RELAY_PIN, LOW);
}
unsigned long currentMillis = millis();
if( Serial.available() > 0)
{
delay( 100); // wait 100ms to get whole line
int h, a, m, b, s;
h = Serial.parseInt(); // get integer with timeout
a = Serial.read(); // get character, no timeout
m = Serial.parseInt(); // get integer with timeout
b = Serial.read(); // get character, no timeout
s = Serial.parseInt(); // get integer with timeout
if( a == ':' && b == ':') // check for right format
{
hours = constrain( h, 0, 23);
minutes = constrain( m, 0, 59);
seconds = constrain( s, 0, 59);
}
else
{
Serial.println( "New time not accepted");
}
// Clear remaining characters from the serial input buffer.
while( Serial.available() > 0)
{
Serial.read();
}
}
if( currentMillis - previousMillis >= interval)
{
// When previousMillis would be set to currentMillis,
// then a delay in the code would delay the clock.
// When previousMillis is incremented with 1 second,
// then it stays synchronized.
previousMillis += interval; // increment with 1 second
seconds++;
if( seconds >= 60)
{
seconds = 0;
minutes++;
if( minutes >= 60)
{
minutes = 0;
hours++;
if( hours >= 24)
{
hours = 0;
}
}
}
// Update the time to the serial monitor.
// The format is hh:mm:ss.
// For example 09:30:55
if( hours < 10)
Serial.print( "0");
Serial.print( hours);
Serial.print( ":");
if( minutes < 10)
Serial.print( "0");
Serial.print( minutes);
Serial.print( ":");
if( seconds < 10)
Serial.print( "0");
Serial.print( seconds);
Serial.println();
// LCD code
lcd.setCursor(1,1);
if( hours < 10)
lcd.print("0");
lcd.print(hours);
lcd.print(":");
if( minutes < 10)
lcd.print( "0");
lcd.print( minutes);
lcd.print( ":");
if( seconds < 10)
lcd.print( "0");
lcd.print( seconds);
lcd.println();
// Attempt of On Off Code
}
}
This is helpful and I have been able to generate the outcome of this in Wokwi.
However, this does not resolve my issue about having this running and the 'clock' continuing to function at the same time so the Arduino can recognise when to power on and off the relay.
Do you have any suggestions how you might intergrate this into your code?
The "clock" runs all the time and changes the state of the LED every second. Every 10 seconds the relays clicks 5 times, which takes longer than one second, but note that the "clock" keeps running while this happens
unsigned long clockTickTime;
unsigned long relayStartTime;
unsigned long clockPeriod = 1000; //1 second clock period
unsigned long relayPeriod = 500; //relay click period
unsigned long currentTime;
unsigned int secondsCounter;
byte relayCounter;
boolean relayRunning = false;
void setup()
{
Serial.begin(115200);
pinMode(LED_BUILTIN, OUTPUT);
}
void loop()
{
currentTime = millis();
if (currentTime - clockTickTime >= clockPeriod)
{
secondsCounter++;
clockTickTime = currentTime;
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
}
if ((secondsCounter % 10) == 0) //start relay every 10 seconds
{
if (!relayRunning)
{
Serial.println("starting relay");
relayRunning = true;
relayStartTime = currentTime;
relayCounter = 0;
}
}
if (relayRunning)
{
if (currentTime - relayStartTime >= relayPeriod)
{
Serial.println("relay click");
relayStartTime = currentTime;
relayCounter++;
if (relayCounter == 5)
{
relayRunning = false;
Serial.println("stopping relay");
}
}
}
}