nRF24L01 2.4 GHz Wireless · Astro Tech Blog

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.

nRF24L01 2.4 GHz Wireless Module

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 PinNameArduino Connection
VCCPower3.3V
GNDGroundGND
CEChip EnablePin 9
CSNSPI Chip SelectPin 10
SCKSPI ClockPin 13 (SCK)
MOSISPI Data InPin 11 (MOSI)
MISOSPI Data OutPin 12 (MISO)
IRQInterruptNot 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

FeatureStandard nRF24L01nRF24L01+ PA+LNA
AntennaPCB traceExternal SMA (dipole)
Range (open air)~30 m~800–1000 m
Peak current~12 mA~115 mA
Voltage regulatorNo3.3V regulator included
5V tolerant VCCNoYes (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. Returns false if 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. Returns true if acknowledged.
  • radio.available() — returns true if 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

  1. 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.
  2. Install the RF24 library by TMRh20 on both computers (or the same computer, one upload at a time).
  3. Configure the transmitter sketch for the first Arduino: Tools > Board, Tools > Port.
  4. Upload the transmitter sketch.
  5. Disconnect the first Arduino and repeat steps 3–4 with the receiver sketch on the second Arduino.
  6. Open the Serial Monitor on the receiver Arduino (9600 baud).
  7. Power both Arduinos. Observe the receiver printing “Received: 1 | 22.5 C | Packet 1” etc. every second.
  8. 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_250KBPS for 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() or radio.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. Call radio.whatHappened() inside the ISR to determine the cause (RX data received, TX success, TX max retries).