nRF24L01+ передача структуры

.c8r
.c8r аватар
Offline
Зарегистрирован: 15.11.2011

Всем привет!

Понимаю, что тема очень избитая, но может ли кто выложить сюда РАБОЧИЙ пример скетчей передатчик + приемник для передачи структуры с произвольными полями (ну или хотяб int,byte,char).

Как дополнение можно проверку получения.

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

Всем большое спасибо.

.c8r
.c8r аватар
Offline
Зарегистрирован: 15.11.2011

Хм...Похоже тема совсем не интересная. 

Ладно, вот код передатчика:

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

#include <avr/sleep.h>
#include <avr/wdt.h>

#define CNT 30 // количество циклов по 8 секунд между "посылками" (30 = 4 минуты между посылками)
int count;    //переменная для счётчика циклов
volatile boolean wdt_tripped=1;

// описание параметров модуля
#define SID 500                        // идентификатор датчика Внешний 1
#define NumSensors 4                   // количество сенсоров (и еще одно обязательное занчение - имя датчика)

boolean mode = 0; // 0 - нормальный режим (редко отправляем данные и не моргаем), 1 - тестовый режим (данные отправляем раз в 8 секунд и моргаем светодиодом)

/////////////////////////////////////////////////////////////////////////////

// создаём структуру для передачи значений
typedef struct{         
  int SensorID;        // идентификатор датчика
  int ParamID;         // идентификатор параметра 
  float ParamValue;    // значение параметра
  char Comment[16];    // комментарий
}
Message;

#define LED 9
#define BUTTON 4

// создаем структуру для описания параметров
typedef struct{
  float Value;         // значение 
  char Note[16];       // комментарий
} 
Parameter;
int tests=0;
/////////////////////////////////////////////////////////////////////////////

Parameter MySensors[NumSensors+1] = {    // описание датчиков (и первичная инициализация)
  NumSensors, "SN3 (in&out)",            // в поле "комментарий" указываем пояснительную информацию о датчике и количество сенсоров
  0, "TempIN, C",                        // температура со встроенного датчика
  0, "VCC, V",                           // напряжение питания (по внутренним данным МК)
  0, "BATT, Flag",                       // статус того, что ионистр в порядке (0 - "мертвый", 1 - "живой")
  0, "NonameSens"                        // Данные с любого датчика
  //0, "TempOUT, C"                      // температура со внешнего датчика
};

Message sensor; 

/////////////////////////////////////////////////////////////////////////////

//RF24 radio(CE,CSN);
RF24 radio(8,7);

// выберем две "трубы" (выбираем свои)
const uint64_t pipes[2] = { 
  0xF0F0F0F0A1LL, 0xF0F0F0F0A2LL };

/////////////////////////////////////////////////////////////////////////////

//режим сна для МК
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;
  
  // светик 
  pinMode(LED, OUTPUT);

  radio.begin();
  //radio.setPALevel(RF24_PA_HIGH);   // Уровень мощности (работает только с версией RF + PA)
  radio.setDataRate(RF24_250KBPS);  // Скорость передачи
  radio.setRetries(15,15);
  
  // номер канала, на котором работаем (подобрать свой)
  radio.setChannel(ххх);

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

  radio.stopListening(); // отключаем режим приёма
  
  // при старте включаем "тестовый" режим - данные отправляем часто и моргаем светодиодом
  mode = 1;
}

void loop(void)
{ 
  //тут можно увеличить интервал времени между отправками данных по RF24 за счёт счётчика циклов
  wdt_interrupt_mode();
  
  if (wdt_tripped) {
    count++;
    wdt_tripped = 0;
    
    // отправим данные, если уже "пора" 
    if (count == ((mode==1) ? (count) : (CNT))) {
      calculateValue();
      // зажжем светодиод
      if (mode == 1) {
        digitalWrite(LED, HIGH);
      }
      
      radio.powerUp();  //подаём питание на NRF24
      delay(20);
      for (int i=1; i<=NumSensors; i++){
        sendSensorMessage(i);
      }
      radio.powerDown(); // отключаем питание RF24
      delay(20);
  
      count = 0;
      // погасим светодиод
      if (mode == 1) {
        digitalWrite(LED, LOW);
      }
    }
  }
  
  if(tests<10) {
    mode = 1;
    tests++;
  }
  else {
    mode = 0;
  }
  
  // спать!
  system_sleep();   //МК засыпает
}


// функция вычисления всех значений датчиков
void calculateValue(){
  // код для получения данных
  // напряжение питания
  MySensors[2].Value = ((float) readVcc())/1000.0;
  
  // температура встроенного датчика (подлючен на А2)
  MySensors[1].Value = (((float)analogRead(A2) * MySensors[2].Value / 1024.0) - 0.5)/0.01;
  
  // если напряжение больше 2.67В - ионистр "жив" (1)
  // если меньше - "скоро помрет" (0)
  MySensors[3].Value = (MySensors[2].Value > 2.67) ? 1 : 0; 
  
  // температура внешнего датчика (подключен на А1 через разъем "Analog")
  //MySensors[4].Value = (((float)analogRead(A0) * MySensors[2].Value / 1024.0) - 0.5)/0.01;
  MySensors[4].Value = 0;
  
  return;
}


// отправить сообщение (идентификатор параметра)
void sendSensorMessage(int ParamID) {

  //подготовим данные в структуру для передачи
  sensor.SensorID = SID;
  sensor.ParamID = ParamID;        
  sensor.ParamValue = MySensors[ParamID].Value;        
  memcpy(&sensor.Comment,(char*)MySensors[ParamID].Note, 16);

  //отправляем данные по RF24
  bool ok = radio.write( &sensor, sizeof(sensor) ); 

  delay (20); 
  return;
}

long readVcc() {
  // Read 1.1V reference against AVcc
  // set the reference to Vcc and the measurement to the internal 1.1V reference
  #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
    ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
    ADMUX = _BV(MUX5) | _BV(MUX0);
  #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
    ADMUX = _BV(MUX3) | _BV(MUX2);
  #else
    ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  #endif  

  delay(75); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Start conversion
  while (bit_is_set(ADCSRA,ADSC)); // measuring

  uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH  
  uint8_t high = ADCH; // unlocks both

  long result = (high<<8) | low;

  result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
  return result; // Vcc in millivolts
}

Взято тут

Может, кто подскажет структуру в приемнике, функцию приема и передачи принятой информации в структуру?

Спасибо за помощь!

maloicds
maloicds аватар
Offline
Зарегистрирован: 21.03.2013
roman2712@mail.ru
Offline
Зарегистрирован: 16.01.2014

Создание\обьявление структуры для данных 

struct struct_data
{ 
  byte adress; 
  byte data[16]; 
};
struct_data send_data;

Отправка в передатчике: radio.write( &send_data, sizeof(send_data) );

Прием в приемнике: radio.read( &send_data, sizeof(send_data) );

обращение к элементам

send_data.adress, send_data.data[0..16]

Все :)

 

 

.c8r
.c8r аватар
Offline
Зарегистрирован: 15.11.2011

roman2712@mail.ru пишет:

Создание\обьявление структуры для данных 

struct struct_data
{ 
  byte adress; 
  byte data[16]; 
};
struct_data send_data;

Отправка в передатчике: radio.write( &send_data, sizeof(send_data) );

Прием в приемнике: radio.read( &send_data, sizeof(send_data) );

обращение к элементам

send_data.adress, send_data.data[0..16]

Все :)

 

 

 

 

До этого я ес-но пробовал, не прокатило так просто. Сейчас еще разок попробую, может, чего из виду упустил. 

Проблема была следующая:

в структуре были int и массив, инт приходил нормально, а вот в массиве - мусор.

Ща оживлю в памяти

.c8r
.c8r аватар
Offline
Зарегистрирован: 15.11.2011

Хм, получилось. До этого я мучался с mirf, там были напряги с переменной буфера приема (тут на форуме обсуждалось вроде).

А вот с RF24 все завелось, спасибо, roman2712@ma

uncle_grin
Offline
Зарегистрирован: 26.04.2015

Вот, у меня работает метеостанция. Библиотека EasyTransferVirtualWire

Внешний блок, передатчик

#include <avr/wdt.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <BH1750FVI.h>        //датчик освещенности
#include <HTU21D.h>           //датчик влажности HTU21C
#include <VirtualWire.h>
#include <EasyTransferVirtualWire.h>


#define TX_PIN           7  // пин подключения передатчика
//*******************************************************************

BH1750FVI myBH1750;         // датчик освещенности BH1750FVI I2C
HTU21D myHTU21D;            // датчик влажности HTU21D I2C

//*********************************************************************
float OutTemperature = 0;   // Температура на улице
float OutHumidity = 0;      // Влажность на улице
float OutLight = 0;            // Освещенность на улице

bool interval = true;

// переменные и константы для таймеров
long timePreviousWDT = 0;       // таймер для сброса сторожевого таймера
long timePreviousSendInfo = 0;  // таймер для отправки данных на локальный экран

long PeriodWDT = 4000;                // интервал сброса таймера 4 секунды
long PeriodSendInfo = 30000;          // интервал отправки информации на дисплей 30 секунд


EasyTransferVirtualWire ET;
struct SEND_DATA_STRUCTURE{
  byte  ID;             // Идентификатор устройства
  float OutTemperature; // Температура снаружи
  float OutHumidity;    // Влажность снаружи
  float OutLight;       // Освещенность
  };
  SEND_DATA_STRUCTURE broadcast;

void setup() {
  // Инициализация сторожевого таймера (Watchdog timer)
  wdt_disable();
  delay(8000);
  wdt_enable(WDTO_8S);

  // **********************************************************************************
  // Инициализация консоли
  Serial.begin(9600);
  Serial.println(F("Serial Init"));
  
  // Инициализация модуля 433 мГц
  ET.begin(details(broadcast));
  vw_set_ptt_inverted(true);
  vw_set_tx_pin(TX_PIN); // для передачи нога № 7
  vw_setup(2000);
  Serial.println(F("Radio Init"));
  
  // Инициализация датчика HTU21D
  myHTU21D.begin() != true;  

  // Инициализация датчика BH1750
  myBH1750.begin() != true;
  myBH1750.setSensitivity(1.0);

  sensor_read();
  send_info();
  
  } // end setup

//********************************************************************


void loop(){
  // Каждые 4 секунды сбрасываем сторожевой таймер микроконтроллера
    if (millis()-timePreviousWDT >=PeriodWDT)
    {
      wdt_reset();
      timePreviousWDT = millis();
    }
    
// Каждые 30 секунд читаем данные с датчиков и отсылаем данные в эфир 433
    if (millis()-timePreviousSendInfo >= PeriodSendInfo)
    {
    sensor_read();
    send_info();
    timePreviousSendInfo = millis();
    }
    
  
} // end loop

//*************************************************************************************


 // функция опроса датчиков
void sensor_read() {

      // Получение освещенности с датчика BH1750 снаружи
      OutLight = myBH1750.readLightLevel();
      
      // Получение влажности и температуры с датчика HTU21D снаружи
      OutHumidity = myHTU21D.readHumidity();
      OutTemperature = myHTU21D.readTemperature();
    
      // отправка в последовательный порт (строки храняться во флэш-памяти контроллера)
      Serial.print(F("OutTemperature="));
      Serial.println(OutTemperature); // Температура снаружи
      Serial.print(F("OutHumidity="));
      Serial.println(OutHumidity);              // Влажность снаружи
      Serial.print(F("Light="));
      Serial.println(OutLight);          // Освещенность
      Serial.println(F("======================================="));     // разделитель
      Serial.println();     
      delay(250);
} // end sensor_read
//*************************************************************************************

// функция отправки информации по радио
void send_info() {
      // Отправляем данные в эфир 433 мГц
      broadcast.ID = 60;
      broadcast.OutTemperature = OutTemperature; // Температура снаружи
      broadcast.OutHumidity = OutHumidity;;              // Влажность снаружи
      broadcast.OutLight = OutLight;          // Освещенность
      ET.sendData();
      delay(1000); //delay(1000);
           
    }  //end send_info
//*************************************************************************************

Приемник:

#include <avr/wdt.h>
#include <VirtualWire.h>
#include <EasyTransferVirtualWire.h>
#include <Wire.h> 
//#include <LiquidCrystal_I2C.h>
#include <Adafruit_BMP280.h>  //датчик давления
#include <DHT.h>              //датчик влажности DHT22
#include <Ethernet.h>
#include <Adafruit_Sensor.h>
#include <SPI.h>


#define TX_PIN           7  // пин подключения приемника
#define DHTPIN           6        // пин подключения датчика влажности DHT22
#define DHTTYPE          DHT22    // тип датчика влажности DHT22/DHT11

//*******************************************************************

Adafruit_BMP280 bme;        // датчик давления BMP280 I2C
DHT dht(DHTPIN, DHTTYPE);   // ассоциация датчика влажности DHT22
//BH1750FVI myBH1750;       // датчик освещенности BH1750FVI I2C
//HTU21D myHTU21D;          // датчик влажности HTU21D I2C

//*********************************************************************
byte mac[] = {0x44, 0x74, 0x00, 0x00, 0x00, 0x00}; //MAC-адрес Arduino
char server[] = "narodmon.ru";
int port = 8283;

IPAddress ip(192,168,1,202);
EthernetClient client;
//*********************************************************************

float OutTemperature = 0;   // Температура на улице
float InTemperature = 0;    // Температура в помещении
float BlockTemperature;     // Температура в блоке
float Pressure = 0;         // Атмосферное давление
float InHumidity = 0;       // Влажность в помещении
float OutHumidity = 0;      // Влажность на улице
float OutLight = 0;            // Освещенность на улице

// 433 reciever data
EasyTransferVirtualWire ET;
struct SEND_DATA_STRUCTURE{
  byte  ID;             // Идентификатор устройства
  float OutTemperature; // Температура снаружи
  float OutHumidity;    // Влажность снаружи
  float OutLight;       // Освещенность
    };
  SEND_DATA_STRUCTURE broadcast;

  // переменные и константы для таймеров
long timePreviousWDT = 0;           // таймер для сброса сторожевого таймера
long timePreviousSendNarodmon = 0;  // таймер для отправки данных на NarodMon
long timePreviousReadSensor = 0;    // таймер для чтения датчиков

long PeriodWDT = 4000;                // интервал сброса таймера - 4 секунды
long PeriodReadSensor = 30000;        // интервал  чтения датчиков - 30 секунд
long PeriodSendNarodmon = 360000;     // интервал отправки информации на Narodmon - 6 минут

// Set the LCD address to 0x3F for a 20 chars and 4 line display
//LiquidCrystal_I2C lcd(0x3F, 20, 4);



void setup(){
   // Инициализация сторожевого таймера (Watchdog timer)
  wdt_disable();
  delay(8000);
  wdt_enable(WDTO_8S);

  
  Serial.begin(9600);

  // initialize the LCD
  //lcd.begin();
  //lcd.backlight();

  // Инициализация модуля 433 мГц
  ET.begin(details(broadcast));
  
  vw_set_ptt_inverted(true);
  vw_set_rx_pin(TX_PIN);
  vw_setup(2000);
  vw_rx_start();

  // Стартуем сеть, если не дождались данных с DHCP сервера то
  // присваеваем себе адрес самостоятельно
  if (Ethernet.begin(mac) == 0) Ethernet.begin(mac, ip);
  // Инициализация 1-Wire
  Wire.begin();
  delay(200);
  
  // Инициализация BMP280 с корректировкой высоты
  // dps.init(MODE_STANDARD, 3200, true);
  // Инициализация BMP280
  bme.begin();

  // Инициализация датчика DHT-22
  dht.begin();


}

void loop()  {
  // Каждые 4 секунды сбрасываем сторожевой таймер микроконтроллера
    if (millis()-timePreviousWDT >=PeriodWDT)
    {
      wdt_reset();
      timePreviousWDT = millis();
    }

    // Каждые 30 секунд читаем данные с датчиков и отсылаем данные в эфир 433
    if (millis()-timePreviousReadSensor >= PeriodReadSensor)
    {
    In_sensor_read();
    send_console();
    timePreviousReadSensor = millis();
    }
  
  if(ET.receiveData()){        // получение данных с внешних датчиков
                               // происходит по инициативе внешнего блока
    if(broadcast.ID == 60)  {
      OutTemperature = broadcast.OutTemperature;    // Температура на улице
      OutHumidity = broadcast.OutHumidity;          // Влажность на улице
      OutLight = broadcast.OutLight;                // Освещенность на улице
      }
     }

     // Каждые 6 минут отправляем данные на "Народный мониторинг"
    if (millis() - timePreviousSendNarodmon >= PeriodSendNarodmon)
    {
    send_narodmon();
    timePreviousSendNarodmon = millis();
    }
}


//*******************************************************************************************
void In_sensor_read() {
      // получение данных с внутренних датчиков
      // Получение давления и температуры с датчика BMP280 внутри блока
      Pressure = bme.readPressure()*0.007500637554192;      // давление в мм рт.ст.
      BlockTemperature = bme.readTemperature();

       // Получение влажности и температуры с датчика DHT22 внутри помещения
      InHumidity = dht.readHumidity(); 
      InTemperature = dht.readTemperature();
       
  }

//******************************************************************************************
  
  void send_narodmon() {
        // Подключаемся к серверу "Народный мониторинг"
        if(client.connect(server, port)) {
          Serial.print(F("Sending info to Narodmon"));
          // Начинаем передачу данных
          // адрес_устройства_в_проекте, имя_устройства, GPS широта, GPS долгота
          client.print(F("#44-74-00-00-00-00#Meteo\n"));
          // Температура снаружи
          client.print(F("#T1#"));
          client.print(OutTemperature);        
          client.print(F("#Температура\n"));
          // Влажность снаружи
          client.print(F("#H1#"));
          client.print(OutHumidity);
          client.print(F("#Влажность\n"));
          // Давление
          client.print(F("#P1#"));
          client.print(Pressure);
          client.print(F("#Давление\n"));
          // Освещенность
          client.print(F("#L1#"));
          client.print(OutLight);
          client.print(F("#Освещенность\n"));
          // Влажность в помещении
          client.print(F("#H2#"));
          client.print(InHumidity);
          client.print(F("#Влажность в помещении\n"));
          // Температура в помещении
          client.print("#T2#");
          client.print(InTemperature);        
          client.print(F("#Температура в помещении\n"));
          // Температура внутри блока
          client.print("#T3#");
          client.print(BlockTemperature);        
          client.print(F("#Температура в блоке\n"));
          // Отправляем конец телеграммы
          client.print(F("##"));
          Serial.print(F("End sending"));
        
          // Даем время отработать Ethernet модулю и разрываем соединение
          delay(250);
          client.stop();
        }
  }// end send_narodmon
  //***********************************************************************
  void send_console() {
      // отправка в последовательный порт (строки храняться во флэш-памяти контроллера)
      Serial.print(F("OutTemperature="));
      Serial.println(OutTemperature); // Температура снаружи
      Serial.print(F("OutHumidity="));
      Serial.println(OutHumidity);              // Влажность снаружи
      Serial.print(F("Pressure="));
      Serial.println(Pressure);     // Давление
      Serial.print(F("Light="));
      Serial.println(OutLight);          // Освещенность
      Serial.print(F("InTemperature="));
      Serial.println(InTemperature);  // Температура внутри
      Serial.print(F("InHumidity="));
      Serial.println(InHumidity);     // Влажность внутри
      Serial.print(F("BlockTemperature="));
      Serial.println(BlockTemperature);  // Температура внутри
      Serial.println(F("======================================="));     // разделитель
      Serial.println();     
      //delay(250);
} // end sensor_read