Экономия аккумулятора, глубокий сон

akas
Offline
Зарегистрирован: 16.03.2021
Нужно сделать с максимально возможной экономией аккумулятора примерно такую штуку.
Есть датчик, при срабатывании он на выходе ставит единицу и удерживает ее минимум 2 секунды (может и дольше). В течение этого времени нужно отправлять через SoftwareSerial сообщение "alarm", пару раз в секунду достаточно. Когда датчик молчит, нужно спать с макс. энергосбережением и примерно раз в минуту отправлять сообщение "ping". Большая точность интервалов времени не обязательна, важно "не прозевать"  срабатывание датчика.
С темой энергосбережения, сна и прерываний впервые столкнулся.
Ниже самый простой вариант, который приходит в голову. Такое будет работать? 
Смущает частая "побудка", наверное будет жрать аккумулятор?
Как это все сделать правильнее и эффективнее?
#include <SoftwareSerial.h>
#include "GyverPower.h"
#define ALARM_PIN 3
#define RX_PIN 7
#define TX_PIN 8
SoftwareSerial channel(RX_PIN, TX_PIN);
void setup() {
	channel.begin(9600);
	pinMode(ALARM_PIN, INPUT);
	attachInterrupt(digitalPinToInterrupt(ALARM_PIN), isr, RISING);
	power.setSleepMode(POWERDOWN_SLEEP);
	power.hardwareDisable(PWR_ALL);
}
void isr(){
	power.wakeUp();  
}
byte counter = 0;
void loop() {
	if(digitalRead(ALARM_PIN)){
		channel.println("alarm");
		counter = 0;
	}else if(++counter == 120){
		channel.println("ping");
		counter = 0;
		if(digitalRead(ALARM_PIN))
			channel.println("alarm");
	}
	power.sleep(SLEEP_512MS);
}

 

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

akas пишет:

Нужно сделать с максимально возможной экономией аккумулятора

...

Как это все сделать правильнее и эффективнее?

#include "GyverPower.h"

Дык ить эта... тып к аффтору биплиоОтики обратился?

------

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

Ну и ысчо много чиво нужно проЯснить, ОК?

akas
Offline
Зарегистрирован: 16.03.2021

wdrakula пишет:
А тут, вот тут конкретно, на этом форуме, нужно указать на чем ты все строишь - на Ардуино или голом контроллере? На каком? Сколько времени будет держаться входной сигнал тревоги? Если ты используешь Ардуино с бутлоадером, то, до начала исполнения программы, пройдет примерно секунда...Ну и ысчо много чиво нужно проЯснить, ОК?

ОК. Подробности:
1) Доплеровский датчик  движения  RCWL-0516.
При обнаружении движения устанавливает на выходе в логическую единицу (3.3V), держит пока чувствует движение, и потом еще 2 секунды. То есть длительность сигнала тревоги 2 сек минимум или больше.
Питание по даташиту 4 - 28V, по факту отлично работает от 3.3, ниже - отказывается. Жрет зараза 2.5 мА, вне зависимости от наличия/отсутствия тревоги. После включения питания стартует 10 секунд, периодически включать/выключать не получится. 
2)  Через SoftwareSerial сообщения передаются в радиодуль HC-12, который пересылает на другой такой же радиомодуль на "базовой станции" по радиоканалу 433МГц. Модули умные, сами обеспечивают в протоколе контрольные суммы и так далее. Интерфейс у них UART. Питание 3,3-5В, ток покоя/передачи зависит от режима, режимов несколько, есть также режим сна, все настраиваются АТ командами, с конкретными режимом пока не определился, надо поэкспериментировать.
3) Между датчиком и модулем  нужна "прокладка", которая как минимум по логической единице на входе (2 сек мин) будет посылать в UART радиомодуля  сигнал (в коде выше я обозначил сигнал "alarm").
В идеале также будет слать на "базу" периодический пинг, реже напряжение аккумулятора, получать и обрабатывать подвтерждения базы, переводить радиомодуль в режим сна и т.п. 
Сначала пробовал по минимуму сделать генератор UART сигнала на Attiny13, в общем получилось но не понравилось, частоту держит плохо, а радиомодулю нужен честный UART на 9600. Возиться с кварцами и паять лень, и контроллер поумнее захотелось.
Поэтому делаю на Arduino Pro Mini 168 8Мгц 3.3.V, светодиод и стабилизатор ампутирую.
Усройство после запуска будет работать непрерывно пока хватает питания, поэтому время  загрузки бутлоадера не важно, а из сна POWERDOWN пробуждение вроде как быстрое (16+6 тактов).
4) Питание от одного 18650 с  защитой на  2200 мАч, напрямую без преобразователей на VCC ардуины,  на датчик и на радиомодуль.
5)  Всего устройств с датчиками будет 4-5 шт и одна "база". Эксплуатация летом (от +10°C), в тайге, девственно чистый радиоэфир, но полное отсутствие розеток и ларьков с батарейками .
Предполагается, что датчики будут срабатывать крайне редко (пару раз в сутки по 10 минут).
В идеале нужно обеспечить непрерывную работу датчика на одном аккумуляторе в течение недели (170 часов).
 

wdrakula пишет:
Дык ить эта... тып к аффтору биплиоОтики обратился?

Там кода внутри библиотеки вроде немного...  Я могу попробовать вместо вызовов этой библиотеки вытащить в пример кода саму работу с регистрами и WDT (которые пока я не очень понимаю). 

 

 

 

sadman41
Offline
Зарегистрирован: 19.10.2016

328й МК умеет просыпаться по LOW на некоторых пинах.
Напр.: http://heliosoph.mit-links.info/atmega328p-wakeup-sleep-via-interrupt/
Это как-будто бы реже будет будить МК.
Но есть проблема - этот ваш модуль по тревоге делает HIGH, если я не ошибаюсь. И это совершенно не то, что нужно. С другой стороны на нем есть место для припайки резисторов, которые увеличат время нахождения в аларме (если верно помню). Т.е. уже не 512мс можно ставить интервал сна, а секунды 4-8.

Но, в целом, насколько будет эффективней побудка по времени в отличии от побудки по событию - покажет только эксперимент. Ведь жрать там будет все. Да и просто от неаккуратного монтажа могут утечки пойти.

И, да, если вы собрались глухарей выслеживать или медведей каких, то учтите, что МКВ сенсоры не отличают теплокровного от ёлки и будут реагировать на колыхание и того и другого.

Upper
Offline
Зарегистрирован: 23.06.2020

Банально, но надо пробовать и измерять потребление.

По скетчу: вроде из описания библиотеки power.wakeUp();  лишнее. Вредно ли это, или просто избыточно - не знаю.

И пробуждение из сна быстрое для внутреннего RC генератора. Если кварц, то намного больше. Это скорее просто для информации, на потребление заметного влияния оказать не должно.

Гриша
Offline
Зарегистрирован: 27.04.2014

пока это того самое, подумайте в сторону солнечной батареи. она не зарядит АКБ, но компенсирует некоторые затраты. Солнечная батарейка (панель) - источник тока, с таким АКБ ее можно цеплять через диод, не заморачиваясь со схемой заряда и контроля... если солнечная панель небольшая.      

akas
Offline
Зарегистрирован: 16.03.2021

sadman41 пишет:
328й МК умеет просыпаться по LOW ... Это как-будто бы реже будет будить МК. Но есть проблема - этот ваш модуль по тревоге делает HIGH, если я не ошибаюсь. И это совершенно не то, что нужно.
У меня Atmega168, вроде тоже понимает LOW, выход модуля можно инвертировать транзистором. Но разве LOW будет реже будить МК чем RISING/FALLING/CHANGE, вроде же наоборот? Или смысл такой, что изменение пина можно и прозевать (напр во время запрета прерываний SoftwareSerial) , а LOW точно  не прозеваешь?
Цитата:
С другой стороны на нем есть место для припайки резисторов, которые увеличат время нахождения в аларме (если верно помню). Т.е. уже не 512мс можно ставить интервал сна, а секунды 4-8. Но, в целом, насколько будет эффективней побудка по времени в отличии от побудки по событию - покажет только эксперимент.
Побудка у меня не только по времени, но и  по событию RISING на пине с датчиком!
По идее время сна нужно бы поставить максимальное  8192 мс, но возможна проблема.
Если датчик включится непосредственно перед уходом в сон, но уже после проверки пина в loop(), то МК прозевает срабатывание датчика и проспит 8 сек.
Если подскажете, как избежать такой ситуации, буду очень благодарен!
Пока что сделал сон полсекунды именно из-за этого. За 2 сек включения датчика МК точно проснется 2-3 раза и напрямую проверит пин, опоздание тревоги в полсекунды допустимо. Решение вроде рабочее, но кривое и неэффективное.

akas
Offline
Зарегистрирован: 16.03.2021

Гриша пишет:
подумайте в сторону солнечной батареи
Во время работы датчиков от солнечных батарей (2 шт 12V 20W) будет заряжаться сменный комплект аккумуляторов. Не уверен, что разумно еще и на все 4-5 датчиков делать свои отдельные батареи.
Самый прожорливый это датчик движения, он постоянно потребляет 2.5 мА, мк и радиомодуль большую часть времени будут спать. Если грубо емкость аккумулятора  2200 мАч поделить на 2.5 мА получим  36 суток.  Реально конечно будет меньше, но столько и не нужно. Достаточно одной недели.   
Разумеется, это все надо будет пробовать и проверять.

sadman41
Offline
Зарегистрирован: 19.10.2016

akas пишет:

sadman41 пишет:
328й МК умеет просыпаться по LOW ... Это как-будто бы реже будет будить МК. Но есть проблема - этот ваш модуль по тревоге делает HIGH, если я не ошибаюсь. И это совершенно не то, что нужно.
У меня Atmega168, вроде тоже понимает LOW, выход модуля можно инвертировать транзистором. 

Инвертировать можно. Но это ещё один потребитель энергии. 

akas пишет:

Но разве LOW будет реже будить МК чем RISING/FALLING/CHANGE, вроде же наоборот?
 Или смысл такой, что изменение пина можно и прозевать (напр во время запрета прерываний SoftwareSerial) , а LOW точно  не прозеваешь?
 
Смысл такой, что из дипслипа контроллер можно вытащить так:

Low level interrupt on INT0 and INT1 is detected asynchronously. This implies that this interrupt can be used for waking the part also from sleep modes other than idle mode. The I/O clock is halted in all sleep modes except Idle mode. Note that if a level triggered interrupt is used for wake-up from power-down, the required level must be held long enough for the MCU to complete the wake-up to trigger the level interrupt. If the level disappears before the end of the start-up time, the MCU will still wake up, but no interrupt will be generated. 

Насколько я понимаю даташит - никакие иные виды внешних прерываний не вытаскивают МК из спячки.

Если вы не используете это, то остается только периодически вскакивать по таймеру.

akas пишет:
Побудка у меня не только по времени, но и  по событию RISING на пине с датчиком!

Сомнительно. См. цитирование выше.

akas пишет:
По идее время сна нужно бы поставить максимальное  8192 мс, но возможна проблема.
Если датчик включится непосредственно перед уходом в сон, но уже после проверки пина в loop(), то МК прозевает срабатывание датчика и проспит 8 сек.
Если подскажете, как избежать такой ситуации, буду очень благодарен!

Модифицировать датчик так, чтобы он 2x времени аларм держал?

akas
Offline
Зарегистрирован: 16.03.2021

Переписал код, без внешних библиотек. Временно для отладки вместо SoftwareSerial отправляю в Serial и смотрю монитором, все работает

//#include <SoftwareSerial.h>
#define ALARM_PIN 3 // пин датчика
#define SLEEP_MODE 2 // POWERDOWN
#define SLEEP_TIME 5 // ~ 512мс
#define PING_PERIOD 8 // 8 x 512мс ~ 4c
//SoftwareSerial channel(RX_PIN, TX_PIN);
uint8_t wdtReg;
void setup() {
    pinMode(ALARM_PIN, INPUT);
    attachInterrupt(digitalPinToInterrupt(ALARM_PIN), alarmRising, RISING);
    // откл всё железо
    ADCSRA &= ~ (1 << ADEN);
    ACSR |= (1 << ACD);
    PRR |= 0xFF;
    // для WDTCSR    
    wdtReg = (1 << WDIE);
    if(SLEEP_TIME < 8)
        wdtReg |= SLEEP_TIME;
    else
        wdtReg |= (SLEEP_TIME - 8) | (1 << WDP3);
    // пока вместо SoftwareSerisal пишем в Serisal
    //channel.begin(9600);
    PRR &= ~ (_BV(1) | _BV(5)); // UART0 + TIMER0 
    Serial.begin(9600); 
}
void alarmRising(){}
ISR(WDT_vect){
    WDTCSR |= (1 << WDCE) | (1 << WDE);
    WDTCSR = 0;
    asm ("wdr");
}
byte counter = 0;
void loop() {
    if(digitalRead(ALARM_PIN)){
        send("alarm");
        counter = 0;
    }else if(++counter == 8){
        send("ping");
        counter = 0;
        if(digitalRead(ALARM_PIN))
            send("alarm");
    }
    cli();
    WDTCSR |= (1 << WDCE) | (1 << WDE);
    WDTCSR = wdtReg;
    sei();
    asm ("wdr");
    SMCR = (SLEEP_MODE << 1) | (1 << SE);    
    MCUCR = (0x03 << 5);
    MCUCR = (0x02 << 5);
    asm ("sleep");
    SMCR = 0;
}
void send(char* str){
    //channel.send(str);
    //channel.flush(str);
    Serial.println(str);
    Serial.flush();
}

Еще раз  кратко -  сигнал на ALARM_PIN устанавливается в единицу на 2 секунды, при его появлении надо несколько раз послать в сериал "alarm", в остальное время нужно спать иногда отправляя сообщение "ping". 
Если сигнал появится во время сна, прерывание alarmRising разбудит, сигнал будет обнаружен и обработан. Если появится в процессе отправки "ping", тоже будет обработан. 
Но если появится после проверки digitalRead(ALARM_PIN) но перед уходом в сон, событие будет потеряно. Точнее говоря будет обнаружено после сна в полсекунды (длительность сигнала 2 сек). Опоздание в полсекунды приемлимо.

Хочется сделать сон более длительным (8 секунд). Но тогда при потере сигнала перед засыпанием опоздание тревоги будет уже 8 секунд, это слишком много.
Как этого избежать? Как отменить засыпание при наличии единицы на пине ALARM_PIN?

 

sadman41
Offline
Зарегистрирован: 19.10.2016

Уверены в том, что просыпается по RISING, а не по WDT?

akas
Offline
Зарегистрирован: 16.03.2021

sadman41 пишет:
Если вы не используете это, то остается только периодически вскакивать по таймеру.
akas пишет:
Побудка у меня не только по времени, но и  по событию RISING на пине с датчиком!
Сомнительно. См. цитирование выше.

Ну я же только что проверил сам своими руками, по RISING отлично просыпается!
Сделал сон подольше (4 сек) чтоб успеть, добавил println("wake") при просыпании и потыкал в пин проводком. Вот лог из монитора:

08:41:25.466 -> wake
08:41:29.555 -> wake
08:41:33.613 -> wake
08:41:37.668 -> wake
08:41:41.752 -> wake
08:41:42.317 -> wake
08:41:42.317 -> alarm
08:41:46.371 -> wake

Все повторы wake через идут 4 секунды.
А когда ткнул в пин сон был меньше секунды!
См строчку 08:41:42.317 wake который прямо перед alarm

 

 

Green
Offline
Зарегистрирован: 01.10.2015

sadman41 пишет:

Уверены в том, что просыпается по RISING, а не по WDT?

Manoraj Gnanadhas (Atmel)
2015-01-20 6:23:36 GMT
Привет,Ник,
Наша проектная группа подтвердила “что” Note-3 упомянутый под таблицей 10-1 "
является ошибкой схемы данных. Таким образом, вы можете использовать любой тип
прерывания (Rising edge/ Falling edge / Low level / любое логическое изменение),
чтобы выйти из спящего режима. Извините за причиненные неудобства.
С Наилучшими Пожеланиями,
Manoraj Gnanadhas
 
sadman41
Offline
Зарегистрирован: 19.10.2016

И там индусы... Ну что ж, будем знать.

Green
Offline
Зарегистрирован: 01.10.2015

И главное, с 15-го года могли бы и исправить в даташите.(

Upper
Offline
Зарегистрирован: 23.06.2020

akas пишет:

Как этого избежать? Как отменить засыпание при наличии единицы на пине ALARM_PIN?

Сначала другие советы.
Можно вообще не спать, а работать на низкой частоте, при необходимости повышать частоту. 
Разница в потреблении для просыпания раз в 8 сек и 2 раза в сек, скорее всего, в данном случае не существенна.
 
Если спать по максимуму.
Дальше чисто теоретически, не проверял.
Возможный вариант с отменой засыпания при 1 на ALARM_PIN.
(засыпание может не отменится, но будет коротким).
 
Собираемся долго спать.
Устанавливаем WDT на долгий сон.
Проверяем ALARM_PIN = 0
Если да, разрешаем прерывание по 1. И командуем спать.
После сна может быть надо установить нужный период WDT
 
В обработчике прерывания по 1
Устанавливаем WDT на самый короткий сон.
Запрещаем прерывание по 1.
akas
Offline
Зарегистрирован: 16.03.2021

Upper пишет:
Можно вообще не спать, а работать на низкой частоте, при необходимости повышать частоту. Разница в потреблении для просыпания раз в 8 сек и 2 раза в сек, скорее всего, в данном случае не существенна.
 
Интересно, думал что POWERDOWN с полностью отключенной периферией потребляет меньше любого другого режима, какие-то микроамперы...  Кстати, у моих Pro Mini кварц 8Мгц, специально такие использую. 
В данном случае, пока датчик не включится, и работы-то нет никакой, наверное проще спать. Если разница  между сном 8 и 0.5 сек несущественная, это сильно упрощает дело. Но все равно хочется разобраться с долгим сном. Спасибо за советы, буду копать дальше!

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Голый контроллер, без кварца, 8 MHz во сне, Powerdown

Меньше мне сделать не удалось. Пишуть, что оне PicoPower, но я так и не добился.

Upper
Offline
Зарегистрирован: 23.06.2020

akas пишет:

Интересно, думал что POWERDOWN с полностью отключенной периферией потребляет меньше любого другого режима, какие-то микроамперы... 

Кстати, у моих Pro Mini кварц 8Мгц, специально такие использую.

Понятно, что POWERDOWN круче всех, но вы пишите, что у вас есть доплеровский модуль который всегда включен и ест 2.5 мА. Поэтому СИЛЬНО стараться снизить до 10 мкА может нет смысла.

И еще раз напомню, если вы используете кварц, то выход из спячки намного дольше, чем вы писали выше. Для общего потребления это не существенно.

strarbit
Offline
Зарегистрирован: 12.06.2016

power-down aatiny13a https://youtu.be/cWddjLl2KCQ

akas
Offline
Зарегистрирован: 16.03.2021

strarbit пишет:
power-down aatiny13a
 Голая аatiny13 без кварцев не справляется с протоколом UART на 9600, работать заставил но результат нестабильный.

 

akas
Offline
Зарегистрирован: 16.03.2021

Краткие итоги, может кому пригодится.
Плата Mini Pro которая "3.3V" кварц 8МГц контроллер Atmega168PA,самый  дешевый китай с надписью www.betemcu.cn 

Сначала отпаял  светодиод питания и стабилизатор, на "пустом скетче" стала потреблять 4.5 мА.
Сделал режиме сна POWERDOWN с полностью отключенной периферией, ток всего 5 мкА!
При этом регулярно просыпается по таймеру ватчдога и сразу же по нажатию кнопки, где прерывание, мигает диодиком. 

Мерял с питанием от  акк 18650, заряженного до 4 вольт. Мультиметр UT33C, разрешение у него 1 мкА точность  ±1% или ±2 разрешения, хотя немолодой уже, но раньше вроде сильно не врал. Но мне уже без разницы 5 или 7 мкА, этого уже достаточно, все равно датчик будет жрать 2.5 мА.

Измерил осциллографом примерное время просыпания, очень грубо. От переднего фронта после кнопки до фронта на 13 пине, который мигает. Получилось 2.69 миллис, для моей задачи этого достаточно.

Всем кто помогал и подсказывал, спасибо!
Вопросов есть еще много, но уже по другим темам.