Lab 5.1 – เทคนิค Pulse Width Modulation (PWM)
โจทย์
ให้นักศึกษาเขียนโปรแกรมควบคุมความสว่างของ LED
- เมื่อเริ่มโปรแกรม LED จะดับอยู่
- ทุกครั้งที่ผู้ใช้กดปุ่ม Run จะทำให้ LED ค่อยๆ สว่างขึ้น (มีอย่างน้อย 5 ระดับ)
แนะนำ PWM เบื้องต้น
การควบคุมพลังงานที่ส่งออกไปยังอุปกรณ์ที่ต้องการควบคุม เช่น ความแรงมอร์เตอร์ ความสว่างของไฟ LED โดยปกติหมายถึงการลดแรงดันที่ส่งออกไปยังมอร์เตอร์ แต่การลดแรงดันนั้นเป็นแนวทางที่ต้องใช้วงจรที่ซับซ้อนมีความยุ่งยากค่อนข้างมาก ดังนั้นโดยทั่วไปจึงนิยมใช้เทคนิคที่เรียกว่า Pulse Width Modulation (PWM) ซึ่งไม่ได้ลดแรงดัน หากแต่ใช้หลักการเปิด/ปิดมอร์เตอร์ด้วยความเร็วสูงๆ จนผลค่าเฉลี่ยของแรงดันที่ได้ออกมาเทียบเท่ากับการเปลียนแรงดันโดยตรง เทคนิคนี้ทำให้ไม่ต้องใช้วงจรซับซ้อน แต่การเขียนโปรแกรมจะยุ่งยากขึ้นบ้าง
PWM นั้นโดยทั่วไปจะมีการสร้างลูกคลื่นสี่เหลี่ยม (Square Wave) ออกมาโดยกำหนดคาบของสัญญาณ (Period) ให้สั้นๆ ซึ่งปกติคาบจะจะมีค่าไม่เกิน 33 ms (30 Hz) สำหรับการทดลองทั่วไป และอาจมีค่าน้อยถึง 0.01 ms (100KHz) หรือน้อยกว่าในงานอุตสาหกรรมบางชนิด หลักการสำคัญของ PWM คือการปรับเปลี่ยนความกว้างของลูกคลื่นในแต่ละคาบ โดยถ้าลูกคลื่นสั้นก็จะทำให้แรงดันเฉลี่ยที่ออกมามีค่าน้อย และถ้าลูกคลื่นยาวแรงดันเฉลี่ยก็จะมีค่ามากขึ้น จากรูปด้านล่าง V เฉลี่ย (เส้นสี่ส้ม) จะสูงหรือต่ำนั้นขึ้นอยู่กับความกว้างของลูกคลื่น ซึ่งความกว้างของลูกคลื่นนี้เรียกว่า pulse width หรือ Duty Cycle
Pulse width จะต้องน้อยกว่าค่าความยาวคาบเสมอ Duty Cycle จะมีหน่วยเป็น % ของความยาวคาบ เช่น ถ้าคาบ = 10ms และ Duty Cycle = 40% นั่นหมายความว่า Pulse width = 10ms * 0.4 = 4 ms เป็นต้น
Algorithm การสร้าง PWM โดยใช้ Timer Interrupt
ตัวแปรที่สำคัญมีดังนี้
- PWM Period = คาบของสัญญาณคลื่นที่สร้างขึ้น
- Interrupt Period = คาบของ Timer Interrupt ซึ่งจะเท่ากับความกว้างของลูกคลื่นที่เล็กที่สุด
- Pulse Width = ค่าความกว้างของลูกคลื่นที่ต้องการ โดยในตัวอย่างแบ่งเป็น 6 ระดับ ตั้งแต่ 0-5
- กำหนดความถี่ของสัญญาณ PWM ที่เหมาะสมสำหรับการขับ LED – โดยความถี่ยิ่งสูงก็จะยิ่งทำให้ LED ที่แสดงผลเนียนเรียบ (ไม่กะพริบ) ซึ่งแลกด้วยภาระการทำงานของ CPU ที่หนักขึ้น โดยทั่วไป PWM สำหรับ LED ไม่ควรน้อยกว่า 30 Hz แต่ถ้าให้เนียนจริงๆ ก็จะเป็น 100 Hz ขึ้นไป
- ใช้ Timer Interrupt สร้าง PWM – ดังรายละเอียดต่อไปนี้
- Duty Cycle ต้องการกี่ระดับ – Algorithm นี้จะกำหนด Duty Cycle เป็นจำนวนระดับ เช่น ถ้ากำหนดว่า 5 ระดับ ก็เท่ากับบอกว่า Duty Cycle ที่จะใช้ได้คือ 0%, 25%, 50%, 75%, 100%
- ตั้งค่า Timer ให้คาบของ Interrupt (Interrupt Period) มีค่าเท่ากับความกว้างของ pulse ที่เล็กที่สุด (ระยะเวลาระหว่างเส้นประในรูป) เช่นในตัวอย่างข้างต้น ถ้าคาบของ PWM (PWM Period) = 10 ms
ค่า Interrupt Period ก็จะกว้าง = 10/5 = 2 ms (ข้อสังเกต! คาบของ Timer Interrupt เป็นคนละตัวกับคาบของ PWM) - สร้างตัวแปรไว้สองตัว คือ
- dutyCycle – จะเก็บค่า duty ของสัญญาณ PWM เช่นถ้ากำหนดว่ามี 6 ระดับ (ดังใน diagram ข้างต้น) ค่าตัวแปรนี้เทียบกับ duty จะเป็นดังนี้
- 0 = 0%
- 1 = 20%
- 2 = 40%
- 3 = 60%
- 4 = 80%
- 5 = 100%
ในภาพไดอะแกรมตัวอย่าง dutyCycle = 3 หรือ 60%
- interruptCounter – มีค่าเริ่มต้นเป็น 0 และจะเพิ่มค่าทุกครั้งที่เกิด Timer Interrupt ถ้า interrupt ครบ 6 ครั้ง ค่านี้จะถูก set กลับไปเป็น 0
- dutyCycle – จะเก็บค่า duty ของสัญญาณ PWM เช่นถ้ากำหนดว่ามี 6 ระดับ (ดังใน diagram ข้างต้น) ค่าตัวแปรนี้เทียบกับ duty จะเป็นดังนี้
ทุกครั้งที่เกิด Interrupt ให้ทำการตรวจสอบดังนี้
โครงสร้างคร่าวๆ ของโปรแกรมอาจเป็นดัง psudocode นี้
Int_timer1() { interruptCounter++; // ติดตามว่านี่เป็น timer interrupt ครั้งที่เท่าใดในรอบ pwm period if (interruptCounter == 5) { // ถ้า interrupt นี้เป็นครั้งสุดท้ายของรอบ pwm period interruptCounter = 0; } // reset ค่าตัวนับสำหรับ pwm period รอบถัดไป if (dutyCycle > 0) {output_high(); } // output high เพื่อเริ่มต้นคลื่น PWM ลูกใหม่ ยกเว้นถ้า duty =0 } If (interruptCounter == dutyCycle) {output_low();} // ถ้านับถึง dutyCycle ก็ output low เพื่อให้ได้ duty ตามระดับที่กำหนดไว้ } Main () { interruptCounter = 0; dutyCycle = 3; While(1); }
ดูตัวอย่างการทำงานในรูปแบบ Animation ได้ที่นี่
Click to view