4.06. Аппаратные прерывания.md
До сих пор все наши программы работали последовательно. Внутри бесконечного цикла loop()
микроконтроллер неустанно проверял условия одно за другим: «Нажата ли кнопка? А сейчас? А теперь?». Такой метод называется опросом (polling), и он похож на то, как если бы вы каждые пять минут подбегали к почтовому ящику в ожидании письма. Это работает, но отнимает всё ваше время и внимание. А что, если письмо придёт и его тут же заберут, пока вы отвернулись? Вы его пропустите.
Точно так же и микроконтроллер может пропустить короткое событие (например, быстрое нажатие кнопки), если в этот момент он был занят выполнением delay()
или сложными вычислениями. Чтобы решить эту проблему, существует гораздо более элегантный и эффективный механизм — аппаратные прерывания.
Принцип работы прерываний
Представьте, что вы оставили курьеру записку: «Когда прибудет посылка, не клади её в ящик, а позвони в дверь». Теперь вы можете спокойно заниматься своими делами: читать книгу, готовить, смотреть фильм. Как только курьер нажмёт на кнопку звонка, вы немедленно отложите свои дела, откроете дверь, заберёте посылку и вернётесь к своему занятию ровно с того места, на котором остановились.
Аппаратное прерывание работает точно так же. Вы «говорите» микроконтроллеру: «Следи за этим пином. Как только на нём изменится сигнал, немедленно приостанови loop()
, выполни вот эту специальную короткую функцию и вернись обратно».
Это даёт два огромных преимущества: 1. Мгновенная реакция: Микроконтроллер реагирует на событие сразу же, а не когда до него дойдёт очередь в loop()
. 2. Эффективность: Процессор не тратит время на постоянные проверки, а может заниматься другими полезными задачами.
Прерывания на плате Рудирон
На плате Рудирон
некоторые пины специально предназначены для работы с аппаратными прерываниями. Как мы видим из документации и схемы, это пины 31, 32 и 35. Удобно, что именно к этим пинам подключены встроенные кнопки B2, B3 и B1 соответственно. Это позволяет нам экспериментировать с прерываниями без подключения внешних компонентов.
Настройка прерываний - attachInterrupt()
Чтобы «повесить» прерывание на пин, используется функция attachInterrupt()
. Её обычно вызывают один раз в setup()
.
Синтаксис функции:
attachInterrupt(digitalPinToInterrupt(номерПина), ISR, режим);
Давайте разберём каждый параметр: 1. digitalPinToInterrupt(номерПина)
: Это важная функция-помощник. Она преобразует обычный номер пина (например, 35
) в специальный номер прерывания, понятный микроконтроллеру. Всегда используйте её, чтобы указать, какой пин будет источником прерывания. 2. ISR
(Interrupt Service Routine): Это имя вашей функции, которая будет вызвана при срабатывании прерывания. Её также называют обработчиком прерывания. Это должна быть функция, которая не принимает аргументов и ничего не возвращает (void myFunction()
). 3. режим
: Указывает, на какое именно изменение сигнала должен реагировать микроконтроллер: * LOW
: Прерывание срабатывает, пока на пине удерживается низкий уровень. * CHANGE
: При любом изменении уровня (с LOW
на HIGH
или с HIGH
на LOW
). * RISING
: При переходе с LOW
на HIGH
(передний фронт импульса). * FALLING
: При переходе с HIGH
на LOW
(задний фронт импульса).
Чтобы отключить прерывание, используется функция detachInterrupt(digitalPinToInterrupt(номерПина))
.
Золотые правила написания обработчика прерываний (ISR)
Функция-обработчик прерывания — особенная. Во время её выполнения весь остальной мир для микроконтроллера замирает. Поэтому при её написании нужно соблюдать несколько строгих правил: 1. Делайте её максимально короткой и быстрой. loop()
ждёт! Внутри ISR обычно только меняют значение переменной (устанавливают флаг), а все долгие действия выполняют в loop()
. 2. Не используйте delay()
и delayMicroseconds()
. Эти функции зависят от таймеров, которые отключаются во время прерывания. 3. Будьте осторожны с Serial
. Отправка данных по Serial
тоже зависит от прерываний и может работать некорректно или привести к потере данных. Лучше установить флаг в ISR, а вывести данные в loop()
. 4. Используйте volatile
. Если вы используете переменную и в ISR
, и в loop()
, её нужно объявить с ключевым словом volatile
. Например: volatile bool flag = false;
. Это говорит компилятору, что переменная может измениться в любой момент (из-за прерывания), и он не должен кэшировать её значение, а всегда считывать из памяти.
Пример (включение/выключение встроенного светодиода L1 по нажатию кнопки B1):
// Используем встроенные имена для пинов
// BUTTON_BUILTIN_1 соответствует пину 35, который поддерживает прерывания
// LED_BUILTIN_1 соответствует пину 5
// Эта переменная будет изменяться в прерывании, поэтому она volatile
volatile bool ledState = LOW;
void setup() {
pinMode(LED_BUILTIN_1, OUTPUT);
pinMode(BUTTON_BUILTIN_1, INPUT_PULLDOWN);
// Настраиваем прерывание. При нажатии кнопки сигнал на пине станет высоким (RISING)
attachInterrupt(digitalPinToInterrupt(BUTTON_BUILTIN_1), toggleLed, RISING);
Serial.begin(9600);
Serial.println("Система готова. Нажмите кнопку B1, чтобы изменить состояние светодиода L1.");
}
void loop() {
// Основной цикл просто обновляет состояние светодиода на основе значения переменной ledState
digitalWrite(LED_BUILTIN_1, ledState);
// Здесь может быть любой другой код, и он не будет мешать реакции на кнопку.
}
// Это наш обработчик прерывания (ISR).
// Название может быть любым, главное — чтобы оно совпадало с тем, что мы указали в attachInterrupt
void toggleLed() {
// Инвертируем состояние светодиода
ledState = !ledState;
}
В этом примере loop()
просто устанавливает состояние светодиода. При каждом нажатии на кнопку B1 мгновенно срабатывает прерывание и вызывается функция toggleLed()
, которая меняет значение флага ledState
. В следующем цикле loop()
светодиод изменит своё состояние. Всё происходит мгновенно, и основной цикл не тратит время на проверку кнопки.
Зачем это нужно?
Аппаратные прерывания — это фундаментальный инструмент для создания отзывчивых и эффективных систем. Они незаменимы, когда нужно:
- Мгновенно реагировать на важные сигналы (например, кнопка аварийной остановки).
- Считать быстрые импульсы от энкодеров или датчиков скорости, не пропуская ни одного.
- Декодировать сигналы от пультов дистанционного управления.
- «Пробуждать» микроконтроллер из режима сна для экономии энергии.
Поздравляем с освоением прерываний! Теперь ваши проекты могут стать по-настоящему быстрыми и эффективными. Если вы хотите применить эти знания на практике, переходите к лабораторным работам, чтобы создать по-настоящему многозадачное устройство. А если вы готовы изучить ещё один способ заставить Рудирон
делать несколько дел одновременно, но уже чисто программным методом, отправляйтесь в следующий параграф, где мы познакомимся с функцией millis()
.
- Страницы
- 1. Введение
- 1.01. Лабораторная работа №1.1
- 1.02. Лабораторная работа №1.2
- 1.03. Лабораторная работа №1.3
- 1.04. Лабораторная работа №1.4
- 1.05. Лабораторная работа №1.5
- 2. Основы электроники
- 2.01. Электрический ток и параметры цепи
- 2.01.1. Лабораторная работа №2.1.1
- 2.01.2. Лабораторная работа №2.1.2
- 2.02. Сопротивление в цепи
- 2.02.1. Лабораторная работа №2.2.1
- 2.02.2. Лабораторная работа №2.2.2
- 2.03. Полупроводники
- 2.03.1. Лабораторная работа №2.3.1
- 2.03.2. Лабораторная работа №2.3.2
- 3. Основы программирование на C++
- 3.01. Типы данных и переменные
- 3.01.1. Практикум
- 3.02. Операторы в C++
- 3.02.1. Практикум
- 3.03. Структуры ветвления
- 3.03.1. Практикум
- 3.04. Структуры повторения
- 3.04.1. Практикум
- 3.05. Массивы
- 3.05.1. Практикум
- 3.06. Функции
- 3.06.1. Практикум
- 3.07. Решения задач
- 4. Программирование микроконтроллеров
- 4.01. Цифровые сигналы и GPIO
- 4.01.1. Лабораторная работа №4.1.1
- 4.01.2. Лабораторная работа №4.1.2
- 4.01.3. Лабораторная работа №4.1.3
- 4.01.4. Лабораторная работа №4.1.4
- 4.01.5. Лабораторная работа №4.1.5
- 4.01.6. Лабораторная работа №4.1.6
- 4.01.7. Лабораторная работа №4.1.7
- 4.01.8. Лабораторная работа №4.1.8
- 4.02. Аналоговые сигналы и ШИМ
- 4.02.1. Лабораторная работа №4.2.1
- 4.02.2. Лабораторная работа №4.2.2
- 4.02.3. Лабораторная работа №4.2.3
- 4.02.4. Лабораторная работа №4.2.4
- 4.02.5. Лабораторная работа №4.2.5
- 4.03. Аналоговый сигнал и АЦП
- 4.03.1. Лабораторная работа №4.3.1
- 4.03.2. Лабораторная работа №4.3.2
- 4.03.3. Лабораторная работа №4.3.3
- 4.03.4. Лабораторная работа №4.3.4
- 4.03.5. Лабораторная работа №4.3.5
- 4.04. Аналоговый сигнал и ЦАП
- 4.04.1. Лабораторная работа №4.4.1
- 4.04.2. Лабораторная работа №4.4.2
- 4.05. Генерация и измерение импульсов
- 4.05.1. Лабораторная работа №4.5.1
- 4.05.2. Лабораторная работа №4.5.2
- 4.06. Аппаратные прерывания
- 4.06.1. Лабораторная работа №4.6.1
- 4.06.2. Лабораторная работа №4.6.2
- 4.07. Псевдопараллелизм
- 4.07.1. Лабораторная работа №4.7.1
- 4.07.2. Лабораторная работа №4.7.2
- 4.08. Интерфейсы связи - UART
- 4.08.1. Лабораторная работа №4.8.1
- 4.09. Интерфейсы связи - I2C
- 4.09.1. Лабораторная работа №4.9.1
- 4.10. Интерфейсы связи - SPI
- 4.10.1. Лабораторная работа №4.10.1
- home
-
imgs
- 1. Введение
- 1.01. Лабораторная работа №1.1
- 1.02. Лабораторная работа №1.2
- 1.03. Лабораторная работа №1.3
- 1.04. Лабораторная работа №1.4
- 1.05. Лабораторная работа №1.5
- 2. Основы электроники
- 2.01. Электрический ток и параметры цепи
- 2.01.1. Лабораторная работа №2.1.1
- 2.01.2. Лабораторная работа №2.1.2
- 2.02. Сопротивление в цепи
- 2.02.1. Лабораторная работа №2.2.1
- 2.02.2. Лабораторная работа №2.2.2
- 2.03. Полупроводники
- 2.03.1. Лабораторная работа №2.3.1
- 2.03.2. Лабораторная работа №2.3.2
- 3. Основы программирование на C++
- 3.01. Типы данных и переменные
- 3.01.1. Практикум
- 3.02. Операторы в C++
- 3.02.1. Практикум
- 3.03. Структуры ветвления
- 3.03.1. Практикум
- 3.04. Структуры повторения
- 3.04.1. Практикум
- 3.05. Массивы
- 3.05.1. Практикум
- 3.06. Функции
- 3.06.1. Практикум
- 3.07. Решения задач
- 4. Программирование микроконтроллеров
- 4.01. Цифровые сигналы и GPIO
- 4.01.1. Лабораторная работа №4.1.1
- 4.01.2. Лабораторная работа №4.1.2
- 4.01.3. Лабораторная работа №4.1.3
- 4.01.4. Лабораторная работа №4.1.4
- 4.01.5. Лабораторная работа №4.1.5
- 4.01.6. Лабораторная работа №4.1.6
- 4.01.7. Лабораторная работа №4.1.7
- 4.01.8. Лабораторная работа №4.1.8
- 4.02. Аналоговые сигналы и ШИМ
- 4.02.1. Лабораторная работа №4.2.1
- 4.02.2. Лабораторная работа №4.2.2
- 4.02.3. Лабораторная работа №4.2.3
- 4.02.4. Лабораторная работа №4.2.4
- 4.02.5. Лабораторная работа №4.2.5
- 4.03. Аналоговый сигнал и АЦП
- 4.03.1. Лабораторная работа №4.3.1
- 4.03.2. Лабораторная работа №4.3.2
- 4.03.3. Лабораторная работа №4.3.3
- 4.03.4. Лабораторная работа №4.3.4
- 4.03.5. Лабораторная работа №4.3.5
- 4.04. Аналоговый сигнал и ЦАП
- 4.04.1. Лабораторная работа №4.4.1
- 4.04.2. Лабораторная работа №4.4.2
- 4.05. Генерация и измерение импульсов
- 4.05.1. Лабораторная работа №4.5.1
- 4.05.2. Лабораторная работа №4.5.2
- 4.06. Аппаратные прерывания
- 4.06.1. Лабораторная работа №4.6.1
- 4.06.2. Лабораторная работа №4.6.2
- 4.07. Псевдопараллелизм
- 4.07.1. Лабораторная работа №4.7.1
- 4.07.2. Лабораторная работа №4.7.2
- 4.08. Интерфейсы связи - UART
- 4.08.1. Лабораторная работа №4.8.1
- 4.09. Интерфейсы связи - I2C
- 4.09.1. Лабораторная работа №4.9.1
- 4.10. Интерфейсы связи - SPI
- 4.10.1. Лабораторная работа №4.10.1
- home