Auto-fish-feeder...how to keep track of time?

I need to tell my auto-fish-feeder to dump food roughly once a day. Millis overflows....when? I think it doesn't matter since I only care roughly about the time.

I'm thinking I can just increment a number of seconds like this

unsigned long seconds;

void loop(){

seconds++;

if (!(seconds % (24*3600))){

feed fish

}

delay(1000);

}

Anyone see any problems with that? Better suggestions? If the fish dies, my wife will not like me.

Millis overflows....when?

Roughly 49 days. But, if you write the code correctly, you needn't worry about the overflow.

Anyone see any problems with that?

The pseudo-code doesn't take into account the time consumed by everything except the delay. Say the rest of loop takes about 1ms and feeding the fish takes about 10ms. Each pass through the loop will be 1001ms instead of the expected 1000ms and each time the fish are feed the total delay will be 1011ms. Assuming I did the math right, after 41 days, the fish feeding will be an hour later than when the application started.

If you're OK with the drift, then the pseudo-code will work. If not, then you'll need to use the technique described here (with a minor correction)... http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay

If the fish dies, my wife will not like me

Let's hope they don't get sick after the automatic feeder goes online!

A more solid approach would be using a RTC IC RealTime Clock)

This way you would not have to worry about millis() overflowing.

A more solid approach would be using a RTC IC RealTime Clock)

This way you would not have to worry about millis() overflowing.

My thoughts exactly

Mowcius

Drift is fine. The fish won't mind; it just has to be reliable.

The pseudo-code doesn't take into account the time consumed by everything except the delay

I suppose I could fix part of it by writing a void feedFish() function and calling that when the condition is met? I have no idea if that would be faster or not...I don't think it would (when can we get multithreading on Arduino?).

I suppose I could fix part of it by writing a void feedFish() function and calling that when the condition is met? I have no idea if that would be faster or not...I don't think it would

The overhead of a function call will make it slower. Not so much slower that you (or the fish) would notice.

Presumably the feedFish function would always perform the same operations, so you could just time them, and knock a few seconds off the time to wait.

There is also a DateTime library that makes the Arduino act like a clock. The time is not persistent, like an RTC, but it's pretty accurate. The downside is that you'd need to reset it every time the Arduino was restarted.

By RTC, are you all talking about a separate IC? Or part of Arduino?

RTC = real time clock. It's a separate IC.

unsigned long time;
unsigned long feedfishtime = 86400000;

void loop(){

time = millis();

if (time >= feedfishtime){
feedfishtime = time + 86400000;
feed fish;
}
}

86400000 is the number of milliseconds in a day. If your arduino is as accurate as mine it will be accurate to a couple of seconds a week. It should automatically loop over the variable limit after 49 days and keep on counting. It takes care of how long it takes to feed the fish itself. Because it doesn't use delay, the arduino can be doing something else between feeding fish. :)

I don't understand how that fixes the overflow. IANAP.

So, suppose millis, time, and feedfishtime are all unsigned longs.

Time and millis should roll over about the same time. But, feedfishtime will roll over about a day before time does. For that whole day, feedfishtime is less than time, so it would feed my fish every loop iteration. Furthermore, it would add a day to feedfishtime every loop!

What am I missing?

When feedFishTime does roll over, it will roll over to a value of less than 86,400,000. Handle that as a special case.

I suppose you could do something like this

if (time >= feedfishtime && !(feedfishtime < 86400000)){
feedfishtime = time + 86400000;
feed fish;
}

I’ll have to think about it for a bit to see what the ramifications are.

Drift is fine. The fish won't mind; it just has to be reliable.

In that case, the pseudo-code you posted will work fine.

Is double-feeding a problem? This would occur because of a power outage.

My code as posted would have an extra feeding cycle every 49 days, it would only do it once every long loop, since feedfishtime is set from the time variable. In the case of a power outage, it would miss a feeding. Fish are pretty tolerant about feeding, they get what they can when they can in the wild. They keep the tank cleaner if you under feed them ;)

In the case of a power outage, it would miss a feeding

That was going to be my next round of questions: What feedback should / could the system provide if the normal feeding was disrupted?

BetterSense indicated his wife would be displeased if the fish expired. I'd hate for his marital bliss to be in jeopardy because he didn't include a "been fed today" LED on the fish-feeder.

I suppose you could do something like this

Not really necessary.

unsigned long time;
unsigned long feedfishtime = 0;

void loop() {

    time = millis();

    if ((time - feedfishtime) > 86400000) {
        feedFish();
        feedfishtime = time;
    }
}

The magic of unsigned two-complement arithmetic will ensure that even when millis() rolls over and time < feedfishtime the result of the subtraction will trigger the feeding at the correct time.

Hi,

So what if you want to stagger the times? ie having a LED light on for 10min, off for 6, on again for 10, and so on?

Here´s what I´ve got. Since I don´t have a LED light, I figured I could test it by having the arduino send the time via serial, but I´m still not sure if it´s working or would work. :-/

unsigned long time;
unsigned long ledontime = 0;
unsigned long ledofftime = 0;
int Pin = 13;

void setup() {
  pinMode(Pin, OUTPUT);
  Serial.print(9600);
}

void loop() {
  time = millis();
  
  if ((time - ledontime) == 648 + ledofftime) {
    ledOn();
    ledontime == time + ledofftime;
  }
  if ((time - ledofftime) == 216 + ledontime) {
    ledOff();
    ledofftime == time + ledontime;
  }
}

void ledOn() {
  digitalWrite(Pin, HIGH);
  Serial.Print(ledontime);
  
}

void ledOff() {
  digitalWrite(Pin, LOW);
  Serial.Print(ledofftime);
}
  if ((time - ledontime) == 648 + ledofftime) {
    ledOn();
    ledontime == time + ledofftime;
  }

The first use of == is correct. It is a equality comparison operator.

The 2nd use of == is wrong. A comparison is performed, but the result is never used. To assign the value of time + ledofftime to ledontime, use =.

Ok, so it should look more like this:

if ((time - ledontime) == 648 + ledofftime) {
    ledOn();
    ledontime = time + ledofftime;
  }

In order to test the code, I tried to get the arduino to send data whenever ledOn() or ledOff() is called with Serial.print(ledontime) or (ledofftime) or with Serial.print("Hello world"), but it doesn´t seem to be working. At least nothing gets printed when I click on Serial Monitor in the Arduino IDE.

You probably want to use >= rather than ==.