Потребляемая мощность является одним из ключевых аспектов функционирования непрерывно функционирующих устройств. Для решения этой проблемы практически все современные микроконтроллеры имеют спящий режим, что позволяет разработчикам проектировать различные электронные гаджеты с оптимальным потреблением энергии. Спящий режим переводит устройство в режим энергосбережения при помощи выключения неиспользуемых модулей.
В данной статье мы рассмотрим спящие режимы платы Arduino и продемонстрируем уменьшение потребления энергии в них с помощью амперметра. В англоязычной литературе для спящих режимов Arduino (Arduino Sleep mode) используют также термины Arduino Power Save mode (режим энергосбережения) и Arduino Standby Mode (режим ожидания).
Спящие режимы в Arduino
Спящие режимы позволяют пользователю остановить или выключить неиспользуемые модули, что может значительно уменьшить потребление энергии. Платы Arduino Uno, Arduino Nano и Pro-mini построены на основе микроконтроллера ATmega328P, который имеет в своем составе специальный детектор для мониторинга питающего напряжения во время спящего режима.
Всего в микроконтроллере ATmega328P есть шесть спящих режимов, показанных в следующей таблице.
Для задействования любого из этих спящих режимов нам необходимо установить бит спящего режима (sleep bit) в регистре управления спящим режимом (Sleep Mode Control Register - SMCR.SE). Доступны такие спящие режимы как Idle, ADC noise reduction, Power-Down, Power-Save, Standby и External Standby. Далее рассмотрим их более подробно.
Вывести плату Arduino из спящего режима могут внутренние или внешние прерывания, а также нажатие на кнопку сброса (Reset).
Idle Mode (холостой режим)
Для перевода платы Arduino в данный режим необходимо в ее биты SM[2,0] записать ‘000’. В этом режиме останавливает свою работу CPU (центральный процессор), однако интерфейсы SPI, TWI, USART, сторожевой таймер (Watchdog), счетчики (таймеры) и аналоговый компаратор продолжают работать. Режим Idle, в основном, останавливает CLKCPU и CLKFLASH. Плату Arduino можно вывести из этого режима с помощью внешнего или внутреннего прерывания.
Команда для Arduino на перевод ее в режим Idle выглядит следующим образом:
1 |
LowPower.idle(SLEEP_8S, ADC_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_OFF, SPI_OFF, USART0_OFF, TWI_OFF); |
В сети можно скачать специальную библиотеку для установки различных спящих режимов в плате Arduino. Скачайте ее по приведенной ссылке и установите ее в Arduino IDE. Используйте приведенную команду чтобы перевести плату Arduino в режим Idle. По этой команде плата Arduino перейдет в спящий режим Idle на 8 секунд и потом выйдет из него (проснется) автоматически. Как видите, с помощью приведенной команды мы также выключаем все таймеры, интерфейсы SPI, USART и TWI.
ADC Noise Reduction Mode (режим АЦП и уменьшения шума)
Для перевода платы Arduino в данный спящий режим необходимо в ее биты SM[2,0] записать ‘001’. Этот режим останавливает CPU, но позволяет функционировать АЦП (аналого-цифровым преобразователям), внешним прерываниям, интерфейсам USART и TWI, сторожевому таймеру и счетчикам. Данный режим останавливает, в основном, CLKCPU, CLKI/O и CLKFLASH. Мы можем вывести плату Arduino из этого режима с помощью:
- внешнего сброса (Reset);
- сброс системы от сторожевого таймера;
- прерывание от сторожевого таймера;
- сброс с помощью пониженного напряжения;
- внешнее прерывание;
- прерывание смены контакта;
- прерывание от таймера/счетчика;
- прерывание от SPM/EEPROM.
Power-Down Mode (режим пониженного энергопотребления)
Этот режим останавливает все часы платы и разрешает функционирование только асинхронным модулям (им не нужны импульсы тактовой частоты). Для перевода платы Arduino в данный спящий режим необходимо в ее биты SM[2,0] записать ‘010’. В этом режиме останавливаются все внешние кварцевые генераторы, но интерфейс TWI, сторожевой таймер и внешние прерывания продолжают работать. Мы можем вывести плату Arduino из этого режима с помощью:
- внешнего сброса (Reset);
- сброс системы от сторожевого таймера;
- прерывание от сторожевого таймера;
- сброс с помощью пониженного напряжения;
- внешнее прерывание;
- прерывание смены контакта.
Команда для перевода платы Arduino в периодический режим Power-Down:
1 |
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF); |
С помощью этой команды плата Arduino перейдет в спящий режим на 8 секунд и потом выйдет из него (проснется) автоматически.
Мы также можем использовать переход в аналогичный спящий режим с условием что выход из него будет осуществлен по внешнему или внутреннему прерыванию. В этом случае код программы для Arduino будет выглядеть следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 |
void loop() { // разрешаем на контакте wake up прерывание по уровню low. attachInterrupt(0, wakeUp, LOW); LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); // отключаем внешнее прерывание на контакте wake up detachInterrupt(0); // делаем что-нибудь здесь } |
Power-Save Mode (режим экономии потребляемой мощности)
Для перевода платы Arduino в данный спящий режим необходимо в ее биты SM[2,0] записать ‘011’. Этот режим аналогичен режиму power-down, но отличается от него тем, что если таймер/счетчик находится во включенном состоянии (enabled), он будет оставаться в этом состоянии даже в спящем режиме. Устройство можно вывести из данного спящего режима используя переполнение таймера.
Если вы не используете таймер/счетчик, то в этом случае рекомендуется применение режима Power-down вместо режима power-save.
Standby Mode (дежурный режим)
Режим Standby аналогичен режиму Power-Down, но отличается от него тем, что в нем внешний кварцевый генератор (external oscillator) продолжает работать. Для перевода платы Arduino в данный спящий режим необходимо в ее биты SM[2,0] записать ‘110’.
Extended Standby Mode (расширенный дежурный режим)
Этот режим аналогичен режиму power-save, но отличается от него тем, что в нем внешний кварцевый генератор (external oscillator) продолжает работать. Для перевода платы Arduino в данный спящий режим необходимо в ее биты SM[2,0] записать ‘111’. Устройству необходимо 6 временных циклов чтобы выйти из данного спящего режима.
В этом проекте мы будет переводить плату Arduino в режим Idle (холостой режим) и измерять снижение ее энергопотребления с помощью USB амперметра.
Необходимые компоненты
- Плата Arduino Uno (купить на AliExpress).
- Датчик температуры и влажности DHT11 (купить на AliExpress).
- USB амперметр (USB Ammeter) (купить на AliExpress).
- Макетная плата.
- Соединительные провода.
Более подробно о подключении датчика DHT11 к плате Arduino можно прочитать в этой статье.
USB амперметр
USB амперметр представляет собой plug and play устройство, способное измерять напряжение и ток на любом USB порту.
В нашем проекте USB амперметр подключается между USB портом компьютера и платой Arduino. Данный амперметр имеет в своем составе резистор сопротивлением 0.05 Ом, с помощью которого и происходит измерение протекающего через устройство тока. USB амперметр снабжен четырех разрядным семисегментным индикатором (аналогичный индикатор мы использовали в проекте часов на Arduino), на котором отображаются измеренные напряжение и ток. Эти данные обновляются каждые 3 секунды.
Спецификация USB амперметра:
- рабочее напряжение: от 3.5V до 7V;
- максимальный измеряемый ток: 3A;
- компактный размер;
- не требует внешнего источника питания.
Схема проекта
Схема тестирования спящего режима в плате Arduino представлена на следующем рисунке.
USB разъем платы Arduino подключается к USB амперметру, который подключается к USB порту компьютера. Контакт данных датчика DHT11 подключен к контакту D2 платы Arduino.
Объяснение программы для Arduino
Полный код программы приведен в конце статьи, здесь же мы кратко рассмотрим его основные фрагменты.
Вначале в программе нам необходимо подключить библиотеку для работы с датчиком DHT11 и библиотеку LowPower (для работы со спящими режимами), которую можно скачать по следующей ссылке. Также мы определим контакт, к которому подключен датчик DHT11 и создадим объект класса DHT.
1 2 3 4 5 |
#include <dht.h> #include <LowPower.h> #define dataPin 2 dht DHT; |
В функции void setup мы инициализируем последовательную связь с помощью функции serial.begin(9600). Мы будем использовать встроенный в плату Arduino светодиод для индикации спящего режима. Также зададим режимы работы используемых контактов.
1 2 3 4 5 |
void setup() { Serial.begin(9600); pinMode(LED_BUILTIN,OUTPUT); digitalWrite(LED_BUILTIN,LOW); } |
В функции void loop мы зажигаем встроенный в плату светодиод (подаем на него HIGH) и считываем значения температуры и влажности с датчика DHT11, которые мы затем сохраняем в переменных ‘t’ и ‘h’. Затем мы данные температуры и влажности выводим в окно монитора последовательной связи (serial monitor).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
void loop() { Serial.println("Get Data From DHT11"); delay(1000); digitalWrite(LED_BUILTIN,HIGH); int readData = DHT.read11(dataPin); // DHT11 float t = DHT.temperature; float h = DHT.humidity; Serial.print("Temperature = "); Serial.print(t); Serial.print(" C | "); Serial.print("Humidity = "); Serial.print(h); Serial.println(" % "); delay(2000); |
Перед переходом в спящий режим мы выводим в окно монитора последовательной связи "Arduino: - I am going for a Nap" и выключаем встроенный в плату светодиод (подаем на него Low). После этого с помощью специальной команды (рассмотрена ранее в статье) плата Arduino переводится в спящий режим.
В нашем примере мы переводим плату Arduino в периодический режим Idle на 8 секунд. В этом режиме АЦП, таймеры, интерфейсы SPI, USART, TWI переводятся в выключенное состояние (OFF). После истечения 8 секунд плата Arduino автоматически выводится из спящего режима и в окно монитора последовательной связи печатается сообщение “Arduino:- Hey I just Woke up”.
1 2 3 4 5 6 7 8 9 |
Serial.println("Arduino:- I am going for a Nap"); delay(1000); digitalWrite(LED_BUILTIN,LOW); LowPower.idle(SLEEP_8S, ADC_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_OFF, SPI_OFF, USART0_OFF, TWI_OFF); Serial.println("Arduino:- Hey I just Woke up"); Serial.println(""); delay(2000); } |
Таким образом, в нашем примере в течение минутного интервала плата Arduino будет находиться в спящем режиме 36 секунд и в обычном режиме 24 секунды, что позволяет значительно уменьшить энергопотребление нашей "станции погоды" на основе платы Arduino.
Таким образом, если мы будем использовать подобный спящий режим в плате Arduino, мы сможем приблизительно увеличить время ее функционирования в 2 раза при ее работе от батарейки.
Исходный код программы (скетча)
Программа с использованием спящего режима
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
#include <dht.h> #include <LowPower.h> #define dataPin 2 dht DHT; void setup() { Serial.begin(9600); pinMode(LED_BUILTIN,OUTPUT); digitalWrite(LED_BUILTIN,LOW); } void loop() { Serial.println("Get Data From DHT11"); delay(1000); digitalWrite(LED_BUILTIN,HIGH); int readData = DHT.read11(dataPin); // DHT11 float t = DHT.temperature; float h = DHT.humidity; Serial.print("Temperature = "); Serial.print(t); Serial.print(" C | "); Serial.print("Humidity = "); Serial.print(h); Serial.println(" % "); delay(2000); Serial.println("Arduino:- I am going for a Nap"); delay(200); digitalWrite(LED_BUILTIN,LOW); LowPower.idle(SLEEP_8S, ADC_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_OFF, SPI_OFF, USART0_OFF, TWI_OFF); Serial.println("Arduino:- Hey I just Woke up"); Serial.println(""); delay(2000); } |
Программа без использования спящего режима
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#include <dht.h> #define dataPin 2 dht DHT; void setup() { Serial.begin(9600); pinMode(LED_BUILTIN,OUTPUT); digitalWrite(LED_BUILTIN,LOW); } void loop() { digitalWrite(LED_BUILTIN,HIGH); int readData = DHT.read11(dataPin); // DHT11 float t = DHT.temperature; float h = DHT.humidity; Serial.print("Temperature = "); Serial.print(t); Serial.print(" C | "); Serial.print("Humidity = "); Serial.print(h); Serial.println(" % "); delay(2000); } |