Программа обработки прерываний, которая была описана в прошлый раз, имеет пару недостатков, которые следует учитывать при разработке реальных программ.
1. В обработчике прерываний ISR(WDT_vect) выполняется довольно "медленная" функция записи бита в порт ввода/вывода digitalWrite. Это плохо, т. к. собственно прерывание должно выполняться максимально быстро, и без насущной необходимости перегружать его лишними действиями не следует. Ведь на время обработки прерывания остальные прерывания, как правило, запрещаются, и можно пропустить какое-нибудь важное событие.
2. Обработчик прерывания выполняет что-то внутри себя, никак не информируя основную программу, чем он там занят и в каком состоянии находится. Как правило прерывание используется, чтобы сообщить основной программе о событии, которое следует или обработать, сообщает, что устройство готово к приему/передаче данных и проч.
Поэтому изменим программу следующим образом (см рис. 1).
Организуем ячейку памяти counter, которая будет использоваться обработчиком прерываний. Кроме того, что это тип int, дополнительно укажем тип volatile. Это требуется для указания доступа к ней из обработчиков прерываний.
Не все версии ArduinoIDE требуют указывать volatile. Например, в Arduino 1.6.5 этого вроде не требуется, однако, чтобы не было неприятных неожиданностей, лучше соблюдать это простое правило.
Следует, однако, учесть, что обозначение переменной, как volatile может "съедать" память. Например, при обозначении переменной как float получаем следующее использование памяти (рис. 2):
А при обозначении volatile float дополнительно "уходит" чуть не сотня байт (рис. 3.).
Ну а наш обработчик прерываний теперь выполняет всего лишь операцию инкремента ячейки (counter++), а все действия по обработке результата возложены на основную программу (loop). Для этого основная программа просто сравнивает содержимое счетчика с заданным значением (switch_led) и выполняет не только операцию по включению/выключению светодиода, но и сбрасывает счетчик counter в начальное состояние.
В заключение необходимо отметить, что любое прерывание связано с работой "железа" — таймера, АЦП, портов ввода/вывода и т. п. Каждое из этих устройств имеет свой принцип и логику работы, а также набор регистров различного назначения (управления, состояния, данных и т. п.). Работу как этих регистров, так и самого "железа" необходимо предварительно внимательно изучить, чтобы правильно использовать само устройство и его прерывание .