การใช้งานฟังก์ชัน pulseIn()
ใน Arduino เพื่อวัดสัญญาณพัลส์อย่างละเอียด และตัวอย่างโครงงาน

บทนำ: เมื่อการวัดสัญญาณพัลส์กลายเป็นเรื่องสำคัญ
ในงานด้านไมโครคอนโทรลเลอร์หรือการประยุกต์ใช้ Arduino นั้น “สัญญาณพัลส์” (Pulse) ถือเป็นหัวใจสำคัญของการอินเทอร์แอคต์ระหว่างฮาร์ดแวร์และซอฟต์แวร์ ตั้งแต่การวัดระยะทาง การวัดความเร็ว ไปจนถึงการควบคุมอุปกรณ์ และหนึ่งในฟังก์ชันที่มีบทบาทสำคัญที่ Arduino จัดเตรียมให้ก็คือ pulseIn()
ฟังก์ชันตัวนี้ช่วยให้นักพัฒนาสามารถวัดความยาว (ความกว้าง) ของช่วงสัญญาณพัลส์ที่กำลังเกิดขึ้นได้โดยไม่ต้องเขียนโค้ดซับซ้อน การใช้งานก็ไม่ยุ่งยาก แถมยังทรงพลังมากพอที่จะให้เรานำไปสร้างสรรค์โครงงานได้มากมาย
เนื้อหาต่อไปนี้ ตั้งใจจะนำเสนอทุกแง่มุมของฟังก์ชัน pulseIn()
ใน Arduino ให้ละเอียดที่สุด ตั้งแต่วิธีการทำงานภายใน โครงสร้างการเรียกใช้ ข้อควรระวัง ไปจนถึงตัวอย่างโครงงานแบบจับต้องได้ที่จะจุดประกายไอเดียของเราให้ต่อยอดได้หลากหลาย เราจะถ่ายทอดด้วยภาษาที่อ่านง่าย แต่ก็จะสอดแทรกรายละเอียดเชิงเทคนิคให้ครบถ้วน เพื่อให้ทั้งมือใหม่และมือเก๋า Arduino สามารถเข้าใจและพร้อมจะนำไปประยุกต์ใช้งานได้ทันที
สำหรับบทความนี้ นอกจากจะอธิบายถึงฟังก์ชัน pulseIn()
แล้ว เรายังตัวอย่างการปฏิบัติจริง บอกเล่าความรู้สึกระหว่างการทำงานว่าอะไรควรระวัง หรือเทคนิคเพิ่มเติมเล็กน้อยที่อาจช่วยให้โค้ดของเรารันได้สมบูรณ์และเสถียรมากขึ้น
1. การวัดสัญญาณพัลส์คืออะไร?
ก่อนอื่นเราควรเข้าใจความหมายของการ “วัดสัญญาณพัลส์” กันเสียก่อน คำว่า “พัลส์” (Pulse) ในที่นี้หมายถึงสัญญาณดิจิทัล (Digital Signal) ที่เปลี่ยนสถานะระหว่าง LOW (0) และ HIGH (1) เมื่อเราพูดถึง “วัดสัญญาณพัลส์” ก็คือการวัดระยะเวลาที่สัญญาณอยู่ในสถานะ HIGH หรือในทางกลับกันอาจวัดระยะเวลาที่สัญญาณอยู่ในสถานะ LOW ก็ได้ ขึ้นอยู่กับการตั้งค่าและการใช้งาน
สัญญาณพัลส์นี้ปรากฏในหลายบริบท ตัวอย่างเช่น
- สัญญาณอัลตราโซนิก: ในโครงงานเซนเซอร์วัดระยะทางด้วย Ultrasonic Sensor (เช่น HC-SR04) จะมีการปล่อยคลื่นเสียงความถี่สูง และจับเวลาที่คลื่นสะท้อนกลับมาเป็นสัญญาณดิจิทัล นี่เป็นการวัดความยาวของพัลส์เพื่อคำนวณระยะทาง
- สัญญาณควบคุมเซอร์โว (PWM/PPM): ในการควบคุมเซอร์โวมอเตอร์ สัญญาณที่ใช้ในการบอกตำแหน่งของเซอร์โวเป็นการส่งพัลส์ที่มีความกว้างต่างกันออกไป หากต้องการอ่านค่าตำแหน่ง หรือประมวลผลพัลส์เพื่อทำอย่างอื่น ก็สามารถใช้
pulseIn()
ได้ - สัญญาณ IR Remote: รีโมตอินฟราเรดที่เราใช้กันตามบ้านมักยิงสัญญาณเป็นชุดพัลส์ออกมา หากเราต้องการจับความยาวของพัลส์เพื่อถอดรหัสสัญญาณ ก็สามารถใช้
pulseIn()
เช่นเดียวกัน
การวัดสัญญาณพัลส์จึงเป็นพื้นฐานที่สำคัญมาก ถ้าเข้าใจและใช้เป็นก็จะเปิดประตูให้เราสร้างโปรเจกต์สร้างสรรค์ได้มากมาย
2. ทำความรู้จักฟังก์ชัน pulseIn()
: ภาพรวมและรูปแบบการเรียกใช้
เมื่อเราต้องการวัดช่วงเวลาที่ขาอินพุตของ Arduino อยู่ในสถานะ HIGH หรือ LOW ฟังก์ชัน pulseIn()
จะเป็นตัวเลือกที่สะดวกมาก รูปแบบการเรียกใช้ (Syntax) พื้นฐานของ pulseIn()
มีดังนี้:
unsigned long pulseIn(uint8_t pin, uint8_t value, unsigned long timeout)
ซึ่งในภาษาที่เข้าใจได้ง่ายก็คือ
- pin: หมายเลขพินดิจิทัลที่เราต้องการจะอ่านค่าสัญญาณพัลส์
- value: กำหนดว่าจะจับเวลาพัลส์ที่เป็น
HIGH
หรือLOW
โดยสามารถใส่ได้สองค่า คือHIGH
หรือLOW
- timeout (ไม่บังคับ): เป็นค่ากำหนดระยะเวลา (หน่วยไมโครวินาที) ที่จะให้
pulseIn()
รอการเกิดพัลส์ก่อนจะรีเทิร์นกลับมาเป็น 0 ถ้าหากสัญญาณพัลส์ไม่เกิดในเวลาที่กำหนด ฟังก์ชันก็จะส่งค่ากลับเป็น 0 ทันที เพื่อป้องกันโค้ดค้างรอ (Default คือ 1,000,000 ไมโครวินาที หรือ 1 วินาที)
ผลลัพธ์ที่ฟังก์ชัน pulseIn()
ส่งกลับมาคือค่าประเภท unsigned long
ที่ระบุระยะเวลา (หน่วยไมโครวินาที) ที่สัญญาณอยู่ในสถานะ value
(คือ HIGH
หรือ LOW
) ซึ่งจะเปิดโอกาสให้เรานำค่าเวลานั้นไปคำนวณหรือประมวลผลต่อไป

3. กลไกการทำงานภายในของ pulseIn()
การที่ pulseIn()
สามารถจับระยะเวลาของพัลส์ได้ก็เพราะ Arduino จะคอยตรวจสอบสถานะของพินแบบวนลูปตลอดเวลา จนกระทั่งมันเจอสภาวะแบบ “ก่อนพัลส์” “ระหว่างพัลส์” และ “หลังพัลส์” เรียงตามขั้นตอนคร่าว ๆ ดังนี้
-
รอให้สัญญาณเปลี่ยนไปเป็นตรงข้ามกับที่เราต้องการวัด
เพื่อเป็นการข้ามช่วงเปลี่ยนแปลงสถานะเก่า ให้แน่ใจว่าเราจะวัดพัลส์ถัดไปจริง ๆ ยกตัวอย่าง ถ้าเราสั่งวัดHIGH
Arduino จะรอให้สัญญาณอยู่ในสถานะLOW
เสียก่อน แล้วจึงเข้าเงื่อนไขเตรียมวัด -
เมื่อเจอสัญญาณเปลี่ยนไปเป็น
value
ที่กำหนด (HIGH หรือ LOW)
Arduino จะจับเวลาว่าเริ่มต้นเมื่อใด -
รอจนกว่าสัญญาณจะเปลี่ยนกลับ
สมมติว่ากำลังวัดHIGH
เมื่อ Arduino ตรวจพบว่าสัญญาณกลับไปเป็นLOW
ก็จะหยุดจับเวลา -
ส่งค่าที่จับได้ (ระยะเวลาในหน่วยไมโครวินาที)
จากนั้นโปรแกรมก็จะส่งค่าดังกล่าวกลับมาเป็นunsigned long
ให้เรา
ระหว่างขั้นตอนนี้ หากมีการกำหนด timeout
ไว้และช่วงเวลาที่รอนานเกินค่าที่กำหนด เช่น วัดไปแล้วไม่พบว่าพัลส์สลับสถานะตามที่คาดไว้ ฟังก์ชันก็จะตัดจบ (timeout) ส่งค่ากลับเป็น 0 เพื่อให้โปรแกรมไม่ค้างรอ
ตรงนี้เป็นเหตุผลว่าทำไม pulseIn()
อาจทำให้ Arduino “หยุดการทำงาน” ชั่วคราวได้ ถ้ารอแล้วสัญญาณไม่มา ก็จะค้างรออยู่จนถึง timeout ซึ่งสามารถลดปัญหาโดยกำหนด timeout ให้เหมาะสมตามโครงงานของเรา
4. รูปแบบการใช้งานและความหมายของพารามิเตอร์
- 4.1 pin :
- เป็นค่าตัวเลขแทนขาของ Arduino ที่จะใช้วัดพัลส์
- ต้องตั้งขานั้นเป็น “อินพุต” ไม่จำเป็นต้องใช้
pinMode(pin, INPUT)
หรือไม่ก็ได้ เพราะโดยทั่วไปpulseIn()
จะปรับเอง แต่เพื่อความเคลียร์ควรตั้งเองก่อน
- 4.2 value :
- มีสองค่าให้เลือก ได้แก่
HIGH
หรือLOW
- สมมติเราต้องการวัดระยะเวลาสัญญาณสูง ก็ใช้
HIGH
หรือถ้าต้องการวัดระยะเวลาสัญญาณต่ำ ก็ใช้LOW
- ขึ้นอยู่กับลักษณะของโครงงาน เช่น ถ้าเป็นโครงงานวัดสัญญาณ PWM บางครั้งอาจต้องวัดช่วงที่สัญญาณเป็น
HIGH
หรือช่วงที่สัญญาณเป็นLOW
เพื่อถอดรหัสข้อมูล
- มีสองค่าให้เลือก ได้แก่
- 4.3 timeout :
- เป็นค่าที่ไม่บังคับ (Optional) ถ้าไม่ใส่จะเท่ากับ 1,000,000 ไมโครวินาที (1 วินาที)
- ถ้าใส่ลงไปก็จะเป็นการกำหนดว่าควรรอการเกิดพัลส์นานแค่ไหนก่อนที่จะรีเทิร์นเป็น 0
- หากโครงงานของเรารู้ช่วงเวลาคาดหวังของสัญญาณอยู่แล้ว เช่น เรารู้ว่าสัญญาณจะเกิดขึ้นทุก 50 มิลลิวินาที อาจตั้ง timeout สัก 100,000 ไมโครวินาที เพื่อไม่ให้โปรแกรมค้างนานเกินไป
5. ตัวอย่างการใช้งาน pulseIn()
พื้นฐาน
ลองมาดูโค้ดตัวอย่างสั้น ๆ ที่ใช้ pulseIn()
เพื่ออ่านระยะเวลาที่สัญญาณดิจิทัลอยู่ในสถานะ HIGH
สมมติว่าเราใช้พิน 7 เป็นอินพุต:
void setup() {
Serial.begin(9600);
pinMode(7, INPUT); // ตั้งเป็นอินพุตเพื่อรับสัญญาณ
}
void loop() {
unsigned long duration;
// วัดเวลาที่สัญญาณอยู่ใน HIGH
duration = pulseIn(7, HIGH);
// แสดงค่าที่วัดได้บน Serial Monitor
Serial.println(duration);
// หน่วงเวลาเล็กน้อย
delay(500);
}
ในตัวอย่างนี้ เมื่อ pulseIn(7, HIGH)
ถูกเรียกใช้งาน Arduino จะ:
- รอให้ขา 7 กลับมาเป็น LOW (เพื่อล้างสถานะก่อนหน้านี้)
- รอให้ขา 7 เปลี่ยนเป็น HIGH (เริ่มจับเวลา)
- รอจนกระทั่งขา 7 เปลี่ยนเป็น LOW (หยุดจับเวลา)
- ส่งค่าระยะเวลา (หน่วยไมโครวินาที) ออกมาในตัวแปร
duration
จากนั้นเราจะพิมพ์ค่าดังกล่าวลง Serial Monitor ซึ่งเราก็จะได้เห็นตัวเลขเป็นไมโครวินาที ถ้าเราลองเอา Generator หรือสัญญาณ PWM เข้าไป ก็จะเห็นค่าที่แตกต่างกันไปตามความกว้างของพัลส์
6. ข้อควรระวังเมื่อใช้ pulseIn()
-
การ Block การทำงานของโค้ด (Blocking Function)
ขณะที่pulseIn()
กำลังทำการตรวจจับพัลส์ ฟังก์ชันจะ “หยุด” (หรือ block) การทำงานของโปรแกรมในส่วนอื่น ๆ ชั่วคราว ซึ่งถ้าโครงงานของเราจำเป็นต้องทำงานหลายอย่างพร้อมกัน (Multitasking) การใช้pulseIn()
อย่างไม่ระวังอาจทำให้โค้ดส่วนอื่นไม่ทำงานได้ ควรตั้งค่าtimeout
ให้เหมาะสมเพื่อหลีกเลี่ยงปัญหานี้ -
สัญญาณที่เข้ามาไม่เสถียร
สัญญาณที่มี Noise หรือมีสัญญาณกวนอื่น ๆ อาจส่งผลให้pulseIn()
จับเวลาได้ไม่ถูกต้อง วิธีแก้ไขคือการใช้ตัวเก็บประจุ (Capacitor) หรือฟิลเตอร์อื่น ๆ ร่วมด้วย หรืออาจต้องเขียนโค้ดกรองสัญญาณที่ไม่ต้องการ -
การขาดการอ่านพัลส์เล็ก ๆ ระหว่างรอ
ถ้าพัลส์ที่เข้ามามีความถี่สูงมากและมีความกว้างพัลส์สั้นpulseIn()
อาจตรวจไม่เจอขึ้นอยู่กับจังหวะที่ฟังก์ชันเริ่มอ่าน เพราะมันจะต้องรอเหตุการณ์เปลี่ยนสถานะก่อนหน้าด้วย ถ้าพัลส์สั้นเกินไปอาจหลุดไปได้ การใช้ฟังก์ชันแบบ interrupt หรือใช้ฮาร์ดแวร์จับเวลา (Timer) อาจเหมาะสมกว่า -
มองหา Library อื่นหรือฮาร์ดแวร์เสริมในกรณีที่ต้องการวัดหลายช่องพร้อมกัน
pulseIn()
ออกแบบมาให้ใช้งานกับช่องสัญญาณเดียวในช่วงเวลาเดียว หากต้องการวัดพัลส์หลาย ๆ เส้นสัญญาณพร้อมกัน อาจต้องหาไลบรารีภายนอก หรือใช้ไมโครคอนโทรลเลอร์ที่มี Input Capture Unit เพื่อทำให้ไม่สูญเสียการจับพัลส์
7. การประยุกต์ใช้งาน pulseIn()
ในโครงงานต่าง ๆ
เมื่อเข้าใจพื้นฐานแล้ว เรามาดูว่าโครงงานที่นิยมใช้งาน pulseIn()
มีอะไรบ้าง เพื่อให้เห็นภาพชัดเจนขึ้น
7.1 การวัดระยะทางด้วย Ultrasonic Sensor (HC-SR04)
เซนเซอร์อัลตราโซนิกอย่าง HC-SR04 ใช้หลักการปล่อยคลื่นเสียงความถี่สูง และรับสัญญาณที่สะท้อนกลับมา เพื่อนำระยะเวลาที่คลื่นเดินทางไป-กลับ มาคำนวณเป็นระยะทาง ในกระบวนการนี้:
- Arduino จะส่งสัญญาณ Trigger (สูง 10 ไมโครวินาที) ไปยังขา TRIG ของเซนเซอร์
- เซนเซอร์จะปล่อยคลื่นเสียง และเมื่อคลื่นสะท้อนกลับ เซนเซอร์จะส่งสัญญาณพัลส์ HIGH ออกมาที่ขา ECHO
- ความยาวของสัญญาณ ECHO จะเป็นตัวระบุระยะเวลาเดินทางไปกลับของคลื่น
- เราสามารถใช้
pulseIn(echoPin, HIGH)
เพื่ออ่านเวลาที่สัญญาณ ECHO อยู่ใน HIGH จากนั้นจึงคำนวณเป็นระยะทางได้
สูตรที่นิยมใช้คือ:
ระยะทาง (เซนติเมตร) = (ระยะเวลา (ไมโครวินาที) / 2)
* (ความเร็วเสียง (340 เมตร/วินาที) * 100 / 1,000,000)
เพราะเราแบ่ง 2 ให้กับเวลาเดินทางไปกลับให้กลายเป็นระยะทางขาเดียว และแปลงหน่วยไมโครวินาทีเป็นวินาที แล้วคูณกับความเร็วเสียง (340 เมตรต่อวินาที) และในที่สุดคูณด้วย 100 เพื่อให้เป็นเซนติเมตร
7.2 การอ่านสัญญาณ IR Remote
รีโมตทีวีหรืออุปกรณ์อื่น ๆ ที่ใช้คลื่นอินฟราเรดส่งข้อมูล มักจะส่งข้อมูลด้วยวิธีการเปิด-ปิด LED อินฟราเรดด้วยความเร็วสูง ส่งเป็นแพตเทิร์นของพัลส์ HIGH และ LOW ที่แตกต่างกันไป การถอดรหัสต้องใช้วิธีการอ่านความยาวของพัลส์ ตัวอย่างการใช้ pulseIn()
คือ:
- ใช้ไดโอด IR Receiver (เช่น TSOP1738) ต่อเข้ากับ Arduino
- เมื่อมีการกดปุ่มที่รีโมต ไดโอดจะส่งสัญญาณเป็นพัลส์ดิจิทัลออกมา
- Arduino สามารถใช้
pulseIn()
จับช่วงเวลาของแต่ละพัลส์ได้ แล้วนำมาเทียบกับค่ามาตรฐานของโปรโตคอล (เช่น NEC, RC5) เพื่อถอดออกมาเป็นหมายเลขปุ่ม
อย่างไรก็ตาม ในงานถอดรหัส IR Remote โดยทั่วไปอาจนิยมใช้ไลบรารีสำเร็จรูป เช่น “IRremote” เพื่อความสะดวก แต่การใช้ pulseIn()
ตรง ๆ ก็เป็นวิธีศึกษาพื้นฐานได้ดี
7.3 การวัดความกว้างพัลส์ PWM สำหรับวัดค่า Duty Cycle
ถ้าเรามีพัลส์ PWM ที่สร้างจากแหล่งสัญญาณภายนอก แล้วเราต้องการทราบ “Duty Cycle” ว่าเป็นกี่เปอร์เซ็นต์ เราสามารถทำได้โดยอ่านเวลาที่สัญญาณอยู่ใน HIGH และอ่านเวลาที่สัญญาณอยู่ใน LOW จากนั้นคำนวณค่า Duty Cycle = (เวลาสัญญาณ HIGH) / (คาบทั้งหมด) * 100
highTime = pulseIn(pin, HIGH);
lowTime = pulseIn(pin, LOW);
totalTime = highTime + lowTime;
dutyCycle = ((float)highTime / (float)totalTime) * 100.0;
ค่าที่ได้ก็จะเป็นเปอร์เซ็นต์ Duty Cycle ของ PWM นั้น ๆ
8. ตัวอย่างโครงงานด้วย pulseIn()
: สร้างเครื่องวัดระยะทางอัตโนมัติด้วย HC-SR04 และแสดงผลบนจอ LCD

8.1 อุปกรณ์ที่ต้องใช้
- Arduino UNO (หรือบอร์ดที่เข้ากันได้)
- Ultrasonic Sensor รุ่น HC-SR04
- จอ LCD 16×2 (พร้อมตัวปรับไฟแบคไลท์และตัวต้านทานถ้าจำเป็น)
- สาย Jumper สำหรับการต่อวงจร
- Breadboard (ถ้ามี)
8.2 การต่อวงจร
- HC-SR04 จะมีขา VCC, Trig, Echo, GND
- VCC ต่อกับ 5V ของ Arduino
- GND ต่อกับ GND ของ Arduino
- Trig ต่อกับ Digital Pin (เช่น 8)
- Echo ต่อกับ Digital Pin (เช่น 9)
- การใช้งานจอ lcd1602 ด้วยวงจร bus i2c ให้ทำการต่อดังนี้ :
- Vcc -> 5v
- Gnd -> Gnd
- SCL -> A5
- SDA -> A4
8.3 โค้ดตัวอย่าง
#include <LCD_I2C.h>
// ประกาศตัวแปรแบบ object ชื่อว่า lcd
//กำหนดคอนสตั๊กพารามิเตอร์สามตัวคือ ตำแหน่งแอดเรด, คอลัม, แถว
LCD_I2C lcd(0x27, 16, 2);
// กำหนดพินสำหรับ Ultrasonic
const int trigPin = 8;
const int echoPin = 9;
// ตัวแปรสำหรับเก็บเวลาและระยะทาง
long duration;
float distance;
void setup() {
// กำหนดโหมดพิน
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
// เริ่มการสื่อสารกับ Serial Monitor
Serial.begin(9600);
// เริ่มการทำงานของ LCD
lcd.begin();
lcd.print("Ultrasonic!");
}
void loop() {
// เคลียร์หน้าจอ LCD ก่อนพิมพ์ข้อมูลใหม่
lcd.clear();
// 1. สั่งให้ TRIG เป็น LOW สักระยะเพื่อเคลียร์ค่าสะสม
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// 2. ยิงพัลส์สูง 10us เพื่อสั่งให้ HC-SR04 ส่งคลื่นอัลตราโซนิก
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// 3. วัดระยะเวลาที่ ECHO เป็น HIGH ด้วย pulseIn()
duration = pulseIn(echoPin, HIGH);
// 4. คำนวณระยะทางเป็นเซนติเมตร
// ความเร็วเสียงประมาณ 340 m/s หรือ 29.412 uS/cm ไป-กลับ
distance = (duration * 0.0343) / 2;
// พิมพ์ค่าลงใน Serial Monitor (Debug)
Serial.print("Distance (cm): ");
Serial.println(distance);
// พิมพ์ค่าลง LCD
lcd.setCursor(0, 0);
lcd.print("Distance:");
lcd.setCursor(0, 1);
lcd.print(distance);
lcd.print(" cm");
// หน่วงเวลาซักครู่
delay(500);
}
การทำงานของโค้ด
- เราเคลียร์ TRIG เป็น LOW ก่อน เพื่อป้องกันสัญญาณค้าง
- ส่งพัลส์ HIGH ระยะเวลา 10 ไมโครวินาทีไปที่ TRIG
- รอและอ่านค่าที่ ECHO เป็น HIGH ด้วย
pulseIn(echoPin, HIGH)
- เอา
duration
ที่ได้ (หน่วยไมโครวินาที) ไปคำนวณเป็นระยะทางด้วยสูตร - แสดงผลบน Serial และบน LCD
เท่านี้ Arduino ก็ทำหน้าที่เหมือนเป็นมิเตอร์วัดระยะทาง เล็งเซนเซอร์ไปที่สิ่งกีดขวาง ก็จะได้ระยะห่างขึ้นมา และเราใช้ pulseIn()
เป็นแกนหลักในการวัดเวลาที่ ECHO เป็นพัลส์ HIGH
9. เทคนิคและเคล็ดลับเพิ่มเติม
-
การตั้งค่า Timeout
หากพบว่าโค้ดของเราค้างหรือช้าเกินไป เพราะบางครั้งวัตถุอาจอยู่ไกลจนสัญญาณสะท้อนไม่กลับมา ลองตั้งค่าtimeout
ในpulseIn(echoPin, HIGH, 30000)
(30 ms) หรือค่าน้อยกว่าที่เหมาะสมกับระยะสูงสุดที่ต้องการวัด -
ความไวของการวัด (Resolution)
ค่าที่pulseIn()
คืนให้เป็นไมโครวินาที ความละเอียดการวัดจึงขึ้นอยู่กับความเร็วสัญญาณของ Arduino และฟังก์ชัน โดยทั่วไปเพียงพอสำหรับงานที่ไม่ต้องการความละเอียดสูงมาก แต่ถ้าเราต้องวัดพัลส์ระดับนาโนวินาที อาจต้องหาวิธีอื่นที่แม่นยำกว่า -
การวัดหลายครั้งเพื่อค่าเฉลี่ย
หากพบว่าสัญญาณแกว่งไม่เสถียร สามารถทำ Loop อ่านหลาย ๆ ครั้ง แล้วหา “ค่าเฉลี่ย” เพื่อลด Noise ได้ เช่น อ่าน 5 ครั้งแล้วเอาค่ามาบวกกันหาร 5 เป็นต้น -
การจัดการสัญญาณรบกวน
ถ้าใช้สายยาวหรือมีอุปกรณ์อื่นรบกวน บางครั้งการวัดอาจผิดเพี้ยนได้มาก ควรออกแบบวงจรให้สั้นที่สุด หรือใช้สาย Shield หรือกรอง Noise ทางฮาร์ดแวร์ -
หลีกเลี่ยงการใช้
pulseIn()
ในระบบ Multitasking
ถ้าต้องการรันโค้ดหลายส่วนพร้อมกัน (เช่น ควบคุมมอเตอร์หมุน ตอบสนองเซนเซอร์หลายตัว) การใช้pulseIn()
อาจไม่ตอบโจทย์เพราะมันเป็น Blocking Function อาจต้องใช้การ Interrupt หรือใช้ Hardware Timer แทน
10. เล่าเรื่องความรู้สึกและประสบการณ์การใช้งาน
การใช้งาน pulseIn()
เป็นจุดเริ่มต้นที่ทำให้เราเข้าใจธรรมชาติของการรับ-ส่งสัญญาณดิจิทัลอย่างเรียบง่าย แต่เปี่ยมด้วยพลัง ใครหลายคนอาจมองว่ามันเป็นฟังก์ชันเล็ก ๆ ไม่มีอะไรซับซ้อน แต่แท้จริงแล้วมันเป็นเหมือนกระจกที่สะท้อนให้เห็นว่า สัญญาณดิจิทัลที่ไหลผ่านขา I/O ของไมโครคอนโทรลเลอร์นั้น เต็มไปด้วยข้อมูลที่มีค่าสำหรับโครงงานมากมาย
ความน่าสนใจอย่างหนึ่งของการใช้ pulseIn()
ก็คือ “ผลลัพธ์ที่จับต้องได้” เมื่อเราได้เห็นตัวเลขบน Serial Monitor หรือบนจอ LCD ที่เปลี่ยนแปลงไปตามการขยับหรือสิ่งกีดขวางที่ผ่านหน้าตัวเซนเซอร์ หรือได้เห็นค่าดิวตี้ไซเคิลของ PWM ที่เปลี่ยนไปแบบเรียลไทม์ มันสร้างความรู้สึกภูมิใจว่า “เรากำลังทำให้ Arduino เข้าใจและสื่อสารกับสัญญาณได้”
แต่ก็ต้องยอมรับว่า pulseIn()
ไม่ได้เหมาะกับทุกบริบท เมื่อโครงงานของเราเริ่มขยายตัว มีการอ่านเซนเซอร์หลาย ๆ ตัวพร้อมกัน หรือมีการเชื่อมต่ออุปกรณ์สื่อสารภายนอกที่ต้องตอบสนองรวดเร็ว ฟังก์ชัน pulseIn()
อาจกลายเป็นข้อจำกัดได้ เพราะมันบล็อกโปรแกรมจนกว่าจะจับพัลส์เสร็จ แต่ในโปรเจกต์ขนาดเล็กหรือการเรียนรู้เบื้องต้น มันยังคงเป็นอาวุธลับที่ช่วยให้ชีวิตการเรียนรู้ Arduino ง่ายขึ้นมาก
ในมุมมองของผม การได้สัมผัส pulseIn()
เป็นครั้งแรกก็คล้ายกับการได้เข้าไปสู่วงการเรียนรู้ไมโครคอนโทรลเลอร์ในเชิงสัญญาณดิจิทัล เพราะหลังจากนั้นไม่นาน ผมก็ได้ทดลองวัดสัญญาณอย่างอื่น ๆ ไม่ว่าจะเป็นสัญญาณจากเซนเซอร์วัดความเร็วลม สัญญาณ IR Remote รวมถึงใช้ตรวจจับการเต้นของชีพจร (ผ่านวงจรเซนเซอร์ชีพจรง่าย ๆ) ซึ่งทำให้ผมรู้สึกว่าศักยภาพของ Arduino นั้นกว้างมาก ต่อไปจะสร้างโปรเจกต์ที่จริงจังยิ่งขึ้น ก็แค่มองหาวิธีต่อยอดจากสิ่งที่ได้เรียนรู้จาก pulseIn()
นี้
11. การต่อยอด และปรับปรุง
หากเราสนใจขยายต่อจากโครงงานที่ใช้ pulseIn()
หรืออยากจะปรับปรุงโปรแกรมของตัวเอง มีแนวทางหลายอย่างที่สามารถทำได้ เช่น
-
ใช้ Interrupt
หากไม่ต้องการให้โค้ดค้าง เมื่อมีการเปลี่ยนสถานะของสัญญาณจึงค่อยเรียกฟังก์ชัน ให้ Arduino ทำอย่างอื่นไปเรื่อย ๆ จนกว่าจะถึงเวลาต้องอ่านค่า แต่รูปแบบการใช้งานจะซับซ้อนขึ้น -
ผสาน
pulseIn()
เข้ากับ IoT
หากต้องการส่งค่าการวัดสัญญาณพัลส์ขึ้น Cloud หรือ SmartPhone อาจเพิ่มโมดูล WiFi (ESP8266, ESP32) หรือโมดูล Bluetooth ให้ Arduino ส่งข้อมูลแบบไร้สาย -
วัดหลายพัลส์พร้อมกัน (Multi-channel)
เราอาจนำแนวคิดการวัดพัลส์ด้วยการเวียนสลับพินไปมา หรืออาจเลือกใช้บอร์ดที่มีทรัพยากรมากกว่า หรือมีไลบรารีเสริม เพื่อจับพัลส์หลาย ๆ ช่องพร้อมกัน -
ปรับใช้กับสัญญาณเฉพาะทาง
ถ้าสัญญาณที่ต้องวัดมีรูปแบบพิเศษ เช่น โค้ดส่งข้อมูลหลายบิตผ่านพัลส์ ลองเขียนโค้ดวิเคราะห์ค่าเวลาทีละช่วงเพื่อถอดรหัสข้อมูล นี่เป็นอีกด่านหนึ่งที่ท้าทายและสนุกมาก
บทสรุป: pulseIn()
กับพลังที่มากกว่าแค่ฟังก์ชันอ่านสัญญาณ
ถึงแม้ pulseIn()
จะเป็นฟังก์ชันสั้น ๆ ใน Arduino IDE แต่มันเป็นกุญแจดอกหนึ่งที่เปิดประตูให้เราสามารถวัด “ความยาว” ของสัญญาณดิจิทัลได้อย่างง่ายดาย งานใดก็ตามที่ต้องมีการวัดช่วงเวลาและสัญญาณ HIGH/LOW ไม่ว่าจะเป็นงานวัดระยะทาง, ควบคุมมอเตอร์, การรับข้อมูลดิจิทัลเชิงเวลา ฯลฯ pulseIn()
สามารถเป็นตัวช่วยให้เราเริ่มต้นได้ดี
ในโครงงานต้นแบบที่เราได้ยกตัวอย่างเครื่องวัดระยะทางด้วย HC-SR04 นั้นก็เห็นได้ว่าเพียงใช้ pulseIn()
ไม่กี่บรรทัด เราก็ได้โค้ดที่มีประโยชน์อย่างจริงจัง ใช้ในชีวิตประจำวันหรือต่อยอดไปเป็นหุ่นยนต์ตรวจจับสิ่งกีดขวางก็ยังได้
นอกจากนั้น องค์ความรู้จากการใช้ pulseIn()
ยังเสริมรากฐานในด้านการวัดสัญญาณดิจิทัลและเวลา เพราะเราจะเริ่มเข้าใจอย่างลึกซึ้งว่า “Arduino ทำงานอย่างไร เมื่อมันเฝ้ารอเปลี่ยนสถานะจาก LOW เป็น HIGH และจาก HIGH กลับมา LOW” นี่คือจุดเริ่มต้นของการต่อยอดอีกมากในศาสตร์ Embedded System เช่น การเขียนโค้ดระดับ Register หรือการใช้งาน Interrupt
ท้ายที่สุด อย่าลืมว่าข้อจำกัดของ pulseIn()
ก็มีอยู่ ไม่ว่าจะเป็นความสามารถในการอ่านได้แค่ช่องสัญญาณเดียวในช่วงเวลาเดียว หรือการที่มันเป็น Blocking Function ที่อาจไม่เหมาะสมในระบบที่ต้องทำงานแบบ Multitask อย่างไรก็ตาม สิ่งเหล่านี้ไม่ใช่อุปสรรคแต่เป็นโอกาสให้เราได้เข้าใจสถาปัตยกรรมของไมโครคอนโทรลเลอร์เชิงลึก และพร้อมจะขยับไปเรียนรู้การใช้งาน Timer/Counter, Input Capture หรืออินเตอร์รัปต์ต่อไป
สรุป
- ฟังก์ชัน
pulseIn()
คือเครื่องมือเบื้องต้นแต่ทรงพลังในการวัดระยะเวลาของสัญญาณดิจิทัล (HIGH/LOW) - เหมาะสำหรับโครงงานเล็กถึงปานกลางที่ต้องการวัดช่วงพัลส์ เช่น Ultrasonic Sensor, IR Remote, PWM Analysis
- ควรระวังเรื่อง Blocking และตั้งค่า Timeout เพื่อไม่ให้โค้ดค้าง
- สามารถปรับแต่งหรือขยายไปสู่โครงงาน IoT, Multiple Sensors หรือระบบซับซ้อนขึ้นได้
เมื่อลองนำไปใช้งานจริง ๆ เราจะค้นพบว่าการวัดพัลส์คือความสนุกอย่างหนึ่ง คล้ายกับการไขปริศนาแห่งคลื่นสัญญาณ เมื่อวัดเวลาได้ เราก็สามารถแปลงเป็นข้อมูล มีประโยชน์ต่อการควบคุมหรือวิเคราะห์ต่าง ๆ ได้อย่างมหาศาล
ปิดท้าย: ก้าวต่อไปหลังจากรู้จัก pulseIn()
หลังจากเราได้ทดลองและสนุกกับ pulseIn()
จนเข้าใจดีแล้ว ลองตั้งคำถามต่อว่า “โครงงานของเราต้องการประสิทธิภาพมากกว่านี้ไหม?” “เราจำเป็นต้องวัดหลายช่องสัญญาณพร้อมกันหรือไม่?” หากคำตอบคือใช่ เราจะพบว่ามันถึงเวลาที่ต้องศึกษาเรื่อง Timer Hardware และ Input Capture ซึ่งเป็นวิธีระดับล่าง (Low-level) ที่สามารถจับเวลาสัญญาณได้แม่นยำและไม่บล็อกโปรแกรม หรืออาจศึกษาเรื่องการใช้ External Interrupt เพื่อตรวจจับสัญญาณเปลี่ยนสถานะ
แต่ถ้าเราต้องการเพียงวัดพัลส์เป็นระยะ ๆ และไม่มีเงื่อนไขความแม่นยำหรือความเร็วที่สูงมาก pulseIn()
นั้นเพียงพอและประหยัดทรัพยากรสุด ๆ เพียงแค่เราวางแผนการเรียกใช้อย่างระมัดระวัง (ไม่วางในลูปที่สำคัญเกินไปหรือนานเกินไป) และตั้ง timeout
เสมอ ก็จะทำให้โค้ดของเราทำงานได้อย่างมีประสิทธิภาพ