Communication between one base station and two slaves with the NRF24l01

Hello guys,
I have been working on this for a while and I didn't get a result so I hope someone can help me out with this.
My main project is an autonomous irrigation system based on a wireless sensors network. For now I want my base station to communicate with 2 nodes (as a test).
I tried to send a request from the base station to the 2 nodes sequentially but I doesn't work even one node sends or the data is not sent well, I have added the capacitors but it seems not to be the problem.

Have a look at this Simple nRF24L01+ Tutorial - I recently added an example that does what you want.

...R

I am working on it, but I get always "Tx failed" even though the slaves receive data, really I don't get it ...

Here is the problem !!!

Image from Reply #3 so we don't have to download it. See this Image Guide

...R

Please post the code that YOU uploaded to your two Arduinos and please post the output as text (copy and paste) rather than as a picture.

In case you have not done so, please start by getting communication working between two Arduinos.

And when posting code please use the code button </>so your code looks like thisand is easy to copy to a text editor See How to use the Forum

...R

Here are the codes (I didn't change mush)
This is the base station code

// MultiTxAckPayload - the master or the transmitter
//   works with two Arduinos as slaves
//     each slave should the SimpleRxAckPayload program
//       one with the adress {'R','x','A','A','A'}
//         and the other with {'R','x','A','A','B'}

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


#define CE_PIN   7
#define CSN_PIN 8

const byte numSlaves = 2;
const uint64_t rAddress[] = {0xB00B1E50D2LL, 0xB00B1E50D3LL};

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

//~ char dataToSend[10] = "Message 0";
byte dataToSend;
float ackData=0; // to hold the two values coming from the slave
bool newData = false;

unsigned long currentMillis;
unsigned long prevMillis;
unsigned long txIntervalMillis = 3000; // send once per second

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

void setup() {

    Serial.begin(9600);
    Serial.println("Starting...");
    radio.begin();
    radio.setChannel(100);
    radio.setDataRate( RF24_250KBPS );
    radio.enableAckPayload();
    radio.setRetries(3,5); // delay, count
        // radio.openWritingPipe(slaveAddress); -- moved to loop()
}

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

void loop() {

    currentMillis = millis();
    if (currentMillis - prevMillis >= txIntervalMillis) {
        send();
    }
        // showData(); -- moved into send()
}

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

void send() {

        // call each slave in turn
    for (byte n = 0; n < numSlaves; n++){

            // open the writing pipe with the address of a slave
        radio.openWritingPipe(rAddress[n]);

            // include the slave number in the message
        dataToSend = n+1;
        
        bool rslt;
        rslt = radio.write( &dataToSend, sizeof(dataToSend) );
            // Always use sizeof() as it gives the size as the number of bytes.
            // For example if dataToSend was an int sizeof() would correctly return 2
 if (rslt) {
            if ( radio.isAckPayloadAvailable() ) {
                radio.read(&ackData, sizeof(ackData));
                newData = true;
            }
            else {
                Serial.println("  Acknowledge but no data ");
            }
            
        }
        else {
            Serial.println("  Tx failed");
        }
        Serial.print("  ========  For Slave ");
        Serial.print(n);
        Serial.println("  ========");
        Serial.print("  Data Sent ");
        Serial.print(dataToSend);
       
        showData();
        Serial.print("\n");
    }

    prevMillis = millis();
 }


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

void showData() {
    if (newData == true) {
        Serial.print("  Acknowledge data ");
        Serial.println(ackData);
        newData = false;
    }
}

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

This is the code of the first slave

// SimpleRx - the slave or the receiver

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

#define CE_PIN   7
#define CSN_PIN 8

const uint64_t rAddress=0xB00B1E50D2LL;
RF24 radio(CE_PIN, CSN_PIN);

byte dataReceived; // this must match dataToSend in the TX
float ackData = 100; // the two values to be sent to the master
bool newData = false;

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

void setup() {

    Serial.begin(9600);

    Serial.println("SimpleRxAckPayload Starting");
    radio.begin();
    radio.setDataRate( RF24_250KBPS );
        radio.setChannel(100);

    radio.openReadingPipe(1, rAddress);

    radio.enableAckPayload();
    radio.writeAckPayload(1, &ackData, sizeof(ackData)); // pre-load data

    radio.startListening();
}

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

void loop() {
    getData();
    showData();
}

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

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

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

void showData() {
    if (newData == true) {
        Serial.print("Data received ");
        Serial.print("Slave ");
        Serial.println(dataReceived);
        Serial.print(" ackPayload sent ");
        Serial.println(ackData);
        newData = false;
    }
}

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

void updateReplyData() {
    ackData += 1;
    if (ackData == 1000) {
        ackData = 100;
    }
    radio.writeAckPayload(1, &ackData, sizeof(ackData)); // load the payload for the next time
}

The second slave is the same as the first (difference in address)

CHEGGARI:
Here are the codes (I didn't change mush)

First of all get it working without changing ANYTHING. Then if it does not work I will try to help.

When the basic example works it will be time to try changing things.

...R

Even the original code doesn't work, it gave me the same thing :frowning:

CHEGGARI:
Even the original code doesn't work, it gave me the same thing :frowning:

Post the two programs that YOU uploaded to your Arduinos and post some examples of the output. I can't help without your co-operation.

Have you wired everything as in my Tutotrial?

Wireless problems can be very difficult to debug so a very methodical approach is essential.

...R

It workeeed :slight_smile: , I have added the capacitor for the master (I already used 2 capacitors for the slaves),
Thanks a lot for your support and Tutorial.

Thanks for the feedback, and the kind words.

...R

After the first step (communication between a master and 2 slaves), I am working on a network of slaves in which I have to transmit a request from the master to the slave chosen. I've tried this with the previous method but it doesn't work
The master code

// MultiTxAckPayload - the master or the transmitter
//   works with two Arduinos as slaves
//     each slave should the SimpleRxAckPayload program
//       one with the adress {'R','x','A','A','A'}
//         and the other with {'R','x','A','A','B'}

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


#define CE_PIN   7
#define CSN_PIN 8

const byte numSlaves = 2;
const uint64_t rAddress[] = {0xB00B1E50D1LL};

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

//~ char dataToSend[10] = "Message 0";
byte dataToSend;
float ackData=0; // to hold the two values coming from the slave
bool newData = false;

unsigned long currentMillis;
unsigned long prevMillis;
unsigned long txIntervalMillis = 3000; // send once per second

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

void setup() {

    Serial.begin(9600);
    Serial.println("Starting...");
    radio.begin();
    radio.setChannel(100);
    radio.setDataRate( RF24_250KBPS );
    radio.enableAckPayload();
    radio.setRetries(3,5); // delay, count
        // radio.openWritingPipe(slaveAddress); -- moved to loop()
}

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

void loop() {

    currentMillis = millis();
    if (currentMillis - prevMillis >= txIntervalMillis) {
        send();
    }
        // showData(); -- moved into send()
}

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

void send() {

        // call each slave in turn
   // for (byte n = 0; n < numSlaves-1; n++){

            // open the writing pipe with the address of a slave
        radio.openWritingPipe(rAddress[0]);

            // include the slave number in the message
        dataToSend = 1;
        
        bool rslt;
        rslt = radio.write( &dataToSend, sizeof(dataToSend) );
            // Always use sizeof() as it gives the size as the number of bytes.
            // For example if dataToSend was an int sizeof() would correctly return 2
        Serial.print("  ========  For Slave ");
        Serial.print(1);
        Serial.println("  ========");
        Serial.print("  Data Sent ");
        Serial.print(dataToSend);
       if (rslt) {
         
            if( radio.isAckPayloadAvailable() )
            {
                radio.read(&ackData, sizeof(ackData));
                newData = true;
            }
            else {
                Serial.println("  Acknowledge but no data ");
            }
            
        }
        else {
            Serial.println("  Tx failed");
        }
        
       
        showData();
        Serial.print("\n");
    

    prevMillis = millis();
 }


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

void showData() {
    if (newData == true) {
        Serial.print("  Acknowledge data ");
        Serial.println(ackData);
        newData = false;
    }
}

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

The slave 1 code

// SimpleRx - the slave or the receiver

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

#define CE_PIN   7
#define CSN_PIN 8

const uint64_t rAddress[]={0xB00B1E50D1LL,0xB00B1E50D3LL};
RF24 radio(CE_PIN, CSN_PIN);
byte dataToSend=2;
byte dataReceived; // this must match dataToSend in the TX
float ackData1 = 0;
float ackData2 = 200;// the two values to be sent to the master
bool newData = false;

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

void setup() {

    Serial.begin(9600);

    Serial.println("SimpleRxAckPayload Starting");
    radio.begin();
    radio.setChannel(100);
    radio.setDataRate( RF24_250KBPS );
    radio.openReadingPipe(1, rAddress[0]);
    //radio.openReadingPipe(2, rAddress[1]);
    radio.enableAckPayload();
    radio.writeAckPayload(1, &ackData2, sizeof(ackData2)); // pre-load data
    radio.startListening();
}

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

void loop() {
    getData();
    showData();
    radio.startListening();
}

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

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

//================
void send_data()
{  radio.stopListening();
   radio.openWritingPipe(rAddress[1]);
  bool rslt;
        rslt = radio.write( &dataToSend, sizeof(dataToSend) );
  if (rslt) {
            if( radio.isAckPayloadAvailable() )
            {
                radio.read(&ackData1, sizeof(ackData1));
                newData = true;
            }
            else {
                Serial.println("  Acknowledge but no data ");
            }
            
        }
        else {
            Serial.println("  Tx failed");
        }


}

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

void showData() {
    if (newData == true) {
        Serial.print("Data received ");
        Serial.print("Slave ");
        Serial.println(dataReceived);
        send_data(); 
        Serial.print("  Acknowledge data ");
        Serial.println(ackData1);
        updateReplyData(); 
        Serial.print(" ackPayload sent ");
        Serial.println(ackData2);
        newData = false;
        }
    //}
}

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

void updateReplyData() {
    ackData2 += 1;
    if (ackData2 == 1000) {
        ackData2 = 100;
    }
    radio.writeAckPayload(1, &ackData2, sizeof(ackData2)); // load the payload for the next time
}

And the slave 2 code

// SimpleRx - the slave or the receiver

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

#define CE_PIN   7
#define CSN_PIN 8

const uint64_t rAddress[]={0xB00B1E50D3LL};
RF24 radio(CE_PIN, CSN_PIN);

byte dataReceived; // this must match dataToSend in the TX
float ackData = 100; // the two values to be sent to the master
bool newData = false;

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

void setup() {

    Serial.begin(9600);

    Serial.println("SimpleRxAckPayload Starting");
    radio.begin();
    radio.setDataRate( RF24_250KBPS );
        radio.setChannel(100);

    radio.openReadingPipe(1, rAddress[0]);

    radio.enableAckPayload();
    radio.writeAckPayload(1, &ackData, sizeof(ackData)); // pre-load data

    radio.startListening();
}

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

void loop() {
    getData();
    showData();
}

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

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

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

void showData() {
    if (newData == true) {
        Serial.print("Data received ");
        Serial.print("Slave ");
        Serial.println(dataReceived);
        Serial.print(" ackPayload sent ");
        Serial.println(ackData);
        newData = false;
    }
}

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

void updateReplyData() {
    ackData += 1;
    if (ackData == 1000) {
        ackData = 100;
    }
    radio.writeAckPayload(1, &ackData, sizeof(ackData)); // load the payload for the next time
}

here are the results
master

Starting...
  ========  For Slave 1  ========
  Data Sent 1  Acknowledge but no data 

  ========  For Slave 1  ========
  Data Sent 1  Acknowledge but no data 

  ========  For Slave 1  ========
  Data Sent 1  Acknowledge but no data 

  ========  For Slave 1  ========
  Data Sent 1  Acknowledge but no data

slave 1

Data received Slave 0
  Acknowledge data 110.00
 ackPayload sent 214.00
Data received Slave 0
  Acknowledge data 111.00
 ackPayload sent 215.00
Data received Slave 0
  Acknowledge data 112.00
 ackPayload sent 216.00

slave 2

Data received Slave 2
 ackPayload sent 110.00
Data received Slave 2
 ackPayload sent 111.00
Data received Slave 2
 ackPayload sent 112.00

Thanks !!!

Slave 1:

void setup() {
....
    radio.writeAckPayload(1, &ackData2, sizeof(ackData2)); // pre-load data
    radio.startListening();
}

Writing an ack-payload and then flushing the tx-fifo is rather senseless.

void loop() {
    getData();
    showData();
    radio.startListening();
}

The startListening() flushes the tx-fifo and is executed each loop, regardless of any reception.
The ackpayload has to be preloaded after calling startListening.

Code from the library (looks rather experimental, with many commented out code)

void RF24::startListening(void)
{
 #if !defined (RF24_TINY) && ! defined(LITTLEWIRE)
  powerUp();
 #endif
  write_register(NRF_CONFIG, read_register(NRF_CONFIG) | _BV(PRIM_RX));
  write_register(NRF_STATUS, _BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) );
  ce(HIGH);
  // Restore the pipe0 adddress, if exists
  if (pipe0_reading_address[0] > 0){
    write_register(RX_ADDR_P0, pipe0_reading_address, addr_width);	
  }else{
	closeReadingPipe(0);
  }

  // Flush buffers
  //flush_rx();
  if(read_register(FEATURE) & _BV(EN_ACK_PAY)){
	flush_tx();
  }

  // Go!
  //delayMicroseconds(100);
}

I have to use the startListening() each loop because when I receive the request from the master, I have to send another one to the slave 2 (from slave 1 to slave 2) and by the way I have to use write() which means I have to use stopListening().
can the problem be caused by the fact that the master wait for the ack for more than the time that it should wait for ?
Thanks for helping!!!

CHEGGARI:
I have to use the startListening() each loop

No.

CHEGGARI:
when I receive the request from the master, I have to send

Only if you call stopListening you have to call startListening and then preload any ackpayloads,
that is not each round of loop.

void send_data()
{  radio.stopListening();
   radio.openWritingPipe(rAddress[1]);
  bool rslt;
        rslt = radio.write( &dataToSend, sizeof(dataToSend) );
  if (rslt) {
            if( radio.isAckPayloadAvailable() )
            {
                radio.read(&ackData1, sizeof(ackData1));
                newData = true;
            }
            else {
                Serial.println("  Acknowledge but no data ");
            }
            
        }
        else {
            Serial.println("  Tx failed");
        }


}

Each time I want to send request to the slave 2 from slave 1 I use stopListening as it is mentioned in the upper code, and this is for each loop

Again, no.

You only send something if you have received a packet.

void showData() {
    if (newData == true) {
        Serial.print("Data received ");
        Serial.print("Slave ");
        Serial.println(dataReceived);
        send_data();

I think a reception of the payload from the other slave will send slave 1 into a never ending
send loop, until an ackpayload or a send fails.

You handle a reception on the ack channel just like a reception of an ack payload of the other slave,
but you only should change and reload the ackpayload in the first case.

CHEGGARI:
I have to use the startListening() each loop because when I receive the request from the master, I have to send another one to the slave 2 (from slave 1 to slave 2) and by the way I have to use write() which means I have to use stopListening().

Please set aside the code for a moment and describe clearly what you are trying to achieve. Maybe draw a diagram of the proposed wireless links and post a photo of the drawing.

Why does Slave1 need to talk to Slave2? Why not do all the communication between the master and slaves?

...R