Передача температуры с датчиков DHT11, DS18B20 через NRF24L01.
- Войдите на сайт для отправки комментариев
Предстоит оснащать дом умной электроникой, который будет скоро построен :).
Начал осваивать основы. Пока сделал обмен данными между блоками на ардуино через модуль NRF24L01. Обмен работает через команды и ответы (структуры AS_Command и AS_Answer): один блок посылает другому команду, а тот отвечает ему. Данные о датчиках храняться в стуртуре AS_SensorStatus. Пока сделал передачу данных с подключенных к комнатному блоку DHT11 и DS18B20 на главный блок и отображение главном блоке на 20х4 символьном LCD. Комнатный блок переходит в спящий режим после передачи данных для экономии потребления. Просыпается при получении запроса на NRF24L01, подключен как в примерах MISO -> 12, MOSI -> 11, SCK -> 13, CE -> 8, CSN -> 7, IRQ -> 2.
Сам еще только начинаю осваивать, поэтому комментарии по кривости реализации приветствуются. Работает ли режим энергосбережения пока не знаю, не уверен, но теоретически должен.
Вот файл ASLibrary.h с описанием структур:
#ifndef __ASLibrary__ #define __ASLibrary__ #define AS_NRF24L01_payload 5 //Максимальный размер буфера в байтах для трансивера NRF24L01 //должен буть не меньше максимальной длины передаваемых данных //и не больше 32 (стркутуры _AS_COMMAND и _AS_ANSWER) // Команды состоят из 1 команды и 1 параметра // 1 x - Получить количество датчиков // 2 x - Выполнить измерение по всем датчикам (записать в глобальные переменные, пока не принимать) // 3 N - Выполнить измерение по датчику N (записать в глобальные переменные, пока не принимать) // 4 N - Получить данные с датчика N (считать из глобальных переменных) typedef struct _AS_COMMAND { byte Command; //Команда byte Parametr; //Параметр }AS_Command; // Ответы состоят из 1 статуса и 1 значения // 0 x - Ошибка // 1 N - Данные переданы корректны, N значение typedef struct _AS_ANSWER { byte Status; //Статус float Value; //Значение }AS_Answer; // Состояние датчиков // 0 x - Ошибка // 1 N - Данные актуальны, значение N typedef struct _AS_SENSORSTATUS { byte Status; //Статус float Value; //Значение }AS_SensorStatus; #endif // __ASLibrary__
вот скетч приеника (главного бока):
#include <SPI.h> #include <Mirf.h> #include <ASLibrary.h> #include <nRF24L01.h> #include <MirfHardwareSpiDriver.h> #include <LiquidCrystal.h> // initialize the library with the numbers of the interface pins LiquidCrystal lcd(6, 9, 2, 3, 4, 5); void setup(){ Serial.begin(9600); Mirf.spi = &MirfHardwareSpi; Mirf.init(); Mirf.setRADDR((byte *)"main");// Устанавливаем адрес, под которым будем принимать данные Mirf.payload = AS_NRF24L01_payload; Mirf.config(); lcd.begin(20, 4); Serial.println("Beginning ... "); } //Рассчитывает все показания на устройстве с именем addr byte CalculateAllParametr(char *addr){ AS_Command MyCommand; // Команда AS_Answer MyAnswer; // Ответ unsigned long time; // Время для отслеживания таймаута при запросе данных Mirf.setTADDR((byte *)addr); //Устанавливаем адрес, окуда считываем данные MyCommand.Command = 2; MyCommand.Parametr = 0; Mirf.send((byte *)&MyCommand); while(Mirf.isSending()){ } //delay(10); time = millis(); while(!Mirf.dataReady()){ if ( ( millis() - time ) > 3000 ) { Serial.println("Timeout on response from server!"); return 0; } } Mirf.getData((byte *) &MyAnswer); if (MyAnswer.Status == 0){ Serial.print("Error calculate all values on "); Serial.println(*addr); return 0; } else{ Serial.print("Calculate all values OK on "); Serial.println(addr); return 1; } } //Получает параметр номер Num с утройства с именем addr float GetParametr(char *addr, byte Num){ AS_Command MyCommand; // Команда AS_Answer MyAnswer; // Ответ unsigned long time; // Время для отслеживания таймаута при запросе данных Mirf.setTADDR((byte *)addr); //Устанавливаем адрес, окуда считываем данные MyCommand.Command = 4; // Получить данные с датчика N MyCommand.Parametr = Num; Mirf.send((byte *)&MyCommand); while(Mirf.isSending()){ } //delay(10); time = millis(); while(!Mirf.dataReady()){ if ( ( millis() - time ) > 3000 ) { Serial.println("Timeout on response from server!"); return 0; } } Mirf.getData((byte *) &MyAnswer); if (MyAnswer.Status == 0){ Serial.print("Error when getting data from "); Serial.println(addr); } else{ Serial.print("Get data OK, from: "); Serial.print(addr); Serial.print(" parametr: "); Serial.println(Num); return MyAnswer.Value; } } void loop(){ //AS_SensorStatus h; //Состояние датчика влажности DHT11 //AS_SensorStatus t; //Состояние датчика температуры DHT11 //AS_SensorStatus ds_t; //Состояние датчика температуры DS18B20 char *addr = "hall"; float t,t1,h; if (CalculateAllParametr(addr) == 1) { t = GetParametr(addr, 2); Serial.print("Temperature DS1820: "); Serial.print(t); Serial.println(" *C"); t1 = GetParametr(addr, 0); Serial.print("Temperature DHT11: "); Serial.print(t1); Serial.println(" *C"); h = GetParametr(addr, 1); Serial.print("Humidity DH11: "); Serial.print(h); Serial.println(" %"); Serial.println(""); lcd.setCursor(0, 0); lcd.print("Temp DS1820: "); lcd.setCursor(0, 1); lcd.print("Temp DHT11: "); lcd.setCursor(0, 2); lcd.print("Humid DHT11: "); lcd.setCursor(13, 0); lcd.print(t); lcd.setCursor(13, 1); lcd.print(t1); lcd.setCursor(13, 2); lcd.print(h); lcd.setCursor(19, 0); lcd.print("C"); lcd.setCursor(19, 1); lcd.print("C"); lcd.setCursor(19, 2); lcd.print("%"); } delay(10); }
Вот скетч передатчика (блока в комнатах):
#include <SPI.h> #include <DHT.h> #include <Mirf.h> #include <ASLibrary.h> #include <MirfHardwareSpiDriver.h> #include <avr/sleep.h> #include <OneWire.h> AS_SensorStatus MySensors[3]; DHT dht(3, DHT11); //Создаем датчик DHT11 на 3 пине OneWire ds(5); //Создаем датчик DS18B20 на 5 пине void wakeupFunction(){ } void toSleep(){ attachInterrupt(0,wakeupFunction,LOW); sleep_mode(); detachInterrupt(0); } void setup() { //Serial.begin(9600); dht.begin(); //Инициализируем датчик DHT MySensors[0].Status = 0; MySensors[1].Status = 0; MySensors[2].Status = 0; Mirf.spi = &MirfHardwareSpi; Mirf.init(); Mirf.setRADDR((byte *)"hall"); //Задаем адрес под которым будем принимать данные Mirf.payload = AS_NRF24L01_payload; //Задаем размер буфера данных Mirf.config(); //Инициализируем модуль NRF24L01 set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_enable();//Переходим в спящий режим } //Возвращает значение температуры с датчика 18B20 float Get_18B20_Data(){ byte DSdata[2]; ds.reset(); ds.write(0xCC); ds.write(0x44); delay(1000); ds.reset(); ds.write(0xCC); ds.write(0xBE); DSdata[0] = ds.read(); DSdata[1] = ds.read(); int Temp = (DSdata[1] << 8) + DSdata[0]; return (float) Temp / 16; } //Вычисляет все данные и заполняет массив значений датчиков byte CalculateAllData() { float t, h; t = dht.readTemperature(); h = dht.readHumidity(); if (isnan(t) || isnan(h)) { MySensors[0].Status = 0; MySensors[0].Value = 0; MySensors[1].Status = 0; MySensors[1].Value = 0; } else { MySensors[0].Status = 1; MySensors[0].Value = t; MySensors[1].Status = 1; MySensors[1].Value = h; } MySensors[2].Status = 1; MySensors[2].Value = Get_18B20_Data(); return 1; } AS_Answer ExecuteCommand(AS_Command MyCommand){ AS_Answer MyAnswer; // Ответ MyAnswer.Status = 0; MyAnswer.Value = 0; switch (MyCommand.Command) { case 2: //Рассчитать все значения датчиков MyAnswer.Status = CalculateAllData(); case 4: //Получиь значение датчика по номеру MyAnswer.Status = MySensors[MyCommand.Parametr].Status; MyAnswer.Value = MySensors[MyCommand.Parametr].Value; } return MyAnswer; } void loop() { AS_Command MyCommand; // Команда AS_Answer MyAnswer; // Ответ if(!Mirf.isSending() && Mirf.dataReady()){ //Serial.println("111"); Mirf.getData((byte *) &MyCommand); MyAnswer = ExecuteCommand(MyCommand); Mirf.setTADDR((byte *) "main"); Mirf.send((byte *) &MyAnswer); } else{ /* No data - night night. */ toSleep(); } }
Видимо, делаю что-то похожее ;) предлагаю объединить усилия...
У Вас работает только один приемник и один передатчик? я правильно понял?
я пошел пока малость по другому пути - есть несколько беспроводных блочков (один типа "внешний" (датчик DHT22), другой "внутренний" (соответственно DHT11, RTC)) и пока один приемник (принимать данные и пока их просто гнать в последовательный порт).
Передатчики работают самостоятельно (просто молотят в эфир свои данные в виде форматированных строк). Каждый из них работает в собтвенном режиме (там, где блок RTC - частота посылок около 2Гц, там где датчик DHT22 - одна посылка в 2 минуты).
Приемником пока удается принимать сигналы только одного передатчика, как заставить работать два сразу - пока не придумал: http://arduino.ru/forum/programmirovanie/nrf24l01#comment-9100
Хотя, если пойти по Вашему пути, то все будет, видимо, проще...
Видимо, делаю что-то похожее ;) предлагаю объединить усилия...
У Вас работает только один приемник и один передатчик? я правильно понял?
Не совсем так. У меня на ведущем и на ведомом стоит трансивер, т.е. приемник-передатчик. Ведомое устройство "слушает" эфир, работает на прием. Когда к нему (они имеют свой адреса, например "hall", "Room1") обращается ведущее устройство(имеет имя "Main", работает в этот момент передатчиком) ведомое отрабатывает команду. После отправки команды ведущее устройство переключается на прием и ждет ответ от ведомого. Ведомое получив команду производит действия, и отправляет ответ, переключившись на передачу.
В качестве ведущего пока используется ардуино уно, потом заменю на мегу, т.к. не хватает каналов на все задумки. Сейчас подключены трансивер, дисплей LCD 20х4, 4 кнопки. Еще надо подключить часы, SD карту. Еще думаю надо 485 подключать.
Ведомые сделаны на ардуино нано. Пока реализован 3 команды, которые отрабатываются ведомым при получении команды с ведущего: 1 – Получить количество датчиков, 2 – выполнить измерение по всем датчикам, 4 – получить данные с датчика N. Измерение и получение разделены т.к. некоторые датчики долго отрабатывают измерение, DS18B20 1 сек измеряет температуру, поэтому производится измерение и записываются в массив показаний датчиков, а потом можно быстро получать несколько раз данные из этого массива.
Дальше планирую добавить команду 3 - измерить данные на датчике N, добавить работу с исполнительными устройствами.
Посмотрел вашу ссылку, если хочется постояно измерять, то можно измерять с нужной периодичностью и записывать в перменные и выдавать данные из переменных по запросу от главного-ведущего устройства. Я же делал измерение по запросу потому что хотел использовать режим пониженого потребления, Нано у меня "засыпает" после передачи данных, просыпается когда приходят запрос на нее. Кстати, DHT11 температуру меряет ужасно, у него погрешность +-2С. Только для влажности их буду использовать раз уж взял. На практике бывает расхождение больше 3С с DS18B20, но он тоже не идеал, может погрешности сложились, надо будет потом несколько штук одновременно подключить и сравнить среднее.
Сейчас дописал примитивные функции для работы с кнопками и менюшками на LCD. Типа по меню кнопками выбираешь Display-hall и выводит на LCD показания датчиков c устройства с именем "hall". Если кому интересно выложу в таком виде. Попозже выложу с работой с исполнительными механизмами, хочу реализовать давюю задумку - автозакрытие закрытие окон если дома светлее чем на улице, автоокрытие по часам (если успеет Мега прийти, а то на часы не осталось каналов) или через меню на LCD, или с универсального пульта по ИК, а то так ломает шторы каждый день открывать - закрывать, пролазия через горшки с цветами. Уже подключил шаговик к Нано через ULN2003, который киндер выковырял из найденной на помойке печ. машинки. Тогда ругался на него, что собирает всякую грязь, а тут пригодился. Осталось механику сделать.
Сергей, очень интересно! Я только что повторил ваш код и заставил работать его у себя (с соответствующими правками).
Теперь я могу с центрального блока опрашивать все датчики и в том темпе, что мне нужно. А когда заставлю спящий режим работать - так вообще красота будет.
Работает все, за исключением спящего режима. Помогите с ним разобраться?
Вопрос - на какую ногу микроконтроллера у вас идет контакт IRQ от трансивера?
Еще у меня трансиверы есть в двух вариантах: с внешней антенной и без нее.
Вроде как все идентично, но замечено следующее: несмотря на то, модуль по документации толерантен к 5В выходам ардуино (питается, естественно, 3.3В), модули с внешней антенной спокойно работают в 5В режиме.. а вот модули со встроенной антенной работают крайне нестабильно - 2-5 посылок и "вешаемся". При этом, если переключить режим работы с 5В на 3.3В (на сидуинах у меня есть такой переключатель на платке) - все модули работают стабильно (по некольку суток гонял - все работает четко).
Хотелось бы узнать, как Вы подключаете эти модули к своим платкам?
Про DHT11 хорошо предупредили - тоже сделаю его только датчиком влажности (пару штук купил), а температуру буду спрашивать с DS18B20.
Кстати, есть неплохой датчик DHT22 - работает от -40*С и точность выше существенно (его буду использовать для наружного датчика).
Еще маленькая идейка - подключать часы не к "центральному блоку", а к одному из внутренних (благо, там с "ногами" свободными проблем нет) и использовать их как еще несколько "датчиков" (часы, минуты, секунды, день недели и т.п.). На центральном блоке - только отображать. У себя сейчас так и реализую.
В своей системе я хочу замутить еще управление газовым котлом (термостат) и кондиционером... Еще с женой подумали над системой автоматического полива растений (пока на балконе, дальше - посмотрим).. Аквариум, опять же, пока не автоматизированный ;))) Простую систему управления жалюзи (отдельную) я уже реализовал (вот тут в конце результат: http://arduino.ru/forum/apparatnye-voprosy/strannost-v-povedenii-kontrollera), правда, требуется доработка...
Спасибо большое за код и направление мысли - ОЧЕНЬ помогло и поставило мозги на место :) Ваш подход несомненно лучше использует железо и более гибко может подстраиваться под логику.
Выкладывайте, что получается :) думаю, не мне одному это интересно.
Питание 3.3 в. беру с ардуино.
Прерывание подключено к 2 цифровому входу (в первом посте указал IRQ -> 2 ).
Most Arduino boards have two external interrupts: numbers 0 (on digital pin 2) and 1 (on digital pin 3)
attachInterrupt(0,wakeupFunction,LOW);
"0" - соотвественно подключает прерывание по pin 2
Вообще я хочу на окна поставить рулонные шторы с направлюющими, они почти не заметны на окне. В магизинах пока попадались только без направляющих - такие не нужны. Жалюзи взял т.к. дешевые попались под руку 0.7х1.2 ~400 р., взял пару на "попробовать". Я на жалюзях хочу сделать подЪем и опускание, чтобы полностью убирались. Если делать открытие поворотом, то можно по фоторезистору отслеживать максимальное освещение, т.к. из-за движения солнца оптимальный угол открытия будет меняться. Все равно хотел внутрь и наружу поставить по фоторезистору на каждую комнату.
Сергей, а у Вас стабильно работает?
Сегодня с утра, пока "главный модуль" и "дочка" были на столе - все работало нормально.
Днем поставил в более-мнее боевые условия (хотя все-таки в "менее" - всего-то несколько метров между модулями) и получаю массу ошибок "Timeout on response from out1"...
Причем, если я пытаюсь опрашивать по очереди сначала одну "дочку", а затем - вторую, количество ошибок увеличивается (такое ощущение, что модули мешают друг-другу работать.. опрашиваю, правда, при прохождении одного цикла... видимо, надо как-то по времени запросы разделять (как разделять понятно.. просто пока писал - возможно, нашел причину нестабильности)...
Сергей, а у Вас стабильно работает?
Пока нет возможности проверить. Основная работа совсем не связанна с электроникой. Это так, хобби. Времени на хобби получается выделить 2-3 часа в неделю, поэтому это дело идет медленно. Может на следующие длинные выходные разберусь как прошивать Atmega и соберу на отдельных МК, протестирую если время выдастся, а то сейчас только 2 МК для отладки - 1 уно и 1 нано.
А мешать друг-другу модули теоретически не должны если они на прием работают. Возможно действительно нужно поставить задержку между опросами.
Сергей, если будет возможность - попробуйте подольше потестировать (сутки, двое) с периодом опроса 2-5 минут... У меня пока стабильность сильно хромает (и я пока даже не представляю, как найти "узкое" место).
Еще сейчас провожу ревизию Вашего кода - есть некоторые замечания (может, обменяемся контактами, чтобы в личной переписке обсудить?).
... чтобы в личной переписке обсудить?).
Не не, нам тоже интересно.
Сергей, если будет возможность - попробуйте подольше потестировать (сутки, двое) с периодом опроса 2-5 минут... У меня пока стабильность сильно хромает (и я пока даже не представляю, как найти "узкое" место).
Еще сейчас провожу ревизию Вашего кода - есть некоторые замечания (может, обменяемся контактами, чтобы в личной переписке обсудить?).
Как время появится, так обязательно подольше потестирую.
Код вполне возможно сильно корявый, я на С уже лет 10 не писал, со времен института. Это так сказать проба пера, то чтос первого раза получилось. Поэтому критика кода приветствуется. Я уже сам нашел несколько косяков, немного поправил всякие указатели, массивы. Но как уже писал, времени катострофически не хватает на хобби, поэтому обновления кода могу делать раз в неделю, не чаще.
Покажите, что получилось на текущий момент?
Код "Непричесанный", комментариев нет, и т.д., в каком виде был когда оторвали семейные дела от развлечений. Но рабочий. Добавлена работа с менюшками на LCD, вывод на LCD показаний датчиков из выбранного в меню блока(комнаты). Рассчитано на дисплей 20х4. Выбор пункта меню кнопками - 1 пункт - 1-я кнопка и т.д. Задействованы пока 3 кнопки.
ASLibrary.h
Ведомый блок
Ведущий блок
Сергей, помогите разобраться...
Модифицировал код под себя немного.
Файл ASLibrary1.h (исправлений минимум - добавлен канал, убрал меню):
файл для "ведомого" блока (тут тоже минимум изменений - датчик DS заменен на аналоговый, добавлен канал для трансивера, общие команды для трансивера выведены в функцию setup):
Файл для "главного" блока (у меня OLED дисплей через i2c - поэтому чуток другой вывод, но суть не меняется, другие незначительные изменения):
и вот в этом файле как раз "непонятка": в строке 126 должен печататься комментарий к датчику (Сергей, отличная мысль этот комментарий отдавать!)... но не печатается.. выдается какой-то мусор на дисплее :(
Подскажите, в чем проблема?... код "ведомого" и "главного" - максимально близок к Вашему (в части этого комментария), но не работает... а у Вас работает нормально?
Еще вопросы по задержкам (по коду) - как получили значения и догадались, что они там нужны? (кстати, от некоторых можно избавиться - те, что закоментированы у меня, а вот от секундной задержки в скетче для главного блока избавитья нельзя - сразу начинают идти недостоверные данные и т.п.).
Кстати... я тут еще одни "грабли" нашел... Помните, я говорил, что начинаются ошибки (и вообще прекращается нормальная работа модулей), если "главный" один, а "ведомых" несколько?
Сегодня экспериментировал (типа, один блок центральный и два - "ведомых")... опрашивал модули последовательно друг за другом с таймаутом в 3-5 секунд.. "ведомые" блоки, конечно же, имеют разные адреса... работали все блоки на одном канале.
Так вот выяснилось, что несмотря на разные адреса (имена), "ведомые" блоки одновременно принимали команды и одновременно же кидались отвечать главному блоку (соответственно, мусор приходил конкретный). Выяснилось это когда добавил вывод отладочных сообщений о принятых командах всех "ведомых" блоков и мониторингом соответствующих ком-портов.
Есть мысль в качестве решения разделить модули по разным каналам, но надо тестировать.
В 126 строке может по разному преобразуются типы переменных у разных классов. Можно попробовать явно указать ссылку SeeedOled.putString((char *)&MyAnswer.Comment); у меня и с "&" работает и без.
Задержки ставил везде, где посчитал что может повляють на работу, чтобы по любому заработало, потом при отладке будут удалены\уменьшены.
Про ответы не на свое имя ведомого блока: попрорбовал, все правильно работает откликается только на свое имя. Если запрашивать другое, то не откликается. У вас точно разные имена забиты в ведомых блоках?
Пример 100% рабочий, вот видео:
youtu.be/9NKUc3GHAUM
Моя ошибка с тем, что не передавался комментарий к датчику оказалась примитивнейшей.... я просто не заметил, что:
Превратилось в
После того, как нашел - передача комментариев заработала.
И разобрался с несколькими "датчиками" (сейчас у меня устойчиво работает один "центральный" и три "дочерних" модуля, уверен, что будут работать и все последующие).
Решение оказалось не очень сложным, но дойти до него было долго.
Если используется несколько блоков (со своими именами, конечно), то у каждого есть код типа:
Где NAME имя соответствующего блока. Предполагалось, что main - имя главного блока и что этот код работает так: Имя, под которым принмаем - NAME, а имя блока, которому передаем - main.
Когда один главный и один ведомый - этот код работает. Как только ведомых становится больше - вот тут начинается чехарда. Данне идут как угодно, видна активность всех ведомых и т.п.
Зато, если исправить код ведомого вот так:
Все сразу встает на свои места. Отзываются только те блоки, что нужно, работает стабильно.
Похоже, эти строчки реально работают так: Имя, под которым принимаем - NAME, имя под которым передаем - NAME.
Почему так - до конца не ясно. Смотрел даташит NRF24L01, так там вообще интересно. Для адресов используется несколько регистров. Один регистр - для "своего имени" и 6 - для модулей, с которыми осуществляется связь. На этих трансиверах можно много чего сделать.
А вот и еще грабли...
Для проверки решил собрать еще один "ведомый" блок. При этом вконструкции уже "ничего лишнего" - на макетке установлена Атмега 168, резистор для подтягивания кнопки "сброс", кварцевый резонатор, два конденсатора к нему, один конденсатор по питанию.
Датчик использоую DHT11 (пока просто для теста, потом поменяю на DHT22), ему тоже 1 резистор потребовался.
Еще на макетке установил стабилизатор питания L78L33 (с соответствующими конденсаторами в цепи питания) - от него запитан модуль NRF2L01.
Вся эта конструкция запитана от 3 батареек ААА.
Теперь о граблях:
1. Если Атмегу запитывать с выхода стабилизатора питания (3.3В) - не заводится почему-то (пришлось микроконтроллер запитать напрямую от блока батареек). Почему?
2. К сожалению, забыл замерить напряжение на батарейках при старте (но брал свежие из упаковки), после двух дней работы (опрос модуля один раз в 4 минуты) - напряжение на батарейном блоке всего 3.7В :( - похоже, блок не сможет работать достаточно продолжительное время :(
Из того, что пока придуалось и готовится к реализации:
1. Убрать внешний резонатор и пользоваться внутренним (минимизация количества элементов в устройстве и еще снижение питания при понижении тактовой частоты).
2. Убрать стабилизатор питания L78L33 и заменить его на делитель из двух резисторов.
Может, у кого-то еще есть мысли, как "продлить жизнь"?
P.S. Напомню, используется режим экономии энергии: set_sleep_mode(SLEEP_MODE_PWR_DOWN);
Всем привет.
Есть следующие идеи:
1. дополнительно к меге прикрутить блютуз (например HC-05) для управления с телефона или с планшета.
2. Прикрутить ethernet модуль. тут 2 варианта:
2.1 данные в инет выкладывать, sms-ки/e-mail-ы слать по определенным событиям
2.2 админить дистанционно.
Тема заглохла?...На какой стадии проект?...если не удалось решить проблему с энергосбережением - могу поделиться мыслями)
Тема не заглохла, а перетекла чуток в другое место.
Про энергосбережение - очень интересно, делитесь, пожалуйста.
Идея была сделать беспроводной датчик температуры на базе NRF24...пока сделал для тестирования два таких датчика на DS18B20...оба работают автономно...Один на батарейкe Li CR2032 (ёмкость 220 mA 3 V), другой на 2х типа AA (преположительно 2000 -3000 mA в сумме 3V) Мозг всего этого ATMega168PA-AU работающий на внутреннем резонаторе. Данные передаются каждые 8 сек, в промежутке мозг и NRF24 уходят в сон. Энергосбережение работает в полном объёме...проверял мультиметром. С каждого уходит инфа о номере датчика, вольтаж батарейки и соответственно температура. Тестировал в пределах квартиры, сигнал проходит через одну бетонную стенку без проблем и через две если немного подкорректировать положение NRF24 в пространстве. В зоне прямой видимости не тестировал, но читал про 100-120 метров (чуть позже проверим). Что сказать о степени разряда батареек...вначале тестирования CR2032 показала 3.1 Vв за первые 10 часов напряжение снизилось 2,9 V...затем стабилизаровалось и уже второй день держится 2,89 V ...судя по графикам разряда батареек найденных на просторах инета так и должно быть т.е в первый момент времени идёт интенсивное снижение напряжение, а затем более плавное и стабилизированное. Будем надеяться, что так и есть ) Две АА батарейки в начальный момент имели напругу 3.18 V, по прошествию 20 часов стабилизировалось на 3.11 V .
Осталось привести код в читаемый для всех вид ...постараюсь выложить сюда через пару тройку дней...
Супер, делитесь :) очень интересно.
Я правильно понимаю, что питание напрямую (без стабилизаторов и преобразователей) подается как на мегу, так и на NRF24?
Какую библиотеку используете для работы NRF24 (Mirf или RF24)?
Да, питание напрямую и к меге и к NRF24....библиотека RF24
тогда сразу делитесь как кодом для "датчика", так и для "сервера" ;)
Выкладываю немного приведя в порядок...может совместными усилиями окультурим потом. Код для передатчика...
Код приёмника...
Теперь о проблемах, которые нарисовываются (...
Напряжение на CR2032 упало до 2.74 V, замер внутри МК немного меньше (был введён поправочный коэф. = 1.05) Поэтому с предыдущей прошивкой фьюзов МК отключался. Прочитал, что народ писал на буржуйских сайтах, мол можно поставить значение отключения МК меньше...выставил новые фьюзы...теперь должен отключаться при 1.8 V, возможно раньше начнутся глюки...посмотрим, пока работает. Но дело не в этом...неужели даже при таком энергосбережении, а оно есть, проверено мультиметром реально, всё равно получим значительный разряд батареии...тогда запаримся менять бытрейки, а это очень грустно. Есть выход ввести счётчик циклов и подавать питание на NRF24 не раз в 8 сек, а допустим 1 раз в минуту. Насколько это даст прирост? в 8 раз?...допустим, когда закончится мой тест батарея проживёт неделю, тогда примерно 2 месяца будет в запасе....уже неплохо, но мало...с другой стороны это на CR2032 емкостью 220 мА...если посмотреть в сторону 2х АА батареек, то там около 2000 мА...увеличим ещё примерно в 9 раз...Второй датчик тестируется на 2х АА...сейчас на этих батареях показывает 3.01 V... разряд идёт немного плавнее чем на CR2032...В общем планирую довести до конца тест на этих элементах и получить реальный срок их работы в таком режиме....дальше нужно будет манипулировать и как-то увеличивать энергосбережение...
Теперь немного ссылок откуда черпалось вдохновение.
http://maniacbug.wordpress.com/2011/10/19/sensor-node/
http://www.bajdi.com/sending-structs-with-nrf24l01-modules-and-the-rf24-...
https://arduino-info.wikispaces.com/Nrf24L01-2.4GHz-HowTo
https://github.com/maniacbug
http://arduino.cc/forum/index.php?PHPSESSID=ee799e863c7f3fa94827ac45459c...
spa-sam, спасибо - обязательно попробую (как только немного времени свободного появится).
Мне кажется, что коду нехватает немного гибкости - сейчас количество передаваемых данных строго ограничено, а как быть, если у "датчика" больше данных? Можно, конечно, создать длинную структуру и грузить туда все, но это как-то не очень.
Может, взять идею из скетчей в начале ветки?
Поясню, что там:
1. Двусторонний обмен ("база" спрашивает "датчик", а "датчик" потом отвечает).
2. Одна команда позволяет "спросить", сколько датчиков.
3. Дальше можно уже давать "адресный" запрос (т.е. "датчик, какое значение параметра номер ххх")
P.S. в скетчах выше есть еще доп.команда - "сделать измерение", а потом уже "пришли данные", тут уже избыточность.. имхо, "датчик" уже должен иметь значение "наготове".
И еще... датчик, думаю, лучше "будить" для измерения через регулярные промежутки времени (для температуры, например, раз в 10 минут, имхо, будет достаточно)... но только "будить", чтобы измерить и запомнить текущие значения и сразу "спать"... а "отдавать" данные уже тогда, когда база их запросила (nrf24 можно завести на прерывание и по нему уже "будить" МК).
Что скажете?
Не совсем понятно как получить данные с МК по запросу (прерыванию), который в данный момент спит, а просыпается максимум на секунду с учётом считывания данных с датчиков? Если завести NRF на прерывание, то я так понимаю сам NRF в сон уже не погрузить - он должен постоянно слушать эфир, а это плохо...всё энергосбережение коню под хвост т.к. NRF24 в активном режиме потребляет поряд 14мА...
К тому же давайте подумаем насколько много данных нужно передавать ?
и ещё совсем забыл про 10 минут...думаю это довольно много....нет...если бы допустим каждые 10 минут данные точно приходили, то нормально, а так бывает, что 2...3 пакета теряются и поэтому время получения данных может значительно увеличится
Передайте свой пакет данных с контрольной суммой, затем - в зависимости от ответа с головного устройства (ACK/NAK) - либо (ACK) засыпайте на очередные 10 минут , либо (NAK) повторяйте передачу до победного конца.
"Протокол ACK/NAK получил свое название по названию управляющих символов стандарта ASCII — AC Knowledge (уведомление об успешном приеме данных) и Not ACKnowledge (отсутствие уведомления об успешном приеме данных). Эти символы используются в качестве средства исправления ошибок переданных данных. В основном, протокол ACK/NAK предполагает, что блоку данных предшествует символ Start-Of-Text (начало текста, STX), а за блоком следуют символ End-Of-Text (конец текста, ЕТХ) и код проверки наличия ошибок. На приемном конце выполняется контроль символа проверки блока (Block Check Character, ВСС) на предмет ошибок. В зависимости от результата проверки возвращается либо сигнал АСК, свидетельствующий об успешности передачи, либо сигнал NAK, свидетельствующий о возникновении ошибки. В случае возврата сигнала NAK передающее устройство отвечает повтором передачи всего блока."
Если ACK/NAK для вас представляется слишком сложным, попробуйте реализовать протокол ETX/ACK - там никаких контрольных сумм нет. Но, соответственно, и никакого контроля ошибок передачи, кроме проверки факта приема на том конце хоть чего-то похожего на правильный пакет данных.
Не совсем понятно как получить данные с МК по запросу (прерыванию), который в данный момент спит, а просыпается максимум на секунду с учётом считывания данных с датчиков? Если завести NRF на прерывание, то я так понимаю сам NRF в сон уже не погрузить - он должен постоянно слушать эфир, а это плохо...всё энергосбережение коню под хвост т.к. NRF24 в активном режиме потребляет поряд 14мА...
Когда читал документацию на NRF24 - у него тоже есть режимы энергосбережения собственные - надо почитать повнимательнее.
К тому же давайте подумаем насколько много данных нужно передавать ?
В каждом конкретном случае это количество может быть разным.
К примеру:
1. датчик температуры - 1 параметр
2. "погодный" датчик - 3-4 параметра (температура, влажность, давление, освещенность)
и т.п. у меня сейчас есть "датчик", который передает 7 параметров
При этом еще один параметр надо добавлять для датчиков, которые работают автономно на батарейке - об уровне заряда элемента питания.
Потом, не все "дочерние" элементы могут быть просто "датчиками" (и по большому счету толкьо отдавать свои данные), но и могут быть "исполнителями" (получили команду и что-то там сделали) - эти вообще если и должны спать, то крайне чутко, чтобы не проспать команду.
Про подтверждение получения - тоже что-то встречалось в документации на NRF24 - надо разбираться.
Правда, если все это разобрать и реализовать, то, пожалуй, уже можно будет выходить и на коммерческий уровень.
В коде передатчика есть строка radio.powerDown();
так вот именно эта команда и переводит NRF24 в спящий режим, а выводит из него radio.powerUp();
Все манипуляции с обратной связью будут в ущерб энергосбережению, тут тогда нужно выбирать, что важнее).
По этой ссылке можно посмотреть пример с обратной связью http://www.bajdi.com/sending-structs-with-nrf24l01-modules-and-the-rf24-library/
Можно конечно попробовать слать команду до посинения, пока датчик не проснётся и поймает пакет, но опять же нужно найти тот баланс...т.е. период просыпаний, чтобы энергосбережение было сохранено на приемлемом уровне.
По поводу количества датчиков...не вижу проблем расширить структуру...в чём может быть негатив?
Итак, батарейка CR2032 продержалась 2 недели, вольтаж показывает 2.37...появилась нестабильная работа МК... 2 недели для CR2032 (ёмкость 220 mA 3 V) при 8 сек частоте передачи данных думаю неплохо...увеличил это дело в 9 раз...теперь частота получится 72 сек...проверил....работает отлично, даже на той же батарейке МК ещё что-то стал передавать...Т.е. получается, что на CR2032 при частоте пердачи данных 72 сек мы можем увеличить жизнь её примерно на 4 месяца... Эксперемент продолжаем...меняем батарейку и проверяем дальше ))
А с ведомого устройства можно получить состояние пинов "1" или "0", и так же поменять состояние пинов "1" или "0".
Допустим управление светом в комнате где стоит ведомый модуль и получение состояния???
Вчера взял за основу код spa-sam (спасибо за "пинок";)) и чуток поколдовал.
Получилось (тестировал в конфигурации 1 "master" и 2 "slave"):
1. Односторонний режим ("slave" периодически отправляет свои данные, "мастер" их принимает)
2. Двустронний режим ("мастер" отправляет конерктному "слейву" команду, "слейв" реагирует)
- режимы работы задаются непосредственно в слейвах (мастер одновременно может работать как с теми, так и с другими).
- команды: получить значение параметра номер ...., установить значение параметра номер....
- команды адресные (указывается от кого и кому команда)
- пакет передаваемых данных модифицировал так, чтобы структура была всегда одинаковая, но количество параметров у каждого девайса - свое и произвольного количества.
В процессе экспериментов получал значение с одного датчика (реально датчик было лень подключать, "слейв" просто счетчик накручивал и его значения периодически отправлял). Второму "слейву" отправлялась команда, которая по установке значения отрабатывала "дрыгание пином" (для наглядности светодиод на него повесил).
Структуру передаваемого пакета пока не выкладываю - обнаружилось, что одну вещь еще не предусмотрел (как поправлю и потестирую - выложу).
P.S. до этого использовал библиотеку Mirf и все мои домашние девайсы с ее помощью реализованы... похоже, придется все переделывать на RF24 (заодно еще ждущие своего времени iBoard и iBoard Pro, похоже, дождались (на них Mirf из-за "неправильного" подключения nrf24 не удавалось завести)).
spa-sam, поясните пожалуйста, что делает вот этот кусок кода:
и вот это:
Итак, батарейка CR2032 продержалась 2 недели, вольтаж показывает 2.37...появилась нестабильная работа МК... 2 недели для CR2032 (ёмкость 220 mA 3 V) при 8 сек частоте передачи данных думаю неплохо...увеличил это дело в 9 раз...теперь частота получится 72 сек...проверил....работает отлично, даже на той же батарейке МК ещё что-то стал передавать...Т.е. получается, что на CR2032 при частоте пердачи данных 72 сек мы можем увеличить жизнь её примерно на 4 месяца... Эксперемент продолжаем...меняем батарейку и проверяем дальше ))
Тоже хочу время между отправками увеличить (правда, раза в 4, думаю, будет достаточно). Как сделать?
этот кусок кода как раз и увеличивает время между просыпаниями...точне тут идёт счёт пробуждений МК ...я сделал так:
т.е. как только счёт равен 9 обнуляем счётчик, подаём питалово на RF24, отправляем данные и снова усыпляем RF24 до того момента пока счёт не станет 9
Hi многоуважаемый All
Занимаюсь примерно темже, только приемником для датчиков будет экран-часы на светодиодных панелях. Код очень сходный, для увеличения срока жизни автономного датчика добавил Li-Ion CR123A с зарядно-разрядным модулем и солнечную батарейку 5.5v 70ма(при 100 Ватт света на 1 м кв.) размером 4см на 7 см. Хотелось компактнее, но что было под рукой. Для повышения дальности вроде можно поиграть со скоростью передачи RF24, но пока руки не дошли, жду панели из китая.
Всем привет!
Не совсем понятно как получить данные с МК по запросу (прерыванию), который в данный момент спит, а просыпается максимум на секунду с учётом считывания данных с датчиков? Если завести NRF на прерывание, то я так понимаю сам NRF в сон уже не погрузить - он должен постоянно слушать эфир, а это плохо...всё энергосбережение коню под хвост т.к. NRF24 в активном режиме потребляет поряд 14мА...
К тому же давайте подумаем насколько много данных нужно передавать ?
На сервере можно сделать "стек" команд, типа:
"Клиент1, дай все данные"
Когда клиент просыпается, он шлет на сервер сообщение, что он проснулся. Сервер отвечает что он слышит клиента, (если в течение какого то времени сервер не присылает ответ, клиент засыпает вновь, но на меньший срок). Сервер смотрит в свой стек и шлет клиенту команды, клиент отвечает. По исчерпанию в "стеке" команд для данного клиента, сервер шлет клиенту команду - "отбой" и клиент засыпает.
На сервере можно сделать "стек" команд, типа:
"Клиент1, дай все данные"
Когда клиент просыпается, он шлет на сервер сообщение, что он проснулся. Сервер отвечает что он слышит клиента, (если в течение какого то времени сервер не присылает ответ, клиент засыпает вновь, но на меньший срок). Сервер смотрит в свой стек и шлет клиенту команды, клиент отвечает. По исчерпанию в "стеке" команд для данного клиента, сервер шлет клиенту команду - "отбой" и клиент засыпает.
я думал уже о таком способе, но пока просто нет надобности в обратной связи
За то контроллеру датчика не надо будет задумываться услышали его или нет, т.е. будет гарантированная доставка данных.
А ещё, я бы сделал отдельный контроллер отвечающий за коммуникации с клиентами. А основной контроллер уже с него брал бы данные.
Контролировать прохождение данных в общем не задача датчика, а вот контроллер должен чтото сделать если данные не получил - например позвать пользователя и нажаловаться :)
Контролировать прохождение данных в общем не задача датчика, а вот контроллер должен чтото сделать если данные не получил - например позвать пользователя и нажаловаться :)
вопрос был таким:
Не совсем понятно как получить данные с МК по запросу (прерыванию), который в данный момент спит, а просыпается максимум на секунду с учётом считывания данных с датчиков? Если завести NRF на прерывание, то я так понимаю сам NRF в сон уже не погрузить - он должен постоянно слушать эфир, а это плохо...всё энергосбережение коню под хвост т.к. NRF24 в активном режиме потребляет поряд 14мА...
К тому же давайте подумаем насколько много данных нужно передавать ?
Я ответил, как я вижу решение этой проблемы. Конечно же вопрос доставки не задача датчика, по этому и говрю что на задачу соединений с датчиками повесил бы на отдельный контроллер.
Предлагаю простой способ - предусмотреть у датчика 2 режима работы: только передача и передача с контролем первый режим использовать постоянно а второй допустим раз в пару часов. И электричество экономится и контроль есть. Сам всегда передаю данные 2 раза подряд, если не совпадают - соответственно передача не прошла...
Доброе время суток. Плиз поделитесь рабочими библиотеками на NRF24L01+, а то что то не могу заставить работать скачанное постоянно возникают ошибки компиляции, а знаний пока мягко говоря недостаточно чтоб поправить код библиотек.
rf24 от maniacbug хорошая.
rf24 от maniacbug хорошая.
Так а где ее качнуть можно? кинь ссылку плиз.
http://bit.ly/14xRzjG
Большое спасибо, буду разбираться, если смогу.
для увеличения срока жизни автономного датчика добавил Li-Ion CR123A с зарядно-разрядным модулем и солнечную батарейку 5.5v 70ма(при 100 Ватт света на 1 м кв.) размером 4см на 7 см.
Поделитесь, пожалуйста, ссылками.