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);
}
高级读者须知:
volatile int button_pressed = 0;
实际上可能只是 volatile int button_pressed;
,因为文件范围内的静态 int
s 被初始化为 0
,但它更清晰显式初始化。
C 程序经常使用 for (;;)
作为 "loop forever" 的成语而不是 while (1)
。
我正在尝试让一个简单的中断例程在 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);
}
高级读者须知:
volatile int button_pressed = 0;
实际上可能只是volatile int button_pressed;
,因为文件范围内的静态int
s 被初始化为0
,但它更清晰显式初始化。C 程序经常使用
for (;;)
作为 "loop forever" 的成语而不是while (1)
。