Задержка Arduino внутри прерывания
Использование функции задержки внутри ISR не одобряется при программировании на Arduino. Общий ответ на решение этого желания состоит в том, чтобы спроектировать программу так, чтобы задержка за пределами прерывания была более аккуратной.
Мой вопрос просто в том, почему. Почему размещение задержки() внутри ISR приводит к нестабильному поведению Arduino. Что происходит под капотом?
@Liro, 👍2
3 ответа
Лучший ответ:
Почему размещение задержки() внутри ISR приводит к нестабильному поведению Arduino? Что происходит под капотом?
Первая проблема заключается в том, что задержка() — это функция мониторинга занятого цикла millis(). Значение, возвращаемое millis(), не изменится внутри ISR, поскольку прерывания внутри ISR отключены; вот почему ISR должны быть как можно более короткими и быстрыми, иначе они будут мешать другим прерываниям
Итак, если вы вызовете метод задержки() внутри ISR, ваш бедный AVR застрянет в тупике! Он ждет чего-то, чего сейчас уже никогда не произойдет.
Вторая проблема заключается в том, что если ваш ISR занимает слишком много времени, вы можете пропустить другие прерывания; millis() и micros() могут пропускать тики и становиться неточными!
Поскольку задержка внутри прерывания приводит к тому, что это прерывание и другие прерывания (с более низким приоритетом) больше не выполняются, пока задержка не закончится.
Предположим, что в ISR вы обрабатываете входящие байты из UART. Если вы добавите задержку в ISR и буфер UART заполнится, он переполнится, и вы пропустите байты.
Это дополнение к ответу эзотерика.
В большинстве случаев, когда люди пытаются использовать delay()
внутри ISR, это плохой выбор дизайна, даже использовать его в общем виде, что приведет к описанным проблемам (ожидание навсегда или отсутствуют другие прерывания). delay()
— простая функция, предназначенная главным образом для новичков, работающих с очень простыми программами. Это простая отправная точка. В большинстве случаев его использование в любой программе не является хорошим выбором, поскольку вы заняты ожиданием и не можете сделать что-то еще (например, ответить на ввод пользователя). Есть более эффективные способы, включающие сам millis()
, которые сохраняют расширяемость вашей программы (так что, если вы захотите добавить функциональность, она не будет заблокирована первой частью кода). И когда ваша программа достигает сложности использования собственных ISR, вам следует избегать delay()
, если вы действительно не знаете, что делаете.
IMO, на каком-то (довольно раннем) этапе каждый программист Arduino должен научиться использовать millis()
для выполнения кода по времени. Вы можете посмотреть пример BlinkWithoutDelay
, который поставляется с Arduino IDE.
- Почему необходимо использовать ключевое слово volatile для глобальных переменных при обработке прерываний в ардуино?
- Серийное прерывание
- Прерывание ардуино при смене контакта
- Влияет ли `millis()` на длинные ISR?
- Как прервать функцию цикла и перезапустить ее?
- Аппаратное прерывание срабатывает случайным образом
- Какой правильный способ запроса устройства I2C из процедуры обслуживания прерывания?
- Чтение квадратурного энкодера в реальном времени с полным разрешением только с одним прерыванием на ATmega328