NRF24L01 to send serial data

Hi,

I'm learning Arduino and coding with example. I'm modifying exemples to fit my needs
but sometime it's harder and then I need help like this time.

On one of my project, I have a UNO that read multiple sensors and it sending me the result
to a LCD on a remote location using a simple 433Mhz RF transmitter. This transmitter is not
strong enough so I don't get a good range.

I want to replace the 433 Mhz with a NRF24L01 transceiver.

In order to get help from you all, I don't know if it's better to show you the code from
my 433 transmitter so you can help me modify it to replace with the NRF24L01 or
if it's better to show the code I found to run the NRF24L01...

I will start with the code I found to run the NRF24L01.

This code is working and I can receive the simple message the code was design to send.
it help me to see how to change channel, TX power, bandwidth etc...

I want to put this code in a Arduino Nano. This nano is receiving the sensors data from
the TX pin of my UNO.

My question is :

How can I modify the following code so it will send the data from the RX of the Nano or a texte on the serial, instead of sending the simple test message "It Work"

#include <nRF24L01.h>
#include <printf.h>
#include <RF24.h>
#include <RF24_config.h>

RF24 transmit (2,3);                    //create RF24 object called transmit

byte address [6] = “00001”;             //set address to 00001

void setup() {

  transmit.begin();
  transmit.openWritingPipe(address);        //open writing pipe to address 00001
  transmit.setPALevel(RF24_PA_MIN);       //set RF power output to minimum
  transmit.setDataRate(RF24_250KBPS);   //set datarate to 250kbps
  transmit.setChannel(100);                     //set frequency to channel 100
  transmit.stopListening();
 
   }

void loop() {

  char data[32] = “It Works !”;           //send character string upto 32 bytes long
  transmit.write(&data,sizeof(data));   //transmit the data
  delay(1000);
      
}

First, what is the distance to the "remote location", then, can you post your existing code, both transmit AND receive?

Properly arranged, and with good quality wireless devices, you should get a longer range at 433MHz compared to 2.4GHz.

Have a look at this Simple nRF24L01+ Tutorial

...R

On one of my project, I have a UNO that read multiple sensors and it sending me the result
to a LCD on a remote location using a simple 433Mhz RF transmitter. This transmitter is not
strong enough so I don't get a good range.

I want to replace the 433 Mhz with a NRF24L01 transceiver.

What transmit and receive devices are you currently using? What antenna arrangements? What range?

As Robin2 says, you will get better range by working at 433 Mhz particularly if you are going through buildings.

There is probably more to be gained by optimizing the transmit power, if the transmitter can take more than 5v, and the antenna's. If necessary, you can go to one of the higher power 433 Mhz solutions and better protocols than the simple OOK/ASK of the basic units.

When I was having problems with a greenhouse monitoring system and loss of range in colder weather and switched out the radios for Hope RFM69HW with Anarduino mini wireless units. Those radios with Moteino's would be another choice.

The integrated radio/arduino solutions are not cheap compared to a clone and NRF24L01, but if range is your issue you will have a better chance of success sticking with 433Mhz.

Hey thanks for your advise.

I'm using a simple 433 transmiter and receiver, I will put a picture below. For the antenna I used a quarter wave length (17.3cm wire). This transmitter can take 12volts so I put the Vcc at 12 volts to get the maximum TX power.

The transmitter is sending me the status of my scuba compressor installed in my Camping car (RV). I built the receiver with a small OLED display in a small box (9 volts battery) While the compressor is filling my scuba tank, I can move around and see on the remote, the status like PSI, Oxygen, temperature and Cabon monoxyde.

If I'm on the good side of the camper I can receive the signal for almost 100 feets but on the other side of the camper or when I'm in front, I can receive only at 20 feets If I'm lucky.

Yes I know that lower is the frequency, better it can pass trough obstacle but when I look at the NRF24L01, it look better built than the small 433Mhz. I was thinking that maybe the quality of the circuit would made it a better transmitter. Also with the NRF24L01, you can choose a different channel in case of local interfrence.

All this to say. If you know how I can modify the code to change the transmitting mode and get a better range, I will begin with that since it's already there.

FYI. It transmit only the numeric value for each sensor with a comma between each and the receiver display it on the OLED. ,1981,20.4,27.2,33,

See the code of my transmiter and tell me what I can do OR tell me if a better 433 transmitter exist.

#include <VirtualWire.h>
#include <Wire.h> //IIC Library
#include <elapsedMillis.h>//For the Status
#include <Adafruit_SSD1306.h>
#define OLED_RESET 4

Adafruit_SSD1306 display(OLED_RESET);

boolean constat = 1; //Status Variable 1=On at start, 0=off at start
boolean splashcleared;//Bool to hold if splash screen has been cleared
String text = " ";//String to hold the text

elapsedMillis packettimer;//The timer for status
#define interval 1500//The threshold for how long it can go without "6"(The connection indicator)

void setup()
{
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);

  pinMode(12, OUTPUT); //Module VCC
  digitalWrite(12, HIGH);   // turn the VCC to High
  vw_set_rx_pin(11);// set you rx pin
  vw_setup(2500);	 // Bits per sec. Lower for further distance. Make sure this matches the number on the transmitter
  vw_rx_start();       // Start the receiver PLL running

  display.clearDisplay();
  display.setTextColor(WHITE);
  display.setCursor(25,0);  
  display.setTextSize(1);
  display.print(F("Scuba Receiver"));
  
  delay (1500);//set this to the interval
}

void loop()
{
  uint8_t buf[VW_MAX_MESSAGE_LEN];
  uint8_t buflen = VW_MAX_MESSAGE_LEN;
 
  if (packettimer< interval){//It the status of the connection is good and "6" was recieved in the last 1.5 secs.
    if (splashcleared==0){//if screen hasn't been cleared of status
      display.clearDisplay();
      display.display();
      splashcleared=1;//make sure it won't be again  
    } 
  }//make sure the screen wont clear again


  if (constat == 1) { //If the status bar is enabled
    if (packettimer < interval) { //It the status of the connection is good and "6" was recieved in the last 1.5 secs.

      display.setTextColor(WHITE, BLACK);
      display.setCursor(115,0);
      display.setTextSize(1);
      display.print(F("OK")); // RF Signal is OK
      display.display();
    }

    else if (packettimer > interval) {//It the status of the connection is bad and "6" was not recieved in the last 1.5 secs.

      delay (450);// wait

      display.clearDisplay();
      display.setTextColor(WHITE, BLACK);
      display.setTextSize(1);
      display.setCursor(120,0);
      display.print(F("X"));  // Not receiving RF Signal
      display.display();
      delay (200);//wait
    }
  }
 
  if (vw_get_message(buf, &buflen)) // Non-blocking
  {
    packettimer = 0;//Reset timer when data is recieved
    text.remove(0);//clear all text from string: text
    text = (char*)buf; //put new data into string "text"

    text.remove(buflen - 1); //Remove garbage after the end of the text

    if (text.startsWith("6")) {//"6" is sent every 300 ms to check the signal, and we dont want it to display
      packettimer = 0;//Reset timer when data is recieved
      if (splashcleared == 0) { //if screen hasn't been cleared of status

       display.clearDisplay();
       display.display();
       
       splashcleared = 1; //make sure the screen wont clear again
      }
    }

    else if (text.startsWith("clear")) {

      display.clearDisplay();
      display.display();
    } 
    
    else if (text.startsWith("status")) { 
      constat = 1; //(ConnectionStatus)this variable will make the signal show
    }
    
    else if (text.startsWith("nostatus")) {
      constat = 0; //(ConnectionStatus)this variable will block the signal from showing
    }
    
    else if (text.startsWith(",")) {
      int sepLocation[5];
      int index = text.indexOf(",");
      int i = 0;
      String extractedValues[4];
      while (index >= 0) {
        sepLocation[i] = index;
        i++ ;
        index = text.indexOf(",", index + 1);
      }
      
      for (int o = 0; o < 4; o++) {
        extractedValues[o] = text.substring((sepLocation[o] + 1), sepLocation[(o + 1)]);
      }
 
           display.setCursor(0, 0);
           display.setTextColor(WHITE, BLACK);
           display.setTextSize(1);
           display.print("PSI = " + extractedValues[0]);
           display.display();
            
           display.setCursor(0, 12);
           display.setTextColor(WHITE, BLACK);
           display.setTextSize(1);
           display.print("Oxygen = " + extractedValues[1] + "%");
           display.display();
                  
           display.setCursor(0, 25);
           display.setTextColor(WHITE, BLACK);
           display.setTextSize(1);
           display.print("Temp = " + extractedValues[2] + "C");
           display.display();             

           
           display.setCursor(75, 25);
           display.setTextColor(WHITE, BLACK);
           display.setTextSize(1);
           display.print("CO = " + extractedValues[3] + "");
           display.display();
    }
  }
}

Using Virtual Wire (now RadioHead) , the 1/4 wave length antennas, and the Tx at 12v like you do is the correct way to go.

Maybe you can mount the transmitter antenna on the roof of the vehicle?

Unfortunately you are using the crappiest modules available. A pretty low cost thing to try is to change the Rx and Tx modules that you have for the slightly better ones which use a saw wave generator on the Transmitter and a superheterodyne Receiver. The modules will not have the big copper coils on them. They should fit into your existing enclosures although the superheterodyne receiver is a bit longer.

Do you have a model number ?

On my side I check a little and found an arduino with an intergrated transceiver.

The Feather MO RFM69HCW

It look new so I might have problem finding good example but
there is a good description in the adafruit learning.

Regarding the better grade ASK modules, EBAY lists many, and I have used something like this
http://www.ebay.com/itm/Geeetech-433Mhz-Superheterodyne-3400RF-Transmitter-and-Receiver-link-kit-Arduino-/311672618668?epid=1191640248&hash=item489122beac:g:mPIAAOSwubRXMpkW

The Feather MO RFM69HCW looks reasonable and is well supported through Adafruit.

Regarding your present modules, using VirtualWire and 12v transmission, the only gains you can make are with antenna design and position.

Hi to All,

I have to doubt that a good 433Mhz transmitter will work better than the cheap one I have now.
I also believe that 433 Mhz will have a better range than the NRF24L01 BUT.

I just made a range test with the NRF24L01 with the first code I put in this post and it's 3 time better
than my cheap 433 Mhz. It passe trough One concrete wall, a door and my pool :slight_smile: and that it's just what I need for this project.

It's probably because even if it's 2.4 Ghz, this transmittter is a better quality than my cheap 433Mhz.

All this to say, for my next project I will choose a better 433Mhz Rf module but for now, since I have the NRF24L01 in my hands and I already paid for them, I would like to used the NRF24L01.

Back to my original question,

If we look at the first code I put in this post, can someone tell me how I can transmit what's coming from the serial / Rx pin of my Nano instead of the simple message "It Works !" ?

hddforensic:
If we look at the first code I put in this post, can someone tell me how I can transmit what's coming from the serial / Rx pin of my Nano instead of the simple message "It Works !" ?

The key part of that code is

char data[32] = "It Works !";           //send character string upto 32 bytes long
  transmit.write(&data,sizeof(data));   //transmit the data

if you put different text into the array named data[] it will be sent.

Or put your text into a different array and send that array in place of the array called dala[]

Have you studied my examples (in Reply #2) ?

...R

I just made a range test with the NRF24L01 with the first code I put in this post and it's 3 time better
than my cheap 433 Mhz. It passe trough One concrete wall, a door and my pool :slight_smile: and that it's just what I need for this project.

It's good to hear that you are having success with the NRF24L01 units. Are you using the PA + LNA versions or the basic units?

I'm transmitting with the PA + LNA and receiving with a basic unit.

I'm reading now to find a way to take what come to my RX pin to send it
but no success for now.

hddforensic:
I'm reading now to find a way to take what come to my RX pin to send it
but no success for now.

Have you tried my examples? They do work!

...R

Hi Robin2,

Sorry I tought I did answer to your question. yes I tried it on Sept 20.. two days before your reply(2).
Before I asked for help on the forum I did some searches on the net.

The examples worked but at that time I was unable to recognize where in the code it was reading
from the serial. But you need to know that I only began with coding and arduino in July and what is not helping me is that I speak french so sometimes reading english is a little hard for me.

Last night I finally found a way to modify my code so it work with the NRF24L01. I can send serial data and receive it on the receiver to see it on the serial windows.

but now I need to find how my receiving code can interpret the data it receive to display it on the OLED display.

The string I receive look like this ,2000,20.4,27.2,33, this is the sensors result from the UNO on the transmitter side.

then the receiver show me on the serial windows the same thing but the receiver code is extracting the values between each comma and put it on the OLED display like this

PSI = 2000 OK
Oxygen = 20.4%
Temp = 27.2
CO = 33

I also have a small "OK" on the right corner of the OLED display to show that I'm receiving the signal.

All that was working with the basic 433Mhz RF module but not anymore since I include the NRF24L01.

You can see the code with the 433RF module with the "extractedValues" lines in my reply (4).

I now need to make that "extractedValues" to work with NRF24L01.

Please post the latest transmitter and receiver codes for the NRF24L01.

Can you get the Serial output and the OLED output in the same sketch? If one is working but the other is not, you should be able to spot the problem.

Are yous saying that you can transfer the received data into a String with something like
text = (char*)buf; //put new data into String "text" and then Serial print successfully,
but that all the subsequent String manipulation to parse out the values between the commas is not working correctly?

Yes

Sending and receiving serial is OK but the parsing is not. It probably due to a variable but I don't know enough yet to find what is it.

This is the code of the Transmitter

#include <nRF24L01.h>
#include <printf.h>
#include <RF24.h>
#include <RF24_config.h>

//#include <VirtualWire.h>
//#include <elapsedMillis.h> //For the status on the receiver


String serialdata; //Holds data coming in
char msg[50]; //Char array to send data out with


RF24 transmit (9,10);                    //create RF24 object called transmit

byte address [6] = "00001";             //set address to 00001

void setup() {
  Serial.begin(9600);
  Serial.println ("Serial Port Open");
  
  transmit.begin();
  transmit.openWritingPipe(address);    //open writing pipe to address 00001
  transmit.setPALevel(RF24_PA_MAX);     //set RF power output to maximum
  transmit.setDataRate(RF24_250KBPS);   //set datarate to 250kbps
  transmit.setChannel(20);             //set frequency to channel 20
  transmit.stopListening(); 
  
   }

void loop() {

  if (Serial.available()){
    delay (200);
    Serial.println ("I found Serial Data");// If you are having issues, these will help you find where your code doesnt work.
    serialdata=Serial.readString();//put text from serial in serialdata string¸
  }
    
    else {

      serialdata.toCharArray(msg, 50);//convert serialdat the the msg char array
      Serial.println ("I converted it to a CHAR ARRAY");
      Serial.println("Text to be Sent-");//debugging
      Serial.println("");//debugging
      Serial.print(msg);//debugging
      Serial.println("");//debugging     
   }

  //char serialdata[32] = "";         //send character string upto 32 bytes long  
 // transmit.write(&serialdata,sizeof(serialdata));   //transmit the data
  transmit.write(msg, 50);
  delay(500);      
}

This is the code of the receiver.
You will see a few lines from the old code (433RF module)
I'm still cuting and pasting to find (like a monkey) what is working or not :slight_smile:

#include <Wire.h> //IIC Library
#include <elapsedMillis.h>//For the Status
#include <Adafruit_SSD1306.h>
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

#include <nRF24L01.h>
#include <printf.h>
#include <RF24.h>
#include <RF24_config.h>

RF24 receive (9,10);                         //create object called receive

byte address [5] = "00001";                 //creat an array with 5 elements, where each element is 1 byte;

boolean constat = 1; //Status Variable 1=On at start, 0=off at start
boolean splashcleared;//Bool to hold if splash screen has been cleared
String text = " ";//String to hold the text

elapsedMillis packettimer;//The timer for status
#define interval 1500//The threshold for how long it can go without "6"(The connection indicator)

void setup()
{
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);

  Serial.begin(9600);
  Serial.print("Starting Receiver \n");
  receive.begin();
  receive.openReadingPipe(0,address);      //open reading pipe 0 at address 00001 
  receive.setPALevel(RF24_PA_MAX);         //Set RF output to maximum
  receive.setDataRate(RF24_250KBPS);       //set datarate to 250kbps
  receive.setChannel(20);                 //set frequency to channel 20 
  receive.startListening(); 

  display.clearDisplay();
  display.setTextColor(WHITE);
  display.setCursor(25,0);  
  display.setTextSize(1);
  display.print(F("Scuba Receiver"));
  
  delay (1500);//set this to the interval
}

void loop()
{
  
    if (receive.available())                //check when received data available
  {
    char text[32];
    receive.read(&text, sizeof(text));
    Serial.println(text);
   
  }
 
  if (packettimer< interval){//It the status of the connection is good and "6" was recieved in the last 1.5 secs.
    if (splashcleared==0){//if screen hasn't been cleared of status
      display.clearDisplay();
      display.display();
      splashcleared=1;//make sure it won't be again  
    } 
  }

  if (constat == 1) { //If the status bar is enabled
    if (packettimer < interval) { //It the status of the connection is good and "6" was recieved in the last 1.5 secs.

      display.setTextColor(WHITE, BLACK);
      display.setCursor(115,0);
      display.setTextSize(1);
      display.print(F("OK")); // RF Signal is OK
      display.display();
    }
    
    else if (packettimer > interval) {//It the status of the connection is bad and "6" was not recieved in the last 1.5 secs.

      delay (450);// wait
      display.clearDisplay();
      display.setTextColor(WHITE, BLACK);
      display.setTextSize(1);
      display.setCursor(120,0);
      display.print(F("X"));  // Not receiving RF Signal
      display.display();
      delay (200);//wait
    }
  }

  {
    packettimer = 0;//Reset timer when data is recieved
    text.remove(0);//clear all text from string: text



    if (text.startsWith(",")) {
      int sepLocation[5];
      int index = text.indexOf(",");
      int i = 0;
      String extractedValues[4];
      while (index >= 0) {
        sepLocation[i] = index;
        i++ ;
        index = text.indexOf(",", index + 1);
      }
      for (int o = 0; o < 4; o++) {
        extractedValues[o] = text.substring((sepLocation[o] + 1), sepLocation[(o + 1)]);
      }
 
           display.setCursor(0, 0);
           display.setTextColor(WHITE, BLACK);
           display.setTextSize(1);
           display.print("PSI = " + extractedValues[0]);
           display.display();
            
           display.setCursor(0, 12);
           display.setTextColor(WHITE, BLACK);
           display.setTextSize(1);
           display.print("Oxygen = " + extractedValues[1] + "%");
           display.display();
                  
           display.setCursor(0, 25);
           display.setTextColor(WHITE, BLACK);
           display.setTextSize(1);
           display.print("Temp = " + extractedValues[2] + "C");
           display.display();             

           display.setCursor(75, 25);
           display.setTextColor(WHITE, BLACK);
           display.setTextSize(1);
           display.print("CO = " + extractedValues[3] + "");
           display.display();
    }
   }
  }

I also lost the feature that was showing the receive status on the right corner of the display
it was showing OK or an X for receiving or not.

That's because I remove too many lines on the TX code but I tought that there is probably a different way to show reveiving status with the library of the NRF24L01 so one step at the time :slight_smile:

In the original code, text was declared as a String (Capital S). This is a String object from the String class

String text = " ";//String to hold the text

and the received data was transferred to it with

text = (char*)buf; //put new data into string "text"

and then processed with String manipulation commands.

In the latest code you declare text globally as a String, and then locally again as a char array, but try to process it as a String.

char text[32];
    receive.read(&text, sizeof(text));
    Serial.println(text);

I'm not sure this will work, but try going back to the original approach

void loop()
{

    if (receive.available())                //check when received data available
  {
    char buf[32];
    receive.read(&buf, sizeof(buf));
    text = (char*)buf;  
  }

Then process "text" as before with the String commands.

You seem to be trying to send 50 characters when the max is 32.

It is not a good idea to use the String (capital S) class on an Arduino as it can cause memory corruption in the small memory on an Arduino. Just use cstrings - char arrays terminated with 0.

Have a look at the examples in Serial Input Basics - simple reliable ways to receive data without using any Strings.

...R

Hey Cattledog,

It's now working with your modifications Thanks

I will now continue reading on the net a few examples, in order
to receive the status of my scuba compressor.

I have 3 LED's on the compressor itself.

Power
Oxygen valve
Purge timer

I found an example to control simple LED remotely with the NRF24L01
so with this example I should and I hope, to TX the LED status from
my compressor to my remote box.

I will then be able to see remotely my sensors and the LED status of
my scuba compressor while it's filling my tanks.

Please post the updated Rx and Tx sketches. It unclear to me what is your message length, and Robin2 has pointed out issues with the size if the send and receive buffers. What are the different transmitter messages? If you read bytes into memory space beyond what is reserved for an array, you can get unexpected corruption.

Robin2 also brings up the point about converting the entire sketch to null terminated character arrays instead of String Objects. You are converting data back and forth from char arrays to Strings several times in the code.

Get some breathing room on this project, step back a bit, study Robin2's tutorial on receiving and parsing serial data and consider re-crafting the sketch. I believe it will be more robust in the long run.

I just noticed that you never actually posted the virtual Wire transmitter code, only the receiver. Please post that, so that we can see what was originally working. Perhaps go back and modify the post with the VW Rx sketch to include the VW Tx code. Or just make a new posting with both codes for reference along with the new updated Rx and TX sketches for the NRF24L01.