ถ้าคุณอ่านค่า ADC ของ ESP32 แล้วงงว่าทำไมบางบทความบอกให้ใช้ ADC_11db ตลอด แต่บางโปรเจกต์กลับอ่านค่าเพี้ยน บทความนี้จะช่วยให้คุณเข้าใจแบบใช้งานจริงครับ
หลายคนเริ่มจาก analogRead() แล้วคิดว่าจบ แต่พออ่านแรงดันจริงจาก sensor, potentiometer หรือวงจรแบ่งแรงดัน กลับเจอค่าที่ไม่ตรงอย่างที่คิด จุดหนึ่งที่คนมองข้ามบ่อยคือ analogSetPinAttenuation() ซึ่งใช้กำหนดช่วงแรงดันที่ ADC ของ ESP32 จะอ่านได้เหมาะกับงานนั้น ๆ
บทความนี้จะอธิบายแบบภาษาคนทำของว่า analogSetPinAttenuation() คืออะไร แต่ละค่า dB ต่างกันยังไง ควรเลือกค่าไหน และมีจุดไหนที่มือใหม่ต้องระวังเป็นพิเศษ
ถ้าคุณยังใหม่กับ ESP32 และยังไม่เห็นภาพรวมว่าบอร์ดนี้ทำอะไรได้บ้าง แนะนำเริ่มจากบทความ ESP32 คืออะไร ก่อน แล้วค่อยกลับมาอ่านเรื่อง ADC และ attenuation ต่อ จะเข้าใจง่ายขึ้นครับ
สารบัญ
- analogSetPinAttenuation() คืออะไร
- ทำไมต้องตั้ง attenuation ก่อนอ่าน ADC
- แต่ละค่า dB อ่านแรงดันได้สูงสุดเท่าไร
- ควรเลือกค่าไหนในงานจริง
- ตัวอย่างโค้ดใช้งาน analogSetPinAttenuation()
- analogSetPinAttenuation() ต่างจาก analogReadResolution() ยังไง
- จุดที่ต้องระวัง
- แนวทางเลือกค่าแบบง่ายสำหรับมือใหม่
- ตัวอย่างงานที่เจอบ่อยในสาย Maker / Smart Farm
- สรุป
- คำถามที่คนใช้ ESP32 ถามบ่อยเรื่อง 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
| Attenuation | ESP32 Classic | ESP32-S2 | ESP32-C3 | ESP32-S3 |
|---|---|---|---|---|
ADC_0db | 100 ~ 950 mV | 0 ~ 750 mV | 0 ~ 750 mV | 0 ~ 950 mV |
ADC_2_5db | 100 ~ 1250 mV | 0 ~ 1050 mV | 0 ~ 1050 mV | 0 ~ 1250 mV |
ADC_6db | 150 ~ 1750 mV | 0 ~ 1300 mV | 0 ~ 1300 mV | 0 ~ 1750 mV |
ADC_11db | 150 ~ 3100 mV* | 0 ~ 2500 mV | 0 ~ 2500 mV | 0 ~ 3100 mV |

*เอกสาร 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_0db, ADC_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 ที่คุณใช้อยู่ด้วย

แนวทางเลือกค่าแบบง่ายสำหรับมือใหม่
- ดูว่าช่วงแรงดันของสัญญาณคุณอยู่ประมาณเท่าไร
- เลือก attenuation ที่ครอบคลุมช่วงนั้นได้พอดี
- ถ้าใช้ Wi-Fi บน ESP32 classic พยายามใช้ ADC1
- ถ้าต้องอ่านแรงดันจริงเป็นโวลต์ ให้เผื่อเรื่อง calibration ด้วย
- ถ้าใช้
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 อ่านได้เยอะกว่า” แต่ให้เลือกตามแรงดันจริงของงานคุณ และทดสอบกับบอร์ดจริงเสมอครับ
อ่านต่อ: บทความ ESP32 ที่เกี่ยวข้อง
ถ้าคุณกำลังเริ่มใช้งาน ADC หรือทำโปรเจควัดค่าต่าง ๆ ด้วย ESP32 บทความเหล่านี้จะช่วยให้เข้าใจและต่อยอดได้ง่ายขึ้น
FAQ: คำถามที่คนใช้ ESP32 ถามบ่อยเรื่อง attenuation
analogSetPinAttenuation() จำเป็นต้องใช้ทุกครั้งไหม
ไม่จำเป็นทุกครั้ง แต่ถ้าคุณต้องการควบคุมช่วงแรงดันให้เหมาะกับขาที่อ่านจริง การตั้งเองจะชัดและปลอดภัยกว่าปล่อย default
ใช้ ADC_11db ตลอดเลยได้ไหม
ได้ในหลายงาน แต่ไม่ใช่คำตอบที่ดีที่สุดเสมอไป เพราะบางงานสัญญาณต่ำ การตั้งช่วงกว้างเกินไปอาจไม่เหมาะเท่าการเลือก attenuation ให้พอดีกับสัญญาณ
ADC_11db อ่าน 3.3V ได้ไหม
ขึ้นกับชิปรุ่นและเอกสารที่อ้างอิง แต่ถึงอย่างนั้นก็ไม่ควรใช้วิธีคิดว่า “แตะ 3.3V ได้เสมอทุกบอร์ด” โดยไม่เทสต์จริง
ทำไมตั้ง attenuation ถูกแล้วค่าก็ยังไม่ตรง
เพราะ ADC ของ ESP32 ยังมีเรื่อง calibration, noise, non-linearity และความต่างของชิปแต่ละตัวเข้ามาเกี่ยวด้วย
ถ้าใช้ Wi-Fi แล้ว ADC เพี้ยน ต้องดูอะไรก่อน
ถ้าเป็น ESP32 classic ให้เช็กก่อนเลยว่าคุณใช้ขาในกลุ่ม ADC2 หรือเปล่า



