analogSetPinAttenuation() คืออะไร? ควรใช้ค่าไหนกับ ESP32

ถ้าคุณอ่านค่า ADC ของ ESP32 แล้วงงว่าทำไมบางบทความบอกให้ใช้ ADC_11db ตลอด แต่บางโปรเจกต์กลับอ่านค่าเพี้ยน บทความนี้จะช่วยให้คุณเข้าใจแบบใช้งานจริงครับ

หลายคนเริ่มจาก analogRead() แล้วคิดว่าจบ แต่พออ่านแรงดันจริงจาก sensor, potentiometer หรือวงจรแบ่งแรงดัน กลับเจอค่าที่ไม่ตรงอย่างที่คิด จุดหนึ่งที่คนมองข้ามบ่อยคือ analogSetPinAttenuation() ซึ่งใช้กำหนดช่วงแรงดันที่ ADC ของ ESP32 จะอ่านได้เหมาะกับงานนั้น ๆ

บทความนี้จะอธิบายแบบภาษาคนทำของว่า analogSetPinAttenuation() คืออะไร แต่ละค่า dB ต่างกันยังไง ควรเลือกค่าไหน และมีจุดไหนที่มือใหม่ต้องระวังเป็นพิเศษ

ถ้าคุณยังใหม่กับ ESP32 และยังไม่เห็นภาพรวมว่าบอร์ดนี้ทำอะไรได้บ้าง แนะนำเริ่มจากบทความ ESP32 คืออะไร ก่อน แล้วค่อยกลับมาอ่านเรื่อง ADC และ attenuation ต่อ จะเข้าใจง่ายขึ้นครับ

analogSetPinAttenuation() คืออะไร

analogSetPinAttenuation() คือฟังก์ชันใน Arduino ESP32 ที่ใช้ตั้งค่า attenuation แบบรายขา ให้กับ ADC pin ที่เราจะอ่านค่า

พูดแบบง่าย ๆ attenuation คือการตั้งว่า ขา ADC นี้จะยอมให้วัดแรงดันได้กว้างแค่ไหน ยิ่งค่า attenuation สูง ช่วงแรงดันที่วัดได้ก็ยิ่งกว้างขึ้น แต่ไม่ได้แปลว่าจะวัดอะไรก็ได้แบบไม่ต้องคิดนะครับ

analogSetPinAttenuation(pin, attenuation);

ตัวอย่างเช่น

analogSetPinAttenuation(34, ADC_11db);

บรรทัดนี้หมายถึง: ให้ขา GPIO34 ใช้ attenuation ระดับ ADC_11db

สรุปสั้น ๆ:
analogSetPinAttenuation() = ตั้งช่วงแรงดันของ ADC เป็นรายขา
analogSetAttenuation() = ตั้ง attenuation แบบรวมทุกขา

ทำไมต้องตั้ง attenuation ก่อนอ่าน ADC

ADC ของ ESP32 ไม่ได้อ่านแรงดันทุกช่วงได้เหมือนกันหมด ถ้าคุณป้อนแรงดันเข้าไปอยู่คนละช่วงกับ attenuation ที่ตั้งไว้ ค่าที่อ่านได้อาจอัดอยู่ปลายสเกล อ่านไม่เต็มช่วง หรือเพี้ยนกว่าที่ควรจะเป็น

นึกภาพง่าย ๆ เหมือนคุณเลือกไม้บรรทัดผิดอัน:

  • ถ้าจะวัดของเล็กมาก ควรใช้สเกลที่ละเอียด
  • ถ้าจะวัดของยาวขึ้น ต้องใช้สเกลที่กว้างขึ้น

ADC ก็คล้ายกัน ถ้าสัญญาณคุณอยู่แค่ประมาณ 0–1V แต่ดันไปตั้งช่วงกว้างเกินความจำเป็น คุณอาจเสียความละเอียดเชิงใช้งานไปโดยไม่รู้ตัว

แต่ละค่า dB อ่านแรงดันได้สูงสุดเท่าไร

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

ตารางสรุป measurable input voltage range

AttenuationESP32 ClassicESP32-S2ESP32-C3ESP32-S3
ADC_0db100 ~ 950 mV0 ~ 750 mV0 ~ 750 mV0 ~ 950 mV
ADC_2_5db100 ~ 1250 mV0 ~ 1050 mV0 ~ 1050 mV0 ~ 1250 mV
ADC_6db150 ~ 1750 mV0 ~ 1300 mV0 ~ 1300 mV0 ~ 1750 mV
ADC_11db150 ~ 3100 mV*0 ~ 2500 mV0 ~ 2500 mV0 ~ 3100 mV
ESP32 ADC attenuation modes showing ADC_0db ADC_2_5db ADC_6db and ADC_11db for different measurement ranges

*เอกสาร Espressif จะมีทั้งตารางจาก Arduino-ESP32 และตารางใน ESP-IDF บางหน้าที่ต่างกัน โดยเฉพาะ ESP32 classic ที่เอกสาร ESP-IDF v4.4 ระบุช่วง ADC_ATTEN_DB_11 ไว้ที่ประมาณ 150–2450 mV สำหรับ measurable range ที่แนะนำในไดรเวอร์ระดับล่าง ขณะที่เอกสาร Arduino-ESP32 แสดง 150–3100 mV สำหรับตารางรวมหลายชิป ดังนั้นถ้าคุณทำงานที่ต้องการความชัวร์สูง ควรเทสต์กับบอร์ดจริงของตัวเองเสมอ

สรุปเข้าใจง่ายๆ

  • ADC_0db เหมาะกับแรงดันต่ำ
  • ADC_2_5db ขยับช่วงได้กว้างขึ้นอีกหน่อย
  • ADC_6db ใช้กลาง ๆ กับ sensor analog หลายงาน
  • ADC_11db เหมาะกับงานที่ต้องอ่านแรงดันสูงขึ้นใกล้ช่วง 2.5V ถึงประมาณ 3.1V ตามชิปรุ่น

ข้อสำคัญ:
ADC_11db ไม่ได้แปลว่า “เอา 5V หรือ 12V มาต่อเข้าขา ADC ตรง ๆ ได้”
ถ้าแรงดันเกินช่วงที่ชิปอ่านได้ คุณยังต้องใช้ voltage divider หรือวงจรลดแรงดันเหมือนเดิม

ควรเลือกค่าไหนในงานจริง

กรณีที่ 1: อ่าน sensor แรงดันต่ำ

เช่น potentiometer, output sensor ต่ำ ๆ หรือสัญญาณที่อยู่ไม่เกินประมาณ 1V การใช้ ADC_0db หรือ ADC_2_5db มักเหมาะกว่า เพราะช่วงวัดไม่กว้างเกินจำเป็น

กรณีที่ 2: อ่าน sensor กลาง ๆ ราว 1–1.5V

งานแนวนี้มักเริ่มดูที่ ADC_2_5db หรือ ADC_6db แล้วเทสต์จริงว่าค่าที่อ่านนิ่งและครอบคลุมช่วงที่ต้องการไหม

กรณีที่ 3: อ่านแรงดันสูงขึ้นใกล้ 2.5V หรือ 3.3V

ถ้าสัญญาณคุณขยับขึ้นสูง และชิปรุ่นที่ใช้รองรับ อันนี้ ADC_11db จะเป็นตัวเลือกที่นิยมที่สุด

กรณีที่ 4: วัดแบตเตอรี่ 12V หรือโซลาร์เซลล์

ตรงนี้มือใหม่พลาดกันเยอะมาก ต่อให้ใช้ ADC_11db ก็ไม่ได้แปลว่าวัด 12V ตรงได้ คุณต้องใช้วงจรแบ่งแรงดันก่อน แล้วค่อยให้แรงดันที่ “ลดแล้ว” เข้ามาที่ ADC

ตัวอย่างโค้ดใช้งาน analogSetPinAttenuation()

#define ADC_PIN 34

void setup() {
  Serial.begin(115200);

  analogSetPinAttenuation(ADC_PIN, ADC_11db);
}

void loop() {
  int raw = analogRead(ADC_PIN);
  Serial.println(raw);
  delay(500);
}

อธิบายแบบสั้น ๆ

  • ADC_PIN คือขาที่จะอ่านค่า
  • analogSetPinAttenuation() ใช้ตั้ง attenuation ให้ขานั้น
  • analogRead() ใช้อ่านค่า raw ออกมา

ถ้าจะเขียนให้ชัดขึ้นเวลาเทสต์

#define ADC_PIN 34

void setup() {
  Serial.begin(115200);

  analogSetPinAttenuation(ADC_PIN, ADC_0db);
}

void loop() {
  int raw = analogRead(ADC_PIN);
  Serial.print("RAW = ");
  Serial.println(raw);
  delay(500);
}

เวลาทดสอบจริง คุณอาจลองป้อนแรงดันที่รู้ค่าชัด เช่น 0.5V, 1.0V, 1.5V แล้วเปลี่ยน attenuation ทีละค่าเพื่อดูว่าช่วงไหนเหมาะกับงานคุณที่สุด

analogSetPinAttenuation() ต่างจาก analogReadResolution() ยังไง

สองตัวนี้คนชอบสับสนกันมาก

ฟังก์ชันหน้าที่
analogSetPinAttenuation()กำหนดช่วงแรงดันที่ ADC pin นั้นจะวัดได้
analogReadResolution()กำหนดจำนวนบิตของค่าที่อ่าน เช่น 12-bit

จำง่าย ๆ แบบนี้ครับ:

  • Attenuation = กำหนด “ช่วงแรงดัน”
  • Resolution = กำหนด “ความละเอียดของตัวเลขที่อ่าน”

จุดที่ต้องระวัง: ชิปรุ่นต่างกัน ช่วงแรงดันก็ไม่เท่ากัน

นี่คือจุดที่บทความทั่วไปชอบข้ามไป คือแม้ชื่อฟังก์ชันจะเหมือนกัน แต่ measurable input voltage range ของแต่ละชิปรุ่นต่างกัน เช่น ESP32 classic, S2, C3, S3 ไม่ได้เท่ากันหมด

ดังนั้นถ้าคุณใช้ ESP32 คนละรุ่นกับเจ้าของบทความที่อ้างอิงอยู่ อย่ารีบเชื่อค่าตัวเลขทันที ควรดูเอกสารของชิปรุ่นนั้น และควรทดสอบกับบอร์ดจริงเสมอ โดยเฉพาะงานที่ต้องอ่านแรงดันเป็นค่า mV หรือ V จริง ๆ

จุดที่ต้องระวัง: ESP32 classic มีข้อจำกัด ADC2 เมื่อใช้ร่วมกับ Wi-Fi

ถ้าคุณใช้ ESP32 classic ต้องจำไว้เลยว่า ADC2 มีข้อจำกัดเมื่อทำงานร่วมกับ Wi-Fi เพราะฮาร์ดแวร์ฝั่ง Wi-Fi ใช้ ADC2 ด้วย

ถ้าคุณทำโปรเจกต์ที่เปิด Wi-Fi แล้วอ่าน ADC ไปพร้อมกัน เช่น IoT sensor, dashboard, web server หรือส่งข้อมูลขึ้นมือถือ แล้วค่ามันแปลก ๆ อย่าเพิ่งโทษ attenuation อย่างเดียว ให้เช็กก่อนว่าคุณเผลอใช้ขาในกลุ่ม ADC2 หรือเปล่า

ถ้าคุณยังไม่แน่ใจว่าขา ADC1 และ ADC2 อยู่ตรงไหนบนบอร์ด แนะนำเปิด [รายละเอียด ESP32 Pinout] ก่อน เพื่อเช็กตำแหน่งขาให้ชัดก่อนต่อวงจรและเขียนโค้ด

คำแนะนำจากงานจริง:
ถ้าคุณทำโปรเจกต์ ESP32 ที่ใช้ Wi-Fi ด้วย ให้พยายามเลือกขา ADC1 ก่อน จะปลอดภัยกว่าในหลายกรณี

จุดที่ต้องระวัง: Calibration ยังสำคัญ แม้ตั้ง attenuation ถูกแล้ว

หลายคนเข้าใจว่าตั้ง attenuation ถูกแล้ว ADC จะตรงเป๊ะเลย แต่ในความจริงค่าอ้างอิงของ ADC แต่ละชิปอาจคลาดจากค่า nominal ได้ ดังนั้น Espressif จึงมีเอกสาร calibration แยกไว้ต่างหาก

แปลเป็นภาษาง่าย ๆ คือ ต่อให้คุณเลือก ADC_0dbADC_6db หรือ ADC_11db ถูกแล้ว ค่าที่อ่านก็ยังอาจมี error ตามความต่างของชิปแต่ละตัวอยู่ดี โดยเฉพาะงานที่ต้องอ่านแรงดันจริงแบบเอาไปคำนวณต่อ

งานแบบไหนที่ควรสนใจ calibration มาก

  • วัดแรงดันแบตเตอรี่
  • วัดแหล่งจ่ายไฟเพื่อแจ้งเตือน
  • วัด sensor analog ที่ต้องแปลงเป็นหน่วยจริง
  • งานที่ต้องการความแม่นมากกว่าดูแนวโน้มคร่าว ๆ

จุดที่ต้องระวัง: analogReadMilliVolts() อาจมีผลไม่ตรงกับ attenuation รายขาในบางกรณี

อีกจุดที่คนทำงานลึกควรรู้คือ มี issue ที่รายงานไว้ใน arduino-esp32 ว่า ถ้าใช้ analogReadMilliVolts() ร่วมกับ analogSetPinAttenuation() แบบรายขา ค่าที่คำนวณเป็น mV อาจไปอิง global attenuation แทนรายขาในบางกรณี

พูดง่าย ๆ คือ:

  • analogRead() อาจยังอ่าน raw ได้ตามขาที่ตั้ง
  • แต่ analogReadMilliVolts() อาจแปลงค่า mV โดยใช้ attenuation รวม ไม่ใช่ attenuation ของขานั้นแบบที่คุณคิด

แนะนำสำหรับสายเทสต์จริง:
ถ้าคุณกำลังวัดแรงดันแบบจริงจัง อย่าเชื่อแค่ analogReadMilliVolts() อย่างเดียว
ให้เทียบกับมัลติมิเตอร์จริง และตรวจสอบ core / board package version ที่คุณใช้อยู่ด้วย

ESP32 ADC important notes showing ADC2 conflict with WiFi calibration warning and that 11dB does not mean direct 12V input is safe

แนวทางเลือกค่าแบบง่ายสำหรับมือใหม่

  1. ดูว่าช่วงแรงดันของสัญญาณคุณอยู่ประมาณเท่าไร
  2. เลือก attenuation ที่ครอบคลุมช่วงนั้นได้พอดี
  3. ถ้าใช้ Wi-Fi บน ESP32 classic พยายามใช้ ADC1
  4. ถ้าต้องอ่านแรงดันจริงเป็นโวลต์ ให้เผื่อเรื่อง calibration ด้วย
  5. ถ้าใช้ analogReadMilliVolts() ให้เทสต์เทียบของจริงเสมอ

ตัวอย่างงานที่เจอบ่อยในสาย Maker / Smart Farm

1) Soil Moisture Sensor

ถ้าเอาไว้ดูแนวโน้มแห้ง-ชื้น อาจไม่ได้ต้องแม่นระดับ mV แต่ต้องอ่านนิ่งและอยู่ในช่วงเหมาะสม [ระบบรดน้ำต้นไม้อัตโนมัติ ESP32]

2) SHARP GP2Y10

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

3) วัดแรงดันแบตเตอรี่

อันนี้ต้องคิดทั้ง attenuation + voltage divider + calibration [ESP32 วัดแรงดันไฟด้วย ADC แบบปลอดภัย]

4) วัดแรงดันจาก potentiometer

เหมาะมากสำหรับใช้เทสต์ช่วงของ attenuation แต่ละค่า เพราะควบคุมแรงดันได้ง่าย [ทดลอง ESP32 อ่านค่าสัญญาณ Analog]

สรุป

analogSetPinAttenuation() คือฟังก์ชันที่ใช้ตั้ง attenuation แบบรายขาให้ ADC ของ ESP32 เพื่อกำหนดว่าขานั้นจะวัดแรงดันได้ในช่วงประมาณไหน

แต่จุดที่สำคัญจริง ๆ คือ:

  • แต่ละชิปรุ่นอ่านช่วงแรงดันได้ไม่เท่ากัน
  • ESP32 classic ต้องระวัง ADC2 ชนกับ Wi-Fi
  • งานที่ต้องการความแม่นควรสนใจ calibration
  • ถ้าใช้ analogReadMilliVolts() ควรเทสต์จริง เพราะมี issue เรื่อง attenuation รายขาในบางกรณี

ดังนั้นถ้าจะใช้ให้ดี อย่าจำแค่ว่า “11db อ่านได้เยอะกว่า” แต่ให้เลือกตามแรงดันจริงของงานคุณ และทดสอบกับบอร์ดจริงเสมอครับ

FAQ: คำถามที่คนใช้ ESP32 ถามบ่อยเรื่อง attenuation

analogSetPinAttenuation() จำเป็นต้องใช้ทุกครั้งไหม

ไม่จำเป็นทุกครั้ง แต่ถ้าคุณต้องการควบคุมช่วงแรงดันให้เหมาะกับขาที่อ่านจริง การตั้งเองจะชัดและปลอดภัยกว่าปล่อย default

ได้ในหลายงาน แต่ไม่ใช่คำตอบที่ดีที่สุดเสมอไป เพราะบางงานสัญญาณต่ำ การตั้งช่วงกว้างเกินไปอาจไม่เหมาะเท่าการเลือก attenuation ให้พอดีกับสัญญาณ

ขึ้นกับชิปรุ่นและเอกสารที่อ้างอิง แต่ถึงอย่างนั้นก็ไม่ควรใช้วิธีคิดว่า “แตะ 3.3V ได้เสมอทุกบอร์ด” โดยไม่เทสต์จริง

เพราะ ADC ของ ESP32 ยังมีเรื่อง calibration, noise, non-linearity และความต่างของชิปแต่ละตัวเข้ามาเกี่ยวด้วย

ถ้าเป็น ESP32 classic ให้เช็กก่อนเลยว่าคุณใช้ขาในกลุ่ม ADC2 หรือเปล่า

Shopping Cart
Scroll to Top