المقاطعات باستخدام pic16f877a

بسم الله الرحمن الرحيم

ملحوظه مهمه : هذا المقال يحتوي علي كثير من المعلومات فيجب الإنتباه لكافة المعلومات التي يحتويها المقال XD 


بعد ان ناقشنا في الدروس السابقة العديد من المواضيع حول التعامل مع متحكم PIC من كيفية التعامل مع هذا المتحكم والتعامل مع المنافذ الرقمية وقمنا بعمل بعض التطبيقات العملية المفيدة في ايضاح فكرة عمل المنافذ
سنناقش اليوم موضوع المقاطعات ومفهومها وكيفية التعامل معها واستخدامات المقاطعه والمخطط الخاص بها
في البداية يجب ان نناقش مفهوم المقاطعه : سنوضح هذا المفهوم بهذا المثال
انت تقرأ كتاب ثم وانت تقرا سمعت احد يطرق علي الباب فقمت بوضع علامه في المكان الذي توقفت فيه عن القراءه وذهبت لتري من الذي يطرق الباب ثم عدت مره اخري لتكمل قراءة الكتاب اينما توقفت عن القراءة
هذا بإختصار مفهوم المقاطعه هذا ما يحدث في متحكم في وحدة المقاطعه اي ان المتحكم يقوم بإيقاف عمل الكود الرئيسي ليقوم بعمل اوامر اخري في حالة حدوث شئ ما ثم يعود لإستكمال الكود الرئيسي حيث توقف البرنامج الرئيسي

تتكون الميموري الخاصه بمتحكم PIC16F877A من عدة اجزاء 
الجزء الخاص بالكود او البرنامج الخاص بنا وهنا يتم وضع الكود في عدة pages 
يقوم المتحكم بتقسم كل instruction من الكود الي عنوان ويخزن هذا العنوان في مكان stack 
يتكون stack من 8 اماكن عندما يصل المتحكم في التخزين الي المكان 8 يقوم بالعودة ليكتب علي المكان الأول وعند حدوث مقاطعه وبعد تنفيذ كود المقاطعه المسمي ب ISR يقوم المتحكم بالعودة للكود الذي توقف عنده عن طريق قراءة اخر عنوان تم كتابته  في stack 
وهناك جزء interrupt vector وهذا الجزء يتم تخزين فيه الكود الذي يتم تنفيذه في حالة حدوث المقاطعه وهنا يسمي هذا الكود ISR




الصورة التي في اﻷعلي توضح المخطط الخاص بوحدة المقاطعه في المتحكم PIC16F877A نري ان كل modules داخل المتحكم متصله بوحدة المقاطعه نلاحظ ان هناك مجموعة من modules متصله ب GIE بخلاف باقة modules التي تتصل ب PEIE ثم تتصل ب GIE 
هناك مصطلح يسمي ب IRQ pins وهي منافذ في متحكم مخصصه لإستقبال اشارة مقاطعه وهذه المنافذ هي RB0 , TMR1 , PORTB 
دعنا ننافش سيناريو الخاص بإشارة المقاطعه 
اتت اشارة مقاطعه من TMR1 module تدخل اشارة المقاطعه المساويه لقيمة 1 للمقاطعه فتحدث عدة اوامر الأمر الأول 
يتم كتابة واحد داخل TMR1IF ثم تنتقل الإشارة الي TMR1IE هنا ياتي دور المبرمج فهذا BIT بمثابة متحكم في تشغيل او إطفاء المقاطعه الخاصه ب module ثم تنتقل الإشارة الي PEIE وهنا ياتي دور المبرمج ايضا في تفعيل هذا bit ففي حالة كتابة هنا 1 يتم السماح بمرور الإشارة ويتم ايضا كتابة 1 في GIE ومن GIE يتم مرور الإشارة الي المعالج وهنا يعرف المتحكم بحدوث اشارة مقاطعه ولكن لا يستطيع المتحكم معرفة مصدر إشارة 
بمعني المتحكم يعلم ان هناك اشارة مقاطعه وينفذ كود المقاطعه ISR ولكن لا يعلم مصدر الإشارة من اين اتي 
وهنا ياتي دور flag الخاص بكل module حيث بقراءة flag يمكننا معرفة مصدر اشارة المقاطعة من اين اتي ومن اي module

هناك نوعين من اشارة المقاطعة falling / rising 
اي  بمعني متي تحدث مقاطعة عندما يصل للمعالج اشارة قيمتها صفر او تصل للمعالج اشارة قيمتها واحد ونحدد هذه العملية عن طريق كتابة في bit في REGISTER يسمي OPTION_REG
نكتب في bit INTEDG واحد او صفر لو كتبنا واحد تكون اشارة المقاطعة مساوية لواحد 
ولو كتبنا صفر تكون اشارة المقاطعة مساوية لصفر

الخلاصة قبل ان ننتقل للتجربة العملية 
لكي نتعامل مع المقاطعات يجب في البداية تحديد اشارة المقاطعة وعن طريق كتابة في REGISTER OPTION_REG داخل BIT INTEDG واحد او صفر لو كتبنا واحد تكون اشارة المقاطعة 1 ولو صفر تكون اشارة المقاطعة 0 
ثم علينا كتابة في REGISTER INTCON داخل GIE bit
نقوم بكتابة 1 داخل هذا المتحكم ونقوم بكتابة داخل PEIE bit نقوم بكتابة واحد وهكذا نقوم بتفعيل عامة المقاطعات 
ثم نتجه لموديول الذي نريد استقبال منه اشارة المقاطعة وكتابة 1 داخل bit الخاص ب enable الخاص بالموديول مثال لتفعيل مقاطعة tmr1 نكتب داخل TMR1IE واحد وهكذا نفعل مقاطعه الموديول ونسمح بمرور الإشارة للمعالج 
ولكي نقوم بمعرفة مصدر الإشارة نقوم بقراءة bit الخاص بflag الذي يتم كتابة فيه 1 في حالة مرور اشارة المقاطعة وهكذا نحدد مصدر الإشارة  

التجربة العملية :
بالتاكيد بعد كل هذه المعلومات يجب علينا ان نجرب هذا الموضوع لكي تتضح الرؤية اكثر 
سنقوم بتوصيل 2 ليد الي متحكم pic وتوصيل سويتش وعمل له pull down عبر مقاومة 10 كيلو اوم وتوصيل الطرف اﻷخر بالموجب سنقوم بعمل وميض لليد بطريقة مستمره وعمل تغيير لحالة الليد الثاني مع كل ضغطه سويتش 

الكود :
#include <pic16f877a.h>
#include <xc.h>
#define _XTAL_FREQ 4000000
int main(void) {
    TRISB0=1;
    TRISB1=0;
    TRISB2=0;
    INTEDG=1;
    INTE=1;
    GIE=1;
    while(1){
        RB1=1;
        __delay_ms(250);
        RB1=0;
        __delay_ms(250);
        
    }
    return (0);
}
void __interrupt() ISR(void){
    if(INTF){
        RB2=!RB2;
        INTF=0;
    }
}
دعنا نناقش الكود في البداية يجب تعريف سرعة الكريستال 
#define _XTAL_FREQ 4000000
قمنا باستخدام كريستال بسرعة 4 ميغا هرتز 
ثم ندخل داخل الكود 
في البداية تعريف منفذ السويتش الذي وصلنا بمنفذ RB0 وتحديد انه كدخل عن طريق كتابة 1 في TRIS الخاص بالمنفذ 
وتحديد منفذ RB1 , RB2 كخرج وكتابة 0 في TRIS الخاص بالمنفذان 
    TRISB0=1;
    TRISB1=0;
    TRISB2=0;
ثم نقوم بتحديد اشارة المقاطعة اذا كانت 1 او 0 نقوم بكتابة داخل BIT INTEDG نقوم بكتابة 1 لكي تكون اشارة المقاطعة 1 
    INTEDG=1;
ثم نفعل GIE ونفعل مقاطعة الخاصه ب RB0 عن طريق 
    INTE=1;
    GIE=1;
ملحوظة : يسمي منفذ RB0 ب INT
وبعد ذلك نقوم بدخول للحلقة الخاصه بالكود اخراج اشارة علي منفذ رقم RB1 تشغيل ليد وانتظار ثم اطفاءه والإنتظار

ثم لكي نقوم بكتابة كود المقاطعة او الكود الذي يتم تخزينة داخل 
interrupt vector نكتب دالة من نوع void بهذه الطريقة 
void __interrupt() ISR(void)
وهنا نقوم بقراءة bit الخاصه ب flag الخاص بالمنفذ rb0 واذا كان اشارة تساوي واحد يقوم المتحكم بتغيير اشارة الليد الثاني ويقوم بعد ذلك بجعل قيمة flag تساوي صفر لكي ينتظر اشارة المقاطعة الجديدة 
    if(INTF){
        RB2=!RB2;
        INTF=0;
ملحوظة مهمه : يجب جعل قيمة flag تساوي صفر بعد قرائته وهذ لكي نستطيع قراءة اشارة مقاطعة جديدة

وهكذا نكون انتهينا من اهم المواضيع الخاصه بهذا المتحكم وهي المقاطعات

تصميم وبرمجة : بلال حسان 

تعليقات