Simple nRF24L01+ 2.4GHz transceiver demo

Introduction
The nRF24L01+ 2.4GHz transceiver modules are cheap and very effective but I have come across a few Threads in which people were having trouble with them so I thought it might be useful to gather together in one place a basic step-by-step sequence for getting them to work.

EDIT 03 Feb 2021 - For this Tutorial install Version 1.1.7 of the RF24 library (available with the Arduino Library Manager). More information in Reply #30.

Edit 29 Aug 2016. I have today downloaded and successfully tested all 3 pairs of programs with Arduino IDE 1.6.3 - 2 small corrections were needed for SimpleTxAckPayload.ino

Edit 06 Sep 2017 2016 (oops). Modified examples 1 and 2 to listen on Pipe 1 in accordance with the text

Edit 18 Mar 2017 Added Reply #29 with a simple program to check the connection with the Arduino

TMRh20 version of the RF24 library
This tutorial uses the TMRh20 version of the RF24 library which fixes some problems in the earlier ManiacBug version. Unfortunately, however, TMRh20 did not think to give his version a different name so it can be difficult to be certain which one is on your PC. If, before reading this, you have downloaded and installed the RF24 library the simplest thing may be to delete all traces of it and then download and install the TMrh20 version. Note that the demo programs will NOT work with the ManiacBug version of the library.

nRF24L01+ module pin connections
The nRF24 modules that I am using look like this.
nRF24r.png

With the pins uppermost and the antenna on the right hand side the pin connections are
Pins.png

Arduino connections
Because the nRF24s use SPI to communicate with the Arduino they must use Arduino pins 13, 12 and 11 (SCK, MISO and MOSI). It is also necessary to connect the CSN and CE pins and any of the Arduino I/O pins can be used for them. However for demo purposes it seems easiest to use pins 10 and 9 so that all 5 connections are adjacent on pins 13 to 9. I use some female-male jumper wires to connect to the nRF24 for test and development. The jumper wires come as a piece of ribbon cable and if you separate a piece with 5 wires and allocate the wires to suit the Arduino pins it is very easy to connect and disconnect the nRF24 from the Arduino without getting the connections mixed up.


If you are using pins other than 10 and 9 for CSN and CE you must still set pin 10 for OUTPUT to ensure that the Uno acts as the SPI master.

Powering the nRF24L01+ module
The nRF24 modules require a 3.3v power supply. Be careful NOT to connect the VCC pin to a 5v power supply. I have found that they work satisfactorily when connected to the 3.3v pin on my Unos.

It is recommended to plce a 10µF capacitor across VCC and GND as near to the module as possible and I have found this essential when I made some units with an Atmega328 chip on a breadboard. The capacitor stabilizes the power supply for the module. However I have not found it necessary to use a capacitor with my Uno (or Mega). But if you believe you have followed all the other instructions correctly and are having problems it would certainly be a good idea to install a capacitor.

Resetting the nRF24
It seems that on some occasions the nRF24 does not reset after a new program is uploaded to the Arduino. This can prevent the program from working properly. If you think that is the case then disconnect the Arduino from the USB cable and reconnect it.

Some of the jargon explained
Because the nRF24s are transceivers they can obviously transmit and receive. To try to avoid confusion I will assume that you are using one them (which I will refer to as TX or "master") to transmit and another one (RX or "slave") to receive.

Like a lot of other equipment (WiFi and Bluetooth, for example) the nRF24L01+ modules broadcast on the 2.4GHz band. The precise frequency is determined by the channel that is selected. Both TX and RX must use the same channel. The default channel for the RF24 library is 76.

When the TX sends a message every RX listening on the same channel will receive the message. The TX includes an "address" in the message and the RX will ignore messages that do not have its address. The address is similar in concept to a phone number except that you cannot easily change the number of your phone. The address is a 5 byte number.

The nRF24L01+ modules can listen on any or all of 6 "pipes". Unfortunately in some RF24 demo programs the variable that is used to hold the address is given the name "pipe" even though pipes and addresses are quite different. For the purpose of this tutorial I will only be using one pipe (pipe 1) for listening. Note that pipe 0 is the only writing pipe. It is possible to listen on pipe 0 but it is simpler to leave that excusively for writing.

The 6 pipes allow an nRF24 to listen for messages from 6 other devices with 6 different addresses. But those devices may not transmit at the exact same time.

Radio interference
Note that if 2 or more TXs transmit at the same time on the same channel they will interfere with each other and the message will not be receivable. That is why an NRF24 cannot receive messages on its 6 pipes at the same instant.

Messages will also be garbled if (say) a nearby Wifi system transmits at the same time on the exact same frequency.

However each individual transmission is very short (a few millisecs) so that it is unlikely that the transmission from your TX will overlap with something else.

Edit 14 Oct 2016 -- It has been pointed out that this is not accurate. I am leaving the erroneous text so that people who may already have read it will understand the changes
Data is sent in 32 byte packets
The nRF24L01+ modules transmit data in 32 byte packets. If you only want to send a few bytes the RF24 library will automaatically pad out the message with \0 chars. If you attempt to send more than 32 bytes it will be transmitted as a number of packets. For this tutorial I will not be sending more than 32 bytes. Also, I do not intend to cover the dynamic payload feature which allows the user to select a smaller packet size to reduce transmission time.
Revised version
Data Packets
The nRF24L01+ modules can transmit a maximum of 32 bytes in a single message. If you need to send more you will need to break it into a number of separate messages. For this tutorial I will not be sending more than 32 bytes.

There are two modes of operation {A} a fixed payload size which defaults to 32 bytes and can be changed with setPayloadSize() and {B} a dynamic payload mode which is chosen with enableDynamicPayloads(). The dynamic payload mode is automatically applied when you choose the ackPayload feature (see Example 2). You can check the payload size with getDynamicPayloadSize().

When using dynamic payloads you must ensure that you read all the bytes that are received or the communication will break down.

Data validation
The nRF24s automatically include sophisticated systems to identify whether the data received matches the data that was sent. If the data is not received correctly the RX will not show data available() and will not send an acknowledgment. That means the TX will consider the transmission to have failed. You will see in the example programs that the TX is instructed automatically to retry the transmission up to 5 time before giving up. (The max is 15).

In your RX code you can therefore assume that if data is available() it will be correct.

Also note that, unlike Arduino Serial communication, when the RF24 library shows data as available() it means that the entire mesage has been correctly received.

Program style
In the example programs I have tried to use the same style that I used in Serial Input Basics and in Planning and Implementing a Program
By arranging the parts into small functions it should be easy to incorporate them into other programs.

Continues in next Post

14 Likes

Simple one way transmission
The following pair of programs sends a simple message "Message N" from the TX to the RX where N is a number that increments from 0 to 9 so that you can see that successive messages are sent and received.

SimpleTx.ino

// 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;
}

SimpleRx.ino

// 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;
    }
}

Edit 20 Jul 2018 ...
When working properly the Rx program should show "Data received Message n" in which n varies from 0 to 9. This should be printed at about one second intervals.
if all you see is "Data received" repeating much more quickly then there is a problem - most likely theArduino is not communicating properly with its nRF24. See Reply #29 for more info

Continues in next Post

3 Likes

Two-way transmission
If the slave is required to send data back to the master it would seem necessary for the two devices to swap roles. Among other things that will mean that the "master" will need an address as well as the slave. The question of timing also needs to be considered - for example, how long should the master continue listening for the reply from the slave? And, if the slave is trying to write rather than listen it may miss a transmission from the master.

Two-way transmission using the ackPayload concept
The complications of swapping roles can be completely avoided by using the ackPayload concept. The idea is that the slave puts data in the ackPayload buffer BEFORE it receives a message from the master and then the data in the ackPayload buffer is sent automatically as part of the normal acknowledgment process without your code needing to make the devices swap roles.

The ackPayload concept can only be used when the amount of data transferring from slave to master is 32 bytes or less.

It also means that the data sent from the slave is always a step behind the data received by the slave. For example the ackPayoad cannot take account of the data received in the message for which it is the acknowledgment.

ackPayload example
In this example the slave will send a pair of numbers back to the master.

SimpleTxAckPayload.ino

// SimpleTxAckPayload - 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';
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/sdb1/SGT-Prog/Arduino/ForumDemos/nRF24Tutorial/SimpleTxAckPayload.ino"));
    Serial.println("SimpleTxAckPayload Starting");

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

    radio.enableAckPayload();

    radio.setRetries(5,5); // delay, count
                                       // 5 gives a 1500 µsec delay which is needed for a 32 byte ackPayload
    radio.openWritingPipe(slaveAddress);
}

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

void loop() {

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

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

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) {
        if ( radio.isAckPayloadAvailable() ) {
            radio.read(&ackData, sizeof(ackData));
            newData = true;
        }
        else {
            Serial.println("  Acknowledge but no data ");
        }
        updateMessage();
    }
    else {
        Serial.println("  Tx failed");
    }

    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;
}

SimpleRxAckPayload.ino

// SimpleRxAckPayload- 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
int ackData[2] = {109, -4000}; // 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.openReadingPipe(1, thisSlaveAddress);

    radio.enableAckPayload();
    
    radio.startListening();

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

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

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.println(dataReceived);
        Serial.print(" ackPayload sent ");
        Serial.print(ackData[0]);
        Serial.print(", ");
        Serial.println(ackData[1]);
        newData = false;
    }
}

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

void updateReplyData() {
    ackData[0] -= 1;
    ackData[1] -= 1;
    if (ackData[0] < 100) {
        ackData[0] = 109;
    }
    if (ackData[1] < -4009) {
        ackData[1] = -4000;
    }
    radio.writeAckPayload(1, &ackData, sizeof(ackData)); // load the payload for the next time
}

Edit 05 Dec 2016 to correct the wrong pipe reference in the function updateReplyData(). Apologies for any confusion.

Edit 18 Mar 2017 - see Reply #17 for a version that works with multiple slaves

Edit 21 Feb 2019 to change setup() in RxAckPayload so the payload is uploaded after startListening()

Edit 20 Jan 2020 to increase delay in setRetries() to allow for longer ackPayloads. Details in section 7.4.2 of the Nordic nRF24L01+ datasheet

Continues in next Post

1 Like

Two-way transmission by swapping roles
I have not found a need for this approach but I will illustrate it in case it is useful for someone else.

In this example the two nRF24s (master and slave) spend most of their time listening and only switch to talking for the minimum time needed to send a message. As with the ackPayload example the slave only sends a message in response to a message from the master.

MasterSwapRoles.ino

// MasterSwapRoles

#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'};
const byte masterAddress[5] = {'T','X','a','a','a'};


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

char dataToSend[10] = "Message 0";
char txNum = '0';
int dataReceived[2]; // to hold the data from the slave - must match replyData[] in 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("MasterSwapRoles Starting");

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

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

    radio.setRetries(3,5); // delay, count
    send(); // to get things started
    prevMillis = millis(); // set clock
}

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

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

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

void send() {

        radio.stopListening();
            bool rslt;
            rslt = radio.write( &dataToSend, sizeof(dataToSend) );
        radio.startListening();
        Serial.print("Data Sent ");
        Serial.print(dataToSend);
        if (rslt) {
            Serial.println("  Acknowledge received");
            updateMessage();
        }
        else {
            Serial.println("  Tx failed");
        }
}

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

void getData() {

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

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

void showData() {
    if (newData == true) {
        Serial.print("Data received ");
        Serial.print(dataReceived[0]);
        Serial.print(", ");
        Serial.println(dataReceived[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;
}

SlaveSwapRoles.ino

// SlaveSwapRoles

#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'};
const byte masterAddress[5] = {'T','X','a','a','a'};

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

char dataReceived[10]; // must match dataToSend in master
int replyData[2] = {109, -4000}; // the two values to be sent to the master
bool newData = false;

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


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();

}

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

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

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

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

        Serial.print("Reply Sent ");
        Serial.print(replyData[0]);
        Serial.print(", ");
        Serial.println(replyData[1]);

        if (rslt) {
            Serial.println("Acknowledge Received");
            updateReplyData();
        }
        else {
            Serial.println("Tx failed");
        }
        Serial.println();
        newData = false;
    }
}

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

void getData() {

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

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

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

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

void updateReplyData() {
    replyData[0] -= 1;
    replyData[1] -= 1;
    if (replyData[0] < 100) {
        replyData[0] = 109;
    }
    if (replyData[1] < -4009) {
        replyData[1] = -4000;
    }
}

End of Tutorial

...R

Edit 02 September 2019 to remove reference to broken link

3 Likes

Reserved for future use

...R

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