جدول المحتويات:

برنامج AVR Assembler التعليمي 3: 9 خطوات
برنامج AVR Assembler التعليمي 3: 9 خطوات

فيديو: برنامج AVR Assembler التعليمي 3: 9 خطوات

فيديو: برنامج AVR Assembler التعليمي 3: 9 خطوات
فيديو: اتهموها باستغلال الموقف.. ممرضة أميركية تنشر فيديو غريب من داخل مستشفى 2024, يوليو
Anonim
برنامج AVR Assembler التعليمي 3
برنامج AVR Assembler التعليمي 3

مرحبًا بك في البرنامج التعليمي رقم 3!

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

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

على أي حال ، كفى من الفلسفة ، فلنبدأ!

ستحتاج في هذا البرنامج التعليمي إلى:

  1. لوحة النماذج الخاصة بك
  2. مصباح LED
  3. توصيل الأسلاك
  4. مقاوم حوالي 220 إلى 330 أوم
  5. دليل مجموعة التعليمات: www.atmel.com/images/atmel-0856-avr-instruction-se…
  6. ورقة البيانات: www.atmel.com/images/Atmel-8271-8-bit-AVR-Microco …
  7. مذبذب بلوري مختلف (اختياري)

هنا رابط لمجموعة كاملة من البرامج التعليمية:

الخطوة الأولى: إنشاء الدائرة

بناء الدائرة
بناء الدائرة

الدائرة في هذا البرنامج التعليمي بسيطة للغاية. سنقوم بشكل أساسي بكتابة برنامج "blink" لذلك كل ما نحتاجه هو التالي.

قم بتوصيل LED بـ PD4 ، ثم بمقاوم 330 أوم ، ثم بالأرض. بمعنى آخر.

PD4 - LED - R (330) - GND

وهذا هو عليه!

ستكون النظرية صعبة رغم …

الخطوة 2: لماذا نحتاج إلى التعليقات وملف M328Pdef.inc؟

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

هذا هو الكود الذي سنكتبه اليوم ، باستثناء أنني أزلت التعليقات وملف التضمين:

.device ATmega328P

.org 0x0000 jmp a.org 0x0020 jmp ea: ldi r16 ، 0x05 out 0x25 ، r16 ldi r16 ، 0x01 sts 0x6e ، r16 sei clr r16 out 0x26 ، r16 sbi 0x0a ، 0x04 sbi 0x0b ، 0x04 b: sbi 0x0b ، 0x04 rcall c cbi 0x0b ، 0x04 rcall c rjmp bc: clr r17 d: cpi r17 ، 0x1e brne d ret e: inc r17 cpi r17 ، 0x3d brne PC + 2 clr r17 reti

بسيط جدا أليس كذلك؟ هاها. إذا قمت بتجميع هذا الملف وتحميله ، فستتسبب في وميض مؤشر LED بمعدل وميض واحد في الثانية مع استمرار الوميض لمدة 1/2 ثانية والتوقف المؤقت بين الومضات لمدة 1/2 ثانية.

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

لذلك دعونا نضع التعليقات ونعيد تضمين الملف حتى نتمكن من فهمه.

الخطوة 3: Blink.asm

هذا هو الكود الذي سنناقشه اليوم:

;************************************

؛ كتبه: 1o_o7 ؛ تاريخ: ؛ الإصدار: 1.0 ؛ تم حفظ الملف كـ: blink.asm؛ من أجل AVR: atmega328p ؛ تردد الساعة: 16 ميجا هرتز (اختياري) ؛ ************************************** ؛ وظيفة البرنامج: ---------------------؛ يحسب الثواني عن طريق وميض مصباح LED ؛ ؛ PD4 - LED - R (330 أوم) - GND ؛ ؛ --------------------------------------.nolist. تتضمن "./m328Pdef.inc".list ؛ =============== ؛ التصريحات:.def temp = r16.def overflows = r17.org 0x0000؛ الذاكرة (الكمبيوتر) موقع إعادة تعيين معالج rjmp ؛ تكاليف jmp دورتين cpu وتكاليف rjmp 1 فقط ؛ لذلك ما لم تكن بحاجة إلى القفز أكثر من 8 كيلو بايت ؛ ما عليك سوى rjmp. لذلك فإن بعض المتحكمات الدقيقة فقط ؛ لديك rjmp وليس jmp.org 0x0020 ؛ موقع الذاكرة الخاص بمعالج تجاوز التدفق Timer0 rjmp overflow_handler ؛ اذهب هنا إذا حدثت مقاطعة تجاوز timer0 ؛ ============ إعادة التعيين: ldi temp، 0b00000101 out TCCR0B، temp؛ اضبط بتات محدد الساعة CS00 و CS01 و CS02 إلى 101 ؛ هذا يضع Timer Counter0 ، TCNT0 في وضع FCPU / 1024 ؛ لذلك يتم وضع علامة على وحدة المعالجة المركزية freq / 1024 ldi temp ، 0b00000001 sts TIMSK0 ، temp ؛ تعيين بت Timer Overflow Interrupt Enable (TOIE0) ؛ من Timer Interrupt Mask Register (TIMSK0) sei ؛ تمكين المقاطعات العالمية - ما يعادل "sbi SREG، I" clr temp out TCNT0، temp؛ تهيئة المؤقت / العداد إلى 0 sbi DDRD، 4 ؛ تعيين PD4 للإخراج ؛ ======================= ؛ الجسم الرئيسي للبرنامج: blink: sbi PORTD، 4 ؛ قم بتشغيل LED على تأخير PD4 rcall ؛ سيكون التأخير 1/2 ثانية cbi PORTD ، 4 ؛ قم بإيقاف تشغيل LED على تأخير PD4 rcall ؛ سيكون التأخير 1/2 ثانية rjmp وميض ؛ حلقة العودة إلى تأخير البدء: تجاوزات clr ؛ تعيين الفائض إلى 0 sec_count: cpi overflows، 30 ؛ مقارنة عدد الفائض و 30 brne sec_count ؛ التفرع للعودة إلى sec_count إذا لم يكن يساوي ret ؛ إذا حدثت 30 حالة فائضة ، ارجع إلى blink overflow_handler: inc overflows ؛ إضافة 1 إلى التدفقات المتغيرة cpi المتغيرة ، 61 ؛ مقارنة بـ 61 brne PC + 2 ؛ عداد البرنامج + 2 (تخطي السطر التالي) إذا لم يكن مساوياً لتدفق clr ؛ إذا حدث 61 فيضانًا ، فقم بإعادة ضبط العداد إلى صفر reti ؛ العودة من المقاطعة

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

سنناقش ما يفعله كل هذا قطعة قطعة ، لكن دعونا أولاً نحاول الحصول على منظور عالمي. يعمل الجسم الرئيسي للبرنامج على النحو التالي.

أولاً قمنا بتعيين بت 4 من PORTD مع "sbi PORTD، 4" وهذا يرسل 1 إلى PD4 الذي يضع الجهد إلى 5V على هذا الدبوس. سيؤدي هذا إلى تشغيل LED. ثم ننتقل إلى الإجراء الفرعي "تأخير" الذي يعد 1/2 في الثانية (سنشرح كيف يتم ذلك لاحقًا). ثم نعود إلى الوميض والوضوح 4 على PORTD الذي يعين PD4 إلى 0V وبالتالي يغلق LED. ثم نتأخر لمدة 1/2 ثانية أخرى ، ثم ننتقل مرة أخرى إلى بداية الوميض مرة أخرى باستخدام "rjmp blink".

يجب عليك تشغيل هذا الرمز ومعرفة أنه يفعل ما ينبغي.

وهناك لديك! هذا هو كل ما يفعله هذا الرمز ماديًا. إن الآليات الداخلية لما يفعله الميكروكونترولر هي أكثر انخراطًا قليلاً وهذا هو سبب قيامنا بهذا البرنامج التعليمي. لذلك دعونا نناقش كل قسم على حدة.

الخطوة 4: توجيهات المجمع.org

نحن نعلم بالفعل ما تفعله توجيهات.nolist و.list و.include و.def من دروسنا السابقة ، لذلك دعونا أولاً نلقي نظرة على الأسطر الأربعة من التعليمات البرمجية التي تأتي بعد ذلك:

.org 0x0000

إعادة تعيين jmp.org 0x0020 jmp overflow_handler

يخبر بيان.org المُجمِّع بالمكان الموجود في "ذاكرة البرنامج" لوضع العبارة التالية. أثناء تنفيذ برنامجك ، يحتوي "عداد البرامج" (اختصار كـ PC) على عنوان السطر الحالي الجاري تنفيذه. لذلك في هذه الحالة عندما يكون الكمبيوتر عند 0x0000 ، سيرى الأمر "jmp Reset" الموجود في موقع الذاكرة هذا. السبب وراء رغبتنا في إعادة تعيين jmp في هذا الموقع هو أنه عندما يبدأ البرنامج ، أو تتم إعادة تعيين الشريحة ، يبدأ الكمبيوتر في تنفيذ التعليمات البرمجية في هذا المكان. لذا ، كما نرى ، أخبرناها للتو أن "تقفز" على الفور إلى القسم المسمى "إعادة تعيين". لماذا فعلنا ذلك؟ هذا يعني أنه تم تخطي آخر سطرين أعلاه! لماذا ا؟

حسنًا ، هذا هو المكان الذي تصبح فيه الأشياء مثيرة للاهتمام. سيتعين عليك الآن فتح عارض pdf مع ورقة بيانات ATmega328p الكاملة التي أشرت إليها في الصفحة الأولى من هذا البرنامج التعليمي (وهذا هو السبب في أنه العنصر 4 في قسم "ستحتاج"). إذا كانت شاشتك صغيرة جدًا ، أو كان لديك عدد كبير جدًا من النوافذ مفتوحة بالفعل (كما هو الحال معي) ، فيمكنك فعل ما أفعله ووضعه على Ereader ، أو هاتف Android الخاص بك. ستستخدمه طوال الوقت إذا كنت تخطط لكتابة رمز التجميع. الشيء الرائع هو أن جميع وحدات التحكم الدقيقة منظمة بطرق متشابهة جدًا ، وبمجرد أن تعتاد على قراءة أوراق البيانات والترميز منها ، ستجد أنه من التافه فعل الشيء نفسه مع متحكم مختلف. لذلك نحن في الواقع نتعلم كيفية استخدام جميع ميكروكنترولر بمعنى ما وليس فقط atmega328p.

حسنًا ، انتقل إلى الصفحة 18 في ورقة البيانات وألق نظرة على الشكل 8-2.

هذه هي الطريقة التي يتم بها إعداد ذاكرة البرنامج في وحدة التحكم الدقيقة. يمكنك أن ترى أنه يبدأ بالعنوان 0x0000 وينقسم إلى قسمين ؛ قسم فلاش التطبيق وقسم فلاش التمهيد. إذا أشرت بإيجاز إلى الصفحة 277 جدول 27-14 ، فسترى أن قسم فلاش التطبيق يشغل المواقع من 0x0000 إلى 0x37FF ويأخذ قسم فلاش التمهيد المواقع المتبقية من 0x3800 إلى 0x3FFF.

التمرين 1: كم عدد المواقع الموجودة في ذاكرة البرنامج؟ بمعنى آخر. حول 3FFF إلى رقم عشري وأضف 1 منذ أن بدأنا العد عند 0. نظرًا لأن كل موقع ذاكرة يبلغ عرضه 16 بت (أو 2 بايت) ، فما هو العدد الإجمالي لبايتات الذاكرة؟ الآن حول هذا إلى كيلوبايت ، تذكر أن هناك 2 ^ 10 = 1024 بايت في كيلو بايت. ينتقل قسم فلاش التمهيد من 0x3800 إلى 0x37FF ، كم كيلو بايت هذا؟ كم عدد كيلوبايتات الذاكرة المتبقية لنا لاستخدامها في تخزين برنامجنا؟ بمعنى آخر ، ما هو حجم برنامجنا؟ أخيرًا ، كم عدد سطور الكود التي يمكننا الحصول عليها؟

حسنًا ، الآن بعد أن عرفنا كل شيء عن تنظيم ذاكرة برنامج الفلاش ، دعنا نواصل مناقشتنا لبيانات.org. نرى أن موقع الذاكرة الأول 0x0000 يحتوي على تعليماتنا للانتقال إلى القسم الذي أطلقنا عليه اسم إعادة التعيين. الآن نرى ما تفعله عبارة ".org 0x0020". تقول أننا نريد وضع التعليمات الموجودة في السطر التالي في موقع الذاكرة 0x0020. التعليمات التي وضعناها هناك قفزة إلى قسم في الكود الذي قمنا بتسميته "overflow_handler" … الآن لماذا يجب أن نطالب بوضع هذه القفزة في موقع الذاكرة 0x0020؟ لمعرفة ذلك ، ننتقل إلى الصفحة 65 في ورقة البيانات ونلقي نظرة على الجدول 12-6.

الجدول 12-6 عبارة عن جدول "متجهات إعادة التعيين والمقاطعة" ويوضح بالضبط أين سيذهب الكمبيوتر عندما يتلقى "مقاطعة". على سبيل المثال ، إذا نظرت إلى المتجه رقم 1. فإن "مصدر" المقاطعة هو "RESET" والذي تم تعريفه على أنه "External Pin و Power-on Reset و Brown-out Reset و Watchdog system reset" بمعنى ، إذا كان أي من تحدث هذه الأشياء لوحدة التحكم الدقيقة الخاصة بنا ، سيبدأ الكمبيوتر في تنفيذ برنامجنا في موقع ذاكرة البرنامج 0x0000. ماذا عن توجيهاتنا.org إذن؟ حسنًا ، لقد وضعنا أمرًا في موقع الذاكرة 0x0020 ، وإذا نظرت إلى أسفل الجدول ، فسترى أنه في حالة حدوث تجاوز في Timer / Counter0 (قادم من TIMER0 OVF) ، فسيتم تنفيذ كل ما هو موجود في الموقع 0x0020. لذلك عندما يحدث ذلك ، سينتقل الكمبيوتر إلى المكان الذي أطلقنا عليه "overflow_handler". رائع ، أليس كذلك؟ سترى في دقيقة واحدة سبب قيامنا بذلك ، ولكن دعنا أولاً ننهي هذه الخطوة من البرنامج التعليمي جانباً.

إذا أردنا أن نجعل الكود الخاص بنا أكثر تنظيمًا وترتيبًا ، فعلينا بالفعل استبدال الأسطر الأربعة التي نناقشها حاليًا مع ما يلي (انظر الصفحة 66):

.org 0x0000

إعادة تعيين rjmp ؛ الكمبيوتر = 0x0000 reti ؛ الكمبيوتر = 0x0002 reti ؛ الكمبيوتر = 0x0004 reti ؛ الكمبيوتر = 0x0006 reti ؛ الكمبيوتر = 0x0008 reti ؛ الكمبيوتر = 0x000A … reti ؛ PC = 0x001E jmp overflow_handler: PC = 0x0020 reti: PC = 0x0022… reti ؛ الكمبيوتر = 0x0030 reti ؛ الكمبيوتر = 0x0032

لذلك في حالة حدوث مقاطعة معينة ، فسيتم فقط "reti" مما يعني "العودة من المقاطعة" ولن يحدث أي شيء آخر. ولكن إذا لم نقم مطلقًا "بتمكين" هذه المقاطعات المتنوعة ، فلن يتم استخدامها ويمكننا وضع رمز البرنامج في هذه الأماكن. في برنامجنا الحالي "blink.asm" ، سنقوم فقط بتمكين المقاطعة الفائضة timer0 (وبالطبع مقاطعة إعادة التعيين التي يتم تمكينها دائمًا) وبالتالي لن ننزعج عن الآخرين.

كيف يمكننا "تمكين" المقاطعة الفائضة timer0 بعد ذلك؟ … هذا هو موضوع خطوتنا التالية في هذا البرنامج التعليمي.

الخطوة 5: عداد / عداد 0

مؤقت / عداد 0
مؤقت / عداد 0

الق نظرة على الصورة أعلاه. هذه هي عملية اتخاذ القرار في "الكمبيوتر الشخصي" عندما "يقاطع" بعض التأثير الخارجي تدفق برنامجنا. أول شيء يفعله عندما يتلقى إشارة من الخارج بحدوث مقاطعة هو أنه يتحقق لمعرفة ما إذا كنا قد قمنا بتعيين بت "تمكين المقاطعة" لهذا النوع من المقاطعة. إذا لم نقم بذلك ، فسيستمر فقط في تنفيذ السطر التالي من التعليمات البرمجية. إذا قمنا بتعيين بت تمكين المقاطعة المحدد هذا (بحيث يكون هناك 1 في موقع البت هذا بدلاً من 0) ، فسيقوم بعد ذلك بالتحقق مما إذا كنا قد قمنا بتمكين "المقاطعات العامة" أم لا ، وإذا لم يكن الأمر كذلك ، فسوف ينتقل مرة أخرى إلى السطر التالي من التعليمات البرمجية والمتابعة. إذا قمنا بتمكين المقاطعات العالمية أيضًا ، فسيتم الانتقال إلى موقع ذاكرة البرنامج لهذا النوع من المقاطعة (كما هو موضح في الجدول 12-6) وتنفيذ أي أمر وضعناه هناك. لذلك دعونا نرى كيف قمنا بتنفيذ كل هذا في الكود الخاص بنا.

يبدأ قسم إعادة التعيين في الكود الخاص بنا بالسطرين التاليين:

إعادة ضبط:

درجة حرارة ldi ، 0b00000101 خارج TCCR0B ، درجة الحرارة

كما نعلم بالفعل ، يتم تحميل هذا في درجة الحرارة (أي R16) الرقم الذي يليه مباشرة ، وهو 0b00000101. ثم يكتب هذا الرقم إلى السجل المسمى TCCR0B باستخدام أمر "الخروج". ما هو هذا السجل؟ حسنًا ، دعنا ننتقل إلى الصفحة 614 من ورقة البيانات. يوجد هذا في منتصف جدول يلخص كافة السجلات. في العنوان 0x25 ستجد TCCR0B. (أنت تعرف الآن من أين جاء السطر "خارج 0x25 ، r16" في إصدار الكود الذي لم يتم التعليق عليه). نرى من خلال مقطع الكود أعلاه أننا قمنا بتعيين البتة 0 والبت الثاني ومسحنا كل البقية. من خلال النظر إلى الجدول ، يمكنك أن ترى أن هذا يعني أننا قمنا بتعيين CS00 و CS02. الآن دعنا ننتقل إلى الفصل في ورقة البيانات المسمى "8-bit Timer / Counter0 with PWM". على وجه الخصوص ، انتقل إلى الصفحة 107 من هذا الفصل. سترى نفس الوصف لسجل "Timer / Counter Control Register B" (TCCR0B) الذي رأيناه للتو في جدول ملخص السجل (لذلك كان من الممكن أن نأتي إلى هنا مباشرةً ، لكنني أردت أن ترى كيفية استخدام جداول الملخص للرجوع إليها في المستقبل). تستمر ورقة البيانات في إعطاء وصف لكل بت في هذا السجل وماذا تفعل. سنتخطى كل ذلك الآن ونحول الصفحة إلى جدول 15-9. يعرض هذا الجدول "وصف الساعة حدد بت". انظر الآن إلى أسفل هذا الجدول حتى تجد السطر الذي يتوافق مع البتات التي حددناها للتو في ذلك السجل. يقول السطر "clk / 1024 (من مقياس مسبق)". ما يعنيه هذا هو أننا نريد أن يعمل Timer / Counter0 (TCNT0) على طول معدل وهو تردد وحدة المعالجة المركزية مقسومًا على 1024. نظرًا لأن لدينا متحكم دقيق يتم تغذيته بواسطة مذبذب بلوري 16 ميجاهرتز ، فهذا يعني أن معدل تنفيذ وحدة المعالجة المركزية للتعليمات هو 16 مليون تعليمات في الثانية. لذا فإن المعدل الذي سيحدده عداد TCNT0 الخاص بنا هو 16 مليون / 1024 = 15625 مرة في الثانية (جربه باستخدام بتات مختلفة على مدار الساعة وانظر ماذا يحدث - تذكر فلسفتنا؟). دعنا نحتفظ بالرقم 15625 في الجزء الخلفي من أذهاننا لوقت لاحق وننتقل إلى السطرين التاليين من الكود:

درجة حرارة ldi ، 0b00000001

sts TIMSK0 ، درجة الحرارة

يقوم هذا بتعيين البت 0 من السجل المسمى TIMSK0 ويمسح كل البقية. إذا ألقيت نظرة على الصفحة 109 في ورقة البيانات ، فسترى أن TIMSK0 تعني "Timer / Counter Interrupt Mask Register 0" وقد قام الكود الخاص بنا بتعيين البت 0 الذي يسمى TOIE0 والذي يرمز إلى "Timer / Counter0 Overflow Interrupt Enable" … هناك! الآن ترى ما هو كل هذا. لدينا الآن "مجموعة بت تمكين المقاطعة" كما أردنا من القرار الأول في صورتنا في الأعلى. لذا الآن كل ما يتعين علينا القيام به هو تمكين "المقاطعات العالمية" وسيتمكن برنامجنا من الاستجابة لهذا النوع من المقاطعات. سنقوم بتمكين المقاطعات العالمية قريبًا ، ولكن قبل أن نفعل ذلك ربما تكون قد ارتبكت بسبب شيء ما.. لماذا استخدمت الأمر "sts" لنسخه في سجل TIMSK0 بدلاً من "الخروج" المعتاد؟

كلما رأيتني أستخدم تعليمات لم ترها من قبل ، فإن أول شيء يجب عليك فعله هو الانتقال إلى الصفحة 616 في ورقة البيانات. هذا هو "ملخص مجموعة التعليمات". ابحث الآن عن التعليمات "STS" التي استخدمتها. تقول أنها تأخذ رقمًا من سجل R (استخدمنا R16) وموقع "التخزين مباشرة إلى SRAM" (في حالتنا التي قدمها TIMSK0). فلماذا يتعين علينا استخدام "sts" التي تستغرق دورتين على مدار الساعة (انظر العمود الأخير في الجدول) للتخزين في TIMSK0 واحتجنا فقط إلى "out" ، والتي تستغرق دورة ساعة واحدة فقط للتخزين في TCCR0B من قبل؟ للإجابة على هذا السؤال ، نحتاج إلى العودة إلى جدول ملخص السجل الخاص بنا في الصفحة 614. هل ترى أن سجل TCCR0B موجود على العنوان 0x25 ولكن أيضًا على (0x45) ، أليس كذلك؟ هذا يعني أنه سجل في SRAM ، ولكنه أيضًا نوع معين من التسجيل يسمى "المنفذ" (أو سجل الإدخال / الإخراج). إذا نظرت إلى جدول ملخص التعليمات بجانب الأمر "out" ، فسترى أنه يأخذ قيمًا من "سجلات العمل" مثل R16 ويرسلها إلى PORT. لذلك يمكننا استخدام "out" عند الكتابة إلى TCCR0B ونوفر على أنفسنا دورة ساعة. لكن الآن ابحث عن TIMSK0 في جدول التسجيل. ترى أنه يحتوي على عنوان 0x6e. هذا خارج نطاق المنافذ (التي هي فقط مواقع 0x3F الأولى من SRAM) ولذا عليك الرجوع إلى استخدام الأمر sts وأخذ دورتين على مدار الساعة لوحدة المعالجة المركزية للقيام بذلك. يرجى قراءة الملاحظة 4 في نهاية جدول ملخص التعليمات في الصفحة 615 الآن. لاحظ أيضًا أن جميع منافذ الإدخال والإخراج ، مثل PORTD موجودة في أسفل الجدول. على سبيل المثال ، PD4 هو بت 4 على العنوان 0x0b (الآن ترى من أين أتت جميع العناصر 0x0b في الكود الذي لم يتم التعليق عليه!).. حسنًا ، سؤال سريع: هل غيرت "sts" إلى "خارج" وانظر ماذا يحدث؟ تذكر فلسفتنا! حطمها! لا تأخذ كلامي على أنها أشياء.

حسنًا ، قبل أن ننتقل ، انتقل إلى الصفحة 19 في ورقة البيانات لمدة دقيقة. ترى صورة لذاكرة البيانات (SRAM). أول 32 تسجيلًا في SRAM (من 0x0000 إلى 0x001F) هي "سجلات العمل للأغراض العامة" R0 إلى R31 التي نستخدمها طوال الوقت كمتغيرات في التعليمات البرمجية الخاصة بنا.السجلات الـ 64 التالية هي منافذ الإدخال / الإخراج حتى 0x005f (أي تلك التي كنا نتحدث عنها والتي تحتوي على تلك العناوين غير الموضوعة بين قوسين بجانبها في جدول التسجيل والتي يمكننا استخدام الأمر "out" بدلاً من "sts") أخيرًا يحتوي القسم التالي من SRAM على جميع السجلات الأخرى في جدول الملخص حتى العنوان 0x00FF ، وأخيرًا الباقي هو SRAM الداخلي. الآن بسرعة ، دعنا ننتقل إلى الصفحة 12 لمدة ثانية. هناك ترى جدول "سجلات العمل للأغراض العامة" التي نستخدمها دائمًا كمتغيرات لدينا. هل ترى الخط السميك بين الأرقام من R0 إلى R15 ثم من R16 إلى R31؟ هذا السطر هو سبب استخدامنا دائمًا لـ R16 كأصغر واحد وسأدخله أكثر قليلاً في البرنامج التعليمي التالي حيث سنحتاج أيضًا إلى سجلات العناوين غير المباشرة الثلاثة ذات 16 بت ، X و Y و Z. لن أفعل الدخول في ذلك حتى الآن على الرغم من أننا لسنا بحاجة إليه الآن ونحن متورطون بدرجة كافية هنا.

اقلب صفحة واحدة للخلف إلى الصفحة 11 من ورقة البيانات. سترى رسمًا تخطيطيًا لسجل SREG في أعلى اليمين؟ ترى أن الجزء 7 من هذا السجل يسمى "أنا". انتقل الآن إلى أسفل الصفحة واقرأ وصف Bit 7…. ياي! إنه بت تمكين المقاطعة العالمية. هذا هو ما نحتاج إلى ضبطه لتمرير القرار الثاني في الرسم التخطيطي أعلاه والسماح لمقاطعات تجاوز التدفق المؤقت / العداد في برنامجنا. لذلك يجب أن يكون السطر التالي من برنامجنا كالتالي:

sbi SREG، I

الذي يحدد البت المسمى "I" في سجل SREG. ومع ذلك ، بدلاً من هذا استخدمنا التعليمات

ساي

في حين أن. يتم تعيين هذا البت في كثير من الأحيان في البرامج التي جعلوا طريقة أبسط للقيام بذلك.

تمام! الآن لدينا المقاطعات الفائضة جاهزة للعمل حتى يتم تنفيذ "jmp overflow_handler" كلما حدث ذلك.

قبل أن ننتقل ، ألق نظرة سريعة على سجل SREG (سجل الحالة) لأنه مهم جدًا. اقرأ ما يمثله كل من الأعلام. على وجه الخصوص ، ستعمل العديد من التعليمات التي نستخدمها على تعيين هذه العلامات والتحقق منها طوال الوقت. على سبيل المثال ، سنستخدم لاحقًا الأمر "CPI" والذي يعني "قارن فوري". ألق نظرة على جدول ملخص التعليمات لهذه التعليمات ولاحظ عدد العلامات التي تحددها في عمود "العلامات". هذه كلها علامات في SREG وسيقوم الكود الخاص بنا بإعدادها والتحقق منها باستمرار. سترى أمثلة قريبا. أخيرًا ، الجزء الأخير من هذا القسم من الكود هو:

درجة الحرارة CLR

خارج TCNT0 ، temp sbi DDRD ، 4

السطر الأخير هنا واضح جدًا. يقوم فقط بتعيين البت الرابع من سجل اتجاه البيانات لـ PortD مما يتسبب في إخراج PD4.

الأول يضبط درجة الحرارة المتغيرة على الصفر ثم ينسخ ذلك إلى سجل TCNT0. TCNT0 هو عدادنا / عداد 0. هذا يضعه على الصفر. بمجرد أن ينفذ الكمبيوتر هذا الخط ، سيبدأ timer0 من الصفر ويحسب بمعدل 15625 مرة كل ثانية. المشكلة هي: TCNT0 هو تسجيل "8 بت" صحيح؟ إذن ما هو أكبر رقم يمكن أن يحتويه سجل 8 بت؟ حسنًا 0b11111111 هو عليه. هذا هو الرقم 0xFF. وهو 255. هل ترى ماذا سيحدث؟ يقوم المؤقت بضغط على طول 15625 مرة في الثانية وفي كل مرة يصل إلى 255 "يفيض" ويعود إلى الصفر مرة أخرى. في نفس الوقت الذي يعود فيه إلى الصفر ، فإنه يرسل إشارة Timer Overflow Interrupt. الكمبيوتر يحصل على هذا وأنت تعرف ماذا يفعل الآن؟ نعم. ينتقل إلى موقع ذاكرة البرنامج 0x0020 وينفذ التعليمات التي يجدها هناك.

رائعة! إذا كنت لا تزال معي فأنت بطل خارق لا يكل! لنستمر…

الخطوة 6: معالج الفائض

لذلك لنفترض أن عداد الوقت / سجل عداد 0 قد فاض للتو. نحن نعلم الآن أن البرنامج يستقبل إشارة مقاطعة وينفذ 0x0020 التي تخبر Program Counter ، الكمبيوتر الشخصي للانتقال إلى التسمية "overflow_handler" التالي هو الكود الذي كتبناه بعد هذا الملصق:

معالج_ تجاوز السعة:

inci overflows cpi overflows، 61 brne PC + 2 clr overflows reti

أول شيء تفعله هو زيادة المتغير "overflows" (وهو اسمنا للأغراض العامة ، سجل R17) ثم "يقارن" محتويات الفائض بالرقم 61. الطريقة التي تعمل بها تعليمات CPI هي أنها تطرح ببساطة الرقمان وإذا كانت النتيجة صفرًا ، فسيتم تعيين علامة Z في سجل SREG (أخبرتك أننا سنرى هذا السجل طوال الوقت). إذا كان الرقمان متساويين ، فسيكون علم Z هو 1 ، وإذا كان الرقمان غير متساويين ، فسيكون 0.

السطر التالي يقول "brne PC + 2" وهو ما يعني "الفرع إن لم يكن متساويًا". بشكل أساسي ، يتحقق من علامة Z في SREG وإذا لم يكن واحدًا (أي أن الرقمين غير متساويين ، إذا كانا متساويين ، فسيتم تعيين علامة الصفر) فروع الكمبيوتر الشخصي إلى PC + 2 ، مما يعني أنه يتخطى التالي ينتقل مباشرة إلى "reti" التي تعود من المقاطعة إلى أي مكان كانت فيه في الكود عند وصول المقاطعة. إذا وجدت تعليمات brne 1 في بت العلم الصفري ، فلن تتفرع ، وبدلاً من ذلك ستستمر فقط إلى السطر التالي الذي من شأنه أن يتدفق clr لإعادة تعيينه إلى 0.

ما هي النتيجة الصافية لكل هذا؟

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

الآن لماذا في العالم نفعل ذلك؟

لنرى. تذكر أن سرعة الساعة لوحدة المعالجة المركزية لدينا هي 16 ميجاهرتز وقمنا "بقياسها مسبقًا" باستخدام TCCR0B بحيث لا يحسب المؤقت إلا بمعدل 15625 حسابًا في الثانية ، أليس كذلك؟ وفي كل مرة يصل فيها العداد إلى 255 يفيض. هذا يعني أنه يفيض 15625/256 = 61.04 مرة في الثانية. نحن نتتبع عدد الفائض باستخدام المتغير "الفائض" ونقارن هذا الرقم بـ 61. لذلك نرى أن "الفائض" سيساوي 61 مرة كل ثانية! لذلك سيعيد معالجنا "الفائض" إلى الصفر مرة كل ثانية. لذا ، إذا أردنا ببساطة مراقبة "الفائض" المتغير وتدوين كل مرة يتم فيها إعادة التعيين إلى الصفر ، فسنحسب ثانية بثانية في الوقت الفعلي (لاحظ أنه في البرنامج التعليمي التالي سنعرض كيفية الحصول على مزيد من الدقة التأخير بالمللي ثانية بنفس الطريقة التي يعمل بها روتين "تأخير" اردوينو).

الآن لدينا "معالجة" المقاطعات تجاوز سعة المؤقت. تأكد من فهمك لكيفية عمل ذلك ، ثم انتقل إلى الخطوة التالية حيث نستفيد من هذه الحقيقة.

الخطوة 7: التأخير

الآن بعد أن رأينا أن روتين معالج المقاطعة تجاوز التدفق "overflow_handler" الخاص بنا سيضبط المتغير "الفائض" على الصفر مرة كل ثانية يمكننا استخدام هذه الحقيقة لتصميم روتين فرعي "تأخير".

ألق نظرة على الكود التالي من تحت تأخيرنا: label

تأخير:

clr overflows sec_count: cpi overflows، 30 brne sec_count ret

سنقوم باستدعاء هذا الإجراء الفرعي في كل مرة نحتاج فيها إلى تأخير في برنامجنا. الطريقة التي يعمل بها هي أولاً تعيين المتغير "الفائض" على الصفر. ثم يدخل منطقة تسمى "sec_count" ويقارن الفائض بـ 30 ، إذا لم تكن متساوية ، فإنه يتفرع مرة أخرى إلى التصنيف sec_count ويقارن مرة أخرى ، ومرة أخرى ، وما إلى ذلك حتى يتساوى في النهاية (تذكر أنه طوال الوقت سيستمر هذا في معالج المقاطعة المؤقت الخاص بنا ، يستمر في زيادة تدفق المتغير وبالتالي فهو يتغير في كل مرة نتجول فيها هنا. عندما تساوي الفيضانات أخيرًا 30 ، فإنها تخرج من الحلقة وتعود إلى المكان الذي نسميه التأخير: من. النتيجة الصافية هي تأخير 1/2 ثانية

التمرين 2: قم بتغيير إجراء overflow_handler إلى ما يلي:

معالج_ تجاوز السعة:

المؤتمر الوطني العراقي يفيض reti

وتشغيل البرنامج. هل هناك شيء مختلف؟ لما و لما لا؟

الخطوة 8: وميض

أخيرًا ، لنلقِ نظرة على روتين الوميض:

رمش:

sbi PORTD ، 4 rcall DELAY CBI PORTD ، 4 rcall تأخير rjmp وميض

أولاً نقوم بتشغيل PD4 ، ثم نطلق على روتين التأخير. نحن نستخدم rcall بحيث عندما يصل الكمبيوتر إلى عبارة "ret" سيعود إلى السطر الذي يلي rcall. ثم تأخيرات روتين التأخير لمدة 30 حسابًا في متغير الفائض كما رأينا وهذا تقريبًا 1/2 ثانية بالضبط ، ثم نوقف PD4 ، ونؤخر 1/2 ثانية أخرى ، ثم نعود إلى البداية مرة أخرى.

النتيجة النهائية هي ضوء LED وامض!

أعتقد أنك ستوافق الآن على أن "blink" ربما ليس أفضل برنامج "hello world" في لغة التجميع.

التمرين 3: قم بتغيير المعلمات المختلفة في البرنامج بحيث يومض LED بمعدلات مختلفة مثل ثانية أو 4 مرات في الثانية ، وما إلى ذلك. التمرين 4: قم بتغييره بحيث يتم تشغيل وإيقاف تشغيل LED لفترات زمنية مختلفة. التمرين 5: قم بتغيير ساعة TCCR0B وحدد وحدات بت إلى 100 ثم استمر في الصعود على الجدول. في أي نقطة يصبح من غير الممكن تمييزه عن برنامجنا "hello.asm" من البرنامج التعليمي 1؟ التمرين 6 (اختياري): إذا كان لديك مذبذب بلوري مختلف ، مثل 4 ميجاهرتز أو 13.5 ميجاهرتز أو أيًا كان ، فقم بتغيير مذبذب 16 ميجاهرتز على اللوح الخاص بك للوحة الجديدة وشاهد كيف يؤثر ذلك على معدل وميض مؤشر LED. يجب أن تكون الآن قادرًا على متابعة الحساب الدقيق والتنبؤ بالضبط بمدى تأثيره على المعدل.

الخطوة 9: الخاتمة

لأولئك منكم الذين وصلوا إلى هذا الحد ، تهانينا!

أدرك أنه من الصعب جدًا العمل عندما تقوم بالقراءة والبحث عن المزيد مما تفعله وتجربته ، لكن أتمنى أن تكون قد تعلمت الأشياء المهمة التالية:

  1. كيف تعمل ذاكرة البرنامج
  2. كيف يعمل SRAM
  3. كيف تبحث عن السجلات
  4. كيفية البحث عن التعليمات ومعرفة ما يفعلونه
  5. كيفية تنفيذ المقاطعات
  6. كيف ينفذ CP الكود ، وكيف يعمل SREG ، وماذا يحدث أثناء المقاطعات
  7. كيف تفعل الحلقات والقفزات وترتد في الكود
  8. ما مدى أهمية قراءة ورقة البيانات!
  9. كيف بمجرد أن تعرف كيفية القيام بكل هذا من أجل متحكم Atmega328p ، سيكون الأمر بمثابة نزهة نسبية لتعلم أي وحدات تحكم جديدة تهتم بها.
  10. كيفية تغيير وقت وحدة المعالجة المركزية إلى الوقت الفعلي واستخدامه في إجراءات التأخير.

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

التمرين 7: "اكسر" الشفرة بطرق مختلفة وانظر ماذا سيحدث! فضول الطفل العلمي! التمرين 8: قم بتجميع الكود باستخدام الخيار "-l" لإنشاء ملف قائمة. بمعنى آخر. "avra -l blink.lst blink.asm" وإلقاء نظرة على ملف القائمة. رصيد إضافي: يختلف الكود الذي لم يتم التعليق عليه والذي قدمته في البداية والشفرة المعلقة التي نناقشها لاحقًا! هناك سطر واحد من التعليمات البرمجية مختلف. هل تستطيع ايجاده؟ لماذا لا يهم هذا الاختلاف؟

أتمنى أنك أستمتعت! أراك في المرة القادمة …

موصى به: