Компоненты · 14 мин чтения

nRF24L01 и Arduino: подключение, код RF24, дальность и решение проблем

nRF24L01 и Arduino: подключение, питание 3,3 V и конденсатор 10 µF, код передатчика и приёмника на RF24, дальность PA+LNA до 1 км, пульт с джойстиком, ESP32 и Pico.

Связка nRF24L01 и Arduino — самый дешёвый и практичный способ передавать данные между двумя платами без кабеля. Этот модуль размером с ноготь работает в диапазоне 2,4 GHz, передаёт до 2 мегабит в секунду и может быть и передатчиком, и приёмником. Он идеален для радиоуправляемых машинок, беспроводных джойстиков, станции, которая передаёт показания садового датчика в дом, или узлов сигнализации, предупреждающих друг друга. Стандартная версия на открытом пространстве достаёт примерно на 100 метров, а версия nRF24L01+PA+LNA с внешней антенной в хороших условиях — до 1 километра.

В этом руководстве ты узнаешь, как работает модуль, какие пины SPI он использует, почему его нужно питать от 3,3 V и как конденсатор 10 µF решает самую частую проблему. Затем напишешь код передатчика и приёмника с библиотекой RF24, разберёшься с адресами и каналами, соберёшь пульт с джойстиком, подключишь модуль к ESP32 и Raspberry Pi Pico и, наконец, пошагово решишь проблемы «radio.begin() false» и «данные не приходят».

Модуль беспроводной связи nRF24L01 на 2,4 GHz
Стандартный модуль nRF24L01+: зигзагообразная дорожка на конце платы — это печатная антенна; подключается по SPI через 8-контактный разъём.

Что такое nRF24L01 и как он работает?

nRF24L01 — микросхема радиоприёмопередатчика на 2,4 GHz от Nordic Semiconductor; почти на всех продаваемых сегодня модулях стоит улучшенная версия nRF24L01+ или совместимый клон. Модуль общается с Arduino по SPI: Arduino записывает по SPI настройки и данные для отправки, а остальное делает чип. Аппаратный протокол Nordic под названием Enhanced ShockBurst снабжает каждый пакет адресом и CRC (проверкой ошибок). Когда приёмник правильно получает пакет, он автоматически отправляет передатчику подтверждение (ACK); если ACK не пришёл, передатчик сам повторяет попытку. Так что код просто говорит «отправить», а повторы и проверка ошибок происходят аппаратно.

Пакет несёт не больше 32 байт данных. Это может показаться мало, но две оси джойстика, несколько кнопок и несколько значений датчиков легко помещаются. Модуль использует один из 126 каналов, а частота канала равна 2400 + номер канала (MHz); канал 76, например, — это 2476 MHz. Приёмник может одновременно слушать 6 разных адресов (так называемых каналов-труб, pipes), так что один хаб может собирать данные с шести передатчиков.

ПараметрЗначение
Частота2,400–2,525 GHz (126 каналов с шагом 1 MHz)
Скорость передачи250 kbps, 1 Mbps, 2 Mbps
Напряжение питания1,9–3,6 V (на практике 3,3 V)
Входные пиныВыдерживают 5 V (CE, CSN, SCK, MOSI)
Выходная мощность0, −6, −12, −18 dBm
Ток (передача, 0 dBm)Около 11,3 mA
Ток (приём, 2 Mbps)Около 13,5 mA
Режим power downОколо 900 nA
Чувствительность приёмника−94 dBm (250 kbps), −85 dBm (1 Mbps), −82 dBm (2 Mbps)
Размер полезной нагрузки1–32 байта
ИнтерфейсSPI, до 10 MHz
Число каналов-труб (pipes)6

nRF24L01 или nRF24L01+PA+LNA

В продаже встречаются два типа модулей. У стандартного модуля антенна — зигзагообразная медная дорожка на плате. Версия nRF24L01+PA+LNA добавляет перед тем же приёмопередатчиком микросхему радиотракта: PA (Power Amplifier, усилитель мощности) усиливает исходящий сигнал, а LNA (Low Noise Amplifier, малошумящий усилитель) усиливает слабые входящие сигналы, прежде чем они дойдут до чипа. Внешняя антенна накручивается на разъём SMA. У обоих модулей одинаковая распиновка и один и тот же код, и они без проблем общаются друг с другом; разница в дальности и потребляемом токе. Цифры ниже приблизительные и зависят от окружения.

Радиомодуль nRF24L01+PA+LNA с антенной
nRF24L01+PA+LNA: версия с усилителями передачи и приёма и антенной SMA. Работает с тем же кодом, но потребляет гораздо больше тока.
ПараметрnRF24L01+ (печатная антенна)nRF24L01+PA+LNA
АнтеннаНапечатана на платеВнешняя антенна SMA
Выходная мощностьДо 0 dBm (1 mW)До +20 dBm (100 mW), в зависимости от модели
Пиковый ток при передачеОколо 12 mAДо 115 mA
Пиковый ток при приёмеОколо 13,5 mAДо 45 mA
Дальность на открытом воздухе (250 kbps)50–100 м800–1100 м
Дальность в помещении10–30 м, 1–2 стеныНесколько этажей и десятки метров
Рекомендуемое питаниеПин 3,3 V + конденсатор 10 µFОтдельный стабилизатор 3,3 V + конденсатор

Распиновка nRF24L01 и подключение к Arduino

У модуля 8 выводов в разъёме 2×4. Вывод с квадратной контактной площадкой — вывод 1, это GND; рядом с ним VCC. CE (Chip Enable) переключает модуль в режим прослушивания или передачи, а CSN (Chip Select Not) притягивают к LOW, чтобы сказать по шине SPI «сейчас я обращаюсь к тебе». SCK, MOSI и MISO — стандартные линии SPI, и они должны идти на фиксированные пины SPI платы, а CE и CSN можно подключить к любым цифровым пинам. Пин IRQ не обязателен; он уходит в LOW, когда приходит пакет или заканчивается передача, и используется, если хочешь работать с прерываниями. Как работает SPI — в статье Что такое SPI, а полную карту пинов своей платы смотри в утилите «Распиновка».

Вывод nRF24L01НазначениеArduino Uno / NanoArduino MegaESP32Raspberry Pi Pico
1 GNDЗемляGNDGNDGNDGND
2 VCCПитание (3,3 V)3.3V3.3V3V33V3(OUT)
3 CEВыбор режимаD9D9GPIO 4GP6
4 CSNВыбор микросхемы SPID10D10GPIO 5GP5
5 SCKТактирование SPID13D52GPIO 18GP2
6 MOSIДанные от платы к модулюD11D51GPIO 23GP3
7 MISOДанные от модуля к платеD12D50GPIO 19GP4
8 IRQПрерывание (не обязательно)Не подключёнНе подключёнНе подключёнНе подключён
Никогда не подключай VCC к 5 V. Чип выдерживает не больше 3,6 V, а 5 V могут повредить его навсегда. Сигнальные пины выдерживают 5 V, так что их можно подключать прямо к пинам SPI у Uno, но питание всегда должно быть 3,3 V. Не вставляй модуль и прямо в макетную плату: из-за разъёма 2×4 противоположные выводы попадают в одну полоску и замыкаются. Вместо этого используй перемычки мама-папа.

Самая частая ошибка: питание и конденсатор 10 µF

Большинство проблем с nRF24L01 вызывает не код, а питание. В момент передачи модуль потребляет короткие резкие импульсы тока. Длинные перемычки и слабый источник 3,3 V за этими импульсами не успевают; напряжение на мгновение проседает, и чип отправляет повреждённый пакет, пропускает ACK или сам перезагружается. По официальной документации пин 3,3 V у Arduino Uno отдаёт не больше 50 mA; этого хватает для стандартного модуля, но не для версии PA+LNA, которая потребляет до 115 mA. На некоторых клонах Nano пин 3,3 V питается от микросхемы USB-UART и ещё слабее. Симптомы будут знакомы: write() то срабатывает, то нет, модуль работает лучше, если его потрогать, или дальность заканчивается на нескольких метрах.

  • Конденсатор 10 µF: поставь электролитический конденсатор 10 µF между выводами VCC и GND модуля, как можно ближе к ним. Длинная ножка (+) идёт к VCC, а сторона с полосой (−) — к GND. Подойдёт и любое значение от 10 до 100 µF; почему это помогает, читай в статье Что такое конденсатор.
  • Керамический конденсатор 100 nF: маленький керамический конденсатор (маркировка 104) параллельно электролитическому отфильтровывает высокочастотные помехи. Маркировку конденсаторов можно расшифровать утилитой «Код конденсатора».
  • Плата-адаптер: 8-контактные платы-адаптеры, которые продаются для nRF24L01, уже содержат стабилизатор AMS1117-3.3 и конденсаторы. На VCC адаптера подаёшь 5 V, а модуль получает чистые 3,3 V.
  • Отдельный стабилизатор: версию PA+LNA питай не от пина 3,3 V Arduino, а от отдельного стабилизатора AMS1117-3.3, запитанного от 5 V, и соедини все земли вместе.
  • Короткие провода: по возможности делай перемычки короче 10 см; длинные болтающиеся провода мешают и питанию, и сигналам SPI.
Стабилизатор напряжения AMS1117 3.3V
Стабилизатор AMS1117-3.3: понижает 5 V до 3,3 V и легко выдерживает большой ток, который модуль PA+LNA потребляет при передаче.

Установка библиотеки RF24

  1. В Arduino IDE открой Инструменты › Управлять библиотеками (Tools › Manage Libraries) или щёлкни по значку библиотек слева.
  2. Введи в поиске RF24 и установи библиотеку RF24 от TMRh20. RF24Network, RF24Mesh и RF24Ethernet — отдельные библиотеки, для начала они не нужны.
  3. После установки в меню «Файл › Примеры › RF24» (File › Examples) появится пример GettingStarted. Код в этой статье использует синтаксис RF24 версии 1.5 и новее.
  4. Если библиотека устанавливается впервые, следуй шагам из статьи Как добавить библиотеку в Arduino.
В старых примерах в интернете встречается radio.openWritingPipe(address), а за ней radio.stopListening(). Начиная с RF24 версии 1.5, рекомендуемый способ — одна строка: radio.stopListening(address). Старая форма всё ещё компилируется, но может выдавать предупреждение «deprecated» (устарело). Если код из этой статьи не компилируется, обнови библиотеку RF24.

Адрес, канал и скорость: как договорить два модуля

Чтобы два модуля слышали друг друга, некоторые настройки должны быть в точности одинаковыми с обеих сторон. Представь разговор по рации: если не настроены одна частота (канал), одна скорость речи (скорость передачи) и один позывной (адрес), другую сторону не услышишь. Адрес — массив из 5 байт, и проще всего записать его в коде строкой из 5 символов, например «00001». Думай об адресе не как об имени устройства, а как об общем пути между двумя устройствами: передатчик кладёт пакеты на этот путь, а приёмник, слушающий его, их подбирает. Важен и размер полезной нагрузки: RF24 по умолчанию использует пакеты фиксированного размера, и если приёмник ждёт не тот же размер, что у передатчика, он пакет не увидит.

НастройкаФункция RF24Значение в этой статьеПримечание
КаналsetChannel(76)76 (2476 MHz)0–125; должен совпадать с обеих сторон
Скорость передачиsetDataRate(RF24_250KBPS)250 kbpsМеньше скорость — больше дальность
АдресstopListening(address) / openReadingPipe(1, address) (передатчик / приёмник)«00001»Цель передатчика = труба приёмника
Размер полезной нагрузкиsetPayloadSize(sizeof(data))32 байта (5 в примере с джойстиком)При фиксированном размере обе стороны должны совпадать
Выходная мощностьsetPALevel(RF24_PA_LOW)НизкаяСовпадать не обязана; задаёт дальность
Auto-ACK и CRCВключены по умолчанию16-битный CRCЕсли отключаешь, отключай с обеих сторон

Код передатчика (TX)

Для первой проверки подключи две Arduino к двум разным USB-портам и разнеси модули на 1–2 метра. Загрузи код передатчика ниже в одну из них. Каждую секунду она отправляет пронумерованное сообщение и выводит в монитор порта, подтвердил ли его приёмник. Не забудь выставить в мониторе порта 115200 бод.

C++ (Arduino IDE)
1#include <SPI.h>
2#include <RF24.h>
3
4RF24 radio(9, 10);                        // CE, CSN pinleri / CE, CSN pins
5const uint8_t address[6] = "00001";       // iki tarafta aynı adres / same address on both sides
6char message[32];                         // en fazla 32 bayt / 32 bytes max
7uint16_t counter = 0;
8
9void setup() {
10  Serial.begin(115200);
11  if (!radio.begin()) {                   // modül cevap vermiyor / module not responding
12    Serial.println(F("nRF24L01 bulunamadi, kablolari kontrol et!"));
13    while (true) {}
14  }
15  radio.setChannel(76);                   // kanal 76 = 2476 MHz / channel 76 = 2476 MHz
16  radio.setDataRate(RF24_250KBPS);        // en uzun menzil / longest range
17  radio.setPALevel(RF24_PA_LOW);          // masa testi için düşük güç / low power for desk tests
18  radio.setPayloadSize(sizeof(message));  // paket boyu 32 bayt / 32-byte payload
19  radio.stopListening(address);           // verici modu + hedef adres / TX mode + target address
20}
21
22void loop() {
23  snprintf(message, sizeof(message), "Merhaba BlueGrays #%u", counter++);
24  bool ok = radio.write(message, sizeof(message));   // onay (ACK) geldi mi? / was it acknowledged?
25  if (ok) {
26    Serial.print(F("Gonderildi: "));
27    Serial.println(message);
28  } else {
29    Serial.println(F("Onay gelmedi"));
30  }
31  delay(1000);
32}

Код приёмника (RX)

C++ (Arduino IDE)
1#include <SPI.h>
2#include <RF24.h>
3
4RF24 radio(9, 10);                        // CE, CSN pinleri / CE, CSN pins
5const uint8_t address[6] = "00001";       // vericiyle aynı adres / same address as the transmitter
6char message[32];
7
8void setup() {
9  Serial.begin(115200);
10  if (!radio.begin()) {
11    Serial.println(F("nRF24L01 bulunamadi, kablolari kontrol et!"));
12    while (true) {}
13  }
14  radio.setChannel(76);                   // ayarlar vericiyle aynı / settings match the transmitter
15  radio.setDataRate(RF24_250KBPS);
16  radio.setPALevel(RF24_PA_LOW);
17  radio.setPayloadSize(sizeof(message));
18  radio.openReadingPipe(1, address);      // 1 numaralı boruyu aç / open pipe 1
19  radio.startListening();                 // alıcı modu / RX mode
20}
21
22void loop() {
23  if (radio.available()) {                // paket geldi mi? / has a packet arrived?
24    radio.read(message, sizeof(message));
25    Serial.print(F("Gelen: "));
26    Serial.println(message);
27  }
28}

radio.write() отправляет пакет и возвращает true, если приёмник его подтвердил; с настройками по умолчанию она 15 раз повторяет попытку с интервалом около 1,5 мс, прежде чем вернуть false. На приёмнике openReadingPipe(1, address) назначает трубе 1 адрес передатчика, startListening() переводит модуль в режим прослушивания, available() сообщает, ждёт ли пакет, а read() копирует его в переменную. Если в мониторе порта приёмника идут строки с растущим номером вроде «Gelen: Merhaba BlueGrays #0», «#1», «#2» (принято: привет), связь работает.

Во время проверки не ставь модули вплотную друг к другу и держи мощность низкой. Особенно модули PA+LNA на полной мощности в нескольких сантиметрах друг от друга перегружают приёмники, и пакеты теряются, что выглядит как неисправность. На малом расстоянии используй RF24_PA_LOW или RF24_PA_MIN, а мощность поднимай уже на реальной дистанции.

Дальность: от 100 метров до 1 километра

Дальность определяют три вещи: выходная мощность, чувствительность приёмника и окружение. Чем ниже скорость передачи, тем более слабые сигналы может расшифровать приёмник; чувствительность −94 dBm на 250 kbps, но −82 dBm на 2 Mbps. Эти 12 dB разницы означают примерно вчетверо большую дальность на открытом пространстве. Стены, деревья, тела людей и металлические поверхности заметно ослабляют сигналы 2,4 GHz, а роутеры Wi-Fi, Bluetooth-устройства и микроволновки делят тот же диапазон.

Скорость передачиЧувствительность приёмникаОтносительная дальностьКогда использовать
250 kbps−94 dBmНаибольшаяПульты, удалённые датчики
1 Mbps−85 dBmСредняяОбщее применение (по умолчанию в RF24)
2 Mbps−82 dBmНаименьшаяВысокая скорость, малое расстояние

Важен и выбор канала. Самые используемые каналы Wi-Fi 1, 6 и 11 занимают примерно 2401–2473 MHz; каналы nRF24L01 74–83 лежат выше и тише, если поблизости нет роутера на Wi-Fi-канале 12 или 13. В Европе (и в Турции) нелицензируемый диапазон 2,4 GHz — от 2400 до 2483,5 MHz, так что не используй каналы выше 83; каналы 100 и выше, которые советуют некоторые примеры в интернете, лежат вне этого диапазона, а точные границы зависят от правил твоей страны. Чтобы увеличить дальность, попробуй следующее:

  • Используй 250 kbps: пультам и данным датчиков высокая скорость не нужна, а низкая даёт дальность.
  • Сначала наладь питание, потом поднимай мощность: RF24_PA_MAX имеет смысл только со стабильными 3,3 V и конденсатором; повышение мощности при слабом питании только ухудшает дело.
  • Ставь антенны высоко и одинаково: 1–2 метра над землёй и обе антенны вертикально в одну сторону заметно увеличивают дальность.
  • Держи подальше от металла: не клади модуль в металлическую коробку и не ставь вплотную к большому аккумуляторному блоку.
  • Оберни неэкранированную плату PA+LNA: если обмотать модуль PA+LNA без металлического экрана изолентой, а затем алюминиевой фольгой, он меньше мешает сам себе; фольга не должна касаться выводов и разъёма антенны.
  • Не передавай без антенны: работа модуля PA+LNA на полной мощности без подключённой антенны перегружает усилитель мощности.

Беспроводной пульт с джойстиком

Теперь соберём настоящий проект: джойстиком на одной Arduino беспроводно управляем сервоприводом и светодиодом на второй. На передатчике пин VRx джойстика идёт на A0, VRy — на A1, а кнопка (SW) — на D2; подробности — в статье Модуль джойстика. На приёмнике сигнальный провод сервопривода идёт на D3, а светодиод — на D4 через резистор 220 Ω. Подключение nRF24L01 на обеих сторонах такое же, как в таблице выше.

Аккуратнее всего отправлять несколько значений в одном пакете через struct (структуру). Здесь есть важная деталь: нужно использовать типы фиксированного размера вроде int16_t и uint8_t. На Arduino Uno int занимает 2 байта, а на ESP32 — 4, и компилятор ESP32 ещё добавляет в конец структуры байты выравнивания. Если одна и та же структура на Uno занимает 5 байт, а на ESP32 — 6, размеры полезной нагрузки не совпадают, и данные не приходят вовсе. __attribute__((packed)) убирает это выравнивание и делает структуру размером 5 байт на любой плате. Сначала передатчик:

C++ (Arduino IDE)
1#include <SPI.h>
2#include <RF24.h>
3
4struct __attribute__((packed)) JoystickData {   // her kartta 5 bayt / 5 bytes on every board
5  int16_t x;
6  int16_t y;
7  uint8_t button;
8};
9
10RF24 radio(9, 10);                        // CE, CSN pinleri / CE, CSN pins
11const uint8_t address[6] = "JOY01";       // kumanda adresi / remote address
12JoystickData data;
13
14void setup() {
15  pinMode(2, INPUT_PULLUP);               // joystick butonu (SW) / joystick button (SW)
16  if (!radio.begin()) {
17    while (true) {}                       // modül yok / no module
18  }
19  radio.setChannel(76);
20  radio.setDataRate(RF24_250KBPS);
21  radio.setPALevel(RF24_PA_HIGH);         // orta-yüksek güç / medium-high power
22  radio.setPayloadSize(sizeof(data));
23  radio.stopListening(address);           // verici modu / TX mode
24}
25
26void loop() {
27  data.x = analogRead(A0);                // VRx ekseni 0-1023 / VRx axis 0-1023
28  data.y = analogRead(A1);                // VRy ekseni 0-1023 / VRy axis 0-1023
29  data.button = (digitalRead(2) == LOW);  // basılıysa 1 / 1 when pressed
30  radio.write(&data, sizeof(data));
31  delay(50);                              // saniyede 20 paket / 20 packets per second
32}

Затем приёмник, управляющий сервоприводом и светодиодом:

C++ (Arduino IDE)
1#include <SPI.h>
2#include <RF24.h>
3#include <Servo.h>
4
5struct __attribute__((packed)) JoystickData {   // vericiyle birebir aynı / identical to the transmitter
6  int16_t x;
7  int16_t y;
8  uint8_t button;
9};
10
11RF24 radio(9, 10);                        // CE, CSN pinleri / CE, CSN pins
12const uint8_t address[6] = "JOY01";       // vericiyle aynı / same as the transmitter
13JoystickData data;
14Servo servo;
15unsigned long lastPacket = 0;
16
17void setup() {
18  pinMode(4, OUTPUT);                     // LED çıkışı / LED output
19  servo.attach(3);                        // servo sinyal pini / servo signal pin
20  if (!radio.begin()) {
21    while (true) {}
22  }
23  radio.setChannel(76);
24  radio.setDataRate(RF24_250KBPS);
25  radio.setPALevel(RF24_PA_HIGH);
26  radio.setPayloadSize(sizeof(data));
27  radio.openReadingPipe(1, address);
28  radio.startListening();                 // alıcı modu / RX mode
29}
30
31void loop() {
32  if (radio.available()) {
33    radio.read(&data, sizeof(data));
34    servo.write(map(data.x, 0, 1023, 0, 180));   // X ekseni -> servo açısı / X axis -> servo angle
35    digitalWrite(4, data.button ? HIGH : LOW);   // buton LED'i yakar / button lights the LED
36    lastPacket = millis();
37  }
38  if (millis() - lastPacket > 500) {      // 0,5 sn paket yok: güvenli konum / no packet for 0.5 s: failsafe
39    servo.write(90);
40    digitalWrite(4, LOW);
41  }
42}

Передатчик отправляет 20 пакетов в секунду; для каждого пакета приёмник переводит ось X в 0–180 градусов и записывает в сервопривод. Часть failsafe (защита при потере связи) на приёмнике очень важна: если в пульте сядет батарейка или он выйдет из зоны действия, последняя команда не будет применяться вечно; если 0,5 секунды не приходит ни одного пакета, сервопривод встаёт в центр, а светодиод гаснет. Если собираешь робот-машинку, в том же месте останавливай моторы. Питание сервопривода от отдельного источника 5 V, а не от пина 5V Arduino, тоже не даёт броскам тока сервопривода мешать nRF24L01. Подключи ось Y к драйверу моторов L298N — и получится беспроводная робот-машинка; подробности о сервоприводе — в статье Что такое сервопривод.

Двусторонняя связь и несколько передатчиков

nRF24L01 не может одновременно передавать и слушать, но есть простой способ получить двустороннюю связь — ACK payload, то есть данные, отправленные внутри пакета подтверждения. Приёмник заранее готовит через writeAckPayload() данные, которые прикрепит к следующему ACK (например, напряжение батареи или показание датчика), а передатчик после успешного write() читает этот ответ через available() и read(). Для этого обе стороны должны вызвать enableDynamicPayloads() и enableAckPayload(). Для нескольких передатчиков у приёмника 6 труб: трубы 0 и 1 получают полный 5-байтовый адрес, а трубы 2–5 делят остальную часть адреса трубы 1 и отличаются лишь одним байтом. В RF24 этот байт — первый символ массива адреса, поэтому адреса вроде «1Node», «2Node» и «3Node» отличаются только первым символом. Для больших сетей есть библиотеки RF24Network и RF24Mesh.

Подключение nRF24L01 к ESP32

Библиотека RF24 без изменений работает на ESP32, а radio.begin() использует шину VSPI по умолчанию: SCK = GPIO 18, MISO = GPIO 19, MOSI = GPIO 23. Для CSN хорошо подходит GPIO 5, а для CE — GPIO 4. Стабилизатор 3,3 V на платах ESP32 DevKit сильнее, чем у Uno, но конденсатор 10 µF не пропускай. На моделях вроде ESP32-C3 или ESP32-S3 пины SPI по умолчанию другие, так что проверь карту пинов своей платы. Поскольку Wi-Fi у ESP32 тоже работает на 2,4 GHz, при совместном использовании выбирай канал nRF24L01 подальше от Wi-Fi-канала роутера. Код ниже читает на ESP32 пакеты передатчика с джойстиком; на той же основе ESP32 можно сделать шлюзом, который пересылает данные с узлов nRF24L01 в интернет. Если плата для тебя новая, начни со статьи Что такое ESP32.

C++ (Arduino IDE)
1#include <SPI.h>
2#include <RF24.h>
3
4struct __attribute__((packed)) JoystickData {   // packed olmasa 6 bayt olurdu / 6 bytes without packed
5  int16_t x;
6  int16_t y;
7  uint8_t button;
8};
9
10RF24 radio(4, 5);                         // CE = GPIO 4, CSN = GPIO 5 pinleri / CE = GPIO 4, CSN = GPIO 5 pins
11const uint8_t address[6] = "JOY01";
12JoystickData data;
13
14void setup() {
15  Serial.begin(115200);
16  if (!radio.begin()) {                   // varsayılan VSPI: SCK 18, MISO 19, MOSI 23 / default VSPI pins
17    Serial.println("nRF24L01 bulunamadi!");
18    while (true) delay(1000);
19  }
20  radio.setChannel(76);
21  radio.setDataRate(RF24_250KBPS);
22  radio.setPALevel(RF24_PA_HIGH);
23  radio.setPayloadSize(sizeof(data));     // packed sayesinde 5 bayt / 5 bytes thanks to packed
24  radio.openReadingPipe(1, address);
25  radio.startListening();
26}
27
28void loop() {
29  if (radio.available()) {
30    radio.read(&data, sizeof(data));
31    Serial.printf("X=%d  Y=%d  Buton=%d\n", data.x, data.y, data.button);
32  }
33}

Если нужно связать между собой только платы ESP32, хорошим вариантом будет и ESP-NOW, которому не нужен дополнительный модуль; преимущество nRF24L01 в том, что он работает и с дешёвыми маломощными платами вроде Uno, Nano и Pro Mini.

nRF24L01 с Raspberry Pi Pico и MicroPython

Для MicroPython на Pico используется драйвер nrf24l01.py из официального репозитория micropython-lib. Файл можно скопировать на Pico через Thonny или установить с компьютера командой mpremote mip install nrf24l01. Подключение использует SPI0: SCK = GP2, MOSI = GP3, MISO = GP4, CSN = GP5, CE = GP6 и VCC = 3V3(OUT). Настройки драйвера по умолчанию отличаются от RF24 (канал 46, полезная нагрузка 16 байт), поэтому для связи с Arduino в коде явно задаём канал, скорость и размер полезной нагрузки. Код ниже расшифровывает на Pico пакеты передатчика с джойстиком:

MicroPython
1from machine import Pin, SPI
2import struct
3import utime
4from nrf24l01 import NRF24L01, POWER_2, SPEED_250K
5
6spi = SPI(0, sck=Pin(2), mosi=Pin(3), miso=Pin(4))   # SPI0 pinleri / SPI0 pins
7csn = Pin(5, mode=Pin.OUT, value=1)                  # CSN pini GP5 / CSN pin GP5
8ce = Pin(6, mode=Pin.OUT, value=0)                   # CE pini GP6 / CE pin GP6
9
10nrf = NRF24L01(spi, csn, ce, channel=76, payload_size=5)   # Arduino ile aynı / same as the Arduino
11nrf.set_power_speed(POWER_2, SPEED_250K)             # -6 dBm güç, 250 kbps / -6 dBm power, 250 kbps
12nrf.open_rx_pipe(1, b"JOY01")                        # vericinin adresi / transmitter address
13nrf.start_listening()                                # alıcı modu / RX mode
14print("Dinleniyor... / Listening...")
15
16while True:
17    if nrf.any():                                    # paket geldi mi? / packet waiting?
18        x, y, button = struct.unpack("<hhB", nrf.recv())   # 2 + 2 + 1 bayt / 2 + 2 + 1 bytes
19        print("X:", x, "Y:", y, "Buton:", button)
20    utime.sleep_ms(5)

struct.unpack("<hhB") превращает 5 пришедших байт в два знаковых 16-битных числа и один байт; начальный «<» задаёт порядок байтов little-endian, который используют AVR и ESP32. Если модуль не найден, драйвер выдаёт «nRF24L01+ Hardware not responding» (устройство не отвечает) — аналог MicroPython для begin(), возвращающей false на Arduino. Если Pico для тебя в новинку, сначала прочитай Что такое Raspberry Pi Pico.

radio.begin() возвращает false: пошаговое решение

Если в мониторе порта появляется «nRF24L01 bulunamadi» (не найден) или сообщение «radio hardware is not responding!!» (радиомодуль не отвечает) из примеров RF24, Arduino вообще не может общаться с модулем по SPI. В таком случае проблема почти всегда в подключении или питании, а не в коде. Сначала загрузи диагностический скетч ниже; он выводит все настройки модуля в читаемом виде.

C++ (Arduino IDE)
1#include <SPI.h>
2#include <RF24.h>
3#include "printf.h"                       // RF24 ile gelir / ships with RF24
4
5RF24 radio(9, 10);                        // kendi CE, CSN pinlerin / your CE, CSN pins
6
7void setup() {
8  Serial.begin(115200);
9  printf_begin();                         // printPrettyDetails için / needed for printPrettyDetails
10  bool ok = radio.begin();
11  Serial.print(F("begin(): "));
12  Serial.println(ok ? "true" : "false");
13  Serial.print(F("isChipConnected(): "));
14  Serial.println(radio.isChipConnected() ? "true" : "false");
15  radio.printPrettyDetails();             // tüm ayarları yazdır / print every setting
16}
17
18void loop() {
19}
  1. Проверь MOSI и MISO: эти два провода путают чаще всего. На Uno и Nano MOSI = D11, MISO = D12 и SCK = D13; на Mega это 51, 50 и 52.
  2. Совпадают ли CE и CSN с кодом: если написано RF24 radio(9, 10), CE идёт на D9, а CSN — на D10. Пример GettingStarted из RF24 использует пины 7 и 8; если пробуешь пример без изменений, подключай так.
  3. Питание 3,3 V? Измерь мультиметром между VCC и GND; должно быть 3,0–3,6 V. Если модуль когда-нибудь подключали к 5 V, он может быть повреждён.
  4. Посмотри вывод printPrettyDetails: если адреса и значения регистров все показывают 0x00 или 0xff, шина SPI не работает. Если значения выглядят осмысленно, но связи всё равно нет, проблема в пине CE, настройках или питании.
  5. Укороти провода и снизь скорость SPI: при длинных или болтающихся проводах напиши RF24 radio(9, 10, 4000000), чтобы снизить скорость SPI с 10 MHz по умолчанию до 4 MHz.
  6. Замени модуль: если всё остальное в порядке, попробуй запасной модуль; в дешёвых наборах по несколько штук может попасться неисправный.

Данные не приходят или приходят с перебоями: частые проблемы

СимптомВероятная причинаРешение
begin() возвращает true, но до приёмника ничего не доходитКанал, скорость, адрес или размер полезной нагрузки различаются на двух сторонахСравни четыре настройки рядом в обоих скетчах
Нет данных от Uno к ESP32Разный размер структуры (5 и 6 байт)Используй типы фиксированного размера и __attribute__((packed))
write() возвращает false, но приёмник данные получаетACK приёмника не доходит до передатчика, обычно из-за питания приёмникаДобавь конденсатор 10 µF и на модуль приёмника
На экране постоянно пустые или мусорные данныеПлохо сидящий провод SPI или оборванное соединение MISOЗамени провода и снизь скорость SPI до 4 MHz
Рядом не работает, а если разнести — работаетПриёмник перегружен на полной мощностиИспользуй setPALevel(RF24_PA_LOW) или RF24_PA_MIN
Работает лучше, если потрогатьНестабильное питание или неэкранированный PA+LNAКонденсатор, отдельный стабилизатор и экранирование фольгой
Связь пропадает через несколько метровСкорость 2 Mbps, слабое питание или помехи от Wi-Fi250 kbps, чистое питание, канал от 74 до 83
При поиске неисправности всегда возвращайся к самой простой конфигурации: два модуля в 1–2 метрах друг от друга, RF24_PA_LOW, 250 kbps, короткие провода и конденсатор 10 µF. Когда в такой конфигурации связь есть, постепенно увеличивай расстояние, мощность и сложность кода — так сразу увидишь, на каком шаге начинается проблема.

Идеи проектов с nRF24L01

  • Беспроводной пульт для робот-машинки: управляй робот-машинкой с расстояния в десятки метров пультом с двумя джойстиками.
  • Садовая станция датчиков: отправляй данные датчика влажности почвы и температуры с передатчика на батарейках на дисплей в доме. С radio.powerDown() модуль во сне потребляет около 900 nA; время работы от батареи можно прикинуть утилитой «Время работы от батареи».
  • Беспроводная сигнализация двери и движения: включай зуммер на хабе, когда срабатывает PIR-датчик или геркон.
  • Температурная сеть на несколько комнат: собирай показания датчиков из шести комнат на одном приёмнике по шести трубам.
  • Шлюз на ESP32: пересылай данные с узлов nRF24L01 в интернет, на телефон или на панель мониторинга через ESP32.
  • Беспроводное табло: обновляй 7-сегментное табло в спортзале с пультов с кнопками.

Несмотря на низкую цену, nRF24L01 по сравнению с Bluetooth даёт большую дальность, меньшую задержку и поддержку многих устройств; взамен он требует лишь чистого питания 3,3 V и одинаковых настроек с обеих сторон. Если нужно управление с телефона, лучше подойдёт Bluetooth-модуль HC-05, а для дальности в километры — LoRa; сравнение вариантов — в статье Модули беспроводной связи для Arduino. В приложении BlueGrays есть проекты вроде связи между двумя Arduino, управления сервоприводом и светодиодом с джойстика и машинки с дистанционным управлением — пошагово, со схемами и готовым кодом.

Частые вопросы

Какая дальность у nRF24L01?

Стандартный nRF24L01+ с печатной антенной на 250 kbps достаёт примерно на 50–100 метров на открытом пространстве и на 10–30 метров в помещении в зависимости от стен. Версия nRF24L01+PA+LNA с внешней антенной на открытом пространстве без препятствий может достать на 800–1100 метров. Чтобы получить такие цифры, нужны чистое питание 3,3 V, конденсатор 10 µF и низкая скорость передачи.

Может ли nRF24L01 работать от 5V?

Нет. Пин VCC работает в пределах от 1,9 до 3,6 V, и 5 V могут уничтожить чип. Зато входные пины CE, CSN, SCK и MOSI выдерживают 5 V, поэтому их можно подключать к пинам SPI у Arduino Uno без преобразователя уровней. Если хочешь питать модуль от 5 V, используй плату-адаптер со стабилизатором AMS1117-3.3.

Почему появляется ошибка «radio hardware is not responding»?

Это сообщение выводится, когда radio.begin() возвращает false, и означает, что Arduino не может общаться с модулем по SPI. Самые частые причины — перепутанные MOSI и MISO, пины CE и CSN, не совпадающие с кодом, слабое питание или питание 5 V и болтающиеся перемычки. Проверь подключение и посмотри вывод printPrettyDetails(), чтобы сузить круг поиска.

nRF24L01 или Bluetooth HC-05: что выбрать?

Если между Arduino нужны большая дальность, малая задержка и несколько устройств, лучший выбор — nRF24L01. Если хочешь управлять с телефона, выбирай Bluetooth-модуль вроде HC-05 или ESP32, ведь телефоны не понимают протокол nRF24L01. HC-05 обычно достаёт примерно на 10 метров, а nRF24L01 за сопоставимую цену — гораздо дальше.

Сколько передатчиков может слушать один приёмник nRF24L01?

Приёмник может одновременно слушать 6 труб, так что напрямую собирает данные с 6 передатчиков. Трубы 2–5 делят основную часть адреса трубы 1 и отличаются лишь одним байтом. Для большего числа узлов можно опрашивать передатчики по очереди или строить гораздо более крупные сети с библиотеками RF24Network и RF24Mesh.

Можно ли подключить nRF24L01 к телефону?

Напрямую нет. Хотя nRF24L01 работает в том же диапазоне 2,4 GHz, он не использует протоколы Wi-Fi или Bluetooth. Если нужно управление с телефона, поставь в центр сети nRF24L01 плату ESP32 и передавай данные на телефон по Wi-Fi или Bluetooth. Тогда удалённые узлы общаются по nRF24L01, а телефон — с ESP32.

Все проекты
Односторонняя связь между двумя Arduino
#57Средний
Premium

Односторонняя связь между двумя Arduino

Ты заставляешь две Arduino разговаривать по одному проводу: нажми кнопку на одной, и на другой загорится светодиод, нажми снова — погаснет. Плата-передатчик сообщает о нажатии кнопки коротким сообщени

4.4(37)
50
Двусторонняя связь между двумя Arduino
#58Средний
Premium

Двусторонняя связь между двумя Arduino

Две Arduino соединены проводами и разговаривают друг с другом: нажми кнопку на одной, и на другой загорится свет, нажми снова — погаснет. На обеих платах одна и та же программа, поэтому каждая и отпра

4.5(20)
26
Управление светодиодами джойстиком
#59Средний
Premium

Управление светодиодами джойстиком

Наклони рычажок джойстика до упора в любую сторону, и загорится светодиод этого направления: вправо, влево, вверх и вниз — четыре разных цвета. Отпусти рычажок, он вернётся в центр, и все светодиоды п

4.7(50)
67
Управление сервоприводом джойстиком
#60Средний
Premium

Управление сервоприводом джойстиком

Управляй двумя моторами джойстиком, как будто поворачиваешь камеру наблюдения. Наклони рычажок влево или вправо, и нижний сервопривод медленно поворачивается, наклони вверх или вниз — верхний сервопри

4.7(42)
58
Машинка на L298N с управлением по Bluetooth
#80Продвинутый
Premium

Машинка на L298N с управлением по Bluetooth

Преврати телефон в пульт и управляй своей машинкой-роботом. Arduino получает команды из приложения-пульта на телефоне через Bluetooth-модуль и вращает колёса через драйвер моторов; машинка едет вперёд

5.0(38)
65
Управление светодиодом с телефона по Bluetooth
#34Новичок
Premium

Управление светодиодом с телефона по Bluetooth

Небольшая репетиция того, как включать и выключать свет в комнате с телефона. Bluetooth-модуль передаёт в Arduino буквы, отправленные с телефона; одна буква включает красный светодиод, другая — зелёны

4.8(68)
89
Включение светодиода ИК-приёмником и пультом
#17Средний
Premium

Включение светодиода ИК-приёмником и пультом

Как будто управляешь тремя отдельными лампами, не вставая с кресла: клавиши 1, 2 и 3 на пульте включают синий, красный и зелёный светодиоды, а клавиши 4, 5 и 6 выключают их в том же порядке. Клавиша п

4.7(45)
66
Универсальный ИК-пульт на ESP32 (ИК-приёмник + пульт + 3 светодиода + зуммер + OLED)
#143Продвинутый
Premium

Универсальный ИК-пульт на ESP32 (ИК-приёмник + пульт + 3 светодиода + зуммер + OLED)

С ESP32 можно читать обычный ИК-пульт и управлять с него своим устройством! В этом проекте инфракрасный приёмник (протокол NEC, 38 kHz) ловит сигналы 20-кнопочного ИК-пульта. Каждой кнопке задано своё действие: кнопки 1, 2 и 3 переключают три отдельных светодиода, кнопка PWR выключает все, а цифры 4–9 показывают на OLED особые символы. OLED-дисплей SSD1306 крупно показывает последнюю нажатую кнопку и описание действия.

4.5(9)
16