Прерываемые приложения
Обратите внимание на следующие детали в коде:
- Для задержки мигания и фильтрации дребезга переключателей мы используем одну и ту же функцию delay(), ту, которая вызывает функцию clock() из time.h. Мы не используем быструю и грязную функцию задержки, использованную ранее для предотвращения дребезга кнопок.
- В этот раз, процесс избегания дребезга не отображается встроенным светодиодом, поскольку он используется для мигания.
Попробуйте приложение и проверьте, правильно ли оно работает. Спойлер: это не так!
Что не так с методом опроса?
Чтобы ответить на этот вопрос, давайте обратимся к части кода, посвященной опросу, в главном цикле:
while (1) { // Кнопки и код ШИМ внешнего светодиода if (Red_V_read_pin(0) == 0) { // Чтение входного пина 0 dc = (dc > 0) ? dc - 25 : dc; // Шаги по 25% для светодиода metal_pwm_set_duty(pwm_1, 1, dc, METAL_PWM_PHASE_CORRECT_DISABLE); delay(50000); // Программное ожидание while (Red_V_read_pin(0) == 0); // Ждем, пока кнопка не будет отпущена delay(50000); // Программное ожидание } else if (Red_V_read_pin(1) == 0) { // Считывание входного пина 1 dc = (dc < 100) ? dc + 25 : dc; // Шаги по 25% для светодиода metal_pwm_set_duty(pwm_1, 1, dc, METAL_PWM_PHASE_CORRECT_DISABLE); delay(50000); // Программное ожидание while (Red_V_read_pin(1) == 0); // Ждем, пока кнопка будет отпущена delay(50000); // Программное ожидание } // Код мигающего светодиода Red_V_clear_pin(5); // Выключение встроенного светодиода delay(500000); // 500 мс в микросекундах Red_V_set_pin(5); // Включение встроенного светодиода delay(500000); // 500 мс в микросекундах }
Обратите внимание, что везде присутствуют задержки, отнимающие время. Проблема в том, что функция задержки - это так называемая блокирующая функция, которая блокирует выполнение до тех пор, пока время не истечет.
Еще один блокирующий элемент можно увидеть в циклах while между задержками в строках кода для предотвращения дребезга. Проблема заключается в том, что приложение не будет выполняться до тех пор, пока кнопка не будет отпущена. Это не является проблемой для части ШИМ, потому что генератор ШИМ - это отдельная часть аппаратного обеспечения, которая работает независимо. Тем не менее, код мигающего светодиода нуждается в процессоре.
Альтернативой блокирующим функциям являются неблокирующие функции. Когда вызывается неблокирующая функция, она вызывается кратко перед возвратом. Если же она должна дождаться выполнения внешней задачи, она возвращается, откладывая обработку результата этой задачи.
Неблокирующая функция задержки может запустить таймер и вернуться. Затем остальная часть кода может использовать опрос для проверки выполнения таймера, не задерживая выполнение в блокирующем цикле.
При разумном использовании в опросе нет ничего плохого. Однако опросом можно злоупотреблять несколькими способами, например, блокировать функции, добавлять слишком много кода в основной цикл или без необходимости прерывать выполнение основной задачи. Именно тогда он становится проблемой.
Необходимость прерыванийй
Прерывания подходят для обработки нечастых запросов ввода-вывода, таких как нажатие клавиш или спорадические входящие сообщения от другого устройства. В целом, обработчики прерываний должны быть намного быстрее, чем скорость поступления прерываний.
Если это условие выполняется, то прерывания помогают сделать встроенные приложения лучше во многих отношениях. Давайте рассмотрим некоторые из этих преимуществ:
- Отзывчивость Благодаря тому, что входящие запросы удовлетворяются быстро, приложения работают бесперебойно. Подумайте о компьютерной клавиатуре: когда вы начинаете печатать, вы ожидаете, что на дисплее без задержек появится текст, который вы набираете. Программное обеспечение, управляемое прерываниями, может помочь, оставив код управления клавиатурой за пределами основного цикла.
- Эффективность Как мы видели ранее, прерывания могут сделать ваши приложения более эффективными с точки зрения времени и расхода ресурсов.
- Масштабируемость Когда вам необходимо модифицировать ваше приложение для поддержки большего количества внешних устройств или, возможно, увеличить рабочую нагрузку, необходимые изменения гораздо проще, чище и эффективнее в приложении, управляемом прерываниями, чем в его аналоге с опросом. На самом деле, добавление работы в приложение с опросом всегда негативно сказывается на его производительности.
- Переносимость Это степень, в которой исходный код может быть перенесен с одного аппаратного обеспечения или фреймворка на другие, а также легкость выполнения этой адаптации. Код обработки ввода-вывода, как правило, является менее переносимой частью встраиваемого приложения, а подход, основанный на прерываниях, позволяет держать этот код внутри обработчиков прерываний и функций конфигурации. Все это обычно способствует переносимости.
- Энергоэффективность Освобождение центрального процессора от тяжелой работы по опросу дает ему больше свободного времени. Более того, микроконтроллеры обычно поддерживают, по крайней мере, спящий режим, который требует меньше энергии, чем обычный режим выполнения. В приложении, управляемом прерываниями, главный цикл может не иметь много работы, поэтому ему может быть полезно периодически переходить в спящий режим. Контроллер прерываний может разбудить процессор, если прерывание произойдет во время одного из таких снов. Все это снижает электропотребление контроллера.
- Осознание приоритетов В маловероятном случае, когда ожидается два или более прерываний, логичнее всего запустить обработчик прерывания для самого срочного из них. Контроллеры прерываний знают о приоритетах между различными прерываниями устройства. Эти приоритеты могут быть фиксированными или иногда устанавливаться программистом, но в любом случае аппаратное обеспечение имеет четкие правила для определения того, какое прерывание должно быть обработано первым. Такого попросту невозможно добиться, используя метод опроса.
Прерывания всегда присутствуют в профессиональных приложениях, но они не очень популярны в сообществе Arduino, возможно, из-за кажущейся сложности процесса по сравнению с простым написанием кода обработки ввода-вывода в основном цикле, что, как мы знаем, является плохой практикой. Если вы решили никогда не использовать прерывания в своих приложениях, то создание программ-игрушек - это максимум, на что вы способны. Если вы серьезно занимаетесь встраиваемыми системами, прерывания, рано или поздно, должны быть добавлены в ваш инструментарий.
Аппаратные средства прерывания в микроконтроллерах
Все микроконтроллеры поддерживают прерывания, и схема может варьироваться от очень простой государственной машины в CPU до очень сложного внешнего блока.
Важно понимать, что обработка прерываний - это аппаратный, а не программный процесс. Как программист, вы не должны беспокоиться об этом процессе, но должны предоставить всю информацию, необходимую аппаратуре для правильной обработки прерываний. По этой причине вы должны знать основные элементы, используемые в контроллере прерываний.
Контроллеры прерываний в микроконтроллерах реализуют некоторые варианты следующих аппаратных средств:
Обратите внимание на следующие детали схемы:
- Показанный контроллер прерываний поддерживает некоторое количество (N) устройств ввода/вывода (GPIO, АЦП, I2C, SPI и так далее). Сигналы прерывания поступают от устройств, и когда эти сигналы достигают центрального процессора, начинается процесс обработки прерывания.
- Схема прерывания для каждого устройства ввода/вывода имеет регистр Interrupt-Enable и регистр Interrupt Flag.
- Биты Interrupt-Enable разрешают определенные прерывания. Вы можете установить эти биты программно, чтобы указать на намерение использовать прерывания для данного устройства.
- Биты Interrupt Flag (также известные как биты ожидания прерывания) устанавливаются аппаратным обеспечением, когда произошло ожидаемое внешнее событие. Эти биты добавляют разрешенные источники в очередь ожидающих прерываний. Вы можете программно очистить эти флаги, чтобы указать, что вы приняли участие в запросе. Очистка флагов прерывания обычно выполняется с помощью специальной процедуры, которая не обязательно записывает в них 0.
- В ядре процессора есть специальный регистр, который называется маска прерываний, который позволяет игнорировать прерывания. Также известный как Global Interrupt Mask, этот регистр обычно является активно-низким регистром процессора, разрешающим все прерывания ввода-вывода, когда он очищен, и игнорирующим прерывания, когда он установлен. В некоторых архитектурах для этого бита используется логика активного высокого уровня, и вместо этого он называется регистром Global Interrupt-Enable. Временное отключение прерываний не означает их полного игнорирования. Если прерывание срабатывает, когда прерывания глобально отключены, оно попадает в очередь, которая будет обработана, когда прерывания будут снова включены.
- Другими источниками событий являются исключения и NMI (Non-Maskable Interrupts).
- Исключения похожи на прерывания, но они приходят не асинхронно от устройств ввода/вывода, а синхронно от центрального процессора. Вы можете быть знакомы с такими исключениями, как "Деление на ноль" или "Незаконная инструкция".
- Non-Maskable Interrupts - это специальные прерывания, которые не могут быть заглушены маской прерывания. Это полезно для реализации аварийных кнопок, игнорировать которые не имеет смысла ни при каких обстоятельствах.