หลักการ:
1. ปุ่มกด (Button)
ปุ่มกดเป็นชิ้นส่วนพื้นฐานที่เจอได้ทั่วไป เอาไว้ควบคุมการเปิด-ปิดวงจรไฟฟ้า แม้ปุ่มกดจะมีหลายไซส์หลายรูปทรง แต่ในแล็บนี้เราจะใช้ปุ่มกดขนาด 12mm ตามรูปด้านล่างนี้

ปุ่มที่เราใช้เป็นแบบ Normally Open (NO) หมายความว่าในสภาวะปกติ ขาของปุ่มจะไม่ต่อกัน พอกดปุ่มถึงจะเชื่อมต่อวงจร
เวลากดปุ่มจริงๆ มันจะมีปัญหา "เด้ง" หรือ "สั่น" ของสัญญาณไฟฟ้า (Button Bounce/Jitter) เกิดขึ้นเสมอ รูปคลื่นจะประมาณนี้:

ปัญหาคือ พอกดปุ่มหนึ่งครั้ง Arduino อาจจะเข้าใจว่าเรากดหลายครั้งเพราะสัญญาณเด้ง! ต้องจัดการกับเจ้าตัว bounce นี้ก่อนใช้งานจริง จัดการได้ทั้งทางซอฟต์แวร์และฮาร์ดแวร์
วิธีซอฟต์แวร์ (Debounce): ตรวจจับว่าสัญญาณที่ขาปุ่มเป็น Low หรือยัง? ถ้าเป็น Low แล้ว ให้รอสัก 5-10ms จากนั้นตรวจสอบอีกที ถ้ายังเป็น Low อยู่จริงๆ ค่อยตัดสินใจว่ากดปุ่มหนึ่งครั้ง
วิธีฮาร์ดแวร์: ใช้ตัวเก็บประจุ (Capacitor) ขนาด 0.1uF ต่อขนานกับปุ่มกด ช่วยกรองสัญญาณ bounce ออกได้เลย วงจรตามรูป:

ตรรกะพื้นฐานของการรับ-ส่งข้อมูล (Fundamental Input/Output Logic)
โปรเจคพื้นฐานที่สอนให้เข้าใจความสัมพันธ์ระหว่างการกดปุ่ม (อินพุตทางกายภาพ) กับการจัดการสถานะในโค้ด (ดิจิทัล)
- การ Debounce ผ่านซอฟต์แวร์: อธิบายว่าทำไมการกดปุ่มหนึ่งครั้งถึงส่งสัญญาณ "สกปรก" (มี noise) โค้ดจะใช้การหน่วงเวลา 50ms เป็นตัวกรอง เพื่อให้การกดหนึ่งครั้ง = การเปลี่ยนสถานะหนึ่งครั้งพอดี
- การใช้ Pull-up Resistor: ใช้
INPUT_PULLUPที่มีอยู่แล้วใน Arduino เพื่อลดจำนวนชิ้นส่วน และป้องกันไม่ให้ขาอินพุต "ลอย" (Floating) ซึ่งจะทำให้ค่าอ่านผิดเพี้ยน
โหมดการทำงาน
- กดค้าง vs สลับเปิดปิด: มีตัวอย่างโค้ดให้ทั้งสองแบบ ทั้งแบบ "กดแล้วติด ปล่อยแล้วดับ" (Momentary) และแบบ "กดสลับเปิด-ปิด" เหมือนสวิตช์ไฟ (Toggle/Latch)
2. การขัดจังหวะ (Interrupt)
Interrupt ถูกออกมาเพื่อแก้ปัญหา "การรอคอย" ของ CPU แทนที่จะให้โปรแกรมวนลูปเช็คขาไมค์รอตลอดเวลา (Polling) ซึ่งเปลืองทรัพยากร ก็ให้ใช้ Interrupt สั่งว่า "ถ้าเกิดเหตุการณ์นี้ขึ้นที่ขานี้ ให้มาทำงานนี้แทน"
ฟังก์ชันหลัก:
attachInterrupt(interrupt, ISR, mode) ใช้กำหนดฟังก์ชัน (ISR - Interrupt Service Routine) ที่จะถูกเรียกเมื่อเกิด Interrupt ขึ้นบนขาที่กำหนด Arduino ส่วนใหญ่จะมี Interrupt ภายนอก 2 ขา คือ ขา 2 (Interrupt 0) และ ขา 3 (Interrupt 1)
กฎสำคัญของ ISR: ควรทำให้สั้นและเร็วที่สุด เพราะเวลาที่ ISR ทำงานอยู่ Interrupt อื่นๆ จะถูกปิดชั่วคราว รวมถึงฟังก์ชันที่พึ่งพา Interrupt อย่าง delay() และ millis() ก็จะไม่ทำงาน แต่ delayMicroseconds() ยังใช้ได้ปกติ
Syntax:
attachInterrupt(pin, ISR, mode)
พารามิเตอร์:
- pin: หมายเลขขาที่จะตั้ง Interrupt
- ISR: ฟังก์ชันที่จะถูกเรียกเมื่อเกิด Interrupt ฟังก์ชันนี้ต้องไม่รับและไม่คืนค่าใดๆ
- mode: กำหนดว่าให้ Trigger Interrupt เมื่อไหร่ มีค่าตั้งต้น 4 แบบ:
- LOW: เกิด Interrupt เมื่อขามีสถานะ Low
- CHANGE: เกิด Interrupt ทุกครั้งที่ค่าสถานะของขาเปลี่ยน
- RISING: เกิด Interrupt เมื่อขาเปลี่ยนจาก Low ไป High
- FALLING: เกิด Interrupt เมื่อขาเปลี่ยนจาก High ไป Low
สรุปสั้นๆ: ใช้ Interrupt เมื่อต้องการให้ระบบตอบสนองต่อเหตุการณ์ทันที โดยไม่ต้องรอให้โปรแกรมหลักวนมาถึง แต่อย่าลืมเขียน ISR ให้กระชับนะน้อง ไม่งั้นระบบจะค้างได้!
digitalRead() ฟังก์ชันนี้ใช้สำหรับอ่านค่าจากขา Digital ที่ระบุ ว่าอยู่ในสถานะ HIGH หรือ LOW นั่นเอง
รูปแบบการเขียน (Syntax):
digitalRead(pin)
พารามิเตอร์ (Parameters):
- pin: หมายเลขขา Digital ที่ต้องการอ่านค่า (ชนิด int)
ค่าที่ส่งกลับ (Returns): HIGH หรือ LOW
delayMicroseconds(us)
หยุดการทำงานของโปรแกรมชั่วคราว เป็นระยะเวลาที่กำหนด (หน่วยไมโครวินาที) จำไว้ให้ดีนะน้อง 1,000 ไมโครวินาที เท่ากับ 1 มิลลิวินาที และ 1,000,000 ไมโครวินาที เท่ากับ 1 วินาทีจ้า
ตอนนี้ค่าที่ดีเลย์ได้แม่นยำสูงสุดคือ 16383 แต่อาจเปลี่ยนในอนาคตได้นะ ถ้าจะดีเลย์นานกว่านี้หลายพันไมโครวินาที ให้ใช้ delay() ไปเลยจะดีกว่า
รูปแบบการเขียน (Syntax):
delayMicroseconds(us)
พารามิเตอร์ (Parameters):
- us: จำนวนไมโครวินาทีที่ต้องการหยุดรอ (ชนิด unsigned int)
ขั้นตอนการทดลอง (Procedure): ขั้นตอนที่ 1: ประกอบวงจรตามรูปให้เรียบร้อย ขั้นตอนที่ 2: Compile โปรแกรมและอัปโหลดลงบอร์ด Arduino UNO
จากนั้นลองกดปุ่มดูสิ น้องจะเห็นว่า LED จะสลับสถานะระหว่างติดกับดับ ง่ายๆ แค่นี้เอง อย่าช็อตนะตัวนี้!