Руководство по Low Power Design на Arduino
Полное руководство по снижению энергопотребления Arduino: режимы сна, внешние события, управление периферией, выбор источника питания и продвинутые техники.
Цель Low Power — снизить потребление энергии устройством, управляя его поведением так, чтобы как можно дольше продлить срок работы от батареи. Устройства, подключённые напрямую к стационарному источнику питания, как правило, не нуждаются в подобных техниках. Другое дело — автономные гаджеты на батарейках: здесь каждый миллиампер на счету.
Практики из этого руководства применимы к любым платам Arduino. Например, платы на базе процессора Arm Cortex-M0 32-bit SAMD21 поддерживают аппаратные функции низкого энергопотребления. Платы Arduino серии SAMD21 с беспроводным протоколом LoRa®, оснащённые модулем Murata CMWX1ZZABZ от MKR WAN 1310, в сочетании с техниками Low Power способны работать очень долго без подзарядки. Список всех плат Arduino можно найти на странице Arduino Documentation Hardware.
Библиотека Low Power
Для работы с режимами низкого энергопотребления на платах Arduino установите библиотеку Arduino Low Power через менеджер библиотек Arduino IDE. Она ориентирована прежде всего на платы семейства MKR.
- Откройте Sketch → Include Library → Manage Libraries, введите в поиске "Arduino Low Power" и установите последнюю версию.
- Если нужно обновить поддержку конкретной платы, зайдите в Tools → Board → Boards Manager и найдите нужное семейство.
Скачать различные версии Arduino IDE можно по ссылкам ниже:
Дополнительные материалы по работе с Arduino IDE:
Техники снижения энергопотребления
Существует несколько основных способов уменьшить потребление энергии микроконтроллером:
- Режим сна (Sleep Mode)
- Внешние события (External Events)
- ADC
- Режим ожидания (Stand-by)
Режим сна
Самый эффективный способ сэкономить энергию — отправить процессор спать. Deep Sleep (глубокий сон) отключает большинство внутренних модулей и обеспечивает максимальную экономию. Его можно настроить с таймером: устройство проснётся через заданный промежуток времени. Есть и Light Sleep (лёгкий сон) — часть модулей остаётся включённой, чтобы поддерживать необходимые процессы и отслеживать состояние внешних устройств при пробуждении.
Внутри этих режимов выделяют Stand-By и Idle — они дают разный уровень контроля над переходом в режим низкого энергопотребления.
Stand-By — один из самых экономичных режимов для плат на базе SAMD21. Он останавливает все тактовые источники и переводит регуляторы напряжения в режим низкого потребления. Генераторы могут находиться в трёх состояниях: остановлены, работают постоянно или запускаются по запросу периферии. Устройство уходит в глубокий сон при активном WFI (Wait For Interrupt). Разбудить его может прерывание или WDT (Watchdog Timer).
Idle похож на Stand-By, но периферия продолжает работать при активном WFI — это означает более высокое потребление. Тактовые источники можно оставить включёнными или отключить — решение за разработчиком. Пробуждение также происходит по прерыванию или WDT.
Внешние события для пробуждения из режима сна
Устройство не всегда должно просыпаться по таймеру — иногда нужно реагировать на события во внешней среде. Внешние события — это условия, при выполнении которых микроконтроллер выходит из режима сна. Чаще всего источниками таких событий служат ADC (Analog to Digital Converter), периферийные интерфейсы типа UART и порты I/O.
Как только на отслеживаемом входе фиксируется изменение сигнала, микроконтроллер просыпается и выполняет нужную задачу. Это удобно, например, для датчиков вибрации, газоанализаторов или детекторов уровня жидкости.
Пробуждение по ADC (Analog to Digital Converter)
Пробуждение по ADC — частный случай внешнего события. Оно срабатывает при изменении напряжения на аналоговом входе платы. Смысл изменения напряжения зависит от задачи: например, падение до нижнего порога может означать, что подключённое устройство выключилось, а рост до верхнего — что оно включилось. Как именно использовать этот сигнал для управления режимами сна — задача разработчика программного обеспечения.
Источники питания и скорость саморазряда
Мало сэкономить энергию внутри микроконтроллера — важно ещё понимать, как ведёт себя сам источник питания. Если батарея саморазряжается быстрее, чем устройство потребляет ток в режиме сна, все усилия по оптимизации теряют смысл.
Разные типы батарей имеют разную ёмкость и скорость саморазряда, причём разряд не линейный: в начале он идёт быстрее. Температура окружающей среды тоже существенно влияет на поведение батареи. Всё это нужно учитывать при проектировании.
Несколько ориентиров для сравнения:
- CR2032: ёмкость ~210 mAH, саморазряд ~1% в месяц.
- NiMH AAA: ёмкость ~900 mAH, саморазряд ~30% в месяц.
- NiMH AA: ёмкость ~2400 mAH, саморазряд ~30% в месяц.
- Li-Ion: ёмкость ~4400 mAH, саморазряд ~10% в месяц.
Характеристики разряда CR2032 при различных нагрузках (ось Y — напряжение в В, ось X — время разряда в ч)
Для расчёта эквивалентного тока саморазряда используется следующая формула:
Формула расчёта эквивалентного тока саморазряда: Эквивалентный ток = (Ежемесячная скорость саморазряда × Ёмкость батареи) / (100 × 24 × 30)
Эта формула позволяет выразить скорость саморазряда в виде непрерывного тока потребления — так удобнее сравнивать её с реальным потреблением устройства.
Помимо ёмкости и скорости саморазряда, важен и форм-фактор батареи: он определяет габариты устройства и ограничивает выбор источников питания для компактных решений.
Примеры Low-Power приложений
Простейший пример Low Power
- Необходимое оборудование: любая плата Arduino семейства MKR на базе SAMD21
Самый простой способ задействовать режим сна. Светодиод используется как индикатор: горит — устройство активно, не горит — спит. Устройство уходит в сон на 5 секунд.
#include "ArduinoLowPower.h"
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
digitalWrite(LED_BUILTIN, HIGH);
delay(1000);
digitalWrite(LED_BUILTIN, LOW);
delay(1000);
LowPower.sleep(5000);
}
Чтобы включить Deep Sleep, достаточно изменить одну строку:
//LowPower.sleep(5000);
LowPower.deepSleep(5000);
Эта строка переводит устройство в режим глубокого сна сразу после включения. Обратите внимание: в примере вызов помещён внутрь loop(), но его можно перенести и в setup(). Помните, что setup() выполняется первым — именно здесь происходит вся первоначальная настройка платы. Поэтому перед написанием кода рекомендуется сначала продумать архитектуру программы.
Пример Low Power с внешними событиями
- Необходимое оборудование: любая плата Arduino семейства MKR на базе SAMD21
Следующий пример показывает, как плата просыпается каждые 10 секунд, но также реагирует на внешнее событие на заданном пине.
#include "ArduinoLowPower.h"
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
pinMode(pin, mode);
LowPower.attachInterruptWakeup(pin, callback, mode);
}
void loop() {
digitalWrite(LED_BUILTIN, HIGH);
delay(1000);
digitalWrite(LED_BUILTIN, LOW);
delay(1000);
LowPower.sleep(10000);
}
void callback() {
// Эта функция вызывается один раз при пробуждении устройства
// Здесь можно выполнять небольшие операции (например, изменять переменные, используемые в loop)
// Не вызывайте delay() и долгие функции — этот код выполняется в контексте прерывания
}
Здесь нужно вызвать функцию LowPower.attachInterruptWakeup(pin, callback, mode), указав пин, функцию-обработчик (callback) и режим срабатывания. Режим определяет, какое изменение сигнала считается событием:
- FALLING — сигнал падает (отрицательный фронт);
- RISING — сигнал растёт (положительный фронт);
- CHANGE — любое изменение.
Для pinMode(pin, mode) доступны режимы INPUT, OUTPUT и INPUT_PULLUP. Полный пример с внешними событиями можно найти в Arduino IDE: Examples → Arduino Low Power → ExternalWakeup.
#include "ArduinoLowPower.h"
// Номер последовательности мигания
// Объявить volatile, так как значение изменяется внутри прерывания
volatile int repetitions = 1;
// Пин для запуска пробуждения
const int pin = 8;
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
// Установить пин 8 как INPUT_PULLUP, чтобы избежать ложных пробуждений
pinMode(pin, INPUT_PULLUP);
// Подключить прерывание пробуждения на пине 8, вызывающее repetitionsIncrease при пробуждении устройства
LowPower.attachInterruptWakeup(pin, repetitionsIncrease, CHANGE);
}
void loop() {
for (int i = 0; i < repetitions; i++) {
digitalWrite(LED_BUILTIN, HIGH);
delay(500);
digitalWrite(LED_BUILTIN, LOW);
delay(500);
}
// Запускает бесконечный сон (устройство пробудится только от зарегистрированных источников пробуждения)
// Потребление тока микросхемы значительно снизится
LowPower.sleep();
}
void repetitionsIncrease() {
// Эта функция вызывается один раз при пробуждении устройства
// Здесь можно выполнять небольшие операции (например, изменять переменные, используемые в loop)
// Не вызывайте delay() и долгие функции — этот код выполняется в контексте прерывания
repetitions ++;
}
Пример Low Power с пробуждением по ADC
- Необходимое оборудование: любая плата Arduino семейства MKR на базе SAMD21
Небольшая модификация предыдущего примера позволяет настроить ADC как источник пробуждения — по заданному диапазону напряжения на аналоговом входе. Пример находится в Examples → Arduino Low Power → AdcWakeup.
#include "ArduinoLowPower.h"
// Номер последовательности мигания
// Объявить volatile, так как значение изменяется внутри прерывания
volatile int repetitions = 1;
// Пин для запуска пробуждения
const int pin = A0;
// Чувствительность к изменениям напряжения
const int margin = 10;
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
pinMode(pin, INPUT);
}
void loop() {
for (int i = 0; i < repetitions; i++) {
digitalWrite(LED_BUILTIN, HIGH);
delay(500);
digitalWrite(LED_BUILTIN, LOW);
delay(500);
}
// Считать напряжение на пине ADC
int value = analogRead(pin);
// Задать диапазон вокруг этого значения
uint16_t lo = max(value - margin, 0);
uint16_t hi = min(value + margin, UINT16_MAX);
// Подключить прерывание ADC на пине A0, вызывающее repetitionsIncrease, когда напряжение выходит за заданный диапазон
// Вызывать непосредственно перед LowPower.sleep(), так как функция перенастраивает ADC внутри
LowPower.attachAdcInterrupt(pin, repetitionsIncrease, ADC_INT_OUTSIDE, lo, hi);
// Запускает бесконечный сон (устройство пробудится только от зарегистрированных источников пробуждения)
// Потребление тока микросхемы значительно снизится
LowPower.sleep();
// Отключить прерывание ADC. Вызывать сразу после LowPower.sleep(), так как функция восстанавливает конфигурацию ADC после пробуждения
LowPower.detachAdcInterrupt();
}
void repetitionsIncrease() {
// Эта функция вызывается один раз при пробуждении устройства
// Здесь можно выполнять небольшие операции (например, изменять переменные, используемые в loop)
// Не вызывайте delay() и долгие функции — этот код выполняется в контексте прерывания
repetitions ++;
}
Здесь задаётся окно напряжений, в котором аналоговый пин A0 будет вызывать прерывание:
uint16_t lo = max(value - margin, 0);
uint16_t hi = min(value + margin, UINT16_MAX);
Настройка прерывания ADC выполняется внутри loop(), чтобы можно было пересконфигурировать его прямо перед уходом в сон:
LowPower.attachAdcInterrupt(pin, repetitionsIncrease, ADC_INT_OUTSIDE, lo, hi);
После пробуждения по прерыванию ADC нужно отсоединить прерывание ADC, чтобы вернуть пину конфигурацию ADC:
LowPower.detachAdcInterrupt();
Функции-обработчики (callback) вызываются при пробуждении из сна. Хорошая практика — избегать внутри них delay() и долгих операций. Это позволяет строить неблокирующую (Non-Blocking) архитектуру, которая одновременно экономит энергию и остаётся отзывчивой.
Пример Low Power с передатчиком LoRa®
- Необходимое оборудование: MKR WAN 1300/1310 (встроенный модуль Murata)
Подробный пример работы с LoRa® на MKR WAN 1310 и модулем Murata — this documentation
Этот пример демонстрирует MKR WAN1300/1310 в роли удалённого передатчика, который периодически отправляет сигнал о своей работоспособности (beacon). Задача — симулировать устройство, которое транслирует данные через определённые интервалы и при этом должно работать как можно дольше. Приёмник остаётся стационарным. Передатчик переводит в режим сна как SAMD21, так и встроенный модуль Murata — чтобы не тратить энергию впустую.
Подробнее о библиотеке LoRa — в репозитории this library на GitHub.
// Библиотека Low Power
#include "ArduinoLowPower.h"
// Библиотека LoRa
#include <SPI.h>
#include <LoRa.h>
// Содержимое пакета LoRa
char* message = "Hello LoRa!";
void setup() {
Serial.begin(9600);
while (!Serial);
// Настройка LoRa
Serial.println(F("LoRa Sender"));
if (!LoRa.begin(868E6)) {
Serial.println(F("Starting LoRa failed!"));
while (1);
} else {
Serial.println(F("Starting LoRa Successful!"));
}
}
void loop() {
LoRa_Packet_Sender();
GoToSleep();
}
// Задача LoRa
void LoRa_Packet_Sender() {
Serial.print(F("Sending packet: "));
Serial.println(message);
// Отправить пакет
LoRa.beginPacket();
LoRa.print(message);
LoRa.endPacket();
// Перевод модуля LoRa в режим сна
Serial.println(F("LoRa Going in Sleep"));
LoRa.sleep();
}
// Задача сна
void GoToSleep(){
Serial.println(F("MKR WAN 1310 - Going in Sleep"));
LowPower.deepSleep(20000);
}
Важно понимать: библиотека Low Power управляет только микроконтроллером. Внешние модули, такие как Murata на MKR WAN 1310, нужно переводить в сон отдельно — через собственный API модуля.
Если используются внешние модули (например, Murata/LPWAN) или датчики — сначала переведите их в режим сна, и только потом отправляйте MCU. Иначе устройство не перейдёт в полноценный режим сна и максимальная экономия энергии будет недостижима. Это касается и периферийных интерфейсов — TWI и SPI.
Простой пример обнаружения низкого напряжения
- Необходимое оборудование: любая плата Arduino
Пример показывает, как определить, что источник питания почти разряжен, — чтобы устройство успело корректно завершить работу до полного отключения. Пример настроен для MKR WAN 1310: напряжение батареи считывается напрямую через аналоговый пин.
/*
Low Power — обнаружение низкого напряжения — пример конфигурации для SAMD21
*/
// Ручное управление питанием
#include "ArduinoLowPower.h"
float voltValue, battery_volt, battery_percentage;
float minimal_voltage = 1800;
float battery_voltage_ref = 3.3;
void setup() {
Serial.begin(57600);
delay(100);
// Установка индикатора низкого питания
pinMode(LED_BUILTIN, OUTPUT);
// Стандартное аналоговое опорное напряжение 3.3V
analogReference(AR_DEFAULT);
// Настройка разрешения 12 бит
analogReadResolution(12);
}
void loop() {
// Чтение с пина батареи
voltValue = analogRead(A0);
// Вычислить текущий уровень напряжения
battery_volt = ((voltValue*battery_voltage_ref)/4095)*1000;
// Уровень заряда батареи в процентах
battery_percentage = 100*abs((battery_volt - minimal_voltage)/((battery_voltage_ref*1000) - minimal_voltage));
Serial.print(F("Battery: "));
Serial.print(battery_percentage);
Serial.println(F(" % "));
if (battery_volt <= minimal_voltage){
//Световое уведомление об обнаружении низкого напряжения
lowBatteryWarning();
}
delay(2000);
// Переход в режим Low Power на 20 секунд
LowPower.deepSleep(20000);
}
// Индикатор низкого заряда батареи
void lowBatteryWarning(){
digitalWrite(LED_BUILTIN, HIGH);
delay (1);
digitalWrite(LED_BUILTIN, LOW);
delay (999);
}
Четыре ключевых параметра конфигурации:
- analogReference() — задаёт опорное напряжение для аналогового входа.
- analogReadResolution() — задаёт разрядность значения, возвращаемого функцией analogRead().
- analogRead() — выбирает аналоговый пин для считывания.
- Делитель разрядности: 4095 для 12-битного разрешения (MKR WAN 1310) или 1023 для 10-битного.
Если используется делитель напряжения, необходимо учесть соотношение резисторов в коде, иначе показания будут некорректными.
Продвинутый пример обнаружения низкого напряжения описан в последнем разделе этого руководства.
Продвинутые техники Low Power на Arduino
Следующие методы применимы к любым платам Arduino и позволяют выжать максимум из аппаратных возможностей. Они дают гибкость при проектировании энергоэффективных систем.
Низкая частота и низкое напряжение
Два мощных инструмента дополнительной экономии — снижение тактовой частоты и рабочего напряжения процессора.
Частоту важно подбирать с учётом задач: некоторые модули, например WiFi, требуют минимального уровня тактирования. Слишком низкая частота приведёт к некорректной работе или полному отказу этих модулей. В ряде случаев для работы на очень низких частотах потребуется внешний кварцевый генератор. Поэтому оптимальная стратегия — не фиксировать частоту на минимуме, а подбирать её под конкретную архитектуру ПО.
Напряжение питания: большинство плат работают на 5 В или 3,3 В. Если внешние компоненты позволяют, переход на 3,3 В заметно снизит общее потребление. Уже только эти два параметра — частота и напряжение — могут вдвое сократить энергопотребление системы.
Выбрать нужный вариант можно в Arduino IDE через меню Tools:

Выбор напряжения и частоты микроконтроллера в меню Tools Arduino IDE
Управление энергопотреблением на уровне микроконтроллера
В большинстве случаев класса library достаточно для достижения низкого потребления. Но если нужно отключать отдельные компоненты микроконтроллера независимо — на помощь приходят регистры управления питанием.
Микроконтроллер SAMD21 — Power Reduction Mode
Для SAMD21 microcontrollers, используемого в платах MKR Family, предусмотрен Power Reduction Mode.
Режим снижения энергопотребления связан с контроллером энергонезависимой памяти (NVM). Регистр CTRLB управляет этим режимом. Когда NVM-контроллер переходит в режим сниженного потребления, соответствующий бит устанавливается в регистре статуса STATUS.PRM. Для входа и выхода из режима используются команды Set и Clear Power Reduction Mode.
Регистр CTRLB микроконтроллера SAMD21
Биты SLEEPPRM регистра CTRLB: управляют режимом снижения энергопотребления NVM во время сна
Микроконтроллер Atmega328P — Power Reduction Register
Платы Classic Family и Arduino Nano на микроконтроллере Atmega328P используют Power Reduction Register (PRR).
Этот регистр позволяет индивидуально отключать: TWI, SPI, USART0, таймеры/счётчики и аналого-цифровой преобразователь. Важный нюанс: перед отключением бита ADC в PRR необходимо сбросить ADCSRA в ноль — иначе ADC зависнет в активном состоянии.
Регистр снижения энергопотребления (PRR) микроконтроллера ATmega328P
Периферия и внутренние модули
Отключение неиспользуемых внутренних модулей — ещё один эффективный способ снизить потребление. Кандидаты на отключение: SPI, I2C, Serial, ADC (ADC), Brown-out Detection и Watchdog Timer.
Периферийные интерфейсы SPI, I2C, Serial часто используются для работы с датчиками. Если какой-то интерфейс не задействован в конкретном приложении — его лучше отключить. Перед отключением интерфейса рекомендуется отправить датчик в режим сна через этот же интерфейс: сначала команда датчику, затем отключение периферии.
ADC (ADC) может служить источником пробуждения, но если эта функция не нужна — ADC стоит отключить: он потребляет заметный ток.
Brown-out Detection сравнивает напряжение питания с порогом и защищает процессор от работы при слишком низком напряжении. Watchdog Timer следит за тем, чтобы микроконтроллер не завис: при зависании он инициирует сброс. Оба модуля можно отключить вручную для экономии энергии — но только после того, как программа тщательно проверена на стабильность.
Внешние устройства
Если к плате подключены SD-карты, датчики и другие внешние устройства, их питание можно коммутировать через MOSFET-транзисторы. Это позволяет полностью обесточить периферию во время глубокого сна и максимально сократить потребление. Особенно эффективно при периодическом цикле «работа → сон → работа».
Low-Dropout регуляторы напряжения
Если схема требует регулятора напряжения, выбирайте Low-Dropout (LDO) регуляторы с минимальным током покоя (Quiescent Current). Это существенно снизит потребление системы в режиме сна. Нужные характеристики всегда указаны в даташите производителя.
Бюджет энергопотребления
Полезная практика — вести таблицу бюджета мощности всей системы. Это даёт наглядное представление о том, как распределяется энергия между компонентами, и помогает найти точки оптимизации — например, увеличить интервал сна или отключить ещё один модуль.
Измерение потребления тока
После всех оптимизаций необходимо измерить реальное потребление системы. Воспользуйтесь Multimeter Basics (раздел Reading Current), чтобы точно определить ток и убедиться в корректной работе всех режимов сна.
Обнаружение низкого напряжения (продвинутый вариант)
Даже самое оптимизированное устройство когда-нибудь разрядится. Важно, чтобы оно успело «почувствовать» критически низкий уровень заряда и корректно завершить работу — например, сохранить данные или отправить сигнал тревоги.
Для оценки времени автономной работы используйте калькулятор: https://www.omnicalculator.com/other/battery-life
Для этого применяется метод управления питанием микроконтроллеров avr, на которых основаны Atmega328P и которые встречаются, например, в Arduino Nano и Classic Family. Метод обнаружения низкого напряжения, разработанный Nick Gammon, Retrolefty и Coding Badly, совмещается с возможностью перехода в режим сна.
// Nick Gammon
// Код предоставлен «Coding Badly» и «Retrolefty» с форума Arduino
#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/wdt.h>
const long InternalReferenceVoltage = 1062; // Скорректируйте это значение под внутреннее опорное напряжение BG вашей платы
void setup() {
Serial.begin(57600);
delay(100);
// Установка индикатора низкого питания
pinMode(LED_BUILTIN, OUTPUT);
// Предварительный режим Low Power
resetWatchdog(); // На случай срабатывания WDT
}
void loop() {
// Включение периферии, таймеров и ADC
manual_periph_ctrl(1);
// Обнаружение уровня напряжения
Serial.println(getBandgap());
// Обнаружение низкого напряжения на уровне 3V (300)
if (getBandgap() < 300){
//Световое уведомление об обнаружении низкого напряжения
lowBatteryWarning();
// Отключение периферии, таймеров и ADC
manual_periph_ctrl(0);
}
// Обработчик низкого уровня
i2c_switch_off();
Manual_LowPower_Mode(1);
}
// Фиксированный вариант на 8 секунд — отключает всё
void Manual_LowPower_Mode(uint8_t multiplier){
delay(70); // Требуется не менее 68 мс запаса для времени загрузки модуля
for(int i = 0; i <= multiplier; i++){ // Множитель для тика Power Down
Deep_Sleep_Manual();
}
}
/*
Задача обнаружения низкого напряжения
*/
// Nick Gammon
// Код предоставлен «Coding Badly» и «Retrolefty» с форума Arduino
// Результаты — Vcc * 100
// Например, 5V соответствует 500
int getBandgap(){
// REFS0: выбирает внешнее опорное напряжение AVcc
// MUX3 MUX2 MUX1: выбирает 1.1V (VBG)
ADMUX = bit (REFS0) | bit (MUX3) | bit (MUX2) | bit (MUX1);
ADCSRA |= bit( ADSC ); // Запустить преобразование
while (ADCSRA & bit (ADSC)){
} // Ждать завершения преобразования
int results = (((InternalReferenceVoltage * 1024) / ADC) + 5) / 10;
return results;
} // Конец getBandgap
/*
Задачи, связанные с Low Power
*/
// Включение Watchdog Timer
void WatchdogEnable() {
// Сбросить различные флаги «сброса»
MCUSR = 0;
// Разрешить изменения, отключить сброс
WDTCSR = bit (WDCE) | bit (WDE);
// Установить режим прерывания и интервал
WDTCSR = bit (WDIE) | bit (WDP3) | bit (WDP0); // Установить WDIE и задержку 8 секунд
wdt_reset(); // Сбросить watchdog
// Отключить ADC
ADCSRA = 0;
// Готов к переходу в сон
set_sleep_mode (SLEEP_MODE_PWR_DOWN); // В лучшем случае даёт ~0.4 мА
noInterrupts();
sleep_enable();
// Программно отключить brown-out detection
MCUCR = bit (BODS) | bit (BODSE);
MCUCR = bit (BODS);
interrupts(); // Гарантирует выполнение следующей инструкции
sleep_cpu ();
// Отменить сон в качестве меры предосторожности
sleep_disable();
}
void resetWatchdog (){
// Сбросить различные флаги «сброса»
MCUSR = 0;
// Разрешить изменения, отключить сброс, сбросить существующее прерывание
WDTCSR = bit (WDCE) | bit (WDE) | bit (WDIF);
// Установить режим прерывания и интервал (WDE должен быть изменён с 1 на 0)
WDTCSR = bit (WDIE) | bit (WDP3) | bit (WDP0); // Установить WDIE и задержку 8 секунд
// Сбросить watchdog
wdt_reset();
} // Конец resetWatchdog
void i2c_switch_off(){
// Отключить I2C
TWCR &= ~(bit(TWEN) | bit(TWIE) | bit(TWEA));
// Отключить подтягивающие резисторы I2C
digitalWrite (A4, LOW);
digitalWrite (A5, LOW);
}
// Выполняется примерно 8 секунд, считая как один цикл
void Deep_Sleep_Manual(){
// Состояние CORE
set_sleep_mode (SLEEP_MODE_PWR_DOWN);
ADCSRA = 0; // Отключить ADC
power_all_disable (); // Отключить питание ADC, Timer 0 и 1, последовательного интерфейса
// Прерывания не учитываются, как требует ADXL
noInterrupts (); // Начинается временна́я последовательность
resetWatchdog (); // Подготовить watchdog
sleep_enable (); // Готов к переходу в сон
interrupts (); // Прерывания теперь необходимы
sleep_cpu (); // Сон
sleep_disable (); // Мера предосторожности
power_all_enable (); // Включить всё обратно
} // Конец goToSleep
// Ручной контроллер периферии
void manual_periph_ctrl(uint8_t selector){
byte old_ADCSRA = ADCSRA;
// Отключить ADC
ADCSRA = 0;
if (selector == 0){
power_adc_disable();
power_spi_disable();
power_timer0_disable();
power_timer1_disable();
power_timer2_disable();
power_twi_disable();
UCSR0B &= ~bit (RXEN0); // Отключить приёмник
UCSR0B &= ~bit (TXEN0); // Отключить передатчик
}
if (selector >= 1){
power_adc_enable();
power_spi_enable();
power_timer0_enable();
power_timer1_enable();
power_timer2_enable();
power_twi_enable();
UCSR0B |= bit (RXEN0); // Включить приёмник
UCSR0B |= bit (TXEN0); // Включить передатчик
}
ADCSRA = old_ADCSRA;
}
// Индикатор низкого заряда батареи
void lowBatteryWarning(){
digitalWrite(LED_BUILTIN, HIGH);
delay (1);
digitalWrite(LED_BUILTIN, LOW);
delay (999);
}
Чтобы найти внутреннее опорное напряжение, можно воспользоваться одним из двух скриптов. После запуска измерьте напряжение на пине AREF мультиметром и умножьте результат на 1000 — это и будет значение Internal Reference Voltage для подстановки в код.
- Через регистр
ADMUX:
// Найти внутреннее опорное напряжение 1.1 на пине AREF
void setup ()
{
ADMUX = bit (REFS0) | bit (REFS1);
}
void loop () { }
- Через функции analogReference и analogRead:
// Найти внутреннее опорное напряжение 1.1 на пине AREF
void setup ()
{
analogReference (INTERNAL);
analogRead (A0); // Принудительно включить опорное напряжение
}
void loop () { }
Подробнее о системах Low Power: https://www.gammon.com.au/power
Торговые марки
- LoRa® — зарегистрированная торговая марка Semtech Corporation.