Pages: [1]   Go Down
Author Topic: please help with millis inside a function  (Read 498 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 16
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi there,

I'm very close to finishing, but I'm having some problems with using millis() inside a function.  This code has been posted in a different thread but I'm posting it here as it is now better suited for Project guidance.

Project overview:
Watering system for my palm. 
  • Check battery level and water level every 5 minutes.  (Right now I have it checking every 5 seconds for testing).
    If the battery level is below 7 volts or if the water level (reed_val) is below a certain point, the LED will blink continuously until water reservoir is filled or battery changed.
  • The function "Water" (checking the moisture value) will be called after it hits a certain amount of Counts (Counter ==5).  Right now I have it set to 25 seconds (run Battery every 5 seconds [increment Counter after each loop]) for testing purposes.
  • When the "Water" function is running (moisture value is < 900 && reed_val ==LOW), I want it to turn on pump for 5 seconds, then shut it off and read the moisture and reed value again, then start pump again, and continue this sequence until either the moisture value is > 900 or the reed value is HIGH.

The problem that I'm having is only in the "Water" function.  If I use
Code:
Alarm.delay(5000);
the "Water" function will continually turn on the pump, while (moisture_val < 900 && reed_val ==LOW). 
If I add
Code:
digitalWrite(waterpump,LOW);
Alarm.delay(5000);
it's inconsistent, waterpump turning on and staying on without delay, or waterpump turning on and then turning off after 5 seconds without restarting until the next time it calls the Water function.

I think that using millis() would help, and it seems so simple - but I keep hitting a brick wall and getting frustrated.  Any help would be greatly appreciated.

Here is the entire code so far:
Code:
/*
 * Gardening Project v1.2.3
 * Combining the capacitive sensor, moisture sensor, pump and led indicator.
 * Reading how much water is in the container.
 * Reading how much moisture is in the ground.
 * Pumping water if moisture is dry.
 * LED
 * Red - low battery , blink
 */
 
#include <Bounce.h>
#include <Time.h>
#include <TimeAlarms.h>
#define LED 9  // LED on pin 9
#define SWITCH 10  // Defines the Reed switch on digital pin 10

int reed_val = 0;  // used to store the input of the reed switch
Bounce bouncer = Bounce( SWITCH,10 );

int Counter = 0;  // Set counter



//  Volt monitoring
  int batteryPin = 1;
  float vout = 0;
  int value = 0;
  float R1 = 991;    // !! resistance of R1 !!
  float R2 = 995;     // !! resistance of R2 !!
  float vin = 0;

// Moisture Sensor
  int moistureSensor = 5;  // Sensor pin 5, other pin connected to GRN through a 10k resistor
  int moisture_val;  // Storing the current value of the Sensor pin
  int waterpump = 7;  // Initializing pin 7 for waterpump


void setup()  {
  Serial.begin(9600);
  pinMode(SWITCH, INPUT);  // Defines the switch as an input
  digitalWrite(SWITCH, HIGH);
  pinMode(LED,OUTPUT);  // LED as an output
  pinMode(waterpump,OUTPUT);  // Setting waterpump to output
  digitalWrite(waterpump,LOW);  // waterpump off
  // Time
  setTime(0,0,0,13,12,11);
  Alarm.timerRepeat(5,Battery);

}

void loop()  {
  // Display the countdown timer
  digitalClockDisplay();
  Alarm.delay(1000); // wait one second between clock display
 
  if (Counter == 5)  {
     Water();
     Counter = 0;
     }
}


// Start of Functions

  void Water()  {
  analogReference(EXTERNAL);
  bouncer.update();
  int reed_val= bouncer.read();
  moisture_val = analogRead(moistureSensor);
  Serial.print("M: ");
  Serial.println(moisture_val);
  // Check whether input is LOW (switch closed)
  while (moisture_val < 900 && reed_val==LOW)  {
    Serial.println ("Turning on pump");   // Debugging or adding add to LCD
    digitalWrite(waterpump,HIGH);  // waterpump on
    Alarm.delay(5000);
    // digitalWrite(waterpump,LOW);  // waterpump on
    // Alarm.delay(5000);
    bouncer.update();
    int reed_val= bouncer.read();
    moisture_val = analogRead(moistureSensor);
    }
   
    if (reed_val==HIGH)  {
      return;
      }
}

 
  void Battery()  {
  // Volt Monitoring
  analogReference(EXTERNAL);
  value = analogRead(batteryPin);
  vout= (value * 5)/1024.0;  //voltage coming out of the voltage divider
  vin = vout / (R2/(R1+R2));  //voltage to display
  while (vin < 7.0)  {
    digitalWrite(waterpump,LOW);
    digitalWrite(LED,HIGH);  // LED turns on
    Alarm.delay(200);
    digitalWrite(LED,LOW);
    Alarm.delay(200); 
  }
  // Debugging with LCD
  Serial.print("V: ");  // Print out V:
  Serial.println(vin);  // This is where the number of volts are displayed
 
  // Reed Switch monitoring
  bouncer.update();
  int reed_val= bouncer.read();
  while (reed_val==HIGH)  {
    Serial.println("Fill Water");
    digitalWrite(waterpump,LOW);
    digitalWrite(LED,HIGH);
    Alarm.delay(200);
    digitalWrite(LED,LOW);
    Alarm.delay(200);
    bouncer.update();
    int reed_val= bouncer.read();
    if (reed_val==LOW)  {
      return;
    }
  }
  Counter++;
}
 
 void digitalClockDisplay()  {
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.println();
  }

void printDigits(int digits)  {
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
  }
Logged

'round the world...
Online Online
Faraday Member
**
Karma: 41
Posts: 3107
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

This is the problem with using classes that you haven't built and can't see what is inside.


Code:
//  Volt monitoring
  int batteryPin = 1;
  float vout = 0;
  int value = 0;
  float R1 = 991;    // !! resistance of R1 !!
  float R2 = 995;     // !! resistance of R2 !!
  float vin = 0;

// Moisture Sensor
  int moistureSensor = 5;  // Sensor pin 5, other pin connected to GRN through a 10k resistor
  int moisture_val;  // Storing the current value of the Sensor pin
  int waterpump = 7;  // Initializing pin 7 for waterpump

memory in the Arduino is scarce. Does the place where you're going to connect the sensors change while the program is running?
Change the pin numbers to a #define for example.

Code:

unsigned long now=0, before=0;
void loop()  {
  // Display the countdown timer
now = millis();
if (now - after > 1000) {//1 second
  digitalClockDisplay();
  after = millis();
  }

//  Alarm.delay(1000); // wait one second between clock display
 
  if (Counter == 5)  {
     Water();
     Counter = 0;
     }
}

I've added an example on how to use millis for this part. I didn't find the implementation of Alarm.delay(). Hopefully is not a "normal" delay.

But when I started going through your Water function I didn't understand it. Because you start the pump, wait 5 seconds and then stop the pump, read and start the pump if the measurement is not right. So what probably will happen is that the pump will stop and restart almost instantaneously. Are you measuring water level in a tank? Or moisture?

If it's water level, the 5 seconds are not a good option. If you are checking moisture, you'll need to also wait some time for the water to spread in the medium (I think).

Depending on where you have your sensor you may take too long to see any change in the humidity (and it is not even through the vase), or you may see a lot of humidity and in the bottom of the vase there is no water. So to have some control over this, it's probably best to maybe have to sensors and average them out? That would in a way eliminate the way of this timing.
Logged

Eu não sou o teu criado. Se respondo no fórum é para ajudar todos mediante a minha disponibilidade e disposição. Responder por mensagem pessoal iria contra o propósito do fórum e por isso evito-o.
Se realmente pretendes que eu te ajude por mensagem pessoal, então podemos chegar a um acordo e contrato onde me pagas pela ajuda que eu fornecer e poderás então definir os termos de confidencialidade do meu serviço. De forma contrária toda e qualquer ajuda que eu der tem de ser visível a todos os participantes do fórum (será boa ideia, veres o significado da palavra fórum).
Nota também que eu não me responsabilizo por parvoíces escritas neste espaço pelo que se vais seguir algo dito por mim, entende que o farás por tua conta e risco.

Dito isto, mensagens pessoais só se forem pessoais, ou seja, se já interagimos de alguma forma no passado ou se me pretendes convidar para uma churrascada com cerveja (paga por ti, obviamente).

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 548
Posts: 46026
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

In the other thread, you alluded to the fact that you were trying to sleep the Arduino between activities. This code does not sleep the Arduino. If sleeping is not necessary, then get rid of the Alarm instance (and Time library).

Define variables to define the last time moisture was checked, the last time watering started, the last time the battery was checked, etc.

Define variables to define the time between moisture checks, the time between watering starting and watering ending, the time between battery checks, etc.

Code:
unsigned long moistureChecked = 0;
unsigned long wateringStarted = 0;
unsigned long batteryChecked = 0;

unsigned long wateringTime = 500UL; // half a second (adjust as needed)
unsigned long batteryTestInterval = 5UL * 60UL * 1000UL; // 5 minutes
unsigned long moisuterCheckIinterval = 15UL * 60UL * 1000UL; // 15 minutes

void loop()
{
   unsigned long now = millis();

  // Is it time to check moisture?
  if(now - moistureChecked >= moistureCheckInterval)
  {
     checkMoisture();
  }

  // Is it time to check the battery?
  if(now - batteryChecked >= batteryCheckInterval)
  {
     checkBattery();
  }

  // Is it time to stop watering?
  if(wateringStarted > 0 && now - wateringStarted >= wateringTime)
  {
     stopWatering();
  }
}

void checkMoisture()
{
   // Do whatever is needed to check moisture
   if(plantIsDry)
     startWatering();

   moistureLastChecked = millis();
}

void startWatering()
{
   // Do whatever is needed to start watering

   wateringStarted = millis();
}

void stopWatering()
{
   // Do whatever is needed to stop watering

   wateringStarted = 0;
}

Add similar code for the battery testing.

You can, in the start and stop watering functions, or in the moisture checking function, change the time between moisture level checks, so that the interval between checks is smaller when the plant is dry than when the plant has just been watered.

Make the interval one minute when you start watering, because the plant is dry, and 15 minutes after the level again is high enough. You can even require that the plant be moist enough for 15 minutes before changing the interval.

Start simple, though.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 16
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thank you both for responding.  PaulS - thank you once again, much appreciated.

I've read about sleeping the Arduino - which is not what I want to do.  I do however think that the Time library is what what I want.

Start the clock and check the battery and waterlevel every 5 minutes.
Each day (24hours - [count the number of times it checks the battery * 12 * 24])  I want to check the moisture and if needed, start the pump.
When it checks the moisture - if the soil is dry it starts the pump for 5 seconds, then stop pump and re-check the moisture, if more water is needed it will start the pump again for another 5 seconds, until the moisture reading is at a certain level.
The reason I want to do it this way is because it takes some time before the moisture reading starts rising (it's not instant).

I was hoping to use the Time library, because now I have most of it working (except the pump pause).

Thank again for all your help
Logged

Austin, TX
Offline Offline
Faraday Member
**
Karma: 63
Posts: 6049
Baldengineer
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Change the pin numbers to a #define for example.
Common gotcha...  #define won't always save memory.  #defines get replaced with constants before the code is compiled.  Constants can use RAM just like any other variable would.
Logged

Capacitor Expert By Day, Enginerd by night.  ||  Personal Blog: www.baldengineer.com  || Electronics Tutorials for Beginners:  www.addohms.com

Pages: [1]   Go Up
Jump to: