Lab 4.2 : การใช้ I/O Interrupt เพื่อสั่งงาน LED


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