C для приложения AVR - повторение ISR
Я пытаюсь заставить простую подпрограмму прерывания работать на ATMega328P. Есть светодиод, подключенный к PD6, и встроенная кнопка на PB7. Светодиод должен нормально мигать до тех пор, пока кнопка не будет нажата, а затем постоянно светиться в течение 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, чтобы он не запускался снова, но все же срабатывает. Заранее благодарю за любую помощь!
1 ответ
Давайте работать на основе того, что вы с радостью игнорируете любые нажатия кнопок, пока светодиод горит в течение 1,5 секунд. Вы можете написать свой обработчик прерываний следующим образом:
ISR(PCINT0_vect,ISR_BLOCK)
{
button_pressed = 1;
}
и поместите это в верхней части вашего кода:
volatile int button_pressed = 0;
(См. Эту страницу для получения информации о том, что 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 (;;)
как идиома для "цикла навсегда" вместоwhile (1)
,