Как перевести ATtiny/ATmega в режим глубокого сна (чтобы годами работать от батарей), но при этом обнаруживать нажатие кнопки?
Вопрос (TL;DR): каков оптимальный метод глубокого сна (для работы ATtiny45 или ATmega на батареях в течение 1+ года), но при этом способный обнаруживать нажатие кнопки? Является ли возможен ли глубокий сон, пока не будет нажата кнопка?
Я использую классический метод устранения дребезга для обнаружения нажатия кнопки:
int buttonState;
int lastButtonState = LOW;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;
void setup() {
pinMode(2, INPUT);
}
void loop() {
int reading = digitalRead(2);
if (reading != lastButtonState) { lastDebounceTime = millis(); }
if ((millis() - lastDebounceTime) > debounceDelay) {
if (reading != buttonState) {
buttonState = reading;
if (buttonState == HIGH) {
// Кнопка нажата, сделайте что-нибудь здесь!
// В моем реальном коде он отправляет пакет через RF 433 МГц
}
}
}
lastButtonState = reading;
// храп(20); // TinySnore здесь
}
Мой ATtiny45 должен работать в течение 1 года на 3 батарейках типа АА, поэтому я добавил режим глубокого сна с помощью Крошечный Храп. Это работает, и потребление увеличилось с более чем 1 мА до 0,2 мА (при частоте 1 МГц).
Я знаю, что можно снизить ток до 5 мкА, если я храплю(1000);
, но тогда, очевидно, он не сможет обнаружить нажатие кнопки.
Я пробовал разные значения сна: храп(10);
, храп(20);
, храп(50);
и т. д. но я не получил последовательных результатов.
Поэтому вопрос: как глубоко заснуть пока кнопка не нажата?
Я думал об использовании attachInterrupt()
но тогда какой сон мы должны использовать? храп()
? delay()
?
@Basj, 👍7
Обсуждение3 ответа
Лучший ответ:
Компьютеры ATTINY спроектированы таким образом, чтобы это было легко сделать, поскольку они могут выходить из спящего режима выключения
путем смены контакта...
В основном вы хотите...
- Подключите нормально разомкнутую кнопку между контактом ввода-вывода и землей.
- Включите подтягивание на IO.
- Включить прерывание смены контакта на выводе ввода-вывода.
- Включить прерывания.
- Войти в спящий режим с отключением питания.
При нажатии кнопки контакт ввода-вывода подключается к земле, что вызывает прерывание смены контакта, которое выводит микросхему из спящего режима.
Обратите внимание, что вам не нужно ничего делать в ISR смены контакта (вы можете использовать макрос компилятора EMPTY_INTERRUPT
). Если ISR пуст, выполнение начнется в строке после сна при пробуждении.
Находясь в глубоком сне, чип потребляет удивительно мало энергии. Например, ATTINY25/45/85, работающий от батарейки типа «таблетка» на 3 В при комнатной температуре, будет потреблять менее 0,2 мкА...
Обычная батарейка типа «таблетка» CR2032 рассчитана на емкость от 235 мАч до 2 В, поэтому при такой скорости мы ожидаем, что сможем дождаться нажатия такой кнопки в течение 100+ лет.
В реальных условиях батарея, скорее всего, саморазрядится и физически ухудшится задолго до этого (рейтинг составляет 1 % в год), но все равно не слишком ветхая.
Спасибо за этот отличный ответ! Связанный вопрос: https://arduinoprosto.ru/q/70292/how-to-assign-an-interrupt-to-a-button-press-with-an-attiny-interrupt-not-fire, @Basj
Сначала я не смог заставить прерывание работать для нескольких контактов, но, наконец, вот рабочий код:
#include <avr/interrupt.h>
#include <avr/sleep.h>
ISR(PCINT0_vect) {
if (digitalRead(0) == LOW) // # PB0 = контакт 5 нажат => светодиод горит
digitalWrite(4, HIGH);
else if (digitalRead(1) == LOW) // # PB1 = контакт 6 нажат => светодиод выключен
digitalWrite(4, LOW);
else if (digitalRead(2) == LOW) // # PB2 = контакт 6 нажат => светодиод горит
digitalWrite(4, HIGH);
}
void setup() {
pinMode(4,OUTPUT); // ВЕЛ
pinMode(0,INPUT_PULLUP);
pinMode(1,INPUT_PULLUP);
pinMode(2,INPUT_PULLUP);
ADCSRA = 0; // АЦП отключен
GIMSK = 0b00100000; // Общий регистр маски прерывания, / Бит 5 — PCIE: Разрешение прерывания по смене контакта / Когда бит PCIE установлен (один) и I-бит в регистре состояния (SREG) установлен (один), прерывание по смене контакта разрешено . Любое изменение на любом включенном выводе PCINT[5:0] вызовет прерывание. Соответствующее прерывание запроса прерывания смены контакта выполняется из вектора прерывания PCI. Выводы PCINT[5:0] активируются индивидуально регистром PCMSK0. / см. https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-2586-AVR-8-bit-Microcontroller-ATtiny25-ATtiny45-ATtiny85_Datasheet.pdf
PCMSK = 0b00000111;
}
void loop() {
sleep_enable();
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_cpu();
}
Примечание. PCINT здесь обрабатывается одним PCINT_vect.
PS: как упомянул Максимилиан в комментарии, этот пост предлагает хорошие решения: Обнаружение нажатия клавиш на клавиатуре во время сна.
- Самая низкая мощность, возможная в Arduino
- Вывод ESP8266 из deepSleep с помощью кнопки
- Как назначить прерывание на нажатие кнопки с помощью ATtiny? (прерывание не срабатывает с моим кодом)
- Как перевести RFID-модуль MFRC522 в спящий режим?
- Легкий сон ESP8266 — не могу проснуться
- Как отслеживать миллисекунды в спящем режиме
- Датчик DHT11: режим ожидания или выключение?
- Не может получить низкую мощность с Adafruit Trinket
#include <avr/sleep.h>
сsleep_cpu
и друзьями, разбуженными прерыванием. У Ника Гэммона есть довольно обширный пост на форуме по этому поводу: https://www.gammon.com.au/forum/?id=11497 (https://github.com/connornishijima/TinySnore/blob/master/src/tinysnore. cpp использует те же функции, но, кажется, может только пробуждать по таймеру), @Maximilian GerhardtСпасибо @MaximilianGerhardt. В этом примере: https://www.gammon.com.au/forum/?id=11497&reply=4#reply4, почему не используется [attachInterrupt](https://www.arduino.cc/reference/en /язык/функции/внешние прерывания/присоединить прерывание/)? Существуют ли разные методы?, @Basj
Вместо
attachInterrupt()
подпрограмма обслуживания прерывания (ISR) для необходимых векторов перехватывается напрямую, например,ISR (PCINT0_vect) { .. }
. Пример сattachInterrupt
находится в первом посте с кодомПробуждение от сна по сигналу
, который лучше соответствует вашей кнопке. Когда прерывание настроено для вывода, событие изменения автоматически выводит ЦП из спящего режима. См. техническое описание (http://www.farnell.com/datasheets/1698186.pdf), раздел 7.1 «Спящие режимы», «INT0 и смена контактов»., @Maximilian GerhardtСразу предостерегаю, что ставлю стандартный ATMEGA. Плата в спящем режиме оставляет вспомогательную схему (интерфейс USB и т. д.) потребляющей мощность, поэтому вам лучше выбрать ATTINY., @kiwiron