Weird behavior with Uno/LCD/RTC

Hey guys,

I have cats that need food, even when we aren’t home.
So I went ahead and built this: Cat Feeder

The project was laking an RTC so I added one and I rewrote the program from scratch.
Unfortunately I encounter(ed) two weird issues that are complicated to explain, one of them being not 100% reproducible.

1/ There are actions being done when buttons are pushed, e.g. modify the feeding time by moving a cursor left and right, up and down to modify hours and minutes.

The LCD looks like this:

Heure 1er dosage
06:00

When going in edit mode, the hours start blinking and one can:

  • push up/down to modify hours
  • push right to edit minutes
  • push left to edit hours (if cursor is on minutes)

Oddly enough, everything was working OK except moving the cursor from minutes to hours (left action) when the LCD’s first line contained 16 chars “Heure 1er dosage”. I changed it to “Heure dosage 1” (14 chars) everything worked perfectly. How can that be? This is the only thing I modified.

2/ Now for the issue I did not solve yet: the user decides when cats are fed, and to activate the stepper when needed I’m checking the RTC time versus the defined timer. However it sometime works, sometimes not. This is so easy and straightforward that I can’t seem to understand what’s wrong.

void loop() {
  [..]

  // Time to feed the cats?
  DateTime now = rtc.now();
  if(now.second() == 0) {
    uint8_t minute = rtc.readnvram((ADDRESS_TIMER+1));
    if(now.minute() == minute) {
      uint8_t hour = rtc.readnvram(ADDRESS_TIMER);
      uint8_t recurrence = rtc.readnvram((ADDRESS_RECURRENCE));
      while(hour < 24) {
        if(now.hour() == hour) feedAnimal(rtc.readnvram(ADDRESS_QUANTITY));
        hour += recurrence;
      }
    }
  }
}

I am basically:

  • checking if seconds == 0
  • then going further and check if current minutes match timer
  • then check hour and recurrence and feed the animals!

Sample value:
minute = 30
hours = 6
recurrence = 6 (meaning cats will be fed at 6h30, then 12h30, then 18h30)

Does anyone know what could be wrong?

Thank you

Oddly enough, everything was working OK except moving the cursor from minutes to hours (left action) when the LCD's first line contained 16 chars "Heure 1er dosage". I changed it to "Heure dosage 1" (14 chars) everything worked perfectly. How can that be? This is the only thing I modified.

RAM issue?

2/ Now for the issue I did not solve yet: the user decides when cats are fed, and to activate the stepper when needed I'm checking the RTC time versus the defined timer. However it sometime works, sometimes not. This is so easy and straightforward that I can't seem to understand what's wrong.

Post complete code, the error is most probably in the part you're hiding from us.

I’m not really proud of my code but here you go (attached as requested below).

I hardly vote for RAM issue:
Sketch uses 12032 bytes (37%) of program storage space. Maximum is 32256 bytes.
Global variables use 581 bytes (28%) of dynamic memory, leaving 1467 bytes for local variables. Maximum is 2048 bytes.

petfeeder-multiple.ino (13.1 KB)

I’m not really proud of my code but here you go :slight_smile:
https://pastebin.com/p1GhwrGB

No, we don’t go to pastebin and co! Post code to this forum! You can use code tags (the </> button in the editor) or attach your code but temporary storage servers are a no-go.

Attached to my previous post!

Remove the PROGMEM declaration from your sketch! You cannot declare a variable PROGMEM and then access it as if it is in RAM. A const doesn't use RAM anyway as the compiler includes the value in the code.

strcpy_PF

dynek:
Oddly enough, everything was working OK except moving the cursor from minutes to hours (left action) when the LCD's first line contained 16 chars "Heure 1er dosage". I changed it to "Heure dosage 1" (14 chars) everything worked perfectly. How can that be? This is the only thing I modified.

The 16-character phrase "Heure 1er dosage" actually occupies 17 bytes because of the terminating null character. The target of your strcpy command is only 16 bytes, so the terminating null is overwriting whatever happens to be stored in memory immediately afterwards.

david_2018:
strcpy_PF
The 16-character phrase “Heure 1er dosage” actually occupies 17 bytes because of the terminating null character. The target of your strcpy command is only 16 bytes, so the terminating null is overwriting whatever happens to be stored in memory immediately afterwards.

Nice catch. It fixes this problem, thanks!

pylon:
Remove the PROGMEM declaration from your sketch! You cannot declare a variable PROGMEM and then access it as if it is in RAM. A const doesn’t use RAM anyway as the compiler includes the value in the code.

Have done so. My understanding was not accurate :expressionless:
Still the stepper doesn’t run at scheduled times, still can’t understand why.

Thank you for your hints.

Can you guarantee that the check for the feeding time will occur at least once per second, since the initial if statement checks for now.second() == 0 ?

david_2018:
Can you guarantee that the check for the feeding time will occur at least once per second, since the initial if statement checks for now.second() == 0 ?

Couple of things make me think I can :slight_smile:

  1. The LCD is displaying the current time, and when I stare at it for a few minutes, I can see each second pass by and being displayed.
  2. When I add a Serial print in the loop (e.g. print seconds), the console is flooded, not like something is blocking the program
  3. I tried modifying the condition with >= 0 && <= 4 to no avail.

Thank you

Oh well that sounds odd to me but I have found two threads where people compare time using an heading zero when lower than 10:

if(now.hour() == 6 && now.minutes() == 00){

if(now.minute() < 10) { //PRINT A 0 IN FRONT OF THE MINUTE IF LESS THAN 10

I’ll give it a try even though I’m doubtful.

How are you powering the stepper motor? Have you verified whether or not you are actually getting to the stepper motor function at the correct times? Any possibility the cat food is jamming the feed auger and the stepper motor just lacks the necessary torque to reliably turn it?

A common technique in the time comparison is to check for the correct hour and minute, then set a flag to indicate you have completed the timed function. The flag gets reset when the times no longer match. That way, you have a whole minute in which to make the match, and the timed function will only execute once.

david_2018:
How are you powering the stepper motor? Have you verified whether or not you are actually getting to the stepper motor function at the correct times? Any possibility the cat food is jamming the feed auger and the stepper motor just lacks the necessary torque to reliably turn it?

I'm using a L298N Dual H Bridge Stepper Motor Driver and it's working fine, no jam or anything. I just doesn't move (no Serial.print when it doesn't work so the problem is outside, I would guess). I also have an option in the menu to trigger a manual feed and it works each time.

david_2018:
A common technique in the time comparison is to check for the correct hour and minute, then set a flag to indicate you have completed the timed function. The flag gets reset when the times no longer match. That way, you have a whole minute in which to make the match, and the timed function will only execute once.

If the double zero mentioned above doesn't work I will give this a try, it sounds like a smart way of doing it.

Thank you

That's completely crazy. Even with the flag it doesn't work.
But it works when connected via USB (as I'm doing Serial.print stuff).
And it also works manually but not from the condition(s).

How are you powering the arduino & stepper motor?

With a Meanwell LRS-150F-12:
https://www.meanwell-web.com/en-gb/ac-dc-single-output-enclosed-power-supply-lrs--150f--12

I've been playing with the conditions and I pretty much feel there's something odd around that, cause sometimes it works, sometimes not (even with the USB cable plugged in to check Serial.print), no reset whatsoever.

So far so good!

I moved Datetime now as a global variable, I'm updating it from the loop() and it now works, at least for the past hours ...

Interesting, not sure why it would make a difference, except that it moves the location in ram where the variable is stored. Maybe the compiler is doing something odd trying to optimize the code. I don't have the correct hardware here to test with, all the RTC boards I have use the DS3231.