مقدمه
پیش از این آموزش ESP8266-01، ماژول وایفایی با تراشه کوچک، که امکان افزودن وایفای به پروژههای کاربران را فراهم میکرد را پوشش دادیم. امروز، دربارهی ماژول nRF24L01+ RF صحبت خواهیم کرد، که به نحوی همانند خواهر ESP8266 ESP01 میباشد که قابلیت اضافه کردن ارتباط بیسیم با فرکانس رادیویی را برای کاربران فراهم میکند. +nRF24L01 و ESP8266 ESP-01 فرم فاکتور و آرایش پین مشابهی (و حتی از راه دور نیز شبیه به هم هستند!) را به کار بستهاند، با این حال به صورت کاملاً متفاوتی کنترل شده عمل میکنند. در این آموزش، امیدواریم بتوانیم اصول اساسی استفاده از ماژولهای RF را معرفی کرده، و همچنین نحوهی ارتباط آن با دیگر ماژولهای RF و میکروکنترلرها را نیز توضیح دهیم. برای این آموزش، ارتباط بین ماژول و برد Arduino Uno را نمایش میدهیم.
+nRF24L01 بر پایهی آیسی گیرنده Nordic Semiconductor nRF24L01+1 برای باند فرکانس ۲.۴ گیگاهرتز ISM (صنعتی، علمی و پزشکی) میباشد.
ویژگیهای +nRF24L01
- عملکرد در باند فرکانسی ۲.۴ گیگاهرتز ISM
- ولتاژ نامی ۳.۳ ولت (ورودیهایی تا ۵ ولت مقاوم)
- رگولاتور ولتاژ روی چیپ
- نرخ انتقال داده 250kbps ،1Mbps ،2Mbps در هوا
- عملکرد فوق کم مصرف
- جریان پایین (900nA – 26uA)
در ابتدا بخش سختافزاری ماژول را بررسی میکنیم. مشابه ESP-01، ماژول RF یک رابط ۴*۲ نرینه دارد. اما چینش پینهای آن متفاوت از ESP-01 میباشد، زیرا ماژول RF از پروتکل ارتباطی متفاوتی SPI برای ارتباط با دیگر دستگاهها استفاده میکند. اگر مایل به یادگیری بیشتر درباره پروتکل SPI هستید، نگاهی به مقاله زیر بیندازید.
- ارتباط SPI – معرفی پروتکل ارتباطی سریال SPI
- پروتکل رابطه وسایل جانبی در آردوینو (SPI)
- راه اندازی SPI در آردوینو
نقشهی پینها برای ماژول RF در دیاگرام زیر از Addicore خلاصه شده است.
ماژول RF به گونهای تنظیم میشود که به صورت یک برده (slave) برای SPI عمل کند، یعنی تنها میتواند با دستگاههایی ارتباط برقرار کند که دارای خط ارتباطی SPI اختصاصی هستند. این بدین معناست که پینهای SPI MOSI ،MISO و SCK (کلاک) نمایش داده شده روی دیاگرام باید به پینهای منتاظرشان روی میکروکنترلر متصل گردند. در آردوینو، این پینها به صورت زیر هستند.
- MOSI: Arduino D11
- MISO: Arduino D12
- SCK: Arduino D13
پینهای CE و CSN را میتوان به هر پین ورودی خروجی (GPIO) روی آردوینو متصل کرد. در نرمافزار، با آغاز ارتباط SPI این پینها به صورت مناسب مشخص میشوند. در زیر، مثالی از نحوه ارتباط بین ماژول RF و آردوینو آورده شده است.
برای ارتباط آردوینو با ماژول، از کتابخانهی TMRh20’s RF24 استفاده خواهیم کرد، این کتابخانه ارتباطات سطح پایین بین ماژول RF و میکروکنترلر را به راحتی به کلاسهای ++C بستهبندی میکند.
قبل از شروع به کار با ماژول، ابتدا اصول اساسی عملکرد آن را بررسی میکنیم. در ایالات متحده، دستگاههایی که از امواج فرکانس رادیویی استفاده میکنند محدود به رنج فرکانسی هستند که FCC تعیین میکند. باند ISM محدودهای است که برای ابزارآلات علمی و پزشکی و دیگر ماژولهای RF که درون رنج ISM عمل میکنند رزرو شده است. برای کار با ماژول RF، نیازی به دانستن جزئیات این فرکانسها و یا اطلاع دقیق از نحوهی ارتباط در این فرکانسها نیست. در عوض تمرکز خود را روی جنبههای مختلفی از ارتباطات RF بیسیم میگذاریم که قابل کنترل هستند.
اگر سری به داکیومنتهای کتابخانه RF24 بزنید، متوجه میشوید که پارامترهای مختلفی برای تنظیم کردن وجود دارد. برخی از پارمترهای کلیدی عبارتند از:
- کانال (Channel): فرکانس تعیین شده کانال که ارتباط درون آن به وقوع میپیوندد (فرکانسها با اعداد صحیحی بین ۰ و ۱۲۵ نگاشت میشوند)
- لوله خوانش (Reading pipe): لوله خواندن (read pipe) یک آدرس یکتای ۲۴، ۳۲ یا ۴۰ بیتی است که ماژول، داده را از آن میخواند.
- لوله نوشتن (Writing pipe): لوله نوشتن (write pipe) یک آدرس یکتا است که ماژول، داده را در آن مینویسد.
- سطح تقویت توان (Power Amplifier(PA) level): سطح PAT توان کشیده شده از چیپ، و بنابراین توان انتقال را مشخص میکند. برای این آموزش (استفاده از آردوینو) از کمترین مقدار توان استفاده میکنیم.
صفحهی داکیومنتهای کتابخانه RF24 مثالهای خوبی برای شروع به کار با کتابخانه فراهم آورده است. این مثالها را میتوان از اینجا مشاهده کرد.
در اینجا نگاهی به نحوهی مقداردهی پارامترهای بالا که در بخش «Getting Started» کد آردوینو آورده شده است، خواهیم انداخت که از این لینک قابل دسترس است.
کد راه اندازی ماژول
/* * Getting Started example sketch for nRF24L01+ radios * This is a very basic example of how to send data from one node to another * Updated: Dec 2014 by TMRh20 */ #include <SPI.h> #include "RF24.h" /****************** User Config ***************************/ /*** Set this radio as radio number 0 or 1 ***/ bool radioNumber = 0; /* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 */ RF24 radio(7,8); /**********************************************************/ byte addresses[][6] = {"1Node","2Node"}; // Used to control whether this node is sending or receiving bool role = 0; void setup() { Serial.begin(115200); Serial.println(F("RF24/examples/GettingStarted")); Serial.println(F("*** PRESS 'T' to begin transmitting to the other node")); radio.begin(); // Set the PA Level low to prevent power supply related issues since this is a // getting_started sketch, and the likelihood of close proximity of the devices. RF24_PA_MAX is default. radio.setPALevel(RF24_PA_LOW); // Open a writing and reading pipe on each radio, with opposite addresses if(radioNumber){ radio.openWritingPipe(addresses[1]); radio.openReadingPipe(1,addresses[0]); }else{ radio.openWritingPipe(addresses[0]); radio.openReadingPipe(1,addresses[1]); } // Start the radio listening for data radio.startListening(); } void loop() { /****************** Ping Out Role ***************************/ if (role == 1) { radio.stopListening(); // First, stop listening so we can talk. Serial.println(F("Now sending")); unsigned long start_time = micros(); // Take the time, and send it. This will block until complete if (!radio.write( &start_time, sizeof(unsigned long) )){ Serial.println(F("failed")); } radio.startListening(); // Now, continue listening unsigned long started_waiting_at = micros(); // Set up a timeout period, get the current microseconds boolean timeout = false; // Set up a variable to indicate if a response was received or not while ( ! radio.available() ){ // While nothing is received if (micros() - started_waiting_at > 200000 ){ // If waited longer than 200ms, indicate timeout and exit while loop timeout = true; break; } } if ( timeout ){ // Describe the results Serial.println(F("Failed, response timed out.")); }else{ unsigned long got_time; // Grab the response, compare, and send to debugging spew radio.read( &got_time, sizeof(unsigned long) ); unsigned long end_time = micros(); // Spew it Serial.print(F("Sent ")); Serial.print(start_time); Serial.print(F(", Got response ")); Serial.print(got_time); Serial.print(F(", Round-trip delay ")); Serial.print(end_time-start_time); Serial.println(F(" microseconds")); } // Try again 1s later delay(1000); } /****************** Pong Back Role ***************************/ if ( role == 0 ) { unsigned long got_time; if( radio.available()){ // Variable for the received timestam while (radio.available()) { // While there is data ready radio.read( &got_time, sizeof(unsigned long) ); // Get the payload } radio.stopListening(); // First, stop listening so we can talk radio.write( &got_time, sizeof(unsigned long) ); // Send the final one back. radio.startListening(); // Now, resume listening so we catch the next packets. Serial.print(F("Sent response ")); Serial.println(got_time); } } /****************** Change Roles via Serial Commands ***************************/ if ( Serial.available() ) { char c = toupper(Serial.read()); if ( c == 'T' && role == 0 ){ Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK")); role = 1; // Become the primary transmitter (ping out) }else if ( c == 'R' && role == 1 ){ Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK")); role = 0; // Become the primary receiver (pong back) radio.startListening(); } } } // Loop
توضیحات کد
دو خط اول کد مورد توجه ما، دو خط C++ #include در بالای فایل هستند، که یکی برای ضمیمه کردن کتابخانه SPI آردوینو و (یادآوری میکنیم که ماژول RF از پروتکل SPI برای ارتباط با آردوینو استفاده میکند)، و دیگری برای ضمیمه کردن کتابخانه RF24 میباشد.
#include <SPI.h> #include “RF24.h”
خط دیگر مورد توجه ما خطی است که شی RF24 را میسازد.
RF24 radio(7,8);
دو پارامتر ارسال شده به سازنده (Constructor) پینهای CE و CSN میباشند که به ماژول متصل شدهاند. اگرچه که پینهای MOSI ،MISO و SCK باید به ترتیب پینهای دیجیتال ۱۱، ۱۲ و ۱۳ باشند، پینهای CE و CSN میتوانند هر پین دیجیتالی باشند.
سپس نگاهی به آدرسهای لوله برای خواندن و نوشتن میاندازیم. همان طور که احتمالا حدس زدهاید، آدرسهای لوله خواندن و نوشتن بین دو رادیویی که در حال ارتباط با یکدیگر هستند مبادله میشوند، یعنی لوله نوشتن برای هر رادیو به منزله لوله خواندن برای دیگری میباشد. اندازه آدرسهای رادیویی ۲۴، ۳۲ و یا ۴۰ بیتی میباشد. در کد مثال، این آدرسها قابل تبدیل به رشتههای ++C هستند، اما میتوان آنها را با فرمت باینری یا هگزادسیمال نیز نوشت.
برای مثال، یک آدرس ۴۰ بیتی مشخص شده با مقدار هگز میتواند به صورت 0xF0F0F0F0F0 باشد. یک روش خوب برنامهنویسی برای مرتبسازی آدرسهای لوله نوشتن و خواندن، قراردادن مقادیر آنها درون یک آرایه میباشد. در کد مثال، ادرس لولههای خواندن و نوشتن در یک آرایه بایت با نام «addresses» ذخیره شده است. در متد ()void setup، باید دستورات مورد نیاز برای مقداردهی اولیه رادیوها با آدرسهای لوله و دیگر پارامترها را فراهم کنیم.
ابتدا متد ()RF24::begin فراخوانی میشود. متد ()begin باید پیش از فراخوانی هر متد دیگری از کتابخانه روی شی radio فراخوانی شود، زیرا عملکرد چیپ RF را مقداردهی اولیه میکند.
سپس، سطح تقویتکننده توان با فراخوانی متد ()RF24::setPALevel تعیین میشود. کتابخانه RF24 مقادیر ثابت مختلفی برای مشخص کردن سطح تقویتکننده توان فراهم آورده است. سطوح بالاتر تقویتکننده توان به این معنی است که ماژول میتواند در مسافتهای طولانیتری ارتباط برقرار کند، اما در عوض حین عملکردش جریان بیشتری کشیده میشود. برای استفاده از اسکچ آغازین، ما ثابت RF_24_LOW را به عنوان پارامتر ورودی به متد ()setPALevel ارسال کردیم زیرا مسافت بین دو ماژول ارتباطی خیلی زیاد نیست. در حالت کلی، هنگام استفاده از ماژول RF همراه با برد آردوینو، احتمالاً بهترین گزینه استفاده از پایینترین سطح ممکن PA برای کاهش جریان کشیده شده از منبع تغذیهی آردوینو میباشد.
سپس، نگاهی به نحوه آغاز لولههای خواندن و نوشتن میاندازیم. تا اینجا لولههای خواندن و نوشتن را به صورت مقادیر بایتی تعریف کردیم. حال باید این تعاریف را به شی radio ارسال کنیم تا ادرسهای لولههای خواندن و نوشتن نیز مشخص شود. لوله نوشتن از طریق متد ()openWritingPipe و لوله خواندن از طریق متد ()openReadingPipe تعیین میگردد. مثالی از بازکردن لوله خواندن و نوشتن به صورت زیر است.
radio.openWritingPipe(addresses[1]); radio.openReadingPipe(1, addresses[0]);
دقت کنید که به متد ()openReadingPipe باید یک پارامتر عدد صحیح اضافی نیز ارسال گردد که مشخص کند که کدام لوله خواندن مقداردهی اولیه شود. این موضوع بدین خاطر است که ماژول RF میتواند همزمان تا ۶ لوله خواندن داشته باشد.
مثال مقادیر لوله خواندن و نوشتن را از طریق یک مقدار بولی role به درستی تخصیص میدهد. بسته به مقدار role، برنامه مشخص میکند که ماژول RF دستگاه ping یا pong است. شما نیز میتوانید در پروژهتان از کد مشابه استفاده کنید. فقط مطمئن شوید که آدرسهای خواندن و نوشتن بین دو قطعه جابهجا باشند، زیرا در غیر این صورت هیچ دادهای ارسال و یا خوانده نمیشود.
در نهایت، کلاس RF24 متدهایی را برای خواندن و نوشتن داده واقعی فراهم میکند. پارامترهای مربوط به متدهای ()RF24::write و ()RF24::read عبارتند از:
- یک اشارهگر به یک متغیر از همان نوع دادهای که قرار است ارسال شود.
- اندازه دادهای که قرار است ارسال شود. در متد ()read، متغیری که اشارهگر به آن اشاره میکند دادهی خوانده شده را دریافت میکند.
در متد ()write، متغیری که اشارهگر به آن اشاره میکند حاوی دادهای است که نوشته میشود. در هر دو متد، کاملاً لازم است که اشارهگر به متغیر از همان نوع ارسالی اشاره کند، و اندازهای که به متد ارسال میشود در واقع منعکس کنندهی اندازهی داده است. ارسال نوع داده و یا اندازهی نادرست به متدهای ()read و ()write میتواند به مقادیر نامطلوب و ناقص منجر شود، و رندر اطلاعات ارسالی را بلا استفاده کند. در کد «Getting Started»، داده ارسالی از نوع unsigned long میباشد. بنابراین اشارهگر ارسالی به عنوان آرگومان به متدهای ()read و ()write به یک نوع داده unsigned long اشاره میکنند. همچنین واضح است که اندازهی داده انتقالی همواره به اندازهی یک unsigned long میباشد. در چنین شرایطی، نیازی به ارسال داده به صورت یک عدد صحیح مشخص نیست، و آرگومان اندازه در عوض میتواند به سادگی برابر (sizeof(unsigned long باشد.
تنها پارامتری که کد «Getting Started» پوشش نمیدهد کانال ارتباطی میباشد. اگر یک کانال خاص، مطلوب ما باشد (برای مثال، اگر چندین شبکه RF دارید که نمیخواهید با همدیگر تداخل داشته باشند)، آنگاه میتوان کانال را با ارسال یک پارامتر عدد صحیح ۸ بیتی به متد ()RF24::setChannel مشخص کرد. برای مثال میتوان نوشت.
(radio.setChannel(10);
دو ماژول RF را به دو بورد آردوینو جداگانه وصل کرده و کد «Getting Started» را روی هرکدام (برای یکی از بوردها، باید مقدار بولی role را به ۱ تغییر دهید) آپلود کنید. اکنون باید قادر به ارسال و دریافت پیامها با زمان پینگ مربوطه باشید. در زیر تصویری از دو serial monitor نوع «ping» و «pong» در کنار هم آمده است.
شما آموزش +nRF24L01 را به پایان رساندید. حال شما با دانش کنونی قادر به ایجاد پروژههایتان و به کارگیری ماژولهای RF در آن هستید. میتوانید بلاگ Device Plus را برای پروژههای مرتبط با ماژولهای RF مشاهده کنید.
- منبع: ترجمه از سایت deviceplus.com
اگر آموزش راه اندازی ماژول +nRF24L01 براتون مفید واقع شده ما را نیز دعا کنید و اگر خواستین میتوانید از محتوای رایگان آموزشی حمایت مالی کنید. همچنین نظرات، پیشنهادات و درخواستهای خود را در کامنتها ⇓ بنویسید. همچنین مقاله آموزش راه اندازی ESP8266 با استفاده از آردوینو میتونه براتون مفید واقع بشه.
اگر این نوشته برایتان مفید بود لطفا کامنت بنویسید.
سلام.لطفا با این ماژول nrf24L01 یک پروژه کنترل دور موتور دی سی از راه دور و یا کنترل شدت نور ال ای دی از راه دور را آموزش دهید.ممنون