Одна кнопка для сна и пробуждения
- Войдите на сайт для отправки комментариев
Всем привет! Не могу заставить Дуину засыпать и просыпаться по прерыванию на кнопке.
На просторах вашего Интернета тема сна Ардуино достаточно распространена. Многие используют прерывания 0 и 1 на пинах 2 и 3 для того, чтобы выводить микроконтроллер Atmega328P из сна, и, реже, вводить его в сон.
Тем не менее, мне не посчастливилось отыскать даже намека на код, который использует единственную кнопку одновременно для ввода в сон и для пробуждения. Более того, мои любительские эксперименты с кодом привели к результату, что МК с легкостью выполняет одно из двух: либо засыпает по прерыванию, либо пробуждается. Но заставить выполнять оба действия разом у меня не получилось:
Код, который уводит в сон по нажатию (сенсорной) кнопки. За сигнал нажатия принимается логическая единица. Стягивающий резистор имеется.
#include <avr/sleep.h> int TOUCH = 3; int LED = 13; void setup(){ pinMode(TOUCH, INPUT); pinMode(LED, OUTPUT); delay(3000); } void Interrupt(void){ sleep_disable(); detachInterrupt(1); } void Sleep(void){ digitalWrite(LED, LOW); // (3) Светодиод гаснет при нажатии кнопки. delay(250); sleep_enable(); attachInterrupt(1, Interrupt, HIGH); set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_mode(); // (4) С этого момента спим. sleep_disable(); // (5) С этого момента пробуждаемся. Должны вернуться в loop(), но светодиод не загорается. delay(250); } void loop(){ digitalWrite(LED, HIGH); // (1) Светодиод горит if (digitalRead(TOUCH)){ // (2) Если кнопка нажата, то вызываем фнкцию засыпания. Sleep(); } }
Код, который выводит из сна по нажатию (сенсорной) кнопки. За сигнал нажатия принимается логическая единица.Стягивающий резистор имеется.
#include <avr/sleep.h> int TOUCH = 3; int LED = 13; void setup(){ pinMode(TOUCH, INPUT); pinMode(LED, OUTPUT); digitalWrite(LED, HIGH); // (1) Светодиод горит. delay(3000); Sleep(); // (2) Уходим в сон. } void Interrupt(void){ sleep_disable(); detachInterrupt(1); } void Sleep(void){ digitalWrite(LED, LOW); // (3) Светодиод гаснет. delay(250); sleep_enable(); attachInterrupt(1, Interrupt, HIGH); set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_mode(); // (4) С этого моента спим. sleep_disable(); // (5) С этого момента пробуждаемся при нажатой кнопке. delay(250); } void loop(){ digitalWrite(LED, HIGH); // (6) Пробудились, светодиод загорелся. delay(3000); Sleep(); // (7) Ушли в сон, но пробуждение по кнопке сработало только один раз. }
Учитывая, насколько распространенной может являться задача, меня раздирает любопытство: 1) почему на первых трех страницах выдачи "arduino sleep button"крупнейших поисковиков нет тем про одновременное использование кнопки для ввода и вывода из сна; 2) возможно ли это в принципе, и если да, то что я упустил.
Буду благодарен за ответы!
Я может не понимаю, а общий скетч где который не работает?
Скорее проблема в дребезге контактов, в коде засыпания поставить паузу минимум на секунду, после которой уже спать
Привет! В обоих скетчах есть то, что работает, и то что не работает (см. комментарии):
1) МК уходит в сон по нажатию, но не выходит из него по нажатию.
2) МК выходит из сна по нажатию, но не входит в него по нажатию.
Кнопка сенсорная, должна срабатывать без дребезга. Я попробовал задержку 500 и 1000 против дребезга. Результат тот же.
Напиши функцию , которая будет запускаться при FALLING или RISING(в зависимости от того как кнопку прицепил). В теле проверка предыдущего состояния с его изменением на противоположное. И в зависимости от текущего, либо спать, либо вставать.
В твоих скетчах, ты сначала вызываешь функцию sleep_enable(), а потом включаешь прерывание.
Не знаю, что там у тебя в библиотеке, но похоже что прерывание уже просто не проверяется. Может не стоит его выключать в 16ой строке ?
И по мне прерывание внутри функции, это как то неправильно. Должно быть наоборот. Логичнее функцию вызывать по прерыванию.
NM, для начала прочитайте п.п. 10.6 и 13.1 даташита - в режиме power_down прерывание надо настраивать на низкий уровен, асинхронно только он распознаётеся. Поэтому, чтобы надёжно пробуждалась, подтягивайте к питанию, а прерывание на LOW. Ну и дребезг надо уирать или программно, или аппаратно.
Всем привет! Заставил Дуину засыпать и просыпаться по прерыванию на кнопке.
Проблема была в малом: открепление прерывания detachInterrupt(1); не срабатывало из функции-обработчика прерываний Interrupt().
Вот проверенный скетч, который надежно уводит МК в сон и выводит из сна по нажатию на единственную кнопку. Также, код использует функцию отключения переферии и Brown Out Detector-а, благодаря чему потребелние в спящем режиме настолько мало, что измерить его моим простеньким амперметром не удалось.
Всем спасибо!
В строке 22 правильнее писать не HIGH, а FALLING.
Спасибо за комментарий! Думаю, там можно и RISING написать? В любом случае, данный скетч работает :)
RISING вряд-ли. Вроде в даташите написано, что в режимах экономии (кроме IDLE) срабатывает только FALLING. Хотя попробовать никто не мешает. Если надо могу найти раздел даташита. Кстати, Ваша HIGH (1) соответсвует CHANGE, но CHANGE предполагает FALLING - потому и работает.
Интересно. Честно признаюсь, даташит не читал, но вам верю на слово :) Непонятно только, почему тогда происходит прерывание при нажатии на кнопку в режиме сна?
А кнопка при нажатии HIGH даёт на пин или LOW (она типа к земле идёт или к питанию)? Если к питанию, то второй вопрос, а просыпается точно по нажатию? Может по отпусканию (в т.ч. и по дребезгу!)
А что гадать, я проверил. C RISING работает также. Кнопка дает HIGH при детектировании нажатия.
Ну, значит либо в даташите перестраховались и это недокументированная возможность, либ ещё чего.