Когда я читал datasheet микроконтроллера наткнулся на раздел спящих режимов. Решил разобраться в этом.
Спящие режимы могут быть очень полезными, если микроконтроллер долго бездействует. У разных микроконтроллеров имеются разные режимы, советую почитать раздел «Power Management and Sleep Mode» в документации микроконтроллера.
Режимы микроконтроллера Atmega168:
- Idle Mode. Режим ожидания (общий для всех моделей). В этом режим останавливается ЦПУ, а периферия — SPI, USART, Аналоговый компаратор, ADC, TWI, таймеры/счетчики, сторожевой таймер и система прерываний продолжает работать.
- ADC Noise Reduction Mode. В этом режиме останавливается процессор, но АЦП, внешние прерывания, TWI, таймер/счетчик2, сторожевой таймер (если включен) продолжают работать.
- Power-down Mode. Общий для всех микроконтроллеров AVR. В этом режиме останавливается все что есть в микроконтроллере, кроме сторожевого таймера, внешних прерываний и TWI. Самый экономный режим.
- Power-save Mode. Этот режим похож на Power-down mode. Отличается он тем, что если Таймер/счетчик2 работает асинхронно, то он продолжит свою работу и во время сна. Это может пригодиться при реализации часов реального времени на микроконтроллере.
- StandbyMode. Этот режим также похож на режим Power-down mode. Но в этом режиме тактовый генератор продолжает работать (если установлен внешний кварц). Из этого режима МК просыпается за 6 тактов.
Чтобы было понятно как можно выйти из того или иного режима — вот таблица:
У микроконтроллера atmega8 — все то же самое, что и у atmega168 кроме StandbyMode.
У микроконтроллера atmega2560 прибавляется еще один режим:
В Arduino IDE спящие режимы реализовываются — так:
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 34 35 36 37 38 39 | #include <avr/sleep.h> #include <avr/power.h> int pin = 2; void wakeUp() { Serial.print("WakeUp"); //Проснулись detachInterrupt(0); //Отключаем прерывания while(1); //Бесконечный цикл } void EnterSleep() { attachInterrupt(0, wakeUp, LOW); //Если на 0-вом прерываниии - ноль, то просыпаемся. delay(100); sleep_enable(); //Разрешаем спящий режим sleep_mode(); //Спим (Прерывания продолжают работать.) Программа останавливается. sleep_disable(); //Запрещаем спящий режим } void setup() { Serial.begin(9600); set_sleep_mode(SLEEP_MODE_PWR_DOWN); //Определяем режим сна pinMode(pin, INPUT); } void loop() { Serial.print("Hello World"); delay(5000) Serial.print("Sleep"); EnterSleep(); //Пора спать } |
В данном примере используется PWR-Down Mode. Чтобы вывести микроконтроллер из сна, нужно — подать ноль на прерывание INT0 (2пин). Другие режимы определяются в программе так:
SLEEP_MODE_IDLE
SLEEP_MODE_ADC
SLEEP_MODE_PWR_SAVE
SLEEP_MODE_STANDBY
SLEEP_MODE_PWR_DOWN
SLEEP_MODE_EXT_STANDBY
Также можно выйти из спящего режима с помощью UART(Serial), нужно соеденить вывод RX(0пин) через 220Ом-ный резистор со внешним прерыванием INT0(2пин). Когда Ардуина — заснет, то просто пульните что нибуль в com порт, и она проснется.
PS: О других возможностях вывода из того или иного спящего режима, напишу возможно позже.
Источники:
Arduino and Zigbee
Electronics Blog
Очень полезная инфа. Хотелось бы больше прояснить по командам
Не совсем ясно
sleep_enable(); //Разрешаем спящий режим
sleep_mode(); //Спим (Прерывания продолжают работать.) Программа останавливается.
sleep_disable(); //Запрещаем спящий режим
Зачем сначала разрешать, и сразу запрещать, и режим раньше прописали
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
Зачем разрешать? — функция sleep_enable() фактически разрешает вызывать функцию sleep_mode(), если первое не было выполнено, то контроллер просто не «уснет».
sleep_disable() — запрещает выполнение функции sleep_mode. В данном примере сделано так, что когда контроллер уснул и проснулся по прерыванию, то в первую очередь выполняется подпрограмма wakeUp, а потом программа начинает продолжать с места остановки(то есть после функции sleep_mode()). И тут, по идее, мы должны запретить функцию sleep_mode, но нам не даст этого сделать пустой цикл в подпрограмме wakeUp. Поэтому sleep_disable() в данном примере не нужен.
А set_sleep_mode(SLEEP_MODE_PWR_DOWN) — просто определяет режим сна.(тк их несколько)
Таково устройство библиотеки sleep/power
как сделать так чтоб только после выхода из сна выполнялась какая-то функция и только один раз?
Есть много способов. В принципе, функция void wakeUp() (в примере) выполняется по прерыванию 1 раз. Единственное, уберите оттуда while(1);.
Случайно нет примера как будить с помощью таймера? Например каждые 60 сек
Попробуйте так:
не работает. если делать
for (times = 0; times < 14; ++times) {
sleep_mode();
то в сон не уходит, а если делать больше 14, например 65, то из сна не выходит…
Иван, а TCNT1=0x0000; стоит в цикле?
Да, и попробуйте выражение перенести в обработчик прерываний.
А, что лучше для МК, крутиться в цикле while проверяя состояние нужной ноги, или сон, если вопрос о энергосбережении не стоит?
Второй вопрос. Сколько лет может проработать МК (например atmega 328), не выключаясь?
И третий. Может ли МК зависнуть в режиме сна? Как предусматривать watch dog в этом режиме.
При «кручении» цикла while процессор постоянно выполняет инструкции, поэтому правильнее будет его усыпить, а также воспользоваться возможностями контроллера прерываний. А общем случае — никакой разницы.
Сам проверял такое лишь в течение года 🙂 Atmega32 управляла освещением в помещении без сбоев.
Шанс зависнуть в режиме сна значительно снижается, особенно в «Power Down». Watch Dog работает независимо от состояния МК. Например, можно просыпаться каждые 5 сек и сбрасывать таймер, тогда это обеспечит отличную защиту от зависаний.
Однако Arduino (или иные платы с их загрузчиком) не работают с этим таймером из-за ошибок в коде загрузчика, как ее исправить можно почитать здесь: https://geektimes.ru/post/255800/ или подобные.
Если у вас МК без загрузчика, то управлять WDT очень просто:
Админ,здравствуйте!
Ваш код прекрасно работает(таймер на 60 сек),но с режимом SLEEP_MODE_IDLE.Можно ли реализовать его с SLEEP_MODE_PWR_DOWN?
сам пробовал-на uno из сна не выходит.
по-идее в режиме SLEEP_MODE_PWR_SAVE таймер отключается, поэтому прерывание по таймеру в этом режиме работать не будет.
Добрый день.
Скажите, Ардуино может просыпаться в режими, например, SLEEP_MODE_PWR_SAVE или SLEEP_MODE_STANDBY от watchdog таймера? В таблице, вроде бы такая возможность указана, а реализацию нигде не могу найти.