Во-первых надуманно, во-вторых есть методы обхода. Да, у каждого модуля есть функция, которую нужно вызывать регулярно. Не обязательно раз в 10мс, как можно чаще, но не реже, чем раз в 100мс -- вот так верней. Функция внутри сама проверяет время (как описано выше). Собственно main превращается в:
int main()
{
clock_t T;
/* do some initialization.. */
module1_init();
module2_init();
...
/* main loop */
while (1) {
T=clock();
module1_func();
module2_func();
...
/* в данной строчке процессор ненадолго
* засыпает, если в цикле все модули не
* потребили много процессорного времени,
* что позволяет экономить энергию... */
if (clock()-T < NNN) usleep(XXX);
}
}
А модули собственно превращаются в такое:
#include "clock.h"
void module1_init(void)
{
...
}
void module1_func(void)
{
switch (state) {
case STATE1:
...
break;
case STATE2:
if (clock() - T < DELAYTIME) break;
do_something();
break;
}
}
Если забыть в главный цикл функцию -- работать не будет. Но не заметить это сложно. Управлять таймером -- не нужно, это просто "счётчик времени" который просто считает.
Тут поднят ещё такой вопрос:
Как говорят знающие люди - программу нужно разбивать на модули - си, асм, не важно. Чем меньше внешних функций позволяет вызывать модуль - тем понятнее его работа и ниже связанность модулей в программе, то есть понятнее вся программа.
Против этого есть метод обхода. Как бы "динамическое связывание", уже после запуска программы. Если, например, какой-то модуль хочет получать прерывания от таймера, но не хочется явно его функцию вносить в модуль таймера (вот где лишняя связность явно вредна), то можно поступить таким образом: в функции module1_init() вызывается функция из модуля таймера и ей аргументом передаётся ссылка на функцию из модуля светодиода, которую нужно вызывать когда таймер срабатывает. Недостаток такого метода -- ссылки на функции плохо работают в профессиональных компиляторах и на профессиональных контроллерах PICC18...