[ บทความ : ถามตอบ # 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 จำนวนเท่าไร
2. ระบบที่เราใช้นั้น ทำงานที่ความถี่ของสัญญาณนาฬิกาเท่าไร
3. เวลาที่เราต้องการหน่วงนั้น มีค่าเท่าไร และจำเป็นที่จะต้องเที่ยงตรง มากน้อยเท่าไร
เมื่อตอบคำถามทั้ง 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

เขียนโดย :ศุภชัย บุศราทิจ
Author : Supachai Budsaratij
e-mail : raek@se-ed.net
วันที่ทำการปรับปรุง : ๑ ก.ย. ๒๕๔๔