การติดต่อเอาท์พุตที่เป็น LED
ลักษณะการต่อ LED จะมี 2 ลักษณะคือ ต่อในลักษณะให้ LED สว่างในสภาวะลอจิก 1 ดังรูป ก.และต่อให้สว่างในสภาวะลอจิก 1ดังรูป ข. ซึ่งทั้ง 2 แบบจะมีกระแสไหลในทิศทางที่แตกต่างกัน โดยในกรณีรูป ก. LED จะสว่างเมื่อเอาท์พุตเป็นลอจิก 1 โดยไอซี จะทำการจ่ายกระแสผ่านตัวต้านทานและ LED ลงกราวน์ เราเรียกกระแสในลักษณะนี้ว่ากระแสซอร์ส(Source Current) คือเป็นกระแสที่จ่ายจากตัวไอซีออกมา ส่วนรูป ข. LED จะสว่างเมื่อเอาท์พุตของไอซีมีสภาวะลอจิก 0 โดยไอซีจะดึงกระแสจากแหล่งจ่ายไฟ ผ่าน LED และตัวต้านทานเข้ามาในตัวไอซีเราเรียกกระแสในลักษณะนี้ว่า กระแสซิงค์(Sink Current) ดังนั้นการจะเลือกต่อแบบใดขึ้นอยู่กับความสามารถในการจ่ายกระแสหรือดึงกระแสของไอซีเพราะไอซีแต่ละเบอร์จะมีความสามารถในการจ่ายกระแส (Source Current) และดึงกระแส(Sink Current) ไม่เท่ากัน
ในกรณีความสามารถในการจ่ายกระแสไม่พอ ก็จะใช้ไอซีที่เป็น บัพเฟอร์ เช่น 74LS244 หรือ 74LS245 เข้ามาต่อคั่นกลางระหว่างไอซีและตัวอุปกรณ์เพื่อให้มีความสามารถในการจ่ายกระแสได้สูงขึ้น โดยทั่วไป LED จะต้องการกระแสระหว่าง 10mA ถึง 20mA โดยถ้าจ่ายกระแสต่ำกว่านี้ LED จะไม่สว่างและถ้าสูงกว่า 20 mA ก็อาจทำให้ LED ร้อนจนอาจเสียหายได้ สำหรับแรงดันที่ตกคร่อม LED ในขณะสว่างจะมีค่าประมาณ 2.5โวลท์ เราสามารถนำมาคำนวณหาค่าความต้านทานที่มาต่อจำกัดกระแสได้ โดย
ตัวอย่าง ถ้าใช้แหล่งจ่ายไฟเลี้ยง 5V และต้องการให้มีกระแสไหลผ่าน LED 10mA ในขณะที่แรงดันตกคร่อม LED ในขณะนำกระแสเท่ากับ 2.5 V
โดยทั่วไปในงานควบคุมเราจะต่อ LED เข้ากับพอร์ตเอาท์พุตแบบ D-FlipFlop เพื่อให้คงสถานะแรงดันค้างไว้ในได้ตามตัวอย่างดังรูป
โดยการต่อในลักษณะดังกล่าวจะใช้ไอซี 74LS374 ซึ่งภายในจะมีD-Flip-Flop 8 ตัวต่อขา CLK ร่วมกัน โดยมีตัวต้านทานแบบชุด(R-Pack)ซึ่งภายในจะมีตัวต้านทาน 8 ตัว ต่อเพื่อจำกัดกระแสที่ไหลผ่าน LED (สมมุติว่าต่อ LED 8 ตัวเข้ากับ Q0 – Q7)สำหรับหมายเลขของพอร์ตจะได้จากการต่อขา A0 – A7 โดยจากวงจร ขา A3 ต้องเป็น 1 นอกนั้นต้องเป็น 0 ซึ่งจะได้หมายเลขของพอร์ตเอาท์พุต = 0000 1000B =08H ถ้าเขียนโปรแกรมควบคุมการทำงานเป็น
LD A,04AAH ; A = 10101010B
OUT (08H),A ; ส่งข้อมูลจาก A ออกไปที่พอร์ต 08H
การทำงานของโปรแกรมคือ คำสั่งแรก Z80 จะกำหนดค่ารีจิสเตอร์ A ภายในตัว Z80 ให้มีค่าเป็น 10101010 คำสั่งที่สองจะเป็นการส่งข้อมูลจากรีจิสเตอร์ A ออกไปที่พอร์ตหมายเลข 08H โดยZ80 จะส่งข้อมูล 1010 10101ไปรอที่ขาข้อมูลD7 – D0 แล้วสร้างสัญญาณให้ขาแอดเดรส A0 – A7 มีสถานะเป็น 0000 1000 ทำให้ไอซีถอดรหัส 74LS138 ที่ต่ออยู่กับขาแอดเดรสมีเอาท์พุตเป็นลอจิก 0 ต่อจากนั้น Z80 จะส่งสัญญาณติดต่อหน่วยความจำและสัญญาณเขียนข้อมูล โดยทำให้ขา IORQ และ ขาWR มีสถานนะเป็นลอจิก 0 ทำให้เอาท์พุตของไอซีเกท ต่างๆ เป็นลอจิก 0 ไปกระตุ้นขาCLK ทำให้ไอซี74LS374 เก็บค่าข้อมูลเข้าไปจึงทำให้ LED ที่ต่ออยู่ที่ขา Q0 ถึง Q7 มีสถานะตามข้อมูล 1010 1010 ที่ส่งออกมาคือจะติดและดับสลับกันไป ถ้าเราควบคุมให้ข้อมูลที่รีจิสเตอร์ A มีค่าเปลี่ยนไปแล้วส่งค่าออกไปที่พอร์ต ก็จะทำให้ LED เกิดติด – ดับตามข้อมูลที่เปลี่ยนแปลง สามารถเขียนโปรแกรมในลักษณะไฟวิ่งได้หลายรูปแบบตามต้องการ
ตัวอย่าง โปรแกรมไฟวิ่งอย่างง่ายๆ
LD A,01H ; A = 0000 0001H
LOOP: OUT(08H),A ; ส่งข้อมูลออกพอร์ตเอาท์พุต หมายเลข 08H
CALL DELAY ; หน่วงเวลา
RLC A ; หมุนข้อมูลในรีจิสเตอร์ A ไปทางซ้าย 1 บิต
JR LOOP ; กลับไปวนทำซ้ำใหม่
DELAY: LD B,FFH ; ให้ B เป็นตัวนับรอบ
AGAN: NOP
DJNZ AGAIN ; ให้กระโดดไปทำซ้ำที่ AGAIN ใหม่จนกว่า B = 0
RET
ในกรณีต้องการให้วิ่งเพียง 1 รอบแล้วหยุดอาจใช้วิธีนับรอบการวิ่ง โดยใช้รีจิสเตอร์ B แต่วิธีนี้ต้องมีการเก็บค่า BC ไว้ก่อนที่จะเข้าสู่โปรแกรมหน่วงเวลา ดังนี้
LD B,08H ; ให้ B เป็นตัวนับมีค่า = 8
LD A,01H ; A = 0000 0001H
LOOP: OUT(08H),A ; ส่งข้อมูลออกพอร์ตเอาท์พุต หมายเลข 08H
RUSH BC ; เก็บค่า BC ไว้ในสแตก
CALL DELAY ; หน่วงเวลา
POP BC ; คืนค่า BC จากสแตก
RLC A ; หมุนข้อมูลในรีจิสเตอร์ A ไปทางซ้าย 1 บิต
DJNZ LOOP ; หยุดการทำงาน
DELAY: LD B,FFH ; ให้ B เป็นตัวนับรอบของลูปด้านนอก
DELAY1: LD C,FFH ; ให้ C เป็นตัวนับรอบของลูปด้านใน
DELAY2: NOP ; กำหนดให้ซีพียู อยู่เฉยๆ
DEC C ; ลดค่า C ลง 1
JR NZ,DELAY2 ; ถ้า C ยังไม่เป็น 0 ให้วนรอบใน DELAY 2
DJNZ DELAY1 ; ให้กระโดดไปทำซ้ำที่ DELAY1 ใหม่จนกว่า B = 0
RET
โดยโปรแกรมใหม่นี้ได้เพิ่มเวลาหน่วงให้มากขึ้นโดยการให้วนรอบแบบ ลูปซ้อนลูปคือ ในแต่ละรอบของ B จะต้องวนรอบภายในของ C =FF รอบ การปรับค่าเวลาหน่วงทำได้โดยการปรับค่าจำนวนรอบของ B และ C และสังเกตว่า ก่อนจะเรียกโปรแกรมย่อยจะมีการเก็บค่า BC เดิมเอาไว้ในสแตกโดยใช้คำสั่ง PUSH BC และเมื่อกลับสู่โปรแกรมหลักก็จะนำค่าเดิมของ BC ที่เก็บในสแตกกลับคทนมาด้วยคำสั่ง POP BC
การตรวจสอบการวิ่งของ LED นอกจากจะตรวจสอบจากจำนวนรอยบแล้วเรายังมีวิธีตรวจสอบจากคำสั่ง BIT n,A ที่จะใช้ตรวจสอบว่าขณะนี้ บิตดังกล่าวของรีจิสเตอร์ A เป็น 0 หรือ 1 ได้ โดยเขียนโปรแกรมดังนี้
LD A,01H ; A = 0000 0001H
LOOP: OUT(08H),A ; ส่งข้อมูลออกพอร์ตเอาท์พุต หมายเลข 08H
EX AF,AF ; เก็บค่า AF
CALL DELAY ; หน่วงเวลา
EX AF,AF ; คืนค่า AF
RLC A ; หมุนข้อมูลในรีจิสเตอร์ A ไปทางซ้าย 1 บิต
BIT 4,A ; ตรวจสอบว่าเลข 1 วิ่งมาถึง บิต 4 หรือยัง
JR Z LOOP2 ; ถ้ายัง(คือ ค่าของบิต 4 ยังเป็น 0)ให้วนกลับไปทำต่อ
HALT ; หยุดการทำงาน
DELAY: LD BC,8000H ; ให้ BC เป็นตัวนับรอบ
DELAY1: DEC BC ; ลดค่า BC
LD A,B ; โหลดข้อมูลจาก B มาให้ A เพื่อกระทำการ OR
LD A,B ; โหลดข้อมูลจาก B มาให้ A เพื่อกระทำการ OR
OR C ; ตรวจสอบค่า BC ว่าเท่ากับ 0000 หรือยัง
JR NZ,DELAT1 ; ถ้า BC ยังไม่เป็น 0 ให้วนกลับไปทำซ้ำที่ DELA 1
RET
จากโปรแกรมจะเห็นว่า เราจะใช้คำสั่ง BIT 4,A ตรวจสอบการวิ่งของ LED ว่าวิ่งวนมาถึงบิต 4 หรือยัง ถ้ายังก็จะอนุญาตให้วิ่งต่อไปได้แต่ถ้าถึงแล้วก็จะหยุดการทำงาน
สำหรับการเขียนโปรแกรมหน่วงเวลาจะใช้ BC เป็นตัวนับซึ่งการตรวจสอบว่า BC เป็นศูนย์หรือไม่จะต้องใช้วิธีนำมา OR โดยใช้รีจิสเตอร์ A เป็นตัวช่วย(เพราะคำสั่งลดค่า DEC BC จะไม่มีผลต่อแฟลก) ดังนั้นก่อนเข้าโปรแกรมหน่วงเวลา เราจึงต้องเก็บค่าข้อมูลในรีจิสเตอร์ A เสียก่อน โดยการใช้คำสั่ง EX AF,AF ซึ่งจะเป็นการเก็บฝากไว้ในรีจิสเตอร์สำรองจากนั้นเมื่อทำโปรแกรมย่อยเสร็จสิ้น ก่อนจะทำโปรแกรมหลักต่อก็จะทำการคืนค่ากลับมาด้วยคำสั่ง EX AF,AF อีกครั้ง เพื่อสลับเอาข้อมูลที่ฝากไว้ในรีจิสเตอร์สำรองกลับคืนมาดังเดิม
หมายเหตุ
การเก็บและคืนค่ารีจิสเตอร์ก่อนเข้าโปรแกรมย่อยและออกจากโปรแกรมย่อยนี้เขียนไว้ในส่วนของโปรแกรมย่อยก็ได้