You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ATmega328的Timer1停止时是否触发输入捕获中断?

ATmega328 Timer1停止时的输入捕获中断触发问题

核心结论

当Timer1处于停止状态(预分频器未使能,计数器不计数)时,ICP1引脚上的下降沿仍然会触发TIMER1 CAPTURE中断,同时会将当前TCNT1的值(手动清零后即为0x0000)锁存到ICR1寄存器中。

原理依据

ATmega328的输入捕获触发逻辑与计数器运行状态是解耦的:

  • 捕获事件的检测由ICP1引脚的边沿变化直接触发,只要满足三个条件:
    1. 捕获中断使能位TICIE1(TIMSK1寄存器)已置1
    2. 全局中断标志SREG.I已置1(通过sei()开启)
    3. 捕获触发边沿配置正确(TCCR1B.ICES1设为0,对应下降沿触发)
  • 无论计数器是否在运行,边沿事件都会触发中断请求,同时锁存当前TCNT1的值到ICR1——哪怕计数器处于停止状态,TCNT1保持初始值(手动清零后就是0x0000),这个值依然会被正常锁存。

针对DCC信号测量的优化实现

你的优化思路完全可行,具体步骤可以这样做:

  1. 初始化配置:
    • 清零TCNT1寄存器:TCNT1 = 0;
    • 配置ICP1引脚为输入(默认就是输入,无需额外配置,除非之前设为输出)
    • 设置捕获触发边沿为下降沿:TCCR1B &= ~(1 << ICES1);
    • 开启捕获中断:TIMSK1 |= (1 << TICIE1);
    • 开启全局中断:sei();
    • 此时Timer1保持停止状态(TCCR1B的CS12~CS10都设为0)
  2. 中断服务程序(ISR):
    ISR(TIMER1_CAPT_vect) {
        // 读取ICR1,自动清除ICF1中断标志
        uint16_t capture_val = ICR1;
        
        // 第一次捕获时,capture_val为0x0000,此时启动Timer1
        static uint8_t timer_started = 0;
        if (!timer_started) {
            // 设置预分频为fCLK/8,启动计数器
            TCCR1B |= (1 << CS11);
            timer_started = 1;
        } else {
            // 后续捕获的capture_val就是脉冲时长,直接处理DCC信号
            process_dcc_pulse(capture_val);
        }
        
        // 清零TCNT1,为下一次捕获做准备
        TCNT1 = 0;
    }
    
  3. 注意事项:
    • 必须手动清零TCNT1,避免初始值不为0的情况
    • 读取ICR1会自动清除ICF1标志,无需额外写1清零
    • 确保在第一次捕获后才启动定时器,避免计数器提前运行导致初始值偏差

内容的提问来源于stack exchange,提问作者Laura

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 05:10:32