這篇文章來(lái)源于DevicePlus.com英語(yǔ)網(wǎng)站的翻譯稿。
在上一個(gè)教程中,我們介紹了ESP8266-01(ESP8266 設(shè)置教程)。這是一款小巧的WiFi模塊,能夠讓用戶輕松地為他們的項(xiàng)目添加WiFi功能。今天,我們將討論nRF24L01+ RF 模塊。該模塊是ESP8266 ESP-01的姊妹模塊,旨在讓用戶在項(xiàng)目中集成無(wú)線射頻通信功能。nRF24L01+和ESP8266 ESP-01具有相似的外形尺寸和引腳布局(乍一看甚至完全相同)。但是兩者的控制方式和功能完全不同。在本教程中,我們將介紹使用該RF模塊所需的基礎(chǔ)知識(shí),同時(shí)還會(huì)介紹該模塊如何與其他RF模塊和微控制器通信。就本教材而言,我們將演示該模塊如何與Arduino Uno微控制器相連。
nRF24L01+基于Nordic Semiconductor nRF24L01+,是一種“用于2.4GHz ISM(工業(yè)、科學(xué)和醫(yī)療)頻段的RF收發(fā)器IC”。
規(guī)格參數(shù):
2.4GHz ISM 頻段運(yùn)行
Vcc標(biāo)稱電壓為3.3V(耐壓輸入5V)
片上穩(wěn)壓
無(wú)線傳輸速率為250kbps、1Mbps、2Mbps
超低運(yùn)行功耗
6個(gè)數(shù)據(jù)通道
首先,我們來(lái)介紹以下該模塊的硬件部分。與ESP-01類似,該RF模塊配有4×2公頭接口。然而,模塊的實(shí)際引腳布局與ESP-01模塊不同,這是因?yàn)樵揜F模塊利用不同的通信協(xié)議——利用不同的與其他設(shè)備通信。如果您想了解有關(guān)SPI協(xié)議的更多信息,請(qǐng)查看我們的Arduino Arduino通信協(xié)議教程!
RF模塊的引腳布局如下圖所示。此信息來(lái)源于Addicore。
圖1.nRF24L01+ RF模塊的引腳說(shuō)明/ ?Addicore
根據(jù)設(shè)置,該RF模塊屬于SPI從器件,這意味著它只能與具有專用SPI通信線路的器件一起工作。因此,圖中顯示的SPI MOSI、MISO和SCK(時(shí)鐘)引腳必須連接到微控制器上的相應(yīng)引腳。在Arduino上,這些引腳的定義如下:
MOSI: Arduino D11
MISO: Arduino D12
SCK: Arduino D13
CE和CSN引腳可以連到Arduino上的任何輸出GPIO引腳。在軟件中,SPI通信初始化時(shí)系統(tǒng)會(huì)指定這些引腳。
RF模塊與Arduino之間的連接示例如下:
圖2.CE和CSN引腳(圖中的黃色和綠色線)可以連至任意兩個(gè)未使用的數(shù)字引腳。在軟件中,您應(yīng)該在構(gòu)造RF模塊對(duì)象時(shí)指定這些引腳。
為了連接Arduino與該模塊,我們將使用TMRh20的RF24庫(kù)。該庫(kù)能夠方便地將RF模塊和MCU之間的低級(jí)通信打包成一個(gè)易于使用的C++類。
開始使用該模塊之前,我們將首先介紹一些背景基礎(chǔ)知識(shí)。在美國(guó),射頻設(shè)備能夠使用的頻率僅限于FCC分配的頻率范圍。ISM頻段是為科學(xué)和醫(yī)療儀器保留的一個(gè)頻率范圍,我們的RF模塊將使用該ISM范圍內(nèi)的頻率進(jìn)行通信。使用RF模塊時(shí),我們無(wú)需了解這些頻率的細(xì)節(jié)或者通信是如何在這些頻率上發(fā)生的。我們將專注于可以控制的無(wú)線RF通信內(nèi)容。
如果滾動(dòng)瀏覽RF24庫(kù)文件,您會(huì)注意到里面有許多參數(shù)可以設(shè)置。關(guān)鍵參數(shù)如下所示:
信道:通信發(fā)生的特定頻率信道(頻率映射為0到125之間的整數(shù))
讀取通道:讀取通道是指一個(gè)唯一的24位、32位或40位地址,模塊從該地址讀取數(shù)據(jù)
寫入通道:寫入通道是模塊寫入數(shù)據(jù)的唯一地址
功放(PA)級(jí)別:PA級(jí)別負(fù)責(zé)設(shè)定芯片的功耗,從而設(shè)定傳輸功率。就本教程而言(與Arduino一起使用),我們將使用最小功率設(shè)置。
RF24庫(kù)文檔頁(yè)面提供了一些入門的優(yōu)秀示例代碼。示例項(xiàng)目的地址如下:https://tmrh20.github.io/RF24/examples.html
接下來(lái),我們?cè)凇癎etting Started”Arduino代碼中查看一下上文列出的參數(shù)是如何初始化的?!癎etting Started”(入門)代碼的地址如下:
https://tmrh20.github.io/RF24/GettingStarted_8ino-example.html
GettingStarted.ino
/* * 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 #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 timestamp 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
首先,我們需要注意文件頂部的兩個(gè)C++ #include指令:一個(gè)用于包含Arduino SPI庫(kù)(前文提到RF模塊使用SPI與Arduino通信),另一個(gè)用于包含RF24庫(kù)。
#include
#include “RF24.h”
接下來(lái),我們需要注意構(gòu)造RF24對(duì)象的這行代碼:RF24 radio(7,8); 傳遞給構(gòu)造函數(shù)的兩個(gè)參數(shù)是連至模塊的CE和CSN數(shù)字引腳。MOSI、MISO和SCK引腳必須分別是數(shù)字引腳11、12和13,可是CE和CSN引腳可以連接任意兩個(gè)數(shù)字引腳!
接下來(lái),我們來(lái)看一下讀寫通道地址。您可能猜到了,寫入和讀取通道地址在兩個(gè)彼此通信的無(wú)線設(shè)備之間是互換的,因?yàn)橐粋€(gè)無(wú)線設(shè)備的寫入通道是另一個(gè)的讀取通道。無(wú)線通訊地址的大小為24位、32位或40位。在示例代碼中,這些地址是從C++字符串文字轉(zhuǎn)換而來(lái),但您也可以以二進(jìn)制或十六進(jìn)制格式指定它們。比如,指定為十六進(jìn)制的40位地址可以是0xF0F0F0F0F0。存儲(chǔ)寫入和讀取通道地址時(shí),一個(gè)良好的編程實(shí)踐是將兩個(gè)值放在一個(gè)數(shù)組中。在示例代碼中,寫入和讀取通道的地址存儲(chǔ)在名為“地址”的字節(jié)數(shù)組中。
在void setup()方法中,我們需要說(shuō)明如何使用地址通道參數(shù)和其他參數(shù)初始化無(wú)線設(shè)備。
首先,系統(tǒng)調(diào)用RF24::begin()方法。針對(duì)radio對(duì)象調(diào)用其它RF24庫(kù)之方法之前,必須先調(diào)用begin() ,這是因?yàn)樵摲椒ㄘ?fù)責(zé)初始化RF芯片的運(yùn)行。
接下來(lái),系統(tǒng)調(diào)用RF24::setPALevel() 方法,以設(shè)定功放(PA)級(jí)別。為了指定功放級(jí)別,RF24庫(kù)提供了不同的常數(shù)值。更高的PA級(jí)別意味著模塊可以實(shí)現(xiàn)更長(zhǎng)距離的通信,但是在運(yùn)行期間會(huì)消耗更多的電流。作為入門程序,我們將RF_24_LOW常數(shù)作為一個(gè)參數(shù)傳遞給setPALevel()方法,因?yàn)閮蓚€(gè)通信模塊之間的距離不會(huì)很大。一般來(lái)講,該RF模塊與Arduino板配合使用時(shí),我們應(yīng)該保持PA級(jí)別盡可能地低,從而減少Arduino穩(wěn)壓電源的電流消耗。
接下來(lái),我們將討論如何初始化寫入和讀取通道。我們已經(jīng)將寫入和讀取通道定義為一些字節(jié)值。現(xiàn)在,我們必須將這些定義傳遞給radio對(duì)象,這樣它才會(huì)知道寫入和讀取通道地址。系統(tǒng)用openWritingPipe() 方法設(shè)定寫入通道;用openReadingPipe()方法設(shè)定讀取通道。打開寫入和讀取通道的示例如下:
radio.openWritingPipe(addresses[1]);
radio.openReadingPipe(1, addresses[0]);
請(qǐng)注意,我們還必須為openReadingPipe()方法傳遞一個(gè)額外的整數(shù)參數(shù),指明初始化哪個(gè)讀取通道。這是因?yàn)镽F模塊在給定時(shí)間最多可以打開6個(gè)讀取通道!
示例代碼通過(guò)一個(gè)role布爾值來(lái)適當(dāng)分配讀取和寫入通道值。根據(jù)role的值,程序確定RF模塊是ping設(shè)備還是pong設(shè)備。您的其他項(xiàng)目也可以使用類似代碼。但是,要確保兩個(gè)設(shè)備的讀寫地址互換,否則無(wú)法實(shí)現(xiàn)數(shù)據(jù)傳輸或讀取!
調(diào)用RF24::startListening()方法之后,無(wú)線模塊開始偵聽。需要注意的是,指示RF模塊開始監(jiān)聽數(shù)據(jù)之前必須初始化讀取通道(即調(diào)用startListening()方法之前必須先調(diào)用openReadingPipe()方法?。?/p>
類似地,RF24類還提供了一個(gè)stopListening()方法,無(wú)線模塊開始寫入之前必須首先調(diào)用該方法。
在示例代碼中,您可能會(huì)注意到程序利用RF24::available()方法告知無(wú)線電模塊檢查傳入的數(shù)據(jù)。這與我們之前見(jiàn)過(guò)的Serial::available()和SoftwareSerial::available() 方法類似——如果RF連接上的數(shù)據(jù)可用,那么available()方法返回真,然后就可以讀取數(shù)據(jù)了。
最后,RF24類提供了實(shí)際數(shù)據(jù)寫入和讀取的方法。RF24::write()與RF24::read()方法的參數(shù)包括(1)指向與傳輸數(shù)據(jù)類型相同的變量的指針,以及(2)傳輸數(shù)據(jù)的大小。在read()方法中,指針指向的變量負(fù)責(zé)接收正在讀取的數(shù)據(jù)。在write()方法中,指針指向的變量負(fù)責(zé)保存正在寫入的數(shù)據(jù)。在這兩種方法中,我們必須確保指針指向與傳輸數(shù)據(jù)類型相同的變量,并且傳遞給方法的大小實(shí)際上反映了數(shù)據(jù)的大小。將不正確的類型或大小值傳遞給read()和write()方法可能會(huì)產(chǎn)生不希望的值截?cái)?,從而?dǎo)致傳輸?shù)臄?shù)據(jù)無(wú)用。在“Getting Started”代碼中,需要傳輸?shù)臄?shù)據(jù)是一個(gè)unsigned long類型。因此,傳遞給read()和write()方法的指針參數(shù)也應(yīng)該指向一個(gè)unsigned long型的變量。很明顯,傳輸數(shù)據(jù)的大小始終是unsigned long類型變量的大小。在這種情況下,大小并不需要用一個(gè)整數(shù)進(jìn)行傳遞,大小(size)參數(shù)可以簡(jiǎn)單地寫為sizeof(unsigned long)。
“Getting Started”(入門)代碼中唯一沒(méi)有涉及的參數(shù)是信道(communication channel)。如果需要指定具體信道(比如您有多個(gè)RF網(wǎng)絡(luò),不希望彼此干擾),那么可以將一個(gè)8位的整數(shù)參數(shù)傳遞給RF24::setChannel() 方法,以設(shè)置信道。其代碼示例如下:radio.setChannel(10);
請(qǐng)將兩個(gè)RF模塊連到兩個(gè)獨(dú)立的Arduino板上,并且都上傳“Getting Started”(入門)代碼(您必須將其中一塊板的role布爾值改為1)。您現(xiàn)在應(yīng)該能夠根據(jù)相應(yīng)的ping時(shí)間發(fā)送消息并且接收返回的消息了!下圖是“ping”和“pong”兩個(gè)串口監(jiān)視器的并排截圖:
圖3.左:“ping”監(jiān)視器語(yǔ)句(設(shè)備1);右:“pong”監(jiān)視器語(yǔ)句(設(shè)備0)
恭喜您完成nRF24L01+教程的學(xué)習(xí)!您現(xiàn)在已經(jīng)掌握了使用這些漂亮RF模塊研發(fā)相關(guān)項(xiàng)目的技能和知識(shí)了!要了解涉及這些RF模塊的項(xiàng)目,您可以瀏覽Device Plus博客!
審核編輯:湯梓紅
-
微控制器
+關(guān)注
關(guān)注
48文章
7932瀏覽量
154022 -
通信協(xié)議
+關(guān)注
關(guān)注
28文章
1021瀏覽量
41042 -
RF
+關(guān)注
關(guān)注
65文章
3175瀏覽量
168694 -
nRF24L01
+關(guān)注
關(guān)注
17文章
331瀏覽量
70959
發(fā)布評(píng)論請(qǐng)先 登錄
NRF24L01無(wú)線模塊_2.4G無(wú)線通信模塊_24L01+升級(jí)
nrf24l01無(wú)線模塊傳輸距離分析
nRF24L01無(wú)線模塊使用教程之經(jīng)典使用程序詳細(xì)資料合集免費(fèi)下載
NRF24L01的模塊資料和C語(yǔ)言程序和使用與開發(fā)攻略合集免費(fèi)下載

微雪電子NRF24L01 RF Board 2.4G無(wú)線模塊簡(jiǎn)介

nrf24l01是什么模塊_nrf24l01工作原理
nRF24L01無(wú)線通信模塊使用簡(jiǎn)介

來(lái)自nrf24L01模塊的BLE信標(biāo)

評(píng)論