Watchdog на час
- Войдите на сайт для отправки комментариев
Всем доброго времени суток. Начал работу над датчиком влажности для комнатных растений, и для снижения энергопотребления решил отправлять ардуинку в сон, потому как замерять влажность чаще 5-10 раз в день не нужно. Все здорово, ардуинка уснула, но как уу будить? Первое что подвернулось под руку - watchdog, но максимальное время для работы вотчдога 8с, далее он перезагружает всю программу. Мне хотелось бы увеличить это время раз в 450. Логично подумать что просыпаясь программа должна считывать состояние некой переменной, и если она не достигла 450, то снова спать. Но ведь вотчдог резетит всю программу, переменные стираются, или нет?
#include <avr/wdt.h> // здесь организована работа с ватчдогом
#include <avr/sleep.h> // здесь описаны режимы сна
int a;
void setup()
{
//инициализация ватчдога
wdt_reset(); // сбрасываем
wdt_enable(WDTO_8S); // разрешаем ватчдог 8 сек
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // если спать - то на полную
}
void loop()
{
if (a > 5)
{
основная программа
}
a = a + 1;
sleep_enable(); // разрешаем сон
sleep_cpu(); // спать!
}
Вот так я вижу этот алгоритм в виде кода, но он не работает. При старте программы вотч дог теоретически должен сбросить контролллер 5 раз, затем дать программе выполнить свою работу и снова 5 сбросов. Но каждый раз после резета переменная "a" забывается, и резет идет постоянно.
Подскажите, возможно ли вообще организовать такой алгоритм, и если да, то в чем я сделал ошибку?
Я вроде бы нигде и не писал что watchdog для засыпания. Watchdog для просыпания. Мне нужно будить контроллер по внутреннему таймеру.
Я вроде бы нигде и не писал что watchdog для засыпания. Watchdog для просыпания. Мне нужно будить контроллер по внутреннему таймеру.
ок. давай узнаем, насколько физически актуальна твоя проблема - узнаем длительность цикла loop твоей программы и посчитаем, сколько микроампер мы тратим, если:
а) включаем контроллер раз в 8 секунд и совершаем один loop
б) включаем контроллер раз в 4 часа и совершаем один loop
Длительность цикла loop программы около 5 секунд, в него входит считывание влажности с датчика и вывод его на дисплей. Повторный замер влажности будет необходим только через час, или более, все остальное время контроллер не нужен.
вотчдог можно сделать двухступенчатым. Сначала он может генерить прерывание, а потом перезагружать систему.
вотчдог можно сделать двухступенчатым. Сначала он может генерить прерывание, а потом перезагружать систему.
Можно подробнее? Не совсем понимаю пока
Можно подробнее? Не совсем понимаю пока
Можно и подробнее. http://avrprog.blogspot.ru/2013/03/watchdog.html
и там же, с примерами http://avrprog.blogspot.ru/2013/03/watchdogc.html
Длительность цикла loop программы около 5 секунд
ты не предположения делай, а замерь и опубликуй реальный результат, потому как, если у тебя loop длится 5 секунд, то остаётся убиться ап стену.
Спасибо DetSimen. Вроде бы разобрался, все получилось. Усыпил мк на пол часа.
Объявил функцию для вотчдога
Ещё можно применить RC цепочку с большой постоянной времени и по прерыванию на выводе будить МК.
Пытаюсь так-же как и ТС увеличить время ожидания watchdog'a, но так и не понял каким образом удалось усыпить МК на пол часа, если предложенная ТС функция просто перезапускает watchdog и устанавливает ей таймер на 8с. Где эта функция вызываться должна? В основном цикле программы? По подробнее расскажите пожалуйста.
Каждые 8 секунд МК просыпается, счётчик /переменная увеличивается, если сумма секунд превысит нужное количество минут, то включается нужный код, если нет - опять засыпать. В теме attiny есть конкретные примеры реальных устройств, если не найдёте - в пн скину ссылку.
Я именно так у себя и сделал, (код отсюда) но тут я подумал, МК ведь все равно просыпается каждые 8 сек. Да при этом он не моргет светодиодом, не опрашивает датчики и т.д., но он ведь просыпаеться и проверяет переменную, а значит жрет энергию?
#include <avr/io.h> #include <avr/wdt.h> // здесь организована работа с ватчдогом #include <avr/sleep.h> // здесь описаны режимы сна #include <avr/interrupt.h> // работа с прерываниями volatile uint8_t i; ISR (WDT_vect) { if ((++i % 4) == 0) { PORTB ^= _BV(PB4); // переключаем светодиод } WDTCR |= _BV(WDTIE); // разрешаем прерывания по ватчдогу. Иначе будет резет. } int main() { i = 0; // инициализация порта светодиода DDRB = _BV(PB4); // на этом пине висит светодиод PORTB = _BV(PB4); // зажгем его //инициализация ватчдога wdt_reset(); // сбрасываем wdt_enable(WDTO_8S); // разрешаем ватчдог 8 сек WDTCR |= _BV(WDTIE); // разрешаем прерывания по ватчдогу. Иначе будет резет. sei(); // разрешаем прерывания set_sleep_mode(SLEEP_MODE_PWR_DOWN); // если спать - то на полную while(1) { sleep_enable(); // разрешаем сон sleep_cpu(); // спать! } }тоже есть такая задача, только бутлоадер на нано никак не перешью (((
Те доли секунды которые работает МК ни в какое сравнение не идёт по потреблению, когда вы включаете и работаете с периферией. Проверено.
Главное правильно выключайте пины и внешние устройства, в идеале вся железка должна потреблять в спящем режиме меньше миллиампера.
Хорошо, спасибо за подсказки. К сожалению мой мультиметр отказываеться показывать токи меньше 200мА, проверить не могу.
тоже есть такая задача, только бутлоадер на нано никак не перешью (((
У меня Attiny13, если разберетесь, то дайте знать, тоже интересно
тоже есть такая задача, только бутлоадер на нано никак не перешью (((
в чем сложность?? На нано прекрасно заливается бут от уно. С догом. Плюс освобождается лишних 1.5 кило памяти.
тоже есть такая задача, только бутлоадер на нано никак не перешью (((
Почитайте интернет /форумы, качественно усыпить можно голые МК, для например Nano необходимо отрывать светодиоды, стабилизатор, usb конвертер....нафига это если можно просто взять atmega328p например.
тоже есть такая задача, только бутлоадер на нано никак не перешью (((
Получилось!
Теперь жду Ваш пример как усыплять ардуину на час
Теперь жду Ваш пример как усыплять ардуину на час
так вроде в #12 andriano все уже рассказал? или что-то не понятно?
у меня таким образом аттини спит минуту - но разницы с часом никакой, любой сон дольше 8сек делается одинаково
Теперь жду Ваш пример как усыплять ардуину на час
так вроде в #12 andriano все уже рассказал? или что-то не понятно?
у меня таким образом аттини спит минуту - но разницы с часом никакой, любой сон дольше 8сек делается одинаково
Лично мне лучше пальцем (кодом) показать )))
Лично мне лучше пальцем (кодом) показать )))
обленились, щас найду.
Лично мне лучше пальцем (кодом) показать )))
играете с огнем %) - новичков за такие пассажи мордой в грязь :)
На работе кода нет, а на паямть не помню
если до того пример не найдете - поздно ночью выложу
http://arduino.ru/forum/programmirovanie/attiny13a-101-primenenie?page=2...
http://arduino.ru/forum/programmirovanie/attiny13a-101-primenenie?page=27#comment-335373
Отличный исходник, почему я раньше его не находил, спасибо!
P.S. С каким датчик производится работа, DS12B20?
P.S. С каким датчик производится работа, DS12B20?
Да.
ЗЫ. Ничего в нем отличного нет, переписать получение температуры надо с использованием библиотеки и с контролем CRC, вместо самодельной отправки воткнуть библиотеку RCswitch. но как обычно некогда....и лень тестировать.
Ничего в нем отличного нет
Как минимум то, что он уже готов(код). А я неделю сидел и разбирал разные примеры, переделывал и палил контроллеры xD
P.S. Какую вы ногу в датчике отывали? из той темы. У меня тоже модули по супергетеродинной схеме WL102-341
P.S. Какую вы ногу в датчике отывали? из той темы. У меня тоже модули по супергетеродинной схеме WL102-341
с трудом :(
откопал маркировку микросхемы, по даташиту нашел пин, своими кривыми руками огромным ножиком с трудом подцепил крощечный пин, китайским паяльником припаял проводок, залил все лаком, т.к. все на улице должно стоять, ну вроде почти год уже работает.
Upd:
Вот последний вариант от 17.01.2018, т.к. проверки на корректность температуры не было, тупо проверяется подряд три раза и если нули - просто ничего не оправляет.
#include <avr/sleep.h> #include <avr/wdt.h> #include <avr/io.h> #include <util/delay.h> /* for _delay_us() */ #define periodusec 400 // mcs #define DS_BIT 4 // pin 3 #define RC_BIT 3 // pin 2 #ifndef cbi #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) #endif #ifndef sbi #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) #endif // PB0 pin 5 #define PB0_OUT sbi(DDRB,PB0) #define PB0_LOW cbi(PORTB,PB0) // PB1 pin 6 - EN pin RFunit WL118 #define PB1_OUT sbi(DDRB,PB1) #define PB1_HIGH sbi(PORTB,PB1) #define PB1_LOW cbi(PORTB,PB1) // PB2 pin 7 #define PB2_OUT sbi(DDRB,PB2) #define PB2_LOW cbi(PORTB,PB2) // PB3 pin 2 #define PB3_OUT sbi(DDRB,PB3); #define PB3_LOW cbi(PORTB,PB3); // PB4 pin 3 #define PB4_OUT sbi(DDRB,PB4) #define PB4_IN cbi(DDRB,PB4) #define PB4_HIGH sbi(PORTB,PB4) #define PB4_LOW cbi(PORTB,PB4) #define TimerCountSec 1027 // ~17min delay start by sec word CurrentTime = 0; void ExecFunc() { unsigned long delp = millis(); while ((millis() - delp) <= 300); // установка режима для ds DDRB |= _BV(DS_BIT); PORTB &= ~_BV(DS_BIT); DDRB &= ~_BV(DS_BIT); // get temp and send PB1_OUT; PB1_HIGH; // ON RF unit word TReading = GetThreeTemp(); if (TReading > (word)0) sendRC((unsigned long)(TReading + (word)11500)); // отправляем данные // OFF pins OneWireReset(); PB0_OUT; PB0_LOW; PB1_OUT; PB1_LOW; PB2_OUT; PB2_LOW; PB3_OUT; PB3_LOW; PB4_IN; PB4_LOW; } word GetThreeTemp() { word result = 0; unsigned long delp = millis(); while ((millis() - delp) <= 300); result = GetTemp(); if (result == (word)0) { delp = millis(); while ((millis() - delp) <= 600); result = GetTemp(); if (result == (word)0) { delp = millis(); while ((millis() - delp) <= 900); result = GetTemp(); } } return result; } void CalcTimer() { ++CurrentTime; if (((CurrentTime + 1UL) * 8UL) >= TimerCountSec) { CurrentTime = 0; ExecFunc(); } } ISR (WDT_vect) { wdt_disable(); // disable watchdog } void setup () { // OFF pins PB0_OUT; PB0_LOW; PB1_OUT; PB1_LOW; PB2_OUT; PB2_LOW; PB3_OUT; PB3_LOW; PB4_IN; PB4_LOW; unsigned long delp = millis(); while ((millis() - delp) <= 1000); // pause for enable all device and get temp to clock // first run ExecFunc(); delp = millis(); while ((millis() - delp) <= 4000); // pause for enable all device and get temp to clock // second run ExecFunc(); // for exactly get temp } void loop () { CalcTimer(); cbi(ADCSRA, ADEN); // switch Analog to Digitalconverter OFF setup_watchdog(9); wdt_reset(); // pat the dog set_sleep_mode (SLEEP_MODE_PWR_DOWN); noInterrupts (); // timed sequence follows sleep_enable(); sleep_bod_disable(); interrupts (); // guarantees next instruction executed sleep_cpu (); // cancel sleep as a precaution sleep_disable(); } // 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms // 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec void setup_watchdog(int ii) { byte bb; int ww; if (ii > 9 ) ii = 9; bb = ii & 7; if (ii > 7) bb |= (1 << 5); bb |= (1 << WDCE); ww = bb; MCUSR &= ~(1 << WDRF); // start timed sequence WDTCR |= (1 << WDCE) | (1 << WDE); // set new watchdog timeout value WDTCR = bb; WDTCR |= _BV(WDIE); } void sendRC(unsigned long data) { // Отправка данных по радиоканалу RCswitch. Двоичный протокол DDRB |= _BV(RC_BIT); data |= 3L << 20; // ? unsigned short repeats = 1 << (((unsigned long)data >> 20) & 7); data = data & 0xfffff; unsigned long dataBase4 = 0; uint8_t i; for (i = 0; i < 20; i++) { dataBase4 <<= 1; dataBase4 |= (data % 2); data /= 2; } unsigned short int j; for (j = 0; j < repeats; j++) { data = dataBase4; uint8_t i; for (i = 0; i < 20; i++) { switch (data & 1) { case 0: PORTB |= _BV(RC_BIT); _delay_us(periodusec); PORTB &= ~_BV(RC_BIT); _delay_us(periodusec * 3); break; case 1: PORTB |= _BV(RC_BIT); _delay_us(periodusec * 3); PORTB &= ~_BV(RC_BIT); _delay_us(periodusec); break; } data >>= 1; } PORTB |= _BV(RC_BIT); _delay_us(periodusec); PORTB &= ~_BV(RC_BIT); _delay_us(periodusec * 31); } } // OneWire функции: void OneWireReset() { PORTB &= ~_BV(DS_BIT); DDRB |= _BV(DS_BIT); _delay_us(500); DDRB &= ~_BV(DS_BIT); _delay_us(500); } void OneWireOutByte(uint8_t d) { uint8_t n; for (n = 8; n != 0; n--) { if ((d & 0x01) == 1) { PORTB &= ~_BV(DS_BIT); DDRB |= _BV(DS_BIT); _delay_us(5); DDRB &= ~_BV(DS_BIT); _delay_us(60); } else { PORTB &= ~_BV(DS_BIT); DDRB |= _BV(DS_BIT); _delay_us(60); DDRB &= ~_BV(DS_BIT); } d = d >> 1; } } uint8_t OneWireInByte() { uint8_t d, n, b; for (n = 0; n < 8; n++) { PORTB &= ~_BV(DS_BIT); DDRB |= _BV(DS_BIT); _delay_us(5); DDRB &= ~_BV(DS_BIT); _delay_us(5); b = ((PINB & _BV(DS_BIT)) != 0); _delay_us(50); d = (d >> 1) | (b << 7); } return (d); } word GetTemp() { uint8_t DSdata[2]; OneWireReset(); OneWireOutByte(0xcc); OneWireOutByte(0x44); PORTB |= _BV(DS_BIT); DDRB |= _BV(DS_BIT); unsigned long delp = millis(); while ((millis() - delp) <= 1000); //_delay_ms(1000); // если хотим ждать когда датчик посчитает температуру. DDRB &= ~_BV(DS_BIT); PORTB &= ~_BV(DS_BIT); OneWireReset(); OneWireOutByte(0xcc); OneWireOutByte(0xbe); DSdata[0] = OneWireInByte(); DSdata[1] = OneWireInByte(); word TReading = (word)(DSdata[1] << 8) + DSdata[0]; if ((word)(TReading & 0x8000) == (word)(0x8000)) { TReading = (~TReading) + (word)1; TReading = (((word)6 * TReading) + TReading / (word)4) / (word)10; } else { TReading = (((word)6 * TReading) + TReading / (word)4) / (word)10 + (word)2000; } return TReading; }а вот вариант правильного получения температуры на Attiny85 и DS18B20 с последующей отправкой по Software UART, соотвественно достаточно дорисовать отправку по радиоканалу и протестировать...никак руки не дойдут.
#include <avr/sleep.h> #include <avr/wdt.h> #include <OneWire.h> #include "SoftwareSerial.h" #ifndef cbi #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) #endif #ifndef sbi #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) #endif #define ds_pin PB3 // this is physical pin 2 OneWire ds18b20(ds_pin); #define rx_pin PB3 // this is physical pin 2 #define tx_pin PB4 // this is physical pin 3 SoftwareSerial pcSerial(rx_pin, tx_pin /* out data */); void setup () { } void loop () { initPins(); showTemp(); offPins(); toSleep(); } word getTemp() { word errTemp = 1111; byte dsData[9]; ds18b20.reset(); ds18b20.write(0xCC); ds18b20.write(0x44); delay(1000); ds18b20.reset(); ds18b20.write(0xCC); ds18b20.write(0xBE); for (byte i = 0; i < 9; i++) dsData[i] = ds18b20.read(); if (OneWire::crc8(dsData, 8) != dsData[8]) return errTemp; word outTemp = (word)(dsData[1] << 8) + dsData[0]; if ((word)(outTemp & 0x8000) == (word)(0x8000)) { outTemp = (~outTemp) + (word)1; outTemp = (((word)6 * outTemp) + outTemp / (word)4) / (word)10; } else { outTemp = (((word)6 * outTemp) + outTemp / (word)4) / (word)10; if (outTemp == 0) return errTemp; outTemp += (word)2000; } return outTemp; } void initPins() { digitalWrite(tx_pin, HIGH); pinMode(tx_pin, OUTPUT); pcSerial.begin(9600); } void offPins() { digitalWrite(PB0, LOW); pinMode(PB0, INPUT); digitalWrite(PB1, LOW); pinMode(PB1, INPUT); digitalWrite(PB2, LOW); pinMode(PB2, INPUT); digitalWrite(PB3, LOW); pinMode(PB3, INPUT); digitalWrite(PB4, LOW); pinMode(PB4, INPUT); } ISR (WDT_vect) { wdt_disable(); // disable watchdog } void toSleep() { cbi(ADCSRA, ADEN); // switch Analog to Digitalconverter OFF setup_watchdog(9); wdt_reset(); // pat the dog set_sleep_mode (SLEEP_MODE_PWR_DOWN); noInterrupts (); // timed sequence follows sleep_enable(); sleep_bod_disable(); interrupts (); // guarantees next instruction executed sleep_cpu (); // cancel sleep as a precaution sleep_disable(); } // 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms // 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec void setup_watchdog(int ii) { byte bb; int ww; if (ii > 9 ) ii = 9; bb = ii & 7; if (ii > 7) bb |= (1 << 5); bb |= (1 << WDCE); ww = bb; MCUSR &= ~(1 << WDRF); // start timed sequence WDTCR |= (1 << WDCE) | (1 << WDE); // set new watchdog timeout value WDTCR = bb; WDTCR |= _BV(WDIE); } void showTemp() { word currT = getTemp(); if (currT == 1111) { pcSerial.println("Error get temp."); return; } pcSerial.print("Current temp = "); if (currT < 2000) pcSerial.print("-"); else currT -= 2000; pcSerial.print((currT / 10), DEC); pcSerial.print("."); pcSerial.print((currT % 10), DEC); pcSerial.println(" `C"); }Сейчас замерил потребление своего утсройства)
Режим глубокого сна: 0.0056 мА
Режим работы: 0.1254 мА
При срабатывании раз в минуту, и длительностью работы 500мс, устройство проживет 1288.86 дня, или 3.53 года. от батарейки CR2032
Невероятно!
Калькулятор
А если морозы учесть ;)?
У меня на совсем китайской cr2032 за 12 рублей отработало на улице 9 месяцев. Поставил в октябре varta батарейки, посмотрим...на сколько хватит.
Я правильно понял, обычная часовая батарейка на 3В?
А как питание организовано? Можно схему посмотреть?
И как организован спящий режим?
А как питание организовано? Можно схему посмотреть?
плюс батарейки на VCC контроллера, минус - на GND
А если тему почитать? - там же все ответы есть. Совсем уже обленились