Timing control within a loop - Sending data at exact intervals [closed]

We have a program where we are sending data wirelessly through GPRS. We retrieve values from ADCs, do our calculations, display it on the screen and also send it to remote servers. The loop can be though of as this

while(1)
{
_ReadADC();
_LCD_Display();
_DoCurrentCalcultions();
_SendCurrentData();  /* I want to send this data exactly every minutes */
}


The problem that I am facing right now is occasionally data is not send successfully so there are skipping, but that is not what I am concerned about.

I want to be able to send data exactly every time, e.g. 11:00:00, 11:01:00, 11:02:00 note that the second value remains same only minute value changes. Now I do not have Real Time Clock (RTC) on my board but definitely have timers. What I am thinking is that I should give some slack time in my loop and if the calculations take more or less time, I should adjust that time in the slack and send data precisely every minute.

How can I do that, it has been long since I did embedded systems programming.

• Sending data every minute is different to sending data at 11:00:00, 11:01:00... - does it matter if it's 11:00:39, 11:01:39..? Aug 15, 2018 at 8:16
• It does not matter, the interval should be exact 1 min 0 sec. 11:00:05, 11:01:05, 11:02:05 is all good too. I can live with a few seconds variation though. Aug 15, 2018 at 8:25
• The accuracy will only be as good as your oscillator. The clock will drift over time if you don't have a RTC. Aug 15, 2018 at 11:47
• But wouldn't an RTC drift over time because of Oscillator? Aug 15, 2018 at 12:04
• @engineer It will drift, but to a lesser extent since it is specifically designed not to. I think you should specify tolerances, since nothing is 100% precise. Aug 16, 2018 at 12:49

2 Answers

You need to use a timer peripheral. Set it up to generate an interrupt every minute. The interrupt should set a global flag (remember to make it volatile). The main loop polls the flag and checks if one minute has elapsed, clears the flag, then prepares the data and sends it.

If you can't configure the timer to make minute intervals, then try to set it to one second intervals, also set a flag in the interrupt handler (name is for example newSecond). The main loop just has to clear the flag, increment a counter and when it reaches 60 prepare the data to send (and reset the counter).

• We are currently not using interrupts. So will this method work in polling (loop)? I think this method would require to use interrupts. Aug 15, 2018 at 8:48
• If you really can't use interrupts then you can just poll the overflow/match flag of the hardware timer in the main loop.
– filo
Aug 15, 2018 at 8:58
• But I want to know how to implement slack as well, for that scenario. The loop is doing a lot of things (I have oversimplified above) and its timing is not guaranteed in any ways. Aug 15, 2018 at 9:00
• If your main loop timing is not guaranteed in any way then........ you can not guarantee any timing. Period. Do measurements first, see what is the average execution time, try to estimate the worst execute time etc.
– filo
Aug 15, 2018 at 9:04
• You really don't do firmware like that. Most of the time the main loop functions just check some flags that are set/cleared by interrupts. If there is nothing to do the main loop puts the MCU into sleep mode to wait for another interrupt.
– filo
Aug 15, 2018 at 9:10

1) First of all, GPRS is a best-effort service, so it's latency is variable. You can try all you want to achieve timing precision, but if bandwidth is not available all that would be for nothing.

2) There are two preferred patterns for applications like yours:

• In power-saving pattern the device is put asleep between sampling/sending. Either external nano-power timer or internal watchdog is used to generate wake-up event. Note that wake-up period can be smaller than required sending period, which gives your code an opportunity to prepare data in advance and send it immediately upon certain timer tick.
• In precision pattern the main loop constantly reads ADC and uses oversampling/rolling average to counter ADC fluctuations. This leaves you with frequently updated value that you can use for your calculations either on every sample or at some intervals. The interrupt from either external or internal timer is used to trigger sending procedure, making sending period independent from the calculation code. This requires somewhat complex task management support because it is not a good idea to do long processing in the interrupt function itself. A simpler variant of this would be to assert "time to send" flag in the interrupt and pepper your long-running code with calls to "check the flag and send when ready" procedure.

3) In both patterns above the timer interrupt is used. Carefully chosen external timer can give you great precision out of the box, but it complicates the schematics. Given uncertain nature of GPRS the precision of internal MCU timers should be sufficient. MCU datasheets usually include detailed description of calibration procedure for RTC, which is ideal for this purpose.

4) No timer is precise. Even very good crystal-based external timer will have some drift. This is exactly the reason I suggested internal MCU timers in the first place, as they are precise enough over certain time period. In the long run you can utilize your GPRS connection for clock synchronization. The simplest would be NITZ service when it is available from current provider, however if you have internet connection you can try using NTP as well.

5) Finally, make sure this is not a XY problem. Ask yourself this: do you want to send data at fixed time only because you need to know when it was obtained? If yes, then simple preparation timestamp on the data allows it to be sent at irregular intervals, removing dependency on GPRS latency and calculation time. You still need precise timer to sign your data, but otherwise your code can do calculations and send results without hard timing constraints.

• Our product sense data remotely and then send it over GPRS. We want to make sure, values are captured every minute(with +-5 sec variation). If also want to track if GPRS failed to send a particular packet (as it can happen). The man reason for exact 1 min interval is part of standardization. Aug 27, 2018 at 5:44
• Well, then this does look like XY problem. As described in 5), you can easily capture data with microsecond precision, timestamp it and send whenever GPRS bandwidth becomes available. Your code can even use all free RAM as a buffer in case of temporary connection problems, so no data will be lost. Aug 27, 2018 at 7:25
• yes that's what I have in mind but we are using loop (vs Interrupt) and I am not exactly sure how to capture data with that precision, as certain tasks inside loop may take longer/shorter. Aug 27, 2018 at 8:11
• I don't understand the comment. If interrupt is what gives you required precision then it is what you should be using. Are you saying that you are designing industrial solution while unable to write code properly?! Also, in 2) I gave you simplified variant that can be used with polling instead of interrupts while still delivering more than required precision, something like milliseconds range. The code will be ugly, though. Aug 27, 2018 at 9:15
• we have existing code and a product. But it lacks the precision which I want to add. We are using the precision mode as supply is form power lines directly. So you think even though we are using loop, we should use interrupt for sending data. That looks like a mix solution to me (loop+interrupt), not sure if it might pose unseen problems. Aug 27, 2018 at 9:19