2017年10月23日 星期一

Arduino 433M 超再生無線模組測試

做完 nRF24L01 無線模組測試後, 我在零件箱裡又找出之前向露天賣家 XLAN 買的 433MHz 超再生無線收發模組, 也是一樣來沒測試過能不能用, 參考 :

#  [X-LAN] Arduino RF 433M 超再生模組 發射接收一對 $45
露天 XLAN 電子零件購買清單

剛好上週五向市圖借的 "Arduino 自造指南 (碁峰, 曾繁勛等譯)" 書已拿到, 其中的專案 47 "建構無線遠端控制" 就是使用這種無線射頻連結模組 (SparkFun 零件編號 wrl-10534 的 RF Link 模組). 今天就趁著上班前的空檔測試看看. 以下的測試還參考了下面這本書 :

# Arduino 互動設計專題與實戰 (碁峰, 柯博文)

此模組有分收發不同板子如下所示,  :




這種 RF Link 模組沒有錯誤檢查功能, 無法確認送出的資料是否正確接收. 注意, 接收板中間的兩個針腳是相同的 Data 腳, 接哪一個都可以. 另外, 兩塊板子上都有一個 ANT 天線孔, 可以用單心線繞原子筆捲成一個 2cm 的彈簧天線, 一端焊在 ANT 孔上才能讓傳送距離增加, 參考商品說明 :

 "使用前,發射與接收端都要接上天線,以達到最佳接收效果; 天線可以用單心線捲成螺旋狀,長度約2公分即可。"

沒有天線的話傳遞距離大約只有 40~50 公分而已, 加上天線空曠處可達 40 公尺 (書上說可達 100 公尺), 參考其規格 :

工作電壓(V):DC 5V
傳輸速率:<10KB/S (一般 4KB/S)
發射功率:25mW
工作電流:4mA
調製方式:調幅
工作溫度: -10 ℃ ~ 70 ℃
接收靈敏度(dBm):-105DB
工作頻率(MHz):433.92MHz
實測距離可以達40公尺(視實際環境有無干擾而定)


使用此模組傳遞資料須使用 VirtualWire 函式庫, 可從下列網址下載最新的 1.27 版, 將 ZIP 檔解壓縮後放在 Arduino 安裝目錄的 libraries 子附錄下即可 :

http://www.airspayce.com/mikem/arduino/VirtualWire/VirtualWire-1.27.zip

VirtualWire 函式庫各函式用法說明可參考 :

https://www.pjrc.com/teensy/td_libs_VirtualWire.html


在 "Arduino 自造指南" 專案 47 中, 傳送板與接收板的 Data 腳都接到 Arduino 的 D8 腳, 傳送板 Arduino 的 D2, D3 各接上一個按鈕開關與上拉電阻; 接收板 Arduino 的 D6, D7 各接一組 LED 與 560 歐姆電阻串聯電路以顯示收到的按鈕狀態訊號. 專案 47 的範例程式如下 :

傳送端程式 :

#include <VirtualWire.h>

uint8_t buf[VW_MAX_MESSAGE_LEN];
uint8_t buflen=VW_MAX_MESSAGE_LEN;

const char *on2="a";
const char *off2="b";
const char *on3="c";
const char *off3="d";

void setup() {
  Serial.begin(9600);
  vw_set_ptt_inverted(true);
  vw_setup(300);
  vw_set_tx_pin(8);
  pinMode(2, INPUT);
  pinMode(3, INPUT);
  }

void loop() {
  if (digitalRead(2)==HIGH) {
    vw_send((uint8_t *)on2, strlen(on2));
    vw_wait_tx();
    Serial.println("a");
    delay(200);
    }
  if (digitalRead(2)==LOW) {
    vw_send((uint8_t *)off2, strlen(off2));
    vw_wait_tx();
    Serial.println("b");
    delay(200);
    }
  if (digitalRead(3)==HIGH) {
    vw_send((uint8_t *)on3, strlen(on3));
    vw_wait_tx();
    Serial.println("c");
    delay(200);
    }
  if (digitalRead(3)==LOW) {
    vw_send((uint8_t *)off3, strlen(off3));
    vw_wait_tx();
    Serial.println("d");
    delay(200);
    } 
  }

接收端程式 :

#include <VirtualWire.h> 4 6

uint8_t buf[VW_MAX_MESSAGE_LEN];
uint8_t buflen=VW_MAX_MESSAGE_LEN;

const char *on2="a";
const char *off2="b";
const char *on3="c";
const char *off3="d";

void setup() {
  Serial.begin(9600);
  vw_set_ptt_inverted(true);
  vw_setup(300);
  vw_set_rx_pin(8);
  vw_rx_start();
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  }

void loop() {
  if (vw_get_message(buf, &buflen)) {
    switch(buf[0]) {
      case 'a':
        digitalWrite(6, HIGH);
        Serial.println("a");
      break;
      case 'b':
        digitalWrite(6, LOW);     
        Serial.println("b");
      break;
      case 'c':
        digitalWrite(7, HIGH);
        Serial.println("c");
      break;
      case 'd':
        digitalWrite(7, LOW);
        Serial.println("d");
      break;
      }
    }
  }

但是我沒有使用上面這組程式來進行測試, 因為我覺得它的範例比較複雜, Arduino 的 DIO 腳本身就有內建上拉電阻了, 不需要外加. 我的測試方法很簡單, 就是在接收端用兩個全域變數紀錄 LED 現在的狀態, 當接收到傳送的送來的信號時就將狀態反轉, 這樣方便一個人做距離測試時檢查狀態是否有改變 (增加測試距離時記住原先狀態, 按下按鈕後再跑過去檢查). 我將其改編為如下的測試 1 :


測試 1 : 接收端 LED 顯示傳送端按鈕的 toggle 狀態

傳送板程式 :

#include <VirtualWire.h>

const char *sendA="A";   //按鈕 A 要傳送的資訊
const char *sendB="B";   //按鈕 B 要傳送的資訊
int buttonA=2;
int buttonB=3;
int TXpin=8;   //傳送板 Data 腳接 Arduino D8 腳

void setup() {
  Serial.begin(9600);
  vw_set_ptt_inverted(true);  //設定RF Link 模組 "push to talk" 極性
  vw_setup(300);   //設定速率 300bps
  vw_set_tx_pin(TXpin);   //設定 Data 傳送腳 (D8)
  pinMode(buttonA, INPUT_PULLUP);    //開啟上拉電阻
  pinMode(buttonB, INPUT_PULLUP);    //開啟上拉電阻
  }

void loop() {
  if (digitalRead(buttonA)==LOW) {   //若按鈕 B 被按下
    vw_send((uint8_t *) sendA, strlen(sendA));    //傳送字元 'A' 給接收板
    vw_wait_tx();
    Serial.println("Send 'A'");
    delay(200);
    }
  if (digitalRead(buttonB)==LOW) {    //傳送字元 'B' 給接收板
    vw_send((uint8_t *) sendB, strlen(sendB));
    vw_wait_tx();
    Serial.println("Send 'B'");
    delay(200);
    } 
  }


接收板程式 :


#include <VirtualWire.h> 4 6

uint8_t buf[VW_MAX_MESSAGE_LEN];
uint8_t buflen=VW_MAX_MESSAGE_LEN;

boolean LEDA_ON=false;  //LED 預設熄滅
boolean LEDB_ON=false;  //LED 預設熄滅
int LEDA=6;
int LEDB=7;
int RXpin=8;   //接收板 Data 腳接 Arduino D8 腳

void setup() {
  Serial.begin(9600);
  vw_set_ptt_inverted(true);  //設定RF Link 模組 "push to talk" 極性
  vw_setup(300);  //設定速率 300bps (須與傳送端一致)
  vw_set_rx_pin(RXpin);   //設定接收板接 Arduino 哪一隻腳
  vw_rx_start();  //RF Link 模組開始接收資料
  pinMode(LEDA, OUTPUT);
  pinMode(LEDB, OUTPUT);
  Serial.println("Receiving...");
  }

void loop() {
  if (vw_get_message(buf, &buflen)) {
    if (buf[0]=='A') {
      Serial.println("Receive 'A'");
      LEDA_ON = !LEDA_ON;
      if (LEDA_ON) {digitalWrite(LEDA, HIGH);}  //狀態為 ON 就點亮 LED
      else {digitalWrite(LEDA, LOW);}  //狀態為 OFF 就點亮 LED
      }
    if (buf[0]=='B') {
      Serial.println("Receive 'B'");
      LEDB_ON = !LEDB_ON;
      if (LEDB_ON) {digitalWrite(LEDB, HIGH);}  //狀態為 ON 就點亮 LED
      else {digitalWrite(LEDB, LOW);}  //狀態為 OFF 就點亮 LED
      }
    }
  }




可見按鈕按下時, 對應的遠端 LED 就會交替明滅 (雖然這個遠端只有 50 公分不到).

傳送端序列埠監控視窗輸出訊息如下 :

Send 'A'
Send 'B'
Send 'A'
Send 'B'
Send 'B'
Send 'B'
Send 'A'
Send 'A'

接收端序列埠監控視窗輸出訊息如下 :

Receiving...
Receive 'A'
Receive 'B'
Receive 'A'
Receive 'B'
Receive 'B'
Receive 'B'
Receive 'A'
Receive 'A'

2017-10-24 補充 :

今天用原子筆捲了兩個彈簧天線焊在收發板上測試, 結果距離有比較遠, 從 30~40 公分變成 5~6 公尺, 這 ..... 對我而言簡直沒有任何實用性, 說好的 40 公尺呢? 失望. 我認為不要把時間浪費在這種無用的模組上.

2015-10-25 補充 :

今天在柯博文寫的 "Arduino 互動設計專題與實戰" 的 13.7 節找到此 433MHz RF 收發器的介紹, 提到發射距離 20~200 公尺 ("不同電壓不同距離"), 原來此種模組可工作於 3.5V~12V 電壓, 所以 200 公尺或許是在 12V 下於空曠地方才有這樣的傳送距離. 難怪這種便宜的模組常用在玩具車, 遙控飛機, 鐵捲門, 防盜器, 汽機車遙控車門啟閉等應用裡, 且常用 12V 的乾電池 (小圓筒形或方形).

我將其範例改編為如下測試 2 :

測試 2 : 傳送板持續送出 'Hello' 給接收板

傳送板程式 :

#include <VirtualWire.h>

int TXpin=8;   //傳送板 Data 腳接 Arduino D8 腳

void setup() {
  Serial.begin(9600);
  vw_set_ptt_inverted(true);
  vw_setup(2000);
  vw_set_tx_pin(TXpin);
  }

void loop() {
  const char *msg="Hello";
  digitalWrite(13, HIGH);
  vw_send((uint8_t *)msg, strlen(msg));
  vw_wait_tx();
  digitalWrite(13, LOW);
  delay(200);
  }

接收板程式 : 

#include <VirtualWire.h> 4 6

uint8_t buf[VW_MAX_MESSAGE_LEN];
uint8_t buflen=VW_MAX_MESSAGE_LEN;

int RXpin=8;   //接收板 Data 腳接 Arduino D8 腳

void setup() {
  Serial.begin(9600);
  vw_set_ptt_inverted(true);
  vw_setup(2000);
  vw_set_rx_pin(RXpin);
  vw_rx_start();
  Serial.println("Receiving...");
  }

void loop() {
  if (vw_get_message(buf, &buflen)) {
    int i;
    digitalWrite(13, HIGH);
    Serial.println("Got: ");
    for (int i=0; i<buflen; i++) {
      Serial.print(buf[i], HEX);
      Serial.print(" ");
      }
    Serial.println("");
    digitalWrite(13, LOW);
    }
  }




傳送板的 Arduino 內建  LED 13 閃爍表示它不斷送出 "Hello" 字串, 而接收板若有收到資料的話, Arduino 的板上 LED 13 也會不斷閃爍, 若超出收訊範圍即停止閃爍.

接收板序列埠監控視窗輸出 :

Receiving...
Got:
48 65 6C 6C 6F
Got:
48 65 6C 6C 6F
Got:
48 65 6C 6C 6F
Got:
48 65 6C 6C 6F
.......

收到的這些 16 進位 bytes 值其實就是 "Hello" 的 ASCII 編碼, 參考 :

https://zh.wikipedia.org/wiki/ASCII
http://maniacbug.github.io/RF24/starping_8pde-example.html

2 則留言 :

匿名 提到...

若要長距離 有什麼模組 好入門的??

Tony Huang 提到...

LoRa, 參考 :
http://yhhuang1966.blogspot.tw/2017/10/lora_16.html