Как перевести 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()?

, 👍6

Обсуждение

#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


3 ответа


Лучший ответ:

7

Компьютеры ATTINY спроектированы таким образом, чтобы это было легко сделать, поскольку они могут выходить из спящего режима выключения путем смены контакта...

В основном вы хотите...

  1. Подключите нормально разомкнутую кнопку между контактом ввода-вывода и землей.
  2. Включите подтягивание на IO.
  3. Включить прерывание смены контакта на выводе ввода-вывода.
  4. Включить прерывания.
  5. Войти в спящий режим с отключением питания.

При нажатии кнопки контакт ввода-вывода подключается к земле, что вызывает прерывание смены контакта, которое выводит микросхему из спящего режима.

Обратите внимание, что вам не нужно ничего делать в 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


2

Сначала я не смог заставить прерывание работать для нескольких контактов, но, наконец, вот рабочий код:

#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: как упомянул Максимилиан в комментарии, этот пост предлагает хорошие решения: Обнаружение нажатия клавиш на клавиатуре во время сна.

,

2

Я бы перевел MCU в глубокий сон, а затем использовал кнопку сброса.

,