4.06.1. Лабораторная работа №4.6.1.md


Мгновенная реакция

Тема работы

Вспомните наши прошлые программы, если в коде есть команда delay(3000), то на целые три секунды микроконтроллер полностью «замирает» и не может реагировать ни на какие нажатия кнопок. Это большая проблема для интерактивных устройств. В этой лабораторной работе мы решим её с помощью аппаратных прерываний. Мы напишем программу, в которой один светодиод будет медленно мигать, блокируя основной цикл, а второй будет мгновенно менять своё состояние по нажатию кнопки, «обгоняя» все задержки.

Цель

  • На практике освоить использование аппаратных прерываний с помощью attachInterrupt().
  • Понять разницу между опросом (polling) в loop() и обработкой событий через прерывания.
  • Научиться писать простые, но эффективные функции-обработчики прерываний (ISR).

Оборудование и материалы

  • Отладочная плата Рудирон.
  • USB-кабель для подключения Рудирона к компьютеру.
  • Компьютер с настроенной средой Arduino IDE.

Ход работы

  1. Подготовка платы и перемычек

    Для этого эксперимента нам понадобятся только встроенные компоненты:

    • Кнопка B1, которая подключена к пину 35. Этот пин поддерживает аппаратные прерывания.
    • Светодиоды L1 (пин 5) и L2 (пин 7).

    Критически важный шаг На плате Рудирон есть специальная перемычка IRQ. По умолчанию она может быть установлена, так как используется для работы с радиомодулем. Чтобы мы могли свободно использовать прерывания на других кнопках (B1 и B3) и избежать конфликтов, эту перемычку необходимо снять.

    • Установите перемычку PRG | RUN в положение PRG.
    • Подключите плату к компьютеру и настройте Arduino IDE (плата Rudiron_Buterbrod_R10_20MHz и правильный COM-порт).
  2. Написание и загрузка кода

    • В Arduino IDE создайте новый скетч и введите следующий код:

      // Используем переменные для хранения состояния светодиодов
      // Ключевое слово "volatile" ОБЯЗАТЕЛЬНО для переменных,
      // которые изменяются внутри прерывания.
      volatile bool led1State = LOW;
      bool led2State = LOW;
      
      void setup() {
      pinMode(LED_BUILTIN_1, OUTPUT);
      pinMode(LED_BUILTIN_2, OUTPUT);
      pinMode(BUTTON_BUILTIN_1, INPUT_PULLDOWN);
      
      // Настраиваем прерывание на кнопке B1
      attachInterrupt(digitalPinToInterrupt(BUTTON_BUILTIN_1), toggleLed1, RISING);
      }
      
      // Обработчик прерывания (ISR)
      void toggleLed1() {
      // Меняем состояние переменной
      led1State = !led1State;
      // И СРАЗУ ЖЕ управляем светодиодом прямо из прерывания
      digitalWrite(LED_BUILTIN_1, led1State);
      }
      
      void loop() {
      // --- Основной цикл, который "тормозит" ---
      
      // Меняем состояние второго светодиода
      led2State = !led2State;
      digitalWrite(LED_BUILTIN_2, led2State);
      
      // Длинная, блокирующая пауза
      delay(3000);
      }
      
    • Нажмите кнопку «Upload», чтобы загрузить код на плату.
  3. Проверка работы

    • Сразу после загрузки светодиод L2 начнёт медленно мигать (включится на 3 секунды, затем выключится на 3 секунды и т.д.).
    • Теперь самое главное - в любой момент, даже когда L2 горит и программа, казалось бы, «зависла» в delay(), нажмите на кнопку B1.
    • Вы увидите, что светодиод L1 мгновенно меняет своё состояние (включается или выключается), не дожидаясь, пока delay() закончит свою работу.

Результаты

Вы создали по-настоящему многозадачную программу! Вы увидели, как аппаратное прерывание позволяет микроконтроллеру выполнять одно действие (реагировать на кнопку) параллельно другому (медленно мигать светодиодом).

Анализ результатов

  • attachInterrupt(...). Эта команда «вооружила» пин 35. Теперь микроконтроллер аппаратно следит за ним.
  • void toggleLed1(). Это наша ISR (Interrupt Service Routine). Когда вы нажимаете кнопку, процессор немедленно приостанавливает выполнение delay() в loop(), «прыгает» в эту функцию, выполняет её и возвращается обратно в delay().
  • digitalWrite() внутри ISR. Ключевой момент этой программы. Мы вызываем digitalWrite(LED_BUILTIN_1, led1State) непосредственно внутри обработчика прерывания. Именно поэтому светодиод L1 меняет своё состояние мгновенно, не дожидаясь завершения delay() в основном цикле. Это наглядно демонстрирует мощь прерываний.
  • volatile. Это ключевое слово говорит компилятору: «Не пытайся оптимизировать эту переменную, её значение может измениться в любой, самый неожиданный момент!». Хотя в данном примере loop() не использует led1State, это остаётся хорошей практикой для всех переменных, разделяемых между loop() и ISR.

Выводы

В этой лабораторной работе вы освоили один из самых мощных инструментов в арсенале программиста микроконтроллероваппаратные прерывания. Вы научились создавать отзывчивые программы, которые могут мгновенно реагировать на важные события, не прерывая выполнение других задач. Этот подход является основой для построения сложных и надёжных систем.

Вопросы для самопроверки

  1. Что такое аппаратное прерывание и чем оно отличается от простого опроса в loop()?
  2. Какая команда используется для настройки прерывания?
  3. Почему для этой лабораторной работы было важно снять перемычку IRQ?
  4. Почему переменная, используемая в ISR, должна быть объявлена как volatile?
  5. Какие действия нельзя выполнять внутри функции-обработчика прерывания (ISR)?
  6. Как изменить код, чтобы светодиод L1 реагировал не на нажатие, а на отпускание кнопки?

Поздравляем с освоением прерываний! Теперь ваши проекты могут стать по-настояшему быстрыми и эффективными. В следующем параграфе мы изучим ещё один способ заставить Рудирон делать несколько дел одновременно, но уже чисто программным методом, без использования delay().