اردوينو والمقاطع المقاطعات

مرحبا يا هبر! أقدم لكم ترجمة المقال "مقاطعات المؤقت" بقلم E.


مقدمة


تسمح لك لوحة Arduino بحل مجموعة متنوعة من المشكلات بسرعة وبصورة ضئيلة. ولكن عندما تكون هناك حاجة إلى فواصل زمنية تعسفية (الاستقصاء الدوري لأجهزة الاستشعار ، وإشارات PWM عالية الدقة ، والنبضات ذات المدة الطويلة) ، فإن وظائف تأخير المكتبة القياسية ليست مريحة. طوال فترة عملهم ، يتم تعليق الرسم ويصبح من المستحيل إدارته.


في وضع مماثل ، من الأفضل استخدام مؤقتات AVR المدمجة. توضح المقالة الناجحة كيفية القيام بذلك وعدم الضياع في البيانات التقنية لأوراق البيانات ، التي يتم توجيه انتباهك إليها.



تتناول هذه المقالة مؤقتات AVR و Arduino وكيفية استخدامها في مشاريع Arduino ودوائر المستخدم.


ما هو الموقت؟


كما هو الحال في الحياة اليومية في ميكروكنترولر ، فإن المؤقت هو شيء يمكن أن يشير في المستقبل ، في اللحظة التي تحددها. عندما تأتي هذه اللحظة ، يتم مقاطعة المتحكم الدقيق ، مما يذكره بفعل شيء ما ، على سبيل المثال ، لتنفيذ جزء معين من التعليمات البرمجية.


تعمل أجهزة ضبط الوقت ، مثل المقاطعات الخارجية ، بشكل مستقل عن البرنامج الرئيسي. بدلاً من تكرار أو تأخير مكالمة تأخير millis () ، يمكنك تعيين مؤقت للقيام بمهمته بينما يقوم الكود الخاص بك بأشياء أخرى.


لذلك ، افترض أن هناك جهازًا يحتاج إلى القيام بشيء ما ، على سبيل المثال ، وميض مؤشر LED كل 5 ثوانٍ. إذا كنت لا تستخدم أجهزة ضبط الوقت ، ولكنك تكتب رمزًا عاديًا ، فستحتاج إلى ضبط متغير في الوقت الذي يتم فيه إشعال مؤشر LED والتحقق باستمرار من وقت التبديل. مع مقاطعة مؤقت ، تحتاج فقط إلى تكوين المقاطعة ، ثم بدء تشغيل جهاز ضبط الوقت. سوف تومض LED في الوقت المحدد تمامًا ، بغض النظر عن تصرفات البرنامج الرئيسي.


كيف يعمل الموقت؟


وهو يعمل عن طريق زيادة متغير يسمى سجل العد . يمكن أن يحسب سجل العد على قيمة معينة ، حسب حجمه. يزيد المؤقت من عداده مرارًا وتكرارًا حتى يصل إلى الحد الأقصى لقيمةه ، في هذه المرحلة سيتجاوز العداد ويعيد ضبطه إلى الصفر. يضبط المؤقت عادةً إشارة للعلم لإعلامك بحدوث تجاوز سعة.


يمكنك التحقق من هذه العلامة يدويًا أو يمكنك عمل مفتاح مؤقت - مما يؤدي إلى مقاطعة تلقائيًا عند تعيين العلامة. مثل أي مقاطعة أخرى ، يمكنك تعيين " خدمة المقاطعة الروتينية" ( ISR ) لتنفيذ التعليمات البرمجية المحددة عند تجاوز الموقت. سوف يقوم ISR نفسه بمسح علامة الفائض ، لذا فإن استخدام المقاطعات عادة ما يكون الخيار الأفضل بسبب بساطته وسرعته.


لزيادة قيم العداد في فواصل زمنية محددة ، يجب توصيل جهاز ضبط الوقت بمصدر الساعة. مصدر الساعة يولد إشارة متكررة باستمرار. في كل مرة يكتشف الموقت هذه الإشارة ، فإنه يزيد من قيمة العداد بواحد. نظرًا لأن المؤقت يعمل على مصدر مدار الساعة ، فإن أصغر وحدة زمنية يمكن قياسها هي فترة الدورة. إذا قمت بتوصيل إشارة ساعة بتردد 1 ميجاهرتز ، فستكون دقة المؤقت (أو فترة المؤقت):


T = 1 / f (f هو تردد الساعة)
T = 1/1 ميجا هرتز = 1/10 ^ 6 هرتز
T = (1 ∗ 10 ^ -6) s


وبالتالي ، فإن دقة الموقت هي مليون من الثانية. على الرغم من أنه يمكنك استخدام مصدر ساعة خارجي لأجهزة ضبط الوقت ، إلا أنه في معظم الحالات يتم استخدام المصدر الداخلي للرقاقة نفسها.


أنواع الموقت


في لوحات Arduino القياسية على شريحة AVR ذات 8 بتات ، توجد عدة أجهزة توقيت في آن واحد. تحتوي رقائق Atmega168 و Atmega328 على ثلاثة مؤقتات Timer0 و Timer1 و Timer2. لديهم أيضًا جهاز مراقبة مؤقت يمكن استخدامه للحماية من الأعطال أو كآلية لإعادة ضبط البرامج. فيما يلي بعض ميزات كل مؤقت.


timer0:
Timer0 هو مؤقت 8 بت ، مما يعني أنه يمكن لسجل الحساب الخاص به تخزين الأرقام حتى 255 (أي بايت غير موقّع). يتم استخدام Timer0 بواسطة الوظائف المؤقتة القياسية في Arduino مثل delay () و millis () ، لذلك من الأفضل عدم الخلط بينها إذا كنت تهتم بالنتائج.


Timer1:
Timer1 هو مؤقت 16 بت مع الحد الأقصى لقيمة عدد 65535 (عدد صحيح غير موقعة). يستخدم هذا المؤقت مكتبة Arduino Servo ، ضع ذلك في الاعتبار إذا كنت تستخدمه في مشاريعك.


Timer2:
Timer2 8 بت ويشبه Timer0. يتم استخدامه في وظيفة نغمة اردوينو () .


Timer3 ، Timer4 ، Timer5:
تحتوي رقائق ATmega1280 و ATmega2560 (المثبتة في متغيرات Arduino Mega) على ثلاثة أجهزة توقيت إضافية. كل منهم 16 بت ويعمل بالمثل Timer1.


تسجيل التكوين


من أجل استخدام هذه المؤقتات ، لدى AVR سجلات إعدادات. أجهزة ضبط الوقت تحتوي على العديد من هذه السجلات. اثنان منهم - سجلات التحكم في الموقت / العداد تحتوي على متغيرات إعداد وتسمى TCCRxA و TCCRxB ، حيث x هو رقم الموقت (TCCR1A و TCCR1B ، إلخ). يحتوي كل سجل على 8 بتات ويقوم كل بت بتخزين متغير التكوين. فيما يلي تفاصيل ورقة البيانات Atmega328:


TCCR1A
قطعة76543210
0x80COM1A1COM1A0COM1B1COM1B0--WGM11WGM10
للقراءة والكتابةRWRWRWRWRRRWRW
القيمة الأولية00000000

TCCR1B
قطعة76543210
0x81ICNC1ICES1-WGM13WGM12CS12CS11CS10
للقراءة والكتابةRWRWRRWRWRWRWRW
القيمة الأولية00000000

الأهم هي البتات الثلاثة الأخيرة في TCCR1B: CS12 و CS11 و CS10. يحددون تردد ساعة الموقت. عند اختيارهم في مجموعات مختلفة ، يمكنك طلب الموقت للعمل بسرعات مختلفة. فيما يلي جدول ورقة بيانات يصف تأثير وحدات البت المحددة:


CS12CS11CS10تأثير
000لا يوجد مصدر عقارب الساعة (توقف مؤقت / عداد)
001clk_io / 1 (بدون تقسيم)
010clk_io / 8 (مقسم التردد)
011clk_io / 64 (مقسم التردد)
100clk_io / 256 (مقسم التردد)
101clk_io / 1024 (مقسم التردد)
110مصدر عقارب الساعة الخارجي في دبوس T1. الركود قطع مسافة السباق
111مصدر عقارب الساعة الخارجي في دبوس T1. الجبهة قطع مسافة السباق

بشكل افتراضي ، يتم تعيين كل هذه البتات على الصفر.


افترض أنك تريد تشغيل Timer1 بتردد ساعة مع عينة واحدة لكل فترة. عندما تفيض ، تريد استدعاء روتين المقاطعة ، والذي يحول مؤشر LED المتصل بالساق 13 إلى حالة التشغيل أو الإيقاف. في هذا المثال ، سنقوم بكتابة كود Arduino ، لكننا سنستخدم الإجراءات والوظائف الخاصة بمكتبة avr-libc كلما كان ذلك لا يجعل الأمور معقدة للغاية. يمكن أنصار AVR النقي تكييف رمز كما يحلو لهم.


أولاً ، تهيئة الموقت:


// avr-libc library includes #include <avr/io.h> #include <avr/interrupt.h> #define LEDPIN 13 void setup() { pinMode(LEDPIN, OUTPUT); //  Timer1 cli(); //    TCCR1A = 0; //  TCCR1A   0 TCCR1B = 0; //   Timer1 overflow: TIMSK1 = (1 << TOIE1); //  CS10  ,      : TCCR1B |= (1 << CS10); sei(); //    } 

سجل TIMSK1 هو سجل قناع مقاطعة مؤقت / عداد 1. يتحكم في المقاطعة التي يمكن أن يسببها المؤقت. يؤدي إعداد TOIE1 إلى إخبار الموقت بالمقاطعة عند تجاوز الموقت. المزيد عن هذا في وقت لاحق.


عند ضبط CS10 بت ، يبدأ المؤقت في العد ، وبمجرد حدوث مقاطعة فيض ، يتم استدعاء ISR (TIMER1_OVF_vect). يحدث هذا دائمًا عندما تفيض المؤقت.


بعد ذلك نحدد وظيفة المقاطعة ISR:


 ISR(TIMER1_OVF_vect) { digitalWrite(LEDPIN, !digitalRead(LEDPIN)); } 

الآن يمكننا تحديد دورة حلقة () وتبديل الصمام بغض النظر عما يحدث في البرنامج الرئيسي. لإيقاف تشغيل المؤقت ، اضبط TCCR1B = 0 في أي وقت.


كم مرة سوف وميض الصمام؟


تم ضبط Timer1 على مقاطعة تجاوز السعة ولنفترض أنك تستخدم جهاز Atmega328 بتردد ساعة يبلغ 16 ميجا هرتز. نظرًا لأن المؤقت هو 16 بت ، يمكن حسابه إلى الحد الأقصى للقيمة (2 ^ 16 - 1) ، أو 65535. عند 16 ميغا هرتز ، تعمل الدورة 1 / (16 ∗ 10 ^ 6) ثانية أو 6.25e-8 ثانية. وهذا يعني أن 65535 عينة ستحدث في (65535 ∗ 6.25e-8 s) وسيتم استدعاء ISR بعد حوالي 0.0041 ثانية. وهكذا مرة بعد مرة ، كل أربعة آلاف من الثانية. إنه سريع للغاية لرؤية وميض.


إذا طبقنا إشارة PWM سريعة جدًا مع تغطية بنسبة 50٪ على مؤشر LED ، فسيظهر التوهج مستمرًا ، ولكنه أقل سطوعًا من المعتاد. تُظهر مثل هذه التجربة القوة المذهلة للميكروكونترولر - حتى شريحة 8 بت غير مكلفة يمكنها معالجة المعلومات بشكل أسرع بكثير مما يمكننا اكتشافه.


مؤقت الموقت ووضع CTC


للتحكم في الفترة ، يمكنك استخدام فاصل يسمح لك بتقسيم إشارة الساعة إلى درجات مختلفة من اثنين وزيادة فترة المؤقت. على سبيل المثال ، ترغب في وميض LED على فترات من ثانية واحدة. هناك ثلاث بتات CS في سجل TCCR1B تقوم بتعيين الدقة الأنسب. إذا قمت بتعيين البتات CS10 و CS12 باستخدام:


 TCCR1B |= (1 << CS10); TCCR1B |= (1 << CS12); 

ثم يتم تقسيم تردد مصدر الساعة على 1024. وهذا يعطي دقة توقيت من 1 / (16 ∗ 10 ^ 6/1024) أو 6.4e-5 s. الآن سيتجاوز الموقت كل (65535 ∗ 6.4e-5s) أو 4.194 ثانية. انها طويلة جدا.


ولكن هناك وضع مؤقت AVR آخر. ويطلق عليه إعادة تعيين مؤقت توقيت أو CTC. بدلاً من الاعتماد على تجاوز السعة ، يقارن المؤقت العداد الخاص به مع المتغير الذي تم تخزينه مسبقًا في السجل. عندما يتطابق العدد مع هذا المتغير ، يمكن لجهاز ضبط الوقت إما تعيين إشارة أو حدوث مقاطعة ، تمامًا كما في حالة تجاوز السعة.


لاستخدام وضع CTC ، تحتاج إلى فهم عدد الدورات التي تحتاجها للحصول على فاصل زمني من ثانية واحدة. افترض أن نسبة القسمة لا تزال 1024.


سيكون الحساب على النحو التالي:


 (target time) = (timer resolution) * (# timer counts + 1) (# timer counts + 1) = (target time) / (timer resolution) (# timer counts + 1) = (1 s) / (6.4e-5 s) (# timer counts + 1) = 15625 (# timer counts) = 15625 - 1 = 15624 

يجب إضافة وحدة إضافية إلى عدد العينات لأنه في وضع CTC ، عندما يتطابق العداد مع القيمة المحددة ، سيتم إعادة تعيين نفسه إلى صفر. تستغرق إعادة التعيين فترة زمنية واحدة ، والتي يجب أخذها في الاعتبار في الحسابات. في كثير من الحالات ، لا يكون الخطأ في فترة واحدة مهمًا للغاية ، ولكن في المهام عالية الدقة قد يكون حرجًا.


ستكون وظيفة setup () هكذا:


 void setup() { pinMode(LEDPIN, OUTPUT); //  Timer1 cli(); //    TCCR1A = 0; //    0 TCCR1B = 0; OCR1A = 15624; //    TCCR1B |= (1 << WGM12); //   CTC  //   CS10  CS12    1024 TCCR1B |= (1 << CS10); TCCR1B |= (1 << CS12); TIMSK1 |= (1 << OCIE1A); //     sei(); //    } 

تحتاج أيضًا إلى استبدال مقاطعة تجاوز السعة بمقاطعة متزامنة:


 ISR(TIMER1_COMPA_vect) { digitalWrite(LEDPIN, !digitalRead(LEDPIN)); } 

الآن سوف يتم تشغيل وإيقاف LED لثانية واحدة بالضبط. ويمكنك أن تفعل أي شيء في حلقة () حلقة. حتى تقوم بتغيير إعدادات المؤقت ، لا علاقة للبرنامج بالمقاطعات. ليس لديك أي قيود على استخدام مؤقت مع أوضاع مختلفة وإعدادات الفاصل.


فيما يلي مثال بدء كامل يمكنك استخدامه كأساس لمشاريعك الخاصة:


 // Arduino  CTC  // avr-libc library includes #include <avr/io.h> #include <avr/interrupt.h> #define LEDPIN 13 void setup() { pinMode(LEDPIN, OUTPUT); //  Timer1 cli(); //    TCCR1A = 0; //    0 TCCR1B = 0; OCR1A = 15624; //    TCCR1B |= (1 << WGM12); //  CTC  TCCR1B |= (1 << CS10); //      1024 TCCR1B |= (1 << CS12); TIMSK1 |= (1 << OCIE1A); //      sei(); //    } void loop() { //   } ISR(TIMER1_COMPA_vect) { digitalWrite(LEDPIN, !digitalRead(LEDPIN)); } 

تذكر أنه يمكنك استخدام وظائف ISR المضمنة لتوسيع وظائف المؤقت. على سبيل المثال ، تحتاج إلى استطلاع المستشعر كل 10 ثوانٍ. ولكن لا توجد إعدادات المؤقت توفر مثل هذا العدد الطويل دون تجاوز. ومع ذلك ، يمكنك استخدام ISR لزيادة متغير العد مرة واحدة في الثانية ومن ثم استطلاع المستشعر عندما يصل المتغير 10. باستخدام وضع STS من المثال السابق ، قد تبدو المقاطعة كما يلي:


 ISR(TIMER1_COMPA_vect) { seconds++; if(seconds == 10) { seconds = 0; readSensor(); } } 

نظرًا لأن المتغير سيتم تعديله داخل ISR ، فيجب إعلانه على أنه متغير . لذلك ، عند وصف المتغيرات في بداية البرنامج ، تحتاج إلى الكتابة:


 volatile byte seconds; 

المترجم بعد


في وقت واحد ، أنقذني هذا المقال كثيرًا من الوقت عند تطوير مولد لقياس النموذج الأولي. آمل أن يكون مفيدًا للقراء الآخرين.

Source: https://habr.com/ru/post/ar453276/


All Articles