Learn

A wireless doorbell with two Arduinos and nRF24L01 radios

Advanced

Or see every lesson.

  • 261parts on the bench
  • 31boards running now
  • 1.00xreal time, on every board
Two Arduino Unos: a radio doorbelllive0.000 s 0.00x
Press the button on the left board to ring the lamp on the right
The Radio doorbell example: two simulated ATmega328Ps, an nRF24L01 on each, and no wire between them.

The nRF24L01 is the small green 2.4 GHz radio with a zigzag antenna printed on the end. Two of them let two Arduinos send short messages to each other with no wire in between. It is the usual choice for a wireless remote, a doorbell or a sensor that reports from across the room.

The circuit above is two Arduino Unos, each with an nRF24L01. Press the button on the left board and it sends "ding dong" to the right board, which prints it and flashes its lamp. The sender also tells you whether the message arrived. It runs in your browser on the two sketches below.

What you need

  • Two Arduino Unos
  • Two nRF24L01 radio modules
  • A pushbutton for the sender
  • An LED and a 220 ohm resistor for the receiver
  • A breadboard and jumper wires
  • On real hardware, a 10 µF capacitor across each radio’s VCC and GND is a common fix for flaky links

Wiring

Part and pinGoes toNote
nRF24L01 VCC3.3 VNot 5 V; the radio runs on 1.9 to 3.6 volts
nRF24L01 GNDGNDShared ground
nRF24L01 CEPin 7Chip enable; the sketch names this pin
nRF24L01 CSNPin 8SPI chip select; the sketch names this pin
nRF24L01 SCKPin 13SPI clock
nRF24L01 MOSIPin 11Data to the radio
nRF24L01 MISOPin 12Data from the radio
nRF24L01 IRQNot connectedMost sketches leave it unwired
Button (sender)Pin 2 and GNDUses the internal pull-up, so pressed reads LOW
LED (receiver)Pin 5Through a 220 ohm resistor to GND

Both radios must agree on three things

The radios have no pairing step. Instead, both sides must use the same channel, the same data rate and the same address. The sketches use channel 76, which is the RF24 library’s default, and the address "00001". Change any one of them on one side only and the messages go nowhere.

The sender calls openWritingPipe() with the address and stopListening(). The receiver calls openReadingPipe() with the same address and startListening(). That is the whole setup.

The sender’s loop, from the Radio doorbell example
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

RF24 radio(7, 8); // CE on 7, CSN on 8
const byte address[6] = "00001";

void loop()
{
    if (digitalRead(BUTTON) == HIGH) {
        return;
    }
    presses++;
    char message[32] = "ding dong ";
    message[10] = (char)('0' + presses % 10);
    bool heard = radio.write(&message, sizeof(message));
    Serial.print(message);
    Serial.println(heard ? ": delivered" : ": no answer");
    while (digitalRead(BUTTON) == LOW) {
        delay(10);
    }
    delay(50);
}

"Delivered" or "no answer": the acknowledgment

This is the most useful thing to understand about the nRF24L01. When the receiving radio gets a packet, it sends a short acknowledgment back on its own, in hardware, before its sketch even looks. radio.write() waits for that answer. It returns true if the answer came and false if it did not, after a few tries.

You can see both results here. Press the button and the sender prints "ding dong 1: delivered", while the receiver prints "heard: ding dong 1". Now open the circuit in the editor, take the program off the right-hand board, or delete its radio’s 3.3 V wire, and press again. The sender prints "ding dong 1: no answer".

That makes "no answer" a great debugging tool on real hardware. It tells you the problem is the link or the other board, not the button or your code on this side.

The receiver

The receiver’s loop checks radio.available(). When a packet is waiting, radio.read() copies it into a buffer. The sketch prints it and flashes the LED for 300 ms. Packets can be up to 32 bytes, so both sides use a 32-byte buffer.

The receiver’s loop, from the Radio doorbell example
void loop()
{
    if (!radio.available()) {
        return;
    }
    char message[32] = "";
    radio.read(&message, sizeof(message));
    Serial.print("heard: ");
    Serial.println(message);
    digitalWrite(LED, HIGH);
    delay(300);
    digitalWrite(LED, LOW);
}

Try it in the editor

Add radio.setChannel(90) to the sender’s setup() only, and every press says "no answer". Add it to the receiver too, and they talk again.

Send a number instead of text: put a potentiometer on the sender, read it with analogRead(), and send the int. That is the start of a wireless remote control.

Add a logic analyzer from the parts bin and clip one channel to a radio’s ANT pin, the hidden antenna pin that stands in for the air. You can watch each packet go past, one byte at a time, and see the short answer come back.

Common mistakes

Powering the radio from 5 V. It is a 3.3 V part. Use the 3.3 V pin.

A weak 3.3 V supply on real hardware. The radio draws short bursts of current when it sends. A 10 µF capacitor across VCC and GND, right at the module, fixes many links that work only now and then.

CE and CSN in the wrong order. RF24 radio(7, 8) takes CE first and CSN second.

Different addresses, channels or data rates on the two sides.

Reading the result of radio.write() as proof the other sketch did something. It only means the other radio got the packet.

Questions

How do I connect an nRF24L01 to an Arduino Uno?

VCC to 3.3 V, GND to GND, SCK to 13, MOSI to 11, MISO to 12, and CE and CSN to any two pins you name in RF24 radio(CE, CSN). This page uses 7 and 8.

Why does radio.write() return false?

No acknowledgment came back. The other radio is off, not listening, on another channel or address, or out of range. On real hardware a weak 3.3 V supply is a very common cause.

What is the range of the nRF24L01?

It depends on the module, the power setting and what is in the way. Mokxi does not model range, walls or interference at all: every radio on the canvas hears every other one.

How does Mokxi connect two radios with no wire?

Each radio has a hidden antenna pin, and Mokxi joins them all. That shared line is the room. Two radios that send at once really do spoil each other’s packets.

Build this for real

Open the editor, change a value and watch the number move with it. Nothing to install, and no account needed.