Подключение модуля nRF24L01+ к Raspberry Pi, Orange Pi, Banana Pi …

nRF24L01 один из самых популярных беспроводных модулей для интернета вещей (IoT). Подключив модуль nRF24L01+ к Raspberry Pi, Orange Pi, Banana Pi и т.п можно организовать многоканальную защищенную связь между мини-компьютерами и/или, например, Arduino. Таким образом можно подключить на каждую плату Arduino по датчику и передать полученые данные на, к примеру, Raspberry Pi, а там обрабатывать эти данные и/или загрузить в БД.

Рассмотрим, как установить библиотеку RF24 и как наладить связь между Orange Pi PC (плату можно менять на любую другую типа Raspberry Pi, Orange Pi, Banana Pi и т.п. — будет также работать) и несколько плат Ардуино по радиоканалу.

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

Библиотека RF24 универсальная, её можно установить и использовать как на Arduino, так и на устройства под ОС Linux (Raspberry Pi, Orange Pi, Banana Pi и т.п) поддерживающие SPIDEV, MRAA, RPi BCM2835 или LittleWire. Опция SPIDEV должна работать с большинством систем Linux, поддерживающих SPI.

Описание методов класса RF24 можете найти на странице Подключение модуля nRF24L01+ к Arduino.

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

  1. Установите необходимые компоненты, если они есть (библиотеки MRAA, LittleWire, SPI и т. д.). На Raspberry Pi используется нативная библиотека BCM2835, по этому нужно её установить. Также не забудьте включить SPI на Raspberry Pi, это можно сделать с помощью утилиты raspi-config;
  2. Загрузите файл install.sh с http://tmrh20.github.io/RF24Installer/RPi/install.sh;
    wget http://tmrh20.github.io/RF24Installer/RPi/install.sh
  3. Сделайте это файл исполняемым
    chmod +x install.sh
  4. Запустите его и выберите параметры
    ./install.sh
  5. Запустите пример из одной из библиотек
    cd rf24libs/RF24/examples_linux
  6. Для проверки можете отредактировать пример gettingstarted, чтобы настроить конфигурацию выводов, и запустить его
    nano gettingstarted.cpp
    make  
    sudo ./gettingstarted

Установка библиотеки RF24 на Orange Pi, Banana Pi и др.

Этот метод подойдёт и для установки на Raspberry Pi, и на любой ОС Linux, что поддерживает SPI.

  1. Установите необходимые компоненты, если они есть (библиотеки MRAA, LittleWire, SPI и т. д.). Не забудьте включить SPI, это можно сделать с помощью утилиты armbian-config, более подробно о том, как настроить SPI на Orange Pi, можете найти на странице Включение и настройка SPI (SPI0 и SPI1) на Orange Pi на ядрах 3.4 (Ubuntu 16.04) и 4.14 (Ubuntu 18.04).
  2. Клонируете репозиторий RF24.
    git clone https://github.com/tmrh20/RF24.git RF24
  3. Перейдите в новый каталог RF24.
    cd RF24
  4. Настройте среду сборки, используя скрипт
    ./configure

    Скрипт автоматически определяет устройство и среду сборки. Если хотите вручную настроить, смотрите на список возможностей скрипта:

    ./configure --help
  5. Соберите и установите библиотеку
    sudo make install
  6. Для проверки можете отредактировать пример gettingstarted, чтобы настроить конфигурацию выводов, и запустить его
    nano gettingstarted.cpp
    make  
    sudo ./gettingstarted

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

Подключается nRF24L01+ к Raspberry Pi по шине SPI (можно использовать как аппаратную так и программную шину). Выводы модуля Vcc и GND подключаются к шине питания 3.3 В постоянного тока. Выводы модуля MISO, MOSI, SCK и подключаются к одноименным выводам шины SPI на плате Raspberry Pi.

Вывод CSN (Chip Select nRF24L01+) подключается к выводу CE (Raspberry Pi) шины SPI, CE (Chip Enable) назначается при объявлении объекта библиотеки RF24 и подключаются к любым назначенным выводам Raspberry Pi. Вывод IRQ на NRF24L01+ в данном случае не используется.

Конкретные имена портов интерфейса SPI могут различаться в зависимости от производителя аппаратных средств, при этом возможны следующие варианты:

  • MOSI: SIMO, SDI (на устройстве), DO, DON, SI, MRSR;
  • MISO: SOMI, SDO (на устройстве), DI, DIN, SO, MTST;
  • SCLK: SCK, CLK;
  • SS: nCS, CS, CSB, CSN, nSS, STE, SYNC.

Полное представление о выводах Raspberry Pi см. http://pinout.xyz/. Если установлена библиотека WiringPi, можете воспользоваться командой

gpio readall

для определения назначения всех выводов на плате.
Схема подключения nRF24L01+ к Raspberry Pi - Raspberry Pi gpio readall

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

Подключение nRF24L01+ к Raspberry Pi напрямую

nRF24L01+ Raspberry Pi
GND 6 / GND
VCC 1 / 3.3V
CE 22 / GPIO25
CSN 24 / GPIO8 / SPI_CE0_N
SCK 23 / GPIO11 / SPI0_CLK
MOSI 19 / GPIO10 / SPI0_MOSI
MISO 21 / GPIO9 / SPI0_MISO
IRQ

Подключение nRF24L01+ к Raspberry Pi через адаптер

nRF24L01+ Raspberry Pi
GND 6 / GND
VCC 2 / 5.0V
CE 22 / GPIO25
CSN 24 / GPIO8 / SPI_CE0_N
SCK 23 / GPIO11 / SPI0_CLK
MO / MOSI 19 / GPIO10 / SPI0_MOSI
MI / MISO 21 / GPIO9 / SPI0_MISO
IRQ

Схема подключения nRF24L01+ к Orange Pi, Banana Pi и др.

Как и в случае с Raspberry Pi, подключается nRF24L01+ к Orange Pi по шине SPI. Выводы модуля Vcc и GND подключаются к 3.3 В и GND соответственно. Тоже самое и с выводами MISO, MOSI, SCK и CSN. Единственное отличие в подключении вывода CE (Chip Enable) номер вывода отличается от Raspberry Pi, так как контроллер другой. Если установлена библиотека WiringOP или BPI-WiringPI (для Banana Pi), можете воспользоваться командой

gpio readall

для определения назначения всех выводов на плате Orange Pi или Banana Pi.
Схема подключения nRF24L01+ к Orange Pi - Orange Pi gpio readall

При объявлении объекта библиотеки RF24 нужно указывать номер пина из колонки BCM.

Схема подключения nRF24L01+ к Orange Pi, Banana Pi и др.

Подключение nRF24L01+ к Orange Pi напрямую

nRF24L01+ Orange Pi
GND 6 / GND
VCC 1 / 3.3V
CE 29 / GPIO7
CSN 24 / GPIO67 / SPI_CE0_N
SCK 23 / GPIO66 / SPI0_CLK
MOSI 19 / GPIO64 / SPI0_MOSI
MISO 21 / GPIO65 / SPI0_MISO
IRQ

Подключение nRF24L01+ к Orange Pi через адаптер

nRF24L01+ Orange Pi
GND 6 / GND
VCC 2 / 5.0V
CE 29 / GPIO7
CSN 24 / GPIO67 / SPI_CE0_N
SCK 23 / GPIO66 / SPI0_CLK
MO / MOSI 19 / GPIO64 / SPI0_MOSI
MI / MISO 21 / GPIO65 / SPI0_MISO
IRQ

Примеры

Пример 1: Сканер диапазона 2.4 ГГц на NRF24L01+

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

Ниже приведённый пример представляет собой сканер, с помощью которого можно определить свободные каналы в ISM (Industrial, Scientific, Medical) диапазоне частот от 2400 МГц до 2527 МГц. Данный сканер сможет определять такие устройства как: WiFi, Bluetooth, некоторые радио телефоны, другие модули nRF24L01.

#include <cstdlib>
#include <iostream>
/*
 * Подключаем файл настроек из библиотеки RF24
 */
#include <RF24/nRF24L01.h>
/*
 * Подключаем библиотеку для работы с nRF24L01+
 */
#include <RF24/RF24.h>

using namespace std;

/*
 * Конфигурация оборудования
 */
#define BCM_PIN 7
#define SPI_DEV 0
#define NUM_CHANNELS 126

/*
 * Информация о канале
 */
uint8_t values[NUM_CHANNELS];
const int numReps = 100;

int main() {
  /*
   * Создаём объект radio для работы с библиотекой RF24,
   * указывая номера вывода CE и SPI порта
   */
  RF24 radio(BCM_PIN, SPI_DEV);

  /*
   * Инициируем работу nRF24L01+
   */
  radio.begin();

  radio.setAutoAck(false);

  /*
   * Вход в режиме ожидания
   */
  radio.startListening();
  radio.stopListening();

  /*
   * Дамп конфигурации RF для отладки
   */
  radio.printDetails();

  /*
   * Распечатка заголовка, верхний и нижний разряд
   */
  for (int i = 0; i < NUM_CHANNELS; ++i) {
    printf("%x", i >> 4);
  }
  cout << endl;
  for (int i = 0; i < NUM_CHANNELS; ++i) {
    printf("%x", i & 0xf);
  }
  cout << endl;

  while (1) {
    /*
     * Очистка значений измерений
     */
    memset(values, 0, sizeof(values));

    /*
     * Сканирование всех каналов numReps раз
     */
    for (int k = 0; k < numReps; ++k) {
      for (int i = 0; i < NUM_CHANNELS; ++i) {

        /*
         * Выбор канала
         */
        radio.setChannel(i);

        /*
         * Послушать немного
         */
        radio.startListening();
        delayMicroseconds(128);
        radio.stopListening();

        /*
         * Проверка наличия несущей частоты на выбранном канале (частоте).
         */
        if (radio.testCarrier()) {
          ++values[i];
        }
      }
    }
    /*
     * Распечатка измерения канала в одну шестнадцатеричную цифру
     */
    for (int i = 0; i < NUM_CHANNELS; ++i) {
      printf("%x", min(0xf, (values[i] & 0xf)));
    }
    cout << endl;
  }
  return 0;
}

Компиляция и сборка

g++ -Ofast -Wall RF24_scanner.cpp -lrf24 -o RF24_scanner

Результат

Сканер диапазона 2.4 ГГц на NRF24L01 - Результат (RF24_scanner)
По полученным результатам мы можем сказать, что довольно много каналов заняты.

Пример 2: Получение данных от одного или нескольких передатчиков

В основном на Raspberry Pi, Orange Pi, Banana Pi и т.п. можно запустить любой рабочий пример для Arduino со страницы Подключение модуля nRF24L01+ к Arduino. Единственое, нужно будет поменять функции для вывода на консоль: Serial.print(); на аналогичные в C/C++: printf(); или cout;.

Приёмнику можно задать до 6 труб функцией openReadingPipe(номер, адрес):

for (int i = 0; i < 6; i++) {
  radio.openReadingPipe(i, pipesAddress[i]);
}

с номерами труб от 0 до 5 и адресами труб совпадающими с адресами труб передатчиков.

/*
 * номера труб
 */
uint8_t pipesAddress[6][5] = {
{ '0', 'P', 'I', 'P', 'E' },
{ '1', 'P', 'I', 'P', 'E' },
{ '2', 'P', 'I', 'P', 'E' },
{ '3', 'P', 'I', 'P', 'E' },
{ '4', 'P', 'I', 'P', 'E' },
{ '5', 'P', 'I', 'P', 'E' },
};

Методом available() осуществляется проверка получения данных. Метод возвращает true если в буфере есть принятые данные доступные для чтения. В качестве необязательного аргумента можно указать адрес переменной в которую будет помещён номер трубы по которой были приняты данные (в примере используется адрес переменной &pipeNumber), зная номер трубы мы знаем от какого передатчика пришли данные.

if (radio.available(&pipeNumber)) {
  /*...*/
}

Чтобы была возможность получить/передать данные разной длины, нужно разрешить динамически изменяемый размер блока данных для всех труб на приёмнике и на передатчике.

radio.enableDynamicPayloads();

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

payloadSize = radio.getDynamicPayloadSize();

Читаем данные в массив receivedData и указываем сколько байт читать payloadSize.

radio.read(&receivedData, payloadSize);

Полный код приёмника:

/*
 * Приемник
 */

#include <cstdlib>
#include <iostream>
#include <stdint.h>
/*
 * Подключаем файл настроек из библиотеки RF24
 */
#include <RF24/nRF24L01.h>
/*
 * Подключаем библиотеку  для работы с nRF24L01+
 */
#include <RF24/RF24.h>

using namespace std;

#define BCM_PIN 7
#define SPI_DEV 0
#define MAX_LEN 32

/*
 * Создаём массив для приёма данных
 */
uint8_t receivedData[MAX_LEN];
uint8_t pipeNumber;
uint8_t payloadSize;

/*
 * номера труб
 */
uint8_t pipesAddress[6][5] = {

{ '0', 'P', 'I', 'P', 'E' },

{ '1', 'P', 'I', 'P', 'E' },

{ '2', 'P', 'I', 'P', 'E' },

{ '3', 'P', 'I', 'P', 'E' },

{ '4', 'P', 'I', 'P', 'E' },

{ '5', 'P', 'I', 'P', 'E' },

};

int main() {
  /*
   * Создаём объект radio для работы с библиотекой RF24,
   * указывая номера вывода CE и SPI порта
   */
  RF24 radio(BCM_PIN, SPI_DEV);
  /*
   * Инициируем работу nRF24L01+
   */
  radio.begin();
  /*
   * режим подтверждения приёма, 1 вкл 0 выкл
   */
  radio.setAutoAck(1);
  /*
   * время между попыткой достучаться, число попыток
   */
  radio.setRetries(0, 15);
  /*
   * Разрешить динамически изменяемый размер блока данных для всех труб.
   */
  radio.enableDynamicPayloads();
  /*
   * Открываем трубу с идентификатором 0x1111111111LL для приема данных
   * (на одном канале может быть открыто до 6 разных труб, которые должны
   * отличаться только последним байтом идентификатора)
   */
  for (int i = 0; i < 6; i++) {
    radio.openReadingPipe(i, pipesAddress[i]);
  }
  /*
   * Указываем канал передачи данных (от 0 до 127),
   * (на одном канале может быть только 1 приёмник и до 6 передатчиков)
   * Выбираем канал в котором нет шумов!
   */
  radio.setChannel(0x70);
  /*
   * Указываем мощность передатчика
   * RF24_PA_MIN=-18dBm
   * RF24_PA_LOW=-12dBm
   * RF24_PA_HIGH=-6dBm
   * RF24_PA_MAX=0dBm
   */
  radio.setPALevel(RF24_PA_MAX);
  /*
   * Указываем скорость передачи данных
   * RF24_250KBPS = 250Кбит/сек
   * RF24_1MBPS = 1Мбит/сек
   * RF24_2MBPS = 2Мбит/сек
   */
  radio.setDataRate(RF24_1MBPS);

  /*
   * Включаем приемник, начинаем прослушивать открытую трубу
   */
  radio.startListening();
  radio.printDetails();
  cout << "startListening" << endl;
  while (true) {
    /*
     * Если в буфере имеются принятые данные
     */
    if (radio.available(&pipeNumber)) {
      payloadSize = radio.getDynamicPayloadSize();
      /*
       * Читаем данные в массив data и указываем сколько байт читать
       */
      radio.read(&receivedData, payloadSize);
      cout << "Pipe: " << (int) pipeNumber << "; ";
      cout << "Size: ";
      printf("%02d", (int) payloadSize);
      cout << "; ";
      cout << "Data: [";
      for (uint8_t i = 0; i < payloadSize; ++i) {
        if (i == 0) {
          printf("%02X", receivedData[i]);
        } else {
          printf(", %02X", receivedData[i]);
        }
      }
      cout << "]" << endl;
    }
    __msleep(10);
  }
  return 0;
}

Компиляция и сборка

g++ -Ofast -Wall RF24_receiver.cpp -lrf24 -o RF24_receiver

Результат

Подключение модуля nRF24L01+ к Raspberry Pi, Orange Pi, Banana Pi - Получение данных от одного или нескольких передатчиков, Результат

Пример 3: Передача данных — Arduino скетч

Ниже приведённый код нужно залить на Arduino, можно залить на 6 плат, но не забудьте менять адрес трубы radio.openWritingPipe(pipesAddress[0]); — от 0 до 5.

/*
  Передатчик
*/
/*
  Подключаем файл настроек из библиотеки RF24
*/
#include <nRF24L01.h>
/*
  Подключаем библиотеку  для работы с nRF24L01+
*/
#include <RF24.h>
#include <printf.h>

/*
  Создаём объект radio для работы с библиотекой RF24,
  указывая номера вывода CE и SPI порта
*/
RF24 radio(9, 10);

byte counter = 0;
uint8_t data[32];
uint8_t payloadSize;
uint8_t pipesAddress[6][5] = {

  { '0', 'P', 'I', 'P', 'E' },

  { '1', 'P', 'I', 'P', 'E' },

  { '2', 'P', 'I', 'P', 'E' },

  { '3', 'P', 'I', 'P', 'E' },

  { '4', 'P', 'I', 'P', 'E' },

  { '5', 'P', 'I', 'P', 'E' },

}; //возможные номера труб

void setup(void) {
  Serial.begin(115200);
  printf_begin();
  /*
    Инициируем работу nRF24L01+
  */
  radio.begin();
  /*
    Режим подтверждения приёма, 1 вкл 0 выкл
  */
  radio.setAutoAck(1);
  /*
    Размер пакета, в байтах
  */
  radio.enableDynamicPayloads();
  /*
    Указываем канал передачи данных (от 0 до 127)
    (на одном канале может быть только 1 приёмник и до 6 передатчиков).
    Выбираем канал в котором нет шумов!
  */
  radio.setChannel(0x70);
  /*
    Указываем скорость передачи данных
    RF24_250KBPS = 250Кбит/сек
    RF24_1MBPS = 1Мбит/сек
    RF24_2MBPS = 2Мбит/сек
    Скорость должна быть одинакова на приёмнике и передатчике.
    При самой низкой скорости имеем самую высокую чувствительность и дальность.
  */
  radio.setDataRate(RF24_1MBPS);
  /*
    Указываем мощность передатчика
    RF24_PA_MIN=-18dBm
    RF24_PA_LOW=-12dBm
    RF24_PA_HIGH=-6dBm
    RF24_PA_MAX=0dBm
  */
  radio.setPALevel(RF24_PA_MAX);
  /*
    Открываем трубу для передачи данных (на одном канале
    может быть открыто до 6 разных труб, которые должны
    отличаться только последним байтом идентификатора)
  */
  radio.openWritingPipe(pipesAddress[0]);
  /*
    Не слушаем радиоэфир, мы передатчик
  */
  radio.stopListening();
  /*
    Дамп конфигурации RF для отладки
  */
  radio.printDetails();
}

void loop(void) {
  /*
    Передаём счетчик
  */
  payloadSize = random(1, 32);
  for (uint8_t i = 0; i < payloadSize; i++) {
    data[i] = i;
  }
  Serial.print("Передача:");
  for (uint8_t i = 0; i < payloadSize; i++) {
    Serial.print(" ");
    Serial.print((int) data[i]);
  }
  Serial.print("; ");
  if (radio.write(data, payloadSize)) {
    Serial.println("Данные приняты приёмником.");
  } else {
    Serial.println("Данные не приняты приёмником.");
  }
  /*
    Ждем 1000мс
  */
  delay(1000);
}

Материалы

Serial Peripheral Interface
Optimized High Speed NRF24L01+ Driver Class Documenation

Похожие записи

Комментарии 18

  • А можно подобным образом создать подобие Walkie-Talkie для подключения к ip-камерам, построенным на базе MotionEYEOs?
    Возможно, вопрос сформулирован коряво (заранее извиняюсь).

    • Если я правильно понимаю, вам нужна простая рация. По мне так легче сделать её на Arduino, на ней есть встроенный АЦП.
      Можно использовать и встроенный или USB микрофон на Orange Pi/Raspberry Pi, но тут будет по сложнее, нужно будет написать драйвер, чтобы передать/получить звук по SPI < -> nRF24L01+

  • Нестыкуется
    Указано в таблице CE пин 22 оранжа, а на картинке с выводом пинов указан пин 29.
    Что куда?

    • Спасибо, что заметили.
      Пин 29 так, как указанно на картинке. Можно использовать любой вывод общего назначения (GPIO), нужно только менять значение константы

      #define BCM_PIN 7
  • подскажите, пожалуйста, как полученные данные передавать в php скрипт на raspberry?
    ^_^

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *