RF24 Array übertragung

Hallo :slight_smile: ,

ich möchte eine Ansammlung von 39 Messdaten in einem Array von einem Arduino zu einem anderen via RF24 versenden. Leider funktioniert das ganze nicht, ich weiß jedoch nicht mehr weiter, weil mir wohl noch Verständnis fehlt. Um das ganze simpel zu halten, habe ich sämtliche Messwerte durch konstante Zahlen ersetzt. Mit dem Code unten spuckt mir der Empfänger jedoch immer nur 0.00 aus. Die Funkverbindung bei Einzelwerten zwischen beiden Arduinos funktioniert. Könnte mir bitte jemand helfen das ganze mit einem Array hinzubekommen?

//Sender

#include <SPI.h>
#include <nRF24L01.h>
#include <printf.h>
#include <RF24.h>
#include <RF24_config.h>

double data=0;
unsigned long received;
unsigned long starttime;
byte package[32];
unsigned long dataset[40];
unsigned long payload;



RF24 radio(7,8);
/**********************************************************/
byte addresses[][6] = {"1Node","2Node"};
/**********************************************************/
void setup(){
  Serial.begin(57600);
  printf_begin();
  radio.begin();
  radio.setPALevel(RF24_PA_HIGH);
  radio.setDataRate(RF24_250KBPS); 
  radio.setAutoAck(1);
  radio.enableDynamicPayloads(); 
  radio.setCRCLength(RF24_CRC_8); 
  radio.enableAckPayload();
  radio.setRetries(0,30);
  radio.setPayloadSize(32);
  radio.openWritingPipe(addresses[1]);
  radio.openReadingPipe(1,addresses[0]);  
  radio.powerUp();
  radio.startListening();
  radio.printDetails();
}

void loop(){
starttime=millis();
    getData();
    }

void getData(){

  

  payload=millis()-starttime;  //Zeitstempel
  
  
  radio.powerUp();
  radio.stopListening();
  dataset[0]=payload;
  payload=(unsigned int)(1);
  dataset[1]=payload;
  payload=(unsigned int)(2);
  dataset[2]=payload;
  for(int i=0;i<16;i++){
  payload=(unsigned int)(3+i);
  if(payload>0)
  dataset[3+i]=payload;
  }
  payload=(unsigned int)(20);
  if(payload!=36172)
  dataset[19]=payload;

  for(int i=0;i<16;i++){
  payload=(unsigned int)(20+i);
  if(payload>0)
  dataset[20+i]=payload;
  }
  payload=(unsigned int)(37);
  if(payload!=36172)
  dataset[36]=payload;
  dataset[37]=payload;
  dataset[38]=payload;
  dataset[39]=123;


for(int i=0;i<16;i++){
  data=(double)dataset[i];
  Serial.print(data);
}
sendDataset(dataset);
 
radio.powerDown();
 
  }
 

void sendDataset(unsigned long load[40]){


  for(int i=0;i<5;i++){
    
    for(int j=0;j<8;j++){
    package[j*4+0]=(load[i*8+j]>>24) & 0xFF;
    package[j*4+1]=(load[i*8+j]>>16) & 0xFF;
    package[j*4+2]=(load[i*8+j]>>8) & 0xFF;
    package[j*4+3]=load[i*8+j] & 0xFF;



    }
  radio.writeFast(&package,32);
  radio.txStandBy();
  }



  
}




void sendData(unsigned long load){



  radio.writeFast(&load,sizeof(unsigned long));
  radio.txStandBy();

  
}
//Empfänger

#include <SPI.h>
#include <nRF24L01.h>
#include <printf.h>
#include <RF24.h>
#include <RF24_config.h>
/**********************************************************/
double data=0;
unsigned long received;
unsigned long dataset[40];
byte package[32];
RF24 radio(7,8);
/**********************************************************/
byte addresses[][6] = {"1Node","2Node"};
/**********************************************************/
void setup() {
  Serial.begin(57600);
  printf_begin();
  radio.begin();
  radio.setPALevel(RF24_PA_HIGH);
  radio.setDataRate(RF24_250KBPS);
  radio.setAutoAck(1);
  radio.enableDynamicPayloads();  
  radio.setCRCLength(RF24_CRC_8);
  radio.enableAckPayload();
  radio.setRetries(1,15);
  radio.setPayloadSize(32);
  radio.openWritingPipe(addresses[0]);
  radio.openReadingPipe(1,addresses[1]);
  radio.powerUp();
  radio.startListening();
  radio.printDetails();
}
void loop() {
if(radio.available()){
    int reads=0;
        while(reads<5){
                                                                   
        if(radio.available()){                                                           
        radio.read( &package, 32 );
        for(int j=0;j<8;j++){
          
          dataset[reads*8+j]= (unsigned long)package[j*4];
          dataset[reads*8+j]= dataset[reads*8+j]<<8 | (unsigned long)package[j*4+1];
          dataset[reads*8+j]= dataset[reads*8+j]<<8 | (unsigned long)package[j*4+2];
          dataset[reads*8+j]= dataset[reads*8+j]<<8 | (unsigned long)package[j*4+3];
          
        }
        reads++;
        }
        
        }  }
for(int i=0;i<40;i++){
data=(double)dataset[i];
Serial.print(data);
Serial.print("");}
Serial.println("");
}

unsigned long dataset[40];

Das soll versendet werden?

Dann wirst du das in Häppchen hacken müssen. Denn der NRF24L01+ kann nur Häppchen senden.

Hi,

übertragen soll/wird package[32]. Da der nrf24L01+ ja nur ein payloadsize von 32 unterstützt, wird der Inhalt von dataset40 über die Funktion sendDataset zunächst in dieses package[32] gepackt,d.h. ein 32 byte Zahl wird in 4 Teile verpackt, und dann verschickt. Darauf willst du hinaus oder?

OK…

Dann habe ich das übersehen.
Oder besser gesagt, nicht als solches erkannt…
(wohl auch, weil ich nie auf eine solche Idee kommen würde)

Eigentlich kannst du dir das fehlerträchtige umkopieren vollständig einsparen, denn die Daten sind ja schon in einem Array.
Oder übersehe ich schon wieder irgendwas…?

Es sollte auch die Frage geklärt werden, ob die Messdaten wirklich unsigned long sind /sein müssen. Ich bin da skeptisch.

Gruß Tommy

Die Messdaten werden von versch. Sensoren gesammelt. Einerseits ist dort die Zeit in ms, wie lang eine Messung geht weiß ich noch nicht. Dazu kommt mind. 34x Temperatur im 2-3 Stelligen Bereich mit 2 Nachkommastellen und Druckmessung bis 11000mbar. Natürlich könnte man ein paar Umrechungen machen, um die Zahlen zunächst deutlich kleiner zu übermitteln und beim Empfänger wieder umzuwandeln.

Dennoch weiß ich nicht, warum das ganze momentan mit den Zahlen, die im Code stehen, nicht funktioniert. Darum gehts mir in erster Linie.

Hi

11000mbar wäre als Zahl 11000 - passt in ein int (16bit, signed, zumindest auf dem Arduino). 3-stellig (wie hoch 3-stellig?) mit 2 Nachkommastellen - x 100 sind die Kommastellen weg, wenn Dir 326°C in Plus und Minus reichen, wäre auch hier ein int ausreichend. (in Minus-Richtung wird Dir Das dicke reichen, man könnte also hier auch den Messbereich verschieben, daß die tiefste zu erfassende Temperatur 0 als Wert bekommt) Messzeit wird wohl nur positiv sein - da wäre ein int unsigned mit 65 Sekunden 'Zeit' wohl auch dicke ausreichend - bei einem Byte (ist eh unsigned) hättest Du 255ms 'Zeit' - Was ggf. etwas knapp sein könnte.

Was aber an der eigentlichen Übertragung Nichts ändert - auch größere Zahlenkolonnen wollen übertragen werden können.

MfG

Schau mal hier daran habe ich mich mal orientiert.https://forum.arduino.cc/index.php?topic=384388.0

Dennoch weiß ich nicht, warum das ganze momentan mit den Zahlen, die im Code stehen, nicht funktioniert. Darum gehts mir in erster Linie.

Ich habe deinen Sender mal aufgeräumt!
Testen kann ich nicht…
Und auf Sinnhaftigkeit habe ich auch nicht geprüft.

//Sender

#include <SPI.h>
#include <printf.h>
#include <RF24.h>

using ArrayType = unsigned long [40];

unsigned long starttime;
ArrayType dataset;



RF24 radio(7,8);
/**********************************************************/
byte addresses[][6] = {"1Node","2Node"};
/**********************************************************/
void setup()
{
  Serial.begin(57600);
  printf_begin();
  radio.begin();
  radio.setPALevel(RF24_PA_HIGH);
  radio.setDataRate(RF24_250KBPS); 
  radio.setAutoAck(1);
  radio.enableDynamicPayloads(); 
  radio.setCRCLength(RF24_CRC_8); 
  radio.enableAckPayload();
  radio.setRetries(0,30);
  radio.setPayloadSize(32);
  radio.openWritingPipe(addresses[1]);
  radio.openReadingPipe(1,addresses[0]);  
  radio.powerUp();
  radio.startListening();
  radio.printDetails();
}

void loop()
{
  starttime=millis();
  getData();
}

void getData()
{
  unsigned long payload;
  double data=0;

  payload=millis()-starttime;  //Zeitstempel
  radio.powerUp();
  radio.stopListening();
  dataset[0]=payload;
  payload=(unsigned int)(1);
  dataset[1]=payload;
  payload=(unsigned int)(2);
  dataset[2]=payload;
  for(int i=0;i<16;i++)
  {
    payload=(unsigned int)(3+i);
    if(payload>0)  dataset[3+i]=payload;
  }
  payload=(unsigned int)(20);
  if(payload!=36172) dataset[19]=payload;

  for(int i=0;i<16;i++)
  {
    payload=(unsigned int)(20+i);
    if(payload>0) dataset[20+i]=payload;
  }
  
  payload=(unsigned int)(37);
  if(payload!=36172) dataset[36]=payload;
  dataset[37]=payload;
  dataset[38]=payload;
  dataset[39]=123;

  for(int i=0;i<16;i++)
  {
    data=(double)dataset[i];
    Serial.print(data);
  }
  sendDataset(dataset);
  radio.powerDown();
}
 

void sendDataset(const ArrayType &load)
{
  size_t zusendende = sizeof(load);
  byte *ptr = (byte*)load;
  while(zusendende)
  {
    size_t blocksize = min(32,zusendende);
    radio.writeFast(ptr,blocksize);
    radio.txStandBy();
    zusendende -= blocksize;
    ptr += blocksize;
  }
}

Danke, probier ich morgen früh mal aus. Muss man jetzt noch was am Empfängercode anpassen oder sollte das auch so laufen?

JoE1205: Muss man jetzt noch was am Empfängercode anpassen oder sollte das auch so laufen?

Den Empfänger habe ich mir noch nicht angesehen. Den überlasse ich erst mal dir, als Baustelle.....

Auch vermisse ich noch irgendeine Form der Synchronisation. So das der Empfänger auch erkennt, WO/WANN ein neuer Datenbereich beginnt.

Hi, hab noch ein paar fragen zu deiner Änderung. Inwiefern zerstückelt mir die Funktion sendDataset jetzt den array bzw. was genau macht die Zeile:

  byte *ptr = (byte*)load;

byte *ptr = …

Erzeugt einen Zeiger auf ein Byte
Welcher dann im folgenden genutzt wird.

… = (byte*)load;

Castet den übergebenen Zeiger, von einem Zeiger auf unsigned long, zu einem Zeiger auf byte.

Nach der Zeile zeigen sowohl load, als auch ptr auf die selbe Stelle im Speicher.
Nur, dass load dort unsigned long Daten an der Stelle erwartet, und ptr byte sieht dort Bytes.

Evt. wäre dieses schöner:

byte *ptr = reinterpret_cast<byte*>(&load);

So hab mal den Empfänger angepasst, jedenfalls insofern wie ich das ganze verstanden hab.
Ich versteh jedoch einige Sache nicht so ganz, weil ich nicht sonderlich viel Erfahrung mit C++ hab. Ausprobieren kann ich es leider erst später

//Empfänger

#include <SPI.h>
#include <printf.h>
#include <RF24.h>

/**********************************************************/
using ArrayType = unsigned long [40];
ArrayType load;
byte ptr[32];
double data=0;

RF24 radio(7,8);
/**********************************************************/
byte addresses[][6] = {"1Node","2Node"};
/**********************************************************/
void setup() {
Serial.begin(57600);
printf_begin();
  radio.begin();
  radio.setPALevel(RF24_PA_HIGH);
  radio.setDataRate(RF24_250KBPS);
  radio.setAutoAck(1);
  radio.enableDynamicPayloads();  
  radio.setCRCLength(RF24_CRC_8);
  radio.enableAckPayload();
  radio.setRetries(1,15);
  radio.setPayloadSize(32);
  radio.openWritingPipe(addresses[0]);
  radio.openReadingPipe(1,addresses[1]);
  radio.powerUp();
  radio.startListening();
  radio.printDetails();
}
void loop() {
if(radio.available()){                                                          
        radio.read( &ptr, 32 );
  while(radio.available()){
    for(int i=0;i<40;i++){
    data=(double)ptr[i];
    Serial.print(data);
    Serial.print("");}
        }}
Serial.println("");
}

Der NRF24L01 kann nur 32 Bytes pro pipe senden. Aber er kann 5 pipes + 1pipe für Acknowledge.
Kannst Du alles in 5*32 bytes packen? Dann würde ich alle 5 pipes verwenden.

NRF24 Pipe Discussion.

P.S. Man muss auch berücksichtigen dass der NRF24L01 bei NACK des Empfängers von sich aus eine erneute Übertragung startet.
Wenn man Frames mit Zeiger sendet muss man sicherstellen, dass die vorherige Übertragung beendet war, sonnst kommt schon der Sender durcheinander.

Wieso sollte es denn möglich sein ptr zu übertragen? Verweist der Pointer * nicht nur auf die lokale adresse von load. Mit anderen worten der andere Microcontroller kann damit nichts anfangen?

 byte *ptr = (byte*)load;

Es ist nicht der Zeiger der übertragen wird. Sondern das Byte auf das er zeigt. Dabei geht es nur darum dass man beliebige Datentypen als eine Reihe von Bytes ansprechen kann

Verweist der Pointer * nicht nur auf die lokale adresse von load.

Da hast du vollkommen Wahr!

Bemerke: radio.writeFast(); erwartet einen Zeiger auf die zu übertragenen Daten. Das load Array ist genau das, was du übertragen möchtest. Und du selber machtest ja auch nichts anderes, als die Adresse/Zeiger auf dein zusammengesetztes Array zu übergeben.

Mit anderen worten der andere Microcontroller kann damit nichts anfangen?

Auch hier hast du vollkommen Wahr! Allerdings bekommt der andere Arduino die Adresse gar nicht zu sehen. Also kann damit auch kein Mist passieren.