Как работает беспроводной модуль nRF24L01+ и его подключение к Arduino

Как работает беспроводной модуль nRF24L01+ и его подключение к Arduino

Представьте, что два или более Arduino могут общаться друг с другом по беспроводной связи! Это открывает целый мир захватывающих возможностей — вы можете удалённо отслеживать показания датчиков, управлять роботами на расстоянии, автоматизировать свой дом и многое другое.

Если вы ищете надёжное и в то же время доступное решение для беспроводной связи, трансивер nRF24L01+ выделяется как отличный выбор. Лучшая часть? Эти модули стоят менее двух долларов в интернете, что делает их одним из самых бюджетных вариантов беспроводной связи для ваших проектов.

В этом руководстве мы проведём вас через настройку модуля nRF24L01+ с Arduino на трёх практических примерах:

  • Сначала мы создадим простую систему односторонней связи, где один Arduino отправляет простое сообщение другому Arduino.

  • Затем мы научимся передавать несколько фрагментов информации (таких как температура, влажность и давление) в одном пакете — идеально подходит для таких проектов, как метеостанции.

  • Наконец, мы рассмотрим двустороннюю связь, где два Arduino могут одновременно отправлять и получать данные — прямо как рация!

Готовы заставить ваши Arduino общаться друг с другом по беспроводной связи? Давайте начнём!

Обзор оборудования

Давайте сначала подробнее рассмотрим оборудование.

nRF24L01+ — это бюджетное одночиповое беспроводное устройство, которое отправляет и принимает радиосигналы на небольших расстояниях. Оно работает в диапазоне частот 2,4–2,5 ГГц (тот же диапазон, что используется WiFi и Bluetooth) и не требует никакой специальной лицензии для использования. Этот маленький модуль может передавать данные на разных скоростях: 250 кбит/с, 1 Мбит/с или 2 Мбит/с.

Вам нужно питать nRF24L01+ напряжением от 1,9 до 3,9 вольт. Будьте осторожны! Использование 5 вольт, вероятно, повредит модуль. Однако его логические выводы толерантны к 5 вольтам, что означает, что вы можете подключить его напрямую к 5-вольтовому микроконтроллеру, такому как Arduino, без необходимости использования преобразователя уровней.

Модуль позволяет регулировать мощность передачи на четырёх разных уровнях: 0 дБм, -6 дБм, -12 дБм или -18 дБм. При максимальной мощности передачи (0 дБм) он потребляет всего 12 мА тока — это меньше, чем потребляет один светодиод! Более того, когда модуль не передаёт данные, он потребляет крайне мало энергии: всего 22 мкА в режиме ожидания и крошечные 900 нА в режиме отключения. Это сверхнизкое энергопотребление делает его идеальным для проектов с батарейным питанием.

nRF24L01+ подключается к микроконтроллерам через 4-контактный интерфейс SPI и может передавать данные на скоростях до 10 Мбит/с.

На открытых пространствах без препятствий стандартная версия (с печатной антенной на плате) может обеспечивать связь на расстояниях около 50–100 метров (150–300 футов), особенно при использовании более низких скоростей передачи данных. Если вам нужна большая дальность, существуют специальные версии с усилителями мощности и внешними антеннами, которые могут достигать до 1000 метров (или 1 километра, что составляет около 0,6 мили) при наличии прямой видимости между устройствами.

Технические характеристики

Вот технические характеристики:

Диапазон частот

2.4 GHz ISM Band

Максимальная скорость передачи данных

2 Mb/s

Формат модуляции

GFSK

Макс. выходная мощность

0 dBm

Рабочее напряжение питания

1.9 V to 3.6 V

Макс. рабочий ток

13.5mA

Мин. ток (режим ожидания)

26µA

Логические входы

Толерантны к 5V

Дальность связи

800+ m (прямая видимость)

Для получения дополнительной информации обратитесь к техническому описанию ниже.

Модуль nRF24L01+ и модуль nRF24L01+ PA/LNA

nRF24L01+ выпускается в двух различных версиях, которые вы можете выбрать.

Первая версия имеет антенну, встроенную прямо в печатную плату. Это делает модуль компактным, но меньшая антенна означает меньшую дальность связи. С этой версией вы можете отправлять и получать сигналы на расстоянии до 100 метров при использовании на открытом воздухе без препятствий. Внутри зданий дальность уменьшается ещё больше, потому что стены и мебель могут блокировать часть сигнала.

Как работает беспроводной модуль nRF24L01+ и его подключение к Arduino

Вторая версия выглядит иначе, потому что имеет разъём SMA с внешней антенной. Но это не единственное отличие — эта версия также включает микросхему расширения дальности RFX2401C. Эта специальная микросхема объединяет усилитель мощности (PA), малошумящий усилитель (LNA) и схему переключения приём-передача. Благодаря этим улучшениям данная версия может передавать сигналы на гораздо большие расстояния — до 1000 метров!

Как работает беспроводной модуль nRF24L01+ и его подключение к Arduino

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

Итак, что именно такое PA и LNA?

PA означает Power Amplifier (усилитель мощности), и он делает именно то, что следует из названия — усиливает мощность сигнала, отправляемого чипом nRF24L01+. Это делает сигнал сильнее и помогает ему распространяться на большие расстояния.

LNA означает Low-Noise Amplifier (малошумящий усилитель), и он работает на приёмной стороне. Когда очень слабый сигнал (иногда всего несколько микровольт) приходит через антенну, LNA усиливает его до более сильного уровня (примерно от полвольта до одного вольта), с которым может работать остальная схема. Часть «малошумящий» важна, потому что это означает, что усилитель усиливает сигнал, не добавляя много статики или помех.

С обоими этими усилителями, работающими вместе, модуль может обеспечивать связь на гораздо больших расстояниях, чем базовая версия.

Как работает модуль nRF24L01+?

Частота RF-канала

Модуль nRF24L01+ осуществляет связь, отправляя и получая данные на определённых частотах, называемых каналами. Чтобы эти модули могли общаться друг с другом, они должны быть настроены на один и тот же канал. Эти каналы могут находиться в диапазоне от 2,400 до 2,525 ГГц (или от 2400 до 2525 МГц).

Каждый канал занимает около 1 МГц пространства в радиоспектре. При полном диапазоне в 125 МГц это даёт нам 125 различных возможных каналов с интервалом в 1 МГц.

Как работает беспроводной модуль nRF24L01+ и его подключение к Arduino

Это означает, что вы можете иметь 125 отдельных групп модулей nRF24L01+, работающих в одной зоне, не мешая друг другу, поскольку каждая группа будет использовать свой собственный канал.

Сеть Multiceiver nRF24L01+

nRF24L01+ имеет специальную функцию, называемую «Multiceiver» — что означает «Несколько передатчиков, один приёмник».

В этой конфигурации каждый RF-канал логически разделён на шесть отдельных каналов данных, называемых «конвейерами данных» (data pipes). Каждый конвейер данных имеет свой уникальный адрес, и только один конвейер может принимать данные одновременно.

Это означает, что один модуль может одновременно общаться с до 6 другими модулями на одном RF-канале.

Как работает беспроводной модуль nRF24L01+ и его подключение к Arduino

Представьте сеть Multiceiver как учителя (приёмник), который может слушать вопросы от шести разных учеников (передатчиков). Учитель может отвечать только одному ученику за раз, но может слышать всех шестерых.

Протокол Enhanced ShockBurst

nRF24L01+ использует специальный протокол связи под названием Enhanced ShockBurst™. Этот протокол помогает обеспечить правильную доставку сообщений благодаря:

  • Буферизации пакетов данных (временное хранение пакетов перед обработкой)

  • Подтверждению полученных пакетов (чтобы отправитель знал, что сообщение было получено)

  • Автоматической повторной отправке потерянных пакетов (для обеспечения надёжной связи)

Эти функции делают беспроводную связь более надёжной, особенно на больших расстояниях. Это также упрощает задачу для микроконтроллеров (таких как Arduino), поскольку им не нужно самим обрабатывать все эти операции.

Распиновка модуля nRF24L01+

Давайте рассмотрим распиновку модуля беспроводной связи nRF24L01+. Каждый вывод имеет определённое назначение, которое помогает модулю взаимодействовать с вашим Arduino:

Как работает беспроводной модуль nRF24L01+ и его подключение к Arduino Как работает беспроводной модуль nRF24L01+ и его подключение к Arduino

GND — это вывод заземления. Вы можете определить его по квадратной маркировке, которая отличает его от остальных выводов.

VCC — вывод питания модуля. Для его работы требуется напряжение от 1,9 до 3,9 вольт. Подключите его к выходу 3.3V на вашем Arduino. Никогда не подключайте его к выводу 5V, иначе вы можете повредить модуль!

CE (Chip Enable) — это активный высокий вывод. Он действует как переключатель включения/выключения модуля. Когда вы устанавливаете его в HIGH, модуль становится активным и может отправлять или получать данные (в зависимости от конфигурации). Когда вы устанавливаете его в LOW, модуль переходит в режим ожидания для экономии энергии.

CSN (Chip Select Not) — это активный низкий вывод. Обычно он поддерживается в состоянии HIGH, но когда вы хотите, чтобы Arduino общался с модулем, вы устанавливаете его в LOW. Это особенно важно, когда к вашему Arduino подключено несколько устройств SPI.

SCK (Serial Clock) — вывод, принимающий тактовые импульсы SPI от вашего Arduino. Эти тактовые импульсы помогают синхронизировать передачу данных.

MOSI (Master Out Slave In) — вход SPI на nRF24L01 от Arduino.

MISO (Master In Slave Out) — выход SPI от nRF24L01 обратно к Arduino.

IRQ (Interrupt Request) — активный низкий выход прерывания. Этот вывод уведомляет ваш Arduino о важных событиях, например, когда данные получены или отправлены. Модуль сигнализирует об этом, кратковременно устанавливая вывод в LOW. Многие простые проекты не используют этот вывод, поэтому вы можете оставить его неподключённым, если не планируете обрабатывать прерывания.

Схема подключения модуля nRF24L01+ к Arduino

Теперь, когда мы понимаем, как работает модуль nRF24L01+, давайте подключим его к Arduino.

Сначала подключите вывод VCC модуля к 3.3V Arduino, а вывод GND — к земле Arduino. Важно: не подключайте его к 5V, так как этот модуль работает от 3.3V и может быть повреждён более высоким напряжением.

Выводы CSN и CE могут быть подключены к любому цифровому выводу вашего Arduino — в нашем примере мы будем использовать цифровой вывод #8 для CSN и цифровой вывод #9 для CE.

Далее мы подключим выводы, используемые для связи по SPI. Поскольку модуль nRF24L01+ требует быстрой передачи данных, лучше всего подключить его к аппаратным выводам SPI на вашем Arduino. Для плат Arduino, таких как UNO или Nano V3.0, эти выводы следующие: цифровой 13 (SCK), 12 (MISO), 11 (MOSI) и 10 (CS).

Если вы используете другую плату Arduino, обязательно проверьте официальную документацию Arduino, чтобы найти правильные аппаратные выводы SPI для вашей конкретной платы.

Для удобства понимания вот таблица, обобщающая подключения выводов:

nRF24L01+ moduleArduino
GNDGND
VCC3.3V
CE9
CSN8
SCK13
MOSI11
MISO12

На изображениях ниже показано, как собрать схему.

Как работает беспроводной модуль nRF24L01+ и его подключение к Arduino Как работает беспроводной модуль nRF24L01+ и его подключение к Arduino

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

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

Для работы с модулем nRF24L01+ доступно множество библиотек, но одной из самых популярных и широко используемых является RF24.

Эта библиотека существует уже давно и проста в использовании, что делает её идеальной для начинающих. В то же время она также предлагает расширенные функции для более опытных пользователей. Благодаря своей гибкости и надёжности мы будем использовать библиотеку RF24 в наших примерах.

Для установки библиотеки:

  1. Сначала откройте программу Arduino IDE. Затем нажмите на значок Менеджер библиотек на левой боковой панели.

  2. Введите «rf24» в поле поиска для фильтрации результатов.

  3. Найдите библиотеку, созданную TmRh20.

  4. Нажмите кнопку Install, чтобы добавить её в Arduino IDE.

Как работает беспроводной модуль nRF24L01+ и его подключение к Arduino

После установки библиотеки настройка завершена! Теперь вы готовы начать писать код и экспериментировать с беспроводной связью с помощью модуля nRF24L01+!

Пример 1 для Arduino — простая односторонняя связь

В этом примере мы настроим базовую одностороннюю линию связи между передатчиком и приёмником. Передатчик будет непрерывно отправлять классическое сообщение «Hello World», а приёмник слушает эти сообщения и отображает их в мониторе последовательного порта.

Код для передатчика

Вот код, который мы будем использовать для нашего передатчика.

//Include Libraries
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

// Define pins
#define CE_PIN 9
#define CSN_PIN 8

// Create RF24 radio object
RF24 radio(CE_PIN, CSN_PIN);

//address through which two modules communicate.
const byte address[6] = "00001";

void setup() {
  while (!Serial)
    ;
  Serial.begin(9600);

  radio.begin();

  //set the address
  radio.openWritingPipe(address);

  //Set module as transmitter
  radio.stopListening();
}
void loop() {
  //Send message to receiver
  const char text[] = "Hello World";
  radio.write(&text, sizeof(text));

  Serial.print("Data sent: ");
  Serial.println(text);

  delay(1000);
}

Объяснение кода

Скетч начинается с подключения необходимых библиотек. Библиотека SPI.h обеспечивает связь по SPI, а библиотеки nRF24L01.h и RF24.h управляют модулем.

//Include Libraries
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

Далее мы создаём объект RF24. Конструктор этого объекта принимает два номера выводов в качестве аргументов, к которым подключены сигналы CE и CSN.

//create an RF24 object
RF24 radio(9, 8);  // CE, CSN

Затем мы создаём байтовый массив для хранения адреса конвейера, используемого двумя модулями nRF24L01+ для связи.

//address through which two modules communicate.
const byte address[6] = "00001";

Адрес конвейера не обязательно должен быть «00001» — это может быть любая строка из 5 символов, например «node1». Просто убедитесь, что и передатчик, и приёмник используют один и тот же адрес.

С помощью адреса конвейера вы можете выбрать конкретный модуль в вашей сети и общаться с ним. Это полезно, если ваша сеть содержит несколько модулей.

В секции setup мы используем функцию begin() для инициализации объекта radio, а затем функцию openWritingPipe() для установки адреса передатчика.

radio.begin();

//set the address
radio.openWritingPipe(address);

Наконец, мы используем функцию stopListening() для установки модуля в режим передатчика.

//Set module as transmitter
radio.stopListening();

В секции loop мы сначала создаём массив символов и сохраняем в нём сообщение «Hello world».

Мы используем функцию write() для отправки сообщения приёмнику. Эта функция принимает два аргумента: сообщение для отправки и количество байтов, которое оно содержит.

const char text[] = "Hello World";
radio.write(&text, sizeof(text));

Важно отметить, что вы можете отправлять сообщения длиной до 32 байт, так как это максимальный размер пакета, который может обработать nRF24L01+.

Функция write() возвращает значение типа bool, которое вы можете использовать для проверки того, были ли данные правильно получены приёмником. Когда данные достигают приёмника, возвращается TRUE; в противном случае возвращается FALSE.

Также важно отметить, что функция write() останавливает выполнение программы до тех пор, пока не получит подтверждение или не исчерпает все попытки повторной передачи.

Код для приёмника

Вот код, который мы будем использовать для нашего приёмника.

//Include Libraries
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

// Define pins
#define CE_PIN 9
#define CSN_PIN 8

// Create RF24 radio object
RF24 radio(CE_PIN, CSN_PIN);

//address through which two modules communicate.
const byte address[6] = "00001";

void setup()
{
  while (!Serial);
    Serial.begin(9600);

  radio.begin();

  //set the address
  radio.openReadingPipe(0, address);

  //Set module as receiver
  radio.startListening();
}

void loop()
{
  //Read the data if available in buffer
  if (radio.available())
  {
    char text[32] = {0};
    radio.read(&text, sizeof(text));
    Serial.print("Data received: ");
    Serial.println(text);
  }
}

Объяснение кода

За исключением нескольких изменений, этот код очень похож на код передатчика.

В начале функции setup мы инициируем последовательную связь. Затем, используя функцию openReadingPipe(), мы устанавливаем тот же адрес конвейера, что и у передатчика. Это позволяет передатчику и приёмнику общаться друг с другом.

Первый аргумент функции openReadingPipe() указывает, какой конвейер открыть для чтения. Поскольку одновременно можно открыть до шести конвейеров для чтения, допустимый диапазон составляет 0–5. В нашем случае для чтения был открыт конвейер 0. Второй аргумент — это 40-битный адрес открываемого конвейера.

//set the address
  radio.openReadingPipe(0, address);

После этого мы настраиваем модуль как приёмник и начинаем приём данных. Для этого мы используем функцию startListening().

//Set module as receiver
  radio.startListening();

Метод available() используется в секции loop для проверки, доступны ли данные для чтения. Этот метод возвращает TRUE, если данные доступны, и FALSE в противном случае.

if (radio.available())
  {
    char text[32] = {0};
    radio.read(&text, sizeof(text));
    Serial.println(text);
  }

Когда данные доступны, создаётся массив из 32 символов, заполненный нулями, для их хранения. Затем данные считываются из буфера и сохраняются в нашем символьном массиве с помощью метода read(&text, sizeof(text)).

Наконец, полученное сообщение выводится в монитор последовательного порта.

Демонстрация

После загрузки скетча на ваши платы Arduino вы должны увидеть следующее:

Как работает беспроводной модуль nRF24L01+ и его подключение к Arduino

Пример 2 для Arduino — отправка нескольких фрагментов информации одновременно

В нашем первом примере мы отправляли только простое текстовое сообщение от передатчика к приёмнику. Однако во многих проектах вам может потребоваться отправлять несколько фрагментов информации одновременно.

Например, представьте, что вы создаёте систему мониторинга погоды. У вас есть датчик DHT11 (температура-влажность), подключённый к передатчику, и вы хотите отправить данные о температуре и влажности приёмнику в одной передаче. Вместо того чтобы отправлять их по отдельности, мы можем упаковать оба значения в один пакет данных и отправить их вместе. Этот пример покажет вам, как именно это сделать.

Схема подключения

Разводка аналогична первому примеру, но мы добавляем датчик DHT11 на сторону передатчика.

Подключите вывод VCC датчика DHT11 к выводу 5V на Arduino и подключите вывод GND к любому выводу GND на Arduino. Подключите вывод Data к цифровому выводу #2 на Arduino. Вам также нужно добавить подтягивающий резистор 10K между выводом Data и выводом VCC. Однако, если у вас DHT11 на отладочной плате, резистор уже встроен, и вы можете пропустить этот шаг.

Как работает беспроводной модуль nRF24L01+ и его подключение к Arduino

Arduino #1

Как работает беспроводной модуль nRF24L01+ и его подключение к Arduino

Arduino #2

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

Для связи с DHT11 мы будем использовать библиотеку DHTlib, поэтому убедитесь, что вы установили её перед продолжением.

Для установки библиотеки:

  • Сначала откройте программу Arduino IDE. Затем нажмите на значок Менеджер библиотек на левой боковой панели.

  • Введите «dhtlib» в поле поиска для фильтрации результатов.

  • Найдите библиотеку «DHTlib», созданную Rob Tillaart.

  • Нажмите кнопку Install, чтобы добавить её в Arduino IDE.

Как работает беспроводной модуль nRF24L01+ и его подключение к Arduino

Код для передатчика

Вот код, который мы будем использовать для нашего передатчика.

//Include Libraries
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <dht.h>

// Define pins
#define CE_PIN 9
#define CSN_PIN 8
#define DHTPin 2

// Create RF24 radio object
RF24 radio(CE_PIN, CSN_PIN);

// Create DHT object
dht DHT;

// Struct for transmitting data
struct SensorData {
  float temperature;
  float humidity;
};

// Create a variable with the above structure
SensorData data;

//address through which two modules communicate.
const byte address[6] = "00001";

void setup()
{
  while (!Serial);
    Serial.begin(9600);

  radio.begin();

  //set the address
  radio.openWritingPipe(address);

  //Set module as transmitter
  radio.stopListening();
}
void loop()
{
  // Read DHT sensor
  DHT.read11(DHTPin);

  data.humidity = DHT.humidity;
  data.temperature = DHT.temperature;

  Serial.print("Sending Data - Temperature: ");
  Serial.print(data.temperature);
  Serial.print("°C, Humidity: ");
  Serial.print(data.humidity);
  Serial.println("%");

  //Send message to receiver
  radio.write(&data, sizeof(data));

  delay(1000);
}

Код для приёмника

Вот код, который мы будем использовать для нашего приёмника.

//Include Libraries
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

// Define pins
#define CE_PIN 9
#define CSN_PIN 8

// Create RF24 radio object
RF24 radio(CE_PIN, CSN_PIN);

// Struct for receiving data
struct SensorData {
  float temperature;
  float humidity;
};

//address through which two modules communicate.
const byte address[6] = "00001";

void setup()
{
  while (!Serial);
    Serial.begin(9600);

  radio.begin();

  //set the address
  radio.openReadingPipe(0, address);

  //Set module as receiver
  radio.startListening();
}

void loop()
{
  //Read the data if available in buffer
  if (radio.available())
  {
    SensorData receivedData;
    radio.read(&receivedData, sizeof(receivedData));

    Serial.print("Received Data - Temperature: ");
    Serial.print(receivedData.temperature);
    Serial.print("°C, Humidity: ");
    Serial.print(receivedData.humidity);
    Serial.println("%");
  }
}

Объяснение кода

Этот скетч аналогичен предыдущему. Однако есть несколько ключевых отличий.

Помимо библиотек SPI, nRF24L01 и RF24, нам также нужно подключить библиотеку DHT для чтения значений температуры и влажности.

#include <DHT.h>  // Library for DHT sensor

Поскольку мы отправляем несколько значений (температуру и влажность), мы не можем отправить простую текстовую строку, как в предыдущем примере. Вместо этого нам нужен способ хранить оба значения вместе. Именно здесь на помощь приходит struct.

Struct (структура) — это пользовательский тип данных, который позволяет группировать связанные переменные потенциально разных типов в единое целое.

В нашем примере мы создаём структуру с именем SensorData для группировки температуры и влажности в единое целое. Оба значения имеют тип float, но вы также можете использовать другие типы данных, такие как bool, int или string.

struct SensorData {
  float temperature;
  float humidity;
};

Далее мы создаём переменную с использованием структуры SensorData.

SensorData data;

В той же глобальной области мы также инициализируем датчик DHT11.

#define DHTPin 2
dht DHT;

Теперь внутри loop() мы считываем значения влажности и температуры с датчика DHT11 и сохраняем их в структурной переменной data. Это гарантирует, что оба значения захвачены и организованы в единое целое.

Обратите внимание, что мы обращаемся к членам структуры с помощью оператора точки (.).

DHT.read11(DHTPin);

data.humidity = DHT.humidity;
data.temperature = DHT.temperature;

Затем мы отправляем всю структуру, включая оба значения.

radio.write(&data, sizeof(data));

На стороне приёмника мы получаем структуру SensorData и извлекаем значения.

SensorData receivedData;
radio.read(&receivedData, sizeof(receivedData));

Наконец, мы выводим полученные значения температуры и влажности по отдельности.

Serial.print("Received Data - Temperature: ");
Serial.print(receivedData.temperature);
Serial.print("°C, Humidity: ");
Serial.print(receivedData.humidity);
Serial.println("%");

Демонстрация

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

Как работает беспроводной модуль nRF24L01+ и его подключение к Arduino

Пример 3 для Arduino — двусторонняя связь

Иногда вы можете захотеть, чтобы два устройства обменивались данными в обоих направлениях, а не просто одно отправляло данные, а другое принимало. Такая конфигурация похожа на рации, где оба устройства могут отправлять и получать сообщения.

В этом примере мы настроим двустороннюю связь между двумя платами Arduino. Каждая плата будет иметь кнопку и светодиод.

Когда вы нажимаете кнопку на одном Arduino, это переключает светодиод на другом Arduino. Аналогично, нажатие кнопки на втором Arduino будет управлять светодиодом на первом Arduino. Таким образом, оба устройства могут отправлять и получать данные.

Схема подключения

Разводка аналогична первому примеру, но мы добавим кнопку и светодиод к каждой схеме.

Подключите одну сторону кнопки к выводу #2, а другую сторону к GND. Мы будем использовать внутренний подтягивающий резистор Arduino, поэтому нам не нужно добавлять внешний резистор.

Для светодиода подключите длинную ножку (анод) к выводу #3 через токоограничительный резистор 220 Ом, а короткую ножку (катод) — к GND.

Как работает беспроводной модуль nRF24L01+ и его подключение к Arduino

Arduino #1

Как работает беспроводной модуль nRF24L01+ и его подключение к Arduino

Arduino #2

Код Arduino

Теперь загрузите один и тот же код на обе платы Arduino. Это потому, что, в отличие от предыдущих примеров, оба Arduino могут отправлять и получать данные. Поэтому вместо написания двух разных программ — одной для отправки и одной для приёма — нам нужен только один скетч, который выполняет обе задачи!

//Include Libraries
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

// Define pins
#define CE_PIN 9
#define CSN_PIN 8
#define SWITCH_PIN 2
#define LED_PIN 3

// Create RF24 radio object
RF24 radio(CE_PIN, CSN_PIN);

//address through which two modules communicate.
const byte address[6] = "00001";

int ledState = HIGH;          // the current state of the output pin
int buttonState;              // the current reading from the input pin
bool lastButtonState = HIGH;  // the previous reading from the input pin

unsigned long lastDebounceTime = 0;      // the last time the output pin was toggled
const unsigned long debounceDelay = 50;  // the debounce time

void setup() {
  pinMode(SWITCH_PIN, INPUT_PULLUP);
  pinMode(LED_PIN, OUTPUT);

  Serial.begin(9600);

  radio.begin();

  //set the address
  radio.openWritingPipe(address);
  radio.openReadingPipe(1, address);

  //Set module as receiver
  radio.startListening();
}
void loop() {
  // Debounce the switch
  bool reading = digitalRead(SWITCH_PIN);
  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {

    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;

      // only toggle the LED if the new button state is HIGH
      if (buttonState == HIGH) {
        ledState = !ledState;  // Toggle LED state

        radio.stopListening();  // Stop listening to send data
        radio.write(&ledState, sizeof(ledState));
        radio.startListening();  // Resume listening

        Serial.print("Data sent: ");
        Serial.println(ledState);
      }
    }
  }

  lastButtonState = reading;

  if (radio.available()) {
    bool receivedState;
    radio.read(&receivedState, sizeof(receivedState));

    digitalWrite(LED_PIN, receivedState ? HIGH : LOW);

    Serial.print("Data received: ");
    Serial.println(receivedState);
  }
}

Демонстрация

После загрузки скетча на ваши платы Arduino связь начинается! Теперь, когда вы нажимаете кнопку на одном Arduino, это переключает светодиод на другом Arduino. Аналогично, нажатие кнопки на втором Arduino будет управлять светодиодом на первом Arduino.

Кроме того, вы сможете видеть передаваемые и получаемые данные в реальном времени в мониторе последовательного порта, что даёт вам ясное представление о том, как два Arduino общаются по беспроводной связи.

Как работает беспроводной модуль nRF24L01+ и его подключение к Arduino

Объяснение кода

Как и в предыдущих примерах, мы начинаем с подключения необходимых библиотек, которые позволяют Arduino взаимодействовать с модулем nRF24L01. Затем мы определяем, какие выводы используются для подключения радиомодуля (CE_PIN и CSN_PIN), кнопки (SWITCH_PIN) и светодиода (LED_PIN).

//Include Libraries
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

// Define pins
#define CE_PIN 9
#define CSN_PIN 8
#define SWITCH_PIN 2
#define LED_PIN 3

Далее мы создаём объект RF24, который будем использовать для отправки и получения сообщений через радиомодуль.

// Create RF24 radio object
RF24 radio(CE_PIN, CSN_PIN);

Мы также создаём байтовый массив для хранения адреса конвейера. Этот адрес используется для настройки канала связи, и оба Arduino должны использовать один и тот же адрес, чтобы знать, куда отправлять и откуда получать сообщения.

//address through which two modules communicate.
const byte address[6] = "00001";

После этого мы настраиваем несколько переменных для управления светодиодом и кнопкой. Переменная ledState отслеживает, должен ли светодиод быть включён или выключен. Переменная buttonState хранит текущее состояние кнопки, а lastButtonState — её предыдущее состояние.

Также есть пара переменных, используемых для устранения дребезга кнопки. При нажатии кнопки сигнал может быстро колебаться между включённым и выключенным состоянием, что может сбить Arduino, заставив думать, что кнопка была нажата несколько раз очень быстро. Чтобы избежать этого, мы ждём небольшой промежуток времени перед реакцией. Таким образом, Arduino реагирует только один раз на каждое нажатие.

int ledState = HIGH;          // the current state of the output pin
int buttonState;              // the current reading from the input pin
bool lastButtonState = HIGH;  // the previous reading from the input pin

unsigned long lastDebounceTime = 0;      // the last time the output pin was toggled
const unsigned long debounceDelay = 50;  // the debounce time

В функции setup() мы сначала сообщаем Arduino, какие выводы будут использоваться для ввода и вывода. Кнопка использует режим INPUT_PULLUP, что означает, что она будет находиться в состоянии HIGH по умолчанию, когда не нажата. Вывод светодиода установлен как выход, потому что мы будем его включать и выключать.

pinMode(SWITCH_PIN, INPUT_PULLUP);
pinMode(LED_PIN, OUTPUT);

Далее мы инициализируем радиомодуль и настраиваем его. Мы открываем как «конвейер записи», так и «конвейер чтения», используя один и тот же адрес для обоих. Это настраивает модуль так, что он может отправлять сообщения и также прослушивать входящие сообщения на том же канале.

radio.begin();

//set the address
radio.openWritingPipe(address);
radio.openReadingPipe(1, address);

Наконец, мы указываем радиомодулю начать прослушивание. Это означает, что теперь он готов принимать любые входящие данные.

//Set module as receiver
radio.startListening();

Переходя к функции loop(), мы сначала проверяем, нажата ли кнопка. Мы сравниваем текущее показание с предыдущим и используем таймер устранения дребезга, чтобы убедиться, что это настоящее нажатие, а не просто быстрый дребезг.

Если кнопка действительно была нажата, мы переключаем состояние светодиода — если он был выключен, мы его включаем; если был включён, выключаем.

Прежде чем отправить это новое состояние светодиода, мы на мгновение прекращаем прослушивание. Мы делаем это потому, что модуль не может одновременно прослушивать и отправлять. Мы отправляем обновлённое состояние через радиомодуль другому модулю, а затем сразу возвращаемся в режим прослушивания.

Мы также выводим сообщение о том, какие данные были отправлены, чтобы мы могли видеть их в мониторе последовательного порта.

// Debounce the switch
bool reading = digitalRead(SWITCH_PIN);
if (reading != lastButtonState) {
  lastDebounceTime = millis();
}

if ((millis() - lastDebounceTime) > debounceDelay) {

  // if the button state has changed:
  if (reading != buttonState) {
    buttonState = reading;

    // only toggle the LED if the new button state is HIGH
    if (buttonState == HIGH) {
      ledState = !ledState;  // Toggle LED state

      radio.stopListening();  // Stop listening to send data
      radio.write(&ledState, sizeof(ledState));
      radio.startListening();  // Resume listening

      Serial.print("Data sent: ");
      Serial.println(ledState);
    }
  }
}

lastButtonState = reading;

После этого мы проверяем, были ли получены новые данные от другого модуля. Если мы что-то получили, мы считываем их и соответственно обновляем локальный светодиод. Именно так оба модуля остаются синхронизированными — одно нажатие кнопки на одном Arduino может изменить состояние светодиода на другом.

И снова мы выводим полученные данные, чтобы можно было следить за происходящим в реальном времени.

if (radio.available()) {
  bool receivedState;
  radio.read(&receivedState, sizeof(receivedState));

  digitalWrite(LED_PIN, receivedState ? HIGH : LOW);

  Serial.print("Data received: ");
  Serial.println(receivedState);
}

Способы улучшения дальности модуля nRF24L01+

Ключевым параметром для системы беспроводной связи является дальность связи. Это часто является решающим фактором при выборе RF-решения. Поэтому давайте поговорим о том, что мы можем сделать для увеличения дальности нашего модуля.

Снижение шума источника питания

Схема, генерирующая радиочастотный (RF) сигнал, чрезвычайно чувствительна к шуму источника питания. Шум источника питания, если его не контролировать, может значительно сократить достижимую дальность.

Если источник питания не является автономной батареей, высока вероятность того, что выходное напряжение зашумлено. Для предотвращения проникновения этого шума в систему рекомендуется разместить фильтрующий конденсатор 10 мкФ на линии питания как можно ближе к модулю nRF24L01+.

Самый простой способ снизить шум источника питания — использовать недорогой адаптер для модуля nRF24L01+.

Как работает беспроводной модуль nRF24L01+ и его подключение к Arduino

Этот адаптер имеет 8-контактный разъём, в который можно вставить модуль nRF24L01+. Он подходит для обеих версий модуля nRF24L01+ — как со встроенной антенной, так и с внешней антенной (PA/LNA).

Он также имеет 2-контактный разъём для подачи питания и 6-контактный штыревой разъём для подключения SPI и прерываний.

Поскольку адаптер имеет встроенный стабилизатор напряжения 3.3V и фильтрующие конденсаторы, вы можете безопасно питать его от источника 5V.

Изменение частоты канала

Внешняя среда также может быть источником шума для RF-схем, особенно если соседние сети настроены на тот же канал.

Поскольку WiFi в основном использует каналы на более низких частотах, рекомендуется использовать 25 самых высоких каналов вашего nRF24L01+, чтобы избежать помех от этих сигналов.

Использование более низкой скорости передачи данных

При 250 Кбит/с nRF24L01+ имеет наивысшую чувствительность приёмника -94 дБм. Однако при скорости 2 Мбит/с чувствительность приёмника падает до -82 дБм. То есть при 250 Кбит/с приёмник примерно в десять раз чувствительнее, чем при 2 Мбит/с, что позволяет ему декодировать в десять раз более слабые сигналы.

В результате снижение скорости передачи данных может значительно увеличить достижимую дальность. К тому же скорость 250 Кбит/с достаточна для большинства наших проектов.

Что означает чувствительность приёмника (Rx)?

Чувствительность приёмника — это минимальный уровень мощности, при котором приёмник может обнаружить RF-сигнал. Чем больше абсолютное значение отрицательного числа, тем выше чувствительность приёмника. Например, чувствительность приёмника -94 дБм превосходит чувствительность -82 дБм на 12 дБ.

Использование более высокой выходной мощности

Установка максимальной выходной мощности также может помочь увеличить дальность связи. nRF24L01+ поддерживает несколько уровней выходной мощности, включая 0 дБм, -6 дБм, -12 дБм и -18 дБм. Выбор выходной мощности 0 дБм отправляет более сильные сигналы в эфир, но потребляет больше энергии.