2015.08.29 13:00

邁入『物聯網』的第一步:如何使用無線傳輸:基本篇

ADVERTISEMENT

物聯網需要傳輸大量的資料,並且需要連接許多的周邊,每一個周邊都要傳輸資料,如果每一個週邊都還要上網,那就太可怕了,不只網路熱點承受不起,一般網路集線器(Switch Hub)也無法承受密集的資料傳輸,何況都必需要通過網路路由器(Router)連接到網際網路,那更是家用網路、中小型企業等無法負擔的網路架構。

文\曹永忠、許智誠、蔡英德

為了解決這樣的問題,我們可以發現,每一個Arduino開發板都有許多記憶體,並且有足夠的能力可以先將資訊儲存後,再發送到大的網路節點,並統一發送到網際網路,但是這些小節點如何傳輸資料到資料收集站呢,如果透過有線網路傳輸,這肯定是不合用的解決方案,如果我們使用無線網路來傳輸,或許可以為這樣的問題提供解決方案,今天的內容就要先介紹『NRF24L01』網路通訊模組如何作一對一的資料傳輸,後續,我們會再進階介紹一對多的資料傳輸,或許可以為此問題提供解決方法。

ADVERTISEMENT

▲ nFR24L01 2.4G無線模組

NRF24L01是一款工作在2.4-2.5GHz世界通用ISM頻段的收發晶片模組,NRF24L01無線收發器包括:頻率發生器 增強型 SchockBurstTM 模式控制器、功率放大器、晶體放大器、調製器、解調器、輸出功率頻道選擇和協定的設置可以通過SPI介面進行設置極低的電流消耗,當工作在發射模式下發射功率為6dBm時,電流消耗為9.0mA,接受模式為12.3mA掉電模式和待機模式下電流消耗模式更低。

ADVERTISEMENT

NRF24L01是一款工作在2.4-2.5GHz區段,採用全球開放ISM 頻段,最大0dBm 發射功率,免許可證(NCC認證)使用。在空曠的地方傳輸可達100米傳輸的距離,並支援六路通道的資料接收。

ISM頻段(Industrial Scientific Medical Band),中文意思分別是工業的(Industrial)、科學的(Scientific)和醫學的(Medical),因此顧名思義ISM頻段就是各國挪出某一段頻段主要開放給工業,科學和醫學機構使用。應用這些頻段無需許可證或費用,只需要遵守一定的發射功率(一般低於1W),並且不要對其它頻段造成干擾即可。ISM頻段在各國的規定並不統一。如在美國有三個頻段902-928 MHz、2400-2484.5 MHz及5725-5850 MHz,而在歐洲900MHz的頻段則有部份用於GSM通信。而2.4GHz為各國共同的ISM頻段。因此無線區域網(IEEE 802.11b/IEEE 802.11g),藍牙,ZigBee等無線網絡,均可工作在2.4GHz頻段上。(http://zh.wikipedia.org/wiki/ISM%E9%A2%91%E6%AE%B5)

ShockBurst 是一種數據通訊的前置處理方式,其作用是改變低速數據在高速通訊訊道的收發間距,以脈衝數據封包packet的模式(burst mode)傳送資料,其目的是有效利用訊道,加長資料封包的連續間距並在這段其間關閉或降低對收發器的供電量,以達致低功耗省電的目的。其中最重要的環節是一組FIFO First In First Out Registers,數據在發送出去前先送進這組FIFO中貯存起來,在收集了一定數量的數據組或是在特定時間達到後,再以高速把整組資料發送出去。

產品規格

  • 低工作電壓:1.9~3.6V低電壓工作。
  • 高速率:2Mbps,由於空中傳輸時間很短,降低了無線傳輸中的碰撞現象(軟體設定1Mbps或者2Mbps的空中傳輸速率)。
  • 多頻點:125 頻點,滿足多點通訊和跳頻通訊需要。
  • 超小型:內置2.4GHz天線,體積小巧,15x29mm(包括天線)。
  • 低功耗:當工作在應答模式通訊時,快速的空中傳輸及啟動時間,極大的降低了電流消耗。
  • 低應用成本:NRF24L01 整合了所有與RF協定相關的高速信號處理部分,比如:自動重發丟失資料封包和自動產生應答信號等,NRF24L01的SPI介面可以利用單片機的硬體SPI口連接或用單片機I/O口進行模擬,內部有FIFO可以與各種高低速微處理器介面,便於使用低成本單片機。
  • 便於開發:由於鏈路層完全整合在模組上,非常便於開發。自動重發功能,自動檢測和重發丟失的資料封包,重發時間及重發次數可由軟體控制 自動存儲未收到應答信號的資料封包自動回應功能,在收到有效資料後,模組自動發送應答信號,無須另行程式檢測—固定頻率檢測、內置硬體 CRC 檢核和點對多點通訊位址控制資料封包傳輸錯誤計數器及載波檢測功能可用於跳頻設置可同時設置六路接收通道位址,可有選擇性的打開接收通道。
  • 標準DIP 2.54MM間距介面,便於焊接與一般電路應用。

 產品特點

  1. 2.4Ghz全球開放ISM頻段免許可證使用。
  2. 最高工作速率2Mbps,高效GFSK調制,抗干擾能力強,適合工業控制。
  3. 125頻道,滿足多點網絡通訊需要。
  4. 內置硬體8/16位CRC檢核和點對多點通訊位址控制,結合TDMA-CDMA-FDMA原理,可實做無線網絡通訊。
  5. 低功耗1.9 - 3.6V工作,待機模式下狀態僅為1uA 電流。
  6. 模組可使用軟體設定位址,只有收到本機位址時才會輸出數位(提供中斷指示),可直接接各種單晶片使用,撰寫軟體非常容易。
  7. 收發完成可以觸發中斷旗標,每次最多可發28字元。
  8. 專門穩壓電路,使用各種電源包括DC/DC開關電源均有很好的通訊效果。
  9. 標準DIP接腳間距,便於嵌入式系統之應用。
  10. CLK,DATA,DR三線接腳,撰寫軟體非常容易。
  11. 雙通道數位接收,外置天線,無干擾空間條件下可通訊距離達100米。
  12. 尺寸: 31mm * 17mm(尺寸不含天線,標準配備為4.5CM柱狀天線)。

如圖所示,這個實驗我們需要用到的是兩組nFR24L01 2.4G無線模組,一組用來發射使用,一組用來接收使用,這裡說一下,nFR24L01 2.4G無線模組只能單向雙工,一個模組只能單純發送或接收,不能改變,所以我們使用兩塊Arduino開發板來分別收發。

▲ nFR24L01 2.4G無線模組

nFR24L01 2.4G無線模組電路連接 

本實驗是使用Arduino Mega 2560開發板與Arduino UNO開發版,連接nFR24L01 2.4G無線模組個自當做一個發射端、接收端模組,不過先當做發射端來使用。

▲nFR24L01 2.4G無線模組接腳

Arduino UNO開發版,也同時連接nFR24L01 2.4G無線模組發當做射端端來使用。

Arduino Mega 2560開發版,也同時連接nFR24L01 2.4G無線模組當做接收端來使用。

由於nFR24L01 2.4G無線模組需要用到SPI界面,我們參考下表進行電路連接,並參考下下表將外部硬體插斷接起來。

表  Arduino SPI接腳對照圖

Arduino Board

MOSI

MISO

SCK

SS
(slave)

SS
(master)

Uno or Duemilanove

11 or ICSP-4

12 or ICSP-1

13 or ICSP-3

10

-

Mega1280 or Mega2560

51 or ICSP-4

50 or ICSP-1

52 or ICSP-3

53

-

Leonardo

ICSP-4

ICSP-1

ICSP-3

-

-

Due

ICSP-4

ICSP-1

ICSP-3

-

4, 10, 52

表  Arduino開發板外部插斷接腳圖

Board

int.0

int.1

int.2

int.3

int.4

int.5

Uno, Ethernet

2

3

 

 

 

 

Mega2560

2

3

21

20

19

18

Leonardo

3

2

0

1

7

 

首先,上述提到Arduino SPI接腳與Arduino開發板外部插斷接腳之後,我們完成下表之nFR24L01 2.4G無線模組發射端接腳表與下下表之nFR24L01 2.4G無線模組接收端接腳表。
表  nFR24L01 2.4G無線模組發射端接腳表

nFR24L01 2.4G無線模組發射模組

接腳

接腳說明

Arduino開發板接腳

1

VCC 3.3V

Arduino +3.3V

2

GND                   

Arduino GND板接

3

MOSI

Arduino Digital Pin 11

4

MISO

Arduino Digital Pin 12

5

SCK

Arduino Digital Pin 13

6

CE

Arduino Digital Pin 8

7

CSN

Arduino Digital Pin 7

8

IRQ(Using Interrupt 0)

Arduino Digital Pin 2

▲透視圖

▲nFR24L01 2.4G無線模組

 

▲Arduino UNO開發版

 

表  nFR24L01 2.4G無線模組接收端接腳表

nFR24L01 2.4G無線模組接收模組

接腳

接腳說明

Arduino開發板接腳 

1

VCC 3.3V

Arduino +3.3V

2

GND                   

Arduino GND板接

3

MOSI

Arduino Digital Pin 51

4

MISO

Arduino Digital Pin 50

5

SCK

Arduino Digital Pin 52

6

CE

Arduino Digital Pin 8

7

CSN

Arduino Digital Pin 53

8

IRQ(Using Interrupt 1)

Arduino Digital Pin 3

 

透視圖

nFR24L01 2.4G無線模組

Arduino Mega 2560開發板

先前我們已將Arduino 開發板的驅動程式安裝好之後,我們打開Arduino 開發板的開發工具:Sketch IDE整合開發軟體,撰寫一段程式,如下表所示之nFR24L01 2.4G無線模組發射測試程式,我們就可以讓nFR24L01 2.4G無線模組發射送出資料,透過2.4Ghz的無線電波傳送資料。

表  nFR24L01 2.4G無線模組發射測試程式

nFR24L01 2.4G無線模組發射測試程式(ping_client)

/**

 * A Mirf example to test the latency between two Ardunio.

 *

 * Pins:

 * Hardware SPI:

 * MISO -> 12

 * MOSI -> 11

 * SCK -> 13

 *

 * Configurable:

 * CE -> 8

 * CSN -> 10

 *

 * Note: To see best case latency comment out all Serial.println

 * statements not displaying the result and load

 * 'ping_server_interupt' on the server.

 */

 

#include <SPI.h>

#include <Mirf.h>

#include <nRF24L01.h>

#include <MirfHardwareSpiDriver.h>

byte num = 0 ;

byte num1 = 0 ;

void setup() {

  Serial.begin(9600);

  /*

   * Setup pins / SPI.

   */

 

  /* To change CE / CSN Pins:

   *

   * Mirf.csnPin = 9;

   * Mirf.cePin = 7;

   */

  /*

  Mirf.cePin = 7;

  Mirf.csnPin = 8;

  */

  Mirf.spi = &MirfHardwareSpi;

  Mirf.init();

   Mirf.payload = 1;      // this means length of send data

  /*

   * Configure reciving address.

   */

 

  /*

   * To change channel:

   *

   * Mirf.channel = 10;

   *

   * NB: Make sure channel is legal in your area.

   */

 

  Mirf.config();

  Mirf.setTADDR((byte *)"bruce");

  Mirf.setRADDR((byte *)"UNO");

 

 

  Serial.println("Beginning ... ");

 

}

 

void loop() {

  unsigned long time = millis();

 // Serial.println("get time data finish...");

//  Mirf.setTADDR((byte *)"bruce");

//  Serial.println("set target server finish...");

  if (num >= 255)

      num = 0 ;

 

    transmit((char)num)  ;

    Serial.print(num);

    Serial.print(" S    " );

    num ++ ;

 

if (!Mirf.isSending() && Mirf.dataReady()) {

        Mirf.getData((byte *) &num1);

           Serial.print("/");

          Serial.print(num1);

            Serial.print("  R ");

            Serial.print("\n");

      }

      else

      {

               Serial.print("\n");

      }

/*

  Serial.print("sending data: ");

  Serial.print(time);

  Serial.print(" to server finish...\n") ;

 

  while (Mirf.isSending()) {

    // wait data sending....until finished

  }

 

  Serial.println("data sending..finished");

 

  delay(10);

  while (!Mirf.dataReady()) {

    //Serial.println("Waiting");

    if ( ( millis() - time ) > 1000 ) {

      Serial.println("Timeout on response from server!");

      return;

    }

  }

 

  Mirf.getData((byte *) &time1);

 

  Serial.print("Ping: ");

  Serial.print(time1);

  //Serial.print("and cost time : ");

  //

  // Serial.print(time1 - time);

  Serial.print(" ; Get echo from server ... \n") ;

 

  Serial.print("==============\n\n\n") ;

  delay(1000);

  */

}

 

void transmit(char st)

{

  byte c;

 

   // Serial.println("Now enter char sending");

    c = st;

    Mirf.send(&c);

    while( Mirf.isSending() ) ;

}

 

 

void transmit( float v)

{

  byte c;

  char buf[10];

 

  dtostrf(v,9,3,buf);

 

  for( int i=0 ; i<8 ; i++ )

  {

    c = buf[i];

    Mirf.send(&c);

    while( Mirf.isSending() ) ;

  }

}

 

// sends a string via the nRF24L01

void transmit(const char *string)

{

  byte c;

 

  for( int i=0 ; string[i]!=0x00 ; i++ )

  {

    c = string[i];

    Mirf.send(&c);

    while( Mirf.isSending() ) ;

  }

}

 

 

 

// send a CR/LF sequence via the nRF24L01

void transmitlf(void)

{

  byte c;

 

  c = '\r';

  Mirf.send(&c);

    while( Mirf.isSending() ) ;

 

  c = '\n';

  Mirf.send(&c);

    while( Mirf.isSending() ) ;

}

 

 

void waitforsending()

{

unsigned long  t1 = millis() ;

unsigned long  t2 = millis() ;

   while(Mirf.isSending())

      {

        t2 = millis() ;

 

            Serial.println(t2-t1) ;

        if ((t2-t1) >=200 )

            return ;

      }

}  

 

void waitforreceiving()

{

unsigned long  t1 = millis() ;

unsigned long  t2 = millis() ;

   while(Mirf.dataReady())

      {

        t2 = millis() ;

 

            Serial.println(t2-t1) ;

        if ((t2-t1) >=200 )

            return ;

      }

}  

原始碼資料網站:https://github.com/brucetsao/arduino_RFProgramming

網友可以由下圖,看到本次實驗- nFR24L01 2.4G無線模組發射測試程式結果畫面。

▲ nFR24L01 2.4G無線模組發射測試程式結果畫面

將Arduino 開發板的驅動程式安裝好之後,我們打開Arduino 開發板的開發工具:Sketch IDE整合開發軟體,撰寫一段程式,如下表所示之nFR24L01 2.4G無線模組接收測試程式,我們就可以讓nFR24L01 2.4G無線模組接收由發射端送出的資料,透過2.4Ghz的無線電波來接收資料。

表 nFR24L01 2.4G無線模組接收測試程式

nFR24L01 2.4G無線模組接收測試程式(ping_server)

/**

 * An Mirf example which copies back the data it recives.

 *

 * Arduino UNO Pins:

 * Hardware SPI:

 * MISO -> 12

 * MOSI -> 11

 * SCK -> 13

 *

  * Arduino MEGA 2560 use Pins:

 * Hardware SPI:

 * MISO -> 50

 * MOSI -> 51

 * SCK -> 52

 * Configurable:

 * CSN -> 7

* CE -> 8

 */

#include <Wire.h>

#include <LiquidCrystal_I2C.h>

 

LiquidCrystal_I2C lcd(0x27, 20, 4); // set the LCD address to 0x27 for a 16 chars and 2 line display

 

 

#include <SPI.h>

#include <Mirf.h>

#include <nRF24L01.h>

#include <MirfHardwareSpiDriver.h>

#define ledpin 7

byte recvdata ;

 

void setup() {

    //  pinMode(ledpin,OUTPUT) ;

  Serial.begin(9600);

  lcd.init();                      // initialize the lcd

 

  // Print a message to the LCD.

  lcd.backlight();

  lcd.print("RF Monitor!");

  /*

   * Set the SPI Driver.

   */

 

 

  Mirf.spi = &MirfHardwareSpi;

  /*

   * Setup pins / SPI.

   */

 

  Mirf.init();

 

  /*

   * Configure reciving address.

   */

 

  Mirf.setRADDR((byte *)"bruce");

   Mirf.setTADDR((byte *)"UNO");

  /*

   * Set the payload length to sizeof(unsigned long) the

   * return type of millis().

   *

   * NB: payload on client and server must be the same.

   */

 

 Mirf.payload =1;

 

  /*

   * Write channel and payload config then power up reciver.

   */

 

  Mirf.config();

 

  Serial.println("Listening...");

  pinMode(ledpin,OUTPUT) ;

}

 

void loop() {

    lcd.setCursor(0, 1) ;

     lcd.print("               ");

      lcd.setCursor(0, 1) ;

      lcd.print(millis()) ;

 

  //  Serial.println(millis()) ;

  /*

   * A buffer to store the data.

   */

 

 

  // byte data[Mirf.payload];

  //  Serial.println("now looping...");

  /*

   * If a packet has been recived.

   *

   * isSending also restores listening mode when it

   * transitions from true to false.

   */

Serial.println("Now waiting Get Data");

if (!Mirf.isSending() && Mirf.dataReady()) {

  //  if(Mirf.dataReady()){

   Serial.println("Get packet before");

 

    /*

     * Get load the packet into the buffer.

     */

 

       Mirf.getData(&recvdata);

   Serial.println("GOt packet after");

 

    /*

     * Set the send address.

     */

    lcd.setCursor(0, 2) ;

     lcd.print("               ");

      lcd.setCursor(0, 2) ;

      lcd.print(millis()) ;

    lcd.setCursor(0, 3) ;

     lcd.print("               ");

      lcd.setCursor(2, 3) ;

      lcd.print(recvdata) ;

      /*

    for (int i = 0 ; i < Mirf.payload; i++)

    {

      lcd.setCursor(2+(i)*4, 2) ;

      lcd.print(data[i],HEX) ;

   //   lcd.print((unsigned long)*data) ;   // use for unsign long

    }

    */

 

    //       delay(10);

 

  }

}

 

void messagecoming()

{

  digitalWrite(ledpin, HIGH) ;

  delay(3);

  digitalWrite(ledpin, LOW) ;

  delay(3); 

原始碼資料網站:https://github.com/brucetsao/arduino_RFProgramming

網友也可以在作者YouTube頻道(https://www.youtube.com/user/UltimaBruce )中,在網址: https://www.youtube.com/watch?v=ubFQfczrsIE&feature=youtu.be,看到本次實驗- nFR24L01 2.4G無線模組接收測試程式結果畫面。

網友可以由下圖,看到本次實驗- nFR24L01 2.4G無線模組接收測試程式結果畫面。

▲ nFR24L01 2.4G無線模組接收測試程式結果畫面

上述內容就是本篇主要介紹nFR24L01 2.4G無線模組在一對一的模式,如何傳輸資料,後續我們會再介紹nFR24L01 2.4G無線模組在一對多的模式傳輸資料,敬請網友密切注意本專欄喔。

作者介紹

曹永忠 (Yung-Chung Tsao):目前為自由作家、台灣資訊傳播學會秘書長,專研於軟體工程、軟體開發與設計、物件導向程式設計,商品攝影及人像攝影。長期投入資訊系統設計與開發、企業應用系統開發、軟體工程、新產品開發管理、商品及人像攝影等領域,並持續發表作品及相關專業著作。

Email: ,Line ID:dr.brucetsao 

Arduino部落格:

範例原始碼網址:https://github.com/brucetsao/arduino_RFProgramming

臉書社群(Arduino.Taiwan):https://www.facebook.com/groups/Arduino.Taiwan/

Arduino活動官網:

Youtube:https://www.youtube.com/channel/UCcYG2yY_u0m1aotcA4hrRgQ

ADVERTISEMENT