noInterrupts()
noInterrupts() отключает все аппаратные прерывания — удобно для защиты критичных участков кода, работающих с long, float или точными таймингами.
Полная статья
Описание
Функция noInterrupts() запрещает обработку аппаратных прерываний. По умолчанию прерывания в Arduino включены: они позволяют микроконтроллеру реагировать на внешние события и выполнять фоновые задачи — например, получать данные по Serial или отсчитывать время с помощью millis(). Иногда, однако, прерывание в самый неподходящий момент может нарушить тайминг критичного участка кода. Именно для таких случаев и нужна noInterrupts().
После того как вы защитили нужный участок, обязательно снова включите прерывания с помощью interrupts() — иначе часть функций Arduino перестанет работать корректно.
Синтаксис
noInterrupts()
Параметры
Функция не принимает параметров.
Возвращает
Ничего не возвращает.
Пример кода
void setup() {}
void loop() {
noInterrupts();
// критический, чувствительный ко времени код
interrupts();
// остальной код
}
Где применяется
- Работа с многобайтовыми переменными. Если прерывание может изменить переменную в середине её чтения или записи (например,
longилиfloat), данные окажутся повреждены.noInterrupts()защищает такие операции. - Точное управление временем. При генерации импульсов с жёсткими требованиями к длительности прерывания могут сдвинуть момент смены состояния вывода.
- Работа с аппаратными протоколами без аппаратной поддержки. Программная реализация протоколов, чувствительных к задержкам, требует гарантированного выполнения без пауз.
- Атомарное чтение данных от ISR. Если обработчик прерывания обновляет переменную, которую читает основной цикл, нужно на момент чтения заблокировать прерывания, чтобы получить согласованное значение.
Практические замечания
- Всегда включайте прерывания обратно. Вызов
noInterrupts()без последующего interrupts() — распространённая ошибка.millis()иdelay()перестанут работать правильно, Serial перестанет принимать данные. - Держите защищённый участок как можно короче. Чем дольше прерывания отключены, тем больше событий будет пропущено: входящие байты Serial, импульсы энкодера, тики таймера.
- Вложенные вызовы не поддерживаются. Если вы вызовете
noInterrupts()дважды подряд, один вызов interrupts() всё равно включит прерывания — счётчика вложенности нет. - Прерывания не буферизуются. Событие, которое произошло во время блокировки, будет потеряно — за исключением случаев, когда аппаратный буфер (например, UART FIFO) успел его сохранить.
- Осторожно на платах с нативным USB. На платах вроде Arduino Leonardo длительное отключение прерываний может нарушить USB-обмен с компьютером. В результате плата может временно перестать отвечать как последовательный порт, пока прерывания не будут снова включены.
Примечания и предупреждения
На платах с нативным USB не держите прерывания отключёнными дольше необходимого: это может нарушить работу USB Serial и сделать отладку через Serial Monitor нестабильной.