nRF24L01 2.4 GHz Wireless Module
The nRF24L01 is a low-cost, low-power 2.4 GHz wireless transceiver from Nordic Semiconductor. It communicates over SPI and can transmit data up to 100 metres (line of sight) with the PA+LNA variant. Using the ShockBurst protocol, it handles packet assembly, automatic acknowledgement, and retransmission in hardware. Six data pipes enable one-to-six and mesh network topologies, making it a popular choice for wireless sensor networks, remote control, and home automation.
For this interfacing you need the following components:
- Arduino board (Uno, Nano, Mega, etc.) × 2 (one transmitter, one receiver)
- nRF24L01 module (standard or PA+LNA) × 2
- 10–100 µF electrolytic capacitor (across VCC and GND near each module)
- Breadboard and jumper wires
- USB cables to connect both Arduinos to your computer
Schematic
Connect the nRF24L01 module to the Arduino as follows:
nRF24L01 Module Arduino
--------------- -------
VCC --> 3.3V
GND --> GND
CE --> Digital Pin 9
CSN --> Digital Pin 10
SCK --> Digital Pin 13 (SCK)
MOSI --> Digital Pin 11 (MOSI)
MISO --> Digital Pin 12 (MISO)
IRQ --> Not connected (optional)
Important: Place a 10–100 µF electrolytic capacitor between VCC and GND as close to the module as possible. The nRF24L01 draws current spikes during transmission that can exceed the Arduino 3.3V regulator’s transient response, causing the module to lock up or reset.
Pin Map
| Module Pin | Name | Arduino Connection |
|---|---|---|
| VCC | Power | 3.3V |
| GND | Ground | GND |
| CE | Chip Enable | Pin 9 |
| CSN | SPI Chip Select | Pin 10 |
| SCK | SPI Clock | Pin 13 (SCK) |
| MOSI | SPI Data In | Pin 11 (MOSI) |
| MISO | SPI Data Out | Pin 12 (MISO) |
| IRQ | Interrupt | Not connected |
For Mega 2560: MOSI = Pin 51, MISO = Pin 50, SCK = Pin 52, CSN = Pin 53. For Leonardo: MOSI = ICSP-4, MISO = ICSP-1, SCK = ICSP-3, CSN/CE = any digital pins.
Standard vs PA+LNA modules
| Feature | Standard nRF24L01 | nRF24L01+ PA+LNA |
|---|---|---|
| Antenna | PCB trace | External SMA (dipole) |
| Range (open air) | ~30 m | ~800–1000 m |
| Peak current | ~12 mA | ~115 mA |
| Voltage regulator | No | 3.3V regulator included |
| 5V tolerant VCC | No | Yes (on some modules) |
PA+LNA modules include an RFX2401C power amplifier and low-noise amplifier, extending range significantly at the cost of higher power consumption. They can often accept 5V input thanks to an onboard regulator.
Install necessary Library
Install the RF24 library by TMRh20 via the Library Manager (Tools > Manage Libraries).
Alternatively, using arduino-cli:
arduino-cli lib install "RF24"
Code with complete explanation
This pair of sketches implements a simple one-way wireless link. The transmitter sends a counter value and a message to the receiver, which prints the received data to the Serial Monitor.
Transmitter sketch (upload to first Arduino)
#include <SPI.h>
#include <RF24.h>
const uint64_t PIPE_ADDRESS = 0xF0F0F0F0E1LL; // Same on both units
RF24 radio(9, 10); // CE, CSN pins
void setup()
{
Serial.begin(9600);
if (!radio.begin())
{
Serial.println("Radio hardware not responding");
while (1) {}
}
// Configure radio
radio.setChannel(100); // 2.500 GHz (channel 0 = 2.400 GHz)
radio.setDataRate(RF24_1MBPS); // 1 Mbps (250KBPS, 1MBPS, 2MBPS)
radio.setPALevel(RF24_PA_LOW); // Power: MIN, LOW, HIGH, MAX
radio.setAutoAck(true); // Enable auto-acknowledgement
radio.setRetries(3, 5); // (delay=3*250us, count=5)
radio.openWritingPipe(PIPE_ADDRESS);
radio.stopListening(); // Set as transmitter
Serial.println("nRF24L01 Transmitter Ready");
}
void loop()
{
static uint32_t counter = 0;
counter++;
// Simple data payload (struct)
struct Payload
{
uint32_t count;
float temperature;
char message[16];
};
Payload data;
data.count = counter;
data.temperature = 22.5 + (counter % 50) / 10.0;
snprintf(data.message, sizeof(data.message), "Packet %u", counter);
bool success = radio.write(&data, sizeof(data));
if (success)
{
Serial.print("Sent: ");
Serial.print(data.count);
Serial.print(" | ");
Serial.print(data.temperature);
Serial.print(" C | ");
Serial.println(data.message);
}
else
{
Serial.println("Transmission failed");
}
delay(1000);
}
Receiver sketch (upload to second Arduino)
#include <SPI.h>
#include <RF24.h>
const uint64_t PIPE_ADDRESS = 0xF0F0F0F0E1LL; // Must match transmitter
RF24 radio(9, 10); // CE, CSN pins
void setup()
{
Serial.begin(9600);
if (!radio.begin())
{
Serial.println("Radio hardware not responding");
while (1) {}
}
radio.setChannel(100);
radio.setDataRate(RF24_1MBPS);
radio.setPALevel(RF24_PA_LOW);
radio.setAutoAck(true);
radio.openReadingPipe(1, PIPE_ADDRESS);
radio.startListening(); // Set as receiver
Serial.println("nRF24L01 Receiver Ready");
}
void loop()
{
if (radio.available())
{
struct Payload
{
uint32_t count;
float temperature;
char message[16];
};
Payload data;
radio.read(&data, sizeof(data));
Serial.print("Received: ");
Serial.print(data.count);
Serial.print(" | ");
Serial.print(data.temperature);
Serial.print(" C | ");
Serial.println(data.message);
}
}
Code breakdown
#include <RF24.h>— includes the RF24 library for nRF24L01 communication.RF24 radio(CE, CSN)— creates a radio object with the specified chip enable and chip select not pins.radio.begin()— initializes the SPI connection and configures the radio. Returnsfalseif the module is not detected.radio.setChannel(ch)— sets the RF channel (0–125). Channel 100 = 2.500 GHz. Both units must use the same channel.radio.setDataRate(rate)— sets the data rate.RF24_250KBPS(longest range),RF24_1MBPS(balanced),RF24_2MBPS(highest speed, shortest range).radio.setPALevel(level)— sets the power amplifier level:RF24_PA_MIN(-18 dBm),RF24_PA_LOW(-12 dBm),RF24_PA_HIGH(-6 dBm),RF24_PA_MAX(0 dBm).radio.setAutoAck(true)— enables automatic hardware acknowledgements from the receiver.radio.setRetries(delay, count)— sets auto-retry: delay in multiples of 250 µs, count up to 15.radio.openWritingPipe(address)— sets the transmit pipe address (40-bit).radio.openReadingPipe(pipe, address)— opens a reading pipe (0–5) with a 40-bit address.radio.stopListening()— sets the radio to transmit mode.radio.startListening()— sets the radio to receive mode.radio.write(&data, size)— transmits a data buffer. Returnstrueif acknowledged.radio.available()— returnstrueif received data is waiting in the RX FIFO.radio.read(&data, size)— reads received data into a buffer.
Bidirectional communication
To turn the example into a two-way link, toggle between transmit and receive on both ends:
// Transmitter
radio.stopListening();
radio.write(&data, sizeof(data));
radio.startListening(); // Wait for reply
unsigned long timeout = millis() + 100;
while (!radio.available())
{
if (millis() > timeout) break;
}
if (radio.available())
{
radio.read(&reply, sizeof(reply));
}
Using multiple data pipes
The nRF24L01 supports up to 6 receiving pipes (0–5). Each pipe has its own 40-bit address for star-network topologies:
// Receiver opens 3 pipes for 3 transmitters
radio.openReadingPipe(0, 0xF0F0F0F0E1LL);
radio.openReadingPipe(1, 0xF0F0F0F0E2LL);
radio.openReadingPipe(2, 0xF0F0F0F0E3LL);
radio.startListening();
// When data arrives, check which pipe
if (radio.available(&pipeNumber))
{
radio.read(&data, sizeof(data));
Serial.print("Received on pipe ");
Serial.println(pipeNumber);
}
Steps to perform this interfacing
- Connect each nRF24L01 module to its Arduino as shown in the schematic. Place a 10–100 µF capacitor across VCC and GND on each module.
- Install the RF24 library by TMRh20 on both computers (or the same computer, one upload at a time).
- Configure the transmitter sketch for the first Arduino:
Tools > Board,Tools > Port. - Upload the transmitter sketch.
- Disconnect the first Arduino and repeat steps 3–4 with the receiver sketch on the second Arduino.
- Open the Serial Monitor on the receiver Arduino (9600 baud).
- Power both Arduinos. Observe the receiver printing “Received: 1 | 22.5 C | Packet 1” etc. every second.
- If no data arrives, check wiring, the decoupling capacitor, and ensure both radios use the same channel, data rate, and pipe address.
Testing range
Start with both modules on the same breadboard. Once communication is verified, gradually increase the distance:
- Standard modules: ~30 m indoors, ~50 m open air
- PA+LNA modules: ~100 m indoors, ~800 m+ open air
- Reduce data rate to
RF24_250KBPSfor maximum range
Caution
- Decoupling capacitor required: The nRF24L01 draws short current spikes of up to 12 mA (standard) or 115 mA (PA+LNA) during transmission. Without a 10–100 µF capacitor across VCC and GND near the module, the voltage dips can cause the module to reset, hang, or corrupt data. This is the most common cause of “radio not responding” errors.
- 3.3V power: Standard nRF24L01 modules operate at 3.3V and are NOT 5V tolerant on VCC. Connecting VCC to 5V will destroy the module. PA+LNA modules typically include a 3.3V regulator and can accept 5V on VCC, but check your module’s datasheet. The logic pins (CE, CSN, MOSI, SCK) are 3.3V-only on all variants — use a voltage divider on 5V Arduino boards or rely on the module’s logic being 5V-tolerant (which varies by manufacturer).
- PA+LNA current draw: The PA+LNA variant draws up to 115 mA during transmission bursts. This exceeds the Arduino 3.3V regulator output (typically 150 mA continuous). If using a PA+LNA module with other 3.3V loads, use an external 3.3V regulator rated for at least 200 mA.
- Channel selection: Channels above 125 are out of the legal 2.400–2.525 GHz ISM band. When using multiple wireless systems nearby (Wi-Fi, Bluetooth), choose a channel that avoids overlap. Wi-Fi channels 1, 6, and 11 occupy the 2.401–2.483 GHz range — nRF24L01 channels 0–125 correspond to 2.400–2.525 GHz in 1 MHz steps. For best coexistence, use channels below 5 or above 80.
- Address uniqueness: Each nRF24L01 communicating on the same channel must use a unique pipe address to avoid cross-talk. The address is 40 bits and should be chosen to be unique per network. For a simple pair, any 40-bit value works, but in multi-device networks, use a structured addressing scheme (e.g., network ID + device ID).
- SPI bus conflicts: The nRF24L01 shares the SPI bus with other SPI devices. After each
radio.write()orradio.read(), the CSN pin goes HIGH to release the bus. If you use other SPI devices (SD card, display), ensure their chip select pins are not active when the nRF24L01 is communicating. - IRQ pin: The IRQ pin (active LOW) can be used for interrupt-driven reception instead of polling
radio.available(). Wire IRQ to a digital pin and attach an interrupt on FALLING. Callradio.whatHappened()inside the ISR to determine the cause (RX data received, TX success, TX max retries).