rflink-uart 與感測器的實作ˆ‡感測器的實...首先,我們以攀藤pm2.5...
TRANSCRIPT
1
RFLink-UART 與感測器的實作
目錄
RFLink-UART 與感測器的實作 ........................................................................................................................... 1
攀藤 PM2.5 感測器介紹 ....................................................................................................................................... 2
傳統使用方式 ......................................................................................................................................................... 3
透過 RFLink-UART 使用方式 .............................................................................................................................. 3
一對一的實作 ......................................................................................................................................................... 4
一對多的使用方式 ................................................................................................................................................ 7
Device 端設定各自的編號 .......................................................................................................................... 7
Root 端的接法 ............................................................................................................................................... 8
Root 端指定 Deivce 編號的程式範例 ....................................................................................................... 8
IO port 的使用 ...................................................................................................................................................... 11
一對多的 UART 與 IO port 實作 ....................................................................................................................... 12
2
RFLink UART 模組使用 2.4G 開放 ISM 頻段進行穩定的連線與傳輸,因此一般支援 UART/TTL
的感測模組或開發板皆可透過本 RFLink UART 模組直接升級無線功能。下方,我們將詳細介紹如
何 RFLink-UART。
攀藤 PM2.5 感測器介紹
首先,我們以攀藤 PM2.5 感測器為例,實作如何將其升級為無線 PM2.5 感測器。
目前市面上偵測 PM2.5 的消費級模組主要有兩大類,一種以雷射為光源,另一種以 LED 為
光源,它們分別藉由檢測經過空氣中灰塵折射過後的光線來判斷灰塵的顆粒量及大小。雷射的較
為精準但也較貴。
雷射光源檢測 PM2.5 的工作原理如下:當顆粒物經過雷射照射到的檢測位置時,會產生微弱
的光散射,而特定方向上的光散射波形與其顆粒直徑有關,因此我們將這些不同粒徑的波形進行
分類統計及換算,便可以得到不同粒徑在當時的顆粒物數量濃度及質量濃度。
目前市面上號稱最物美價廉且廣為 Maker 們所喜愛的 PM2.5 感測器,無非就是中國攀藤科
技(Plantower)所出品的 PMS 系列 PM2.5 感測器,採用雷射光源進行感測且號稱能檢測到更細
微的 PM1.0。此外 PMS 系列的 PM2.5 感測器也是台灣 LASS 環境感測網路系統(一個由網友發起
的開源公益專案)所指定使用的 PM2.5 感測模組,可見其準確性相當不錯。
3
傳統使用方式
攀藤 PM2.5 感測器為 UART 介面,baud rate 為 9,600,一般我們會透過開發板的 RX/TX 腳位
與其對接以便讀取 PM2.5 資訊或送出控制訊號。
透過 RFLink-UART 使用方式
PM2.5 模組端與開發板之間都是一樣的接線方法,但是連接的對象是 RFLink-UART 模組,如此一
來,你的攀藤 PM2.5 感測器瞬間便升級為無線的 PM2.5 感測器了。
4
一對一的實作
PM2.5 模組那端只要接上 RF-Link device 端即可。請注意,其連接方式如下, 1 對 1 的傳輸(即
Root 與 Device 各一張)ID0/ID1 保持空接即可。
Arduino 程式碼
請先下載 PM2.5 Arduino Library,下載位置:
https://github.com/Arduinolibrary/DFRobot_PM2.5_Sensor_module/blob/master/serialReadPMVal
ue.rar?raw=true
下載解壓後放置於 Arduino 安裝路徑的 libraries 資料夾。
在接收端,我們使用一片 Arduino MEGA2560 開發板並撰寫 Arduino 程式如下,使用的 RX/TX 腳
位為 3,請注意,無論有否使用 RFLink-UART 模組,這程式完全通用,可見 RFLink-UART 能夠無
痛的將您的有線 UART 模組升級無線功能哦。
5
您也可以採用其它版本的 Arduino,例如 UNO 或 Mini Pro、Nano…等,硬體的 RX/TX 腳位也
可以改為 Software Serial 的方式。
#include "serialReadPMValue.h"
long pmat10 = 0;
long pmat25 = 0;
long pmat100 = 0;
unsigned int temperature = 0;
unsigned int humandity = 0;
void retrievepm25(){
int count = 0;
unsigned char c;
unsigned char high;
while (Serial3.available()) {
c = Serial3.read();
if((count==0 && c!=0x42) || (count==1 && c!=0x4d)){
Serial.println("check failed");
break;
}
if(count > 27){
Serial.println("complete");
break;
}
else if(count == 10 || count == 12 || count == 14 || count == 24 || count == 26) {
6
high = c;
}
else if(count == 11){
pmat10 = 256*high + c;
Serial.print("PM1.0="); Serial.print(pmat10); Serial.println(" ug/m3");
}
else if(count == 13){
pmat25 = 256*high + c;
Serial.print("PM2.5="); Serial.print(pmat25); Serial.println(" ug/m3");
}
else if(count == 15){
pmat100 = 256*high + c;
Serial.print("PM10="); Serial.print(pmat100); Serial.println(" ug/m3");
}
else if(count == 25){
temperature = (256*high + c)/10;
Serial.print("Temp="); Serial.print(temperature); Serial.println(" (C)");
}
else if(count == 27){
humandity = (256*high + c)/10;
Serial.print("Humidity="); Serial.print(humandity); Serial.println(" (%)");
}
count++;
}
while(Serial3.available()) Serial3.read();
Serial.println();
}
void setup() {
Serial.begin(9600);
Serial3.begin(9600);
}
void loop() {
retrievepm25();
Serial.print("PM1.0: " + String(pmat10) + "ug");
Serial.print("PM2.5: " + String(pmat25) + "ug");
Serial.print("PM100: " + String(pmat100) + "ug");
delay(1500);
}
7
燒錄到 Arduino,便可在序列埠監控視窗看到執行結果。
一對多的使用方式
RFLink-UART 最多可接到四個 device,因此您可以同時讀取四組不同的 UART 模組的資料,而且
一對多使用方法並不會比一對一來得複雜,您只要先設定好每片 device 的編號後,在 Root 端便
可透過設定 IO0, IO1 這兩個腳位與指定的 device 連接並開始相互傳輸資訊了。
Device 端設定各自的編號
首先,我們需要設定四個(或其它數目)device 的編號。剛買來的 device 每片都是預設編號
#1,我們可以手動將其變更為其它編號(最多到#4)。
*請注意,所謂的 LOW 即是輸入 GND,HIGH 則是輸入大於 3.3V 的電壓。
8
Root 端的接法
Root 端的 ID0, ID 腳位與 Device 端的編號是對應的,換句話說,Root 端會與其 ID0, ID1 相同狀態
的 Device 相連接,例如,當您透過 Arduino 將 Root 端的 ID0, ID1 分別設為 LOW 與 HIGH,那麼
Root 就會與 Device #3 連接,因為 Device 3 的 ID0, ID1 是 LOW(GND)與 HIGH (空接),可參考上圖的
Device 編號設定。
Root 端指定 Deivce 編號的程式範例
請先將您的 RFLink-UART 模組 Root 端的 ID0 與 ID1 分別接到 Arduino 的 D2 與 D3 腳位,接
著燒錄下方的程式到 Arduino。該程式每隔五秒鏡會分別讀取一次 Device #1 與 Device #2 的 PM2.5
數值。
9
此程式與上方的一對一程式類似,差異只在於紅色字體部份,您可以從差異的部份瞭解如何
去指定並連接不同的 device。
#include "serialReadPMValue.h"
byte pinID0 = 2; byte pinID1 = 3; long pmat10 = 0;
long pmat25 = 0;
long pmat100 = 0;
unsigned int temperature = 0;
unsigned int humandity = 0;
void retrievepm25(){
int count = 0;
unsigned char c;
unsigned char high;
while (Serial3.available()) {
c = Serial3.read();
if((count==0 && c!=0x42) || (count==1 && c!=0x4d)){
Serial.println("check failed");
break;
}
if(count > 27){
Serial.println("complete");
break;
}
else if(count == 10 || count == 12 || count == 14 || count == 24 || count == 26) {
high = c;
}
else if(count == 11){
pmat10 = 256*high + c;
Serial.print("PM1.0=");
Serial.print(pmat10);
Serial.println(" ug/m3");
}
else if(count == 13){
pmat25 = 256*high + c;
Serial.print("PM2.5=");
Serial.print(pmat25);
Serial.println(" ug/m3");
}
else if(count == 15){
10
pmat100 = 256*high + c;
Serial.print("PM10=");
Serial.print(pmat100);
Serial.println(" ug/m3");
}
else if(count == 25){
temperature = (256*high + c)/10;
Serial.print("Temp=");
Serial.print(temperature);
Serial.println(" (C)");
}
else if(count == 27){
humandity = (256*high + c)/10;
Serial.print("Humidity=");
Serial.print(humandity);
Serial.println(" (%)");
}
count++;
}
while(Serial3.available()) Serial3.read();
Serial.println();
}
void setup() {
//Arduino 啟始後預設要連的 Device 編號。例如下方為連到第四個:ID0=HIGH, ID1=HIGH
digitalWrite(pinID0, HIGH);
digitalWrite(pinID1, HIGH);
//Arduino 連接 RFLink 模組 ID0, ID1 的腳位需設定為 OUTPUT
pinMode(pinID0, OUTPUT);
pinMode(pinID1, OUTPUT);
Serial.begin(9600);
Serial3.begin(9600);
}
int i = 0;
void loop() {
if(i % 2 == 0) {
Serial.println("Switch to #1");
digitalWrite(pinID0, HIGH);
digitalWrite(pinID1, HIGH);
}else{
Serial.println("Switch to #2");
digitalWrite(pinID0, HIGH);
11
digitalWrite(pinID1, LOW);
}
//等待 10ms,讓系統 ready 後開始傳輸
delay(10);
retrievepm25();
Serial.print("PM1.0: " + String(pmat10) + "ug");
Serial.print("PM2.5: " + String(pmat25) + "ug");
Serial.println("PM100: " + String(pmat100) + "ug");
delay(5000);
}
IO port 的使用
除了無線傳輸 UART 的資料,RFLink-UART 模組還提供一組無線按鈕功能,方便您快速的傳送
On/Off 訊號到 device 端,使用方式也很簡單,您在模組一端的 In 腳位是 HIGH 或 LOW,另一端
模組的 OUT 腳位便會是相同的 HIGH 或 LOW。(IN 腳位預設空接為 HIGH)
一對多的使用方式也是相同的!當您透過 ID0, ID1 在 Root 端切換到不同的 Device 之後,透
過 Root 的 OUT 腳位即可讀取目前連接 device 的 IN 腳位狀態,若在 Root 端送出 LOW 訊號到 IN
腳位,那麼該連接中的 device 也會收到相同的訊號。
12
一對多的 UART 與 IO port 實作
接下來,我們使用 PM2.5 感測器以及數種可輸出類比(Analog)與數位(Digital)訊號的感測模組
來建構一個無線的感測系統。目前很多環境感測器有同時支援數位與類比輸出,代表您不需要去
讀取類比輸出的數值,只要直接調整模組上的旋鈕,當感測值超過旋鈕設定時,模組便會直接從
數位 pin 腳輸出 HIGH 或 LOW 的訊號。
因此,我們可將感測模組的數位 pin 腳,直接接到 RFLink-UART 模組的 IN,那麼,當感測
器偵測到數值超過設定值時,所發出的 HIGH/LOW 訊號便可從 Device 無線傳送到 Root 端的 OUT
腳位,原本必須接在 Arduino 才能使用的模組,搖身一變成為無線感測模組,是不是很神奇呢?
請參考下圖進行接線,如果您更改了 Arduino 與 Root device 的連接腳位,記得要更改程式
中相對應的 pin腳數字。此程式會循序的讀取有害氣體(IO Port)、pm2.5(RX/TX)、雨水偵測(IO
Port)、PIR(IO Port)等四個模組的偵測值,並顯示於監控視窗。
程式範例:
#include "serialReadPMValue.h"
byte pinIO_IN = 4;
13
byte pinIO_OUT = 5;
byte pinID0 = 2;
byte pinID1 = 3;
byte pinLat = 9;
//PM2.5
long pmat10 = 0;
long pmat25 = 0;
long pmat100 = 0;
unsigned int temperature = 0;
unsigned int humandity = 0;
void retrievepm25(){
int count = 0;
unsigned char c;
unsigned char high;
while (Serial3.available()) {
c = Serial3.read();
if((count==0 && c!=0x42) || (count==1 && c!=0x4d)){
Serial.println("check failed");
break;
}
if(count > 27){
Serial.println("complete");
break;
}
else if(count == 10 || count == 12 || count == 14 || count == 24 || count == 26) {
high = c;
}
else if(count == 11){
pmat10 = 256*high + c;
Serial.print("PM1.0=");
Serial.print(pmat10);
Serial.println(" ug/m3");
}
else if(count == 13){
pmat25 = 256*high + c;
Serial.print("PM2.5=");
Serial.print(pmat25);
Serial.println(" ug/m3");
}
else if(count == 15){
pmat100 = 256*high + c;
14
Serial.print("PM10=");
Serial.print(pmat100);
Serial.println(" ug/m3");
}
else if(count == 25){
temperature = (256*high + c)/10;
Serial.print("Temp=");
Serial.print(temperature);
Serial.println(" (C)");
}
else if(count == 27){
humandity = (256*high + c)/10;
Serial.print("Humidity=");
Serial.print(humandity);
Serial.println(" (%)");
}
count++;
}
while(Serial3.available()) Serial3.read();
Serial.println();
}
void pm25Check() {
for (int count=0; count <= 10; count++){
retrievepm25();
//display.clearDisplay();
Serial.print("PM1.0: " + String(pmat10) + "ug");
Serial.print("PM2.5: " + String(pmat25) + "ug");
Serial.print("PM100: " + String(pmat100) + "ug");
delay(1000);
}
}
void rainningCheck() {
for (int count=0; count <= 10; count++){
byte device2 = digitalRead(pinIO_OUT);
Serial.print("Rainning: ");
Serial.println(device2);
delay(1000);
}
}
void pirCheck() {
15
for (int count=0; count <= 10; count++){
byte device2 = digitalRead(pinIO_OUT);
Serial.print("PIR: ");
Serial.println(device2);
delay(2000);
}
}
void gasCheck() {
for (int count=0; count <= 10; count++){
byte device2 = digitalRead(pinIO_OUT);
Serial.print("GAS: ");
Serial.println(device2);
delay(2000);
}
}
void setup() {
pinMode(pinIO_OUT, INPUT);
digitalWrite(pinIO_IN, LOW);
digitalWrite(pinID0, HIGH);
digitalWrite(pinID1, HIGH);
pinMode(pinIO_IN, OUTPUT);
pinMode(pinID0, OUTPUT);
pinMode(pinID1, OUTPUT);
Serial.begin(9600);
Serial3.begin(9600);
}
int i = 0;
void loop() {
if(i % 4 == 0) {
digitalWrite(pinID0, HIGH);
digitalWrite(pinID1, LOW);
Serial.println("");
Serial.println("Switch to #2");
delay(10);
pm25Check();
16
}else if(i % 4 == 1) {
digitalWrite(pinID0, LOW);
digitalWrite(pinID1, HIGH);
Serial.println("");
Serial.println("Switch to #3");
delay(10);
rainningCheck();
}else if(i % 4 == 2) {
digitalWrite(pinID0, LOW);
digitalWrite(pinID1, LOW);
Serial.println("");
Serial.println("Switch to #4");
delay(10);
pirCheck();
}else if(i % 4 == 3) {
digitalWrite(pinID0, HIGH);
digitalWrite(pinID1, HIGH);
Serial.println("");
Serial.println("Switch to #1");
delay(10);
gasCheck();
}
i++;
delay(500);
}