Руководство Arduino по энергоэффективному дизайну

Изучите основы энергоэффективного проектирования с использованием аппаратного и программного обеспечения Arduino.

Авторы: Taddy Chung, José Bagur

Последнее обновление: 28.02.2025

Цель Low Power (энергосбережение) — снижение потребления энергии устройством за счёт управления его поведением для продления срока службы. Электронные устройства, питающиеся непосредственно от источника питания, как правило, не требуют применения Low Power или аналогичных методов для продления ресурса. С другой стороны, для устройств, работающих от таких источников питания, как батарейки, необходимо экономить потребление энергии, чтобы продлить срок их работы.

Данное руководство по созданию энергоэффективных систем применимо к любым платам Arduino. Например, платы Arduino на базе процессора Arm Cortex-M0 32-bit SAMD21 могут воспользоваться функциями энергосбережения. Платы Arduino SAMD21 с беспроводным протоколом на основе технологии LoRa® с модулем Murata CMWX1ZZABZ, входящим в состав MKR WAN 1310, можно сочетать с функциями энергосбережения для длительной работы. С помощью продвинутых методов, таких как руководство по источнику питания и расчёт скорости саморазряда, возможно проектировать энергоэффективные системы для любых плат Arduino. Информацию о платах Arduino можно найти на странице Arduino Documentation Hardware.

Библиотека Low Power

Для включения функций Low Power на платах Arduino можно загрузить библиотеку Arduino Low Power из менеджера библиотек в Arduino IDE. Эта библиотека активирует функции энергосбережения для плат семейства MKR.

  • Управление библиотекой: Sketch -> Include Library -> Manage Libraries в Arduino IDE, поиск «Arduino Low Power» — выбрать последнюю версию.

  • При необходимости обновить компоненты платы: Tools -> Board -> Boards Manager, поиск соответствующего семейства плат Arduino.

Скачать различные версии Arduino IDE можно по ссылке:

Подробнее об Arduino IDE:

Методы энергоэффективного проектирования

Существует несколько различных способов снизить потребление энергии микроконтроллерами:

  • Режим сна (Sleep Mode)

  • Внешние события (External Events)

  • АЦП (ADC)

  • Режим ожидания (Stand-by)

Метод Sleep (сон)

Лучший способ реализовать функции энергосбережения — перевести процессор в режим сна. Режим Deep Sleep позволяет отключить ряд внутренних модулей и максимально снизить потребление энергии. Режим Deep Sleep можно настроить с таймером: устройство будет просыпаться по истечении заданного времени. Кроме того, существует режим Light Sleep, при котором часть внутренних модулей остаётся включённой для выполнения необходимых задач. Как правило, Deep Sleep применяется для максимальной экономии энергии, тогда как Light Sleep помогает сохранить некоторые настройки и отслеживать состояние внешних модулей при пробуждении.

В рамках этих режимов сна режимы Stand-By и Idle предоставляют различные уровни настройки перевода микроконтроллера в режим низкого энергопотребления. В зависимости от требований устройства, некоторые компоненты или модули могут оставаться активными в режиме сна. Stand-By — один из режимов с наименьшим потреблением энергии для плат на базе SAMD21. При его активации останавливаются все источники тактового сигнала микроконтроллера, а регуляторы напряжения переходят в режим низкого потребления. Генераторы могут находиться в 3 различных состояниях: остановлены, работают или работают по запросу периферии. Устройство переходит в режим глубокого сна, пока активен WFI (Wait For Interrupt — ожидание прерывания). Прерывание или WDT (Watchdog Timer) служат триггерами для пробуждения устройства из режима сна.

То же самое справедливо и для режима Idle по сравнению со Stand-By. В режиме Idle периферия продолжает работать, пока активен WFI. Однако устройство не переходит в режим глубокого сна, что означает более высокое потребление энергии по сравнению со Stand-By. Источники тактового сигнала зависят от решения разработчика программного обеспечения — оставить их работающими или отключить для снижения потребления энергии. Прерывание или WDT (Watchdog Timer) служат триггерами для пробуждения устройства из режима сна, как и в предыдущем режиме.

Внешние события для выхода из режима сна

Приложение не всегда предназначено для постоянного нахождения в режиме сна после завершения запланированных задач — ему нужна возможность реагировать на окружающую среду и выполнять задачи по заданному триггеру. Внешние события — это причины, по которым микропроцессор выходит из режима сна при выполнении заданных условий. Как правило, такие внешние события инициируются АЦП (Аналого-цифровым преобразователем), периферийными устройствами, например UART, а также портами ввода-вывода (I/O).

Таким образом, когда устройство распознаёт изменение сигнала, микропроцессор просыпается и приступает к выполнению запрограммированных задач. Например, для измерения интенсивности вибрации, низкого или избыточного уровня ресурсов, которые необходимо количественно оценить, — например, компонентов газа в воздухе.

Пробуждение по срабатыванию АЦП (Аналого-цифрового преобразователя)

Пробуждение по триггеру АЦП (Аналого-цифрового преобразователя) относится к категории пробуждений по внешним событиям. Оно срабатывает при изменении напряжения, обнаруженном через аналоговый вывод платы. Изменение уровня напряжения может интерпретироваться по-разному: обычно это означает, что устройство, подключённое к аналоговому выводу, отключается от питания — и напряжение достигает нижнего порога.

В то время как то же подключённое устройство может быть включено — тогда напряжение достигнет верхнего порога. Определить, как использовать это поведение в качестве сигнала пробуждения, — задача разработчика программного обеспечения, который стремится обеспечить длительную работу от батареи при выполнении нужных задач.

Руководство по источнику питания и скорости саморазряда

Руководство по источнику питания помогает понять, что, помимо управления платами Arduino для экономии энергии, важно знать: сам источник питания имеет собственную скорость разряда. Нет смысла экономить энергию всеми этими методами и ресурсами, если сам источник питания саморазряжается быстрее, чем потребляет устройство в режиме низкого энергопотребления.

В качестве источника питания рассматриваются батарейки, поскольку именно они питают устройство. Существуют различные батарейки с разной ёмкостью и скоростью саморазряда, которая не является постоянной — они разряжаются быстрее в начале. На этот фактор, как правило, влияет температура, которая заставляет батарейки вести себя по-разному в зависимости от условий окружающей среды. Поэтому это необходимо учитывать как ориентир при разработке эффективного устройства Low Power.

Батарейки CR2032 имеют ёмкость 210 мАч и скорость саморазряда 1% в месяц. Батарейки NiMH типа AAA обладают ёмкостью 900 мАч — больше, чем у CR2032, но скоростью саморазряда 30% в месяц; версия формата AA имеет ёмкость 2400 мАч при той же скорости разряда. Литий-ионные батарейки обладают ёмкостью 4400 мАч и скоростью саморазряда 10% в месяц.

Характеристики разряда Omnienergy CR2032 при различных нагрузках

Характеристики разряда Omnienergy CR2032 при различных нагрузках

Очевидно, что существует несколько типов источников питания с различными характеристиками, которые можно использовать в качестве факторов проектирования. Некоторые специфические конструктивные случаи могут предъявлять строгие требования к химическому составу источника питания, но здесь в качестве основных параметров для разработки энергоэффективных устройств будут использоваться ёмкость и скорость разряда. Требование к химическому составу обусловлено соображениями безопасности, чтобы устройство могло работать в строго контролируемой среде.

Скорость саморазряда выражается следующим уравнением:

Формула скорости саморазряда

Формула скорости саморазряда

Это уравнение скорости саморазряда поможет вам узнать, с какой скоростью источник питания будет разряжаться за час. Это значение позволит понять, что оно является приблизительной скоростью непрерывного потребления.

При создании энергоэффективного устройства в игру вступает ряд конструктивных факторов. Источники питания подвержены указанным условиям, поэтому их необходимо принимать во внимание при проектировании. Это позволит избежать риска, упомянутого ранее, — ситуации, когда потребление самого источника питания превышает фактическое потребление устройства.

Кроме того, важно знать форм-фактор источника питания, поскольку он определяет размер устройства и ограничивает выбор источников питания, если устройство должно быть очень маленьким. В этом случае продвинутые методы энергосбережения помогут вам разобраться в конструктивных соображениях и в полной мере воспользоваться данным руководством по Low Power.

Примеры приложений с Low Power

Следующие простые примеры помогут вам понять и реализовать режим Low Power.

Стандартный пример Low Power

  • Необходимое оборудование: любые платы Arduino на базе SAMD21 (семейство MKR)

Это наиболее простой способ реализации режима Low Power. Светодиод используется как индикатор: сообщает, находится ли устройство в активном состоянии или в режиме сна. Устройство будет находиться в режиме сна в течение 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);

Это переведёт устройство в режим Deep Sleep при включении питания. Как видно из этого простого примера кода, он написан внутри функции loop, однако данную строку кода Low Power можно разместить и внутри функции setup.

Важно помнить, что функция setup выполняется первой — это сектор, в котором плата надлежащим образом настраивается перед выполнением различных задач. Поэтому всегда рекомендуется сначала разработать структуру программного обеспечения, а затем приступать к написанию реального кода — это поможет создать энергоэффективное устройство.

Пример Low Power на основе внешних событий

  • Необходимое оборудование: любые платы Arduino на базе SAMD21 (семейство MKR)

Следующий пример демонстрирует, как плата просыпается каждые 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 и указать mode — режим определения изменения сигнала на заданном выводе. Режим mode может быть задан в 3 различных вариантах: FALLING, RISING и CHANGE.

Режим Falling означает, что сигнал на заданном выводе находится в отрицательном тренде; Rising — сигнал в положительном тренде; Change — любой из трендов, когда на заданном выводе фиксируется любой тип изменения. Для

pinMode(pin, mode)

режимы — это INPUT, OUTPUT или INPUT_PULLUP. Конкретный пример Low Power на основе внешних событий можно найти, перейдя в 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 на основе АЦП (Аналого-цифрового преобразователя)

  • Необходимое оборудование: любые платы Arduino на базе SAMD21 (семейство MKR)

Немного изменив предыдущий пример Low Power на основе внешних событий, можно настроить АЦП (Аналого-цифровой преобразователь) как источник пробуждения при обнаружении заданного диапазона значений напряжения. Этот пример можно найти, перейдя в 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);
  }

  // Считываем напряжение на выводе АЦП
  int value = analogRead(pin);

  // Определяем окно вокруг этого значения
  uint16_t lo = max(value - margin, 0);
  uint16_t hi = min(value + margin, UINT16_MAX);

  // Прикрепляем прерывание АЦП на вывод A0, вызывающее repetitionsIncrease, когда напряжение выходит за пределы заданного диапазона.
  // Должно вызываться непосредственно перед LowPower.sleep(), так как внутри перенастраивает АЦП.
  LowPower.attachAdcInterrupt(pin, repetitionsIncrease, ADC_INT_OUTSIDE, lo, hi);

  // Запускает бесконечный сон (устройство будет пробуждено только зарегистрированными источниками пробуждения)
  // Потребление энергии чипа значительно снизится
  LowPower.sleep();

  // Отключает прерывание АЦП. Должно вызываться непосредственно после LowPower.sleep(), так как восстанавливает конфигурацию АЦП после пробуждения.
  LowPower.detachAdcInterrupt();
}

void repetitionsIncrease() {
  // Эта функция будет вызвана один раз при пробуждении устройства
  // Здесь можно выполнять небольшие операции (например, изменять переменные, которые используются в loop)
  // Помните: нельзя вызывать delay() и долго выполняющиеся функции, так как эта функция выполняется в контексте прерывания
  repetitions++;
}

Углубляясь в предыдущий код, мы задаём окно значений, в котором будет работать аналоговый вывод A0 устройства:

uint16_t lo = max(value - margin, 0);
uint16_t hi = min(value + margin, UINT16_MAX);

Конфигурация прерывания АЦП (Аналого-цифрового преобразователя) выполняется внутри функции loop, чтобы обеспечить возможность перенастройки непосредственно перед переходом устройства в режим сна:

LowPower.attachAdcInterrupt(pin, repetitionsIncrease, ADC_INT_OUTSIDE, lo, hi);

После пробуждения устройства через настроенное прерывание АЦП (Аналого-цифрового преобразователя) оно отключает прерывание АЦП, восстанавливая конфигурацию АЦП:

LowPower.detachAdcInterrupt();

Функции обратного вызова используются при пробуждении системы из режима сна через настроенное прерывание. В таких функциях — и в рамках всей программной архитектуры — хорошей практикой является избегание вызова delay() и долго выполняющихся функций. Это позволяет избежать так называемой блокирующей операции и проектировать систему в неблокирующем стиле, что очень помогает в подобных конструктивных случаях. В данном контексте это позволяет проектировать энергоэффективную систему, которая одновременно является отзывчивой.

Пример Low Power с передатчиком на базе технологии LoRa®

  • Необходимое оборудование: MKR WAN 1300/1310 (встроенный модуль Murata)

Примечание

Подробное описание и примеры использования технологии LoRa® с MKR WAN 1310 и модулем Murata можно найти в данной документации.

Данный пример показывает MKR WAN1300/1310 в роли удалённого устройства-передатчика, которое периодически отправляет сообщение с маяком о своей работоспособности. Это имитация устройства, периодически транслирующего данные маяка и требующего длительного срока службы. Приёмное устройство остаётся стационарным в роли приёмной башни. Удалённое устройство-передатчик переводит SAMD21 в режим сна, а также встроенный модуль Murata для устранения излишнего потребления энергии.

Примечание

Дополнительную информацию о библиотеке LoRa см. в репозитории библиотеки на 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, должны быть переведены в режим сна отдельной задачей в коде.

Важно

Если используются внешние модули, такие как модуль Murata (LPWAN) и датчики, не забудьте перевести их в режим сна до того, как MCU перейдёт в режим сна. В противном случае устройство не перейдёт в полный режим сна и максимальная экономия энергии будет недостижима. Это включает отключение периферийных интерфейсов, таких как TWI и SPI.

Пример простого обнаружения низкого напряжения

  • Необходимое оборудование: любая плата Arduino

Это пример реализации простейшей задачи обнаружения низкого напряжения. Устройство будет определять, когда источник питания иссякает, чтобы предотвратить его отключение из-за отсутствия питания. Задача простая, однако требует использования определённых параметров в качестве ориентира для получения корректных измерений. Следующий пример настроен для использования с MKR WAN 1310 с прямой подачей на аналоговый вывод для извлечения процента заряда батареи.

/*
Low Power - Low Voltage Detection - SAMD21 Specific Configuration Example
*/

// Ручное управление питанием
#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.3В
  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){
    //LED уведомление при обнаружении низкого напряжения
    lowBatteryWarning();
  }

  delay(2000);

  // Переход в Low Power на 20 секунд
  LowPower.deepSleep(20000);
}

// Индикатор низкого заряда батареи
void lowBatteryWarning(){
  digitalWrite(LED_BUILTIN, HIGH);
  delay (1);
  digitalWrite(LED_BUILTIN, LOW);
  delay (999);
}

Вот 4 важные конфигурации:

  • analogReference() используется для настройки опорного напряжения для аналогового входа.

  • analogReadResolution() используется для определения разрешения значения, возвращаемого analogRead().

  • analogRead() используется для задания аналогового вывода для считывания значения.

  • И наконец, соответствующий делитель разрешения. В настоящем примере используется 4095 для 12-битного разрешения, применимого для MKR WAN 1310. При использовании другого разрешения, например 10 бит, необходимо задать значение 1023.

Если в приложении используется делитель напряжения, необходимо задать и установить соотношение резисторов в коде для получения правильного значения.

Совет

Для более продвинутого обнаружения низкого напряжения см. последний раздел настоящего руководства: Продвинутые методы Low Power в Arduino.

Продвинутые методы Low Power в Arduino

Следующие продвинутые методы Low Power применимы к любым платам Arduino, поскольку они используют все возможности платы изнутри и снаружи для максимального снижения потребления энергии. Эти методологии помогут вам творчески и гибко проектировать систему Low Power с любыми платами Arduino.

Низкая частота и низкое напряжение

Для более сложных случаев использования существуют методы дальнейшего снижения потребления энергии. Перевод процессора на низкую частоту и низкое напряжение. Для низких частот это может зависеть от функциональности устройства, поскольку для работы коммуникационных модулей, таких как WiFi, требуется минимальный уровень частоты. Кроме того, возможно эксплуатировать устройство при низком напряжении 3,3 В, что помогает снизить общее потребление энергии. Эта конфигурация выполняется в Arduino IDE перед загрузкой скетча в устройство.

Конфигурация напряжения и частоты микроконтроллера

Конфигурация напряжения и частоты микроконтроллера

Процессор, как правило, изменяет частоту в зависимости от рабочей нагрузки. Частота процессора варьируется, чтобы ускорить процесс вычислений за минимальное время. Для некоторых модулей, таких как Wi-Fi и Bluetooth® Low Energy, требуется минимальный уровень частоты. В противном случае работа на ещё более низких частотах приведёт к некорректной работе модулей или их полному отказу. В некоторых случаях дальнейшее снижение частоты требует внешнего кварцевого генератора, поскольку необходимо соответствующее согласование.

Таким образом, принудительное снижение частоты не поможет — это нарушит работу модулей или операций. В то же время оставлять частоту неограниченной также не поможет обеспечить длительную работу от батареи. Рекомендуется устанавливать уровни частот в зависимости от программной архитектуры, чтобы поддерживать потребление энергии при выполнении запрограммированных задач. Уровни частот можно найти в паспорте данных платы, что позволит спроектировать программную архитектуру и улучшить потребление энергии.

Что касается напряжения, платы обычно можно настроить на рабочее напряжение 5 В или 3,3 В. Это рабочее напряжение, как правило, зависит от внешних компонентов, которые будут сопряжены с центральными платами, — в данном случае с платами Arduino. Однако не всегда требования внешних компонентов или аналогичные случаи требуют высокого напряжения. Поэтому в таких ситуациях можно установить рабочее напряжение 3,3 В, что даёт гораздо лучший шанс создать энергоэффективное устройство. Потребление энергии, начиная с этих двух факторов, может снизить или даже вдвое уменьшить общее потребление.

Управление питанием на уровне микроконтроллера

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

SAMD21 — режим снижения мощности

В микроконтроллерах SAMD21, используемых на платах семейства MKR, предусмотрен режим снижения мощности (Power Reduction Mode).

Режим снижения мощности связан с контроллером энергонезависимой памяти. Регистр CTRLB используется для управления этим режимом. Бит режима снижения мощности устанавливается в регистре состояния (STATUS.PRM), когда контроллер и блок энергонезависимой памяти находятся в режиме снижения мощности. Команды установки и сброса режима снижения мощности используются для входа и выхода контроллера и блока энергонезависимой памяти из этого режима. Для визуализации таблицы регистров можно обратиться к следующим ссылкам и паспорту данных для получения подробной информации.

Регистр CTRLB микроконтроллера SAMD21

Регистр CTRLB микроконтроллера SAMD21

Бит SLEEPPRM из регистра CTRLB микроконтроллера SAMD21

Бит SLEEPPRM из регистра CTRLB микроконтроллера SAMD21

Atmega328P — регистр снижения мощности

В классическом семействе и Arduino Nano, использующих микроконтроллеры Atmega328P, предусмотрен регистр снижения мощности (Power Reduction Register).

Этот регистр снижения мощности позволяет отключать ряд элементов внутри микроконтроллера. Он может отключить TWI, SPI, USART0, таймеры и счётчики, а также Аналого-цифровой преобразователь. Если бит Аналого-цифрового преобразователя должен быть отключён, ADCSRA должен быть установлен в ноль — иначе он останется замороженным в активном состоянии.

Регистр снижения мощности

Регистр снижения мощности

Периферия и внутренние модули

Отключение ненужных внутренних модулей в зависимости от разработанного приложения очень помогает дополнительно снизить потребление энергии. Такими модулями могут быть SPI, I2C, Serial и АЦП (Аналого-цифровой преобразователь). Кроме этих модулей, существуют детектор провала напряжения (Brown-out Detection) и сторожевой таймер (Watchdog timer).

Периферийные интерфейсы, такие как SPI, I2C, последовательная связь, регулярно используются для установки моста с датчиками. Зная общие требования к конструкции, можно определить, какие периферийные устройства не будут задействованы в приложении. Вместо того чтобы оставлять неиспользуемые периферийные устройства в неопределённом состоянии, хорошей практикой является их отключение для экономии энергии. Помимо этого, датчики также могут переводить себя в режим низкого энергопотребления по команде. Через установленные периферийные интерфейсы можно отправить команды для перевода датчиков в режим низкого потребления перед отключением периферии и переходом в режим сна.

АЦП (Аналого-цифровой преобразователь) может использоваться как источник пробуждения, как было обсуждено ранее. Но его также можно отключить для экономии энергии, если он не используется как источник пробуждения. Этот периферийный элемент иногда потребляет значительное количество энергии, поэтому его отключение может помочь получить дополнительную энергию для увеличения срока службы батареи.

Детектор провала напряжения (Brown-out Detection) и сторожевой таймер (Watchdog timer) — это внутренние модули, которыми при необходимости можно управлять вручную для достижения ещё более низкого потребления энергии. Детектор провала напряжения обычно используется для сравнения при необходимости обнаружения низкого напряжения в процессоре. Сторожевой таймер имеет решающее значение, поскольку контролирует состояние работы микроконтроллера.

Если микроконтроллер когда-либо зависнет, остановится или перейдёт в незаконный процесс, сторожевой таймер сработает для сброса и возврата микроконтроллера к нормальной работе. С другой стороны, тот же сторожевой таймер можно временно отключить для экономии энергии. Это всегда рекомендуется реализовывать после того, как программное обеспечение проверено на достаточную стабильность. В противном случае это не поможет снизить потребление энергии и нарушит работу системы.

Внешние устройства

Если имеются внешние устройства, такие как SD-устройства и датчики, их можно отключить, добавив между ними MOSFET. MOSFET может помочь прервать питание SD-устройств, подключённых к плате Arduino, для снижения потребления энергии, когда устройство переходит в режим глубокого сна, например. В случае с датчиками, если требуется полностью сэкономить потребление энергии, их также можно отключить с помощью MOSFET. Этот метод полезен, когда устройство периодически переходит в режим сна, что позволяет в полной мере сэкономить потребление энергии.

Регулятор с малым падением напряжения (LDO)

Некоторые конструкции требуют применения регуляторов напряжения для правильной работы. Если конструкция предполагает использование регулятора напряжения, постарайтесь найти регуляторы с малым падением напряжения (Low-Dropout, LDO) с малым током покоя. Это поможет устройству иметь значительно более низкое потребление энергии в режиме сна. Подобные сведения можно найти в паспортах данных производителей регуляторов.

Бюджетирование мощности

Хорошей практикой является ведение учёта бюджета потребления энергии системы. Это даёт обзор и детали для анализа распределения энергии по всей конструкции. Это может помочь улучшить потребление энергии, поскольку может предоставить информацию, например, о возможном увеличении интервала таймера режима сна.

Метод измерения потребления энергии

Применив все методы и приёмы для снижения потребления энергии платой Arduino, вам также потребуется измерить потребление энергии системы для подтверждения её корректной работы. Можно воспользоваться основами работы с мультиметром в разделе Reading Current для измерения тока и определения фактического потребления энергии системы.

Обнаружение низкого напряжения

Устройство, корректно выполняющее запрограммированные задачи и имеющее низкое потребление энергии, — уже хорошая конструкция в целом. Тем не менее в какой-то момент устройство исчерпает источник питания, независимо от того, как долго оно может работать. Конечно, при правильной конфигурации и архитектуре кода оно, возможно, способно работать целый год. Однако неизбежно, что в какой-то момент устройство выйдет из строя из-за низкого уровня питания. Можно узнать, что устройство работает при минимальной ёмкости источника питания, прежде чем оно прекратит работу, — и именно тогда в системе обнаруживается низкое напряжение.

Совет

Для получения расчётного срока службы можно воспользоваться следующим калькулятором заряда батареи: https://www.omnicalculator.com/other/battery-life

Для этого используется метод управления питанием микроконтроллеров avr, на которых основан Atmega328P, встречающийся, например, в Arduino Nano и классическом семействе. Метод обнаружения низкого напряжения, разработанный 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() {
  // Включение периферии, таймеров и АЦП
  manual_periph_ctrl(1);

  // Определение уровня напряжения
  Serial.println(getBandgap());
  // Обнаружение низкого напряжения при 3В (300)
  if (getBandgap() < 300){
    //LED уведомление при обнаружении низкого напряжения
    lowBatteryWarning();

    // Отключение периферии, таймеров и АЦП
    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
// Например, 5В будет равно 500.
int getBandgap(){
  // REFS0 : Выбирает внешний источник опорного напряжения AVcc
  // MUX3 MUX2 MUX1 : Выбирает 1.1В (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;
} // end of getBandgap

/*
* Задачи, связанные с Low Power
*/
// Включение сторожевого таймера
void WatchdogEnable() {
  // сбросить различные флаги "сброса"
  MCUSR = 0;
  // разрешить изменения, отключить сброс
  WDTCSR = bit (WDCE) | bit (WDE);
  // установить режим прерывания и интервал
  WDTCSR = bit (WDIE) | bit (WDP3) | bit (WDP0);    // установить WDIE и задержку 8 секунд
  wdt_reset();  // погладить пса

  // отключить АЦП
  ADCSRA = 0;

  // готов ко сну
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);  // Должно давать ~0.4мА в лучшем случае
  noInterrupts();
  sleep_enable();

  // отключить детектор провала напряжения программно
  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 секунд
  // погладить пса
  wdt_reset();
}  // end of 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(){
  // Состояние ЯДРА
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);
  ADCSRA = 0;            // отключить АЦП
  power_all_disable ();  // отключить питание АЦП, Таймера 0 и 1, последовательного интерфейса

  // Прерывания не учитываются, как требует ADXL
  noInterrupts ();       // начинается временная последовательность
  resetWatchdog ();      // подготовить сторожевой таймер
  sleep_enable ();       // готов ко сну
  interrupts ();         // прерывания теперь требуются
  sleep_cpu ();          // сон
  sleep_disable ();      // мера предосторожности
  power_all_enable ();   // включить всё обратно

}  // end of goToSleep

// Ручной контроллер периферии
void manual_periph_ctrl(uint8_t selector){
  byte old_ADCSRA = ADCSRA;
  // отключить АЦП
  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, чтобы использовать его как внутреннее опорное напряжение.

  • Использование регистра 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.