Подключение радио модуля 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 г.