nRF24L01 not receiving messages from multiple slaves

Hi,
I'm creating something like a feedback system and i have problem with receiving data from slaves, here is my code.
Master:

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


#define CE_PIN   7
#define CSN_PIN 8

const byte numSlaves = 3;
const byte slaveAddresses[numSlaves][5] = {
  {'R', 'x', 'A', 'A', 'A'},
  {'R', 'x', 'A', 'A', 'B'},
  {'R', 'x', 'A', 'A', 'C'}
};
const byte masterAddress[numSlaves][5] = {
  {'T', 'X', 'a', 'a', 'a'},
  {'T', 'X', 'a', 'a', 'b'},
  {'T', 'X', 'a', 'a', 'c'}
};

RF24 radio(CE_PIN, CSN_PIN); // Create a Radio

char dataToSend[31] = "hello?";
int dataReceived[1];
bool newData = false;
bool rslt;

uint32_t period = 12000L;
uint32_t period2 = 3000L;
//============

void setup() {
  Serial.begin(9600);
  Serial.println("MasterSwapRoles Starting");

  radio.begin();
  radio.setDataRate( RF24_250KBPS );

  //radio.openReadingPipe(1, masterAddress);
  radio.openReadingPipe(1, masterAddress[0]);
  radio.openReadingPipe(2, masterAddress[1]);
  radio.openReadingPipe(3, masterAddress[2]);
  radio.setRetries(3, 5); // delay, count
  pinMode(3, INPUT);
}

//=============

void loop() {
  if (digitalRead(3) == HIGH) {
    send();
    for (uint32_t tStart = millis();  (millis() - tStart) < period;);
    Serial.print("\nStart listening\n");
    radio.startListening();
    getData();
    //showData();
  }
}

//====================

void send() {
  for (byte n = 0; n < numSlaves; n++) {
    radio.stopListening();
    radio.openWritingPipe(slaveAddresses[n]);
    rslt = radio.write( &dataToSend, sizeof(dataToSend) );
    //radio.startListening();
    Serial.print("Wysłano: ");
    Serial.print(dataToSend);
    Serial.print("     to slave: ");
    Serial.println(n + 1);
    if (rslt) {
      Serial.println("  Success");
    }
    else {
      Serial.println("  Error");
    }
  }
}

//================

void getData() {
  for (uint32_t tStart = millis();  (millis() - tStart) < period2;) {
    for (byte n = 0; n < numSlaves; n++) {
      if ( radio.available(&n + 1) ) {
        radio.read( &dataReceived, sizeof(dataReceived) );
        Serial.print("\nfrom slave: ");
        Serial.println(n + 1);
        newData = true;
        showData();
      }
    }
  }
  Serial.print("------------------------------------------------\n");
}

//================

void showData() {
  if (newData == true) {
    Serial.print("  Received: ");
    if (dataReceived[0] == 1) {
      Serial.print("YES\n");
    }
    else if (dataReceived[0] == 2) {
      Serial.print("NO\n");
    }
    else if (dataReceived[0] == 3) {
      Serial.print("HOLDING\n");
    }
    else {
      Serial.print("NO VOTE\n");
    }
    newData = false;
  }
}

Slave1:

// SlaveSwapRoles

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


#define CE_PIN   7
#define CSN_PIN 8

const byte slaveAddress[5] = {'R', 'x', 'A', 'A', 'A'};
const byte masterAddress[5] = {'T', 'X', 'a', 'a', 'a'};

RF24 radio(CE_PIN, CSN_PIN);

char dataReceived[31];
int replyData[1];
bool newData = false;
bool rslt;

uint32_t period = 10000L;

void setup() {

  Serial.begin(9600);

  Serial.println("SlaveSwapRoles Starting");

  radio.begin();
  radio.setDataRate( RF24_250KBPS );

  radio.openWritingPipe(masterAddress);
  radio.openReadingPipe(1, slaveAddress);

  radio.setRetries(3, 5); // delay, count
  radio.startListening();

  pinMode(3, INPUT); //tak / yes
  pinMode(4, INPUT); //nie / no
  pinMode(5, INPUT); //wstrzymuje sie /holding
}

//====================

void loop() {
  getData();
  if (newData == true) {
    showData();
    vote();
    send();
  }
}

//====================

void send() {
  if (newData == true) {
    radio.stopListening();
    rslt = radio.write( &replyData, sizeof(replyData) );
    radio.startListening();

    Serial.print("Wysłano: ");
    Serial.print(replyData[0]);

    if (rslt) {
      Serial.println("   Success");
    }
    else {
      Serial.println("Error");
    }
    Serial.println();
    newData = false;
  }
}

//================

void getData() {
  if ( radio.available() ) {
    radio.read( &dataReceived, sizeof(dataReceived) );
    newData = true;
  }
}

//================

void showData() {
    Serial.print("Received: ");
    Serial.println(dataReceived);
}

//================

void vote() {
  for (uint32_t tStart = millis();  (millis() - tStart) < period;) {
    if (digitalRead(3) == HIGH) {
      replyData[0] = 1;
    }
    else if (digitalRead(4) == HIGH) {
      replyData[0] = 2;
    }
    else if (digitalRead(5) == HIGH) {
      replyData[0] = 3;
    }
  }
}

Slave2:

// SlaveSwapRoles

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


#define CE_PIN   7
#define CSN_PIN 8

const byte slaveAddress[5] = {'R', 'x', 'A', 'A', 'B'};
const byte masterAddress[5] = {'T', 'X', 'a', 'a', 'b'};

RF24 radio(CE_PIN, CSN_PIN); // Create a Radio

char dataReceived[31]; // must match dataToSend in master
int replyData[1]; // the two values to be sent to the master
bool newData = false;
bool rslt;

uint32_t period = 10000L;

void setup() {

  Serial.begin(9600);

  Serial.println("SlaveSwapRoles Starting");

  radio.begin();
  radio.setDataRate( RF24_250KBPS );

  radio.openWritingPipe(masterAddress); // NB these are swapped compared to the master
  radio.openReadingPipe(1, slaveAddress);

  radio.setRetries(3, 5); // delay, count
  radio.startListening();

  pinMode(3, INPUT); //tak
  pinMode(4, INPUT); //nie
  pinMode(5, INPUT); //wstrzymuje sie
}

//====================

void loop() {
  getData();
  if (newData == true) {
    showData();
    vote();
    send();
  }
}

//====================

void send() {
  if (newData == true) {
    radio.stopListening();
    rslt = radio.write( &replyData, sizeof(replyData) );
    radio.startListening();

    Serial.print("Wysłano: ");
    Serial.print(replyData[0]);

    if (rslt) {
      Serial.println("   Powodzenie");
    }
    else {
      Serial.println("Blad wysylania.");
    }
    Serial.println();
    newData = false;
  }
}

//================

void getData() {

  if ( radio.available() ) {
    radio.read( &dataReceived, sizeof(dataReceived) );
    newData = true;
  }
}

//================

void showData() {
    Serial.print("Otrzymano: ");
    Serial.println(dataReceived);
}

//================

void vote() {
  for (uint32_t tStart = millis();  (millis() - tStart) < period;) {
    if (digitalRead(3) == HIGH) {
      replyData[0] = 1;
    }
    else if (digitalRead(4) == HIGH) {
      replyData[0] = 2;
    }
    else if (digitalRead(5) == HIGH) {
      replyData[0] = 3;
    }
  }
}

Master module should send a message to all slaves when button is clicked (this part is working), then It sould wait till voting is complete and read data that was send by slaves.
I can't collect data from all slaves, only one. Could you pleeease help me? :wink:

Also I've used code from Simple nRF24L01+Tutorial from second reply.

You are using three pipes,

but the used pipe addresses are invalid for that purpose,
pipe 1 and pipe 2 don't have a common high part.

try

const byte slaveAddresses[numSlaves][5] = {
  {'A', 'R', 'x', 'A', 'A'},
  {'B', 'R', 'x', 'A', 'A'},
  {'C', 'R', 'x', 'A', 'A'}
};
const byte masterAddress[numSlaves][5] = {
  {'a','T', 'X', 'a', 'a'},
  {'b','T', 'X', 'a', 'a'},
  {'c','T', 'X', 'a', 'a'}
};
1 Like

This statement is nonsensical.

You should re-examine the documentation of available(&).

1 Like

@Whandall I don't know if i understand this correctly but:

bool RF24::available	(	uint8_t * 	pipe_num	)	
Test whether there are bytes available to be read.

Use this version to discover on which pipe the message arrived.

Parameters:
[out]	pipe_num	Which pipe has the payload available
Returns:
True if there is a payload available, false if none is

It means that I check if there is any data waiting on specific pipe, am I wrong?

Yes you are wrong.

available() returns true if a packet is pending, and if, the passed variable gets set to the pipe it was received on.

You try to filter the packets, which is backwards and does not work.

In your code you even overwrite memory with the &n +1 (n being a byte).
You need a different strategy to check for all responses.

Btw I see no benefit in your three pipe approach, with the different strategy the returned pipe number could be used to index something, so there would be at least some benefit.
Using three pipes does not really parallelize anything,
like three mail boxes don't create three postmen.

I very much dislike your blocking approach and I think it does not help you in any way.

for (uint32_t tStart = millis();  (millis() - tStart) < period;);

This is delay, if you insist to use it, don't disguise it.

It's even more like one mailbox with three slots to drop in letters that will just pile up.

Ok, in a NRF the pile is only three elements high,
but you should remove them from the pile as fast as possible anyway.

Well I eventually came up with something like this:

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


#define CE_PIN   7
#define CSN_PIN 8

const byte numSlaves = 3;
const byte slaveAddresses[numSlaves][5] = {
  {'A', 'R', 'x', 'A', 'A'},
  {'B', 'R', 'x', 'A', 'A'},
  {'C', 'R', 'x', 'A', 'A'}
};
const byte masterAddress[numSlaves][5] = {
  {'a','T', 'X', 'a', 'a'},
  {'b','T', 'X', 'a', 'a'},
  {'c','T', 'X', 'a', 'a'}
};

RF24 radio(CE_PIN, CSN_PIN); // Create a Radio

char dataToSend[31] = "hello?";
int dataReceived[1];
int data[3];
bool newData = false;
bool rslt;

uint32_t period = 12000L;
uint32_t period2 = 3000L;
//============

void setup() {
  Serial.begin(9600);
  Serial.println("MasterSwapRoles Starting");

  radio.begin();
  radio.setDataRate( RF24_250KBPS );

  //radio.openReadingPipe(1, masterAddress);
  radio.openReadingPipe(1, masterAddress[0]);
  radio.openReadingPipe(2, masterAddress[1]);
  radio.openReadingPipe(3, masterAddress[2]);
  radio.setRetries(3, 5); // delay, count
  pinMode(3, INPUT);
}

//=============

void loop() {
  if (digitalRead(3) == HIGH) {
    send();
    radio.startListening();
    for (uint32_t tStart = millis();  (millis() - tStart) < period;);
    getData();
    for (int x = 0; x<3; x++){
      Serial.print("stan: ");
      Serial.print(data[x]);
      Serial.println();
    }
    //showData();
  }
}

//====================

void send() {
  for (byte n = 0; n < numSlaves; n++) {
    radio.stopListening();
    radio.openWritingPipe(slaveAddresses[n]);
    rslt = radio.write( &dataToSend, sizeof(dataToSend) );
    //radio.startListening();
    Serial.print("Wysłano: ");
    Serial.print(dataToSend);
    Serial.print("     to slave: ");
    Serial.println(n + 1);
    if (rslt) {
      Serial.println("  Success");
    }
    else {
      Serial.println("  Error");
    }
  }
}

//================

void getData() {
  for (uint32_t tStart = millis();  (millis() - tStart) < period2;) {
    for (byte n = 0; n < numSlaves; n++) {
      if ( radio.available() ) {
        radio.read( &dataReceived, sizeof(dataReceived) );
        data[n] = dataReceived[0];
        Serial.print("\nfrom slave: ");
        Serial.println(n + 1);
        newData = true;
        showData();
      }
    }
  }
  Serial.print("------------------------------------------------\n");
}

//================

void showData() {
  if (newData == true) {
    Serial.print("  Received: ");
    if (dataReceived[0] == 1) {
      Serial.print("YES\n");
    }
    else if (dataReceived[0] == 2) {
      Serial.print("NO\n");
    }
    else if (dataReceived[0] == 3) {
      Serial.print("HOLDING\n");
    }
    else {
      Serial.print("NO VOTE\n");
    }
    newData = false;
  }
}

And It is working well. I don t know how to do it without theree pipes. If you know any better solution i would be gratefull to see it.
About this:

for (uint32_t tStart = millis();  (millis() - tStart) < period;);

Yes i should use delay here, I used this function in slave to be able to "vote" for 10 seconds and I brainlessly copied it...
Thanks for help anyways :wink:

I doubt that.

    for (byte n = 0; n < numSlaves; n++) {
      if ( radio.available() ) {
        radio.read( &dataReceived, sizeof(dataReceived) );
        data[n] = dataReceived[0];
        Serial.print("\nfrom slave: ");
        Serial.println(n + 1);
        newData = true;
        showData();
      }
    }

You have to be very lucky to get all three packets before the loop starts or it will just skip later ones.

There is no guarantee about the order of your packets.

You try to use the pipe feature to distinguish packets, but fail.
I would send all packets to the same vote slot and have an identification inside the packet.

Likewise I would send the "you may vote now" as a multicast, again to a single address.

I would suggest not to use any delays or for loops.

Your receiving for loop can not serve more than three clients, which is another bummer.

A simple state machine for the "master" would be the best solution.

You have to be very lucky to get all three packets before the loop starts or it will just skip later ones.

That s why i start reading 2 sec after slaves send their data. Also the order doesn t matter here.

I will try to implement this in other way as you said. Thanks for help ;d