โปรเจคเครื่องมือตรวจวัด PM2.5 ด้วย ESPino32 และ PMS5003ST

โปรเจคเครื่องมือตรวจวัด PM2.5 ด้วย ESPino32 และ PMS5003ST

        ปัจจุบันประเทศไทยประสบกับปัญหามลพิษทางอากาศเกี่ยวกับเรื่องของฝุ่นละออง หรือที่เรารู้จักกันคือ ฝุ่นละอองที่มีขนาดเล็ก PM2.5 (ฝุ่นขนาดเล็กที่มีเส้นผ่านศูนย์กลางไม่เกิน 2.5 ไมครอน) ซึ่งส่งผลกระทบโดยตรงต่อสุขภาพเป็นอย่างมาก และยังนำไปสู่ปัญหาที่เกี่ยวข้องกับระบบทางเดินหายใจ โรคปอด หลอดเลือด เเละอื่นๆอีกมากมาย ซึ่งทางองค์การอนามัยโลกกำหนดมาตรฐานค่าเฉลี่ย 24 ชั่วโมงของฝุ่น PM 2.5 ไว้ที่ไม่เกิน 25 ไมโครกรัมต่อลูกบาศก์เมตร (ส่วนของประเทศไทย ปี พ.ศ. 2553 คณะกรรมการสิ่งแวดล้อมแห่งชาติ ออกประกาศฉบับที่ 23 กำหนดมาตรฐานค่าเฉลี่ย 24 ชั่วโมงของฝุ่น PM 2.5 ไว้ที่ไม่เกิน 50 ไมโครกรัมต่อลูกบาศก์เมตร) จะดีกว่าไหม หากเรารู้ว่าบริเวณไหนบ้างที่มีค่าฝุ่น PM2.5 เกินค่ามาตรฐาน และสามารถป้องกันตัวเองอย่างทันท่วงที เช่น การสวมหน้ากากสำหรับป้องกันฝุ่น PM 2.5 หรือหากเป็นภายในบ้านให้เปิดเครื่องกรอกอากาศที่มีฟิลเตอร์สำหรับกรอกฝุ่น PM2.5 โดยในบทความนี้จะแสดงให้เห็นการประยุกต์ใช้งาน ESPino32 ร่วมกับเซ็นเซอร์ PMS5003ST ซึ่งสามารถตรวจวัดค่าฝุ่นขนาด PM1.0  PM2.5 PM10 ค่าอุณหภูมิ ค่าความชื้น และฟอร์มัลดีไฮด์ได้ จากนั้นนำค่ามาแสดงบนจอ OLED ขนาด 128×64 

อุปกรณ์ที่ใช้ในบทความนี้ประกอบด้วย

        1 . ESPino32 Wifi BLE Development Board (ETEE061S) จำนวน 1 pcs เป็นไมโครคอนโทรลเลอร์ที่ใช้สำหรับอ่านค่าจากเซ็นเซอร์

        2 . PMS5003ST Dust Formaldehyde, Temperature and Humidity Sensor (ESEN298) จำนวน 1 pcs เป็นเซ็นเซอร์ตรวจวัดฝุ่นที่สามารถวัดค่า PM1.0 PM2.5 และ PM10 โดยเซ็นเซอร์วัดค่าอนุภาคของฝุ่นที่มีขนาดเล็กถึง 0.3 ไมโครเมตร อีกทั้งยังสามารถวัดค่าฟอร์มาลดีไฮด์ อุณหภูมิและความชื้น

        3 . จอ 128×64 OLED Display (EDPM046) จำนวน 1 pcs จอแสดงผลแบบ OLED (Organic Light-Emitting Diode) หรือ ไดโอดเปล่งแสงอินทรีย์ ซึ่งถูกนำเอาใช้แทนจอ LCD ในรูปแบบเดิม โมดูลนี้ออกมาให้ใช้งานร่วมกับ Microcontroller โดยเชื่อมต่อผ่าน I2C เพื่อแสดงค่าจากตัวเซ็นเซอร์

        ในบทความนี้ เราจะเริ่มต้นด้วยการใช้ ESPino32 อ่านค่าจากเซ็นเซอร์ PMS5003ST จากนั้นจะนำค่ามาแสดงขึ้นบนจอ จอ 128×64 OLED Display

การใช้งาน ESPino32 ร่วมกับ PMS5003ST และอ่านค่า PM2.5 ค่าอุณหภูมิ ค่าความชื้น และฟอร์มัลดีไฮด์ แสดงผลบน Serial Monitor

โดยสามารถดูวิธีการติดตั้งบอร์ด ESPino32 ลงบน Arduino IDE ได้ตามบทความนี้

        – การติดตั้งชุดพัฒนา ESPino32 บนแพลตฟอร์ม Arduino

        – การต่อวงจรระหว่าง ESPino32 และ PMS5003ST โดยในบทความนี้ เราจะใช้งาน Serial2 สำหรับอ่านค่าจากเซ็นเซอร์ 

         – ขา Pin ของ PMS5003ST

         – ทำการอัพโหลดโปรแกรมสำหรับอ่านค่าเซ็นเซอร์และแสดงบน Serial Monitor โดยเลือกบอร์ดเป็น ThaiEasyElec’s ESPino32 

char col;
unsigned int PMSa = 0, FMHDSa = 0, TPSa = 0, HDSa = 0, PMSb = 0, FMHDSb = 0, TPSb = 0, HDSb = 0;
unsigned int PMS = 0, FMHDS = 0, TPS = 0, HDS = 0, CR1 = 0, CR2 = 0;
unsigned char buffer_RTT[40] = {}; //Serial buffer; Received Data
char DataStr[15];
String temp, Humi;

void Read_PMS_DATA() {
  while (!Serial2.available());
  while (Serial2.available() > 0) //Data check: weather there is any Data in Serial2
  {
    for (int i = 0; i < 40; i++)
    {
      col = Serial2.read();
      buffer_RTT[i] = (char)col;
      delay(2);
    }
    Serial2.flush();
    
    CR1 = (buffer_RTT[38] << 8) + buffer_RTT[39];
    CR2 = 0;
    for (int i = 0; i < 38; i++)
      CR2 += buffer_RTT[i];
    if (CR1 == CR2)               //Check
    {
      PMSa = buffer_RTT[12];       //Read PM2.5 High 8-bit
      PMSb = buffer_RTT[13];       //Read PM2.5 Low 8-bit
      PMS = (PMSa << 8) + PMSb;    //PM2.5 value
      FMHDSa = buffer_RTT[28];       //Read Formaldehyde High 8-bit
      FMHDSb = buffer_RTT[29];       //Read Formaldehyde Low 8-bit
      FMHDS = (FMHDSa << 8) + FMHDSb; //Formaldehyde value
      TPSa = buffer_RTT[30];        //Read Temperature High 8-bit
      TPSb = buffer_RTT[31];        //Read Temperature Low 8-bit
      TPS = (TPSa << 8) + TPSb;  //Temperature value
      HDSa = buffer_RTT[32];        //Read Humidity High 8-bit
      HDSb = buffer_RTT[33];        //Read Humidity Low 8-bit
      HDS = (HDSa << 8) + HDSb; //Humidity value
    }/*
    else
    {
      PMS = 0;
      FMHDS = 0;
      TPS = 0;
      HDS = 0;
    }*/
    sprintf(DataStr, "%d%d.%d", TPS / 100, (TPS / 10) % 10, TPS % 10);
    temp = DataStr;
    sprintf(DataStr, "%d%d.%d", HDS / 100, (HDS / 10) % 10, HDS % 10);
    Humi = DataStr;
  }
}

void PRINT_PMS_DATA() {
  Serial.println("-----------------------PMS5003ST--------------------------");
  Serial.print("Temp : ");
  Serial.print(temp);
  Serial.println("C");               //Serial pring Temperature
  Serial.print("RH   : ");
  Serial.print(Humi);            //Serial print humidity
  Serial.println(" %");               //"%"
  Serial.print("HCHO : ");
  Serial.print(FMHDS);
  Serial.println(" ug/m3");        // Serial print formaldehyde, unit: ug/m³
  Serial.print("PM2.5: ");
  Serial.print(PMS);
  Serial.println(" ug/m3");       // Serial print PM2.5, unit: ug/m³
  Serial.println();
}

void setup()
{
  Serial.begin(115200);
  Serial2.begin(9600);
}


void loop()
{
  Read_PMS_DATA();
  PRINT_PMS_DATA();
}

        – ผลลัพธ์ทาง Serial monitor ที่ baudrate (115200)

การใช้งาน ESPino32 ร่วมกับ จอ 128×64 OLED Display และทดสอบการแสดงผล

        – ทำการติดตั้ง Library สำหรับใช้งาน จอ 128×64 OLED Display ลงบน Arduino IDE โดยเข้าไปที่เมนู Sketch > Include Library > Manager Libraries… จากนั้นทำการค้นหาเช่น ESP32 OLED โดยในบทความนี้จะใช้ Library ของ ThingPulse

        – จากนั้นทำการต่อวงจรระหว่าง ESPino32 ร่วมกับ จอ 128×64 OLED Display โดยตัวบอร์ด ESPino32 ออกแบบมาให้สามารถต่อใช้งานกับ 128×64 OLED Display โดยสามารถเสียบลงบนขา I2C ได้เลย

        – สามารถเสียบจอลงบนขา I2C ของบอร์ด ESPino32 ได้เลย ดังรูป

        – ทำการอัพโหลดโปรแกรมตัวอย่างเพื่อทดสอบการทำงานของ ESPino32 กับ จอ 128×64 OLED Display

        – มีผลลัพธ์ดังรูป

เมื่อสามารถใช้งานบอร์ด ESPino32 ร่วมกับอุปกรณ์หลักได้เรียบร้อยแล้ว ขั้นตอนสุดท้ายคือการนำ ESPino32 เซ็นเซอร์ PMS5003ST และ จอ 128×64 OLED Display มาประยุกต์ใช้งานร่วมกัน

        – โดยต่อวงจร ESPino32 เซ็นเซอร์PMS5003ST และ จอ 128×64 OLED Display ดังรูป

        – จากนั้นทำการอัพโหลดโค้ดสำหรับอ่านค่าจากเซ็นเซอร์ PMS5003ST และแสดงผลบนจอ 128×64 OLED Display 

// ทำการเพิ่ม Library ที่เกี่ยวข้อง
#include <Wire.h>
#include "SSD1306Wire.h"
#include "OLEDDisplayUi.h"

//ตั้งค่าสำหรับจอ OLED
SSD1306Wire  display(0x3c, SDA, SCL);
OLEDDisplayUi ui     ( &display );

//ตั้งค่ารอบเวลาอ่านของเซ็นเซอร์ทุกๆ 10 วินาที หรือ 10000 ms
unsigned long previousMillis = 0;
const long interval = 10000; 

//ประกาศตัวแปลที่จำเป็นในการอ่านค่าเซ็นเซอร์
char col;
unsigned int PMSa = 0, FMHDSa = 0, TPSa = 0, HDSa = 0, PMSb = 0, FMHDSb = 0, TPSb = 0, HDSb = 0;
unsigned int PMS = 0, FMHDS = 0, TPS = 0, HDS = 0, CR1 = 0, CR2 = 0;
unsigned char buffer_RTT[40] = {}; //Serial buffer; Received Data
char DataStr[15];
String temp, Humi;

//ฟังก์ชันสำหรับอ่านค่าจะเซ็นเซอร์ PMS5003ST 
void Read_PMS_DATA() {
  while (!Serial2.available());
  while (Serial2.available() > 0) //Data check: weather there is any Data in Serial1
  {
    for (int i = 0; i < 40; i++)
    {
      col = Serial2.read();
      buffer_RTT[i] = (char)col;
      delay(2);
    }
    Serial2.flush();

    CR1 = (buffer_RTT[38] << 8) + buffer_RTT[39];
    CR2 = 0;
    for (int i = 0; i < 38; i++)
      CR2 += buffer_RTT[i];
    if (CR1 == CR2)               //Check
    {
      PMSa = buffer_RTT[12];       //Read PM2.5 High 8-bit
      PMSb = buffer_RTT[13];       //Read PM2.5 Low 8-bit
      PMS = (PMSa << 8) + PMSb;    //PM2.5 value
      FMHDSa = buffer_RTT[28];       //Read Formaldehyde High 8-bit
      FMHDSb = buffer_RTT[29];       //Read Formaldehyde Low 8-bit
      FMHDS = (FMHDSa << 8) + FMHDSb; //Formaldehyde value
      TPSa = buffer_RTT[30];        //Read Temperature High 8-bit
      TPSb = buffer_RTT[31];        //Read Temperature Low 8-bit
      TPS = (TPSa << 8) + TPSb;  //Temperature value
      HDSa = buffer_RTT[32];        //Read Humidity High 8-bit
      HDSb = buffer_RTT[33];        //Read Humidity Low 8-bit
      HDS = (HDSa << 8) + HDSb; //Humidity value
    }/*
    else
    {
      PMS = 0;
      FMHDS = 0;
      TPS = 0;
      HDS = 0;
    }*/
    sprintf(DataStr, "%d%d.%d", TPS / 100, (TPS / 10) % 10, TPS % 10);
    temp = DataStr;
    sprintf(DataStr, "%d%d.%d", HDS / 100, (HDS / 10) % 10, HDS % 10);
    Humi = DataStr;
  }
}

//ฟังก์ชันสำหรับแสดงค่าเซ็นเซอร์ PMS5003ST บน Serial monitor
void PRINT_PMS_DATA() {
  Serial.println("-----------------------PMS5003ST--------------------------");
  Serial.print("Temp : ");
  Serial.print(temp);
  Serial.println("C");               //Serial pring Temperature
  Serial.print("RH   : ");
  Serial.print(Humi);            //Serial print humidity
  Serial.println(" %");               //"%"
  Serial.print("HCHO : ");
  Serial.print(FMHDS);
  Serial.println(" ug/m3");        // Serial print formaldehyde, unit: ug/m³
  Serial.print("PM2.5: ");
  Serial.print(PMS);
  Serial.println(" ug/m3");       // Serial print PM2.5, unit: ug/m³
  Serial.println();
}

//ฟังก์ชันสำหรับออกแบบหน้าจอ โดยจะแบ่งเป็น 4 เฟรม ในแต่ละเฟรมจะแสดงค่าต่างๆที่อ่านมาจากเซ็นเซอร์
void drawFramePM2_5(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
  display->setTextAlignment(TEXT_ALIGN_CENTER);
  display->setFont(ArialMT_Plain_16);
  display->drawString(64 + x, 0 + y, "PM 2.5");

  display->setFont(ArialMT_Plain_24);
  display->drawString(64 + x, 19 + y, String(PMS));

  display->setFont(ArialMT_Plain_10);
  display->drawString(64 + x, 45 + y, "ug/m3");
}

void drawFrameTemp(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
  display->setTextAlignment(TEXT_ALIGN_CENTER);
  display->setFont(ArialMT_Plain_16);
  display->drawString(64 + x, 0 + y, "TEMPERATURE");

  display->setFont(ArialMT_Plain_24);
  display->drawString(64 + x, 19 + y, String(temp));

  display->setFont(ArialMT_Plain_10);
  display->drawString(64 + x, 45 + y, "°C");
}

void drawFrameHumi(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
  display->setTextAlignment(TEXT_ALIGN_CENTER);
  display->setFont(ArialMT_Plain_16);
  display->drawString(64 + x, 0 + y, "HUMIDITY");

  display->setFont(ArialMT_Plain_24);
  display->drawString(64 + x, 19 + y, String(Humi));

  display->setFont(ArialMT_Plain_10);
  display->drawString(64 + x, 45 + y, "%");
}

void drawFrameFormal(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
  display->setTextAlignment(TEXT_ALIGN_CENTER);
  display->setFont(ArialMT_Plain_16);
  display->drawString(64 + x, 0 + y, "Formaldehyde");

  display->setFont(ArialMT_Plain_24);
  display->drawString(64 + x, 19 + y, String(FMHDS));

  display->setFont(ArialMT_Plain_10);
  display->drawString(64 + x, 45 + y, "ug/m3");
}

FrameCallback frames[] = { drawFramePM2_5, drawFrameTemp, drawFrameHumi, drawFrameFormal};
int frameCount = 4;

//เริ่มใช้งานฟังก์ชันและประกาศตั้งค่าเริ่มต้นการทำงานของฟังก์ชันจอแสดงผล
void setup() {
  Serial.begin(115200);
  Serial2.begin(9600);
  Read_PMS_DATA();
  PRINT_PMS_DATA();
  ui.setTargetFPS(60);
  ui.setIndicatorPosition(BOTTOM);
  ui.setIndicatorDirection(LEFT_RIGHT);
  ui.setFrameAnimation(SLIDE_LEFT);
  ui.setFrames(frames, frameCount);
  ui.init();
  display.flipScreenVertically();
}

//การทำงานในลูป จะทำงานฟังก์ชันอ่านค่าจากเซ็นเซอร์ทุกๆ 10 วินาทีและแสดงผลบนหน้าจอ จะทำงานวนไปเรื่อยๆ
void loop() {
  ui.update();
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    Read_PMS_DATA();
    PRINT_PMS_DATA();
  }
}

        – มีผลลัพธ์ดังภาพ 

>> บทความถัดไป โปรเจคเครื่องมือตรวจวัด PM2.5(PMS5003ST) ด้วย ESPino32 และส่งค่าขึ้น Blynk อย่างง่ายๆ<<