Arduino筆記(98):nRF24L01傳送與接收AHT10溫濕度值

nRF24L01是使用全球 2.4-2.5 GHz ISM(Industrial Scientific Medical Band) 頻段的單晶片無線電收發器,應用這些頻段無需許可證,只需要遵守符合規定的發射功率(一般低於1W),且不要對其它頻段造成干擾即可。nRF24L01透過 SPI 介面傳送資料的單向雙工無線模組,單向雙工是指能有一方傳送或接收,無法同時進行雙方同時傳送與接收。本篇實作要來瞭解一下 nRF24L01 無線傳輸的功能,將溫度感測值傳送至遠方的 nRF24L01,再經由 Arduino 連接的 LCD 顯示出來。


nRF24L01 的規格及特點如下:
  • 具有125個頻道,每個頻道支援6通道(Pipe)接收,傳輸速度高達2Mbps,可以滿足多點通訊和跳頻通訊的要求。
  • VCC 工作電壓 1.9~3.6V
  • 使用SPI介面進行設置,可設定輸出功率通道和協議等。
  • 傳送資料的單向雙工無線模組,亦即同一時間僅一方進行傳送,另一方進行接收。
  • 體積超小:24 * 15mm,內置2.4GHz天線。
  • 發射訊號在0dBm時,耗電11.3mA。發射功率 6dBm 時電流消耗為 9.0mA, 接收模式為 12.3mA, 比一顆 LED 耗電還低。
  • 接收2Mbps時,電流消耗12.3mA。
  • 空曠處傳輸距離可達180-240公尺。
  • 在應用方面,可用於無線鼠標和鍵盤、遊戲控制桿、遙控器、玩具及工業傳感器等。

nRF24L01接腳位置與說明如下:

接腳編號接腳簡稱功能說明
1GND(Ground)接地
2VCC(Power)使用3.3V電源
3CE(Chip Enable)是否啟動 SPI通訊
4CSN(Ship Select Not)該引腳必須始終保持高電平,否則將禁用SPI
5SCK(Serial Clock)提供用於SPI通信的時鐘脈衝
6MOSI(Master Out Slave In)連接到MCU的MOSI引腳,以使模塊從MCU接收數據
7MISO(Master In Slave Out)連接到MCU的MISO引腳,用於模塊從MCU發送數據
8IRQ(Interrupt)它是低電位有效的接腳,僅在需要中斷時使用,通常為傳送資料或收到資料的狀況下使用。

[安裝程式庫Library]

除了硬體的連接外,還需要 RF24 程式庫,才能驅動或管理這個無線射頻模組的接收與發射。本實作需要安裝以下程式庫:
如為下載程式庫(Library)安裝方法請參考另一篇文章:Arduino筆記:安裝 Arduino IDE 程式庫(Library)

[nRF24L01程式撰寫]

將 nRF24L01 模組連接到 Arduino Uno 後,就可以準備發送端和接收端的程式了。程式中需先將 SPI 及 RF24 這兩個程式庫包含(include)進來。接著構建 RF24 物件,這個物件需要兩個參數,就是連接 nRF24L01 模組的 CE 和 CSN 接腳編號,以本例來說,CE 跟 CSN 接在 Uno 的接腳 7 跟 8,建立一個名為 radio 的物件,指令如下:
RF24 radio(7,8);
接著再指定雙方或多方可以識別的通訊的頻道位址給一個變數,最長可為 40 位元。這個位址可以是一個位元陣列,作為不同的通訊頻道使用。如果是兩個設備間通訊,可以設定兩個位址,第一個位址負責傳送,第二個位址負責接收,設定範例如下:
const uint64_t addr = 0x00FF;
或
const uint8_t addresses[][6] = {"1Node","2Node"};
繼續使用 begin() 函式來啟動 RF24 晶片。
radio.begin();
啟動後,如果是傳送端,可使用 openWritingPipe(addr) 來初始化寫入資料的頻道位址。如果要寫入時,可以改變寫入的位址,或使用 stopListening() 函式管理正在發送或接收的頻道。
radio.openWritingPipe(addr);
開啟寫入頻道設定後,就可以使用 write 寫入字串給遠端的設備,需傳入兩個參數,分別是傳送字串的變數及傳送的長度,如下例:
radio.write(&temperature, sizeof(temperature));
到這裡已經將要傳送的資料送出,就等著接收端接收資料。

接收端需有不同的指令來進行接收,程式同樣要先將 SPI 及 RF24 這兩個程式庫包含(include)進來,指定傳送位址變數、構建 RF24 物件、使用 begin() 函式啟動,到這裡都和傳送端一樣。不同的是接收端需執行 openReadingPipe() 來設定接收的位址,這個函式需帶兩個參數,如以下範例,num 為通訊通道,在同一個位址下,最多可以開啟 6 個通道,也就是 num 的數值介於 0-5 之間, addr 則需與傳送端一樣,否則會收不到資料。
radio.openReadingPipe(num, addr);
開啟讀取頻道設定後,就可以使用 read 指令讀取遠端傳來的資料,函式指令如下,需帶兩個參數,一個是接收資料存放的變數以及接收的字元長度。
radio.read(temperature, sizeof(temperature));
到這裡,接收端可以順利完成資料的接收,這個過程只能單向資料傳輸。另一個情境是雙向傳輸,且定義兩個頻道時,第一個 Arduino 的寫入地址必須是第二個 Arduino 的讀取地址,反之亦然,第一個 Arduino 的讀取地址是第二個Arduino的寫入地址。我們將第一個 Arduino設置為發送器,使用 stopListening()函式停止傳送,再將要傳送的資料,使用 write()函式發送到接收端。在接收端,使用 startListening()函式將 Arduino 設置為接收器,並檢查是否有資料可讀取。當有讀取的資料時,使用 read()函式將讀取的值存到變數中,作為其他應用。

其他常用函式:
• startListening():開啟通道準備接收資料,開啟前要先開啟 openReadingPipe()。
• stopListening():停止偵聽傳入的資料,然後切換到傳輸模式。
• setPALevel() 設定廣播功率(PA, Power Amplifier)級別,RF24 函數庫提供四個常數值來設定不同的功率。功率的級別會影響傳送的距離,也會消耗更多的電流,也就是要將資料傳送更遠的距離就會耗掉較多的電流。通常在環境空曠的較佳環境下可達 1 公里以上;如有障礙或阻隔,大概也可達 100 米左右的距離,取決於環境的因素。通常距離很近,可以使用 RF24_PA_MIN 最小功率即可。設定的常數如下:
  • RF24_PA_MIN(最小功率)
  • RF24_PA_LOW(低功率)
  • RF24_PA_HIGH(高功率)
  • RF24_PA_MAX(最大功率)
• setDataRate():設定資料傳輸速率,預設的常數值有以下三種速率:
  • RF24_250KBPS:每秒250kb
  • RF24_1MBPS:每秒1Mbps
  • RF24_2MBPS:每秒2Mbps


[材料]

  • Arduino UNO  x2
  • nRF24L01 x2 
  • LCD1602液晶顯示器
  • I2C/介面 LCD1602轉接板 PCF8574
  • 麵包板 x2
  • AHT10 溫濕度感測器 x1
  • 排線 n 條

[接線圖]

發射端:
Arduino UnonRF24L01AHT10
GNDGNDGND
3.3VVCC-
5V-VCC
D8CE-
D9CSN-
D13SCK-
D11MOSI-
D12MISO-
A5-SCL
A4-SDA


接收端:
Arduino UnonRF24L01LCD1602
GNDGNDGND
3.3VVCC-
5V-VCC
D8CE-
D9CSN-
D13SCK-
D11MOSI-
D12MISO-
SCL-SCL
SDA-SDA



[程式]

傳送端程式:
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <Wire.h>
#include <AHT10.h>

uint8_t readStatus = 0;

AHT10 myAHT10(AHT10_ADDRESS_0X38);

float temperature[2];
float temp = 0;
float humidity = 0;

RF24 radio(8, 9);  // nRF24L01 連接 CE 及 CSN 的 Arduino 接腳編號
const uint64_t pipe = 0x00FF; // 設定發送端 pipe 名稱
 
void setup(void) {
  Serial.begin(9600);
  radio.begin();
  radio.openWritingPipe(pipe);

  while (myAHT10.begin() != true)
  {
    Serial.println(F("AHT10 not connected...")); 
    delay(5000);
  }
  Serial.println(F("AHT10 initial OK"));
}
 
void loop(void) {
    // 讀取 AHT10 的溫濕度
    temp = myAHT10.readTemperature();    //讀取 AHT10 溫度
    humidity = myAHT10.readHumidity();   //讀取 AHT10 濕度
    Serial.print("Temperatura: ");
    Serial.println(temp);
    Serial.print("Humidity': ");
    Serial.println(humidity);
    
    temperature[0] = temp;
    temperature[1] = humidity;
    radio.write(&temperature, sizeof(temperature));
    delay(1000);
}

接收端程式:
#include <SPI.h>
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <LiquidCrystal_I2C.h>   // 引用 LiquidCrystal_I2C Library

LiquidCrystal_I2C lcd(0x27,16,2);  // 設定 LCD 位址為 0x27,有 16 個字元 2 列
RF24 radio(8, 9);  // nRF24L01 連接 CE 及 CSN 的 Arduino 接腳編號
const uint64_t pipe = 0x00FF;

float temperature[2];
 
void setup() 
{
  Serial.begin(9600);
  
  lcd.init();               // 初始化 lcd 
  lcd.backlight();           // 設定背板為亮  
  lcd.clear();      
  
  radio.begin();
  radio.openReadingPipe(1, pipe);
  radio.startListening(); 
 
  lcd.print("Humidity & temp");
  delay(2000);
  lcd.clear();
  lcd.print("Starting.....");
  delay(2000);
}
 
void loop() {
  if (radio.available()) {
     bool done = false;
     radio.read(temperature, sizeof(temperature));

     lcd.clear();
     delay(500);
     lcd.setCursor(0, 0);
     lcd.print("Temp");
     lcd.setCursor(9, 0);
     lcd.print(temperature[0]);
     lcd.print(" C");
     lcd.setCursor(0, 1);
     lcd.print("Humidity");
     lcd.setCursor(9, 1);
     lcd.print(temperature[1]);
     lcd.print(" %");
     delay(1000);
  }
  else
  {
    lcd.setCursor(0, 0);
    lcd.print("No radio Found");
  }
}

[實作結果]

當傳送端沒有訊號時,接收端的LCD會顯示「No radio Found」,如下畫面:
正常傳輸時,每次閃動代表讀取一次資料。

Post a Comment

較新的 較舊