Микроконтроллеры AVR отлично подходят для простых автономных проектов с питанием от батареи. В этой статье на примере микроконтроллера ATtiny85 я расскажу как снизить энергопотребление, чтобы продлить срок службы батареи. Использование режимов сна позволяет отключать неиспользуемые модули микроконтроллера, тем самым уменьшая потребляемую мощность. Микроконтроллеры AVR поддерживают до 6-ти режимов сна, позволяющих разработчику оптимизировать энергопотребление под требования проекта. Вот список режимов сна:

- IDLE(Холостой ход)
- ADC Noise Reduction(Уменьшение шумов АЦП)
- Power-down(Выключение);
- Power-save(Экономичный);
- Standby(Дежурный);
- Extended Standby(Расширенный дежурный).

MCU Control Register(Регистр управления МК)

Для перевода микроконтроллера в один из шести режимов сна необходимо предварительно установить биты SE2..0(Sleep Mode) в регистре MCUCR, установить бит SE(Sleep Enable) в регистре MCUCR, а затем выполнить инструкцию SLEEP.

IDLE(Холостой ход)

Если значение бит SM2..0 равно 000, то после выполнения инструкции SLEEP микроконтроллер переходит в режим холостого хода, в котором останавливается ЦПУ, но продолжают работу SPI, UART, аналоговый компаратор, АЦП, двухпроводной интерфейс, таймеры-счетчики, сторожевой таймер и система прерываний. По сути, в данном режиме останавливается синхронизация ядра ЦПУ и флэш-памяти, а остальная продолжает работу.

В режиме холостого хода допускается пробуждение от любого внешнего или внутреннего прерывания, например, при переполнении таймера или завершении передачи UART. Если пробуждение по прерыванию аналогового компаратора не требуется, то аналоговый компаратор может быть отключен путем установки бита ACD в регистре управления и состояния аналогового компаратора ACSR. Это позволит уменьшить потребляемый ток в режиме холостого хода. Если разрешена работа АЦП, то преобразование автоматически запускается после перевода в данный режим.

ADC Noise Reduction(Уменьшение шумов АЦП)

Если значениям бит SM2..0 присвоить 001, то выполнение инструкции SLEEP приведет к переводу микроконтроллера в режим уменьшения шумов АЦП, в котором останавливается ЦПУ, но продолжают работу АЦП, внешние прерывания, наблюдение за адресом двухпроводной последовательного шины, таймер-счетчик 0 и сторожевой таймер (конечно, если были предварительно активизированы). Фактически в данном режиме прекращается синхронизация ввода-вывода, ядра ЦПУ и флэш-памяти, а остальная синхронизация продолжает работу.

В этом режиме создается более благоприятные условия для аналогово-цифрового преобразования с повышенной разрешающей способностью за счет снижения влияния шумов на результат измерения. Если разрешена работа АЦП, то преобразование автоматически запускается при переводе в данный режим. Выход из данного режима допускается не только при генерации запроса на прерывание по завершению преобразования АЦП, но и при внешнем сбросе, сбросе по сторожевому таймеру, сбросе при недопустимом снижении питания, прерывании при обнаружении установленного адреса на двухпроводной последовательной шине, прерывании по таймеру-счетчику 0, прерывании по готовности SPM/EEPROM, прерывании по внешнему уровню на выводах INT7:4 или внешнем прерывании по входам INT3:0.

Power-down(Выключение)

Если SM2..0 = 010, то выполнение команды SLEEP означает перевод микроконтроллера в режим выключения. В данном режиме прекращает работу внешний генератор, но в действии остаются внешние прерывания, наблюдение за адресом на двухпроводной последовательной шине и сторожевой таймер (при условии, что они активизированы). Выход из данного режима возможен только по внешнему сбросу, сбросу сторожевым таймером, сбросу супервизором питания, прерывании по обнаружении установленного адреса на двухпроводной последовательной шине, прерывании по внешнему уровню на выводах INT7:4 или внешним прерывании INT3:0. В данном режиме фактически отключена генерация всех тактовых частот, поэтому дальнейшая работа модулей продолжается только в асинхронном режиме.
Обратите внимание, что если для выхода из прерывания используется прерывание по установке заданного уровня на внешнем входе, то выход из режима сна возможен только если этот уровень присутствует в течение определенного времени. Выход из режима выключения сопровождается задержкой с момента выполнения условия прерывания до эффективного пробуждения. Данная задержка позволяет перезапустить синхронизацию и дождаться стабильности ее работы. Период пробуждения определяется некоторыми конфигурационными битами CKSEL, которые определяют период задержки при сбросе.

Power-save(Экономичный)

Если установить значения бит SM2..0 равным 011, то действие команды SLEEP приведет к переводу микроконтроллера в экономичный режим. Данный режим идентичен режиму выключения за некоторыми исключениями:

- Если таймер-счетчик 0 тактируется асинхронно, т.е. установлен бит AS0 в регистре ASSR, то таймер-счетчик 0 в режиме сна продолжит работу. Выход из режима сна возможен как по переполнению таймера, так и при выполнении условия сравнения, если соответствующее прерывание для таймера-счетчика разрешено в регистре TIMSK, а также установлен бит общего разрешения прерываний в регистре SREG.
- Если для асинхронного таймера НЕ включено асинхронное тактирование, то рекомендуется использовать режим выключения вместо экономичного, т.к. содержимое регистров асинхронного таймера должно рассматриваться как неопределенное после выхода из экономичного режима, в котором значение AS0 было равно 0.
В данном режиме сна останавливаются все тактовые источники за исключением асинхронных, работающих только совместно с асинхронными модулями, в т.ч. таймер-счетчик 0 с разрешенной опцией асинхронного тактирования.

Standby(Дежурный)

После установки значения SM2..0 = 110 и выбора опции тактирования от внешнего кварцевого или керамического резонатора выполнение инструкции SLEEP приводит к переходу микроконтроллера в дежурный режим. Данный режим идентичен режиму выключению за исключением того, что генератор продолжает свою работу. Из дежурного режима микроконтроллер выходит за 6 машинных циклов.

Extended Standby(Расширенный дежурный)

Запись в SM2..0 значения 111 с учетом выбора в качестве тактового источника внешнего кварцевого или керамического резонатора означает, что после выполнения команды SLEEP микроконтроллер будет переведен в расширенный дежурный режим. Данный режим идентичен экономичному за исключением продолжения работы тактового генератора. Выход из расширенного дежурного режима происходит за шесть машинных циклов.

Power Reduction Register(Регистр снижения мощности)

Микроконтроллеры с пониженным энергопотреблением, например ATtiny85 и другие, имеют регистр снижения мощности. Он обеспечивает метод остановки синхронизации для отдельных периферийных устройств для снижения энергопотребления. При отключении модуля его текущий статус запоминается, и все его регистры становятся недоступными для модификации. Ресурсы, используемые периферийным устройством при остановке синхронизации остаются занятыми, поэтому периферийное устройство в большинстве случаев следует отключить перед остановкой синхронизации. Пробуждение модуля, которое выполняется очисткой бита в PRR, помещает модуль в такое же состояние, как до выключения. Отключение модуля можно использовать в режиме ожидания и в активном режиме, чтобы значительно снизить общую потребляемая мощность.

Понижение мощности Таймера/Счетчика 1

Запись логической единицы в бит PRTIM1 отключает модуль Таймер/Счетчик 1. Когда Таймер/Счетчик 1 будет включен, работа продолжится, как до выключения.

Понижение мощности Таймера/Счетчика 0

Запись логической единицы в бит PRTIM0 отключает модуль Таймер/Счетчик 0. Когда Таймер/Счетчик 1 будет включен, работа продолжится, как до выключения.

Понижение мощности USI(Универсального последовательного интерфейса)

Запись логической единицы в бит PRUSI отключает USI, останавливая тактирование модуля. Когда USI будет активирован, его необходимо повторно инициализировать, чтобы обеспечить правильную работу.

Понижением мощности АЦП

Запись логической единицы в бит PRADC отключает АЦП, перед этим АЦП необходимо деактивировать. Аналоговый компаратор не может использовать входной мультиплексор АЦП, когда АЦП выключен.

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

Программа

Напишем небольшую программу для ATtiny85, где контроллер будет управлять светодиодом, при этом будет использоваться 3 уровня яркости и режим сна Power-Down. ATtiny85 тактируется от внутреннего генератора частотой 1 МГц. Здесь я применил нестандартное подключение кнопки, она подключается к выводу RESET.

Алгоритм программы такой: при подключении питания будет инициализироваться переменная status, которая расположена в секции энергозависимой памяти noinit. Это можно сделать путем проверки бита PORF регистра MCUSR, он устанавливается в единицу после включения питания микроконтроллера. Переменной присваиваем первоначальное значение off, это как раз будет режим сна. Так как при аппаратном сбросе(нажатие на кнопку) секция памяти noinit не инициализируется, переменная status будет хранить нужное нам значение. Каждое нажатие на кнопку бедет менять значение status по кругу. Для управления режимом сна я использовал стандартную библиотеку sleep.h из AVRStudio, для этого подключаем заголовочный файл avr/sleep.h

Эксперименты показали такое потребление тока ATtiny85:

Напряжение 3 В 5 В
Частота 1 МГц 8 МГц 1 МГц 8 Мгц
Нормальный режим 0,7 мА 3,6 мА 2,5 мА 8 мА
Режим сна 0,2 мкА 0,2 мкА 0,5 мкА 0,5 мкА
// Режимы сна и пониженного энергопотребления микроконтроллеров AVR
#include <avr/io.h>
#include <avr/sleep.h>

uint8_t status __attribute__ ((section (".noinit"))); // Переменная в секции памяти noinit

#define mode_1  100 // Коды режимов работы
#define mode_2  101
#define mode_3  102
#define off     103

void start_pwm()
{
TCCR0A |= (1 << COM0A1); // Включаем выход таймера Т0 
TCCR0A |= (1 << WGM00)|(1 << WGM01); // Режим Fast PWM
TCCR0B |= (1 << CS01);	 // Предделитель на 8, 488Hz
}

int main(void)
{
PRR |= (1 << PRTIM1)|(1 << PRUSI)|(1 << PRADC); // Отключаем T1, USI и АЦП
ACSR |= (1 << ACD);   // Отключаем аналаговый компаратор

DDRB |=  (1 << PB0);  // Выход ШИМ

if(MCUSR&(1 << PORF)) // Проверяем флаг запуска МК после включения питания 
{
status = off;         // Инициализируем переменную  
MCUSR = 0;            // Сбрасываем регистр статуса МК
}

while(1)
{
  switch(status)
  {
    case mode_1:
    status = mode_2;
    start_pwm();  
	for(;;) {OCR0A = 64;}
    break;

	case mode_2:
    status = mode_3;
    start_pwm();  
    for(;;) {OCR0A = 128;}
    break;

	case mode_3:
    status = off;
    start_pwm();  
    for(;;) {OCR0A = 255;}
    break;

    case off:
    status = mode_1;
    DDRB = 0;
    PORTB = 0; 
	TCCR0A = TCCR0B = 0; // Отключаем Таймер/Счетчик 0
	set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Режим Power-down
    sleep_enable();                      // Разрешаем сон
    sleep_cpu();                         // Сон 
	break;
   }
}
}