- لماذا المؤقت عندما يكون لدينا تأخير ()؟
- مؤقتات متحكم الموافقة المسبقة عن علم:
- شرح البرمجة والعمل:
- مخطط الدائرة ومحاكاة المتقلبة:
سيكون هذا هو البرنامج التعليمي الخامس في سلسلة دروس PIC ، والتي ستساعدك على تعلم واستخدام المؤقتات في PIC16F877A. في دروسنا السابقة ، بدأنا بمقدمة عن PIC و MPLABX IDE ، ثم كتبنا أول برنامج PIC لميض LED باستخدام PIC ثم صنعنا تسلسل وميض LED باستخدام وظيفة التأخير في PIC Microcontroller. الآن ، دعنا نستخدم نفس تسلسل وميض LED الذي استخدمناه في أجهزة البرنامج التعليمي السابقة ، وبهذا سوف نتعلم كيفية استخدام المؤقتات في PIC MCU. لقد أضفنا للتو زرًا آخر في لوحة LED لهذا البرنامج التعليمي. اذهب من خلال البرنامج التعليمي لمعرفة المزيد.
الموقتات هي واحدة من أحصنة العمل المهمة للمبرمج المضمن. سيشمل كل تطبيق نصممه بطريقة ما تطبيق توقيت ، مثل تشغيل أو إيقاف تشغيل شيء ما بعد فترة زمنية محددة. حسنًا ، ولكن لماذا نحتاج إلى أجهزة ضبط الوقت عندما يكون لدينا بالفعل وحدات ماكرو تأخير (__delay_ms ()) نفعل نفس الشيء !!
لماذا المؤقت عندما يكون لدينا تأخير ()؟
يسمى ماكرو التأخير تأخير "تفريغ". لأنه أثناء تنفيذ وظيفة التأخير ، يجلس MCU على التفريغ بمجرد إنشاء تأخير. خلال هذه العملية ، لا تستطيع MCU الاستماع إلى قيم ADC الخاصة بها أو قراءة أي شيء من سجلاتها. ومن ثم لا يُنصح باستخدام وظائف التأخير باستثناء التطبيقات مثل وميض LED حيث لا يلزم أن يكون تأخير الوقت دقيقًا أو طويلاً.
تحتوي وحدات ماكرو التأخير أيضًا على العناصر القصيرة التالية ،
- يجب أن تكون قيمة التأخير ثابتة لوحدات ماكرو التأخير ؛ لا يمكن تغييره أثناء تنفيذ البرنامج. ومن ثم يبقى تعريف المبرمج.
- لن يكون التأخير دقيقًا مقارنة باستخدام المؤقتات.
- لا يمكن إنشاء قيم أكبر للتأخيرات باستخدام وحدات الماكرو ، على سبيل المثال لا يمكن إنشاء تأخير لمدة نصف ساعة بواسطة وحدات ماكرو التأخير. يعتمد الحد الأقصى للتأخير الذي يمكن استخدامه على مذبذب الكريستال المستخدم.
مؤقتات متحكم الموافقة المسبقة عن علم:
فيزيائيًا ، المؤقت هو سجل تتزايد قيمته باستمرار إلى 255 ، ثم يبدأ من جديد: 0 ، 1 ، 2 ، 3 ، 4… 255…. 0 ، 1 ، 2 ، 3…..إلخ.
تحتوي PIC16F877A PIC MCU على ثلاث وحدات مؤقت. وهي أسماء مثل Timer0 و Timer1 و Timer2. Timer 0 و Timer 2 عبارة عن مؤقتات 8 بت و Timer 1 هو Timer 16 بت. في هذا البرنامج التعليمي ، سنستخدم Timer 0 لتطبيقنا. بمجرد أن نفهم Timer 0 ، سيكون من السهل العمل على Timer 1 و Timer 2 أيضًا.
يحتوي عداد / عداد وحدة Timer0 على الميزات التالية:
- عداد / عداد 8 بت
- مقروء وقابل للكتابة
- جهاز قياس مسبق برمجي 8 بت قابل للبرمجة
- تحديد الساعة الداخلية أو الخارجية
- مقاطعة عند التدفق من FFh إلى 00h
- حدد الحافة للساعة الخارجية
لبدء استخدام مؤقت ، يجب أن نفهم بعض المصطلحات الفاخرة مثل مؤقت 8 بت / 16 بت ، و Prescaler ، و Timer interrupts و Focs. الآن ، دعونا نرى ما يعنيه كل واحد حقًا. كما ذكرنا سابقًا ، هناك كلا من مؤقتات 8 بت و 16 بت في PIC MCU ، والفرق الرئيسي بينهما هو أن المؤقت 16 بت لديه دقة أفضل بكثير من المؤقت 8 بت.
Prescaler هو اسم جزء من متحكم يقسم ساعة المذبذب قبل أن تصل إلى المنطق الذي يزيد من حالة المؤقت. يتراوح نطاق معرف prescaler من 1 إلى 256 ويمكن ضبط قيمة Prescaler باستخدام OPTION Register (نفس الرقم الذي استخدمناه لسحب المقاومات). على سبيل المثال إذا كانت قيمة و prescaler هي 64، ثم كل 64 عشر نبض الموقت سيتم بمقدار 1.
عندما يزداد المؤقت وعندما يصل إلى قيمته القصوى البالغة 255 ، فإنه سيطلق مقاطعة ويعيد تهيئة نفسه إلى الصفر مرة أخرى. تسمى هذه المقاطعة باسم Timer Interrupt. يُعلم هذا المقاطعة MCU أن هذا الوقت المحدد قد انقسم.
و FOSC لتقف على التردد من المذبذب ، هو تواتر الكريستال المستخدمة. الوقت المستغرق لسجل المؤقت يعتمد على قيمة Prescaler وقيمة Fosc.
شرح البرمجة والعمل:
في هذا البرنامج التعليمي ، سنقوم بتعيين زرين كمدخلين و 8 LED كثمانية مخرجات. سيتم استخدام الزر الأول لضبط التأخير الزمني (500 مللي ثانية لكل ضغطة) وسيتم استخدام الزر الثاني لبدء وميض تسلسل المؤقت. على سبيل المثال ، إذا تم الضغط على الزر الأول ثلاث مرات (500 * 3 = 1500 مللي ثانية) ، فسيتم ضبط التأخير على 1.5 ثانية وعندما يتم الضغط على الزر الثاني ، سيتم تشغيل وإيقاف كل مؤشر LED مع التأخير الزمني المحدد مسبقًا. تحقق من فيديو العرض التوضيحي في نهاية هذا البرنامج التعليمي.
الآن ، مع وضع هذه الأساسيات في الاعتبار ، دعونا نلقي نظرة على برنامجنا المقدم في النهاية في قسم التعليمات البرمجية.
لا بأس إذا لم تحصل على البرنامج إلا إذا حصلت عليه !! امنح نفسك ملف تعريف ارتباط وتفريغ البرنامج للاستمتاع بإنتاجك. بالنسبة للآخرين ، سأقسم البرنامج إلى أجزاء ذات معنى وأشرح لك ما يحدث في كل كتلة.
كما هو الحال دائمًا ، فإن الأسطر القليلة الأولى من الكود هي إعدادات التكوين وملفات الرأس ، لن أشرح ذلك لأنني قمت بذلك بالفعل في دروسي التعليمية السابقة.
بعد ذلك ، دعنا نتخطى جميع الخطوط ونقفز مباشرة إلى الوظيفة الرئيسية الفارغة ، والتي يوجد بداخلها تكوين PORT لـ Timer0.
void main () {/ ***** تهيئة المنفذ لـ Timer ****** / OPTION_REG = 0b00000101؛ // Timer0 مع التكرار الخارجي و 64 كمقياس مسبق // يتيح أيضًا PULL UPs TMR0 = 100 ؛ // قم بتحميل القيمة الزمنية لـ 0.0019968 ثانية ؛ يمكن أن تتراوح قيمة delayValue بين 0-256 فقط TMR0IE = 1 ؛ // تمكين بت مقاطعة المؤقت في سجل PIE1 GIE = 1 ؛ // Enable Global Interrupt PEIE = 1 ؛ // تمكين المقاطعة الطرفية / *********** ______ *********** /
لفهم ذلك علينا أن ننظر إلى سجل الخيارات في ورقة بيانات الموافقة المسبقة عن علم.
كما تمت مناقشته في البرنامج التعليمي السابق ، يتم استخدام البتة 7 لتمكين مقاومة سحب ضعيفة لـ PORTB. انظر إلى الشكل أعلاه ، فإن البت 3 مصنوع 0 لإرشاد MCU إلى ضرورة استخدام المقياس المسبق التالي الذي يتم تعيينه للموقت وليس لـ WatchDogTimer (WDT). يتم تحديد وضع المؤقت بمسح البت 5 T0CS
(OPTION_REG <5>)
الآن ، يتم استخدام bits2-0 لتعيين قيمة المقياس المسبق للمؤقت. كما هو موضح في الجدول أعلاه لتعيين قيمة ما قبل المقياس 64 ، يجب ضبط البتات على 101.
بعد ذلك ، دعونا نلقي نظرة على السجلات المرتبطة بـ Timer0
سيبدأ المؤقت في الزيادة بمجرد التعيين والتجاوز بعد الوصول إلى قيمة 256 ، لتمكين مقاطعة المؤقت خلال هذه النقطة ، يجب ضبط السجل TMR0IE على درجة عالية. نظرًا لأن Timer 0 نفسه هو جهاز طرفي ، يتعين علينا تمكين المقاطعة المحيطية من خلال جعل PEIE = 1. أخيرًا ، يتعين علينا تمكين المقاطعة العالمية بحيث يتم إخطار MCU بالمقاطعة أثناء أي عملية ، ويتم ذلك عن طريق جعل GIE = 1.
التأخير = ((256-REG_val) * (Prescal * 4)) / Fosc
يتم استخدام الصيغة أعلاه لحساب قيمة التأخير.
أين
REG_val = 100 ؛
بريسكال = 64
Fosc = 20000000
هذا على الحساب يعطي ،
التأخير = 0.0019968 ثانية
المجموعة التالية من الخطوط هي تعيين منافذ الإدخال / الإخراج.
/ ***** تكوين المنفذ لـ I / O ****** / TRISB0 = 1 ؛ // قم بإرشاد MCU إلى أن PORTB pin 0 يستخدم كمدخل للزر 1. TRISB1 = 1 ؛ // إرشاد MCU إلى أن منفذ PORTB pin 1 يستخدم كمدخل للزر 1. TRISD = 0x00 ؛ // إرشاد MCU إلى أن جميع المسامير الموجودة على المنفذ D هي إخراج PORTD = 0x00 ؛ // تهيئة جميع المسامير إلى 0 / *********** ______ *********** /
هذا هو نفسه الموجود في برنامجنا التعليمي السابق لأننا نستخدم نفس الجهاز. إلا أننا أضفنا زرًا آخر كمدخل. يتم ذلك بواسطة السطر TRISB1 = 1.
بعد ذلك ، داخل حلقة أثناء اللانهاية ، لدينا كتلتان من التعليمات البرمجية. يتم استخدام أحدهما للحصول على إدخال المؤقت من المستخدم والآخر لتنفيذ تسلسل التأخير عبر مصابيح LED. لقد شرحت لهم باستخدام التعليقات مقابل كل سطر.
بينما (1) {عدد = 0 ؛ // لا تقم بتشغيل المؤقت أثناء التواجد في الحلقة الرئيسية // ******* احصل على تأخير الرقم من المستخدم **** ////// if (RB0 == 0 && flag == 0) // متى الإدخال معطى {get_scnds + = 1 ؛ // get_scnds = get_scnds + http: // علامة متغير الزيادة = 1 ؛ } if (RB0 == 1) // لمنع علامة الزيادة المستمرة = 0 ؛ / *********** ______ *********** /
يتم زيادة متغير يسمى get_scnds في كل مرة يضغط فيها المستخدم على الزر 1. يتم استخدام متغير علامة (برنامج محدد) للاحتفاظ بالعملية المتزايدة حتى يزيل المستخدم إصبعه من الزر.
// ******* تنفيذ التسلسل بتأخير **** ////// بينما (RB1 == 0) {PORTD = 0b00000001 <
يبدأ تشغيل الكتلة التالية إذا تم الضغط على الزر الثاني. نظرًا لأن المستخدم قد حدد بالفعل التأخير الزمني المطلوب باستخدام الزر الأول وتم حفظه في المتغير get_scnds. نستخدم متغيرًا يسمى hscnd ، ويتم التحكم في هذا المتغير بواسطة ISR (روتين خدمة المقاطعة).
و روتين خدمة المقاطعة هو المقاطعة التي سوف يطلق في كل مرة Timer0 غير الفيضانات. دعونا نرى كيف يتم التحكم فيه بواسطة ISR في الكتلة التالية ، مثل أننا نريد زيادة التأخير الزمني بمقدار نصف ثانية (0.5 ثانية) على كل ضغطة زر ، ثم نحتاج إلى زيادة hscnd المتغير لكل نصف ثانية. نظرًا لأننا قمنا ببرمجة عداد الوقت الخاص بنا على التدفق الزائد لكل 0.0019968 ثانية (حوالي 2 مللي ثانية) ، لذلك لحساب متغير نصف ثانية يجب أن يكون 250 لأن 250 * 2 مللي ثانية = 0.5 ثانية. لذلك عندما يصل العد إلى 250 (250 * 2 مللي ثانية = 0.5 ثانية) ، فهذا يعني أنه كان نصف ثانية ، لذلك نزيد hscnd بمقدار 1 ونبدأ العد إلى الصفر.
void interrupt timer_isr () {if (TMR0IF == 1) // تم تشغيل علامة Timer بسبب تجاوز الموقت {TMR0 = 100 ؛ // قم بتحميل قيمة المؤقت TMR0IF = 0 ؛ // مسح عداد إشارة مقاطعة العد ++ ؛ } إذا (العد == 250) {hscnd + = 1 ؛ // hscnd ستزداد لكل نصف ثانية = 0 ؛ }}
لذلك نستخدم هذه القيمة ونقارنها بـ hscnd الخاص بنا ونحول مؤشر LED الخاص بنا بناءً على الوقت الذي يحدده المستخدم. إنه أيضًا مشابه جدًا للدورة التعليمية الأخيرة.
هذا كل شيء لدينا فهم برنامجنا والعمل.
مخطط الدائرة ومحاكاة المتقلبة:
كالعادة ، يتيح التحقق من المخرجات باستخدام Proteus أولاً ، لقد ربطت هنا الملفات التخطيطية لـ Proteus.
أضف زرًا إلى لوحة LED السابقة وأجهزتنا جاهزة للعمل. يجب أن يبدو مثل هذا:
بعد الانتهاء من الاتصال ، قم بتحميل الرمز وتحقق من الإخراج. إذا كان لديك أي مشكلة يرجى استخدام قسم التعليقات. تحقق أيضًا من الفيديو أدناه لفهم العملية برمتها.