Main article: How to use the NRF24L01 module with Arduino
Having two or more Arduino boards be able to communicate with each other wirelessly over a distance opens lots of possibilities like remotely monitoring sensor data, controlling robots, home automation and the list goes on. A good, reliable and inexpensive solution is NRF24L01.
The NRF24L01+ is a newer version of the NRF24L01, capable of doing an extra 250kbps of on-air data rate while the one without “+” has only 1Mbps and 2Mbps. Both versions can be mixed together as long as 1 or 2 MBps is being used as the data rate.
NRF24L01 vs NRF24L01+PA+LNAThe NRF24L01 module strictly needs 3.3V but the logic pins are 5V tolerant. That why we recommend to use the NRF24L01 adapter which acts as regulator, keep the voltage stable, apply filtering and reduce noises.
The first version (on the left) uses on-board antenna. This allows for a more compact version of the breakout. With this version, you’ll be able to communicate over a distance of 100 meters (range indoors, especially through walls, will be slightly weakened). We will use it for the receiver.
The second version (on the right) integrates the PA, LNA, and transmit-receive switching circuitry. This range extender chip along with external antenna helps the module achieve about 1000m. We will use it for the transmitter.
The adapter works identically for both versions and has the same pinout as original boards.
Wiring schemaThe NRF24L01 module communicates with the Arduino using SPI protocol. The module acts as an SPI slave, which means that it can only be used with devices that have dedicated SPI communication lines. This means that the MOSI, MISO, and SCK pins must be connected to their corresponding pins on the microcontroller. We've used Arduino Nano and these pins are as follows:
- MOSI: Arduino Nano D11
- MISO: Arduino Nano D12
- SCK: Arduino Nano D13
The CE and the CSN pins can be connected to Arduino Nano D9 and D10 respectively (you can use any pins). However, pin D10 is a special pin, it must be set as OUTPUT for the Arduino Nano to operate as an SPI master. In case you are using different Arduino board, it is advisable to check the Arduino official documentation before proceeding.
Note: you need to make two of these circuits. One acts as a transmitter and the other as a receiver. The wiring for both is identical.
Install Arduino library for nRF24L01The library will provide you an interface to communicate with the module saving you a lot of time and providing a robust code base tested and improved by the community during years. You can download the library from our official repository.
To import it, open the Arduino IDE, go to Sketch > Include Library > Add.ZIP Library and then select the file that you just downloaded.
Then you can simply use include statement:
#include "RF24.h"
#include "nRF24L01.h"
It will include the library with predefined functions to interact with module.
Transmitter Arduino codeWe've defined a struct (called payload) which will be sent every INTERVAL_MS_TRANSMISSION milliseconds.
- setup() function initiate the module as transmitter with the provided configuration.
- loop() function will take care of updating the payload values and sending them.
#include "SPI.h"
#include "RF24.h"
#include "nRF24L01.h"
#define CE_PIN 9
#define CSN_PIN 10
#define INTERVAL_MS_TRANSMISSION 250
RF24 radio(CE_PIN, CSN_PIN);
const byte address[6] = "00001";
//NRF24L01 buffer limit is 32 bytes (max struct size)
struct payload {
byte data1;
char data2;
};
payload payload;
void setup()
{
Serial.begin(115200);
radio.begin();
//Append ACK packet from the receiving radio back to the transmitting radio
radio.setAutoAck(false); //(true|false)
//Set the transmission datarate
radio.setDataRate(RF24_250KBPS); //(RF24_250KBPS|RF24_1MBPS|RF24_2MBPS)
//Greater level = more consumption = longer distance
radio.setPALevel(RF24_PA_MAX); //(RF24_PA_MIN|RF24_PA_LOW|RF24_PA_HIGH|RF24_PA_MAX)
//Default value is the maximum 32 bytes
radio.setPayloadSize(sizeof(payload));
//Act as transmitter
radio.openWritingPipe(address);
radio.stopListening();
}
void loop()
{
payload.data1 = 123;
payload.data2 = 'x';
radio.write(&payload, sizeof(payload));
Serial.print("Data1:");
Serial.println(payload.data1);
Serial.print("Data2:");
Serial.println(payload.data2);
Serial.println("Sent");
delay(INTERVAL_MS_TRANSMISSION);
}
Receiver Arduino codeWe will be listening for the struct defined in the transmitter (called payload). The connection will be considered as lost after INTERVAL_MS_SIGNAL_LOST milliseconds.
- setup() function initiate the module as receiver with the provided configuration.
- loop() function will take care of listening for the payload and handling it.
- lostConnection() function will handle the lost connection to prevent unwanted behavior.
#include "SPI.h"
#include "RF24.h"
#include "nRF24L01.h"
#define CE_PIN 9
#define CSN_PIN 10
#define INTERVAL_MS_SIGNAL_LOST 1000
#define INTERVAL_MS_SIGNAL_RETRY 250
RF24 radio(CE_PIN, CSN_PIN);
const byte address[6] = "00001";
//NRF24L01 buffer limit is 32 bytes (max struct size)
struct payload {
byte data1;
char data2;
};
payload payload;
unsigned long lastSignalMillis = 0;
void setup()
{
Serial.begin(115200);
radio.begin();
//Append ACK packet from the receiving radio back to the transmitting radio
radio.setAutoAck(false); //(true|false)
//Set the transmission datarate
radio.setDataRate(RF24_250KBPS); //(RF24_250KBPS|RF24_1MBPS|RF24_2MBPS)
//Greater level = more consumption = longer distance
radio.setPALevel(RF24_PA_MIN); //(RF24_PA_MIN|RF24_PA_LOW|RF24_PA_HIGH|RF24_PA_MAX)
//Default value is the maximum 32 bytes1
radio.setPayloadSize(sizeof(payload));
//Act as receiver
radio.openReadingPipe(0, address);
radio.startListening();
}
void loop()
{
unsigned long currentMillis = millis();
if (radio.available() > 0) {
radio.read(&payload, sizeof(payload));
Serial.println("Received");
Serial.print("Data1:");
Serial.println(payload.data1);
Serial.print("Data2:");
Serial.println(payload.data2);
lastSignalMillis = currentMillis;
}
if (currentMillis - lastSignalMillis > INTERVAL_MS_SIGNAL_LOST) {
lostConnection();
}
}
void lostConnection()
{
Serial.println("We have lost connection, preventing unwanted behavior");
delay(INTERVAL_MS_SIGNAL_RETRY);
}
TestingRemember that we must build two circuits with identical wiring.
On the one hand, we will upload the transmitter code. It will generate the message payload and send it every INTERVAL_MS_TRANSMISSION.
On the other hand, we will upload the receiver code. It will listen for the message payload and process it. The serial monitor will output something similar to:
The last line indicates lost connection (after INTERVAL_MS_SIGNAL_LOST milliseconds with no signal). In our case, it was an expected behavior. In real life the signal can be lost due to many known and unknown reasons, we should be able to control that and act with corrections (in lostConnection() function).
Comments