المؤقتات والمقاطعة والميكروكونترولر PIC16F877A مع المترجم CCS C :
منتديات الهندسة الكهربية والإلكترونية والميكاترونكس والكومبيوتر :: برمجة الميكروكونترولر PIC بلغة السى مع المترجم CCS - C
صفحة 1 من اصل 1
المؤقتات والمقاطعة والميكروكونترولر PIC16F877A مع المترجم CCS C :
المؤقتات والمقاطعة والميكروكونترولر PIC16F877A مع المترجم CCS C :
يحتوى الميكروكونترولر PIC15F877A على ثلاثة مؤقتات :
• المؤقت Timer0 سعة 8 بت .
• المؤقت Timer1 سعة 16 بت .
• المؤقت Timer2 سعة 8 بت .
تستخدم المؤقتات فى كثير من التطبيقات مثل التوقيت Timing، والتقاط البيانات Capture ، وتعديل عرض النبضات PWM ، وغيرها .
يوجد سجلات تعمل كمقسم تردد سابق prescale أو لاحق postscale (فى المؤقت timer2 فقط ) للمؤقت ، يمكن التحكم فى نسبة القسمة من 1:1 إلى 1:256 بغرض تقليل التردد أو زيادة الزمن . علما بأنه إذا كان تردد المذبذب الخارجى هو Fosc يكون تردد الساعة الداخلية للميكروكونترولر Fosc/4 . فى حالة استخدام مذبذب خارجى بالقيمة 4Mhz يكون تردد الساعة الداخلية Fosc/4=4/4=1 Mhz وبالتالى يكون الزمن الدورى واحد ميكرو ثانية 1us أى نبضة كل ميكروثانية :
مثال :
العبارة التالية :
setup_timer_0 (RTCC_INTERNAL | RTCC_DIV_4); //
تقوم بإعداد (ضبط) المؤقت Timer0 (أو يسمى RTCC) ليعمل على الساعة الداخلية ، مع معامل قسمة سابق ( ليس له معامل قسمة لاحق ) 1:4 وبالتالى فإن نبضات الساعة التى تطبق على المؤقت Timer0 فى حالة استخدام مذبذب خارجى بالقيمة 4Mhz تكون : (Fosc/4) / 4 = Fosc/16 ، ومن ثم فإننا نحصل على زمن دورى 4us ( نبضة كل أربعة ميكروثانية) بدلا من 1us .
المؤقت Timer0 هو فى حقيقة الأمر سجل بسعة 8 بت يعمل تلقائيا كعداد يتزايد بواحد فى كل مرة بدءا من الصفر (أو أى قيمة تحددها برمجيا) ويتزايد حتى يصل إلى أقصى مدى له وهو العدد “256” ، عندئذ يقال أنه مملوء ، بعد ذلك يدور إلى الصفر مرة أخرى ، هذه اللحظة تسمى overflow "تجاوز" وعندها تتولد إشارة إعلام بذلك حيث يمكن استخدامها فى توليد مقاطعة (بعد تمكينها) تستخدم فى الكثير من التطبيقات العملية .
مثال :
فى المثال السابق ونتيجة لاستخدام العبارة السابقة ، يصل إلى سجل المؤقت timer0 نبضة كل 4us (من خرج قاسم التردد السابق)، ويحدث overflow بعد وصول “256” نبضة من هذه النبضات أى بعد زمن قدرة 4 * 256 = 1024 us .
ملحوظة :
للحصول على أزمنة أطول يمكننا استخدام متغير كعداد لعدد مرات حدوث التجاوز ، كما سوف يتضح فى المثال أدناه .
استخدام المقاطعة بالمؤقت Timer0 فى توليد تأخير زمنى قيمته واحد ثانية
مبدأ العمل :
• يتم ضبط المؤقت timer0 ليعمل على الساعة الداخلية (البارامتر الأول) ، مع معامل قسمة سابق بالقيمة 1:2 (البارامتر الثانى)عن طريق العبارة التالية :
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_2);
نتيجة لذلك ، يصل إلى المؤقت timer0 نبضة كل 2us (بدلا من 1us) .
• يتم وضع القيم “6” كقيمة ابتدائية داخل سجل المؤقت timer0 عن طريق استخدام العبارة التالية :
set_timer0(6);
نتيجة لذلك يحدث تجاوز overflow للمؤقت بعد مرور (256-6=250) نبضة وكل نبضة تستغرق 2us أى تجاوز كل (2 * 250 = 500 us) . بعد حدوث “2000” تجاوز يكون قد مر زمن قدره (500 * 2000 = 1000000 us = 1 s)
البرنامج التالى يوضح خطوات التنفيذ :
يمكن وصف عمل البرنامج كما يلى :
1- فى البداية ، وكالمعتاد ، يتم وضع توجية ملف الرأس الخاص بجهاز الميكروكونترولر المستخدم بالصيغة #include <16F877A.h> ، يليه توجيه ساعة المذبذب الخارجى المستخدم بالصيغة
#use delay(clock=4000000) .
2- بعد ذلك يتم تعريف المتغيرات الشاملة global ، وهنا يتم تعريف كلمة PORTB على أنها البايت الموجود بالعنوان “0x06” بالصيغة #byte PORTB = 0x06 ، وهو العنوان الفعلى للمنفذ PORTB حتى يمكن استخدام كلمة PORTB مباشرة حيث أنها غير معرفة بهذا الشكل فى ملف الرأس ، وتعريف المتغير count نوع int16 ، والمتغير “a” نوع in8 .
3- بعد ذلك ، وقبل الدالة الرئيسية ، نصل إلى تناول المقاطعة بالمؤقت timer0 حيث نتبع الخطوات التالية :
أ- فى البداية ينبغى كتابة توجيه المقاطعة المستخدم بالصيغة #int_timer0 لكى نخبر المترجم بأن الدالة القادمة مباشرة void interrupt_timer0() ، هى دالة روتين خدمة المقاطعة وللقيام بعمل اللازم نيابة عنك .
ب- عند حدوث مقاطعة بالمؤقت timer0 نتيجة حدوث تجاوز overflow يتم تلقائيا ومن خلف الستار تنفيذ كتلة دالة خدمة المقاطعة المطلوبة . كلما حدث تجاوز يتم القيام بما يلى :
• فى البداية يتم وضع القيمة الابتدائية للمؤقت بالصيغة set_timer0(6); .
• زيادة عداد عدد مرات التجاوز بواحد بالصيغة ++count; .
• اختبار عدد مرات المقاطعة بالصيغة if(count == 2000) فإذا وصل إلى العدد “2000” وهو ما يناظر مرور زمن قدره واحد ثانية يتم تصفير العداد بالصيغة count=0; ، ثم القيام بالمهمة المطلوبة وهى هنا إزاحة محتويات المتغير بواحد جهة اليسار بالصيغة rotate_left(&a,1); . يمكن تغيير هذه المهمة بأى مهمة أخرى .
4- والآن جاء وقت الدخول إلى الدالة الرئيسية ( والتى تشير إلى بداية تنفيذ البرنامج) وفى البداية والمعتاد يتم أعداد المنافذ المطلوبة set_tris_b(0); (وتعريف المتغيرات إن وجدت) ثم نبدأ فى معالجة المقاطعة ، وفيها يتم ما يلى :
• تمكين المقاطعة ذاتها enable_interrupts(int_timer0); .
• تحديد إعدادات هذه المقاطعة setup_timer_0(RTCC_INTERNAL|RTCC_DIV_2); وهنا نحدد أن المقاطعة بالمؤقت timer0 تستخدم الساعة الداخلية ، مع استخدام معمل قسمة على “2” .
• بعد ذلك يتم تمكين جميع المقاطعات enable_interrupts(global); .
• وفى النهاية يتم وضع القيمة الابتدائية لسجل المؤقت timer0 .
5- قبل الدخول إلى الحلقة الغير منتهية يتم تخصيص قيمة “1” للمتغير بالصيغة a = 0x01; .
6- داخل الحلقة الغير منتهية يتم وضع كود المهمة الأساسية ، وهى هنا نسخ محتويات المتغير “a” إلى سجل المنفذ PORTB .
ملاحظة :
التغيير فى محتويات المتغير “a” عبارة عن إزاحة بتاته جهة اليسار موقع واحد فى كل مرة بدءا من القيمة واحد ، أى تكون المحتويات “00000001” ، ثم “00000010” وهكذا حتى “10000000” ، وهكذا نحصل على إضاءة متحركة لليدات المتصلة بالمنفذ PORTB ، كل ذلك يحدث فى خلفية البرنامج نتيجة استخدام المقاطعة بالمؤقت timer0 .
يحتوى الميكروكونترولر PIC15F877A على ثلاثة مؤقتات :
• المؤقت Timer0 سعة 8 بت .
• المؤقت Timer1 سعة 16 بت .
• المؤقت Timer2 سعة 8 بت .
تستخدم المؤقتات فى كثير من التطبيقات مثل التوقيت Timing، والتقاط البيانات Capture ، وتعديل عرض النبضات PWM ، وغيرها .
يوجد سجلات تعمل كمقسم تردد سابق prescale أو لاحق postscale (فى المؤقت timer2 فقط ) للمؤقت ، يمكن التحكم فى نسبة القسمة من 1:1 إلى 1:256 بغرض تقليل التردد أو زيادة الزمن . علما بأنه إذا كان تردد المذبذب الخارجى هو Fosc يكون تردد الساعة الداخلية للميكروكونترولر Fosc/4 . فى حالة استخدام مذبذب خارجى بالقيمة 4Mhz يكون تردد الساعة الداخلية Fosc/4=4/4=1 Mhz وبالتالى يكون الزمن الدورى واحد ميكرو ثانية 1us أى نبضة كل ميكروثانية :
مثال :
العبارة التالية :
setup_timer_0 (RTCC_INTERNAL | RTCC_DIV_4); //
تقوم بإعداد (ضبط) المؤقت Timer0 (أو يسمى RTCC) ليعمل على الساعة الداخلية ، مع معامل قسمة سابق ( ليس له معامل قسمة لاحق ) 1:4 وبالتالى فإن نبضات الساعة التى تطبق على المؤقت Timer0 فى حالة استخدام مذبذب خارجى بالقيمة 4Mhz تكون : (Fosc/4) / 4 = Fosc/16 ، ومن ثم فإننا نحصل على زمن دورى 4us ( نبضة كل أربعة ميكروثانية) بدلا من 1us .
المؤقت Timer0 هو فى حقيقة الأمر سجل بسعة 8 بت يعمل تلقائيا كعداد يتزايد بواحد فى كل مرة بدءا من الصفر (أو أى قيمة تحددها برمجيا) ويتزايد حتى يصل إلى أقصى مدى له وهو العدد “256” ، عندئذ يقال أنه مملوء ، بعد ذلك يدور إلى الصفر مرة أخرى ، هذه اللحظة تسمى overflow "تجاوز" وعندها تتولد إشارة إعلام بذلك حيث يمكن استخدامها فى توليد مقاطعة (بعد تمكينها) تستخدم فى الكثير من التطبيقات العملية .
مثال :
فى المثال السابق ونتيجة لاستخدام العبارة السابقة ، يصل إلى سجل المؤقت timer0 نبضة كل 4us (من خرج قاسم التردد السابق)، ويحدث overflow بعد وصول “256” نبضة من هذه النبضات أى بعد زمن قدرة 4 * 256 = 1024 us .
ملحوظة :
للحصول على أزمنة أطول يمكننا استخدام متغير كعداد لعدد مرات حدوث التجاوز ، كما سوف يتضح فى المثال أدناه .
استخدام المقاطعة بالمؤقت Timer0 فى توليد تأخير زمنى قيمته واحد ثانية
مبدأ العمل :
• يتم ضبط المؤقت timer0 ليعمل على الساعة الداخلية (البارامتر الأول) ، مع معامل قسمة سابق بالقيمة 1:2 (البارامتر الثانى)عن طريق العبارة التالية :
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_2);
نتيجة لذلك ، يصل إلى المؤقت timer0 نبضة كل 2us (بدلا من 1us) .
• يتم وضع القيم “6” كقيمة ابتدائية داخل سجل المؤقت timer0 عن طريق استخدام العبارة التالية :
set_timer0(6);
نتيجة لذلك يحدث تجاوز overflow للمؤقت بعد مرور (256-6=250) نبضة وكل نبضة تستغرق 2us أى تجاوز كل (2 * 250 = 500 us) . بعد حدوث “2000” تجاوز يكون قد مر زمن قدره (500 * 2000 = 1000000 us = 1 s)
البرنامج التالى يوضح خطوات التنفيذ :
- الكود:
#include <16F877A.h>
#use delay(clock=4000000)
#byte PORTB = 0x06
int16 count;
int8 a;
// TMR0 Interrupt
#int_timer0 // Interrupt directive
void interrupt_timer0() // Interrupt function name
{
set_timer0(6); // set initial value
++count; //Counter increments each overflow
if(count == 2000) // 2000*500us = 500000us = 1s
{
count=0;
rotate_left(&a,1);
}
}
//Main function
void main(void)
{
set_tris_b(0); // port B as output
enable_interrupts(int_timer0); // Enable local interrupt
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_2); // setup timer mode , prescaler
enable_interrupts(global); // Enable global interrupt
set_timer0(6);// Set initial value to get overflow each 500us
a = 0x01;
while(true)
{
PORTB = a;
}
}
يمكن وصف عمل البرنامج كما يلى :
1- فى البداية ، وكالمعتاد ، يتم وضع توجية ملف الرأس الخاص بجهاز الميكروكونترولر المستخدم بالصيغة #include <16F877A.h> ، يليه توجيه ساعة المذبذب الخارجى المستخدم بالصيغة
#use delay(clock=4000000) .
2- بعد ذلك يتم تعريف المتغيرات الشاملة global ، وهنا يتم تعريف كلمة PORTB على أنها البايت الموجود بالعنوان “0x06” بالصيغة #byte PORTB = 0x06 ، وهو العنوان الفعلى للمنفذ PORTB حتى يمكن استخدام كلمة PORTB مباشرة حيث أنها غير معرفة بهذا الشكل فى ملف الرأس ، وتعريف المتغير count نوع int16 ، والمتغير “a” نوع in8 .
3- بعد ذلك ، وقبل الدالة الرئيسية ، نصل إلى تناول المقاطعة بالمؤقت timer0 حيث نتبع الخطوات التالية :
أ- فى البداية ينبغى كتابة توجيه المقاطعة المستخدم بالصيغة #int_timer0 لكى نخبر المترجم بأن الدالة القادمة مباشرة void interrupt_timer0() ، هى دالة روتين خدمة المقاطعة وللقيام بعمل اللازم نيابة عنك .
ب- عند حدوث مقاطعة بالمؤقت timer0 نتيجة حدوث تجاوز overflow يتم تلقائيا ومن خلف الستار تنفيذ كتلة دالة خدمة المقاطعة المطلوبة . كلما حدث تجاوز يتم القيام بما يلى :
• فى البداية يتم وضع القيمة الابتدائية للمؤقت بالصيغة set_timer0(6); .
• زيادة عداد عدد مرات التجاوز بواحد بالصيغة ++count; .
• اختبار عدد مرات المقاطعة بالصيغة if(count == 2000) فإذا وصل إلى العدد “2000” وهو ما يناظر مرور زمن قدره واحد ثانية يتم تصفير العداد بالصيغة count=0; ، ثم القيام بالمهمة المطلوبة وهى هنا إزاحة محتويات المتغير بواحد جهة اليسار بالصيغة rotate_left(&a,1); . يمكن تغيير هذه المهمة بأى مهمة أخرى .
4- والآن جاء وقت الدخول إلى الدالة الرئيسية ( والتى تشير إلى بداية تنفيذ البرنامج) وفى البداية والمعتاد يتم أعداد المنافذ المطلوبة set_tris_b(0); (وتعريف المتغيرات إن وجدت) ثم نبدأ فى معالجة المقاطعة ، وفيها يتم ما يلى :
• تمكين المقاطعة ذاتها enable_interrupts(int_timer0); .
• تحديد إعدادات هذه المقاطعة setup_timer_0(RTCC_INTERNAL|RTCC_DIV_2); وهنا نحدد أن المقاطعة بالمؤقت timer0 تستخدم الساعة الداخلية ، مع استخدام معمل قسمة على “2” .
• بعد ذلك يتم تمكين جميع المقاطعات enable_interrupts(global); .
• وفى النهاية يتم وضع القيمة الابتدائية لسجل المؤقت timer0 .
5- قبل الدخول إلى الحلقة الغير منتهية يتم تخصيص قيمة “1” للمتغير بالصيغة a = 0x01; .
6- داخل الحلقة الغير منتهية يتم وضع كود المهمة الأساسية ، وهى هنا نسخ محتويات المتغير “a” إلى سجل المنفذ PORTB .
ملاحظة :
التغيير فى محتويات المتغير “a” عبارة عن إزاحة بتاته جهة اليسار موقع واحد فى كل مرة بدءا من القيمة واحد ، أى تكون المحتويات “00000001” ، ثم “00000010” وهكذا حتى “10000000” ، وهكذا نحصل على إضاءة متحركة لليدات المتصلة بالمنفذ PORTB ، كل ذلك يحدث فى خلفية البرنامج نتيجة استخدام المقاطعة بالمؤقت timer0 .
مواضيع مماثلة
» دليل ربط شاشة LCD نوع 2X16 بالميكروكونترولر PIC16F877A مع استخدام المترجم CCS C :
» ربط الميكروكونترولر PIC16F877A مع لوحة مفاتيح Keypad ووحدة عرض LCD
» دوائر ( مشاريع ) المؤقتات timers
» فديوهات : المؤقتات والبرمجة بلغة السلم والبرنامج LDmicro
» ترجمة وإعداد كتاب البرمجة بلغة السى المدمجة وتطبيقات لغة السى والميكروكونترولر PIC مع المترجم CCS C : Embedded C Programming Techniques and Applications of C and PIC® MCUS
» ربط الميكروكونترولر PIC16F877A مع لوحة مفاتيح Keypad ووحدة عرض LCD
» دوائر ( مشاريع ) المؤقتات timers
» فديوهات : المؤقتات والبرمجة بلغة السلم والبرنامج LDmicro
» ترجمة وإعداد كتاب البرمجة بلغة السى المدمجة وتطبيقات لغة السى والميكروكونترولر PIC مع المترجم CCS C : Embedded C Programming Techniques and Applications of C and PIC® MCUS
منتديات الهندسة الكهربية والإلكترونية والميكاترونكس والكومبيوتر :: برمجة الميكروكونترولر PIC بلغة السى مع المترجم CCS - C
صفحة 1 من اصل 1
صلاحيات هذا المنتدى:
لاتستطيع الرد على المواضيع في هذا المنتدى