NRF24L01 Arduino Code: Transmitter, Receiver and the Capacitor Fix

Cartoon of two black nRF24L01 radio modules with gold zig-zag antenna traces facing each other across teal and orange radio waves, a fingertip pressing a black button on a white breadboard beside the left module and a black electrolytic capacitor with a grey stripe standing beside the right one

Two Arduinos talk over a pair of nRF24L01 modules in about an hour: wire both modules identically, give both ends the same five-byte address, and run one sketch that writes and one that listens. The step most builds skip is a 10–100 Β΅F capacitor across each module’s own VCC and GND pins β€” without it the radio answers on SPI and still delivers nothing.

What do you need to link two Arduinos wirelessly?

The nRF24L01 module is a transceiver, not a transmitter β€” the same board sends and receives, so a link needs two of them and two boards to drive them. The button sits on the transmitting node only, and the receiving node reports over Serial until you give it something to switch. Both nodes get a breadboard, though β€” that is where each module’s capacitor bridges VCC to GND.

Optional β€” range upgrade, a real load to switch, and the capacitor

ItemPriceQty
High Performance NRF24L01 RF Wireless Transceiver Module Antenna 2.4Ghz 1100m - NRF24L01 + ANTENNAHigh Performance NRF24L01 RF Wireless Transceiver Module Antenna 2.4Ghz 1100m - NRF24L01 + ANTENNANRF24ANRM14.25
Relay Module 3.3V 5V 12V 1/2/4/8 Ways Optocoupler Trigger Relay Module 1 2 4 8 Channel Relay Module - 5V RELAY MODULE(1WAY)Relay Module 3.3V 5V 12V 1/2/4/8 Ways Optocoupler Trigger Relay Module 1 2 4 8 Channel Relay Module - 5V RELAY MODULE(1WAY)1WRELAYRM3.15
Electronic Component Set Beginner Electrical Learning Kit For Arduino Beginner Learning - ELECTRICAL STARTER KITElectronic Component Set Beginner Electrical Learning Kit For Arduino Beginner Learning - ELECTRICAL STARTER KITELECTRKRM39.95

The antenna version is a range upgrade for BOTH ends, never one: auto-acknowledgement means the far node transmits too, so a single upgraded end is still limited by the other. The relay module gives the receiving node something to switch. The capacitor this build needs is a 10–100 Β΅F electrolytic β€” the starter kit is where to find one, since it carries both ceramic and electrolytic capacitors along with resistors, LEDs and a breadboard.

The eight pins stand in a 2Γ—4 double row, so the nRF24L01 cannot sit in a breadboard β€” the two rows would land on the same tie strips and short together. Male-to-female jumpers are what fits: the female end grips the module’s pins, the male end enters the Uno‘s sockets. Male-to-male jumpers wire the button on the breadboard, and their bare pins clamp into the relay’s screw terminals. The FT232 Uno suits a PC that fights CH340 drivers.

How do you wire the nRF24L01 to an Arduino Uno?

The nRF24L01 speaks SPI, so three of its pins land on the Uno’s fixed SPI pins and cannot move; CE and CSN are ordinary outputs, chosen by convention. Pin 1 is the one with the square solder pad underneath. Both nodes are wired identically β€” roles are decided in software.

Module pin Uno pin What it does
1 GND GND Ground, shared with the capacitor’s negative leg
2 VCC 3V3 3.3 V only. 5 V here destroys the chip
3 CE D9 Chip enable β€” puts the radio on air. Any free pin
4 CSN D10 SPI chip select. Any free pin
5 SCK D13 SPI clock. Fixed
6 MOSI D11 Uno to module. Fixed
7 MISO D12 Module to Uno. Fixed
8 IRQ leave open Interrupt output. These sketches poll instead

The supply pin and the logic pins follow different rules, and mixing them up is what kills modules. The Nordic datasheet puts VDD between 1.9 V and 3.6 V absolute, so the Uno’s 5 V rail is about 40% over maximum. The digital pins are separately rated to 5.25 V, which is why an Uno drives CE, CSN, SCK and MOSI straight in with no level shifter. Supply from 3V3, signals from the 5 V logic pins: both are correct at once.

The tactile button is the only other wiring, and it hides a trap: its four legs are two joined pairs, the two on each side of the body permanently connected inside it. Sit it across the breadboard’s centre channel so one pair lands in each half, then take one leg to D2 and the diagonally opposite leg to GND β€” diagonal is always the switching pair. A quarter turn and each joined pair bridges the channel by itself, which reads as a button held down forever. INPUT_PULLUP holds D2 high through a resistor inside the ATmega, so no external resistor is needed.

Seeing two boards actually pass a message helps before you commit:

Why is the nRF24L01 not working, and how does the capacitor fix it?

The nRF24L01’s classic failure has a signature: radio.begin() succeeds, the module reports its registers back correctly, and radio.write() still returns false every time. SPI is happy and the radio is not β€” which says the wiring is right and the supply is failing only during the microseconds the radio is on air.

Idling in standby the chip draws 22 Β΅A, or 26 Β΅A on the nRF24L01+; transmitting at 0 dBm it draws 11.3 mA. That 500-fold step arrives inside the 130 Β΅s the internal PLL takes to settle β€” a near-vertical edge, not a ramp. The sketches below run at RF24_PA_LOW and draw less than that, which lowers the step without softening it: a regulator is beaten by how fast the current arrives, not by how much of it there is.

Put a number on the charge it needs. One packet carries an 8-bit preamble, a 40-bit address, a 9-bit control field, your 8-bit payload and a 16-bit CRC: 81 bits, which at 1 Mbps is 81 Β΅s. Add the 130 Β΅s to settle into transmit and the turnaround to hear the acknowledgement, and the burst is roughly 0.4 ms at something like 10 mA. Charge is current times time, so the module wants about 4 Β΅C inside half a millisecond.

A capacitor’s voltage falls by charge divided by capacitance, so that 4 Β΅C picks the value. The ceramics already on the module are far too small for it: Nordic’s own reference design for this chip specifies 33 nF, 10 nF and 1 nF beside the supply pins, and 33 nF asked to carry that burst alone would drop over 100 V. They are there for nanosecond edges, not for this β€” which is why the same document tells you to fit a large capacitor in parallel with them. A 10 Β΅F electrolytic drops 0.4 V; a 100 Β΅F drops 0.04 V. That division is the whole reason the range quoted everywhere is 10–100 Β΅F, and why the low end is the minimum rather than the answer.

The Uno’s regulator does not close the gap, and its rating is what misleads people. Arduino rates the 3V3 pin at 50 mA, so 11.3 mA looks comfortable β€” but 50 mA is a steady-state figure. A linear regulator’s feedback loop needs tens of microseconds to notice a step, and 20 cm of jumper wire adds resistance and inductance in the way. The regulator arrives late; a capacitor on the module’s own pins is already there.

The same arithmetic says how deep the sag goes. With only tens of nanofarads nearby, the module’s local rail does not dip by a few hundred millivolts during a burst β€” it falls away toward the chip’s 1.9 V floor. The nRF24L01 runs its power amplifier and its digital core from regulators inside the chip, and no regulator holds its output once its own input has gone, so packets leave malformed, acknowledgements never come back, and write() reports failure while the SPI registers β€” read between bursts, at microamps β€” answer perfectly. That is why the capacitor goes across the module’s own pins rather than the Uno’s header β€” the wire between them is the problem.

Cartoon comparison of two supply-voltage traces: a navy line collapsing into a deep dip with an orange arrow and a black nRF24L01 module marked with a no-entry symbol above, and below a teal line dipping only slightly beside a black electrolytic capacitor with a grey stripe, with the same module shown transmitting teal waves
The same transmit burst, drawn twice. Without a local reservoir the module’s own supply collapses for the length of the packet; with one, the same burst costs a few tens of millivolts.

The electrolytic is polarised: the stripe down its can marks the negative leg, and that leg goes to GND. Fitted backwards it heats and fails. Any 10–100 Β΅F part rated 6.3 V or more works; the starter kit carries electrolytics alongside its ceramics.

Mounting it is the step most guides skip, because the module’s pins are already wearing jumper sockets. Best: solder the capacitor’s legs straight onto the VCC and GND pins β€” our header pin soldering guide covers the technique. Solderless: run the module’s VCC and GND leads into a breadboard and bridge the capacitor across those two rows, a few centimetres from the chip instead of a jumper’s length plus the Uno’s own tracks. Worst: the Uno’s 3V3 and GND holes, which leaves the entire jumper inside the path you were trying to bypass. Both nodes get one, which is why the parts list carries two breadboards.

What do addresses and pipes actually do?

The RF24 library’s openWritingPipe() and openReadingPipe() are not network sockets. A pipe address is five bytes riding inside every packet, and the receiving chip compares them in hardware before it wakes the Arduino at all. Both ends share one address, and two links in the same room stay apart by using different ones. It is a filter, not a password: anyone with a matching address hears you.

Roles come from two calls, not from wiring. stopListening() makes a node the transmitter, startListening() makes it the receiver, and swapping those lines between the sketches changes no hardware.

Acknowledgement is where the mental model usually breaks. When a packet arrives and passes its CRC, the receiver turns its own transmitter on and answers automatically. So both ends transmit, both ends need the capacitor, and write() returning true is a delivery report rather than a “sent” flag. It also explains the pipe numbering: pipe 0 is reserved for those acknowledgements, so a hub uses pipes 1 to 5. Those four share the top four bytes of pipe 1’s address and differ only in the last, because the chip stores one full five-byte address for the group and a single byte per pipe after it.

Cartoon showing two black nRF24L01 modules each tagged with an identical row of five coloured squares, a teal arrow carrying a message between them and an orange arrow returning an acknowledgement, while a third faded module tagged with a different colour sequence is blocked by an orange no-entry symbol
An address is five bytes carried inside every packet. Two nodes holding the same five match and answer each other; a third holding different bytes is filtered out in hardware, before its Arduino ever wakes up.

That last detail turns this two-node link into a network of sensors reporting to one board:

What does the nRF24L01 transmitter and receiver code look like?

Both sketches use RF24 by TMRh20 β€” open Library Manager, search RF24, install. Upload the transmitter to the node with the button and the receiver to the other, then open both Serial Monitors at 115200 β€” two IDE windows, since one window watches one port. Each node needs its own power the moment they separate: a USB cable, a charger or a power bank each. Nothing else is shared between the two nodes, not even ground.

/*
  nRF24L01 remote button - TRANSMITTER node (Arduino Uno + RF24 by TMRh20).

  nRF24L01 VCC -> Uno 3V3  (NEVER 5V)      GND -> Uno GND
  CE  -> D9      CSN -> D10
  SCK -> D13     MOSI -> D11      MISO -> D12      IRQ -> not used
  10-100uF electrolytic across the module's own VCC and GND pins, stripe to GND.

  Button between D2 and GND. INPUT_PULLUP means no external resistor.
  The node sends one byte on every change and again every 200 ms, so the
  receiver can tell "still pressed" from "link died".
*/

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

RF24 radio(9, 10);                 // CE, CSN

const byte address[6] = "MHUB1";   // 5 bytes; must be identical on both nodes

const uint8_t  PIN_BUTTON   = 2;
const uint16_t DEBOUNCE_MS  = 25;  // contacts settle in a few ms; 25 is safe
const uint16_t HEARTBEAT_MS = 200; // repeat the current state this often

uint8_t  stableState = 0;          // 1 = pressed
uint8_t  lastRaw     = 0;
uint32_t lastEdgeAt  = 0;
uint32_t lastSendAt  = 0;

void setup() {
  Serial.begin(115200);
  pinMode(PIN_BUTTON, INPUT_PULLUP);

  if (!radio.begin()) {
    // begin() reads a register back. Failing here is wiring or supply,
    // never radio range - the other node is not involved yet.
    Serial.println(F("radio not responding: check 3.3V, CE/CSN, capacitor"));
    while (1) {}
  }

  // RF24_PA_LOW is -12 dBm - gentler on a weak 3.3V rail than the 0 dBm
  // RF24_PA_MAX, which is the one to use once the supply is solid.
  radio.setPALevel(RF24_PA_LOW);
  // RF24_250KBPS trades throughput for receiver sensitivity, but that rate
  // exists only on nRF24L01+ silicon; setDataRate() returns false if refused.
  radio.setDataRate(RF24_1MBPS);
  radio.setChannel(76);             // 2476 MHz - above Wi-Fi 1/6/11, in band
  radio.setPayloadSize(sizeof(stableState));
  radio.openWritingPipe(address);
  radio.stopListening();            // this node talks

  Serial.println(F("transmitter ready"));
}

void loop() {
  uint8_t  raw = (digitalRead(PIN_BUTTON) == LOW);  // pulled up: LOW = pressed
  uint32_t now = millis();

  if (raw != lastRaw) {             // any bounce restarts the settling clock
    lastRaw    = raw;
    lastEdgeAt = now;
  }

  bool changed = false;
  if (raw != stableState && (now - lastEdgeAt) >= DEBOUNCE_MS) {
    stableState = raw;
    changed     = true;
  }

  if (changed || (now - lastSendAt) >= HEARTBEAT_MS) {
    lastSendAt = now;

    // write() returns true only when the receiver's auto-ACK came back,
    // so it is a delivery report, not a "sent" flag.
    bool acked = radio.write(&stableState, sizeof(stableState));

    if (changed) {
      Serial.print(stableState ? F("pressed  ") : F("released "));
      Serial.println(acked ? F("- ack received") : F("- NO ack"));
    }
  }
}
/*
  nRF24L01 remote button - RECEIVER node (Arduino Uno + RF24 by TMRh20).

  Wiring is identical to the transmitter:
  VCC -> 3V3, GND -> GND, CE -> D9, CSN -> D10, SCK -> D13, MOSI -> D11,
  MISO -> D12, plus the 10-100uF capacitor across the module's VCC and GND.

  D3 is the output pin. It drives the relay module's IN terminal, or an LED
  with a series resistor. D13 is NOT available as an indicator here: on an
  Uno that pin is SPI SCK and the radio owns it.
*/

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

RF24 radio(9, 10);                 // CE, CSN

const byte address[6] = "MHUB1";   // same five bytes as the transmitter

const uint8_t  PIN_OUT     = 3;
const uint16_t FAILSAFE_MS = 1000; // 5 missed heartbeats = link gone

uint8_t  lastState = 0;
uint32_t lastHeard = 0;

void setup() {
  Serial.begin(115200);
  pinMode(PIN_OUT, OUTPUT);
  digitalWrite(PIN_OUT, LOW);      // drive the output off before anything else

  if (!radio.begin()) {
    Serial.println(F("radio not responding: check 3.3V, CE/CSN, capacitor"));
    while (1) {}
  }

  radio.setPALevel(RF24_PA_LOW);    // every setting below must match the TX
  radio.setDataRate(RF24_1MBPS);
  radio.setChannel(76);
  radio.setPayloadSize(sizeof(lastState));
  radio.openReadingPipe(1, address);  // pipe 1 listens on the shared address
  radio.startListening();             // this node listens

  Serial.println(F("receiver listening"));
}

void loop() {
  if (radio.available()) {
    uint8_t state = 0;
    radio.read(&state, sizeof(state));
    lastHeard = millis();

    if (state != lastState) {
      lastState = state;
      digitalWrite(PIN_OUT, state ? HIGH : LOW);
      Serial.println(state ? F("output ON") : F("output OFF"));
    }
  }

  // Nothing heard for a second: the transmitter is off, out of range or
  // dead. Release the output rather than leave it stuck on.
  if (lastState && (millis() - lastHeard) > FAILSAFE_MS) {
    lastState = 0;
    digitalWrite(PIN_OUT, LOW);
    Serial.println(F("link lost - output released"));
  }
}

On an Uno the transmitter compiles to 3,802 bytes of flash and 244 bytes of RAM; the receiver to 3,424 and 239. The output is D3 and deliberately not D13: on an Uno that pin is SPI clock and the radio owns it, so the onboard LED flickers with traffic and is useless as an indicator. Take D3 to the relay module‘s IN screw terminal, and power the module itself: DC+ to the Uno’s 5 V, DC- to GND. A signal on IN with nothing powering the board switches nothing. Set the H/L trigger jumper to H, because the sketch’s off state is a LOW on D3 β€” driven at startup, and returned to whenever the failsafe fires β€” and on the L setting each of those off moments energises the relay instead, so a lost link would switch the load on rather than off. Keep the switched side low-voltage DC; mains brings its own rules on enclosures, clearances and cable rating, so read our relay module safety guide first.

The heartbeat and the failsafe are a pair: the transmitter repeats the button state every 200 ms, and the receiver drops its output after a second of silence, so a flat battery or a walk out of range switches the load off instead of leaving it latched on. Swap the button for a joystick and the same structure carries two axes.

PCB antenna or the antenna version β€” which one should you buy?

NRF24RF (PCB antenna) NRF24AN (antenna version)
Antenna Gold trace etched into the board SMA socket, duck antenna screws on
Transmit Bare chip, up to 0 dBm Power amplifier, around +20 dBm
Receive Bare chip Low-noise amplifier ahead of the chip
Peak transmit current 11.3 mA Roughly 115 mA
Uno 3V3 pin can feed it Yes, with the capacitor No β€” needs its own 3.3 V supply
Good for Same room, next room, across a small house Across a field, between buildings

The NRF24AN’s advantage is arithmetic, not marketing. The amplifier adds roughly 20 dB on transmit and the low-noise amplifier about 10 dB on receive, so the link budget improves by around 30 dB. Free-space loss rises 6 dB every time distance doubles, since the same power spreads over four times the area, so 30 dB is five doublings β€” about thirty times the range, which is how open-field figures in the hundreds of metres sit beside a plain module that manages tens. Those maxima are clear line-of-sight, and walls and bodies each eat several dB of that budget.

Range costs power. At 115 mA the antenna version asks more than twice what the Uno’s 3V3 pin is rated for, so hanging it there makes the brownout worse rather than better: run it at RF24_PA_LOW, fit at least 100 Β΅F, and give it a dedicated 3.3 V supply with its ground tied to the Uno’s. Upgrade both ends, since the acknowledgement means the far node transmits too β€” then separate them before judging the result, because a low-noise amplifier is built for faint signals and two amplified modules a hand’s width apart swamp each other’s front ends. Give them several metres for the first test. One detail decides whether an antenna works at all β€” the module’s jack is standard SMA, while most spare Wi-Fi antennas are RP-SMA. Reverse polarity swaps the contacts and not the thread: both halves end up with a socket, so they screw together with nothing but air where the pin should be.

Cartoon top view comparing two black nRF24L01 modules β€” a short one with a gold zig-zag PCB antenna trace and short teal waves, and a longer one with a gold SMA socket, a black screw-on rod antenna, two chips and much longer teal waves
The two nRF24L01 variants from above: a gold antenna etched into the board on the left, a gold SMA socket and a screw-on black antenna on the right. The longer board carries two chips because the amplifier is a second chip.

When is the nRF24L01 the wrong radio?

The nRF24L01 is a short-range, high-rate link, and three jobs suit something else. Kilometres for a handful of bytes a minute β€” a water tank across a plantation, a gate sensor down a long drive β€” is LoRa territory: a sub-GHz spread-spectrum radio that trades data rate for reach, a different design rather than a bigger nRF24, and not something we carry.

If one end is a phone, you want Bluetooth, not a radio the phone does not have β€” our HC-05 guide covers that pairing and the Bluetooth RC car is the same idea driving motors. If both ends are already ESP32s, ESP-NOW uses Wi-Fi silicon you have paid for and needs no extra module. The nRF24L01 wins exactly here: two microcontrollers, a room or a house apart, cheap enough to put on both ends.

Common mistakes we see from real customers

5 V on the VCC pin. The logic pins really are 5 V tolerant; the supply pin tops out at 3.6 V. One wrong header hole and the module never answers begin() again.

Skipping the capacitor because it “works on the bench”. A short packet at close range survives a sagging rail; the same link three rooms away does not.

Sketches that disagree. Channel, data rate, address and payload size must match, and startListening() on both ends leaves two receivers and no transmitter. Both failures are silent β€” no error, just a receiver that never reports anything.

FAQ

Why does radio.write() always return false?

No acknowledgement came back: either the receiver’s settings differ, or the transmitter’s supply is sagging during the burst. Fit the capacitor first, then compare the sketches.

Can I power the nRF24L01 from the Arduino’s 5 V pin?

No. 3.6 V is the absolute maximum on VCC. Use 3V3 β€” the signal pins are 5 V tolerant, the supply pin is not.

What capacitor value should I use?

10–100 Β΅F electrolytic, 6.3 V or more, across the module’s own VCC and GND pins with the striped leg to GND. Use 100 Β΅F for the antenna version.

Do both modules need to be the same type?

No, they pair fine. But range is set by the weaker end, so upgrading only one buys far less than expected.

How far will two modules reach indoors?

A PCB-antenna pair covers a room comfortably and usually a wall or two beyond. Houses here are brick and reinforced concrete rather than timber and plasterboard, so a wall costs more signal than the same wall in a video filmed elsewhere. If it drops sooner than that, check the supply before blaming range.

Last updated August 2026. Stuck? Chat with us on WhatsApp.

Leave a Reply

Your email address will not be published. Required fields are marked *