02-G5+nodeMCU

(2017/12/31)

比照之前G3+nodeMCU,再來做一次G5+NodeMCU,G5也就是PMS5003ST攀藤測PM2.5的感測器,可以偵測PM2.5、甲醛及溫濕度的值。

一、NodeMCU+G5+LCD顯示器:

  • 接線說明:

    • 一個nodeMCU+擴展板、一個LCD顯示器(SDA接D2、SCL接D1)、一個G5(pin5(Tx)接Rx)

    • LCD要接5V的電,不然電太弱會看不清楚

        • 從下面這資料,好像用大氣環境下的為主

        • 首先,它可以採樣測定的空氣懸浮微粒有三種規格 0.3-1.0um/1.0-2.5um/2.5-10um,也就是說我們可以拿到 PM1.0/PM2.5/PM10 的測定資料(ug/m3)。而且PMS3003 的 datasheet 寫到他有兩套檢定空氣品質濃度的方法,分別是可以獲得「大氣環境下」和「標準顆粒物」兩組資料值,所以程式裡面每一次從 sensor 那邊得到的資料就會有2組,6個測定值。這裡我會在意的是「大氣環境下」測得的這組,所以,以下顯示的是大氣環境下這組的數據。

    • 利用下面程式可以得到PM1.0、PM2.5、PM10分別在CF=1為標準顆粒物、atmosphere為大氣環境下

        • CF=1 根据美国TSI公司的仪器校准

        • 大气环境下 根据中国气象局的数据校准

  • 程式說明:

    • G5程式採上一單元參考一的程式,LCD程式採用TUNIOT的程式,以下紅色字的部分(參考01TUNIOT入門課程)

    • 進入TUNIOT網站:http://easycoding.tn/tuniot/demos/code/

    • #include <Wire.h>

    • #include <LiquidCrystal_I2C.h>

      • LiquidCrystal_I2C lcd(0x27,16,2); //注意是0x27或0x3F

      • static unsigned int pm_cf_10; //定义全局变量

      • static unsigned int pm_cf_25;

      • static unsigned int pm_cf_100;

      • static unsigned int pm_at_10;

      • static unsigned int pm_at_25;

      • static unsigned int pm_at_100;

      • static unsigned int particulate03;

      • static unsigned int particulate05;

      • static unsigned int particulate10;

      • static unsigned int particulate25;

      • static unsigned int particulate50;

      • static unsigned int particulate100;

      • static float HCHO;

      • static float Temperature;

      • static float Humidity;

      • void getG5(unsigned char ucData)//获取G5的值

      • {

      • static unsigned int ucRxBuffer[250];

      • static unsigned int ucRxCnt = 0;

      • ucRxBuffer[ucRxCnt++] = ucData;

      • if (ucRxBuffer[0] != 0x42 && ucRxBuffer[1] != 0x4D)//数据头判断

      • {

      • ucRxCnt = 0;

      • return;

      • }

      • if (ucRxCnt > 38)//数据位判断//G5S为32,G5ST为38

      • {

      • pm_cf_10=(int)ucRxBuffer[4] * 256 + (int)ucRxBuffer[5]; //大气环境下PM2.5浓度计算

      • pm_cf_25=(int)ucRxBuffer[6] * 256 + (int)ucRxBuffer[7];

      • pm_cf_100=(int)ucRxBuffer[8] * 256 + (int)ucRxBuffer[9];

      • pm_at_10=(int)ucRxBuffer[10] * 256 + (int)ucRxBuffer[11];

      • pm_at_25=(int)ucRxBuffer[12] * 256 + (int)ucRxBuffer[13];

      • pm_at_100=(int)ucRxBuffer[14] * 256 + (int)ucRxBuffer[15];

      • particulate03=(int)ucRxBuffer[16] * 256 + (int)ucRxBuffer[17];

      • particulate05=(int)ucRxBuffer[18] * 256 + (int)ucRxBuffer[19];

      • particulate10=(int)ucRxBuffer[20] * 256 + (int)ucRxBuffer[21];

      • particulate25=(int)ucRxBuffer[22] * 256 + (int)ucRxBuffer[23];

      • particulate50=(int)ucRxBuffer[24] * 256 + (int)ucRxBuffer[25];

      • particulate100=(int)ucRxBuffer[26] * 256 + (int)ucRxBuffer[27];

      • HCHO=((int)ucRxBuffer[28] * 256 +(int)ucRxBuffer[29])/1000.000;

      • Temperature = ((int)ucRxBuffer[30] * 256 +(int)ucRxBuffer[31])/10.000;//包含温度

      • Humidity = ((int)ucRxBuffer[32] * 256 +(int)ucRxBuffer[33])/10.000;//包含湿度

      • if (pm_cf_25 > 999)//如果PM2.5数值>1000,返回重新计算

      • {

      • ucRxCnt = 0;

      • return;

      • }

      • ucRxCnt = 0;

      • return;

      • }

      • }

      • void setup() {

      • Serial.begin(9600);

      • lcd.begin();

      • }

      • void loop() {

      • while (Serial.available())

      • {

      • getG5(Serial.read());

      • }

      • Serial.print(" PM_CF1.0:");Serial.print(pm_cf_10);Serial.print(" ug/m3");//硬件串口输出数据

      • Serial.print(" PM_CF2.5:");Serial.print(pm_cf_25);Serial.print(" ug/m3");

      • Serial.print(" PM_CF10 :");Serial.print(pm_cf_100);Serial.println(" ug/m3");

      • Serial.print(" PM_AQI1.0:");Serial.print(pm_at_10);Serial.print(" ug/m3");

      • Serial.print(" PM_AQI2.5:");Serial.print(pm_at_25);Serial.print(" ug/m3");

      • Serial.print(" PM_AQI10:");Serial.print(pm_at_100);Serial.println(" ug/m3");

      • Serial.print(" PM_count03:");Serial.print(particulate03);Serial.print(" pcs/0.01cf");

      • Serial.print(" PM_count05:");Serial.print(particulate05);Serial.print(" pcs/0.01cf");

      • Serial.print(" PM_count10:");Serial.print(particulate10);Serial.print(" pcs/0.01cf");

      • Serial.print(" PM_count25:");Serial.print(particulate25);Serial.print(" pcs/0.01cf");

      • Serial.print(" PM_count100:");Serial.print(particulate100);Serial.println(" pcs/0.01cf");

      • Serial.print(" HCHO:");Serial.print(HCHO,3);Serial.println(" mg/m3");

      • Serial.print(" TS:");Serial.print(Temperature,1);Serial.println(" C"); //包含温度

      • Serial.print(" HS:");Serial.print(Humidity,1);Serial.println(" %RH"); //包含湿度

      • Serial.println("*********************************************");

    • lcd.setCursor(0, 0);

    • lcd.print(String("At")+pm_at_10 + String(",")+pm_at_25 + String(",")+pm_at_100+String("F:")+HCHO );

    • lcd.setCursor(0, 1);

    • lcd.print( String(" T:")+Temperature + String(" H:")+Humidity );

      • delay(2000);

      • }

二、NodeMCU+G5+OLED顯示器:

  • 接線說明:

    • 一個nodeMCU+擴展板、一個OLED顯示器(SDA接D2、SCL接D1)、一個G5(pin5(Tx)接Rx)

    • OLED接3.3V的電,即可

  • 程式說明:

    • G5程式採上一單元參考一的程式,OLED程式採用TUNIOT的程式,以下紅色字的部分(參考01TUNIOT入門課程)

    • 進入TUNIOT網站:http://easycoding.tn/tuniot/demos/code/

    • #include <Wire.h>

    • #include "SSD1306.h"

    • SSD1306 display(0x3C, 4, 5);

      • static unsigned int pm_cf_10; //定义全局变量

      • static unsigned int pm_cf_25;

      • static unsigned int pm_cf_100;

      • static unsigned int pm_at_10;

      • static unsigned int pm_at_25;

      • static unsigned int pm_at_100;

      • static unsigned int particulate03;

      • static unsigned int particulate05;

      • static unsigned int particulate10;

      • static unsigned int particulate25;

      • static unsigned int particulate50;

      • static unsigned int particulate100;

      • static float HCHO;

      • static float Temperature;

      • static float Humidity;

      • void getG5(unsigned char ucData)//获取G5的值

      • {

      • static unsigned int ucRxBuffer[250];

      • static unsigned int ucRxCnt = 0;

      • ucRxBuffer[ucRxCnt++] = ucData;

      • if (ucRxBuffer[0] != 0x42 && ucRxBuffer[1] != 0x4D)//数据头判断

      • {

      • ucRxCnt = 0;

      • return;

      • }

      • if (ucRxCnt > 38)//数据位判断//G5S为32,G5ST为38

      • {

      • pm_cf_10=(int)ucRxBuffer[4] * 256 + (int)ucRxBuffer[5]; //大气环境下PM2.5浓度计算

      • pm_cf_25=(int)ucRxBuffer[6] * 256 + (int)ucRxBuffer[7];

      • pm_cf_100=(int)ucRxBuffer[8] * 256 + (int)ucRxBuffer[9];

      • pm_at_10=(int)ucRxBuffer[10] * 256 + (int)ucRxBuffer[11];

      • pm_at_25=(int)ucRxBuffer[12] * 256 + (int)ucRxBuffer[13];

      • pm_at_100=(int)ucRxBuffer[14] * 256 + (int)ucRxBuffer[15];

      • particulate03=(int)ucRxBuffer[16] * 256 + (int)ucRxBuffer[17];

      • particulate05=(int)ucRxBuffer[18] * 256 + (int)ucRxBuffer[19];

      • particulate10=(int)ucRxBuffer[20] * 256 + (int)ucRxBuffer[21];

      • particulate25=(int)ucRxBuffer[22] * 256 + (int)ucRxBuffer[23];

      • particulate50=(int)ucRxBuffer[24] * 256 + (int)ucRxBuffer[25];

      • particulate100=(int)ucRxBuffer[26] * 256 + (int)ucRxBuffer[27];

      • HCHO=((int)ucRxBuffer[28] * 256 +(int)ucRxBuffer[29])/1000.000;

      • Temperature = ((int)ucRxBuffer[30] * 256 +(int)ucRxBuffer[31])/10.000;//包含温度

      • Humidity = ((int)ucRxBuffer[32] * 256 +(int)ucRxBuffer[33])/10.000;//包含湿度

      • if (pm_cf_25 > 999)//如果PM2.5数值>1000,返回重新计算

      • {

      • ucRxCnt = 0;

      • return;

      • }

      • ucRxCnt = 0;

      • return;

      • }

      • }

      • void setup() {

      • Serial.begin(9600);

    • display.init();

      • }

      • void loop() {

      • while (Serial.available())

      • {

      • getG5(Serial.read());

      • }

      • Serial.print(" PM_CF1.0:");Serial.print(pm_cf_10);Serial.print(" ug/m3");//硬件串口输出数据

      • Serial.print(" PM_CF2.5:");Serial.print(pm_cf_25);Serial.print(" ug/m3");

      • Serial.print(" PM_CF10 :");Serial.print(pm_cf_100);Serial.println(" ug/m3");

      • Serial.print(" PM_AQI1.0:");Serial.print(pm_at_10);Serial.print(" ug/m3");

      • Serial.print(" PM_AQI2.5:");Serial.print(pm_at_25);Serial.print(" ug/m3");

      • Serial.print(" PM_AQI10:");Serial.print(pm_at_100);Serial.println(" ug/m3");

      • Serial.print(" PM_count03:");Serial.print(particulate03);Serial.print(" pcs/0.01cf");

      • Serial.print(" PM_count05:");Serial.print(particulate05);Serial.print(" pcs/0.01cf");

      • Serial.print(" PM_count10:");Serial.print(particulate10);Serial.print(" pcs/0.01cf");

      • Serial.print(" PM_count25:");Serial.print(particulate25);Serial.print(" pcs/0.01cf");

      • Serial.print(" PM_count100:");Serial.print(particulate100);Serial.println(" pcs/0.01cf");

      • Serial.print(" HCHO:");Serial.print(HCHO,3);Serial.println(" mg/m3");

      • Serial.print(" TS:");Serial.print(Temperature,1);Serial.println(" C"); //包含温度

      • Serial.print(" HS:");Serial.print(Humidity,1);Serial.println(" %RH"); //包含湿度

      • Serial.println("*********************************************");

    • display.clear();

    • display.setTextAlignment(TEXT_ALIGN_LEFT);

    • display.setFont(ArialMT_Plain_16);

    • display.drawString(0, 0, String("At")+pm_at_10 + String(",")+pm_at_25 + String(",")+pm_at_100);

    • display.display();

    • display.setTextAlignment(TEXT_ALIGN_LEFT);

    • display.setFont(ArialMT_Plain_16);

    • display.drawString(0, 16, String("F:")+HCHO);

    • display.display();

    • display.setTextAlignment(TEXT_ALIGN_LEFT);

    • display.setFont(ArialMT_Plain_16);

    • display.drawString(0, 32, String(" T:")+Temperature + String(" H:")+Humidity);

    • display.display();

      • delay(2000);

      • }

  • 經過一夜房間的數據與小米清淨機的比較,但不知兩者間有沒有關係?

三.加入上網功能,並將PM2.5相關數據上傳到thingspeak

    • 轉為Arduino語言,並修改程式內容

        • #include <Wire.h>

        • #include "SSD1306.h"

        • SSD1306 display(0x3C, 4, 5);

        • #include <ESP8266WiFi.h>

        • #include <ESP8266HTTPClient.h>

        • WiFiClient client;

        • String thingSpeakAddress= "http://api.thingspeak.com/update?";

        • String writeAPIKey;

        • String tsfield1Name;

        • String request_string;

        • HTTPClient http;

          • static unsigned int pm_cf_10; //定义全局变量

          • static unsigned int pm_cf_25;

          • static unsigned int pm_cf_100;

          • static unsigned int pm_at_10;

          • static unsigned int pm_at_25;

          • static unsigned int pm_at_100;

          • static unsigned int particulate03;

          • static unsigned int particulate05;

          • static unsigned int particulate10;

          • static unsigned int particulate25;

          • static unsigned int particulate50;

          • static unsigned int particulate100;

          • static float HCHO;

          • static float Temperature;

          • static float Humidity;

          • void getG5(unsigned char ucData)//获取G5的值

          • {

          • static unsigned int ucRxBuffer[250];

          • static unsigned int ucRxCnt = 0;

          • ucRxBuffer[ucRxCnt++] = ucData;

          • if (ucRxBuffer[0] != 0x42 && ucRxBuffer[1] != 0x4D)//数据头判断

          • {

          • ucRxCnt = 0;

          • return;

          • }

          • if (ucRxCnt > 38)//数据位判断//G5S为32,G5ST为38

          • {

          • pm_cf_10=(int)ucRxBuffer[4] * 256 + (int)ucRxBuffer[5]; //大气环境下PM2.5浓度计算

          • pm_cf_25=(int)ucRxBuffer[6] * 256 + (int)ucRxBuffer[7];

          • pm_cf_100=(int)ucRxBuffer[8] * 256 + (int)ucRxBuffer[9];

          • pm_at_10=(int)ucRxBuffer[10] * 256 + (int)ucRxBuffer[11];

          • pm_at_25=(int)ucRxBuffer[12] * 256 + (int)ucRxBuffer[13];

          • pm_at_100=(int)ucRxBuffer[14] * 256 + (int)ucRxBuffer[15];

          • particulate03=(int)ucRxBuffer[16] * 256 + (int)ucRxBuffer[17];

          • particulate05=(int)ucRxBuffer[18] * 256 + (int)ucRxBuffer[19];

          • particulate10=(int)ucRxBuffer[20] * 256 + (int)ucRxBuffer[21];

          • particulate25=(int)ucRxBuffer[22] * 256 + (int)ucRxBuffer[23];

          • particulate50=(int)ucRxBuffer[24] * 256 + (int)ucRxBuffer[25];

          • particulate100=(int)ucRxBuffer[26] * 256 + (int)ucRxBuffer[27];

          • HCHO=((int)ucRxBuffer[28] * 256 +(int)ucRxBuffer[29])/1000.000;

          • Temperature = ((int)ucRxBuffer[30] * 256 +(int)ucRxBuffer[31])/10.000;//包含温度

          • Humidity = ((int)ucRxBuffer[32] * 256 +(int)ucRxBuffer[33])/10.000;//包含湿度

          • if (pm_cf_25 > 999)//如果PM2.5数值>1000,返回重新计算

          • {

          • ucRxCnt = 0;

          • return;

          • }

          • ucRxCnt = 0;

          • return;

          • }

          • }

          • void setup() {

        • Serial.begin(9600);

        • display.init();

        • WiFi.disconnect();

        • delay(3000);

        • display.setTextAlignment(TEXT_ALIGN_LEFT);

        • display.setFont(ArialMT_Plain_16);

        • display.drawString(0, 0, "START ... Connecting");

        • display.display();

        • WiFi.begin("Xiaomi_6F5A","12345678");

        • delay(10000);

        • if (!(WiFi.status() == WL_CONNECTED)) {

        • display.setTextAlignment(TEXT_ALIGN_LEFT);

        • display.setFont(ArialMT_Plain_24);

        • display.drawString(0, 30, "Can\'t connect to wifi ...");

        • display.display();

        • } else {

        • display.setTextAlignment(TEXT_ALIGN_LEFT);

        • display.setFont(ArialMT_Plain_16);

        • display.drawString(0, 16, "I am connected! My IP address is");

        • display.display();

        • display.setTextAlignment(TEXT_ALIGN_LEFT);

        • display.setFont(ArialMT_Plain_16);

        • // display.drawString(0, 32, (WiFi.localIP()));

        • display.display();

        • }

        • delay(3000);

          • }

          • void loop() {

          • while (Serial.available())

          • {

          • getG5(Serial.read());

          • }

          • Serial.print(" PM_CF1.0:");Serial.print(pm_cf_10);Serial.print(" ug/m3");//硬件串口输出数据

          • Serial.print(" PM_CF2.5:");Serial.print(pm_cf_25);Serial.print(" ug/m3");

          • Serial.print(" PM_CF10 :");Serial.print(pm_cf_100);Serial.println(" ug/m3");

          • Serial.print(" PM_AQI1.0:");Serial.print(pm_at_10);Serial.print(" ug/m3");

          • Serial.print(" PM_AQI2.5:");Serial.print(pm_at_25);Serial.print(" ug/m3");

          • Serial.print(" PM_AQI10:");Serial.print(pm_at_100);Serial.println(" ug/m3");

          • Serial.print(" PM_count03:");Serial.print(particulate03);Serial.print(" pcs/0.01cf");

          • Serial.print(" PM_count05:");Serial.print(particulate05);Serial.print(" pcs/0.01cf");

          • Serial.print(" PM_count10:");Serial.print(particulate10);Serial.print(" pcs/0.01cf");

          • Serial.print(" PM_count25:");Serial.print(particulate25);Serial.print(" pcs/0.01cf");

          • Serial.print(" PM_count100:");Serial.print(particulate100);Serial.println(" pcs/0.01cf");

          • Serial.print(" HCHO:");Serial.print(HCHO,3);Serial.println(" mg/m3");

          • Serial.print(" TS:");Serial.print(Temperature,1);Serial.println(" C"); //包含温度

          • Serial.print(" HS:");Serial.print(Humidity,1);Serial.println(" %RH"); //包含湿度

          • Serial.println("*********************************************");

          • display.clear();

          • display.setTextAlignment(TEXT_ALIGN_LEFT);

          • display.setFont(ArialMT_Plain_16);

          • display.drawString(0, 0, String("At")+pm_at_10 + String(",")+pm_at_25 + String(",")+pm_at_100);

          • display.display();

          • display.setTextAlignment(TEXT_ALIGN_LEFT);

          • display.setFont(ArialMT_Plain_16);

          • display.drawString(0, 16, String("F:")+HCHO);

          • display.display();

          • display.setTextAlignment(TEXT_ALIGN_LEFT);

          • display.setFont(ArialMT_Plain_16);

          • display.drawString(0, 32, String(" T:")+Temperature + String(" H:")+Humidity);

          • display.display();

        • if (client.connect("api.thingspeak.com",80)) {

        • writeAPIKey = "key=DBHMUBZGACL1P8U8";

        • // tsfield1Name = "&field1=10";

        • request_string = thingSpeakAddress;

        • // request_string += "key=";

        • request_string += writeAPIKey;

        • request_string += "&";

        • request_string += "field1";

        • request_string += "=";

        • request_string += pm_at_10;

        • request_string += "&";

        • request_string += "field2";

        • request_string += "=";

        • request_string += pm_at_25;

        • request_string += "&";

        • request_string += "field3";

        • request_string += "=";

        • request_string += pm_at_100;

        • request_string += "&";

        • request_string += "field4";

        • request_string += "=";

        • request_string += HCHO;

        • request_string += "&";

        • request_string += "field5";

        • request_string += "=";

        • request_string += Temperature;

        • request_string += "&";

        • request_string += "field6";

        • request_string += "=";

        • request_string += Humidity;

        • http.begin(request_string);

        • http.GET();

        • http.end();

          • delay(5000);

          • }

          • }

  • 呈現結果:

四.加入量測CO2的值

  • 接線說明:

    • 一個nodeMCU+擴展板、一個OLED顯示器(SDA接D2、SCL接D1)、一個G5(pin5(Tx)接Rx)、一個MH-Z19 CO2檢測傳感器

    • OLED接3.3V的電,即可

    • MH-Z19 (測CO2):參考先前的文章,採用PWM的方式(ppm3)來讀取資料,因為pwm3的值與UART的值相近,將MH-Z19的PWM接Arduino的D6(可自選),另外Vin接VCC、GND接GND

  • 之前所完成的設備暫不拆除(含MH-Z19) ,再將這次的設備(G5)與上次的設備(G3)兩者所量測出的PM2.5值做一比較。