[ บทความ : ถามตอบ # 2 การหน่วงเวลา ] |
From : Pradit dittawong prasiam@chaiyo.com
Subject : การคำนวณโปรแกรมหน่วงเวลา
Q: สวัสดีครับ อ.ศุภชัย ผมเป็นอีกคนหนึ่งที่ติดตามบทความของ อาจารย์มาตลอดเห็นว่าอาจารย์มีความชำนาญทางด้าน Z - 80 และ MCS - 51 ผมเองเป็นคนชอบระบบพวกนี้อยู่เหมือนกัน ศึกษาอยู่ตลอด แต่มีปัญหาตรงการคำนวณหาค่าหน่วงเวลา อยู่ตลอดเลยทำให้การพัฒนาไปไม่ดีนัก จึงขอความอนุเคราะห์จากอาจารย์ช่วยลงบทความเกี่ยวกับการคำนวณค่าหน่วงเวลา เอาแบบว่าการคำนวณนะครับ ไม่ใช่โปรแกรมที่อาจารย์ลงไว้ เพราะจะได้ดัดแปลงได้ง่ายกว่า ( เอาแบบละเอียดเลยนะครับ )ขอบคุณครับ
A: การหน่วงเวลา
การหน่วงเวลาหรือการ delay นั้น เป็น การเขียนโปรแกรมเพื่อให้หน่วยประมวลผล (Processor หรือ CPU) สูญเสียเวลา โดยที่ไม่ต้องกระทำการใดๆ ในช่วงนั้น (ในระบบปฏิบัติการแบบ Multitasking นั้น ผู้ออกแบบจะแนะนำให้เราทำการ Delay ให้น้อยที่สุด เนื่องจาก ระบบปฏิบัติการต้องการ เอาเวลาว่างจาก โปรแกรมของเรา นั้นไปทำการประมวลผลงานอื่นๆ)
แต่ว่าในบางครั้ง เราหลีกเลื่ยงไม่ได้ (โดยเฉพาะงานควบคุม เรามักไม่ได้เขียนโปรแกรม บนระบบปฏิบัติการ) หรือจำเป็นต้องใช้จริงๆ การ delay ก็กลายเป็นสิ่งจำเป็น เช่น ถ้าเราต้องการหน่วงเวลา 10msec เราจะเขียนได้อย่างไร ... ก่อนที่จะมาดูว่า จะเขียนได้อย่างไร เราต้องมาก่อนว่า เรากำลังใช้งานบนระบบใดอยู่ ...
สิ่งที่เราต้องรู้ก่อนที่จะทำการหน่วงเวลาแบบ มีความเที่ยงตรงสูงๆ คือ
1. คำสั่งในระดับภาษาแอสเซมบลี ว่าทำสั่งใด ใช้ clock เป็นจำนวนเท่าไร ซึ่งบางระบบ ไม่บอกเป็นจำนวน clock แต่บอกเป็น Machine Cycle เราก็ต้องรู้ให้ได้ว่า แต่ละ Machine Cycle นั้นต้องการ clock จำนวนเท่าไรเมื่อตอบคำถามทั้ง 3 ข้อได้แล้ว ก็มาดูล่ะครับ ว่าเราจะใช้คำสั่งอะไรบ้าง จะวนรอบเป็นจำนวนรอบเท่าไร ซึ่งจะเขียนโปรแกรมออกมาหน้าตาอย่างไรนั้น ก็ขึ้นอยู่กับคนเขียนโปรแกรมเลยล่ะครับ ...
2. ระบบที่เราใช้นั้น ทำงานที่ความถี่ของสัญญาณนาฬิกาเท่าไร
3. เวลาที่เราต้องการหน่วงนั้น มีค่าเท่าไร และจำเป็นที่จะต้องเที่ยงตรง มากน้อยเท่าไรแล้วเราทำการวนรอบแบบเที่ยงตรงในภาษาอื่นๆ ที่ไม่ใช่ แอสเซ็มบลี ได้ไหม คำตอบ คือ เราบอกไม่ได้ว่า คำสั่ง ภาษาอื่นๆ นั้น 1 คำสั่ง ใช้เวลาเท่าไร เพราะ มีเงื่อนไขที่เกี่ยวข้องอยู่ด้วยกันหลายอย่าง ยิ่งตัวแปลภาษา ที่เป็นภาษาเดียวกัน แต่ต่างค่าย คำสั่งเดียวกันนั้น ก็ใช้ความเร็วไม่เท่ากันอยู่ดี ดังนั้น การหน่วงเวลา เราเลยเขียนกันในระดับภาษาแอสเซ็มบลี
แต่ปัจจุบันเทคโนโลยีของไมโครโปรเซสเซอร์นั้น ก้าวไปไกลมาก ถึงขนาดที่ว่า ถ้าเราเขียนโปรแกรมให้รัดกุมแล้ว ใน 1 clock ก็สามารถประมวลผลคำสั่งได้หลายคำสั่งเลยทีเดียว นั่น ยิ่งเป็นการบ่งบอกว่า การหน่วงเวลานั้น ต้องออกแบบมาเฉพาะกับ ระบบใดระบบหนึ่งเป็นการเฉพาะเลย เช่น ส่วนของโปรแกรมที่ทำการหน่วงเวลา ได้ 20msec บน MCS-51 (12 clock/1Machine Cycle) ที่ใช้ clock 12MHz พอเราเปลี่ยน มาใช้ P89C51RD2 โปรแกรมก็ใช้ไม่ได้แล้วล่ะ (ข้อแม้คือ เราต้องโปรแกรม P89C51RD2 ทำงานที่ 6 clock/1 Machine cycle) ทั้งนี้เพราะ P89C51RD2 มันเร็วกว่าเดิม ถึง 1 เท่าตัว ...
จากทั้งหมดพอมองออกไหมครับ ว่าเราจะเขียนโปรแกรมหน่วงเวลา (delay) ได้อย่างไร
ตัวอย่างการหน่วงเวลา (MCS51)
จากแนวคิดด้านบน คราวนี้เรามาดูตัวอย่าง การหน่วงเวลา โดยใช้กับ MCS51 กันครับ โปรแกรมตัวอย่างนี้จะใช้กับ MCS51 (ที่ทำงาน 12 clocks/1 machine cycle) และ XTAL 11.0592 MHz โดยจะทดลองหน่วงเวลา 10msec มาเริ่มกันเลยครับ
1 machine cycle = 12 clocks จะได้ว่า 11.0592MHz หรือ 11,059,200 Hz (1 Hz = 1 cycle / sec) สามารถทำงานได้ 11,059,200 / 12 = 921,600 Machine cycles หรือเรียกได้ว่า ใน 1 วินาที สามารถทำงานได้ 921,600 machine cycles 1 sec = 1,000 msec 100 msec = 1/10 sec 10 msec = 1/100 sec 1 msec = 1/1,000 sec 1 sec = 921,600 machine cycles 1,000 msec = 921,600 machine cycles 100 msec = (1/10)*921,600 machine cycles = 92,160 machine cycles 10 msec = (1/100)*921,600 machine cycles = 9,216 machine cycles 1 msec = (1/1,000)*921,600 machine cycles = 921.6 machine cyclesดังนั้น ถ้าเราต้องการหน่วงเวลา 10 msec เราก็ต้อง มีการสูญเสียเวลาของหน่วยประมวลผลไป 9,216 machine cycles แต่ถ้าเราจะทำการหน่วงในระดับ 1 msec ก็จะติดปัญหาทันทีครับว่า 921.6 นั้น มันไม่ลงตัว ... แต่ถ้าเปลี่ยน XTAL เป็น 12MHz ก็จะได้ผลการคำนวณออกมาดังนี้
1 machine cycle = 12 clocks จะได้ว่า 12 MHz หรือ 12,000,000 Hz (1 Hz = 1 cycle / sec) สามารถทำงานได้ 12,000,000 / 12 = 1,000,000 Machine cycles หรือเรียกได้ว่า ใน 1 วินาที สามารถทำงานได้ 1,000,000 machine cycles 1 sec = 1,000,000 machine cycles 1,000 msec = 1,000,000 machine cycles 100 msec = (1/10)*1,000,000 machine cycles = 100,000 machine cycles 10 msec = (1/100)*1,000,000 machine cycles = 10,000 machine cycles 1 msec = (1/1,000)*1,000,000 machine cycles = 1,000 machine cyclesดังนั้น การเลือกความถี่ของสัญญาณนาฬิกาก็มีผลกับการทำงานด้วยเหมือนกัน ... พอจะเข้าใจไหมครับ
ตัวอย่างการหน่วงเวลา (Z80)
คราวนี้เรามาดูในแง่ของการใช้กับ Z80 กันครับ Z80 นั้น มีวิธีการนับ clock ไม่เหมือนกับ MCS51 (MCS51 มีหน่วยการคำนวณ เป็น Machine Code) แต่ Z80 มีหน่วยการทำงานเป็น clock ... เรามาลองหาวิธีการหน่วงเวลา 1 sec โดยใช้ Z80 ที่ใช้ XTAL 4MHz กัน ครับ
1 sec = 4,000,000 clocks 4 MHz = 4,000,000 clocks / 1 secผมพยายาม หาการวนรอบ ที่ ทำงานแล้ว 1 รอบกินเวลา 100 clocks แล้ว วนรอบ 40,000 รอบ ก็จะได้ออกมาเป็น 4,000,000 clocks พอดี ตัวอย่างโปรแกรมเป็นดังนี้ครับ
delay: ld B,200 ; 7 clocks lp_dly1: ld C,10 ; 7 clocks lp_dly2: ld HL,0 ; 10 clocks ld HL,0 ; 10 clocks ld HL,0 ; 10 clocks ld HL,0 ; 10 clocks ld HL,0 ; 10 clocks nop ; 4 clocks nop ; 4 clocks dec C ; 4 clocks jp nz,lp_dly2 ; 10 clocks dec B ; 4 clocks jp nz,lp_dly1 ; 10 clocks retจากโปรแกรม จะได้ว่า 7+7+10+10+10+10+10+4+4+4+10+4+10 = 100 clocks
แต่มีความคลาดเคลื่อนอยู่ 10 clocks จากคำสั่ง RET และยังมีคำสั่ง CALL ที่กิน 17 clocks รวมได้ว่า เมื่อเราเรียก Delay 1 ครั้ง เราจะใช้เวลาไป 1 sec กับ 27 clocks
เป็นอย่างไรครับ การคำนวณการวนรอบเพื่อทำการหน่วงเวลา คงพอเป็นแทนวทางได้นะครับ
Supachai Budsaratij 10.20PM July 26, 2001