Interrupts vs Watchdog vs loop() using RTC

Hello,

I've got Arduino UNO + DS3231 RTC + LCD + DHT22 sensor. The task at hand is following:

  1. Every second update the time on LCD
  2. Every 5 seconds update readings from DHT22 on LCD.

One restriction is that RTC has to be used: it has an external battery, so time isn't reset on Arduino power off.

And now confusion starts. So I have these three options to go with:

a. Use interrupts: set alarm on RTC to fire every second and on receiving an interrupt update time display and if (seconds%5 == 0) also update the humidity reading.

b. Use watchdog. Basically, same as option a, but watchdog would be source for interrupts. In this approach I particularly don't understand how to synchronise watchdog seconds with RTC seconds.

c. Use loop and RTC. Quite dull approach IMO: in loop() check if the the seconds value returned by RTC has changed and act accordingly.

Since 'c' is very inefficient, could anybody enlighten me on cons and pros of 'a' and 'b' please, and for 'b' in particular - how to sync watchdog with RTC. And even though the whole setup is going to be powered by wall wart, I'd still like to make it a power efficient as possible.
Thanks in advance!

Since 'c' is very inefficient

Whether it is inefficient, or not, depends on what else loop() is doing. If nothing, then efficiency doesn't matter.

Reading from the clock chip is fast. Evaluating a couple of comparisons won't take much time or processor power.

I particularly don't understand how to synchronise watchdog seconds with RTC seconds.

You have time as determined by the Arduino, which is a pretty inaccurate time keeper. You have time as determined by the RTC, which is generally pretty accurate. There is no syncing needed. When the watchdog fires, read the clock time.

To me b) and c) do not make sense. a) only makes sense if you don't use the RTC alarm but configure the RTC to interrupt the CPU every second using INT/SQW. I know this works because that is exactly what I do.

Whether it is inefficient, or not, depends on what else loop() is doing. If nothing, then efficiency doesn't matter.

By inefficient I've meant that loop is run multiple times per second and in this case reading each time from RTC is unneeded waste of resources.

You have time as determined by the Arduino, which is a pretty inaccurate time keeper. You have time as determined by the RTC, which is generally pretty accurate. There is no syncing needed. When the watchdog fires, read the clock time.

But if they're out of sync, there's no precision. Say, current time (RCT) is 00:00:01.9 and watchdog fires an interrupt, so LCD is update with time 00:00:01, which has a 0.9 sec delay from real time. Of course 1 second delay isn't crucial in my case, but I'd like it to be as precise as possible, thus a sync between watchdog and RTC seems to be a must.

b) and c) do not make sense

c) quite obviously doesn't (though, still works), but why b) doesn't make sense?

Another question is the memory usage. Is b) using more memory than a), given that I'd also have to include avr/wdt.h library?

stowite:
a) only makes sense if you don't use the RTC alarm but configure the RTC to interrupt the CPU every second using INT/SQW. I know this works because that is exactly what I do.

Could you please post an example how to send interrupt each second without using the alarm?

c) quite obviously doesn't (though, still works), but why b) doesn't make sense?

You have a perfectly good and accurate timer in the RT clock that, using an interrupt generated from SQW, can very accurately signal every second with minimum code. Why create a less accurate timer using more code? Why waste the watchdog resource, that you may need later, when you have an unused resource in the SQW.

antti_s:
Could you please post an example how to send interrupt each second without using the alarm?

Take a look at the datasheet and the configuration of the DS3231's SQW to provide a 1 second tick output.

antti_s:
By inefficient I've meant that loop is run multiple times per second and in this case reading each time from RTC is unneeded waste of resources.

Yeah so? It's not like the uC has anything else to do then?

antti_s:
But if they're out of sync, there's no precision.

Then fire the watchdog more often... OR be smart and use the SQW output of the RTC.

antti_s:
c) quite obviously doesn't (though, still works), but why b) doesn't make sense?

If the loop will run multiple times a second (like, thousands of times) like it should, then c has no noticable inaccuracy at all!

antti_s:
Is b) using more memory than a),

I don't think memory is an issue here. At least not regarding syncing to the RTC. I suspect more difference in memory use because of you not programming compact then the difference between a) and b).

Ow, and DON'T update the display in the interrupt. Just set a flag and check it in loop().

Computers and Arduinos exist to serve us. Having it query the RTC 10,000 times per second "Are we there yet?" is not inefficient. It doesn't 'waste' anything doing that.

Your time spent thinking up these elaborate interrupts and watchdogs is more valuable than the processor clock cycles. The more elaborate you make it, the more difficulty you will have with it. Get the simplest solution working first, then if you need those clock cycles do do something else in the future, you might try to optimise it.

septillion:
Yeah so? It's not like the uC has anything else to do then?

Well, actually it has some other things to do. In this topic I've only outlined the part of my project that I had problem understanding.

septillion:
Then fire the watchdog more often... OR be smart and use the SQW output of the RTC.

That's exactly why I've asked about a) vs b) in the first place.

septillion:
If the loop will run multiple times a second (like, thousands of times) like it should, then c has no noticable inaccuracy at all!

True, neither inaccuracy, nor optimisation:)

septillion:
I don't think memory is an issue here. At least not regarding syncing to the RTC. I suspect more difference in memory use because of you not programming compact then the difference between a) and b).

Given that code is same, including one more library takes more space, right?

septillion:
Ow, and DON'T update the display in the interrupt. Just set a flag and check it in loop().

At least this I was doing from the beginning, but thanks for the hint anyways.

So to sum up in case interrupts are needed every second:

  • Don't use alarms, use 1Hz SQW interrupt;
  • Don't update LCD inside interrupt method, set flag instead.

MorganS:
Computers and Arduinos exist to serve us. Having it query the RTC 10,000 times per second "Are we there yet?" is not inefficient. It doesn't 'waste' anything doing that.

Well, let me just say that from my POV your point is highly arguable.

MorganS:
Your time spent thinking up these elaborate interrupts and watchdogs is more valuable than the processor clock cycles. The more elaborate you make it, the more difficulty you will have with it. Get the simplest solution working first, then if you need those clock cycles do do something else in the future, you might try to optimise it.

I totally agree about making kind of "shitty first draft" that works and then optimising. First version I have (actually, using option c) from the first post), so now it's time for refactoring.

antti_s:
Well, actually it has some other things to do.

Time enough for that... So maybe it will now run 1000 times a second instead of 100.000 times a second, so? Just don't block the loop. And the most common block of the loop is the stupid delay() :wink:

antti_s:
Well, let me just say that from my POV your point is highly arguable.

From my POV it's not. And I think most will agree. At least untill you put power saving in the mix but that's not as simple as not poll the RTC. The micro doesn't draw a lot. And you can save all you want but if you turn on a led the saving is not significant anymore.

@septillion
Alright, so what exactly is the point of spamming the RTC multiple times per second with "are we there yet?" if the RTC itself can tell us "now we're there"?

Even though on this scale it might look like nothing: run 1K times instead of 100K and performance isn't affected, but I consider deliberately limiting the performance 100 times a bad design. I mean, it would be okay for learning and wouldn't affect small projects at all, but what's the point?

And yes, power saving isn't an issue here, but doing something that could be done once per second multiple times per second I consider inefficient.

I feel kind'a like we don't understand each other or talk about different aspects, especially if you say that most will agree.

Because what do you define as "are we there yet"? What's there? I think here you mean 1 second. Okay, that's fair. But what if we want to be there to be an hour? Isn't it then as wasteful to let the RTC tell us "I have no idea if we're there but 1 second has passed"? Okay, you could set an alarm. So you disable the SQW and set an alarm. Great, we get a "we are there" if it's a certain time. We set a second alarm. The "we are there" now becomes a "we are there or there, just ask me". Okay, fair. But how about a third?

Also, it doesn't give us a "we are there", it tells "we passed another fixed distance".

Or the same principle, only now we don't ask a external device but it does not matter, blink without delay. Is it wasteful to ask 100k a second if 10 seconds have passed?

antti_s:
but I consider deliberately limiting the performance 100 times a bad design.

Then don't limit it to 100 times and make better/faster code...

But yeah, here you have a nice SQW so it's just as easy to use it then.

Alright, now I got your point, but I'm afraid you didn't completely get mine. I wasn't suggesting an ultimate solution for every existing issue. I meant, that in my case specifically, using the SQW is the optimal solution.

The general point I was trying to make is to use only those resources, that you really need for particular task.
But in case of need to set 3+ alarms, I'd first check if the times have a common denominator and set one alarm accordingly, even if common denominator is 1 second. If even that isn't the case, I don't see another approach except for spamming RTC from loop().

Yeah, it would be the easiest in this case to just use SQW. But if you for example don't have a spare pin left there is nothing wrong with spamming the RTC. And you could limit the number of requests. Do it every 100ms, which is just 10 times a second, and a user will never notice.

And as far as alarms, as long I don't put the device to sleep I would implement them all in software on the Arduino anyway :stuck_out_tongue:

Maybe someone else will need to add functionality in the future.

Probably they will complain for your unthoughtful use of delay() or abuse of "processing power", but in the end most helpful to their human-time resource is to look at a code that is short and easy to understand. Let them bother with optimizations in the unlikely case they-ll need to.