Пробуждение 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 или новее.
Запрет прерываний и пропущенные события прерываний (статья Аналоговый компаратор Arduino).
Пробуждение Arduino из спящего режима по нажатию кнопки.