#include "sched.h" #include #include #include "hal_time.h" void sched_periodic_init(sched_periodic_t *p, uint32_t period_ms) { assert(p != NULL); assert(period_ms > 0); /* 事件驱动的任务不该走这里 */ p->period_ms = period_ms; p->next_ms = hal_time_now_ms() + period_ms; p->cycles = 0; p->overruns = 0; p->worst_late_ms = 0; } uint32_t sched_periodic_delay_from(sched_periodic_t *p, uint32_t now_ms) { assert(p != NULL && p->period_ms > 0); p->cycles++; /* ⚠️ 一律用有符号差判先后,不要写 `now >= next`。 32 位 ms 在 49.7 天回绕,农场是长稳跑的,回绕一定会发生 —— 裸比较会在回绕那一刻把「还早着呢」判成「已经迟到了」, 现象是巡检突然连着空转 49.7 天份的周期。 */ const int32_t late = (int32_t)(now_ms - p->next_ms); if (late < 0) { const uint32_t delay = (uint32_t)(-late); p->next_ms += p->period_ms; return delay; } /* 到点了活还没干完。跳过错过的整周期、保住相位,见 sched.h。 */ p->overruns++; if ((uint32_t)late > p->worst_late_ms) { p->worst_late_ms = (uint32_t)late; } const uint32_t missed = (uint32_t)late / p->period_ms + 1u; p->next_ms += missed * p->period_ms; return 0; } uint32_t sched_periodic_wait(sched_periodic_t *p) { const uint32_t delay = sched_periodic_delay_from(p, hal_time_now_ms()); if (delay > 0) { hal_time_delay_ms(delay); } return delay; }