В настоящее время технологии беспроводной связи (радиосвязи) получают все большее распространение. К наиболее распространенным сейчас технологиям беспроводной связи можно отнести такие системы как Bluetooth Low Energy (BLE 4.0), Zigbee, Wi-Fi, Lora, 4G и 5G. Для радиосвязи на небольшие расстояния в последнее время получают широкое распространение радиочастотные (RF) модули nRF24L01, которые работают в диапазоне ISM 2,4 ГГц, используемого для безлицензионного применения в науки, промышленности и медицине в большинстве современных стран. Эти модули обеспечивают скорость передачи информации от 250 кБит/с до 2 Мбит/с и с внешней антенной обеспечивают дальность связи до 100 м.
Ранее модули nRF24L01 мы рассматривали в следующих проектах на основе платы Arduino на нашем сайте:
- пульт дистанционного управления дроном на Arduino;
- радиостанции на Arduino и модулях nRF24L01;
- передача данных на смартфон с помощью Arduino, модуля NRF24L01 и Bluetooth (BLE);
- создание приватной комнаты чата с помощью Arduino и радиочастотных модулей.
В данной статье мы рассмотрим подключение модулей nRF24L01 2.4GHz к платам Raspberry Pi и Arduino Uno и установим беспроводную связь между этими платами с помощью модулей nRF24L01. Плата Raspberry Pi будет выступать в роли передатчика, а плата Arduino Uno – в роли приемника. К плате Arduino будет подключен ЖК дисплей 16x2, на его экран будут выводиться принимаемые по радиоканалу сообщения. Модули nRF24L01 также поддерживают функционал технологии Bluetooth Low Energy (BLE).
Необходимые компоненты
- Плата Raspberry Pi (купить на AliExpress).
- Плата Arduino Uno (купить на AliExpress).
- ЖК дисплей 16x2 с модулем I2C для него (купить на AliExpress).
- Модуль nRF24L01 – 2 шт. (купить на AliExpress).
- Соединительные провода.
Радиочастотный модуль nRF24L01 (RF Module)
nRF24L01 является приемопередающим модулем, что означает что один и тот же модуль может как передавать информацию, так и принимать ее. Но поскольку модули nRF24L01 работают в полудуплексе (half-duplex, то в один момент времени они могут либо передавать информацию, либо принимать ее. Модули работают по интерфейсу SPI, поэтому их без проблем можно подключить к любому современному микроконтроллеру. Особенно легко их подключать к плате Arduino, для которой разработано достаточно много библиотек для работы с данными радиомодулями. Внешний вид и распиновка модуля nRF24L01 показаны на следующем рисунке.
Рабочее напряжение для модулей nRF24L01 составляет от 1.9V до 3.6V (типовое – 3.3V). В режиме покоя они потребляют очень маленький ток (12mA), что делает их крайне энергоэффективными и позволяет использовать их в устройствах, работающих от батареек. Хотя рабочее напряжение для контактов модулей составляет 3.3V, тем нее менее, они достаточно терпимо (или как сейчас модно говорить – толерантно) воспринимают и напряжение 5V, что позволяет их напрямую подключать к плате Arduino.
Другим преимуществом радиомодулей nRF24L01 является наличие у них 6 каналов – это означает что каждый модуль может взаимодействовать с 6 аналогичными модулями. Это свойство позволяет развертывать на основе модулей сети типа “звезда” и mesh сети. Модули также очень удобны для применения в приложениях интернета вещей (IoT) и поддерживают до 125 уникальных адресов, что позволяет в замкнутой области разместить до 125 таких модулей чтобы они не мешали работе друг друга.
Схемы проекта
С платой Arduino
Схема подключения модуля nRF24L01 к плате Arduino представлена на следующем рисунке.
В представленной схеме модуль nRF24L01 подключается к плате Arduino с использованием интерфейса SPI, а ЖК дисплей 16x2 подключается к плате Arduino по интерфейсу I2C.
Внешний вид собранной схемы с платой Arduino показан на следующем рисунке.
С платой Raspberry Pi
Схема подключения модуля nRF24L01 к плате Raspberry Pi представлена на следующем рисунке.
В представленной схеме модуль nRF24L01 подключается к плате Raspberry Pi с использованием интерфейса SPI.
Внешний вид собранной схемы с платой Raspberry Pi показан на следующем рисунке.
Объяснение программы для Raspberry Pi
Полный код программы приведен в конце статьи, здесь же мы кратко рассмотрим его основные фрагменты.
Программировать плату Raspberry Pi в нашем проекте мы будем с использованием языка Python3. Также можно использовать и язык C/C++ как и в плате Arduino, однако в данном случае преимуществом написания программы на языке python является то, что на нем написана специальная библиотека для работы с модулями nRF24l01, которую можно скачать с ее официальной страницы на github. Но здесь необходимо отметить, что наша программа на python и указанная библиотека должны находиться в одном и том же каталоге, иначе программа на python не сможет найти библиотеку. После скачивания библиотеки извлеките ее из архива и создайте отдельный каталог, в котором будут храниться все программы и библиотеки вашего проекта. Когда установка библиотеки будет закончена, можно приступать к написанию программы.
Первым делом в программе необходимо подключить (импортировать) все используемые библиотеки.
1 2 3 4 |
import RPi.GPIO as GPIO import time import spidev from lib_nrf24 import NRF24 |
Далее установим режим работы контактов (GPIO mode) платы Raspberry Pi "Broadcom SOC channel", что будет означать что мы будем обращаться к контактам платы по их физическим номерам (а не по их номерам на плате).
1 |
GPIO.setmode(GPIO.BCM) |
Далее в программе мы зададим адреса каналов (pipe address) – они будут нужны для взаимодействия с приемной частью проекта на основе платы Arduino. Адреса укажем в шестнадцатеричном коде.
1 |
pipes = [[0xE0, 0xE0, 0xF1, 0xF1, 0xE0], [0xF1, 0xF1, 0xF0, 0xF0, 0xE0]] |
Инициализируем модуль nRF24l01 используя контакты GPIO08 в качестве CE и GPIO25 в качестве CSN.
1 |
radio.begin(0, 25) |
Установим размер пакета (payload size) 32 бита, адрес канала 76, скорость передачи данных 1 Мбит/с и выходную мощность модуля на минимум.
1 2 3 4 |
radio.setPayloadSize(32) radio.setChannel(0x76) radio.setDataRate(NRF24.BR_1MBPS) radio.setPALevel(NRF24.PA_MIN) |
Откроем каналы и начнем в них запись данных. Также будем выводить на экран основные параметры (details) работы модуля nRF24l01.
1 2 |
radio.openWritingPipe(pipes[0]) radio.printDetails() |
Подготовим сообщение в форме строки. Это сообщение мы будем передавать плате Arduino UNO.
1 2 3 |
sendMessage = list("Hi..Arduino UNO") while len(sendMessage) < 32: sendMessage.append(0) |
Начнем запись информации в радио модуль и будем продолжать запись пока не закончится вся строка для передачи. Одновременно с этим зафиксируем текущее время и выведем на экран сообщение об успешной передаче (в целях отладки).
1 2 3 4 5 6 |
while True: start = time.time() radio.write(sendMessage) print("Sent the message: {}".format(sendMessage)) send radio.startListening() |
Если передача сообщения завершена и радио канал закрыт (не доступен) более 2-х секунд, то выведем на экран сообщение о том, что время истекло (timed out).
1 2 3 4 5 |
while not radio.available(0): time.sleep(1/100) if time.time() - start > 2: print("Timed out.") # print error message if radio disconnected or not functioning anymore break |
Закрываем прослушивание (listening) радио канала, закрываем соединение и заново открываем соединение спустя 3 секунды чтобы передать другое сообщение.
1 2 |
radio.stopListening() # close radio time.sleep(3) # give delay of 3 seconds |
Выполнение программы на Python для Raspberry Pi
Для выполнения программы необходимо сделать следующую последовательность шагов.
1. Сохраните программу на Python и библиотеку для работы с радиочастотным модулем в одном и том же каталоге.
2. Мы назвали программу nrfsend.py и поместили в каталог с ней все другие файлы, необходимые для работы проекта.
3. Откройте окно терминала Raspberry Pi и войдите в нем в каталог с программой используя команду “cd”.
4. Откройте каталог и напишите в терминале команду “sudo python3 your_program.py”, после чего нажмите enter. После этого вы на экране увидите установленные параметры работы модуля nRF24l01 и увидите как модуль начнет передавать сообщения каждые 3 секунды. На экране каждое передаваемое сообщение будет показываться посимвольно.
Объяснение программы для Arduino
Полный код программы приведен в конце статьи, здесь же мы кратко рассмотрим его основные фрагменты.
Программа для платы Arduino UNO будет во многом похожа на программу для платы Raspberry Pi, только написана она будет на другом языке программирования. Библиотеку для Arduino для работы с модулями nRF24l01 можно скачать с ее страницы в github.
Первым делом в программе нам необходимо подключить используемые библиотеки. Мы используем ЖК дисплей 16x2 с шилдом I2C, поэтому в программе нам необходимо подключить библиотеку Wire.h. Для работы с модулем nRF24l01 кроме скачанной библиотеки с github необходимо также подключить библиотеку SPI.
1 2 |
#include<SPI.h> #include <Wire.h> |
Также подключаем библиотеку RF24 для работы с радиочастотными модулями и библиотеку LiquidCrystal_I2C.h для работы с ЖК дисплеем по интерфейсу I2C.
1 2 |
#include<RF24.h> #include <LiquidCrystal_I2C.h> |
ЖК дисплей имеет адрес I2C равный 27, поэтому создадим объект для работы с ним следующим образом:
1 |
LiquidCrystal_I2C lcd(0x27, 16, 2); |
Модуль RF24 подключается по стандартному интерфейсу SPI: CE – к контакту 9, CSN – к контакту 10.
1 |
RF24 radio(9, 10) ; |
Далее инициализируем радиочастотный модуль, установим для него уровень мощности и зададим номер канала с номером 76. Также установим адрес канала такой же как и в плате Raspberry Pi и откроем канал для чтения.
1 2 3 4 5 |
radio.begin(); radio.setPALevel(RF24_PA_MAX) ; radio.setChannel(0x76) ; const uint64_t pipe = 0xE0E0F1F1E0LL ; radio.openReadingPipe(1, pipe) ; |
Инициализируем связь по интерфейсу I2C и ЖК дисплей.
1 2 3 4 |
Wire.begin(); lcd.begin(); lcd.home(); lcd.print("Ready to Receive"); |
Начнем прослушивание радиоканала на предмет поступления входящих сообщений и установим длину сообщения равную 32 байтам.
1 2 |
radio.startListening() ; char receivedMessage[32] = {0} |
Если радиочастотный модуль доступен, то начинаем считывание сообщения с него и сохраняем сообщение. Выводим полученное сообщение в окно монитора последовательной связи и на экран ЖК дисплея. Останавливаем прослушивание радиоканала и снова начинаем его прослушивание через некоторое время.
1 2 3 4 5 6 7 8 9 |
if (radio.available()) { radio.read(receivedMessage, sizeof(receivedMessage)); Serial.println(receivedMessage) ; Serial.println("Turning off the radio.") ; radio.stopListening() ; String stringMessage(receivedMessage) ; lcd.clear(); delay(1000); lcd.print(stringMessage); } |
Готовую программу загружаем в плату Arduino UNO и ждем поступления сообщений из радиоканала.
Таким образом, мы рассмотрели проект с использованием Raspberry Pi и nRf24l01 в качестве передающей части и Arduino UNO и nRF24l01 в качестве приемной части. Принимаемое сообщение будет выводиться на экран ЖК дисплея 16x2 и в окно монитора последовательной связи. Обратите особое внимание на адреса каналов (pipe) в программах для Arduino и Raspberry Pi – они критически важны для успешной работы проекта.
Более подробно работу проекта вы можете посмотреть на видео, приведенном в конце статьи.
Исходные коды программ
Программа для Raspberry Pi (передающая часть)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
import RPi.GPIO as GPIO # import gpio import time #import time library import spidev from lib_nrf24 import NRF24 #import NRF24 library GPIO.setmode(GPIO.BCM) # set the gpio mode # устанавливаем адреса каналов, они должны соответствовать адресам каналов на приемной стороне pipes = [[0xE0, 0xE0, 0xF1, 0xF1, 0xE0], [0xF1, 0xF1, 0xF0, 0xF0, 0xE0]] radio = NRF24(GPIO, spidev.SpiDev()) # use the gpio pins radio.begin(0, 25) # start the radio and set the ce,csn pin ce= GPIO08, csn= GPIO25 radio.setPayloadSize(32) # устанавливаем размер пакета 32 байта radio.setChannel(0x76) # set the channel as 76 hex (устанавливаем номер канала) radio.setDataRate(NRF24.BR_1MBPS) # устанавливаем скорость передачи 1 Мбит/с radio.setPALevel(NRF24.PA_MIN) # устанавливаем уровень излучаемой мощности (на минмум) radio.setAutoAck(True) # устанавливаем подтверждение (acknowledgement) в true radio.enableDynamicPayloads() radio.enableAckPayload() radio.openWritingPipe(pipes[0]) # открываем канал для записи radio.printDetails() # выводим на экран основные параметры радиомодуля sendMessage = list("Hi..Arduino UNO") # сообщение, которое необходимо передать while len(sendMessage) < 32: sendMessage.append(0) while True: start = time.time() #start the time for checking delivery time (запоминаем текущее время) radio.write(sendMessage) # передаем сообщение по радиоканалу print("Sent the message: {}".format(sendMessage)) # выводим сообщение на экран после успешной передачи radio.startListening() # начинаем прослушивание радиоканала while not radio.available(0): time.sleep(1/100) if time.time() - start > 2: print("Timed out.") # выводим сообщение об ошибке если модуль отключен от платы или не функционирует break radio.stopListening() # закрываем радиоканал time.sleep(3) # задержка 3 секунды |
Программа для Arduino (приемная часть)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
#include<SPI.h> // библиотека для работы с интерфейсом spi #include <Wire.h> // i2c libary fro 16x2 lcd display (библиотека для работы с интерфейсом i2c #include<RF24.h> // библиотека для работы с радиочастотным модулем #include <LiquidCrystal_I2C.h> // библиотека для работы с ЖК дисплеем по интерфейсу I2C LiquidCrystal_I2C lcd(0x27, 16, 2); // i2c address is 0x27 RF24 radio(9, 10) ; // контакты ce, csn void setup(void) { while (!Serial) ; Serial.begin(9600) ; // последовательная связь со скоростью 9600 бод (для целей отладки) Serial.println("Starting.. Setting Up.. Radio on..") ; // debug message radio.begin(); // start radio at ce csn pin 9 and 10 radio.setPALevel(RF24_PA_MAX) ; // set power level radio.setChannel(0x76) ; // set chanel at 76 (устанавливаем номер канала) const uint64_t pipe = 0xE0E0F1F1E0LL ; // pipe address same as sender i.e. raspberry pi (адреса каналов должны быть такие как и на передающей стороне) radio.openReadingPipe(1, pipe) ; // начинаем считывание канала radio.enableDynamicPayloads() ; radio.powerUp() ; Wire.begin(); //инициализируем связь по протоколу i2c lcd.begin(); // инициализируем ЖК дисплей lcd.home(); lcd.print("Ready to Receive"); // приветственное сообщение на экране ЖК дсиплея delay(2000); lcd.clear(); } void loop(void) { radio.startListening() ; // начинаем прослушивание радиоканала char receivedMessage[32] = {0} ; // устанавливаем размер входящего сообщения 32 байта if (radio.available()) { // проверяем пришло ли сообщение radio.read(receivedMessage, sizeof(receivedMessage)); // считываем сообщение и сохраняем его Serial.println(receivedMessage) ; // печатаем принятое сообщение в окне монитора последовательной связи Serial.println("Turning off the radio.") ; // print message on serial monitor radio.stopListening() ; // останавливаем прослушивание радиоканала String stringMessage(receivedMessage) ; // преобразуем char в string (строку) lcd.clear(); // очищаем экран для нового сообщения delay(1000); // задержка 1 секунду lcd.print(stringMessage); // выводим на экран ЖК дисплея принятое сообщение } delay(10); } |