# Thread: timing algorithm, assistance required,

1. ## timing algorithm, assistance required,

hi all,

I'm programming a Pic, and have it up and running bare code, but i wish to control three relays, one closes every three seconds, for 1 second duration, another during the first relays activation only for 0.1 of a second. The third closes for 120 seconds, every seven days..... i am reverting to drawing diagrams, but any assistance greatly welcomed as i am struggling a bit on how to approach this.

many thanks

SB

2. 7 days in 0.1 second intervals is 6,048,000

You can either do
Code:
```for ( int i = 0 ; i < 6048000 ; i++ ) {
sleep(0.1);
}```
Or arrange an interrupt every 0.1 sec and call
Code:
```volatile int counter = 0;
void isr ( void ) {
if ( ++counter == 6048000 )
counter = 0;
}```
The rest is just working out what value(s) represent which state(s)

3. Originally Posted by Salem
7 days in 0.1 second intervals is 6,048,000

You can either do
Code:
```for ( int i = 0 ; i < 6048000 ; i++ ) {
sleep(0.1);
}```
Or arrange an interrupt every 0.1 sec and call
Code:
```volatile int counter = 0;
void isr ( void ) {
if ( ++counter == 6048000 )
counter = 0;
}```
The rest is just working out what value(s) represent which state(s)
thanks salem,

its more a question of structure as timing is easy, the inter-relationship of the actuation of the relays is my concern,

4. The smallest period of time you must deal with is 0.1s, so you need to count everything in tenths of a second.

Salem showed you how to count out a 7-day period. Now, you need to apply that to your other relays.

Each relay has a period, the time it takes to repeat the on-off pattern. Thankfully you have a simple pattern, which repeats after just a single on and single off.

Relay 1 has a 3 second period, which is ??? tenths of a second.
Relay 2 also has a 3 second period, which is ??? tenths of a second.
Relay 3 has a 7 day period, which we know is 6048000 tenths of a second.

So you need one counter for the 3 day period relays and one counter for the 7 day period relay. Figure out what values for each counter should correspond to each relay opening/closing; Perhaps draw a timeline and label the open/close points and timer reset point. Then, constuct a simple if/else-if chain for each timer that covers all the open/close and reset values.

5. i do have a concern in that my hardware is outputting to lcd every second, the short time cycles will not allow the per sec update of the lcd, so i need something a bit more refined i fear,,

steven

6. Your main time interval is three seconds. Every seven days or 7×24×60×60/3 = 201,600 intervals, the third relay is active for 120/3 = 40 intervals. That is, the third relay is deactive for 201,560 intervals, then active for 40.

During each three-second interval, you have the following events:

+0.0 seconds: Update LCD
+0.0 seconds: Activate latch 1
+0.0 seconds: Activate latch 2
+0.1 seconds: Deactivate latch 2
+1.0 seconds: Update LCD
+1.0 seconds: Deactivate latch 1
+2.0 seconds: Update LCD

The next interval is just like above, just three seconds later.

The first 201,558 intervals are as as above. The 201,559th interval, you also activate latch 3 at +0.0 seconds. The next 38 intervals are as above. The 201,599th interval, you also deactivate latch 3 at +0.0 seconds. Then, you start from the beginning.

Depending on the relative offsets of the latch triggers and LCD updates, you'll want to adjust the details above, but as I see it, it's pretty straightforward.

I would personally also use a reliable RTC, and if supported by your PIC and the RTC, use a low-power sleep to wait for the next interesting event to happen. It is often easier to consider the intervals rather than the absolute time when something happens, but you need an RTC or other reliable clock source to sync to (using the 1Hz output many RTCs provide), to avoid drifting (because the work done at each event takes a bit of time, and we don't know exactly how long, and it might even vary).

Questions?

7. thanks for input,

i have realised my application requires flexibility, in that the on periods, and the time also between events for each relay has to be flexible, so i will have to use seconds, the application i have may need to be 2 seconds on, etc. i will post my first attempt, i suppose i am realising the problem as i am going along here, but thanks for everyones input thus far, its a great help,

steven

8. How about something like the following simulator code:
Code:
```#include <stdio.h>

/* Let's assume we use 0.1 second precision. */
#define PER_SEC         10

/* LCD updates. Happen at the start. */
#define LCD_PERIOD      (PER_SEC)
#define LCD_UPDATE      (0)

/* Relay states. */
#define RELAY_WAIT      0   /* Before activation */
#define RELAY_ON        1   /* Active */
#define RELAY_OFF       2   /* After activation */

/* Relay 1 state durations. */
#define RELAY_1_WAIT    (1*PER_SEC)
#define RELAY_1_ON      (1*PER_SEC)
#define RELAY_1_OFF     (3*PER_SEC - RELAY_1_ON - RELAY_1_WAIT)

/* Relay 2 state durations. */
#define RELAY_2_WAIT    (15*PER_SEC/10)
#define RELAY_2_ON      (1*PER_SEC/10)
#define RELAY_2_OFF     (3*PER_SEC - RELAY_2_ON - RELAY_2_WAIT)

/* Relay 3 state durations. */
#define RELAY_3_WAIT    (7*24*60*60*PER_SEC - RELAY_3_ON - RELAY_3_OFF)
#define RELAY_3_ON      (120*PER_SEC)
#define RELAY_3_OFF     (0)

int main(void)
{
long    lcd_ticks = LCD_UPDATE;
long    relay_1_ticks = RELAY_1_WAIT;
long    relay_2_ticks = RELAY_2_WAIT;
long    relay_3_ticks = RELAY_3_WAIT;
long    ticks, sleepticks;
char    relay_1_state = RELAY_WAIT;
char    relay_2_state = RELAY_WAIT;
char    relay_3_state = RELAY_WAIT;

sleepticks = 0L;

while (1) {
/* Obtain actual elapsed time using
*     prev_timer = curr_timer;
*     curr_timer = timer();
*     ticks = curr_timer - prev_timer;
* where timer() is an RTC at PER_SEC resolution.
* Note that you should check for wraparound (in ticks),
* the following code assumes ticks is >= 0 and small.
*
* Here, we just assume our sleep was perfect.
*/
ticks = sleepticks;

lcd_ticks -= ticks;
if (lcd_ticks <= 0L) {
printf("Update LCD.\n");
lcd_ticks += LCD_PERIOD;
}

relay_1_ticks -= ticks;
while (relay_1_ticks <= 0L)
switch (relay_1_state) {
case RELAY_WAIT:
relay_1_state = RELAY_ON;
relay_1_ticks += RELAY_1_ON;
printf("Activate relay 1.\n");
break;
case RELAY_ON:
relay_1_state = RELAY_OFF;
relay_1_ticks += RELAY_1_OFF;
printf("Deactivate relay 1.\n");
break;
default:
relay_1_state = RELAY_WAIT;
relay_1_ticks += RELAY_1_WAIT;
}

relay_2_ticks -= ticks;
while (relay_2_ticks <= 0L)
switch (relay_2_state) {
case RELAY_WAIT:
relay_2_state = RELAY_ON;
relay_2_ticks += RELAY_2_ON;
printf("Activate relay 2.\n");
break;
case RELAY_ON:
relay_2_state = RELAY_OFF;
relay_2_ticks += RELAY_2_OFF;
printf("Deactivate relay 2.\n");
break;
default:
relay_2_state = RELAY_WAIT;
relay_2_ticks += RELAY_2_WAIT;
}

relay_3_ticks -= ticks;
while (relay_3_ticks <= 0L)
switch (relay_3_state) {
case RELAY_WAIT:
relay_3_state = RELAY_ON;
relay_3_ticks += RELAY_3_ON;
printf("Activate relay 3.\n");
break;
case RELAY_ON:
relay_3_state = RELAY_OFF;
relay_3_ticks += RELAY_3_OFF;
printf("Deactivate relay 3.\n");
break;
default:
relay_3_state = RELAY_WAIT;
relay_3_ticks += RELAY_3_WAIT;
}

/* Now, determine how long to sleep. */
sleepticks = lcd_ticks;
if (relay_1_ticks < sleepticks)
sleepticks = relay_1_ticks;
if (relay_2_ticks < sleepticks)
sleepticks = relay_2_ticks;
if (relay_3_ticks < sleepticks)
sleepticks = relay_3_ticks;

printf("Sleep for %.1f seconds.\n", (double)sleepticks / 10.0);

}

/* Never reached; press Ctrl+C to break. */
return 0;
}```
Note that I deliberately didn't use arrays, as this is microcontroller code, and I wanted to make it as easy as possible to add per-relay quirks later on.

Using while instead of if allows you to use zero duration for some events. For example, the third latch has zero "off" duration, i.e. it turns off exactly at the start of a new period.

At 0.1 second precision, 32-bit signed ints can hold a period of over six years. Note that the ticks variables do need to be signed, in case you occasionally sleep maybe one or few ticks longer than intended. (If you just zero the ticks variables, you'll induce clock drift between the latches/LCD.)

Instead of compile-time constants, you can use variables to hold the durations. If you have an UI for the device (say, a small LCD display with three to five buttons), you could let the user reprogram the intervals (saving to spare variables), then copy all the states at once to the ticks and states variables ("update now?"), to resync or start a new period. State durations can be modified at any time, but they won't take effect until the next time that state is entered into.

Questions?

9. I strongly favor Salem's second suggestion in post #2. This will not only follow the recommended "one interrupt per microcontroller" rule, but will create a neat, time-driven architecture that seems perfectly suited for your application.

In fact, this is the crux of the book "Embedded C" by Michael Pont, which I'd recommend as a read.

i do have a concern in that my hardware is outputting to lcd every second, the short time cycles will not allow the per sec update of the lcd, so i need something a bit more refined i fear,,
This is a non-issue with a time-driven architecture.