【发布时间】:2019-04-07 01:56:08
【问题描述】:
我正在尝试让一个简单的中断例程在 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 例程循环了两次。我想这是某种按钮弹跳问题,但我不熟悉如何处理它。我尝试在开始时引入 500 毫秒延迟,并且我还尝试清除 ISR 中的引脚更改中断标志,以便它不会再次触发,但它仍然会触发。提前感谢您的帮助!
【问题讨论】:
-
请不要在中断处理程序中设置延迟,它应该尽可能快,并且可能会阻止其他中断被服务。更好的是记录按下按钮的时间计数。如果在上一个按钮之后太快按下按钮,请记录时间但忽略它。使用中断处理程序设置的信息从较低级别控制 LED。
-
最简单的方法是让 ISR 只设置一个
button_pressed标志并退出。然后在主循环中打开灯后输入if (button_pressed) {delay(1000); button_pressed=false;}。但总的来说,嵌入式代码应该完全避免延迟循环,并用时钟检查和/或定时器中断来代替它们。 -
我确实听说避免使用 delay() 更可取,我会寻找一些示例来用计时器控件替换 delay() 函数。
标签: c avr atmega debouncing isr