آموزش قدم به قدم راه اندازی +NRF24L01

2
1059
راه اندازی +NRF24L01
راه اندازی +NRF24L01

آموزش قدم‌به قدم راه‌اندازی +NRF24L01 با کتابخانه سازگار با انواع میکروکنترلرها و کامپایلرها

قبل‌از اینکه قسمت بشه با ماژول +NRF24L01 کار کنم، خیلی از دوستان را دیده‌بودم که با این ماژول درگیر بودند و توی راه‌­اندازیش مشکل داشتند و مثل یک اپیدمی شده توی گروه­های تلگرامی و فروم­ها. همان­طورکه حدس می‌­زنید وقتی که به ماژول+NRF24L01 نیاز پیدا کردم تا راهش بندازم و ازش استفاده‌کنم دقیقا همین بلا سر خودم هم اومد. هدفم از نوشتن این مطلب این هست که دیگه مشکلی توی راه‌­اندازی ماژول +NRF24L01 نباشه و همه به‌راحتی بتونن باهاش کار کنن و از قابلیت‌های این کتابخونه تقریباً بطور کامل استفاده‌کنن. پس وقت را تلف نکنیم و بریم سراغ راه‌اندازی… با ماهمراه باشید.

ترتیب پایه‌های ماژول +NRF24L01

ترتیب پایه های ماژول +NRF24L01
ترتیب پایه های ماژول +NRF24L01

 

نکات

  • در این کتابخانه از پین IRQ استفاده نمی­‌شود.
  • CSN همان SS در ارتباط SPI است و CE یک پین اضافه کنترلی برای ماژول +NRF24L01 می­‌باشد.
  • نحوه اتصال پایه­‌ها به میکروکنترلر در فایل c تعریف می‌شود که متعاقباً مفصل توضیح داده‌خواهد‌شد.
  • همان­طورکه می­‌دانید تغذیه ماژول ۳ولت هست اما بقیه پایه‌­های ارتباطی ماژول(۵v tolerant) هستند. یعنی سطح لاجیک ۵ولت رو تحمل می­کنه و می‌­تونیم مستقیم به میکروکنترلر­های ۵ولتی، مثل بعضی‌از مدل­‌های avr متصل‌کنیم.

توضیحات درمورد کتابخانه

این کتابخانه شاید بهینه­‌ترین نباشه اما احتمالاً portableترین هست. (نمی­‌دونم فارسیش چیه) یعنی شما می‌­توانید با تغییرات کوچکی این کتابخانه را متناسب با میکروکنترلر خودتان شخصی‌­سازی کنید. علت این صحبت هم این هست که شما با تغییردادن چندتا تابع (که به قسمت GPIO هر میکروکنترلر مربوط میشه) در فایل radioPinFunctions.c، می‌توانید کتابخانه موردنظر را شخصی‌سازی کنید و هر پایه­‌ای از میکروکنترلر را به هرکدام از پایه‌­های ماژول +NRF24L01 که خواستید وصل‌کنید و از این بابت جای هیچ‌نگرانی نیست. این قسمت فقط یکم دانش زبان C می­‌خواد و آشنایی با GPIO میکروکنترلر مربوطه. در این کتابخانه حالت­‌های Auto Acknowledgement و Auto Retransmission فعال‌شده است و تعداد دیتا باید یک اندازه ثابت باشه (static length payload mode). دو ویژگی ذکرشده از مهم­ترین قابلیت­های +NRF24L01 هستند که با آن‌ها می­‌توانیم بفهمیم دیتا درست رسیده یا نه! همچنین اگر دیتا در مرحله ارسال ازدست‌رفت و درست به مقصد نرسید این چیپ می‌تواند خودش کار ارسال دوباره (Retransmision) رو انجام بدهد، که می­‌توانیم این قسمت را هم خودمان تنظیم‌کنیم که چه تعداد تلاش دوباره انجام‌بدهد و بین هر‌کدام از این تلاش‌ها چه تاخیری ایجاد شود. البته تعداد تلاش دوباره روی ۱۵بار و تاخیر ۱۰۰۰میکرو­ثانیه به‌صورت خودکار تنظیم‌شده‌است، اما با تابع nrf24_RetransmissionConfig می‌توانیم این مقادیر را تغییر‌بدهیم. برای راه‌­اندازی ماژول باید چهار فایل زیر در مسیر پروژه قرار بگیرد:

  • nrf24.c
  • nrf24.h
  • nRF24L01.h
  • radioPinFunctions.c

و در ابتدای کد برنامه باید دو فایل زیر ضمیمه شود:

#include <nrf24.c> 
#include <radioPinFunctions.c>

ممکن‌است کامپایلر یک‌سری Warning هم بدهد، آنقدر مهم نیستند، آن‌ها را نادیده بگیرید.(علت اینکه فایل­های c. رو داریم ضمیمه می‌­کنیم این هست که یه‌سری از توابعی که داخل فایل nrf24.c وجود دارند داخل فایل nrf24.h موجود نیست. حال اگر فایل h. رو ضمیمه کنیم، احتمالا کامپایلر کلی ارور خواهد داد؛ اگرچه در عمل فایل­‌های h. و c. فرقی باهم ندارند و فقط فایل h. یک نامگذاری دیگر است که تفاوت بین فایل­های کتابخانه و کد پروژه مشخص باشد) قبل‌از اینکه برویم سراغ کد­نویسی یه نکته رو بگم،

حتی­‌الامکان اگر از هر تابعی داخل پروژه استفاده می‌کنید آن‌را دستی ننویسید و بروید از هدر nrf24.h کپی و استفاده‌کنید، چون حروف کوچک و بزرگ داخل این توابع زیاد هست و ممکن‌است اشتباهات ناخواسته‌ای رخ بدهد.

خب شروع‌کنیم به یاد‌گرفتن توابع که ماشالله کم هم نیستن، ولی دست ما رو تقریباً واسه هر‌کاری باز می­‌گذارند.

نحوه شخصی­‌سازی فایل radioPinFunctions.c برای میکروکنترلر موردنظر

ابتدا ببینیم اصلا هدف و کاربرد این فایل چی هست؟! قرار است ما در این فایل به کتابخانه بفهمانیم که چه پایه‌­ای از ماژول به چه پایه‌­ای از میکروکنترلر وصل است، سپس بیایم ورودی-خروجی بودن اون پایه­‌ها رو تعیین‌کنیم و در‌نهایت نحوه صفر و یک کردن اون پایه رو به کتابخانه یاد بدهیم. علت این‌کار هم این هست که کتابخونه بتونه با spi نرم­‌افزاری با ماژول صحبت کند.‌(یعنی یه spi که ما خودمون با gpio‌ها ساختیم و دیگه محدودیت کتابخونه به یک میکروکنترلر رو برداشتیم و می‌توانیم با هر میکروکنترلری کار کنیم) در این قسمت همه مثال‌­ها و کد­ها بر‌اساس میکروکنترلر atmega8 ،avr است چراکه یک چیز‌عام باشد و همه بتوانند درکش کنند و ازش استفاده‌کنند. و شما باتوجه‌به فهمی که از avr دارید و توضیحاتی که داده‌شده، باید کد‌های مربوط‌به میکروکنترلر خودتان را جایگزین کنید. بریم سراغ کدنویسی‌… در خطوط اول فایل باید هدر میکروکنترلر مربوطه رو ضمیمه کنید تا برنامه رجیستر­های GPIO را بشناسد.

مثال

#include <mega8.h>

 

در ادامه سه تا define خواهید دید که کارشان مثل یک تابع هست که دو‌تا ورودی می‌­گیرد و اونا رو توی یک عملیات جای­گذاری ‌میکند. (این قسمت برای کوتاه‌شدن کد استفاده‌شده‌است و شما ممکن‌است اصلا بهش‌نیازی نداشته‌باشید و بستگی‌به میکروکنترلرتون داره‌…)

  • (set_bit(reg,bit: یک بیت از یک رجیستر رو ۱ می­کند.
  • (clr_bit(reg,bit: یک بیت از یک رجیستر رو ۰ می­کند.
  • (check_bit(reg,bit: مقدار یک بیت بخصوص از یک رجیستر را بر‌می‌گرداند. بقیه فایل دارای پنج تابع است که کاربرد و نحوه تغییرداد نشون را خدمت شما شرح‌خواهیم‌داد.
  • ()nrf24_setupPins: نقش این تابع تعیین ورودی-خروجی‌بودن پایه‌­های متصل‌به میکروکنترلر از ماژول می­‌باشد.

مثال

می‌خواهیم پایه x از یک پورت میکرکنترلر مورد‌نظر را که به ce ماژول متصل است خروجی کنیم:

set_bit(Register,x);

که Register همان رجیستر مربوط‌به تعیین خروجی میکروکنترلر موردنظر است.

مثال

پایه ce ماژول به پین ۱ از پورت B میکروکنترلر mega8 متصل است که باید خروجی شود، پس:

set_bit(DDRB,1);

مابقی را نیز به‌همین شکل انجام می­‌دهیم.

نکته: توجه‍‌داشته‌باشید چه در سمت فرستنده چه در سمت گیرنده میکروکنترلر ما درحالت Master قرار دارد و ماژول Slave است، پس باید تمام پایه­‌های متصل‌به ماژول +NRF24L01، به‌جز پایه MISO، در هر‌دو‌طرف خروجی شوند.

تابع (nrf24_ce_digitalWrite(state برای‌مثال در این قسمت ما پایه ce را به پایه۱ پورت B میکروکنترلر atmega8 متصل‌کرده‌­ایم و تغییر آن به شکل‌زیر می­‌شود:

void nrf24_ce_digitalWrite(unsigned char state)
{
       if(state)              
    {   
      set_bit(PORTB,1);       
    }    
    else    
    {  
     clr_bit(PORTB,1);  
   }    
}

 

همان­طورکه مشاهده می­‌کنید کار این تابع این است که از ورودی ۰یا ۱ می­‌گیرد و اگر ۱ بود دستور set_bit و اگر ۰ بود دستور clr_bit را اجرا می­‌کند. اما این‌­بار ورودی دستورات define شده، رجیستری است که مستقیماً سطح لاجیکی(Logic Level) پایه­‌ها را کنترل می­‌کند. برای مابقی توابع همین عملیات تکرار می­‌شود. برای تابع آخر هم باید مانند این مثال تغییر را اعمال‌کنیم. برای‌مثال اگر پایه miso ماژول به پین ۴پورت B متصل باشد، کد مربوطه‌به شکل‌زیر خواهدشد:

unsigned char nrf24_miso_digitalRead()
{
    return check_bit(PINB,4);
}

 

خب کار شخصی­‌سازی این فایل تمام شد، فایل را ذخیره می­‌کنیم و دیگه کاری با فایل­‌های کتابخانه نداریم و می‌رویم سراغ یادگیری توابع و بکارگیری­شون داخل کداصلی برنامه. توابع شامل چنددسته میشن که به‌ترتیب توضیح‌داده‌میشه :
پیکربندی (Configuration) ماژول +NRF24L01
برای پیکربندی اولیه ماژول +NRF24L01 سه تابع زیر تعریف می‌­شود:

۱- ()nrf24_init این تابع باید اول از همه در تابع main فراخوانی شود و کارش تعیین ورودی-خروجی پایه­‌های انتخاب شده از قبل و در کل، تخصیص پایه­‌های میکروکنترلر به پایه­‌های ماژول است.

۲- (nrf24_config(channel , payload_length , data_rate داخل این تابع کارهای زیادی انجام می‌شود، اما کارهایی که ما می­‌‎توانیم با ورودی تغییرشان بدهیم دو متغیر است، یکی انتخاب کانال فرکانسی هست؛ که می­‌توانیم به‌جای channel از ۰ تا ۸۳ قرار‌بدهیم و دیگری تعداد بایت‌­هایی که می­‌خواهیم در هر ارسال فرستاده‌شود؛ که می­‌توانیم به‌جای payload_length از ۰ تا ۳۲ قرار بدهیم. به‌جای data_rate باید یکی‌از ۳عدد زیر قرار‌گیرد:
0 -> 1Mbit/s

1 -> 2Mbit/s 2 -> 250Kbit/s

توجه: این سه متغیر باید در هر دو طرف فرستنده و گیرنده یکی باشند.

مثال

void main(void)
{
    nrf24_init();
    nrf24_config(1,4,1);
while(1)
      {    }
 }

در این مثال کانال۱ انتخاب‌شده‌است، یعنی فرکانس ۲.۴۰۱Ghz تعداد بایت‌­های ارسالی ۴عدد و سرعت ارسال ۲Mbit/s می­‌باشد.
نکته: بعد‌از فراخوانی این تابع ماژول به‌صورت خودکار به‌حالت گیرنده می­‌رود.

3- (nrf24_RetransmissionConfig( delay_us , trial این تابع برای تعیین تعداد تلاش دوباره برای ارسال و تاخیر بین هر‌دو تلاش در‌حالتی که دیتا به مقصد نرسیده‌است یا خطا دارد کاربرد دارد. در این تابع مقدار‌تاخیر، به‌جای delay_us فقط ضرایب خاصی از ۲۵۰ می­تواند قرار‌گیرد. در‌غیر این­صورت رفتار ماژول قابل پیش‌­بینی نیست.

این مقادیر تاخیر از‌طریق فرمول‌زیر به‌دست می­‌آیند: delay = (۲۵۰*n)+۲۵۰ که n از ۰ تا ۱۵ مقدار می­‌پذیرد . یعنی ضرایب ۲۵۰تا حداکثر عدد ۴۰۰۰ قابل‌فهم و کار‌کردن برای ماژول است. پس می­توانیم اعداد ۲۵۰، ۵۰۰، ۷۵۰، ۱۰۰۰، …، ۴۰۰۰ را در ورودی تابع قراردهیم. این تاخیر برحسب میکروثانیه می‌­باشد. تعداد تلاش دوباره برای ارسال ۰تا ۱۵بار می‌باشد و به‌جای trial قرار می‌گیرد. این تابع را خودم به کتابخونه اضافه‌کردم و دیدم به‌درد می­‌خورد!

آدرس‌دهی

هر ماژول یک مک آدرس ۵بایتی مختص‌به خود را دارد که ما آن­‌‌را به دلخواه انتخاب می­‌کنیم و به ماژول اعلام می‌­کنیم. یک چیز‌دیگر که باید به ماژول اعلام شود، این است که طرف مقابل چه مک آدرسی دارد. که این­‌ها از‌طریق دو‌تابع زیر انجام می‌شود:

nrf24_rx_address(rx_mac);
nrf24_tx_address(tx_mac);

 

این توابع باید در تابع main، بعد‌از توابع پیکربندی نوشته‌شوند. اما چرا نوشتن این دو تابع مهم است؟ لطفا به‌مثال‌زیر دقت‌کنید تا اشتباه من رو مرتکب نشوید و مثل من یک هفته وقتتان گرفته‌نشود…

مثال:

کد در قسمت فرستنده

unsigned char rx_mac[5] = {0xE7,0xB2,0xE7,0xE7,0xE7};

unsigned char tx_mac[5] = {0xD7,0xD7,0xD7,0x12,0xD7};

nrf24_rx_address(rx_mac);

nrf24_tx_address(tx_mac);

کد در قسمت گیرنده

unsigned char rx_mac[5] = {0xD7,0xD7,0xD7,0x12,0xD7};

unsigned char tx_mac[5] = {0xE7, 0xB2,0xE7,0xE7,0xE7};

nrf24_rx_address(rx_mac);

nrf24_tx_address(tx_mac);

 

می­‌بینید که [rx_mac[5 در قسمت فرستنده با [tx_mac[5 در قسمت گیرنده برابر است و [tx_mac[5 در قسمت فرستنده با [rx_mac[5 در قسمت گیرنده برابر است و مک آدرس­‌ها به‌صورت ضربدری عوض شده‌­اند.

تنظیم فرستنده یا گیرنده

برای این‌کار از دو‌تابع زیر استفاده می‌­شود که نیازی‌به توضیح ندارند.

  • ()nrf24_powerUpRx: تنظیم به‌عنوان گیرنده.
  • ()nrf24_powerUpTx: تنظیم به‌عنوان فرستنده.

بردن ماژول +NRF24L01 به‌حالت‌خواب(Sleep Mode)

بااستفاده‌از تابع‌زیر در زمان­‌هایی که به ماژول نیاز نداریم می­‌تو‌انیم مصرف توان ماژول را به حداقل برسانیم.

nrf24_powerDown();

 

ارسال داده(Transmit)

برای ارسال داده از تابع‌زیر استفاده می­‌شود:

nrf24_send(data_array);

متغیر ورودی تابع در اینجا، برای مثال‌ما data_array می­‌باشد. در این تابع، برای فرستادن دیتا ابتدا ماژول به‌صورت‌خودکار درحالت فرستنده قرار می­‌گیرد (کد داخل این تابع به این شکل هست) و برای برقراری ارتباط باید ماژول دیگر درحالت گیرنده قرارگرفته‌باشد و قسمت ( …. , …. , …. )nrf_config باید یکی باشند. برای‌مثال متغیر data_array هم به‌شکل‌زیر تعریف می‌شود‌(‌با فرض‌اینکه payload_length در تابع nrf_config برابر با ۴ باشد):

unsigned char data_array[4];
data_array[0] = 0x00;
data_array[1] = 0xAA;
data_array[2] = 0x55;
data_array[3] = 0xFF;

بعد‌از هر ارسال نباید دیتای دیگری را ارسال‌کرد و باید ابتدا از ارسال کامل دیتای قبلی اطمینان حاصل نمود برای این‌کار از تابع‌زیر استفاده می­‌شود: ()nrf24_isSending این تابع ورودی نمی‌­گیرد و تاوقتی‌که دیتا درحال ارسال است، ۱ را برمی‌گرداند و وقتی که ارسال تمام‌شد، ۰ را برمی‌گرداند. و معمولا قبل‌از هر ارسال کد زیر قرار می‌گیرد:

while(nrf24_isSending());

 

بعد‌از هر ارسال پیشنهاد می­‌شود از درست ارسال‌شدن آخرین دیتا اطمینان حاصل‌کنیم و روی آخرین ارسال پردازش انجام‌دهیم که با دو‌تابع زیر انجام‌پذیر است: ()nrf24_lastMessageStatus این تابع ورودی نمی­‌گیرد و اگر ۰ را برگرداند یعنی دیتا درست ارسال‌شده و اگر ۱ را برگرداند یعنی ارسال دیتا به مشکل بر­خورده است. ()nrf24_retransmissionCount این تابع نیز ورودی نمی‌­گیرد و تعداد تلاش دوباره برای فرستادن آخرین دیتا را برمی­‌گرداند.

دریافت داده(Recieve)

چون در این کتابخانه از پین IRQ استفاده نمی­‌شود، بنابراین برای دریافت داده باید پیوسته تابع زیر را بخوانیم تا از رسیدن دیتا مطلع‌شویم: ()nrf24_dataReady این تابع ورودی نمی‌­گیرد و هروقت عدد ۱ را برگرداند یعنی در FIFO ماژول حداقل یک دیتا رسیده و باید خوانده شود.

نکته:‌ اگر یک عملکرد بهینه در دریافت مدنظرتان است کمی در‌مورد پین IRQ مطالعه‌کنید و به کمک اینتراپت­ خارجی میکروکنترلر میتوانید کارهای جالبی انجام بدهید.

برای دریافت دیتا باید تابع روبرو فراخوانی شود:

nrf_getData(data_array);

چون در زبان C قابلیت return یک آرایه قرار‌داده‌نشده‌است ما از این ترفند و ورودی قرار‌دادن آرایه در تابع استفاده‌کردیم. که متغیر data_array باید به شکل‌زیر تعریف‌شود‌(فرض‌بر این است که payload_length در تابع nrf_config برابر ۴ تنظیم‌شده‌است):

unsigned char data_array[4];

که دیتای اول در [data_array[0، دیتای دوم در [data_array[1 و… قرار می­‌گیرند. با این توضیحات و توابعی که ذکر‌شد می­‌توانید کاملا ماژول را راه‌­اندازی کنید. توابعی که در پایین‌ ­تر ذکر می­‌شود توابع دیگری هستند که در کتابخانه موجود است و ممکن‌است برحسب پروژه خود، به آنها نیاز پیدا کنید.

  • nrf24_rxFifoEmpty: ورودی نمی­‌گیرد و اگر FIFO دریافت خالی باشد ۱ را برمی­‌گرداند.
  • nrf24_payloadLength: ورودی نمی­‌گیرد و تعداد بایت منتظر در FIFO را برمی­‌گرداند.
  • nrf24_getStatus: رجیستر Status در NRF را برمی­‌گرداند.
  • nrf24_configRegister: فقط یک بایت داده را در رجیستر موردنظر می­‌نویسد.
  • nrf24_readRegister: رجیستر موردنظر را از NRF را می­‌خواند.
  • nrf24_writeRegister: هر تعداد بایت داده به دلخواه در رجیستر موردنظر می­‌نویسد.

نکات کلی

برای استفاده‌از این ماژول ابتدا از میکروکنترلر mega ۸ استفاده‌کردم با کلاک ۸مگاهرتز. و سپس قرار شد که میکروکنترلر عوض‌شود و LPC1768 استفاده‌شود با کلاک ۱۰۰مگاهرتز، پس من به این فکر افتادم که سرعت Software spi رو چک‌کنم تا از حد پشتیبانی nrf بیشتر نشود. تست من طبق شرایط‌زیر است: میکرو mega8 کلاک ۸مگاهرتز. کلاک تایمر-کانتر را بر ۸ تقسیم‌کردم تا محاسبات ساده‌تر شود و هر عدد کانتر نماینده یک میکروثانیه باشد. با یک کد ساده محاسبه شد که ارسال یک بایت داده با spi نرم‌افزاری ۱۵۰میکروثانیه طول می‌کشد. با یک محاسبه می‌توان فهمید سرعت ارسال داده ۵۳.۳۳۳Kbit/s است پس با ۱۰برابر‌شدن کلاک GPIO باز هم از مرز ۱۰Mbit/s رد نمی­‌شویم و این خبر خوبیست. خبربد این است که برای جاهایی که سرعت ارسال داده‌(data rate) بالا نیاز است، خوب‌نیست و به‌درد نمی‌خورد. پس بهترین‌کار این است که تابع spi_transfer در فایل nrf24.c را برای میکروکنترلر خودمان به spi سخت‌افزاری تغییر بدیم تا دیگه این کتابخانه هیچ‌مشکلی نداشته‌باشد.(اینو دیگه میذارم به‌عهده خودتون) فقط تنظیمات spi باید به‌شکل‌زیر باشد:Sck idle state :low Sampling rising edge :idle to active Bit order :MSB First شرایط بالا Mode=۰، پروتکل spi را توصیف می‌کند. یک تست خاص هم برای بُرد ماژول انجام‌دادم گفتم بذارم شاید به‌درد کسی بخورد.

شرایط تست: فرستنده از نوع دارای pa+lna مشکی­ رنگ می‌باشد و گیرنده از نوع معمولی +NRF24L01 .

میکروکنترلر: ۸مگا در محیط بسته تا ۳لایه دیوار ارتباط برقرار است.(تا صدمترفاصله) اگر هردو از نوع pa+lna باشد تا ۱۰لایه دیوار نیز ارتباط برقرار است.

خب خسته‌نباشید امیدوارم ماژول +NRF24L01 را راه‌انداخته‌باشید و ازش به‌خوبی استفاده‌کنید. اگر سوالی داشتید حتما کامنت بگذارید سعی می‌­کنم همه سوالات را جواب‌بدهم. سورس کامل را هم میتوانید از منبع‌(‌گیت‌هاب) و هم‌چنین در زیر رایگان دانلود و استفاده‌نمایید. NRF24L01 Library-Example 

 

منبع: سیسوگ

مطلب قبلیآموزش FPGA قسمت هفتم: ساختار ارجاع انتخابی
مطلب بعدیساخت ماینر با FPGA و ARM

2 نظرات

  1. با سلام مهندس ببریان هستم میتونم تماس بگیرم خدمتتون در مورد پروژه راه اندازی NRF24l01

پاسخ دهید

لطفا نظر خود را وارد کنید!
لطفا نام خود را در اینجا وارد کنید