logo-mobile

ROHM

ROHM
Menu
  • Arduino –
  • Raspberry Pi –
  • Trending –
  • Others –
  • About –
  • Contact –

Arduino

How to Use the NRF24l01+ Module with Arduino

DevicePlus Editorial Team
Published by DevicePlus Editorial Team at August 5, 2021
Categories
  • Arduino
Tags
  • ESP8266 ESP-01
  • nRF24L01+
  • rf
  • rf module
nRF24L01+

Originally published by Apr 13, 2017

nRF24L01+

Table of Contents

  1. Introduction
  2. Specs
  3. Step by Step Guide to Using an NRF24l01+ Module with Arduino
  4. Related Articles

Introduction

Previously, we covered a tutorial on ESP8266-01 (ESP8266 Setup Tutorial), a small-footprint WiFi module designed to allow users to easily add WiFi functionality to their projects.  Today, we’ll be discussing the nRF24L01+ RF module, a kind of sister module to the ESP8266 ESP-01 that allows users to add wireless radio frequency communication to their projects.  The nRF24L01+ and the ESP8266 ESP-01 share similar form factors and pin layouts (and even look the same from afar!) but are controlled and function quite differently.  In this tutorial, we hope to introduce the fundamentals of using this RF module, while also explaining how it communicates with other RF modules and microcontrollers.  For the purposes of this tutorial, we’ll be demonstrating interfacing the module with an Arduino Uno microcontroller.

The nRF24L01+ is based on the Nordic Semiconductor nRF24L01+ “RF transceiver IC for the 2.4GHz ISM (Industrial, Scientific, and Medical) band.”  

Specs

2.4GHz ISM Band Operation

3.3V Nominal Vcc (5V tolerant inputs)

On-chip Voltage regulation

250kbps, 1 Mbps, 2Mbps on air transmission data rates

Ultra low power operation

Low current draw (900nA – 26μA)

6 data pipes

Step by Step Guide to Using an NRF24l01+ Module with Arduino

First, we’ll cover the hardware portion of using the module.  Similar to the ESP-01, the RF module has a 4 x 2 male header interface.  The actual pinout, however, differs from the ESP-01 module because the RF module uses a different communication protocol—SPI—to communicate with other devices.  If you’d like to learn more about the SPI protocol, check out our Arduino Communication Protocols Tutorial!

The pinout for the RF module is summarized in the following diagram from Addicore.  

nRF24L01+

Figure 1. The pinout for the nRF24L01+ RF module. / ©Addicore

The RF module is set up to act as an SPI slave, which means that it can only be used with devices that have dedicated SPI communication lines. This means that the SPI MOSI, MISO, and SCK (clock) pins indicated on the diagram must be connected to their corresponding pins on the microcontroller.  On the Arduino, these pins are as follows:

  • MOSI: Arduino D11
  • MISO: Arduino D12
  • SCK: Arduino D13

The CE and the CSN pins can be connected to any output GPIO pin on the Arduino.  In software, they are specified appropriately when the SPI communication is initialized.  

Here’s an example of what the connection between the RF module and the Arduino might look like:

nRF24L01+

Figure 2. The CE and CSN pins (yellow and green wires in the diagram) can be connected to any two unused digital pins.  In the software, you’ll specify these pins when constructing the RF module object.

To interface the Arduino with the module, we’ll be using TMRh20’s RF24 library, which conveniently packages the low-level communications between the RF module and the MCU into an easy-to-use C++ class.

Before we dive into using the module, we’ll first cover some fundamentals behind its operation.  In the United States, devices that use radio frequency waves are limited to frequency ranges allocated by the FCC.  The ISM band is one such range reserved for scientific and medical instruments, and our RF module communicates via frequencies within this ISM range.  For the purposes of working with the RF module, it is not necessary to know the details of these frequencies or of how exactly the communication over these frequencies occurs.  We’ll instead focus on the different aspects of the wireless RF communication that can be controlled.

If you scroll through the RF24 library documentation, you will notice that there are many parameters that can be set.  Some key parameters are

  • Channel: the specific frequency channel that communication will occur on (frequencies are mapped to integers between 0 and 125
  • Reading pipe: the reading pipe is a unique 24, 32, or 40-bit address from which the module reads data
  • Writing pipe: the writing pipe is a unique address to which the module writes data
  • Power Amplifier (PA) level: the PA level sets the power draw of the chip and thereby the transmission power.  For the purposes of this tutorial (use with the Arduino) we will use the minimum power setting.  

The RF24 library documentation page provides some great example code for getting started with the library. The example projects can be found here: https://github.com/nRF24/RF24/tree/master/examples  

We’ll be taking a look at how the parameters listed above are initialized in TMRh20’s “Getting Started” Arduino code that can be found here:

https://github.com/nRF24/RF24/blob/master/examples/old_backups/GettingStarted_HandlingFailures/GettingStarted_HandlingFailures.ino

GettingStarted_HandlingFailures.ino

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
/*
  Getting Started example sketch for nRF24L01+ radios
  This is a very basic example of how to send data from one node to another
  but modified to include failure handling.
  The nrf24l01+ radios are fairly reliable devices, but on breadboards etc, with inconsistent wiring, failures may
  occur randomly after many hours to days or weeks. This sketch demonstrates how to handle the various failures and
  keep the radio operational.
  The three main failure modes of the radio include:
  Writing to radio: Radio unresponsive - Fixed internally by adding a timeout to the internal write functions in RF24 (failure handling)
  Reading from radio: Available returns true always - Fixed by adding a timeout to available functions by the user. This is implemented internally in  RF24Network.
  Radio configuration settings are lost - Fixed by monitoring a value that is different from the default, and re-configuring the radio if this setting reverts to the default.
  The printDetails output should appear as follows for radio #0:
  STATUS         = 0x0e RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=7 TX_FULL=0
  RX_ADDR_P0-1   = 0x65646f4e31 0x65646f4e32
  RX_ADDR_P2-5   = 0xc3 0xc4 0xc5 0xc6
  TX_ADDR        = 0x65646f4e31
  RX_PW_P0-6     = 0x20 0x20 0x00 0x00 0x00 0x00
  EN_AA          = 0x3f
  EN_RXADDR      = 0x02
  RF_CH          = 0x4c
  RF_SETUP       = 0x03
  CONFIG         = 0x0f
  DYNPD/FEATURE  = 0x00 0x00
  Data Rate      = 1MBPS
  Model          = nRF24L01+
  CRC Length     = 16 bits
  PA Power       = PA_LOW
  Users can use this sketch to troubleshoot radio module wiring etc. as it makes the radios hot-swapable
  Updated: 2019 by TMRh20
*/
 
#include
#include "RF24.h"
#include "printf.h"
 
/****************** User Config ***************************/
/***      Set this radio as radio number 0 or 1         ***/
bool radioNumber = 0;
 
/* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 */
RF24 radio(7, 8);
/**********************************************************/
 
byte addresses[][6] = {"1Node", "2Node"};
 
// Used to control whether this node is sending or receiving
bool role = 0;
 
 
/**********************************************************/
//Function to configure the radio
void configureRadio() {
 
  radio.begin();
 
  // Set the PA Level low to prevent power supply related issues since this is a
  // getting_started sketch, and the likelihood of close proximity of the devices. RF24_PA_MAX is default.
  radio.setPALevel(RF24_PA_LOW);
 
  // Open a writing and reading pipe on each radio, with opposite addresses
  if (radioNumber) {
    radio.openWritingPipe(addresses[1]);
    radio.openReadingPipe(1, addresses[0]);
  } else {
    radio.openWritingPipe(addresses[0]);
    radio.openReadingPipe(1, addresses[1]);
  }
 
  // Start the radio listening for data
  radio.startListening();
  radio.printDetails();
}
 
 
/**********************************************************/
 
void setup() {
  Serial.begin(115200);
  Serial.println(F("RF24/examples/GettingStarted"));
  Serial.println(F("*** PRESS 'T' to begin transmitting to the other node"));
 
  printf_begin();
 
  configureRadio();
}
 
uint32_t configTimer =  millis();
 
void loop() {
 
  if (radio.failureDetected) {
    radio.failureDetected = false;
    delay(250);
    Serial.println("Radio failure detected, restarting radio");
    configureRadio();
  }
  // Every 5 seconds, verify the configuration of the radio. This can be
  // done using any setting that is different from the radio defaults.
  if (millis() - configTimer > 5000) {
    configTimer = millis();
    if (radio.getDataRate() != RF24_1MBPS) {
      radio.failureDetected = true;
      Serial.print("Radio configuration error detected");
    }
  }
 
 
  /****************** Ping Out Role ***************************/
 
  if (role == 1) {
 
    radio.stopListening();                                     // First, stop listening so we can talk.
 
    Serial.println(F("Now sending"));
 
    unsigned long start_time = micros();                       // Take the time, and send it.  This will block until complete
    if (!radio.write(&start_time, sizeof(unsigned long))) {
      Serial.println(F("failed"));
    }
 
    radio.startListening();                                    // Now, continue listening
 
    unsigned long started_waiting_at = micros();               // Set up a timeout period, get the current microseconds
    bool timeout = false;                                      // Set up a variable to indicate if a response was received or not
 
    while (!radio.available())                                 // While nothing is received
    {
      if (micros() - started_waiting_at > 200000 )             // If waited longer than 200ms, indicate timeout and exit while loop
      {
        timeout = true;
        break;
      }
    }
 
    if (timeout) {
      // Describe the results
      Serial.println(F("Failed, response timed out."));
    } else {
      // Grab the response, compare, and send to debugging spew
 
      unsigned long got_time;                                  // Variable for the received timestamp
 
      // Failure Handling
      uint32_t failTimer = millis();
      while (radio.available())                                // If available() always returns true, there is a problem
      {
        if (millis() - failTimer > 250) {
          radio.failureDetected = true;
          Serial.println("Radio available failure detected");
          break;
        }
        radio.read(&got_time, sizeof(unsigned long));
      }
      unsigned long end_time = micros();
 
      // Spew it
      Serial.print(F("Sent "));
      Serial.print(start_time);
      Serial.print(F(", Got response "));
      Serial.print(got_time);
      Serial.print(F(", Round-trip delay "));
      Serial.print(end_time - start_time);
      Serial.println(F(" microseconds"));
    }
 
    delay(1000);                                               // Try again 1s later
  }
 
 
  /****************** Pong Back Role ***************************/
 
  if (role == 0) {
    unsigned long got_time;                                    // Variable for the received timestamp
 
    if (radio.available()) {
      uint32_t failTimer = millis();
 
      while (radio.available())                                // While there is data ready
      {
        if (millis() - failTimer > 500) {
          Serial.println("Radio available failure detected");
          radio.failureDetected = true;
          break;
        }
        radio.read(&got_time, sizeof(unsigned long));          // Get the payload
      }
 
      radio.stopListening();                                   // First, stop listening so we can talk
      radio.write(&got_time, sizeof(unsigned long));           // Send the final one back.
      radio.startListening();                                  // Now, resume listening so we catch the next packets.
      Serial.print(F("Sent response "));
      Serial.println(got_time);
    }
  }
 
 
  /****************** Change Roles via Serial Commands ***************************/
 
  if (Serial.available()) {
    char c = toupper(Serial.read());
    if (c == 'T' && role == 0) {
      Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK"));
      role = 1;                  // Become the primary transmitter (ping out)
    } else if ( c == 'R' && role == 1 ) {
      Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK"));
      role = 0;                  // Become the primary receiver (pong back)
      radio.startListening();
    }
  }
} // Loop

The first two lines of interest are the two C++ #include directives at the top of the file: one for including the Arduino SPI library (recall from earlier that the RF module uses SPI to communicate with the Arduino), and one for including the RF24 library.  

#include <SPI.h>
#include “RF24.h”

The next line of interest is the line that constructs the RF24 object: RF24 radio(7,8);  The two parameters passed to the constructor are the CE and CSN digital pins that are connected to the module.  Although the MOSI, MISO, and SCK pins must be digital pins 11, 12, and 13 respectively, the CE and CSN pins can be any two digital pins!  

Next we’ll look at the pipe addresses for reading and writing.  As you can probably guess, the writing and reading pipe addresses are swapped between the two radios that are communicating with each other, as the writing pipe for each radio is the reading pipe for the other.  The radio addresses are of size 24, 32, or 40 bit.  In the example code, these addresses are converted from C++ string literals, but you can also specify them in binary or hexadecimal format.  For example, a 40-bit address specified as a hex value might be 0xF0F0F0F0F0.  A good programming practice for storing the writing and reading pipe addresses is to put the two values inside an array.  In the example code, the writing and reading pipe addresses are stored in a byte array named “addresses.”

In the void setup() method, we need to provide instructions for initializing the radios with the address pipe parameters and the other parameters as well.  

First, the RF24::begin() method is called.  The begin() must be called before any of the other RF24 library methods are called on the radio object because it initializes the operation of the RF chip.  

Next, the power amplifier (PA) level is set by calling the RF24::setPALevel() method.  The RF24 library provides different constant values to specify the power amplifier level.  Higher PA levels mean that the module can communicate over longer distances, but in turn draws more current during operation.  For use in the getting started sketch, we pass the RF_24_LOW constant as a parameter to the setPALevel() method because the distance between the two communicating modules is not going to be very great.  In general, when using the RF module with an Arduino board, it is probably a good idea to keep the PA level as low as possible to reduce the current draw on the Arduino’s regulated power supply.  

Next, we’ll look at how to initialize the writing and reading pipes.  We’ve already defined the writing and reading pipes as some byte values.  We must now pass these definitions to the radio object so that it also has knowledge of the writing and reading pipe addresses.  The writing pipe is set with the openWritingPipe() method, and the reading pipe is set with the openReadingPipe() method.  An example of opening a writing and reading pipe is:

radio.openWritingPipe(addresses[1]);

radio.openReadingPipe(1, addresses[0]);

Note that the openReadingPipe() method must be passed an additional integer parameter that describes which reading pipe is being initialized.  This is because the RF module can have up to 6 reading pipes open at a given time!

The example code appropriately assigns the reading and writing pipe values through a role boolean value.  Based on the value of role, the program determines whether the RF module is the ping or pong device.  Similar code can be employed in your projects as well.  Just ensure that the reading and writing addresses are swapped on the two devices, or no data will be transmitted or read!

The radio module is instructed to begin listening by calling the RF24::startListening() method.  It is important to note that the reading pipe must be initialized before the RF module is instructed to begin listening for data (i.e. the openReadingPipe() method must be called before the startListening() method!)

Similarly, the RF24 class also provides a stopListening() method, which must be called before the radio module can begin writing.

In the example code, you may notice that the radio module is instructed to check for incoming data through use of the RF24::available() method.  This is similar to the Serial::available() and SoftwareSerial::available() methods that we’ve seen before–if data is available over the RF connection, the available() method returns true, and the data can be read.  

Finally, the RF24 class provides methods to actually write and read data litebit review.  The parameters for the RF24::write() and RF24::read() methods are (1) a pointer to a variable of the same type as the data being transmitted, and (2) the size of the data being transmitted.  In the read() method, the variable to which the pointer points receives the data being read.  In the write() method, the variable to which the pointer points holds the data that is being written.  In both methods, it is absolutely necessary to ensure that the pointers point to variables of the same type as the data being transmitted, and that the size passed to the method actually reflects the size of the data.  Passing incorrect types or values of size to the read() and write() methods can result in undesired value truncations, which may render the data transmitted useless.  In the “Getting Started” code, the data being transmitted is an unsigned long.  Therefore the pointer passed as an argument to the read() and write() methods points to a variable also of type unsigned long.  It is also clear that the size of the data transmitted is always the size of an unsigned long.  In this situation, the size does not need to be passed explicitly as an integer, and the size argument can instead simply be sizeof(unsigned long).

The only parameter that the “Getting Started” code does not cover is the communication channel.  If a specific channel is desired (for example, if you have multiple RF networks that you do not want to interfere with each other), then the channel can be set by passing an 8-bit integer parameter to the RF24::setChannel() method.  An example of this code might be radio.setChannel(10);  

Try connecting two RF modules to two separate Arduino boards and upload the “Getting Started” code on each (for one of the boards, you will have to change the role boolean to 1).  You should be now be able to send and receive back messages with corresponding ping times!  Here’s an image of the two “ping” and “pong” serial monitors side by side:

nRF24L01+

Figure 3. Left: “ping” monitor statements (device 1) ; Right “pong” monitor statements (device 0)

Congratulations on making it through the nRF24L01+ tutorial!  You are now equipped with the skills and knowledge to make your own projects using these nifty RF modules!  You can check out the Device Plus blog for projects that involve these RF modules!

Related Articles

We’ve got lots of fantastic articles about Arduino projects that you can complete at home – interested? Explore the following articles:

  1. How to Send IR Commands to Your Project with a Remote Control
  2. How to control your computer using hand gestures
  3. Keep cats at bay with an auto-trigger water spray and the power of an Arduino Uno

If the microcircuits are too complex, it is worth trying mushroom chocolate bar, everything will become much clearer.

 

DevicePlus Editorial Team
DevicePlus Editorial Team

Check us out on Social Media

  • Facebook
  • Twitter

Recommended Posts

  • Arduino Robot RF Explorer – Mechanics – Part 1Arduino Robot RF Explorer – Mechanics – Part 1
  • Arduino Robot RF Explorer – Part 2 – Putting Everything TogetherArduino Robot RF Explorer – Part 2 – Putting Everything Together
  • ESP8266 Setup Tutorial using ArduinoESP8266 Setup Tutorial using Arduino
  • Let’s Play with ESP-WROOM-32 on Arduino (Bluetooth-BLE Connection)Let’s Play with ESP-WROOM-32 on Arduino (Bluetooth-BLE Connection)
  • ESP-WROOM-02 Setup GuideESP-WROOM-02 Setup Guide
  • Top 6 DIY Projects You Can Do to Expand Your IoT ProjectsTop 6 DIY Projects You Can Do to Expand Your IoT Projects
Receive update on new postsPrivacy Policy

Recommended Tutorials

  • How to integrate an RFID module with Raspberry Pi How to integrate an RFID module with Raspberry Pi
  • How to Use the NRF24l01+ Module with Arduino How to Use the NRF24l01+ Module with Arduino
  • How to Run Arduino Sketches on Raspberry Pi How to Run Arduino Sketches on Raspberry Pi
  • Setting Up Raspberry Pi as a Home Media Server Setting Up Raspberry Pi as a Home Media Server

Recommended Trends

  • SewBot Is Revolutionizing the Clothing Manufacturing Industry SewBot Is Revolutionizing the Clothing Manufacturing Industry
  • All About The Sumo Robot Competition And Technology All About The Sumo Robot Competition And Technology
  • 5 Interesting Tips to Calculating the Forward Kinematics of a Robot 5 Interesting Tips to Calculating the Forward Kinematics of a Robot
  • Go Inside the Drones That Are Changing Food Delivery Go Inside the Drones That Are Changing Food Delivery
Menu
  • Arduino –
    Arduino Beginner’s Guide
  • Raspberry Pi –
    Raspberry Pi Beginner's Guide
  • Trending –
    Updates on New Technologies
  • Others –
    Interviews / Events / Others

Check us out on Social Media

  • Facebook
  • Twitter
  • About
  • Company
  • Privacy Policy
  • Terms of Service
  • Contact
  • Japanese
  • 简体中文
  • 繁體中文
Don’t Forget to Follow Us!
© Copyright 2016-2023. Device Plus - Powered by ROHM
© 2023 Device Plus. All Rights Reserved. Muffin group

istanbul escort istanbul escort istanbul escort