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

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

Практика для школьников. Мясищев А.А.

При разработке электронных устройств нередко возникает потребность в передаче каких-либо данных на некоторое расстояние. Например термодатчик, расположенный на улице, должен передавать значение температуры центральному устройству, а датчик движения – отдавать команду на включение сирены, расположенной в отдельном помещении. Подобных задач существует множество, как и методов их решения. В тех случаях, когда организовать проводную связь не представляется возможным, на помощь приходят радиомодули NFR24L01, работающие в диапазоне частот 2.4-2.5 ГГц.

Рис.1. Внешний вид NRF24L01+

Эта комплектация платы является базовой и содержит сам чип, штыревую колодку и антенну в виде извилистой дорожки. Такой набор обеспечивает дальность связи до 100м при прямой видимости или до 30м в помещении. Если этого недостаточно, то есть возможность приобрести такие же модули, только с дополнительным усилителем и внешней антенной. В таком случае дальность связи можно увеличить до 1000м. Ниже - схема модуля

Рис.2. Схема модуля

Технические характеристики Модули nRF24L01+

-Напряжение питания: 1,9В – 3,6В;

-Интерфейс обмена данными: SPI;

-Частота приёма и передачи: 2,4 ГГц;

-Количество каналов: 128 с шагом 1МГц;

-Тип модуляции: GFSK;

-Скорость передачи данных: 250kbps, 1Mbps и 2Mbps;

-Чувствительность приёмника: -82 dBm;

-Расстояние приёма/передачи данных: 100м – прямая видимость; 30м – помещение;

-Коэффициент усиления антенны: 2dBm;

-Диапазон рабочей температуры: -40оС…+85оС;

-Организация сети на одном канале: 7 модулей (1 приёмник и 6 передатчиков).

Подключение радиомодуля NRF24L01+ к Arduino осуществляется по SPI-интерфейсу, что предполагает использование 5 проводов не считая выводов питания. Для разных линеек Arduino номера выводов, на которые завязан аппаратный SPI-интерфейс, могут отличаться. Ниже показана карта подключения NRF24L01+ к различным сериям Arduino.

Выводы CE(выбор приемника или передатчика) и CSN(выбор устройства на шине SPI) могут быть соединены с любыми цифровыми пинами Arduino. Единственное что потребуется – указать их номера при написании скетча. Что касается программирования, то для взаимодействия с NRF24L01+ существует несколько библиотек, но наиболее популярной и стабильной является библиотека RF24.

Как правило, большинство любительских проектов начального уровня предусматривают использование двух модулей NRF24L01+, один из которых работает в режиме передатчика, а другой как приёмник на одинаковой частоте. Но на одном канале можно контролировать сразу несколько датчиков, например температуру в разных комнатах. В этом случае, функциональные возможности радиомодуля NRF24L01+ предусматривают возможность организации мини-сети. А именно, на одной частоте или канале могут работать до 6 передатчиков и 1 приёмник. При этом каждому передатчику присваивается свой уникальный идентификатор («Pipe ID» или «Идентификатор трубы»), а приёмнику необходимо присвоить все идентификаторы тех передатчиков, от которых он будет принимать данные.

Каждый идентификатор представляет из себя произвольное число, состоящее из 5 байт, но он должен задаваться по определённым правилам, а именно:

-На одном и том же канале идентификатор каждого передатчика должен быть обязательно уникальным;

-Чтобы приёмник мог принимать данные от передатчиков, ему должны быть указаны их идентификаторы;

-Идентификаторы труб Pipe0 и Pipe1 должны отличаться всеми пятью байтами, например Pipe0 = 0x7878787878, а Pipe1 = 0xB4B5B6B7F1;

-Идентификаторы труб Pipe2 – Pipe5 должны отличаться от Pipe1 только последним байтом, например: Pipe1 = 0xB4B5B6B7F1; Pipe2 = 0xB4B5B6B7CD; Pipe3 = 0xB4B5B6B7A3; Pipe4 = 0xB4B5B6B70F; Pipe5 = 0xB4B5B6B705;

Работа нескольких передатчиков и одного приемника.

Например, как прописать в коде приёмника получение данных с нескольких передатчиков?

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

void setup() {

// .......

// Первый передатчик имеен идентификатор 0xAABBCCDD11LL

radio.openReadingPipe (1, 0xAABBCCDD11LL);

// Второй передатчик имеен идентификатор 0xAABBCCDD22LL

radio.openReadingPipe (2, 0xAABBCCDD22LL);

radio.startListening();

// .......

}

void loop() {

// Если поступили данные, определяем номер трубы передатчика по ссылке на pipe

if(radio.available(&pipe)) {

radio.read(&data, sizeof(data)); // Считываем данные в массив

if(pipe==1){ // Если данные пришли от 1-го передатчика

// Выполняем какие-либо действия для 1-го передатчика

}

if(pipe==2){ // Если данные пришли от 2-го передатчика

// Выполняем какие-либо действия для 2-го передатчика

}

}

}

Рассмотрим примеры

Рис.3. Подключение радиомодуля, кнопки и светодиода к Ардуино.

Резистор на приемнике ~500 Ом(светодиод),

на передатчике ~10 кОм(кнопка)

1. Программа срабатывания светодиода на приемном модуле при нажатии кнопки на передающем модуле.

Передатчик.

#include <SPI.h> // Подключаем библиотеку SPI

#include <nRF24L01.h> // Подключаем библиотеку файл конфигурации из библ. RF24

#include <RF24.h> // Подключаем библиотеку RF24 для работы с модулем nRF24L01

int data[1]; // Создаём массив для приёма данных

RF24 radio(9,10);//Указываем номера выводов nRF24L01+(CE,CSN) и создаем объект radio

int button = 7; // Создаем переменную button и указываем номер вывода

void setup(void){

delay(1000);// Ждем 1с для подачи питания на модуль

pinMode(button, INPUT); // Устанавливаем вывод 7 на вход

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

radio.setChannel(100); // Указываем канал передачи (от 0 до 126) - 2.500ГГц

radio.setDataRate (RF24_1MBPS); // Указываем скорость передачи (250KBPS, 1MBPS,

//2MBPS) - 1МБит/с

radio.setPALevel(RF24_PA_HIGH); // Указываем мощность передатчика (MIN=

//-18dBm, LOW=-12dBm, HIGH=-6dBm, MAX=0dBm)

radio.openWritingPipe(0x0123456789LL);// Задаем идентификатором 0x0123456789LL для

// передачи данных

}

void loop(void)

{

if (digitalRead(button) == HIGH){ // Считываем переменную "button", если HIGH идем

// дальше, если LOW зацикливаемся

data[0] = 123; // Записываем значение 123 в массив data

radio.write(data, 1);} // Отправляем данные из массива data

}

Приемник

#include <SPI.h> // Подключаем библиотеку SPI

#include <nRF24L01.h> // Подключаем библиотеку nRF24L01

#include <RF24.h> // Подключаем библиотеку RF24

int data[1]; // Создаём массив для приёма данных

RF24 radio(9,10); // Указываем номера выводов nRF24L01+ (CE, CSN)

int LED = 3; // Создаем переменную SW1 и указываем номер вывода

void setup(void){

delay(1000); // Ждем 1с для подачи питания на модуль

pinMode(LED,OUTPUT); // Устанавливаем вывод 3 на выход

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

radio.setChannel(100); // Указываем канал передачи (от 0 до 126)

radio.setDataRate (RF24_1MBPS); // Указываем скорость передачи (250KBPS,

// 1MBPS, 2MBPS)

radio.setPALevel(RF24_PA_HIGH); // Указываем мощность передатчика (MIN=-

//18dBm, LOW=-12dBm, HIGH=-6dBm, MAX=0dBm)

radio.openReadingPipe(1,0x0123456789LL);// Задаем идентификатором 0x1234567890LL

// передатчика

radio.startListening ();

}

void loop(void)

{

if (radio.available()){ // Если в буфере поступили данные

radio.read(data, 1); // Считываем данные с массива data и задаем количество

// считываемых байт

if(data[0] == 123){ // Если в массиве data значение 123

digitalWrite(LED, HIGH);} // Включаем светодиод

delay(10); // Ждем 10мс

}

else{ // Если в массиве data другое значение

digitalWrite(LED, LOW); // Выключаем светодиод

delay(10); // Ждем 10мс

}

}

Следующая программа работает на схеме подключения, которая является комбинацией схем на рис.3 и рис.4. без использования датчика DS18B20.

2. Программа передачи текстового сообщения с передатчика на приемник с отображением текста на семисегментном индикаторе как на передатчике, так и на приемнике. Материал по индикатору TM1637 здесь.

Передатчик.

#include <SPI.h> // Подключаем библиотеку SPI

#include <nRF24L01.h> // Подключаем библиотеку nRF24L01

#include <RF24.h> // Подключаем библиотеку RF24

#include <TM1637Display.h>

// Подключение TM1637

#define CLK 2

#define DIO 3

TM1637Display display(CLK, DIO);

RF24 radio(9,10); // Указываем номера выводов nRF24L01+ (CE, CSN)

void setup(void){

display.clear();

display.setBrightness(7);

delay(1500);// Ждем 1.5с для подачи питания на модуль

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

radio.setChannel(100); // Указываем канал передачи (от 0 до 126)

radio.setDataRate (RF24_1MBPS); // Указываем скорость передачи (250KBPS, 1MBPS,

//2MBPS)

radio.setPALevel(RF24_PA_HIGH); // Указываем мощность передатчика (MIN=-

//18dBm, LOW=-12dBm, HIGH=-6dBm, MAX=0dBm)

radio.openWritingPipe(0x0123456789LL);// Задаем идентификатором 0x0123456789LL для

//передачи данных

}

void loop(void)

{

byte date[4];

date[0]= {SEG_A | SEG_B | SEG_G | SEG_F | SEG_E}; //Символ Р

date[1]= {SEG_G};//Символ -

date[2]=display.encodeDigit(1);

date[3]=display.encodeDigit(4);

// Вывод символов Р-13

display.setSegments(date);

// Передача данных

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

}

Приемник.

#include <SPI.h> // Подключаем библиотеку SPI

#include <nRF24L01.h> // Подключаем библиотеку nRF24L01

#include <RF24.h> // Подключаем библиотеку RF24

#include <TM1637Display.h>

// Подключение TM1637

#define CLK 2

#define DIO 4

TM1637Display display(CLK, DIO);

byte date[4]; // Массив принятых данных

RF24 radio(9,10); // Указываем номера выводов nRF24L01+ (CE, CSN)

void setup(void){

display.clear();

display.setBrightness(7);

delay(1000); // Ждем 1с для подачи питания на модуль

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

radio.setChannel(100); // Указываем канал передачи (от 0 до 126)

radio.setDataRate (RF24_1MBPS); // Указываем скорость передачи (250KBPS,

// 1MBPS, 2MBPS)

radio.setPALevel(RF24_PA_HIGH); // Указываем мощность передатчика (MIN=-

//18dBm, LOW=-12dBm, HIGH=-6dBm, MAX=0dBm)

radio.openReadingPipe(1,0x0123456789LL);// Задаем идентификатором 0x1234567890LL

// для передачи данных

radio.startListening ();

}

void loop(void)

{

if (radio.available()){

radio.read(&date, sizeof(date));

display.setSegments(date);

}

}

Рис.4. Подключение датчика температуры и индикатора к Ардуине

Следующая программа работает на схеме подключения, которая является комбинацией схем на рис.3 и рис.4.

3. Программа передачи температуры с отображением ее на передатчике и приемнике. Температура передается и отображается в целых градусах с символом градуса и символом C

Передатчик.

#include <SPI.h> // Подключаем библиотеку SPI

#include <nRF24L01.h> // Подключаем библиотеку nRF24L01

#include <RF24.h> // Подключаем библиотеку RF24

#include <OneWire.h>

#include <DallasTemperature.h>

#include <stdio.h>

#include <stdlib.h>

#include <TM1637Display.h>

// Подключение TM1637

#define CLK 2

#define DIO 3

TM1637Display display(CLK, DIO);

#define ONE_WIRE_BUS 6 // Подключение датчика температуры к 6 выводу

OneWire oneWire(ONE_WIRE_BUS); // Создание экземпляра класса

DallasTemperature sensors(&oneWire); // Создание экземпляра класса

byte buf[10];

RF24 radio(9,10); // Указываем номера выводов nRF24L01+ (CE, CSN)

void setup(void){

sensors.begin();

display.clear();

display.setBrightness(7);

delay(1500);// Ждем 1.5 сек. для подачи питания на модуль

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

radio.setChannel(100); // Указываем канал передачи (от 0 до 126)

radio.setDataRate (RF24_1MBPS); // Указываем скорость передачи (250KBPS, 1MBPS,

//2MBPS)

radio.setPALevel(RF24_PA_HIGH); // Указываем мощность передатчика (MIN=-

//18dBm, LOW=-12dBm, HIGH=-6dBm, MAX=0dBm)

radio.openWritingPipe(0x0123456789LL);// Задаем идентификатором 0x0123456789LL для

//передачи данных

}

void loop(void)

{

byte data[4];

data[2] = {SEG_A | SEG_F | SEG_G | SEG_B}; // Построение собственного символа

sensors.requestTemperatures();

float cel=sensors.getTempCByIndex(0); // Определение температуры

dtostrf(cel,2,0,buf); // Запись числа cel в символьный массив buf

int temH=buf[0]-48; //Преобразование десятичного кода символа в число

int temL=buf[1]-48;

// Вывод температуры

data[0]=display.encodeDigit(temH);

data[1]=display.encodeDigit(temL);

data[3]=display.encodeDigit(12);// символ C

display.setSegments(data);

//

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

}

Приемник.

#include <SPI.h> // Подключаем библиотеку SPI

#include <nRF24L01.h> // Подключаем библиотеку nRF24L01

#include <RF24.h> // Подключаем библиотеку RF24

#include <TM1637Display.h>

// Подключение TM1637

#define CLK 2

#define DIO 4

TM1637Display display(CLK, DIO);

byte data[4]; // Создаём массив для приёма данных

RF24 radio(9,10); // Указываем номера выводов nRF24L01+ (CE, CSN)

void setup(void){

display.clear();

display.setBrightness(7);

delay(1000); // Ждем 1с для подачи питания на модуль

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

radio.setChannel(100); // Указываем канал передачи (от 0 до 126)

radio.setDataRate (RF24_1MBPS); // Указываем скорость передачи (250KBPS,

//1MBPS, 2MBPS)

radio.setPALevel(RF24_PA_HIGH); // Указываем мощность передатчика (MIN=-

//18dBm, LOW=-12dBm, HIGH=-6dBm, MAX=0dBm)

radio.openReadingPipe(1,0x0123456789LL);// Задаем идентификатором 0x1234567890LL

//для передачи данных

radio.startListening ();

}

void loop(void)

{

if (radio.available()){

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

display.setSegments(data);

}

}

Рис.5. Фото стенда

Задание

1. Написать программу по передаче с передатчика на приемник температуры с одним числом после запятой и номер своего варианта в формате Р-13. Использовать датчик DS18B20. Температура на передатчике должна выводиться в формате 21.3С. На приемнике температура должна выводиться в том же формате в течении 2 сек. Далее в течении 2 сек. должен быть выведен вариант. Потом по циклу.

2. Сделать отчет по работе с описанием радиомодуля, его подключения к Ардуино с датчиком температуры, кнопкой, светодиодом и индикатором. Представить программы для передатчика и приемника.

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

Передатчик

#include <SPI.h> // Подключаем библиотеку SPI

#include <nRF24L01.h> // Подключаем библиотеку nRF24L01

#include <RF24.h> // Подключаем библиотеку RF24

#include <OneWire.h>

#include <DallasTemperature.h>

#include <stdio.h>

#include <stdlib.h>

#include <TM1637Display.h>

// Подключение TM1637

#define CLK 2

#define DIO 3

TM1637Display display(CLK, DIO);

#define ONE_WIRE_BUS 6 // Подключение датчика температуры к 6 выводу

OneWire oneWire(ONE_WIRE_BUS); // Создание экземпляра класса

DallasTemperature sensors(&oneWire); // Создание экземпляра класса

byte buf[10];

RF24 radio(9,10); // Указываем номера выводов nRF24L01+ (CE, CSN)

void setup(void){

sensors.begin();

display.clear();

display.setBrightness(7);

delay(1500);// Ждем 1.5с для подачи питания на модуль

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

radio.setChannel(100); // Указываем канал передачи (от 0 до 126)

radio.setDataRate (RF24_1MBPS); // Указываем скорость передачи (250KBPS, 1MBPS, 2MBPS)

radio.setPALevel(RF24_PA_HIGH); // Указываем мощность передатчика (MIN=-18dBm, LOW=-12dBm, HIGH=-6dBm, MAX=0dBm)

radio.openWritingPipe(0x0123456789LL);// Задаем идентификатором 0x0123456789LL для передачи данных

}

void loop(void)

{

byte data[4];

byte date[4];

data[2] = {SEG_A | SEG_F | SEG_G | SEG_B}; // Построение собственного символа

date[0]= {SEG_A | SEG_B | SEG_G | SEG_F | SEG_E}; //Символ Р

date[1]= {SEG_G};//Символ -

date[2]=display.encodeDigit(1);

date[3]=display.encodeDigit(3);

sensors.requestTemperatures();

float cel=sensors.getTempCByIndex(0); // Определение температуры

Serial.println(cel);

dtostrf(cel,2,0,buf); // Запись числа cel в символьный массив buf

int temH=buf[0]-48; //Преобразование десятичного кода символа в число

int temL=buf[1]-48;

// Вывод температуры

data[0]=display.encodeDigit(temH);

data[1]=display.encodeDigit(temL);

data[3]=display.encodeDigit(12);// символ C

display.setSegments(data);

//

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

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

}

Приемник

#include <SPI.h> // Подключаем библиотеку SPI

#include <nRF24L01.h> // Подключаем библиотеку nRF24L01

#include <RF24.h> // Подключаем библиотеку RF24

#include <TM1637Display.h>

// Подключение TM1637

#define CLK 2

#define DIO 4

TM1637Display display(CLK, DIO);

byte data[4]; // Создаём массив для приёма данных

byte date[4];

RF24 radio(9,10); // Указываем номера выводов nRF24L01+ (CE, CSN)

void setup(void){

display.clear();

display.setBrightness(7);

delay(1000); // Ждем 1с для подачи питания на модуль

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

radio.setChannel(100); // Указываем канал передачи (от 0 до 126)

radio.setDataRate (RF24_1MBPS); // Указываем скорость передачи (250KBPS, 1MBPS, 2MBPS)

radio.setPALevel(RF24_PA_HIGH); // Указываем мощность передатчика (MIN=-18dBm, LOW=-12dBm, HIGH=-6dBm, MAX=0dBm)

radio.openReadingPipe(1,0x0123456789LL);// Задаем идентификатором 0x1234567890LL для передачи данных

radio.startListening ();

}

void loop(void)

{

if (radio.available()){

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

radio.read(&date, sizeof(date));

display.setSegments(data);

delay(2000);

display.setSegments(date);

delay(2000);

}

}

Литература

1. Обзор радио модуля NRF24L01+. https://robotchip.ru/obzor-radio-modulya-nrf24l01/ - 2016.

2. Урок 26.4 Соединяем две arduino по радиоканалу через nRF24L01+.

https://lesson.iarduino.ru/page/urok-26- 4-soedinyaem-dve-arduino-po-radiokanalu-cherez-nrf24l01/ - 2017.

3. Радио модуль NRF24L01. https://3d-diy.ru/wiki/arduino-moduli/radio-modul-nrf24l01/

4. Подключение и настройка nRF24L01 к Arduino (модуль беспроводной связи). https://www.youtube.com/watch?v=ACVtKDJVXS4

15.11.2019 г.