Список временных задач
Я ищу помощь по встроенному приложению на 16-битном устройстве. Мне нужно запустить несколько простых "задач / функций" через указатели функций. Эти задачи выполняются с заранее заданными интервалами.
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)();
}
}
У меня есть возможность запустить прерывание по таймеру на 1 мс.
interrupt void TimerTick(void)
{
time++;
}
Есть идеи, как рассчитать прошедшее время? Как убедиться, что% (по модулю) работает с определенной скоростью, если время переполнено. В любом случае, как избежать переполнения времени и иметь правильную синхронизацию через% (по модулю)?
2 ответа
Я бы сделал что-то вроде этого:
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;
}
}
}
Это должно работать до тех пор, пока вы можете гарантировать, что a) ни один период не будет превышать половины времени пролонгации (0x8000 мс), и b) вы сможете выполнить все функции в течение кратчайшего периода.
Вот код из моего очень похожего приложения, подходящего для небольших приложений MCU, и совместимого с MISRA-C. Он основан на статическом размещении "программных таймеров" в вызывающем приложении. Несколько модулей в вашем проекте могут использовать один и тот же модуль таймера, так как он использует внутренний список для отслеживания всех таймеров.
Вызовите tim_traverse_timers() из прерывания в 1 мс. Если у вас очень высокие требования к точности, вам может потребоваться очистить источник прерывания перед вызовом функции, чтобы издержки "дрожания кода" самой функции не влияли на таймер.
Если вам нужны более длительные задержки, чем 65535 мс, просто измените счетчик и интервал на 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);
...
}