Это седьмой урок из цикла «Знакомство с Arduino». В этом уроке Вы научитесь работать с прерываниями, а  также с некоторыми режимами энергосбережения в Arduino.

Для урока Вам понадобится следующие детали:

  • Arduino Nano;
  • беспаечная макетная плата (она же breadboard);
  • провода типа папа-папа;
  • резистор номиналом 10 кОм и 220 Ом;
  • тактовая кнопка;
  • светодиод;
  • дисплей OLED 0.96».

Также Вам понадобится скачать и установить библиотеку Low Power и среду Arduino IDE. Если не знаете/забыли как это сделать, то вернитесь к уроку по среде Arduino IDE.

Для начала давайте разберёмся, что же такое прерывание. Прерывание — это сигнал, который сообщает процессору о наступлении какого-либо события, которое требует немедленного внимания. Процессор реагирует на этот сигнал, прервав выполнение всех текущих команд и передаёт управление обработчику прерывания. Обработчик прерывания — это обычная функция, в которой находятся команды, которые выполняют определённые действия, как реакцию на прерывание.

С понятием прерывания разобрались. Теперь давайте разберёмся, что же при поступлении сигнала прерывания.

Когда приходит сигнал прерывания, процессор приостанавливает выполнение текущей программы и переходит к подпрограмме обработки прерывания. Далее он выполняет те команды, которые находятся непосредственно в самом обработчике. После это процессор продолжает выполнять основную программу начиная с того места, в котором остановился.

Прерывания в модулях Arduino бывают нескольких видов:

  • Аппаратные (на уровне микропроцессора). Само же событие может произойти в произвольный момент времени и от внешнего устройства (нажатие на кнопку и т.д.);
  • Программные (на уровне программы). Они запускаются внутри программы при помощи специальной команды и используются для того, чтобы вызвать обработчик прерываний;
  • Внутренние (синхронные). Они возникают в результате изменения или ошибки при выполнении программы (например, при обращении к недопустимому адресу, недопустимый код операции и т.д.).

В этом уроке мы рассмотрим только аппаратные прерывания.

В модулях Arduino реализовано 4 типа аппаратных прерывания. Все они различаются уровнем сигнала на выводе модуля, на котором разрешено прерывание:

  • LOW. Прерывание срабатывает когда на выводе Arduino низкий уровень напряжения (0 В);
  • CHANGE. Прерывание срабатывает когда на выводе изменяется уровень напряжения с низкого на высокий (с 0 В на 5 В) или с высокого на низкий (с 5 В на 0 В);
  • RISING. Прерывание срабатывает когда на выводе изменяется уровень напряжения с низкого на высокий (с 0 В на 5 В);
  • FALLING.Прерывание срабатывает когда на выводе изменяется уровень напряжения с высокого на низкий (с 5 В на 0 В).

Прерывания обычно используются для задач, которые должны быть выполнены автоматически при наступлении какого либо внешнего события (считывание значения какого-либо датчика, реакция на нажатие кнопки и т.д.). Зачастую просто невозможно написать программу, которая непрерывно считывает все импульсы, не пропустив ни одного из них. Чтобы исключить такую ситуацию и используются прерывания.

Существует ряд ограничений при работе с прерываниями:

  • Обработчик прерывания не должен выполняться слишком долго по времени. Проблема в том, что модули Arduino не могут обрабатывать несколько прерываний одновременно. Пока выполняется один обработчик прерывания, все остальные прерывания останутся без внимания со стороны процессора и таким образом мы просто пропустим их. Есть довольно простой выход из этой ситуации. Если нужно выполнить довольно большой объём команд в обработчике прерывания, то нужно передавать саму обработку в цикл loop(), а в обработчике прерывания установить флаг события. Тогда в loop() нужно только проверять флаг и в соответствии с его значением выполнять обработку;
  • Нужно быть очень аккуратным с переменными, значение которых изменяется в обработчике прерывания. Переменная должна быть объявлена квалификатором volatile, если её значение может быть изменено чем-либо за пределами того участка программы, где она объявлена (например, параллельно выполняющимся процессом — прерыванием). Квалификатор volatile изменяет способ интерпретации и доступа к переменной компилятором и программой. Он указывает компилятору загрузить переменную из ОЗУ, и не из запоминающего регистра, т.к. при определенных условиях значения переменных, хранящихся в регистрах, могут оказаться неточными;
  • В обработчике прерывания нельзя использовать функцию delay(), т.к. механизм определения интервала задержки использует таймеры, а они тоже работают в прерываниях, которые заблокирует обработчик. В итоге все будут ждать всех и программа зависнет. По этой же причине нельзя использовать протоколы связи, основанные на прерываниях (например, I2C);
  • Возможна потеря данный передаваемых по последовательному соединению (Serial) в момент выполнения функции обработки прерывания.

С основной теорией по прерываниям мы теперь познакомились. Теперь пришло время попытаться сделать какой-нибудь практический пример.

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

Электрическая принципиальная схема:

Подключение кнопки и светодиода к Arduino Nano

Схема подключения на макетной плате:

Подключение кнопки и светодиода к Arduino Nano

Итак, схема собрана. Теперь подключите модуль Arduino к компьютеру. Далее откройте среду разработки Arduino IDE и запишите в Arduino следующую программу:

Текст программы:

Пояснение программы »

В самом начале программы мы создаём необходимые переменные для работы с портами ввода/вывода Arduino. Функция setup() запускается однократно при запуске программы. В ней инициализируются выводы, к которым подключены кнопка и светодиод (как входной и выходной порты, соответственно — команда pinMode), а также устанавливается прерывание для обработки нажатия кнопки (команда attachInterrupt (0, button_press, RISING)). Функция loop() вызывается после функции setup(). Функция представляет собой бесконечный цикл, в котором выполняется пользовательская программа. В ней мы выводим в порт, к которому подключён светодиод, либо высокий либо низкий уровень напряжения, в зависимости от состояния кнопки. Функция button_press является обработчиком прерывания. В ней при нажатии на кнопку инвертируется состояние флага, который отвечает за то, будет гореть или нет наш светодиод. Также в обработчике прерывания реализована небольшая защита от дребезга контактов. 

Таким образом, когда мы нажмём на кнопку наш светодиод загорится, при повторном нажатии он погаснет. Так мы реализовали простейший алгоритм управления светодиодом по нажатии на клавишу при помощи аппаратного прерывания.

Данный пример достаточно прост. Давайте возьмём что-нибудь посложнее. Довольно часто разные проекты на модулях Arduino необходимо питать от аккумуляторов/батареек. Появляется вопрос: как сделать, чтобы наш проект работал как можно дольше без замены аккумуляторов/батареек? Одним из решений данной проблемы является использование различных режимов энергосбережения.

Модуль Arduino можно погрузить в сон, отключить часть периферии (АЦП и т.д.). Но как же разбудить Arduino потом? Есть несколько способов, в зависимости от выбранного режима сна. В примере мы используем самый энергосберегающий режим — powerDown. Будить Arduino мы будем по прерыванию от нажатой кнопки. Также будем выводить на OLED текущее состояние модуля (режим сна или нет).

Чтобы собрать пример, дорогой читатель, воспользуйтесь следующими схемами:

Электрическая принципиальная схема:

Схема подключения на макетной плате:

Когда схема собрана, можно подключать модуль Arduino к компьютеру и записывать в него следующую программу:

Текст программы:

Пояснение программы »

В самом начале программы мы подключаем необходимы библиотеки для работы с OLED дисплеем и режимами энергосбережения модулей Arduino, а также создаём константу button, которая отвечает за номер вывода Arduino (№2), к которому подключена кнопка. Функция setup() запускается однократно при запуске программы. В ней инициализируются OLED (размер текста, его цвет и т.д.), а также вывод, к которому подключена кнопка (как входной порт — команда pinMode(button, INPUT)). Функция loop() вызывается после функции setup(). Функция представляет собой бесконечный цикл, в котором выполняется пользовательская программа. В ней мы сначала на OLED выводим состояние Arduino — уход в режим сна (команда LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF)). Далее мы устанавливаем прерывание для обработки нажатия кнопки (команда attachInterrupt (0, button_press, RISING)). Обработчик прерывания — пустая функция. Когда срабатывает прерывание Arduino выходит из режима сна. Далее мы запрещаем прерывание по кнопке (нам уже не нужно просыпаться — выходить из режима сна). На OLED выводится сообщение о том, что модуль Arduino вышел из режима сна. В течении 3х секунд модуль находится в рабочем режиме, а после опять уходит в режим сна.

Пример демонстрирует, как можно переводить модуль Arduino в режим пониженного энергопотребления и как из него выйти по прерыванию.

Для проверки, насколько хорошо Вы усвоили урок, выполните следующие задания.

Чтобы проверить себя, дорогой читатель, воспользуйтесь подсказками после вопросов.

Задания:

  1. Для первого примера:
    • Измените схему и программу так, чтобы использовать другой вывод модуля Arduino Nano для аппаратного прерывания; 

      Показать ответ »

      Нужно просто переключить кнопку на цифровой вывод № 3 Arduino Nano, т.к. на нём тоже можно установить аппаратное прерывание.
      Электрическая принципиальная схема:

      Схема подключения на макетной плате:
      В программе, соответственно, нужно имзменить номер вывода, к которому подключена кнопка и номер прерывания, который соответствует этому выводу Arduino.
      Текст программы: 

    • Измените программу так, чтобы прерывание срабатывало по любому изменению уровня сигнала (с высокого на низкий или наоборот);

      Показать ответ »

      Для этого нужно изменить аргумент функции attachInterrupt с RISING на CHANGE.
      Текст программы: 

  2. Для второго примера:
    • Прочитайте документацию и примеры из библиотеки Low Power и вместо режима powerDown используйте другой режим сна. 

      Показать ответ »

      Существует несколько режимов энергосбережения Arduino. Таблицу с характеристиками каждого режима можно найти по этой ссылке. Мы изменим режим powerDown на powerStandby.Текст программы: 

 

 

Уважаемый читатель, мы предлагаем Вам обратиться к разделу «Программирование» на нашем сайте. Там Вы найдёте описание и примеры работы с различными функциями программирования модулей Arduino.

Спасибо за то, что учитесь познавать удивительный мир радиоэлектроники вместе с нами.

Верьте в себя, учитесь и у Вас всё обязательно получится!

Удачи в дальнейших проектах!