У меня на pro mini (все лишнее выпаяно) с внутренним генератором и делителем на 2 при питании от двух АА станция живет немногим больше года (13-14 месяцев). Просыпается раз в минуту по watchdog (на самом деле там за минуту несколько раз просыпается и засыпает, интервалы вычисляются, привязка к стандартным значениям времени сна watchdog), измеряет и кидает данные в nrf24 (без подтверждения приема). Вся периферия глушится на время сна, пины на вход с подтяжкой. Питание датчиков коммутируется p-канальным мосфетом. Во сне 7-8 мкА (если правильно помню, но точно меньше 10 мкА).
Управление полевиком землёй или через биполярник? Интересно где потери меньше: при удержании высокого уровня во сне или физической подтяжки на транзисторе? Математически даже 100кОм проигрывают вроде?
Землей включаю. Полевик IRLML6401. Подтянут к питанию резистором порядка 10-51кОм (не смог схему найти, видимо на старом винте, но лень его подключать).
При нуле не разбудит из Power down.
Вот тут я был не прав. Сброс по WDT не ведёт к ресету МК(речь про Power down) - он продолжает работать с той точки, где заснул. Это очень удобно, т.к. можно спать сколько угодно времени(в разумных пределах конечно)).
А если нужен непрерывный сон - цикл while(1) в помощь
Спойлер
#include <util/delay.h>
#define Power PB0
#define sleep_dis() MCUCR &= ~(1 << SE)
#define sleep_en() MCUCR |= (1 << SE)
#define wdt_res() asm volatile("wdr\n\r")
#define sleep_CPU() asm volatile("sleep\n\r")
void Res()
{
PORTB |= (1 << Power);
_delay_ms(250);
PORTB &= ~(1 << Power);
_delay_ms(250);
}
void Vkl()
{
PORTB |= (1 << Power);
_delay_ms(50);
PORTB &= ~(1 << Power);
_delay_ms(50);
}
ISR (WDT_OVERFLOW_vect) // watchdog interrupt
{
Serial.print("q");
}
void setup() {
Serial.begin(9600);
Serial.print("z");
DDRB |= (1 << Power);
Res();
//===настройка WDT ==============
WDTCSR |= (1<<WDCE) | (1<<WDE);//включаем сброс по wdt
WDTCSR = (1 << WDP0) | (1 << WDP3) | (1 << WDIE);//уст. делитель на 8сек и вкл. прерывание от wdt
//==== настройка сна ==============
MCUCR |= (1 << SM0);//SM0=1; режим Power down,
}
void sleep8sec()
{
cli();
sleep_en();
sei();
sleep_CPU();
sleep_dis();
}
void loop() {
Vkl();
wdt_res();
for(uint8_t i = 0; i < 3; i++)//спим 3 раза по 8сек
sleep8sec();
}
P.S. Для Тини 2313
Ха! А я то думал куда WDT_OVERFLOW затолкать, ведь в таблице векторов в даташите одиночного WDT тупо нет. Заменил в своём исправленном - работает как дОлжно.
Спасибо за скетч и уделённое время. Бум ковырять дальше.
#include <avr/sleep.h>
#include <avr/io.h>
#include <util/delay.h>
#include <avr/wdt.h>
#define Power PB0
void Res()
{
PORTB |= (1 << Power);
_delay_ms(250);
PORTB &= ~(1 << Power);
_delay_ms(250);
}
void Vkl()
{
PORTB |= (1 << Power);
_delay_ms(50);
PORTB &= ~(1 << Power);
_delay_ms(50);
}
ISR (WDT_OVERFLOW_vect) // watchdog interrupt
{
wdt_disable(); // disable watchdog
} // end of WDT_vect
void setup() {
DDRB |= (1 << Power);
Res();
}
void loop() {
Vkl();
MCUSR = 0; // clear various "reset" flags
WDTCR = (0 << WDIF) | (0 << WDIE) | (1 << WDP3) | (1 << WDCE) | (0 << WDE) | (0 << WDP2) | (0 << WDP1) | (1 << WDP0);
WDTCR = (1 << WDIF) | (1 << WDIE) | (1 << WDP3) | (0 << WDCE) | (0 << WDE) | (0 << WDP2) | (0 << WDP1) | (1 << WDP0);
wdt_reset(); // pat the dog
set_sleep_mode (SLEEP_MODE_PWR_DOWN);
noInterrupts (); // timed sequence follows
sleep_enable();
interrupts (); // guarantees next instruction executed
sleep_cpu ();
sleep_disable(); // cancel sleep as a precaution
}
Заманался искать чтение пина с ентими кракозябрами. Хоть миллис в этом аддоне работает, ничего изобретать не пришлось. Типа всё получилось, но интересует вопрос: Не проще ли(надёжней, правильней) было бы оставить делеи, а порт читать через прерывание? И гарантированно достучится и есть выбор из нескольких типов срабатывания!?
//#include <util/delay.h>
#define Power PB0
#define Done PB1
#define sleep_dis() MCUCR &= ~(1 << SE)
#define sleep_en() MCUCR |= (1 << SE)
#define wdt_res() asm volatile("wdr\n\r")
#define sleep_CPU() asm volatile("sleep\n\r")
const uint32_t interval = 2000;
ISR (WDT_OVERFLOW_vect) // watchdog interrupt
{
}
void setup() {
DDRB |= (1 << Power);
//===настройка WDT ==============
WDTCSR |= (1 << WDCE) | (1 << WDE); //включаем сброс по wdt
WDTCSR = (1 << WDP0) | (1 << WDP3) | (1 << WDIE);//уст. делитель на 8сек и вкл. прерывание от wdt
//==== настройка сна ==============
MCUCR |= (1 << SM0);//SM0=1; режим Power down,
}
void sleep8sec()
{
cli();
sleep_en();
sei();
sleep_CPU();
sleep_dis();
}
void loop() {
PORTB |= (1 << Power);
static uint32_t previousMillis = 0;
uint32_t currentMillis = millis();
if ((currentMillis - previousMillis >= interval) || ((PINB & 1 << Done))) {
previousMillis = currentMillis;
PORTB &= ~(1 << Power);
wdt_res();
for (uint8_t i = 0; i < 1; i++) //спим 3 раза по 8сек
sleep8sec();
}
}
Енто аддон от чувака “ЧУВААААК”(с) Засада в том, что обычные выражения ардуины компилируются без ошибок, но нифига не работают. ![]()
Там ещё прикол есть с выбором частоты: типа есть настройка на внутренний 1МГц(чего нет в даташите), а реально зашивается 8МГц с делителем на восемь и, соответственно, жрёть больше чем при на честных четырёх.
Вот, не зря написал вроде. Т.к. был не уверен. Подкинул в Протеусе - PCINT тоже работают, (по крайней мере в симуляторе). Но(!) , они приводят к ресету МК. Так что - смотри сам, что тебе нужно, хозяин-барин))
INT0 тоже, может к ресету приведут(не проверял)
