Победа над nRF24L01: на три шага ближе

от автора

Многие испытывают трудности при соединении по эфиру радиомодулей nRF24L01. Об этом свидетельствует тема на форуме Амперки, открытая в конце 2014г. За пять с небольшим лет в теме накопилось более 120(!) страниц. Это при том, что автор темы не просто обозначил проблему, а поделился своим трехнедельным опытом победного для него боя. Кроме того, он тут же — в первом сообщении создал навигатор по страницам темы, где приводит ссылки на решения проблемы другими. Этот своеобразный путеводитель постоянно обновляется.

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

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

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

Я же разделил эту задачу на несколько простых задачек. Вначале модули проверяются на работоспособность и правильность подключения (шаг 1), затем один из пары работающих радиомодулей тестируется на работу в режиме передатчика без ожидания отклика с приемника (шаг 2) и последний этап — улучшение качества связи в этой связке передатчик-приемник (шаг 3).

Итак …

Шаг 1

Загрузить в контроллер платы Ардуино скетч сканера эфира, который можно найти среди примеров Arduino IDE: Файл -> Примеры -> RF24 -> scanner. Ниже под спойлером есть этот скетч с несущественным изменением. В нем изменено время между стартом и остановкой сканирования одного канала с 128 мксек на 512 мксек. Увеличение времени позволило за один цикл выявлять бОльше источников помех и сигналов. Это равнозначно замене результата измерений в канале на сумму результатов в этом канале за четыре цикла сканирования эфира до изменения времени задержки. При этом, время прохода всего прослушиваемого диапазона сканером увеличилось несущественно: примерно с 8-ми до 10-ти сек.

В разных скетчах адрес канала в командах приводится в разных форматах: в одних — …(0x6f), в других — …(112). Перевод с одного формата в другой станет понятным с примера перевода. Например, для (0x1а) — это: (1+1)*16 + а = (1+1)*16 + 10 = 42. Отсчет каналов начинается с частоты 2,4 ГГц, далее идет увеличение частоты на 1 МГц с увеличением номера канала на 1.

скетч сканера эфира

/* Победа над nRF24L01: на три шага ближе, сканер эфира https://habr.com/ru/post/476716/ */  /*   Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>    This program is free software; you can redistribute it and/or   modify it under the terms of the GNU General Public License   version 2 as published by the Free Software Foundation. */  /**    Channel scanner     Example to detect interference on the various channels available.    This is a good diagnostic tool to check whether you're picking a    good channel for your application.     Inspired by cpixip.    See http://arduino.cc/forum/index.php/topic,54795.0.html */  #include <SPI.h> #include "nRF24L01.h" #include "RF24.h" #include "printf.h"  // // Hardware configuration //  // Set up nRF24L01 radio on SPI bus plus pins 9 & 10  RF24 radio(9, 10); //Arduino UNO  // // Channel info //  const uint8_t num_channels = 128; uint8_t values[num_channels];  // // Setup //  void setup(void) {   //   // Print preamble   //    Serial.begin(57600);   Serial.println("Scanner Air On");   printf_begin();    //   // Setup and configure rf radio   //    radio.begin();   radio.setAutoAck(false);    // Get into standby mode   radio.startListening();   radio.stopListening();    // Print out header, high then low digit   int i = 0;   while ( i < num_channels )   {     printf("%x", i >> 4);     ++i;   }   printf("\n\r");   i = 0;   while ( i < num_channels )   {     printf("%x", i & 0xf);     ++i;   }   printf("\n\r"); }  // // Loop //  const int num_reps = 100;  void loop(void) {   // Clear measurement values   memset(values, 0, sizeof(values));    // Scan all channels num_reps times   int rep_counter = num_reps;   while (rep_counter--)   {     int i = num_channels;     while (i--)     {       // Select this channel       radio.setChannel(i);        // Listen for a little       radio.startListening();       delayMicroseconds(512);       radio.stopListening();        // Did we get a carrier?       if ( radio.testCarrier() )         ++values[i];     }   }    // Print out channel measurements, clamped to a single hex digit   int i = 0;   while ( i < num_channels )   {     printf("%x", min(0xf, values[i] & 0xf));     ++i;   }   printf("\n\r"); }  // vim:ai:cin:sts=2 sw=2 ft=cpp 

Далее подключаем модуль nRF24L01 к плате Ардуино или любому прототипу, собранному, допустим, на контроллере ATMEGA328P. Я собрал два образца на платах для прототипирования на контроллере ATMEGA328P по схеме контроллер + резонатор. Один образец подключаю к компу через плату Arduino UNO, а второй — через конвертор USB/TTL.

Мощность стабилизатора платы Arduino UNO вполне приемлема для подключения дополнительной импульсной нагрузки такой, как nRF24L01+ c адаптером 5В/3,3В для этого модуля или без адаптера.

На мониторе последовательного порта Arduino IDE увидите нечто похожее:

Если вы увидели похожую картинку — тест на работоспособность (исправность) радиомодуля и правильность его подключения пройден успешно. Замените радиомодуль другим, с которым планируете работать дальше.

Обратите внимание на чистый диапазон, начиная с канала 4а. У меня он остается чистым даже, если на расстоянии нескольких метров работает старая СВЧ-печь — мощный источник помех в этом диапазоне. А в общем-то, в Интернете рекомендуют выбирать каналы для своих проектов выше «60».

Если на каналах — шум, но радиомодуль определяется (смотрим преамбулу на мониторе Arduino IDE, подробно тут) — это однозначно копия (подделка). Не отчаивайтесь — ее тоже можно запустить.

Шаг 2

По схеме, аналогичной первой собираем второй радиоузел. Это будет передатчик. В его контроллер загружаем скетч передатчика (под спойлером).

скетч приемника

/* Победа над nRF24L01: на три шага ближе, приемник https://habr.com/ru/post/476716/ */  #include <SPI.h> #include <RF24.h> RF24 radio(9, 10); // порты D9, D10: CSN CE const uint32_t pipe = 111156789; // адрес рабочей трубы;  byte data;  void setup() {   Serial.begin(115200);   Serial.println("TransmitterTester ON");    radio.begin();                // инициализация   delay(2000);   radio.setDataRate(RF24_1MBPS); // скорость обмена данными RF24_1MBPS или RF24_2MBPS   radio.setCRCLength(RF24_CRC_8); // размер контрольной суммы 8 bit или 16 bit   radio.setPALevel(RF24_PA_MAX); // уровень питания усилителя RF24_PA_MIN, RF24_PA_LOW, RF24_PA_HIGH and RF24_PA_MAX   radio.setChannel(0x6f);         // установка канала   radio.setAutoAck(false);       // автоответ   radio.setRetries(0, 15);  //время между попыткой достучаться, число попыток   radio.powerUp();               // включение или пониженное потребление powerDown - powerUp   radio.stopListening();  //радиоэфир не слушаем, только передача   radio.openWritingPipe(pipe);   // открыть трубу на отправку }  void loop() {   data = 109;   radio.write(&data, 1);   Serial.println("data= " + String(data)); } 

Передатчик без пауз в работе передает сигнал на канале 6f (112).

Подаем питание на сканер эфира и передатчик. Присмотритесь что творится на канале 6f и соседних с ним каналах. Сканер эфира при включенном передатчике рано или поздно прорисует единички или другие одноразрядные числа в шестнадцатиричном исчислении в области 6f, на который запрограммирован передатчик. Наберитесь терпения, особенно при работе со сканером из примеров.

Увидев сигнал от передатчика делаем следующий шаг.

Шаг 3

Загружаем вместо сканера скетч приемника (под спойлером).

скетч приемника

/* Победа над nRF24L01: на три шага ближе, передатчик https://habr.com/ru/post/476716/ */ #include <SPI.h> #include "nRF24L01.h" #include "RF24.h"  RF24 radio(9, 10); // порты D9, D10: CSN CE  const uint32_t pipe = 111156789; // адрес рабочей трубы; byte data[1]; int scn;  //счетчик циклов прослушивания эфира int sg;  //счетчик числа принятых пакетов с передатчика  void setup() {   Serial.begin(9600);   Serial.println("ReceiverTester ON");    radio.begin();  // инициализация   delay(2000);   radio.setDataRate(RF24_1MBPS); // скорость обмена данными RF24_1MBPS или RF24_2MBPS   radio.setCRCLength(RF24_CRC_8); // размер контрольной суммы 8 bit или 16 bit   radio.setChannel(0x6f);         // установка канала   radio.setAutoAck(false);       // автоответ   radio.openReadingPipe(1, pipe); // открыть трубу на приём   radio.startListening();        // приём }  void loop() {   if (scn < 1000)   { // прослушивание эфира     if (radio.available())     {       radio.read(data, 1);        if (data[0] == 109) {         sg++;       }     }   } else {//всего принято     {       Serial.println("Принято: " + String(sg) + " пакетов");       sg = 0;     }     scn = 0;   }   scn++;   delay(20);    if (scn >= 1000) scn = 1000; //защита от переполнения счетчика } 

Логика работы приемника такая же, как и у сканера эфира, но он в отличие от сканера принимает сигналы только на частоте передатчика 6f и, как и сканер, не посылает автоответ. Скорость обмена информацией и размер контрольной суммы у приемника такие же, как у передатчика. После каждых 1000-и циклов прослушивания в скетче обнуляется счетчик числа циклов и выводится инфа о количестве принятых пакетов с передатчика в монитор порта Arduino IDE.

Включаем передатчик и приемник. Если приемник принимает хотя бы каждый третий пакет — это уже успех. У меня не получилось. Приемник по непонятным причинам принимал максимум 40 пакетов.

Подумал о увеличении мощности передаваемого сигнала с помощью дополнительной антенны. Для начала, подключил крокодилом монтажный провод «папа-мама» к «корню» штатной антенны. И счастье привалило — сразу 999 принятых пакетов!

Юзерам, которые захотят сделать все грамотно, придется поработать. Дополнительная антенна в данном случае — это отрезок коаксиального кабеля с волновым сопротивлением 50 Ом и длиной 115 мм. Антенна подключается к выводу 13 (АNT2) микросхемы nRF24L01+. Схему подключения и номиналы нескольких недостающих smd компонентов, которые надо поставить на плату радиомодуля, можно найти на принципиальной электрической схеме nRF24L01+ тут. Впрочем, есть альтернатива — в магазин за NRF24L01+PA+LNA

Теперь обязательно припаиваем между пинами GND и VCC обеих радиомодулей по два конденсатора. Керамический конденсатор, выполняющий роль ВЧ-фильтра, емкостью не менее 0,15 мкФ (чем больше, тем лучше) и электролит емкостью около 10 мкФ (можно и больше, но бесполезно) — это НЧ-фильтр. ВЧ-фильтр шунтирует высокочастотные помехи по цепи питания радиомодуля, а НЧ-фильтр сглаживает пульсации питания. Для надежности, цепи питания радиомодулей лучше непосредственно подпаять к пинам контроллеров.

Все! Надеюсь, как и у меня, у вас в дальнейшем поубавится проблем с nRF24L01 в своих проектах. Успехов!

Безусловно эта простые шаги не могут гарантировать решение всех проблем с nRF24L01 — мне их и не перечесть, но теперь вы, как и я, будете уверены:

  • радиомодули не бракованные;
  • подключены верно;
  • уровень сигнала передатчика, чуствительность приемника удовлетворительны и, в случае необходимости, обеспечиваются дополнительной антенной;
  • пара nRF24L01+ однозначно работает в режиме «передатчик-приемник» без откликов и их ожидания. Иногда этого достаточно.

Ссылки по теме

  1. Обзор радио модуля NRF24L01+
  2. nRF24L01+: побеждаем модуль.
  3. nRF24L01 и Ардуино: побеждаем модуль (видео)
  4. SE8R01. Подделка под NRF24L01 (видео)
  5. Обзор радио модуля NRF24L01+PA+LNA

ссылка на оригинал статьи https://habr.com/ru/post/476716/


Комментарии

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

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