Go Down

Topic: Simple nRF24L01+ 2.4GHz transceiver demo (Read 18042 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.

nurulb

#24
Jun 11, 2017, 08:28 am Last Edit: Jun 11, 2017, 08:39 am by nurulb
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)

Code: [Select]


#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


Code: [Select]

#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)

Code: [Select]

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

#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

vaj4088

"...it always failed" is not very helpful.  What do your Serial.println(...) statements tell you?

Why oh why do you use delay(...) ?


nurulb

#26
Jun 12, 2017, 07:23 am Last Edit: Jun 12, 2017, 07:32 am by nurulb
the Serial println show that the transmission is failed, it can't send the data "Hello World" to the Receiver
so in the serial monitor the message shown is

failed
failed
failed

i use delay to make it send once after 1000ms

but for the details i think it is not failed at all but, i make a mistake about how to get notification when the data sent or failed, when i try the conde again this is what happen

when i used the first code, Mega as a transmitter and when i pressed the button, this happened


and when i looked out to the uno as the receiver, it happened


so i think that's work, for send simplex mode

but this happen when i press the button on my Mega and see the serial monitor


i notice, it means that the transmission is fail


now i try to make difference for the code so we can notice if the data sent from Mega or uno

in the Mega Code, i change the string from "Hello World " to "Hello world from Mega", so when we see in the uno Serial monitor as receiver, we can know that the data is coming from arduino mega, i do it for my uno too

when i press the button on my Mega(it means that my mega is tx), i see this in the serial monitor of my Uno (it means that my uno is Rx)



and when i press the button on my uno (uno as Tx), i see this in the serial monitor of my Mega (Mega as Rx)




nurulb

i just modify my code, and now it is work
when i press the button, it will send the data, and if we do not push the button, it will stay listening

here is the code for Uno with input from button is in pin 4 and pin 7 is Vcc for the button

Code: [Select]

#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);
 Serial.println("Receiving Mode, Press button to send data");
 radio.begin();
 radio.openWritingPipe(address[0]);
 radio.openReadingPipe(1,address[1]);
 radio.setPALevel(RF24_PA_HIGH);
 radio.setDataRate(RF24_250KBPS);
 radio.setRetries(15, 15);
 radio.startListening();
 
}

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

  if(tombol != LOW)
  {
    radio.stopListening();
    abc();
  }
  else
  {
    radio.startListening();
  }

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

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



here is the code for Mega with input from button is in pin 4 and pin 7 is Vcc for the button
Code: [Select]

#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);
 Serial.println("Receiving Mode, Press button to send");
 radio.begin();
 radio.openWritingPipe(address[1]);
 radio.openReadingPipe(1,address[0]);
 radio.setPALevel(RF24_PA_HIGH);
 radio.setDataRate(RF24_250KBPS);
 radio.setRetries(15, 15);
 radio.startListening();
}

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

  if(tombol != LOW)
  {
    radio.stopListening();
    abc();
  }
  else
  {
    radio.startListening();
  }

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

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

Go Up