สร้างเครื่องวัดฝุ่นแบบง่ายๆด้วย ESP32 และ HPMA115S0

Cytron Thailand
5 min readJan 31, 2021

สวัสดีครับในวันนี้เราจะมาลองสร้างเครื่องวัดฝุ่นแบบพกพาโดยใช้บอร์ด NODEMCU ESP32 และ เซนเซอร์ Honeywell HPMA115S0 กันนะครับ โดยอุปกรณ์ มีดังนี้ครับ

หากสนใจโปรเจ็กต์นี้ สามารถสั่งซื้ออุปกรณ์ได้ที่ Cytron Thailand : https://bit.ly/3r7VLmS

อุปกรณ์ที่ใช้

  1. NODEMCU ESP32
NODEMCU ESP32

2. Honeywell HPMA115S0

Honeywell HPMA115S0

3. 1.8-inch 128x160 TFT LCD Breakout — ST7735

1.8-inch 128x160 TFT LCD Breakout — ST7735

4. Grove 4 Pin Buckled to Female Cable

Grove 4 Pin Buckled to Female Cable

5. Rocker Switch Small 2 Pins Red

โดยขั้นตอนการประกอบสามารถศึกษาได้จากคลิปนี้ได้เลยครับ

หากท่านใดมีข้อสงสัยสามารถทิ้ง Comment ไว้ได้เลยนะครับ

หากสนใจโปรเจ็กต์นี้ สามารถสั่งซื้ออุปกรณ์ได้ที่ Cytron Thailand : https://bit.ly/3r7VLmS

Wiring Diagram

Wiring Diagram

โดยเพื่อนๆสามารถดาว์นโหลดโค้ดโปรแกรมได้ที่นี่: https://drive.google.com/drive/folders/10H6veHu-Hfitpnf-yuvv0FXjQzmXEIsZ?usp=sharing

และสามารถดาว์นโหลด Library สำหรับเซนเซอร์ HPMA115S0 ได้จากที่นี่ : https://github.com/Electronza/HPMA115S0

Arduino Code

#include <hpma115s0.h>
#include <TFT_eSPI.h> // Graphics and font library for ST7735 driver chip
#include <SPI.h>

TFT_eSPI myGLCD = TFT_eSPI(); // Invoke library, pins defined in User_Setup.h

#define DELAY 5000
#define TFT_GREY 0x7BEF
#define TFT_W 160
#define TFT_H 128

int pm25s[120];
int PM25;
int PM10;
bool my_status;
float p25;
float p10;
int addr = 0;
int initc = 0;
int minute = 60;

HPMA115S0 my_hpm(Serial2);

void setup()
{
myGLCD.init();
myGLCD.setRotation(3);
myGLCD.fillScreen(TFT_BLACK);
myGLCD.setTextColor(TFT_WHITE);
Serial.begin(115200);
myGLCD.drawCentreString(“Measurement starting”, TFT_W / 2, TFT_H / 2, 2);
Serial2.begin(9600);
my_status = my_hpm.stop_autosend();
if (my_status == 1){
Serial.println(“Autosend disabled”);
}
else{
Serial.print(“Error”);
}
delay(500);

// Start fan (and measurement mode)
my_status = my_hpm.start_measurement();
if (my_status == 1){
myGLCD.drawCentreString(“Sensor Ready”, TFT_W / 2, TFT_H / 4, 2);
Serial.println(“Start sensor”);
}
else{
myGLCD.drawCentreString(“Initialing”, TFT_W / 2, TFT_H / 4, 2);
}

myGLCD.fillScreen(TFT_BLACK);
myGLCD.fillRect(0, 0, TFT_W — 1, 14, TFT_RED);
myGLCD.fillRect(0, TFT_H — 14, TFT_W — 1, 14, TFT_GREY);
myGLCD.setTextColor(TFT_BLACK, TFT_RED);
myGLCD.drawCentreString(“Particulate Measurement”, TFT_W / 2, 4, 1);
myGLCD.setTextColor(TFT_YELLOW, TFT_GREY);
myGLCD.drawCentreString(“Cytron”, TFT_W / 2, TFT_H — 12, 1);
myGLCD.drawRect(0, 14, TFT_W — 1, TFT_H — 28, TFT_BLUE);
myGLCD.drawLine(TFT_W / 2–1, 15, TFT_W / 2–1, TFT_H / 2–1, TFT_BLUE);
myGLCD.drawLine(1, TFT_H / 2–1, TFT_W — 2, TFT_H / 2–1, TFT_BLUE);
myGLCD.setTextColor(TFT_WHITE);
myGLCD.drawString(“PM 2.5”, 18, 20, 2);
myGLCD.drawString(“PM 10”, 100, 20, 2);
}

void loop(){
my_status = my_hpm.read(&p25,&p10); //Measure particulate matter in air.
if(initc == 0){ //First 60-min for initial and collect data of particulate in air.
if (my_status == 1){
pm25s[addr] = p25; // Write data to EEPROM
for(int i=0;i<20;i++){
Serial.print(pm25s[i]); Serial.print(“ “);
}
Serial.println(“ “);
for(int i=20;i<40;i++){
Serial.print(pm25s[i]); Serial.print(“ “);
}
Serial.println(“ “);
for(int i=40;i<60;i++){
Serial.print(pm25s[i]); Serial.print(“ “);
}
Serial.println(“ “);
for(int i=60;i<80;i++){
Serial.print(pm25s[i]); Serial.print(“ “);
}
Serial.println(“ “);
for(int i=80;i<100;i++){
Serial.print(pm25s[i]); Serial.print(“ “);
}
Serial.println(“ “);
for(int i=100;i<120;i++){
Serial.print(pm25s[i]); Serial.print(“ “);
}
Serial.println(“ “);
Serial.print(“ADDR : “); Serial.println(addr);
addr = addr + 1; //Change position in EEPROM
myGLCD.drawNumber(p25, 35, 40, 2); //Write PM2.5 value on TFT screen
myGLCD.drawNumber(p10, 113, 40, 2); //Write PM10 value on TFT screen
myGLCD.drawCentreString(“Collecting data in…”, TFT_W / 2, 70, 2);
if(addr%2 == 1){
minute = minute — 1;
}
myGLCD.fillRect(48, 90, 14, 14, TFT_BLACK);
myGLCD.drawNumber(minute, 50, 95, 1);
// myGLCD.drawNumber(minute, 50, 95, 1); //Write minute value on TFT screen
myGLCD.drawString(“minutes”, 65, 95, 1);
if(addr == 120){
initc = 1;
addr = 0;
myGLCD.fillRect(1, TFT_H / 2, 145, 50, TFT_BLACK);
}
}
else{
Serial.println(“Measurement fail 0”);
delay(1000);
myGLCD.fillScreen(TFT_BLACK);
myGLCD.drawCentreString(“Sensor Error, Restarting..”, TFT_W / 2, TFT_H / 4, 2);
delay(2000);
ESP.restart();
}
}
if(initc == 1){
if(addr == 120){
addr = 0;
}
if (my_status == 1){
int sum = 0;
int avrg_pm25;
int aqi;
for (int i = 0; i < 120; i++){
sum = sum + pm25s[addr];
}
avrg_pm25 = sum / 120;
Serial.print(“Average PM2.5/hr = “);Serial.println(avrg_pm25);
myGLCD.drawString(“PM 2.5/hr :”, 10, 67, 1);
myGLCD.fillRect(80, 67, 20, 10, TFT_BLACK);
myGLCD.drawNumber(avrg_pm25, 80, 67, 1); //Write PM2.5/hr value
if(avrg_pm25 >= 0 && avrg_pm25 <= 12){
aqi = 4.17*avrg_pm25;
}
else if(avrg_pm25 > 12 && avrg_pm25 <= 35.5){
aqi = (2.13*avrg_pm25)+24.44;
}
else if(avrg_pm25 > 35.5 && avrg_pm25 <= 55.5){
aqi = (2.5*avrg_pm25)+11.25;
}
else if(avrg_pm25 > 55.5 && avrg_pm25 <= 150.5){
aqi = (0.53*avrg_pm25)+120.585;
}
else if(avrg_pm25 > 150.5 && avrg_pm25 <= 250.5){
aqi = avrg_pm25+49.5;
}
else if(avrg_pm25 > 250.5 && avrg_pm25 <= 350.5){
aqi = avrg_pm25+49.5;
}
else if(avrg_pm25 > 350.5 && avrg_pm25 <= 500.5){
aqi = (0.67*avrg_pm25)+165.165;
}
Serial.print(“AQI:”);
Serial.println(aqi);
myGLCD.drawString(“AQI :”, 10, 78, 1);
myGLCD.fillRect(45, 78, 20, 10, TFT_BLACK);
myGLCD.drawNumber(aqi, 45, 78, 1); //Write AQI value

if(aqi >= 0 && aqi <= 50){
myGLCD.setTextColor(TFT_GREEN);
myGLCD.fillRect(10, 90, 140, 14, TFT_BLACK);
myGLCD.drawCentreString(“GOOD”, TFT_W / 2, 90, 2);
}
else if(aqi > 50 && aqi <= 100){
myGLCD.setTextColor(TFT_ORANGE);
myGLCD.fillRect(10, 90, 140, 14, TFT_BLACK);
myGLCD.drawCentreString(“MODERATE”, TFT_W / 2, 90, 2);
}
else if(aqi > 100 && aqi <= 150){
myGLCD.setTextColor(TFT_BROWN);
myGLCD.fillRect(10, 90, 140, 14, TFT_BLACK);
myGLCD.drawCentreString(“UNHEALTHY FOR KID”, TFT_W / 2, 90, 2);
}
else if(aqi > 150 && aqi <= 200){
myGLCD.setTextColor(TFT_RED);
myGLCD.fillRect(10, 90, 140, 14, TFT_BLACK);
myGLCD.drawCentreString(“UNHEALTHY”, TFT_W / 2, 90, 2);
}
else if(aqi > 200 && aqi <= 300){
myGLCD.setTextColor(TFT_RED);
myGLCD.fillRect(10, 90, 140, 14, TFT_BLACK);
myGLCD.drawCentreString(“VERY UNHEALTHY”, TFT_W / 2, 90, 2);
}
else if(aqi > 300 && aqi <= 400){
myGLCD.setTextColor(TFT_VIOLET);
myGLCD.fillRect(10, 90, 140, 14, TFT_BLACK);
myGLCD.drawCentreString(“HARZARDOUS”, TFT_W / 2, 90, 2);
}
else if(aqi > 400 && aqi <= 500){
myGLCD.setTextColor(TFT_VIOLET);
myGLCD.fillRect(10, 90, 140, 14, TFT_BLACK);
myGLCD.drawCentreString(“VERY HARZARDOUS”, TFT_W / 2, 90, 2);
}

myGLCD.fillRect(113, 40, 15, 15, TFT_BLACK);
myGLCD.fillRect(30, 40, 20, 15, TFT_BLACK);
myGLCD.drawNumber(p25, 30, 40, 2); //Write PM2.5 value on TFT screen
myGLCD.drawNumber(p10, 113, 40, 2); //Write PM10 value on TFT screen
pm25s[addr] = p25; // Write data to array
Serial.print(“ADDR : “); Serial.println(addr);
addr = addr + 1;
}
else{
Serial.println(“Measurement fail 1”);
delay(1000);
myGLCD.fillScreen(TFT_BLACK);
myGLCD.drawCentreString(“Sensor Error, Restarting..”, TFT_W / 2, TFT_H / 4, 2);
delay(2000);
ESP.restart();
}
}
delay(30000);
myGLCD.setTextColor(TFT_WHITE, TFT_BLACK);
}

--

--