C for AVR 应用 - ISR 重复

C for AVR Application - ISR Repetition

我正在尝试让一个简单的中断例程在 ATMega328P 上工作。有一个 LED 连接到 PD6,PB7 上有一个内置按钮。 LED 应该正常闪烁,直到按下按钮,然后在恢复闪烁之前稳定 1.5 秒。这是代码:

#define F_CPU 16000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

int main(void)
{
    // Enable pull-ups and set pin directions
    MCUCR |= (1<<PUD);
    PORTD &= ~(1<<PORTD6);
    DDRD |= (1<<DDD6);
    PORTB |= (1<<PORTB7);
    DDRB &= ~(1<<DDB7);

    // Enable pin change interrupt
    PCICR = 0x01;
    PCMSK0 = 0x80;
    sei();

    while (1) 
    {
        // Blink LED at standard rate
        _delay_ms(500);
        PORTD ^= (1<<PORTD6);
        _delay_ms(500);
        PORTD ^= (1<<PORTD6);
    }
}

ISR(PCINT0_vect,ISR_BLOCK)
{
    PORTD &= ~(1<<PORTD6);
    _delay_ms(500);
    PORTD |= (1<<PORTD6);
    _delay_ms(1500);
    PORTD &= ~(1<<PORTD6);
}

中断正确触发,但 ISR 例程循环两次。我想这是某种按钮弹跳问题,但我不熟悉如何处理它。我尝试在开始时引入 500 毫秒延迟,我还尝试清除 ISR 中的引脚更改中断标志,这样它就不会再次触发,但它仍然会触发。在此先感谢您的帮助!

让我们在 LED 亮起 1.5 秒时忽略任何按钮按下的基础上工作。你可以这样写你的中断处理程序:

ISR(PCINT0_vect,ISR_BLOCK)
{
    button_pressed = 1;
}

并将其放在代码顶部的旁边:

volatile int button_pressed = 0;

(请参阅 this page 了解有关 volatile 的全部内容以及此处需要它的原因的信息。)

然后你的主循环看起来像这样:

while (1) 
{
    // Blink LED on and off

    PORTD |= (1<<PORTD6);   // Turn LED on.
    if (button_pressed) {
        _delay_ms(1500);    // Long delay if button was pressed.
        button_pressed = 0;
    } else {
        _delay_ms(500);     // Regular delay otherwise.
    }

    PORTD &= ~(1<<PORTD6);  // Turn LED off.
    _delay_ms(500);
}

高级读者须知:

  1. volatile int button_pressed = 0; 实际上可能只是 volatile int button_pressed;,因为文件范围内的静态 ints 被初始化为 0,但它更清晰显式初始化。

  2. C 程序经常使用 for (;;) 作为 "loop forever" 的成语而不是 while (1)