КОРЗИНА
магазина
8 (499) 500-14-56 | ПН. - ПТ. 12:00-18:00
ЛЕСНОРЯДСКИЙ ПЕРЕУЛОК, 18С2, БЦ "ДМ-ПРЕСС"

Сканер ISM диапазона на базе модуля nRF24L01 (2.4 ГГц: WiFi, Bluetooth, …)

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

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

Нам понадобится:

Для реализации проекта нам необходимо установить библиотеки:

  • Библиотека UTFT (для работы с цветными TFT дисплеями).
  • Библиотека RF24 (для работы с радио модулями nRF24L01+).

Видео:

Схема подключения:

При подключении радио модуля nRF24L01+ и TFT дисплея нужно учитывать уровни напряжений питания и логики:

  • Питание радио модуля nRF24L01+ подключается к напряжению 3,3 В, а информационные выводы могут работать от 5 В логики.
  • Питание TFT дисплея может подключаться к 5 В, а информационные выводы и питание подсветки требуют 3,3 В уровни.

Поэтому радио модуль подключается через адаптер, а TFT дисплей, через резистивные делители напряжения.

Радио модуль nFR24L01+ подключается к аппаратной шине SPI. Так как мы не используем адаптер SD карты, на обратной стороне TFT дисплея, то можем его подключать к любым выводам arduino. Питание адаптера nFR24L01+ и TFT дисплея взято с контактов GND и Vcc (5 В).

Сканер радиочастот на Arduino Uno

Таблица подключения радио модуля nFR24L01+

Адаптер nRF24L01+ Arduino Uno Назначение
CE 9 (меняется в скетче) Выбор режима: приёмник / передатчик
CSN (CS/SS) 10 (меняется в скетче) Шина SPI - выбор устройства
SСK 13 (SCK) Шина SPI - линия тактирования
MO 11 (MOSI) Шина SPI - линия данных (от мастера к ведомому)
MI 12 (MISO) Шина SPI - линия данных (от ведомого к мастеру)
IRQ Не используется Прерывание

Таблица подключения TFT дисплея 2.2” / 320×240

TFT 2.2'' Arduino Uno Назначение
SDO/MISO Не используется Линия данных от дисплея (3,3 В)
LED 5V (через делитель) Питание подсветки дисплея (3,3 В)
SСK 8 (через делитель) Линия тактирования (3,3 В)
SDI/MOSI 7 (через делитель) Линия данных к дисплею (3,3 В)
DC/RS 6 (через делитель) Выбор типа информации: команда или данные (3,3 В)
RESET 5 (через делитель) Сброс (3,3 В)
CS 4 (через делитель) Выбор устройства (3,3 В)
GND GND Общий
Vcc 5V Питание логики дисплея

Алгоритм работы:

В начале скетча мы инициируем работу радио модуля и TFT дисплея. После чего отключаем функцию автоподтверждения приёма, вызовом функции setAutoAck с параметром false и выводим координаты графика.

При каждом проходе кода loop увеличиваем номер канала от 0 до 127. Открываем очередной канал и переводим радио модуль в режим приёма данных на 50 мс, после чего отключаем приём данных. Далее обращаемся к функции testRPD, которая возвращает true только в том случае, если мощность принятого сигнала на открытом канале была выше -64 дБм. Если это так, то приращаем ячейку массива ChannelPowerNow на 1, номер ячейки массива совпадает с номером канала.

Как только просканированы все каналы, от 0 до 127. Выводим один из элементов массива ChannelPowerNow на дисплей, а саму ячейку массива обнуляем. И начинаем сканировать все каналы от 0 до 127 заново. Но по завершении сканирования выведем следующий по порядку элемент массива ChannelPowerNow. Таким образом максимальное значение для любой ячейки массива не может быть выше 127. Чем чаще на канале «встречается» мощный сигнал, тем выше значение ячейки массива.

Используя данный алгоритм, во время вывода графика, мы сканируем не очередной (выводимый) канал, а все каналы сразу. Следовательно, не пропустим даже «кратковременное» появление нового устройства на любом из каналов.

Максимальные значения ячеек массива ChannelPowerNow копируются в ячейки массива ChannelPowerMax. На дисплей выводятся графики обоих массивов и повторяют АЧХ сканируемого диапазона для текущих и максимальных показаний.

Код программы:

#include <SPI.h>                                                                                            // подключаем библиотеку SPI для работы с шиной SPI
#include "nRF24L01.h"                                                                                       // подключаем файл настроек из библиотеки RF24
#include "RF24.h"                                                                                           // подключаем библиотеку RF24 для работы с модулем nRF24L01+
#include <UTFT.h>                                                                                           // подключаем библиотеку UTFT для работы с TFT дисплеем
UTFT            myGLCD(TFT01_22SP, 7, 8, 4, 5, 6);                                                          // объявляем  объект myGLCD для работы с библиотекой UTFT, указывая тип дисплея и выводы (TFT01_22SP, SDI/MOSI, SCK, CS, RESET, DC/RS);
RF24            radio(9, 10);                                                                               // создаём объект radio для работы с библиотекой RF24, указывая номера выводов nRF24L01+ (CE, CSN)
extern uint8_t  SmallFont[];                                                                                // подключаем маленький шрифт
       uint8_t  Loading        = 0;                                                                         // первый проход по не сохраняется
       uint8_t  ChannelScan    = 0;                                                                         // номер сканируемого канала
       uint8_t  ChannelPrint   = 1;                                                                         // номер выводимого канала
       uint8_t  ChannelPowerNow[128];                                                                       // текущая мощность сигналов на каждом канале
       uint8_t  ChannelPowerMax[128];                                                                       // максимальная мощность сигналов на каждом канале
       uint16_t PositionPoints[10];                                                                         // положение точек на дисплее
const  uint16_t ColorBG          = VGA_BLACK;                                                               // цвет фона
const  uint16_t ColorScale       = VGA_BLUE;                                                                // цвет шкалы и векторов графика
const  uint16_t ColorTextLoad    = VGA_WHITE;                                                               // цвет текста отображающего проценты при старте
const  uint16_t ColorGraphNow    = VGA_WHITE;                                                               // цвет графика отображающего текущие значения
const  uint16_t ColorGraphMax    = VGA_RED;                                                                 // цвет графика отображающего максимальные значения
const  uint16_t PositionLeft     = 20;                                                                      // крайнее левое положение графика на дисплее
const  uint16_t PositionWidth    = 2;                                                                       // ширина одного канала на дисплее
const  uint16_t PositionTop      = 10;                                                                      // крайнее верхнее положение графика на дисплее
const  uint16_t PositionBottom   = 230;                                                                     // крайнее нижнее  положение графика на дисплее
const  uint8_t  PositionHeight1  = 3;                                                                       // размер каждой 1  линии каналов на нижней шкале графика
const  uint8_t  PositionHeight5  = 9;                                                                       // размер каждой 5  линии каналов на нижней шкале графика
const  uint8_t  PositionHeight10 = 15;                                                                      // размер каждой 10 линии каналов на нижней шкале графика
const  uint8_t  FactorGraph      = 4;                                                                       // множитель значений графика
void setup(){
//  подготавливаем дисплей и модуль к работе
    myGLCD.InitLCD();                                                                                       // инициируем дисплей
    myGLCD.fillScr(ColorBG);                                                                                // заливаем дисплей цветом фона
    myGLCD.setFont(SmallFont);                                                                              // устанавливаем маленький шрифт
    myGLCD.setBackColor(ColorBG);                                                                           // устанавливаем цвет фона для фона текста
    radio.begin();                                                                                          // инициируем работу модуля nRF24L01+
    radio.setAutoAck(false);                                                                                // отключаем режим подтверждения приёма
    memset(ChannelPowerNow, 0, sizeof(ChannelPowerNow));                                                    // заполняем все элементы массива ChannelPowerNow значением 0
    memset(ChannelPowerMax, 0, sizeof(ChannelPowerMax));                                                    // заполняем все элементы массива ChannelPowerMax значением 0
    PositionPoints[6]=PositionBottom-myGLCD.getFontYsize();                                                 // положение текста с номерами каналов
    PositionPoints[7]=PositionBottom-myGLCD.getFontYsize()*2;                                               // положение текста с числами частот
    PositionPoints[8]=PositionBottom-myGLCD.getFontYsize()*2-PositionHeight10;                              // положение нулевой координаты по оси Y
//  выводим нижнюю шкалу графика для всего диапазона каналов
        myGLCD.setColor(ColorScale);                                                                        // устанавливаем цвет заливки шкалы
    for(uint8_t i=0; i<128; i++){                                                                           // создаём цикл по всему диапазону каналов
        PositionPoints[9]=PositionLeft+i*PositionWidth;                                                     // положение координаты очередного канала по оси X
        myGLCD.drawLine(PositionPoints[9],i?PositionPoints[8]:PositionTop,PositionPoints[9],PositionPoints[8]+(i%10?(i%5?PositionHeight1:PositionHeight5):PositionHeight10));  // выводим вертикальные линии шкалы графика
        if(i%20==0){myGLCD.printNumI(i, PositionPoints[9]-(i==0?(myGLCD.getFontXsize()/2):(i<100?(myGLCD.getFontXsize()):(myGLCD.getFontXsize()*3/2))), PositionPoints[7]);} // выводим текст - номера каналов
        if(i%40==0){myGLCD.printNumI(((int)2400+i), PositionPoints[9]-(i==0?(myGLCD.getFontXsize()/2):(myGLCD.getFontXsize()*2)), PositionPoints[6]);} // выводим текст - частоты каналов
    }   myGLCD.drawLine(PositionLeft,PositionPoints[8],(PositionLeft+128*PositionWidth),PositionPoints[8]); // выводим горизонтальную линию
        myGLCD.print("N",   PositionLeft+129*PositionWidth, PositionPoints[7]);                             // выводим название шкалы - номер  канала
        myGLCD.print("MGz", PositionLeft+129*PositionWidth, PositionPoints[6]);                             // выводим название шкалы - частота канала
}
void loop(){
//  сканируем очередной канал и сохраняем его данные
    radio.setChannel(ChannelScan);                                                                          // устанавливаем очередной канал работы модуля
    radio.startListening();                                                                                 // начинаем прослушивать очередной канал
    delayMicroseconds(50);                                                                                  // ждём 50 мкс
    radio.stopListening();                                                                                  // останавливаем прослушивание
    if(radio.testRPD()){ChannelPowerNow[ChannelScan]++;}                                                    // если сигнал на указанном канале имел мощность > -64 дБм, то увеличиваем значение в массиве ChannelPowerNow для текущего канала (функция не работает на модулях nRF24L01 без знака «+»)
    if (ChannelPowerMax[ChannelScan]<ChannelPowerNow[ChannelScan]){                                         // если мощность отсканированного канала превышает ранее полученное максимальное значение для этого канала, то ...
        ChannelPowerMax[ChannelScan]=ChannelPowerNow[ChannelScan];                                          // сохраняем мощность отсканированного канала как максимальную
    }   ChannelScan++;                                                                                      // увеличиваем номер сканируемого канала
//  выводим полученные данные                                                                               // данные выводятся по одному каналу, через полный цикл сканирования всех каналов
    if(ChannelScan==127){                                                                                   // если был просканирован последний возможный канал, то ...
        ChannelScan=0;                                                                                      // переходим к 0 каналу
        if(Loading<128){                                                                                    // если это первый проход по диапазону каналов после пуска, то
            Loading++;                                                                                      // увеличиваем счетчик каналов
            myGLCD.setColor(ColorTextLoad);                                                                 // устанавливаем цвет текста отображающего проценты при старте
            if(Loading>=128){myGLCD.print("    ",CENTER, PositionTop+10);}                                  // стираем текст
            else{myGLCD.print((String)map(Loading,0,127,0,100)+"%",CENTER,PositionTop+10);}                 // выводим количество процентов загруженной информации о мощности сигналов в каналах
        }else{                                                                                              // если это не первый проход по диапазону каналов, то ...
//          Рассчитываем положение точек графиков на дисплее
            PositionPoints[0]=PositionPoints[8]-ChannelPowerMax[ChannelPrint-1]*4; if(PositionPoints[0]<PositionTop){PositionPoints[0]=PositionTop;} // координата 1 точки по оси Y для графика максимальных значений
            PositionPoints[1]=PositionPoints[8]-ChannelPowerMax[ChannelPrint  ]*4; if(PositionPoints[1]<PositionTop){PositionPoints[1]=PositionTop;} // координата 2 точки по оси Y для графика максимальных значений
            PositionPoints[2]=PositionPoints[8]-ChannelPowerNow[ChannelPrint-1]*4; if(PositionPoints[2]<PositionTop){PositionPoints[2]=PositionTop;} // координата 1 точки по оси Y для графика текущих значений
            PositionPoints[3]=PositionPoints[8]-ChannelPowerNow[ChannelPrint  ]*4; if(PositionPoints[3]<PositionTop){PositionPoints[3]=PositionTop;} // координата 2 точки по оси Y для графика текущих значений
            PositionPoints[4]=(ChannelPrint-1)*PositionWidth+PositionLeft;                                  // координата 1 точки по оси X для обоих графиков
            PositionPoints[5]= ChannelPrint   *PositionWidth+PositionLeft;                                  // координата 2 точки по оси X для обоих графиков
//          Выводим графики на дисплей
            myGLCD.setColor(ColorBG);       myGLCD.fillRect(PositionPoints[4]+1,0,PositionPoints[5],PositionPoints[8]);                              // стираем с дисплея часть предыдущих графиков
            myGLCD.setColor(ColorScale);    myGLCD.drawLine(PositionPoints[4],PositionPoints[8],PositionPoints[5],PositionPoints[8]);                // выводим горизонтальную часть линии шкалы
            myGLCD.setColor(ColorGraphMax); myGLCD.drawLine(PositionPoints[4],PositionPoints[0],PositionPoints[5],PositionPoints[1]);                // выводим график максимальных данных
            myGLCD.setColor(ColorGraphNow); myGLCD.drawLine(PositionPoints[4],PositionPoints[2],PositionPoints[5],PositionPoints[3]);                // выводим график текущих данных
        }   ChannelPowerNow[ChannelPrint-1]=0;                                                              // стираем показания мощности для только что выведенного канала
            ChannelPrint++; if(ChannelPrint==128){ChannelPrint=1;}                                          // увеличиваем номер выводимого канала
    }
}

Скачать

Ссылки:

  • Библиотека UTFT (для работы с цветными TFT дисплеями).
  • Библиотека RF24 (для работы с радио модулями nRF24L01+).
  • Код программы.



Обсуждение

Гарантии и возврат Используя сайт Вы соглашаетесь с условями