What is causing my program to spam even though it was working fine in previous iterations?

Hello!

This is my first time reaching out to an online community about coding help. I hope I'm doing everything correctly, but let me know if I need to fix anything.

I'm trying to make an automatic plant waterer. There are 3 phases of my code: initialization, checkMoisture / determining if water is needed, and waitBeforeNextScan() method/wait until the next read cycle. Initialization will find the initial state of the water and find the average. Then the checkMoisture method should take values from the water sensor, find an average over 3 seconds, and check whether the plant needs water by seeing if the average water value is too low from the initial average found in the initialization phase. The waitBeforeNextScan() method should simply wait 5 seconds then allow the checkMoisture method to run again. This cycle should continue on forever.

Right now I’m facing an issue that causes the program to spam/repeat without waiting between the checkMoisture method and the waitBeforeNextScan method. The serial print statements look fine and all in order but I think there may be a timing or even a memory problem that causes this issue. I tried changing/printing the values of the time to wait and the boolean values that control what phase of code is running but I can't figure it out. There aren't any error messages that are posted when I compile and run the program.

I am using an ARDUINO UNO R3 - SMD, a Songhe Rain Water Level Sensor, and an Arducam 1602 16x2 LCD Display.

Thank you for anyone reading all this and for helping me out. I appreciate it a lot!

#include <Array.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Stepper.h>

int waterInputPin = A0;
int buttonInputPin = 9;

LiquidCrystal_I2C lcd (0x27, 16, 2);

int start;
int waterVal = 0;
int eventInterval = 1000;

const int totalScanLength = 3;
int highestAverageMoisture[totalScanLength];
int averageSum = 0;
int arrayLength = sizeof(highestAverageMoisture) / sizeof(highestAverageMoisture[0]);

int timeTillNextScan = 5; 
bool wait = false;
bool shouldScan = false;

int initialSetupStep = 0;
int arrayIndex = 0;
int timePassed = 0;

int fullSaturation = 0;
int threeFourthSaturation = 0;
int halfSaturation = 0;
int dryBoi = 0;

// LEDs for testing spammingIssue
int leftLED = 11;
int middleLED = 12;
int rightLED = 13;

void setup() 
{
    pinMode(leftLED, OUTPUT);
    pinMode(middleLED, OUTPUT);
    pinMode(rightLED, OUTPUT);

    Serial.begin(9600);
    lcd.begin(16, 2);
    lcd.backlight();
    lcd.setCursor(0, 0);
    lcd.print("Hello There!");
    Serial.println("--------------");
    Serial.println("Starting System");
   
} // end of setup

void loop()
{
    waterVal = analogRead(waterInputPin);
   
    initialSetup();
    
    checkMoisture();
    
    waitBeforeNextScan();
}

void checkMoisture()
{
   if(millis() - start >= eventInterval && timePassed < totalScanLength && shouldScan)
   {
      digitalWrite(leftLED, LOW);
      digitalWrite(middleLED, HIGH);
      digitalWrite(rightLED, LOW);

      // this will pass data from water sensor into array
      // if time is almost up we will continue getting the values
      // when time is up we will get the final value in the else statement
      if(timePassed < totalScanLength - 1)
      {
         timePassed++;
         
          highestAverageMoisture[arrayIndex] = waterVal;
          Serial.println(highestAverageMoisture[arrayIndex]);
          arrayIndex++;
          
          start = millis();
      }else
      {
        highestAverageMoisture[arrayIndex] = waterVal;
        Serial.println(highestAverageMoisture[arrayIndex]);

        // find average of moisture
        for(int x = 0; x < arrayLength; x++)
        {
            averageSum += highestAverageMoisture[x];
        }
        
        Serial.print("Average : ");
        Serial.println(averageSum / arrayLength);

        // determine if water is needed
        if ((averageSum / arrayLength) <= halfSaturation)
        {
          Serial.println("Needs water");
          
        }else
        {
          Serial.println("Still moist");
        }
        
         clearArray();
        
        // settings for next method
        timePassed = 0;
        shouldScan = false;
        wait = true;

        start = millis();
      }
   }
}

void waitBeforeNextScan()
{
   if(millis() - start >= eventInterval && timePassed < timeTillNextScan && wait)
   {
      digitalWrite(middleLED, LOW);
      digitalWrite(rightLED, HIGH);

      // this will pass data from water sensor into array
      // if time is almost up we will continue getting the values
      // when time is up we will get the final value in the else statement
      if(timePassed < timeTillNextScan - 1)
      {
        timePassed++;
        Serial.println(timePassed);
        start = millis();
        
      }else   
      {
        
        timePassed++;
        Serial.println(timePassed);
        
        // settings for next method
        shouldScan = true;
        wait = false;
        timePassed = 0;  
        Serial.println("Wait Complete");
        start = millis();
      }
   }
}

void createLevelsOfMoisture(int average)
{
    fullSaturation = average;
    threeFourthSaturation = average * 0.75;
    halfSaturation = average / 2;
    dryBoi = average / 5;    

    // values for next phase
    timePassed = 0; 
    shouldScan = true;
    start = millis();
    
}

int initialSetup()
{
  if(digitalRead(buttonInputPin) == HIGH && initialSetupStep == 0)
  {
    digitalWrite(leftLED, HIGH);

    while(digitalRead(buttonInputPin) == HIGH) {}
    Serial.println("Placed in soil");
    initialSetupStep++;
    start = millis();
    
  }
  
  //long currentTime = millis();
  // every second, for totalScanLength : get moisture of water
  if(millis() - start >= eventInterval && timePassed < totalScanLength && initialSetupStep == 1)
  {
     digitalWrite(leftLED, HIGH);
      
     // this will pass data from water sensor into array
     // if time is almost up we will continue getting the values
     // when time is up we will get the final value in the else statement
     
     if(timePassed < totalScanLength - 1)
     {
        Serial.println(waterVal);
        highestAverageMoisture[arrayIndex] = waterVal;
        arrayIndex++;
     
        start = millis();  
        timePassed++; 
     } else {
        // get the last value
        Serial.println(waterVal);
        highestAverageMoisture[arrayIndex] = waterVal;
        arrayIndex++;
        start = millis();  
        timePassed++; 
        // move onto next part of code: finding average
        initialSetupStep++;
        
     }
  }

   // if scan is complete. find average
  if(initialSetupStep == 2)
  {

    digitalWrite(leftLED, HIGH);

    Serial.println("Find average");
    for(int x = 0; x < arrayLength; x++)
    {
         averageSum += highestAverageMoisture[x];
    }
    
    Serial.print("Average : ");
    Serial.println(averageSum / arrayLength);
    createLevelsOfMoisture(averageSum / arrayLength);
    
    clearArray();
    
    initialSetupStep++;
    
  }
}// end of initialWaterReading

void  clearArray()
{
    for(int x = 0; x < arrayLength; x++)
    {
      highestAverageMoisture[x] = 0;
    }
    
    averageSum = 0;
    arrayIndex = 0;
    
    Serial.println("array cleared");
     
}

does this make sense?

Trigger the check moisture to only do the thing if shouldscan is true, is something to try.

if(millis() - start >= eventInterval && timePassed < timeTillNextScan && wait)

millis() - start >= eventInterval

true if time is elapsed

timePassed < timeTillNextScan

true when time is not elapsed

start should be unsigned long, not int. millis() returns an unsigned long.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Stepper.h> //?????????????????????

LiquidCrystal_I2C lcd (0x27, 16, 2);

#define waterInputPin  A0
#define  buttonInputPin  9
// LEDs for testing spammingIssue
#define  leftLED  11
#define  middleLED  12
#define  rightLED  13

#define totalScans  3
const int eventInterval = 5000;

int fullSaturation = 0;
int threeFourthSaturation = 0;
int halfSaturation = 0;
int dryBoi = 0;


void setup() {
  pinMode(leftLED, OUTPUT);
  pinMode(middleLED, OUTPUT);
  pinMode(rightLED, OUTPUT);
  Serial.begin(9600);
  lcd.begin(16, 2);
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("Hello There!");
  Serial.println("--------------");
  Serial.println("Starting System");
  digitalWrite(leftLED, HIGH);
  Serial.println("Placed in soil");
  int averageSum = 0;
  int value = 0;
  int highestMoisture = 0;
  for (byte x = 0; x < totalScans; x++)      {
    value = analogRead(waterInputPin);
    Serial.println(value);
    if (highestMoisture < value)highestMoisture = value;
    averageSum += value;
    delay(eventInterval);
  }
  Serial.print("highest Moisture : ");  Serial.println(highestMoisture);
  int average = averageSum / totalScans;
  Serial.print("Average : ");  Serial.println(average);
  fullSaturation = average;
  threeFourthSaturation = average * 0.75;
  halfSaturation = average / 2;
  dryBoi = average / 5;
  digitalWrite(leftLED, LOW);
} // end of setup

void loop() {
  checkMoisture();
  waitBeforeNextScan();
}

byte checkMoisture() {
  digitalWrite(middleLED, HIGH);
  if (analogRead(waterInputPin) <= halfSaturation) Serial.println("Needs water");
  else Serial.println("Still moist");
  digitalWrite(middleLED, LOW);
}

void waitBeforeNextScan() {
  digitalWrite(rightLED, HIGH);
  uint32_t startTime = millis();
  bool x = true;
  while (x) {
    uint32_t check = millis() - startTime;
    if ((check % 1000) == 0) {
      Serial.print("Elapsed seconds: ");
      Serial.println(check / 1000);
    }
    if (check >= eventInterval)x = false;
  }
  Serial.println("Wait Complete");
  digitalWrite(rightLED, LOW);
}


millis() sometimes counts by 2 instead of 1 so "check == eventInterval" may never be true. Try "check >= eventInterval".

Try this to avoid reporting the same "Elapsed seconds:" more than once:

void waitBeforeNextScan()
{
  digitalWrite(rightLED, HIGH);
  uint32_t startTime = millis();
  int elapsedSecondCount = 0;

  uint32_t elapsedTime;
  do
  {
    elapsedTime = millis() - startTime;
    int elapsedSecond = elapsedTime / 1000;

    if (elapsedSecond > elapsedSecondCount)
    {
      Serial.print("Elapsed seconds: ");
      Serial.println(elapsedSecond);
      elapsedSecondCount = elapsedSecond;
    }
  }
  while (elapsedTime < eventInterval);

  Serial.println("Wait Complete");
  digitalWrite(rightLED, LOW);
}

of course. thy. I was stunned by monstrosity of original program and it was late night.

Thanks for this! You really helped reduce the code and make it more readable!

This also worked like a charm, thank you!

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