ESP32-C3 อ่านค่าฝุ่นจาก GP2Y10

ESP32-C3 อ่านค่าฝุ่นจาก GP2Y10 แบบนิ่งขึ้น พร้อมอธิบายโค้ด EMA Filter และการเฉลี่ย 20 จุด

ถ้าคุณอยากทำโปรเจกต์วัดฝุ่นแบบ DIY ด้วย ESP32-C3 Super Mini และเซนเซอร์ Sharp GP2Y10 บทความนี้จะช่วยให้คุณเข้าใจทั้งการต่อวงจร หลักการอ่านค่า ADC การเปิด LED ภายในเซนเซอร์ตามจังหวะเวลา การแปลงแรงดันเป็นค่าฝุ่น รวมถึงเทคนิคทำให้ค่าที่อ่านได้ นิ่งขึ้นและใช้งานจริงได้ดีขึ้น ด้วยวิธี EMA Filter และการ เฉลี่ย 20 จุด ก่อนนำไปใช้ควบคุมพัดลมหรือแสดงผลบน OLED

ESP32-C3 กับ GP2Y10 คืออะไร และเหมาะกับงานแบบไหน

ESP32-C3 เป็นไมโครคอนโทรลเลอร์ที่เหมาะมากสำหรับงาน IoT และงาน DIY ขนาดเล็ก เพราะบอร์ดมีขนาดกะทัดรัด ใช้พลังงานไม่สูง รองรับ Wi-Fi และสามารถอ่านค่าอนาล็อกจากเซนเซอร์ภายนอกได้ ส่วน GP2Y10 เป็นเซนเซอร์ตรวจจับฝุ่นแบบ Optical Dust Sensor ที่นิยมใช้ในงานทดลอง งานทำเครื่องวัดคุณภาพอากาศเบื้องต้น และงานควบคุมพัดลมอัตโนมัติเมื่อฝุ่นสูงเกินค่าที่กำหนด

จุดเด่นของคู่ ESP32-C3 + GP2Y10 คือ “ต้นทุนไม่แรง แต่ต่อยอดได้เยอะ” เช่น ทำเครื่องวัดฝุ่นติดโต๊ะ, ระบบสั่งเปิดพัดลมอัตโนมัติ, แสดงผลผ่าน OLED, หรือส่งข้อมูลขึ้น Web UI ภายหลังได้ สำหรับสาย Maker หรือคนที่กำลังทำคอนเทนต์สอน ESP32 โปรเจกต์นี้ถือว่าเหมาะมาก เพราะมีทั้งเรื่อง ADC, timing, filter, การแปลงค่า, และการควบคุมอุปกรณ์ต่อพ่วงอยู่ในโปรเจกต์เดียว

หลักการทำงานของ GP2Y10 แบบเข้าใจง่าย

GP2Y10 ใช้หลักการยิงแสงอินฟราเรดเข้าไปในช่องอากาศภายในตัวเซนเซอร์ เมื่อมีฝุ่นลอยผ่าน แสงจะสะท้อนกลับเข้าตัวรับแสง แล้วถูกแปลงเป็นแรงดันไฟฟ้าออกมาที่ขาเอาต์พุต จากนั้น ESP32-C3 จะอ่านแรงดันนี้ผ่าน ADC แล้วนำไปตีความเป็นค่าความเข้มข้นฝุ่น

สิ่งสำคัญคือเซนเซอร์ตัวนี้ไม่ได้อ่านแบบ “เปิดค้างแล้วอ่านตลอด” แต่จะมีจังหวะการเปิด LED ภายในช่วงสั้น ๆ แล้วอ่านค่าสัญญาณในช่วงเวลาที่เหมาะสม จึงทำให้โค้ดต้องควบคุมเวลาเป็นไมโครวินาที ถ้าอ่านผิดจังหวะ ค่าอาจแกว่งหรือผิดจากความจริงได้

แนวคิดสั้น ๆ คือ: เปิด LED ภายในเซนเซอร์ → หน่วงเวลาสั้น → อ่าน ADC → ปิด LED → หน่วงก่อนรอบถัดไป

อุปกรณ์ที่ใช้ในโปรเจกต์

อุปกรณ์หลัก

  • ESP32-C3 Super Mini
  • Sharp GP2Y10 Dust Sensor
  • จอ OLED 0.96 นิ้ว I2C
  • Relay Module หรือวงจรขับพัดลม
  • ตัวต้านทานแบ่งแรงดัน สำหรับลดแรงดันจากเซนเซอร์ให้เหมาะกับ ADC 3.3V ของ ESP32-C3

เหตุผลที่ต้องมีวงจรแบ่งแรงดัน

เนื่องจากเอาต์พุตของ GP2Y10 อาจมีแรงดันสูงกว่า 3.3V ในบางสภาพการใช้งาน การต่อเข้าขา ADC ของ ESP32-C3 โดยตรงจึงไม่ปลอดภัย โค้ดนี้เลยออกแบบให้มีตัวแปร DIV_RATIO เพื่อใช้ชดเชยค่าหลังผ่านวงจรแบ่งแรงดัน ทำให้สามารถคำนวณย้อนกลับไปหาแรงดันจริงที่ออกจากเซนเซอร์ได้

ลำดับการอ่านค่าฝุ่นในโปรแกรม

  1. สั่งให้ LED ภายใน GP2Y10 ทำงาน
  2. หน่วงเวลาเพื่อให้สัญญาณนิ่งพอสำหรับการวัด
  3. อ่านค่า ADC จาก ESP32-C3
  4. ปิด LED ภายในเซนเซอร์
  5. รอครบเฟรมก่อนอ่านรอบถัดไป
  6. อ่านหลายครั้งแล้วเฉลี่ย
  7. แปลงค่าเป็นแรงดัน Vadc
  8. แปลงย้อนกลับเป็น Vout ก่อนแบ่งแรงดัน
  9. กรองด้วย EMA Filter
  10. คำนวณเป็นค่าฝุ่นโดยประมาณ
  11. นำไปแสดงผลหรือควบคุมพัดลม

ดาว์นโหลดโค้ด

กรุณา เข้าสู่ระบบ เพื่อดาวน์โหลด

โครงสร้างไฟล์โค้ดในโปรเจกต์

1) config.h

ใช้เก็บค่าคงที่สำคัญ เช่น ขา ADC, ขา LED, ขารีเลย์ และตัวแปรกลางที่ใช้ร่วมกันทั้งโปรเจกต์ แนวทางนี้ช่วยให้แก้ไขง่าย เวลาย้ายบอร์ดหรือเปลี่ยนขาไม่ต้องไล่แก้หลายไฟล์

2) sharpAp2y10.h / sharpAp2y10.cpp

เป็นหัวใจของการอ่านค่าฝุ่น ประกอบด้วยฟังก์ชันอ่านค่า ADC, แปลงแรงดัน, คำนวณค่าฝุ่น และกรองสัญญาณด้วย EMA Filter ถ้าจะอธิบายด้านเทคนิคในบทความ SEO ส่วนนี้คือแกนหลักที่ควรอธิบายให้ละเอียดที่สุด

3) ControlFan.h / ControlFan.cpp

ส่วนนี้ใช้เอาค่าฝุ่นที่อ่านได้ไปตัดสินใจเปิดหรือปิดพัดลม โดยมีค่า setpoint เปิด-ปิดแยกกัน ซึ่งช่วยลดอาการสั่งเปิดปิดถี่เกินไปเวลาค่าฝุ่นแกว่งใกล้จุดตัด

4) display.h / display.cpp

ใช้แสดงผลค่าฝุ่นบน OLED เช่น ค่า Dust, Vadc, Vout และสถานะพัดลม ทำให้โปรเจกต์ดูสมบูรณ์และพร้อมนำไปทำเดโมหรือคอนเทนต์ได้ง่ายขึ้น

อธิบายโค้ดส่วนสำคัญ

การอ่านค่า ADC จาก GP2Y10

จุดสำคัญของโค้ดอ่าน GP2Y10 คือเรื่อง timing ไม่ใช่อ่าน analogRead() ตรง ๆ แบบเซนเซอร์ทั่วไป แต่ต้องสั่ง LED ภายในเซนเซอร์ให้ทำงานก่อน จากนั้นหน่วงเวลาสั้น ๆ แล้วค่อยอ่าน ADC ในช่วงที่เอกสารหรือแนวทางใช้งานแนะนำ

int readDustRaw() {
  digitalWrite(PIN_LED, LOW);  // LED ON
  delayMicroseconds(280);
  int adc = analogRead(PIN_ADC);  // sample
  delayMicroseconds(40);
  digitalWrite(PIN_LED, HIGH);  // LED OFF
  delayMicroseconds(9680);      // frame ~10ms
  return adc;
}

การจัดลำดับแบบนี้ช่วยให้ค่าที่อ่านจากเซนเซอร์สอดคล้องกับสภาพฝุ่นจริงมากขึ้น ถ้าใครอ่านค่าแล้วไม่นิ่งหรือได้ค่าน้อยผิดปกติ ให้กลับมาตรวจช่วงเวลาในฟังก์ชันนี้ก่อนเป็นอันดับแรก

เพื่อให้เข้าใจการอ่านค่า Analog อย่างถูกต้อง
แนะนำให้ศึกษาพื้นฐาน ADC ของ ESP32 จากบทความนี้ก่อน: ESP32 ADC คืออะไร — คู่มือพื้นฐานสำหรับมือใหม่

การเฉลี่ย 20 จุด คืออะไร และช่วยอะไร

ถึงแม้เราจะอ่านถูกจังหวะแล้ว แต่ค่าจาก Dust Sensor ก็ยังมี noise อยู่ดี โดยเฉพาะเวลาใช้ในห้องที่ลมพัด, มีสัญญาณรบกวนจากแหล่งจ่าย, หรืออนุภาคฝุ่นผ่านเข้ามาแบบไม่สม่ำเสมอ วิธีง่ายที่สุดที่ช่วยให้ข้อมูลนิ่งขึ้นคือ “อ่านหลายครั้งแล้วเฉลี่ย”

const int N = 20;  // เฉลี่ยลด noise
    long sum = 0;
    for (int i = 0; i < N; i++) sum += readDustRaw();
    float adc_avg = (float)sum / N;

ข้อดีของการเฉลี่ย 20 จุด

  • ลด noise ระยะสั้นจาก ADC
  • ลดผลกระทบจากค่ากระโดดเพียง 1-2 รอบ
  • ทำให้ค่าที่แสดงบนจอและค่าที่ใช้ควบคุมพัดลมดูนิ่งและเชื่อถือได้มากขึ้น

ทำไมต้อง 20 จุด

เลข 20 ไม่ได้เป็นเลขตายตัว แต่เป็นค่าที่สมดุลระหว่าง “ความนิ่ง” และ “ความเร็วในการตอบสนอง” ถ้าใช้จำนวนน้อยเกินไปค่าจะยังสวิงเยอะ แต่ถ้าใช้มากเกินไประบบจะตอบสนองช้า สำหรับงาน DIY ทั่วไป 10–30 จุดถือว่าเป็นช่วงที่ใช้งานได้ดี และ 20 จุดเป็นค่าที่เข้าใจง่ายสำหรับมือใหม่

EMA Filter คืออะไร และทำไมควรใช้กับค่าฝุ่น

EMA หรือ Exponential Moving Average คือวิธีกรองสัญญาณที่ให้น้ำหนักกับข้อมูลล่าสุดมากกว่าข้อมูลเก่า ต่างจากการเฉลี่ยธรรมดาที่ให้น้ำหนักทุกจุดเท่ากัน จุดเด่นของ EMA คือทำให้ค่าดูนิ่งขึ้น แต่ยังตอบสนองต่อการเปลี่ยนแปลงได้ไวพอสมควร

float emaFilter(float v) {
  if (vout_f == 0.0f) vout_f = v;           // init ครั้งแรก
  vout_f = vout_f + ALPHA * (v - vout_f);
  return vout_f;
}

อธิบายทีละบรรทัด

  • if (vout_f == 0.0f) vout_f = v; ใช้กำหนดค่าเริ่มต้นครั้งแรก ไม่ให้ค่ากรองเริ่มจากศูนย์แล้วเพี้ยน
  • vout_f = vout_f + ALPHA * (v - vout_f); คือสูตร EMA หลัก
  • ALPHA คือค่าความไวของฟิลเตอร์ ยิ่งน้อยยิ่งนิ่ง แต่ตอบสนองช้า

เข้าใจ ALPHA แบบง่าย

ค่า ALPHAลักษณะการทำงานเหมาะกับงานแบบไหน
0.05นิ่งมาก แต่ช้ากว่างานแสดงผลที่อยากให้ตัวเลขดูนิ่ง
0.10สมดุลดีงานวัดฝุ่น DIY ทั่วไป
0.20ไวขึ้น แต่แกว่งมากขึ้นงานที่ต้องการตอบสนองเร็ว

แนวทางที่ดีคือใช้ การเฉลี่ย 20 จุดก่อน แล้วค่อยส่งผลลัพธ์เข้า EMA Filter วิธีนี้จะช่วยให้ได้ค่าที่นิ่งกว่าใช้วิธีใดวิธีหนึ่งเพียงอย่างเดียว

การแปลง ADC → Vadc → Vout → Dust

หลังจากอ่านค่า ADC แล้ว ขั้นตอนต่อมาคือการแปลงค่าให้อยู่ในรูปที่เข้าใจง่ายขึ้น เริ่มจากแปลงเป็นแรงดันที่ขา ADC ของ ESP32-C3 ก่อน จากนั้นค่อยแปลงย้อนกลับไปเป็นแรงดันจริงของเซนเซอร์ก่อนผ่านวงจรแบ่งแรงดัน

float adcToVadc(float adc) {
  return (adc * VREF) / ADC_MAX;
}

float vadcToVout(float vadc) {
  return vadc / DIV_RATIO;
}

// สูตรประมาณจากตัวอย่างที่นิยมใช้: slope ~0.5V ต่อ 1 mg/m3
float voutToDustMg(float vout) {
  float dv = vout - V0_clean;
  if (dv < 0) dv = 0;
  return (dv / 0.5f) * 0.1f;  // mg/m3 (ประมาณ)
}

ความหมายของตัวแปรสำคัญ

  • VREF คือแรงดันอ้างอิงของ ADC
  • ADC_MAX คือค่ามากสุดของ ADC 12-bit
  • DIV_RATIO คืออัตราส่วนของวงจรแบ่งแรงดัน
  • V0_clean คือแรงดันของเซนเซอร์ตอนอากาศสะอาด ใช้เป็นค่า baseline

ตรงนี้ต้องเข้าใจด้วยว่า ค่าฝุ่นที่ได้จากสูตรนี้เป็น ค่าประมาณ ไม่ใช่ค่ามาตรฐานระดับเครื่องวัดเชิงอุตสาหกรรม ถ้าต้องการแม่นยำมากขึ้น ควรทำ calibration เทียบกับเครื่องวัดมาตรฐานจริง

การเอาค่าฝุ่นไปควบคุมพัดลม

เมื่อได้ค่าฝุ่นแล้ว เราสามารถเอาไปควบคุมพัดลมอัตโนมัติได้ เช่น ถ้าค่าฝุ่นเกิน 0.03 mg/m3 ให้เปิดพัดลม และถ้าลดลงต่ำกว่า 0.02 mg/m3 ให้ปิดพัดลม วิธีนี้ทำให้ระบบไม่เปิดปิดรัวอยู่ที่จุดเดียว


bool ContronFanfromdust(float dust) {
  if (dust >= setFanon) {
    FlagOn = true;
  } else if (dust <= setFanoff) {
    FlagOn = false;
  }

  if(FlagOn != rel.get(FAN)){
    rel.set(FAN, FlagOn);
    Serial.printf("FAN : %s \n", rel.get(FAN)? "ON" : "OFF");
  }
  return FlagOn;
}

เทคนิคนี้เรียกว่า hysteresis หรือการตั้งจุดเปิดกับจุดปิดแยกกัน ช่วยให้รีเลย์หรือพัดลมไม่สั่นไปมาเวลาค่าฝุ่นอยู่ใกล้เส้นแบ่ง

ข้อควรระวังในการใช้งานจริง

1) อย่าต่อเอาต์พุตเซนเซอร์เข้าขา ADC โดยตรงถ้าแรงดันเกิน

ESP32-C3 รับแรงดันอนาล็อกได้ในระดับ 3.3V การใช้วงจรแบ่งแรงดันจึงสำคัญมาก

2) ค่า GP2Y10 ต้องมีการคาลิเบรต

ถ้าอยากให้ค่าที่อ่านได้ใกล้เคียงความจริงมากขึ้น ควรเก็บค่า V0_clean ในสภาพอากาศสะอาดจริง และทดสอบซ้ำหลายครั้ง

3) อย่าพึ่งเชื่อค่าที่แกว่งทันที

Sensor ฝุ่นประเภทนี้ไวต่อสภาพลม การขยับเซนเซอร์ และสัญญาณรบกวนจากแหล่งจ่ายไฟ การใช้ค่าเฉลี่ย 20 จุดและ EMA Filter จะช่วยได้มาก

4) บทความที่เกี่ยวข้อง

สรุป

ถ้าคุณกำลังมองหาบทความสอน ESP32-C3 อ่านค่าฝุ่นจาก GP2Y10 แบบที่ไม่ได้หยุดแค่การต่อวงจร แต่ลงลึกถึงตรรกะในโค้ดจริง บทความนี้คือโครงสร้างที่ดีมากสำหรับทำ SEO และต่อยอดเป็นบทความคุณภาพบน DevaDIY เพราะมีทั้งพื้นฐานบอร์ด, หลักการของเซนเซอร์, การอ่าน ADC อย่างถูกจังหวะ, การเฉลี่ย 20 จุด, การใช้ EMA Filter, การแปลงค่าแรงดันเป็นค่าฝุ่น และการนำผลลัพธ์ไปควบคุมพัดลมอัตโนมัติ

สำหรับสายสอนและสายทำโปรเจกต์จริง จุดสำคัญที่สุดคืออย่ามองเพียงตัวเลขที่อ่านได้ แต่ต้องเข้าใจว่าทำไมค่าถึงนิ่งหรือไม่นิ่ง, ทำไมต้องกรองสัญญาณ, และทำไมการตั้งจุดเปิดปิดพัดลมแบบมี hysteresis จึงสำคัญมาก เมื่อเข้าใจภาพรวมเหล่านี้แล้ว คุณจะสามารถต่อยอดโปรเจกต์ไปเป็นระบบแจ้งเตือนฝุ่น, Smart Fan, หรือเครื่องวัดฝุ่น DIY ที่ใช้งานได้ดีขึ้นจริง

FAQ คำถามที่พบบ่อย

GP2Y10 ใช้วัด PM2.5 ได้ตรง ๆ ไหม

โดยทั่วไปควรมองว่าเป็นการวัดฝุ่นเชิงประมาณจากหลักการ optical sensor มากกว่าจะเป็นค่า PM2.5 

สาเหตุหลักมักมาจาก timing การอ่านไม่ตรง, แหล่งจ่ายไฟไม่นิ่ง, ไม่มีวงจรกรอง, หรือยังไม่ได้ใช้การเฉลี่ยหลายจุดและ EMA Filter

ไม่จำเป็นแบบตายตัว แต่แนะนำมาก เพราะช่วยลด noise และทำให้ค่าที่อ่านเสถียรขึ้นอย่างเห็นได้ชัด

averaging คือเฉลี่ยหลายค่าด้วยน้ำหนักเท่ากัน ส่วน EMA ให้น้ำหนักกับค่าล่าสุดมากกว่า ทำให้ยังนิ่งแต่ตอบสนองไวกว่า

ได้ เช่น ESP32 DevKit V1 หรือ ESP32-S3 แต่ต้องตรวจสอบขา ADC และแรงดันที่รองรับให้เหมาะกับวงจรของคุณ

ไม่จำเป็น OLED เป็นเพียงส่วนแสดงผลเพิ่มความสะดวก ถ้าไม่ใช้ก็สามารถดูค่าทาง Serial Monitor ได้

ควรวัดในสภาพอากาศที่สะอาดจริงหลายครั้ง แล้วหา baseline ที่เหมาะสมกับเซนเซอร์ของคุณ

เพื่อป้องกันแรงดันจากเซนเซอร์สูงเกินขีดจำกัดของ ADC บน ESP32-C3 และเพื่อให้คำนวณค่าได้อย่างปลอดภัย

ได้ แต่ควรมี hysteresis หรือ setpoint เปิด-ปิดคนละค่า เพื่อไม่ให้รีเลย์สั่นเปิดปิดถี่

Shopping Cart
Scroll to Top