1

The code I use probably has a math problem since an Arduino can only count a 16 bit integer. This problem is with the WeekDelay() function. The project is for an Aerogarden. It pumps water into the garden every week from information based on my collected data. It writes on the LCD information like if it is pumping, waiting (it should have the timer here and display on the LCD), and it can show when it is going to pump with a beep warning. After beeping, pumping, and waiting for a few times I run out of information and do a loop and show a warning message, blinking the LCD and pumping a set amount. More specifically WeekDelay() should be a delay for a week. It clears the LCD, Sets the cursor to 0,0 and prints "Waiting one week". It should then have a countdown of 24 hours on the screen and then just how many days it is waiting. It does that through clearing the LCD, Setting the cursor, printing days and waiting.

Because of the glitch it does not display any days even though it should show 7. It displays 04:09:36. Somebody was helping me out and said this:

Ah, it is the integer math interacting with the size of days. 04:09:36 = 43600+960+36 = 14976 which happens to be equal to 7243600 % 32768. See gammon.com.au/forum/?id=12146 and https://wiki.sei.cmu.edu/confluence/display/c/INT35-C.+Use+correct+integer+precisions for what's happening.

This is some cut-down version of my code:

int beeper_pin = 2; //Naming buzzer pin
int resetGarden_pin = 3; //Naming the warning led pin
int pump_pin = 6; //Naming the pump pin
#include <LiquidCrystal_I2C.h> // Driver Library for the LCD Module
LiquidCrystal_I2C lcd(0x27, A4, A5);
void clearLCDLine(int line)
{
 lcd.setCursor(0, line);
 for (int n = 0; n < 20; n++) // 20 indicates symbols in line. For 2x16 LCD write - 16
 {
 lcd.print(" ");
 }
}
void beepWarning() { //Makes beeping a subroutine
 lcd.setCursor(0, 0);
 lcd.print("WARNING");
 delay(100);
 lcd.setCursor(0, 1);
 for (int x = 0; x < 3; x++) {
 lcd.setCursor(0, 1);
 lcd.print("WATER PUMP ACTIVE");
 delay(100);
 clearLCDLine(1);
 lcd.setCursor(0, 1);
 lcd.print("WATER PUMP ACTIVE.");
 delay(100);
 clearLCDLine(1);
 lcd.setCursor(0, 1);
 lcd.print("WATER PUMP ACTIVE..");
 delay(100);
 clearLCDLine(1);
 lcd.setCursor(0, 1);
 lcd.print("WATER PUMP ACTIVE...");
 delay(100);
 clearLCDLine(1);
 }
 lcd.setCursor(0, 1);
 lcd.print("WATER PUMP ACTIVE...");
 for (int x = 0; x < 3; x++) { //Repeats 3 times
 digitalWrite(beeper_pin, HIGH); //Turn on buzzer
 delay(100); //Delay of 400 milliseconds
 digitalWrite(beeper_pin, LOW); //Turns off buzzer
 delay(100); //Delay of 400 milliseconds
 }
}
void SOSWarning() { //Makes SOS a subroutine
 clearLCDLine(1);
 lcd.setCursor(0, 0);
 lcd.print("WPA Reset Aerogarden");
 for (int x = 0; x < 3; x++) { //Repeats 3 times
 for (int d = 0; d < 3; d++) { //Repeats 3 times
 digitalWrite(beeper_pin, HIGH); //Turn on buzzer
 delay(200); //Delay of 400 milliseconds
 digitalWrite(beeper_pin, LOW); //Turns off buzzer
 delay(200); //Delay of 400 milliseconds
 }
 for (int a = 0; a < 3; a++) { //Repeats 3 times
 digitalWrite(beeper_pin, HIGH); //Turn on buzzer
 delay(400); //Delay of 400 milliseconds
 digitalWrite(beeper_pin, LOW); //Turns off buzzer
 delay(400); //Delay of 400 milliseconds
 }
 for (int d = 0; d < 3; d++) { //Repeats 3 times
 digitalWrite(beeper_pin, HIGH); //Turn on buzzer
 delay(200); //Delay of 400 milliseconds
 digitalWrite(beeper_pin, LOW); //Turns off buzzer
 delay(200); //Delay of 400 milliseconds
 }
 delay(500); //Delay of 500 milliseconds
 }
}
void weekDelay() { //Makes waiting for a week a subroutine
 clearLCDLine(1);
 clearLCDLine(0);
 lcd.setCursor(0, 0);
 lcd.print("Waiting One Week");
 unsigned long start = millis();
 unsigned long week_secs = 7 * 24 * 3600;
 unsigned long countdowntime_seconds;
 while (countdowntime_seconds = week_secs - (millis() - start)/1000){
 char buff[80];
 int countdown_day = countdowntime_seconds / 3600 / 24;
 int countdown_hour = (countdowntime_seconds / 3600) % 24;
 int countdown_minute = ((countdowntime_seconds / 60) % 60);
 int countdown_sec = countdowntime_seconds % 60;
 sprintf(buff,"%1d days, %02d:%02d:%02d",
 countdown_day, 
 countdown_hour, 
 countdown_minute,
 countdown_sec
 );
 Serial.print(buff); 
 clearLCDLine(1);
 lcd.setCursor(2, 1);
 lcd.print(buff); 
 delay(1000);
 }
}
void pumpOn() { //Makes turning on the pump a subroutine
 clearLCDLine(1);
 lcd.setCursor(0, 1);
 lcd.print("PUMPING");
 delay(100);
 digitalWrite(pump_pin, HIGH); //Turning on the pump
}
void pumpOff() { //Makes turning off the pump a subroutine
 digitalWrite(pump_pin, LOW); //Turning off the pump
 clearLCDLine(1);
 lcd.setCursor(0, 1);
 lcd.print("WATER PUMP OFF");
 delay(1000);
}
void setup() {
 //run once:
 lcd.backlight();
 lcd.init();
 lcd.setCursor(4, 0);//////////////////////////////////////////////////////
 lcd.print("HH:MM:SS"); //////////////////////////////////////////////////
 lcd.clear(); // Clear the screen
 lcd.setCursor(0, 0);
 lcd.print("Aero_Pump V3");
 delay(1000);
 lcd.setCursor(0, 1);
 lcd.print("By Alex");
 delay(1000);
 pinMode (beeper_pin, OUTPUT); //Setting outputs
 pinMode (resetGarden_pin, OUTPUT); //Setting outputs
 pinMode (pump_pin, OUTPUT); //Setting outputs
 lcd.clear(); // Clear the screen
 digitalWrite(resetGarden_pin, LOW); //Turning off the reset garden light
 beepWarning(); //Beeps a warning
 pumpOn(); //Turns on the pump
 delay(3000); //Adds a delay of 24000 milliseconds
 pumpOff(); //Turns off the pump
 weekDelay(); //Waits a week
 beepWarning(); //Beeps a warning
 pumpOn(); //Turns on the pump
 delay(12000); //Adds a delay of 24000 milliseconds
 pumpOff(); //Turns off the pump
 weekDelay(); //Waits a week
}
void loop() {
 SOSWarning(); //Beeps an SOS warning
 pumpOn(); //Turns on the pump
 delay(48000); //Adds a delay of 48000 milliseconds
 pumpOff(); //Turns off the pump
 for (int x = 0; x < 3024000; x++) {
 lcd.backlight(); // turn on backlight.
 delay(100);
 lcd.noBacklight(); // turn off backlight
 delay(100);
 }
 lcd.backlight(); // turn on backlight.
}

This is the function that needs to be fixed:

void weekDelay() { //Makes waiting for a week a subroutine
 clearLCDLine(1);
 clearLCDLine(0);
 lcd.setCursor(0, 0);
 lcd.print("Waiting One Week");
 unsigned long start = millis();
 unsigned long week_secs = 7 * 24 * 3600;
 unsigned long countdowntime_seconds;
 while (countdowntime_seconds = week_secs - (millis() - start)/1000){
 char buff[80];
 int countdown_day = countdowntime_seconds / 3600 / 24;
 int countdown_hour = (countdowntime_seconds / 3600) % 24;
 int countdown_minute = ((countdowntime_seconds / 60) % 60);
 int countdown_sec = countdowntime_seconds % 60;
 sprintf(buff,"%1d days, %02d:%02d:%02d",
 countdown_day, 
 countdown_hour, 
 countdown_minute,
 countdown_sec
 );
 Serial.print(buff); 
 clearLCDLine(1);
 lcd.setCursor(2, 1);
 lcd.print(buff); 
 delay(1000);
 }
}
asked Dec 14, 2021 at 4:17
1
  • 1
    tip: do lcd.print("WATER PUMP ACTIVE"); ... delay(100); ... lcd.print("."); ... there is no need to clear LCD and print same line over and over Commented Dec 14, 2021 at 4:44

1 Answer 1

1

As the comment already tells, you are trying to calculate a constant with int literals that overflows:

unsigned long week_secs = 7 * 24 * 3600;

This is 604800 (0x93A80), but since ints are just signed 16 bits numbers (with your compiler system), only the lower 16 bits are taken into account. Fortunately these lower 16 bits are positive in two's complement, and so you get 14976 (hex 0x3A80).

The correct statement uses at least one unsigned long value, and the integer promotion rules make sure that all values are converted to that type, too.

unsigned long week_secs = 7UL * 24 * 3600;

answered Dec 14, 2021 at 8:41
1
  • I hope I see you in heaven. Thank you so much. This has taken so long to figure out. Commented Dec 14, 2021 at 13:00

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.