Організувавши взаэмодію радіо модуля з Arduino, можна управляти роботом, серво приводами і моторами за допомогою пульта управління, організувати телеметрію, збір даних з віддалених об'єктів: температура, вологість, дані лічильників і багато іншого.
Радіо модуль nRF24L01+
Заявлена дальність до 1100 метрів при швидкості 250 кбіт. При 1Мбіт - 750 метрів, а при швидкості 2 Мбіт - 520 метрів. Швидше за все, ці параметри вказані при відсутності перешкод і якщо всі радіо модулі в радіомережі будуть однаковими.
Кількість каналів: 126. Нульовий канал починається з 2400МГц і далі з кроком 1 мегагерц, наприклад, 70 канал знаходиться відповідно на частоті 2470мгц. При установці швидкості 2 МГц займається ширина двох каналів.
Рекомендується зменшувати надлишкову потужність через setPALevel (в бібліотеці) або безпосередньо в регістрі RF_SETUP.
Модуль nRF24L01+ (ліворуч) і модуль nRF24L01+ PA + LNA (праворуч)
Інтерфейс SPI
Для взаємодії з модулями nRF24L01+ ми повинні використовувати шину SPI. SPI - послідовний інтерфейс (Serial Peripheral Interface), який працює з налаштуванням ведучий/ведений. Шина SPI може працювати з одним головний (master) пристроєм і одним або декількома підлеглими (slave) пристроями. Використовуються три загальні з’єднання і одне додаткове для кожного з залежних (ведених) пристроїв. Трьома загальними з’єднаннями (пов'язаними з усіма пристроями) є:
- SCLK(SCK): тактування (вихід з майстра)
- MOSI: головний (master) вихід (output) - вхід (input) веденого (slave): вихід з master
- MISO: вхід (input) master - вихід (output) веденого (slave): вихід із slave
- Додаткове з’єднання називається SS (slave select – вибір залежного) або CS (chip select – вибір мікросхеми) або CE (chip enable – дозвіл мікросхеми)
Функція SS полягає в забезпеченні веденого пристрою, з яким ми хочемо спілкуватися (одночасно може бути включений тільки один ведений). У нашому випадку ми будемо використовувати тільки один залежних пристрій, але ви можете побачити загальну схему з кількома веденими пристроями на рис.:
Типова шина SPI: master і три незалежні slaves.
Підготовка Arduino
Ми почнемо з підготовки Arduino, бо це найлегша частина. Дана інструкції для Arduino UNO, але ви можете використовувати будь-яку плату Arduino, але майте на увазі, що з’єднання, як правило, відрізняються. Якщо будете шукати свою модель Arduino в Інтернеті, то знайдіть, які виводи ви повинні використовувати для SPI. У наступній таблиці ви бачите необхідні з'єднання для Arduino UNO:
Ви повинні запам’ятати кілька речей:
• Модуль працює з 3.3 В, тому вам доведеться підключитися до даного виводу, а не до виводу 5 В
• Модуль використовує додаткове з’єднання “data”, крім SPI, так званий CE
• Бібліотека не використовує вивід SS Arduino, а звичайний цифровий вивід як SS
• Обидва з’єднання (CE і SS) визначається при ініціалізації бібліотеки і можуть бути змінені
• SCK, MOSI і MISO з'єднання "Arduino залежні", і будуть іншими, якщо ви використовуєте іншу плату Arduino
• 8-ий вивід модуля для переривань і в даний час в бібліотеці він не використовується
Маємо схему під’єднання модуля nRF24L01+ до Arduino:
Для надійної роботи рекомендується підключити паралельно живленню якомога ближче до радіо модулів електролітичний конденсатор не менше 100 мкФ, а також паралельно йому керамічний на 0.1 мкФ.
Радіо сканер діапазону WiFi
Найпростіший пристрій – радіо сканер, для якого необхідний лише один модуль nRF24L01+. Він діє як простий сканер і показує радіосигнали навколо нього.
Тепер встановіть бібліотеку RF24. Завантажити її можна звідси. Для установки розпакуйте файли і перейменуйте папку в RF24 (з RF24-master) і помістіть цю папки у папку вашої бібліотеки Arduino (наприклад, був на Desktop / Arduino-1.0.5 / бібліотеки /) і перезавантажте Arduino IDE. Тепер бібліотека готова до роботи. Тепер можете завантажити і протестувати приклад скетча.
Вставте наведений скетч в Arduino IDE і завантажити в плату UNO. Відкриємо послідовний монітор, натиснувши на маленьку кнопку з лупою на IDE, і встановимо швидкість передачі даних 57600 (інакше ви побачите деякий текст-тарабарщину):
#include <SPI.h> // Підключаємо бібліотеку SPI
// Простий сканер діапазону 2.4ГГц
// використовує nRF24L01p, приєднаний до Arduino
// Схема приєднань:
// SS(CSN) -> 10
// MOSI -> 11
// MISO -> 12
// SCK -> 13
// CE -> 9
#define CE 9
// Масив для зберігання даних каналу
#define CHANNELS 64
int channel[CHANNELS];
// відтінки сірого зображення
int line;
char grey[] = " .:-=+*aRW";
// необхідні регістри nRF24L01P
#define _NRF24_CONFIG 0x00
#define _NRF24_EN_AA 0x01
#define _NRF24_RF_CH 0x05
#define _NRF24_RF_SETUP 0x06
#define _NRF24_RPD 0x09
// отримуємо значення регістра nRF24L01p
byte getRegister(byte r)
{
byte c;
PORTB &=~_BV(2);
c = SPI.transfer(r&0x1F);
c = SPI.transfer(0);
PORTB |= _BV(2);
return(c);
}
// встановлюємо значення регістра nRF24L01p
void setRegister(byte r, byte v)
{
PORTB &=~_BV(2);
SPI.transfer((r&0x1F)|0x20);
SPI.transfer(v);
PORTB |= _BV(2);
}
// подаємо живлення на мікросхему nRF24L01p
void powerUp(void)
{
setRegister(_NRF24_CONFIG,getRegister(_NRF24_CONFIG)|0x02);
delayMicroseconds(130);
}
// вимикаємо nRF24L01p
void powerDown(void)
{
setRegister(_NRF24_CONFIG,getRegister(_NRF24_CONFIG)&~0x02);
}
// дозволяємо RX (приймач)
void enable(void)
{
PORTB |= _BV(1);
}
// вимикаємо RX (приймач)
void disable(void)
{
PORTB &=~_BV(1);
}
// встановлюємо режим RX на nRF24L01p
void setRX(void)
{
setRegister(_NRF24_CONFIG,getRegister(_NRF24_CONFIG)|0x01);
enable();
// тут трохи менша, ніж рекомендується
// затримка в 130 мкс
// - але працює і трохи прискорює процес...
delayMicroseconds(100);
}
// скануємо всі канали в діапазоні 2.4ГГц
void scanChannels(void)
{
disable();
for( int j=0 ; j<200 ; j++)
{
for( int i=0 ; i<CHANNELS ; i++)
{
// вибираємо новий канал
setRegister(_NRF24_RF_CH,(128*i)/CHANNELS);
// перемикаємо на RX
setRX();
// достатнє чекання для регулювання RX
delayMicroseconds(40);
// це актуальна точка, де встановлюється RPD-прапор
// коли CE стає низьким
disable();
// читаємо наш RPD-прапор; встановлюємо в 1, якщо
// прийнята потужність > -64dBm
if( getRegister(_NRF24_RPD)>0 ) channel[i]++;
}
}
}
// виводимо дані каналу у вигляді простої сірої карти
void outputChannels(void)
{
int norm = 0;
// знаходимо максимальну кількість в масиві каналу
for( int i=0 ; i<CHANNELS ; i++)
if( channel[i]>norm ) norm = channel[i];
// тепер виводимо дані
Serial.print('|');
for( int i=0 ; i<CHANNELS ; i++)
{
int pos;
// розрахунок значення сірої позиції
if( norm!=0 ) pos = (channel[i]*10)/norm;
else pos = 0;
// збільшення низьких значень
if( pos==0 && channel[i]>0 ) pos++;
// зменшення великих значень
if( pos>9 ) pos = 9;
// виведення
Serial.print(grey[pos]);
channel[i] = 0;
}
// відображення загальної потужності
Serial.print("| ");
Serial.println(norm);
}
// надання візуалізації між WLAN-каналами і відображеними даними
void printChannels(void)
{
// приблизні вихідні позиції WLAN-каналів
Serial.println("> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <");
}
void setup()
{
Serial.begin(57600);
Serial.println("Starting Poor Man's Wireless 2.4GHz Scanner ...");
Serial.println();
// Макет каналів
// 0 1 2 3 4 5 6
// 0123456789012345678901234567890123456789012345678901234567890123
// 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
//
Serial.println("Channel Layout");
printChannels();
// Налаштування SPI
SPI.begin();
SPI.setDataMode(SPI_MODE0);
SPI.setClockDivider(SPI_CLOCK_DIV2);
SPI.setBitOrder(MSBFIRST);
// Активація дозволу мікросхеми
pinMode(CE,OUTPUT);
disable();
// тепер запуск приймача
powerUp();
// вимикаємо Shockburst
setRegister(_NRF24_EN_AA,0x0);
// перконуємося, що RF-секція налаштована вірно
// - просто записуємо значення за замовчуванням...
setRegister(_NRF24_RF_SETUP,0x0F);
// обнулюємо лічильник лінії
line = 0;
}
void loop()
{
// виконуємо сканування
scanChannels();
// виведимо результат
outputChannels();
// виведення довідника WLAN-каналу кожну 12-ту лінію
if( line++>12 )
{
printChannels();
line = 0;
}
}
Передача даних від ультразвукового вимірювача відстані
Один модуль під’єднаний до плати Arduino UNO, яка буде підключена до комп’ютера, другий же, після завантаження скетча може бути відключений від комп’ютера і живитися від окремого джерела. До нього приєднується модуль ультразвукового вимірювача відстані (Trig – вивід 4, Echo – вивід 3) , з якого дані передаються на перший модуль і відображаються на моніторі послідовного порту комп’ютера.
Скетч передавача
#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>
#include "Ultrasonic.h"
#define MAX_BUFF 32
Ultrasonic ultrasonic(4,3); //Trig - 4, Echo - 3
void setup(){
Serial.begin(9600);
Mirf.cePin = 7;
Mirf.csnPin = 8;
Mirf.spi = &MirfHardwareSpi;
Mirf.init();
Mirf.setRADDR((byte *)"app1");
Mirf.payload = sizeof(unsigned int);
// Mirf.channel = 10;
Mirf.config();
Serial.println("Beginning ... ");
}
void loop(){
unsigned int range;
//відправка даних
Mirf.setTADDR((byte *)"app2");
range = ultrasonic.Ranging(CM);
Mirf.send((uint8_t *)&range);
while(Mirf.isSending()){
}
Serial.println(range);
delay(100);
}
Скетч приймача
#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>
#define MAX_BUFF 32
void setup(){
Serial.begin(9600);
Mirf.cePin = 7;
Mirf.csnPin = 8;
Mirf.spi = &MirfHardwareSpi;
Mirf.init();
Mirf.setRADDR((byte *)"app2");
Mirf.payload = sizeof(unsigned int);
// Mirf.channel = 10;
Mirf.config();
Serial.println("Beginning ... ");
}
uint8_t buff[4];
int c_count = 0;
void loop(){
int i;
//приймання даних
while(!Mirf.dataReady()) {
}
Mirf.getData(buff);
Serial.println((unsigned int)*buff);
delay(100);
}
Приймач-передавач
Можна організувати і двох направлене приймання-передавання. Звичайно, при використанні двох пристроїв, код повинен бути різним для приймачів-передавачів.
Просто в одному поставити Mirf.setRADDR((byte *)"app1");
а в другому Mirf.setRADDR((byte *)"app2");
відповідно, в першому Mirf.setTADDR((byte *)"app2");
а в другому Mirf.setTADDR((byte *)"app1");
Код скетча для Arduino:
#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>
#define MAX_BUFF 32 //Буфер приймання-передавання
void setup(){
Serial.begin(9600);
Mirf.spi = &MirfHardwareSpi;
Mirf.init();
Mirf.setRADDR((byte *)"app2"); //Тут задаємо адресу
Mirf.payload = MAX_BUFF; //Тут задаємо буфер
Mirf.channel = 10;
//Канал приймання-передавання - повинен
//бути однаковим в пристроях.
Mirf.config();
Serial.println("Start..");
}
char buff[MAX_BUFF];
int c_count = 0;
void loop(){
int i;
//sending
if (c_count = Serial.available()) {
if (c_count <= MAX_BUFF) {
for (i=0; i<c_count; i++) {
buff[i] = Serial.read();
}
} else {
for (i=0; i<MAX_BUFF; i++) {
buff[i] = Serial.read();
}
}
buff[i] = 0;
Mirf.setTADDR((byte *)"app1"); //Адрес!
Serial.print(">");
Mirf.send((uint8_t *)buff);
while(Mirf.isSending()){
}
Serial.println(buff);
}
delay(10);
//receiving
if(Mirf.dataReady()) {
Mirf.getData((uint8_t *)buff);
Serial.print("<");
Serial.println(buff);
}
delay(100);
}
(За матеріалами: arduino.ru. blog.riyas.org. geek.kg)