Yazar: z1rqdym

MERHABA ARKADAŞLAR

Aslında ilk zamanlardan beri üzerinde kafa patlattığım ancak bir çok farklı sebepten dolayı hep askıya aldığım zaman zaman datasheet’lerini alt üst ettiğim ve kütüphanesini yazmaya kalkıştığım fakat başarısız olduğum bir kablosuz haberleşme modülü olan nRF24L01’den bu konu ile sizlere bahsedeceğim. Sonunda çalışır aksama yapmayan bir nRF24L01 kütüphanesi buldum ve sizlere bu kütüphane ile nRF24L01 nasıl kullanılır hepsini anlatmış olacağım. Elimde bu modülden sadece iki adet olmasından dolayı ikiden fazla nRF24L01 nasıl bir biri ile haberleştirilir ile ilgili deneme yapamadığımdan çoklu nRF24L01 uygulamasını daha sonra ayrı bir konu olarak paylaşacağım.

Başlayalım…

nRF24L01 NEDİR?
Nordic firması tarafından geliştirile 2.4GHz frekans bandında hem alıcı hemde verici özelliğinde çalışan bir dijital radyo frekans kablosuz haberleşme çipidir. Aşağıda bu çipe ait görsel bulunmaktadır.
nRF24L01
nRF24L01 mikrodenetleyiciler ile SPI haberleşme protokolü ile iletişim kurmaktadır. QFN20 kılıf yapısında SMD olarak üretildiğinden bu çipi alıp kullanmak çok zahmetlidir. Bu yüzden piyasada modül olarak üretilip satılmaktadır. Bu modüller nRF24L01 datasheet’inde bulunan referans modül tasarımını baz alınarak üretilmektedirler. Aşağıda nRF24L01 modülü ve bacak isimleri görülmektedir.

nRF24L01 pin isimleri

 

SPI iletişimde kullanılan temelde 4 adet bağlantı vardır. MOSI, MISO, SCK ve SS adlı bu bacaklardan MOSI ve MISO veri alış verişi için, SCK saat sinyali için ve SS slave cihazı seçmek için kullanılmaktadır.

nRF24L01 bir slave cihaz olarak çalışmaktadır. Buna göre aşağıdaki şekilde Arduino’nun veya başka bir mikrodenetleyici ile kullanılacağı zaman SPI bacakları ile bağlanması gerekmektedir. Slave cihazı kontrol eden cihaz ise Master cihazdır. Bu durumda Arduino veya başka bir mikrodenetleyici Master cihazdır.

nRF24L01 devre şeması

Dikkat etmeniz gereken tek şey SCK MISO ve MOSI bağlantılarıdır. IRQ, CS ve CE bacaklarını arduinoda istediğiniz yere bağlayabilirsiniz. IRQ pini için özel bir durum var tabi o da IRQ bacağını Arduino’nun harici kesme özelliği olan pinlerden birine bağlamalısınız. Başka pinlere bağlasanızda olur ancak bağlamanız durumunda IRQ pininden gelen sinyalleri Arduino daha kararlı algılayacaktır ve nRF24L01 ile Arduino arasında veri kayıpları meydana gelmeyecektir. CS bacağı ise Arduino’da SS pininne bağlanması gereklidir ancak herhangi bir pine bağlanmasında da sorun yoktur.

Zaten kütüphaneyi kullanırken CS CE ve IRQ bacaklarını arduino’da hangi pine bağlayacağımızı seçiyoruz.

Özetle bağlantı şu şekilde olmalıdır.

nRF24L01              Arduino
MOSI              =>     MOSI (NANO ve UNO için 11, MEGA için 51, MICRO için MOSI)
MISO              =>     MISO (NANO ve UNO için 12, MEGA için 50, MICRO için MISO)
SCK                =>     SCK   (NANO ve UNO için 13, MEGA için 52, MICRO için SCK)
CS                  =>     SS     (NANO ve UNO için 10, MEGA için 53, MICRO için SS)
CE                  =>     Herhangi bir dijital pin olabilir yukarıdaki şemada pin 9’a bağlı
IRQ                =>     Herhangi Harici kesme özelliği olan bir dijital pine bağlanabilir şemada UNO ve NANO için bunlardan birisi olan pin 2’ye bağlı
VCC                =>     +3.3V (kesinlikle +5V’a bağlamayınız modülünüz anında bozulacaktır!!!)
GND               =>     GND

Buraya kadar nRF24L01 nedir nasıl bir yapısı vardır ve bir Arduino veya herhangi bir mikrodenetleyici ile nasıl bağlanılacağını gördük. Şimdi sizlere alıcı verici modülünü Arduino ile kullanabilmek için benim de kullandığım bir kütüphaneyi tanıtacağım.

nRF24L01 KÜTÜPHANESİ – Enrf24
github üzerinden spirilis kullanıcı adında bir geliştirici tarafından paylaşılmış olan bu nRF24L01 kütüphanesi sanırım daha önce denediğim bir çok geleiştiriciye ait olan kütüphaneler arasında en iyisi ve en sorunsuzu. Fonksiyonlarının sürekli bir döngü içerisinde bulunması gerekmemesi bence en iyi yanlarından biri. Bu sayede kodlarınızı aksatmak zorunda kalmadan gereken yerde istediğiniz yerde nRF24L01’ler arasında veri alıp gönderebilirsiniz.

Kütüphaneyi kullanabilmek için dikkat etmeniz gereken 3 nokta var;

  • Hazırlık Bloğu
#include <Enrf24.h>
#include <nRF24L01.h>
#include <SPI.h>

Enrf24 nRF(9, 10, 2);  // CE , CSN/CS/SS , IRQ

// aşağıdaki değişken tanımlaması satırlarından sadece biri kullanılacak
const byte verici_adresi[] = { 0xDE, 0xAD, 0xBE, 0x0F, 0x01 }; // verici kodları için 
const byte alici_adresi[] = { 0xDE, 0xAD, 0xBE, 0x0F, 0x01 }; // alıcı kodları için

Burada dikkat etmeniz gereken hem alıcı hem de verici kodlarında neredeyse aynı satırları yazılacak olmasıdır.

Hazırlık Bloğu programın en başında olup toplamda 3 adet başlık dosyası dahil edilmiştir. Kesinlikle yukarıdaki sıralamada olmalıdır aksi halde derleme sorunları yaşayabilirsiniz.Daha sonra “Enrf24” adlı nesneye “nRF” şeklinde yeni bir ad veriyoruz siz istediğiz ismi yazabilirsiniz. Parantez içerisinde sırayla nRF24L01 modülünde bulunan CE, CSN/CS/SS ,IRQ adlı 3 adet pinin arduinoda hangi dijital pinlere bağlayacağımızı belirtiyoruz. Yukarıdaki şemada CE 9 nolu pine, CS 10 nolu pine ve IRQ ise 2 nolu pine bağlanmıştır ve bunlar parantez içerisinde de belirtilmiştir. Modülün IRQ bacağının Arduinonun harici kesme özelliği olan dijital pinlerinden birine bağlı olmasını tavsiye ederim, 2 nolu pin bunlardan biridir.

En sonda ise const byte verici_adresi[]={…..}; şeklinde bir değişken tanımlaması görüyorsunuz. Burada verici modülümüzün veya alıcı ise alıcı modülümüzün eşleşmesi için gerekli olan 5 adet adres verisi tanımlıyoruz. Verici kodlarında da alıcı kodlarında da bu 5 adet adres verisi bire bir aynı olmak zorundadır aksi halde iki modül bir biri ile iletişim kuramazlar. siz istediğiniz  veriyi yazabilirsiniz.

Örneğin Verici için:
const byte verici_adresi[]={ 0xFF , 0xFF , 0x00 , 0x11 , 0x01 };
Örneğin Alıcı için:
                                                  const byte alici_adresi[]={ 0xFF , 0xFF , 0x00 , 0x11 , 0x01 };

  • Setup Bloğu
  // Verici için Setup() bloğu //
  ///////////////////////////////
  SPI.begin(); // SPI başlat
  SPI.setDataMode(SPI_MODE0); // SPI MODE0 seçildi
  SPI.setBitOrder(MSBFIRST); // bit sıralaması MSB'den LSB'ye doğru ayarlandı
  
  // veri-oranı 250000/1000000/2000000, kanal 0/125
  nRF.begin(1000000,124);  
  nRF.setTXaddress(verici_adresi);
  // Alıcı için Setup() bloğu //
  //////////////////////////////
  SPI.begin(); // SPI başlat
  SPI.setDataMode(SPI_MODE0); // SPI MODE0 seçildi
  SPI.setBitOrder(MSBFIRST); // bit sıralaması MSB'den LSB'ye doğru ayarlandı

  // datarate 250000/1000000/2000000, channel 0/125
  nRF.begin(1000000,124); 
  nRF.setRXaddress(alici_adresi);
  nRF.enableRX();  // Dinlemeye başla

Burada ise Setup() fonksiyonu içerisine nRF24L01 modülümüzü alıcı veya verici olarak ayarlayacağımız ve arduino ile iletişime hazır hale getiren ve aynı zamanda Arduinonun SPI donanımını iletişimie hazırlayan fonksiyonları yazıyoruz.

Bizim için önemli olan burada toplamda 4 fonksiyon var, Enrf24 kütüphanesine ait olan nRF.begin() ,  nRF.setTXaddress() , nRFsetRXaddress() ve nRF.enableRX() fonksiyonlarıdır.

Fonksiyonların başlarındaki nRF, Hazırlık bloğunda Enrf24 nesne adını nRF yaptığımızdan dolayıdır. Eğer bu nesne adını LRT yapsaydık;
Örneğin:

Enrf24 LRT(9,10,2);
fonksiyon adları LRT.begin(); , LRT.setTXaddress(); vs… şeklinde olurdu.​

nRF.begin(parametre1, parametre2); fonksiyonu ve parametreleri
Parametre1 yerine 250000, 1000000 veya 2000000 değerleri yazılabilir. bu değerler bir saniyede gönderilen bit sayısını ifade etmektedir. eğer 1000000 yazarsanız saniyede 1Mbit veri yollayabilecek şekilde nRF24L01 ayarlanmaktadır. Yani bu bizim veri iletişim hızımızı belirlemektedir. Ben 1Mbit yani 1000000 değerini kullanıyorum siz isterseniz diğerlerini de kullanabilirsiniz.

Parametre2 ise iletişim kanalımızı belirliyor. nRF24L01 toplamda 126 kanaldan aynı anda sadece birinden iletişim yapabilmektedir ve seçilen kanal 0-125 arasında bir sayı olarak parametre2 yerine yazılmalıdır.

Hem kanallar hem de iletişim hızları alıcı ve verici kodlarında aynı olmalıdır. yani bu fonksiyon ve parametre değerleri verici ve alıcıda bire bir aynı olmalıdır.

nRF.setTXaddress(parametre); ve nRF.setRXaddress(parammetre); fonksiyonları ve parametresi
Tek bir parametresi var. Parametre olarak Hazırlık Bloğunda tanımladığımız:
verici için;

const byte verici_adresi[]={ 0xFF , 0xFF , 0x00 , 0x11 , 0x01 };

alıcı için;

const byte alici_adresi[]={ 0xFF , 0xFF , 0x00 , 0x11 , 0x01 };

adres değişkenlerinin isimlerini yazıyoruz:
Verici için;

nRF.setTXaddress(verici_adresi);

Alıcı için;

nRF.setRXaddress(alici_adresi);

şeklinde kullanıyoruz.

nRF.enableRX(); fonksiyonu
Bu fonksiyon sadece alıcı tarafı için yazılan kodlarda kullanılmaktadır. Bu fonksiyonu çağırdığımız anda nRF24L01 alıcı moda geçerek gelecek verileri dinlemeye başlar ve gelen bir veri olduğunda bunu kendi hafızasında okunmaya hazır vaziyette bekletir. sadece Setup() fonksiyonu içerisinde ” nRF.setRXaddress(alici_adresi); ” fonksiyonunun hemen ardından kullanılmalıdır.

  • Loop Bloğu VERICI KODLARI için
   // Verici tarafında kullanılan bu iki fonksiyon arka arkaya kullanılmalıdır. //
   ///////////////////////////////////////////////////////////////////////////////
   nRF.print(...);
   nRF.flush();  

Loop Bloğu hem verici hemde alıcı taraf için farklılıklar içerdiğinden önce kolay olan verici tarafından bahsetmek istiyorum.

nRF.print(…); fonksiyonu
bu fonksiyon içine …’lı yere yazılan değişken bir string ifade olabilir, int , char , byte veya float türünde bir değişken bir bilgi veya değer olabilir bir dizi olabilir hiç fark etmez. Veriyi her türlü alıcıya yollamaktadır.

nRF.flush(); fonksiyonu
Bu fonksiyon nRF.print(…); fonksiyonundan hemen sonra kullanılmalıdır. Bu fonksiyon ile vericinin gönderdiği verileri paketler halinde göndermesini sağlamış oluyoruz. Bunu kullanmazsak arka arkaya gönderilen veriler tek tek değil arka arkaya bitişik ve bir bütün olarak yollanmaktadır. Tavsiyem kullanmanızdan yanadır.

Loop Bloğu ALICI KODLARI için
Burada bilinmesi gereken en önemli şey alıcı kodlarında kullanılan okuma fonksiyonun okuduğu değerlerin string değerde olduğudur. Yani okunan veri aslında yazı tipindedir. Alınan veri 1234 şeklinde bir rakam değil karakter dizisidir. Bu yüzden okunan değerleri bir dizi değişkene aktarılması gerekmektedir. Bu dizi değişkeni Arduino’nun RAM hafızasını çok doldurmaması için çok geniş tutulmamalıdır. tavsiye olarak en fazla 100 byte genişliğinde bir dizi değişken tanımlanması yönündedir.
Ancak okunan veri sayısal değerler olduğu durumlarda bu değerler karakter olduğundan dolayı bunları daha sonra hesaplama işlemlerinde doğrudan kullanamayız. Bu yüzden rakam karakterlerini sayısal değerler dönüştüren atoi(); adlı fonksiyonu kullanmamız gerekmektedir. atoi(); fonksiyonunu kullanabilmek için kodların en başında Enrf24, nrf24l01 ve SPI kütüphane dosyalarının yanında birde string kütüphaneside tanımlanmalıdır.
Gelen verileri akataracağımız dizi değişekni ise loop içerisinde tanılanması da daha doğru olacaktır. Bu şekilde gereksiz olduğu durumlarda Arduino RAM hafızasında sürekli yer kaplamamış oluruz. Aşağıda Loop Bloğu için Alıcı kodlarına ait temel ifadeler görlmektedir.

#include <Enrf24.h>
#include <nRF24L01.h>
#include <string.h> // konuda bahsedilen string kütüphanesi
#include <SPI.h>

void loop()
{
  char gelen_bilgi[33]; // gelen bilgi için geçici dizi değişken
  int bilgi=0; // strinden sayısala dönüşümden sonra okunana değerin saklanacağı değişken tanımlandı
  if (nRF.read(gelen_bilgi)) // vericiden bilgi geldiyse bunu gelen_bilgi adlı dizi değişkene aktarmaktadır.
  {
    bilgi = atoi(gelen_bilgi); // string ifadeyi decimal yani sayısal hale dönüştürme işlemi
  }
}

Yukarıda setup() görülmemektedir bu önemli değil maksat gerekli yerleri göstermek daha sonra örnek uygulama da hem alıcı hemde verici için tam kodlarda neyin nasıl kullanıldığını daha iyi görmüş olacaksınız.

gelen_bilgi char tipinde 33byte genişliğinde bir dizi değişkendir. bilgi int tipinde yani decimal bir değişken olup atoi() fonksiyonu ile string yani karakter türünde dizi ifadeyi sayısal hale dönüştüren fonksiyon sonucunda elde edilen sayısal bilginin saklanacağı değişkendir.
Bu iki değişkende yerel değişkendir ve içinde bulunduğu döngü boyunca vardırlar her döngü başında yeniden tanımlanır ve sıfırlanırlar.

nRF.read(…); fonksiyonu ve parametresi
bu fonksiyon ile gelen bir veri var mı yok mu bize geri döndürür. gelen veri varsa 1 sonucunu döndürür ve içindeki …’lı yere yazılan dizi değişken tipinde bir değilken adı ile parametresi olmaktadır ve gelen veriyi bu dizi değişkene kaydeder.

Şimdi gelin sizlere nRF24L01 modülü ile Alıcı ve Verici uygulamasına ait Arduino kodlarını görelim.
Bu kodlar minimum kodlardır ve gerektiğinde istediğiniz şekilde kendi projenize uyarlayarak kullanabilirsiniz.

ARDUINO ile nRF24L01 ALICI VE VERICI UYGULAMASI
Bu uygulama ile Verici tarafı ile bir buton ile alıcı tarafındaki bir LED aç kapat yapılacak ve aynı zamanda yine verici tarafında bir potansiyometre ile alıcı tarafındaki bir LED’in parlaklığı ayarlanacaktır. Bu sayede yukarıda bahsedilen tüm fonksiyonlara değinilmiş olunacaktır aynı zamanda giriş-orta düzey bir Arduino uygulamasına da bir örnek teşkil etmiş olacaktır.

Bu uygulamayı yapabilmeniz için aşağıdaki malzemelere ihtiyacınız olacaktır.

  • 2 adet Arduino.
  • 2 Adet nRF24L01 Modül.
  • 1 Adet Potansiyometre.
  • 1 Adet Buton.
  • 1 Adet 10kOhm veya 4.7kOhm Direnç.
  • 2 Adet 100Ohm-560Ohm Arasında Direnç.
  • 2 Adet LED (renk önemli değil LED olsun yeterli).
  • Yeterince Breadboard, bakır tel veya Jumper kablolar.

Aşağıda Vericiye ait fritzing devre şeması görülmektedir.

nRF24L01 uygulaması devre şeması

Verici için gerekli Kodlar aşağıdaki gibidir.

Aşağıda Alıcıya ait fritzing devre şeması görülmektedir.

nRF24L01 uygulaması alıcı devre şeması

Alıcı için gerekli Kodlar aşağıdaki gibidir.

Yukarıdaki her iki devreyi kurup kendilerine ait örnek kodları upload ettiğiniz takdirde verici taraftan alıcı tarafa nRF24L01 modüller arasında veri iletişimini sağlayabilmiş olacaksınız. Potansiyometre ile alıcıdaki bir LED’in parlaklığını ayarlayabilecek buton ile de bir LED’i yakıp söndürebileceksiniz. Kodların gerekli açıklamaları yanlarında bulunmaktadır. Açıklamalar yetmezse zaten yukarıda her bir fonksiyonun ne işe yaradığını da detaylı olarak ifade ettim. Bunun dışında kafanıza takılan bir şeyler olursa konu altına yorumlarınızı bırakmayı ihmal etmeyiniz.

Son olarak nRF24L01 modülleri ile ilgili belirtmem gereken bir nokta var. Bazı kullanıcıların bu modüllerin haberleşirken sorun yaşadığını söylüyorlar. Çözüm olarak modülün VCC ile GND bacaklarına paralel 10uF – 100uF arasında kondansatör koyduklarını belirtiyorlar. Ben bu durumun aksini söylemek zorundayım çünkü bu modüller 3.3V ile çalışmaktadırlar ve maksimum 3.6V sınır değerine sahiptirler. Eğer siz de kondansatör koyma ihtiyacı duyarsanız mümkün olduğunca 10V veya daha düşük değerde 10uF – 100uF arasında bir kondansatör bağlayınız. Çünkü kondansatörler yük altına kalmadıkları besleme hatlarında düşşükte olsa gerilim artışlarına neden olmaktadırlar, bunun da sebebi kondansatörlerin yük depolama özelliklerinden kaynaklıdır. 28V bir beslemeye 50V değerinde bir kondansatör bağlandığında 39V okunduğunu görmüşlüğüm oldupundan dolayı ve aynısının bu modüllerde de olup olmadığını test etmek amacıyla 15V 10uF bir kondansatörü bu modüllerden birinin VCC ve GND bacaklarına bağladım ve sonuç olarak okuduğum gerilim 3.7V düzeyindeydi. Ancak 10V değerinde 10uF kondansatör bağladığımda bunun 3.5V civarında olduğunu gözlemledim. Bu  tamamen benim gözlemlerimden derlediğim bir uyarı. Multimetreden kaynaklı hatalar da olabilir. Bu uyarıyı dikkate almanızı önemle rica ediyorum sonra modülüm bozuldu gibi durumlar yaşadığınızda beni suçlamayınız. Zaten bundan dolayı ben asla böyle bir kondansatör bağlamayı gerek duymadım, iletişimde sorunda yaşamadım.
Yine bu uyarıya ek olarak şunuda belirteyim internetteki diğer nRF24L01 kütüphanelerinin bu konuda anlattığım kütüphanelerden farklı olduğundan dolayı da iletişimde sorunların yaşandığını gördüm. Ben bu kütüphane ile hiç bir sorun yaşamamaktayım.

Ekte konuda bahsi geçen kütüphane dosyasına ait link bulunmaktadır. Yine aynı kişinin github link olarak ekte bulabileceksiniz. dilediğiniz linkten kütüphaneyi indirebilirsiniz, ikisi de birebir aynıdır.

EK: spirilis Enrf24 Kütüphanesi

EK: spirilis Enrf24 github

Böylece bir konunun daha sonuna gelmiş bulunmaktayım. Yararlı olması dileklerimle. Eksiklerim ve hatalarım olduğunu görürseniz lütfen yorum atmayı unutmayın böylece eksik taraflarını ekler hatalarım varsa düzeltebilirim.

Uygulamasını hazırlayan “Online” hocamıza teşekkür ederim :)
Ders Sonu uygulaması ​
nRF24L01              Arduino
MOSI              =>     MOSI (NANO ve UNO için 11, MEGA için 51, MICRO için MOSI)​
MISO              =>     MISO (NANO ve UNO için 12, MEGA için 50, MICRO için MISO)​
SCK                =>     SCK   (NANO ve UNO için 13, MEGA için 52, MICRO için SCK)​
CS                  =>     SS     (NANO ve UNO için 10, MEGA için 53, MICRO için SS)​
CE                  =>     Herhangi bir dijital pin olabilir yukarıdaki şemada pin 9’a bağlı​
IRQ                =>     Herhangi Harici kesme özelliği olan bir dijital pine bağlanabilir şemada UNO ve NANO için bunlardan birisi olan pin 2’ye bağlı​
VCC                =>     +3.3V (kesinlikle +5V’a bağlamayınız modülünüz anında bozulacaktır!!!)​
GND               =>     GND​
nRF24L01 pin isimleri
Alıcı Devremiz
nRF24L01 ders sonu uygulaması alıcı devresi devre şeması
Alıcı Kodu
Verici Devremiz
nRF24L01 ders sonu uygulaması verici devresi devre şeması
Verici Kodu
 

Online tarafından hazırlanmış kısa bir uygulama videosu:
nRF24L01 KABLOSUZ ALICI VERİCİ HABERLEŞME MODÜLÜ