Wireless RF Communication using nRF24L01 Module

Published  August 1, 2019   5
Wireless RF Communication between Raspberry Pi and Arduino UNO using nRF24L01 Module

Designers use many wireless communication systems like Bluetooth Low Energy (BLE 4.0), Zigbee, ESP8266 Wi-Fi Modules, 433MHz RF Modules, Lora, nRF etc. And the selection of medium depends on the type of application it is being used in. Among all, one popular wireless medium for local network communication is the nRF24L01. These modules operate on 2.4GHz (ISM band) with baud rate from 250Kbps to 2Mbps which is legal in many countries and can be used in industrial and medical applications. It is also claimed that with proper antennas these modules can transmit and receive signals upto a distance of 100 meters between them. We previously used nRF24L01 with Arduino to control servo motor and create a Chat Room.

 

Here we will use nRF24L01 – 2.4GHz RF Transceiver module with Arduino UNO and Raspberry Pi to establish a wireless communication between them. The Raspberry pi will act as a transmitter and Arduino Uno will listen to Raspberry Pi and print the message sent by Raspberry Pi using nRF24L01 on a 16x2 LCD. nRF24L01 also have inbuilt BLE capabilities and it can also communicate wirelessly using BLE.

 

The tutorial is divided into two sections. The first section will include the interfacing of nRF24L01 with Arduino to act as Receiver and the second section will include the interfacing of nRF24L01 with Raspberry Pi to act as Transmitter. The complete code for both of the section with working video will be attached at the end of this tutorial.

 

The nRF24L01 RF Module

The nRF24L01 modules are transceiver modules, meaning each module can both send and receive data but since they are half-duplex they can either send or receive data at a time. The module has the generic nRF24L01 IC from Nordic semi-conductors which is responsible for transmission and reception of data. The IC communicates using the SPI protocol and hence can be easily interfaced with any microcontrollers. It gets a lot easier with Arduino since the libraries are readily available. The pinouts of a standard nRF24L01 module is shown below

 

The module has on operating voltage from 1.9V to 3.6V (typically 3.3V) and consumes very less current of only 12mA during normal operation which makes it battery efficient and hence can even run on coin cells. Even though the operating voltage is 3.3V most of the pins are 5V tolerant and hence can be directly interfaced with 5V microcontrollers like Arduino.  Another advantage of using these modules is that, each module has 6 Pipelines. Meaning, each module can communicate with 6 other modules to transmit or receive data. This makes the module suitable for creating star or mesh networks in IoT applications. Also they have a wide address range of 125 unique ID’s, hence in a closed area we can use 125 of these modules without interfering with each other. 

 

Circuit Diagram

nRF24L01 with Arduino: 

The circuit diagram for connecting nRF24L01 with Arduino is easy and doesn’t have much components. The nRF24l01 will be connected by SPI interface and the 16x2 LCD is interfaced with I2C protocol which uses only two wires.

Circuit Diagram for Interfacing nRF24L01 with Arduino

Circuit Hardware for Interfacing nRF24L01 with Arduino

 

nRF24L01 with Raspberry Pi:

The circuit diagram for connecting nRF24L01 with Raspberry Pi is also very simple and only the SPI interface is used to connect Raspberry Pi and nRF24l01.

Circuit Diagram for Interfacing nRF24L01 with Raspberry PiCircuit Hardware for Interfacing nRF24L01 with Raspberry Pi

 

Programming Raspberry Pi to Send Message using nRF24l01

Programming of the Raspberry Pi will be done using Python3. You can also use C/C++ as Arduino. But there is already a library available for nRF24l01 in python which can be downloaded from github page. Note that the python program and the library should be on the same folder or the python program will not be able to find the library. After downloading the library just extract and make a folder where all programs and library files will be stores. When library installation is done, just start writing the program. The program start with the inclusion of libraries which will be used in code like import GPIO library for accessing the Raspberry Pi GPIOs and import time for accessing the time related functions. If you are new to Raspberry Pi then fall back to getting started with Raspberry pi.

import RPi.GPIO as GPIO 
import time     
import spidev
from lib_nrf24 import NRF24 

 

Set the GPIO mode in "Broadcom SOC channel". This means that you are referring to the pins by the "Broadcom SOC channel" number, these are the numbers after "GPIO"( for e.g. GPIO01,GPIO02…). These are not the Board Numbers.

GPIO.setmode(GPIO.BCM)  

 

Next we will set it up the pipe address. This address is important in order to communicate with the Arduino receiver. The address will be in the hex code.

pipes = [[0xE0, 0xE0, 0xF1, 0xF1, 0xE0], [0xF1, 0xF1, 0xF0, 0xF0, 0xE0]]

 

Begin the radio using GPIO08 as CE and GPIO25 as CSN pins.

radio.begin(0, 25)  

 

Set payload size as 32 bit, channel address as 76, data rate of 1 mbps and power levels as minimum.

radio.setPayloadSize(32)  
radio.setChannel(0x76) 
radio.setDataRate(NRF24.BR_1MBPS)    
radio.setPALevel(NRF24.PA_MIN)

 

Open the pipes to start writing the data and print the basic details of nRF24l01.

radio.openWritingPipe(pipes[0])     
radio.printDetails()

 

Prepare a message in the string form. This message will be sent to Arduino UNO.

sendMessage = list("Hi..Arduino UNO")  
while len(sendMessage) < 32:    
    sendMessage.append(0)

 

Start writing to the radio and keep on writing the complete string till the radio is available. Along with it, note down the time and print a debug statement of message delivery.

while True:
    start = time.time()      
    radio.write(sendMessage)   
    print("Sent the message: {}".format(sendMessage))  
send
    radio.startListening()      

 

If the string is completed and pipe is closed then print a debug message of timed out.

while not radio.available(0):
        time.sleep(1/100)
        if time.time() - start > 2:
            print("Timed out.")  # print error message if radio disconnected or not functioning anymore
            break

 

Stop listening to the radio and close the communication and restart the communication after 3 seconds to send another message.

  radio.stopListening()     # close radio
    time.sleep(3)  # give delay of 3 seconds

 

The Raspberry program is simple to understand if you know the basics of python. Complete Python program is given at the end of tutorial.

 

Executing the Python Program in Raspberry Pi:

Executing the program is very easy after following the below steps:

  • Save the Python Program and Library files in the same folder.

Executing the Python Program in Raspberry Pi

 

  • My program file name for Sender is nrfsend.py and also every files are in the same folder

Setup the Python Program in Raspberry Pi

 

  • Go to Command Terminal of Raspberry Pi. And locate the python program file by using “cd” command.

Command Terminal of Raspberry Pi

 

  • Then open the folder and write command “sudo python3 your_program.py” and hit enter. You will be able to see the basic details of nRf24 and the radio will start sending the messages after every 3 seconds. The message debug will display after sending is done with all characters sent.

Programming Raspberry Pi to Send Message using nRF24l01

 

Now we will see the same program as receiver in the Arduino UNO.

 

Programming Arduino UNO to Receive Message using nRF24l01

Programming the Arduino UNO is similar to programming the Raspberry Pi. We will follow similar methods but with different programming language and steps. The steps will include the reading part of nRF24l01. The library for nRF24l01 for Arduino can be downloaded from github page. Start with including necessary libraries. We are using 16x2 LCD using I2C Shield so include Wire.h library and also the nRF24l01 is interfaced with SPI so include SPI library.

#include<SPI.h>                   
#include <Wire.h>

 

Include RF24 and LCD library for accessing the RF24 and LCD functions.

#include<RF24.h>                  
#include <LiquidCrystal_I2C.h>

 

The LCD address for I2C is 27 and it is a 16x2 LCD so write this into the function.

LiquidCrystal_I2C lcd(0x27, 16, 2);

 

The RF24 is connected with standard SPI pins along with CE in pin 9 and CSN in pin 10.

RF24 radio(9, 10) ;  

 

Start the radio, set the power level and set channel to 76. Also set the pipe address same as Raspberry Pi and open the pipe to read.

radio.begin();        
  radio.setPALevel(RF24_PA_MAX) ;   
  radio.setChannel(0x76) ;            
  const uint64_t pipe = 0xE0E0F1F1E0LL ;    
  radio.openReadingPipe(1, pipe) ;

 

Begin the I2C communication and initialise the LCD display.

Wire.begin();                 
  lcd.begin();                    
  lcd.home();                       
  lcd.print("Ready to Receive");

 

Start listening to the radio for incoming messages and set the message length as 32 bytes.

radio.startListening() ;        
  char receivedMessage[32] = {0}

 

If radio is attached then start reading the message and save it. Print the message to serial monitor and also print to the display until the next message arrives. Stop the radio to listen and retry after some interval. Here it is 10 micro seconds.

if (radio.available()) {       
    radio.read(receivedMessage, sizeof(receivedMessage));        Serial.println(receivedMessage) ;    
    Serial.println("Turning off the radio.") ;   
    radio.stopListening() ;   
    String stringMessage(receivedMessage) ;     
    lcd.clear();    
    delay(1000);    
    lcd.print(stringMessage);   
  }

 

Upload the complete code given at the end to the Arduino UNO and wait for the message to be received.

Wireless RF Communication between Raspberry Pi and Arduino UNO using nRF24L01 Module

 

This finishes the complete tutorial on sending a message using Raspberry Pi & nRf24l01 and receiving it using Arduino UNO & nRF24l01. The message will be printed to the 16x2 LCD. The pipe addresses are very important in both Arduino UNO and Raspberry Pi. If you face any difficulty while doing this project then please comment below or reach to out forum for more detailed discussion.

Also check the demonstration video below.

Code

NRF Transmitter Side Code (Raspberry Pi):

import RPi.GPIO as GPIO  # import gpio
import time      #import time library
import spidev
from lib_nrf24 import NRF24   #import NRF24 library

GPIO.setmode(GPIO.BCM)       # set the gpio mode

  # set the pipe address. this address shoeld be entered on the receiver alo
pipes = [[0xE0, 0xE0, 0xF1, 0xF1, 0xE0], [0xF1, 0xF1, 0xF0, 0xF0, 0xE0]]
radio = NRF24(GPIO, spidev.SpiDev())   # use the gpio pins
radio.begin(0, 25)   # start the radio and set the ce,csn pin ce= GPIO08, csn= GPIO25
radio.setPayloadSize(32)  #set the payload size as 32 bytes
radio.setChannel(0x76) # set the channel as 76 hex
radio.setDataRate(NRF24.BR_1MBPS)    # set radio data rate
radio.setPALevel(NRF24.PA_MIN)  # set PA level

radio.setAutoAck(True)       # set acknowledgement as true 
radio.enableDynamicPayloads()
radio.enableAckPayload()

radio.openWritingPipe(pipes[0])     # open the defined pipe for writing
radio.printDetails()      # print basic detals of radio

sendMessage = list("Hi..Arduino UNO")  #the message to be sent
while len(sendMessage) < 32:    
    sendMessage.append(0)

while True:
    start = time.time()      #start the time for checking delivery time
    radio.write(sendMessage)   # just write the message to radio
    print("Sent the message: {}".format(sendMessage))  # print a message after succesfull send
    radio.startListening()        # Start listening the radio
    
    while not radio.available(0):
        time.sleep(1/100)
        if time.time() - start > 2:
            print("Timed out.")  # print errror message if radio disconnected or not functioning anymore
            break

    radio.stopListening()     # close radio
    time.sleep(3)  # give delay of 3 seconds

# >

 

NRF Receiver Side Code (Arduino):

#include<SPI.h>                   // spi library for connecting nrf
#include <Wire.h>                             // i2c libary fro 16x2 lcd display
#include<RF24.h>                  // nrf library
#include <LiquidCrystal_I2C.h>     // 16x2 lcd display library

LiquidCrystal_I2C lcd(0x27, 16, 2);         // i2c address is 0x27

RF24 radio(9, 10) ;  // ce, csn pins    
void setup(void) {
  while (!Serial) ;
  Serial.begin(9600) ;     // start serial monitor baud rate
  Serial.println("Starting.. Setting Up.. Radio on..") ; // debug message
  radio.begin();        // start radio at ce csn pin 9 and 10
  radio.setPALevel(RF24_PA_MAX) ;   // set power level
  radio.setChannel(0x76) ;            // set chanel at 76
  const uint64_t pipe = 0xE0E0F1F1E0LL ;    // pipe address same as sender i.e. raspberry pi
  radio.openReadingPipe(1, pipe) ;        // start reading pipe 
  radio.enableDynamicPayloads() ;
  radio.powerUp() ;          
  Wire.begin();                 //start i2c address
  lcd.begin();                    // start lcd 
  lcd.home();                       
  lcd.print("Ready to Receive");  // print starting message on lcd 
  delay(2000);
  lcd.clear();
}

void loop(void) {

  radio.startListening() ;        // start listening forever
  char receivedMessage[32] = {0} ;   // set incmng message for 32 bytes
  if (radio.available()) {       // check if message is coming
    radio.read(receivedMessage, sizeof(receivedMessage));    // read the message and save
    Serial.println(receivedMessage) ;    // print message on serial monitor 
    Serial.println("Turning off the radio.") ;   // print message on serial monitor
    radio.stopListening() ;   // stop listening radio
    String stringMessage(receivedMessage) ;     // change char to string
    lcd.clear();    // clear screen for new message
    delay(1000);    // delay of 1 second 
    lcd.print(stringMessage);   // print received mesage
  }
  delay(10);
}

Video

Have any question realated to this Article?

Ask Our Community Members

Comments

I want to reverse this process, which seems simple enough.  But where I run into a problem is getting the data from the nrf24l01 to the MQTT server.  How can I do this?  Is there a solution?  My setup is:

remote motion+nrf24l01 (transmit only) ---)))) >>> (((---local nrf24l01+RPiAP/wMQTT (receive only)

Is there any way using the NRF libraries to test whether a NRF24l01 board is functioning and/or wired up correctly?  I have tried several different libraries on Raspberry Pi and Arduino.  The closest I get is that when I execute a receiver script it repeatedly acts as if it is receiving garbage data.  Amazingly the same happens when I unplug the NRF24l01 completely!  It is very hard to debug when you can't tell if data being reported as received is not actually coming from the board.  Is there any methods that give health data or report values from registers on the board (that would fail if the board were not connected at all)?  Thanks in advance!

I can't figure out what I did wrong.  The RPi is not sending, because the Arduino does not see data coming in.

Raspberry Pi 3B+

I'm sure my wiring is correct.  SPI is enabled on the RPi.  I loaded a new, latest (Buster) Raspbian.  I ported the RPi program to another Arduino with radio, this worked.

I missed something.  Can anyone help?

I have triple checked wiring having setup coding as per this article - no dialog! Tried Arduino to Arduino and it works! So have to assume that the Raspi doesn't like the Arduino - Huh!

Anyway, replaced nRF hardware at Raspi end, still no dialog... Instictively not happy about the "pipes" statement and the following list of param's. Can't find a way to code replicate the pipe numbers )as called for to be the same on both systems, relevant to the Arduino. Thought I have it but certainly it could be where the problem lies. Any help in this area would be gratefully accepted.

hi,

 

I found two problems why it did not work.
I have an Rasperry pi 4 and by default SPI master driver is disabled by default on Raspberry Pi OS.

To enable:

ensure the line dtparam=spi=on isn't commented out in /boot/config.txt, and reboot. If the SPI driver was loaded, you should see the device /dev/spidev0.0.
https://circuitdigest.com/microcontroller-projects/wireless-rf-communication-between-arduino-and-raspberry-pi-using-nrf24l01

and the second problem was that CRC length was disabled:

to enable:

The problem is that I use Python to access the bus and it is not evident how, when and where I should set the speed of the SPI bus.
EDIT: I found it: In lib_nrf24.py in function:

def begin(self, csn_pin ... after self.spidev.open add:
self.spidev.max_speed_hz = 4000000
(in my case 5 MHz did not work)

found here: https://raspberrypi.stackexchange.com/questions/71730/possible-spi-issues-around-nrf24-operations-post-rpi-system-update

Now it works fine - thanks a lot