Go Down

Topic: Simple nRF24L01+ 2.4GHz transceiver demo (Read 15219 times) previous topic - next topic

juan3211

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,


sapman

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


Robin2

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
Code: [Select]



// 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.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
Two or three hours spent thinking and reading documentation solves most programming problems.

CHEGGARI

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

DevilWAH

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

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 !!!   

BlackChart

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:
Code: [Select]

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


to

Code: [Select]

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 :(

DevilWAH

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.

JoshuaACNewman

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
Code: [Select]

/*
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

Code: [Select]

/*
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.

Go Up