После предыдущих публикаций я не могу не упомянуть о библиотеке Low-Power. Данная библиотека предназначена для управления режимами энергосбережения Ардуино. Чтобы перевести Ардуино в интересующий режим достаточно вызвать соответствующую функцию:
Я лишь изменил режим работы пина 2 на INPUT_PULLUP, чтобы по умолчанию на нем всегда был высокий уровень и не требовался внешний подтягивающий резистор. Обработчик прерывания wakeUp не содержит кода, он здесь и не нужен, т.к. единственная задача внешнего прерывания - это разбудить микроконтроллер. При вызове функции powerDown выполняются те же действия, что и в моем скетче MinimizingPowerConsumption из предыдущей публикации. Конечно, здесь это все делается короче и проще. Единственное ограничение данной библиотеки - это тип используемого микроконтроллера.
На момент написания статьи библиотека Low-Power поддерживает следующие микроконтроллеры:
- idle;
- adcNoiseReduction;
- powerDown;
- powerSave;
- powerStandby;
- powerExtStandby;
- standby.
Каждая из этих функций имеет параметр для указания периода пребывания микроконтроллера в данном режиме (т.е. будет задействован WatchDog таймер для пробуждения) - от 15мс до 8с. Если периодическое пробуждение не требуется, то при вызове функции следует указать значение SLEEP_FOREVER. Остальные параметры функций предназначены для отключения периферии микроконтроллера, я не стану их перечислять и объяснять, вместо этого предлагаю заглянуть в файл LowPower.cpp, там все подробно расписано. Попробуйте найти, например, строку Name: powerDown - с нее начинается описание данной функции, приводятся ее параметры, их назначение и возможные значения.
С библиотекой идут несколько примеров для пробуждения Ардуино по сторожевому таймеру и от внешнего прерывания. Давайте рассмотрим пример powerDownWakeExternalInterrupt.ino, его листинг с моими комментариями приведен ниже.
// **** INCLUDES *****
#include "LowPower.h"
// Используем пин 2 для пробуждения
const int wakeUpPin = 2;
void wakeUp(){
// Обработчик прерывания от пина 2
}
void setup(){
// Настраиваем наш пин на ввод и задействуем подтягивающий резистор
pinMode(wakeUpPin, INPUT_PULLUP);
}
void loop(){
// Разрешаем внешнее прерывание на пине 2 при низком уровне
attachInterrupt(0, wakeUp, LOW);
// Переводим Ардуино в режим power down с отключением модулей ADC и BOD
// Остальные модули в этом режиме уже отключены
LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
// При низком логическом уровне на пине 2 будет сгенерировано прерывание
// и после вызова обработчика wakeUp() выполнение данной функции продолжится
// Временно запретим прерывания, они пока не нужны
detachInterrupt(0);
// А здесь должен быть код, который будет выполняться при пробуждении Ардуино
// Это может быть опрос датчиков, обработка данных, передача или отображение
// информации и т.п.
}
Я лишь изменил режим работы пина 2 на INPUT_PULLUP, чтобы по умолчанию на нем всегда был высокий уровень и не требовался внешний подтягивающий резистор. Обработчик прерывания wakeUp не содержит кода, он здесь и не нужен, т.к. единственная задача внешнего прерывания - это разбудить микроконтроллер. При вызове функции powerDown выполняются те же действия, что и в моем скетче MinimizingPowerConsumption из предыдущей публикации. Конечно, здесь это все делается короче и проще. Единственное ограничение данной библиотеки - это тип используемого микроконтроллера.
На момент написания статьи библиотека Low-Power поддерживает следующие микроконтроллеры:
- ATMega168
- ATMega328P
- ATMega32U4
- ATMega2560
- ATMega256RFR2
- ATSAMD21G18A
Поэтому если вы работаете, например, с tiny85, то переводить ее в энергосберегающий режим придется вручную. А в целом библиотека весьма удачная, можете смело использовать ее для создания энергоэффективных устройств на Ардуино.
Ардуино нано, в сон в ходит, но по нажатию не выходит. 10 из 10
ОтветитьУдалитьДобрый день!
УдалитьЭтого не может быть. Скетч используете приведенный выше? Вы обратили внимание на комментарий после detachInterrupt(0)? Данный пример - это лишь заготовка для скетча и без его доработки Ардуино после пробуждения сразу уснет. Скорее всего дело в этом.
Добрый день!
ОтветитьУдалитьДействительно, при компиляции LowPower для ATMega168 возникает ошибка, связанная с тем, что данный микроконтроллер не поддерживает режим Extended Standby Mode. Попробуйте добавить в LowPower.cpp (хоть с самого начала файла) следующий код, мне это помогло избежать ошибки при компиляции.
#if defined __AVR_ATmega168__
#ifndef SLEEP_MODE_EXT_STANDBY
#define SLEEP_MODE_EXT_STANDBY SLEEP_MODE_STANDBY
#endif
#endif
Не за что.
ОтветитьУдалитьА то уж собрался тестить на версии IDE 1.8.5, потому что до этого проверял на другой. Ну хорошо, что разобрались.
а можно атмега328р разбудить по радиосигналу? всмысле, есть передатчик и приемник(привод камеры наблюдения). приемник спит, пока по передатчику не начинаешь посылать для него радиосигналы
ОтветитьУдалитьРадиомодуль какой планируется использовать?
Удалитьhc-12
ОтветитьУдалитьв приемнике я на пин 3 подсоединил вывод rx модуля, думал будет просыпаться обрабатывать команду и выполнять какие то действия, но нет(
ОтветитьУдалитьЯ попробовал, у меня получилось. Без библиотеки LowPower. Если использовать режим Power-Down, то при пробуждении первый символ переданного сообщения теряется. Думаю, из-за того, что тактовому генератору нужно время, чтобы войти в рабочий режим. Выход - использовать режим Standby, он идентичен режиму Power Down, за исключением того, что тактовый генератор продолжает функционировать. Благодаря этому пробуждение микроконтроллера и переход в рабочий режим требуют всего 6 тактов. Попробуйте такой код:
Удалить#include "avr/sleep.h"
#include "SoftwareSerial.h"
#define pin_rx 2
#define pin_tx 3
SoftwareSerial mySerial(pin_rx, pin_tx);
void setup()
{
Serial.begin(9600);
mySerial.begin(9600);
}
void loop()
{
Serial.println("go to sleep");
delay(100);
attachInterrupt(digitalPinToInterrupt(pin_rx), myISR, LOW);
set_sleep_mode(SLEEP_MODE_STANDBY);
sleep_mode();
Serial.println("wake up");
while (mySerial.available()){
Serial.write(mySerial.read());
delay(1);
}
}
void myISR() {
detachInterrupt(digitalPinToInterrupt(pin_rx));
}
а режим SLEEP_MODE_STANDBY поддерживает прерывания типа CHANGE?
УдалитьПоддерживает
Удалитьспасибо)
Удалитьа на сколько этот режим экономнее, чем pwr_down и как еще можно в данном коде снизить энергопотребление?
УдалитьРазница, конечно, есть: в одном случае микроконтроллер потребляет единицы микроампер, в другом десятки. Но эта разница несущественна на фоне потребления HC-12: согласно документации, с завода модуль поставляется сконфигурированным на режим FU3, при котором ток в режиме ожидания составляет 16мА; в режиме FU2 это значение снижается до 3.6мА; наименьший ток - 80мкА в режиме FU1, но при этом снижается и скорость обмена до 4800 бит/c
УдалитьУчтите, что Standby mode используется при работе микроконтроллера от внешнего источника тактирования.
Можно попробовать все-таки использовать режим Power Down, но передатчик должен будет сначала разбудить микроконтроллер фиктивным сообщением, дать ему время на пробуждение и уже после этого передавать данные.
Для минимизации энергопотребления уменьшайте напряжения питания, снижайте частоту МК. И используйте отдельный микроконтроллер, а не Ардуино.
я вообще радиомодуль настроил на режим fu4, где макс. дальность и минимальная скорость передачи 1200бод. какая частота мк для таких настроек подойдет?
Удалитькстати, полез я в ттх радиомодуля, так там 16мА это рабочий ток (для фю4), а в режиме спячки он потребляет всего 22мкА. одна загвоздка в том, что он не засыпает вместе с ардуино, а при помощи ат команды AT+SLEEP и пробуждается по любой другой ат команде. так что, в моем коде, который я ниже привел, модуль находится в активном режиме
УдалитьЯ бы настроил МК на работу от внутреннего RC(8мгц) и понизил до 1мгц фьюзом ckdiv8.
УдалитьА режим sleep радиомодуля, я так понимаю, не подойдет. Потому что в нем он сам спит и не получает сообщения
я даже не могу ат команды устанавливать. с замкнутой на землю ногой сет радиомодуля скетч почему то не работает
Удалитьа так да, ардуино должна просыпаться по радиосигналу от радиомодуля, который сам спит. т.е. замкнутый круг какой то(
Удалитьа просто если понизить частоту мк до 1-2МГц?
Удалитьи какой эффект даст отключение ацп?
УдалитьМожно и так. Только при изменении частоты "на ходу", тайминги, рассчитанные на 16мгц, не соответствуют реальной частоте. Из-за этого меняется длительность задержек по delay. Или вместо 9600, указанных в Serial.begin(), получаеся другая скорость обмена.
УдалитьЯ как-нибудь соберусь, напишу публикацию про использование atmega328 без ардуино. Чтобы при этом тайминги не ломались. Сейчас пока другим занят...
а какой эффект будет при таком коде?
Удалитьvoid loop() {
deepSleep();
if(mySerial.available() > 1){
int input = mySerial.parseInt(); // read serial input and convert to integer
if(input == 1111){
flag=true;
}
if(input == 0000){
flag=false;
}
mySerial.flush();//clear the buffer for unwanted inputs
}
}
void deepSleep(){
ADCSRA &= ~(1 << ADEN); //отключаем ацп
set_sleep_mode(SLEEP_MODE_STANDBY);
attachInterrupt(1, myItrpt, CHANGE); // контакт D3
digitalWrite(13,flag);
sleep_mode(); // включить энергосберегающий режим
// Теперь микроконтроллер простаивает
}
void myItrpt(){
detachInterrupt(0);
ADCSRA |= 1 << ADEN; // Включаем АЦП
}
отключение ацп даст экономию?
УдалитьДаст. Конкретное значение зависит от напряжения питания. Навскидку - 2-3 сотни микроампер.
Удалитьспасибо) залил скетч и все работает. жалко сейчас нет мультиметра, чтоб замерить энергопотребление. а вот с уменьшением частоты возникают проблемы. если добавлю команду clock_prescale_set(clock_div_8); то скетч перестает работать
УдалитьЕсли уменьшаете частоту вызовом clock_prescale_set(clock_div_8) то, соответственно, в mySerial ее нужно увеличить в 8 раз. Чтобы фактическая скорость передачи осталась прежней. Это то, о чем я писал выше про тайминги. Или уменьшите скорость обмена у передатчика
Удалитья уменьшил до 1200бод. меньше нету
Удалитьtx:
ОтветитьУдалить#include
#include
SoftwareSerial mySerial(4,3);//tx,rx
const int inputPin = 2;
volatile boolean flag = true;
int button=0;
void setup() {
mySerial.begin(1200);
pinMode(inputPin,INPUT_PULLUP);
}
void loop() {
goToSleep();
if(button == 1){
mySerial.println(1111);
flag=true;
}
if(button == 0 && flag == true){
mySerial.println(0000);
flag=false;
}
}
void goToSleep(){
set_sleep_mode(SLEEP_MODE_IDLE);
attachInterrupt(0, ReadButton, CHANGE); // контакт D2
sleep_mode(); // включить энергосберегающий режим
}
void ReadButton(){
detachInterrupt(0);
button = !digitalRead(inputPin);
}
rx:
#include
#include
SoftwareSerial mySerial(4,3); //tx, rx
volatile boolean flag = false;
void setup() {
mySerial.begin(1200);
pinMode(13,OUTPUT);
}
void loop() {
deepSleep();
if(mySerial.available() > 1){
int input = mySerial.parseInt(); // read serial input and convert to integer
if(input == 1111){
flag=true;
}
if(input == 0000){
flag=false;
}
mySerial.flush();//clear the buffer for unwanted inputs
}
}
void deepSleep(){
set_sleep_mode(SLEEP_MODE_STANDBY);
attachInterrupt(1, myItrpt, CHANGE); // контакт D3
digitalWrite(13,flag);
sleep_mode(); // включить энергосберегающий режим
// Теперь микроконтроллер простаивает
}
void myItrpt(){
detachInterrupt(0);
}
вот решил начать постепенно, с малого. тут я кнопкой на передатчике просто включаю и выключаю светодиод на приемнике. вроде работает, но с задержкой
LowPower версии 1.81 работает с ATMega168 без проблем, компилируется из Arduino IDE без ошибок. Но потребление по сравнению с ATMega328P в режимах сна в несколько раз выше.
ОтветитьУдалитьОшибка при компиляции для atmega168 была исправлена в версии библиотеки 1.8 от 4 октября 2018.
УдалитьДобавлю к моему предыдущему сообщению.
УдалитьОказывается, не все так однозначно с ATMega168. Есть две платы Pro Mini ATmega168 16MHz с отпаянными стабилизатором и индикатором. Энергопотребление почему-то значительно отличается. Например, с внутренним генератором на 1 МГц в режиме полного сна потребление соотв. 1,5 и 0,09 мкА (питание 3,3 В).
Платы покупались вместе, но партии контроллеров разные: 168PA MU1235 и 168PA MU1028 (эта которая лучше).
0,09 мкА - очень хороший результат, хотя и не исключительный, у меня есть несколько плат ATMega328P с примерно таким же током.
эта библиотека не работает с 88 мегой...
ОтветитьУдалитьне компилирует, пишет ошибку
вот:
ОтветитьУдалитьC:\Users\Alexandr\Documents\Arduino\libraries\LowPower-master/LowPower.h:148:6: error: #error "Please ensure chosen MCU is either 88, 168, 168P, 328P, 32U4, 2560 or 256RFR2."
#error "Please ensure chosen MCU is either 88, 168, 168P, 328P, 32U4, 2560 or 256RFR2."
А должна =работать с 88..
168 и 328 компилирует.
с 88 достаточно указать библиотеку и все - выскакивает ошибка.
Какой пакет используете для работы с 88 мегой?
Удалитьответил ниже
Удалить1.8.15 ide
ОтветитьУдалитьскажите, у вас компилируется что нибудь с данной библиотекой и на 88 мегу?
а, да, использую https://mcudude.github.io/MiniCore/package_MCUdude_MiniCore_index.json
указал в нстройках, появились платы, выбрал 88 мегу, прошил загрузчик, пробовал много разных скетчей - работает, светодиод мигает ит.д. И вот нужно теперь запусктить в экономном режиме, но засада.. сам разобраться не смогу.
не подскажите в чем дело? Как можно решить мою проблему?
Удалить