Представьте: у вас есть клавиатура 4×4, и вы хотите обрабатывать нажатия без опроса в loop().
volatile bool keyPressed = false;
volatile uint8_t lastState = 0;
void setup() {
// Настраиваем пины 0-7 (PORTD) как входы с подтяжкой
DDRD = 0b00000000; // Все как входы
PORTD = 0b11111111; // Включаем внутренние pull-up резисторы
// Настраиваем прерывания для PORTD
PCICR |= (1 << PCIE0); // Включаем прерывания для PCINT0 (PORTD)
PCMSK0 = 0xFF; // Разрешаем прерывания на ВСЕХ пинах PORTD
sei(); // Глобально разрешаем прерывания
}
// Обработчик прерывания (сработает при ЛЮБОМ изменении на пинах 0-7)
ISR(PCINT0_vect) {
uint8_t currentState = PIND; // Читаем ВСЕ 8 пинов за 1 такт
// Проверяем, какие пины изменились
uint8_t changedPins = currentState ^ lastState;
if (changedPins & (1 << 0)) {
// Пин 0 изменился!
if (currentState & (1 << 0)) {
// Пин 0 стал HIGH (кнопка отпущена)
} else {
// Пин 0 стал LOW (кнопка нажата)
}
}
if (changedPins & (1 << 3)) {
// Пин 3 изменился — делаем что-то срочное!
}
lastState = currentState; // Запоминаем для следующего раза
}
void loop() {
// Ваш код выполняется, пока прерывания работают в фоне!
// Можно спокойно управлять дисплеем, не опрашивая кнопки.
}
Важные хакерские нюансы:
- Антидребезг: В прерываниях НЕЛЬЗЯ использовать
delay(). Вместо этого ставьте флаг и обрабатывайте кнопку вloop()черезmillis(). - Разделяем пины по портам: Если вы используете PCINT0 для кнопок, не вешайте на этот порт ШИМ или UART — прерывания будут срабатывать постоянно.
- Скорость реакции: Pin Change прерывания срабатывают через 0.1 микросекунды после изменения сигнала. Это в 50 раз быстрее, чем
digitalRead()вloop().