0

Hello I want to exit a function if conditions are meet .

I have this code inside the loop()

if (t.hour == 7 && t.min == 16) {
  if(moistureOneSensorValue >= 700 ){
     RelayOne();
  }
}

If its true it will call the RelayOne() function and open the solenoid valve inside the relayOne() fucntion i have also code for waterflow sensor

below is the relayOne function code for opening the valve and getting data from waterflow

 void RelayOne(){


//Serial.println("Valve Open");  
digitalWrite(RELAY1, 0); //OPEN VALVE
digitalWrite(WATERFLOW1, HIGH);//READY WATER FLOW FOR SENSING
//WATER FLOW 

if((millis() - oldTime) > 1000)    // Only process counters once per second
  { 
    // Disable the interrupt while calculating flow rate and sending the value to
    // the host
    detachInterrupt(sensorInterrupt);

    // Because this loop may not complete in exactly 1 second intervals we calculate
    // the number of milliseconds that have passed since the last execution and use
    // that to scale the output. We also apply the calibrationFactor to scale the output
    // based on the number of pulses per second per units of measure (litres/minute in
    // this case) coming from the sensor.

    flowRate = ((1000.0 / (millis() - oldTime)) * pulseCount) / calibrationFactor;

    //Serial.print(pulseCount);

    // Note the time this processing pass was executed. Note that because we've
    // disabled interrupts the millis() function won't actually be incrementing right
    // at this point, but it will still return the value it was set to just before
    // interrupts went away.

    oldTime = millis();

   //  Serial.print("::");
    // Serial.print(oldTime);
    // Divide the flow rate in litres/minute by 60 to determine how many litres have
    // passed through the sensor in this 1 second interval, then multiply by 1000 to
    // convert to millilitres.

    flowMilliLitres = (flowRate / 60) * 1000;

    // Serial.print(flowMilliLitres);
    // Add the millilitres passed in this second to the cumulative total

    totalMilliLitres += flowMilliLitres;

    unsigned int frac;

    // Print the cumulative total of litres flowed since starting
    Serial.print("  Output Liquid Quantity: ");             // Output separator
    Serial.print(totalMilliLitres);
    Serial.println("mL"); 

    //setPointForN1 = EEPROM.get(0, WATEREQFORN1) / 2;

   if(totalMilliLitres >= setPointForN1 ){
       closeSolenoidValve();

      }

     // Reset the pulse counter so we can start incrementing again
    pulseCount = 0;


    // Enable the interrupt again now that we've finished sending output
    attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
  }



  if(flowMilliLitres == 0){
     totalMilliLitres = 0;
  }


}

this line of code will supposedly close the valve but its not working

`if(totalMilliLitres >= setPointForN1 ){
           closeSolenoidValve();

          }`

the problem is that it will wait for 1 minute before closing the valve even tho the set point already reach .

Below is My full code

#include <EEPROM.h>


#include <TimeAlarms.h>
#include <Wire.h>
#include <dht.h>
#include <DS3231.h>

// Init the DS3231 using the hardware interface
DS3231  rtc(SDA, SCL);
//RTC_DS1307 rtc;

Time  t;

dht DHT;


//PINS
#define MOISTURE1 A15
#define MOISTURE2 A14

#define RELAY1 7
#define RELAY2 6
#define ALARM 13
#define DHT11_PIN A11


int relayState1 = 1;
int relayState2 = 1;
//WATER FLOW VARIABLES


byte sensorInterrupt = 0;  // 0 = digital pin 2
byte sensorInterrupt2 = 1;  // 0 = digital pin 3
byte  WATERFLOW1 = 2;
byte  WATERFLOW2 = 3;

// The hall-effect flow sensor outputs approximately 4.5 pulses per second per
// litre/minute of flow.
float calibrationFactor = 4.5;

volatile byte pulseCount;  
volatile byte pulseCount2;
//For Waterflow sensor pin 13
float flowRate;
float frac;
unsigned int flowMilliLitres;
unsigned long totalMilliLitres;

//For Waterflow sensor pin 12
float flowRate2;
float frac2;
unsigned int flowMilliLitres2;
unsigned long totalMilliLitres2;


unsigned long setPointForN1;
unsigned long setPointForN2;


unsigned long oldTime;

unsigned long oldTime2;

///END OF WATER FLOW VARIABLES

unsigned int val;
int DELAYNI = 1000;


//Sensor Variables

int  moistureOneSensorValue;
int  moistureTwoSensorValue;
int  waterLevelSensorValue;
int  humiditySensorValue;
int  tempSensorValue;

//FOR EEPROM
unsigned int WATEREQFORN1;
unsigned int WATEREQFORN2;
unsigned long DELAYINTERVALOFDATA;
unsigned long prevMillis = 0;

unsigned long interval;


// -------------------------------------------------------------------
// SETUP    SETUP    SETUP    SETUP    SETUP    SETUP    SETUP    SETUP
// -------------------------------------------------------------------

void setup() {

  // put your setup code here, to run once:

  // Setup Serial connection
  Serial.begin(9600);
  rtc.begin();
  Wire.begin();

   //EEPROM

  //int eepromSize=EEPROM.length();
  //Serial.print("EEPROM found, size=");
 // Serial.println(eepromSize);
    // Get the last fade value (as an integer)
  //EEPROM.get(0, WATEREQFORN1);
  //Serial.print("Last Value N1: ");
 // Serial.println(WATEREQFORN1);

 // EEPROM.get(3, WATEREQFORN2);
 // Serial.print("Last Value N2: ");
 // Serial.println(WATEREQFORN2);


pinMode(MOISTURE1, INPUT);
pinMode(MOISTURE2, INPUT);
pinMode(WATERFLOW1, INPUT);
pinMode(WATERFLOW2, INPUT);
pinMode(DHT11_PIN, INPUT);  
pinMode(RELAY1, OUTPUT);
pinMode(RELAY2, OUTPUT);

//WATER FLOW 
  pulseCount        = 0;
  flowRate          = 0.0;
  flowMilliLitres   = 0;
  totalMilliLitres  = 0;

  oldTime           = 0;
   attachInterrupt(sensorInterrupt, pulseCounter, FALLING);

  pulseCount2        = 0;
  flowRate2          = 0.0;
  flowMilliLitres2   = 0;
  totalMilliLitres2  = 0;

  oldTime2           = 0;
  attachInterrupt(sensorInterrupt2, pulseCounter2, FALLING);

  digitalWrite(RELAY1, 1);
  digitalWrite(RELAY2, 1);
}



void loop() {


  // put your main code here, to run repeatedly:
  t = rtc.getTime();
//DateTime now = rtc.now();
//This will get data send from the Desktop Application
char inc;
  while (Serial.available()) { // Get characters
    inc = Serial.read();
    if (inc >= '0' && inc <= '9') {
      val = 10*val + (inc-'0');
    } else {
      switch (toupper(inc)) {
      case 'A':
        Serial.print("Case A got ");
        Serial.println(val);
        WATEREQFORN1 = val;

            EEPROM.put(0, WATEREQFORN1);
            //Serial.print("DATA SAVE TO EEPROM");

        break;
      case 'B':
        Serial.print("Case B got ");
        Serial.println(val);
         WATEREQFORN2 = val;
         EEPROM.put(5, WATEREQFORN2);
         //Serial.print("DATA SAVE TO EEPROM");

        break;
      case 'D':
        Serial.print("Case D got ");
        Serial.println(val);
        DELAYINTERVALOFDATA = val;
        EEPROM.put(10,DELAYINTERVALOFDATA);
        break;


      default :
        ; // handle blanks, returns, etc
      }
      val = 0;  // Set val to zero after any non-digit
    }//END of SWITCH
  }//END of WHILE





   moistureOneSensorValue = analogRead(MOISTURE1);
   moistureTwoSensorValue = analogRead(MOISTURE2);



 // -------------------------------------------------------------------
 // Alarm Every Morning 7 AM Check If The Soil is DRY if DRY it will water 
 // -------------------------------------------------------------------
if (t.hour == 0 && t.min == 49) {
  if(moistureOneSensorValue >= 700 ){
     RelayOne();

  }
  //if(moistureTwoSensorValue >= 700 ){
  //  RelayTwo();
 // }
}else{
   digitalWrite(RELAY1, 1); //CLOSE VALVE

}
// -------------------------------------------------------------------
// Alarm Every Afternoon 4 PM and Check if the soil is DRY if DRY it will water
// -------------------------------------------------------------------

if (t.hour == 16 && t.min == 00 && moistureOneSensorValue >= 700 ) {
  if(moistureOneSensorValue >= 700 ){
     RelayOne();
     digitalWrite(RELAY1, 1);
  }
  if(moistureTwoSensorValue >= 700 ){
     RelayOne();
  }
}
 readAllSensorStatus();

//Setting alarm/timer at every 2:32:53pm, 
//in other words you can insert t.dow for every Thursday?, t.date for specific date?
//  {Serial.println("RELAY ON");

//Lets say that your component is wired to pin 99 and be switched on for 5 seconds, 
//whatever you want to do with it



  // Wait one second before repeating :)
 // delay (1000);
 if(RELAY1 == LOW){
      digitalWrite(RELAY1, 1);
 }
}



void readAllSensorStatus(){
   unsigned long currentMillis = millis();

   interval = EEPROM.get(10,DELAYINTERVALOFDATA);
   if(currentMillis - prevMillis > interval) {
        prevMillis = currentMillis; 
  //moistureSensorValue >= 700 DRY
  //
  //moistureSensorValue < 700 && moistuteSensorValue >= 300 Moist soil
  //
  //moistureSensorValue < 300 soggy soil
  //
  //Moisture
 moistureOneSensorValue = analogRead(MOISTURE1);
 moistureTwoSensorValue = analogRead(MOISTURE2);
 //Humidity and Temperature
 int chk = DHT.read11(DHT11_PIN);

 humiditySensorValue = DHT.humidity;
 tempSensorValue = DHT.temperature;
 //Water LEvel




  String LineOne = "-";
  String SensorValue = moistureOneSensorValue + LineOne + moistureOneSensorValue + LineOne + humiditySensorValue + LineOne + tempSensorValue;

  Serial.println(SensorValue);
  Serial.println(t.hour+LineOne+t.min);
   }

}
void closeSolenoidValve(){
   digitalWrite(RELAY1, 1); //Close

}
void RelayOne(){


//Serial.println("Valve Open");  
digitalWrite(RELAY1, 0); //OPEN VALVE
digitalWrite(WATERFLOW1, HIGH);//READY WATER FLOW FOR SENSING
//WATER FLOW 

if((millis() - oldTime) > 1000)    // Only process counters once per second
  { 
    // Disable the interrupt while calculating flow rate and sending the value to
    // the host
    detachInterrupt(sensorInterrupt);

    // Because this loop may not complete in exactly 1 second intervals we calculate
    // the number of milliseconds that have passed since the last execution and use
    // that to scale the output. We also apply the calibrationFactor to scale the output
    // based on the number of pulses per second per units of measure (litres/minute in
    // this case) coming from the sensor.

    flowRate = ((1000.0 / (millis() - oldTime)) * pulseCount) / calibrationFactor;

    //Serial.print(pulseCount);

    // Note the time this processing pass was executed. Note that because we've
    // disabled interrupts the millis() function won't actually be incrementing right
    // at this point, but it will still return the value it was set to just before
    // interrupts went away.

    oldTime = millis();

   //  Serial.print("::");
    // Serial.print(oldTime);
    // Divide the flow rate in litres/minute by 60 to determine how many litres have
    // passed through the sensor in this 1 second interval, then multiply by 1000 to
    // convert to millilitres.

    flowMilliLitres = (flowRate / 60) * 1000;

    // Serial.print(flowMilliLitres);
    // Add the millilitres passed in this second to the cumulative total

    totalMilliLitres += flowMilliLitres;

    unsigned int frac;

    // Print the cumulative total of litres flowed since starting
    Serial.print("  Output Liquid Quantity: ");             // Output separator
    Serial.print(totalMilliLitres);
    Serial.println("mL"); 

    setPointForN1 = EEPROM.get(0, WATEREQFORN1) / 2;

   if(totalMilliLitres >= setPointForN1 ){
       //closeSolenoidValve();
        digitalWrite(RELAY1, 1); //OPEN VALVE
      return loop();
      }

     // Reset the pulse counter so we can start incrementing again
    pulseCount = 0;


    // Enable the interrupt again now that we've finished sending output
    attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
  }



  if(flowMilliLitres == 0){
     totalMilliLitres = 0;
  }


}

void RelayTwo(){


digitalWrite(RELAY2, 0);
digitalWrite(WATERFLOW2, HIGH);//READY WATER FLOW FOR SENSING
//WATER FLOW 

if((millis() - oldTime2) > 1000)    // Only process counters once per second
  { 
    // Disable the interrupt while calculating flow rate and sending the value to
    // the host
    detachInterrupt(sensorInterrupt2);

    // Because this loop may not complete in exactly 1 second intervals we calculate
    // the number of milliseconds that have passed since the last execution and use
    // that to scale the output. We also apply the calibrationFactor to scale the output
    // based on the number of pulses per second per units of measure (litres/minute in
    // this case) coming from the sensor.

    flowRate2 = ((1000.0 / (millis() - oldTime2)) * pulseCount2) / calibrationFactor;

    //Serial.print(pulseCount);

    // Note the time this processing pass was executed. Note that because we've
    // disabled interrupts the millis() function won't actually be incrementing right
    // at this point, but it will still return the value it was set to just before
    // interrupts went away.

    oldTime2 = millis();

   //  Serial.print("::");
    // Serial.print(oldTime);
    // Divide the flow rate in litres/minute by 60 to determine how many litres have
    // passed through the sensor in this 1 second interval, then multiply by 1000 to
    // convert to millilitres.

    flowMilliLitres2 = (flowRate2 / 60) * 1000;

    // Serial.print(flowMilliLitres2);
    // Add the millilitres passed in this second to the cumulative total

    totalMilliLitres2 += flowMilliLitres2;

    unsigned int frac2;

    // Print the cumulative total of litres flowed since starting
    //Serial.print("  Output Liquid Quantity: ");             // Output separator
    //Serial.print(totalMilliLitres2);
    //Serial.println("mL"); 

   setPointForN2 = EEPROM.get(5, WATEREQFORN2) / 2;

   if(totalMilliLitres >= setPointForN2 ){
       Serial.println("Solenoid Close Set Point Reach");
       digitalWrite(RELAY2, 1); //CLOSE VALVE
    }

     // Reset the pulse counter so we can start incrementing again
    pulseCount2 = 0;


    // Enable the interrupt again now that we've finished sending output
    attachInterrupt(sensorInterrupt2, pulseCounter2, FALLING);
  }

  if(flowMilliLitres2 == 0){
     totalMilliLitres2 = 0;
  }

}


/*
Insterrupt Service Routine
 */
void pulseCounter()
{
  // Increment the pulse counter
  pulseCount++;
}

void pulseCounter2()
{
  // Increment the pulse counter
  pulseCount2++;
}
  • 1
    You'll need to show the complete code. It isn't clear from just this snippet what is going on. – Delta_G May 21 '17 at 16:29
  • @Delta_G see edit – kaisar Great May 21 '17 at 16:39
  • That's still not complete code. My guess is either that the closeSolenoidValve function doesn't do what you expect or that the solenoid is being closed and thenimmediately reopened again because whatever condition got you into that state is still true. – Delta_G May 21 '17 at 16:44
  • 2
    return loop(); That line is pretty useless. You can't return the value of a function that returns nothing. It also causes a recursion in your code, you're calling loop before the previous call to loop has finished. Do that too many times and the whole thing crashes. – Delta_G May 21 '17 at 16:58
  • 1
    OK, if you're not into answering my questions then I'm done helping. – Delta_G May 21 '17 at 17:42
3

This may not be a direct answer to the question, in the sense that I cannot tell you where exactly is the bug in your program. But hopefully it will help you getting a program that does work. I tried to find the bug, but it's quite hard. When reading your code, I could not stop asking myself “Why is this so convoluted?”. As a general rule, a simple program is easier to get working than a complex program. So I would ask you: why don't you try something simple instead?

The first thing that stroke me is that it seems you did not realize that the pulse count from the flow sensor is a direct measurement of the volume that went through it. You are timing the pulses in order to convert a pulse count into a pulse rate, then you convert that into a flow rate, then you integrate the flow rate rate to get the volume. All this is unnecessary complication: just count the pulses, the count is a water volume, albeit in an unusual unit.

Second thing is the logic of the whole program. It should be clear at first sight under what conditions the watering starts and under what conditions it stops. This is best done with a finite state machine with two state: either we are watering the plants or we are not. The state variable is then a boolean, and the logic could written along those lines:

void loop()
{
    // Should we start watering?
    if (!watering) {
        if (some_condition()) {
            start_watering();
            watering = true;
        }
    }

    // Should we stop watering?
    else {
        if (some_other_condition()) {
            stop_watering();
            watering = false;
        }
    }
}

Something explicit like this is generally easier to read, to understand and to debug. And likely to be less buggy in the first place.

Third thing, you seems to be doing too much stuff at once: controlling two different pumps, monitoring a DHT sensor, updating the setpoints... You should try to get a minimal program working, and only then start to add more stuff. The more functionality you add, the more complex the program gets. Don't expect something complex to just work: you should really get a simple version working first, and only then build on that.

Here is a proposed simplified version for your program. Absolutely not tested: it is just meant to get you started.

#include <EEPROM.h>
#include <DS3231.h>

const uint8_t RELAY_PIN = 7;
const uint8_t MOISTURE_PIN = A15;
const uint8_t FLOW_SENSOR_PIN = 2;
const uint8_t SENSOR_INTERRUPT = 0;
const float PULSES_PER_ML = (4.5*60)/1e3;  // 0.27 pulses/mL
const int MOISTURE_THRESHOLD = 700;

uint16_t wateringPulseCount;  // required pulses of water to deliver
DS3231  rtc(SDA, SCL);

/***********************************************************************
 * Handling of pulse counts.
 */

volatile uint16_t pulseCount;

// Interrupt handler.
void pulseCounter()
{
    pulseCount++;
}

// Safely read the current pulse count.
static inline uint16_t getPulseCount()
{
    noInterrupts();
    uint16_t pulseCountCopy = pulseCount;
    interrupts();
    return pulseCountCopy;
}

/***********************************************************************
 * Main program.
 */

void setup()
{
    pinMode(RELAY_PIN, OUTPUT);
    pinMode(MOISTURE_PIN, INPUT);
    pinMode(FLOW_SENSOR_PIN, INPUT);

    // Initialize the watering limit as a pulse count.
    uint16_t wateringVolume;
    wateringPulseCount = EEPROM.get(0, wateringVolume) * PULSES_PER_ML;
}

void loop()
{
    static bool watering;  // are we watering now?

    // Start watering at 07:00 if the soil is dry.
    Time t = rtc.getTime();
    if (!watering && t.hour == 7 && t.min == 0) {
        if (analogRead(MOISTURE_PIN) > MOISTURE_THRESHOLD) {
            pulseCount = 0;
            attachInterrupt(SENSOR_INTERRUPT, pulseCounter, FALLING);
            digitalWrite(RELAY_PIN, LOW);  // open valve
            watering = true;
        }
    }

    // Stop watering after the required volume.
    if (watering) {
        if (getPulseCount() >= wateringPulseCount) {
            digitalWrite(RELAY_PIN, HIGH);  // close valve
            detachInterrupt(SENSOR_INTERRUPT);
            watering = false;
        }
    }
}

Note that the pulse count has to be read with interrupts disabled, but you should not detach the interrupt handler. Detaching the handler means you will miss pulses, wheres disabling the interrupts only delays their handling until you enable them again. You won't miss pulses unless to keep the interrupts disabled for too long (which you shouldn't do).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.