Пробуждение Arduino из спящего режима по нажатию кнопки

Итак, подключив к выводу INT0 (Digital 2) (см. схему подключения) кнопку и помигав светодиодом, я подумал, что с точки зрения экономии электроэнергии было бы неплохо, если бы Arduino пребывал в спящем режиме всё то время, пока пользователь не нажмёт на кнопку. После нажатия на кнопку скетч мигает светодиодом и снова погружает Arduino в сон.

Получилась следующая структура новой версии скетча:

В этой версии я решил использовать библиотеку VEduino, чтобы код скетча был более читаемым и портируемым. В результате кода стало заметно меньше.

Однако на практике такой алгоритм хорош, если мы имеем дело с виртуальной кнопкой, которую "нажимает" другая микросхема. В случае же обычной кнопки имеет место проблема дребезга контакта, что приводит к ложным срабатываниям. Например, светодиод или светится дольше положенного, или загорается и при нажатии на кнопку, и при отпускании, если кнопку подержать нажать дольше 250 мс в нашем случае.

Поэтому поэкспериментировав я изменил алгоритм таким образом, чтобы Arduino зажигал светодиод не сразу, а подождав 10 мс, и дополнительно проверил, нажата ли кнопка или уже отпущена. Экспериментируя с FPGA, я опытным путём выяснил, что тактируя логику с циклом примерно 32 Гц удаётся избежать проблемы дребезга контакта в случае реальной кнопки. А 32 Гц - это 31.250 мс, то есть выждав 10 мс и сделав проверку, нажата ли кнопка, алгоритм не реагирует на дребезг контакта при нажатии и избегает ложного срабатывания при отпускании кнопки.

Получился следующий код:

#include <ve_avr.h> // Будет использоваться библиотека VEDuino.


#define LEDPIN 13 // Вывод светодиода

#define BTNPIN 2 // Вывод кнопки


volatile int count = 0; // Переменная счётчика (volatile означает указание компилятору не оптимизировать код её чтения,

// поскольку её значение изменяется внутри обработчика прерывания)


ISR(INT0_vect) // Функция обработки прерывания INT0

{

count = 25; // Инициализировать счётчик

}


void setup() {

pinMode(LEDPIN, OUTPUT); // Вывод светодиода в режим вывода

pinMode(BTNPIN, INPUT); // Вывод кнопки в режим ввода

// Прерывание INT0 в режиме переднего фронта (в данном случае при нажатии на кнопку)

DEV_EXTINTCTRL.setSenseType0(ExtIntControl::RISING_EDGE);

DEV_EXTINTFLAGS.enableInterrupt0(); // Разрешить прерывание INT0

interrupts(); // Разрешить прерывания глобально

}


void loop() {

if(count==0) {

digitalWrite(LEDPIN, LOW); // Выключить светодиод, если счётчик равен 0...

DEV_SLEEP.setMode(SleepControl::PWR_DOWN); // Выбор режима сна

DEV_SLEEP.enableSleep(); // Разрешить переход в спящий режим

sleep(); // Переход в режим сна

}

else {

delay(10); // ... иначе подождать 10 милисекунд,

if(digitalRead(BTNPIN) == HIGH) // проверить, нажата ли кнопка

digitalWrite(LEDPIN, HIGH); // и либо включить светодиод,

else

count = 1; // либо сбросить счётчик.

--count; // уменьшить счётчик на 1.

}

}

Код скетча можно скачать как файл INO. Библиотеку VEduino нужно будет обновить до версии 0.15 или новее.