nRF24L01 – Arduino Interfacing, Circuits, Codes, PA + LNA
Table of Contents
nRF24L01:
If you want to master the nRF24L01 RF Transceiver modules, you need to read this article from start to finish. Because, after reading this article, you will not only be able to build similar development boards for yourself, but you will also learn how to use these boards in simple, intermediate, and advanced level projects.
- We will start with simple one-way communication where we will send the Hello message wirelessly from the Transmitter side to the Receiver side.
- Then, we will modify the same project, and build a wireless temperature monitoring system. Temperature value will be printed on the Receiver’s side Oled display module.
- In example number 3, again we are going to modify the code and while using the same one-way communication; we will send two sensors values from the Transmitter side to the Receiver side. So, if you learn how to send values of two sensors, then you can also send readings of multiple sensors to the receiver side; all you need is to increase the number of variables. And that’s not all;
- We are also going to cover two-way communication. You should not skip Example 4, as it will be very useful for your future projects. Learning two-way communication will enable you to generate feedback messages, which is crucial for effective communication. Imagine a situation where you want to turn a load ON/OFF from another room or it could be any situation when the load is not visible to you. You send a command, but you don’t know if the receiver received it or whether the load is actually turned ON/OFF. You need to know if your command was successful, and that’s where feedback messages come in. To explain two-way communication well, I will put sensors on both the transmitter and receiver sides.
- Apart from explaining one-way and two-way communication, I will also provide a practical demonstration on how to secure your wireless communication using unique addresses. This will ensure that only authorized devices can access the transmitted data, preventing unauthorized access and maintaining data privacy.
- We will also explore different data rates and demonstrate their practical applications. By adjusting data rates, you will learn how to control the communication range and speed, optimizing your wireless communication system for specific use cases.
I recommend making similar development boards for yourself. This will save you a lot of time because you won’t need to do much wiring. You can download the PCB Gerber files from my Patreon page. If you want to design PCBs yourself, you can watch my videos on PCB designing; available on my YouTube channel “Electronic Clinic”.
NextPCB – Order High Quality PCBs:
After designing your PCB, you can order high-quality PCBs from NextPCB. To check for errors in your PCB design, you can use their free online or offline HQDFM tool and Gerber Viewer. NextPCB also provides component sourcing services.
Get $30 off for any new customer who has never placed an order before.
Do not worry about SMD components; they are not intimidating at all! Soldering them is super easy, as long as you have the right tools and know how to use them. I have already written detailed article on SMD components soldering.
Let me also tell you – these boards are not compulsory; you can also use a breadboard to connect the nRF24L01 module to Arduino.
Required Components:
- You will need a pair of Arduino Nano or Arduino Uno boards.
- A pair of NRF24L01 Transceiver modules and let me tell you; you can also use a pair of NRF24L01 PA+LNA modules, these modules share the same pins layout and same date rates. If you want to communicate over a long distance in the range of 500 meters to 1000 meters then these are the modules you should go for.
- You will also need a pair of SSD1306 Oled display modules. Again, it’s totally up to you, if you want to use one or two displays.
- The choice of sensors depends on you. In my case, I am going to use the DS18b20 one-wire waterproof digital temperature sensor, an LDR module, and an ultrasonic sensor.
Amazon Links:
Arduino Nano USB C type (Recommended)
nRF24L01 RF Transceiver Modules
DS18B20 Waterproof Temperature Sensor
*Disclosure: These are affiliate links. As an Amazon Associate I earn from qualifying purchases.
NRF24L01 Transceiver Module:
nRF24L01 Specifications:
2.4GHz RF transceiver Module
Operating Voltage: 3.3V
Nominal current: 50mA
Range : 50 – 200 feet
Operating current: 250mA (maximum)
Communication Protocol: SPI
Baud Rate: 250 kbps – 2 Mbps.
Channel Range: 125
Maximum Pipelines/node : 6
Low cost wireless solution
The nRF24L01 module supports three different data rates:
RF24_250KBPS (250 kbps)
RF24_1MBPS (1 Mbps)
RF24_2MBPS (2 Mbps)
This is the nRF24L01 2.4GHz RF transceiver module. Its operating voltage is 3.3V. Nominal current is 50mA. Range is 200 Feet. Operating current is 250mA (maximum). Communication protocol is SPI. Baud Rate is 250kbps to 2 Mbps. Channel Range is 125 and maximum pipelines/nodes are 6. The nRF24L01 Transceiver module supports three different data rates; 250kbps, 1 Mbps, and 2 Mbps.
nRF24L01 Pinout:
It has a total of 8 pins.
- Pin Number1 is the ground.
- Pin Number2 is the VCC and it should be connected to a separate dedicated 3.3V power supply. For the initial testing you can also use the Arduino’s 3.3V.
- Pin Number3 is the CE “Chip Enable”. It is used to enable SPI communication.
- Pin Number4 is the CSN “Chip Select Not”. This pin has to be kept high always, else it will disable the SPI.
- Pin Number5 is the SCK “Serial Clock”. It provides the clock pulse.
- Pin Number 6 is the MOSI “Master Out Slave In”. It is connected to the MOSI pin of the Arduino.
- Pin Number7 is the MISO “Master In Slave Out”. It is connected to the MISO pin of the Arduino. And finally;
- Pinumber8 is the IRQ “Interrupt Request”. It is an active low pin and is used only if interrupt is required.
Let’s start with these boards. Some of you might want to use the nRF24L01 modules at an advanced level. As you can see, both boards are 100% identical. You can use either board as a transmitter or receiver. You can create multiple boards like this if you want to implement a network.
nRF24L01 interfacing with the Arduino Nano/Uno.
On this board, I have added a 5V 3A power supply, which is the same one I used last time with the ESP32 WiFi + Bluetooth module. You can follow this circuit diagram for the 5V 3A power supply.
Additionally, I have added a 3.3V power supply for the nRF24L01 module.
On the boards, I have also added i2c supported SSD1306 OLED display modules. If you don’t want to use those displays, you can skip it and use analog sensors instead on the SDA and SCL pins (A4 and A5).
Using those male headers located on the right side of the Arduion, you can connect sensors and ESCs (electronic speed controllers). The first pin is the signal, the middle pin is 5V, and the third pin is GND. So, those male headers are fully compatible with servo motors and ESCs.
We can easily power these board with a power supply ranging from 7V to 25V. You can also power it up using 3-male headers next to the DC Female Socket. The Gerber files for this board are available for download on my Patreon page. Now, let’s move on to our first example.
nRF24L01 Example 1:
In example 1, we will send a “Hello” message wirelessly from the transmitter to the receiver side. This will be one-way communication. For this example, you can see that I haven’t connected any sensors to the boards.
For breadboard connections, you can simply follow this circuit diagram.
The nRF24L01 connections will be the same on both the transmitter and receiver sides. On the receiver side, you can also print the “Hello” message on the serial monitor, if incase you don’t want to use a display. And if you want to use a display then you can connect an SSD1306 OLED display module on the receiver side.
Simply connect the VCC and GND pins of the Oled display module to the Arduino’s 3.3V and GND pins. Connect the SDA and SCL pins to the Arduino’s A4 and A5 pins. And that’s it.
Now, let’s go ahead and take a look at the Transmitter and Receiver side programs.
Programming:
First, let’s go ahead and install the required libraries.
Required Libraries:
RF24
Adafruit_GFX
Adafruit_SSD1306
DallasTemperature
For this, simply copy the library name, then go to the Sketch Menu, then to Include Library, and click on the Manage Libraries. Paste the library name in the search box; as you can see; I have already installed this library.
nRF24L01 Tx Arduino code:
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 |
/*Transmitter code pins connections vcc 3.3 gnd gnd ce pin9 scn pin10 sck pin13 mosi pin11 miso pin12 */ #include <SPI.h> #include "RF24.h" RF24 myRadio (9, 10); byte addresses[][6] = {"0"}; struct package { char msg[8]={"Hello"}; }; typedef struct package Package; Package dataTransmit; void setup() { myRadio.begin(); myRadio.setChannel(115); myRadio.setPALevel(RF24_PA_MAX); myRadio.setDataRate( RF24_250KBPS ); // for the maximum communication range //myRadio.setDataRate(RF24_1MBPS); // Sets the data rate to 1 Mbps //myRadio.setDataRate(RF24_2MBPS); // Sets the data rate to 2 Mbps myRadio.openReadingPipe(1, addresses[0]); } void loop() { myRadio.openWritingPipe(addresses[0]); myRadio.write(&dataTransmit, sizeof(dataTransmit)); } |
Code explanation:
1 2 3 |
RF24 myRadio (9, 10); byte addresses[][6] = {"0"}; |
This line creates an RF24 object named myRadio with CE pin connected to pin 9 and CSN pin connected to pin 10.
This is a 2D byte array to hold addresses. The address “0” is used here.
Right now, this communication is not secure at all. In the upcoming examples, we will use unique addresses, so then no one will be able to monitor our data.
1 2 3 4 5 6 7 8 |
struct package { char msg[8] = {"Hello"}; }; typedef struct package Package; Package dataTransmit; |
Next, we define a structure named package with a character array msg of size 8, initialized with the string “Hello”.
typedef is used to create an alias Package for the struct package.
This line creates an instance of Package named dataTransmit.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
void setup() { myRadio.begin(); myRadio.setChannel(115); myRadio.setPALevel(RF24_PA_MAX); myRadio.setDataRate(RF24_250KBPS); myRadio.openReadingPipe(1, addresses[0]); } |
Initializes the nRF24L01 Transceiver module.
Sets the RF channel to 115. You can also select any other channel, just make sure you use the same channel on the receiver side.
Sets the power amplifier level to maximum for the longest range.
Sets the data rate to 250 kbps for maximum communication range. There are some other data rates which we will cover in upcoming examples.
Opens a reading pipe on address “0”.
1 2 3 4 5 6 7 |
void loop() { myRadio.openWritingPipe(addresses[0]); myRadio.write(&dataTransmit, sizeof(dataTransmit)); } |
This line of code, opens a writing pipe on address “0”.
And then this line sends the data contained in dataTransmit over the writing pipe.
Now, let’s go ahead and take a look at the receiver side program.
nRF24L01 Rx Arduino code:
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 |
/*Receiver code pins connections vcc 3.3 gnd gnd ce pin9 scn pin10 sck pin13 mosi pin11 miso pin12 */ #include <SPI.h> #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #include "RF24.h" RF24 myRadio (9, 10); byte addresses[][6] = {"0"}; struct package { char msg[8]={}; }; typedef struct package Package; Package dataRecieve; #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height, in pixels // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) #define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin) Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); void setup() { myRadio.begin(); myRadio.setChannel(115); myRadio.setPALevel(RF24_PA_MAX); myRadio.setDataRate( RF24_250KBPS ); //myRadio.setDataRate(RF24_1MBPS); // Sets the data rate to 1 Mbps //myRadio.setDataRate(RF24_2MBPS); // Sets the data rate to 2 Mbps myRadio.openReadingPipe(1, addresses[0]); myRadio.startListening(); display.begin(SSD1306_SWITCHCAPVCC, 0x3C); display.clearDisplay(); display.setTextColor(WHITE); } void loop() { if ( myRadio.available()) { while (myRadio.available()){ myRadio.read( &dataRecieve, sizeof(dataRecieve) ); } } myRadio.openReadingPipe(1, addresses[0]); myRadio.startListening(); display.clearDisplay(); display.setCursor(10,0); display.setTextSize(2); display.setTextColor(WHITE); display.print(dataRecieve.msg ); display.display(); } |
Code explanation:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
RF24 myRadio (9, 10); byte addresses[][6] = {"0"}; struct package { char msg[8] = {}; }; typedef struct package Package; Package dataRecieve; #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height, in pixels #define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin) Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); |
We are using the same CE and CSN pins on the receiver side. CE pin is connected to pin 9 and CSN pin is connected to pin 10.
As I said earlier, the address should be same on the transmitter and receiver side, so that’s why I am using the same address 0 on the receiver side.
This line defines a structure named package with a character array msg of size 8.
This time we create an instance of Package named dataRecieve.
All these instructions are used with the SSD1306 Oled display module.
1 2 3 4 5 6 7 8 9 10 11 |
myRadio.begin(); myRadio.setChannel(115); myRadio.setPALevel(RF24_PA_MAX); myRadio.setDataRate( RF24_250KBPS ); myRadio.openReadingPipe(1, addresses[0]); myRadio.startListening(); |
These are the same instructions we used on the transmitter side except myRadio.startListening().
Because, it puts the nRF24L01 module in listening mode.
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 |
void loop() { if (myRadio.available()) { while (myRadio.available()) { myRadio.read(&dataRecieve, sizeof(dataRecieve)); } } myRadio.openReadingPipe(1, addresses[0]); myRadio.startListening(); display.clearDisplay(); display.setCursor(10, 0); display.setTextSize(2); display.setTextColor(WHITE); display.print(dataRecieve.msg); display.display(); } |
Then inside the loop() function; we check if there is data available to read.
Continues reading as long as data is available.
Reads the received data into the dataRecieve structure.
Re-opens the reading pipe on address “0”.
Ensures the nRF24L01 module is in listening mode.
Clears the OLED display.
Sets the cursor position to (10, 0).
Sets the text size to 2.
Sets the text color.
Prints the received message on the OLED display.
Updates the OLED display to show the printed message.
I have already uploaded these programs; so, let’s go ahead and watch this in action.
Example 1 Practical Demonstration:
As you can see, there is no physical connection between the boards. As soon as I power up the transmitter side, the message “Hello” was printed on the receiver side’s OLED display module.
As you can see, we have successfully sent the “Hello” message from the transmitter side to the receiver side. If you understood this example, then the upcoming examples will be quite easy for you all. Because we will be using 80-90% of the same code. Anyway, let’s move on to our 2nd example.
nRF24L01 Example 2:
For the second example, you can see that I have connected a DS18B20 one-wire waterproof digital sensor to the transmitter side, and I haven’t connected anything to the receiver side. This example also uses one-way communication. We will send the temperature value wirelessly from the transmitter side to the receiver side and then print the temperature value on the OLED display module. This project itself is at an intermediate level, so, you can use this same example as a project.
nRF24L01 Tx Circuit:
The VCC and GND pins of the NRF24L01 are connected with the 3.3v and GND pins of the Arduino. Don’t forget to add a 10uF capacitor between the VCC and GND pins of the NRF24L01 module. The CE, SCN, SCK, MOSI, and MISO pins of the NRF24 module are connected with the Arduino pins 9, 10, 13, 11, and 12 respectively.
The VCC and GND pins of the DS18B20 are also connected with the 5V and GND pins of the Arduino. While the data pin is connected with D4 pin of the Arduino. There is also a 330 ohm resistor connected between the data wire and VCC.
nRF24L01 Rx Circuit:
The NRF24L01 connection with the Arduino remains exactly the same. The SSD1306 Oled display module SDA and SCL/SCK pins are connected with the A4 and A5 pins while the VDD/VCC and GND pins are connected with the Arduino’s 3.3V and GND pins.
Now, let’s go ahead and take a look at the programming.
nRF24L01 Temperature Monitoring Codes:
These are the same exact programs, we used for sending and receiving the hello message. This time round I made a few changes.
This time I defined a unique address “3x;y”, you can use any combination of letters, numbers, and characters. Make sure, you use the same address on the receiver side, otherwise, there will be no communication between the transmitter and receiver.
Another change that I made is; this time I defined a variable for the temperature.
Everything else remains exactly the same.
nRF24L01 Tx Program:
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 |
/*Transmitter code pins connections vcc 3.3 gnd gnd ce pin9 scn pin10 sck pin13 mosi pin11 miso pin12 */ #include <SPI.h> #include "RF24.h" #include <OneWire.h> #include <DallasTemperature.h> RF24 myRadio (9, 10); byte addresses[][6] = {"3x;y"}; #define ONE_WIRE_BUS 4 OneWire oneWire(ONE_WIRE_BUS); // Pass our oneWire reference to Dallas Temperature. DallasTemperature sensors(&oneWire); struct package { float temperature = 0; }; typedef struct package Package; Package dataTransmit; void setup() { sensors.begin(); myRadio.begin(); myRadio.setChannel(115); myRadio.setPALevel(RF24_PA_MAX); myRadio.setDataRate( RF24_250KBPS ); // for the maximum communication range myRadio.openReadingPipe(1, addresses[0]); } void loop() { sensors.requestTemperatures(); // Send the command to get temperatures float temperaturevalue=sensors.getTempCByIndex(0); dataTransmit.temperature = temperaturevalue; myRadio.openWritingPipe(addresses[0]); myRadio.write(&dataTransmit, sizeof(dataTransmit)); } |
Now, if we take a look at the receiver side program, you will see, I am using the same instructions. The only difference is that this time I am printing the text Temp and the temperature value.
nRF24L01 Rx Program:
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 |
/*Receiver code pins connections vcc 3.3 gnd gnd ce pin9 scn pin10 sck pin13 mosi pin11 miso pin12 */ #include <SPI.h> #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #include "RF24.h" RF24 myRadio (9, 10); byte addresses[][6] = {"3x;y"}; struct package { float temperature = 0; }; typedef struct package Package; Package dataRecieve; #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height, in pixels // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) #define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin) Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); void setup() { myRadio.begin(); myRadio.setChannel(115); myRadio.setPALevel(RF24_PA_MAX); myRadio.setDataRate( RF24_250KBPS ); myRadio.openReadingPipe(1, addresses[0]); myRadio.startListening(); display.begin(SSD1306_SWITCHCAPVCC, 0x3C); display.clearDisplay(); display.setTextColor(WHITE); } void loop() { if ( myRadio.available()) { while (myRadio.available()){ myRadio.read( &dataRecieve, sizeof(dataRecieve) ); } } display.clearDisplay(); display.setCursor(10,0); display.setTextSize(2); display.setTextColor(WHITE); display.print("Temp:"); display.setCursor(10,30); display.setTextSize(2); display.setTextColor(WHITE); display.print(dataRecieve.temperature); display.print((char)247); display.print("C"); display.display(); } |
Example 2 Practical demonstration:
As you can see, we can monitor the temperature wirelessly. Similarly, you can monitor more than one sensor. For example, if you want to monitor both the temperature and an LDR for day and night detection, you can do that too. Let’s do it.
nRF24L01 Example 3:
For the third example, you can see that I have connected both a DS18B20 one-wire waterproof digital temperature sensor and an LDR module to the transmitter side, while I haven’t connected anything to the receiver side. This is also based on one-way communication. We will send the temperature and LDR values wirelessly from the transmitter side to the receiver side.
On the display, we will print the temperature value and a day/night message based on the LDR value, which can be 1 or 0.
For the transmitter and receiver side connections, you can follow these circuit diagrams.
nRF24L01 Tx Circuit:
nRF24L01 Rx Circuit:
Now, let’s go ahead and take a look at the programming.
nRF24L01 Multiple Sensors Monitoring Codes:
As you can see, the programs for the transmitter and receiver are almost the same. Since, this time, I am also using an LDR sensor, so that’s why I have also defined a variable for the LDR which is connected to Arduino pin number 7.
This time, I have also added two more data rates, which we will check during the practical demonstration.
Inside the loop() function, first, we read the LDR value and store it in dataTransmit.ldrvalue. Similarly, we read the temperature sensor value and store it in dataTransmit.temperature. Finally, we send this data.
nRF24L01 Tx Code:
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 |
/*Transmitter code pins connections vcc 3.3 gnd gnd ce pin9 scn pin10 sck pin13 mosi pin11 miso pin12 */ #include <SPI.h> #include "RF24.h" #include <OneWire.h> #include <DallasTemperature.h> RF24 myRadio (9, 10); byte addresses[][6] = {"3x;y"}; #define ONE_WIRE_BUS 4 #define ldr 7 OneWire oneWire(ONE_WIRE_BUS); // Pass our oneWire reference to Dallas Temperature. DallasTemperature sensors(&oneWire); struct package { float temperature = 0; int ldrvalue=0; }; typedef struct package Package; Package dataTransmit; void setup() { pinMode(ldr,INPUT); sensors.begin(); myRadio.begin(); myRadio.setChannel(115); myRadio.setPALevel(RF24_PA_MAX); //myRadio.setDataRate(RF24_250KBPS); // Sets the data rate to 250 kbps //myRadio.setDataRate(RF24_1MBPS); // Sets the data rate to 1 Mbps myRadio.setDataRate(RF24_2MBPS); // Sets the data rate to 2 Mbps myRadio.openReadingPipe(1, addresses[0]); } void loop() { dataTransmit.ldrvalue=digitalRead(ldr); sensors.requestTemperatures(); // Send the command to get temperatures float temperaturevalue=sensors.getTempCByIndex(0); dataTransmit.temperature = temperaturevalue; myRadio.openWritingPipe(addresses[0]); myRadio.write(&dataTransmit, sizeof(dataTransmit)); } |
On the receiver side, first, we read the temperature, and print it on the display. Then we check if the value received from the LDR is 1 or 0. Based on this value, we print the messages “Night” or “Day” accordingly.
nRF24L01 Rx Code:
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 |
/*Receiver code pins connections vcc 3.3 gnd gnd ce pin9 scn pin10 sck pin13 mosi pin11 miso pin12 */ #include <SPI.h> #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #include "RF24.h" RF24 myRadio (9, 10); byte addresses[][6] = {"3x;y"}; struct package { float temperature = 0; int ldrvalue=0; }; typedef struct package Package; Package dataRecieve; #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height, in pixels // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) #define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin) Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); void setup() { display.begin(SSD1306_SWITCHCAPVCC, 0x3C); display.clearDisplay(); display.setTextColor(WHITE); myRadio.begin(); myRadio.setChannel(115); myRadio.setPALevel(RF24_PA_MAX); //myRadio.setDataRate(RF24_250KBPS); // Sets the data rate to 250 kbps //myRadio.setDataRate(RF24_1MBPS); // Sets the data rate to 1 Mbps myRadio.setDataRate(RF24_2MBPS); // Sets the data rate to 2 Mbps myRadio.openReadingPipe(1, addresses[0]); myRadio.startListening(); } void loop() { if ( myRadio.available()) { while (myRadio.available()){ myRadio.read( &dataRecieve, sizeof(dataRecieve) ); } } display.clearDisplay(); display.setCursor(10,0); display.setTextSize(2); display.setTextColor(WHITE); display.print(dataRecieve.temperature); display.print((char)247); display.print("C"); display.setCursor(10,35); display.setTextSize(2); display.setTextColor(WHITE); if ( dataRecieve.ldrvalue == 1 ) { display.print("Night"); } if ( dataRecieve.ldrvalue == 0 ) { display.print("Day"); } display.display(); //delay(10); } |
Example 3 Practical Demonstration:
As you can see, it’s working perfectly. I can monitor both the temperature and the LDR sensor. On the LDR module, you can see both the LEDs are ON, which means, the LDR module is detecting enough light that’s greater than the set value. So, That’s why on the Oled display module Day is printed.
When the light falling on the LDR is less than the set value then the message Night is printed on the Oled display Module. You can set/pre-define a value/level using that blue color pot on the LDR module.
If you remember, we used a data rate of 250 kbps in the program. The 250 kbps data rate will give you a greater communication range, but the speed will be quite low. You can see there is a noticeable delay. In this project, the speed is acceptable because it is not a highly sensitive project, so even if the speed is lower, it doesn’t matter.
However, if you try to control RC planes or RC cars with this same delay, it won’t work. You won’t get that real-time feeling.
To increase the speed, you can try data rates of 1 Mbps or 2 Mbps. But remember, the higher the communication speed, the shorter the range. So, if you want to communicate at maximum speed within a range of 50 to 100 meters, you can use these small nRF24L01 modules to control RC cars and robots.
If you need both speed and a longer range, you will need to use the nRF24L01 PA+LNA versions. As I explained at the start, their pins layout is exactly the same, and they support the same data rates. So, the programs I have explained so far and the ones I will explain can all be used with the PA+LNA versions as well.
Now, let’s go ahead and start with example number 4.
nRF24L01 Example 4:
For the fourth example, you can see that I have connected a temperature sensor to the transmitter side and an HC-SR04 ultrasonic sensor to the receiver side. This time, we will perform two-way communication.
We will print the temperature sensor value on the Receiver side display and the distance value on the Transmitter side display. Using the same technique, you can also generate feedback messages, which I already talked about at the beginning of this article.
Anyway, for the transmitter and receiver side connections, you can follow these circuit diagrams.
nRF24L01 Transmitter Circuit:
nRF24L01 Receiver Circuit:
nRF24L01 Two-Way Programming:
In both programs, we are still using the same instructions, with the only difference being that previously we were using one-way communication and now we are using two-way communication. That’s why I created two instances of packages named dataReceive and dataTransmit.
Then in the loop() function, first we read the temperature sensor and send its value to the remote side Receiver module.
And then we open the reading pipe and wait for the data from the Receiver side. When the data is received; we simply retrieve the distance value and print it on the Oled display module.
nRF24L01 Tx Code:
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 |
/*Transmitter code pins connections vcc 3.3 gnd gnd ce pin9 scn pin10 sck pin13 mosi pin11 miso pin12 */ #include <SPI.h> #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #include "RF24.h" #include <OneWire.h> #include <DallasTemperature.h> RF24 myRadio (9, 10); byte addresses[][6] = {"3x;y"}; #define ONE_WIRE_BUS 4 OneWire oneWire(ONE_WIRE_BUS); // Pass our oneWire reference to Dallas Temperature. DallasTemperature sensors(&oneWire); struct package { float temperature = 0; int distance=0; }; typedef struct package Package; Package dataRecieve; Package dataTransmit; #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height, in pixels // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) #define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin) Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); void setup() { display.begin(SSD1306_SWITCHCAPVCC, 0x3C); display.clearDisplay(); display.setTextColor(WHITE); sensors.begin(); myRadio.begin(); myRadio.setChannel(115); myRadio.setPALevel(RF24_PA_MAX); //myRadio.setDataRate(RF24_250KBPS); // Sets the data rate to 250 kbps //myRadio.setDataRate(RF24_1MBPS); // Sets the data rate to 1 Mbps myRadio.setDataRate(RF24_2MBPS); // Sets the data rate to 2 Mbps // myRadio.openReadingPipe(1, addresses[0]); // myRadio.startListening(); } void loop() { sensors.requestTemperatures(); // Send the command to get temperatures float temperaturevalue=sensors.getTempCByIndex(0); dataTransmit.temperature = temperaturevalue; myRadio.openWritingPipe(addresses[0]); myRadio.write(&dataTransmit, sizeof(dataTransmit)); myRadio.openReadingPipe(1, addresses[0]); myRadio.startListening(); if ( myRadio.available()) { while (myRadio.available()){ myRadio.read( &dataRecieve, sizeof(dataRecieve) ); } display.clearDisplay(); display.setCursor(10,0); display.setTextSize(2); display.setTextColor(WHITE); display.print(dataRecieve.distance); display.display(); //delay(1000); myRadio.stopListening(); } } |
Now, the same exact thing we do on the receiver side for sending the distance value and for reading the temperature value from the transmitter side.
nRF24L01 Rx Code:
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 |
/*Receiver code pins connections vcc 3.3 gnd gnd ce pin9 scn pin10 sck pin13 mosi pin11 miso pin12 */ #include <SPI.h> #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #include "RF24.h" RF24 myRadio (9, 10); byte addresses[][6] = {"3x;y"}; const int trigPin = 7; const int echoPin = 8; // defines variables long duration; struct package { float temperature = 0; int distance=0; }; typedef struct package Package; Package dataRecieve; Package dataTransmit; #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height, in pixels // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) #define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin) Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); void setup() { pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output pinMode(echoPin, INPUT); // Sets the echoPin as an Input display.begin(SSD1306_SWITCHCAPVCC, 0x3C); display.clearDisplay(); display.setTextColor(WHITE); myRadio.begin(); myRadio.setChannel(115); myRadio.setPALevel(RF24_PA_MAX); //myRadio.setDataRate(RF24_250KBPS); // Sets the data rate to 250 kbps //myRadio.setDataRate(RF24_1MBPS); // Sets the data rate to 1 Mbps myRadio.setDataRate(RF24_2MBPS); // Sets the data rate to 2 Mbps myRadio.openReadingPipe(1, addresses[0]); myRadio.startListening(); } void loop() { if ( myRadio.available()) { while (myRadio.available()){ myRadio.read( &dataRecieve, sizeof(dataRecieve) ); } } myRadio.stopListening(); digitalWrite(trigPin, LOW); delayMicroseconds(2); // Sets the trigPin on HIGH state for 10 micro seconds digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); // Reads the echoPin, returns the sound wave travel time in microseconds duration = pulseIn(echoPin, HIGH); // Calculating the distance dataTransmit.distance = duration * 0.034 / 2; Serial.print(dataTransmit.distance); Serial.print("\n"); myRadio.openWritingPipe(addresses[0]); myRadio.write(&dataTransmit, sizeof(dataTransmit)); myRadio.openReadingPipe(1, addresses[0]); myRadio.startListening(); ///////////////// Serial.println(stat); display.clearDisplay(); display.setCursor(10,0); display.setTextSize(2); display.setTextColor(WHITE); display.print(dataRecieve.temperature); display.print((char)247); display.print("C"); display.display(); //delay(1000); } |
Example 4 Practical Demonstration:
You can clearly see the temperature on the Receiver side Oled display and the distance value on the Transmitter side Oled display.
In the next article, we will use this nRF24L01 based remote to control simple DC motors, BLDC motors, and Servo motors. After that article, you will be able to control RC planes, RC cars, and all kinds of RC robots. So, consider subscribing if you don’t want to miss that article and Video.