радио пульт с максимальной энергоавтономностью
- Войдите на сайт для отправки комментариев
Здравствуйте форумчане, хотел показать скетч, что я написал, я понимаю, что мой скетч дал мне некую экономию батарейки, но я знаю, что можно сделать еще лучше. Имеются предположения по данному вопросу.
Опишу ситуацию сначала, в своем доме решил для упрощения жизни поставить на насос радио реле, насос используется для накачки воды в различные резервуары(баня и тд). Захотелось сделать обычный пульт на ардуино. Да можно просто вскрыть пульт и припаятся к кнопке если такова одна. На уже имеющемся не хотелось ничего портить паяльником (из личного опыта, из трех пультов смог только на двух сделатьэто, на третьем явно накосячил, только хз, либо из-за того что сместил smd конденсатор, те пульт по выведенной отдельно кнопке то отсылает то нет сигнал(батареи меняю, без разницы), то меняю то нет)
еще ненмого предыстории
Была задача, сделать простой штатный включатель выключатель(по радио), но чтобы все это было полностью автономным. Начал изучать интернет, на готовые варианы. Однозначного ответа я не получил. Сначала натолкнулся на статью https://sites.google.com/site/vanyambauseslinux/arduino/ispolzovanie-preryvanij-arduino , да много чего не понятного, такты какие-то ардуина и куча переферии на ней, прерывания какие-то(до этого у меня за плечами только курс из 5ти уроков Джереми Блюма). Из всего этого меня удивило, что led на ардуине отвечающий за питание, вобщее никак не отключить(все и везде рекомендуют ради примерно 2мА спиливать его, я это еще не делал) и это как-то сыровато(по смыслу). В итоге в статье , на которую я дал ссылку, имеется подстатья со следующей темой: "Пробуждение Arduino из спящего режима по нажатию кнопки", вроде что нужно
#include <ve_avr.h> // Будет использоваться библиотека VEDuino. //#include <RemoteSwitch.h> // это скачанная библиотека //#include <RemoteReceiver.h> #define LEDPIN 12 // Вывод светодиода #define BTNPIN 2 // Вывод кнопки #define LEDPI 13 #define PERIOD 246; boolean onoff = LOW; volatile int counnt = 0; // Переменная счётчика (volatile означает указание компилятору не оптимизировать код её чтения, // поскольку её значение изменяется внутри обработчика прерывания) ISR(INT0_vect) // Функция обработки прерывания INT0 { counnt = 25; // Инициализировать счётчик } void setup() { // Serial.begin(9600); pinMode(LEDPI, OUTPUT); pinMode(LEDPIN, OUTPUT); // Вывод светодиода в режим вывода pinMode(BTNPIN, INPUT); // Вывод кнопки в режим ввода digitalWrite(LEDPIN, LOW); DEV_EXTINTCTRL.setSenseType0(ExtIntControl::RISING_EDGE); // Прерывание INT0 в режиме переднего фронта (в данном случае при нажатии на кнопку) DEV_EXTINTFLAGS.enableInterrupt0(); // Разрешить прерывание INT0 interrupts(); // Разрешить прерывания глобально } void loop() { //interrupts(); if(counnt==0) { //delay(10); digitalWrite(LEDPIN, LOW); // Выключить светодиод, если счётчик равен 0... // Serial.print("VIKl"); // Serial.println(""); DEV_SLEEP.setMode(SleepControl::PWR_DOWN); // Выбор режима сна DEV_SLEEP.enableSleep(); // Разрешить переход в спящий режим sleep(); // Переход в режим сна //Serial.println(""); } //Serial.print("VIKl"); else { //delay(10); delay(10); //if (digitalRead(BTNPIN) == HIGH) { //Serial.println(""); while (digitalRead(BTNPIN) == HIGH ) { digitalWrite(LEDPIN, HIGH); // ... иначе включить светодиод, if (onoff == LOW) { //Serial.println(" on "); //transmit(477522); } else { //Serial.println(" off "); //transmit(477495); } //Serial.println(""); //delay (500); } //} //else { counnt = 0; if (onoff == LOW) onoff = HIGH; else onoff = LOW; } //delay (1000); //} //--count; // и уменьшить счётчик на 1. //delay(10); // Подумать 10 милисекунд. } /* void transmit(unsigned long rcode){ unsigned long code = rcode; unsigned long period = PERIOD; //for (unsigned long period=1; period <= 469; period++) //{ //delay(1000); //Serial.print("period: " ); //Serial.print( period); code |= (unsigned long)period << 23; code |= 4L << 20; //(|= 4L) цифра перед (L), это (условное число), количества повторов посылаемого сигнала. (соответственно и паузы) RemoteSwitch::sendTelegram(code, 9); // RF transmitter pin - пин радио передатчика } */в таком варианте вся балалайка работает(светодиод горит, пока нажата кнопка, отпускаю уходит в сон), смотрел мультиметром(правда он показывал только изменения в сотых А, тысячных увы нет), как видно из кода я пытался прикрутить отправку кодов ридиопульта(все что в коментах), но при инициализации библиотеки #include <RemoteSwitch.h>, появилась ошибка , без понятия, как ее устранить
ошибка :
Я думал, сразу написать о своей проблеме на форуме, но интуиция мне подсказывала, что вообще никто коктрено не поможет, различные манипуляции со скетчем, никак не влияло на ошибку, стало понятно, что конфликт библиотек скорее всего. Решил найти еще приближенные скетчи по данной теме. Наткнулся на видео http://playground.arduino.cc/Learning/arduinoSleepCode , которое ссылалось на статью http://http://playground.arduino.cc/Learning/arduinoSleepCode, где я взял скетч:
#include <avr/sleep.h> #include <RemoteSwitch.h> #define PERIOD 246; int wakePin = 2; // pin used for waking up int sleepStatus = 0; // variable to store a request for sleep int count = 0; // counter int dd = 0; void wakeUpNow() // here the interrupt is handled after wakeup { } void setup() { pinMode(wakePin, INPUT); pinMode(13, OUTPUT); digitalWrite(13, LOW); attachInterrupt(0, wakeUpNow, HIGH); // use interrupt 0 (pin 2) and run function // wakeUpNow when pin 2 gets LOW } void sleepNow() // here we put the arduino to sleep { set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here sleep_enable(); // enables the sleep bit in the mcucr register // so sleep is possible. just a safety pin attachInterrupt(0,wakeUpNow,HIGH); // use interrupt 0 (pin 2) and run function // wakeUpNow when pin 2 gets LOW sleep_mode(); // here the device is actually put to sleep!! // THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP sleep_disable(); // first thing after waking from sleep: // disable sleep... detachInterrupt(0); // disables interrupt 0 on pin 2 so the // wakeUpNow code will not be executed // during normal running time. } void loop() { /* if (dd == 1) { transmit(477522); dd =0; } else { transmit(477495); dd = 1; } */ /* if (dd == 1) { transmit(366776); dd =0; } else { //transmit(477495) transmit(366776); dd = 1; } */ if (dd == 1) { transmit(51786); dd =0; } else if (count > 0) { transmit(51759); dd = 1; } //delay(1000); // waits for a second delay(100); // this delay is needed, the sleep //function will provoke a Serial error otherwise!! count++; sleepNow(); // sleep function called here //} } void transmit(unsigned long rcode){ unsigned long code = rcode; unsigned long period = PERIOD; //for (unsigned long period=1; period <= 469; period++) //{ //delay(1000); //Serial.print("period: " ); //Serial.print( period); code |= (unsigned long)period << 23; code |= 4L << 20; //(|= 4L) цифра перед (L), это (условное число), количества повторов посылаемого сигнала. (соответственно и паузы) RemoteSwitch::sendTelegram(code, 9); // RF transmitter pin - пин радио передатчика }данный код работает хорошо, нажал на кнопку отправился код на радиореле и ардуина ушла в сон, нажал повторно, ардуиона послала другой код. Те получил и экономию энергии и отправку на реле, осталось только прикрутить чтобы на втором пине, прерывание работало при 0 и при 1 , те подал 5ть вольт на второй пин, отправился один код и сон наступил сразу, разомкнул выключатель подал 0 на пин2 и чтобы послался другой код и наступил опять сон, над этим я еще думаю. В рабочем коде я использовал тактовую кнопку, вот не ясно для выключателя(включателя) нужен ли будет резистор стягивающий, наверное нет(хотя я хз насчет дребезга в данном случае). Но не это меня пока волнует, как достигнуть еще большей экономии энергии , так как в статье откуда я взял код, потребление энергии под 10 мА, при всей экономии.
Нашел статью, как можно перевести на потребление 6 мкА http://robotosha.ru/arduino/arduino-interrupts.html
а именно
#include <avr/sleep.h> #include <avr/wdt.h> #define LED 13 // процедура обработки прерывания по нажатию кнопки void wake () { wdt_disable(); // отключаем сторожевой таймер } // прерывание сторожевого таймера ISR (WDT_vect) { wake (); } void myWatchdogEnable (const byte interval) { noInterrupts (); MCUSR = 0; // сбрасываем различные флаги WDTCSR |= 0b00011000; // устанавливаем WDCE, WDE WDTCSR = 0b01000000 | interval; // устанавливаем WDIE, и соответсвующую задержку wdt_reset(); byte adcsra_save = ADCSRA; ADCSRA = 0; // запрещаем работу АЦП power_all_disable (); // выключаем все модули set_sleep_mode (SLEEP_MODE_PWR_DOWN); // устанавливаем режим сна sleep_enable(); attachInterrupt (0, wake, LOW); // позволяем заземлить pin 2 для выхода из сна interrupts (); sleep_cpu (); // переходим в сон и ожидаем прерывание detachInterrupt (0); // останавливаем прерывание LOW ADCSRA = adcsra_save; // останавливаем понижение питания power_all_enable (); // включаем все модули } void setup () { digitalWrite (2, HIGH); // кнопка с подтягивающим резистором } void loop() { pinMode (LED, OUTPUT); digitalWrite (LED, HIGH); delay (5000); digitalWrite (LED, LOW); delay (5000); // шаблон битов sleep: // 1 секунда: 0b000110 // 2 секунды: 0b000111 // 4 секунды: 0b100000 // 8 секунд: 0b100001 // засыпаем на 8 секунд myWatchdogEnable (0b100001); // 8 секунд } «Голая» плата, то есть без регулятора напряжения, USB-интерфейса и прочего, с запущенным на ней приведенным выше кодом, потребляет: Со светящимся светодиодом — 19.5 мА При включенном светодиоде — 16.5 мА В режиме сна — 6 мкА Использование сторожевого таймера в комбинации с режимом сна может сберечь значительное количество энергии во время периодов, когда процессор может быть не нужен. Это также иллюстрирует, что можно выйти из режима сна двумя различными способами. Один из них — нажатие клавиши (то есть заземление пина D2), другой — это периодическое просыпание (каждые 8 секунд), хотя вы можете сделать это каждые 1, 2, 4 или 8 секунд (возможно, даже короче, но для этого нужно подробнее изучить техническое руководство на микроконтроллер). После того, как процессор проснулся, возможно, потребуется некоторое время, чтобы стабилизировать свой таймер. Например, вы можете увидеть «мусор» на последовательном порту, пока он синхронизируется. Если это проблема есть, вы можете установить короткую задержку после выхода из режима сна. Замечание по-поводу определения пониженного напряжения: полученные выше цифры получены с отключенным определением пониженного напряжения (brownout detection). Для создания опорного напряжения для определения пониженного напряжения требуется небольшой ток. Если его включить, то в режиме сна будет потребляться около 70 мкА (вместо 6 мкА). Одним из способов выключить определение пониженного напряжения является использование компилятора avrdude из командной строки: avrdude -c usbtiny -p m328p -U efuse:w:0x07:m 1 avrdude -c usbtiny -p m328p -U efuse:w:0x07:m При помощи параметров устанавливается efuse (дополнительные фьюзы) равным 7, что отключает определение пониженного напряжения. Здесь предполагается, что используется программатор USBtinyISP.осталось тока срастить что значит «Голая» плата, то есть без регулятора напряжения, сколько напряжения подавать на ардуино и как сделать функционал на обычый включатель выключатель