Lab 4.2 – Basic Parallel Processing – การใช้ I/O Interrupt ควบคุม LED และอ่านสถานะปุ่มพร้อมๆ กัน
โจทย์
ให้นักศึกษาเขียนโปรแกรมที่ทำงานตามนี้
- (A) ทำให้ LED กระพริบทุกๆ 1 วินาที – แนะนำให้เลือกต่อ LED เข้ากับ PORT B4-B7 เพราะเป็นขาที่มี Interrupt on change ให้ใช้
- (B) เมื่อใดที่ผู้ใช้กดปุ่ม ให้กลับสถานะของไฟ LED ทันที (กลับเฉพาะตอนกด ตอนปล่อยไม่ต้องกลับ)
Timing diagram ต่อไปนี้แสดงตัวอย่างสถานะของ LED เมื่อมีการกดปุ่มเกิดขึ้น
การส่งงาน
ให้เขียนโปรแกมโดย
- ใช้ Timer Interrupt ควบคุมการกระพริบของ LED
- ใช้ I/O Interrupt ตรวจจับการกดปุ่ม
หากใช้ Simulator
- ให้ส่ง Screen Capture ของ Wave form ที่แสดงให้เห็นว่าโปรแกรมทำงานตามเงื่อนไขที่กำหนด
หากใช้วงจรจริง
- ให้ส่ง Screen Capture ของ Wave form จาก Logic Analyser ที่แสดงให้เห็นว่าโปรแกรมทำงานตามเงื่อนไขที่กำหนด
เกริ่นนำ
โจทย์ข้างต้นอาจฟังดูไม่ยาก แต่จริงๆ แล้วจะพบว่าเขียนโปรแกรมแบบ Linear ธรรมดาค่อนข้างยาก การจะทำให้ LED ติดและดับทุกๆ วินาที วิธีปกติจะใช้คำสั่ง delay_ms() ซึ่งในช่วงเวลาที่มีการ delay นั้นโปรแกรมจะไม่สามารถทำงานอย่างอื่นได้ ดังนั้นจะไม่สามารถตรวจสอบการกดปุ่มได้ เป็นต้น
การตรวจจับการกดปุ่มโดยใช้ Interrupt
การ Setup สำหรับ PIC16F877a
เนื่องจาก PIN B4-B7 มี Interrupt on change ไว้คอยตรวจการเปลี่ยนแปลงสถานะของ Pin จึงสามารถนำมาใช้งานสำหรับโจทย์นี้ได้ โดยใน main() จะต้องประกาศดังนี้
enable_interrupts(INT_RB); // generate interrupt when B4-B7 changes enable_interrupts(GLOBAL);
และสร้าง function ที่จะทำงานทุกครั้งที่เกิด Interrupt ขึ้นมาโดยมีชื่อ Interrupt ประกาศไว้ด้วย ดังนี้
#INT_RB void rb_isr(void) { ... }
ดังนั้นโครงสร้างของโปรแกรมทั้งหมดจะเป็นดังนี้
#INT_RB void rb_isr(void) { if(input(PIN_B7) == 1) { /* do work */ } } void main(void) { enable_interrupts(INT_RB); // generate interrupt when B4-B7 changes enable_interrupts(GLOBAL); ... }
เนื่องจาก Interrupt นี้จะเกิดขึ้นเมื่อ Pin B4-B7 มีการเปลี่ยนสถานะ ไม่สามารถระบุได้ว่าจะเป็น pin ใด ดังนั้นในโปรแกรมอาจต้องตรงสอบสถานะของ pin ที่สนใจเองว่ามีการเปลี่ยนแปลงหรือไม่ เช่น ในโปรแกรมตัวอย่างข้างต้นทำการตรวจสถานะของ Pin B7 เป็นต้น
การ Setup สำหรับ PIC16F886
เนื่องจากทุก Pin ของ Port B มี Interrupt on change ไว้คอยตรวจการเปลี่ยนแปลงของ Pin ของ Port B ที่ต้องการได้ (PIC16F886 สามารถตั้งค่าให้ Interrupt on change เฉพาะ pin ที่ต้องการได้) จึงสามารถนำมาใช้งานสำหรับโจทย์นี้ได้ โดยใน main() จะต้องประกาศดังนี้หากต้องการตรวจสอบการเปลี่ยนสถานะของ PIN B7
enable_interrupts(INT_RB7); // generate interrupt when B7 changes enable_interrupts(GLOBAL);
และสร้าง function ที่จะทำงานทุกครั้งที่เกิด Interrupt ขึ้นมาโดยมีชื่อ Interrupt ประกาศไว้ด้วย ดังนี้
#INT_RB void rb_isr(void) { ... }
ดังนั้นโครงสร้างของโปรแกรมทั้งหมดจะเป็นดังนี้
#INT_RB void rb_isr(void) { ... } void main(void) { enable_interrupts(INT_RB7); // generate interrupt when B7 changes enable_interrupts(GLOBAL); ... }
คำแนะนำ
- rb_isr จะเปลี่ยนเป็นชื่ออื่นใดก็ได้ แต่จะต้องมีประกาศ #INT_RB นำหน้าเสมอ
- ห้ามแทรกคำสั่งใดๆ ระหว่าง #INT_RB กับชื่อ function เพราะจะทำให้ interrupt หยุดทำงาน
- เนื่องจาก Interrupt จะเกิดเมื่อสถานะของขาเปลี่ยนแปลง ดังนั้น interrupt นี้จะเกิดทั้งตอนกด และปล่อย ปุ่ม ขอให้เขียนโปรแกรมตรวจสอบสิ่งนี้ไว้ให้ดี เช่น ใน rb_isr ให้เขียนเช็คด้วยว่าตอนนั้นๆ ขา RB0 เป็น high หรือ low