Single.9

Single‧9


RF24 - nRF24L01 專屬 Library

Posted: 02 Jan 2015 07:27 PM PST

nRF24L01

我在大學研究的專題可以說是自幹一個 Zigbee 的無線網路系統,我所採用無線傳輸模組是不在 IEEE 規範中的 2.4GHz 無線網路模組 nRF24L01,並且利用 以及 Raspberry Pi 做雛形開發。很久之前還有為了它與 Launchpad 之間的通訊而寫過一篇文章。至於我專題的細節,改天再來說說。

nRF24L01 是一個非常便宜,便宜到可以說是不可思議的無線傳輸模組,且透過 SPI 的方式與微處理器溝通與傳輸資料。以下是 nRF24L01 的一些特色。

  • 使用2.4GHz全球開放頻寬
  • 126個可選擇頻道
  • 可設定收發位址及頻率
  • 最高 2Mbps 的資料傳輸速率
  • 可程式控制的輸出功率(最大0dBm,消耗11.3mA)
  • 1.9~3.3V低電壓
  • 使用SPI界面控制
  • 細節可以參考官方網站

如果你剛剛有去翻閱一下先前寫的那篇文章的話,應該會對於這個傳輸模組有些微的概念。但那篇文章的操作環境主要是在 Launchpad 這個由 TI 出品的開發板上,而今天要介紹的,則是讓你能透過 Raspberry Pi 的 GPIO 來操作這個無線傳輸模組。

RF24

RF24 是一個支援多種單板電腦的 C++ 程式函式庫(Library),因為這種外接模組並不像是 USB 裝置那樣,可以隨插隨用,而是要透過一些特殊的程式才能運作,而通常這些程式都是由一些義工愛好者們所提供的。RF24便是其中之一。

RF24 提供許多方便好用的 function 讓你可以快速的掌握 nRF24L01 ,並且讓他可以跟 Raspberry Pi 緊密結合,做更多你想用他做的事情。

目前支援的單板電腦除了 Raspberry 以外,還有...

  • Intel Galileo
  • Arduino Uno, Nano... ATMega 328 核心的
  • Arduino Mega Boards
  • Arduino Due
  • ATTiny

其他細節可以參考他的 Git Page

Class Reference

可以直接參考這裡的內容,因為項目繁多,我就不一一介紹了。

範例

範例程式其實包在所下載下來的資料包中,不過都是英文,所以我就把幾個內容給簡單的翻譯一下,也順便讓你了解這個函式庫的使用方法。

/*
 Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 version 2 as published by the Free Software Foundation.
 03/17/2013 : Charles-Henri Hallard (http://hallard.me)
              Modified to use with Arduipi board http://hallard.me/arduipi
                          Changed to use modified bcm2835 and RF24 library
TMRh20 2014 - Updated to work with optimized RF24 Arduino library
 */
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <string>
#include <RF24/RF24.h>
using namespace std;
//
// Hardware configuration
// Configure the appropriate pins for your connections
// Radio CE Pin, CSN Pin, SPI Speed
// Setup for GPIO 22 CE and CE1 CSN with SPI Speed @ 1Mhz
//RF24 radio(RPI_V2_GPIO_P1_22, RPI_V2_GPIO_P1_26, BCM2835_SPI_SPEED_1MHZ);
// Setup for GPIO 22 CE and CE0 CSN with SPI Speed @ 4Mhz
//RF24 radio(RPI_V2_GPIO_P1_22, BCM2835_SPI_CS0, BCM2835_SPI_SPEED_4MHZ);
// NEW: Setup for RPi B+
//RF24 radio(RPI_BPLUS_GPIO_J8_15,RPI_BPLUS_GPIO_J8_24, BCM2835_SPI_SPEED_8MHZ);
// Setup for GPIO 15 CE and CE0 CSN with SPI Speed @ 8Mhz
RF24 radio(RPI_V2_GPIO_P1_15, RPI_V2_GPIO_P1_24, BCM2835_SPI_SPEED_8MHZ);
/********** User Config *********/
// Assign a unique identifier for this node, 0 or 1
bool radioNumber = 1;
/********************************/
// Radio pipe addresses for the 2 nodes to communicate.
const uint8_t pipes[][6] = {"1Node","2Node"};
int main(int argc, char** argv){
  bool role_ping_out = true, role_pong_back = false;
  bool role = role_pong_back;
  printf("RF24/examples/GettingStarted/\n");
  // Setup and configure rf radio
  radio.begin();
  // optionally, increase the delay between retries & # of retries
  radio.setRetries(15,15);
  // Dump the configuration of the rf unit for debugging
  radio.printDetails();
/********* Role chooser ***********/
  printf("\n ************ Role Setup ***********\n");
  string input = "";
  char myChar = {0};
  cout << "Choose a role: Enter 0 for pong_back, 1 for ping_out (CTRL+C to exit) \n>";
  getline(cin,input);
  if(input.length() == 1) {
    myChar = input[0];
    if(myChar == '0'){
        cout << "Role: Pong Back, awaiting transmission " << endl << endl;
    }else{  cout << "Role: Ping Out, starting transmission " << endl << endl;
        role = role_ping_out;
    }
  }
/***********************************/
  // This simple sketch opens two pipes for these two nodes to communicate
  // back and forth.
    if ( !radioNumber )    {
      radio.openWritingPipe(pipes[0]);
      radio.openReadingPipe(1,pipes[1]);
    } else {
      radio.openWritingPipe(pipes[1]);
      radio.openReadingPipe(1,pipes[0]);
    }

    radio.startListening();

    // forever loop
    while (1)
    {
        if (role == role_ping_out)
        {
            // First, stop listening so we can talk.
            radio.stopListening();
            // Take the time, and send it.  This will block until complete
            printf("Now sending...\n");
            unsigned long time = millis();
            bool ok = radio.write( &time, sizeof(unsigned long) );
            if (!ok){
                printf("failed.\n");
            }
            // Now, continue listening
            radio.startListening();
            // Wait here until we get a response, or timeout (250ms)
            unsigned long started_waiting_at = millis();
            bool timeout = false;
            while ( ! radio.available() && ! timeout ) {
                if (millis() - started_waiting_at > 200 )
                    timeout = true;
            }
            // Describe the results
            if ( timeout )
            {
                printf("Failed, response timed out.\n");
            }
            else
            {
                // Grab the response, compare, and send to debugging spew
                unsigned long got_time;
                radio.read( &got_time, sizeof(unsigned long) );
                // Spew it
                printf("Got response %lu, round-trip delay: %lu\n",got_time,millis()-got_time);
            }
            sleep(1);
        }
        //
        // Pong back role.  Receive each packet, dump it out, and send it back
        //
        if ( role == role_pong_back )
        {

            // if there is data ready
            if ( radio.available() )
            {
                // Dump the payloads until we've gotten everything
                unsigned long got_time;
                // Fetch the payload, and see if this was the last one.
                while(radio.available()){
                    radio.read( &got_time, sizeof(unsigned long) );
                }
                radio.stopListening();

                radio.write( &got_time, sizeof(unsigned long) );
                // Now, resume listening so we catch the next packets.
                radio.startListening();
                // Spew it
                printf("Got payload(%d) %lu...\n",sizeof(unsigned long), got_time);

                delay(925); //Delay after payload responded to, minimize RPi CPU time

            }

        }
    } // forever loop
  return 0;
}

總結

其實個人覺得這個無線模組不難用,但問題在於傳輸距離。雖然宣稱可以長達 100 公尺以上的傳輸距離,但那只限定在沒有過多障礙物且傳輸速率較慢的環境下才有可能抵達這麼遠的距離,在我的實測過程中,2Mbps的速率下,最多只能到30M左右。

但是他的便宜、小巧以及低功耗可以讓它在小區域的無線控制上佔上一席之地。

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 knoledge 的頭像
    knoledge

    討論

    knoledge 發表在 痞客邦 留言(0) 人氣()