воскресенье, 25 февраля 2018 г.

Уменьшаем энергопотребление Ардуино

Данная тема весьма актуальна при разработке устройств, которые должны работать от автономного источника питания. Это могут быть беспроводные датчики, системы контроля и автоматизации, устройства для умного дома и многое другое. Как можно заставить их работать дольше без подзарядки аккумуляторов и замены батарей? Давайте разбираться.
В основе большинства плат Ардуино и ее клонов лежат AVR микроконтроллеры (МК) фирмы Atmel, известные своей технологией picoPower, которая позволяет добиться минимального уровня энергопотребления по сравнению с большинством МК других производителей. Так если обратиться к даташиту ATmega328P, то в самом его начале приводятся данные по энергопотреблению в различных режимах при частоте 1МГц и напряжении питания 1,8В:
  • Active Mode: 0.2мА
  • Power-down Mode: 0.1мкА
  • Power-save Mode: 0.75мкА

Режимы энергосбережения рассмотрим чуть позже, а сейчас пока остановимся на двух других факторах: напряжении питания МК и его частоте.

Согласно закону Ома, сила тока в цепи прямо пропорциональна напряжению. Поэтому для уменьшения тока, потребляемого Ардуино, необходимо уменьшить напряжение питания. Требуемое рабочее напряжение (5В или 3.3В) в Ардуино обеспечивают линейные стабилизаторы типа AMS1117, при этом входное напряжение должно быть несколько больше (6,5В и 4,8В).  Чтобы запитать Ардуино меньшим напряжением его следует подавать в обход стабилизатора:  на пин +5V или через USB разъем. Но будьте осторожны, превышение максимально допустимого напряжения питания МК (для ATmega328P оно составляет 6В) выведет его из строя. Других причин не использовать пин +5V для питания Ардуино нет.

Если использование стабилизатора все-таки необходимо, то вместо линейных лучше использовать импульсные, так как они имеют больший КПД. Вполне реально найти импульсный стабилизатор, подходящий по габаритам и распиновке для замены AMS1117 на плате UNO.

Другой фактор, влияющий на расход энергии, это тактовая частота МК. Чем выше частота МК, тем больший ток он потребляет. Если нам не нужна вся вычислительная мощь Ардуино, то можно понизить его тактовую частоту, чтобы уменьшить энергопотребление. И в этом нам поможет предделитель тактовой частоты (System Clock Prescaler).

Описание предделителя МК ATmega328P и управляющего им регистра CLKPR (Clock Prescale Register) приведено в разделе 13.11 даташита. Согласно документации для того чтобы изменить значение делителя необходимо сначала установить в управляющем регистре бит Clock Prescaler Change Enable (CLKPCE), записав в него значение 0x80. После этого новое значение делителя, а точнее его код, записывается в младшие 4 бита регистра. На время внесения данных изменений все прерывания должны быть запрещены. Таким образом для уменьшения частоты, например, в 8 раз можно использовать следующий код:

void setup() {
  //Уменьшим тактовую частоту Ардуино при помощи делителя
  noInterrupts (); // cli()
  CLKPR = 0x80;    // Разрешаем изменение значения делителя
  CLKPR = 3;       // Записываем в регистр значение 3, что соответствует значению делителя 8.
                   // Все значения CLKPR и соответствующие им коэффициенты приведены в даташите
  interrupts ();   // sei()
}

void loop() {

}

Данный пример иллюстрирует принцип управления частотой Ардуино на низком уровне. Но все же гораздо удобнее для этих целей использовать функцию clock_prescale_set() из файла power.h. Пример скетча с ее использованием ниже:

#include <avr/power.h>
void setup() {
  //Уменьшим тактовую частоту Ардуино в 8 раз при помощи делителя
  clock_prescale_set(clock_div_8);
}

void loop() {

}

Параметром функции clock_prescale_set() должно быть одно из следующих значений:
  • clock_div_1
  • clock_div_2
  • clock_div_4
  • clock_div_8
  • clock_div_16
  • clock_div_32
  • clock_div_64
  • clock_div_128
  • clock_div_256
Управляя частотой МК, можно добиться значительного снижения потребляемого тока.

Еще один важный момент на пути к минимизации энергопотребления - это выбор конкретной платы Ардуино. Платы могут отличаться моделями используемых МК, частотой кварцевых резонаторов, микросхемами для соединения с компьютером через USB и т.д. Например, в оригинальных платах Ардуино за соединение с компьютером отвечает МК ATmega16U2, в дешевых клонах вместо нее устанавливают преобразователи интерфейсов USB в UART вроде CH340G, а в Arduino Pro Mini преобразователь отсутствует в принципе.

Я измерил ток, который потребляют имеющиеся у меня ардуинки. Самой прожорливой оказалась оригинальная UNO: при питании 5В (запитывал через пин +5V) и скетче из пустых функций setup и loop ток составил 44,2мА. Китайский клон с микросхемой CH340G потребляет 23,5мА. Наименьший ток оказался у платы Pro Mini 5В 16МГц без встроенного преобразователя USB-UART, он составил 15,4мА - с ней я и решил проводить свои эксперименты по снижению энергопотребления. И начал я их с управления тактовой частотой. Ниже приведены значения тока, который потребляет моя Arduino Pro Mini при питании 5В и различных коэффициентах делителя частоты:

clock_div_1       (16МГц):   15,4мА
clock_div_2       (8МГц):     11,4мА
clock_div_4       (4МГц):     9,5мА
clock_div_8       (2МГц):     7,7мА
clock_div_16     (1МГц):     7,3мА
clock_div_32     (512кГц):   6,9мА
clock_div_64     (256кГц):   6,7мА
clock_div_128   (128кГц):   6,6мА
clock_div_256   (64кГц):     6,5мА

Бросаться в крайности и уменьшать частоту в 256 раз может и не стоит. А вот понизить ее до 1МГц вполне адекватное решение, этого хватит для большого круга задач.

Однако, здесь есть и нюанс. Изменение тактовой частоты микроконтроллера сказывается на работе всех его модулей, работающих в синхронном режиме. Если во время выполнения программы тактовая частота будет уменьшена вдвое, то и скорость обмена по I2C, USART или SPI также уменьшится в 2 раза, задержки функцией delay станут в 2 раза дольше, исказится ШИМ и т.д. Это происходит потому, что при компиляции скетча была заявлена одна частота, а по факту микроконтроллер работает на другой. Поэтому программное изменение тактовой частоты стоит использовать в тех участках кода, которые от частоты не зависят.

Следующий шаг - снижение напряжения питания. При тактовой частоте 1МГц и снижении напряжения до 3,3В Ардуино ProMini потребляет 2мА. Все еще много. Поэтому я решил выпаять из Ардуино светодиод-индикатор питания, в результате ток уменьшился до 1,2 мА - это уже что-то!
Arduino Pro Mini снижение энергопотребления

Следующий шаг в минимизации энергопотребления Ардуино - это управление энергосберегающими режимами. Поэтому предлагаю перейти к следующей статье - Режимы энергосбережения Ардуино.

29 комментариев:

  1. Как я устал тебя искать дружище. Наконец то нормальная статья в которой всё разложено по полочкам!!!!!!!
    Спасибо большее тебе автор.

    ОтветитьУдалить
    Ответы
    1. Спасибо на добром слове! Рад, что моя статья помогла)

      Удалить
  2. Зачётно, не думал что частотой можно так просто управлять. Моя Nano без светодиода и стабилизатора потребляет 4.1в х 13 мА (от LiIon), - буду пробовать занизить потребление ещё, благодарю))

    ОтветитьУдалить
    Ответы
    1. Жаль, ... на ардуино Нано не хочет работать ни один из вариантов, вроде и ошибок не выдаёт, но и не работает скетч.

      Удалить
    2. Проверил на своей нано: при 4,1В и 16МГц потребляет около 16мА, при 1МГц - 9мА.
      Делители пробовали менять?

      Удалить
  3. Уважаемый Владимир. Я чайник чайникович и вопрос у меня такой-же нубский. Как привести/сбросить МК Atmega328P к заводскому состоянию? Что я имею ввиду. По материалам этой статьи, я в setup
    добавил отключение BOD и снижение частоты до 1MHz clock_prescale_set(clock_div_16)
    и он у меня перестал слать Serial.print в UART отладочную информацию(видимо нарушились пропорции таймера для Baudrate UART) Все остальное вроде работает(судя по лампочкам), но понятно что в 16 раз медленнее. Изменение clock_prescale_set на clock_div_1, чтобы вернуть как было - не помогло. Все перепроверил, провода, контакты. Ума не приложу, как вернуть Serial.print(пока даже махнул рукой на энергопотребление) Очень хочется знать/видеть ЧЕРЕЗ UART, что происходит с моим скетчем. Попутно, второй вопрос: Если я снижаю частоту до 1MHz clock_prescale-ом, как/где мне выставлять Baudrate UART, чтобы видеть свои 9600 в COM порту? Если, конечно, мое предположение верно, что слетает Baudrate. Заранее спасибо за ответ и прошу снисхождения у профей за нубские вопросы.

    ОтветитьУдалить
    Ответы
    1. Добрый день!
      Начну с вопроса по поводу Baudrate. Все верно, при изменении тактовой частоты делителем, меняется и скорость обмена по UART. Таким образом если в Serial.begin указано значение 9600 и делитель установлен в 16, то реальная скорость обмена составить 600 бод. Такого значения в мониторе порта IDE Ардуино нет. Поэтому лучше подстраиваться под имеющиеся в IDE значения и в Serial.begin указывать скорость обмена, умноженную на значение делителя.

      А вот это "Изменение clock_prescale_set на clock_div_1, чтобы вернуть как было - не помогло" непонятно. Точно ничего не напутали? Достаточно загрузить любой другой скетч (хоть пустой или Blink), чтобы Ардуино "забыла" предыдущую программу вместе с ее делителями и т.п. Попробуйте Blink.

      Удалить
  4. Владимир спасибо за быстрый ответ. Пробовал после своего, другие скетчи из примеров Ардуины, перепрошивал загрузчик, чего только не делал. По всему видно, что ардуина работает на 16MHz, лампочки моргают посекундно, если delay 1000) а с родного UARTa шиш, народная индейская изба - ФигВам называется. Неужели спалил ноги Rx Tx, сразу обе, очень маловероятно. В компе, COMPort смотрю не IDE Arduino, а более продвинутой прогой, там на RX и TX моргают лампочки, если что приходит уходит. А конвертер TTL-USB замечательно работает с другой Ардуининой, правда, с другим скетчем. Я больше не решился менять clock_prescale на другой Ардуинине. Короче, я в недоумении.

    ОтветитьУдалить
    Ответы
    1. Если Ардуино прошивается через USB, значит UART работает. Кстати, о какой плате Ардуино идет речь? И как/чем прошивали загрузчик?

      Удалить
  5. Ой, в догонку, еще вопрос пожалуйста. Если я снижаю prescale до 1MHz, в скетчах, где используется SPI, тоже надо учитывать замедление таймеров? А как?

    ОтветитьУдалить
    Ответы
    1. Изменение системной частоты сказывается на работе всех синхронных модулей МК. Поэтому скорость SPI также будет меняться. Но в отличие от асинхронного интерфейса UART, который требует согласования скоростей приемника и передатчика, SPI является синхронным и скорость работы задает ведущее устройство, лишь бы она была не слишком высока для ведомого. Поэтому при снижении тактовой частоты скорость SPI уменьшится, но работе это не помешает.

      Удалить
  6. Спасибо вам за ваши статьи, впринципе тот же материл что в сети, но все наконец-то стало понятно :)
    И вот вопрос по стабилизатору, я собираюсь усыплять Ардуину и питать ее напрямую от 4,5В (3хАА), нужно ли выпаивать стабилизатор если он не подключен, вроде бы как он не должен работать, но кто его знает, внутренние сопротивления, RC-фильтры.
    Может вы уже замеряли сколько он потребляет в пассивном режиме?

    ОтветитьУдалить
    Ответы
    1. Добрый вечер!
      Спасибо за хороший отзыв, рад помочь.
      Если запитаете Ардуино в обход стабилизатора, то он не повлияет на энергопотребление. Не стоит выпаивать его. Сам я тоже не пробовал.

      Удалить
  7. Ув. Владимир! Статей такого качества, как Ваши в интернетах, особенно русскоязычных, - по пальцам перечесть. Спасибо Вам огромное за Ваше бескорыстно потраченное время и силы.

    ОтветитьУдалить
    Ответы
    1. Спасибо! Подобный отзыв - лучшая мотивация для написания новых статей.

      Удалить
  8. Владимир, я совершенный дилетант, но у меня есть конкретный вопрос касательно вашей статьи. Как считаете можно ли собрать на arduino систему с 5-10 цифровыми датчиками температуры, которая могла бы проработать в течение года от аккумулятора (он в принципе может быть достаточно большим)?

    ОтветитьУдалить
    Ответы
    1. Добрый день!
      Если поставить такую цель, то можно, только аккумулятор должен быть реально большим. Всё зависит от потребляемого устройством тока, по нему можно примерно оценить время работы от аккумулятора заданной емкости (погуглите "расчет времени работы аккумулятора").
      А вообще Ардуино для таких целей не подходит. На ней можно отладить систему, все проверить. Но в конечном устройстве, тем более, если требуется продолжительная автономная работа, лучше использовать отдельно микроконтроллер: его можно настроить на работу от внутреннего RC-генератора 8МГц, не потребуется никакая внешняя обвязка и ток в режиме сна составит менее 1мкА. И это совсем не сложно. С Ардуино вы не добьетесь такого результата.
      Я сейчас пишу статью про использование микроконтроллера ATtiny85 с тактированием от внутреннего генератора. Если интересно, могу подготовить аналогичную про ATmega328p.

      Удалить
    2. Добрый день, спасибо за подробный ответ. Можно ли обратиться к вам лично? мой адрес volodukeпочтару

      Удалить
    3. Можно. Напишите мне на VladimirTsibrov@yandex.ru

      Удалить
  9. а как ардуино работает от аккумулятора 3,2В? какое вообще минимальное напряжение допустимо для работы ардуино?

    ОтветитьУдалить
    Ответы
    1. Нормально работает, если запитывать через пин 5V. Минимальное где-то около 2В, при условии, что вы отключили BOD. Вообще микроконтроллеру достаточно 1,8В

      Удалить
  10. Ответы
    1. Тогда bod (схема контроля питания) переведет микроконтроллер в состояние сброса и будет удерживать его в нем до тех пор, пока напряжение не полнимется до нужного уровня. О том какие это уровни и как их изменить/отключить можете прочитать в публикации про фьюзы:
      https://tsibrov.blogspot.com/2018/08/fuse-bits.html

      Удалить
  11. а с включенной bod при 3В ардуино будет работать?

    ОтветитьУдалить
    Ответы
    1. Будет. Я все-таки очень советую почитать статью, на которую я дал ссылку. Там есть ответ на этот вопрос.

      Удалить
  12. Есть смысл менять частоту, если после кода я всегда в сон ухожу или delay делаю. Код-то активный физически дольше работать будет, или он реально меньше энергии на одном и том же количестве тактов тратит?

    ОтветитьУдалить
    Ответы
    1. Если речь о том, чтобы побыстрее выполнить какие-то расчеты и уснуть, то сказать сложно. Возможно, разница в потреблении будет несущественной.

      Другое дело, если микроконтроллер просыпается для работы с медленными устройствами. Датчикам, например, зачастую нужно время (до нескольких секунд) для выдачи результата. В этом случае быстродействие не нужно. Уж лучше их ждать, потребляя минимум энергии. С delay аналогично.

      Удалить