สวัสดีครับนักศึกษาทุกคน ในบทที่แล้วเราเป็นฝ่าย “สั่งงาน” (Output) ให้ไฟติดไปแล้ว ในบทนี้เราจะเปลี่ยนมาเป็นฝ่าย “รับคำสั่ง” (Input) กันบ้างครับ

อุปกรณ์ Input พื้นฐานที่สุดคือ สวิตช์ปุ่มกด (Tactile Switch) ดูเหมือนจะง่ายแค่กดติด-ปล่อยดับ แต่ถ้านักศึกษาต่อวงจรไม่ถูกหลักทางไฟฟ้า จะเจอกับปรากฏการณ์ “ผีหลอก” คือไม่ได้กดปุ่ม แต่ไฟกระพริบเอง หรือค่าที่อ่านได้แกว่งไปมา บทความนี้จะมาไขความลับและวิธีแก้ปัญหานี้ด้วยฟังก์ชันพิเศษของ ESP32 ครับ


ชื่อคำอธิบาย
1.l / 1.rการติดต่อครั้งแรก (ซ้าย / ขวา)
2.l / 2.rการติดต่อครั้งที่สอง (ซ้าย / ขวา)

1. คำสั่งอ่านค่า Digital Input

ในการอ่านสถานะของขา Pin ว่ามีไฟเข้ามาหรือไม่ เราจะใช้คำสั่ง:

C++
int buttonState = digitalRead(pin);
  • pin: หมายเลขขาที่ต้องการอ่าน
  • ค่าที่ได้คืนมา:
    • HIGH (1): มีไฟเข้า (ประมาณ 3.3V)
    • LOW (0): ไม่มีไฟเข้า (0V / GND)

2. ปัญหา “สัญญาณลอย” (Floating State) คืออะไร?

สมมติเราต่อสวิตช์ระหว่างขา GPIO กับไฟบวก (3.3V)

  • ตอนกดปุ่ม: ไฟ 3.3V ไหลเข้าขา ขามีสถานะเป็น HIGH (ชัดเจน)
  • ตอนปล่อยปุ่ม: ขา GPIO ไม่ได้ต่อกับอะไรเลย ลอยอยู่กลางอากาศ (Open Circuit)

ในสภาวะที่ขาลอยอยู่นี้ ขาของ ESP32 จะทำตัวเหมือน “สายอากาศ” ที่คอยรับสัญญาณรบกวนรอบข้าง (Noise) ทำให้ค่าที่อ่านได้สลับไปมาระหว่าง HIGH กับ LOW มั่วไปหมด เราเรียกสภาวะนี้ว่า Floating ครับ


3. ทางแก้: ตัวต้านทาน Pull-up และ Pull-down

เพื่อไม่ให้ขาลอย เราต้อง “ดึง” (Pull) สัญญาณไว้ที่ระดับแรงดันใดแรงดันหนึ่งเสมอเมื่อไม่ได้กดปุ่ม

  1. Pull-down Resistor: ต่อตัวต้านทานลง GND
    • ปกติ (ไม่กด): อ่านได้ LOW (เพราะถูกดึงลงดิน)
    • กดปุ่ม (ต่อไฟ 3.3V): อ่านได้ HIGH
  2. Pull-up Resistor: ต่อตัวต้านทานขึ้นไฟ 3.3V
    • ปกติ (ไม่กด): อ่านได้ HIGH (เพราะถูกดึงขึ้นไฟเลี้ยง)
    • กดปุ่ม (ต่อลง GND): อ่านได้ LOW

4. ฟีเจอร์เด็ดของ ESP32: Internal Pull-up

ข่าวดีคือ! บอร์ด ESP32 มีตัวต้านทาน Pull-up ฝังมาให้ในตัวชิปเลย (Internal Pull-up) ทำให้เราไม่ต้องไปหาตัวต้านทานมาต่อเพิ่มให้รกวงจร เพียงแค่ตั้งค่าในโค้ดครับ

การต่อวงจรแบบ Internal Pull-up (นิยมใช้ที่สุด):

  1. ขาหนึ่งของสวิตช์ -> ต่อเข้าขา GPIO (เช่น GPIO 18)
  2. อีกขาของสวิตช์ -> ต่อลง GND (ไม่ต้องต่อไฟ 3.3V)

การเขียนโค้ด:

C++
void setup() {
  // ใช้โหมด INPUT_PULLUP เพื่อเปิดใช้ R ภายใน
  pinMode(18, INPUT_PULLUP); 
}

ข้อควรจำ (Active Low): เมื่อใช้ INPUT_PULLUP ตรรกะจะกลับกันนะครับ

  • ปล่อยปุ่ม: ได้ค่า HIGH (1)
  • กดปุ่ม: ได้ค่า LOW (0) -> เพราะกระแสไหลลง Ground

5. ปฏิบัติการ: กดติด-ปล่อยดับ (ด้วย Internal Pull-up)

เราจะลองเขียนโปรแกรมรับค่าจากปุ่มกด (GPIO 18) เพื่อควบคุม LED (GPIO 23)

ผังวงจร:

  • LED: ขาบวกต่อ GPIO 23, ขาลบต่อ R-220Ω ลง GND
  • Button: ขาหนึ่งต่อ GPIO 18, อีกขาต่อ GND

โค้ดตัวอย่าง:

C++
const int ledPin = 23;
const int buttonPin = 18;

void setup() {
  Serial.begin(115200); // เปิด Serial Monitor ไว้ดูค่า
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP); // *สำคัญมาก*
}

void loop() {
  int buttonState = digitalRead(buttonPin);
  
  // แสดงผลค่าที่อ่านได้ทางหน้าจอคอมฯ
  Serial.println(buttonState);

  // ตรวจสอบเงื่อนไข (จำไว้ว่า กด = LOW)
  if (buttonState == LOW) {
    digitalWrite(ledPin, HIGH); // สั่งไฟติด
  } else {
    digitalWrite(ledPin, LOW);  // สั่งไฟดับ
  }
  
  delay(50); // หน่วงเวลาเล็กน้อยเพื่อความเสถียร
}

6. ปัญหาของแถม: Switch Bouncing (สัญญาณกระเด้ง)

ในความเป็นจริง หน้าสัมผัสของสวิตช์เป็นโลหะ เมื่อมันกระทบกัน มันจะมีการ “สั่น” หรือ “กระเด้ง” (Bouncing) ในเสี้ยววินาที ทำให้ไมโครคอนโทรลเลอร์ที่ทำงานเร็วมาก อ่านค่าว่ามีการกด-ปล่อย-กด-ปล่อย หลายครั้งในการกดเพียงครั้งเดียว

ในบทความระดับสูง เราจะแก้ด้วยการเขียนโค้ด De-bouncing แบบจับเวลา แต่ในเบื้องต้นการใส่ delay(50); เล็กน้อยใน Loop ก็พอจะช่วยลดปัญหานี้ในการทดลองพื้นฐานได้ครับ


สรุปท้ายบท

วันนี้เราได้เรียนรู้เรื่อง Digital Input และเทคนิคการใช้ INPUT_PULLUP ซึ่งเป็นเทคนิคมาตรฐานที่นักพัฒนามืออาชีพใช้กัน เพื่อลดอุปกรณ์ภายนอกและทำให้วงจรเสถียรครับ

ภารกิจต่อไป: ตอนนี้เราเล่นกับอุปกรณ์ Digital (0 กับ 1) จนคล่องแล้ว ในบทความหน้า เราจะก้าวเข้าสู่โลกของ Analog กันบ้าง มาดูกันว่า ESP32 จะอ่านค่าแรงดันไฟฟ้าที่ “ไม่ใช่แค่ 0 หรือ 3.3V” ได้อย่างไร ในเรื่อง ADC (Analog to Digital Converter) ครับ