我正在尝试获取一个简单的中断例程以在ATMega328P上工作。 PD6上有一个LED指示灯,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例程循环两次。我认为这是某种按钮弹跳的问题,但我不熟悉如何处理。我尝试在开始时引入500ms延迟,并且还尝试清除ISR中的引脚更改中断标志,以便它不会再次触发,但仍然会触发。预先感谢您的帮助!
答案 0 :(得分:1)
我们的工作基于您很高兴在LED亮起1.5秒时忽略任何按钮按下。您可以这样编写中断处理程序:
ISR(PCINT0_vect,ISR_BLOCK)
{
button_pressed = 1;
}
,然后将其放在代码的顶部:
volatile int button_pressed = 0;
(有关volatile
的全部内容以及为什么需要使用它的信息,请参见this page。)
然后您的主循环如下所示:
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
初始化为0
,但是显式初始化要清晰得多。
C程序经常使用for (;;)
作为“永远循环”的惯用语,而不是while (1)
。