millis(0 - стандартная функция Ардуино, возвращает uint32_t, кол-во миллисекунд с момента старта. Об атомарности позаботились в ней. Но поначалу, когда-то давно, я под 8-битные Ардуино об атомарности заботился сам:
// ========================================
// Scheduler invokes user tasks
// ========================================
void Coos::run_scheduler(void)
{
int res;
char rdy;
void (*tsk)(void);
// --------------------------
// Init tasks
// --------------------------
for (task_no=0; task_no<COOS_MAX_TASKS; task_no++)
{
if (tsk_p[task_no] != 0) // if task was registered
{
res = setjmp(main_context);
if (res == 0)
{
tsk = tsk_p[task_no];
tsk(); // invoke task
}
else
{
cli();
task_delay[task_no] = --res; // task returns required delay
sei();
}
}
}
// --------------------------
// Scheduler loop
// --------------------------
task_no = 0;
while(1)
{
cli(); // ensure atomic check
if (task_delay[task_no] == 0) // if task is active
rdy = 1; // set "ready" flag
else
rdy = 0;
sei();
if (rdy)
{
res = setjmp(main_context); // set return point and get delay value from the task
if (res == 0) // after setting return point
{
longjmp(task_context[task_no], 1); // invoke task
}
else // after returning from task
{
cli(); // must be atomic
task_delay[task_no] = --res; // set task delay (negative delay - task stopped)
sei();
}
}
if (++task_no >= COOS_MAX_TASKS) // next task
{
task_no = 0; // round-robin
}
}
}
// ========================================
// Timer0 compare ISR, 1 ms
// ========================================
ISR(TIMER0_COMPA_vect)
{
uint i;
for (i=0; i<COOS_MAX_TASKS; i++)
{
if (coos.task_delay[i] > 0)
{
coos.task_delay[i]--;
}
}
}