Timed task list

400 views Asked by At

I am looking for help on embedded application on 16bit device. I need to run several simple "tasks/functions" via function pointers. Those tasks run in predeterimned intervals.

typedef struct
{
  int  timeToRun;
  void (*fcn)(void);

} task_t;

task_t tasks[] =
{
  { 13_MSEC,  fcn1 },
  { 50_MSEC,  fcn2 },
  { 0, NULL }
};

volatile unsigned int time;   

main()
{

  for (ptr = tasks; ptr->timeToRun !=0; ptr++)
  {
    if (!(time % ptr->timeToRun))
       (ptr->fcn)();
  }
}

I have possibility to run timer interrupt at 1ms.

interrupt void TimerTick(void)
{
 time++;
}

Any idea how to calculate elapsed time? How to make sure that % (modulo) works in definded rate if time overflows. Anyway how to avoid time overflow and have correct timing via % (modulo)?

2

There are 2 answers

0
AShelly On BEST ANSWER

I would do something like this:

typedef struct
{
  unsigned int nextRunTime
  int  period;
  unsigned int  rollover;
  void (*fcn)(void);
} task_t;


main()
{
  //setup goes here
  /*...*/
  //loop
  while (1)
  {
     for (ptr = tasks; ptr->period!=0; ptr++)
     {
       if ((time > ptr->nextRunTime) && (time <= ptr->rollover) )
       {
           ptr->nextRunTime+=ptr->period;
           ptr->rollover = (ptr->nextRunTime < ptr->period)? 2*ptr->period : 0xFFFF;
           (ptr->fcn)();
       }
       ptr->nextRunTime = timeToRun;
     }
  }
}

This should work as long as you can guarantee that a) no period is greater than half the rollover time (0x8000 ms), and b) you can execute all the functions within the shortest period.

0
Lundin On

Here is some code from a very similar app of mine, suitable for small MCU applications, and MISRA-C conformant. It is based on allocation of "software timers" statically in the calling app. Multiple modules in your project can use the same timer module, as it is using a linked list internally to keep track of all timers.

Call tim_traverse_timers() from your 1ms interrupt. If you have very high accuracy demands, you may have to clear the interrupt source before calling the function, so that the "code jitter" overhead from the function itself doesn't affect the timer.

If you have need for longer delays then 65535ms, simply change the counter and interval to uint32.

    typedef struct timer
    {
      struct timer* next;                            /* Next timer in the linked list   */

      uint16 counter;                                /* 16-bit timer counter            */
      uint16 interval;                               /* The interval between triggers   */
      BOOL   is_enabled;                             /* Timer enabled/disabled          */

      void (*callback_func)(void);                   /* Callback timer function         */

    } Timer;



    static Timer* timer_list;


    void tim_init (void)
    {
      timer_list = NULL;
    }

    void tim_add (Timer*   timer,
                  void (*  callback_func)(void),
                  uint16   interval_ms,
                  BOOL     enabled)
    {
      tim_enable_interrupt (FALSE);                  /* hardware function disabling timer interrupt */

      timer->callback_func  = callback_func;
      timer->counter        = 0U;
      timer->interval       = interval_ms;
      timer->is_enabled     = enabled;

      timer->next           = timer_list;
      timer_list            = timer;

      tim_enable_interrupt (TRUE);
    }



    void tim_enable (Timer* timer, BOOL enable)
    {
      if(enable)
      {
        timer->counter    = 0U;                      /* Reset counter each time function is called */
      }

      timer->is_enabled = enable;
    }

    void tim_traverse_timers  (void)
    {
      Timer* timer;

      for(timer=timer_list; timer!=NULL; timer=timer->next)
      {
        if(timer->is_enabled == TRUE)
        {
          timer->counter++;

          if(timer->counter == timer->interval)
          {
            timer->counter = 0U;
            timer->callback_func();
          }

        }
      }
    }

#include "timer.h"

void my_func (void);  /* lights some LED etc... */
void my_other_func (void);

void main (void)
{
  Timer some_task;
  Timer some_other_task;
  ...

  tim_init();
  ...

  tim_add(&some_task, &my_func, SOME_DELAY_IN_MS, TRUE);
  tim_add(&some_other_task, &my_other_func, SOME_OTHER_DELAY_IN_MS, TRUE);
  ...


}