Про Ардуино и не только
Для того чтобы перевести Ардуино в один из перечисленных режимов достаточно выполнить 2 функции: set_sleep_mode(mode) для задания конкретного режима и sleep_mode(). Они объявлены в файле sleep.h, поэтому он должен быть добавлен в секцию include вашего скетча.
Для указания режима используются константы:
- SLEEP_MODE_IDLE
- SLEEP_MODE_ADC
- SLEEP_MODE_PWR_DOWN
- SLEEP_MODE_PWR_SAVE
- SLEEP_MODE_STANDBY
- SLEEP_MODE_EXT_STANDBY
Пробуждение по сторожевому таймеру
В основе сторожевого таймера (WatchDog Timer) лежит многоразрядный счетчик, снабженный собственным тактовым генератором. Если таймер включен, то значение счетчика будет постоянно увеличиваться и при его переполнении будет сгенерирован сигнал сброса МК. Чтобы избежать сброса по переполнению программа должна постоянно обнулять счетчик специальной командой. Если программа зависла и счетчик не был вовремя сброшен, то сигнал сброса выведет МК из зависшего состояния, таким образом повышается стабильность системы на основе МК.
Наличие собственного тактового генератора и способность работать когда другие узлы МК остановлены позволяют использовать сторожевой таймер для вывода МК из спящего режима. Для этого следует настроить его на генерацию прерывания, а не сигнала сброса. Также необходимо задать значение предделителя, чтобы получить интересующую задержку. Ниже приведен пример скетча, в котором Ардуино будет просыпаться каждые 2 секунды и мигать встроенным светодиодом для индикации пробуждения.
Здесь задается интервал сторожевого таймера и режим его работы для генерации прерываний через 2 секунды. После выполнения функции sleep_mode() Ардуино переходит в спящий режим. При генерации прерывания от сторожевого таймера и пробуждении МК, управление передается соответствующему обработчику (ISR (WDT_vect)). После его выполнения продолжится работа основной программы, т.е. выполнится следующая после sleep_mode() команда. Для задания значения предделителя сторожевого таймера можно использовать одну из следующих констант:
- WDTO_15MS
- WDTO_30MS
- WDTO_60MS
- WDTO_120MS
- WDTO_250MS
- WDTO_500MS
- WDTO_1S
- WDTO_2S
- WDTO_4S
- WDTO_8S
Пробуждение при нажатии кнопки
Пробуждение микроконтроллера при замыкании/размыкании контактов, будь то кнопка, геркон, энкодер и т.п. — это пробуждение по внешнему прерыванию (INT) или по прерыванию изменения уровня (PCINT). Для работы с первыми в IDE Arduino предусмотрены удобные функции. Для вторых ничего подобного в IDE нет, поэтому придется работать с регистрами микроконтроллера, отвечающими за настройку PCINT (хотя, наверняка, существуют библиотеки для работы с ними, я не искал). Для тех и других у меня есть подробные публикации с примерами использования: Прерывания в Ардуино. Часть 1, и Часть 2.
Предположим, что микроконтроллер в нашем устройстве должен всегда спать, просыпаться при нажатии кнопки, подключенной к входу запроса прерывания INT0, что-то делать и снова засыпать. Вход запроса прерывания (для INT0 — это вывод D2 Ардуино) должен быть подтянут к питанию или земле. Публикация про подтяжку в тему. Мы воспользуемся внутренними подтягивающими резисторами микроконтроллера. Кнопку установим между выводами D2 и Gnd. Простой скетч для ухода в сон и пробуждения при нажатии может быть таким:
Скетч содержит достаточно комментариев, я поясню лишь назначение цикла while. Все электромеханические коммутирующие устройства подвержены дребезгу контактов. В нашем случае дребезг на входе запроса прерывания будет воспринят микроконтроллером как многократное нажатие кнопки, в результате чего он будет выходить из спящего режима, выполнять заданный код и уходить в сон несколько раз подряд. Чтобы этого не происходило мы откладываем уход в сон до момента отпускания кнопки и возвращения сигнала на входе D2 к высокому уровню. Если сигнал остается высоким в течение 5 выборок с интервалом в 1мс, то считаем, что он стабилизировался и можно снова переводить микроконтроллер в режим энергосбережения.
Если добавить в схему аппаратное подавление дребезга, то можно обойтись без описанного цикла.
Пробуждение при нажатии кнопки, уход в сон по таймауту
Другой пример: есть устройство с дисплеем, которое должно просыпаться при нажатии кнопки, а засыпать по истечении некоторого времени, чтобы пользователь успел увидеть всё необходимое на дисплее. В простейшем случае хватило бы задержки на несколько секунд перед уходом в сон. Но если предполагается дополнительное взаимодействие с пользователем (опрос элементов управления, изменение выводимой информации и т.д.), то в этом случае поможет следующий подход:
Здесь уход микроконтроллера в сон возможен только при выполнении условия: разница между текущим значением millis() и значением переменной tm должно быть больше 10 секунд. Для того чтобы отложить сон, достаточно записать в tm значение millis(), что и делается при пробуждении и при нажатии на кнопку.
Также в данном примере отключается подсветка дисплея (текстовый дисплей типа 20*4 или 16*2) при переходе микроконтроллера в режим энергосбережения и включается при выходе из него. Сделано это в большей степени для демонстрации. В реальном же устройстве лучше отключать питание дисплея, поскольку он не имеет режима энергосбережения, а отключение подсветки уменьшит ток недостаточно — экономия должна быть экономной.
- Аналого-цифровой преобразователь;
- Аналоговый компаратор;
- Детектор пониженного напряжения питания (Brown-Out Detector);
- Внутренний источник опорного напряжения;
- Сторожевой таймер;
- Порты ввода-вывода;
- Модуль внутрисхемной отладки.
В режиме Power Down продолжают работать АЦП и схема контроля питания. В приведенном скетче есть команды для их отключения. АЦП при необходимости потом можно будет включить установкой бита ADEN. Потребляемый Arduino Pro Mini ток с данным скетчем составил 136мкА.
Я считаю, это неплохой результат по сравнению с начальными 15мА.
Чтобы уменьшить потребление еще больше, придется отказаться от использования плат Ардуино и перейти на использование "голых" микроконтроллеров. Оцените, например, потребление ATmega328P при тактировании от внутреннего RC генератора в этой статье.
Советую также посмотреть следующую мою статью об управлении режимами энергосбережения Ардуино — Библиотека Low-Power.
Источник: