首页 > 解决方案 > 如何使用定时器在 2 秒后关闭数字输出

问题描述

我有一个 Atmega328p,想通过按下按钮打开数字输出,然后在 2 秒后自动关闭。

我知道如何为按钮使用硬件中断,但如何设置定时器中断以自动关闭数字输出?


更新:

我能够弄清楚。这是我的解决方案(仅显示相关功能):

static inline void initTimer1(void) {

    TCCR1B |= (1 << WGM12);  // CTC Mode, immediate
    TCCR1B |= (1 << CS10) | (1 << CS12);  // Clock speed: 16 MHz / 1024, ~= 15.6 ticks per ms

}

void set_valve_on_time(uint16_t on_time) {

    OCR1A = on_time;  // set output compare register for valve on time

}

void open_valve(uint8_t state) {

    if (state > 0) {
        PORTD |= (1 << PIND6);  //turn on PD6, open valve
        PORTD &= ~(1 << PIND7);  //turn off PD7, turn off close valve in case it was on
        if (state == 2) {
            TCNT1 = 0;
            TIFR1 |= (1 << OCF1A);  // clear output compare match flag
            TIMSK1 |= (1 << OCIE1A);  // enable output compare interrupt
        }
    }
    else {
        PORTD &= ~(1 << PIND6);  //turn off PD6, stop opening valve
    }   

}

ISR(TIMER1_COMPA_vect) {

    TIMSK1 &= ~(1 << OCIE1A);  // disable output compare interrupt
    open_valve(0);  //turn off close valve output

}

按下按钮(未显示)调用 open_valve 函数。我遇到的最困难的时候是弄清楚我需要 TIFR1 |= (1 << OCF1A) 它才能正常工作。我仍然不太明白为什么,因为我认为 ISR 应该自动执行此操作。

标签: timerinterruptavratmega

解决方案


您必须大致遵循以下步骤:

  • 在您的按钮处理例程中设置具有以下属性的计时器:
    • 在 CTC 模式下最好使用 16 位定时器(如果你有可用的空闲定时器)
    • 设置预分频器,使定时器的其他流比您的比较值慢一点:
      对于 2 秒和 10MHz CPU 频率,我将在 1/1024 预分频器上运行它,因此在 (10.000.000/1024/65536) -> 上会发生溢出每约 6.7 秒 1 次溢出(265 次溢出比每 2 秒更频繁)
    • 将 ctc 最高值(请参阅所选模式的说明 - 特定寄存器会有所不同)设置为 2s 后达到的值:10.000.000/1024 * 2s --> 19531
  • 实施 ISR(查看在所选 CTC 模式下哪个是正确的)并激活屏蔽寄存器中的中断
    • 在 ISR 中设置你的输出,并停止计时器
  • 奖励:设置它使用输出比较引脚来停用输出的定时器
    然后根本不需要 ISR,只需将比较输出模式设置为“匹配时清除”

如果您没有可用的 16 位定时器,我建议在 CTC 模式下使用 1 个定时器来生成(10)毫秒时基,并在此 ms 事件处理中实现时间计数逻辑。


推荐阅读