Simple nRF24L01+ 2.4GHz transceiver demo

I have the Due and 2560 boards but no Unos. I suppose these instructions apply for them too?

I wish I could find something similar for STM32F407 Discovery boards, too.

1 Like

Some thing is wrong with RF24 lib.
Ever since I updated my RF24 library (and Arduino IDE) to the latest, the nRF24L01+ seemed to have stopped working.

They were working fine previously.
My setup is Mega 2560 R3 with one nRF24L01+ (with CE and CSN as 9 and 10 as in code)
and the other is Nano 3.0 with another nRF24L01+ (CE & CSN = 9 and 10).

I powered the radios with on board 3.3v regulator, no extra caps and it was all working fine.

Just needed to update/change my code recently and thats when it happened. Compiling my code with the new library seemed to have caused the trouble (or perhaps the IDE updated SPI.h - Arduino 1.6.12).

So I came to this thread, and copy pasted the examples for test. Still no communication.
Tried the many examples included in RF24 lib (pingpair, getting started, call handling, transfer etc)
Nothing seems to work.

BTW the radios, I bought from Chinese store online, but the Mega and Nano are genuine (bought from UK).
Just in case Arduino/nordic implemented some anti-pirated checks.

Is anyone else having problems.

burhanmz:
Some thing is wrong with RF24 lib.
Ever since I updated my RF24 library (and Arduino IDE) to the latest, the nRF24L01+ seemed to have stopped working.

If the previous library was the one of ManiacBug some things are changed so some previous sketch doesn't work.
Take care not to have the two libraries at the same time since the IDE can use the wrong one.

I guess this needs correction :

In the SimpleRxAckPayload.ino sketch , inside the function updateReplyData() the following line,

radio.writeAckPayload(0, &ackData, sizeof(ackData)); // load the payload for the next time

needs to have 1 in place of 0.

Otherwise the Tx module complains of No Data feedback.

Hi,

I plugged the wire to 3.3 and 5V entry. I didn#t notice any difference.
I reused the simple example.

Here is the code:

// SimpleTx - the master or the transmitter

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


#define CE_PIN   9
#define CSN_PIN 10

const byte slaveAddress[5] = {'R','x','A','A','A'};


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

char dataToSend[10] = "Message 0";
char txNum = '0';


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


void setup() {

    Serial.begin(9600);

    Serial.println("SimpleTx Starting");

    radio.begin();
    radio.setDataRate( RF24_250KBPS );
    radio.setRetries(3,5); // delay, count
    radio.openWritingPipe(slaveAddress);
}

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

void loop() {
    currentMillis = millis();
    if (currentMillis - prevMillis >= txIntervalMillis) {
        send();
        prevMillis = millis();
    }
}

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

void send() {

    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("Data Sent ");
    Serial.print(dataToSend);
    if (rslt) {
        Serial.println("  Acknowledge received");
        updateMessage();
    }
    else {
        Serial.println("  Tx failed");
    }
}

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

void updateMessage() {
        // so you can see that new data is being sent
    txNum += 1;
    if (txNum > '9') {
        txNum = '0';
    }
    dataToSend[8] = txNum;
}

and

// SimpleRx - the slave or the receiver

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

#define CE_PIN   9
#define CSN_PIN 10

const byte thisSlaveAddress[5] = {'R','x','A','A','A'};

RF24 radio(CE_PIN, CSN_PIN);

char dataReceived[10]; // this must match dataToSend in the TX
bool newData = false;

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

void setup() {

    Serial.begin(9600);

    Serial.println("SimpleRx Starting");
    radio.begin();
    radio.setDataRate( RF24_250KBPS );
    radio.openReadingPipe(1, thisSlaveAddress);
    radio.startListening();
}

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

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

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

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

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

I get:
SimpleTx Starting

And
Data received
Data received
Data received

Apparently the information is not sent by the transmitter.

I have also set-up two nRF's with two Uno's and am trying get the simpleTx and simpleRx one way communication working; it's not working.

I'm using this library:

I've followed Robin2's instructions, added the 10uf capacitor for stabilizing power, and my nRF modules look like the ones in his picture.

Still no luck; i get this on the sender:

SimpleTx Starting
Data Sent Message 0 Tx failed
Data Sent Message 0 Tx failed
Data Sent Message 0 Tx failed
Data Sent Message 0 Tx failed
...

And this on the receiver:

SimpleRx Starting
Data received Message 0
Data received Message 0
Data received Message 0
Data received Message 0

No errors other wise. Has anyone successfully gotten "Simple one way transmission" working with Robin2's provided SimpleTx and SimpleRx code?

Ali

Thanks for this fantastic guide Robin, having a simple sent/receive program is really useful.
I have a strange issue when trying to use the NRF24L01 radios. I have it all wired up, but whenever my sketch calls the radio.write function the program freezes. I've used Serial.print to debug and can see that the program steps through correctly all the way until it reaches the radio.write call, and then it jut stops working completely.
I've also tried commenting out the radio.write call and the program works fine- obviously it gives a 'Tx failed' response, but that is to be expected.
This error persists in both your example sketch and all of the examples that come with the library.
Do you have any thoughts on what could be causing this? It is doing my head in.
EDIT: I should say that I am powering the radio module with an LM3940 regulator with plenty of bypass and filtering capacitance.

1 Like

pleas where is the video to this process ?

how can i use three transmitter and one reciever. could you pls explain with new adress format of the tmrh 20 library. iam really confused with new format

Thanks Robin I've read it all but I'm wondering what the output looks like in the Serial monitor.
Is it actually even possible to send messages (master) like 'a' 'b' 'd' 'z', and to read these out in your Arduino (slave) to let your Arduino react to that message and then send a message back to the master.

Hi @Robin2.

I like a lot your samples. I have already worked with NRF24 last year. 3 TX and 1 RX. Each TX with its address and its pipe, so everything works fine.

Now I want to start another project.

The RX node will be an arduino with a SIM800L GSM module. I want it to send to a web page, or with MQTT broker all the data that it receives. It acts as a gateway between NRF24 net and GPRS data.

But my question is about TX nodes. I want to do them in next months, and I don't want to reprogram the TX sketch

For example, I want to put one TX node in my room to get temperature. Two months after, I will put another one that measures wattage and voltage in my home, after another one that measures temperature and humity in the outside.

I want to program my RX gateway node to receive all these packets (different TXs and sizes) and send them to a web server.

The web server (PHP file) will read all data and "understand" it. RX gateway only cast the data. If I add in future another TX node, I have to change only PHP file to understand "another type of information" (see questions)

I have two questions:

  1. does NRF24 RX node listen only one pipe and all of TX nodes writting in that pipe ? (I HAVE TO USE ACK PAYLOADs to know TX that its info has been read)
    Will it be impossible for RX node to get all information ? Imagine 2 nodes --> probably OK, but with 20 nodes ????

  2. My payloads have to be something like this in order to mantain flexibility for future TX nodes:

  • 32 bytes
  • first byte will be the ID of the Node to be "understood" by my PHP page
  • after first byte all data in a row. PHP will be responsible for extract information of the rest of 31 bytes

Have you got any opinion or improvement about this way of transmiting data ?

Regards,

Robin2,

thank your for sample code. each one of them just worked out of the box for the most part. I'm using the nRF24L01 modules with the power amp and external antenna with the base module. I'm using a Mega as the master, one thing to point out for other people how are using the Mega, the pins are in a different location, MISO,MOIS,SCK,CSN are on pins d50-d53.

thanks,

Dan

I thought it would be helpful to add a slightly modified version of the program SimpleTxAckPayload.ino to illustrate how it can be used as a master with two slaves. And, of course, it could be extended to work with several slaves. For this example the slaves should each use the program SimpleRxAckPayload.ino with the address for one of the slaves changed to {'R','x','A','A','B'}. Please note this version does not use any extra pipes compared to the SimpleTxAckPayload program.

MultiTxAckPayload.ino

// 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   9
#define CSN_PIN 10

const byte numSlaves = 2;
const byte slaveAddress[numSlaves][5] = {
        // each slave needs a different address
                            {'R','x','A','A','A'},
                            {'R','x','A','A','B'}
                        };

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

//~ char dataToSend[10] = "Message 0";
char dataToSend[10] = "ToSlvN  0";
char txNum = '0';
int ackData[2] = {-1, -1}; // to hold the two values coming from the slave
bool newData = false;

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

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

void setup() {

    Serial.begin(9600);
    Serial.println(F("Source File = /mnt/SGT/SGT-Prog/Arduino/ForumDemos/nRF24Tutorial/MultiTxAckPayload.ino "));
    Serial.println("SimpleTxAckPayload Starting");

    radio.begin();
    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.stopListening();
        radio.openWritingPipe(slaveAddress[n]);

            // include the slave number in the message
        dataToSend[5] = n + '0';

        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(n);
        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 ");
            }
            updateMessage();
        }
        else {
            Serial.println("  Tx failed");
        }
        showData();
        Serial.print("\n");
    }

    prevMillis = millis();
 }


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

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

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

void updateMessage() {
        // so you can see that new data is being sent
    txNum += 1;
    if (txNum > '9') {
        txNum = '0';
    }
    dataToSend[8] = txNum;
}

...R

In the last example, it gave me "tx failed" , even the data is received by the slaves...

With the Ackpayload method can you set up different replies depending on what slave has transmitted.

So my example would be I have one device acting as a master in a hub/spoke arrangement, lets supose a master device and slave devices A,B and C

Devices A B and C are monitoring the number of times some one presses a button connected to each device.

every x amount of time each node transmits back to the master the number of times its button has been pressed since the last update.

The master than takes all 3 values and calculates the % each button has been presses, then the next time the slave "checks in" it transmits back to each station its value to be displayed on a LED display.

so A transmits back 50, B 30 and C 20

The master calculates the % as 50,30,20%

next time A transmits back 30, B 20 and C 70.

The master would replay to A update with 50, B with 30 and C with 20 (results one step behind).

If this possible, I know in this case I could send all values back to all and have them work out what is for them but image if it was 100 devices or larger amounts of data.

Cheers

I don't know if the ack method is working well, but I advise you not to use it because as I know, when you send a request to a node(A,B or C) these have to reply immediately this will work just if you are sending requests sequentially, yet you have to use other method !!!

I have this type of radio, and I won't work with this example:
https://www.aliexpress.com/store/product/10PCS-LOT-NRF24L01-PA-LNA-Onboard-Ceramic-Antenna-Wireless-Transmission-Module-905-CC1101/610196_2026712476.html

If i change this:

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

to

void getData() {
   if ( radio.available() ) {
       radio.read( &dataReceived, sizeof(dataReceived) );
       newData = true;
   } else {
       Serial.println("No radio available");
   }
}

I only get a serial console flooded with "No radio available" messages :frowning:

CHEGGARI:
I don't know if the ack method is working well, but I advise you not to use it because as I know, when you send a request to a node(A,B or C) these have to reply immediately this will work just if you are sending requests sequentially, yet you have to use other method !!!

I have been playing with it as it does work using the ack method.

The slave node builds an array of data it wants to send back. then it simply populates the buffer ready for the ACK with the first item in the array. The master polls it 5 times a second (will get faster), and collect the data via the ack method.

Because this is for racing gates and there are only up to 16 cars/drone on track, I am not limited by time, There are generally several seconds between items and / or laps. I am adding error correction so the master has to poll the slave 22 time to collect all 16 items in the array and check them off, and generally has 30+ seconds per lap to achieve this. Once up to speed I am planning to poll the slaves 9 times a second I have plenty of time to do this via acks.

I tried both having send and receive method on slaves and master, and using the ack and the ack version is much easier to code, and because i know only the master is talking and the rest are listening i can cut down on the timeouts and retries so make the process quicker.

After a solid couple of days working with this, I'm still not receiving any information. I see the Tx light blinking once a second on the transmitter, but nothing happens at the Rx end. I've added a bit of code just so it says, "nope" when it doesn't have any new data, and the result is a solid string of "nope"s.

I know that these modules can't take more than 3.3v, but mine came without numbered pins and I plugged them in backward, misreading which side of the board the diagram was representing. Could the 5v signal have blown the radio board? How could I confirm that?

I'm using a Nano for both Tx and Rx. Could I maybe have them plugged into the wrong pins? I've corrected my pin order so many times that I have no faith in the order they're in now. Nonetheless, I've listed the order I'm currently using in the comment at the top of the code, just so I have a reference to work from as I go.

Tx code

/*
Transmitter for nRF24L01

nRF24L01 pin    Nano pin    Color (arbitrary)
CE   03         9(any)      orange
CS/N 04         10(any)     yellow
SCK  05         13          green
MOSI 06         11          blue
MISO 07         12          purple
IRQ  08         (none)      grey

Nano pins, in order   color
9                     orange
10                    yellow
11                    blue
12                    purple
13                    green

*/

// SimpleTx - the master or the transmitter

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


#define CE_PIN   9
#define CSN_PIN 10

const byte slaveAddress[5] = {'R','x','A','A','A'};


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

char dataToSend[10] = "Message 0";
char txNum = '0';


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


void setup() {

    Serial.begin(9600);
    
    digitalWrite(10, HIGH); //sets it to master mode?

    Serial.println("SimpleTx Starting");

    radio.begin();
    radio.setDataRate( RF24_250KBPS );
    radio.setRetries(3,5); // delay, count
    radio.openWritingPipe(slaveAddress);
}

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

void loop() {
    currentMillis = millis();
    if (currentMillis - prevMillis >= txIntervalMillis) {
        send();
        prevMillis = millis();
    }
}

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

void send() {

    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("Data Sent ");
    Serial.print(dataToSend);
    if (rslt) {
        Serial.println("  Acknowledge received");
        updateMessage();
    }
    else {
        Serial.println("  Tx failed");
    }
}

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

void updateMessage() {
        // so you can see that new data is being sent
    txNum += 1;
    if (txNum > '9') {
        txNum = '0';
    }
    dataToSend[8] = txNum;
}

Rx Code

/*
Receiver for nRF24L01

nRF24L01 pin    Nano pin    Color (arbitrary)
CE   03         9           orange
CS/N 04         10          yellow
SCK  05         13          green
MOSI 06         11          blue
MISO 07         12          purple
IRQ  08         (none)      grey

Nano pins, in order   Color
9                     orange
10                    yellow
11                    blue
12                    purple
13                    green

*/

// SimpleRx - the slave or the receiver

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

#define CE_PIN   9
#define CSN_PIN 10

const byte thisSlaveAddress[5] = {'R','x','A','A','A'};

RF24 radio(CE_PIN, CSN_PIN);

char dataReceived[10]; // this must match dataToSend in the TX
bool newData = false;

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

void setup() {
    digitalWrite(10, HIGH); //Sets to Master mode? I don't understand how it can only work in Master mode.
    Serial.begin(9600);

    Serial.println("SimpleRx Starting");
    radio.begin();
    radio.setDataRate( RF24_250KBPS );
    radio.openReadingPipe(1, thisSlaveAddress);
    radio.startListening();
}

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

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

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

void getData() {
    if ( radio.available() ) {
        radio.read( &dataReceived, sizeof(dataReceived) );
        newData = true;
    }else{
      Serial.println("nope");
    }
}

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

This is like a steering wheel stuck on a pirate's crotch.

Hi Robin2

Thank's a lot for your clear explanation, and your example about simple one way transmission using NFR24L01

I Tried it with my NRF24l01 + PA + LNA
and that's work fine, i just modified a little configuration, adapt it to the hardware connection

I tried another type of simple one way transmission using push button to controll the transmiter

the main idea of the projcet is the transmitter will send "Hello World" message if we push the button on, if we do not push the button, nothing wil transmit

I use pin 7 as vcc for the push button so i set the pin become High

here is the code of Transmitter (using Arduino Mega 2560)

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
RF24 radio(9, 53); // CE, CSN
const byte address[][6] = {"00001","00002"};
const int pinout = 7;
const int pinin = 4; //input from button to arduino

void setup() {
  Serial.begin(115200); 
  radio.begin();
  radio.openWritingPipe(address[1]);
  radio.setPALevel(RF24_PA_MIN); // it doesn't matter what power level we use (MIN, LOW, HIGH, MAX)it still works for my trial
  radio.stopListening();
  
  pinMode(pinin, INPUT);
  pinMode(pinout, OUTPUT);
}
void loop() {
  digitalWrite(pinout, HIGH);
  
  int tombol = digitalRead(pinin);
  
  if(tombol != LOW){
  txin();}
  else{
  Serial.println("Press the button to send data");
  delay(1000);}
}
void txin(){
  bool txan;
  const char data[] = "Hello World";
  txan = radio.write(&data, sizeof(data));
  delay(1000);
  if(txan)
    Serial.println("Data Sent");
  else
    Serial.println("Failed");
}

and this is the Receiver

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

RF24 radio(9, 10); // CNS, CE
const byte address[][6] = {"00001","00002"};
void setup() {
  Serial.begin(115200);
  radio.begin();
  radio.openReadingPipe(0, address[1]);
  radio.setPALevel(RF24_PA_MIN);
  radio.startListening();
  
}
void loop() {
  if (radio.available()) {
    char text[90] = "";
    radio.read(&text, sizeof(text));
    Serial.println(text);
  }

and it works Properly

my question is, i try to make two way transmission which the data is variable
but i try to make simple trial

the main ide is, when i push the button on arduino(1), the first arduino will stop listening and transmit the data (hello world for example) and if we push the button in arduino (2), the second arduino will stop listening and transmit the data

and i try this code for The Arduino(1) (using Arduino uno R3)

include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
RF24 radio(9, 10); //CE,CSN
const byte address[][6] = {"00001","00002"};
const int pinout = 7;
const int pinin = 4;

void setup() 
{
  // put your setup code here, to run once:
 pinMode(pinin, INPUT);
 pinMode(pinout, OUTPUT);
 
 Serial.begin(115200); 
 radio.begin();
 radio.openWritingPipe(address[0]);
 radio.openReadingPipe(0,address[1]);
 radio.setPALevel(RF24_PA_MAX);
 radio.setDataRate(RF24_250KBPS);
 radio.startListening();
 
}

void loop() 
{
  // put your main code here, to run repeatedly:
  digitalWrite(pinout, HIGH);
  int button = digitalRead(pinin);

  if(button != LOW)
  {
    radio.stopListening();
    abc();
  }
  else
  {
    radio.startListening();
    Serial.println("Receiving Mode, Press button to send");
    delay(1000);
  }

  if( radio.available() && button == LOW )
  {
    while (radio.available()) 
    {
    char text[] = "";
    radio.read(&text, sizeof(text));
    Serial.println(text); 
    }
  }
}

void abc()
{
  bool txan;
  const char data[] = "Hello World1 ";
  txan = radio.write(&data, sizeof(data));
  delay(1000);
  if(txan)
    Serial.println("Data Sent");
  else
    Serial.println("Failed");
}

and this is the code for Arduino(2) (Using Arduino Mega 2560)

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
RF24 radio(9, 53); //CE,CSN
const byte address[][6] = {"00001","00002"};
const int pinout = 7;
const int pinin = 4;

void setup() 
{
  // put your setup code here, to run once:
 pinMode(pinin, INPUT);
 pinMode(pinout, OUTPUT);
 
 Serial.begin(115200); 
 radio.begin();
 radio.openWritingPipe(address[1]);
 radio.openReadingPipe(0,address[0]);
 radio.setPALevel(RF24_PA_LOW);
 radio.setDataRate(RF24_250KBPS);
 radio.setRetries(15, 15);
 radio.startListening();
}

void loop() 
{
  // put your main code here, to run repeatedly:
  digitalWrite(pinout, HIGH);
  int button = digitalRead(pinin);

  if(button != LOW)
  {
    radio.stopListening();
    abc();
  }
  else
  {
    radio.startListening();
    Serial.println("Receiving Mode, Press button to send");
    delay(1000);
  }

  if((radio.available()) && (button == LOW))
  {
   while (radio.available()) 
    {
    char text[50] = "";
    radio.read(&text, sizeof(text));
    Serial.println(text); }
  }
}

void abc()
{
  bool txan;
  const char data[] = "Hello World 2";
  txan = radio.write(&data, sizeof(data));
  delay(1000);
  if(txan)
    Serial.println("Sent");
  else
    Serial.println("Failed");
}

done uploading but when i try the transmission, it always failed

I hope you can know and explain what is my mistake

thank's a Lot