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

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

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

فيديو: برنامج AVR Assembler التعليمي 2: 4 خطوات
فيديو: Example of an AVR Assembly Program 2024, يوليو
Anonim
برنامج AVR Assembler التعليمي 2
برنامج AVR Assembler التعليمي 2

هذا البرنامج التعليمي هو استمرار لـ "AVR Assembler Tutorial 1"

إذا لم تكن قد مررت بالبرنامج التعليمي 1 ، فيجب عليك التوقف الآن والقيام بذلك أولاً.

في هذا البرنامج التعليمي ، سنواصل دراستنا لبرمجة لغة التجميع لـ atmega328p المستخدمة في Arduino.

سوف تحتاج:

  1. لوحة توصيل Arduino أو مجرد Arduino عادي كما في البرنامج التعليمي 1
  2. مصباح LED
  3. مقاوم 220 أوم
  4. زر ضغط
  5. توصيل الأسلاك لعمل الدائرة على اللوح الخاص بك
  6. دليل مجموعة المثيل: www.atmel.com/images/atmel-0856-avr-instruction-s…
  7. ورقة البيانات: www.atmel.com/images/Atmel-8271-8-bit-AVR-Microco …

يمكن العثور على المجموعة الكاملة من البرامج التعليمية الخاصة بي هنا:

الخطوة 1: بناء الدائرة

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

تحتاج أولاً إلى إنشاء الدائرة التي سنقوم بدراستها في هذا البرنامج التعليمي.

هذه هي الطريقة التي يتم توصيلها بها:

PB0 (دبوس رقمي 8) - LED - R (220 أوم) - 5 فولت

PD0 (دبوس رقمي 0) - زر ضغط - GND

يمكنك التحقق من أن مؤشر LED الخاص بك موجه بشكل صحيح عن طريق توصيله بـ GND بدلاً من PB0. إذا لم يحدث شيء ، فعكس الاتجاه ويجب أن يضيء الضوء. ثم أعد توصيله بـ PB0 وتابع. تُظهر الصورة كيفية توصيل لوح اردوينو الخاص بي.

الخطوة 2: كتابة كود التجميع

كتابة كود التجميع
كتابة كود التجميع

اكتب الكود التالي في ملف نصي يسمى pushbutton.asm وقم بتجميعه باستخدام avra كما فعلت في البرنامج التعليمي 1.

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

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

؛ كتبه: 1o_o7 ؛ التاريخ: 23 أكتوبر 2014 ؛ **************************************

.nolist

. تتضمن "m328Pdef.inc".list.def temp = r16 ؛ تعيين سجل العمل r16 كـ temp rjmp Init ؛ تم تنفيذ السطر الأول

فيه:

درجة الحرارة اضبط كل البتات في درجة الحرارة على 1. خارج DDRB ، درجة الحرارة ؛ تعيين بت كـ 1 على Data Direction I / O ؛ التسجيل في PortB ، وهو DDRB ، يحدد ذلك ؛ دبوس كإخراج ، سيؤدي الرقم 0 إلى تعيين هذا الدبوس كمدخل ؛ حتى هنا ، جميع دبابيس PortB عبارة عن نواتج (مضبوطة على 1) ldi temp ، 0b11111110 ؛ تحميل الرقم "الفوري" في السجل المؤقت ؛ إذا كانت مجرد ld ثم الوسيطة الثانية ؛ يجب أن يكون موقع ذاكرة بدلاً من DDRD ، temp ؛ mv temp إلى DDRD ، والنتيجة هي أن PD0 هو إدخال ؛ والباقي نواتج clr temp ؛ جميع وحدات البت في temp مضبوطة على 0's out PortB ، temp ؛ اضبط جميع البتات (أي الدبابيس) في PortB على 0V ldi temp ، 0b00000001 ؛ تحميل رقم فوري لدرجة الحرارة خارج PortD ، temp ؛ نقل درجة الحرارة إلى PortD. PD0 لديه مقاومة سحب. (أي ضبط على 5V) لأنه يحتوي على 1 في تلك البتة ؛ الباقي هو 0V منذ 0.

الأساسية:

في درجة الحرارة ، رقم التعريف الشخصي ؛ يحمل PinD حالة PortD ، انسخ هذا إلى temp ؛ إذا كان الزر متصلاً بـ PD0 فسيكون هذا ؛ 0 عند الضغط على الزر ، 1 بخلاف ذلك ؛ يحتوي PD0 على مقاوم سحب يكون عادةً عند 5 فولت من PortB ، درجة الحرارة ؛ يرسل 0 و 1 للقراءة أعلاه إلى PortB ؛ هذا يعني أننا نريد توصيل LED بـ PB0 ، عندما يكون PD0 منخفضًا ، فإنه يضبط PB0 على LOW ويتحول ؛ على LED (نظرًا لأن الجانب الآخر من LED ؛ متصل بـ 5V وهذا سيحدد PB0 إلى 0V ، لذا سيتدفق التيار) rjmp Main ؛ حلقات العودة إلى بداية الرئيسي

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

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

الخطوة 3: تحليل الكود سطراً بسطر

سأتخطى الأسطر التي هي مجرد تعليقات لأن الغرض منها بديهي.

.nolist

تتضمن قائمة "m328Pdef.inc"

تتضمن هذه الأسطر الثلاثة الملف الذي يحتوي على تعريفات Register و Bit لـ ATmega328P التي نقوم ببرمجتها. يخبر الأمر.nolist المُجمّع بعدم تضمين هذا الملف في ملف pushbutton.lst الذي ينتجه عند تجميعه. يقوم بإيقاف تشغيل خيار القائمة. بعد تضمين الملف ، نعيد تشغيل خيار القائمة مرة أخرى باستخدام الأمر list. سبب قيامنا بذلك هو أن ملف m328Pdef.inc طويل جدًا ولا نحتاج حقًا إلى رؤيته في ملف القائمة. مُجمِّعنا ، avra ، لا يُنشئ تلقائيًا ملف قائمة وإذا أردنا واحدًا ، فسنجمعه باستخدام الأمر التالي:

avra -l pushbutton.lst زر الضغط

إذا قمت بذلك ، فسيتم إنشاء ملف يسمى pushbutton.lst وإذا قمت بفحص هذا الملف ستجد أنه يعرض رمز البرنامج الخاص بك إلى جانب معلومات إضافية. إذا نظرت إلى المعلومات الإضافية ، فسترى أن الأسطر تبدأ بحرف C: متبوعًا بالعنوان النسبي في شكل سداسي عشري حيث يتم وضع الرمز في الذاكرة. يبدأ بشكل أساسي عند 000000 مع الأمر الأول ويزيد من هناك مع كل أمر لاحق. العمود الثاني بعد المكان النسبي في الذاكرة هو الكود السداسي للأمر متبوعًا بالرمز السداسي عشرية لوسيطة الأمر. سنناقش ملفات القائمة بشكل أكبر في البرامج التعليمية المستقبلية.

.def temp = r16 ؛ تعيين سجل العمل r16 كدرجة الحرارة

في هذا السطر ، نستخدم توجيه المجمع ".def" لتعريف المتغير "temp" على أنه يساوي r16 "سجل العمل". سنستخدم السجل r16 باعتباره الرقم الذي يخزن الأرقام التي نريد نسخها إلى منافذ وسجلات مختلفة (لا يمكن الكتابة إليها مباشرة).

التمرين 1: حاول نسخ رقم ثنائي مباشرة في منفذ أو سجل خاص مثل DDRB وانظر ماذا يحدث عندما تحاول تجميع الكود.

يحتوي السجل على بايت (8 بتات) من المعلومات. بشكل أساسي هو عبارة عن مجموعة من مزلاج SR ، كل منها عبارة عن "بت" وتحتوي على 1 أو 0. قد نناقش هذا (وحتى نبني واحدة!) لاحقًا في هذه السلسلة. قد تتساءل ما هو "سجل العمل" ولماذا اخترنا r16. سنناقش ذلك في برنامج تعليمي مستقبلي عندما نغوص في مستنقع الأجزاء الداخلية للرقاقة. في الوقت الحالي ، أريدك أن تفهم كيفية القيام بأشياء مثل كتابة التعليمات البرمجية والبرمجة المادية. ثم سيكون لديك إطار مرجعي من تلك التجربة والذي سيجعل الذاكرة وتسجيل خصائص المتحكم أسهل في الفهم. أدرك أن معظم الكتب المدرسية التمهيدية والمناقشات تفعل ذلك في الاتجاه المعاكس ، لكنني وجدت أن ممارسة لعبة فيديو لفترة من الوقت أولاً للحصول على منظور عالمي قبل قراءة دليل التعليمات أسهل بكثير من قراءة الدليل أولاً.

rjmp التهيئة ؛ تم تنفيذ السطر الأول

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

فيه:

درجة الحرارة اضبط كل البتات في درجة الحرارة على 1.

بعد تسمية التهيئة نقوم بتنفيذ أمر "set register". يؤدي هذا إلى تعيين كل 8 بتات في السجل "temp" (التي تتذكرها هي r16) على 1. لذا تحتوي درجة الحرارة الآن على 0b11111111.

خارج DDRB ، درجة الحرارة ؛ تعيين بت كـ 1 في سجل إدخال / إخراج توجيه البيانات

؛ بالنسبة لـ PortB ، وهو DDRB ، يعين هذا الدبوس كإخراج ؛ 0 من شأنه تعيين هذا الدبوس كمدخل ؛ حتى هنا ، جميع دبابيس PortB عبارة عن نواتج (مضبوطة على 1)

يخبر سجل DDRB (سجل اتجاه البيانات لـ PortB) المسامير الموجودة على PortB (أي PB0 إلى PB7) المعينة كمدخلات والتي تم تعيينها كمخرجات. نظرًا لأن لدينا دبوس PB0 متصل بمؤشر LED الخاص بنا والباقي غير متصل بأي شيء ، فسنقوم بتعيين كل البتات على 1 مما يعني أنها جميعها مخرجات.

ldi temp ، 0b11111110 ؛ قم بتحميل الرقم "الفوري" في السجل المؤقت

؛ إذا كانت مجرد ld ، فستكون الوسيطة الثانية ؛ يجب أن يكون موقعًا في الذاكرة

يقوم هذا الخط بتحميل الرقم الثنائي 0b11111110 في السجل المؤقت.

خارج DDRD ، درجة الحرارة ؛ mv temp إلى DDRD ، والنتيجة هي أن PD0 هو إدخال و

؛ الباقي نواتج

الآن قمنا بتعيين سجل اتجاه البيانات لـ PortD من temp ، نظرًا لأن درجة الحرارة لا تزال تحتوي على 0b11111110 ، نرى أنه سيتم تعيين PD0 كدبوس إدخال (نظرًا لوجود 0 في أقصى اليمين) ويتم تعيين الباقي كمخرجات نظرًا لوجود 1 في تلك الأماكن.

درجة الحرارة CLR جميع وحدات البت في temp مضبوطة على 0

خارج المنفذ ، درجة الحرارة ؛ اضبط كل البتات (أي الدبابيس) في PortB على 0V

أولاً نقوم "بمسح" درجة حرارة التسجيل مما يعني تعيين كل وحدات البت على الصفر. ثم نقوم بنسخ ذلك إلى سجل PortB الذي يحدد 0V على كل تلك المسامير. يعني الصفر على بت PortB أن المعالج سيبقي هذا الدبوس عند 0 فولت ، وسيؤدي واحدًا على بت إلى ضبط هذا الدبوس على 5 فولت.

التمرين 2: استخدم مقياسًا متعددًا للتحقق مما إذا كانت جميع المسامير الموجودة على PortB صفرية بالفعل. هل هناك شيء غريب يحدث مع PB1؟ أي فكرة لماذا قد يكون ذلك؟ (على غرار التمرين 4 أدناه ثم اتبع التعليمات البرمجية…) التمرين 3: قم بإزالة السطرين أعلاه من التعليمات البرمجية الخاصة بك. هل لا يزال البرنامج يعمل بشكل صحيح؟ لماذا ا؟

درجة حرارة ldi ، 0b00000001 ؛ تحميل رقم فوري لدرجة الحرارة

خارج المنفذ ، درجة الحرارة ؛ نقل درجة الحرارة إلى PortD. PD0 عند 5 فولت (له مقاومة سحب) ؛ نظرًا لأنه يحتوي على 1 في ذلك الجزء ، فإن الباقي هو 0 فولت. التمرين 4: قم بإزالة السطرين أعلاه من التعليمات البرمجية الخاصة بك. هل لا يزال البرنامج يعمل بشكل صحيح؟ لماذا ا؟ (هذا يختلف عن التمرين 3 أعلاه. راجع الرسم التخطيطي المعلق. ما هو إعداد DDRD الافتراضي لـ PD0؟ (انظر الصفحة 90 من ورقة البيانات

أولاً نقوم "بتحميل فوري" الرقم 0b00000001 إلى درجة الحرارة. الجزء "الفوري" موجود لأننا نقوم بتحميل رقم مباشر إلى مؤقت بدلاً من مؤشر إلى موقع ذاكرة يحتوي على الرقم المراد تحميله. في هذه الحالة سنستخدم ببساطة "ld" بدلاً من "ldi". ثم نرسل هذا الرقم إلى PortD الذي يحدد PD0 إلى 5V والباقي على 0V.

الآن قمنا بتعيين المسامير كمدخلات أو مخرجات وقمنا بإعداد حالاتها الأولية إما 0V أو 5V (LOW أو HIGH) ولذا فإننا ندخل الآن برنامجنا "loop".

الرئيسي: في درجة الحرارة ، PinD ؛ يحمل PinD حالة PortD ، انسخ هذا إلى temp

؛ إذا كان الزر متصلاً بـ PD0 فسيكون هذا ؛ a 0 عند الضغط على الزر ، 1 بخلاف ذلك ؛ يحتوي PD0 على مقاومة سحب يكون عادةً عند 5 فولت

يحتوي السجل PinD على الحالة الحالية لدبابيس PortD. على سبيل المثال ، إذا قمت بتوصيل سلك 5 فولت بـ PD3 ، فعند دورة الساعة التالية (والتي تحدث 16 مليون مرة في الثانية نظرًا لأن لدينا المتحكم الدقيق متصل بإشارة ساعة 16 ميجاهرتز) بت PinD3 (من الحالة الحالية لـ PD3) سيصبح 1 بدلاً من 0. لذا في هذا السطر نقوم بنسخ الحالة الحالية للمسامير إلى درجة الحرارة.

خارج المنفذ ، درجة الحرارة ؛ يرسل 0 و 1 للقراءة أعلاه إلى PortB

؛ هذا يعني أننا نريد توصيل LED بـ PB0 ، لذلك ؛ عندما يكون PD0 منخفضًا ، فإنه سيضبط PB0 على LOW ويتحول ؛ على LED (الجانب الآخر من LED متصل ؛ بـ 5V وهذا سيضبط PB0 على 0V بحيث يتدفق التيار)

نرسل الآن حالة المسامير في PinD إلى إخراج PortB. بشكل فعال ، هذا يعني أن PD0 سيرسل 1 إلى PortD0 ما لم يتم الضغط على الزر. في هذه الحالة ، نظرًا لأن الزر متصل بالأرض ، سيكون هذا الدبوس عند 0 فولت وسيقوم بإرسال 0 إلى PortB0. الآن ، إذا نظرت إلى الرسم البياني للدائرة ، فإن 0V على PB0 يعني أن مؤشر LED سوف يتوهج لأن الجانب الآخر منه عند 5V. إذا لم نضغط على الزر ، بحيث يتم إرسال 1 إلى PB0 ، فهذا يعني أن لدينا 5 فولت على PB0 وأيضًا 5 فولت على الجانب الآخر من مؤشر LED وبالتالي لا يوجد فرق محتمل ولن يتدفق أي تيار وهكذا لن يتوهج LED (في هذه الحالة ، يكون مصباح LED عبارة عن صمام ثنائي وبالتالي يتدفق التيار فقط في اتجاه واحد بغض النظر عن أي شيء آخر).

rjmp الرئيسية حلقات العودة إلى البداية

هذه القفزة النسبية تعيدنا إلى Main: التسمية ونتحقق من PinD مرة أخرى وهكذا. التحقق من كل 16 مليون من الثانية ما إذا كان يتم الضغط على الزر وضبط PB0 وفقًا لذلك.

التمرين 5: قم بتعديل الكود الخاص بك بحيث يتصل مؤشر LED الخاص بك بـ PB3 بدلاً من PB0 ولاحظ أنه يعمل. التمرين 6: قم بتوصيل مؤشر LED الخاص بك في GND بدلاً من 5V وقم بتعديل الكود وفقًا لذلك.

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

في هذا البرنامج التعليمي ، قمنا بفحص لغة التجميع الخاصة بـ ATmega328p وتعلمنا كيفية التحكم في LED باستخدام زر ضغط. على وجه الخصوص تعلمنا الأوامر التالية:

يحدد سجل ser جميع وحدات البت في السجل إلى 1

يعيّن clr register جميع وحدات البت في السجل إلى 0

في السجل ، يقوم i / o register بنسخ الرقم من i / o register إلى سجل العمل

في البرنامج التعليمي التالي ، سنقوم بفحص هيكل ATmega328p والسجلات المختلفة والعمليات والموارد الموجودة فيه.

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

موصى به: