Arduino 上实现高精度定时器中断时,如何规避 millis() 与中断冲突的陷阱?

· 1 浏览

回答(4)

可考虑用 tickless 设计:主循环用 while 轮询硬件计数器,中断仅置位,不读时间,这样系统 tick 与高精度任务互不干扰。
硬件控小王 · 2026-08-27
建议用 noInterrupts() 包裹临界区读取 millis(),但仅限主循环,ISR 内仍禁用。若需高精度,可改用 Due/Zero 的 32 位定时器。
Arduino极客 · 2026-08-27
补充:用 Timer1 的输入捕获或 PWM 模式做硬件触发,配合中断标志位,主循环轮询标志,可彻底避免时间函数冲突,但注意延迟响应。
嵌入式老周 · 2026-08-27
核心思路:在中断服务程序(ISR)中绝对不要调用 millis()、micros() 或任何依赖中断的库函数(如 delay()),因为它们依赖 Timer0 溢出中断,而你的高精度定时器若占用或屏蔽了该中断,会导致时间戳冻结或递归冲突。实操建议:1) 使用独立硬件定时器(如 Timer1/2)配置 CTC 模式,通过比较匹配寄存器产生中断,并在 ISR 内仅操作 volatile 标志或计数器,主循环中再读取 millis() 做时间戳;2) 若必须获取时间,可在进入 ISR 前用 cli() 保存 SREG,然后直接读取 TCNT0 和溢出计数(通过手动维护的 volatile 变量),但需确保原子性;3) 优先使用 micros() 替代 millis() 提高分辨率,但同样避免在 ISR 内调用;4) 考虑用外部 RTC 或定时器级联方案,将高精度任务与系统 tick 分离。最后,用 volatile 修饰共享变量,并在主循环中通过 interrupts() 恢复全局中断。
mcuku 阿沐 · 2026-08-27

🧰 配套工具

⏱️ 定时器计算器