กรณีที่1
เมื่อตรวจพบสัญญาณขาเข้าเป็น HIGH ฟังก์ชันนี้จะเริ่มนับเวลาในหน่วยไมโครวินาที (microsec, $\mu$s) และรอจนกว่าจะเจอสัญญาณ LOW ถึงจะหยุดนับเวลา
กรณีที่2 กำหนดให้ตรวจสัญญาณ LOW ก่อน ฟังก์ชันนี้จะเริ่มนับเวลาในหน่วยไมโครวินาที และรอจนกว่าจะเจอสัญญาณ HIGH ถึงจะหยุดนับเวลา
รูปที่1 แสดงสัญญาณคลื่นสี่เหลี่ยม (square wave) และตรวจวัดสัญญาณ HIGH ---> LOW และ ตรวจวัดสัญญาณ LOW ---> HIGH
สรุปได้ว่าฟังก์ชัน pulseIn ทำหน้าที่เป็นนาฬิกาจับเวลาโดยใช้สัญญาณ LOW หรือ HIGH เป็นตัวกำหนด start/stop นั่นเอง
ฟังก์ชัน pulseIn มีรูปแบบการใช้งาน (https://www.arduino.cc/en/Reference/PulseIn)
Syntax
1) ===> pulseIn(pin, value)
2) ===> pulseIn(pin, value, timeout)
pin คือ กำหนดสัญญาณเข้าไหน เช่น ขา digital3, pin คือ 3
value คือ พารามิเตอร์ที่เรากำหนดให้บอร์ดตรวจวัดสัญญาณ HIGH หรือ LOW ก่อน (กำหนดให้เริ่มนับเวลาดังกล่าวข้างต้น)
timeout คือช่วงเวลาสูงสุดที่ฟังก์ชันนี้ยังทำงานอยู่ หากไม่กำหนดพารามิเตอร์นี้ เช่นกรณีแรกจะกำหนด default ไว้ที่ 1 วินาที หรือ 1,000,000 ไมโครวินาที นั่นหมายความว่าถ้าความกว้างเพาส์สัญญาณที่จะวัดมากกว่า 1 วินาที ฟังก์ชันนี้จะไม่ทำงานและส่งค่า 0 ออกมาแทน ดังนั้นหากต้องการกำหนดให้ timeout สูงสุด 5 วินาที จะเขียนได้ว่า
pulseIn(3, HIGH, 5000000)
ตัวอย่างการใช้งาน และแสดงผลทาง serial communication
int pin = 3;
unsigned long duration;
void setup()
{
// initialize serial communications at 9600 bps:
Serial.begin(9600);
pinMode(pin, INPUT);
}
void loop()
{
duration = pulseIn(pin, HIGH, 10000000);
float time=duration/1000.00;
Serial.print("DelT=");
Serial.print(time);
Serial.println(" ms");
}
ตัวอย่างการใช้งานและแสดงผลทางจอ LCD
#include
int pin = 3;
unsigned long duration;
void setup()
{
lcd.begin(16, 2);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("UP VeloMeterV1.0");
delay(2500);
pinMode(pin, INPUT);
}
void loop()
{
duration = pulseIn(pin, HIGH, 10000000);
float time=duration/1000.00;
lcd.setCursor(0, 1);lcd.print("DelT= ms");
lcd.setCursor(6, 1);lcd.print(time);
}
ก่อนจะทดสอบกับอุปกรณ์จริงขอทำการจำลองในโปรแกรมก่อน ในภาพใช้สวิทซ์เป็นเพื่อกำหนดสัญญาณ HIGH เมื่อสวิทซ์ on และเป็น LOW เมื่อสวิทซ์ off ได้ผลลัพธ์ดังภาพ โดยต่อสัญญาณเข้าที่ขา digital 3 จากรูปกำหนดแกนเวลาใน oscilloscope เป็น 0.5 s/div หากอ่านค่าเวลาเทียบกับตัวเลขที่ได้จากฟังก์ชัน pulseIn ที่แสดงในจอ LCD สอดคล้องกันเป็นอย่างดี ดังนั้นการทดสอบครั้งนี้ถือว่าบรรลุวัตถุประสงค์ขั้นต้น
รูปที่2 ภาพการจำลองการวัดความกว้าง pulse ในโปรแกรม proteus ด้วยฟังก์ชัน pulseIn ใน Arduino โดยวัดเวลาที่กดสวิทซ์
ลำดับต่อไปจะทดสอบกับอุปกรณ์จริงโดยใช้ function generator (GWINSTEK รุ่น SFG-1013) เป็นเครื่องกำเนิดสัญญาณคลื่นสี่เหลี่ยมความถี่ต่างๆ เพื่อทดสอบความถูกต้อง (accuracy) และความแม่นยำ (precise) จากนั้นใช้ oscilloscope (Tektronix รุ่น TDS-1002) เพื่อวัดความกว้างเพาส์ (pulse width) เทียบกับฟังก์ชัน pulseIn ของ Arduino เพื่อให้เห็นภาพที่ชัดเจนขึ้นขออธิบายเกี่ยวสัญญาณสี่เหลี่ยมและการคำนวณเล็กน้อย
เวลาที่คลื่นเคลื่อนที่ครบ 1 รอบ เรียกว่า คาบการเคลื่อนที่ หรือ period มักใช้สัญลักษณ์เป็น "T" มีหน่วยเป็น วินาที ปริมาณที่เป็นส่วนกลับของคาบเรียกว่า ความถี่ หรือ frequency มักใช้สัญลักษณ์เป็น "f" มีหน่วยเป็น รอบต่อวนาที หรือ Hertz (Hz) หรือจะกล่าวว่าความถี่กำลังบอกว่า ใน 1 วินาที คลื่นเคลื่อนที่ผ่านจุดใดจุดหนึ่งไปกี่ลูกนั่นเองเขียนความสัมพันธ์ทางคณิตศาสตร์ ระหว่าง T กับ f ได้เป็น
$T=\frac{1}{f}$
สำหรับคลื่นสี่เหลี่ยมมีค่า ดิวตี้ไซเคิล (duty cycle) 50 % ดังภาพด้านล่างนั้น คลื่น 1 ลูกจะประกอบด้วยสัญญาณค่าสูงครึ่งหนึ่ง และอีกครึ่งหนึ่งเป็นสัญญาณค่าต่ำ หรือกล่าวได้ว่าความกว้างของเพาส์สัญญาณสูงเท่ากับความกว้างเพาส์สัญญาณต่ำ สมมติสัญญาณสี่เหลี่ยมมีความถี่ 50 Hz คาบการเคลื่อนที่ T คำนวณได้ดังนี้
$T=\frac{1}{50\, Hz}=0.02\, s=20\, \, ms$
ดังนั้น pulse width จะเท่ากับ 10 ms
รูปที่ 3 แสดงคลื่นสี่เหลี่ยมและความกว้างสัญญาณ (ภาพจาก www.electronics-tutorials.ws)
ในการทดสอบครั้งนี้จะอ่านค่า ความกว้างเพาส์ในหน่วย มิลลิวินาที และขอยกตัวอย่างมาให้เห็นเพียงสองความถี่ คือ 5 และ 25 Hz รูปที่ 4 แสดงความถี่ของสัญญาณสี่เหลี่ยมที่ตั้ง 25 Hz (รูปที่4 ก) รูปสัญญาณและความกว้างเพาส์จากออสซิลโลสโคป (รูปที่4 ข) และค่าความกว้างเพาส์ที่อ่านได้จาก Arduino (รูปที่4 ค) จากการทดลองพบว่า Arduino อ่านค่าความกว้างเพาส์ได้สอดคล้องกับการคำนวณและค่าที่อ่านได้จากออสซิลโลสโคป เป็นอย่างดี
รูปที่ 4 แสดงความถี่ รูปสัญญาณ และความกว้างเพาส์ที่ความถี่ 25 Hz
สำหรับที่ความถี่ต่ำ พบว่าค่าที่อ่านได้จาก Arduino ไม่ตรงกับผลการคำนวณและค่าที่อ่านได้จากออสซิลโลสโคป ซึ่งความผิดเพี้ยนส่วนนี้จะได้ทำการทดลองและทดสอบต่อไปเพื่อหาความคลาดเคลื่อนที่เกิดขึ้น
รูปที่ 5 แสดงความถี่ รูปสัญญาณ และความกว้างเพาส์ที่ความถี่ 5 Hz
เมื่อทดสอบวัดความกว้างเพาส์เพื่อนำมาเทียบกับผลการคำนวณเชิงทฤษฎี ได้ผลลัพธ์ดังนี้พบว่าที่ความถี่สูงขึ้น (กรณีนี้ f สูงกว่า 10 Hz) ฟังก์ชัน pulseIn จะวัดได้ถูกต้อง แสดงดังกราฟด้านล่าง
รูปที่ 6 ภาพซ้ายมือแสดง กราฟระหว่างความกว้างเพาส์ (positive pulse width) กับความถี่ โดยเปรียบเทียบระหว่าง ค่าการคำนวณกับการทดลอง ส่วนภาพด้านขวามือแสดง เปรียบเทียบผลต่างของ pulse width กับความถี่
ภาพที่ 6 บ่งบอกความคลาดเคลื่อนของฟังก์ชัน pulse in พบว่าความถี่ต่ำกว่า 10 Hz จะทำให้ความคลาดเคลื่อนมีค่ามากขึ้น ดังนั้นจากผลการทดลองนี้การอ่านค่าความถี่ต่ำไม่ควรใช้ฟังก์ชัน pulseIn
นอกจากนี้ข้าพเจ้ายังนำ pusleIn ฟังก์ชัน ไปเขียนรวมกับวิธีการส่งข้อมูลไปให้ MS excel มีรายละเอียดของ source code ดังนี้ (การส่งข้อมูลถึง MS excel ลองติดตามในนี้เลย Arduino2Excel)
#include
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
int x = 0;
int row = 0;
int pin = 3;
unsigned long duration;
void setup()
{
Serial.begin(128000); // opens serial port, sets data rate to 9600 bps
Serial.println("CLEARDATA");
Serial.println("LABEL,Time,Index,SensorValueA0");
lcd.begin(16, 2);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("UP VeloMeterV1.0");
delay(2500);
pinMode(pin, INPUT);
}
void loop()
{
row++;
x++;
Serial.print("DATA,TIME");
Serial.print(","); Serial.print(x);
duration = pulseIn(pin, HIGH, 10000000);
float time=duration/1000.00;
Serial.print(","); Serial.println(time);
lcd.setCursor(0, 1);lcd.print("DelT= ms");
lcd.setCursor(6, 1);lcd.print(time);
}
และได้ผลดังภาพด้านล่างนี้ (ส่วนรายละเอียดจะมาเล่าให้ฟังในโอกาสต่อไป)