Help understanding timers (delay or millis)?

Hi everyone

Im new to arduino and programming.
Im building an aquarium controller using some the sketches already created by other people.

I now have something I want to build for my design.
What I want to do is automate the Automatic Top Off (ato) for my aquarium.

The basic construction.
Read the floatswitch.
If it is high, turn on a pump.
(I have that part working fine, but I want to put some time constraints on it)

What I want it to do is this:
Turn on pump for 20seconds.
Allow this to occur only once per hour(or whatever time variable)

Ive read that using delay will esentially lockup an arduino from doing anything else.

And ive played with millis but have figured it out.

Am I heading down the correct path in using timers, or is there something else in the library I should be looking at?

Thanks everyone
Pogue

millis() can handle all of this. StateChangeDetection example shows you how to look for a signal edge, as in, you want to know when the float switch goes from LOW to HIGH. You can then use millis to get the current time, and turn on the pump. Outside of those conditions, you can check to see if has been 20 seconds since you recorded the time, and turn the pump off if that's the case.

The demo in the first post of this Thread illustrates the use of millis() and variables that record the state of things.

...R

Thank you for your replys...

I've been trying to use the millis examples you've suggested and have made a dogs breakfast out of it.
I'm still trying to get it to work.

I think I'm missing a time variable in my code somewhere

Finally got it working the way I wanted it too.
Thanks again for the link you provided Robin, very helpful.

Probably a silly question but would using millis() be taxing on the cpu/chip?
I have an rtc attached to my project. Is there another way, so millis() isn't constantly checking on a value of something,

Could I include something that would take advantage of the rtc?

There isn't really any concept of anything being "taxing" on a chip. It runs 16 million cycles per second whether it is doing anything useful or not.

In the Arduino system the value of millis() counts up whether you use it or not.

It probably takes less CPU cycles to make use of millis() than to read an RTC.

You could certainly use the RTC instead of millis() - but you should use it in much the same way as millis() is used so that your code isn't blocked by the timing process. In my view that code would be more complex and would only be warranted if the real-time inaccuracy in millis() matters. (The Arduino clock doesn't run at exactly 16MHz so the timing eventually drifts away from clock-time.)

...R

Millis() are counted anyway, even if you use it or not. It's a simple counter that starts at 0 every time your board is reset or powered on. If you need just that it is perfect to use.
As far as using the RTC, it's possible, but I have no experience with that, just trying to figure it out myself.

Thanks for your replies...I'll be sticking with millis() as I'm beginning to have a minor understanding of some of it.
I thought my code was working but it's a bit off and I'm having a hard time wrapping my head around it.

Would it be OK to ask someone if they can comment on what I'm doing wrong in my test code?
The issue this:
When Float_Switch_Pin starts a pumpon cycle I want it to stay on for the full 5 seconds, regardless if it's value switches to low.'
After the 5 seconds I want LED_Pin to go low.
What's happening, is if I physically close the float switch the else runs and the led turns off.
(I've burnt out too may float switches by having them constantly sit at the "top off level")
If I remove the else, and close the float switch the LED stays on indeffinately...VERY VERY bad as I plan on controlling a pump to top off my aquarium...flooding all over the place.

Thanks again for all comments.

// --------CONSTANTS (won't change)---------------
const int FLOAT_SWITCH_PIN = 2;
const int SAFETY_SWITCH_PIN = 5;
const int LED_PIN = 7;  //testing with an led for now

const int safetyinterval = 15000;  //I plan to set this for ~ 45 mins
const int pumpon = 5000;        //I plan to set this for ~ 20 seconds


//------------ VARIABLES (will change)---------------------

unsigned long currentMillis = 0; 
unsigned long previoussafetyMillis = 0;
unsigned long previousfloatMillis = 0; 

byte atocycle = LOW;             // used to record whether the LEDs are on or off
byte pumprun = LOW;

//setup runs once
void setup()
{
  pinMode(FLOAT_SWITCH_PIN, INPUT_PULLUP);
  pinMode(SAFETY_SWITCH_PIN, INPUT_PULLUP);
  
  //setup output pins for relays/pumping station and LED board
  pinMode(LED_PIN, OUTPUT);
  
}

//======================================== 
void loop() {
    
  currentMillis = millis();  
  if (digitalRead(SAFETY_SWITCH_PIN) == HIGH) {
    pumpcycle();
  }
  else {
    digitalWrite(LED_PIN, LOW);    //turn off the LED
  }
}
//========================================

void pumpcycle () {
if (digitalRead(FLOAT_SWITCH_PIN) == HIGH){
  if (atocycle == LOW) {
          if (currentMillis - previousfloatMillis >= safetyinterval) {
            atocycle = HIGH;
           digitalWrite(LED_PIN, HIGH);    //turn on the LED
           previousfloatMillis += safetyinterval;
          }
  }
  else {  // i.e. if onBoardLedState is HIGH
    if (currentMillis - previousfloatMillis >= pumpon) {
          // time is up, so change the state to LOW
          atocycle = LOW;
       digitalWrite(LED_PIN, LOW);
       previousfloatMillis += pumpon;
       }   
  }
}
  else {
       digitalWrite(LED_PIN, LOW);    //turn off the LED
  }
}

I thought I could make a few changes to your code to help but I have got stuck because I can't figure out what is supposed to happen in the pump cycle. Perhaps you can explain it in english.

I suspect you would be better to check the time before anything else because most of the time you won't want to do anything.

It may also make sense to have separate functions to deal with the different timing intervals.

I will come back to it when you explain what is meant to happen.

...R

Thanks for taking a look Robin.

This is what I would like to happen in the pump cycle:

  • If the float switch goes high I want to turn on an led for 5 seconds.
  • (If the floatswitch value goes low during that 5 seconds I want the led to stay on.)
  • (I'm thinking of this one like a button...if it gets pressed and released...turn on led for 5 seconds)
  • I want to put in a safety restriction of how frequently this cycle can occur.
  • I only want the led to be able to turn on once every 20 seconds.

I think this does what you described. It doesn't use SAFETY_SWITCH_PIN - I don't know what that is for.
Look for changes everywhere. I haven't tested it.

// --------CONSTANTS (won't change)---------------
const int FLOAT_SWITCH_PIN = 2;
const int SAFETY_SWITCH_PIN = 5;
const int LED_PIN = 7;  //testing with an led for now

const unsigned long safetyinterval = 15000;  //I plan to set this for ~ 45 mins
const unsigned long pumpon = 5000;        //I plan to set this for ~ 20 seconds


//------------ VARIABLES (will change)---------------------

unsigned long currentMillis = 0; 
unsigned long startSafetyMillis = 0;
unsigned long startFloatMillis = 0; 

byte floatSwitchState;  // NEW
byte safetySwitchState; // NEW


byte atocycle = LOW;             // used to record whether the LEDs are on or off
byte pumprun = LOW;

//setup runs once
void setup()
{
  pinMode(FLOAT_SWITCH_PIN, INPUT_PULLUP);
  pinMode(SAFETY_SWITCH_PIN, INPUT_PULLUP);
  
  //setup output pins for relays/pumping station and LED board
  pinMode(LED_PIN, OUTPUT);
  
}

//======================================== 
void loop() {
    
  currentMillis = millis();
  readSwitches();
  pumpCycle();
  checksafetyPeriod();

}
//========================================

void readSwitches() {
   floatSwitchState = digitalRead(FLOAT_SWITCH_PIN); // assume it is 0 when pressed
   safetySwitchState = (digitalRead(SAFETY_SWITCH_PIN);
}

void pumpcycle () {
  if (floatSwitchState == 0 && safetyPeriodExpired == true){ 
   digitalWrite(LED_PIN, HIGH);    //turn on the LED
   startfloatMillis = currentMillis;
   startSafetyMillis = currentMillis;
   safetyPeriodExired = false;
  }
  if (currentMillis - startFloatMills >= pumpon) {
     digitalWrite(LED_PIN, LOW);
  }
}

void checkSafetyPeriod() {
   if (currentMillis - startSafetyMillis >= safetyinterval) {
       safetyPeriodExpired = true;
   }
}

...R

thanks Robin,

Those code changes make it work exactly as I had hoped.
(some minor syntax and typos)

(the safety_float is an additional safety measure. It sits higher up in the tank out of the water. If for some reason my main return pump fails, all the water in the plumbing will fall back down into the sump tank. This float will then activate and shutdown the pumpcycle process. I really don't want gallons and gallons of water all over my floor :fearful:)

Thanks again...