Передача температуры с датчиков DHT11, DS18B20 через NRF24L01.

Serega7411
Offline
Зарегистрирован: 06.04.2012

Предстоит оснащать дом умной электроникой, который будет скоро построен :).

Начал осваивать основы. Пока сделал обмен данными между блоками на ардуино через модуль 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();
  }
}

 

 

ustas
Offline
Зарегистрирован: 12.03.2012

 Видимо, делаю что-то похожее ;) предлагаю объединить усилия... 

У Вас работает только один приемник и один передатчик? я правильно понял?

я пошел пока малость по другому пути - есть несколько беспроводных блочков (один типа "внешний" (датчик DHT22), другой "внутренний" (соответственно DHT11, RTC)) и пока один приемник (принимать данные и пока их просто гнать в последовательный порт).

Передатчики работают самостоятельно (просто молотят в эфир свои данные в виде форматированных строк). Каждый из них работает в собтвенном режиме (там, где блок RTC - частота посылок около 2Гц, там где датчик DHT22 - одна посылка в 2 минуты).

Приемником пока удается принимать сигналы только одного передатчика, как заставить работать два сразу - пока не придумал: http://arduino.ru/forum/programmirovanie/nrf24l01#comment-9100

Хотя, если пойти по Вашему пути, то все будет, видимо, проще... 

Serega7411
Offline
Зарегистрирован: 06.04.2012

 

ustas пишет:

Видимо, делаю что-то похожее ;) предлагаю объединить усилия...

У Вас работает только один приемник и один передатчик? я правильно понял?

Не совсем так. У меня на ведущем и на ведомом стоит трансивер, т.е. приемник-передатчик. Ведомое устройство "слушает" эфир, работает на прием. Когда к нему (они имеют свой адреса, например "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, который киндер выковырял из найденной на помойке печ. машинки. Тогда ругался на него, что собирает всякую грязь, а тут пригодился. Осталось механику сделать.

 

ustas
Offline
Зарегистрирован: 12.03.2012

Сергей, очень интересно! Я только что повторил ваш код и заставил работать его у себя (с соответствующими правками).

Теперь я могу с центрального блока опрашивать все датчики и в том темпе, что мне нужно. А когда заставлю спящий режим работать - так вообще красота будет.

Работает все, за исключением спящего режима. Помогите с ним разобраться?

Вопрос - на какую ногу микроконтроллера у вас идет контакт IRQ от трансивера?

Еще у меня трансиверы есть в двух вариантах: с внешней антенной и без нее.

Вроде как все идентично, но замечено следующее: несмотря на то, модуль по документации толерантен к 5В выходам ардуино (питается, естественно, 3.3В), модули с внешней антенной спокойно работают в 5В режиме.. а вот модули со встроенной антенной работают крайне нестабильно - 2-5 посылок и "вешаемся". При этом, если переключить режим работы с 5В на 3.3В (на сидуинах у меня есть такой переключатель на платке) - все модули работают стабильно (по некольку суток гонял - все работает четко). 

Хотелось бы узнать, как Вы подключаете эти модули к своим платкам?

 

Про DHT11 хорошо предупредили - тоже сделаю его только датчиком влажности (пару штук купил), а температуру буду спрашивать с DS18B20.

Кстати, есть неплохой датчик DHT22 - работает от -40*С и точность выше существенно (его буду использовать для наружного датчика).

Еще маленькая идейка - подключать часы не к "центральному блоку", а к одному из внутренних (благо, там с "ногами" свободными проблем нет) и использовать их как еще несколько "датчиков" (часы, минуты, секунды, день недели и т.п.). На центральном блоке - только отображать.  У себя сейчас так и реализую.

В своей системе я хочу замутить еще управление газовым котлом (термостат) и кондиционером... Еще с женой подумали над системой автоматического полива растений (пока на балконе, дальше - посмотрим).. Аквариум, опять же, пока не автоматизированный ;))) Простую систему управления жалюзи (отдельную) я уже реализовал (вот тут в конце результат: http://arduino.ru/forum/apparatnye-voprosy/strannost-v-povedenii-kontrollera), правда, требуется доработка... 

Спасибо большое за код и направление мысли - ОЧЕНЬ помогло и поставило мозги на место :) Ваш подход несомненно лучше использует железо и более гибко может подстраиваться под логику.

Выкладывайте, что получается :) думаю, не мне одному это интересно.

Serega7411
Offline
Зарегистрирован: 06.04.2012

Питание 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 р., взял пару на "попробовать". Я на жалюзях хочу сделать подЪем и опускание, чтобы полностью убирались. Если делать открытие поворотом, то можно по фоторезистору отслеживать максимальное освещение, т.к. из-за движения солнца оптимальный угол открытия будет меняться. Все равно хотел внутрь и наружу поставить по фоторезистору на каждую комнату.

ustas
Offline
Зарегистрирован: 12.03.2012

 Сергей, а у Вас стабильно работает?

Сегодня с утра, пока "главный модуль" и "дочка" были на столе - все работало нормально.

Днем поставил в более-мнее боевые условия (хотя все-таки в "менее" - всего-то несколько метров между модулями) и получаю массу ошибок "Timeout on response from out1"... 

Причем, если я пытаюсь опрашивать по очереди сначала одну "дочку", а затем - вторую, количество ошибок увеличивается (такое ощущение, что модули мешают друг-другу работать.. опрашиваю, правда, при прохождении одного цикла... видимо, надо как-то по времени запросы разделять (как разделять понятно.. просто пока писал - возможно, нашел причину нестабильности)...

Serega7411
Offline
Зарегистрирован: 06.04.2012

ustas пишет:

 Сергей, а у Вас стабильно работает?

Пока нет возможности проверить. Основная работа совсем не связанна с электроникой. Это так, хобби. Времени на хобби получается выделить 2-3 часа в неделю, поэтому это дело идет медленно. Может на следующие длинные выходные разберусь как прошивать Atmega и соберу на отдельных МК, протестирую если время выдастся, а то сейчас только 2 МК для отладки - 1 уно и 1 нано.

А мешать друг-другу модули теоретически не должны если они на прием работают. Возможно действительно нужно поставить задержку между опросами. 

ustas
Offline
Зарегистрирован: 12.03.2012

Сергей, если будет возможность - попробуйте подольше потестировать (сутки, двое) с периодом опроса 2-5 минут... У меня пока стабильность сильно хромает (и я пока даже не представляю, как найти "узкое" место).

Еще сейчас провожу ревизию Вашего кода - есть некоторые замечания (может, обменяемся контактами, чтобы в личной переписке обсудить?).

Zapek@n
Offline
Зарегистрирован: 16.02.2012

ustas пишет:

... чтобы в личной переписке обсудить?).

Не не, нам тоже интересно.

Serega7411
Offline
Зарегистрирован: 06.04.2012

ustas пишет:

Сергей, если будет возможность - попробуйте подольше потестировать (сутки, двое) с периодом опроса 2-5 минут... У меня пока стабильность сильно хромает (и я пока даже не представляю, как найти "узкое" место).

Еще сейчас провожу ревизию Вашего кода - есть некоторые замечания (может, обменяемся контактами, чтобы в личной переписке обсудить?).

Как время появится, так обязательно подольше потестирую.

Код вполне возможно сильно корявый, я на С уже лет 10 не писал, со времен института. Это так сказать проба пера, то чтос первого раза получилось. Поэтому критика кода приветствуется. Я уже сам нашел несколько косяков, немного поправил всякие указатели, массивы. Но как уже писал, времени катострофически не хватает на хобби, поэтому обновления кода могу делать раз в неделю, не чаще.

ustas
Offline
Зарегистрирован: 12.03.2012

 Покажите, что получилось на текущий момент?

Serega7411
Offline
Зарегистрирован: 06.04.2012

Код "Непричесанный", комментариев нет, и т.д., в каком виде был когда оторвали семейные дела от развлечений. Но рабочий. Добавлена работа с менюшками на LCD, вывод на LCD показаний датчиков из выбранного в меню блока(комнаты). Рассчитано на дисплей 20х4. Выбор пункта меню кнопками - 1 пункт - 1-я кнопка и т.д. Задействованы пока 3 кнопки.

 ASLibrary.h

#ifndef __ASLibrary__
#define __ASLibrary__

#define CommentLen 20		//Длина комментария в сообщении
#define AS_NRF24L01_payload 25 	//Максимальный размер буфера в байтах для трансивера 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; 		//Значение
	byte   Comment[CommentLen];	//Описание
}AS_Answer;


// Состояние датчиков
// 0 x - Ошибка 
// 1 N - Данные актуальны, значение N

typedef struct _AS_SENSORSTATUS
{
	byte   Status; //Статус
	float  Value; //Значение
	byte   Comment[CommentLen];	//Описание
}AS_SensorStatus;

// Структура пункта меню

typedef struct _AS_MENUITEM
{
	char *Name; 	//Отображаемая трока
	byte Type;	//Тип пункта меню
			//1 - подменю
			//10 - вывести значения датчиков с устройства, имя устройства дадано именем пункта меню
	byte *Menu; 	//Ссылка на меню, на которое нужно перейти при выборе этого пункта
}AS_MenuItem;

// Структура меню

typedef struct _AS_MENU
{
	byte Count;	//Количество пунктов меню
	AS_MenuItem *MenuItems; 	//Ссылка на список пунктов меню
}AS_Menu;


#endif // __ASLibrary__

 

 

Ведомый блок

#include <SPI.h>
#include <DHT.h>
#include <Mirf.h>
#include <ASLibrary.h>
#include <MirfHardwareSpiDriver.h>
#include <avr/sleep.h>
#include <OneWire.h>

#define NumSensors 3

AS_SensorStatus MySensors[NumSensors] = {
  0,0,"DHT_temp(C)",
  0,0,"DHT_hidm(%)",
  0,0,"DS_temp(C)"};

DHT dht(4, 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();
  //Serial.print(t);
  //Serial.print(h);
  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();
  //Serial.print(MySensors[2].Value);
  
  return 1;
}

AS_Answer ExecuteCommand(AS_Command MyCommand){

  AS_Answer  MyAnswer;  // Ответ
  MyAnswer.Status = 0;
  MyAnswer.Value  = 0;
  char P[]="Y";

  switch (MyCommand.Command) {
  case 1: //Получиь количество датчиков
    MyAnswer.Status = 1;
    MyAnswer.Value  = NumSensors;    
    //Serial.println("1.");
    break;
  case 2: //Рассчитать все значения датчиков
    MyAnswer.Status = CalculateAllData();
    ///Serial.println("2.");
    break;
  case 4: //Получиь значение датчика по номеру
    //Serial.println("4.");
    if ((MyCommand.Parametr+1) > NumSensors){
      MyAnswer.Status = 0;
      MyAnswer.Value  = 0;
      memcpy(&MyAnswer.Comment,&"Too big num par.", CommentLen);
    }
    else{
      MyAnswer.Status = MySensors[MyCommand.Parametr].Status;
      MyAnswer.Value  = MySensors[MyCommand.Parametr].Value;    
      memcpy(&MyAnswer.Comment,&MySensors[MyCommand.Parametr].Comment, CommentLen);
      //MyAnswer.Comment[0] = P[0];
    }
    break;
  }

  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");
    delay(100);
    Mirf.send((byte *) &MyAnswer);

  }
  else{
    /* No data - night night. */
    toSleep();
  }
}


 

Ведущий блок

 

#include <SPI.h>
#include <Mirf.h>
#include <ASLibrary.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>
#include <LiquidCrystal.h>

#define button1Pin 14
#define button2Pin 15
#define button3Pin 16
#define button4Pin 17


// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(6, 9, 2, 3, 4, 5);

AS_Menu *CurrentMenu;

AS_MenuItem SettingMenuItems[3]={
  "Time",0,0,
  "Temp",0,0,
  "Exit",1,0};

AS_Menu SettingMenu = {
  3, SettingMenuItems};

AS_MenuItem DisplayMenuItems[3]={
  "hall",10,0,
  "kitchen",0,0,
  "Exit",1,0};

AS_Menu DisplayMenu = {
  3, DisplayMenuItems};

AS_MenuItem MainMenuItems[2]={
  "Display",1,(byte *)&DisplayMenu,
  "Setting",1,(byte *)&SettingMenu};

AS_Menu MainMenu = {
  2, MainMenuItems};

void setup(){

  Serial.begin(9600);

  pinMode(button1Pin, INPUT);
  pinMode(button2Pin, INPUT);
  pinMode(button3Pin, INPUT);
  pinMode(button4Pin, INPUT);

  Mirf.spi = &MirfHardwareSpi;
  Mirf.init();
  Mirf.setRADDR((byte *)"main");// Устанавливаем адрес, под которым будем принимать данные
  Mirf.payload = AS_NRF24L01_payload; //Задаем размер буфера данных
  Mirf.config();//Инициализируем модуль NRF24L01

  lcd.begin(20, 4);

  Serial.println("Beginning ... "); 
  //lcd.print("MM0 ");
  //lcd.print((long)&MainMenu);
  DrawMenu(&MainMenu);
}

void loop(){

  //char *addr = "hall";
  float t,t1,h;
  byte CurrentButton;
  AS_MenuItem * MI;

  CurrentButton = PressedButton();

  //Serial.print(CurrentButton);
  //lcd.setCursor(0, 2);
  if (CurrentButton != 0 ){

    if ((*CurrentMenu).Count >= CurrentButton)
    { 
      //Serial.print(" k ");
      //Serial.print(CurrentButton);
      switch((*CurrentMenu).MenuItems[CurrentButton-1].Type){
      case 10:
        ShowSensors((*CurrentMenu).MenuItems[CurrentButton-1].Name);          
      case 1:
        DrawMenu((AS_Menu *)(*CurrentMenu).MenuItems[CurrentButton-1].Menu);      
      }
    }
    // CurrentButton = 0;
  }
  delay(200);

} 

//Получает данные с передатчика и выводит на LCD
void ShowSensors(char * Name){
  byte Count=3;
  //char t[]= "tt";
  AS_Answer MyAnswer;
  lcd.clear();
  lcd.print("Calculate sensor on ");
  lcd.println(Name);
  if (CalculateAllParametr(Name) == 1 ){
    lcd.clear();
    lcd.print("Getting count sensors");
    delay(10);
    MyAnswer = GetAnswer(Name, 1, 0);
    if (MyAnswer.Status == 1) {
      //MyAnswer.Value = 3;
      Count = MyAnswer.Value;
      //Serial.println(Count);
      lcd.clear();
      for(byte i=0; i<Count; i++){
        delay(10);
        MyAnswer = GetAnswer(Name, 4, i);
        //memcpy(&MyAnswer.Comment,&t, CommentLen);
        if(i < 4)        {
          lcd.setCursor(0, i);  
          //Serial.println((char *)MyAnswer.Comment);//Выводим номер пункта меню
          lcd.print((char *)MyAnswer.Comment);//Выводим номер пункта меню
          lcd.print(" : ");
          lcd.print(MyAnswer.Value);
        }
      }
    }
  }
  else{
    lcd.clear();
    lcd.println("Error calculate sensors");
  }
  while (PressedButton() == 0)
    delay(200);
  DrawMenu(&MainMenu);
}

//Выводим меню на дисплей
void DrawMenu(AS_Menu * Menu) {
  lcd.clear();
  for(byte i=0; i<(*Menu).Count; i++){
    lcd.setCursor(0, i);  
    lcd.print(i+1);//Выводим номер пункта меню
    lcd.print(".");
    lcd.print((*Menu).MenuItems[i].Name);
    if(strcmp((*Menu).MenuItems[i].Name, "Exit") == 0){//Если пункт меню называется "Exit"
      (*Menu).MenuItems[i].Menu = (byte *)CurrentMenu;//то нужно указать, что по этому пункту выход в предыдущее меню
      //Serial.print("MM3 ");
      //Serial.print((long)CurrentMenu);
    }
  }
  //Serial.print("MM2 ");
  //Serial.println((long)Menu);
  CurrentMenu = Menu;
  //Serial.print("CM1 ");
  //Serial.print((long)CurrentMenu);
}



//Рассчитывает все показания на устройстве с именем addr
byte CalculateAllParametr(char *addr){

  AS_Answer MyAnswer = GetAnswer(addr, 2, 0);

  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;
  }
}

//Посылает команду на устройство и вовращает ответ
AS_Answer GetAnswer(char *addr, byte Command, byte Parametr){

  AS_Command MyCommand; // Команда
  AS_Answer  MyAnswer;  // Ответ
  unsigned long time;   // Время для отслеживания таймаута при запросе данных
  
  Mirf.setTADDR((byte *)addr); //Устанавливаем адрес, окуда считываем данные

  MyCommand.Command = Command;
  MyCommand.Parametr = Parametr;

  Mirf.send((byte *)&MyCommand);
  while(Mirf.isSending()){
  }
  delay(1000);
  time = millis();
  while(!Mirf.dataReady()){
    if ( ( millis() - time ) > 1000 ) {
      Serial.print("Timeout on response from ");
      Serial.println(addr);
      MyAnswer.Status = 0;
      return MyAnswer;
    }
  }

  Mirf.getData((byte *) &MyAnswer);

  Serial.print("Response OK from ");
  Serial.println(addr);
      
  return MyAnswer;

}
/*
//Получает параметр номер 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;
 }
 }*/

byte PressedButton(void)
{
  if(digitalRead(button1Pin)==HIGH){
    return 1;
  }
  else{
    if(digitalRead(button2Pin)==HIGH){
      return 2;
    }
    else{
      if(digitalRead(button3Pin)==HIGH){
        return 3;
      }
      else{
        return 0;
      }
    }
  }
}

 

ustas
Offline
Зарегистрирован: 12.03.2012

 Сергей, помогите разобраться... 

Модифицировал код под себя немного.

Файл ASLibrary1.h (исправлений минимум - добавлен канал, убрал меню):

#ifndef __ASLibrary__
#define __ASLibrary__

#define CommentLen 20		//Длина комментария в сообщении
#define AS_NRF24L01_payload 5 	//Максимальный размер буфера в байтах для трансивера NRF24L01
				//должен буть не меньше максимальной длины передаваемых данных
				//и не больше 32 (стркутуры _AS_COMMAND и _AS_ANSWER)
#define AS_NRF24L01_channel 77 	//канал, на котором работает трансивер NRF24L01
				//RF Channel 0 - 127 or 0 - 84 in the US, default 0.

// Команды состоят из 1 команды и 1 параметра
// 0 x - Перезагрузка
// 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; //Значение
	byte   Comment[CommentLen]; //Описание
}AS_Answer;


// Состояние датчиков
// 0 x - Ошибка 
// 1 N - Данные актуальны, значение N

typedef struct _AS_SENSORSTATUS
{
	byte   Status; //Статус
	float  Value; //Значение
	byte   Comment[CommentLen]; //Описание
}AS_SensorStatus;




#endif // __ASLibrary__

файл для "ведомого" блока (тут тоже минимум изменений - датчик DS заменен на аналоговый, добавлен канал для трансивера, общие команды для трансивера выведены в функцию setup):

#include <SPI.h>
#include <DHT.h>
#include <Mirf.h>
#include <ASLibrary1.h>
#include <MirfHardwareSpiDriver.h>
#include <avr/sleep.h>

#define NumSensors 3

AS_SensorStatus MySensors[NumSensors] = {
  0,0,"DHT_temp(C)",
  0,0,"DHT_hidm(%)",
  0,0,"Batt_pow(V)"};

DHT dht(6, DHT22);  //Создаем датчик DHT22 на 6 пине

const int analogInPin = A0;  // Analog input pin that the VBAT pin is attached to
float v = 0;        // variable for voltage calculation

void wakeupFunction(){
}

void toSleep(){
  attachInterrupt(0,wakeupFunction,LOW);
  sleep_mode();
  detachInterrupt(0);
}

void(* resetFunc) (void) = 0; // Reset MC function


void setup() {
  Serial.begin(9600); 

  dht.begin(); //Инициализируем датчик DHT

  for(int i=0; i<NumSensors; i++){
    MySensors[i].Status = 0;
  }
  
  Mirf.spi = &MirfHardwareSpi;
  Mirf.csnPin = 9;
  Mirf.cePin = 8;
  Mirf.init();
  
  Mirf.setRADDR((byte *)"WTHR"); //Задаем адрес под которым будем принимать данные
  Mirf.setTADDR((byte *)"main");
    
  Mirf.payload = AS_NRF24L01_payload; //Задаем размер буфера данных
  Mirf.channel = AS_NRF24L01_channel; //Задаем канал
  Mirf.config(); //Инициализируем модуль NRF24L01

  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();//Переходим в спящий режим

}

//Вычисляет все данные и заполняет массив значений датчиков
byte CalculateAllData()
{
  //Serial.println("Calculate!");
  
  float t, h, v;

  t = dht.readTemperature();
  h = dht.readHumidity();
  v = (float)(analogRead(analogInPin)*5)/1023;

  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 = v;
  
//* 
 Serial.print("Data: ");
 Serial.print(t);
 Serial.print("*C ");
 Serial.print(h);
 Serial.print("% ");
 Serial.print(v);
 Serial.println("V");
//*/
 
  return 1;
}

AS_Answer ExecuteCommand(AS_Command MyCommand){
  
  AS_Answer  MyAnswer;  // Ответ
  MyAnswer.Status = 0;
  MyAnswer.Value  = 0;
  //char P[]="Y";
  
  switch (MyCommand.Command) {
    case 0: //Reset
      Serial.println("0.");
      //resetFunc();
      break;
    case 1: //Получиь количество датчиков
      Serial.println("1.");
      MyAnswer.Status = 1;
      MyAnswer.Value  = NumSensors;    
      break;
    case 2: //Рассчитать все значения датчиков
      Serial.println("2.");
      MyAnswer.Status = CalculateAllData();
    case 4: //Получиь значение датчика по номеру
      Serial.println("4.");
      if ((MyCommand.Parametr+1) > NumSensors){
        MyAnswer.Status = 0;
        MyAnswer.Value  = 0;
        memcpy(&MyAnswer.Comment,&"Too big num par.", CommentLen);
      }
      else{
        MyAnswer.Status = MySensors[MyCommand.Parametr].Status;
        MyAnswer.Value  = MySensors[MyCommand.Parametr].Value;    
        memcpy(&MyAnswer.Comment,&MySensors[MyCommand.Parametr].Comment, CommentLen);
        //MyAnswer.Comment[0] = P[0];
      }
    }
  return MyAnswer;
}

void loop() {

  AS_Command MyCommand; // Команда
  AS_Answer  MyAnswer;  // Ответ
  
  if(!Mirf.isSending() && Mirf.dataReady()){
    Mirf.getData((byte *) &MyCommand);
    MyAnswer = ExecuteCommand(MyCommand);
    //delay(100); //это зачем?
    Mirf.send((byte *) &MyAnswer);
    while(Mirf.isSending()){}
    Serial.println("Send!");
  }
  else{
    /* No data - night night. */
    toSleep();
  }
}

Файл для "главного" блока (у меня OLED дисплей через i2c - поэтому чуток другой вывод, но суть не меняется, другие незначительные изменения):

#include <SPI.h>
#include <Mirf.h>
#include <ASLibrary1.h>
#include <MirfHardwareSpiDriver.h>
#include <Wire.h>
#include <SeeedOLED.h>

boolean flag=0;

unsigned long cnt=0;

char buf[9];

void setup(){
  Wire.begin();
  SeeedOled.init();  //initialze SEEED OLED display
  DDRB |= 0x21;        //digital pin 8, LED glow indicates Film properly Connected .
  PORTB |= 0x21;

  SeeedOled.clearDisplay();
  SeeedOled.setNormalDisplay();      //Set display to normal mode (i.e non-inverse mode)
  SeeedOled.setPageMode();           //Set addressing mode to Page Mode
          
  Mirf.spi = &MirfHardwareSpi;
  
  Mirf.csnPin = 9;
  Mirf.cePin = 8;
  Mirf.init();
  
  Mirf.setRADDR((byte *)"main");// Устанавливаем адрес, под которым будем принимать данные
  
  Mirf.payload = AS_NRF24L01_payload;
  Mirf.channel = AS_NRF24L01_channel; //Задаем канал
  Mirf.config(); 
}


void loop(){
 
  // внешний датчик, температура (DHT22), влажность (DHT22), температура (DS18B20), заряд батареи
  char *addr = "WTHR";
  
  GetMeasure(addr);
  
  SeeedOled.setTextXY(7,0);
  SeeedOled.putString("cnt=");
  SeeedOled.putNumber(cnt);     
  
  cnt++;
  
  //delay(300000); // 5 минут 
  delay(1000); 
  
} 

//Посылает команду на устройство и вовращает ответ
AS_Answer GetAnswer(char *addr, byte Command, byte Parametr){

  AS_Command MyCommand; // Команда
  AS_Answer  MyAnswer;  // Ответ
  unsigned long time;   // Время для отслеживания таймаута при запросе данных
  
  Mirf.setTADDR((byte *)addr); //Устанавливаем адрес, окуда считываем данные

  MyCommand.Command = Command;
  MyCommand.Parametr = Parametr;

  Mirf.send((byte *)&MyCommand);
  while(Mirf.isSending()){
  }
  
  delay(1000);  // зачем?
  
  time = millis();
  while(!Mirf.dataReady()){
    if ( ( millis() - time ) > 1000 ) {
      SeeedOled.clearDisplay();
      SeeedOled.putString("Timeout on ");
      SeeedOled.putString(addr);
      MyAnswer.Status = 0;
      return MyAnswer;
    }
  }

  Mirf.getData((byte *) &MyAnswer);

  return MyAnswer;
}

//Рассчитывает все показания на устройстве с именем addr
byte CalculateAllParametr(char *addr){

  AS_Answer MyAnswer = GetAnswer(addr, 2, 0);

  if (MyAnswer.Status == 0){
    SeeedOled.clearDisplay();
    SeeedOled.putString("Error calculate all values on  ");
    SeeedOled.putString(addr);
    return 0;
  }  
  else{  
    //Serial.print("Calculate all values OK on ");
    //Serial.println(addr);
    return 1;
  }
}

void GetMeasure(char *addr){
  byte Count;
  AS_Answer MyAnswer;
  
  if (CalculateAllParametr(addr) == 1) {
      delay(10);
      MyAnswer = GetAnswer(addr, 1, 0); //сколько датчиков?
      if (MyAnswer.Status == 1) {
        Count = MyAnswer.Value;
          SeeedOled.setTextXY(0,0);          //Set the cursor to Xth Page, Yth Column  
          SeeedOled.putString(addr);
          SeeedOled.putString(" sensors: "); //Print the String
          SeeedOled.putNumber(Count);
          
        for(byte i=0; i<Count; i++){
          delay(10);
          MyAnswer = GetAnswer(addr, 4, i);
          SeeedOled.setTextXY(i+1,0);          //Set the cursor to Xth Page, Yth Column  
          SeeedOled.putString((char *)MyAnswer.Comment);
          dtostrf(MyAnswer.Value,8,2,buf);
          SeeedOled.putString(buf);
          }
      }
    } else {
      SeeedOled.clearDisplay();
      SeeedOled.putString("Wrong!");
    }
}

 и вот в этом файле как раз "непонятка": в строке 126 должен печататься комментарий к датчику (Сергей, отличная мысль этот комментарий отдавать!)... но не печатается.. выдается какой-то мусор на дисплее :(

Подскажите, в чем проблема?... код "ведомого" и "главного" - максимально близок к Вашему (в части этого комментария), но не работает... а у Вас работает нормально?

Еще вопросы по задержкам (по коду) - как получили значения и догадались, что они там нужны? (кстати, от некоторых можно избавиться - те, что закоментированы у меня, а вот от секундной задержки в скетче для главного блока избавитья нельзя - сразу начинают идти недостоверные данные и т.п.). 

 

Кстати... я тут еще одни "грабли" нашел... Помните, я говорил, что начинаются ошибки (и вообще прекращается нормальная работа модулей), если "главный" один, а "ведомых" несколько?

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

Так вот выяснилось, что несмотря на разные адреса (имена), "ведомые" блоки одновременно принимали команды и одновременно же кидались отвечать главному блоку (соответственно, мусор приходил конкретный). Выяснилось это когда добавил вывод отладочных сообщений о принятых командах всех "ведомых" блоков и мониторингом соответствующих ком-портов.

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

Serega7411
Offline
Зарегистрирован: 06.04.2012

 В 126 строке может по разному преобразуются типы переменных у разных классов. Можно попробовать явно указать ссылку SeeedOled.putString((char *)&MyAnswer.Comment); у меня и с "&" работает и без.

Задержки ставил везде, где посчитал что может повляють на работу, чтобы по любому заработало, потом при отладке будут удалены\уменьшены.

Про ответы не на свое имя ведомого блока: попрорбовал, все правильно работает откликается только на свое имя. Если запрашивать другое, то не откликается. У вас точно разные имена забиты в ведомых блоках?

Пример 100% рабочий, вот видео:
 

youtu.be/9NKUc3GHAUM

ustas
Offline
Зарегистрирован: 12.03.2012

 Моя ошибка с тем, что не передавался комментарий к датчику оказалась примитивнейшей.... я просто не заметил, что:

#define AS_NRF24L01_payload 5

Превратилось в 

#define AS_NRF24L01_payload 25

После того, как нашел - передача комментариев заработала.

И разобрался с несколькими "датчиками" (сейчас у меня устойчиво работает один "центральный" и три "дочерних" модуля, уверен, что будут работать и все последующие).

Решение оказалось не очень сложным, но дойти до него было долго. 

Если используется несколько блоков (со своими именами, конечно), то у каждого есть код типа:

  Mirf.setRADDR((byte *)"NAME"); 
  Mirf.setTADDR((byte *)"main");

Где NAME имя соответствующего блока. Предполагалось, что main - имя главного блока и что этот код работает так: Имя, под которым принмаем - NAME, а имя блока, которому передаем - main.

Когда один главный и один ведомый - этот код работает. Как только ведомых становится больше - вот тут начинается чехарда. Данне идут как угодно, видна активность всех ведомых и т.п.

Зато, если исправить код ведомого вот так:

  Mirf.setRADDR((byte *)"NAME"); 
  Mirf.setTADDR((byte *)"NAME");

Все сразу встает на свои места. Отзываются только те блоки, что нужно, работает стабильно. 

Похоже, эти строчки реально работают так: Имя, под которым принимаем - NAME, имя под которым передаем - NAME.

Почему так - до конца не ясно. Смотрел даташит NRF24L01, так там вообще интересно. Для адресов используется несколько регистров. Один регистр - для "своего имени" и 6 - для модулей, с которыми осуществляется связь. На этих трансиверах можно много чего сделать.

 

ustas
Offline
Зарегистрирован: 12.03.2012

А вот и еще грабли...

Для проверки решил собрать еще один "ведомый" блок. При этом  вконструкции уже "ничего лишнего" - на макетке установлена Атмега 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);

Elridge
Offline
Зарегистрирован: 11.06.2012

Всем привет.

Есть следующие идеи:

1. дополнительно к меге прикрутить блютуз (например HC-05) для управления с телефона или с планшета.

2. Прикрутить ethernet модуль. тут 2 варианта:

2.1 данные в инет выкладывать, sms-ки/e-mail-ы слать по определенным событиям

2.2 админить дистанционно.

spa-sam
Offline
Зарегистрирован: 14.12.2012

Тема заглохла?...На какой стадии проект?...если не удалось решить проблему с энергосбережением - могу поделиться мыслями)

ustas
Offline
Зарегистрирован: 12.03.2012

Тема не заглохла, а перетекла чуток в другое место.

Про энергосбережение - очень интересно, делитесь, пожалуйста.

spa-sam
Offline
Зарегистрирован: 14.12.2012

Идея была сделать беспроводной датчик температуры на базе 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 .

Осталось привести код в читаемый для всех вид ...постараюсь выложить сюда через пару тройку дней...

ustas
Offline
Зарегистрирован: 12.03.2012

Супер, делитесь :) очень интересно.

Я правильно понимаю, что питание напрямую (без стабилизаторов и преобразователей) подается как на мегу, так и на NRF24?

Какую библиотеку используете для работы NRF24 (Mirf или RF24)?

 

spa-sam
Offline
Зарегистрирован: 14.12.2012

Да, питание напрямую и к меге и к NRF24....библиотека RF24

ustas
Offline
Зарегистрирован: 12.03.2012

тогда сразу делитесь как кодом для "датчика", так и для "сервера" ;)

spa-sam
Offline
Зарегистрирован: 14.12.2012

Выкладываю немного приведя в порядок...может совместными усилиями окультурим потом. Код для передатчика...

#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
#include <avr/sleep.h>
#include <avr/wdt.h>
#include <Wire.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 3
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

//int battVolts;
int count;    //переменная для счётчика циклов
volatile boolean wdt_tripped=1;

RF24 radio(8,7); 
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };

//создаём структуру для передачи 4х значений
typedef struct{         
  int W;
  int X;
  float Y;
  float Z;
}
B_t;
B_t duino2; 

//режим сна для МК
void system_sleep() {
	delay(2);                            // Wait for serial traffic
	_SFR_BYTE(ADCSRA) &= ~_BV(ADEN);     // Switch ADC off
	set_sleep_mode(SLEEP_MODE_PWR_DOWN);
	sleep_enable();
	sleep_mode();                        // System sleeps here
	sleep_disable();
	_SFR_BYTE(ADCSRA) |= _BV(ADEN);      // Switch ADC on
	}
void wdt_interrupt_mode() {
	wdt_reset();
	WDTCSR |= _BV(WDIE); // Restore WDT interrupt mode
	}
ISR(WDT_vect) {
	wdt_tripped=1;  // set global volatile variable
	}




void setup()
{
  wdt_disable();
	wdt_reset();
	wdt_enable(WDTO_8S);   //пробуждение каждые 8 сек
	count = 0;


sensors.begin();
radio.begin();
radio.openWritingPipe(pipes[0]);
radio.openReadingPipe(1,pipes[1]);

}
 
void loop(void)
{ 
radio.powerUp();  //подаём питание на NRF24
radio.stopListening(); // отключаем режим приёма
sensors.requestTemperatures();  
float t = sensors.getTempCByIndex(0);
delay(20);

int vb = getBandgap (); // записываем в переменную vb значение замеренного напряжения с батарии

//записываем в структуру данные для передачи
duino2.W = 11;  // этот номер передатчика для идентификации в принятом пакете данных
duino2.X = vb;  // передаём напряжение батареи
duino2.Y =t;    // передаём температуру
duino2.Z = t;   // продублирована (можно менять на любую переменную)


//тут можно увеличить интервал времени между отправками данных по RF24 за счёт счётчика циклов
wdt_interrupt_mode();
	if (wdt_tripped) {
		count++;
		wdt_tripped = 0;

		if (count == 9) {
		delay(20);
		count = 0;
		}
	}



bool ok = radio.write( &duino2, sizeof(duino2) ); //отправляем данные по RF24
delay (20); 
radio.powerDown(); // отключаем питание RF24
system_sleep();   //МК засыпает
 

}

//внутренний контроль напряжения на батареи 

const long InternalReferenceVoltage = 1062; 
int getBandgap () 
  {
  // REFS0 : Selects AVcc external reference
  // MUX3 MUX2 MUX1 : Selects 1.1V (VBG)  
   ADMUX = _BV (REFS0) | _BV (MUX3) | _BV (MUX2) | _BV (MUX1);
   ADCSRA |= _BV( ADSC );  // start conversion
   while (ADCSRA & _BV (ADSC))
     { }  // wait for conversion to complete
   int results = (((InternalReferenceVoltage * 1024) / ADC) + 5) / 10; 
   return results;
  } // end of getBandgap

 

spa-sam
Offline
Зарегистрирован: 14.12.2012

Код приёмника...


#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"

typedef struct{
  int W;
  int X;
  float Y;
  float Z;
}
B_t;
B_t duino2;
 
RF24 radio(8,7);   // make sure this corresponds to the pins you are using
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };
 
void setup()
{
  Serial.begin(9600);
  radio.begin();
  radio.openWritingPipe(pipes[1]);
  radio.openReadingPipe(1,pipes[0]);
  radio.startListening();
}
 
void loop(void)
{ 

  if ( radio.available() )
  {
    bool done = false;
    while (!done)
    {
      done = radio.read( &duino2, sizeof(duino2) );
  
  Serial.print("duino2.W = ");
  Serial.println(duino2.W);
  Serial.print("duino2.X = ");
  Serial.println(duino2.X);
  Serial.print("duino2.Y = ");
  Serial.println(duino2.Y);
  Serial.print("duino2.Z = ");
  Serial.println(duino2.Z); 
  }
  }

}

 

spa-sam
Offline
Зарегистрирован: 14.12.2012

 Теперь о проблемах, которые нарисовываются (...

Напряжение на CR2032 упало до 2.74 V, замер внутри  МК немного меньше (был введён поправочный коэф. = 1.05) Поэтому с предыдущей прошивкой фьюзов МК отключался. Прочитал, что народ писал на буржуйских сайтах, мол можно поставить значение отключения МК меньше...выставил новые фьюзы...теперь должен отключаться при 1.8 V, возможно раньше начнутся глюки...посмотрим, пока работает.  Но дело не в этом...неужели даже при таком энергосбережении, а оно есть, проверено мультиметром реально, всё равно получим значительный разряд батареии...тогда запаримся менять бытрейки, а это очень грустно. Есть выход ввести счётчик циклов и подавать питание на NRF24 не раз в 8 сек, а допустим 1 раз в минуту. Насколько это даст прирост? в 8 раз?...допустим, когда закончится мой тест батарея проживёт неделю, тогда примерно  2 месяца будет в запасе....уже неплохо, но мало...с другой стороны это на CR2032  емкостью 220 мА...если посмотреть в сторону 2х АА батареек, то там около 2000 мА...увеличим ещё примерно в 9 раз...Второй датчик тестируется на 2х АА...сейчас на этих батареях показывает 3.01 V... разряд идёт немного плавнее чем на CR2032...В общем планирую довести до конца тест на этих элементах и получить реальный срок их работы в таком режиме....дальше нужно будет манипулировать и как-то увеличивать энергосбережение...

spa-sam
Offline
Зарегистрирован: 14.12.2012
ustas
Offline
Зарегистрирован: 12.03.2012

spa-sam, спасибо - обязательно попробую (как только немного времени свободного появится).

Мне кажется, что коду нехватает немного гибкости - сейчас количество передаваемых данных строго ограничено, а как быть, если у "датчика" больше данных? Можно, конечно, создать длинную структуру и грузить туда все, но это как-то не очень.

Может, взять идею из скетчей в начале ветки?

Поясню, что там:

1. Двусторонний обмен ("база" спрашивает "датчик", а "датчик" потом отвечает).

2. Одна команда позволяет "спросить", сколько датчиков.

3. Дальше можно уже давать "адресный" запрос (т.е. "датчик, какое значение параметра номер ххх")

P.S. в скетчах выше есть еще доп.команда - "сделать измерение", а потом уже "пришли данные", тут уже избыточность.. имхо, "датчик" уже должен иметь значение "наготове".

И еще... датчик, думаю, лучше "будить" для измерения через регулярные промежутки времени (для температуры, например, раз в 10 минут, имхо, будет достаточно)... но только "будить", чтобы измерить и запомнить текущие значения и сразу "спать"... а "отдавать" данные уже тогда, когда база их запросила (nrf24 можно завести на прерывание и по нему уже "будить" МК).

Что скажете? 

spa-sam
Offline
Зарегистрирован: 14.12.2012

Не совсем понятно как получить данные с МК по запросу (прерыванию), который в данный момент спит, а просыпается максимум на секунду с учётом считывания данных с датчиков? Если завести NRF на прерывание, то я так понимаю сам NRF в сон уже не погрузить - он должен постоянно слушать эфир, а это плохо...всё энергосбережение коню под хвост т.к. NRF24 в активном режиме потребляет поряд 14мА...

К тому же давайте подумаем насколько много данных нужно передавать ? 

spa-sam
Offline
Зарегистрирован: 14.12.2012

и ещё совсем забыл про 10 минут...думаю это довольно много....нет...если бы допустим каждые 10 минут данные точно приходили, то нормально, а так бывает, что 2...3 пакета теряются и поэтому время получения данных может значительно увеличится 

step962
Offline
Зарегистрирован: 23.05.2011

Передайте свой пакет данных с контрольной суммой, затем - в зависимости от ответа с головного устройства (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 - там никаких контрольных сумм нет. Но, соответственно, и никакого контроля ошибок передачи, кроме проверки факта приема на том конце хоть чего-то похожего на правильный пакет данных.

ustas
Offline
Зарегистрирован: 12.03.2012

spa-sam пишет:

Не совсем понятно как получить данные с МК по запросу (прерыванию), который в данный момент спит, а просыпается максимум на секунду с учётом считывания данных с датчиков? Если завести NRF на прерывание, то я так понимаю сам NRF в сон уже не погрузить - он должен постоянно слушать эфир, а это плохо...всё энергосбережение коню под хвост т.к. NRF24 в активном режиме потребляет поряд 14мА...

Когда читал документацию на NRF24 - у него тоже есть режимы энергосбережения собственные - надо почитать повнимательнее. 

spa-sam пишет:

К тому же давайте подумаем насколько много данных нужно передавать ? 

В каждом конкретном случае это количество может быть разным. 

К примеру:

1. датчик температуры - 1 параметр

2. "погодный" датчик - 3-4 параметра (температура, влажность, давление, освещенность)

и т.п. у меня сейчас есть "датчик", который передает 7 параметров 

При этом еще один параметр надо добавлять для датчиков, которые работают автономно на батарейке - об уровне заряда элемента питания.

Потом, не все "дочерние" элементы могут быть просто "датчиками" (и по большому счету толкьо отдавать свои данные), но и могут быть "исполнителями" (получили команду и что-то там сделали) - эти вообще если и должны спать, то крайне чутко, чтобы не проспать команду.

 

Про подтверждение получения - тоже что-то встречалось в документации на NRF24 - надо разбираться.

Правда, если все это разобрать и реализовать, то, пожалуй, уже можно будет выходить и на коммерческий уровень.

spa-sam
Offline
Зарегистрирован: 14.12.2012

В коде передатчика есть строка  radio.powerDown(); 

так вот именно эта команда и переводит NRF24 в спящий режим, а выводит из него radio.powerUp();

Все манипуляции с обратной связью будут в ущерб энергосбережению, тут тогда нужно выбирать, что важнее). 

По этой ссылке можно посмотреть пример с обратной связью http://www.bajdi.com/sending-structs-with-nrf24l01-modules-and-the-rf24-library/

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

По поводу количества датчиков...не вижу проблем расширить структуру...в чём может быть негатив?

spa-sam
Offline
Зарегистрирован: 14.12.2012

Итак, батарейка CR2032 продержалась 2 недели, вольтаж показывает 2.37...появилась нестабильная работа МК... 2 недели для CR2032 (ёмкость 220 mA 3 V) при 8 сек частоте передачи данных думаю неплохо...увеличил это дело в 9 раз...теперь частота получится 72 сек...проверил....работает отлично, даже на той же батарейке МК ещё что-то стал передавать...Т.е. получается, что на CR2032 при частоте пердачи данных 72 сек мы можем увеличить жизнь её примерно на 4 месяца... Эксперемент продолжаем...меняем батарейку и проверяем дальше ))

9ser
Offline
Зарегистрирован: 18.11.2012

 А с ведомого устройства можно получить состояние пинов "1" или "0", и так же поменять состояние пинов "1" или "0".

Допустим управление светом в комнате где стоит ведомый модуль и получение состояния???

ustas
Offline
Зарегистрирован: 12.03.2012

Вчера взял за основу код spa-sam (спасибо за "пинок";)) и чуток поколдовал. 

Получилось (тестировал в конфигурации 1 "master" и 2 "slave"):

1. Односторонний режим ("slave" периодически отправляет свои данные, "мастер" их принимает)

2. Двустронний режим ("мастер" отправляет конерктному "слейву" команду, "слейв" реагирует)

 - режимы работы задаются непосредственно в слейвах (мастер одновременно может работать как с теми, так и с другими).

 - команды: получить значение параметра номер ...., установить значение параметра номер....

 - команды адресные (указывается от кого и кому команда)

 - пакет передаваемых данных модифицировал так, чтобы структура была всегда одинаковая, но количество параметров у каждого девайса - свое и произвольного количества.

 

В процессе экспериментов получал значение с одного датчика (реально датчик было лень подключать, "слейв" просто счетчик накручивал и его значения периодически отправлял). Второму "слейву" отправлялась команда, которая по установке значения отрабатывала "дрыгание пином" (для наглядности светодиод на него повесил).

Структуру передаваемого пакета пока не выкладываю - обнаружилось, что одну вещь еще не предусмотрел (как поправлю и потестирую - выложу).

 

P.S. до этого использовал библиотеку Mirf и все мои домашние девайсы с ее помощью реализованы... похоже, придется все переделывать на RF24 (заодно еще ждущие своего времени iBoard и iBoard Pro, похоже, дождались (на них Mirf из-за "неправильного" подключения nrf24 не удавалось завести)).

ustas
Offline
Зарегистрирован: 12.03.2012

spa-sam, поясните пожалуйста, что делает вот этот кусок кода: 

  wdt_interrupt_mode();
  if (wdt_tripped) {
    count++;
    wdt_tripped = 0;

    if (count == 9) {
      delay(20);
      count = 0;
    }
  }

и вот это:

spa-sam пишет:

Итак, батарейка CR2032 продержалась 2 недели, вольтаж показывает 2.37...появилась нестабильная работа МК... 2 недели для CR2032 (ёмкость 220 mA 3 V) при 8 сек частоте передачи данных думаю неплохо...увеличил это дело в 9 раз...теперь частота получится 72 сек...проверил....работает отлично, даже на той же батарейке МК ещё что-то стал передавать...Т.е. получается, что на CR2032 при частоте пердачи данных 72 сек мы можем увеличить жизнь её примерно на 4 месяца... Эксперемент продолжаем...меняем батарейку и проверяем дальше ))

Тоже хочу время между отправками увеличить (правда, раза в 4, думаю, будет достаточно). Как сделать?

spa-sam
Offline
Зарегистрирован: 14.12.2012

этот кусок кода как раз и увеличивает время между просыпаниями...точне тут идёт счёт пробуждений МК ...я сделал так:

wdt_interrupt_mode();
	if (wdt_tripped) {
		count++;
		wdt_tripped = 0;

		if (count == 9) {
                radio.powerUp();
              
                bool ok = radio.write( &duino2, sizeof(duino2) ); //отправляем данные по RF24
		delay(20);
		count = 0;
                radio.powerDown();
		}
	}

т.е. как только счёт равен 9 обнуляем счётчик, подаём питалово на RF24, отправляем данные и снова усыпляем RF24 до того момента пока счёт не станет 9

ales2k
Offline
Зарегистрирован: 25.02.2013

Hi многоуважаемый All 

Занимаюсь примерно темже, только приемником для датчиков будет экран-часы на светодиодных панелях. Код очень сходный, для увеличения срока жизни автономного датчика добавил Li-Ion CR123A с зарядно-разрядным модулем и солнечную батарейку 5.5v 70ма(при 100 Ватт света на 1 м кв.) размером 4см на 7 см. Хотелось компактнее, но что было под рукой. Для повышения дальности вроде можно поиграть со скоростью передачи RF24, но пока руки не дошли, жду панели из китая.

mr.il
Offline
Зарегистрирован: 05.01.2013

Всем привет!

spa-sam пишет:

Не совсем понятно как получить данные с МК по запросу (прерыванию), который в данный момент спит, а просыпается максимум на секунду с учётом считывания данных с датчиков? Если завести NRF на прерывание, то я так понимаю сам NRF в сон уже не погрузить - он должен постоянно слушать эфир, а это плохо...всё энергосбережение коню под хвост т.к. NRF24 в активном режиме потребляет поряд 14мА...

К тому же давайте подумаем насколько много данных нужно передавать ? 

На сервере можно сделать "стек" команд, типа:

"Клиент1, дай все данные"

Когда клиент просыпается, он шлет на сервер сообщение, что он проснулся. Сервер отвечает что он слышит клиента, (если в течение  какого то времени сервер не присылает ответ, клиент засыпает вновь, но на меньший срок). Сервер смотрит в свой стек и шлет клиенту команды, клиент отвечает. По исчерпанию в "стеке" команд для данного клиента, сервер шлет клиенту команду - "отбой" и клиент засыпает.

spa-sam
Offline
Зарегистрирован: 14.12.2012

mr.il пишет:

 

На сервере можно сделать "стек" команд, типа:

"Клиент1, дай все данные"

Когда клиент просыпается, он шлет на сервер сообщение, что он проснулся. Сервер отвечает что он слышит клиента, (если в течение  какого то времени сервер не присылает ответ, клиент засыпает вновь, но на меньший срок). Сервер смотрит в свой стек и шлет клиенту команды, клиент отвечает. По исчерпанию в "стеке" команд для данного клиента, сервер шлет клиенту команду - "отбой" и клиент засыпает.

я думал уже о таком способе, но пока просто нет надобности в обратной связи

mr.il
Offline
Зарегистрирован: 05.01.2013

За то контроллеру датчика не надо будет задумываться услышали его или нет, т.е. будет гарантированная доставка данных.

А ещё, я бы сделал отдельный контроллер отвечающий за коммуникации с клиентами. А основной контроллер уже с него брал бы данные.

ales2k
Offline
Зарегистрирован: 25.02.2013

Контролировать прохождение данных в общем не задача датчика, а вот контроллер должен чтото сделать если данные не получил - например позвать пользователя и нажаловаться :)

mr.il
Offline
Зарегистрирован: 05.01.2013

ales2k пишет:

Контролировать прохождение данных в общем не задача датчика, а вот контроллер должен чтото сделать если данные не получил - например позвать пользователя и нажаловаться :)

вопрос был таким:

<em>spa-sam</em> пишет:

Не совсем понятно как получить данные с МК по запросу (прерыванию), который в данный момент спит, а просыпается максимум на секунду с учётом считывания данных с датчиков? Если завести NRF на прерывание, то я так понимаю сам NRF в сон уже не погрузить - он должен постоянно слушать эфир, а это плохо...всё энергосбережение коню под хвост т.к. NRF24 в активном режиме потребляет поряд 14мА...

К тому же давайте подумаем насколько много данных нужно передавать ?

Я ответил, как я вижу решение этой проблемы. Конечно же вопрос доставки не задача датчика, по этому и говрю что на задачу соединений с датчиками повесил бы на отдельный контроллер.

ales2k
Offline
Зарегистрирован: 25.02.2013

Предлагаю простой способ - предусмотреть у датчика 2 режима работы: только передача и передача с контролем первый режим использовать постоянно а второй допустим раз в пару часов. И электричество экономится и контроль есть. Сам всегда передаю данные 2 раза подряд, если не совпадают - соответственно передача не прошла...

triada13
Offline
Зарегистрирован: 04.01.2013

Доброе время суток. Плиз поделитесь рабочими библиотеками на NRF24L01+, а то что то не могу заставить работать скачанное постоянно возникают ошибки компиляции, а знаний пока мягко говоря недостаточно чтоб поправить код библиотек.

toc
Offline
Зарегистрирован: 09.02.2013

rf24  от  maniacbug хорошая.

triada13
Offline
Зарегистрирован: 04.01.2013

toc пишет:

rf24  от  maniacbug хорошая.

Так а где ее качнуть можно? кинь ссылку плиз.

toc
Offline
Зарегистрирован: 09.02.2013
triada13
Offline
Зарегистрирован: 04.01.2013

Большое спасибо, буду разбираться, если смогу.

dbg
Offline
Зарегистрирован: 30.01.2013

ales2k пишет:

для увеличения срока жизни автономного датчика добавил Li-Ion CR123A с зарядно-разрядным модулем и солнечную батарейку 5.5v 70ма(при 100 Ватт света на 1 м кв.) размером 4см на 7 см.

Поделитесь, пожалуйста, ссылками.