# الميكرو كونترولر انواعه و برمجته و استخداماته



## ماجد عباس محمد (4 يونيو 2018)

*الميكروكونترولر *

*هذاالشرح يتناول أنواع الميكروكونتروللر،وشرح لأهم عائلتين هما أتمل **Atmel **وعائلة ميكرو تشيب **PIC **ويتناول الحاجة إليهم و استخداماتهم و ماتصلح له وما لا تصلح و كيفية برمجتهم بلغات عدة**.*
*ليس الهدف أن أجعلك محترفا ولا أن أكشف لك خبايا اللغات ولكن يكفينى أن أبين لك فروق هذه الأمور وأن أضعك على الطريق و عليك أن تختار الأنسب لك وهذا الاختيار هو مايجعلك تصل للاحترافية لكن لو فرضت عليك طريقا ، قد يكون الأفضل لغيرك لكن الأفض للك شيء آخر.*
*قد تبدو المقدمة التالية طويلة بعض الشيء لكنها ضرورة لوضع أساس حوار تركيبه الداخلى و لغات البرمجة.*
*كيف بدأ*

*منذبدء الحضارة و سعى الإنسان لصنع آله حاسبة لتسرع الإنجاز و تتجنب الأخطاء ولاحقا تتجنب النسيان و توصل العديد من العلماء لآلات و لكنها عجزت عن الطلب الأخير فمفهوم الذاكرة و التذكر كان صعب التحقيق حتى توصل العالم **LeeDe Forest **لى دى فورست لوضع شبكة للتحكم فى مسارالإلكترونات فصنع أول صمام مكبر و من ثم أمكن عمل أول حاسب آلى إلكترونى تماثلى حقق كافة العلاقات الرياضية المعقدة مثل اللوغاريتمات و الحسابات المثلثية وحتى استخدمت كثير من الوسائل لتحقيق الذاكرة مثل الشرائط المثقبة أو الأجزاء المتحركةالخ لكن ظلت العقبة الرئيسية هى سهولةالبرمجة**.كانت الوظائف تصنع فى صناديق قياسية بعرض **19بوصة و البرمجة بتثبيتها فى دولاب خاص يسمى راك **19بوصة ثم توصل الصناديق ببعضها بكابلات و أيضاعمل حاسب يؤدى عدة وظائف تختار بينها بمفتاح صعبة لكون الأسلاك تحد من سرعةالاستجابة فتبطئ الأداء**.*
*سعى العلماء لتصغير **ألصمامات الإلكترونية **بهدف تصغير الحجم و تقليل الفاقد فى حرارةالتسخين و تقليل الفولت المطلوب لتشغيلها من مئات لأقل من مائه فولت.صممت كافة الدوائر المنطقية بألصمامات و صمم المذبذب متعدد التوافقيات **(سلسلةتصميم الدوائر المنطقية**)وألذى اعتبر أول خلية ذاكرة سهلة التطبيقثم تطورت لعمل مسجلات و بوابات أمكن الوصوللأول حاسب آلى إلكترونى فى الأربعينات سمى *ENIAC*اختصارجمله **ElectronicNumerical Integrator and Computer**وكان يشغل مبنى كاملا و له مبنى ملحق لأجهزةالتكييف و التبريد و كانت سرعته بلغت **2ميجاهرتز و كان وقتها سحرا – تخيل أن تقوم بمليونى عملية حساب فى الثانية الواحدةو ذكر أحدهم أننا لو بنينا جهاز آخر سيكفي انحاجة العالم من الحسابات و الآن كل من الديه حاسبان على الأقل فى يده، الهاتف المحمول و الساعة **...*
*حتى هذا الوقت اقتصرت الدوائر المتكاملة على المقاومات و المكثفات بهدف تصغير الحجم و تقليل الوصلات.*
*فى ديسمبر 1947توصل العلماء لأول ترانزستور من الجرمانيوم و الثنائيات من المواد الصلبة وأضافت الدوائر المتكاملة الثنائيات فقط لعدم ملاءمة الجرمانيوم لهذا الأسلوب فى التصنيع. ظهرت عائلات رقمية مثل عائلة RDL وهى المقاومة و الثنائى و DTLأوالثنائى مع الترانزستور فى صورة كروت إلكترونية قابلة للوضع فى قاعدة Plugin أوالرفع و الاستبدال.*
*عندم اتمكن العلماء من استخدام السيليكون أمكن صنع أول دوائر متكاملة تحتوى ترانزستورات و صنعت عائلة TTLالشهيرة و صنعت حاسبات تسمى مينى كمبيوتر و هيكل أساسى MainFrame وهى"العملاقة وقتها"ولم تصل لجزء من مائه من هاتفك المحمول.*
*أغلب الحاسبات وقتها صنعت طبقا لنسق سمى هارفاردحيث يكون مكان حفظ البيانات و مسار حفظها مستقلين تماما عن مكان حفظ البرنامج (الكود)ومسار التعامل معه وهذا وفر المرونة والسرعة حيث لا يجب تساوى عرض كل منهما وطلب ومعالجة أحدهما لا يتعارض مع التعامل مع الآخر و كان عادة البرنامج فى كروت مثقبة أو شريط مثقوب و البيانات فى وسائل كهر وميكانيكية .*
*الهيكل الأساسى لحاسب آلى تبلور فى وحدة معالجة مركزية للحساب و المنطق و حولها الذاكرة و وسائل إدخال و إخراج .*
*بعد تطور TTLأمكن صنع وحدة معالجة مركزية فى صورة دائرة متكاملة وهى 74181ولاحقا المعدلة 74881 وهى قادرة على تنفيذ 16عملية حسابية أو منطقية جمع أو طرح أو إزاحة أومقارنة أو دوال المنطق المعروفة AND-OR-XORوالمتمم أو Complementعلى4 بت معا وهى 24طرف و بسرعة تصل إلى أكثر من 10ميجا و قابلة للامتداد أى توصل بعضها ببعض للتعامل مع 8بت أو اكثر.*
 *ظهور دوائر منطقية من عائلات أخرى مثل NMOS, PMOS عازل أكسيد السيليكون الموجب و السالب القناة،ولاحقا CMOS عازل أكسيد السيليكون مع المكمل، مكن من تصغيرحجم الترانزستور بصورة كبيرة و أمكن من دمج وحدة المعالجة السابقة مع مثيلتها لمعالجة 8بت معا و إضافة مراكمات و عداد للبرنامج وحافظ للبيانات تحت المعالجة و ظهرت طريقة"فون نيومن" فى الحاسبات حيث تكون خطوات البرنامج والبيانات فى ذات الذاكرة و بتتابع، أى كود أمر يليه البيان ألذى يتعامل معه وسميت ميكروبروسيسور لأنها تعالج البيانات..*
*أشهرهذه الميكروبروسيسور هو 8080 وألذى أنتجته إنتيل و ألذى تفوقت عليه شركة زيلوج بالميكرو Z80 وألذى أصبح عصب كل الحاسبات الشخصية و تبنتIBM هذاالنوع من إنتيل وهذا سبب شهرته لكن باقى الشركات استخدمت Z80 لأفضليته و سهولة استخدامه و منافستها الأساسية شركة موتورولا انتجت MC6800 وألذى كان أسهل بكثير فى الاستخدام و أنسب للماكينات و الصناعة عموما وهنا مقارنة بينهما*





*كل منهما 40 طرف بنسق DIP اختصار DualInline Package وتشمل على حافلة للعنوان AddressBus من16 طرف يتيح أقصى تناول للذاكرة 16كيلوبايت أو 65536 خانه، و أخرى للبيانات DataBuss من8 بت تتيح التعامل مع بايت كاملة فى المرةالواحدة وثالثة للتحكم ControlBuss أوأحيانا SystemBuss وأطراف التغذية و كانت تعمل بكريستال 2ميجا و أقصاها وصل 4 ميجا.*
*على اليمين نجد Z80 ونجد حافلة ألعنوان AddressBus تشمل الجزء العلوى على الجانبين (أطراف من 1:5 على الجانب الأيسر ثم من 30:40 على الجانب الأيمن) بينما فى 6800 نجدها مرتبة بالتتالي على الجانب الأيسر من الطرف 9 وحتى 20 ثم الجانب الأيمن حتى 25.*
*حافلة البيانات DataBuss فى Z80 فى الأطراف 14 ثم 15 ثم 12 ثم 8 ثم7 ثم9 ثم10 ثم13 مقابل اليسرى مرتبة .*
*لاننسى هنا ذكر شركة روكويل و منتجها 6500 وهىما اختارته شركة أبل لحاسباتها.*
*لاننسى أن كل هذه الميكرو لم يحتوى ذاكرة ودوما كنا نشترى ذاكرة لحاسباتنا ولم يحتوى اتصال تسلسلي ولا عدادات تايمر ولا محول تماثلى رقمى – الحساب و المقارنة و المنطق فقط و الحساب كان جمع وطرح فقط أما الضرب و القسمة فكان لها معالج مساعد Co-processor لمعالجة الضرب و القسمة و الأرقام العشرية و كل هذه الخواص كانت إضافات محيطية ولها ماسمى بروسيسور خاص بها.*
*معذرة للإطالة لكن هذا تسبب فى الحاجة لأشياء هامة جدا تربط مفاهيم لغات البرمجة وأكوادها Software مع المكونات الملموسة Hardware ومدى حاجتنا لأى منهما فى عالم الميكرو،هذا موضوعنا القادم بإذن الله*


----------



## ماجد عباس محمد (4 يونيو 2018)

*بدء التشغيل و البايوس bios*

بدء التشغيل و البايوس BIOS
كل ميكرو يجب أن يبدأ بالريسيت Reset ألذى يحدد له مكان فى الذاكرة يبدأ به فيضع على حافلة العنوان رقم الخانة المقصودة ثم يضع إشارة قراءة من الذاكرة على حافلة التحكم فتجيبه الذاكرة بمحتواها وهنا تحدد وحدة المعالجة ما إن كانت الخطوة التالية هى بيان مطلوب أو أمر جديد فمثلا أمر المتمم Complement يكون للمراكم فقط ولا يتطلب بيانات أخرى على العكس من أمر الجمع مثلا سيحتاج ما نجمعه.
الحاسبات الصغيرة تعمل على ملف واحد فقط له بداية واحدة فقط يبدأ منها ليشعر المستخدم أنه يعمل ثم يختار المستخدم لعبة ما أو برنامج وحيد لكى يشغله لكن، هل هذا البرنامج لا يحفظ بيانات؟
هنا تظهر مشكلة كبيرة وهى كيف؟
سنحتاج مكان ثم نقسم المكان لوحدات و نعطى البيانات اسما – أصبحت ملف ، و هنا نشأت الحاجة لنظام تشغيل يتولى هذه الأمور. يفرق بين أنواع الملفات و يحتفظ بفهرس للملفات و أماكنها و إن تم تعديل أحدها إين تضاف الزيادة؟ و إن حذف كيف نحررها من الفهرس الخ. باختصار نظام تشغيل Operating system لمعالجة هذه الأمور.
هنا ظهرت الحاجة لوسائط تخزين غير الذاكرة تكون دائمة عند غلق الجهاز مثل القرص الصلب أو المرن الخ.


مما سبق بات واضحا أن تركيب الحاسب أصبح مفتوحا للخيارات الشخصية فقد أشترى قرص صلب أو لا و قد أركب قارئ أقراص مرنة أو لا وقد احتاج لأن ابدأ من خارج الجهاز كليا، لذا كان لابد من استخدام نظام أساسيات الإدخال و الإخراج Basic Input Output System و اختصارا BIOS لكى ندل الميكرو ما لديه من وسائل الإدخال و الإخراج و أيها يبدأ منها التشغيل حيث يجد نظام التشغيل و ألذى بدأ بالدوس DOS وهى اختصار Disk Operating System أى نظام تشغيل الأقراص و ألذى مازال يستخدم حتى وقت كتابة هذه الكلمات ثم الويندوز وغيرهما من الأنظمة مثل يونكس و لينكس الخ.
تطور الجيل التالى و استخدم 16 بت للبيانات و طبيعى أن ينشدوا حجم أكبر من البيانات و البرامج و سرعات اكبر أى 24 بت للعنوان مع 16 بت للبيانات و لذا استخدموا 48 طرف فى صورة متكاملة مربعة و تصل حتى 64 طرف.
لكن ما تلى ذلك من أجيال سعت لحجم أكبر من الذاكرة ولم تعد هذه الأشكال من المتكاملات مناسبة لذا لجأوا لعدة صفوف داخل بعضها مثل إنتيل 486 حيث لونت الصف الخارجى باللون الأحمر و الأوسط بالأخضر و الداخلى بالأصفر و تسمى PGA اختصارا Pin Grid Array مصفوفة الأطراف الشبكية.




الآن هذه لا تصلح لك ولى فهى تتطلب بوردة متعددة الطبقات كما أيضا لها احتياطات خاصة لسرعتها العالية و التى زادت عن 100 ميجا فلا يجب أن تتغير ألسعات فى أطراف البيانات حتى لا تصل بعض أطرافها متأخرة عن الأخرى من الذاكرة.
من أهم الأمور أن أوضح لك أن حافلة العنوان وحافلة البيانات كانت تصل الميكروبروسيسور بالذواكر وكافة المحيطات، أجل كل الأطراف السبعة و عشرون. 
حقا هم 16 للعنوان مع 8 للبيانات أى 24 ثم خط تحكم يحدد ما إن كان التعامل مع الذاكرة أم محيطات IO request و نظرا لإضطراب القيم على الحافلات هناك خط تحكم آخر يسمى العنوان صحيح Valid Memory Address اختصارا VMA أى أن الميكروبروسيسور قد وضع العنوان النهائى وهو هكذا ببساطة فلا أريد أن أعقد لك الأمور بخاصية DMA أو Direct Memory Access حيث تتولى الأجهزة التعامل مع الذاكرة دون تدخل الميكرو والتى تضيف خطين تحكم أخريين 
Buss request , Buss Available 
- و فى النهاية خط يسمى ألفاز2 أو أک2 وهى الجزء من الدورة التى تشمل من2 :4 نبضة و التى سيقرأ فيها الميكروبروسيسور البيان.


هنا نشأت الحاجة لعمل الميكروكونتروللر أى العودة للجذور من جديد حتى تتمكن انت و أنا من صنع بوردة بإمكانياتنا المحدودة و أن نضع هذا الميكرو على بوردة تجميع Bread Board و نجرى تجاربنا وهو موضوعنا القادم إن شاء الله


----------



## ماجد عباس محمد (5 يونيو 2018)

*العودة للجذور*

 العودة للجذور:
مما سبق وجدنا أن الحاجة نشأت لعدة أمور مثل:
1- ألعودة للشكل الأساسى DIP أو المربعة على أقصى تقدير لتمكين الشخص ألعادى من التعامل معه.
2- السرعات المتوسطة و التى لا تشكل عائقا فى التنفيذ.
3- الإسغناء عن نظام التشغيل و من ثم البايوس و ترك الميكرو متاح للمبرمج لكى يتعامل معه مباشرة على مستوى المكونات الداخلية.
4- التخلص من صعوبة توصيل 16 خط للعنوان مع 8 خط للبيانات و باقى التحكم أى 29 طرف و من ثم العودة لنظام هارفارد أى ذاكرة مستقلة للبرنامج و أخرى مستقلة للبيانات.
5- من النقطة السابقة يمكن التخلص كليا من 24 طرف و بعض خطوط التحكم بجعل الذواكر كلها داخلية و احتواء المداخل و المخارج Input Output ما أمكن داخل الميكرو وبعض الوظائف الطرفية مثل التواصل التسلسلى و التحويل تماثلى لرقمى و من ثم أصبحت كافة الأطراف متاحة للمبرمج للتحكم فى العالم الخارجى و تحسس وسائل التحكم مثل الحساسات و المفاتيح
6- لم تعد هناك حاجة لكل التعليمات فى الميكروبروسيسور لذا سنستغنى عن التعليمات التى ستتم فى الذاكرة و نكتفى بالتعليمات التى تتم بين الذاكرة ووحدة المعالجة فقط و نسمى هذا مجموعة الأوامر المخفضة Reduced Instruction Set Computer اختصاراRISC رغم أن هذا يتطلب زيادة عدد خطوات تنفيذ ذات المهمة للحاجة لنقل البيان الأول لوحدة المعالجة ثم نقل النتيجة للذاكرة.

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

تنافست شركات عديدة فى إنتاج هذا الشكل و أصبح لكل منها منتج له خواصه و ميزاته و مجالاته الأنسب لكن أشهرها كان من إنتاج إنتيل و سمى C51 و ميكرو تشيب. إلا أن إنتيل باعت منتجها لشركة أتميل و التى سمته بدورها AT89x5x حيث AT تعنى Atmel و 89 رقم المجموعة ثم x قد تكون C,S, L,LV حيث كل حرف يعنى خاصية ما ثم 5X قد تكون 51 أو52 أو53 أو54 أو 58 أو 2051 الخ حسب نوع و طراز الميكرو ثم سلسلة AVR و المعروفة بالإسم AtMega بينما ميكرو تشيب أنتجت PIC10cxxx ثم PIC12cxx ثم PIC16xxx ثم PIC18xxx الخ 
المجموعتان من إنتاج ميكروتشيب PIC10cxxx و PIC12cxx غالبا من ثمانية أطراف وهى محدودة الإمكانيات لكن لها العديد من التطبيقات مثلا موتور توجيه طبق الأقمار الصناعية، لا يحتاج سوى طرف لتلقى الأوامر من الريموت و آخر لعد نبضات إنكودر الموتور و طرفين لتحريك الموتور يمين أو يسار و طرفين لخزن المعلومات فى ذاكرة فلاش ملحقة بالبوردة. هذا لأبين مدى أهمية أن نعلم عن كل الأنواع ، فمهما كان الميكرو صغيرا و محدود الإمكانات فله عديد من التطبيقات التى يمكن استخدامها فيها و تحقق إنجازا كبيرا. فقط حاول أن تفكر كيف تستبدله بإلكترونيات رقمية لتدرك الفارق.
هذه المجموعة لم أعلم لها موازى من أتميل سوى لاحقا من فصيلة AVR و سميت ATtiny وهى اختصار AT وهو اسم الشركة ثم tiny بمعنى صغير.
كيف نستخدمه و نبرمجه؟ حسنا لو شرحت لك بيك 16 سيعترض هواة بيك 18 ولو شرحت C51 سيحتج هواة AVR ولكنى سقت لكم مثالا موتور الدش لغرض فى نفسى وهو هذا الأمر. سأشرح الكل لكى تعلم انت كيف تبحث عما تريد و كيف تدرس أى ميكرو ولا تقف عاجزا ثم تختار الأنسب . كنت أبرمج C51 بالأسيمبلى حين طلب منى جهاز بالميكرو تشيب لعدم توافر النوع الآخر ، كمصمم يجب ألا تتوقف، ادرس الداتاشيت ، أتعرف على الفروق و أبرمج بأى لغة تناسب التطبيق.
لهذا يجب أن نعلم التركيب الداخلى و كيفية البرمجة. وهذا موضوعنا القادم بإذن الله


----------



## ماجد عباس محمد (6 يونيو 2018)

*أشهر أنواع المتحكمات*

أشهر الأنواع:
كما ذكرنا فشركتى ميكروتشيب و أتميل هما أشهر الشركات فى هذا المجال و سنقارن أشهر الأنواع من كل منهما ثم نشرح التركيب الداخلى و كيفية البرمجة بالأسيمبلى و البيزك و لغة C و سنعرض أخيرا للجيل المتطور من كل منهما و عليك أن تكمل المشوار.
أولا لنقارن بين الأطراف سنجد أننا فى حاجة لأن نعرف كيف يتصرف الميكروكونتروللر وما هى احتياجاته من العتاد لكى ينفذ أى برنامج.
ألتركيب العام:
الشرح التالى لا يخص رقم بعينه ولكنه صحيح لكل الأرقام ومن الشركتين أيضا.
أولا سنفتح مصدر التغذية و بالتالى يجب أن يبدأ الميكروكونتروللر فى العمل وهذا يتطلب مذبذب داخله لكى يعطى له نبضات تجعله يكرر دورة واحدة محددة وحتى قطع التغذية عنه. هذه الدورة هى أخذ كود الخطوة المعنية ثم يشير للخطوة التالية ثم تحليل الكود ليعرف ما هو ثم تنفيذه (نقل رقم للمراكم – نقل من المراكم للذاكرة-جمع رقم للمراكم..الخ) و يكرر.
لهذا يجب أن يحتوى على عداد للبرنامج Program Counter و وحدة تحليل التعليمات Instruction decoder و مراكم أو أكثر Accumulator حيث سيضع البيان ألذى تأمره به ألتعليمه و مجموعة من المسجلات لزوم الحاجة.
هنا نفرق بوضوح بين المسجل و المراكم. كلاهما تخزن فيه بيان و تقرأ منه و تستخدمه فى الحسابات و بعضها يمكنك أن تستخدم محتواه كعنوان لكن نتيجة العمليات الحسابية تذهب للمراكم فقط ، ولو به أكثر من مراكم قد يمكن الاختيار بينهما.
هكذا يمكنك التعامل مع معظم الأوامر لكننا ذكرنا أن هناك كثير من الأجهزة المحيطة مثلا التواصل التسلسلى، حسنا مشكلة هذا التسلسلى انك لا تخبر الطرف الآخر عن ترددك ولا أوقات وضعك للبيانات لذا يجب أن تعتمد الدقة العالية فى إرسالك و توقيت استقبالك لذا يتطلب الأمر أن يكون المذبذب يعمل بكريستال لتوفير الدقة كما انك لن تتمكن من تغيير الكريستال لو أردت تغيير معدل الإرسال،ولا أن تستخدم 2 كريستال واحدة بطيئة للتسلسلى و أخرى سريعة لباقي البرنامج ، لذا يجب وضع مؤقتات داخلية "تايمر" Timer و من ثم أغلب الوحدات تحتوى واحد 8 بت و آخر أو اثنان 16 بت. تضع فى أى منهما القيمة المناسبة (تحميل العداد) ليعطيك معدل الإرسال المطلوب أو أيضا أى توقيت تريد أو وظيفة أخرى كما سيلى الشرح إن شاء الله. 
إذن تتولى وحدة الاتصال التسلسلى عند تمام العد أن تعيد تحميل العداد حتى نهاية إرسال البايت. كيف تخبر الميكرو بأنها أتمت المهمة أو أنها تلقت من الخارج بايت كاملة تحتاج التعامل معها قبل أن تصل بايت جديدة؟
إذن تنشأ الحاجة لاستبقاء نظام المقاطعة من الميكروبروسيسور السابق وهو أن يكون بداخل وحدة المعالجة مسجل به 8 بت كأى مسجل ، واحدة لإتاحة المقاطعة ككل أو إيقافها ككل و بعض من ألباقى يخصص بت لكل حدث.
عندما تصبح واحدة منهم =1 فسيتحسس الميكرو ذلك فى نهاية الدورة ثم يحفظ العنوان الحالى (أى خطوة هو على وشك تنفيذها) فى "ذاكرة ما" ثم يذهب لعنوان آخر تحدده أى بت سببت هذه المقاطعة و فى نهاية كود المقاطعة يجب وضع تعليمه خاصه اسمها عودة من المقاطعة لكى يفهم الميكرو أن عليه استعادة العنوان ألذى سيق أن خزنه فى تلك "الذاكرة ما" ليعود للبرنامج الأصلى.
هذا الموضوع سنتناوله تفصيلا لاحقا لكن ما يهم الآن انه أثناء خدمة المقاطعة قد يحتاج الأمر لمقاطعة ثانية و سيضع الميكرو العنوان الجديد فوق السابق (ترص فوق بعضها) وهكذا ، لذا سميت هذه "الذاكرة ما" بالمرصوصة Stack ولها عداد مستقل أيضا لمتابعة أين نحن الآن يسمى مؤشر الرصة Stack Pointer وهو يزداد بواحد أولا ثم يحفظ المطلوب حفظه و بالعكس يقرأ المحتوى أولا ثم ينقص بواحد.
التعامل مع العالم الخارجى:
مما سبق أصبح الميكروكونتروللر مهيأ للتعامل أساسا مع العالم الخارجى لذا صنعت أغلب أطرافه مداخل ومخارج فى مجموعات تسمى بوابه PORT و نظرا لأن معظم البيانات تعالج بالبايت وهى 8 بت قسمت هذه الأطراف لمجموعات أقرب ما تكون لهذا العدد و من ثم كل تعاملك مع بايت و تتحكم أيضا فى مخرج عرضه بايت و أيضا تعطى بيانات لأى جهاز خارجى أو تأخذ منه بعرض بايت أيضا.
لذا احتوى الميكرو على هذه البوابات PORTs و فيما عدا عائلة C51 فلكل منها داخل الميكرو مسجل مناظر لتحول أى طرف "بت" منها أو كلها معا من دخول لخروج. طبعا هناك فرق كبير بين أن يكون الطرف دخول أو يكون خروج.
الطرف الخروج سيكون إما صفر أو 1 حسب الأمر ألجارى تنفيذه وهو قادر على إعطاء تيار محدود عندما يكون =1 أو يقبل "يبتلع" تيار عندما يكون = صفر، أما الطرف المهيأ كدخول سيكون ذو إعاقة عالية حتى لا يسبب سحب تيار من أى مصدر يتصل به و يتبع المصدر من حيث الفولت.
حسنا هذا المنفذ PORT سواء كان دخول أم خروج، فلابد من مسجل ما فى مكان ما يحتوى البيانات الخاصة به ، أين يكون؟ و الأسوأ أنه سيحتاج لديكودر لتحليل عنوانه عندما تريد التعامل معه.
ابتكر أحدهم فكرة بسيطة و ظريفة و سهلة التعامل من حيث العتاد و البرمجة. قال لماذا لا نضعهم جميعا فى ذاكرة كالأصلية و نطلبها عند اللزوم. نظام الذاكرة ممتاز بالنسبة للدوائر المتكاملة لأنه يتناول قطعة مربعة صغيرة جدا و يقسمها لخانات متناهية الصغر و يطالها بالصف و العمود إذن لا نكرر العتاد لكل مسجل هى مجموعة من 128 خانة ذاكرة أو غيره طبقا للتصميم و كل خانة منها 8 بت كالذاكرة الأصلية ولكن إحداها للمنفذ " أ" و الآخر للمنفذ " ب" وهكذا و يمكن أيضا وضع كل المؤقتات "تايمر" Timers فيها ، و التايمر 16 بت يشغل خانتين متجاورتين .
أيضا أحدها يمكن أن يكون للمراكم الأساسى و آخر لكل مسجل أو مراكم و أيضا مؤشر الرصة SP السابق الخ.
هذه الذاكرة أسمتها كل من إنتيل و ميكروتشيب SPECIAL FUNCTION REGISTERS 
الآن يمكننا المقارنة بين أشهر رقمين و هما PIC16F877A و عائلة AT89c5x هذه الصورة تضعهما بجوار بعض لتوضيح الفروق، وقد وضعت لون مختلف لكل بوابة PORT




يمكننا أن نلخص الفروق فى الجدول التالى








سنناقش هذا الجدول بالتفصيل المرة القادمة إن شاء الله


----------



## ماجد عباس محمد (8 يونيو 2018)

*الفروق بالتفصيل*

ألفروق بالتفصيل:
البند الأول: أن تكون كل المنافذ Ports ثابتة العرض 8 بت يجعلها قياسية و يسهل تعاملها مع المحيطات لكن كون لديك عدد مختلف يجعلك حائرا فى باقى المنافذ خاصة بعضها 4 بت فقط



فمثلا عندما تود التحكم فى 8 مخارج معا مثل شاشة سباعية 7Segment أو بعض الحساسات التى تعطى 8 بت معا أو التحكم فى 8 مخارج معا ستجد من الأسهل استخدام منفذ ثمانى للتوصيل لمكبرات أو عواكس مثل ULNxxxx كما أن الأمر لمنفذ كامل يعطيك التحكم فى 8 مخارج بأمر واحد على العكس من عدد من المنافذ كل منها يتطلب أمرا مستقلا.
هذا ينعكس على السرعة وحجم البرنامج معا.

البند الثانى : كل منفذ Port تجده مجمع و مرتب فى أطراف متجاورة فى أتميل مما يجعل توصيله لأى جهاز يكون سهلا – طرف بطرف و البوردة الناتجة منسقة ولا تحتوى كبارى jumpers ولا تعارضات أما فى بيك فالمنفذ C ممزق و بينه أطراف منفذD .
مثلا عند استخدامك منفذ B كاملا فإن استخدام منفذ C مع منفذ D سيجعل هذه الخطوط متقاطعة و البوردة تحتوى عديد من الكبارى، حتى لو أردت استخدام شاشة LCD و فضلت للسهولة استخدام 4 بت لن تجد 6 أطراف متجاورة منهم.
فى الجيل التالى مثلا PIC18 و أتميل ATMega سنجد أن ميكروتشيب استخدمت نفس الإسلوب فى الجيل المطور وهى ميزة تحتسب لهم أنك إن شئت التطوير فقد لا تعوقك الأطراف



بينما اتميل فقد صنعت رقم من عائلة AVR رقم مطابق فى الأطراف لعائلة 51 يمكنك من الترقية





و صنعت الجيل المطور بذات التنسيق فى الأطراف مع تعديلات طفيفة فى ترتيب أطراف القدرة و البدء RESET و الكريستال



ولم نجد سوى المنفذ D الطرف 7 فقط قد رحل إلى الجانب الآخر أى كوبرى واحد فقط.

البند الثالث: فى كل ميكرو يوجد مسجل للحالة Status register وهو بالغ الأهمية لأنه يتابع حالة المراكم خطوة بخطوة و يحفظ نتائج الخطوات للخطوات اللاحقة فمثلا لو كان المراكم خاليا نجد فى مسجل الحالة خانة فيها 1 و عدا ذلك تكون بصفر ولذا يسمى Zero Flag أى علم أو إشارة وجود صفر فى المراكم وهى هامة جدا فمثلا لا يجوز القسمة على صفر ولذا فباختبار هذه الخانة تتصرف طبقا للصواب.
و آخر للنتيجة السالبة و ثالث لمعالجة الأرقام BCD ورابع لفائض الجمع و اقتراض الطرح Carry/Borrow الخ و هو بإجمالى سته أعلام Flags و بقى 2 دون توظيف، شركة أتميل أعطتها أسماء F1,F0 و يمكن للمستخدم أن يستغلهم كما يشاء عند توافر شرط ما يجعل أحدهما = 1 للتذكر لاحقا.
هذا يوفر كثيرا فى الكود وكذا أسرع فى التنفيذ لأن هناك أمر JB أى القفز لو هذه البت =1 و عكسه JNB لو كانت = صفر دون التعرض للمراكم و ما به من حساب أما اختبار خانة فى الذاكرة فتحتاج لتحميلها أولا فى المراكم قبل الاختبار ولو كان ما فى المراكم مطلوبا عليك حفظه فى مكان ما مثل الرصة أو غيرها من الذاكرة.
أما فى بيك فعدد هذه الخانات قليلا مما يجعل القدرة الحسابية له أقل .


البند الرابع: كثرة الأوامر تعنى أنه يمكنك اختصار خطوتين أو أكثر فى خطوة
أفضل مثال لذلك وجود الاختبار السابق وفر خطوات التعامل مع المراكم و حفظه، و أيضا هناك أوامر أخرى منها وجود مسجل 16 بت يسمى مؤشر البيانات أو Data Pointer و اختصارا DP وهو يمكنك من أخذ أى بيان من ذاكرة البرنامج للمراكم وهذا يسهل عليك وضع رسائل المستخدم كجزء من ذاكرة البرنامج (وهى كبيرة) و بهذا المسجل تأخذها حرف بحرف للعرض على الشاشة بأمر واحد و غيره من التطبيقات.

البند الخامس: تدعم حساب BCD 
مثال لو تريد عداد فوجود حساب BCD يمكنك من استخدام BCD to 7 segment و توفر كثير من المعالجات بالكود للتحويل من ثنائى لعشرى، أيضا متكاملات الوقت كلها تعمل BCD و أيضا بعض الحساسات و بعض الموازين.

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


----------



## ماجد عباس محمد (10 يونيو 2018)

*المنافذ Ports*

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

هناك نقطة هامة يجب تذكرها فى كافة الأنواع وهى كم مللى أمبير يتحملها المنفذ، حسنا طبقا للداتاشيت ستجد بعض الطرز 25 مللى و البعض الآخر 40 مللى لكن الميكرو 40 طرف يحتوى على 32 طرف دخول / خروج أى 25*32 = 800 مللى على الأقل، لكن من الداتاشيت أيضا ستجد أن طرف التغذية VDD يقبل 400 مللى كحد أقصى فقط .
لو بحثت أيضا ستجد بيان آخر يقول أقصى تيار لمجموع المنافذ هو 300 مللى، إذن هذا هو ما نلتزم به أى لا نحمل مجموع المنافذ أكثر من هذا القدر رغم أنك تستطيع تحميل أى منها القيمة القصوى سواء كانت 25 أم 40 مللى و ذلك حتى لا يختل أداء الميكرو أو تعرضه للتلف.

أيضا يوجد مسجل لكل منفذ يحتوى البيانات التى تضعها على المنفذ PORT لكن لا تخرج مباشرة و إنما عبر عازل Buffer وذلك لزوم التحكم فى خواص الطرف و شرح ذلك لاحقا إن شاء الله. لذا يجب الحيطة عندما تقرأ المنفذ حتى لا تعيد قراءة ما وضعته عليه عوضا عن قراءة حالة الطرف الخارجية.

تنقسم المنافذ لنوعين C51 من إنتاج أتميل و باقى الأنواع AVR من إنتاج أتميل و كافة منافذ ميكروتشيب تقريبا.
الأول سيلى شرحة فى منافذ أتميل لكونه مخلف قليلا أما ألباقى من إنتاج الشركتين تشترك فى الخواص التالية
1- يحتوى كل منفذ على مسجل للبيانات و مسجل آخر تحدد كل خانه فيه كون الطرف المقابل من المنفذ إدخال أو إخراج.
2- يحتوى كل منفذ على مسجل ثالث يحتوى حالة الطرف الفعلية الآن و بصرف النظر عن المسجل الأول ألذى تكتب أنت فيه ما تريد فقد تكتب على الطرف 1 ولكن عليه مفتاح يفرض صفر، هنا سيقرأ مسجل البيانات 1 و مسجل الطرف صفر.

منافذ أتميل: 
فى عائلة C51 نجد أن المنافذ تسمى بالأرقام المنفذ صفر ثم 1 و 2 و 3. أما فى عائلة AVR فتسمى بالأحرف منفذ A,B,C,D
فى عائلة C51 المنفذ صفر هو الأقوى حيث يستطيع أن "يبتلع" تيار معادل 8 حمل TTL وهذا الحمل يبلغ 1.6 مللى أمبير وهو الحمل القياسى لأحمال الدوائر المنطقية ولمعرفة المزيد عنه راجع سلسلة الدوائر المنطقية ، أى ان كل طرف يتحمل 12.8 مللى أمبير.
هذا المنفذ ذو مخرج يسمى المصب المفتوح Open drain (سلسلة الدوائر المنطقية) لذ عندما يكون = 1 ، لا يخرج منه تيار و لا يظهر عليه فولت و يحتاج لمقاومة أو حمل ما متصل بالطرف الموجب +5 فولت ليظهر هذا الواحد (+5فولت) .
أما عندما يكون = صفر يقبل تيار حتى القيمة المذكورة. لذا هو مناسب لتشغيل ليد بيان LED أو شاشات 7 شرائح 7Segment من النوع المهبط المشترك Common Anode أو أوبتو كبلر الخ. أيضا أغلب المفاتيح Switch تحتاج لمقاومة Pull Up لذا يمكن استخدام هذا المنفذ.
المنافذ الأخرى 1،2،3 متماثلة حيث تصدر و تقبل تيار بنصف القيمة السابقة أى 4 حمل أو 6.4 مللى أمبير عندما تضع على أى طرف منها صفر تيار كما سبق ولو وضعت عليه 1 يمكنك أن تضع مفتاح أو توصله بخرج أى دائرة إلكترونية أخرى تعطيه بيانات.
الحالة الفرضية هى ما يكون عليه عند البدء أو إعادة التشغيل وهى كل المخارج فى وضع الخرج أى كلها 11111111

فى عائلة AVR فقد اختلف الأمر و أصبحت المنافذ الأربع متماثلة و من الممكن أن تتحكم فى أى منفذ تحكما أكثر .

فى المرة القادمة إن شاء الله نتحدث عن منافذ AVR و منافذ ألبيك


----------



## ماجد عباس محمد (11 يونيو 2018)

*منافذ عائلة avr من أتميل*

*منافذ عائلة AVR من أتميل* :
كما سبق أن ذكرنا لكل منفذ مسجل بيانات و آخر يسمى DDR اختصار Data Direction Register أى مسجل اتجاه البيانات (دخول أم خروج) مضاف إليه اسم المنفذ مثلا DDRA للمنفذ A و هكذا حتى DDRD للمنفذ D . 
الوضع الافتراضى للبدء هو دخول أى محتواه = صفر ووضع 1 فى أى خانه تجعل الطرف خروج فمثلا لو وضعنا فى المسجل DDRA=10101010 سنجعل المنفذ A طرف دخول و المجاور خروج و هكذا، كما أنك يمكن فى أى لحظة فى البرنامج أن تغير خصائص أى طرف فلو فى أى مكان فى البرنامج استخدمت الأمر DDRA=10101011 ستغير الطرف صفر من المنفذ A (أقصى اليمين) من إدخال لإخراج. 
كما ذكرنا سابقا أنه لدينا مسجل آخر لقراءة حالة الأطراف وهو باسم PINA و حتى PIND واحد لكل منفذ. فمثلا لو قرأت القيمة PORTA ستعطيك آخر قيمة سجلتها أنت فى هذا المنفذ ولو عليه أزرار لن تعرف حالتها، لكن لو قرأت القيمة PINA ستعلم أى الأزرار يضع 1 و أيها يضع صفر.
المسجلين المذكورين يمكن التعامل معهما كمنفذ ذو 8 طرف أو تحدد الطرف المختار من الثمانية. 
منافذ ألبيك : 
الأمر مختلف قليلا مع ألبيك فمسجل الاتجاه TRIS اختصار Tri-State و يسمى TRISA وحتى TRISF حسب اسم المنفذ و عند وضع 1 فى أى خانه يجعلها دخول و صفر يجعلها خروج وهى أسهل حفظاً من أتميل لأن 1 مشابهة شكلا للحرف I أو INPUT و الرقم 0 أشبه بالحرف O أو Output.
فى عائلة PIC16 سنجد لها مسجلين فقط أولهما السابق ذكره للاتجاه و الثانى اسمه PORT باسم المنفذ، هنا لا يوجد مسجل لحالة الطرف و قراءة المنفذ PORTA مثلا تعطى حالة الأطراف ولا وسيلة لقراءة ما سبق لك كتابته.
أما فى عائلة PIC18 فمازال قراءة المنفذ PORTA مثلا تعطى حالة الأطراف وأضيف مسجل أخر باسم LAT وهى اختصار Latch ويضاف اسم المنفذ أصبح قراءتها هى التى تعطى ما سبق لك كتابته على المنفذ فمثلا قراءة LATA تعطى ما كتبته انت بينما PORTA تعطى حال الطرف حاليا فقد يكون هناك مفتاح ما فرض حالة عكس ما كتبت.
*فى عائلة **PIC16 **الحالة الافتراضية لمنفذ **A **هو تماثلى لذا يجب تهيئته لو يستخدم كأطراف رقمية فيما عدا ذلك ففى العائلة **16 **و العائلة **18 **كل المنافذ ستكون دخول ما عدا بعض الأطراف  لذا يجب الرجوع للداتاشيت لمعرفة أى الأطراف مرتبطة بأى الوظائف حتى تعيد تهيئتها كمداخل **/ **مخارج أو تستخدمها كما هى فقط اعرف ماذا تفعل*

الآن لدينا 32 طرف للتحكم فى العالم الخارجى و بهذه الأطراف نستطيع التحكم فى كثير من الأدوات المنزلية كخلاط مثلا أو غسالة أو كثير من الآلات الصناعية أيضا.
لنرى كيف ذلك نبدأ فى كتابة بعض البرامج لتشغيله.
لتكتب بالأسيمبلى لعائلة أتميل فهناك برنامجان أسهل من غيرهم فى هذا المجال
برنامج MIDE 
http://mide-51.software.informer.com/0.2/
وهو مجانى لكن ينقصه تتبع الأعطال Debug
الثانى 
يمكنك إنزال BASCOM نسخة 8051 لإستخدامها مع c51 و نسخة AVR لإستخدامها مع AVR و كلاهما يصلح للأسيمبلى أو بيزك أو كلاهما معا
أو يمكنك استخدام ميكرو الكترونيكا كما يمكنك أن تستخدم بروتس أيضا.
سنبدأ المرة القادمة إن شاء الله بكتابة برنامج بسيط يقرأ 3 أزرار فى مداخل و يضئ 3 ليد تمثل العدد 1 أو 2 أو 3 حسب أيها تم الضغط عليه


----------



## ماجد عباس محمد (12 يونيو 2018)

*أول برامجنا*

 أول برامجنا:
 عائلةC51 - أتميل
لتسهيل الأمور فى أول برنامج، أعلم أن الغالبية تفضل برنامج بروتس حيث ترسم الدائرة و تحاكيها قبل التنفيذ العملى. حسنا
لننشئ مشروع جديد كما بالصورة التالية




نستخدم فيه AT89c51 متصلة كما بالصورة.
سنلاحظ هنا أن الليدات متصله على منفذ صفر PORT0 من خلال مقاومات متصلة بالموجب. السبب أن منافذ هذه العائلة لا تمد بتيار رغم أن الداتاشيت تقول أنها تستطيع ذلك لكن أيضا عندما تسحب منها تيار تحد فورا من تيار الخرج. باختصار لا تصدر تيار يضئ ليد أو يفعل ترانزستور . لكنه يقبل تيار حتى 20 مللى أمبير.
توصل المفاتيح كما بالرسم. أعلم أن البعض سيعترض لكن كل أوجه الإعراض ليست لها ضرورة الآن.
فى صفحة البرنامج ستجد العديد من الأسطر كتبها لك البرنامج و كلها تبدأ بالفاصلة المنقوطة ";” و السطر بكاملة باللون الأخضر. هذا لأن هذه الفاصلة جعلت السطر بكاملة "تعليق" أى غير وارد فى البرنامج ولكنه للشرح أو التنسيق.
ثم يلى ذلك تعريف أن هذا هو الملف ألرئيسى و يمكنك حذفه.

```
[LEFT][COLOR=#008000]; ============================================= 
; Main.asm file generated by New Project wizard
;
; Created:   Thu May 24 2018
; Processor: 80C51
; Compiler:  ASEM-51 (Proteus)
;==============================================
[/COLOR][/LEFT]
```
ثم يلى ذلك تعليمه للمترجم بالنسق المستخدم وهو NOMOD51 و نلاحظ أنه مسبوق بعلامة الدولار $، هذه ألتعليمه تخص المترجم أى ستختلف باختلاف المترجم المستخدم و سيضعها آليا عند بدء مشروع جديد وهى فى بروتس تعنى لا تستخدم النسق الإفتراضى لهذه العائلة و لذا يجب أن تتبعها بالخطوة التالية و تختار رقم الميكرو و تردد الكريستال الخ. 
و يليه تعليمه للمترجم بالميكرو المستخدم وهو 8051 و هو ملف يلحق بالبرنامج به تعريفات لكل المسجلات و المنافذ و محتويات الميكرو الداخلية. بدونه لن تستطيع أن تكتب أمرا واحدا . أيضا مسبوق بعلامة $ و فى مترجم غيره قد تكون علامة # و اسم الملف 8051.MCU و كل مترجم سيضع اسم الملف الصحيح له.

```
$NOMOD51
$INCLUDE (8051.MCU)
```
ما يلى قسمين واحد للتعريفات ثم المتغيرات و متجهات إعادة التشغيل و خلافة و سيأتى شرحها لاحقا إن شاء الله
يمكنك حذف التالى أيضا ، سنبقى فقط على السطرين السابقين فقط.

```
[LEFT][COLOR=#008000];==================================
; DEFINITIONS
;==================================


;==================================
; VARIABLES
;==================================


;==================================
; RESET and INTERRUPT VECTORS
;==================================[/COLOR][/LEFT]
```
و الآن سنصل لتعليق ; Reset Vector و لتعليمه هى

org 0000h
هذه اختصار Origin بمعنى نقطة أصل أو نقطة بدء لتقول للمترجم "أريد الكود التالى فى هذا العنوان"
وهى احتياطا لو تريد برنامج متقدم سيكون لها جدوى أما فى هذا البرنامج البسيط سيكون الكود فعلا فى خانة صفر ولا حاجة لتكرارها و يمكن حذفها.
حتى الآن كل ما سبق هو تعليمات للمترجم ولا ينتج عنها أى كود ولو حاولت أن تعكس المسار لتحصل منها على التعليمات من الكود ، فلن تحصل مما سبق على أى كود ليكتب لك بدلا عنه هذه الأسطر.
أول أمر هو JMP start أى اقفز حيث العنوان Start
لكى تضع عنوان تذهب إليه وقتما شئت يجب أن يكون من كلمة واحدة قد تحتوى _ لزيادة الإيضاح و أن تبدأ بحرف وليس رقم و ألا تكون من كلمات الكود المستخدمة و أن تكون أول ما فى السطر أو قبلها مسافات بيضاء و أن تنتهى بالنقطتين ":” مثلا 
LCD_TEST: عنوان جيد أو Delay25u:
ألتعليمه JMP بمعنى اقفز بدون قيد أو شرط للعنوان المذكور وهو هنا start 
كما ذكرنا البرنامج سيبدأ دوما من خانة صفر و بدون استخدام باقى مكونات المتحكم فلا حاجة لها ويمكن حذفها
jmp Start
ثم الشرح ألذى يقول قطاع الكود و أيضا تعليمه مشابهة لتحديد مكان كتابة باقى البرنامج org 0100h و تعنى العنوان 100 بالنظام الستة عشرى لوجود الحرف h أما لو b سيكون ثنائى ولو بدون سيكون العشرى المعتاد
```
[COLOR=#008000];==========================
; CODE SEGMENT
;==========================


   ;   org   0100h
Start:
      ; Write your code here[/COLOR]
```
يمكن حذف كل ما سبق ما عدا سطرى التعريف المذكورين و سطر العنوان Start 
أى لدينا ثلاثة أسطر فقط وهنا نبدأ أول البرنامج الفاعل
وهذا موضوعنا القادم بإذن الله.


----------



## ماجد عباس محمد (13 يونيو 2018)

*أول برامجنا ج2*

*ابتكر أحدهم فى شركة إنتيل استخدام كلمة **Move **وهى تعنى حرك أو انقل لكى تعنى انسخ ولا أدرى لماذا بينما استخدم نظيره فى موتورولا كلمة **Load **وهى بمعنى **"**حمًّل**" **أو **"**ضع شيء فى**" **، وهى أقرب للمنطق لكن هكذا سارت الأمور و تبنت **Mov **كل من إنتيل و لاحقا أتميل و أيضا ميكرو تشيب *
*الاسم **Mov **هو مختصر ودوما بدون حرف **e **و يليها المنقول إليه أو الهدف ثم فاصلة **"," **ثم المنقول منه أو المصدر و لا قيود على من سيكون المصدر و من سيكون الهدف ، محتوى خانة ذاكرة أو عنوان الخانة أو مسجل و بهذا**. **لو كان المصدر حرفيا بمعنى رقم ما تريد نسخه أو وضعه فى مسجل ما نضع قبله علامة شباك **"#” **و بدون هذه العلامة سواء فى المصدر أو الهدف فهو عنوان لخانة ذاكرة و ما سيتأثر هو محتواها*


*السطر الأول سيكون *
*Mov P0 , #255*
*Mov p3 , #255*
*وهذا يعنى ضع فى المنفذ **P0 **القيمة **255 **لوجود علامة **"#” **ثم السطر الثانى سيعنى ضع فى المنفذ **P3 **القيمة **255 **لوجود **"#” **أيضا**. **هذا يعنى جعل كل أطراف هذين المنفذين عليهما **+5 **فولت و يمكن استخدامهم كمداخل أيضا**.*
*ماذا لو لم نضع الشباك؟ أى هكذا **MOV P3 , 255 **سيترجمها المترجم انك تريد محتوى خانة الذاكرة رقم **255 **حسبما يتصادف محتواه**.*

```
[LEFT][B]Loop: [/B]
[B][COLOR=#0000ff]jb[/COLOR] p3.0 , SW2test[/B]
[B][COLOR=#0000ff]mov [/COLOR]P0 , #11111110b[/B]
[B]SW2Test: [/B]
[B][COLOR=#0000ff]jb [/COLOR]P3.1 , SW3Test[/B]
[B][COLOR=#0000ff]mov [/COLOR]P0 , #11111100b[/B]
[B]SW3Test:[/B]
[B][COLOR=#0000ff]jb [/COLOR]p3.2 , start[/B]
[B][COLOR=#0000ff]mov [/COLOR]P0 , #11111000b[/B]
[B][COLOR=#0000ff]jmp [/COLOR]start[/B]
[COLOR=#008000][B];===========================[/B]
[/COLOR][B]END[/B][/LEFT]
```

*الآن انسخ السطور السابقة فى مترجم بروتس وهذا شرح كل منها**.*
*Loop: *
*عنوان و لدينا أيضا عنوانين آخرين هما **SW2Test **و **SW3Test **وهى ذات فائدة فى تحديد مسار البرنامج*
*يليه الأمر **JB **وهو اختصار **Jump if Bit set **و يعنى اقفز لو البت **=1 **وهو يليه اسم هذه البت ثم فاصلة ثم إزاحة عدد الخطوات التى يجب الانتقال إليها**. **هذه الخطوات هى فى بايت واحدة لذا ستكون بإجمالي **255 **خانة بين للأمام **128 **خطوة و للخلف **127 **خطوة**.*
*سيكون من الصعب عليك حساب عدد الخطوات فستحتاج لمعرفه كم خطوة لكل تعليمه الخ لذا نستخدم عنوان و نترك المهمة الصعبة للمترجم**.*
*إذن السطر التالى يعنى*
*لو البت **"**المنفذ**3 **الطرف صفر**" =1 **اقفز حيث العنوان **SW2test **وهذا يعنى أنني اختبرت المفتاح **SW1 **فإن لم يفعل سينتقل للعنوان **"**اختبار المفتاح**2” **وهذا من فوائد العنوان أن يكون معبرا عن هدف هذه الخطوة لتذكيرك ماذا أنت ذاهب لتفعل*
*أما لو كان مضغوطا على المفتاح**1 **سيجعل الطرف **= **صفر و من ثم لن ينتقل و سينفذ ألتعليمه*
*mov P0 , #11111110b*
*أى سيضع صفرا على الطرف المتصل بالليد الأول ليضئ وهنا كان ممكن أن نكتب **MOV P0 , 254 **لكن قد تتساءل لاحقا ماذا تعنى **254 **ووضعها بالصورة الثنائية أوضح لك أن كل الأطراف آحاد ماعدا الأول بصفر ، ثم نكرر عند العنوان **SW2Test **حيث نجد نفس ألتعليمه إلا أن البت أصبحت **P3.1 **أى المنفذ **3 **الطرف رقم **1 **و القفز للعنوان **SW3Test*
*إن لم ينتقل أو يقفز سينفذ الأمر *
*mov P0 , #11111100b*
*و به تضيء ألليد الأول و الثانى**.*
*و بعد العنوان الأخير سنجد الاختبار الأخير للبت الثالثة إلا أن القفز للبداية فإن لم يقفز سيضيء الليدات الثلاث ثم يقفز للبداية لتكرار الاختبارات مرة أخرى لتحديد متى يتم الضغط على أى الأزرار**.*
*قبل أن نترك الموضوع تعلمنا الأمر **JB **و هناك الأمر عكسه وهو **JNB **أظن توقعت **Jump if Not Bit set **يعنى سيختبر البت و الانتقال سيكون لو **= **صفرا بدلا من لو **=1*
*آخر سطر وهو **END **لا معنى له و كثير من المترجمات استغنت عنه ولكنه مستبقى لأسباب تاريخية فقط**.*
*قديما عندما كانت البرامج تدخل للحاسب بالبطاقات المثقبة لم يكن هناك وسيلة لتعلم الحاسب أن هذا آخر كارت برنامج وهذا تمام الكود عكس الآن حيث يقوم نظام التشغيل بهذه المهمة و يحدد لك أول و آخر الملف **. **لذا كان لابد أن يكون آخر كارت عليه هذا الكود **END **و إلا سيحصل على رسالة أن الملف غير كامل**. **أما الآن فسيقول لك لم أجد كلمة **END**، حسنا وماذا لو وجدتها؟؟ أليست آخر كلمة فى الملف؟ ولو انتهى الملف أليس هذا كاف من نظام التشغيل أن يخبرك بتمام الملف؟؟*
*الآن جرب محاكاة البرنامج و ستجده يعمل و الليدات تضئ و تطفئ طالما الزر مضغوطا عليه**.*
*لكن هناك ملاحظات تتطلب التعديل، حاول أن تكتشفها و تعدلها قبل موضوعنا القادم بإذن الله**.*


----------



## ماجد عباس محمد (14 يونيو 2018)

*المشكلة و اصلاحها*

لعلك لاحظت أن المحاكاة كشفت أن الليدات الثلاث تطفئ ثم تضيء مرة أخرى وهذا فى برنامجنا لا شيئ لكن فى الواقع لو هذا فى آله و تقوم بذبذبة جزء منها بهذا المعدل قد تتلفها، إذن ما العيب و كيف نصلحه؟؟
العيب أنك فى كل مرة تقفز إلى Start لتعيد الدورة و فيها تطفئ الكل بدلا من أن تعدل فقط حسب المطلوب لذا نضع عنوان آخر هو Loop وهو فيه الدورة التكرارية

```
[LEFT][B][SIZE=3]Start: 
      Mov    P0 , #255
      Mov    p3 , #255
Loop:    
      jb        p3.0 ,  SW2test
      mov    P0 , #11111110b
      sjmp    Loop
SW2Test:     
     jb        P3.1 , SW3Test
     mov        P0 , #11111100b
     sjmp    LOOP
SW3Test:
      jb        p3.2 , start
      mov    P0 , #11111000b
      jmp     Loop
[COLOR=#008000];===========================
[/COLOR]      END[/SIZE][/B][/LEFT]
```
هنا سنقدم تعليمه جديدة وهى sjmp اختصار Short Jump وهى للانتقال فى مدى +128 و -127 خطوة و بهذا توفر بايت فى كل تعليمه من حجم البرنامج بالمقارنة بتلك JMP و التى تنتقل لأى مكان ولكنها تحتاج لخانة أخرى لتكملة العنوان 2 بايت.
الآن بعد الاختبار الأول إن لم يتم الانتقال و أضأنا ألليد سنعود لأول الاختبار مباشرة فلا جدوى من تكملة الاختبارات، بل على العكس عندما نختبر الأخير لا دلالة لدينا عن حالة الأول مثلا و من ثم الأفضل إضافة ألتعليمه sjmp loop لنعيد الاختبارات من الأول لنحدد أى الأزرار مضغوط.
نفس الأمر فى نهاية الاختبار الثانى حيث لو لم ينتقل نتيجة لأول اختبار سيختبر الثانى فينفذ أو ينتقل
إن نفذ فسيعود لبدء الاختبارات مرة أخرى
إن لم ينتقل سيذهب للثالث و الآن وصولة للثالث هو حكم بأن الأول و الثانى لم يضغط على أى منهما لكن عدد الخطوات للانتفال قد تغير. من فوائد العنوان انه عندما يتحرك صعودا أو هبوطا ستحسب الخطوات آليا ولو زادت عن المسموح سيعطى المترجم رسالة خطا لمعالجة الموقف.
الآن وباختبار الثالث إن كان غير مضغوط فيجب إطفاء الكل بالانتقال للعنوان start و إن كان مضغوط سنضيء الكل بتنفيذ الأمرMov P0 , #11111000b ثم نقفز لتكرار الاختبارات دون إطفاء.


جرب المحاكاة الآن
لو حاولت تنفيذ هذا عمليا على بوردة تجميع فلن يعمل لعدم توصيل كثير من الأطراف الهامة و التى لا يعيرها ألمحاكي اهتماما، ولكى تنفذها يجب أن تكون الدائرة هكذا.












ألمرة القادمة بإذن الله سنكرر نفس البرنامج مع بيك.
ألمرة القادمة بإذن الله سنكرر نفس البرنامج مع بيك.


----------



## ماجد عباس محمد (15 يونيو 2018)

*الدائرة باستخدام ميكروتشيب pic16f877a*

*ميكروتشيب PIC16F877A*

*الآن سننفذ ذات الدائرة على بروتس باستخدام **PIC16c877A **متحكم و معه ذات المكونات و الدائرة كما بالرسم**.*
*سنلاحظ اختلاف فى توصيل الليدات و السبب أن منافذ ألبيك قادرة على الإمداد بالتيار عكس أتميل التى تقبل فقط**.*




*نلاحظ أيضا أننا لن نتعامل حاليا مع منفذي **A,E **لارتباطهما بالمحول تماثلى رقمى و يجب تهيئتهما للتعامل كمنفذ رقمى فقط**.*
*يمكننا استخدام ألباقى وسنختار المنفذ **D .*


*المنفذ **B **يحتوي مقاومات جذب للأعلى **Pull-up **وهى خاصية ضرورية لأن المنفذ عندما يهيأ كدخول ستكون له معاوقة دخول عالية و من ثم الجهد عليه غير محدد و عند قراءته كطرف رقمى قد يقرأ **1 **ثم يقرأ صفر بلا انتظام ولكنها توضع للأطراف الثمانية معا أو تحذف معا ولا ينصح باستخدامها لو البعض دخول و الباقى خروج و هذا يعالج بوضع المقاومات هذه خارجيا وهى **R4,R5,R6 **و عادة ما تكون **10 **ك أوم **, **ولذا لم يعد مهما استخدام المنفذ **B **كدخول أو خروج و سنختار كما هو بالرسم**.*
*بمراجعة صفحة الكود سنجد كما سبق كثير من الأسطر لا حاجة لها الآن سوى سطر**#include p16f877a.inc ; Include register definition file*​*وهو لتعريف المترجم أسماء مكونات المتحكم ثم يلى ذلك تعريف بدء البرنامج بتحديد البدء **RESET **ثم الانتقال لأول البرنامج بالأمر **GOTO START **وأخيرا إلغاء طرف البرمجة فى البوردة **PGM*
*RST code 0x0 *
*goto Start*
*PGM code*​*بعد ذلك نبدأ بتهيئة المنفذ **B **كخروج و المنفذ **D **كدخول و هذا بتنفيذ الأمر **TRISB=0 **و يكتب هكذا*

```
[LEFT][B]CLRF STATUS                  [COLOR=#008000]; Bank0[/COLOR][/B]
[B]CLRF PORTB[/B][COLOR=#008000][B]; Initialize PORTB by clearing output data latches[/B][/COLOR]
[B]CLRF PORTD [/B][COLOR=#008000][B]; Initialize PORTD by clearing output data latches[/B][/COLOR]
[B]BSF STATUS, RP0 [/B][B]          [COLOR=#008000] [/COLOR][/B][COLOR=#008000][B]; Select Bank1[/B][/COLOR]
[B]CLRF TRISB ; All OUTs[/B][/LEFT]
```
*
حيث **CLRF **تعنى **Clear **أو إلغاء محتوى المسجل المشار إليه بالحرف **f **وهو هنا **STATUS **وهذا لاختيار المجموعة صفر حيث لا يمكن للبيك أن يتعامل مع الذاكرة ككل و يقسمها لمجموعات كل منها تسمى بانك أو مجموعة أو **BANK **و نختار **Bank0 **لجعل المخارج أصفار بالأمرين **CLRF PORTB **ثم **CLRF PORTD **بعد ذلك نختار بانك رقم **1 **بالأمر **BSF STATUS, RP0 **لتهيئة المنافذ بعد ذلك بالأمر **CLRF TRISB **لجعل المنفذ **B **مخارج**.*

*لتهيئه المنفذ **D **كدخول نحتاج لأمر مشابه للسابق أى **TRISD=255 **و المشكلة أنك لا تملك أمر مماثل لأتميل حيث تكتب ما تشاء حيث تشاء كيف تشاء لكن يمكنك فقط كتابه ما تشاء فى المسجل **W **ثم تنسخه حيث تشاء بعد ذلك، ولهذا تحتاج لأمرين هما*
*MOVLW 255*
*MOVWF TRISD*​*حيث الأول **Move Literal W **أو اكتب حرفيا فى المسجل **W **و القيمة المطلوب كتابتها هى **255 **أى **11111111 **ثنائى ثم نسخها للمسجل **TRISD **بالأمر التالى **MOVWF **أو انقل محتوى **W **للمسجل **F **و المسمى هنا **TRISD **و أخيرا الأمر*
*CLRF STATUS **; Bank0*​*لنعود للبانك صفر مرة أخرى لنكتب فى المنافذ**. **نبدأ البرنامج بالعنوان*

```
[LEFT][B]Loop: [/B]
[B]BTFSC PORTD , 0[/B]
[B]GOTO Sw1[/B]
[B]MOVLW 1[/B]
[B]MOVWF PORTB[/B]
[B]GOTO Loop[/B][/LEFT]
```
*هذا حيث سيتكرر البرنامج دوما و سنختبر المفاتيح بالأمر*


*BTFSS *f, b Bit Test f, Skip if Set
*و هى تعنى اختبر البت **f **و لو **=1 **لا تنفذ الأمر التالى مباشرة و عكسها*
*BTFSC *f, b Bit Test f, Skip if Clear
*و هى تعنى اختبر البت **f **و لو **=0 **لا تنفذ الأمر التالى مباشرة وهذا الأمر التالى طبعا يجب أن يكون أمر انتقال لمكان ما*
*GOTO xxx*
*وهكذا يصبح اختبر المنفذ **PORTD **الطرف صفر فإن كان **=1 **انتقل لعنوان **Sw1 **و إلا فالزر مضغوط ولذا نكتب **1 **فى المسجل **W **ثم ننسخه للمنفذ **B **و نعود للعنوان **Loop **لنكرر الاختبار**. **أما لو انتقلنا إلى **Sw1 **سنجد*

```
[LEFT][B]Sw1:[/B]
[B]BTFSC PORTD , 1[/B]
[B]GOTO Sw2[/B]
[B]MOVLW 3[/B]
[B]MOVWF PORTB[/B]
[B]GOTO Loop[/B][/LEFT]
```
*اختبار مماثل لكن للمنفذ **PORTD **الطرف **1 **بدلا من صفر و الانتقال إلى **Sw2 **أو إنارة **2 **ليد بدلا من الأول فقط ثم العودة لأول الدورة **Loop*

```
[LEFT][B]Sw2:[/B]
[B]BTFSC PORTD, 2[/B]
[B]GOTO SW3[/B]
[B]MOVLW 7[/B]
[B]MOVWF PORTB[/B]
[B]GOTO Loop[/B][/LEFT]
```
*فى عنوان **Sw2 **سنجد اختبار مماثل لكن للمنفذ **PORTD **الطرف **2 **بدلا من صفر أو **1 **و الانتقال إلى **Sw3 **أو إنارة **3 **ليد بدلا من الأول فقط ثم العودة لأول الدورة **Loop*

```
[B]SW3: [/B]
[B]CLRF PORTB [/B]
[B]GOTO Loop[/B]
[COLOR=#008000][B];===========[/B]
[/COLOR][B]END
[/B]
```
*و أخيرا فى عنوان **SW3 **سنطفئ الكل لنعود للأول **Loop **مرة أخرى و كما ذكرنا أن واقعيا هذه الدائرة لا تعمل و يجب أن تصبح هكذا*





*من الواضح أن كم التعليمات أكثر بكثير مما استخدم مع السابق **C51 **وهذا راجع لقله الأوامر المتاحة فضلا عن كثير من التعليمات لا تستنتجها وحدك لبدء التهيئة و التشغيل**.*
*لذا فألبيك يفضل دوما برمجته باستخدام اللغات العالية مثل البيزك أو **C. **فهذا البرنامج البسيط تطلب العديد من التعليمات ولو كان البرنامج أكثر تطورا ربما أصبح من الصعب تنفيذه بالأسيمبلى بألبيك **.*
*يجب أن نتذكر هنا أننا باستخدام لغة ما غير الأسيمبلى قد تضيف كثير من التعليمات التى كان من الممكن اختصارها بالأسيمبلى**.**، لكن هناك أمر لا يسهل التغاضي عنه وهو استخدام مكتبات الأرقام العشرية و أنا شخصيا لو احتاج لعدد ثابت من الأرقام العشرية استخدم الحساب بدلا من المكتبات الجاهزة لاستهلاكها لذاكرة البرنامج فمثلا لو احتاج لرقمين صحيحين و كسرين عشريين أعتبر الحسابات ستكون على رقم أعلاه **9999 **صحيح و استخدم له **2 **بايت **(**حتى **65000) **أو بالإشارة **+/-32000 **ثم فى عرض الرقم أضيق علامة عشرية بين الثانى و الثالث**. *
*من المثال السابق نستخلص منهجا لما سيلى وهو أننا يمكننا مناقشة الأسيمبلى لمنتجات أتميل **C51 **فقط بينما **AVR , **ميكروتشيب سنكتفي باللغات العالية وذلك لكون الأسماء قد تغيرت و أيضا ذاكرة البرنامج زادت حتى سهل استخدام الحساب بالأرقام العشرية و من ثم اقتصرت البرمجة بالأسيمبلى على السرعة أولا و تقليل الحجم إن اضطر الأمر **.*

*المرة القادمة إن شاء الله سنحاول كتابة هذا البرنامج باللغات العالية *


----------



## ماجد عباس محمد (16 يونيو 2018)

*تمهيد للغات العالية*

*تمهيدللغات العالية:*

*التعريفات:*

*قبل أن نتناول اللغات العالية يجب أن نتعرض لما تركناه فى الشرح السابق و هو يخص البرمجة بشكل عام سواء بالأسيمبلى أو أى من اللغات العالية وهى الأجزاء الثلاث التالية*

```
[COLOR=#009900][B];==================================[/B][/COLOR]
[COLOR=#009900][B];DEFINITIONS[/B][/COLOR]
[COLOR=#009900][B];==================================[/B][/COLOR][/LEFT]
```
*هذا الجزء يسمى التعريفات و كما سبق الذكر فهذه الأسطر هى تعليقات لتذكرك فقط أين يفضل أن تملأ هذه البيانات، لذا يمكنك بعد حذفه أن تكتب ما تريد أو تتركه للتنسيق فقط**.*
*أغلب المترجمات تفترض أنك تضع هذا فى أول البرنامج دوما لأنه سيحتاج هذه المعلومات لاحقا و القلة فقط تدعم الإعلان لاحقا فهى ستحتاج لمسح الملف كاملا مرة لتحديد كل التعريفات ثم تبدأ فى التحليل **.*
*لنعدللبرنامج السهل الأول سنجد *

```
[LEFT][COLOR=#000000][B]Start:[/B][/COLOR]
[COLOR=#000000]      [B]Mov    P0, #255[/B][/COLOR]
[COLOR=#000000]      [B]Mov    p3, #255[/B][/COLOR]
[COLOR=#000000][B]Loop:    [/B][/COLOR]
[COLOR=#000000]      [B]jb        p3.0,  SW2test[/B][/COLOR]
[COLOR=#000000]      [B]mov    P0, #11111110b[/B][/COLOR]
[COLOR=#000000]      [B]sjmp    Loop[/B][/COLOR]
[COLOR=#000000][B]SW2Test:    [/B][/COLOR]
[COLOR=#000000]     [B]jb        P3.1, SW3Test[/B][/COLOR]
[COLOR=#000000]     [B]mov        P0, #11111100b[/B][/COLOR]
[COLOR=#000000]     [B]sjmp    LOOP[/B][/COLOR]
[COLOR=#000000][B]SW3Test:[/B][/COLOR]
[COLOR=#000000]      [B]jb        p3.2, start[/B][/COLOR]
[COLOR=#000000]      [B]mov    P0, #11111000b[/B][/COLOR]
[COLOR=#000000]      [B]jmp    Loop[/B][/COLOR]
[/LEFT]
```
*بالتأكيد أنك نسيت ما قلنا و الآن تتساءل ما هو أو فيم يستخدم **P0 **وما هو **P3 **و ستضطر للعودة للدوائر لتكتشف أن **P0 **الخاص بالليدات و **P3 **الخاص بالأزرار لذا لو هناك وسيلة تسهل هذاالأمر؟**!!*
*أجل هذا القسم هو لهذا الغرض فيمكنك مثلا كتابة*

```
[LEFT][COLOR=#000000][B]Switches    EQUP0[/B][/COLOR]
[COLOR=#000000][B]LEDs        EQUP3[/B][/COLOR]
[COLOR=#000000][B]SW1        EQUP0.0[/B][/COLOR]
[COLOR=#000000][B]SW2        EQUP0.1[/B][/COLOR]
[COLOR=#000000][B]SW3        EQUP0.2[/B][/COLOR][/LEFT]
```
*كلمة **EQU **اختصار **Equal **وهى شائعة فى مترجمات الأسيمبلى و فى البيزك باسكوم تستخدم كلمة **Alias **وهى تعنى اسم مرادف ، وفى ميكروإلكترونيكا تستخدم **Symbol **وهى ليست قياسية فى لغة البيزك أما **C **فتستخدم كلمة **at **أو **#define *
 *Switches Alias P0*
*هكذاتعطى اسم للمنفذ ككل و اسم لكل طرف إن شئت، بل لو عرفت المنفذ أولا يمكنك استخدام اسمه لاحقا للتسهيل أكثر هكذا*
*SW1 EQU Switches.0*
*فى ميكروإلكترونيكا *
*Symbol Sw1 = Switches*
*فىلغة **C **نجد تعليمه للمترجم هى*

```
[LEFT][COLOR=#000000] [B]#defineMy_Name System_Name[/B][/COLOR][/LEFT]
```
*فكلمة **define **تعنى "أعرف" و هذه الجملة تقول استخدم **My_Name**بدلا من **System_Name **هكذا*

```
[LEFT][COLOR=#000000] [B]#defineSwitches PORT0[/B][/COLOR][/LEFT]
```
*هذه الطريقة سهلت التذكر كثيرا ففى أى وقت تراجع البرنامج ستعلم ماذا – أين*
*هناك نقطة أخرى بالغة الأهمية أيضا، فماذا لو بعد الانتهاء من البرنامج و بدأت فى رسم البوردة وجدت تعارض فى المسارات ووجدت أنه من الأفضل استخدام منفذ آخر أو طرف آخر**.**من الأفضل أن تتحمل الخطأ فلو حاولت مراجعة البرنامج كاملا لتغير هذا الطرف بالتأكيد ستنسى و تعانى الأمرين حتى تجعله يعمل مرة أخرى**.*
*باستخدام هذه المسميات سيكفى أن تغير التعريف فى أول البرنامج و هو سطر واحد فقط ليعمل البرنامج كما يجب على الوضع الجديد بالأطراف الجديدة**. **أليست هذه نعمة؟**!*
*الآن الخبر الجيد أن هذه المسميات تكون للمترجم فقط ولا ينتج عنها أى كود لذا لا تبخل فىجعل الاسم مناسبا لا هو قصير جدا ويصعب تذكره مثل **X,C **فلن تذكر لاحقا **X **يعنى ماذا ولا **C **أيضا ، ولا تجعل الاسم طويلا فيصعب عليك كتابته كل مرة داخل البرنامج مثل **Liquid_Crystal_Data_Port **ويكفى مثلا **LCD_Data*
*أيضا هذه الطريقة لا تشترط على ماذا تطبق فيمكنك تطبيقها على ثوابت مثل **NoOfLoops=25 **أو حتى على معادلة أو كود مثلا*

```
[LEFT][COLOR=#000000] [B]PressTimeAlias delay (25)[/B][/COLOR][/LEFT]
```
*فماسيفعله المترجم هو ببساطة كما لو أنه استخدم خاصية **"**استبدل**" Replace **من القائمة **"**تحرير**"EDIT **و بدل النصوص كلها قبل أن يبدأ الترجمة **.*
*بلغة ميكرو سى نستخدم الصورة التالية ولاحظ أن ميكروإلكترونيكا هى الشركة الوحيدة التى تستخدم تعريفين **bit , sbit , **فى كل منتجاتها وتنصح باستخدام **sbit **دوما**.*

```
[LEFT][COLOR=#008000][B]sbit SW1 at RC5_bit;[/B][/COLOR][/LEFT]
```


```
[LEFT][COLOR=#008000][B]char Switches at PORT0 ;      [/B][/COLOR][/LEFT]
```
*لاتسألنى لماذا يجب أن ينتهى السطر بالفاصلةالمنقوطة **";” **فلم أجد إجابة شافية حتى الآن*
*البعض يقول تحديد نهاية السطر، حسنا هذا كانضروريا وقت ما كنا نقرأ من الكروت المثقوبة لنحدد بها أى **";” **نهاية السطر أما الآن فهناك فى الويندوز **2 **بايت فى نهاية كل سطر هما **CR,LF **وهما كود **10**وكود **13 **أما فى أبل أو يونكس **/**لينيكس و ملفات الأردوينو فهى إما الأولى أو الثانية فقط حيث **CR **اختصار **Carriage Return **أى رجوع العربة **(**الحاملة للورقة**) **أى الرجوع لأول السطر و **LF **اختصار **Line Feed **أى تحرك لسطر جديد **...**أى أن هناك نهاية سطر مزدوجة فى كل سطر ولا حجة لهذا العذر و لكن لها ميزة عظيمة فى إرباك المبرمج خاصة أنها أحيانا لو وضعت تسبب إرباك المترجم ولا يعطى رسالة خطأ حتى ، فقط يعطيك برنامج كما تخيله هو ،ولو نسيتها فكثيرا ما يكتشفها لكن ليست دوما**.*
*السطر الأول يعنى المفتاح **SW1 **عند الطرف رقم **5 **من المنفذ **C **من المسجل **PORT*
*السطر الثانى يعنى تخصيص اسم **Switches **للمنفذ **0*
* الثوابت:*

*نفس مفهوم الأسماء يمكن امتداده للقيم الثابتة رغم عدم ظهورها فى المثال السابق إلا أنك قد تحتاج للتعامل مع **25 **مدخلا و تحتاج دورة فيها **25 **للقراءة ثم أخرى ربما للحساب و ثالثة للمقارنة ورابعة للعرض على الشاشة الخ فستجد نفسك فى عديد من الدورات كلها **25 **مرة*
*ومثال آخر أنك تحتاج تكرار أمر ما عدة مرات لتحصل على نتيجة ثابته أو تتأكد من ثبات القيمة فعادة ما نضع رقم*
*لكن بنفس القياس لو احتجت لتغيير الدورات فى المثال الأول بالنقصان أو الزيادة سيكون ذلك كابوسا لكن لو استخدمت التعريف السابق فى إعطاء اسم للرقم فكل ما عليك هو تعديله فى أول البرنامج مرة واحدة*
*كل مترجم له طريقته فى هذا فالبعض يستخدم طريقة **EQU **السابقة أو **Alias **أو يجعلها واضحة باستخدام اللفظ **"**ثابت**" **أو **Constant **واختصارا **Const **هكذا*
*Const Loops= 25*
*Const repeat= 50*
*نفس الخبر الجيد السابق ينطبق هنا فهذه الثوابت لا تأخذ من ذاكرة المتحكم لأنها لا تحفظ فى البرنامج و يقوم المترجم باستبدال كل كلمة **Loops **بالعدد **25 **وهكذا و فى النهاية يقوم بالترجمة باستخدام الأعداد و ليس الأسماء و سنوضح الفروقبالأمثلة على لغتى البيزك و السي**..*
*لكن هل من الممكن أن نعدل هذه القيمة بحسب الحاجة؟ هذا يسمى **"**المتغيرات**" **لكن لتنوعها سنجعلها المرة القادمة بإذن الله*​


----------



## ماجد عباس محمد (17 يونيو 2018)

*المتغيرات*

[h=3]*المتغيرات *[/h]*نأتى الآن للجزء التالى من التعليقات التى سبق حذفها وهى باسم المتغيرات*
```
[COLOR=#008000][B];==================================[/B]
[B]; VARIABLES[/B]
[B];==================================[/B][/COLOR][/LEFT]
```
*لكونها تتغير بحسب الحاجة إذن يجب أن نعلم مسبقا أو نحدد لها حجم ما مناسب لأننا سنضطر لوضعها فى الذاكرة و من ثم ستأخذ قدر من المتاح، وقد تقول لا بأس فالمتحكم به عدة الآف من الخانات، للأسف يجب أن أذكر هنا أنها من حجم الذاكرة العشوائية وليست ذاكرة البرنامج وهى فى أتميل **AT89x51 **قدرها **128 **خانة فقط و ألباقى **AT89x52 **فما فوق قدرها **256 **خانة وفى **AVR **تصل **1 **ك و أكثر و تصل **368 **خانة فى **PIC16 **أو اقل فى بعض الأرقام**. **يمكنك أن تخصص لكل متغير من بايت واحدة إلى **4 **بايت ولا تزيد عن ذلك إلا فى حالة النصوص**.*
*كن حذرا هنا فما لم تكن تتعامل مع الأسيمبلى فكل تخصيص لمتغير أنه بت واحدة ، سيحجز المترجم مقابلها بايت كاملة **!!.*
*يجب أن تعلن صراحة عن المتغيرات التى ستستخدمها و إلا ستلقى رسالة خطأ و يتوقف عن الترجمة**.*
*فى الأسيمبلى تستخدم كلمه **EQU **السابقة أيضا، ستقول كيف؟ سأقول كما سبق أن ذكرنا هى تعنى هذا يساوى أو يستبدل بذلك فلو تصف خانة ذاكرة إذن هى متغير لأن محتواها يأخذ أى قيمة من صفر إلى **255 **و أذكر أننا قلنا فى ألتعليمه **Mov P0 , #255 ` **ذكرنا أن **"#” **تضع **255 **على المنفذ لكن لو حذفناها سيأخذ محتوى الذاكرة **255 **حسبما كان هذا و يضعه على المنفذ ، بهذا لو كتبت ألتعليمه*
*Days EQU 50*
*فهذا يعرف المترجم أن عليه استبدال كلمة **Days **بالقيمة **50 **فى الأمرين التاليين*
*Mov P0 , #Days *
*Mov P0 , Days *
*ومن ثم فى السطر الأول سيضع حرفيا على المنفذ صفر قيمة **50 **أما فى السطر الثانى سيأخذ محتوى خانة الذاكرة رقم **50 **و يضعها على المنفذ**. **لو تريد تخصيص **Word **وهى من **2 **بايت سيخصص المترجم المكان الأول الذى أشرت إليه فى الأمر و التالى له آليا**. **لا يوجد فى الأسيمبلى أكبر من **2 **بايت إلا بتخليقك أنت لما تحتاج أو تستخدم مكتبة خارجية**.*

*فى لغة البيزك تستخدم كلمة **Dim **و هى اختصار **Dimension **بمعنى **"**يصنع وفقا لأبعاد محددة**" **و أكثر المترجمات تسمح بتسمية عدد من المتغيرات المتساوية الحجم مثلا*
*Dim Loop , Cycle , X , T as byte*
*وهى هنا تقول أصنع متغيرات واحد باسم **Loop **وآخر باسم **Cycle **وآخر باسم **X **وآخر باسم **T **كل منها بايت واحدة و لتسمى آخر بحجم **2 **بايت يجب أن تعلن من جديد باستخدام **Dim*
*فى لغة **C **تضع النوع أولا هكذا*
```
[B]Byte Loop , Cycle , X , T ;[/B][/LEFT]
[h=4]
```
أنواع المتغيرات و أحجامها :[/h]أصغر متغير هو البت الواحدة وفى عائلة C51 يوجد منها 2 بت للمستخدم و للأسف لا يوجد مثلها فى أى من المتحكمات الأخرى.
داخل كل متحكم يوجد ما يسمى مسجل حالة البرنامج أو Program Status Word و اختصارا PSW وهذا اسمه أى لو تريد الكتابة فيه أو القراءة منه تستخدم الاسم PSW.1 مثلا لقراءة البت رقم 1



الصورة لعائلة C51 حيث نجد فيها 2 بت للمستخدم الأولى باللون الأصفر و اسمها F0 أى يمكنك أن تستخدم هذا الاسم مباشرة هكذا
JB F0, Next_Action
أو تعيد تسميتها بالتعريفات السابق شرحها و الثانية باللون البرتقالى وهى بلا اسم لذا يمكنك استخدام PSW.1 أو تعريفها بأي اسم مناسب . باقى الخانات سيلى شرحها لاحتوائه على كثير من الأمور الهامة.
لو اخترت أى بت أخرى سيخصص المترجم بايت كاملة لها.
لو ستستخدم مترجمات ميكرو الكترونيكا تذكر أنها تسمى sbit

الوحدة الثانية من المتغيرات هى البايت وهى 8 بت وهى تعبر عن حرف من كلمة أى حرف هجائى أو عدد من صفر وحتى 255.
بعض المترجمات خاصة فى اللغات العالية مثل ميكرو الكترونيكا تسمى الحرف Chr اختصار Character و تسمى أيضا Short اختصار Short-Integer و من كل تضع بلا إشارة UN-signed Character أو بالإشارة signed Character و تصبح أعلى بت فيها رقم 7 تمثل إشارة الرقم. لو صفر يكون العدد موجبا و لو 1 يصير سالبا و بهذا تعبر عن +127 إلى -128 فقط بدلا من صفر إلى 255 أيضا
Signed short int أو Un-signed short int لنفس المدى
أما مترجم BASCOM فيستخدم Byte من صفر إلى 255​


----------



## ماجد عباس محمد (19 يونيو 2018)

*اللغات العالية*

*اللغات العالية :*

*ربما نسينا برنامجنا السابق لذا ها هو مجددا و بعد إضافة المسميات
*

```
[LEFT][B]Switches EQU P0[/B]
[B]LEDs EQU P3[/B]
[B]SW1 EQU P3.0[/B]
[B]SW2 EQU P0.1[/B]
[B]SW3 EQU P0.2[/B]

[B]Start:[/B]
[B]Mov Switches , #255[/B]
[B]Mov LEDs , #255[/B]
[B]Loop: [/B]
[B]jb SW1 , SW2test[/B]
[B]mov LEDs , #11111110b ; = 254[/B]
[B]sjmp Loop[/B]
[B]SW2Test: [/B]
[B]jb SW2 , SW3Test[/B]
[B]mov LEDs , #11111100b ; = 252[/B]
[B]sjmp LOOP[/B]
[B]SW3Test:[/B]
[B]jb SW3 , start[/B]
[B]mov LEDs , #11111000b ; = 248[/B]
[B]jmp Loop[/B]
[/LEFT]
```
*و أظن أنه أصبح مفهوما بصورة أوضح**. **هل يمكننا وضعه فى كلمات لشرح خطواته؟*
*نعطى منفذ الليدات اسم **LEDs **ونعطى السويتشات اسم **Switches **و السويتش الأول اسم **SW1 **وهكذا*
*ضع على منفذ السويتشات **255 **و على منفذ الليدات **255*
*العنوان دورة**:*
*لو المفتاح **Sw1 =1 **عندها انتقل للعنوان **SW2test*
*و إلا ضع على الليدات **254 **ثم عد للدورة*
*العنوان **SW2test:*
*لو المفتاح **Sw2 =1 **عندها انتقل للعنوان **SW3test*
*و إلا ضع على الليدات **252 **ثم عد للدورة*
*العنوان **SW3test:*
*لو المفتاح **Sw3 =1 **عندها انتقل للعنوان **start*
*و إلا ضع على الليدات **248 **ثم عد للدورة*


*هل نترجمه للإنجليزية؟؟*
*لو **= IF **، و إلا **= Else **و عندها **= Then **و إعطاء اسم هى **Dimension **لآنها تعنى اسم و حجم معا أو حيز أو صنع شيء طبقا لمواصفة محددة أما استخدام اسم بديل فهو **Alias . **كثير من المترجمات تفضل البدء بكلمة **Main **بمعنى أساسى ، لا بأس فهى تعرفك أنت أين يبدأ البرنامج و دوما ما تحتاج عنوان فى بداية البرنامج لتكراره**.
*

```
[LEFT][B]Main:[/B]
[B]Switches = 255[/B]
[B]LEDs = 255[/B]
[B]Loop:[/B]
[B]If Sw1 = 1 then[/B]
[B]Goto SW2test[/B]
[B]Else[/B]
[B]LEDs = 254[/B]
[B]Goto loop[/B]
[B]End If[/B][/LEFT]
```
*حيثما تريد كتابة أكثر من تعليمه فى أى من الجزأين فإما تكتب كل منهما فى سطر مستقل كما سبق أو تفصل بينهما بالحرف **": “ **كما فى المثال التالى أو ربما المترجم يتبنى حرف آخر، فلنستخدمه إذن**.*
*طبعا هنا ستقول أن كلمة **"**عندها أو **Then “ **زائدة لكن ستجد ضرورتها لو كتبتها فى سطر واحد هكذا*
*If Sw1 = 1 then Goto SW2test Else LEDs = 254 : Goto loop *
*فهى تفصل بين كود الشرط و ألذى قد يكون معادلة طويلة و بين الأوامر الواجب تنفيذها عند تحقق الشرط كما **Else **تفصل بين كود التحقق و كود عدم التحقق – كل كلمة لها مكانها و ضرورتها و مفهومة إن نسيت بمقدورك أن تستنتجها و تركز فى البرنامج بدلا من التركيز على ما لا جدوى منه من أقواس و فواصل منقوطة وهل الفاصلة قبل القوس أم بعده**..*
*وفى نمط السطر الواحد سنستغنى عن حد الختام وهو **End If **لأنها تفصل بين كود **Else **و باقى البرنامج**.*
*هكذا يمكننا أن نكتب باقى البرنامج بالسطر الواحد هكذا
*

```
[LEFT][B]SW2test:[/B]
[B]If Sw2 = 1 then Goto SW3test Else LEDs = 252 : Goto loop [/B]
[B]SW3test:[/B]
[B]If Sw3 = 1 then Goto Start Else LEDs = 248 : Goto loop [/B][/LEFT]
```

*طبعا لو عكسنا المنطق سنوفر قفزة من الاثنتين **(**الأولى**) **بحكم أنها للمكان التالى مباشرة فيمكننا القول*
*If Sw1 = 0 then LEDs = 254 : Goto loop *
*If Sw2 = 0 then LEDs = 252 : Goto loop *
*If Sw3 = 0 then LEDs = 248 : Goto loop *
*Goto Main *
*
لاحظ أن البرنامج الأفضل هو ألذى يقوم بمهام أكثر بكود أقل فى زمن أسرع**.*

*و لنكتبه بلغة **C **أولا يجب أن تلتزم بالأحرف المكتوبة بمعنى لو كتبت **Loop **ثم لاحقا **goto loop **سيعترض أن العنوان غير موجود**. **هذا من بقايا نشأة اللغة فالفرق بين الحرف الكبير و الصغير هو البت رقم **5 **فمثلا*
*حرف **A = 0100 0001 **بينما حرف **a=0110 0001 **وهكذا فى باقى الأحرف و لتوحيد المقاس يلزم تنفيذ أمر على كل الحروف مثل **OR x,#0010 0000 **لجعل الحروف صغيرة أو **AND x,1101 1111 **لجعلها كبيرة وهذا كان رفاهية و إسراف عندما كانت ذاكرة الحاسبات تحسب بالبايت و تشترى بالبت و حتى لاحقا عندما حسبت بالكيلو بايت**. **أيضا كل الأوامر تكتب بالأحرف الصغيرة ولو كتبت أى حرف كبير لن يتعرف عليها المترجم**. **هذا قد يوقعك فى مشكلة لو أخطأت فى حجم حرف فى اسم متغير فى برنامج من عدة صفحات حسب المترجم المستخدم**.*
*سنجد أن البداية بالتعريفات كما سبق الشرح ثم بكلمة **Void **وهى تعنى **"**خلاء**" **أو فراغ أو مساحة و كلمة **main **ضرورية للبدء ثم قوسين لتحديد أنك لا تضع بينهما أى بيانات مطلوب معالجتها ثم القوس المعوج ألذى يحدد البداية و مثله للنهاية
*

```
[LEFT][B]void main() [/B]
[B]{[/B]
[B]TRISA = 0xFF;      [COLOR=#008000][I]// PORTA is input[/I][/COLOR][/B]
[I][B]TRISC = 0;            [COLOR=#008000]// PORTC is output[/COLOR][/B][/I]
[B]Loop:[/B]
[B]if (Sw1=1) {[/B]
[B]Goto SW2test ;[/B]
[B]}[/B]
[B]else {[/B]
[B]LEDs = 254 ; [/B]
[B]Goto loop ;[/B]
[B]}[/B][/LEFT]
```
*
الشرط يجب أن تضعه بين قوسين **(**لماذا ؟ لا تسألنى فلم يجيبنى أحد ولا أرى سببا غير ما شرحت سابقا**) **لو أردت أن تضع بعد ذلك أكثر من سطر فيجب أن تبدأ بالقوس المعوج **} **و تنتهى بآخر **{ **و كل سطر منتهى بالمقدسة **";" **من غير ليه و الصورة المختصرة تصبح
*

```
[LEFT][B]SW2test:[/B]
[B]if (Sw1 = 0 ) [/B]
[B]{ LEDs = 254 ;[/B]
[B]Goto loop ;[/B]
[B]}[/B]
[B]if (Sw2 = 0) {[/B]
[B]LEDs = 252 ;[/B]
[B]Goto loop ; }[/B]
[B]if (Sw3 = 0) {[/B]
[B]LEDs = 248 ;[/B]
[B]Goto loop ;[/B]
[B]Goto Start ;[/B]
[B]}[/B][/LEFT]
```
*
هكذا حولنا البرنامج الصغير إلى كافة اللغات المعنية**. **هل نطوره؟ حسنا المرة القادمة إن شاء الله نبدأ فى معرفة المزيد من تفاصيل المعالج و المزيد من الأوامر لنصنع كارت تحكم فى غسالة كهربية مثلا ثم فرن ميكرو ويف **.*
*أيضا التعليمات بالبيزك و السى أعطت ذات الكود أى لا توجد لغة أقرب للمكونات من الأخرى**.*


----------



## ماجد عباس محمد (20 يونيو 2018)

*صورة أخرى من ألتعليمه if*

[h=4]صورة أخرى من ألتعليمه IF[/h]*بعض الشركات تحبط استخدام الأمر **GOTO **و تفضل عدم استخدامه و مثال لذلك تقترح الصورة المتداخلة من الأمر **IF **وتسمى **Nested IF **وهى أنك بعد الجزء **ELSE **تضع الشرط التالى مباشرة وهى قد تبدو منطقية و أسهل فهما و لنجرب ذلك فى المثال السابق حيث كان البرنامج بعد التعريفات
*

```
[LEFT][B]Start:[/B]
[B]Switches = 255[/B]
[B]LEDs = 255[/B]
[B]Loop:[/B]
[B]If Sw1 = 0 then LEDs = 254 : Goto loop [/B]

[B]If Sw2 = 0 then LEDs = 252 : Goto loop [/B]

[B]If Sw3 = 0 then LEDs = 248 : Goto loop [/B]
[B]Goto Start [/B][/LEFT]
```
*
باستخدام الطريقة المتداخلة تصبح*

```
[LEFT][B]Start:[/B]
[B]Switches = 255[/B]
[B]LEDs = 255[/B]
[B]Loop:[/B]
[B]If Sw1 = 0 then [/B]
[B]LEDs = 254 [/B]
[B]Else If Sw2 = 0 then[/B]
[B]LEDs = 252 [/B]
[B]Else If[/B] Sw3 = 0 then
[B]LEDs[/B] = 248
[B]Else[/B]
LEDs = 255 [B] ; [/B][B]الس[/B][B]طر الأخير[/B]
[B]End IF[/B]
[B]Goto Start [/B][/LEFT]
```
*حسنا تخلصنا من معظم **GOTO **ماعدا الأخيرة فقط وهذه لها أمر آخر يمكن استخدامه لكن لو الذاكرة محدودة فمن الأفضل استخدام الأسلوب الأول ، لماذا؟*
*سينشئ المترجم آليا أمر انتقال لنهاية الدورة حيث تكتب **END IF **أو تضع القوس المعوج فى لغة **C **وهذا سيضيف المقابل للسطر الأخير أمر وضع **255 **على المنفذ و انتقال لأخر الدورة بدلا من **Start *

*و قبل أن نطور برنامجنا السابق و نتعمق أكثر نرى كيف نطبق هذا باستخدام النوعين الآخرين وهذا موضوعنا القادم بإذن الله*


----------



## ماجد عباس محمد (21 يونيو 2018)

*البرنامج بالمتحكمات الآخرى*

[h=4]البرنامج باستخدام AVR[/h]*باستخدام الأسيمبلى سنحاج لتعديل البرنامج كله فقد تغير الأمر **MOV **ليصبح **LDI **اختصار **LOAD Immediate **أى تضع قيمة ما مباشرة فى مسجل و **LDS **لنسخ ذاكرة إلى مسجل و عكسها **STS Store Data to space **فضلا عن باقى التعليمات أيضا كما أن المنافذ هنا قد تغيرت و أصبح لكل منفذ **3 **مسجلات واحد للخرج و يسمى **PORTx **و الثانى للاتجاه دخول**/**خروج و يسمى **DDRx **و الثالث لحالة الطرف و يسمى **PINx **كما سبق الشرح ، لذا سيكون أصعب بقليل كتابة هذا البرنامج لكنه ممكن ، و نظرا لكبر الذاكرة المتاحة و الرغبة فى التعامل مع الأرقام العشرية سيكون من الأفضل الاكتفاء باللغات العالية*
*كما علمنا سابقا أن منافذ **AVR **أصبحت تعطى تيار أو تقبل تيار مشابه لمنافذ ألبيك و عكس **C51 **لذا يمكن أن نتبنى الأسلوبين أى المطابق للسابق*



*أو مشابه للبيك هكذا مع مراعاة تغيير أوامر إضاءة ألليد من صفر إلى **1 **وأذكر هذا تمهيدا للتعامل مع الريلايات لاحقا*




*أيضا لم أوصل طرف **RESET **لأنه يمكن الاستغناء عنه باختيار خاصية **Brown out detect **مع فولت **2.7 **فعندما يهبط جهد التغذية لهذه القيمة يحدث ريست داخلى آليا ولا حاجة للتوصيل الخارجى لكن إن شئت فليكن، أيضا لم أوصل الكريستال لأنه يمكن استخدام المولد الداخلى **1 **ميجا أو **2 **أو **4 **أو **8 **ميجا و إن كان دقيق فى حدود **1% **وهو فى نظرى كاف لكثير من التطبيقات ما عدا الوقت الدقيق ألذي يحتاج أكثر من هذه الدقة أو لو تستخدم التواصل التسلسلى**.*

*باستخدام البيزك و مراعاة المسجلات الثلاث السابقة سيصبح البرنامج*

```
[LEFT][B]$regfile = "m16def.dat" [COLOR=#006400]' [/COLOR][/B][COLOR=#006400][B]تحديد الميكرو[/B][/COLOR]
[B]$Crystal=4000000  [COLOR=#006400]' [/COLOR][/B][COLOR=#006400][B]تردد الكريستال[/B][/COLOR]
[B]$hwstack=40  [COLOR=#006400]' [/COLOR][/B][COLOR=#006400][B]تحديد المرصوصة[/B][/COLOR]
[B]$swstack=16  [COLOR=#006400]' [/COLOR][/B][COLOR=#006400][B]تحديد المرصوصة[/B][/COLOR]
[B]$framesize=32  [COLOR=#006400]' [/COLOR][/B][COLOR=#006400][B]ذاكرة كمسودة لبعض ألدوال [/B][/COLOR][/LEFT]
```
*
السطور الخمس السابقة تخص المترجم أساسا و تجدها مسبوقة بعلامة الدولار **$ **وهى فى باسكوم كما يلى*
*الأول تحديد ملف التعريف بالميكرو **Atmega16A*
*الثانى تردد الكريستال وهو لا يهم إلا فى حساب الكود اللازم للمنفذ التسلسلى و حساب التأخير المطلوب فى بعض الوظائف*
*الثالث تخصيص مرصوصة الانتقال و المقاطعة الخ وتسمى **Hardware **أو مرصوصة المكونات*
*الرابع تخصيص مرصوصة تسمى **Software **أو مرصوصة البرامج وهى مطلوبة للمترجم لبعض العناوين*
*الخامس كمسودة لحسابات يحتاجها المترجم لبعض ألدوال كتنسيق النصوص الخ
*

```
[LEFT][B]Leds Alias PORTA : Leds_dcn Alias DDRA  [COLOR=#006400]' [/COLOR][/B][COLOR=#006400][B]تسميه المنافذ و المفاتيح و مسجل الاتجاه[/B][/COLOR]
[B]Switches Alias PORTD : Switch_dcn Alias DDRD[/B]
[B]Sw1 Alias PIND.0 : Sw2 Alias PIND.1 : Sw3 Alias PIND.2[/B]
[COLOR=#006400][B]' [/B][B]تسميه المفاتيح لاحظ استخدام [/B][B]PIND [/B][B]بدلا من [/B][B]PORTD [/B][/COLOR]
[B]Main:[/B]
[B]Leds_dcn = 0 : Switch_dcn = 255[/B]
[B]Start:[/B]
[B]Switches = 255[/B]
[B]Leds = 255  ' enable Pullup[/B]
[B]Loop:[/B]
[B]If Sw1 = 0 then LEDs = 254 : Goto loop [/B]
[B]If Sw2 = 0 then LEDs = 252 : Goto loop [/B]
[B]If Sw3 = 0 then LEDs = 248 : Goto loop [/B]
[B]Goto Start [/B][/LEFT]
```
*
نلاحظ أن البرنامج لم يختلف كثيرا لدرجة أننا لم نحتاج لإعادة رسم الدائرة فيمكننا أن نستخدم ذات الأطراف فقط نراعى أن أطراف التغذية و الكريستال و الريسيت قد تغيرت أرقامها**.*
*المرة القادمة إن شاء الله نعيده بالبيك **16 **و **18*


----------



## ماجد عباس محمد (22 يونيو 2018)

*البرنامج باستخدام pic16877a*

*البرنامج باستخدام PIC16 *




*
الدائرة سبق رفعها لذا سنستدعيها للمرجعية و سنعيد كتابة البرنامج بالبيزك*
*نلاحظ هنا تطبيق تعديل إضاءة ألليد من صفر إلى **1 **وهو سيستخدم فى الريلايات لاحقا سواء مع ألبيك أو مع **AVR*
*سنلاحظ أيضا مع ميكروإلكترونيكا ستحتاج لتعريف اتجاه المنفذ نصا بالاسم و لن تستطيع استخدام اسم سبق تعريفه وهذا قصور فى هذا المترجم ثم تعين الاتجاه لاحقا عكس باسكوم سيقدم أمر **Config **للتهيئة أيضا هو لا يدعم **Elseif **لذا يجب تفصيلها*


```
[LEFT][B]program Proj01PIC16[/B]
[COLOR=#008000][B]' Declarations section [/B]
[/COLOR][B]Dim Leds as byte at PORTB[/B]
[B]DIM Leds_DCN as byte at TRISB[/B]
[B]DIM Switches_DCN as byte at TRISD[/B]
[B]Dim SW1 as sbit at PORTD.0[/B]
[B]Dim SW2 as sbit at PORTD.1[/B]
[B]DIM SW3 as sbit at PORTd.2[/B]
[B]main:[/B]


[B]If Sw1 = 0 then [/B]
[B]  LEDs = 1      [/B]
[B]else [/B]
[B]If Sw2 = 0 then      [/B]
[B]LEDs = 2          [/B]
[B]else      [/B]
[B]If Sw3 = 0   [/B][B]then          
LEDs = 3                 
[/B][B]else          [/B]
[B]Leds = 0                  [/B]
[B]end if          [/B]
[B]end if      [/B]
[B]end if[/B]
[B]Goto Main[/B]
[B]end.[/B][/LEFT]
```

*البرنامج باستخدام PIC18*

*رغم أن تركيب الأطراف كما هو ولم يتغير **(**عكس الانتقال من **C51 **للأحدث**) **إلا أن بعض الأطراف أضيفت لها وظائف جديدة و كعادة ميكروتشيب أحيانا تفترض الوظيفة الجديدة هى الأساس ، لذا لو أردت استخدام الطرف كمنفذ رقمى يجب أن تلغى الوظيفة الجديدة **.*
*استخدمنا سابقا المنفذين **B,D **و على وجه الخصوص **B0,B1,B2 **لليدات و الأطراف **D0,D1,D2 **للأزرار**.*
*فى الطراز الجديد نجد أن **B0:B4 **تعمل كأطراف تماثلية لذا يجب إعادة تهيئه المنفذ كرقمى و كدخول لذا سيكون من الأسهل استبدال الأطراف للأطراف **B5,B6,B7 **و ستصبح الدائرة هكذا*




*الآن نجد التسمية ذات فائدة كبرى إذ بدلا من إعادة كتابة البرنامج كله نحتاج فقط لتصحيح التسمية فى أول البرنامج سواء استخدمنا البيزك أو **C **وهذه أيضا إحدى حسنات اللغات العالية وهى أن الكود أغلبه لا يحتاج تعديل **. *
مزيد من خواص المتحكم فى المرة القادمة إن شاء الله


----------



## ماجد عباس محمد (23 يونيو 2018)

*مسجل الوظائف الخاصة Special Function Register*

[h=3]مسجل الوظائف الخاصة Special Function Register :[/h]*حسنا عرفنا أن هناك بعض المسجلات لتغيير خواص المنافذ **Ports **و أخرى لوظائف أخرى، أين هى و كيف تعمل؟*
*ببساطة هى ذاكرة داخل المعالج و من خواص أى ذاكرة أن يكون لها حجم محدد و غالبا مرتبط بنظام العد الثنائى ذلك تصنع بحجم ما أكبر من الحاجة الفعلية المستخدمة ، بعض هذه الخانات يوظف و البعض الآخر يرجئ استخدامه لطرز أحدث أو أكثر إمكانيات**. **وهذا يكون أوفر و أسرع فى التصنيع **.*
*تفاصيل كل مسجل ستجدها فى الداتاشيت ولذا سنعرض لواحد منها فقط من قبيل العلم بالشيء لكن ما يهمنا فعلا هو أسماء الخانات ووظيفة كل منها و هل تعدل على مستوى البت أم البايت كاملة ومحتواه عند البدء **RESET*



*هناك مثيل له فى البيك و آخر للأتميل **AVR **و لكل منها طريقتة للكتابه فيه**. **ستجد أن كل ما يحتويه المتحكم فى هذه الذاكرة مثل المنافذ **P0,P1,P2,P3 **و المراكم الأساسى **A **و الثانوى **B **و خانة حالة البرنامج **PSW **السابق ذكرها و عدد من المؤقتات وخانات تعديل خواصها و التحكم فيها و عداد البرنامج و عداد ألرصه و عداد آخر يسمى مؤشر البيانات **Data Pointer **اختصارا **DP **و مسجل المقاطعات و ستجد فى كل خانة اسم و رقم**. **الاسم هو ما يمكنك استخدامه لتكتب أو تقرأ من هذه الخانة مثلا **P0 **للمنفذ صفر و القيمة **11111111 **هى عند البدء سيكون هكذا أى به هذه القيمة وعنوانه **80 **هيكسا و بجواره مباشرة فى الخانة **81 **هيكسا نجد مؤشر ألرصه **SP **أو **Stack Pointer **و الرقم **00000111 **أى أنه يبدأ بالرقم **7 **و طبعا يمكنك تغيير الرقم كما تشاء أما الأرقام المدونة **XXX **فهى تعنى غير متوقعة و يجب تخصيصها قبل قراءتها و خانه التواصل التسلسلى**.*
*نلاحظ هنا أن العمود الأول و الملون يمكنك معالجة كل بت على حدة أو الخانة كاملة بينما الباقى فيجب أن تتعامل بالبايت**.*

[h=2]*مسجل حالة البرنامج **Program Status Word -PSW*[/h]*سبق أن ذكرنا بعض المعلومات عنه لكن هنا سنتناوله بالتفصيل**.*
*هل الميكرو به فقط **A,B* *لا غير؟ ماذا لو احتجت لأكثر من ذلك؟*
*تقدم لك هذه العائلة عدد كبير من المسجلات **Registers* *و يمكنك أن تفعل بها أى شيء سوى أن تجعلها مراكم أى تأخذ مباشرة نتيجة العملية الجارية *
*أولا لديك ثمانية مسجلات تسمى **r0-r7* *و طبعا تمتاز بأن أمر الحفظ فيها أو القراءة منها يستخدم بايت واحدة لأنها معروفة و تحتاج **3 **بت فقط من البايت للإشارة إليه فمثلا*
*MOV R2, #data*
*ستضع قيمة **data* *فى المسجل **R2 **مباشرة
**علىالمقابل من الأمر مثلا*
*MOV50, #data*
*حيثتحتاج لبايت للأمر **MOV**مشيراللذاكرة ثم بايت أخرى لتحدد العنوان **50**فىالذاكرة و البايت الثالثة قيمة **data**التىتريد حفظها**.*


*حسنا **! **أين إذن هذه المسجلات الثمانية؟*
*لا تفاجأ – فهى يمكن أن تحتل أربع أماكن من الذاكرة **العشوائية ، **إما من* * صفر إلى **7* *، **أو من **8 **إلى **F **، **أو من **10* *إلى **17 **، أو من **18 **إلى **1F*
*ما هذه الحيرة*
*كلا يا صديقى هذه مصدر القوة كيف؟*
*لو أنك تحسب لبيانات قادمة من جزء فى ماكينة مثلا ، عادة أسرع وسائل الحفظ هى المسجلات*
*الآن تود حساب **شيء **آخر ثم تعود لما أنت عليه الآن*
*لابد من حفظ المسجلات فى مكان آمن ثم تحسب الأمر المستجد و تحفظ نتائجه أيضا فى مكان آمن آخر ثم تقرا ما كنت تحسب للجزء الأول – قصة طويلة مملة ، أليس كذلك؟*
*ما رأيك فى أن تستبدل هذا السيناريو بكلمة استخدم طقم **2 **وعند العودة قل استخدم طقم **1**؟ أليس أسهل و أبسط؟؟*
*و كيف يتم هذا؟*
*ببساطة نعود لمسجل **PSW **وهى اختصار **Program Status Word **أو خانة حالة البرنامج وهى تحتوى ثمانية خانات **Flip Flop* *تعمل كل منها عمل الراية **Flag* *إما **1 **أو صفر حسب الحالة*



*لاحظ **Bit3,Bit4* *باسم **Register Bank Select **أو اختيار بنك المسجلات **(**البنك **= **المجموعة**) *
*لو **= **صفر تعنى المدى من صفر إلى **7 **من الذاكرة العشوائية أى أول سبعة أماكن*
*لو **= **Ol* *يكون المدى الثانى **أو من **8 **إلى **F *
*لو **= lO* *يكون المدى الثالث أو من **1O* *إلى **17 *
*لو **= **l l * *يكون المدى الرابع أى من **18 **إلى **1F*
*كل ما عليك عمله هو تغيير بت واحدة أو **2 **بت فقط لتحصل على طقم جديد **مع الحفاظ على القديم بلا تغيير للعودة إليه*
*وماذا عن الباقى فى **PSW*
*حسنا*
*رقم صفر أقصى اليمين هى **Parity** "**تكافؤ**" **وتحدد إن كان المراكم **A* *يحتوى عدد فردى أو زوجى من **"1"*
*رقم **1 **هى للمستخدم كيف يشاء لتذكر هل حدث أمر ما أم لم يحدث**.*
*رقم **2 **لو زاد العدد عن الحد و تتحكم بها وحدة الحساب والمنطق لتصحيح الناتج فى حال كان الرقم موجب و سالب**(127 **إلى **-128 ) **أم موجب فقط من **0 **إلى **255*
*رقم **3**،**4 **سبق الحديث عنهما*
*رقم **5 **للاستخدام العام مثل رقم **1*
*رقم **6 **AC* *وهو لتصحيح جمع الأرقام بالنظام العشرى بدلا من النظام الثنائى فمثلا عند جمع **17 + 26 **لا يوجد سوى الجمع الثنائى أى الناتج سيكون **3D **و لكننا نريد جمع عشرى أى **17+26 =43 **فماذا نفعل؟ *
*عند جمع **7+6= 13 **أى **D **سيوضع آليا واحد فى الراية **AC **دلالة أن المجموع تعدى **9 **و باستخدام بعد الجمع مباشرة ألتعليمه *
*DA A **وهى اختصار **Decimal Adjust ACCUMULATOR *
*فتتولى بفحص هذه الراية و باقى الرايات مثل **C **تصحيح الرقم آليا من **3D **إلى **43.*
*وهذا مفيد فى التعامل مع كثير من الأرقام **BCD **و التى توجد فى بعض الحساسات أو تسهل التعامل مع الأرقام**. **يجب ألا ننسى أن الأرقام التى تجمع يجب أن تكون أصلا **BCD **و إلا سينتج خطأ*

*الأخير رقم **7 **Carry* *هو مثل السابق لكن لأى عملية جمع عندما يكون المجموع زائد عن **255 **أو بعد تعليمه **DA A **لو الناتج أعلى من **99*

*طبعا غنى عن الذكر أن هذه الخانة يمكنك التعامل فيها على مستوى البت فتختبر هذه أو تفرض تلك أو تلغيها **(**تجعلها**=1 **أو صفر**)*

*فى هذا الرابط*
http://datasheets.chipdb.org/Intel/MCS51/MANUALS/27238302.PDF
*نجد مرجع شامل كتبته شركة إنتل **INTEL **وهى مبتكرة هذا الميكرو و إن اشتهر أكثر بأنه من إنتاج **ATMEL *
*ومن مراجع **ATMEL **حقيقة وجدت صعوبات كثيرة فى لم شمل أجزاء الميكرو و فهم مكوناته من أكثر من مرجع معا*
*ولكن فى هذا الملف نجد معظم البنود مرتبة و مشروحة**.*
*فى كل متحكم ستجد **PSW **أو مسجل حالة البرنامج مع اختلافات طفيفة فى المحتوى و استخدام اللغة العالية عادة يغنى عن تفاصيله و استخدامه **.*
*فى سلسلة **AVR **أصبح عدد المسجلات **32 **مسجل منها **6 **تعمل كثلاثة مسجلات كل منها **16 **بت باسم **X,Y,Z **ولها خواص برمجية مميزة**. *
*فى عائلة ميكروتشيب فعددها محدود جدا مما يعقد استخدامها*

*فيم يستخدم المتحكم و متى لا يكون مجديا؟ وهل ما زالت الطريقة التقليدية باستخدام الدوائر التماثلية تناسب تطبيقات أكثر من المتحكم؟ هذا موضوعنا القادم بإذن الله*


----------



## ماجد عباس محمد (24 يونيو 2018)

*استخدامات الميكروكونتروللر أو المتحكم*

[h=2]استخدامات الميكروكونتروللر أو المتحكم[/h]البعض يتخيل أن الميكرو أو المتحكم هو رائعة العلم و أنه أتى ليقول لعالم ألتماثلى وداعا لكن مهلا نحتاج لفهم بعض الحقائق عن هذه الأشياء ثم نحكم.
أولا ما هى أقصى سرعة نتحدث عنها هنا؟ حسنا نلجأ للدائرة و سنجد كريستال هى الحاكم ألرئيسى و من الداتاشيت لهذه الأنواع نجد أن أعلى تردد استخدم هو 30 ميجا – طبعا الكثير منها 25 فقط أو 20 ميجا فقط.
إذن لا تحلم بأسرع من 30 ميجا
ماذا تعنى؟ أجل تعنى حدك الأقصى فلا تستطيع توليد تردد أو قياسه أو التحكم فى شيء بمعدل أسرع من ذلك.
أيضا هناك نقطة هامة وهى كيف يعمل الميكرو من الداخل؟
لدينا ما يسمى Sequencer أو مرتب الأحداث أو موالى الأحداث أو سمه ما شئت وهو المسؤول عن تنفيذ الأحداث بتتالى محدد وهو
1- قراءة الكود من ذاكرة البرنامج
2- زد واحد على مسجل عنوان البرنامج
3-تحليل الكود و معرفة الخطوة التالية هل تنفيذ السابق كأمر مفرد (مثلا NOP لا تفعل شيئا أو INC A زد واحد لمحتوى المراكم أو CLR A ألغى محتويات المراكم الخ) أو هو حساب يتطلب أخذ قيمة تالية من الذاكرة
4- قراءة *الكود التالى* من الذاكرة كبيان
5- تنفيذ الأمر ثم البدء من جديد
هذه الخطوات يأخذ وقتا وهذا الوقت يحسب بعدد نبضات الكريستال لهذا فعائلة C51 تحتاج 12 نبضة لتنفيذ دورة كاملة و التى قد تكفى تنفيذ أمر وحيد الخانات أو أمر مفرد كما سبق (مثلا NOP لا تفعل شيئا أو INC A زد واحد لمحتوى المراكم أو CLR A ألغى محتويات المراكم الخ) أو قد تحتاج 12 أخرى لغالبية الأوامر و التى تأخذ دورتين.
إذن30 ميجا / 24 ستصبح1.25 مليون أمر فقط فى الثانية.
لاحقا أنتجت الشركة وحدات تنفذ فى 6 دورات و حتى دورتين فقط لكن بكريستال لا تزيد عن 20 ميجا و من ثم أعلى سرعة هى 10 مليون أمر فى الثانية.
بالنسبة لميكروتشيب فهى تحتاج 4 نبضات فى الدورة إذن 30 /4 تصبح 7.5 مليون أمر فى الثانية
رائع ماذا نحتاج أكثر من ذلك؟
أجل أنت لست وحدك فى هذا العالم و تتحكم فيما حولك بالبرنامج أى المسألة ليست بسيطة كما نظن ولو عدنا للمثال السابق سنجد أننا لنتحكم فى بضع أمور بسيطة تطلب الأمر عدة خطوات و رغم أن البرنامج لا ينفذ كله فى كل مرة إلا أننا يجب أن نستوعب هنا خاصية من أهم خصائص البرمجة عن سرعة التنفيذ
*لاحظ أن دورة أو **Cycle **هى **12 **نبضة من الكريستال، وهكذا نستهلك **2 **دورة فى كل تعليمه أى **4 **دورات تمهيد من **Start **إلى **Loop **و من ثم **6 **دورة لو كان المفتاح الأول مضغوطا ثم نكرر و إلا سنضيف **6 **للمفتاح الثانى و إلا **6 **للمفتاح الثالث**.*
*أى كل دورة كاملة للبرنامج إما **6 **أو **12 **أو **18 **دورة أى **72 **نبضة من الكريستال أو **144 **أو **216 **دورة**. **وهذا زمن لا بأس به، و بالطرز الحديثة حيث تستخدم **2 **نبضة من الكريستال لكل تعليمه ستستهلك **12 **أو **24 **أو **36 **دورة من الكريستال*

```
[LEFT][B]Start:[/B]
[B]Mov Switches , #255           [/B] [COLOR=#008000][B] ; [/B][B]2Byte, 2Cycle[/B][/COLOR]
[B]Mov LEDs , #255                   [COLOR=#008000]; 2Byte, 2Cycle[/COLOR][/B][COLOR=#008000]
[/COLOR][B]Loop: [/B]
[B]jb SW1 , SW2test ; 3Byte, 2Cycle[/B]
[B]mov LEDs , #11111110b      [COLOR=#008000]; = 254 2Byte, 2Cycle[/COLOR][/B]
[B]sjmp Loop                              [COLOR=#008000]; 2Byte, 2Cycle[/COLOR][/B]
[B]SW2Test: [/B]
[B]jb SW2 , SW3Test ; 3Byte, 2Cycle[/B]
[B]mov LEDs , #11111100b       [COLOR=#008000]; = 252 2Byte, 2Cycle[/COLOR][/B]
[B]sjmp LOOP                             [COLOR=#008000]; 2Byte, 2Cycle[/COLOR][/B]
[B]SW3Test:[/B]
[B]jb SW3 , start                        [COLOR=#008000] ; 3Byte, 2Cycle[/COLOR][/B]
[B]mov LEDs , #11111000b          [COLOR=#008000]; = 248 2Byte, 2Cycle[/COLOR][/B]
[B]jmp Loop                                  [COLOR=#008000]; 2Byte, 2Cycle[/COLOR][/B]
[/LEFT]
```
*مع ميكروتشيب الأمر أسهل حيث الكل يأخذ **3 **دورة و بايت واحدة فيكون البرنامج يحتاج **8 **تعليمات حتى يصل إلى **Loop **أى **32 **دورة للتمهيد ثم*


```
[LEFT][B]CLRF STATUS         [COLOR=#008000] ; Bank0[/COLOR][/B]
[B]CLRF PORTB            [COLOR=#008000]; Initialize PORTB by clearing output data latches[/COLOR][/B]
[B][COLOR=#008000][/COLOR]CLRF PORTD           [COLOR=#008000] ; Initialize PORTD by clearing output data latches[/COLOR][/B]
[B]BSF STATUS, RP0    [COLOR=#008000]; Select Bank1[/COLOR][/B]
[B]CLRF TRISB            [COLOR=#008000] ; All OUTs[/COLOR][/B]

[B]MOVLW 255[/B]
[B]MOVWF TRISD[/B]
[B]CLRF STATUS ; Bank0[/B][/LEFT]
```
*
هنا أمرين لو لم يكن المفتاح الأول مضغوطا أو **4 **لو مضغوطا ليكرر الدورة أى**4 **أو **6 **للثانى أو **8 **للثالث أو تكرار الدورة كاملة وهذا يعنى **4*4=16 **أو **24 **أو **32 **دورة إضافة للتمهيد **32 **دورة كريستال*

```
[LEFT][B]Loop: [/B]
[B]BTFSC PORTD , 0[/B]
[B]GOTO Sw1[/B]
[B]MOVLW 1[/B]
[B]MOVWF PORTB[/B]
[B]GOTO Loop[/B]
[B]Sw1:[/B]
[B]BTFSC PORTD , 1[/B]
[B]GOTO Sw2[/B]
[B]MOVLW 3[/B]
[B]MOVWF PORTB[/B]
[B]GOTO Loop[/B]
[B]Sw2:[/B]
[B]BTFSC PORTD, 2[/B]
[B]GOTO SW3[/B]
[B]MOVLW 7[/B]
[B]MOVWF PORTB[/B]
[B]GOTO Loop[/B]
[B]SW3: [/B]
[B]CLRF PORTB [/B]
[B]GOTO Loop[/B][/LEFT]
```
*
هناك كثير من الأشياء الأخرى يجب مراعاتها مثلا محول ألتماثلى رقمى وفى **PIC16 **يحتاج على الأقل **200 **ميكرو ثانية لكل تحويله أى **5000 **مرة فى الثانية وأسرع من ذلك فى كل من **PIC18 **و عائلة **AVR*
*وهذا يقودنا لمثال بسيط، تود أن تصنع دائرة مثبت فولت ، لديك طريقين إما تماثلى بالمتكاملات أو بمتحكم و الأخير يعطى إيهاما بأننا ننظمها بالحاسب الآلى*
*حسنا سرعة المتكاملة الخطية تستجيب فى أقل من ميكرو ثانية طبقا للداتاشيت فكم تعليمه تنفذها فى هذا الوقت؟؟ يمكنك وضع ميكرو للوجاهة و تعرض التيار و الفولت الخ لكن دع التحكم للمتكاملة الخطية سواء أكانت تماثلية أو تقطيعية**.*


*الآن يمكننا أن نفكر فى تطوير برنامجنا السابق لنبدأ مثلا بغساله آلية ذات **6 **برامج وهو موضوعنا القادم بإذن الله**.*


----------



## ماجد عباس محمد (25 يونيو 2018)

*برنامج غسالة صغيرة*

[h=1]برنامج غسالة صغيرة  :[/h]*الغسالة عادة ما يكون لها شاشة تكتب المراحل و مجموعة أزرار لتحديد برنامج من عشرات البرامج، لكن لكوننا لسنا خبراء فى الغسيل سنكتفى بما يلى**:*
*ثلاث أزرار لاختيار البرنامج خفيف – وسط – كامل يحدد الوقت من **4 **أو **10 **أو **20 **دقيقة وثلاث للدورة بارد**/**بارد أو غسيل دافئ و شطف بارد أو غسيل ساخن و شطف بارد ، وآخر للبدء و سابع إيقاف للطوارئ و ثامن للباب مفتوح**/**مغلق و مدخل تاسع لحساس الحرارة العالية و عاشر لحساس الحرارة المتوسطة و حادى عشر لمستوى الماء*
*سته مخارج لسته ليدات للبرامج الثلاث و الدورات الثلاث و مخرج سابع لتشغيل **/ **إيقاف الموتور مخرج ثامن للسخان و مخرج تاسع لفتح دخول المياه و عاشر لصرف المياه و حادى عشر لسرعة الموتور **. *
*قبل أن نعرض للدائرة هناك بعض الأساسيات التى تجعلنا نلجأ لتصميم ما أفضل من الآخر وهذا يرجع أساسا لسلوك الميكرو ألذى سنستخدمه لذلك سنكرر هذا البرنامج مع الأربع متحكمات المتفق عليها و اللغات الثلاث **.*

[h=2]غسالة باستخدام C51 و لغة الأسيمبلى:[/h]*من الخبرة السابقة وجدنا أن عند تطبيق التيار يحدث إعادة بدء تشغيل **RESET **ومن ثم كل المنافذ تصبح آحاد أى **+5 **فولت وكثير من المصممون يفضلون أسلوب أن واحد يعنى تشغيل و صفر يعنى إيقاف لأنه منطقى و يبدأ البرنامج بأمر جعل المنفذ **=**صفر و يفاجأ أنه عند التشغيل تفعل كل الريلايات معا ثم تفصل مما يسبب لحظة بدء تشغيل خاطئه فى البدء**.*
*هذه قد تكون مكروهة ولكنها أحيانا تكون خطيرة و تسبب مشاكل**.*
*قد تسأل نفسك أليس أول أمر هو التصفير؟ وهل فى ميكرو ثانية تستجيب الريلايات؟ هذا غير منطقى**!!*
*الواقع أنك لم تحسب كم من الوقت يمر قبل أن ينفذ هذا الأمر، ارجع للداتاشيت ستجد أن المذبذب أولا يحتاج بضع مللى ثانية ليقوم و يستقر و الميكرو يحتاج لبضع نبضات حتى يستجيب للريسيت أو إعادة التشغيل و أخيرا يبدأ فى تنفيذ الأمر**.*
*لذا الأفضل أن تعتمد حالة البدء كأساس و عندما تريد تغييرها افعل ذلك فى الوقت المناسب**.*
*من هنا سنجعل كافة المخارج كما هى **= 1 **و تعنى فصل الريلايات و عندما نريد تفعيل أى منها نستخدم صفر**.*
*أسهل طريقة و أقلها كلفة أن نستخدم ريلاى **5 **فولت وهو متوافرو معه ترانزستور س م س أو **PNP **ومقاومة و دايود كالآتى*
*PNP relay drv.png*




*ببساطة عندما تكون مقاومة القاعدة **R8 **متصله ب **+5 **فولت سيكون جهد القاعدة **Base **مساو للباعث**Emitter **ولا يمر تيار و عندما يكون طرف المقاومة **= **صفر سيمر تيار القاعدة **Base **و من ثم يفتح الترانزستور و يفعل الريلاى**. **الدايود **D8 **طبعا لإلغاء تأثير الملف عند الغلق**.*
*هذه الدائرة سنكررها **5 **مرات لتشغيل الموتور و تسريع الموتور عند العصر و فتح المياه و فتح مصرف المياه و تشغيل السخان*
*دوائر الليدات لبيان الدورة و الحرارة سبق نقاشها فى البرنامج الأول وهى هنا امتداد له و أيضا توصيل المفاتيح **Switches **هو امتداد لما سبق فيما عدا طرفى **Start/Stop **أو بدء التشغيل و طرف **Emergency. **طرف بدء التشغيل لبدء التشغيل بالخيارات المطروحة ولكن لن يوقف الغسالة فى المنتصف**. **هذا لا ينفى حدوث مشاكل تستوجب توقف الدورة لذا بالضغط على زر **Start **أو البدء مع زر الطوارئ **Emergency **تفرض إيقاف الغسالة **و ذلك لتجنب إيقاف الغسالة بالخطأ عند الضغط العفوى على الزر**.*
*هذا تم بحيلة بسيطة وهى إدخال إشارة الطوارئ على طرف المقاطعة الخارجية **INT0 *




*نحتاج لمنطق يقول لو صفر مع صفر يكون الخرج صفر ولو أى تركيبة أخرى يكون الخرج **=1*

*هذا يتطلب بوابة **"**أو**" OR-Gate **كما بالرسم المتكاملة **4071 **فعند الضغط على أى من المفتاحين سيكون على الطرف الآخر واحد و يبقى الخرج واحد حتى يتم الضغط على كلاهما فيصبح الخرج صفر وهذا يسبب مقاطعة المتحكم ومن ثم إيقافه لكونه على طرف **INT0 .*
*أعلم أن من سيفحص البرنامج لاحقا سيقول أن الطرف المتصل بالمنفذ**3.0 **و المسمى **Emergency **لم يستخدم، نعم و لكن إما تستبدل البوابة و تستخدم **7432 **أو توصل طرف **4071 **بمقاومة للموجب ولو نحتاج لهذا الطرف للتحكم فى أى شيء آخر يمكننا فعل ذلك ** - بهذه الطريقة نوفر مقاومة تعليق Pullup .*
*الآن دورة الغسالة تحتاج حتى **24 **دقيقة فكيف نحصل عليها؟*
*البعض يلجأ فى اللغات العالية لأوامر تسبب عدم استجابة المتحكم لأى شيء آخر وهذا يلغى فائدته لذا استخدام عداد و نقوم بتغييره له مضاره ومثال على ذلك*
*MOV R0,#250*
*DJNZ R0,$*
*وهذه تعنى ضع فى المسجل **R0 **القيمة **250 (**لاحظ وجود شباك هنا**) *
*ثم الأمر **DJNZ **هو اختصار **Decrement and Jump if Not Zero **ثم المسجل **R0 **و علامة الدولار ، علامة الدولار هذه اختصار لكلمة **"**هنا**" **فكأنك استبدلت العنوانين التاليين بها*
*Here: DJNZ R0,Here*
*فيما عدا أنك فى كل مرة تستخدم هذه الدورة ستحتاج لأسم جديد لها أما **"$” **فلا*
*و الحادث أنك تضع **250 **فى المسجل ثم تنقص **1 **فإن لم يكن صفرا تعود لذات الأمر أى تنقص منه **1 **أى باختصار تظل تنقص **1 **حتى يصبح محتواه صفرا لن تنفذ الانتقال مرة أخرى و تخرج منها أى لف حول نفسه **250 **مرة كل مرة تستهلك **24 **نبضة من الكريستال – زمن قليل جدا *
*وكان من الممكن استخدام الأمر*
*MOV 10,#250*
*DJNZ 10,$*
*وهو يعنى ضع فى خانة الذاكرة **10 (**لاحظ عدم وجود شباك هنا**) **القيمة **250 (**لاحظ وجود شباك هنا**) … **فقط ستستهلك خانة ذاكرة اكثر لأن العنوان يحتاج بايت بينما المسجل جزء من الأمر**.*
*لذا سنحتاج عديد من هذه الدوائر و يا حبذا لو متداخلة لكن بصعوبة نصل لثانية لذا نلجأ لحيلة المقاطعة أيضا
*





*نأخذ عينة من أحد طرفى المحول **9 **فولت متردد **(**النقطة **1) **و من خلال الدايود **D7 **نأخذ أنصاف الموجة الموجبة فقط ثم نمررها على ترانزستور كمكبر يحولها لموجة مربعة و نضعها على طرف المقاطعة **INT1 **باسم **Clock **إذن كل مقاطعة بعد **20 **مللى ثانية و كل **50 **مقاطعة بثانية كاملة**.*
*إذن مزيد من شرح المقاطعة المرة القادمة إن شاء الله*


----------



## ماجد عباس محمد (26 يونيو 2018)

*المقاطعة فى عائلة c51*

[h=3]المقاطعة فى C51 [/h]*سبق أن شرحنا عناوين المقاطعة و ما يحدث**. **عند المقاطعة و هنا لنبرمج المقاطعة يجب أن نعود لجدول الوظائف الخاصة فنجد فى خانة **0A8h **حيث نجد مسجل باسم **IE **اختصار **Interrupt Enable **أى إتاحة المقاطعة و آخر فى **08Bh **باسم **IP **اختصار **Interrupt Priority **أى أولوية المقاطعة**.*
*الأول **IE **يحدد أى من المصادر متاح و الأول على اليسار بت **7 **إتاحة الكل*





*لو **EA **أو إتاحة الكل **= **صفر **(**حالة البدء**) **لن يتاح أى من المقاطعات الأخرى لذا يجب أن يكون **=1 **لتتاح أى من الباقيات**.*
*بعد ذلك نجد البت **4 **للتسلسلى و البت رقم **3 **لتايمر **1 **و البت رقم **2 **للخارجى رقم **1 **و البت رقم **1 **لتايمر صفر و البت رقم صفر للخارجى رقم صفر*
*يجب أن تكون أى منهم **= 1 **لكى تفعل المقاطعة المناظرة له و إلا فعكس الميكرو تشيب لن تسبب أى مقاطعة**.*
*ما يسبب المقاطعة الفعلية هى بت أخرى فى كل موديول مثلا موديول التايمر به بت للمقاطعة لن تستجيب ما لم **EA = 1 **و أيضا بت التايمر الخاصة بها **= 1 **فى هذا المسجل **IE **و سنعرض لذلك لاحقا**.*
*عندما تحدث مقاطعة فستستجيب الدائرة آليا كما شرحنا سابقا ولكن قبل الانتقال للعنوان تجعل **EA =**صفر فلا يستجيب لأى مقاطعة أخرى**. **لذلك يجب أن ينتهى برنامج المقاطعة بأمر خاص هو **RETI **وتعنى العودة من المقاطعة وهى تخبر الدائرة أن المقاطعة تمت خدمتها و من ثم آليا تعيد **EA=1 **مرة أخرى**.*
*قد يكون البرنامج طويلا و تحتاج لمراقبة أشياء أخرى و تحتاج المقاطعة أثناء المقاطعة، الحل بسيط*
* SETB EA*
*CLR EA*
*الأمر الأول يجعل البت المشار إليها **(**وهى هنا نصا **EA ) **بواحد و التالى يجعلها **= **صفر لو أحتاج الأمر أن تنفذ شيء ما دون مقاطعة و طبعا يمكنك الإشارة لأى بت حتى فى منفذ ما بأى من الأمرين السابقين مثلا **SETB P0.3 **أو لو اسمها معروف مثل **CLR C **أو المراكم **A **أيضا **CLR A **كلها متاحة و تسهل العمل **.*
*ماذا يحدث لو حدث **2 **مقاطعة أو أكثر فى آن؟ حسنا الدائرة تتولى فحص البيتات بالترتيب وهذا يعطيها أولوية ترتيب كما يلى*
*IE0 **الخارجى صفر ثم **TF0 **تايمر صفر ثم **IE1 **الخارجى واحد ثم **TF1 **تايمر واحد ثم التسلسلى بشقيه إرسال أو استقبال و أخيرا تايمر **2*
*الآن ماذا يحدث لو أردت تغيير هذه الأولوية كأن تعطى الأولوية للتسلسلى مثلا أو اكثر من مصدر؟*
*حسنا المسجل الآخر **IP **اختصار **Interrupt Priority **أى أولوية المقاطعة**. **لهذا الغرض حيث تجد الخمسة مصادر من بت صفر إلى بت **4*




*كلها تكون **= **صفر فى البدء و أى بت تغيرها **=1 **تضع المقاطعة المناظرة بأولوية أعلى**.*
*الآن لو نقلت أى مقاطعة لأولوية أعلى سيستجاب لها أولا قبل أى من الأخريات**. **لو نقلت أكثر من واحدة فذات ترتيب الفحص السابق سيسرى بين الأعلى أولوية فقط ثم ينتقل بعد ذلك لما بقى من الأقل أولوية**. **ولو حدثت مقاطعة لأقل أولوية لن يقاطعها سوى شيء من الأعلى أولوية**.*
*لا أدرى لماذا ألغيت الأولوية فى عائلة **AVR.*

*الآن بالعودة لدائرة الطوارئ لإيقاف الغسالة نجد أنها متصلة بالمقاطعة الخارجية صفر **IE0 **ذات الأولوية الأعلى*




*لتفعيلها نحتاج لتنفيذ الأمرين*
*SETB EA*
*SETB EX0*
*أو تنفيذ الأمر*
*MOV IE,#10000001b*

*الآن نريد أن نفعل المقاطعة الأخرى للمؤقت صفر و المتصل بالنبضات **Clock **لتحسب الزمن وهذا موضوعنا القادم بإذن الله*


----------



## ماجد عباس محمد (27 يونيو 2018)

*حساب الزمن بالمقاطعة*

*حساب الزمن بالمقاطعة*

*الدائرة السابق شرحها لتوليد موجة مربعة من **50 **هرتز توفر لنا نبضة أو مقاطعة **50 **مرة فى الثانية أى **60*50=3000 **مرة فى الدقيقة، إذن بتوفير عداد يعد **3000 **سيعطى خرج كل دقيقة و من ثم نعد **20 **دقيقة لزمن الغسيل، لكن لو أردت إضافة شاشة رقمية تبين الوقت لن يكون لديك وسيلة لعد الثوانى ، لذا سنعد الثوانى و منها الدقائق**.*
*فى الوحدة **AT89C51 **يوجد مؤقت صفر و مؤقت **1 **و بدء من **AT89C52 **و باقى المتحكمات أضيف لها مؤقت ثالث اسمه **T2 **وهو **16 **بت ذاتى التحميل و صمم خصيصا لتسهيل التعامل مع المنفذ التسلسلى لذا لا حاجة لاستخدامه هنا**.*
*المؤقت **1. **أيضا **16 **بت ولذا لا حاجة أيضا لاستخدامه هنا **. **جدير بالذكر أن كل المسجلات و المؤقتات ذات **16 **بت تكون من خانتين و تجد هذا صراحة فى جدول الوظائف الخاصة **Special Function Register SFR **و هذا يمكنك من استخدام أمرين لتحميل النصف العلوى و الثانى لتحميل النصف السفلى أو تستخدم أمر واحد بتحميل المسجل أو المؤقت دفعة واحدة لكنها مهمة المترجم أن يحول هذا الأمر المقبول بأغلب المترجمات للأمرين السابقين**.*
*أما مؤقت صفر فيتكون من نصفين **TH0 **و **TL0 **حيث **H=High, L=Low **و يمكننا أن نشغله بهما معا كمؤقت **16 **بت أو مؤقت **8 **بت ذاتى التحميل حيث نضع ذات القيمة فى كلا النصفين و عند تشغيله يرتفع من القيمة الموضوعة و حتى **255 **أى **0FFh **و عندها يعطى مقاطعة و يعود للقيمة المحفوظة فى النصف الآخر ليكرر الدورة ما لم يتدخل المبرمج لتغيير القيمة المحفوظة فى **TH0 . *
*ملحوظة *: *فى هذه العائلة المؤقتات**/**عدادات تعد صاعدا فقط**...**، أيضا عند تهيئتها كعداد تأخذ من طرف خارجى بذات الاسم و عند تهيئتها كمؤقت ستأخذ من النظام الداخلى أى تردد الكريستال مقسوما على **12 **أى عدد الدورات**.*
*هكذا بوضع **255-50 = 205 **فى كلا النصفين فإن **TL0 **سيتصاعد حتى **255 (**بعد **50 **نبضة**) **ثم يحدث مقاطعة و ينسخ **205 **من **TH0 **ليكمل دورة جديدة **.*
*خرج دائرة توليد **50 **هرتز السابق شرحها المرة الماضية تدخل على طرف المؤقت **"**تايمر صفر**" **و لذا يجب أن نهيئه لهذا العمل**. **فى **SPR **نجد خانتين أحداهما يسمى **TMOD **وهى تايمر مود أى نسق التشغيل وهذا محتواها*




*نلاحظ أن نصفه الأيمن **4 **بت **(**باللون الأصفر**) **تخص تايمر صفر و الأخريات للتايمر **1*
*البت اليسرى تسمى **Gate **وهى لتمكن التحكم فى التايمر من خارج المتحكم*
*البت التالية تسمي **C/T **وهى تجعل المسجل يعمل تايمر أو مؤقت**. **لو **1 **يكون عداد و يعد النبضات على الطرف المناظر **T0 **أو **T1*
*بعد ذلك **2 **بت يحددان وظيفة العداد**/**مؤقت*
*لو صفر صفر كما بالجدول سيعمل **13 **بت منها **5 **مقسم سابق **Prescaler *
*لو واحد صفر يكون **16 **بت *
*لو صفر واحد يكون **8 **بت ذاتى التحميل كما شرحنا وهو النسق ألذى سنتبناه*
*لو **11 **سيتوقف تايمر **1 **ولو فى النصف الأيمن ، تايمر صفر كل قسم منفصل حيث **TL0 **يعمل **8 **بت بينما **TL1 **هو**8 **بت أيضا لكن يخضع لنبضات تحكم **T1*
*لذلك سنضع فيه **00000010 **لكى يعمل تحميل ذاتى*

*بعد ذلك نجد خانة أخرى اسمها **TCON **أى تحكم فى التايمر*




*و نجد أن كل **2 **بت متجاورة توفر وظائف مختلفة الذات الموقت فمثلا باللون الأصفر نجد*
*TF1 **اختصار **Timer1 over Flow **وهذه البت هى فعلا مسببة المقاطعة *
*و دوائر المتحكم تقيمها عندما ينتقل محتوى المسجل **Timer1 **من الحد الأقصى للصفر فتسبب مقاطعة و عندما ينتقل البرنامج لتنفيذ برنامج المقاطعة **(**أى خدمة المقاطعة**) **يعيدها صفرا **(**عكس ما يحدث فى ميكرو تشيب إذ يجب أن تفعلها بنفسك وهو أحد أسباب مشقة برمجته بالأسيمبلى هنا وفى باقى البيتات فى هذا المسجل**) . *
*الثانية **TR1 **وهى اختصار **Timer Run **أى تايمر واحد تشغيل**/**إيقاف عندما يقيمها **(=1) **البرنامج يعمل المؤقت و عندما يلغيها **= **صفر يتوقف*
*باللون البرتقالى **TF0 **بت المقاطعة للتايمر صفر وكما سبق **=1 **عند ألمقاطعة و عند خدمة المقاطعة ستعود آليا لصفر و **TR0 **تشغيل و إيقافه و بتهيئته كعداد سيأخذ من الطرف **T0 (**وهو فى دائرتنا نوصلها بمولد **50 **هرتز**) .*
*باللون الأخضر مقاطعة خارجية رقم **1 **أى **IE1 **وهى **Interrupt External **التى تسبب المقاطعة نتيجة نزول الطرف الخارجى **INT1 **منفذ **3 **طرف **3 **و البت التالية **IT1 **هى **Interrupt Trigger **تغير استجابة المتحكم للتغيير على الطرف **INT1 **منفذ **3 **طرف **3 **،من قدح بالمستوى **Level Trigger **أى تستجيب للمستوى **= **صفر إلى قدح بالحافة **Edge Trigger **أى حافة هابطة من**+ 5 **فولت للصفر**.*
*لو هذه البت **= **صفر ستستجيب المقاطعة للمستوى **= **صفر و من ثم لو تمت الاستجابة له و لم يعود للمستوى **1 **قبل العودة من المقاطعة ، فإن الميكرو سيجدها ما زالت صفر و من ثم بالخطأ يظنها مقاطعة جديدة، أما لو كانت **1 **فهذا يعنى أن الاستجابة تحدث نتيجة الانتقال من واحد للصفر و لن تتكرر مرة أخرى حتى تعود الحالة للواحد مرة أخرى ثم تنتقل للصفر و كثيرا ما يكون هذا أسلم **.*
*و أخيرا باللون الأزرق ذات الخاصيتين لكن للطرف **INT0 **و بهذا نحتاج لوضع **IT0=1 **بالأمر*
*SETB IT0*

*وهكذا اكتملت الدائرة و أصبحت كما يلى*





*برجاء ملاحظة أن هذا للتعليم ولكن واقعيا يجب إضافة مكثف من **0.01uF **إلى **0.1uF **على طرفى كل مفتاح لتجنب الارتداد و الاهتزاز **Bouncing **و ضمان عدم تكرار النبضة كما أن كل طراز له حساسات مختلفة عن ما اقترحته هنا و أيضا الدورات ستختلف لذا يمكنك تعديل أى برنامج حسب الواقع**.*
*الآن نبدأ بالبرمجة بالأسيمبلى و حتى ذلك الحين نفكر كيف نهيكله ، مثلا يقرأ المفاتيح حتى يقرأ **Start **ثم يبدأ ملئ المياه حتى يقفل المفتاح ثم يبدأ التسخين حتى الحساس المعنى ثم تدور **5 **أو **12 **أو **20 **دقيقة غسيل ثم صرف حتى الحساس ثم ملئ مرة أخرى للشطف ثم دوران دقيقتين ثم صرف ثم ملئ و شطف دقيقتين أخرتين ثم دورة العصر خمسة دقائق ثم التوقف*

*حسنا هذا المرة القادمة إن شاء الله*


----------



## ماجد عباس محمد (28 يونيو 2018)

*برنامج الغسالة بالأسيمبلى*

*كتابة البرنامج بالأسيمبلى:*

*البداية و التعريفات والمقاطعة:*

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

```
[LEFT][B]$NOMOD51[/B]
[B]$INCLUDE (80C52.MCU)[/B]
[B];=====================================[/B]
[B]; DEFINITIONS[/B]
[B];=====================================[/B]
[B]LEDs Equ P0[/B]
Relays [B]equ[/B] P1
[B]Switches equ P2[/B]
[B]Controls Equ P3[/B]
[B]FullLED Equ LEDs.0[/B]
[B]HalfLED Equ LEDS.1[/B]
[B]SmallLED Equ LEDs.2[/B]
[B]HOTLED Equ LEDs.3[/B]
[B]MildLED Equ LEDs.4[/B]
[B]ColdLED Equ LEDs.5[/B]
[B]WaterOn Equ Relays.0[/B]
[B]DrainOn Equ Relays.1[/B]
[B]HeaterOn Equ Relays.2[/B]
[B]MotorOn Equ Relays.3[/B]
[B]Run_Nspin Equ Relays.4[/B]
[B]WaterFull Equ Relays.5[/B]
[B]WaterEmpty Equ Relays.6[/B]
[B]DoorOpen Equ Relays.7[/B]
[B]MidTemp Equ Switches.0[/B]
[B]HiTemp Equ Switches.1[/B]
[B]Cold Equ Switches.2[/B]
[B]Mild Equ Switches.3[/B]
[B]Hot Equ Switches.4[/B]
[B]Small Equ Switches.5[/B]
[B]Half Equ Switches.6[/B]
[B]Full Equ Switches.7[/B]
[B]RUN Equ Controls.1[/B]
[B];=====================================[/B]
[B]; VARIABLES[/B]
[B];=====================================[/B]
Seconds Equ [B]R7[/B]
Minutes Equ [B]R6[/B]
[B]JobPending Equ F0[/B]
[B];=====================================[/B]
[B]; RESET and INTERRUPT VECTORS[/B]
[B];===================================== [/B]
org 0000h ; Reset Vector
[B]sjmp Start[/B]
[B]org 0003h ; Adress of INT0 (IE0)Emergency  [/B]
[B]sjmp Start ; Reset All Parameters and Ports[/B]
[B]org 000Bh ; Adress of Interrupt Timer 0 (TF0)[/B]
[B]DJNZ Seconds,Tfinish[/B]
[B]MOV seconds,#59[/B]
[B]Djnz Minutes,Tfinish[/B]
[B]CLR Jobpending[/B]
[B]CLR[/B] [B]TR0[/B] ; Stop counter
[B]Tfinish: RETI[/B][/LEFT]
```
*بعد التعريفات يأتى دور المتغيرات و نعرف أنها إما تكون اسم لخانة فى الذاكرة أو لو أمكن يكون مسجل لكونه أسرع**. **نذكر أن فى أتميل مجموعة مسجلات منها ثمانية يسهل التعامل معهم ولبعضهم ميزات إضافية وهى تعرف باسم **R0:R7 **لذلك سنعرف أحدهما باسم الدقائق و آخر باسم الثوانى هما **R7,R6 **و نحتاج لعلم **Flag **يشير أن الزمن لم ينتهى بعد**.*
*أعلم أنك ستقول سينتهى عندما كل من **R7,R6 **أو بمسمياتهم **Minuted,Seconds **يساويان صفر*
*أجل لكن لتعلم ذلك يجب أن تختبرهما على التوالى كل مرة تريد فيها التحقق من انتهاء الزمن وهذا ما يسمى برمجة غير احترافية لإضاعتهما كود و زمن و أنت أصلا لا تحتاج لذلك*
*لا تنسى أن كل مقاطعة وظيفتها أن تنقص الثوانى و تنقص الدقائق حتى تتساوى بالصفر أى أنك بالفعل حسبت هذا الأمر وما عليك سوى حفظ النتيجة ، هنا نستخدم البت **F0 **السابق شرحها فى **PSW **و المسماة **User Flag **فتجعلها **=1 **ثم تبدأ العد و عند تمامه اجعلها **= **صفر و بالتالى كل ما عليك أن تختبرها فقط بتعليمه صغيرة و بسيطة لتعلم إن كان الزمن قد تم أم لا**.*


*بعد ذلك يأتى البدء و المقاطعة، سنجد فى خانة صفر حيث الريسيت قفزة لعنوان **Start **حيث بدء البرنامج الفعلى*
*يليها فى العنوان **3 **حيث عنوان مقاطعة الطرف الخارجى **INT0 **وهى الطوارئ و هنا يجب الإيقاف و العودة حيث بدأنا لذلك نستخدم القفز إلى **Start **أيضا كما لو أننى أطفأت الوحدة ثم أعدت تشغيلها مرة أخرى*
*و أخيرا فى عنوان **B **وهو **=12 **حيث مقاطعة العداد ألذى يستقبل **50 **هرتز من الخارج و بعد **50 **عد أى كل ثانية سيحدث مقاطعة**. **هنا سننقص الثوانى **1 **فإن بقى ثوانى نعود من المقاطعة و إلا لو أصبحت صفرا ننقص الدقائق **1 **فإن لم تكن صفرا نعيد الثوانى إلى **59 **و نبدأ الدورة من جديد أى نعود من المقاطعة وهكذا حتى تنتهى الدقائق وتصبح صفرا نوقف العداد و نعلن انتهاء الزمن بتصفير العلم **Jobpending **و نخرج من المقاطعة**.*
*لاحظ هنا أن آخر دقيقة لم تحول لثوانى و بالتالى لم تحسب لذا عند البدء مثلا بخمس دقائق نضع **5 **دقائق و **59 **ثانية**.*
*المرة القادمة إن شاء الله نكمل باقى البرنامج **.*


----------



## ماجد عباس محمد (29 يونيو 2018)

*تجهيز الغسالة و اعداد الخيارات*

*تجهيز الغسالة :*

*بعد أن مهدنا للمقاطعة و البدء الخ نبدأ البرنامج طبقا للهيكلة السابقة فمثلا نقول بعد أن نختار الكمية و الحرارة ، لو الباب مغلق نبدأ ملئ الخزان و عند تمامه نشغل السخان طبقا للحرارة*
*ما بين عنوان البدء و عنوان الدورة **"**التكرارى**" **نجد ما يسمى التمهيد أو**House Keeping **أو حرفيا ترتيب المنزل*
*السطر الأول إتاحة كل المقاطعات و مقاطعة **T0 **ومقاطعة الخارجى **INT0*
*الثانى و الثالث تحميل كل من نصفى المسجل **T0 **بالقيمة المطلوبة و الرابع تهيئه **T0 **كعداد ذاتى التحميل بعدها جعل المقاطعة الخارجية قدح بالحافة **Edge Trigger **ثم تغيير مؤشر الرصة بعيدا ثم وضع المنافذ الأربع فى حال البداية رغم أنها كذلك إلا أن هنا ضرورة لحالة الطوارئ فهى لن تعيد المنافذ لحال البدء لذا تفرض بالبرنامج تحسبا**.*
*لو حدث طارئ و ضغطت على زر الطوارئ ستجبر المتحكم على البدء من جديد و سينهى التهيئة و الوصول هنا و ينتقل عبره لدورة تشغيل الموتور قبل أن تتمكن من رفع إصبعك من على زر البدء لذا وجب الانتظار هنا حتى ترفع يدك عنه لذا نختبر لو البت **Run = 0 **سنظل فى دوره وذلك بالأمر **JNB **اختصار **Jump if Not Bit set **ثم اسم البت **Run **و العنوان المقصود الذهاب إليه و علامة الدولار هى رمز مختصر لكلمة **"**هنا**" **بدلا من و ضع عنوان أول السطر و كتابته مرة أخرى فى الأمر هكذا*
*Here: JNB Run,Here*
*هكذا سنظل ندور هنا طالما زرار **RUN=0 **ثم بعده نختبر الخيارات *

```
[LEFT][SIZE=3][COLOR=#008000][B];=====================================[/B]
[B]; CODE SEGMENT[/B]
[B];=====================================[/B]
[/COLOR][B]Start: [/B]
[B]MOV IE,#10000011b        [COLOR=#008000] ; Enable T0 & INT0 external[/COLOR][/B]
[B]MOV TH0,#205                   [COLOR=#008000]; Auto reload[/COLOR][/B]
[B]MOV TL0,#205[/B]
[B]MOV TMOD,#00000110b    [COLOR=#008000]; T0 8bit counter auto reload[/COLOR][/B]
[B]MOV TCON,#1                    [COLOR=#008000] ; Clear All interrupts, SETB IT0 Edge triggered[/COLOR][/B]
[B]MOV SP,#70                       [COLOR=#008000] ; Move stack away[/COLOR][/B]
[B]MOV LEDs,#11011011b      [COLOR=#008000]; Reset All PORTS! select Small cold cycle[/COLOR][/B]
[B]MOV Relays,#255[/B]
[B]MOV Switches,#255[/B]
[B]MOV Controls,#255 [/B]
[B]JNB RUN,$                            [COLOR=#008000]; Run button release[/COLOR][/B]
[B]JB Full,TstHalf[/B]
[B]Loop: [/B]
[B]ORL LEDs,#00000111b[/B]
[B]CLR FullLED[/B]
[B]TstHalf: JB Half,TSTSmall[/B]
[B]ORL LEDs,#00000111b[/B]
[B]CLR HalfLED[/B]
[B]TSTSmall: JB Small,TstHot[/B]
[B]ORL LEDs,#00000111b[/B]
[B]CLR SmallLED[/B]
[B]TstHot: JB Hot,TstMild[/B]
[B]ORL LEDs,#00111000b[/B]
[B]CLR HotLED[/B]
[B]TstMild: JB Mild,TstCold[/B]
[B]ORL LEDs,#00111000b[/B]
[B]CLR MildLED[/B]
[B]TstCold: JB Cold,TstStart[/B]
[B]ORL LEDs,#00111000b[/B]
[B]CLR ColdLED[/B]
[/SIZE][B][SIZE=3]TstStart:[/SIZE]
[/B]
[/LEFT]
```
*
بعد ذلك نجد العنوان **Loop **التكرارى *
*الخيار الافتراضى هنا **Small Cold **بعد ذلك نفحص أى الأزرار تضغط فإن لم يكن **Full **ننتقل للتالى و إلا نضيء ألليد الخاص بالكمية **Full **بجعل طرفه **= **صفر ولو أردنا السرعة نضع أمر انتقال **sjmp TstHot **حتى لا نضيع وقت فى اختبار الحالتين التاليتين و للكود الأقل نكتفى بما لدينا*
*أود هنا أن أوضح أساسا من أساسيات البرمجة وهى السرعة مقابل الكود، من المنطقى أن يكون الكود الأكثر أبطا فى التنفيذ لكن غالبا ما يكون الكود الأطول أسرع فى التنفيذ وهذا مثال على ذلك فإضافة أوامر انتقال يضيف كود ليختصر تنفيذ ما لا يجدى تنفيذه**.*
*بعد ذلك نختبر **Half **و ننتقل لو لم يضغط لاختبار **Small **و إلا نضيء **HalfLED **، ولكى نضئ واحد يجب أن نطفئ أى ليد آخر قد يكون مضاء و لكنا لا نعلم ما هو ، لذا نطفئ الكل بأمر*
*ORL LEDs,#00000111b*
*حيث **ORL **اختصار **OR Logic **وهى تنفيذ وظيفة **OR **أى وظيفة **"**أو**" **على مستوى البت**. **تسمى **Logic **لأن هناك فى بعض المترجمات للغات العالية تستخدم دوال على مستوى المتغير تسمى **Boolean OR **حيث يعتبر أى رقم هو موجود أو **= **منطق واحد أو حقيقى أو **TRUE **و الصفر فقط هو منطق صفر أو **False **أو غير موجود وهو يعطى نتائج مختلفة فمثلا متمم **complement **أى رقم هو صفر بينما متمم الصفر هو **FF **أو **255 **و مترجمات **C51 **لا تدعمه **.*
*تنفيذ الأمر السابق يفرض **111 **فى البيتات الثلاث الأقل فيطفئ الليدات الثلاث معا ثم أمر **CLR **لإضاءة ما نريد*
*بعد ذلك نكرر العمل مع البتات الثلاث الأخريات لاختيار الحرارة ساخن أو دافئ أو بارد مع ملاحظة أن أمر **ORL **الآن مع البيتات الثلاث **.*
*المرة القادمة إن شاء الله نختبر هل نبدأ أم نكرر ما سبقت*


----------



## ماجد عباس محمد (30 يونيو 2018)

*التشغيل و الإيقاف*

*التشغيل و الإيقاف:*

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

```
[LEFT][SIZE=4][B]TstStart:[/B]
[B]JB run,Loop                   [COLOR=#006400] ; Wait Run Press[/COLOR][/B]
[B]JB DoorOpen,$              [COLOR=#008000] ; Wait Door to close[/COLOR][/B]
[B]CLR WaterOn                 [COLOR=#008000]; Fill with water[/COLOR][/B]
[B]JB WaterFull,$              [COLOR=#008000] ; Wait full Tank[/COLOR][/B]
[B]SETB WaterON              [COLOR=#008000] ; Close water Valve[/COLOR][/B]
[B]JNB ColdLED,SetCycle   [COLOR=#008000]; Cold cycle No Heat needed[/COLOR][/B]
[B]CLR HeaterON               [COLOR=#008000] ; Turn Heater ON[/COLOR][/B]
[B]JNB MildLED,HOTTemp[/B]
[B]JB HiTemp,$                  [COLOR=#008000] ; wait Hot sensor[/COLOR][/B]
[B]SJMP SetCycle [/B]
[B]HOTTemp: [/B]
[B]JB MidTemp,$                 [COLOR=#008000]; wait Warm sensor[/COLOR][/B]
[B]SetCycle:                        [COLOR=#008000] ; Now Start Washing[/COLOR][/B]
[B]SETB HeaterON             [COLOR=#008000]  ; Turn off heater[/COLOR][/B]
[B]JNB FullLED,HalfCycle[/B]
[B]MOV Minutes,#20[/B]
[B]SJMP RunMotor[/B]
[B]HalfCycle: JNB HalfLED,SmallCycle[/B]
[B]MOV Minutes,#8[/B]
[B]SJMP RunMotor[/B]
[B]SmallCycle:[/B]
[B]MOV Minutes,#5[/B]
[B]RunMotor:[/B][/SIZE][/LEFT]
```
*
الآن انتقلنا لتحديد الزمن، فنغلق السخان و من الجيد أن نغلقه هنا فالبعض يكرر أمر الإغلاق فى الحالات الثلاث السابقة وهو تكرار مستهلك للذاكرة لا داعى له**. *
*نختبر **Full **فإن كانت مختارة نضع فى الدقائق **20 **دقيقة و ننتقل لتشغيل الموتور و إلا نختبر **Half *
*هيه، ذكرت أنك تحتاج تضع **59 **فى الثوانى**!! **أجل ذاكرة جيدة ، لكنك لم تقرأ السطر قبل السابق**! **و لم تتعلم الدرس**!*
*نختبر **Half **و فإن كانت مختارة نضع فى الدقائق **8 **دقائق و ننتقل لتشغيل الموتور و كما سبق و قلنا هو الاحتمال الأخير الباقى أن نضع **5 **دقائق و الانتقال هنا أيضا حتمى بتتابع الأحداث**.*
*المرة القادمة إن شاء الله سنتحدث عن تشغيل الموتور فى دورة الغسيل ثم دورتين للشطف و ثالثة للعصير و التوقف بانتظار تحديد دورة أخرى أو تكرار هذه الدورة**.*


----------



## ماجد عباس محمد (1 يوليو 2018)

*دورات الغسيل و الشطف و العصر ثم الإيقاف*

[h=4]دورات الغسيل و الشطف و العصر ثم الإيقاف:[/h]*لم نضع سابقا قيمة **59 **للثوانى ، حسنا أول ما نفعله هو وضعها فهى مكررة للكل ثم نقيم العلم أى البت **JobPending **والتى هى دليل انتهاء الزمن و المقاطعة سترجعها للصفر عند انتهاء الزمن ثم نبدأ الموتور و نشغل العداد الداخلى **T0 **و ننتظر انتهاء الوقت ثم نوقف الموتور**. **ثم نفتح الصرف و ننتظر حساس المياه لنعلم خلو الخزان ثم نغلق الصمام ثم نفتح الماء للشطف و ننتظر حساس الملئ و نغلق الصمام ثم نضع **5 **دقائق لدورة الشطف و نبدأ كما سبق ثم نوقف الموتور
*

```
[LEFT][B]RunMotor:[/B]
[B]MOV[/B] Seconds,#59
[B]SETB[/B] JobPending
[B]CLR[/B] MotorOn
[B]SETB[/B] TR0                          [COLOR=#008000] ; Start Timer/Counter[/COLOR]
[B]JB[/B] JobPending,$             [COLOR=#008000]  ; Wait to Finish[/COLOR]
[B]SETB[/B] MotorON               [COLOR=#008000]; stop motor[/COLOR]
[B]CLR[/B] DrainON                 [COLOR=#008000]; Open Drain[/COLOR]
[B]JB[/B] WaterEmpty,$          [COLOR=#008000] ;Wait Drain[/COLOR]
[B]Setb[/B] DrainON                 [COLOR=#008000] ; Close Drain[/COLOR]
[B]CLR[/B] WaterON                 [COLOR=#008000] ; Fill again
[/COLOR][B]JB[/B] WaterFull,$
[B]SETB[/B] WaterON               [COLOR=#008000] ; Close Water[/COLOR]
[B]MOV[/B] Minutes,#5           [COLOR=#008000] ; 1St Rinze[/COLOR]
[B]MOV[/B] Seconds,#59
[B]SETB[/B] JobPending
[B]CLR[/B] MotorOn                  [COLOR=#008000]; Start Rinze[/COLOR]
[B]SETB[/B] TR0                       [COLOR=#008000] ; Start Timer[/COLOR]
[B]JB[/B] JobPending,$             [COLOR=#008000] ; Wait to Finish[/COLOR]
[B]Setb[/B] MotorOn                 [COLOR=#008000]  ; Stop Rinze[/COLOR]


[B]CLR[/B] DrainON                 [COLOR=#008000]; Open Drain second cycle
[/COLOR][B]JB[/B] WaterEmpty,$          [COLOR=#008000] ;Wait Drain[/COLOR]
[B]Setb[/B] DrainON                [COLOR=#008000]; Close Drain[/COLOR]
[B]CLR[/B] WaterON                 [COLOR=#008000] ; Fill again[/COLOR]
[B]JB[/B] WaterFull,$
[B]SETB[/B] WaterON              [COLOR=#008000]; Close Water[/COLOR]
[B]MOV[/B] Minutes,#5          [COLOR=#008000] ; 2nd Rinze[/COLOR]
[B]MOV[/B] Seconds,#59
[B]SETB[/B] JobPending
[B]SETB[/B] TR0                      [COLOR=#008000] ; Start Timer/Counter[/COLOR]
[B]CLR[/B] MotorOn                [COLOR=#008000] ; Start Rinze[/COLOR]
[B]SETB[/B] TR0                      [COLOR=#008000]; Start Timer[/COLOR]
[B]JB[/B] JobPending,$         [COLOR=#008000]  ; Wait to Finish[/COLOR]
[B]Setb[/B] MotorOn              [COLOR=#008000] ; Stop Rinze[/COLOR]
[B]CLR[/B] DrainON                [COLOR=#008000] ; Open Drain second cycle[/COLOR]
[B]JB[/B] WaterEmpty,$          [COLOR=#008000];Wait Drain[/COLOR]
[B]MOV[/B] Minutes,#3            [COLOR=#008000]; SPIN[/COLOR]
[B]MOV[/B] Seconds,#59
[B]SETB[/B] JobPending
[B]CLR[/B] MotorOn                 [COLOR=#008000]; Start Rinze[/COLOR]
[B]CLR[/B] Run_Nspin              [COLOR=#008000]; SPIN[/COLOR]
[B]SETB[/B] TR0                       [COLOR=#008000]; Start Timer/Counter[/COLOR]
[B]JB[/B] JobPending,$          [COLOR=#008000]  ; Wait to Finish[/COLOR]
[COLOR=#008000][B];           SETB Run_NSpin'[/B]
[B]; SETB MotorON               ; Stop Motor'[/B]
; Setb DrainON                 ;[B] Close DRAIN'[/B][/COLOR]
[B]MOV[/B] Relays,#255          [COLOR=#008000];[B] ALL OFF, INITIAL State[/B][/COLOR]
[B]MOV[/B] Controls,#255
[B]jmp [/B][B]Loop[/B]
[COLOR=#008000][B];====================================[/B]
[/COLOR][B]END[/B][/LEFT]
```
*ثم نصرف المياه و نكرر الشطف مرة ثانية ثم نتوقف وبعد الصرف نضع **3 **دقائق لدورة العصر و نبدأ كما سبق مع تفعيل طرف **RUN_NSPIN **للسرعة العالية ثم نتوقف**.*
*الآن قبل أن نعود للدورة نحتاج للتأكد من أن الموتور مغلق و العودة للسرعة العادية و الصرف مغلق بالثلاث أوامر المذكورة ولكنها موضوعة بصورة تعليق لأن استخدام أمرين فقط كما هو مبين كافى لإعادة الوضع كاملا للتوقف**.*


*أيضا هنا استخدمنا أزرار وليدات وهو أمر جيد لكثير من التطبيقات لكنه فى إدخال الأرقام متعب قليلا لذا بعد انتهاء شرح اللغات أفكر فى برنامج ميكروويف منزلى لتناول لوحة الأرقام **Key Pad **مع الشاشات السباعية و تغير وظيفة طرف حسب الظروف ثم برنامج لشيء آخر لتناول محول تماثلى رقمى و ألشاشة **LCD **هذا لو لم تشير رغباتكم لاتجاه آخر**.*


*قبل أن نبدأ فى إعادة البرنامج بالبيزك ثم بلغة **C **أود شرح بعض النقاط العملية فى التنفيذ وهو موضوعنا القادم بإذن الله*


----------



## ماجد عباس محمد (2 يوليو 2018)

*اعتبارات عملية فى تنفيذ مثل هذه ألبوردات*

[h=4]اعتبارات عملية فى تنفيذ مثل هذه ألبوردات:[/h]*الكثير يعانى من مشكلة أن الأمور تسير على ما يرام و عندما توضع الريلايات تختل الأمور و يعيد المتحكم البدء من جديد ولا يستقر إطلاقا*
*الكثير يقترح استخدام أوبتوكبلر و حلول أخرى كثيرة لكن المشكلة أن الأحمال ألحثية تكون فى لحظة توصيلها صفر أوم أى قصر و حتى يبنى المجال و يقل التيار تدريجا ، تتسبب فى نبضة قاسية على خطوط التغذية**.*
*المعروف من مفكوك فورير أن النبضة الحادة لها مركبات حتى ترددات ما لانهاية وهذا يوفر قدرا كبيرا من الترددات العالية**.*
*عند ترددات مثل **100 **ميجا و لا أفترض الأعلى، ستجد أن وصلات التغذية تشكل ملفات و مكثفات و دوائر رنين غير مرئية و غير محسوبة*

*رجاء للفحص و الدراسة وليس التطبيق حاول تصفح مرسل إذاعة **FM **، ستجد كم المشاكل حول أنه لم يعمل كثيرة رغم أننى نفذت أكثر من واحد – المشكلة فقط **"**أنه كان متاحا لى راسم ذبذبات يرسم و يحسب هذا التردد**" **و من ثم علمت كم هو بعيد عن التردد المطلوب**.*
*الآن ماذا يهمك و أنت تدرس متحكم؟ رجاء راجع حجم الملف المستخدم ستجده ثلاث إلى **5 **لفات على قلم رصاص رفيع أى طول السلك لا يزيد عن**10 **سم**. **كم هو طول خطوط التغذية لديك؟؟*
*تغليظ المسارات يقلل من الأثر لكنه ليس بالقدر المطلوب، وفى هذا المجال *



*التوصيل على اليسار أكثر أمنا و أقل تأثيرا عن التوصيل على اليمين وهذا يعنى أن مسارات تغذية الريلايات من المنبع تكون منفصلة تماما عن باقى المكونات الإلكترونية ولا تجعل الرجوع مشتركا إلا فى نقطة البدء*
*أيضا وضع مكثف بجوار كل ريلاى أو فى مدخل تغذيتهم سيجعل نبضات الريلاى مأخوذة منه ولا تعبره لباقى الدوائر*
*لو تستخدم وسائل خارجية مثل الموتورات و السولينويدات أى صمامات المياه الكهربية فكلها قد تعمل من**220 **متردد و الريلاى سيتحكم فيها**. **حسنا ضوضاء هذه المعدات ستشكل مشكلة أيضا لذا عادة ما تفصل مساراتها عن مسارات وحدة التغذية**.*
*استخدام وحدات تغذية مثبتة الجهد و تقطيعية تقلل كثيرا من أثر هذه الضوضاء لأنها تعتمد التقطيع ثم التخلص من أثره**. **و استخدام مرشح دخول للبوردة يقلل كثيرا من أثر هذه التداخلات**.*
*استخدام مرشح تغذية يفيد جدا فى التخلص من أثر هذه التداخلات **Line Filter **و ممكن أن يكون على البوردة لو تغذى من مصدر متردد سواء **220 **أو **12 **فولت أو يكون قبل محول الدخول**.*



*أيضا يجب الاهتمام جيدا بتغذية المتحكم ذاته حتى لا تدخل له نبضات من طرفى التغذية**. **كما أن الكثير لا يعبأ بطرف **MCLR **أو **RESET **فإما تلغيه و تهيء الطرف كمدخل **/ **مخرج وتعتمد على الريسيت الذاتى مع انخفاض الفولت و تضع على طرفى التغذية مكثفات كافية أو تجعله طرف بدء تشغيل و توصله بالمقاومة و المكثف المناسبين*
*أيضا لا تنسى أن وضعك مكثف **100 **ميكروفاراد لا يغنى عن واحد **0.1 **ميكرو على ألتوازى معه و الأفضل أن يكون قرص سيراميك لأن لف طبقات المكثف يخلق ملف داخلى يعوق الاستجابة للترددات العالية**.*

*قبل البدء قى تحويل البرنامج باللغات العالية سنبدأ فى المرة القادمة فهم ما هى اللغات العالية وهو موضوعنا القادم إن شاء الله*


----------



## ماجد عباس محمد (3 يوليو 2018)

*هيكل اللغات العالية و تكونها*

*هيكل اللغات العالية و مم تتكون:*

*اللغات العالية تشترك فى مجموعة من الصفات مع اختلافات فى نص كتابتها و قد تتعجب أنها تتكون من **10 **أوامر فقط تنقسم لثلاثة أقسام هى الشروط **Conditions **و الدورات **Iteration **ثم القفز أو الانتقال **Jump*
*قبل دراسة تفاصيلها ندرس الهيكل العام لأى برنامج*
*الهيكل العام:*

تبدأ بالتسميات حيث تعطى لأى مكون اسم مريح من واقع الدائرة لتذكرك ما دور كل اسم سواء كان منفذ كامل أو طرف من منفذ أو مكون داخلى كمسجل أو علم Flag أو قيمة ثابتة أو متغيرة الخ. التسميات لا تأخذ أى ذاكرة لأنها تنتهى عند بدء الترجمة حيث يستبدل المترجم كل اسم بما يساويه سواء أكان مكون أو حتى معادلة رياضيه (كثير من المترجمات تسمح بهذا وليست الكل) . هذه التسميات تكون بالتعليمه Alias أو Symbol حسب المترجم باسكوم أو ميكروإلكترونيكا و يفضل غالبا و يحتم أحيانا كثيرة أن يكون فى أول البرنامج لحاجة المترجم لها لترجمة باقى الأسطر .
يلى ذلك التعريفات حيث تعرف المتغيرات و الثوابت اسم كل منها و حجمه (كم بايت) وهل هو موجب فقط أم موجب و سالب كما سبق الشرح و هل هى رقم عشرى Float
يلى ذلك تعريف ألدوال و الوظائف حيث يمكن تعريفها وكتابة الكود اللازم لها أو نكتفى بالتعريف فقط و نضع الكود لها لاحقا.
فى اللغات العالية يتكون البرنامج من مجموعة من الوظائف و قد تحتاج ألدوال أيضا و الوظيفة هى ببساطة مجموعة أوامر متتابعة تؤدى مهمة معينه. مثلا اكتب على الشاشة كذا الخ ولا ناتج لها سوى العمل المطلوب. أما ألدوال فهى مشابهة إلا أنها تعطى نتيجة مثلا جيب الزاوية فهى دالة أعطيها 30 تعطينى نصف لأن جا 30 = 0.5
هذه الأسماء عامة أى تشمل البرنامج كاملا بكافة أقسامه. أغلب المترجمات تسمح بالتعريف داخل الدالة أو الوظيفة و يكون ظهور هذه القيمة داخل الدالة فقط مثلا لو عرفت دالة باسم "Send" و عرفت داخلها قيمة "Count" فقيمة Count هذه لا تستطيع أى تعليمه فى البرنامج خارج "Send" أن تصل إليها و تتعامل معها.
*تعريف الوظيفة:*

هى مجموعة تعليمات بين بداية و نهاية يحددان ما يخص هذه الوظيفة ففى البيزك نجد باسكوم تستخدم فى قسم التعريفات

```
[LEFT][B]Declare Sub InitLCD
Declare Sub Testvar(b As Byte , I As Integer , W As Word )[/B][/LEFT]
```
و الكلمة الأولى هى Declare وتعنى إشهار أو إعلان ثم كلمة Sub اختصار Subroutine للدلالة أنها لا تعطى نتيجة حسابية ثم يلى ذلك اسمها وهو InitLCD وهى تهيئه الشاشة LCD و يمكن أن تضيف () قوسين لتذكرك أنها لا تقبل بيانات أو بالصورة فى السطر التالى وهى باسم Testvar لاختبار متغيرات مثلا ثم تضع بين قوسين أسماء لهذه المتغيرات غير الأسماء التى سبق لك استخدامها فى التعريفات مع كلمة As و حجم أو نوع كل منها ولو أكثر من واحد تفصل بينهم بفاصلة)
لاحقا فى البرنامج و حيث تريد لهذه الوظيفة أن توضع فى الذاكرة بين باقى البرنامج تكتب ما يلى
```
Sub InitLCD
.
.
End Sub


Sub Testvar(b As Byte , I As Integer , W As Word )
.
.
.
End Sub[/LEFT]
```
هذه الطريقة تتيح لك أن تقسم الذاكرة حسب ما تريد و تضع كل وظيفة أو دالة بالضبط حيت ترى ، أما طريقة ميكروإلكترونيكا فيجب أن تعلنها و تضعها قبل استخدامها هكذا أو تكتب كلمة Forward كما سيلى

```
[LEFT]SUB PROCEDURE DoThisThing ()
.
.
.
End Sub[/LEFT]
```
البداية هى كلمة Sub اختصار Subroutine ثم كلمة PROCEDURE للدلالة أنها لا تعطى نتيجة حسابية (لا معنى لتكرار الأمر هنا ولكنها ليست قياسية فى أى نظام بيزك) ثم يلى ذلك اسمها وهو ما عبرت عنه بكلمة DoThisThing ثم قوسين () لتبيان أننا لا نحتاج أى شيء لهذه الوظيفة أما لو مثل وظيفة الكتابة على الشاشة مثلا تكون

```
[LEFT]SUB PROCEDURE WriteLCD (Line2Print as string)
.كود
.
.
End Sub[/LEFT]
```
فتضع بين القوسين Line2Print as string وهى Line2Print مجرد اسم ليذكرك لاحقا ماذا تحتاج لأن تضع بدلا منه ثم as string تعريف أنها نص
و لكى تستخدم أى منهم نتبع الصيغة البسيطة كأى تعليمه أخرى مثلا

```
[LEFT]InitLCD
Testvar(5 , 20 , 1245 )
DoThisThing
WriteLCD (“ Hello World “)[/LEFT]
```
*تعريف الدالة*

أما الدالة فتكون بطريقة باسكوم 
*Declare Function Myfunction(byval I As Integer , S As String) As Integer*
و نغير كلمة Sub بكلمة Function للدلاله على أنها وظيفة تعيد نتيجة إما رقم أو نصوص أو ما تحدد لها
لاحقا وحيث تريد أن تضعها تكتب الكود لها هكذا

```
[LEFT]Function Myfunction(byval I As Integer , S As String) As Integer .
.كود
.كود
MyFunction = 2*I/y
End Function[/LEFT]
```
السطر MyFunction = ….. هو نتيجة هذه الدالة التى سترد بها وهى تقابل مثلا فى الدالة الشهيرة لجيب تمام الزوايا القيمة 0.5 لدالة جا30 ولا يشترط أن تكون آخر سطر بل يمكنك أن تجعلها مشروطة مثلا لو Length بكذا MyFunction = 1 ولو بكذا MyFunction = 2 الخ أى يمكم أن تتكرر بحسب الشروط.

و تطلبها كما تطلب أى دالة عادية فستحتاج مثلا أن تعرف بعض المتغيرات منها CurrentVal مثلا و تريد أن تضع فيه جا 30 ستكتب ببساطة

```
[LEFT]CurrentVal = Sin(30)
CurrentVal = Myfunction(5,”Day”)[/LEFT]
```
والسطر التالى لو ستطلب ألداله Myfunction بدلا منها

أما بطريقة ميكروإلكترونيكا فيمكن تعريفها مسبقا بكتابة
*sub function First(dim a as word, dim b as word) as word forward*

البداية هى كلمة Sub اختصار Subroutine ثم كلمة *function *للدلالة على أنها تعيد نتيجة ثم يلى ذلك اسمها وهو ما عبرت عنه بكلمة First ثم قوسين () بينهما الأسماء و أحجامها و بعد ذلك كلمتى *as word *لتفيد أنها ستعيد قيمة بحجم *Word *و أخيرا كلمة *forward *للدلالة على أن الكود سيأتى لاحقا
لاحقا تضع الكود كما يلى


```
[LEFT]SUB [B]function[/B] First([B]dim[/B] a [B]as word[/B], [B]dim[/B] b [B]as word[/B]) [B]as word[/B]
.كود
.كود
.Result = 5*a/b
End Sub[/LEFT]
```
و القيمة التى تعاد هى Result=... و نفس الشروط السابقة و طلبها كما فى المثال السابق أيضا.
ذكرنا سابقا أن التعريفات ذات مدى عام أو شامل تغطى كل الوظائف و ألدوال أى يمكن لأى منها أن تقرأ هذه التعريفات أو تغيرها بصرف النظر عن كونها دالة أو وظيفة لكن لو فى داخل أى دالة أو وظيفة أعلنت متغير جديد سيكون مجاله محليا فقط أى بداخل الدالة أو الوظيفة ولا يمكن التعامل معه خارجها.
لاحظ أن كل البرنامج مجموعة من الوظائف لذا على الأقل سيحتوى على وظيفة واحدة فقط و تسمى Main ولا تعلن بأى من الوظائف السابقة Declare , SUB و لذلك تنتهى بكلمة END فقط بدون أى إضافات .

فى لغة C نجد الأمر مختلف قليلا فلا يوجد وظيفة أو دالة ولكن كلها subroutine فإن أعاد شيئا فهو دالة وإلا فيكون وظيفة و الإعلان عنها كما يلى

```
[LEFT]int max(int x, int y) {
return (x>=y) ? x : y;
}[/LEFT]
```
أول كلمة int تعنى أن العائد من حجم Integer ، إذن هى دالة و ليست وظيفة و اسمها max و بين القوسين القيمتين المطلوب المفاضلة بينهما و حجم كل منهما ثم القوس المعوج الشهير أما إن كانت void فتعنى خلاء او لا شيء فلا تعيد شيئا ومن ثم هى وظيفة.
القيمة التى سترد بها هى بعد return و طبعا نفس الشروط السابقة و هى هنا تقول ما بين القوسين x أكبر من أو تساوى y . أما بعدها نجد ؟ وهذه تعنى "هل ما بين القوسين صحيح؟ لو نعم صحيح أعد أو قيمة تالية وهى هنا X و إن لم تكن أعد القيمة التى تليها أى Y . عبقرية لكن حاول أن تتذكرها عندما تحتاجها أو تستنتجها ما لم أكن ذكرتها لك ولو خطأ ما فى النص حاول اكتشافه ، شخصيا أفضل كثيرا الصيغة
IF X>=Y THEN RESULT=X ELSE RESULT =Y
بسيطة و مفهومة بلا شرح و منطقية. و أخيرا القوس المعوج الغالق .
هواة هذه اللغة يعيبون على لغة البيزك كلمة مثل End Sub , End Function.
حسنا كل الأوامر العشرة و كل وظيفة تنتهى بذات القوس “{” و المترجم يربطه بأقرب واحد مفتوح “}” ونادرا ما تكون دالة أو وظيفة لا تحتوى عدد من الأوامر المتداخلة 
فعندما ترى { لا تعلم أى شيء يخص هذا القوس و تبذل جهدا كبيرا لتتبع الأقواس عبر الصفحات
أما لو وجدت END IF فقد علمت أنك أغلقت دورة IF ولم تغلق غيرها ولن تذهب END IF لأقرب شيء مفتوح مثل دورة For لأنه لا يخصها، لذلك أستطيع أن اركز اهتمامى على البرمجة و منطقها عوضا عن فوازير الأقواس التى لا تربح جوائز - معذرة هذا رأيى المتواضع و لكل رأى يسعد به
أخيرا لاحظنا كلمة ByVal ولم نقل عنها شيئا، هى اختصار By Value و مقابلها ByRef أى By Reference. لو لدينا متغير ما مثل Angle و لديك وظيفة باسم ChK_A فيها ستختبر قيمة Angle و بناء عليها تفعل خيار من خيارات كثيرة قد تحتاج لتعليمه مثل If sin(Angle) =.5 Then فماذا سيفعل المترجم؟؟
سابقا هو خصص مثلا الخانة 10 من الذاكرة لحفظ قيمة Angle و فى هذه اللحظة Angle=45 و الآن تطلب منه استخدام دالة من داخل دالتك ChK_A لحساب جيب الزاوية، إذن هل سيرسل لدالة حساب جيب الزاوية قيمة 10 حيث تقبع قيمة Angle أم يرسل المحتوى 45 قيمتها الآن؟ و ما الفرق !! كلاهما واحد!!
كلا الفرق شاسع فلو أرسل القيمة By_Val فالتغيير داخل الدالة سيكون على القيمة 45 فقط أما لو أرسلتها By_ref فالتغيير سيكون على محتوى الخانة. وهذا هو الوضع الافتراضى أى أن أى تغيير داخل الدالة سيطال المتغير الأصلى.
مهلا سبق أن قلت أن الدالة لا تعيد شيئا وهنا تقول أنها تغير من قيمة المتغيرات أى أنها تعيد شيئا!! أجل وهذه ميزة يمكنك استخدامها و تسمى الأثر الجانبى أو الغير مباشر Side Effect

المرة القادمة إن شاء الله نتكلم عن الأوامر أو الأكواد التى تستخدم لبناء البرنامج​


----------



## ماجد عباس محمد (4 يوليو 2018)

*الأكواد العشرة*

*الأكواد العشرة*

تنقسم الأكواد العشر لثلاث مجموعات هى الشروط و الدورات و الانتقال
*الشروط:*

*الأمر IF*

الأول هو ما سبق شرحه IF و نعيد شرحه هنا أولا بالأسيمبلى كان فى صورة JB أو JNB وهما القفز لو بت =1 أو = صفر ولكن عموما تحتاج مقارنة رقمين لذا نستخدم معها الأمر CJNE وهو اختصار Compare and Jump if Not Equal وهى تقارن بين المراكم A و قيمة مباشرة أو محتوى ذاكرة مع المراكم أو محتوى مسجل مع المراكم أو باعتبار مسجل من R0,R1 حامل عنوان فيقارن المراكم بالذاكرة التى يشير إليها هذا المسجل أو مسجل مع قيمة مباشرة مثلا سنقارن محتوى المسجل R7 بالقيمة المباشرة 60 هيكسا و ننتقل لو مختلفين إلى Not_Eq. ما يحدث حقا هو طرح القيمة 60 هيكسا من محتوى R7 و بالتالى لو 60 أكبر ستسبب Carry =1 و إلا سيكون Carry = Zero و يمكن التحقق بالأمر JC أى قفز لو Carry =1

```
[LEFT]CJNE R7, # 60H, NOT_EQ      [COLOR=#008000]; . . . . . . . . ;R7 = 60H[/COLOR].
Code if equal          
sjmp Finish
NOT_EQ: JC REQ_LOW          [COLOR=#008000]; IF R7 < 60H[/COLOR].
Some Code for R7 > 60H.  [COLOR=#008000] ; . . . . . . . . ;R7 > 60H[/COLOR].    
sjmp Finish
REQ_LOW: code for R7 < 60H.  


Finish:[/LEFT]
```
لو تريد أن تقارن شيء آخر ستضع قيمة فى R7 و الثانية فى الأمر المباشر و هكذا أى ستحتاج لأوامر MOV لتعديل القيم
نفس الشيء بالبيزك و مثال للمقارنة على التساوى فقط فى التالى أو يمكنك التعديل بلا يساوى أو اكبر من أو أصغر من أو ما تشاء من شروط متعددة


```
[LEFT][SIZE=3]If Sw1 = 1 then
Goto SW2test   
Else
LEDs = 254   
End If
كما يمكنك أن تجعلها متداخلة Nested أى أكثر من أمر داخل بعض هكذا
If PORT1 = 1 then            [COLOR=#008000] ; Level 1[/COLOR]
Goto SW2test   
Else IF PORT2 = 1 THEN   [COLOR=#008000]; Level 2[/COLOR]
LEDs = 254   
ELSE                                 [COLOR=#008000]; Level 2[/COLOR]
LEDs= 255   
Else                                 [COLOR=#008000] ; Level 1[/COLOR]
LEDs=255   
End If[/SIZE][/LEFT]
```
*
لاحظ هنا نقطة مهمة **IF **الأولى استفسرت عن شيء ما وهو **PORT1 **بينما **Else IF **التالية استفسرت عن شيء آخر تماما وهو **PORT2 **وهذه قيمة هذا الأمر ولو عدنا للغة الأسيمبلى سنجد أن هذا الأمر سيضع **PORT1 **أولا فى المراكم **A **ثم يقارنها بالقيمة **1 **و بعد ذلك يضع القيمة **PORT2 **فى المراكم ليقارنها بالقيمة **1 **وفى كل مرة نستخدم أمر **MOV **قبل الاختبار*
*نقطة هامة أخرى، أين تضع **End If **يعتمد على المترجم فالمترجم باسكوم يعتمد **Elseif **و يعتبرها امتداد للأولى **(**وهذا من سمات لغة البيزك المرئى الأصلية للحاسبات**) **و من ثم تفاضل بين عديد من الخيارات و متى تحقق أحدها خرجت من الدورة ولذا تحتاج **End if **واحدة فقط فى آخرها و يمكنك وضع **IF **أخرى متداخلة حيث تشاء لتتمكن من فحص خيارات أخرى متى شئت و هذا يصعب فى ميكروإلكترونيكا فمثلا
*

```
[LEFT][SIZE=3]If a = b then         [COLOR=#008000]'…...1[/COLOR]
Led0 = 1
elseif c=d then     [COLOR=#008000]'…....2[/COLOR]
Led1=1
elseif porta = 5 then  [COLOR=#008000]'…......3[/COLOR]
[COLOR=#ff0000]if a= 8 then     
Print Porta = 5 and a=8         
elseif g=7 then    
Motor1 = 1         
else    
Motor 1 =0         
end if    
[/COLOR]else if Portc =0     [COLOR=#008000]'….....4[/COLOR]
Led3=1 
else                       [COLOR=#008000]' ….....5[/COLOR]
Led4 = 0  
end if[/SIZE][/LEFT]
```
*
سنلاحظ هنا أن الشروط **1**،**2**،**3**،**4**،**5 **تبادلية فإن تحقق **1 **ينفذ الأمر **Led0 = 1 **ثم تخرج و إلا يفحص **2 **و هكذا، بهذا فالشروط باللون الأحمر لن تفحص إلا لو لم تتحقق الشروط السابقة أولا ثم تحقق الشرط **porta = 5 **و عندها نتحقق كما لو ان كل أمر من الأحمر تعنى لو **porta = 5 **مع **a= 8 **و قد تكتب هكذا *
*(a= 8) AND (porta = 5)*
*إلا أننا وفرنا تنفيذ أمر **AND **فى كل تساؤل**.*
*ميكروإلكترونيكا لا تعتمد **elseif **و تعتمد بدلا عنه **else if **بمسافة تفصل بينهما فتعتبر **if **التالية جديدة و تتطلب **End If **خاصة نفس فكرة أقواس السى وهذا يجعل الأمور معقدة و مربكة **. *
*مما سبق أيضا نستنتج أن ترتيب الأوامر يعطى أولوية الاختبار فقد يسبب تساؤل عن أمر ما أقل أهمية فى عدم فحص أمر آخر أكثر أهمية **.*

*و لنكتبه بلغة **C *


```
[CODE][LEFT][B]if (PORT1=1) {[/B]
[B]goto SW2test ;[/B]
[B]}[/B]
[B]else if (PORT2) {[/B]
[B]LEDs = 254 ; [/B]
[B]}[/B]
[B]else {[/B]
[B]LEDs=255;[/B]
[B]}[/B][/LEFT]
```
[/CODE]*
الآن علمنا أن هناك **MOV **زائدة فى كل أمر حتى لو كان المتغير لم يتغير لكن تريد مقارنته بعدة قيم ولا داعى لنقله كل مرة للمراكم **A **لنقارنه ، فهذا سيوفر خانة ذاكرة فى كل اختبار و يزيد سرعة الاستجابة ، لذا كان الأمر الثانى**.*
*
الأمر Select case أو switch*
*وهو الثانى ، فكما رأينا الحاجة أم الاختراع فقد وضع هذا الأمر لمقارنة قيمة واحدة مقابل عدد كبير من الاحتمالات، لذا فهذا الأمر بالأسيمبلى سيكون ذات التعليمات السابقة و ستكرر الأمر **CJNE **عدة مرات كل مرة بقيمة اختبار أخرى و لكن لن تستخدم **JC **إلا لو احتجت لها و ستضع القيمة التى تختبرها مرة واحدة فقط فى المراكم وهى فى المثال التالى قيمة **reg **و بعد ذلك تكرر **CJNE **حسب ما تريد، أى ستوفر أمر **MOV **مع كل مقارنة**.*
*و فى البيزك **/ **باسكوم *

```
[LEFT][SIZE=3]select case reg
case 0  
opmode = 0    
case 1,2,6  
opmode = 1    
case 5 TO 7  
opmode = 2    
  Case > 9 : Print “Too High”  
Case else : PRINT “NOT Valid”  
end select[/SIZE][/LEFT]
```
*
السطر الأول نجد هو المتغير تحت الاختبار و من ثم يوضع أول الأمر فى المراكم ثم يقارن عدة مرات بعد ذلك**. **قد يكون أى متغير مثل **PORT0 **أو أى شيء تسميه أو حتى معادلة يجب حلها أولا مثل **select case x*y/z *
*المهم أنها رقم صحيح **(**قيد بسبب الميكرو لكن فى الحاسبات الشخصية تكون أى شيء**) **أو قد يكون نصا أو حرف**.*
*هذا المترجم يسمح من لغة البيزك الأصلية بكلمة **TO **لتحديد مدى **"**من إلى**" **كما يسمح بتعدد القيم **1,2,6 **و بالعلاقات النسبية أكبر من أو أصغر من أو اكبر من و يساوى أو أصغر من و يساوى*
*لاحظ أنه لو تطابق المتغير مع أول شرط ستنفذ الأوامر المرتبطة به بكاملها **(**واحد أو أكثر**) **ثم يخرج آليا من الشرط ولا تختبر باقى الحالات**. **لو لم يتطابق فسيقارن التالى وهكذا*


*ميكروإلكترونيكا تستخدم الصيغة ذاتها مع تعديل طفيف*

```
[LEFT][B]select case reg[/B]
[B]case 0[/B]
[B]opmode = 0[/B]
[B]case 1,2,3,4[/B]
[B]opmode = 1[/B]
[B]case 5,6,7[/B]
[B]opmode = 2[/B]
[B]end select[/B][/LEFT]
```
*وهو أنها لم تتبنى كلمة **TO **باعتبار أن القيم المتعددة قد تغنى لكن لن تكون مثلا مثل من **100 **إلى **200 **و لم تتبنى المقارنات **> < >= <= **أيضا**.*

*بلغة السى نجدها*


```
[LEFT][B]switch (phase) {[/B]
[B]case 0: Lo(); break;[/B]
[B]case 1: Mid(); break;[/B]
[B]case 2: Hi(); break;[/B]
[B]default: Message("Invalid state!");[/B]
[B]}[/B][/LEFT]
```
*
حيث **phase **هى المتغير تحت المقارنة ثم تلى القيمة الأولى وهى صفر فينفذ الأمر لو متطابق ولا ينفذه لو غير مطابق و فى كلتا الحالتين سينتقل لاختبار القيمة التالية،**(**لماذا؟؟**) **لذا وجب وضع الأمر **break **حتى يخرج من الدورة عند تحقق الشرط **!!! *
*لاحظ أيضا أنك لا تستطيع استخدام مدى من **.. **إلى **.. **ولا أكثر من قيمة **1,2,3,4 **ولا نسب أكبر و أصغر الخ**. **رقم و فقط و بسبب ذلك قد تضطر لاستخدام أمر **IF **بدلا منها **!!!!! **أو تفضل البيزك مثلى*
*المرة القادمة إن شاء الله ندرس الدورات*


----------



## ماجد عباس محمد (5 يوليو 2018)

*الدورات Iteration*

*الدورات Iteration*

*For Loop*

*الثالث و اشهرها إطلاقا هى دورة **For **أى بينما المتغير **"**ص**" **من كذا إلى كذا افعل هذا ثم عدل قيمة **"**ص**" **وهى بالأسيمبلى تكون هكذا*

```
[LEFT][B]MOV R7,#50[/B]
[B]Loop5:[/B]
[B]DoThis[/B]
[B]DJNZ R7,Loop5[/B][/LEFT]
```
*المتغير ص نريده **= 50 **لذا سنضع مثلا فى الذاكرة أو للأسرع فى المسجل **R7 **هذه القيمة بالأمر الأول**. **يليه عنوان بداية الدورة ثم مجموعة التعليمات المرغوب تنفيذها مشار إليها بكلمة **DoThis **و أخيرا الأمر **DJNZ **وهو اختصار **Decrement and Jump if Not Zero **و يليه ما يحتوى الرقم المطلوب إنقاصه ثم العنوان ألذى ينتقل إليه و هذا العنوان يجب أن يكون فى نطاق بايت واحدة أى **255 +128 **إلى **-127*

*هذا الأمر بالبيزك لكلا المترجمين*
*تأخذ الصورة **For **المتغير **= **البداية **TO **النهاية بخطوة عدد موجب أو سالب*

```
[LEFT][B]Dim[/B] A [B]As[/B] [B]Byte[/B] , B1 [B]As[/B] [B]Byte[/B] , C [B]As[/B] [B]Integer[/B]


[B]For[/B] A = 1 [B]To[/B] 10 [B]Step[/B] 2
[B]Print[/B] "This is A " [COLOR=#008000]; A[/COLOR]
[B]Next[/B] A
 
[B]Print[/B] "Now lets count down"
[B]For[/B] C = 10 [B]To[/B] -5 [B]Step[/B] -1
[B]Print[/B] "This is C "[COLOR=#008000] ; C[/COLOR]
[B]Next[/B][/LEFT]
```

*نلاحظ هنا أن **Step **ليست ضرورة لو كانت **= **موجب **1. **هذه الدورة تظل تنفذ التعليمات فى جسم الدورة حتى يزيد المتغير عن الحد الأقصى بعد كلمة **To **وهنا تتوقف الدورة**. **لاحظ أن الدورة تنتهى بكلمة **NEXT **وهى فى الدورات المتداخلة تتيح لك التذكر هذه تخص من فمثلا*

```
[LEFT][B]For c = 1 To 10[/B]
[B]…[/B]
[B]For D = 2 to 8[/B]
[B]…[/B]
[B]Next D[/B]
[B]…. [/B]
[B]….[/B]
[B]Next c[/B][/LEFT]
```
*رغم أنك لا تحتاج كتابة الحرف و تكتفى بكلمة **Next **إلا أنها توضح لك أين يبدأ هذا و أين ينتهى ذاك **. **فى ميكروإلكترونيكا يجب كتابة المتغير وإن كان هذا ليس قياسيا فى لغة البيزك و يلوم البعض كلمة **Next **إلا أنها واضحة و تخص **For **ولن تخص دالة أخرى ولا تكملها أو تغلقها كما لو كانت كلها **} **و ممكن قوس **For **يغلق قوس **IF **خاصة حيت تكثر الأكواد عبر الصفحات**.*

*أما بلغة **C **فلأمر كما هو معروف مختلف حيث تكون *

```
[LEFT][B]for ( i = 0; i < n; i++ ) s += a[i] * b[i];[/B][/LEFT]
```
*i = 0 **هى حد البداية ثم فاصلة منقوطة **";” **ثم **i < n **حد النهاية ولاحظ هنا أنه أقل من و ليست تساوى فلو كانت تساوى و العد زاد لن تنتهى الدورة كما يحدث فى البيزك لذا لو تريد مثلا **10 **يجب أن تكتب أقل من **11 **للتسهيل و البساطة و الوضوح**. **أخيرا **i++ **تعنى اضف واحد و بالمناسبة **++ **على يمين المتغير تختلف عن على يساره حيث أحدهما تعنى أعد القيمة قبل الزيادة و الأخرى تعنى أعد القيمة بعد الزيادة ثم نغلق القوسين و نكتب ما نريد تنفيذه ثم نختم بالمقدسة **";”*
*لو لديك أكثر من أمر للتنفيذ عندها تضعهم بين قوسين معوجين **{…..} **و كل سطر ينتهى بالمقدسة **";”*
*هذه اللغة تتيح لك استخدام أكثر من متغير معا*


*Do Loop*

*الرابع و بذات كود الأسيمبلى السابق يمكنك أن تهئ هذه الدورة، يمكنك تحقيقها بالأمر **DJNZ **أو **CJNE **السابقين*
*أما بالبيزك فالصيغة المشتركة هى*


```
[LEFT]A = 1     [COLOR=#008000]'assign a var[/COLOR]
[B]Do[/B]         [COLOR=#008000]'begin a do..loop[/COLOR]
[B]Print[/B] A  [COLOR=#008000]'print var[/COLOR]
[B]Incr[/B] A                       [COLOR=#008000] 'increase by one[/COLOR]
[B]Loop[/B] [B]Until[/B] A = 10      [COLOR=#008000]'do until a=10[/COLOR][/LEFT]
```
*فى السطر الأول تضع قيمة ما فى متغير ما تستخدمه حكم لإنهاء الدورة ، ثم تكتب **" **افعل **Do " **لتحدد بداية المطلوب و يلى ذلك مجموعة الأوامر حسب حاجتك و يجب أن تحتوى وسيله لتعديل هذا المتغير سواء بالبرنامج أو قد تكون خارجية حيث هذا المتغير مثلا قيمة المنفذ **PORT0 **أو قد يكون حالة طرف **PORT0.3 **و آخر سطر سيكون **Loop Until A = 10 **وهو يعنى كرر حتى يصل المتغير لهذه القيمة*
*كما لاحظت أننا نقول دوما ذات الكود، فعلا هى دورة تكرارية تنتهى بمقارنة ثم القفز للبداية أو القفز خارجها فلم نتوقع كود مختلف؟ هى فقط تعبيرات مختلفة لتسهيل الوصول للهدف*
*لو حذفت جملة **Until A = 10 **ستتحول إلى دورة غير منتهية فلا شرط ينهيها و هى بذلك تتحول إلى أمر **GOTO **وهى مطابقة للأمر **AJMP **أو **LJMP **بالأسيمبلى**.*
*نلاحظ هنا أن الشرط **Until A = 10 **أو ما يسمى بالاختبار يكون فى آخر الدورة مما يضمن تنفيذها مرة واحدة على الأقل لذا سيكون لدينا أمر آخر لضمان عدم التنفيذ**.*
*أما بلغة **C *

```
[LEFT][B]do {[/B]
[B]s += a[i] * b[i];[/B]
[B]i++;[/B]
[B]} while ( i < n );[/B][/LEFT]
```
*كلمة **do **ثم القوس المعوج لتحدد التعليمات المطلوب تكرارها ثم الأوامر المطلوب تكرارها مع مراعاة الشروط السابقة لتعديل قيمة المتغير الحاكم لإنهاء الدورة ثم تضع كلمة **while **و الشرط المطلوب تحقيقه بين قوسين و تنهى بالمقدسة*

*كما ذكرنا لو نريد عدم التنفيذ إطلاقا لو الشرط غير محقق نلجأ للأمر الخامس

**While / While-WEND*

*الاختلاف الوحيد فى الأمر الخامس هو وضع الشرط و اختباره فى البداية و لهذا فإن لم يتحقق لا تنفذ باقى الأوامر و بالأسيمبلى فغنى عن التعريف أنها مسألة إعادة تنسيق للأوامر فقط*
*بالبيزك تكون*


```
[LEFT]A = 1                                                       [COLOR=#008000] 'assign var[/COLOR]
[B]While[/B] A < 10                                           [COLOR=#008000]'test expression[/COLOR]
  [B]Print[/B] A                                               [COLOR=#008000]'print var[/COLOR]
  [B]Incr[/B] A                                               [COLOR=#008000] 'increase by one[/COLOR]
[B]Wend                                              [/B][COLOR=#008000]                                                      'continue loop[/COLOR][/LEFT]
```

*كما سبق الشرح سنضع فى متغير ما قيمة ما وهو حاكم الدورة ثم نضع الشرط ألذي بتحققه ننفذ ما يلى من تعليمات أما لو لم يتحقق نخرج و يجب ضمان تغير قيمة الحاكم حتى يصل بالشرط للخروج من الدورة و كما ذكرنا هذا المتغير قد يكون منفذ أو طرف من منفذ أو أى متغير آخر**. **و أيضا يمكن عمل دورة لا منتهية باستبدال الشرط بالرقم **1 **أو البعض يسمح بكلمة **TRUE **و أخيرا تنتهى بكلمة **Wend **اختصار **While End **لكى ترى بوضوح أين تنتهى الأمور*


*بلغة **C *

```
[LEFT][B]while[/B] (i < n) {
s += a[i] * b[i]; i++;
}[/LEFT]
```
*المرة القادمة إن شاء الله نتحدث عن المجموعة الأخيرة وهى الانتقال أو التفرع*


----------



## ماجد عباس محمد (6 يوليو 2018)

*الانتقال أو التفرع Branching*

[h=5]الانتقال أو التفرع Branching[/h]*الحقيقة هنا بعض الأوامر مختلفة بين اللغات لذلك فالعدد هنا يعتمد على اللغة لكن أشهرها و اعمها هى الأمر السادس*
[h=6]GOTO[/h]*و صيغته ببساطة **Goto **ثم العنوان المراد الانتقال إليه وهو غير مشروط ولا خلاف عليه فى اللغات وهو يسبب الانتقال المباشر من مكان هذا الأمر للعنوان المذكور بدون قيد أو شرط*

*ماذا يحدث لو دخلت فى دورة مثل **For **و تأكد لك أنها انتهت مبكرا لتحقق شرط ما أو اصبح الاستمرار فيها يسبب مشكلة ما؟ *
*حسنا توافر لك الأمر السابع وهو **Exit*
[h=6]Exit Break Continue[/h]*الأمر السابع هو أمر للخروج الطارئ وفى باسكوم لديك أربعة صور هى حيث **Exit Sub **و **Exit Function **هما ذات الشيء*
EXIT FOR
EXIT DO
EXIT WHILE
EXIT SUB
EXIT FUNCTION


*و تكتب كما هى أى لا تكتفى بكلمة **Exit **ولكن تتبعها بالدالة وهى للخروج الطارئ عند حدوث خطأ ما أو جدت أنه لا داعى للاستمرار **. **و سبب ضرورة ذكر اسم الدالة لا يخفى على أحد فغالبا ما تكون مثلا دورة **For **داخل وظيفة **Function **أو داخل دورة أخرى مثل **Do **لذا وجب تحديد مما تخرج بالضبط**.*
*فى ميكروإلكترونيكا و فى كلا المترجمين البيزك و **C **قصرت على **SUB **أو **Function **وتكتب وحدها فقط أى لو لديك وظيفة أو دالة ثم فى خطوة ما وجدت أنه لا داعى للاستمرار أوحدث خطأ ما و يجب الخروج تكتبها فتعود لاستكمال الكود الأصلى**. *
*أما باقى ألدوال **For,DO,WHILE **فقد استخدمت كلمة **Break **للخروج و نذكر أننا تعرضنا لها فى أمر **Switch **السابق و أضافت أمر آخر هو **Continue **لتفويت أو تخطى هذه الدورة فقط دون الخروج و استكمال باقى الدورات*


*الأمر الثامن هو العودة **Return*
[h=6]Return[/h]*قبل مناقشته يجب أن نعود للأسيمبلى للارتباط الوثيق بينهما**. **كلنا نعلم ما هو **Subroutine **و لمن لا يعلم هو قطعة من الكود ستتكرر كثيرا فى البرنامج ولو أعدنا كتابتها قد لا نجد ذاكرة تكفى، تخيل أنك لو كل مرة تريد كتابة رقم أو حرف على شاشة ستكتب لها كود، كم مليون مرة ستحتاج لكل تحديث للمعروض ؟ ، لذا يكتب هذا الكود فى عنوان فى مكان ما من الذاكرة أى يبدأ بهذا العنوان وهذا الكود يسمى **Subroutine **أى إجراء فرعى وهو فى اللغات العالية تحول إلى دالة أو وظيفة أما كونه يعيد قيمة ما فببساطة يضعها فى خانات من الذاكرة محددة ليستغلها الكود الطالب لاحقا**.*
*حسنا كيف ستنهيه إذن لتكمل باقى البرنامج أو حتى تكتب كود **Subroutine **آخر؟ أجل الأمر **GOTO **لكن مهلا نذهب لأين و أنا أصلا لا أعلم من أين استدعيت؟*
*حسنا يجب إذن أن نضيف لها أمر نهاية خاص بكود مختلف وهو أمر **RET **اختصار **Return **و أمر الانتقال إليه لا يكون بالأمر **GOTO **ولكن أيضا بأمر مختلف **GOSUB*
*إذن المتحكم عندما يجد الأمر **GOSUB **متبوعا بعنوان ، يعلم أنه عائد للخطوة التالية لذا سيحفظ عنوان العودة **(**عنوان الخطوة التالية**) **فى الرصة **Stack **و يذهب لعنوان **Subroutine **المذكور فى الأمر و ينفذه و عندما ينتهى سيجد الأمر **RET **وهذا يجعله يستعيد العنوان من الرصة ليستأنف العمل حيث كان قبل طلب **Subroutine*
*حسنا هذا جميل لكن مهلا هناك موضوع آخر على قدر كبير من الأهمية وهو المقاطعة ، عندما تحدث سيفعل المتحكم ذات الشيء من حفظ الخطوة التالية ثم الانتقال لعنوان خدمة المقاطعة و يوقف كافة المقاطعات التالية و يجب عندما يعود من خدمه المقاطعة أن يتيح المقاطعة أيضا إضافة لاسترجاع العنوان ، لذا فكود المقاطعة ينتهى بأمر مختلف هو **RETI **اختصار **Return from Interrupt **أى أن كلاهما سيعيد المتحكم للعنوان الصحيح لكن المقاطعة ستختلف و الخطأ فى استخدامها قد يسبب أن المتحكم يستجيب لأول مقاطعة ثم يمتنع بعد ذلك وقد تظن أنه لا يستجيب إطلاقا لو كانت أول مقاطعة من مصدر سريع مثل **50 **هرتز الخ**. **هذا فضلا عن أن فى كثير من المتحكمات يتم حفظ بعض المسجلات آليا و استعادتها آليا لضرورة ما بها من بيانات و أهميتها**.*
*هذا التمهيد يتيح لنا فهم الخلافات ففى ميكروإلكترونيكا جعلت الأمر **Return **واحدا وهو العودة للخطوة الطالبة أى ستولد **RET **أما لو كان الأمر يخص مقاطعة فإعلان كود المقاطعة هو ألذى سيحدد أن العودة ستكون **RETI . *
*أما فى باسكوم فالأمر مختلف ، لو فى داخل شرط ستعطى **RET **ولو بدون شرط فأول واحدة فقط تعطى **RETI **وهذا فى رأى المتواضع تعقيد لا جدوى منه و سيفرض استخدام الأمر **GOTO **لتذهب حيث الأمر ألذى يعطى **RETI*


*الأمر التاسع هو **GOSUB*
[h=6]GOSUB هو أمر للانتقال إلى *Subroutine **سواء فى الكود أو داخل وظيفة أو دالة*[/h]*قد ترى أن الأمر مكرر ولا جدوى من هذا الأمر لكن معذرة أخى الكريم فللضرورة أحكام و السبب ببساطة أنك لا تستطيع أن تعلن عن وظيفة أو دالة من داخل أخرى لذا فإن احتجت لتكرار كود داخل دالة فإما تجعله فى دالة منفصلة و هذا يزيد عددهم بلا داعى أو لو هذا التكرار لا يطلب إلا فى هذه الدالة أو وظيفة فقط فلتسهيل تتبع الكود يمكنك أن تجعلها داخلية بهذا الأمر وهى ستطال كافة المتغيرات أى لا حاجة لتفريقها كدالة أو وظيفة فهى فقط **Subroutine*
*الأمر بسيط وهو **GOSUB **متبوعا بالعنوان وهو فى البيزك لكلا المترجمين لكن للأسف **C **لا يدعمه*


*الأمر العاشر و الأخير هو *
[h=6]On Value[/h]*استخدمت باسكوم أمرا من أوامر البيزك المرئى للحاسب مع المتحكمات و هو أن تكتب **ON **متبوعة بمتغير ثم تختار **GOTO **أو **GOSUB **ثم مجموعة من العناوين *

```
[LEFT][B]ON var [GOTO] [GOSUB] label1 [, label2 ] [,CHECK][/B][/LEFT]
```
*لو المتغير **= **صفر سينتقل لأول عنوان أو لو **= 1 **سينتقل للثانى و هكذا ولو كان الرقم أكبر من عدد العناوين ستتلف الرصة لذا يمكنك إضافة الكلمة الأخيرة **CHECK **فلو حدث هذا لا يتم أى انتقال و ينفذ السطر التالى مباشرة *


*إذن ما هذه الضجة حول اللغات العالية و المترجمات؟*
*هى يا عزيزى تسمى المكتبات وهى مجموعة أوامر إضافية تتبناها كل شركة لخدمة عملائها مثل كتابة الشاشة **LCD **و قراءة أزرار **Keypad **و التعامل مع المنفذ التسلسلى أو **I2C **الخ**. **لذا فهى تختلف من مترجم لآخر و ليست من لغة لأخرى فقط**. **ولا حل أمامنا سوى ملفات المساعدة*


*المرة القادمة إن شاء الله نعيد البرنامج بالبيزك ثم إن شاء الله بعده بلغة **C*


----------



## ماجد عباس محمد (7 يوليو 2018)

*الغسالة باستخدام c51 و لغة البيزك*

*الغسالة باستخدام C51 و لغة البيزك:*

*من الأفضل أن نعيد هنا ذات الدائرة حتى نرجع إليها*




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

*و نبدأ بالبيزك ، باسكوم ثم سنستخدم ميكروإلكترونيكا لتبيان الفرق ثم **C . **عند بدء مشروع جديد سيفتح لك صفحة خالية و من القائمة **Option\Compiler\chip **تحدد اسم المتحكم و تردد الكريستال الخ**. **ثم تنقر زر **Add Code **ثم تعود للصفحة و إن شئت تكتب فى أول سطر تعليق أنها تعريفات **Definition **فلا بأس يلى ذلك التعريفات السابق استخدامها**. **بما أننا نستخدم ذات الدائرة فللتسهيل يمكنك نسخ الكود بالأسيمبلى كاملا من بروتس و لصقه هنا ثم من قائمة **Edit **اختار **Replace **أو انقر **CTRL+R **و اكتب فى الخانة الأولى كلمة **EQU **و فى التالى كلمة **Alias **واختار **Replace all **و بهذا انتهت أول خطوة*
*إن شئت يمكنك تجميع كل ثلاثة أوامر فى سطر واحد باستخدام **":” **و إن شئت فلا ولكنى سأفعلها حتى لا تكون الصفحة طويلة خاصة فى المنتديات**- **لاحظ أن وجود كود الأسيمبلى لن يضير المترجم و ستصبح هكذا*
*التعريفات*


```
[LEFT][SIZE=3][COLOR=#008000]' DEFINITIONS 
[/COLOR]Leds Alias P0 : Relays Alias P1 : Switches Alias P2 : Controls Alias P3
Fullled Alias Leds.0 : Halfled Alias Leds.1 : Smallled Alias Leds.2
Hotled Alias Leds.3 : Mildled Alias Leds.4 : Coldled Alias Leds.5
Wateron Alias Relays.0 : Drainon Alias Relays.1 : Heateron Alias Relays.2
Motoron Alias Relays.3 : Run_nspin Alias Relays.4 : Waterfull Alias Relays.5
Waterempty Alias Relays.6 : Dooropen Alias Relays.7 : Midtemp Alias Switches.0
Hitemp Alias Switches.1 : Cold Alias Switches.2 : Mild Alias Switches.3
Hot Alias Switches.4 : Small Alias Switches.5 : Half Alias Switches.6
Full Alias Switches.7 : Run Alias Controls.1

[COLOR=#008000]' VARIABLES
[/COLOR]Dim Runtime As Word
Jobpending Alias PSW.5

Emergency:
Goto Begin
Counttime:
Decr Runtime
If Runtime = 0 Then
Reset Jobpending
Stop Timer0
End If
Return

[/SIZE][/LEFT]
```
*هنا نلاحظ أننا وضعنا تعريفا بأن التالى متغيرات فقط لتذكيرك لكن المترجم لا يقرأه بل سيتعرف على ذلك من كلمة **Dim **السابق شرحها و نختار اسم **Runtime **وهو الزمن الإجمالى ثم **As Word **أى من صفر حتى **65535 **و بذلك أكبر زمن هو **1092 **دقيقة و نغير كلمة **F0 **بالمكافئ لها وهو **PSW.5 **لأن المترجم لا يعرفها وهذا قصور فيه ، ثم من شريط الأدوات ستجد زر عليه علامة صح فقط – انقر عليه سيتوقف على أول سطر **org 0000h **و ذلك لأنه لا يدعمها و نحن عادة لا نحتاجها إلا للمقاطعة وهذا المترجم يتعامل معها بطريقة خاصة فكما علمنا أن هذه المهام ليست من اللغات العالية ولكنها إضافات بحسب المترجم**. **حسنا احذف هذا السطر و التالى **sjmp Start **فلم نعد بحاجة إليه فهو سيتولى ذلك عنا**.*

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

*ثم بعد ذلك سنجد عنوان **INT0 (IE0)Emergency **وهو خانة **3 **فى الذاكرة ولكن المترجم سيتولى ذلك فكيف نعرفه ما نريد أى أن هذا الكود لمقاطعة و أيها هى؟*
*حسنا نضع عنوان فى أى مكان و ليكن **Emergency: **و نكتب تحته ما فعلناه فى البرنامج السابق و كان **sjmp Start **لكن بمجرد كتابة الكلمة **Start **ستظهر بجوار مؤشر الكتابة مربع به ثلاث خيارات للمؤقتات الثلاثة ، إذن كلمة **Start **من الكلمات المحجوزة لتشغيل و إيقاف المؤقتات و لن تصلح كعنوان فنستبدله بكلمة **Begin **و التى لا تسبب شيء فنضع بعدها مباشرة **":” **لتصبح عنوان ولا تكتب شيء بعده على السطر **. **لاحظ أنك تفصل بين الأوامر بالحرف **" : “ **و الفارق هو مسافة قبله و بعده لذا لو وضعتها ستحصل على رسالة خطأ أن الأمر **Emergency **غير معروف فى السطر رقم كذا ، الآن **sjmp Start **ستصبح **Goto Begin **وهذا فقط ما يفعله لكن لم يعلم بعد أنه لمقاطعة*
*سنكتب عنوان جديد للمقاطعة الثانية الخاصة بالتايمر صفر وكان لحساب الزمن فكنا ننقص الثوانى و من ثم الدقائق فإن أصبحت صفرا نوقف العداد و ننزل العلم أى نصفر **F0 **و هنا دمجناهما معا فى متغير واحد اسمه **Runtime **و لذا ننقصه ثم نختبره بالأمر **IF **فإن تحقق نستخدم الأمر **RESET **لجعل أى بت **= **صفر أى أنه صالح لبت من منفذ أو من متغير بأى حجم و عكسها **Set **و تكتب **RESET x **حيث **x **اسم البت أو **RESET y.x **حيث **y **هو المتغير و **x **رقم البت فيه وبذلك جعلنا العلم **= **صفر و الأمر **Stop Timer0 **لإيقاف التايمر و أخيرا أمر العودة من المقاطعة **Return **و أيضا هذا هو كود المقاطعة لكنه لم يعلم بعد أنها كذلك*
*هنا ستسأل، لماذا لم تكتب فى الأولى أيضا **Return **؟ *
*معك حق لكنها لن تنفذ لأن قبلها أمر انتقال للبداية وهناك يجب أن نتأكد أن كل الأمور مهيأة على الوجه الكامل**.*
*أرجو أن تمحو كل الأوامر بالأسيمبلى التى استبدلناها بالبيزك**. **ألآن سيكون لدينا البداية **Begin **و أول سطر كان 
*

```
[LEFT][SIZE=3]MOV IE,#10000011b                [COLOR=#008000] ' Enable T0 & INT0 external[/COLOR] 
MOV TMOD,#00000110b           [COLOR=#008000]; T0 8bit counter auto reload[/COLOR]  
لم نعد بحاجة إليه ولا للسطر الخاص TMOD فسنستخدم بدلا منهما الأمر 
CONFIG TIMERx = COUNTER/TIMER , GATE=INTERNAL/EXTERNAL , MODE=0/3[/SIZE][/LEFT]
```

*CONFIG **من ما سميناه المكتبات وهى بعضها داخلية أى فى بناء المترجم مثل هذا الأمر و بعضها مضاف أى مكتبة يضاف كود منها عند اللزوم و توجد فى مجلد خاص بالمترجم وكلاهما تجد شرحه فى ملفات المساعدة و بعضها مضافة من مصدر ثالث وهذا الأمر اختصار **CONFIGure **أى نسّق أو هيأ أو أضبط التالى على الصورة التالية ، ثم اسم المطلوب تهيئته وهو **TIMER0 *
*مجرد أن تكتب **CONFIG **ستظهر قائمة تختار منها بالأسهم أول بند هو **TIMER0 **ثم اضغط مسافة أو **Enter **أو إدخال فتضاف للكود ثم تكتب علامة **= **فيظهر خيارين **COUNTER **و **TIMER **و بالأسهم اختار **COUNTER **ثم مسافة أو **Enter **أو إدخال ثم تكتب فاصلة **, **فتظهر لك أربع خيارات **MODE=x **و تختار منها **2= MODE **و اضغط مسافة و فاصلة لتختار بين **INTERNAL/EXTERNAL **و طبعا **EXTERNAL **لأنه سيعد نبضات من الخارج و بعد ذلك نضيف القيم **205 **بالأمر **= **بدلا من الأمر **mov **ثم قيمة **TCON **لتجعل **INT0 **قدح بالحافة **. *
*التهيئة تجهز العداد لكن يبقى متوقف لذا نكتب **Enable **فتفتح قائمة نختار آخرها كلمة **Interrupts **لإتاحة الكل ثم نكرر ونختار **Int0 **لإتاحة المقاطعة**. **الأمر **MOV SP **أيضا سيتولاه المترجم ولم نعد بحاجة إليه*
*هنا نلحظ فرق بين الأسيمبلى و اللغة العالية أننا فى الأسيمبلى بأمر واحد وضعنا فى **IE **إتاحة ما تشاء من المقاطعات بينمت هنا خطوة لكل شيء تتيحه**. **طبعا يمكنك استخدام الأمر **IE=xx **كما سبق لكن ستشرح ما هو المتاح و الغير متاح لتتذكره لاحقا مقابل الاختصار**. **المترجم الذكى يدرك سلسلة الأوامر المتتالية للإتاحة و يجمعها فى أمر واحد أيضا**.*

```
[LEFT][SIZE=3]Begin:
Config Timer0 = Counter , Mode = 2 , Gate = Exteral 
TH0 = 205                 [COLOR=#008000]; Auto reload[/COLOR]
TL0 = 205 
TCON = 1                  [COLOR=#008000]; Clr All interrupts, Set INT0 Edge trigger[/COLOR]
Enable Interrupts
Enable Int0
Leds = 11011011b   [COLOR=#008000]' Reset All PORTS! select Small cold cycle[/COLOR]
Relays = 255
Switches = 255
Controls = 255 
On Int0 Emergency , Nosave
On Timer0 CountTime 
Bitwait Run , Set ' Run button release
LoopAgain: [/SIZE][/LEFT]
```
*
ثم تحدد القيم الابتدائية للمنافذ عند بدء التشغيل بالأوامر الأربعة التالية وسطر انتظار زرار **Run **عند الطوارئ و استخدمنا لها**jnb RUN,$ **وهى سنستبدلها بالأمر **BitWait **أى انتظر البت ثم الاسم و القيمة **Set **تعنى **1 **وهذا يعنى انتظر البت اسمها **RUN **حتى تصبح **1 **ثم اكمل**. **و أخيرا السطرين*
*On Int0 Emergency , Nosave*
*On Timer0 CountTime *
*والأول يعنى **"**عند حدوث مقاطعة من**" Int0 **انتقل للعنوان **Emergency **ولا تحفظ أى من قيم المسجلات فى الرصة*
*و الثانى يعنى **"**عند حدوث مقاطعة من**" Timer0 **انتقل للعنوان **CountTime **مع حفظ أى من قيم المسجلات فى الرصة*
*القيمة الفرضية عندما لا تكتب كلمة **"Nosave” **أن يحفظ البرنامج المسجلات التى تستخدم فى خطوات برنامج خدمة المقاطعة وهو أسلم بالطبع وبهاتين الخطوتين عرفنا المتحكم ماذا يفعل عند كل مقاطعة **. **و أخيرا كلمة **Loop **من كلمات اللغة لذا نستبدلها بكلمة **LoopAgain **و هكذا انهينا ألتهيئة ولو راجعتها الآن ستجدها أسهل من الأسيمبلى فأمر يغنيك عن كثير لكن أحيانا تجد أنك أقل حرية من الأسيمبلى**. **المرة القادمة إن شاء الله نكتب باقى البرنامج**.*


----------



## ماجد عباس محمد (8 يوليو 2018)

*أول البرنامج*

*أول البرنامج*

*بعد التهيئة السابقة وصلنا لأول البرنامج حيث العنوان التكرارى**LoopAgain **بعد ذلك الاختبار **If Full = 0 Then **أى لو زرار **Full **مضغوط إذن نفعل السابق وهو **ORL **ثم **LEDs,#00000111b **، الوظيفة **"**أو**" OR **وهى بالأسيمبلى **ORL **وفى البيزك **OR **لأنه هنا لا يعتمد النوع الآخر **Boolean **من **OR **و تتحول الوظيفة لهذه الصيغة **Leds = Leds Or &B00000111*
*أى أن اجعل **LEDs **تساوى **= LEDs OR 00000111 **و هنا الرمز **&B **ليعنى أن الرقم بالنظام ألثنائى **Binary*
*قبل أن نترك هذه الخطوة نعلم أن هناك أربعة وظائف هى **OR,AND,NOT, EXOR **وهى أو – مع – عاكس – أو المطلقة وهى كما هى هكذا لا تحتاج لتفكير ولا تذكر ولا تستخدم رموز أو إشارات – لغة انجليزية بسيطة و مفهومة*
*كان من الممكن أن نكمل بطريقتين، الأولى
*

```
[LEFT][SIZE=4][COLOR=#0000ff]If [/COLOR]Full=0 [COLOR=#0000ff]Then[/COLOR]
Leds = Leds [COLOR=#0000ff]Or[/COLOR] &B00000111 : [COLOR=#0000ff]Reset [/COLOR]FulLed   
[COLOR=#0000ff]End if
If [/COLOR]Half = 0 [COLOR=#0000ff]Then[/COLOR]
  Leds = Leds Or &B00000111 : [COLOR=#0000ff]Reset [/COLOR]HalfLed 
[COLOR=#0000ff]End If
if [/COLOR]Small = 0 [COLOR=#0000ff]Then[/COLOR]
Leds = Leds Or &B00000111 : [COLOR=#0000ff]Reset [/COLOR]SmallLed 
[COLOR=#0000ff]End If[/COLOR][/SIZE][/LEFT]
```
*
لكن كما ذكرنا أن الاختبار الأول لو نجح فمضيعة للوقت إجراء الثانى و الثالث لذلك فاستخدام الطريقة الثانية **Elseif **يجعل الاختبار الأول عند نجاحه سنخرج من المجموعة الأولى ذات الخيارات المتبادلة أى لا يمكن أن يختار **2 **منها معا ، واحد وواحد فقط فى كل مرة ، و نفس الشيء فى المجموعة الثانية واحد من ثلاث فقط لذا سنكرر الهيكلية معهم*
*البرنامج أصبح
*

```
[LEFT][SIZE=3][FONT=times new roman]LoopAgain: 

[COLOR=#0000ff]If[/COLOR] Full = 0 [COLOR=#0000ff]Then[/COLOR]
Leds = Leds [COLOR=#0000ff]Or [/COLOR]&B00000111 : [COLOR=#0000ff]Reset[/COLOR] FulLed        
[COLOR=#0000ff]Elseif [/COLOR]Half = 0 [COLOR=#0000ff]Then[/COLOR]
Leds = Leds [COLOR=#0000ff]Or [/COLOR]&B00000111 : [COLOR=#0000ff]Reset [/COLOR]HalfLed        
[COLOR=#0000ff]Elseif [/COLOR]Small = 0 [COLOR=#0000ff]Then[/COLOR]
Leds = Leds [COLOR=#0000ff]Or [/COLOR]&B00000111 : [COLOR=#0000ff]Reset [/COLOR]SmallLed        
[COLOR=#0000ff]End If
[/COLOR]
[COLOR=#0000ff]If [/COLOR]Hot = 0 [COLOR=#0000ff]Then[/COLOR]
Leds = Leds [COLOR=#0000ff]Or [/COLOR]&B00111000 : [COLOR=#0000ff]Reset [/COLOR]Hotled      
[COLOR=#0000ff]Elseif [/COLOR]Mild = 0 [COLOR=#0000ff]Then[/COLOR]
Leds = Leds [COLOR=#0000ff]Or [/COLOR]&B00111000 : [COLOR=#0000ff]Reset [/COLOR]Mildled      
[COLOR=#0000ff]Elseif [/COLOR]Cold = 0 [COLOR=#0000ff]Then[/COLOR]
Leds = Leds Or &B00111000 : [COLOR=#0000ff]Reset [/COLOR]Coldled      
[COLOR=#0000ff]End If
[/COLOR]
[COLOR=#0000ff]If[/COLOR] Run = 1 [COLOR=#0000ff]Then [/COLOR]Goto Loop            [COLOR=#008000]   ' Wait Run Press[/COLOR]
[/FONT][/SIZE]
[INDENT]Bitwait  Dooropen , Reset   [COLOR=#008000] ' Wait Door to close[/COLOR][/LEFT][/INDENT]
[LEFT][INDENT=4][SIZE=3][FONT=times new roman]Reset Wateron                 [COLOR=#008000]                   ' Fill with water[/COLOR]
[/FONT][/SIZE][/LEFT][/INDENT]
[LEFT][SIZE=3][FONT=times new roman]Bitwait Waterfull , Reset [COLOR=#008000]                  ' Wait full Tank[/COLOR]
[/FONT][/SIZE]
[SIZE=3][FONT=times new roman]Set Wateron   [COLOR=#008000]                                     ' Close water Valve[/COLOR] [/FONT][/SIZE][/LEFT]
```
*أصبح استبدال أوامر الأسيمبلى بالبيزك تكراريا و مفهوما*
*فى الأمر التالى استخدمنا فى الأسيمبلى الأمر *
*JNB ColdLED,SetCycle ; Cold cycle No Heat needed*
*لنختبر إذا زرار البارد قد اختير ننتقل و إلا نشغل السخان و تترجم*

```
[LEFT][B][COLOR=#0000ff]If[/COLOR] Coldled = 1 [COLOR=#0000ff]Then [/COLOR]Reset Heateron  [COLOR=#008000]' No Cold then Heater On[/COLOR][/B][/LEFT]
```
*ثم نختبر إذا زرار الوسط قد اختير ننتقل لنرقب حساس الدافئ و إلا نرقب حساس الحار *

```
[LEFT][SIZE=3][FONT=times new roman]JNB MildLED,HOTTemp
jb HiTemp,$ ; wait mild sensor
sjmp SetCycle 
HOTTemp: 
jb MidTemp,$ ; wait HOT sensor

و تترجم هكذا

[COLOR=#0000ff]If [/COLOR]Coldled = 1 [COLOR=#0000ff]Then    [/COLOR][COLOR=#008000]                 ' not Cold then[/COLOR]
[/FONT][/SIZE]
[INDENT=2][COLOR=#0000ff]Reset [/COLOR]Heateron  [COLOR=#008000]         ' Heater on[/COLOR]   [/LEFT][/INDENT]
[LEFT][SIZE=3][FONT=times new roman][COLOR=#0000ff]If [/COLOR]Mildled = 0 [COLOR=#0000ff]Then Bitwait[/COLOR] Midtemp , Reset [COLOR=#0000ff]Else Bitwait[/COLOR] Hitemp , Reset    
Set Heateron                       [COLOR=#008000]     ' Turn off heater[/COLOR]    
[COLOR=#0000ff]End If                          [/COLOR][COLOR=#008000]                  ' Now Start Washing[/COLOR]
[/FONT][/SIZE][/LEFT]
```
*
تذكر أن تعليمه **If **فى سطر واحد لا تحتاج **End If **فى آخره، ثم يلى ذلك نفس الهيكلية لاختيار زمن التشغيل نختبر ليد **Full **أو حمولة كاملة أو **small **أى حمولة صغيرة ونحدد الزمن هكذا
*

```
[LEFT][SIZE=3][FONT=times new roman]SetCycle: ; Now Start Washing
JNB FullLED,HalfCycle
MOV Minutes,#20
sjmp RunMotor
HalfCycle: JNB HalfLED,SmallCycle
MOV Minutes,#8
sjmp RunMotor
SmallCycle:
MOV Minutes,#5
RunMotor:

و تترجم هكذا
[COLOR=#0000ff]If[/COLOR] Fullled = 0 [COLOR=#0000ff]Then[/COLOR]
Runtime = 20 * 60         
[COLOR=#0000ff]Elseif[/COLOR] Halfled = 0 [COLOR=#0000ff]Then[/COLOR]
Runtime = 480         
[COLOR=#0000ff]Else[/COLOR]
Runtime = 300         
[COLOR=#0000ff]End If[/COLOR][/FONT][/SIZE][/LEFT]
```
*
تعمدت أن اذكرك أننا سنكتب عدد الثوانى مرة واحدة و يمكنك كتابته بصورة رياضية للتذكر و سيحلها المترجم قبل التكويد أى الترجمة أى لن تضيف للناتج أى خطوات فبالنسبة للمترجم **20*60 **هى ذاتها **1200 **و بهذا لسنا فى حاجة لوضع **59 **ثانية**. **الآن نشغل الموتور دورة الغسيل*

*باقى الدورات موضوعنا القادم بإذن الله*


----------



## ماجد عباس محمد (9 يوليو 2018)

*باقى الدورات*

[h=4]باقى الدورات[/h]*ألان ندير الموتور الفترة الزمنية المحددة ، ولكى نعرف الزمن يجب أن نقيم **JobPending **أى نجعله **= 1 **و ندير الموتور و ننتظر **JobPending **أن يحدد نهاية المدة و كانت هكذا*

```
[LEFT][SIZE=3][B]RunMotor:[/B]
[B]MOV Seconds,#59[/B]
[B]SETB JobPending[/B]
[B]CLR MotorOn[/B]
[B]SETB TR0                   [COLOR=#006400]  ; Start Timer/Counter[/COLOR][/B][COLOR=#006400]
[/COLOR][B]JB JobPending,$       [COLOR=#006400]   ; Wait to Finish[/COLOR][/B][COLOR=#006400]
[/COLOR][B]SETB MotorON           [COLOR=#006400]   ; stop motor[/COLOR][/B][COLOR=#006400]
[/COLOR]

[B]لا خانة للثوانى الآن فلا تترجم والعنوان[/B][B]Runmotor [/B][B]لا حاجة له ثم جعل دليل الوقت [/B][B]Jobpending=1 [/B][B]ثم تشغيل الموتور و انتظار نهاية الوقت ثم إيقاف الموتور [/B][B].[/B]
[B]Set  Jobpending         [COLOR=#006400]              ' Timing flag[/COLOR][/B]
[B]Reset  Motoron            [COLOR=#006400]            ' Start Motor[/COLOR][/B]
[B]Start  Timer0                           [COLOR=#006400]' Start Timer/Counter[/COLOR][/B]
[B]Bitwait Jobpending , Reset    [COLOR=#006400]' Wait to Finish[/COLOR][/B][COLOR=#006400]
[/COLOR][B]Set  Motoron [/B][/SIZE][/LEFT]
```
*
ألان نحتاج لدورتين للشطف و من المتوقع أن يكونا متطابقتين، لذا لونت إحداهما بلون مختلف ليمكنك متابعة خطوة بمثيلتها للتحقق من ذلك**. **فتح الصرف و انتظار حساس **" **فارغ**" **ثم غلق الصرف ثم فتح المياه و انتظار تمام ألملو ثم تشغيل الموتور و انتظار الوقت ثم إيقاف الموتور **. **حسنا هل كان من الممكن كتابة كود واحد و تكراره مرتين، نعم فقط سنضيف فى قسم التعريف بالأعلى التعريف **Rinse Equ 20 **أى أن متغيرا باسم **Rinse **فى خانة الذاكرة رقم **20 (**أو أى خانى فارغة تريد**) **و هذا يتيح لنا أن نأتى فى أول الدورة و نكتب ما يلى بالأسيمبلى*

```
[LEFT][B]CLR DrainON            ; Open Drain[/B]
[B]JB WaterEmpty,$      ;Wait Drain[/B]
[B]Setb DrainON            ; Close Drain[/B]
[B]CLR WaterON            ; Fill again[/B]
[B]JB WaterFull,$[/B]
[B]SETB WaterON          ; Close Water[/B]
[B]MOV Minutes,#5          ; 1St Rinse[/B]
[B]MOV Seconds,#59[/B]
[B]SETB JobPending[/B]
[B]CLR MotorOn                  ; Start Rinse[/B]
[B]SETB TR0                       ; Start Timer[/B]
[B]JB JobPending,$             ; Wait to Finish[/B]
[B]Setb MotorOn                ; Stop Rinse[/B]

[COLOR=#800000]
[B]CLR DrainON                   ; Open Drain second cycle[/B]
[B]JB WaterEmpty,$               ;Wait Drain[/B]
[B]Setb DrainON                 ; Close Drain [/B]
[B]CLR WaterON                 ; Fill again[/B]
[B]JB WaterFull,$[/B]
[B]SETB WaterON               ; Close Water[/B]
[B]MOV Minutes,#5            ; 2nd Rinse[/B]
[B]MOV Seconds,#59[/B]
[B]SETB JobPending[/B]
[B]SETB TR0                        ; Start Timer/Counter[/B]
[B]CLR MotorOn                  ; Start Rinse[/B]
[B]SETB TR0                        ; Start Timer[/B]
[B]JB JobPending,$             ; Wait to Finish[/B]
[B]Setb MotorOn                   ; Stop Rinse [/B][/COLOR][/LEFT]
```

*هكذا نستخدم نظام الدورات لاحظ أن السطر الأول تمهيدى و قد أضيف لتحديد عدد الدورات بدورتين **. **أيضا السطر الأخير تكملة له أما باقى التعليمات فهى ملونة لتقارنها بالملون السابق و ستجدها نسخة مكررة**.*

```
[LEFT][B]Mov Rinse,#2[/B]
[B]RinseLoop:[/B]
[B]CLR DrainON             [COLOR=#006400] ; Open Drain[/COLOR][/B]
[B]JB WaterEmpty,$      [COLOR=#006400] ;Wait Drain[/COLOR][/B]
[B]Setb DrainON            [COLOR=#006400] ; Close Drain[/COLOR][/B]
[B]CLR WaterON            [COLOR=#006400] ; Fill again[/COLOR][/B]
[B]JB WaterFull,$[/B]
[B]SETB WaterON           [COLOR=#006400]; Close Water[/COLOR][/B]
[B]MOV Minutes,#5          [COLOR=#006400] ; 1St Rinse[/COLOR][/B][COLOR=#006400]
[/COLOR][B]MOV Seconds,#59[/B]
[B]SETB JobPending[/B]
[B]CLR MotorOn              [COLOR=#006400] ; Start Rinse[/COLOR][/B]
[B]SETB TR0                   [COLOR=#006400] ; Start Timer[/COLOR][/B]
[B]JB JobPending,$      [COLOR=#006400]   ; Wait to Finish[/COLOR][/B]
[B]Setb MotorOn            [COLOR=#006400] ; Stop Rinse[/COLOR][/B]
[B]Djnz Rinse, RinseLoop[/B][/LEFT]
```

*وهكذا نوفر كتابة الكود مرتين و نضيف فقط زمن الاختبار و الانتقال وهذا مثال آخر للكود الأقصر طولا و أطول زمنا لكن له ميزة أخرى لا تقدر وهى أننا لو أردنا تغيير عدد دورات الشطف فكل ما نحتاجه هو أن نضع قيمة مختلفه **(**من المستخدم عبر لوحة مفاتيح مثلا**) **فى الخانة المسماة **Rinse **أو ذاكرة رقم **20 **وهو سيكررها بالعدد آليا بدلا من تكرار الكود عدة مرات مستهلكا كم أكبر من ذاكرة البرنامج**.*
*ألان نترجم هذا بلغة البيزك نضيف فى التعريفات **Dim Rinse As Byte , cntr as byte **و هنا تترجم التعليمات هكذا **.*

```
[LEFT][B]For cntr = 1 To [/B][B]Rinse[/B]
[B]Reset  Drainon                          [COLOR=#006400] ' Open Drain[/COLOR][/B]
[B]Bitwait Waterempty , Reset    [COLOR=#006400] ' Wait Drain[/COLOR][/B]
[B]Set  Drainon                              [COLOR=#006400] ' Close Drain[/COLOR][/B]
[B]Reset  Wateron                          [COLOR=#006400]' Fill again[/COLOR][/B]
[B]Bitwait Waterfull , Reset[/B]
[B]Set  Wateron                             [COLOR=#006400]  ' Close Water[/COLOR][/B]
[B]Runtime = 300                          [COLOR=#006400] ' Rinse Time[/COLOR][/B]
[B]Set  Jobpending[/B]
[B]Reset  Motoron                            [COLOR=#006400]  ' Start Rinse[/COLOR][/B]
[B]Start  Timer0                               [COLOR=#006400] ' Start Timer[/COLOR][/B]
[B]Bitwait  Jobpending , Reset          [COLOR=#006400] ' Wait to Finish[/COLOR][/B]
[B]Set [/B][B] Motoron                                   [COLOR=#006400]' Stop Rinse[/COLOR] [/B]
[B]Next                                              [COLOR=#006400]  '[/COLOR][/B][COLOR=#006400][B] Loop Back[/B][/COLOR][/LEFT]
```
*
الخطأ هنا أننا لم نضع قيمة فى المتغير **Rinse **لذا يجب أن نكتب فى التهيئة مثلا **Rinse=2 **أو لاحقا يمكنك تطوير البرنامج ليعدل مرات الشطف حسب كمية الغسيل أو باختيار المستخدم من لوحة مفاتيح الخ**. **فهذا تعليمى على أى حال**. **الباقى هو دورة العصر وهى لا تختلف إلا فى تفعيل ريلاى العصر لدوران الموتور بسرعة عالية*

```
[LEFT][B]CLR DrainON                      ; Open Drain [/B]
[B]JB WaterEmpty,$                 ;Wait Drain[/B]
[B]MOV Minutes,#3                  ; SPIN[/B]
[B]MOV Seconds,#59[/B]
[B]SETB JobPending[/B]
[B]CLR MotorOn                        ; Start Rinse[/B]
[B]CLR Run_Nspin                      ; SPIN[/B]
[B]SETB TR0                              ; Start Timer/Counter[/B]
[B]JB JobPending,$                    ; Wait to Finish[/B]
[B]MOV Relays,#255                    ; ALL OFF, INITIAL State[/B]
[B]MOV Controls,#255 [/B]
[B]jmp Loop[/B]
[B];====================================[/B]
[B]END[/B]
[B]وتترجم هكذا[/B]
[B]Reset  Drainon                         [COLOR=#006400] ' Open Drain second cycle[/COLOR][/B][COLOR=#006400]
[/COLOR][B]Bitwait Waterempty , Reset    [COLOR=#006400]' Wait Drain[/COLOR][/B]
[B]Runtime = 180                        [COLOR=#006400]' SPIN[/COLOR][/B]
[B]Set  Jobpending[/B]
[B]Reset  Motoron                         [COLOR=#006400]' Start Rinse[/COLOR][/B]
[B]Reset  Run_nspin                      [COLOR=#006400]' SPIN[/COLOR][/B]
[B]Start Timer0                           [COLOR=#006400]  ' Start Timer/Counter[/COLOR][/B]
[B]Bitwait Jobpending , Reset       [COLOR=#006400]  ' Wait to Finish[/COLOR][/B]
[B]Relays = 255                           [COLOR=#006400] ' ALL OFF, INITIAL State[/COLOR][/B]
[B]Controls = 255[/B]
[B]Goto Loop[/B][B]ِ[/B][B]again[/B][/LEFT]
```
*
لو استخدمت**Goto Begin **يمكنك الاستغناء عن الأمرين السابقين لها أيضا للتكرار **. **المرة القادمة إن شاء الله سنستخدم بيزك ميكروإلكترونيكا و بعدها **C **من ميكروإلكترونيكا*


----------



## ماجد عباس محمد (10 يوليو 2018)

*البرنامج بمترجم بيزك من ميكروإلكترونيكا*

*البرنامج بمترجم بيزك من ميكروإلكترونيكا*

*ها هو البرنامج كاملا لمترجم باسكوم و سنعدل ما نحتاج فقط*

```
[LEFT][B][SIZE=3]' DEFINITIONS[/SIZE][/B][SIZE=3]
[B]Leds Alias P0 : Relays Alias P1 : Switches Alias P2 : Controls Alias P3[/B]
[B]Fullled Alias Leds.0 : Halfled Alias Leds.1 : Smallled Alias Leds.2[/B]
[B]Hotled Alias Leds.3 : Mildled Alias Leds.4 : Coldled Alias Leds.5[/B]
[B]Wateron Alias Relays.0 : Drainon Alias Relays.1 : Heateron Alias Relays.2[/B]
[B]Motoron Alias Relays.3 : Run_nspin Alias Relays.4 : Waterfull Alias Relays.5[/B]
[B]Waterempty Alias Relays.6 : Dooropen Alias Relays.7 : Midtemp Alias Switches.0[/B]
[B]Hitemp Alias Switches.1 : Cold Alias Switches.2 : Mild Alias Switches.3[/B]
[B]Hot Alias Switches.4 : Small Alias Switches.5 : Half Alias Switches.6[/B]
[B]Full Alias Switches.7 : Run Alias Controls.1[/B]

[B]' VARIABLES[/B]
[B]Dim Runtime As Word[/B]
[B]Jobpending Alias Psw.5[/B]
[B]Dim Rinse As Byte , cntr as byte[/B]

[B]Emergency:[/B]
[B]Goto Begin[/B]
[B]Counttime:[/B]
[B]Decr Runtime[/B]
[B]If Runtime = 0 Then[/B]
[B]Reset Jobpending[/B]
[B]Stop Timer0[/B]
[B]End If[/B]
[B]Return[/B]
[B]نظرا لعدم قبوله أكثر من أمر لكل سطر فسنضطر إلى التعريف هكذا[/B]
[B]program WM[/B]
[COLOR=#008080][B]' Declarations section[/B]
[/COLOR][B]symbol FullLED = LEDs.0[/B]
[B]symbol HalfLED = LEDS.1[/B]
[B]symbol SmallLED = LEDs.2 [/B]
[B]symbol HOTLED = LEDs.3[/B]
[B]symbol MildLED = LEDs.4[/B]
[B]symbol ColdLED = LEDs.5 [/B]
[B]symbol WaterOn = Relays.0[/B]
[B]symbol DrainOn = Relays.1[/B]
[B]symbol HeaterOn = Relays.2 [/B]
[B]symbol MotorOn = Relays.3[/B]
[B]symbol Run_Nspin = Relays.4[/B]
[B]symbol WaterFull = Relays.5 [/B]
[B]symbol WaterEmpty = Relays.6 [/B]
[B]symbol DoorOpen = Relays.7[/B]
[B]symbol MidTemp = Switches.0 [/B]
[B]symbol HiTemp = Switches.1[/B]
[B]symbol Cold = Switches.2[/B]
[B]symbol Mild = Switches.3 [/B]
[B]symbol Hot = Switches.4[/B]
[B]symbol SmallLoad = Switches.5[/B]
[B]symbol Half = Switches.6 [/B]
[B]symbol Full = Switches.7 [/B]
[B]symbol RUN = Controls.1[/B]
[B]Dim Leds as byte at P0[/B]
[B]dim Relays as byte at P1[/B]
[B]Dim Switches as byte at P2[/B]
[B]Dim Controls as byte at P3 [/B]


[B]Dim JobPending as sbit at PSW.F0 [/B]
[B]dim RunTime as word [/B]
[B]dim Rinse as byte[/B]
[B]dim cntr as byte[/B]
[B]sub procedure INT0_Interrupt() org IVT_ADDR_EX0[/B]
[B]asm[/B]
[B]sjmp 0[/B]
[B]end asm[/B]
[B]end sub[/B]


[B]sub procedure Timer0_Interrupt() org IVT_ADDR_ET0[/B]
[B]Dec (RunTime)[/B]
[B]If RunTime = 0 then [/B]
[B]JobPending = 0 [/B]
[B]TR0_bit = 0  ' Stop Timer1[/B]
[B]end if[/B]
[B]end sub[/B]
[/SIZE][/LEFT]
```
*
السطر الأول اسم البرنامج ثم التعريفات كما سبق الشرح و لكن هذا المترجم يتطلب إعلان الاسم بكلمه **DIM **قبل استخدامه أى **Symbol **لا تجدى فى تعريف ما يلى كما فى باسكوم لذا سنعرف المنافذ كلها*
*للمقاطعة يستخدم هذا المترجم تعريف مختلف*
*sub procedure INT0_Interrupt() org IVT_ADDR_EX0*
*حيث **Sub **كلمة يستخدمها دوما كما فى فكر لغة **C **وهى زائدة كما بينا فى باسكوم فهو يتبعها بكلمة **procedure **أو كلمة **Function **وواحدة تغنى ثم اسم المقاطعة وهو هنا **INT0_Interrupt() **ثم كلمة **org **أو **IV **لتخبره أنها مقاطعة **Interrupt Vector **و أخيرا العنوان **IVT_ADDR_EX0*
*فى المقاطعة الخاصة بالطوارئ كنا سنستخدم انتقال للبداية **GOTO Begin **لكنها لا تقبل رقم و تطلب عنوان **"**سبق تعريفه**" **لذا إما ننقل كل الكود لآخر البرنامج أو لنتحايل و نبقى على التتابع استخدمنا الأسيمبلى بالتعريف **asm **ثم القفز ثم **end asm. **المقاطعة الثانية نستخدم نفس الأوامر**.*
*يلى ذلك أوامر التهيئة ما بين **Begin , LoopAgain*

```
[LEFT][SIZE=3][B]
Begin:[/B]
[COLOR=#ff0000][B]Config Timer0 = Counter , Mode = 2 , Gate = Exteral[/B]
[/COLOR][B]Th0 = 205 [COLOR=#008080]' Auto reload[/COLOR][/B]
[B]Tl0 = 205[/B]
[B]Tcon = 1[/B]
[COLOR=#ff0000][B]Enable Interrupts[/B]
[B]Enable Int0[/B][/COLOR]
[B]Leds = &B11011011 [COLOR=#008080]' Reset All PORTS! select Small cold cycle[/COLOR][/B]
[B]Relays = 255[/B]
[B]Switches = 255[/B]
[B]Controls = 255[/B]
[B]Rinse = 2[/B]
[COLOR=#ff0000][B]On Int0 Emergency , Nosave[/B]
[B]On Timer0 Counttime[/B][/COLOR]
[B]الأسطر الحمراء لا يدعمها هذا المترجم ولذلك سنضطر لتهيئة التايمر يدويا كما سبق فى الأسيمبلى كما أن نتيح المقاطعة و نبدأ و نوقف العداد بالأمر النصى بدلا من [/B][B]Enable [/B][B]فتصبح[/B]
[B]IE=%10000011 [COLOR=#008080]' Enable T0 & INT0 external[/COLOR][/B]
[B]TH0 = 205 [COLOR=#008080]' Auto reload[/COLOR][/B]
[B]TL0 = 205 [COLOR=#008080]' Start Value[/COLOR][/B]
[B]TMOD = %00000110[/B]
[B]TCON = 1 ' Clear All interrupts, Set INT0 Edge trigger[/B]
[B]SP = 70 [COLOR=#008080]' Move stack away[/COLOR][/B]
[B]Leds = %11011011 [COLOR=#008080]' Reset All PORTS! select Small cold cycle[/COLOR][/B]
[B]Relays = 255[/B]
[B]Switches = 255[/B]
[B]Controls = 255[/B]
[B]Rinse = 2[/B][/SIZE][/LEFT]
```
*
الآن أول أمر كان انتظار عودة زر **RUN **لحالة عدم الضغط و لكن الأسف الأمر **Bitwait **غير مدعوم ولا بديل له فالمكتبة تتيح أمر **sub function Button(dim time_ms as byte, dim active_state as byte) as byte **حيث يجب أن تعرف قبل استخدامه متغير باسم **Button_PIN **ثم تحدد الزمن و تحدد **1 **أم صفر فتعيد لك **255 **لو حدث أو صفر لو لم يحدث و من ملف المساعدة نجد أنها تختبر الطرف ثم بعد الزمن تعيد اختباره وهذا يحتاج لمكافئ بالأسيمبلى كبير لا حاجة له فضلا عن أننا يجب أن نعيد التعريف عند كل تغيير للطرف وهذا عبئ لا معنى له ، لذا سنستغل الكود ألعادى **Do loop*
*الشرط لو **Full=0 **سيتطلب الأمرين التاليين و نظرا لحدود المترجم سنحتاج سطرين منفصلين الأول كالسابق مع تغيير **&B **واستخدام الحرف **% **ثم السطر الثانى لا يدعم المترجم الأمر **Reset **و لكنه يوفر أمر **SetBit(P0, 2) ' Set P0.2 **و الأمر **ClearBit(P0, 7) ' Clear P0.7 **والمشكلة هنا أنهما لا يقبلا سوى الأمر الصريح كما بالمثالين السابقين أى لا نستطيع الاستفادة بالتسميات ولو أردنا التعديل لاحقا سنفحص كل سطر بحثا عنها لذا سنستخدم الأمر الصريح أيضا **.*
*أيضا يجب ملاحظة أن هذا المترجم لا يدعم الأمر **Elseif **لذا يجب أن نكتب **Else **و فى داخلها نضع **If **جديدة لها **Else **وهكذا و نضع **End If **بعدد **If **المستخدمة عكس باسكوم **End If **واحدة للدورة كلها مما يجعل باسكوم أكثر وضوحا**.*
*الكود يصبح*

```
[LEFT][B][SIZE=3]do[/SIZE][/B][SIZE=3][B] [COLOR=#008080]' Wait Run =1 unpressed[/COLOR][/B]
[B]loop until[/B][B] Run = 1[COLOR=#008080]  ' Run button release[/COLOR][/B]
[B]Loopagain:[/B]
[B]If[/B][B] Full = 0 Then[/B]
[B]Leds = Leds Or %00000111[/B]
[B]FullLED = 0[/B]
[B]Else[/B]
[B]if[/B][B] Half = 0 Then[/B]
[B]Leds = Leds Or %00000111 [/B]
[B]Halfled = 0[/B]
[B]Else[/B]
[B]if SmallLoad = 0 Then[/B]
[B]Leds = Leds Or %00000111[/B]
[B]Smallled = 0[/B]
[B]end if[/B]
[B]end if[/B]
[B]End If[/B]


[B]If [/B][B]Hot = 0 Then[/B]
[B]Leds = Leds Or %00111000 [/B]
[B]Hotled = 0[/B]
[B]Else[/B]
[B]if[/B][B] Mild = 0 Then[/B]
[B]Leds = Leds Or %00111000[/B]
[B]Mildled = 0[/B]
[B]Else[/B]
[B]if[/B][B] Cold = 0 Then[/B]
[B]Leds = Leds Or %00111000 [/B]
[B]Coldled = 0[/B]
[B]end if[/B]
[B]end if[/B]
[B]End If[/B]
[B]If [/B][B]Run = 1 Then Goto LoopAgain  [COLOR=#008080]' Wait Run Press[/COLOR][/B]
[/SIZE][/LEFT]
```
*
أخيرا سنجد أمر **If Run = 1 Then Goto LoopAgain **وسيخطر على بالك أنه من الممكن استبداله مع العنوان **LoopAgain **بدورة **DO Loop until **أو دورة **While-WEND **، وهو ممكن فى الأمثلة السابقة لكن لم أريد تعقيد الأمور حتى لا تتساءل كيف فكر فى هذا ، ربما الأمر يصعب على الاستمرار فيه، المسألة ببساطة كلما وجدت وسيلة لاختصار بعض الخطوات فلم لا ، لكن الأفضل أن تبدأ بالبسيط السهل المتيسر تتبع أخطاؤه ثم بعد التأكد من نجاحه ، اختصر شيء و جرب فعندها ستحصر الخطأ فيما غيرت ولا بأس من حفظ القديم كاملا مادام قد نجح حتى يسهل عليك العودة له دوما**. *

```
[LEFT][B][SIZE=3]do[/SIZE][/B][SIZE=3]
[B]loop until[/B][B] Run = 1  [COLOR=#008080]' Run button release[/COLOR][/B]
[B]do[/B]
[B]If [/B][B]Full = 0 Then[/B]
[B]Leds = Leds Or %00000111[/B]
[B]FullLED = 0[/B]
[B]Else[/B]
[B]if[/B][B] Half = 0 Then[/B]
[B]Leds = Leds Or %00000111 [/B]
[B]Halfled = 0[/B]
[B]Else[/B]
[B]if[/B][B] SmallLoad = 0 Then[/B]
[B]Leds = Leds Or %00000111[/B]
[B]Smallled = 0[/B]
[B]end if[/B]
[B]end if[/B]
[B]End If[/B]


[B]If[/B][B] Hot = 0 Then[/B]
[B]Leds = Leds Or %00111000 [/B]
[B]Hotled = 0[/B]
[B]Else[/B]
[B]if[/B][B] Mild = 0 Then[/B]
[B]Leds = Leds Or %00111000[/B]
[B]Mildled = 0[/B]
[B]Else[/B]
[B]if[/B][B] Cold = 0 Then[/B]
[B]Leds = Leds Or %00111000 [/B]
[B]Coldled = 0[/B]
[B]end if[/B]
[B]end if[/B]
[B]End If[/B]
[B]loop until[/B][B] RUN =0[/B]
[/SIZE][/LEFT]
```
*
بعد ذلك غلق الباب و تحديد الفترة الزمنية حسب الخيارات و هذا موضوعنا القادم بإذن الله*


----------



## ماجد عباس محمد (11 يوليو 2018)

*تكملة البرنامج*

*بعد ذلك غلق الباب و تحديد الفترة الزمنية حسب الخيارات و كانت*

```
[LEFT][B]Bitwait Dooropen , Reset ' Wait Door to close[/B]
[B]Reset Wateron ' Fill with water[/B]
[B]Bitwait Waterfull , Reset ' Wait full Tank[/B]
[B]Set Wateron ' Close water Valve[/B]

[B]If Coldled = 1 Then ' not Cold then[/B]
[B]Reset Heateron ' Heater on[/B]
[B]If Mildled = 0 Then Bitwait Midtemp , Reset Else Bitwait Hitemp , Reset[/B]
[B]Set Heateron ' Turn off heater[/B]
[B]End If ' Now Start Washing[/B]


[B]If Fullled = 0 Then[/B]
[B]Runtime = 20 * 60[/B]
[B]Elseif Halfled = 0 Then[/B]
[B]Runtime = 480[/B]
[B]Else[/B]
[B]Runtime = 300[/B]
[B]End If[/B]

[/LEFT]
```
*و كما سبق التعديل ستصبح بعد استبدال **Waitbit **و **Elseif*

```
[LEFT][B]do  [COLOR=#008080]' Wait Door to close[/COLOR][/B]
[B]loop until Dooropen = 1[/B]
[B]Wateron = 0 [COLOR=#008080]' Fill with water[/COLOR][/B]
[B]do [/B]
[B]loop until Waterfull = 1 [COLOR=#008080]' Wait full Tank[/COLOR][/B]
[B]Wateron = 1 [COLOR=#008080]' Close water Valve[/COLOR][/B]

[B]If [/B][B]Coldled = 1 Then  [COLOR=#008080]' not Cold then[/COLOR][/B]
[B]Heateron = 0  [COLOR=#008080]' Heater on[/COLOR][/B]
[B]If[/B][B] Mildled = 0 Then[/B]
[B]do[/B]
[B]loop until [/B][B]Midtemp = 0[/B]
[B]Else[/B]
[B]do[/B]
[B]loop until [/B][B]Hitemp = 0[/B]
[B]end if[/B]
[B]Heateron = 1 [COLOR=#008080]' Turn off heater[/COLOR][/B]
[B]End If [/B][B]  [COLOR=#008080]' Now Start Washing[/COLOR][/B]


[B]If Fullled [/B][B]= 0 Then[/B]
[B]Runtime = 20 * 60[/B]
[B]Else [/B]
[B]if [/B][B]Halfled = 0 Then[/B]
[B]Runtime = 480[/B]
[B]Else[/B]
[B]Runtime = 300[/B]
[B]end if[/B]
[B]End If[/B]
[B]' Runmotor:[/B]
[/LEFT]
```
*ثم تشغيل الموتور دورة غسيل ثم شطف و عصر و كانت*

```
[LEFT][B]Runmotor:[/B]
[B]Set Jobpending ' Timing flag[/B]
[B]Reset Motoron ' Start Motor[/B]
[B]Start Timer0 ' Start Timer/Counter[/B]
[B]Bitwait Jobpending , Reset ' Wait to Finish[/B]
[B]Set Motoron ' stop motor[/B]
[B]For cntr = 1 To rinse[/B]
[B]Reset Drainon ' Open Drain[/B]
[B]Bitwait Waterempty , Reset ' Wait Drain[/B]
[B]Set Drainon ' Close Drain[/B]
[B]Reset Wateron ' Fill again[/B]
[B]Bitwait Waterfull , Reset[/B]
[B]Set Wateron ' Close Water[/B]
[B]Runtime = 300 ' 1St Rinse[/B]
[B]Set Jobpending[/B]
[B]Reset Motoron ' Start Rinse[/B]
[B]Start Timer0 ' Start Timer[/B]
[B]Bitwait Jobpending , Reset ' Wait to Finish[/B]
[B]Set Motoron ' Stop Rinse[/B]
[B]Next[/B]


[B]Reset Drainon ' Open Drain second cycle[/B]
[B]Bitwait Waterempty , Reset ' Wait Drain[/B]
[B]Runtime = 180 ' SPIN[/B]
[B]Set Jobpending[/B]
[B]Reset Motoron ' Start Rinse[/B]
[B]Reset Run_nspin ' SPIN[/B]
[B]Start Timer0 ' Start Timer/Counter[/B]
[B]Bitwait Jobpending , Reset ' Wait to Finish[/B]

[B]Relays = 255 ' ALL OFF, INITIAL State[/B]
[B]Controls = 255[/B]

[B]Goto Loopagain[/B]
[B]End[/B]
[B]
بعد استبدال ألدوال السابقة و استبدال [/B][B]Start Timer0 [/B][B]بالمكافئ لها وهو [/B][B]TR0_bit = 1 [/B][B]ستصبح[/B]

[B]' Runmotor:[/B]
[B]Jobpending = 1  [COLOR=#008080]' Timing flag[/COLOR][/B]
[B]Motoron = 0  [COLOR=#008080]' Start Motor[/COLOR][/B]
[B]TR0_bit = 1  [COLOR=#008080]' Start Timer/Counter[/COLOR][/B]
[B]do[/B]
[B]loop until Jobpending =0  [COLOR=#008080]' Wait to Finish[/COLOR][/B]
[B]Motoron = 1  [COLOR=#008080]' stop motor[/COLOR][/B]
[B]For cntr = 0 To Rinse[/B]
[B]Drainon = 0  [COLOR=#008080]' Open Drain[/COLOR][/B]
[B]do[/B]
[B]loop until[/B][B] Waterempty = 0  [COLOR=#008080]' Wait Drain[/COLOR][/B]
[B]Drainon = 1  [COLOR=#008080]' Close Drain[/COLOR][/B]
[B]Wateron = 0  [COLOR=#008080]' Fill again[/COLOR][/B]
[B]do[/B]
[B]loop unti[/B][B]l Waterfull = 0[/B]
[B]Wateron = 1  [COLOR=#008080]' Close Water[/COLOR][/B]
[B]Runtime = 300  [COLOR=#008080]' 1St Rinse[/COLOR][/B]
[B]Jobpending = 1[/B]
[B]Motoron = 1  [COLOR=#008080]' Start Rinse[/COLOR][/B]
[B]TR0_bit = 1  [COLOR=#008080]' Start Timer[/COLOR][/B]
[B]do[/B]
[B]loop until[/B][B] Jobpending = 0  [COLOR=#008080]' Wait to Finish[/COLOR][/B]
[B]Motoron = 1  [COLOR=#008080]' Stop Rinse[/COLOR][/B]
[B]Next [/B][B]cntr[/B]

[B]Drainon = 0  [COLOR=#008080]' Open Drain second cycle[/COLOR][/B]
[B]do[/B]
[B]loop until [/B][B]Waterempty = 0  [COLOR=#008080]' Wait Drain[/COLOR][/B]
[B]Runtime = 180[COLOR=#008080]  ' SPIN[/COLOR][/B]
[B]Jobpending = 1[/B]
[B]Motoron = 0  [COLOR=#008080]' Start Rinse[/COLOR][/B]
[B]Run_nspin = 0  [COLOR=#008080]' SPIN[/COLOR][/B]
[B]TR0_bit = 1  [COLOR=#008080]' Start Timer/Counter[/COLOR][/B]
[B]do[/B]
[B]loop until [/B][B] Jobpending = 0  [COLOR=#008080]' Wait to Finish[/COLOR][/B]

[B]Relays = 255  [COLOR=#008080]' ALL OFF, INITIAL State[/COLOR][/B]
[B]Controls = 255[/B]

[B]Goto Loopagain[/B]

[B]end.[/B][/LEFT]
```
*بقى الأمر الأخير **Goto Loopagain **مع العنوان **Loopagain: **يمكن استبدالهما بدورة أخرى مثلا 

تستبدل العنوان *
*While TRUE*
*ثم تستبدل **Goto Loopagain *
*WEND *
*و استبقيتهم للآخر حتى لا يبدو البرنامج معقد و به كثير من التنبؤات ولكن يمكن استبدال شيء بأخر *
*المرة القادمة إن شاء الله سنستخدم ذات البرنامج بلغة **C*


----------



## ماجد عباس محمد (12 يوليو 2018)

*الغسالة باستخدام c51 و لغة c*

*الغسالة باستخدام C51 و لغة C:*

*للأسف لا يوجد مصدر آخر سهل سوى ميكروإلكترونيكا لذا لا مقارنة سوى بين اللغتين و أتميل لها أتميل استوديو لكنه كبير جدا و ثقيل على الحاسب و سنبدأ بالبيزك و نحوله إلى **C*
طبعا نفس الدائرة السابقة ، *سنبدأ بالتعريفات وكانت*

```
[LEFT][SIZE=3][B]' DEFINITIONS[/B]
[B]Leds Alias P0 : Relays Alias P1 : Switches Alias P2 : Controls Alias P3[/B]
[B]Fullled Alias Leds.0 : Halfled Alias Leds.1 : Smallled Alias Leds.2[/B]
[B]Hotled Alias Leds.3 : Mildled Alias Leds.4 : Coldled Alias Leds.5[/B]
[B]Wateron Alias Relays.0 : Drainon Alias Relays.1 : Heateron Alias Relays.2[/B]
[B]Motoron Alias Relays.3 : Run_nspin Alias Relays.4 : Waterfull Alias Relays.5[/B]
[B]Waterempty Alias Relays.6 : Dooropen Alias Relays.7 : Midtemp Alias Switches.0[/B]
[B]Hitemp Alias Switches.1 : Cold Alias Switches.2 : Mild Alias Switches.3[/B]
[B]Hot Alias Switches.4 : Small Alias Switches.5 : Half Alias Switches.6[/B]
[B]Full Alias Switches.7 : Run Alias Controls.1[/B]


[B]' VARIABLES[/B]
[B]Dim Runtime As Word[/B]
[B]Jobpending Alias Psw.5[/B]
[B]Dim Rinse As Byte , Cntr As Byte[/B]
[B]Emergency:[/B]
[B]Goto Begin[/B]
[B]Counttime:[/B]
[B]Decr Runtime[/B]
[B]If Runtime = 0 Then[/B]
[B]Reset Jobpending[/B]
[B]Stop Timer0[/B]
[B]End If[/B]
[B]Return[/B][/SIZE][/LEFT]
```
*قد تظن أنك تستطيع أن تعرف المنافذ أولا ثم تستخدمها فى تعريف الأطراف بعد ذلك كما فعلنا فى البيزك لكن لا ليس هنا، ستحصل على رسالة غريبة جدا أن المتوقع هو متغير عام **Global Variable **و لكنه وجد **"**مثلا**" Leds **ولا تسألنى لماذا لا يعتبر التعريف السابق للمنفذ **Leds **من النوع **Global **بينما هو يستخدمه استخدام عام و شامل فى كل البرنامج أى **Global **ولذا سنستخدم دوما اسم المنفذ و أصبحت بعد تعريف كل منها كمتغير*

```
[LEFT][B]// DEFINITIONS[/B]
[B]char Leds at P0 ;[/B]
[B]char Relays at P1 ;[/B]
[B]char Switches at P2 ;[/B]
[B]char Controls at P3 ;[/B]
[B]sbit Fullled at P0_0_bit ;[/B]
[B]sbit Halfled at P0_1_bit ;[/B]
[B]sbit Smallled at P0_2_bit ;[/B]
[B]sbit Hotled at P0_3_bit ;[/B]
[B]sbit Mildled at P0_4_bit ;[/B]
[B]sbit Coldled at P0_5_bit ;[/B]
[B]sbit Wateron at P1_0_bit ;[/B]
[B]sbit Drainon at P1_1_bit ;[/B]
[B]sbit Heateron at P1_2_bit ;[/B]
[B]sbit Motoron at P1_3_bit ;[/B]
[B]sbit Run_nspin at P1_4_bit ;[/B]
[B]sbit Waterfull at P1_5_bit ;[/B]
[B]sbit Waterempty at P1_6_bit ;[/B]
[B]sbit Dooropen at P1_7_bit ;[/B]


[B]sbit Midtemp at P2_0_bit ;[/B]
[B]sbit Hitemp at P2_1_bit ;[/B]
[B]sbit Cold at P2_2_bit ;[/B]
[B]sbit Mild at P2_3_bit ;[/B]
[B]sbit Hot at P2_4_bit ;[/B]
[B]sbit Small at P2_5_bit ;[/B]
[B]sbit Half at P2_6_bit ;[/B]
[B]sbit Full at P2_7_bit ;[/B]
[B]sbit Run at P3_1_bit ;[/B]


[B]sbit Jobpending at F0_bit ;[/B]
[B]unsigned short Rinse ;[/B]
[B]unsigned short Cntr ;[/B]
[B]unsigned Runtime ;[/B]


[B]void External_Interrupt() org IVT_ADDR_EX0 {[/B]
[B]asm ajmp 0 ;[/B]
[B]}[/B]


[B]void Timer0_Interrupt() org IVT_ADDR_ET0 {[/B]
[B]if ( --Runtime = 0 ){ // End of time[/B]
[B]Jobpending = 0 ; // Clear Flag[/B]
[B]TR0_bit = 0 ; // stop timer 0[/B]
[B]} }[/B]


[B]void main() {[/B]
[B]Begin:[/B][/LEFT]
```
*بعد التعريفات تأتى تسمية المقاطعة بطريقة ميكروإلكترونيكا و أضاف لها لغة السى عدم التعرف على العنوان **Begin **لكونه لاحقا لذا اضطررت لاستخدام الأسيمبلى**.*
*فى كود المقاطعة الثانى الخاص بالطوارئ أى المقاطعة الخارجية نجد ألتعليمه *
*if ( --Runtime = 0 ){ *
*وهى للمبتدئ تعنى ما يلى على خطوتين*
*Runtime = --Runtime *
*if (Runtime = 0) {*
*و السطر الأول علامتى السالب يعنى انقص من المتغير التالى وهو هنا **Runtime **واحد أما لو كانا على يمين المتغير سيكون معناها انقص واحد لكن ليس الآن أى بمعنى لو كان بها **5 **مثلا فكلمة **IF **سيكون على الخمسة و بعد القرار ستصبح **4 **و الفرق لو بها **1 **لو العلامات سابقة، سيصبح صفر ثم نسأل هل **= **صفر أم لا لكن لو على اليمين سنسأل أولا و الإجابة لا فننقص و ننفذ **. **لاحظ أيضا أن **IF **غير معروفة بينما **if **معروفة و كل الأوامر بالأحرف الصغيرة**.*
*يلى ذلك جزء التعريفات و كما سبق مع ميكروإلكترونيكا سنحتاج تهيئة العدادات يدويا فالتعليمة **Config **غير مدعومة*
*أى أن هذا الكود التالى سيصبح كما سيلى بعد التعديل*

```
[LEFT][B]Begin:[/B]
[B]Config Timer0 = Counter , Mode = 2 , Gate = Exteral[/B]
[B]Th0 = 205 ' Auto reload[/B]
[B]Tl0 = 205[/B]
[B]Tcon = 1[/B]
[B]Enable Interrupts[/B]
[B]Enable Int0[/B]
[B]Leds = &B11011011 ' Reset All PORTS! select Small cold cycle[/B]
[B]Relays = 255[/B]
[B]Switches = 255[/B]
[B]Controls = 255[/B]
[B]On Int0 Emergency , Nosave[/B]
[B]On Timer0 Counttime[/B]
[B]Loopagain:[/B]
[B]Do[/B]
[B]Bitwait Run , Set ' Run button release[/B]
[B]If Full = 0 Then[/B]
[B]Leds = Leds Or &B00000111 : Reset Fullled[/B]
[B]Elseif Half = 0 Then[/B]
[B]Leds = Leds Or &B00000111 : Reset Halfled[/B]
[B]Elseif Small = 0 Then[/B]
[B]Leds = Leds Or &B00000111 : Reset Smallled[/B]
[B]End If[/B]


[B]If Hot = 0 Then[/B]
[B]Leds = Leds Or &B00111000 : Reset Hotled[/B]
[B]Elseif Mild = 0 Then[/B]
[B]Leds = Leds Or &B00111000 : Reset Mildled[/B]
[B]Elseif Cold = 0 Then[/B]
[B]Leds = Leds Or &B00111000 : Reset Coldled[/B]
[B]End If[/B]
[B]until Run = 0 ' Wait Run Press[/B][/LEFT]
```
*الكود السابق أصبح بعد تغيير **Enable,Config,Bitwait , Elseif **لاحظ أيضا أن كلمة **OR **و التى تعنى وظيفة **"**أو**" **المنطقية ستستبدل بالرمز **"|” **و الوظيفة **"**مع**" AND **تستبدل بالرمز **& **أما العكس **NOT **فأصبح **" ~ “ **أجل هذه العلامة التى نستخدمها لتعنى **"**تقريبا يساوى أو يساوى بالتقريب**" **و ما يزيد الأمور إرباكا أنها على مستوى البت فقط أما **XOR **فتصبح **^ **و هنا أحذر من أن هذه العلامة تعنى فى كثير من الحالات رفع للأس حيث **10^2 = 100 **و فى حساب **Boolean **تزاوج العلامات فمثلا **AND boolean **تصبح **&& **و **"**أو**" OR **تصبح **|| **و العكس **NOT **تصبح**" !” **علامة التعجب أما **XOR **فبحثت على النت ولم أجد لها جواب – أعانك الله على الحفظ*
*فى البيزك عموما هى غير مدعومة لكن فى المترجمات الخاصة الوحدات المتقدمة مثل **AVR **فالكل يقول مدعومة ولا يذكر كيف، و الأفضل عملها يدويا*

```
[LEFT][B]void main() {[/B]
[B]Begin:[/B]
[B]IE = 0B10000011 ;  //Enable T0 & INT0 external[/B]
[B]TH0 = 205 ; //Auto reload[/B]
[B]TL0 = 205 ; // Start Value[/B]
[B]TMOD = 0b00000110 ;[/B]
[B]TCON = 1 ;  // Clear All interrupts, Set INT0 Edge trigger[/B]
[B]SP = 70 ;  // Move stack away[/B]
[B]Leds = 0b11011011 ;  //Reset All PORTS! select Small cold cycle[/B]
[B]Relays = 255 ;[/B]
[B]Switches = 255 ;[/B]
[B]Controls = 255 ;[/B]
[B]EA_bit = 1 ;  // Enable Interrupts[/B]
[B]do {[/B]
[B]} while (Run = 0) ;  // Run button release[/B]
[B]Loopagain:[/B]
[B]do {[/B]
[B]if (Full = 0) {[/B]
[B]Leds = Leds | 0B00000111 ;[/B]
[B]Fullled = 0 ;[/B]
[B]}[/B]
[B]else[/B]
[B]if (Half = 0) {[/B]
[B]Leds = Leds | 0B00000111 ;[/B]
[B]Halfled = 0 ; }[/B]
[B]else[/B]
[B]if (Small = 0) {[/B]
[B]Leds = Leds | 0B00000111 ;[/B]
[B]Smallled =0 ; }[/B]


[B]if (Hot = 0) {[/B]
[B]Leds = Leds | 0B00111000 ;[/B]
[B]Hotled = 0 ;[/B]
[B]}[/B]
[B]else if (Mild = 0) {[/B]
[B]Leds = Leds | 0B00111000 ;[/B]
[B]Mildled = 0 ;[/B]
[B]}[/B]
[B]else if (Cold = 0 ) {[/B]
[B]Leds = Leds | 0B00111000 ;[/B]
[B]Coldled = 0 ;[/B]
[B]}[/B]
[B]} while ( Run = 1 ) ;  // Wait Run Press[/B]
[B]أظن أن التحويل أصبح نمطيا و تكراريا و يمكن تكملة الباقى وهو[/B]


[B]Bitwait Dooropen , Reset ' Wait Door to close[/B]
[B]Reset Wateron ' Fill with water[/B]
[B]Bitwait Waterfull , Reset ' Wait full Tank[/B]
[B]Set Wateron ' Close water Valve[/B]


[B]If Coldled = 1 Then ' not Cold then[/B]
[B]Reset Heateron ' Heater on[/B]
[B]If Mildled = 0 Then Bitwait Midtemp , Reset Else Bitwait Hitemp , Reset[/B]
[B]Set Heateron ' Turn off heater[/B]
[B]End If ' Now Start Washing[/B]


[B]If Fullled = 0 Then[/B]
[B]Runtime = 20 * 60[/B]
[B]Elseif Halfled = 0 Then[/B]
[B]Runtime = 480[/B]
[B]Else[/B]
[B]Runtime = 300[/B]
[B]End If[/B]




[B]Runmotor:[/B]
[B]Set Jobpending ' Timing flag[/B]
[B]Reset Motoron ' Start Motor[/B]
[B]Start Timer0 ' Start Timer/Counter[/B]
[B]Bitwait Jobpending , Reset ' Wait to Finish[/B]
[B]Set Motoron ' stop motor[/B]
[B]For Cntr = 1 To Rinse[/B]
[B]Reset Drainon ' Open Drain[/B]
[B]Bitwait Waterempty , Reset ' Wait Drain[/B]
[B]Set Drainon ' Close Drain[/B]
[B]Reset Wateron ' Fill again[/B]
[B]Bitwait Waterfull , Reset[/B]
[B]Set Wateron ' Close Water[/B]
[B]Runtime = 300 ' 1St Rinse[/B]
[B]Set Jobpending[/B]
[B]Reset Motoron ' Start Rinse[/B]
[B]Start Timer0 ' Start Timer[/B]
[B]Bitwait Jobpending , Reset ' Wait to Finish[/B]
[B]Set Motoron ' Stop Rinse[/B]
[B]Next[/B]


[B]Reset Drainon ' Open Drain[/B]
[B]Bitwait Waterempty , Reset ' Wait Drain[/B]
[B]Runtime = 180 ' SPIN[/B]
[B]Set Jobpending[/B]
[B]Reset Motoron ' Start Rinse[/B]
[B]Reset Run_nspin ' SPIN[/B]
[B]Start Timer0 ' Start Timer/Counter[/B]
[B]Bitwait Jobpending , Reset ' Wait to Finish[/B]


[B]Relays = 255 ' ALL OFF, INITIAL State[/B]
[B]Controls = 255[/B]


[B]Goto Loopagain[/B]


[B]End[/B]

[/LEFT]
[B]سيصبح هكذا ، نلاحظ هنا أن دورة [/B][B]do-while [/B][B]يمكن اختصارها لأمر [/B][B]while [/B][B]فقط كما سيلى بعد [/B][B]Runmotor[/B]
[B]do{[/B]
[B]} while (Dooropen = 1 ) ; // Wait Door to close[/B]
[B]Wateron = 0 ; // Fill with water[/B]
[B]do[/B][B]{[/B]
[B]} while ( Waterfull = 1 ); // Wait full Tank[/B]
[B]Wateron = 1 ; // Close water Valve[/B]


[B]if (Coldled = 1) {  // not Cold then[/B]
[B]Heateron = 0 ; }  // Heater on[/B]
[B]if (Mildled = 0) {[/B]
[B]do {[/B]
[B]} while ( Midtemp = 1 ) ; }[/B]
[B]else {[/B]
[B]do {[/B]
[B]} while ( Hitemp = 1 ) ;[/B]
[B]}[/B]
[B]Heateron = 1 ; // Now Start Washing[/B]


[B]if ( Fullled = 0 ) {[/B]
[B]Runtime = 20 * 60 ; }[/B]
[B]else  {[/B]
[B]if [/B][B]( Halfled = 0 ) {[/B]
[B]Runtime = 480 ; }[/B]
[B]else [/B][B]{[/B]
[B]Runtime = 300 ; }[/B]
[B]}[/B]

[B]// Runmotor:[/B]
[B]Jobpending = 1 ;  // Timing flag[/B]
[B]Motoron = 0 ; // Start Motor[/B]
[B]TR0_bit = 1 ; // start timer 0[/B]
[B]while ( Jobpending = 1 ) ;  // Wait to Finish[/B]
[B]Motoron = 0 ; // stop motor[/B]
[B]for [/B][B]( Cntr = 0 ; Cntr < Rinse ; Cntr++ ) {[/B]
[B]Drainon = 0 ; // Open Drain[/B]
[B]while ( Waterempty = 0 ) ;  // Wait Drain[/B]
[B]Drainon = 1 ; // Close Drain[/B]
[B]Wateron = 0 ; // Fill again[/B]
[B]while [/B][B]( Waterfull = 0 ) ; // Wait fill up[/B]
[B]Wateron = 1 ; // close water valve[/B]
[B]Runtime = 300 ; // Rinse time[/B]
[B]Jobpending = 1 ; // timer flag[/B]
[B]Motoron = 0 ; // Start Rinse[/B]
[B]TR0_bit = 1 ; // start timer 0[/B]
[B]while [/B][B]( Jobpending = 0 ) ;  // Wait to finish[/B]
[B]Motoron = 1 ; // Stop Rinse[/B]
[B]}[/B]
[B]Drainon = 0 ;  // Open Drain second cycle[/B]
[B]while ( Waterempty = 0 ) ; // Wait Drain[/B]
[B]Runtime = 180 ; // SPIN time[/B]
[B]Jobpending = 1 ; // timer flag[/B]
[B]Run_nspin = 0 ; // high speed[/B]
[B]Motoron = 0 ; // Start SPIN[/B]
[B]TR0_bit = 1 ;  // start timer 0[/B]
[B]while ( Jobpending = 1 ) ; // wait end of time[/B]
[B]Relays = 255 ; // ALL OFF, INITIAL State[/B]
[B]Controls = 255 ;[/B]
[B]goto Loopagain ;[/B]

[B]}[/B]
```
*المرة القادمة إن شاء الله سنكررها باستخدام **AVR **و لغة البيزك*


----------



## ماجد عباس محمد (13 يوليو 2018)

*الغسالة باستخدام avr و لغة البيزك*

*الغسالة باستخدام AVR و لغة البيزك:*

*سنضع الدائرة لكى نرى ما إن كنا نحتاج أى من التعديلات وهذه هى*



*أولا سنحاول الحفاظ على الهيكل العام للدائرة و نستبدل المتحكم و أول ما نلاحظه أننا استخدمنا الترانزستورات **NPN **مع الريلايات **12 **فولت لا لسبب سوى شيوع هذه الطريقة و خشيت أن أبقى على الطريقة القديمة مخافة الظن أن هذا ما يجب أن يكون بينما لك مطلق الحرية فى تبنى أى من الحلين ، و إثباتا لذلك سأبقيه مع الليدات**.*
*لهذا فكل ما نحتاجه هو تعديل أوامر التحكم فى الريلايات من **Set **إلى **RESET **و العكس بالعكس**. **و ستجد ذلك فى الكود مشروحا للتذكرة **.*
*ثانيا لم أوصل دائرة الريسيت و دائرة الكريستال لآن المتحكم يدعم الريسيت الداخلى و مذبذب م س داخلى و لك الحرية فى استخدامهما بدلا من المكونات الخارجية لتحقيق الوفر ، فقط من خيارات المبرمجة يجب أن تختار هذه الخيارات في مجموعة تسمى فيوزات من المبرمجة وليست فى البرنامج**.*
*وجب هنا إيضاح نقطة أن هناك أشياء تبرمج بالكود و أشياء تبرمج أثناء عملية البرمجة و من خلال المبرمجة ذاتها و تسمى فيوزات لآنها تبرمج مع الكود لكن فى كثير من الأحوال ستحتاج لمبرمجة توازى لإلغاء وضع هذه الفيوزات و تغييرها أما المبرمجة التوالى و التى تناسب البرمجة فى البوردة فيمكنها تفعيل الفيوزات و لكن كثيرا ما تكون غير قادرة على إرجاع هذه الفيوزات لأصلها باعتبار أنها خيارات المصمم و يفضل عدم تغييرها فى الموقع بواسطة المستخدم**.*
*هذا فى العائلتين سواء لكن الفرق الوحيد أن وضع هذه الفيوزات فى ميكروتشيب تضبطه من المترجم وهو يتولى إنشاء ما يلزم لذلك أما فى أتميل فيجب اختيار الفيوزات من واجهة المبرمجة ذاتها و ليس من المترجم**.*
*و أخيرا المقاطعات حيث يجب توصيل التايمر الخارجى للطرف المناسب وهو هنا المنفذ **B **الطرف صفر و كان عليه أحد الريلايات **WaterOn **أى فتح صمام المياه للملو و سنضطر لتوصيله لمكان آخر و نختار مثلا **PORTA.6 (**أو اختار ما يناسبك**)*
*الآن سننقل كود بيزك باسكوم **C51 **إلى باسكوم **AVR **و نرى ما يحدث ، نفتح صفحة جديدة ثم من قائمة **options **نختار **Compiler **ثم **Chip. **يفتح لنا عدة خيارات تحدد منها نوع المتحكم و تردد الكريستال و بعض الأمور الأخرى مثل لو تستخدم شاشة **LCD **أو المنفذ التسلسلى الخ ثم اضغط على زر **ADD TO CODE **فسيضيف مجموعة التعليمات السابق الحديث عنها ثم ننسخ النص السابق**.*
*أسماء المنافذ تغيرت من صفر **-1-2 **الخ إلى أحرف لذا سنغيرها إلى **PORTA,PORTB **الخ**. **أيضا كما شرحنا عن وجود **PINA **لقراءة الطرف و أخيرا **DDRA **لتحديد اتجاه المنفذ **A **و مثله لباقى المنافذ*

*مقاومة الانحياز لأعلى أو التعليق لأعلى **PULLUP **هنا عامة لكل طرف و ليست لمنفذ واحد كما فى ميكروتشيب و تصبح فاعلة بجعل الطرف **(**أو المنفذ**) **دخول ثم تكتب فيه **1 . **لاحظ أنه كدخول تقرأ منه لا أن تكتب فيه لذا هذه الكتابة تذهب لمقاومة **Pullup **و متاحة لكل الأطراف فى كل المنافذ و كل طرف يتحكم فيه على حده بهذه الطريقة**.*
*لكن ماذا لو تحسبا لظرف ما يجب ألا تتاح هذه المقاومات؟ هل سنعدل كافة المنافذ أم ماذا؟ كلا فهناك بت واحدة اسمها **PUD **اختصار **Pull Up Disable **فى مسجل اسمه **SFIOR **وهى غالبا معروفة دون الحاجة لاسم المسجل**. **وهذه البت عادة **= **صفر و عند تغييرها إلى **1 **توقف عمل كافة المقاومات فى كل المنافذ**.*

*عندما تضغط على زرار **"**صح**" **سيعترض على التعليمات الخاصة بالتايمر صفر فالقيم **TH,TL,TCON **لم تعد موجودة و تغيرت لتوسعة عمليات هذا المؤقت فقد شمل العد التصاعدى أو التنازلى و المقارنة بالصفر أو **255 **أو قيمة أخرى فى مسجل آخر باسم **OCR0 **و هذه يمكن توجيهها لتوليد موجة بتعديل عرض **PWM . *
*بيزك باسكوم لا يدعم خاصية **PWM **لتايمر صفر ذو **8 **بت لكنه يدعمها لتايمر **1 **ذو **16 **بت بصورة أشمل، لذا لو شئت فيمكنك استخدام مجموعة أوامر لتهيئه تايمر صفر لهذا الغرض **. **عموما فى هذا التطبيق سنحتاج فقط عد النبضات لذا يكفينا التنسيق الذاتى المدعم من المترجم**. **قد تكون النسخة المسجلة عدلت هذه السمة ولكنى لم اشتريها بعد**.*
*سنحذف الثلاث أسطر الخاصين بالتعليمات **TH,TL,TCON **و نستبدلها بالأمر **TIMER0=205 *
*وهكذا سيصبح البرنامج*

```
[LEFT][B][SIZE=3]$regfile = "m16adef.dat"
$crystal = 4000000
$hwstack = 40
$swstack = 16
$framesize = 32  ' DEFINITIONS


Leds Alias Porta : Relays Alias Portb : Switches Alias Portc : Controls Alias Portd
Fullled Alias Pina.0 : Halfled Alias Pina.1 : Smallled Alias Pina.2
Hotled Alias Pina.3 : Mildled Alias Pina.4 : Coldled Alias Pina.5
Wateron Alias Relays.0 : Drainon Alias Relays.1 : Heateron Alias Relays.2
Motoron Alias Relays.3 : Run_nspin Alias Relays.4 : Waterfull Alias Relays.5
Waterempty Alias Relays.6 : Dooropen Alias Relays.7 : Midtemp Alias Switches.0
Hitemp Alias Switches.1 : Cold Alias Switches.2 : Mild Alias Switches.3
Hot Alias Switches.4 : Small Alias Switches.5 : Half Alias Switches.6
Full Alias Switches.7 : Run Alias Controls.1


' VARIABLES
Dim Runtime As Word , Rinse As Byte , Cntr As Byte , Jobpending As Bit


Emergency:
Goto Begin
Counttime:
Decr Runtime
Timer0 = 205
If Runtime = 0 Then
Reset Jobpending
Stop Timer0
End If
Return


Begin:
Config Leds = Input : Config Switches = Input : Config Controls = Input
Ddrb = &B00011110
Config Timer0 = Counter , Edge = Falling
Timer0 = 205 [COLOR=#008080] ' Was Th0 = 205[/COLOR]
' Tl0 = 205
' Tcon = 1
Enable Interrupts
Enable Int0
Leds = &B11011000        [COLOR=#008080]' Reset All PORTS! select Small cold cycle[/COLOR]
Relays = &B11100000 [COLOR=#008080]    ' Set Pullups for pins5,6,7[/COLOR]
Switches = 255          [COLOR=#008080]' Writing ones to input activates Pullup resistors[/COLOR]
Controls = 255 '[COLOR=#008080] " " "[/COLOR]
On Int0 Emergency , Nosave
On Timer0 Counttime


Bitwait Run , Set  ' Run button release
Loopagain:
Do
Do
If Full = 0 Then
Leds = Leds Or &B00000111 : Reset Fullled
Elseif Half = 0 Then
Leds = Leds Or &B00000111 : Reset Halfled
Elseif Small = 0 Then
Leds = Leds Or &B00000111 : Reset Smallled
End If


If Hot = 0 Then
Leds = Leds Or &B00111000 : Reset Hotled
Elseif Mild = 0 Then
Leds = Leds Or &B00111000 : Reset Mildled
Elseif Cold = 0 Then
Leds = Leds Or &B00111000 : Reset Coldled
End If
Loop Until Run = 0 ' was If Run = 1 Then Goto Loopagain ' Wait Run Press


Bitwait Dooropen , Reset  [COLOR=#008080]' Wait Door to close[/COLOR]
Reset Wateron [COLOR=#008080]                 ' Fill with water[/COLOR]
Bitwait Waterfull , Reset [COLOR=#008080] ' Wait full Tank[/COLOR]
Set Wateron             ' Close water Valve


If Coldled = 1 Then  '[COLOR=#008080] not Cold then[/COLOR]
Set Heateron  ' was Reset Heateron [COLOR=#008080]'Heater on[/COLOR]
If Mildled = 0 Then Bitwait Midtemp , Reset Else Bitwait Hitemp , Reset
Reset Heateron  ' was Set Heateron[COLOR=#008080] ' Turn off heater[/COLOR]
End If  [COLOR=#008080]                                     ' Now Start Washing
[/COLOR]

If Fullled = 0 Then
Runtime = 20 * 60
Elseif Halfled = 0 Then
Runtime = 480
Else
Runtime = 300
End If


' Runmotor:
Set Jobpending  [COLOR=#008080]' Timing flag[/COLOR]
Set Motoron  [COLOR=#008080]' was Reset Motoron' Start Motor[/COLOR]
Start Timer0 [COLOR=#008080] ' Start Timer/Counter[/COLOR]
Bitwait Jobpending , Reset  [COLOR=#008080]' Wait to Finish[/COLOR]
Reset Motoron  [COLOR=#008080]' was Set Motoron ' stop motor[/COLOR]
For Cntr = 1 To Rinse
Set Drainon [COLOR=#008080] ' was Reset Drainon ' Open Drain[/COLOR]
Bitwait Waterempty , Reset [COLOR=#008080] ' Wait Drain[/COLOR]
Reset Drainon[COLOR=#008080]  ' was Set Drainon ' Close Drain[/COLOR]
Set Wateron[COLOR=#008080] ' was Reset Wateron ' Fill again[/COLOR]
Bitwait Waterfull , Reset
Reset Wateron [COLOR=#008080] ' was Set Wateron' Close Water[/COLOR]
Runtime = 300   [COLOR=#008080]' 1St Rinse[/COLOR]
Set Jobpending
Set Motoron           [COLOR=#008080]' was Reset Motoron' Start Rinse[/COLOR]
Start Timer0[COLOR=#008080]          ' Start Timer[/COLOR]
Bitwait Jobpending , Reset  ' Wait to Finish
Reset Motoron [COLOR=#008080] ' was Set Motoron ' Stop Rinse[/COLOR]
Next


Set Drainon [COLOR=#008080] ' was Reset Drainon ' Open Drain second cycle[/COLOR]
Bitwait Waterempty , Reset [COLOR=#008080] ' Wait Drain[/COLOR]
Runtime = 180 [COLOR=#008080] ' SPIN[/COLOR]
Set Jobpending
Set Motoron[COLOR=#008080] 'was Reset Motoron ' Start Rinse[/COLOR]
Set Run_nspin [COLOR=#008080] ' was Reset Run_nspin ' SPIN[/COLOR]
Start Timer0  [COLOR=#008080]' Start Timer/Counter[/COLOR]
Bitwait Jobpending , Reset  [COLOR=#008080]' Wait to Finish[/COLOR]


Relays = &B11100000  [COLOR=#008080]' ALL OFF, INITIAL State[/COLOR]


Loop [COLOR=#008080] ' was Goto Loopagain[/COLOR]
End[/SIZE][/B][/LEFT]
```
*نلاحظ أيضا أننا استخدمنا **Do – Loop **و **while-wend **و لم يعد لدينا أوامر **GOTO **لكنها لن تختفى فهناك حالات مثل التى فى المقاطعة صريحة ولا يحل مكانها أى أمر آخر*


*المرة القادمة إن شاء الله سنشرح الدائرة بالميكرو **C*


----------



## ماجد عباس محمد (14 يوليو 2018)

*الدائرة بلغة c*

*الدائرة بلغة C*

*كما فعلنا سننسخ البرنامج بلغة **C **لمتحكم **c51 **و نضعها فى ميكروإلكترونيكا مترجم **AVR **و نحاول الترجمة ، طبعا المشاكل و الاعتراضات أغلبها تعود لمترجمات ميكروإلكترونيكا عوضا عن اللغة فاختلافات **C **سبق تحديدها**. **سنجد اعتراضات أسماء المنافذ يلى ذلك اعتراضات تغيير التعريفات فقد كانت *

```
[LEFT][B]sbit Fullled at P0_0_bit ;[/B][/LEFT]
[B]و أصبحت [/B]
[LEFT][B]sbit Fullled at PortA.b0 ;[/B][/LEFT]
[B]
```
لذا سنضطر لتغيير كل التعريفات السابقة[/B]
*سيعترض أيضا على تعريف المقاطعة و لن تجد شرحا للمتوافر فى ملف المساعدة و لكنه فقط يقول لك تجد المتاح فى مساعد التحرير حيث تكتب **IVT **ثم تضغط **CNTRL+Space **تظهر لك نافذة تختار منها أنواع المقاطعة المتاحة لذلك سنختار مرة مقاطعة **Timer0 **و مرة المقاطعة الخارجية**.*
*أيضا أمر **ajmp **أصبح **Jmp **فقط من تغيرات لغة الأسيمبلى كما أن أسماء المسجلات للعدادات قد اختلفت لذا سنستبدل تعليماتها بالأمر **TCNT0 = 205. **الآن لم يعد لدينا **Start timer, Stop Timer , Config Timer **كما فى باسكوم لذا سنضطر لفهم المتحكم أكثر لكى نعيد تهيئته *
*العداد تايمر صفر يعتمد على المسجل **TCCR0 **و ألذى يحتوى على **4 **مجموعات لمهام عدة لذا قمت بتلوين كل مجموعة لتسهيل التتبع**. **أيضا تحت الخانة نجد **W=Write **أى كتابة فقط **R=Read **أى قراءة فقط **R/W=Read Write **قراءة ز كتابة ثم تحتها نجد قيمة البدء إما **0 **أو **1 **أو **X **أى غير محددة
*




*البت رقم **7 **و اسمها **FOC0 **اختصار **Force Out Compare **تجعل نتيجة المقارنة تحدث فورا و هى لا تعمل فى حال نظام **PWM*
*البت **6 **و **3 **باسم **WGM00,WGM02 **لاحظ عدم التجاور وهما بمعنى **Waveform Generator Mode **يحددان النسق ألذى يعمل به فلو **00 **أى صفر يكون النسق العادى ولو ثنائى **01 **أى **= 1 **يكون النسق تعديل عرض النبضة مع تصحيح الوجه **PWM phase correct **ولو **10 **أى **=2 **تعمل بنظام **CTC **أى **Clear Timer on Compare Match **أى يصفر العدان عند تطابق العد، أما لو ثنائى **11 **أى **= 3 **يكون النسق **Fast PWM **أى تعديل عرض النبضة السريع**.*
*البت رقم **4 **و رقم **5 **باسم **COM00,COM01 **أى **Compare Output Match Mode **فلو يساويان صفر تكون الأداء العادى للعداد أما الحالات الثلاث الباقية فلها وظائف تتغير بحسب ما إن كان **WGM **السابقة قد حددت**PWM **أو **CTC **أو **Fast PWM*
*الثلاثة بت **CS00,CS01,CS02 **تحدد مصدر القدح*
*000 **تعنى بدون مصدر وبذلك يوقف المؤقت ، لو **001 **أى **= **واحد تأخذ من النبضات الداخلية لوحدة **I/O **بدون تقسيم ، ولو **010 **أى **2 **تقسم على **8 **ولو **011 **أى ثلاثة تقسم على **64 **ولو **100 **أى **4 **تقسم على **256 **ولو **101 **أى حمسة تقسم على **1024 **ولو **110 **أى سته تأخذ من الخارج أى الطرف **T0 **الحافة هابطة ولو **7 **أى **111 **يأخذ من الخارج ذات الطرف **T0 **الحافة الصاعدة**. **و بذلك نوقف التايمر بجعلها صفر *
*المطلوب الآن أن نضع فيه صفر ليتوقف ثم نضع فيه **111 **أى **7 **ليعمل فى النسق العادى بحافة صاعدة أو **6 **لحافة هابطة*

*رجاء لا تسألنى لماذا أفضل باسكوم عن ميكروإلكترونيكا **!!!*


*المقاطعة :*

*كان فى **C51 **عدد **8 **خانات لكل مقاطعة تنفذ فيها شيئ ما أو تنتقل أما هنا فلكل واحد **2 **بايت فقط ولا تسأل لماذا فقد أصبح لديك **21 **مصدر للمقاطعات المختلفة منها مثلا لكل تايمر عدد من المقاطعات واحد عند بلوغ العد الأقصى وواحد عند تساوى العد العلوى وآخر للعد السفلى الخ لذا فليس أمامك سوى الانتقال ما لم تكن المصادر المجاورة غير مستخدمة *
*أيضا كنتيجة لذلك لم يعد هناك مسجل واحد يكقى هذا العدد لذا تمت إضافة المقاطعة العامة فى مسجل الحالة **Status register **اختصارا **SREG **وهى البت رقم **7 **ولها أمرين بالأسيمبلى هما **SEI بمعنى Set Interrupts **و الأمر **CLI بمعنى Clear Interrupts **وهى تعطل مع المقاطعة و فى نهاية كود الخدمة و بسبب تعليمه **RETI **تعود للإتاحة مرة أخرى أو ما كانت عليه قبل المقاطعة ، كما يمكنك إتاحة المقاطعة داخل كود الخدمة بالأمر السابق لو شئت **. **هناك أيضا بت لكل من باقى المقاطعات ولكنها موزعة على مسجلات عدة مرتبطة بالوظيفة فستجد مع المؤقت إتاحة مقاطعته و هكذا**. **أعلم أنك تقول هذا أمر شاق ولا أستطيع مجادلتك فى هذا لكن هذا ما يجعل باسكوم أسهل باستخدام أمر **Config **ما لم تريد معرفة كافة التفاصيل و تتحكم به لأقصى حد و تتعمق فى الاحتراف فلا بأس يمكنك فعل ذلك باستخدام أى مترجم**.*
*بالنسبة للمقاطعة الخارجية نجد المسجل **MCUCR **أى **MCU Control Register **حيث **MCU = Micro Control Unit **يختص الجزء الأيمن منه بهذه المقاطعة و الأيسر فى وضع الكمون **Sleep **حيث عندما لا نحتاج نشاطه يدخل فى مرحلة كمون لتوفير الطاقة لحين حدوث مقاطعة أو ريست ، و له **7 **أوضاع تحددها **SM0,SM1,SM2 **أما **SE **فهى عامة بمعنى تنفيذ الخيار أو تعطيله للتأكد من أن الدخول فى هذا النمط بأمر المبرمج فقط و الأنماط هى، لو صفر يكون نمط **Idle **و لو ثنائى **001 **أى **1 **نمط تقليل ضوضاء للمحول ألتماثلى رقمى ولو **010 **أى **2 **يكون نمط **Power Down **و لو **011 **أى **3 **نمط توفير الطاقة و لو **4 **أو **5 **فغير موظفه ولو **110 **أى **6 **يكون وضع **Standby ,**ولو **111 **أى **7 **يكون **extended standby **وكلها تفرق فى أى الوظائف متاحة و ما يمكنه إيقاظ المتحكم**.*




*الجزء الأيمن للمقاطعة الخارجية رقم **1 **و البت**3 **و البت **2 **باسم **ISC11,ISC10 **بمعنى **Interrupt Sense **يحددان كيفية الاستجابة فلو كانا صفر فالطرف **INT1 **يستجيب للمستوى صفر ولو كانا ثنائى **01 **أى **= 1 **فيستجيب لأى تغيير و إن كانا ثنائى **10 **أى **= 2 **فالاستجابة للحافة الهابطة و إن كانا ثنائى **11 **أى **3 **تكون للحافة الصاعدة*
*البت صفر و البت **1 **باسم **ISC01,ISC00 **يعنيان نفس السلوك لمدخل **INT0 *
*عرفنا كيف نهيئ تايمر صفر و الدخول **INT0 **بقى أن نفعل المقاطعات*




*لدينا مسجل باسم **General Interrupt Control Register **أو مسجل التحكم العام فى المقاطعة و اختصارا **GICR **فيه البت **6 **للمقاطعة **INT0 **و البت **7 **للمقاطعة **INT1 **و البت **5 **للمقاطعة **INT2 **و وضع **1 **فى أى منها يفعل المقاطعة طبقا للضبط السابق**. **نلاحظ هنا أن المقاطعة ستحدث حتى لو كان الطرف خرج و ذلك إتاحة مقاطعة بالكود أى **Software interrupt *
*و لدينا المسجل **TIMSK-Timer-Counter Interrupt Mask Register **وهو يتيح المقاطعة*

*فالبت صفر باسم **TOIE0 **تتيح المقاطعة **OV **أى عندما يصل العد إلى **255 **ثم يقلب لصفر أما البت رقم **1 **باسم **OCIE0 **فهى تتيح المقاطعة عندما يساوى العد تلك القيمة السابق حفظها فى مسجل باسم **OCR0 **أى **Output Compare Register **للتايمر صفر*





*و بهذا يمكننا أن نستخدم الخاصية الأولى و نعيد العد مرة أخرى فى العداد كما كان أو نضع فى **OCR0 **قيمة ما و لتكن **50 **و نعد صعودا حتى تحدث المقاطعة لتساوى العد فنصفر العداد مرة أخرى*
*باقى المسجل لإتاحة مقاطعات مختلفة للتايمر **1 **و التايمر **2 **فى المتحكم*
*المرة القادمة إن شاء الله نكمل البرنامج*


----------



## ماجد عباس محمد (15 يوليو 2018)

*كود البرنامج*
*مما سبق سنستبدل تشغيل تايمر صفر بالكود **TCCR0=6 **أو **7 **حسب الخافة هابطة أم صاعدة **(**هنا لا فرق**) **و إيقافه **TCCR0=0 *
*لإتاحة المقاطعة الخارجية **GICR.6=1 **أو **INT0 = 1 **وللأسف ميكروإلكترونيكا لا يقبل **INT0 = 1 **لذا سنستخدم **GICR.6=1 **و للتهيئه **MCUCR=2 **للحافة الهابطة و لإتاحة تايمر صفر نستخدم **TOIE0 = 1 **فى المسجل **TIMSK **و ميكروإلكترونيكا لا يقبل اسم البت ولذا نستخدم **TIMSK=1 **اسم المسجل و بالصدفة لا نحتاج لتفعيل أى بت أخرى فيه**.*
*سيصبح الكود*

```
[LEFT][B]// DEFINITIONS[/B]
[B]char Leds at PortA ;[/B]
[B]char Relays at PortB ;[/B]
[B]char Switches at Portc ;[/B]
[B]char Controls at Portd ;[/B]
[B]sbit Fullled at PortA.b0 ;[/B]
[B]sbit Halfled at PortA.b1 ;[/B]
[B]sbit Smallled at PortA.B2 ;[/B]
[B]sbit Hotled at PortA.b3 ;[/B]
[B]sbit Mildled at PortA.b4 ;[/B]
[B]sbit Coldled at PortA.b5 ;[/B]
[B]sbit Wateron at PortA.b6 ;[/B]


[B]sbit Drainon at Portb.b1 ;[/B]
[B]sbit Heateron at Portb.b2 ;[/B]
[B]sbit Motoron at Portb.b3 ;[/B]
[B]sbit Run_nspin at Portb.b4 ;[/B]
[B]sbit Waterfull at Portb.b5 ;[/B]
[B]sbit Waterempty at Portb.b6 ;[/B]
[B]sbit Dooropen at Portb.b7 ;[/B]


[B]sbit Midtemp at PortC.b0 ;[/B]
[B]sbit Hitemp at PortC.b1 ;[/B]
[B]sbit Cold at PortC.b2 ;[/B]
[B]sbit Mild at PortC.b3 ;[/B]
[B]sbit Hot at PortC.b4 ;[/B]
[B]sbit Small at PortC.b5 ;[/B]
[B]sbit Half at PortC.b6 ;[/B]
[B]sbit Full at PortC.b7 ;[/B]

[B]sbit Run at PortD.b1 ;[/B]

[B]bit Jobpending ;[/B]
[B]unsigned short Rinse ;[/B]
[B]unsigned short Cntr ;[/B]
[B]unsigned Runtime ;[/B]


[B]void External_Interrupt() org IVT_ADDR_INT0 {[/B]
[B]asm jmp 0 ;[/B]
[B]}[/B]


[B]void Timer0_Interrupt() org IVT_ADDR_TIMER0_OVF {[/B]
[B]TCNT0 = 205 ;[/B]
[B]if ( --Runtime = 0 ){  [COLOR=#008080]                // end of time[/COLOR][/B]
[B]Jobpending = 0 ;         [COLOR=#008080]               // set flag[/COLOR][/B]
[B]TCCR0 = 0 ;                  [COLOR=#008080]              // TR0_bit = 0 ; // stop timer 0[/COLOR][/B]
[B]}[/B]
[B]}[/B]


[B]void main() {[/B]
[B]Begin:[/B]
[B]Sreg.b7 = 1 ;              [COLOR=#008080]         // was EA_bit = 1 ; // Enable Interrupts[/COLOR][/B]
[B]gicr.b6 = 1 ;        [COLOR=#008080]       // was IE = 0B10000011 ; //Enable T0 & INT0 external[/COLOR][/B][COLOR=#008080]
[/COLOR][B]mcucr = 2 ;               [COLOR=#008080] // Falling Edge trigger[/COLOR][/B]
[B]TIMSK = 1 ;           [COLOR=#008080]    // enable Timer0 over flow interrupt[/COLOR][/B]
[B]TCNT0 = 205;    [/B][COLOR=#008080]// TH0 = 205 ; //Auto reload TL0 = 205 ; // Start Value
// TMOD = 0b00000110 ; TCON = 1 ;   // Clr All interrupts, Set INT0 Edge trigger
// SP = 70 ;                       //Move stack away[/COLOR]
[B]ddra = 255 ;[/B]
[B]DDRB = 0b11111000 ;[/B]
[B]DDRC = 255 ;[/B]
[B]ddrd = 0b00000011 ;[/B]
[B]Leds = 0b11011000 ;      [COLOR=#008080]  //Reset All PORTS! select Small cold cycle[/COLOR][/B]
[B]Relays = 0B11100000 ;[/B]
[B]Switches = 255 ;     [COLOR=#008080]         // pullup enable[/COLOR][/B]
[B]Controls = 255 ;[/B]


[B]do {[/B]
[B]} while (Run = 0) ;        [COLOR=#008080]  // Run button release[/COLOR][/B]
[B]Loopagain:[/B]
[B]do {[/B]
[B]do {[/B]
[B]if (Full = 0) {[/B]
[B]Leds = Leds | 0B00000111 ;[/B]
[B]Fullled = 0 ;[/B]
[B]}[/B]
[B]else[/B]
[B]if (Half = 0) {[/B]
[B]Leds = Leds | 0B00000111 ;[/B]
[B]Halfled = 0 ; }[/B]
[B]else[/B]
[B]if (Small = 0) {[/B]
[B]Leds = Leds | 0B00000111 ;[/B]
[B]Smallled =0 ; }[/B]


[B]if (Hot = 0) {[/B]
[B]Leds = Leds | 0B00111000 ;[/B]
[B]Hotled = 0 ;[/B]
[B]}[/B]
[B]else if (Mild = 0) {[/B]
[B]Leds = Leds | 0B00111000 ;[/B]
[B]Mildled = 0 ;[/B]
[B]}[/B]
[B]else if (Cold = 0 ) {[/B]
[B]Leds = Leds | 0B00111000 ;[/B]
[B]Coldled = 0 ;[/B]
[B]}[/B]
[B]} while ( Run = 1 ) ;     [COLOR=#008080]             // Wait Run Press[/COLOR][/B]


[B]do{[/B]
[B]} while (Dooropen = 1 ) ;   [COLOR=#008080]        // Wait Door to close[/COLOR][/B]
[B]Wateron = 0 ;    [COLOR=#008080]                      // Fill with water[/COLOR][/B]
[B]do{[/B]
[B]} while ( Waterfull = 1 );      [COLOR=#008080] // Wait full Tank[/COLOR][/B]
[B]Wateron = 1 ;         [COLOR=#008080]         // Close water Valve[/COLOR][/B]


[B]if (Coldled = 1) {            [COLOR=#008080]        // not Cold then[/COLOR][/B]
[B]Heateron = 0 ; }              [COLOR=#008080]      // Heater on[/COLOR][/B][COLOR=#008080]
[/COLOR][B]if (Mildled = 0) {[/B]
[B]do {[/B]
[B]} while ( Midtemp = 1 ) ; }[/B]
[B]else {[/B]
[B]do {[/B]
[B]} while ( Hitemp = 1 ) ;[/B]
[B]}[/B]
[B]Heateron = 1 ;               [COLOR=#008080]          // Now Start Washing[/COLOR][/B]


[B]if ( Fullled = 0 ) {[/B]
[B]Runtime = 20 * 60 ; }[/B]
[B]else {[/B]
[B]if ( Halfled = 0 ) {[/B]
[B]Runtime = 480 ; }[/B]
[B]else {[/B]
[B]Runtime = 300 ; }[/B]
[B]}[/B]


[B][COLOR=#008080]//           [/COLOR]           Runmotor:[/B]
[B]Jobpending = 1 ;      [COLOR=#008080]      // Timing flag[/COLOR][/B]
[B]Motoron = 0 ;       [COLOR=#008080]           // Start Motor[/COLOR][/B]
[B]TCCR0 = 6 ;         [COLOR=#008080]           // was TR0_bit = 1 ; // start timer 0 falling edge[/COLOR][/B]
[B]while ( Jobpending = 1 ) ;      [COLOR=#008080]   // Wait to Finish[/COLOR][/B]
[B]Motoron = 0 ;                            [COLOR=#008080] // stop motor[/COLOR][/B]
[B]for ( Cntr = 0 ; Cntr < Rinse ; Cntr++ ) {[/B]
[B]Drainon = 0 ;              [COLOR=#008080]                  // Open Drain[/COLOR][/B]
[B]while ( Waterempty = 0 ) ;  [COLOR=#008080]        // Wait Drain[/COLOR][/B]
[B]Drainon = 1 ;   [COLOR=#008080]                              // Close Drain[/COLOR][/B]
[B]Wateron = 0 ;    [COLOR=#008080]                            // Fill again[/COLOR][/B]
[B]while ( Waterfull = 0 ) ;[COLOR=#008080]                // Wait fill up[/COLOR][/B]
[B]Wateron = 1 ;          [COLOR=#008080]                         // close water valve[/COLOR][/B]
[B]Runtime = 300 ;      [COLOR=#008080]                        // Rinse time[/COLOR][/B]
[B]Jobpending = 1 ;     [COLOR=#008080]                       // timer flag[/COLOR][/B]
[B]Motoron = 0 ;        [COLOR=#008080]                         // Start Rinse[/COLOR][/B]
[B]TCCR0 = 6 ;                  [COLOR=#008080]                  // was TR0_bit = 1 ; // start timer 0[/COLOR][/B]
[B]while ( Jobpending = 0 ) ; [COLOR=#008080]             // Wait to finish[/COLOR][/B]
[B]Motoron = 1 ;                     [COLOR=#008080]              // Stop Rinse[/COLOR][/B]
[B]}[/B]
[B]Drainon = 0 ;                        [COLOR=#008080]           // Open Drain second cycle[/COLOR][/B]
[B]while ( Waterempty = 0 ) ;    [COLOR=#008080]           // Wait Drain[/COLOR][/B]
[B]Runtime = 180 ;                     [COLOR=#008080]           // SPIN time[/COLOR][/B]
[B]Jobpending = 1 ;                      [COLOR=#008080]         // timer flag[/COLOR][/B]
[B]Run_nspin = 0 ;                        [COLOR=#008080]         // high speed[/COLOR][/B]
[B]Motoron = 0 ;                            [COLOR=#008080]          // Start SPIN[/COLOR][/B]
[B]TCCR0 = 6 ;                           [COLOR=#008080]             // was TR0_bit = 1 ; // start timer 0[/COLOR][/B]
[B]while ( Jobpending = 1 ) ;    [COLOR=#008080]             // wait end of time[/COLOR][/B]
[B]Relays = 0B11100000 ;        [COLOR=#008080]             // ALL OFF, INITIAL State[/COLOR][/B]
[B]Controls = 255 ;[/B]
[B]} while (1) ;                                      [COLOR=#008080] // was goto Loopagain[/COLOR] ;[/B]


[B]}[/B]
[B]و أيضا استخدمنا [/B][B]DO [/B][B]لتحل محل [/B][B]goto [/B][B]و الكود أعتقد لا مشكلة فيه[/B][/LEFT]
```

*المرة القادمة إن شاء الله سنكررها بالميكروتشيب **PIC16C877A **و اللغتان أيضا*


----------



## ماجد عباس محمد (16 يوليو 2018)

*الغسالة باستخدام PIC16F877A و لغة البيزك:*

*للأسف فشركة باسكوم لا تدعم ميكروتشيب ولم أجد مترجم بالبيزك لميكروتشيب فلا مفر من ميكروإلكترونيكا **.*
*نلاحظ تقاطع منفذى**C,D **لذا أمامنا طريقتين للتوصيل ، إما نوصل كل منفذ على مكوناته كما سبق و نتحمل التقاطع فى التوصيل هكذا*




*أو نوصل كل مجموعة مكونات للأطراف المجاورة و نتلافى التقاطعات فى البرنامج هكذا*




*غالبا لم يلحظ هذا الفرق كثير ممن صمموا دوائر لإعتمادهم على بروتس ألذى يضع كل منفذ منظم و مرتب ويوهم المستخدم أن الأمور منسقة و سهلة لكنى أفضل أن ارسم المكون مقارب للحقيقة تجنبا للمشاكل لاحقا**. **لتسهيل البرمجة سنختار الحل الأول**.*
*كما سبق أن ناقشنا أننا سنتجنب منفذ **A **لكونه يحتاج تهيئة لكى يصبح رقمى بدلا من تماثلى و هذه التهيئة ليست صعبة وهى فى الداتاشيت لكن فى مجال المقارنة ستعطى ظن أن الأمور أكثر تعقيدا**..*
*نلاحظ أيضا أن منفذ **A **ثمانى أطراف منها سبعة فقط متصلة بالتماثلى بينما الطرف الوحيد **RA4 **لا يتصل بها و بدلا من ذلك متصل بالعداد **Timer0 **و ألذى نستخدمه لحساب الوقت ، وهذا ما فعلناه*
*أيضا هناك نقطة يمكن ذكرها وهى ستخفض عدد الأطراف المطلوبة أن طرف **Emergency **حقيقة لا يحتاج أن يتصل بالمتحكم فلم يتعرض له البرنامج سابقا و لكن فقط استفدنا بالمقاومة الداخلية على الطرف، لا بأس هنا نضع المقاومة و نوفر الطرف و ليس هذا خيارا لكن المنفذ **B **وحده هو المزود بهذه المقاومات و قد استنفذ سبعة منه لسبعة أزرار و الثامن متصل بالمقاطعة الخارجية**.*
*هنا يجب أن نجعل هذه المقاومات الداخلية **"**تعليق لأعلى **" Pullup **فاعلة بت**صفير البت **RBPU **من **(OPTION_REG.7). **فهى تفصل مع إعادة التشغيل**.*
*هنا أيضا نقطة نفضل مناقشتها وهى أن هذا المنفذ **B **له خاصية فريدة على الأطراف من **4 : 7 **وهى **interrupt on-change **يمكن تفعيلها لكن أولا هم على ذات المنفذ فلا شيء سيضاف و الثانية أنها تسبب مقاطعة عند التغيير و ليس عند الانتقال من **1 **إلى صفر أو العكس لذا يجب الحيطة حتى لا تسبب مقاطعة عند أول النبضة و آخر عند نهايتها فكلاهما تغيير**.*
*الآن سنعيد التعريفات طبقا للدائرة المعدلة و نظرا لاستخدامنا الدائرة التقليدية للريلاى سنغير تفعيله من صفر إلى **1 **و سنبقى الحساسات و الأزرار كما هى**.*
*قبل أن نناقش البرنامج فهناك مترجم آخر جيد اسمه **Great Cow Basic **ويحتوى محرر بيزك قوى جدا و نسخة أخرى للمبتدئ رسومية أى تجد به المربعات و المثلثات و المعين و بها التعليمات **IF **و غيره يمكن وضعها و رسم البرنامج أشبه ما يكون بالسلمى لوحدات **PLC **وهو يترجم بعد ذلك و هو يصلح لبيك و أتميل **AVR **وهذا رابطه*
*http://www.greatcowbasic.com*
*http://www.greatcowbasic.com/gcb.html*
*ورابط الشرح و المساعدة*
*http://gcbasic.sourceforge.net/help/*
*ولكن للأسف فلم أجربه بعد*
*كما سبق الشرح مع **C51 **سنحتاج لتايمر صفر و تجهيز المقاطعة و للأسف ميكروإلكترونيكا لا تقدم أمر مختصر مثل باسكوم **Config **لذا نحتاج لدراسة كل جزئية منها لتهيئتها كما يجب و طبعا من الداتاشيت و لكنها ترشدنا لملف آخر أعم لكل عائلة **PIC16 **وبه تفاصيل أكثر وهو معروف باسم **DS33023 **وها هو رابطه*
*DS33023 Mid Range up counters.pdf*
*يعتمد التايمر صفر على مسجل اسمه **Option_Reg **وبه **8 **بت وهى أيضا مكتوبة فى خانة و فوقها **R/W **لتحدد ما إن كانت كتابة أم قراءة أم كلاهما ثم **-1 **أى حالة البدء **= 1 **كالآتى*




*البت **7 **المسؤولة عن مقاومات **Pullup **للمنفذ **B **و لا تسألنى ما علاقتها بالتايمر صفر فالإجابة الوحيدة لدى **"**أنهم جيران على ذات السيليكون**" *
*البت **6 **تحدد استجابة المقاطعة الخارجية للحافة الهابطة **(**صفر**) **أم الصاعدة **(1) **و هنا لا تفرق سوى أن لا يسبب كلاهما مقاطعة*
*البت **5 T0CS **تحدد عمله لو **= **صفر يكون تايمر و يعد تعليماته الداخلية **(**ربع تردد الكريستال**) **أو **=1 **يعد خارجيا من الطرف **RA4*
*البت **4 **تحدد استجابة التايمر للحافة الهابطة **(1) **أم الصاعدة **(**صفر**) **و هنا لا تفرق سوى أن لا يسبب كلاهما عد*
*البت **3 **تحدد القاسم السابق **(**العداد السابق **) Prescaler **متصل بالعداد **(**صفر**) **أم بالحراسة **WDT **لو **=1*
*نسبة التقسيم للعداد السابق تخص الثلاث بت الباقية*
*أما المقاطعة فهى تعتمد على المسجل **INTCON **وهذه مكوناته
*




*البت **7 **إتاحة الكل*
*البت **6 **إتاحة المقاطعة من الدوائر المحيطة وهى الدوائر التى تؤدى وظائف إضافية مثل **I2C, USB, **التسلسلى الخ**.*
*البت **5 **تايمر **T01E **إتاحة التايمر صفر*
*البت **4 INTE **إتاحة المقاطعة الخارجية*
*البت **3 **إتاحة المقاطعة عند تغير بت من **RB4:RB7 *
*البت **2 **هى علم حدوث مقاطعة من تايمر **1 **أى **T01F*
*البت **1 **علم حدوث مقاطعة خارجية*
*البت صفر علم حدوث مقاطعة من تغير المنفذ **RB4:RB7 **و يجب البحث أيها*
*مع ملاحظة أن البت رقم **5 **يتيح لك تشغيل و إيقاف المؤقت لذا سنستخدمها**. **الآن يمكننا أن نقول أن البرنامج يمكن كتابه الجزء التمهيدى هكذا *


```
[LEFT][SIZE=3]program WM16
' Declarations section 
dim Switches as byte at PORTB
dim Leds as byte at Portc
Dim Relays As byte at Portd 

dim Fullled as sbit at Portc.0
dim Halfled as sbit at Portc.1
dim Smallled as sbit at Portc.2
dim Hotled as sbit at Portc.3
dim Mildled as sbit at Portc.4
dim Coldled as sbit at Portc.5
dim Wateron as sbit at Portc.6
dim Drainon as sbit at Portc.7


dim Hitemp as sbit at Portd.0
dim Midtemp as sbit at Portd.1
dim Waterfull as sbit at Portd.2
dim Waterempty as sbit at Portd.3
dim as sbit at Portd.4
dim Run_nspin as sbit at Portd.5
dim Motoron as sbit at Portd.6
dim Heateron as sbit at Portd.7


dim Dooropen as sbit at Portb.0
dim Run as sbit at Portb.1
dim Cold as sbit at Portb.2
dim Mild as sbit at Portb.3
dim Hot as sbit at Portb.4
dim SmallLoad as sbit at Portb.5
dim Half as sbit at Portb.6
dim Full as sbit at Portb.7


dim Jobpending as bit
' VARIABLES
dim Runtime as word
Dim Rinse , Cntr As Byte


sub procedure interrupt
if TestBit(INTCON, TMR0IF) = 1 then
dec (Runtime)
If Runtime = 0 Then
Jobpending = 0
ClearBit(INTCON, TMR0IF)  ' Interrupt Timer0 Flag
ClearBit(INTCON, TMR0IE)  ' Stop Interrupt Timer0
End If
' ClearBit is realised as an inline function, and may be called from within an interrupt
' else
' if TestBit(INTCON, RBIF) = 1 then
' ClearBit(INTCON,RBIF)
' setbit (Config.bits , wdte)
' WDTE = 1 
' end if
' end if
end sub


main:   ' Main program


Begin:[/SIZE][/LEFT]
```
*سنلاحظ هنا أن تعريف **sbit **سيتطلب أن تحدد لها مكان بكلمة **at **لذا لن نستطيع استخدامها كمتغير مستقل فنضطر لاستخدام **bit **بدلا منها ، ثم يلى التعريفات مشكلة المقاطعة و لذا نكتب العنوان **sub procedure interrupt **و بداخله نفحص بالأمر **TestBit **و بين قوسين اسم المسجل ثم اسم البت أو رقمها ولا أدرى لماذا فلا يتكرر اسم بت مرتين إطلاقا فمثلا **TMR0IF **تعنى تايمر صفر **Interrupt Flag **أو علم المقاطعة فكيف يتكرر؟ على أى حال هذا هو ميكروإلكترونيكا فإن كانت **= 1 **ننفذ كود المقاطعة وهو كما سبق ننقص الزمن بواحد فإن بلغ الصفر نصفر علم الزمن ثم نعود و إلا لو كان مقاطعة خارجية سنضطر لعمل ريست ولا يوجد أمر لهذا، أيضا ميكروإلكترونيكا لا تقبل أمر **Goto **داخل المقاطعة لأن العنوان بعدها ولذا لا يمكن عمل ريست بهذا المترجم لذا نفكر فى عداد الحراسة **WDT **وهو للأسف يحتاج تهيئة فى البرمجة ولا يتاح و لا يوقف بحسب الحاجة و يجب شرحه مع باقى المتحكمات بلا حاجة حقيقة لاستخدامه لهذا لا يمكن تنفيذ الطوارئ بهذه الطريقة و سنلغيها و نستخدم ريست مباشر من طرف المتحكم وهذا موضوعنا القادم إن شاء الله*


----------



## ماجد عباس محمد (17 يوليو 2018)

*معالجة RESET فى البرنامج خارجيا*

*سنجرى تعديل طفيف فى الدائرة لتصبح*



*وهو أن نجعل خرج دائرة **4071 **يدخل مباشرة على طرف **Reset **فى المتحكم ويمكن تطبيق هذه الفكرة على أى متحكم شرط أن نجعل طرف الريست فاعلا ففى بعض المتحكمات يمكن جعل الطرف ريست غير فاعل و يتحول لطرف دخول أو خروج *
*لاحظ أن وضع الخرج **= 0 **كان لتفعيل الريلاى و أصبح **= 1 **و العكس بالعكس*
*تركت الأمر السابق فى باسكوم كتعليق بجوار الأمر الجديد و المقابل له من ميكروإلكترونيكا و لهذا ستجد ما يبدو كخطأ أو تعارض مثل*
*MotorOn = 0 ' Set Motoron ' Stop Rinse*
*DrainOn = 1 ' Reset Drainon ' Open Drain second cycle*
*و لكنه صحيح فهو يعنى أن الأمر المستخدم مثلا **MotorOn = 0 **و كان فى البرنامج السابق **C51 **باسكوم بنص **' Set Motoron **و الهدف منه إيقاف الشطف **' Stop Rinse **و هذا لأننا بدلنا وضع الريلاى فأصبح **1 **للتفعيل و صفر للقفل أو الفصل أو الإيقاف الخ فالأمر إذن أول تعليق هو ما كان فى البرنامج السابق و المطلوب تعديله*
*يبقى أن نكمل البرنامج كما سبق فيصبح*


```
[LEFT][B][SIZE=3]program WM16
' Declarations section 
dim Switches as byte at PORTB
dim Leds as byte at Portc
Dim Relays As byte at Portd 

dim Fullled as sbit at Portc.0
dim Halfled as sbit at Portc.1
dim Smallled as sbit at Portc.2
dim Hotled as sbit at Portc.3
dim Mildled as sbit at Portc.4
dim Coldled as sbit at Portc.5
dim Wateron as sbit at Portc.6
dim Drainon as sbit at Portc.7

dim Hitemp as sbit at Portd.0
dim Midtemp as sbit at Portd.1
dim Waterfull as sbit at Portd.2
dim Waterempty as sbit at Portd.3
dim Run_nspin as sbit at Portd.5
dim Motoron as sbit at Portd.6
dim Heateron as sbit at Portd.7

dim Dooropen as sbit at Portb.0
dim Run as sbit at Portb.1
dim Cold as sbit at Portb.2
dim Mild as sbit at Portb.3
dim Hot as sbit at Portb.4
dim SmallLoad as sbit at Portb.5
dim Half as sbit at Portb.6
dim Full as sbit at Portb.7

dim Jobpending as bit
' VARIABLES
dim Runtime as word
Dim Rinse , Cntr As Byte

sub procedure interrupt
if TestBit(INTCON, TMR0IF) = 1 then
dec (Runtime)
If Runtime = 0 Then
Jobpending = 0
ClearBit(INTCON, TMR0IF)  [COLOR=#008080]' Clear flag[/COLOR]
ClearBit(INTCON, TMR0Ie)  [COLOR=#008080]' Disable timer[/COLOR]
' clearbit(Pie1,TMR1iE)
End If
ClearBit(INTCON, TMR0IF)  [COLOR=#008080]' clear Interrupt Timer0 to receive another
' ClearBit is realised as an inline function, and may be called from within an interrupt[/COLOR]
end if
end sub


main: [COLOR=#008080] ' Main program[/COLOR]
Begin:
option_Reg = %00111111 [COLOR=#008080] ' setting RB Pull up clearing bit RBPU (OPTION_REG.7).
' INTEDG = falling ,TOCS counter not timer, Count Falling Edge Prescale to WDT , ratio
[/COLOR]intcon = %10100000 [COLOR=#008080]' Interrupt Control GIE All,Peie edge falling, T01E Enable[/COLOR]
[COLOR=#008080]' INTE External disable , T01 Ov flag,intf ext flag , RBIF port change flag
[/COLOR]TRISB = 255
TRISC = 0  [COLOR=#008080]' out[/COLOR]
PORTC = %00100100 [COLOR=#008080] 'small Cold[/COLOR]
TRISD = %00011111 [COLOR=#008080] ' some in and some out[/COLOR]
Heateron = 0
Motoron = 0
Run_nspin = 0
ClearBit(INTCON, TMR0IF)  [COLOR=#008080]' Interrupt Timer0 Flag[/COLOR]
ClearBit(INTCON, TMR0IE) [COLOR=#008080] ' Stop Interrupt Timer0[/COLOR]
while true [COLOR=#008080]' Loopagain[/COLOR]:


while Run = 1[COLOR=#008080]  ' Bitwait Run , Set[/COLOR]
wend [COLOR=#008080] ' Run button release[/COLOR]
do
If Full = 0 Then
Leds = Leds Or %00000111
Fullled = 0
Else
if Half = 0 Then
Leds = Leds Or %00000111
Halfled = 0
Else
if SmallLoad = 0 Then
Leds = Leds Or %00000111
Smallled = 0
end if
end if
End If


If Hot = 0 Then
Leds = Leds Or %00111000
Hotled = 0
Else
if Mild = 0 Then
Leds = Leds Or %00111000
Mildled = 0
Else
if Cold = 0 Then
Leds = Leds Or %00111000
Coldled = 0
end if
end if
End If

loop until run = 0  [COLOR=#008080]' Wait Run Press[/COLOR]
while DoorOpen = 1  [COLOR=#008080]' Bitwait Dooropen , Reset ' Wait Door to close
[/COLOR]wend
WaterOn = 1 [COLOR=#008080]' Set Wateron Open Water Valve[/COLOR]
while Waterfull = 1  [COLOR=#008080]' Bitwait Waterfull , Reset ' Wait full Tank
[/COLOR]wend
WaterOn = 0  [COLOR=#008080]' ReSet Wateron ' Close water Valve[/COLOR]


If Coldled = 1 Then  [COLOR=#008080]' not Cold then[/COLOR]
Heateron = 1 [COLOR=#008080] ' Heater on[/COLOR]
If Mildled = 0 Then
while Midtemp = 1 [COLOR=#008080]' Bitwait Midtemp , Reset[/COLOR]
wend
Else
while Hitemp = 1 [COLOR=#008080]' Bitwait Hitemp , Reset[/COLOR]
wend
end if
HeaterOn = 0 [COLOR=#008080]' Set Heateron ' Turn off heater[/COLOR]
End If [COLOR=#008080]' Now Start Washing[/COLOR]

If Fullled = 0 Then
Runtime = 20 * 60
else ' Elseif Halfled = 0 Then
if Halfled = 0 Then
Runtime = 480
Else
Runtime = 300
end if  [COLOR=#008080]' because elseif in not supported in MikroElektronika producta[/COLOR]
End If


[COLOR=#008080]' Runmotor:
[/COLOR]Jobpending = 1  [COLOR=#008080]' Set Jobpending ' Timing flag[/COLOR]
Motoron = 1 [COLOR=#008080]' Motoron = 0 ' Start Motor[/COLOR]
TMR0 = 205[COLOR=#008080] ' Load Tomer0[/COLOR]
SetBit(INTCON, TMR0IE) [COLOR=#008080] ' enable Timer0[/COLOR]
setBit(INTCON, TMR0IF)[COLOR=#008080] ' Interrupt Timer0 Flag[/COLOR]
while jobPending = 1  [COLOR=#008080]' Bitwait Jobpending , Reset ' Wait to Finish[/COLOR]
wend
motorOn = 0 [COLOR=#008080]' Set Motoron ' stop motor[/COLOR]


For Cntr = 1 To Rinse
Drainon = 1  [COLOR=#008080]' Reset Drainon ' Open Drain[/COLOR]
while Waterempty = 1[COLOR=#008080] ' Bitwait Waterempty , Reset ' Wait Drain[/COLOR]
wend
DrainOn = 0[COLOR=#008080] ' Set Drainon ' Close Drain[/COLOR]
WaterOn = 1 [COLOR=#008080] ' Reset Wateron ' Fill again[/COLOR]
while WaterFull = 1  [COLOR=#008080]' Bitwait Waterfull , Reset[/COLOR]
wend
WaterOn = 0 [COLOR=#008080] ' Set Wateron ' Close Water[/COLOR]
Runtime = 300[COLOR=#008080] ' Rinse Time[/COLOR]
TMR0 = 205
Jobpending = 1 [COLOR=#008080]' Set Jobpending[/COLOR]
Motoron =1 [COLOR=#008080]' Reset Motoron ' Start Rinse[/COLOR]
SetBit(INTCON, TMR0IE)  [COLOR=#008080]' enable Timer0 ' Start Timer0 ' Start Timer[/COLOR]
setBit(INTCON, TMR0IF)  [COLOR=#008080]' Interrupt Timer0 Flag[/COLOR]
while Jobpending = 1[COLOR=#008080] ' Bitwait Jobpending , Reset ' Wait to Finish[/COLOR]
wend
Motoron = 0  [COLOR=#008080]' Set Motoron ' Stop Rinse[/COLOR]
Next cntr

MotorOn = 0  [COLOR=#008080]' Set Motoron ' Stop Rinse[/COLOR]
DrainOn = 1[COLOR=#008080] ' Reset Drainon ' Open Drain second cycle[/COLOR]
while Waterempty = 1[COLOR=#008080]  ' Bitwait Waterempty , Reset ' Wait Drain[/COLOR]
wend
Runtime = 180[COLOR=#008080]  ' SPIN[/COLOR]
JobPending = 1 [COLOR=#008080] ' Set Jobpending [/COLOR]
motorOn = 1 [COLOR=#008080] ' Reset Motoron ' Start Spin[/COLOR]
Run_nSpin = 1  [COLOR=#008080]' Reset Run_nspin ' SPIN[/COLOR]
TMR0 = 205
Jobpending = 1
SetBit(INTCON, TMR0IE)[COLOR=#008080] ' enable Timer0 ' Start Timer0[/COLOR]
setBit(INTCON, TMR0IF)  [COLOR=#008080]' Interrupt Timer0 Flag ' Start Timer0 ' Start [/COLOR]Timer/Counter
while JobPending = 1 [COLOR=#008080] ' Bitwait Jobpending , Reset ' Wait to Finish[/COLOR]
wend
Relays = 255[COLOR=#008080]  ' ALL OFF, INITIAL State[/COLOR]

wend [COLOR=#008080] ' Goto Loopagain[/COLOR]
end.[/SIZE][/B][/LEFT]
```
*المرة القادمة إن شاء الله نستخدم **PIC18 *


----------



## ماجد عباس محمد (18 يوليو 2018)

*الغسالة باستخدام PIC18F و لغة البيزك*

*قد نفكر فى استخدام **4552 **لكن استخدام وحدة **usb **سيضع تغذية **usb **على أحد الأطراف المستخدمة كما أننا لا نحتاج هذه الخاصية الآن ، لذا سنستخدم هنا ميكرو **PIC18F452 **لأن كل أطرافه مطابقة للسابق و لهذا سنجد أن ذات البرنامج فيما عدا بعض المسميات و المسجلات تحتاج تعديل*



*ما زالت مقاومات التعليق **Pull Up **فقط لمنفذ **B **و لتفعيلها نحتاج المسجل **INTCON2 **وهذا تكوينه*




*البت رقم **7 **لإتاحة أو فقص مقاومات التعليق لأعلى للمنفذ **B **و فى البدء **=1 **أى غير متاحة و يجب تصفيرها فى دائرتنا*
*البت رقم **6 **و **5 **و **4 **لحافة المقاطعات الخارجية صفر ،**1**، **2 **و أى منهم **=1 **تعنى حافة صاعدة و صفر حافة هابطة**.*
*البت رقم **2 **باسم **TMR0IP **هى أولوية مقاطعة تايمر صفر لزيادة العد حيث **1 **تعنى أولوية عالية و صفر أولوية منخفضة*
*البت رقم **0 **أولوية مقاطعة تغيير حالة أطراف المنفذ **B **حيث **1 **تعنى أولوية عالية*
*الآن نحتاج لتفعيل المقاطعة العامة و كذا المنفذ تايمر صفر و لم نعد نحتاج لمدخل **INT0 .*





*البت **7 **باسم **GIE **وهى المقاطعة العامة وهى عندما تكون **= **صفر توقف إتاحة المقاطعة أما لو **=1 **فبحسب البت **RCON.7 فى المسجل **RCON**و المسماة **IPEN **لو **= **صفر تتيح كل المقاطعات المتاحة أما لو **IPEN = 1 **فستتاح كل المقاطعات ذات الأولوية العالية فقط**.*
*البت رقم **6 **باسم **PEIE **فعندما تكون **= **صفر تمنع إتاحة كافة مقاطعات الدوائر المحيطية **(**التسلسلى بأنواعه الخ**) . **أما لو **=1 **فبحسب البت **RCON.7 **و المسماة **IPEN **لو **= 1 **تتيح كل المقاطعات المحيطة ذات الأولوية المنخفضة أما لو **IPEN = **صفر فستتاح كل المقاطعات المسموح بها من الدوائر المحيطية **. *
*البت رقم **5 **باسم **TMR0IE **فهى لو **=1 **تتيح مقاطعة اكتمال العد للتايمر صفر **Timer0 OV*
*البت رقم **4 **باسم **INT01E **لو **=1 **تتيح المقاطعة الخارجية **INT0 *
*البت رقم **3 **باسم **RBIE **هى **PortB Interrupt Enable **لإتاحة المقاطعة من تغير حالة أطراف منفذ **B **لو **=1*
*البت رقم **2 **باسم **TMR0IF **هى علامة **Flag **المقاطعة الفعلية لتايمر صفر*
*البت رقم **1 **باسم **INT0IF **هى علامة **Flag **المقاطعة الخارجية الفعلية رقم صفر **INT0*
*البت رقم صفر باسم **RBIF **هى علامة **Flag **المقاطعة الفعلية لتغير حالة طرف منفذ **B*
*لاحظ المربع الأحمر بأعلى الصورة و التى تقول يجب على المبرمج التأكد من تصفير العلامات **Flags **قبل حدوث المقاطعة ليتمكن من استقبال التالية **(**وهذا عكس أتميل التى تتغير آليا بمجرد الاستجابة للمقاطعة بالكود و توقف باقى المقاطعات حتى نهاية الخدمة و العودة آليا أو أتاحها المبرمج بالكود**)*
*و أخيرا تشغيل و إيقاف التايمر صفر من المسجل **T0CON **أو تحكم تايمر صفر*




*بت **7 **باسم **TMR0ON **هى تشغيل **= 1 **و إيقاف التايمر **= **صفر*
*بت **6 **باسم **T08BIT **اختيار **8 **بت أم **16 **و لو **1 **يكون **8 **بت*
*بت **5 **باسم **TOCS **وهى اختيار مصدر العد ولو **1 **يكون خارجيا*
*بت **4 **باسم **TOSE **للحافة ولو **1 **للحافة الهابطة*
*بت **3 **باسم **PSA **لتحديد المقسم السابق **Prescaler **ولو **1 **تعنى غير مستخدم*
*الباقيات لنسبة التقسيم من صفر تساوى **1:2 **إلى **111 **أى ثنائى سبعة لنسبة **1:256*

*و أخيرا القيمة التى تضاف للتايمر تحتاج تعديل فقد تغير اسمه من **TMR0 **إلى **TMR0L*
*و اصبح الكود هكذا
*

```
[LEFT][B]program WM18[/B]
[COLOR=#008080][B]' Declarations section[/B]
[/COLOR][B]dim Switches as byte at PORTB[/B]
[B]dim Leds as byte at Portc[/B]
[B]Dim Relays As byte at Portd[/B]

[B]dim Fullled as sbit at Portc.0[/B]
[B]dim Halfled as sbit at Portc.1[/B]
[B]dim Smallled as sbit at Portc.2[/B]
[B]dim Hotled as sbit at Portc.3[/B]
[B]dim Mildled as sbit at Portc.4[/B]
[B]dim Coldled as sbit at Portc.5[/B]
[B]dim Wateron as sbit at Portc.6[/B]
[B]dim Drainon as sbit at Portc.7[/B]

[B]dim Hitemp as sbit at Portd.0[/B]
[B]dim Midtemp as sbit at Portd.1[/B]
[B]dim Waterfull as sbit at Portd.2[/B]
[B]dim Waterempty as sbit at Portd.3[/B]
[B]dim Run_nspin as sbit at Portd.5[/B]
[B]dim Motoron as sbit at Portd.6[/B]
[B]dim Heateron as sbit at Portd.7[/B]

[B]dim Dooropen as sbit at Portb.0[/B]
[B]dim Run as sbit at Portb.1[/B]
[B]dim Cold as sbit at Portb.2[/B]
[B]dim Mild as sbit at Portb.3[/B]
[B]dim Hot as sbit at Portb.4[/B]
[B]dim SmallLoad as sbit at Portb.5[/B]
[B]dim Half as sbit at Portb.6[/B]
[B]dim Full as sbit at Portb.7[/B]
[COLOR=#008080][B]تشغيل و إيقاف التايمر[/B]
[/COLOR][B]dim Jobpending as bit[/B]
[B]' [COLOR=#008080]VARIABLES[/COLOR][/B]
[B]dim Runtime as word[/B]
[B]Dim Rinse , Cntr As Byte[/B]

[B]sub procedure interrupt[/B]
[B]if TestBit(INTCON, TMR0IF) = 1 then[/B]
[B]dec (Runtime)[/B]
[B]If Runtime = 0 Then[/B]
[B]Jobpending = 0[/B]
[B]ClearBit(INTCON, TMR0IF) [COLOR=#008080]' Clear flag[/COLOR][/B]
[B]ClearBit(INTCON, TMR0Ie)  [COLOR=#008080]' Disable timer[/COLOR][/B]
[B]Clearbit (T0Con, TMR0ON)  [COLOR=#008080]' stop timer[/COLOR][/B]
[B]End If[/B]
[B]ClearBit(INTCON, TMR0IF)  [COLOR=#008080]' clear Interrupt Timer0 to receive another[/COLOR][/B][COLOR=#008080]
[B]' ClearBit is realised as an inline function, and may be called from within an interrupt[/B][/COLOR]
[B]end if[/B]
[B]end sub[/B]

[B]main:[COLOR=#008080]  ' Main program[/COLOR][/B]
[B]Begin:[/B]
[B]INTCON2 = 0  [COLOR=#008080]' setting RB Pull up clearing bit RBPU and all falling edge.[/COLOR][/B]
[B]intcon = %10100000  [COLOR=#008080]' Interrupt Control GIE All,Peie edge falling, T01E Enable[/COLOR][/B][COLOR=#008080]
[B]' INTE External disable , T01 Ov flag,intf ext flag , RBIF port change flag[/B][/COLOR]
[B]TRISB = 255[/B]
[B]TRISC = 0  [COLOR=#008080]' out[/COLOR][/B]
[B]PORTC = %00100100[COLOR=#008080]  'small Cold[/COLOR][/B]
[B]TRISD = %00011111[COLOR=#008080]  ' some in and some out[/COLOR][/B]
[B]Heateron = 0[/B]
[B]Motoron = 0[/B]
[B]Run_nspin = 0[/B]
[B]ClearBit(INTCON, TMR0IF) [COLOR=#008080]' Interrupt Timer0 Flag[/COLOR][/B]
[B]ClearBit(INTCON, TMR0IE)  [COLOR=#008080]' Stop Interrupt Timer0[/COLOR][/B]
[B]Cleartbit (T0Con, TMR0ON)[COLOR=#008080]  ' stop timer[/COLOR][/B]
[B]while true     [COLOR=#008080]                       ' Loopagain:[/COLOR][/B]
[B]while Run = 1[COLOR=#008080]  ' Bitwait Run , Set[/COLOR][/B]
[B]wend          [COLOR=#008080]     ' Run button release[/COLOR][/B]
[B]do[/B]
[B]If Full = 0 Then[/B]
[B]Leds = Leds Or %00000111[/B]
[B]Fullled = 0[/B]
[B]Else[/B]
[B]if Half = 0 Then[/B]
[B]Leds = Leds Or %00000111[/B]
[B]Halfled = 0[/B]
[B]Else[/B]
[B]if SmallLoad = 0 Then[/B]
[B]Leds = Leds Or %00000111[/B]
[B]Smallled = 0[/B]
[B]end if[/B]
[B]end if[/B]
[B]End If[/B]

[B]If Hot = 0 Then[/B]
[B]Leds = Leds Or %00111000[/B]
[B]Hotled = 0[/B]
[B]Else[/B]
[B]if Mild = 0 Then[/B]
[B]Leds = Leds Or %00111000[/B]
[B]Mildled = 0[/B]
[B]Else[/B]
[B]if Cold = 0 Then[/B]
[B]Leds = Leds Or %00111000[/B]
[B]Coldled = 0[/B]
[B]end if[/B]
[B]end if[/B]
[B]End If[/B]

[B]loop until run = 0[COLOR=#008080]  ' Wait Run Press[/COLOR][/B]
[B]while DoorOpen = 1  [COLOR=#008080]' Bitwait Dooropen , Reset ' Wait Door to close[/COLOR][/B]
[B]wend[/B]
[B]WaterOn = 1[COLOR=#008080] ' Set Wateron Open Water Valve[/COLOR][/B]
[B]while Waterfull = 1  [COLOR=#008080]' Bitwait Waterfull , Reset ' Wait full Tank[/COLOR][/B]
[B]wend[/B]
[B]WaterOn = 0[COLOR=#008080]  ' ReSet Wateron ' Close water Valve[/COLOR][/B]

[B]If Coldled = 1 Then[COLOR=#008080]  ' not Cold then[/COLOR][/B]
[B]Heateron = 1[COLOR=#008080]  ' Heater on[/COLOR][/B]
[B]If Mildled = 0 Then[/B]
[B]while Midtemp = 1[COLOR=#008080]  ' Bitwait Midtemp , Reset[/COLOR][/B]
[B]wend[/B]
[B]Else[/B]
[B]while Hitemp = 1[COLOR=#008080] ' Bitwait Hitemp , Reset[/COLOR][/B]
[B]wend[/B]
[B]end if[/B]
[B]HeaterOn = 0  [COLOR=#008080]' Set Heateron ' Turn off heater[/COLOR][/B]
[B]End If  [/B][COLOR=#008080][B]  ' Now Start Washing[/B][/COLOR]

[B]If Fullled = 0 Then[/B]
[B]Runtime = 20 * 60[/B]
[B]else ' Elseif Halfled = 0 Then[/B]
[B]if Halfled = 0 Then[/B]
[B]Runtime = 480[/B]
[B]Else[/B]
[B]Runtime = 300[/B]
[B]end if [COLOR=#008080]     ' because elseif in not supported in MikroElektronika producta[/COLOR][/B]
[B]End If[/B]

[COLOR=#008080][B]' Runmotor:[/B]
[/COLOR][B]Jobpending = 1[COLOR=#008080]  ' Set Jobpending ' Timing flag[/COLOR][/B]
[B]Motoron = 1 [COLOR=#008080]                 ' Motoron = 0 ' Start Motor[/COLOR][/B]
[B]TMR0L = 205[COLOR=#008080]              ' Load Tomer0[/COLOR][/B]
[B]SetBit(INTCON, TMR0IE)[COLOR=#008080] ' enable Timer0[/COLOR][/B]
[B]setBit(INTCON, TMR0IF)  [COLOR=#008080]' Interrupt Timer0 Flag[/COLOR][/B]
[B]setbit (T0Con, TMR0ON)  [COLOR=#008080]' start timer [/COLOR][/B]
[B]while jobPending = 1[COLOR=#008080]  ' Bitwait Jobpending , Reset ' Wait to Finish[/COLOR][/B]
[B]wend[/B]
[B]motorOn = 0  [COLOR=#008080]' Set Motoron ' stop motor[/COLOR][/B]

[B]For Cntr = 1 To Rinse[/B]
[B]Drainon = 1  [COLOR=#008080]' Reset Drainon ' Open Drain[/COLOR][/B]
[B]while Waterempty = 1[COLOR=#008080]  ' Bitwait Waterempty , Reset ' Wait Drain[/COLOR][/B]
[B]wend[/B]
[B]DrainOn = 0 [COLOR=#008080]' Set Drainon ' Close Drain[/COLOR][/B]
[B]WaterOn = 1[COLOR=#008080]  ' Reset Wateron ' Fill again[/COLOR][/B]
[B]while WaterFull = 1[COLOR=#008080] ' Bitwait Waterfull , Reset[/COLOR][/B]
[B]wend[/B]
[B]WaterOn = 0            [COLOR=#008080]' Set Wateron ' Close Water[/COLOR][/B]
[B]Runtime = 300 [COLOR=#008080]     ' Rinse Time[/COLOR][/B]
[B]TMR0L = 205[/B]
[B]Jobpending = 1[COLOR=#008080]            ' Set Jobpending[/COLOR][/B]
[B]Motoron =1     [COLOR=#008080]        ' Reset Motoron ' Start Rinse[/COLOR][/B]
[B]SetBit(INTCON, TMR0IE)[COLOR=#008080]  ' enable Timer0 ' Start Timer0 ' Start Timer[/COLOR][/B]
[B]setBit(INTCON, TMR0IF)[COLOR=#008080] ' Interrupt Timer0 Flag[/COLOR][/B]
[B]setbit (T0Con, TMR0ON)  [COLOR=#008080]' start timer [/COLOR][/B]
[B]while Jobpending = 1 [COLOR=#008080]' Bitwait Jobpending , Reset ' Wait to Finish[/COLOR][/B]
[B]wend[/B]
[B]Motoron = 0[COLOR=#008080]  ' Set Motoron ' Stop Rinse[/COLOR][/B]
[B]Next cntr[/B]

[B]MotorOn = 0[COLOR=#008080]  ' Set Motoron ' Stop Rinse[/COLOR][/B]
[B]DrainOn = 1[COLOR=#008080]  ' Reset Drainon ' Open Drain second cycle[/COLOR][/B]
[B]while Waterempty = 1[COLOR=#008080]  ' Bitwait Waterempty , Reset ' Wait Drain[/COLOR][/B]
[B]wend[/B]
[B]Runtime = 180[COLOR=#008080]  ' SPIN[/COLOR][/B]
[B]JobPending = 1[COLOR=#008080]  ' Set Jobpending[/COLOR][/B]
[B]motorOn = 1[COLOR=#008080]  ' Reset Motoron ' Start Spin[/COLOR][/B]
[B]Run_nSpin = 1[COLOR=#008080] ' Reset Run_nspin ' SPIN[/COLOR][/B]
[B]TMR0L = 205[/B]
[B]Jobpending = 1[/B]
[B]SetBit(INTCON, TMR0IE)  [COLOR=#008080]' enable Timer0 ' Start Timer0[/COLOR][/B]
[B]setBit(INTCON, TMR0IF)[COLOR=#008080]  ' Interrupt Timer0 Flag ' Start Timer0 [/COLOR] [/B]
[B]setbit (T0Con, TMR0ON)  [COLOR=#008080]' start timer [/COLOR][/B]
[B]while JobPending = 1[COLOR=#008080]  ' Bitwait Jobpending , Reset ' Wait to Finish[/COLOR][/B]
[B]wend[/B]
[B]Relays = 255[COLOR=#008080]  ' ALL OFF, INITIAL State[/COLOR][/B]
[B]wend[COLOR=#008080]  ' Goto Loopagain[/COLOR][/B]

[B]end.[/B][/LEFT]
```
*المرة القادمة إن شاء الله نعيدهم بلغة **C*


----------



## ماجد عباس محمد (19 يوليو 2018)

*الغسالةباستخدام PIC16F877Aولغة C:*

*طبعاالدائرة لم تتغير و الكود لم يتغير أيضا و شركة المترجم هى ميكروإلكترونيكا، لذاسننسخ البرنامج من مترجم البيزك لمترجم اللغة **C **و من قائمة تحرير نستخدم **"**تغيير**" Replace **ونستبدل علامة التعليق فى البيزك **"' “ **بعلامة السى و لا بأس أيضا من إضافة الخاتمة المقدسة **"; “ **وإن كان هذا خطر فهناك حالات لا يجوز فيها ذلك لذا سنفضل إضافتها يدويا و نضيف الأقواس العادية و المعوجة فيصبح البرنامج هكذا

*

```
[LEFT][COLOR=#000000] [COLOR=#009900]  [FONT=Times New Roman][B]//program WM16       Declarations section[/B][/FONT][/COLOR][/COLOR]

[COLOR=#000000] [FONT=Times New Roman][B]charSwitches  at PORTB ;[/B][/FONT][/COLOR]
[COLOR=#000000] [FONT=Times New Roman][B]charLeds at Portc ;[/B][/FONT][/COLOR]
[COLOR=#000000] [FONT=Times New Roman][B]charRelays  at Portd ;[/B][/FONT][/COLOR]

[COLOR=#000000]  [FONT=Times New Roman][B]sbitFullled at Rc0_bit ;[/B][/FONT][/COLOR]
[COLOR=#000000]  [FONT=Times New Roman][B]sbitHalfled at rc1_bit ;[/B][/FONT][/COLOR]
[COLOR=#000000]  [FONT=Times New Roman][B]sbitSmallled at rc2_bit ;[/B][/FONT][/COLOR]
[COLOR=#000000]  [FONT=Times New Roman][B]sbitHotled at rc3_bit ;[/B][/FONT][/COLOR]
[COLOR=#000000]  [FONT=Times New Roman][B]sbitMildled at rc4_bit ;[/B][/FONT][/COLOR]
[COLOR=#000000]  [FONT=Times New Roman][B]sbitColdled at rc5_bit ;[/B][/FONT][/COLOR]
[COLOR=#000000]  [FONT=Times New Roman][B]sbitWateron at rc6_bit ;[/B][/FONT][/COLOR]
[COLOR=#000000]  [FONT=Times New Roman][B]sbitDrainon at rc7_bit ;[/B][/FONT][/COLOR]

[COLOR=#000000]  [FONT=Times New Roman][B]sbitHitemP at rd0_bit ;[/B][/FONT][/COLOR]
[COLOR=#000000]  [FONT=Times New Roman][B]sbitMidtemP at rd1_bit ;[/B][/FONT][/COLOR]
[COLOR=#000000]  [FONT=Times New Roman][B]sbitWaterfull at rd2_bit ;[/B][/FONT][/COLOR]
[COLOR=#000000]  [FONT=Times New Roman][B]sbitWaterempty at rd3_bit ;[/B][/FONT][/COLOR]
[COLOR=#000000]  [FONT=Times New Roman][B]sbitRun_nspin at rd5_bit ;[/B][/FONT][/COLOR]
[COLOR=#000000]  [FONT=Times New Roman][B]sbitMotoron at rd6_bit ;[/B][/FONT][/COLOR]
[COLOR=#000000]  [FONT=Times New Roman][B]sbitHeateron at rd7_bit ;[/B][/FONT][/COLOR]

[COLOR=#000000] [FONT=Times New Roman][B]sbitDooropen at rb0_bit ;[/B][/FONT][/COLOR]
[COLOR=#000000] [FONT=Times New Roman][B]sbitRun at rb1_bit ;[/B][/FONT][/COLOR]
[COLOR=#000000] [FONT=Times New Roman][B]sbitCold at rb2_bit ;[/B][/FONT][/COLOR]
[COLOR=#000000] [FONT=Times New Roman][B]sbitMild at rb3_bit ;[/B][/FONT][/COLOR]
[COLOR=#000000] [FONT=Times New Roman][B]sbitHot at rb4_bit ;[/B][/FONT][/COLOR]
[COLOR=#000000] [FONT=Times New Roman][B]sbitSmallLoad at rb5_bit ;[/B][/FONT][/COLOR]
[COLOR=#000000] [FONT=Times New Roman][B]sbitHalf at rb6_bit ;[/B][/FONT][/COLOR]
[COLOR=#000000] [FONT=Times New Roman][B]sbitFull at rb7_bit ;[/B][/FONT][/COLOR]

[COLOR=#000000] [FONT=Times New Roman][B]bitJobpending ;[/B][/FONT][/COLOR]

[COLOR=#009900][FONT=Times New Roman][B]//VARIABLES[/B][/FONT][/COLOR]
[COLOR=#000000]  [FONT=Times New Roman][B]unsignedint Runtime ;[/B][/FONT][/COLOR]
[COLOR=#000000]  [FONT=Times New Roman][B]charRinse , Cntr ;[/B][/FONT][/COLOR]

[COLOR=#000000][FONT=Times New Roman][B]voidTimer0_int() iv 0x0004 ics ICS_AUTO {[/B][/FONT][/COLOR]
[COLOR=#000000]   [FONT=Times New Roman][B]if(INTCON.TMR0IF =1 ) {[/B][/FONT][/COLOR]
[COLOR=#000000]       [FONT=Times New Roman][B][COLOR=#009900]// dec (Runtime)[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]         [FONT=Times New Roman][B]if(--Runtime = 0 ) {[/B][/FONT][/COLOR]
[COLOR=#000000]           [FONT=Times New Roman][B]Jobpending= 0   ;[/B][/FONT][/COLOR]
[COLOR=#000000]           [FONT=Times New Roman][B]INTCON.TMR0IF=0  ; [COLOR=#009900]  // ClearBit(INTCON, TMR0IF) ;   //Clear flag[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]           [FONT=Times New Roman][B]INTCON.TMR0Ie= 0 ;   [COLOR=#009900]//  ClearBit(INTCON, TMR0Ie)      //Disable timer[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]            [FONT=Times New Roman][B]}                   [COLOR=#009900] // End If[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]    [FONT=Times New Roman][B]INTCON.TMR0IF=0  ;   [COLOR=#009900]// ClearBit(INTCON, TMR0IF)  //  clearInterrupt Timer0 to[/COLOR] [/B][/FONT][/COLOR][COLOR=#008080][FONT=Times New Roman][B]receiveanother[/B][/FONT][/COLOR]
[COLOR=#000000]  [FONT=Times New Roman][B][COLOR=#009900]//ClearBit is realised as an inline function, and may be called fromwithin an interrupt[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]  [FONT=Times New Roman][B]}[/B][/FONT][/COLOR]
[COLOR=#000000][FONT=Times New Roman][B]}[/B][/FONT][/COLOR]

[COLOR=#000000][FONT=Times New Roman][B]voidmain() {                                    [COLOR=#009900] //  Main program[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]    [FONT=Times New Roman][B]OPTION_REG=  0b00111111 ;   [COLOR=#009900] // setting RB Pull upclearing bit  RBPU [/COLOR][COLOR=#009900](OPTION_REG.7).[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]  [FONT=Times New Roman][B][COLOR=#009900]//INTEDG = falling ,TOCS counter not timer, Count Falling Edge Prescaleto WDT , ratio[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]    [FONT=Times New Roman][B]INTCON= 0B10100000 ; [COLOR=#009900] // Interrupt Control GIEAll,Peie edge falling, T01E Enable[/COLOR][/B][/FONT][/COLOR]
[COLOR=#009900]      [FONT=Times New Roman][B]//INTE External disable , T01 Ov flag,intf ext flag , RBIF port changeflag[/B][/FONT][/COLOR]
[COLOR=#000000]    [FONT=Times New Roman][B]TRISB= 255 ;[/B][/FONT][/COLOR]
[COLOR=#000000]    [FONT=Times New Roman][B]TRISC= 0   ;                  [COLOR=#009900]//  out[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]    [FONT=Times New Roman][B]Leds= 0b00100100  ;          [COLOR=#009900] //small Cold[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]    [FONT=Times New Roman][B]TRISD= 0b00011111  ;         [COLOR=#009900] // some in and someout[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]    [FONT=Times New Roman][B]Relays= 0b00001111 ;[/B][/FONT][/COLOR]
[COLOR=#000000]    [FONT=Times New Roman][B]Heateron= 0  ;[/B][/FONT][/COLOR]
[COLOR=#000000]    [FONT=Times New Roman][B]Motoron= 0  ;[/B][/FONT][/COLOR]
[COLOR=#000000]    [FONT=Times New Roman][B]Run_nspin=  0 ;[/B][/FONT][/COLOR]
[COLOR=#000000]    [FONT=Times New Roman][B]INTCON.TMR0IF=0  ;   [COLOR=#009900]// ClearBit(INTCON, TMR0IF) //Interrupt Timer0 Flag[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]    [FONT=Times New Roman][B]INTCON.TMR0IE=0  ;  [COLOR=#009900] // ClearBit(INTCON, TMR0IE) // StopInterrupt Timer0[/COLOR][/B][/FONT][/COLOR]

[COLOR=#000000]    [FONT=Times New Roman][B]while(Run = 1 )    [COLOR=#009900]//   Bitwait Run , Set[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]              [FONT=Times New Roman][B]{}      [COLOR=#009900]   // wend          // Run button release[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]  [FONT=Times New Roman][B]while(1) {     [COLOR=#009900]  //  Loopagain:[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]     [FONT=Times New Roman][B]do{[/B][/FONT][/COLOR]
[COLOR=#000000]        [FONT=Times New Roman][B]if(Full = 0)      {            [COLOR=#009900]    //  Then[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]           [FONT=Times New Roman][B]Leds= Leds | 0B00000111 ;    [COLOR=#009900]   // Leds OR 00000111[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]          [FONT=Times New Roman][B]Fullled = 0  ; }[/B][/FONT][/COLOR]
[COLOR=#000000]        [FONT=Times New Roman][B]elseif ( Half = 0) {               [COLOR=#009900]  // Then[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]           [FONT=Times New Roman][B]Leds= Leds | 0b00000111  ; [COLOR=#009900]  // Leds = Leds Or%00000111[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]          [FONT=Times New Roman][B]Halfled= 0 ;    }[/B][/FONT][/COLOR]
[COLOR=#000000]        [FONT=Times New Roman][B]else if ( SmallLoad = 0 ){     [COLOR=#009900] //  Then[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]           [FONT=Times New Roman][B]Leds= Leds | 0b00000111 ;    [COLOR=#009900]//Leds = Leds Or%00000111[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]          [FONT=Times New Roman][B]Smallled= 0  ;         }    [COLOR=#009900] // end if[/COLOR][/B][/FONT][/COLOR]

[COLOR=#000000]        [FONT=Times New Roman][B]if( Hot = 0)   {               [COLOR=#009900] // Then[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]           [FONT=Times New Roman][B]Leds= Leds | 0B00111000   ; [COLOR=#009900] //Leds = Leds Or%00111000[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]           [FONT=Times New Roman][B]Hotled= 0 ;  }[/B][/FONT][/COLOR]
[COLOR=#000000]        [FONT=Times New Roman][B]elseif (Mild = 0)  {         [COLOR=#009900]   //  Then[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]           [FONT=Times New Roman][B]Leds= Leds | 0b00111000 ;   [COLOR=#009900] //Leds = Leds Or0b00111000[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]          [FONT=Times New Roman][B]Mildled= 0 ;     }[/B][/FONT][/COLOR]
[COLOR=#000000]        [FONT=Times New Roman][B]elseif (Cold = 0)              [COLOR=#009900] //  Then[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]              [FONT=Times New Roman][B]{ Leds = Leds | 0b00111000 ;[/B][/FONT][/COLOR]
[COLOR=#000000]                [FONT=Times New Roman][B]Coldled= 0 ;[/B][/FONT][/COLOR]
[COLOR=#000000]               [FONT=Times New Roman][B]}                      [COLOR=#009900]  // end if[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]      [FONT=Times New Roman][B]}while (Run = 1) ;            [COLOR=#009900]    // loop untilrun = 0 // Wait Run Press[/COLOR][/B][/FONT][/COLOR]

[COLOR=#000000]    [FONT=Times New Roman][B]while( DoorOpen = 1 ) ;    [COLOR=#009900] // Bitwait Dooropen ,Reset // Wait Door to close[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]    [FONT=Times New Roman][B]WaterOn= 1  ;              [COLOR=#009900] // Set Wateron  Open WaterValve[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]    [FONT=Times New Roman][B]while(Waterfull = 1 ) ;     [COLOR=#009900]// Bitwait Waterfull ,Reset  // Wait full Tank[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]    [FONT=Times New Roman][B]WaterOn= 0   ;             [COLOR=#009900] // ReSet Wateron     //Close water Valve[/COLOR][/B][/FONT][/COLOR]

[COLOR=#000000]   [FONT=Times New Roman][B]if(Coldled = 1)      [COLOR=#009900]  // Then  // not Cold then[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]     [FONT=Times New Roman][B]{Heateron  = 1 ;            [COLOR=#009900]// Heater on[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]         [FONT=Times New Roman][B]if(Mildled = 0)        [COLOR=#009900] // Then[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]             [FONT=Times New Roman][B]{[/B][/FONT][/COLOR]
[COLOR=#000000]            [FONT=Times New Roman][B]while( Midtemp = 1 ); [COLOR=#009900] // Bitwait Midtemp , Reset[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]             [FONT=Times New Roman][B]}                    [COLOR=#009900] // wend[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]           [FONT=Times New Roman][B]else[/B][/FONT][/COLOR]
[COLOR=#000000]             [FONT=Times New Roman][B]{while  (Hitemp = 1 ) ;   [COLOR=#009900]//  Bitwait Hitemp ,Reset[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]             [FONT=Times New Roman][B]}                     [COLOR=#009900]//   wend[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]                                 [COLOR=#009900]  [FONT=Times New Roman][B]//endif[/B][/FONT][/COLOR][/COLOR]
[COLOR=#000000]         [FONT=Times New Roman][B]HeaterOn=  0 ;           [COLOR=#009900]  // reSet Heateron     //Turn off heate[/COLOR]r[/B][/FONT][/COLOR]
[COLOR=#000000]      [FONT=Times New Roman][B]}                           [COLOR=#009900]  // End if   // NowStart Washing[/COLOR][/B][/FONT][/COLOR]

[COLOR=#000000] [FONT=Times New Roman][B]if(Fullled = 0)                [COLOR=#009900]    // Then[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]     [FONT=Times New Roman][B]Runtime= 20 * 60 ;[/B][/FONT][/COLOR]
[COLOR=#000000] [FONT=Times New Roman][B]elseif (Halfled = 0)       [COLOR=#009900]// Elseif Halfled = 0Then[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]        [FONT=Times New Roman][B]{Runtime = 480  ; }[/B][/FONT][/COLOR]
[COLOR=#000000] [FONT=Times New Roman][B]else[/B][/FONT][/COLOR]
[COLOR=#000000]        [FONT=Times New Roman][B]{Runtime = 300 ; }     [COLOR=#009900] // end if[/COLOR][/B][/FONT][/COLOR]

[COLOR=#000000]     [FONT=Times New Roman][B]//Runmotor:[/B][/FONT][/COLOR]
[COLOR=#000000]   [FONT=Times New Roman][B]Jobpending= 1  ;         [COLOR=#009900] // Set Jobpending   // Timing flag[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]   [FONT=Times New Roman][B]Motoron  = 1  ;         [COLOR=#009900]  // Motoron   = 0    // Start Motor[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]   [FONT=Times New Roman][B]TMR0= 205     ;          [COLOR=#009900] // Load Tomer0[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]   [FONT=Times New Roman][B]INTCON.TMR0IE= 1  ;     [COLOR=#009900]   // enable Timer0[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]   [FONT=Times New Roman][B]INTCON.TMR0IF= 1  ;      [COLOR=#009900]  // Interrupt Timer0 Flag[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]   [FONT=Times New Roman][B]while(jobPending = 1)  ;        [COLOR=#009900]// BitwaitJobpending , Reset    // Wait to Finish[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]   [FONT=Times New Roman][B]motorOn= 0;                        [COLOR=#009900]    // Set Motoron                  // stop motor[/COLOR][/B][/FONT][/COLOR]

[COLOR=#000000]   [FONT=Times New Roman][B]for(Cntr =0; Cntr < Rinse; Cntr++)    [COLOR=#009900]  //   for Cntr = 1 To Rinse[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]    [FONT=Times New Roman][B]{  Drainon = 1  ;                [COLOR=#009900]// Reset Drainon// Open Drain[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]        [FONT=Times New Roman][B]while(Waterempty = 1) ;    [COLOR=#009900]// Bitwait Waterempty ,Reset // Wait Drain[/COLOR][/B][/FONT][/COLOR]
[COLOR=#009900]                              [FONT=Times New Roman][B]// wend[/B][/FONT][/COLOR]
[COLOR=#000000]        [FONT=Times New Roman][B]DrainOn=  0  ;          [COLOR=#009900] // Set Drainon // Close Drain[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]        [FONT=Times New Roman][B]WaterOn= 1   ;          [COLOR=#009900] // Reset Wateron // Fillagain[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]        [FONT=Times New Roman][B]while(WaterFull = 1) ;    [COLOR=#009900] // Bitwait Waterfull ,Reset[/COLOR][/B][/FONT][/COLOR]
[COLOR=#009900]                          [FONT=Times New Roman][B]// wend[/B][/FONT][/COLOR]
[COLOR=#000000]        [FONT=Times New Roman][B]WaterOn= 0   ;        [COLOR=#009900]   // Set Wateron    // CloseWater[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]        [FONT=Times New Roman][B]Runtime= 300  ;                         [COLOR=#009900]  // RinseTime[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]        [FONT=Times New Roman][B]TMR0= 205  ;[/B][/FONT][/COLOR]
[COLOR=#000000]       [FONT=Times New Roman][B]Jobpending= 1   ;                 [COLOR=#009900]// Set Jobpending[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]        [FONT=Times New Roman][B]Motoron=1 ;                        [COLOR=#009900]  // Reset Motoron // Start Rinse[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]       [FONT=Times New Roman][B]INTCON.TMR0IE= 1  ;      [COLOR=#009900]// SetBit(INTCON, TMR0IE)// enableTimer0[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]       [FONT=Times New Roman][B]INTCON.TMR0IF= 1 ;      [COLOR=#009900] // setBit(INTCON, TMR0IF)   //Interrupt Timer0 Flag[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]        [FONT=Times New Roman][B]while(Jobpending = 1) ;     [COLOR=#009900] // Bitwait Jobpending ,Reset // Wait to Finish[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]        [FONT=Times New Roman][B]Motoron= 0    ;                  [COLOR=#009900]  // Set Motoron    // Stop Rinse[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]     [FONT=Times New Roman][B]}         [COLOR=#009900]  // Next  cntr[/COLOR][/B][/FONT][/COLOR]

[COLOR=#000000]    [FONT=Times New Roman][B]MotorOn= 0  ;                    [COLOR=#009900]// Set Motoron     //Stop Rinse[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]    [FONT=Times New Roman][B]DrainOn= 1   ;                   [COLOR=#009900]// Reset Drainon   //Open Drain second cycle[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]    [FONT=Times New Roman][B]while (Waterempty = 1 );        [COLOR=#009900]// BitwaitWaterempty , Reset     // Wait Drain[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]    [FONT=Times New Roman][B]Runtime= 180  ;                     [COLOR=#009900] // SPIN[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]    [FONT=Times New Roman][B]JobPending= 1 ;                [COLOR=#009900]  // Set Jobpending[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]    [FONT=Times New Roman][B]motorOn= 1  ;                   [COLOR=#009900] // Reset Motoron      // Start Spin[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]    [FONT=Times New Roman][B]Run_nSpin= 1  ;                  [COLOR=#009900]   // Reset Run_nspin   // SPIN[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]    [FONT=Times New Roman][B]TMR0= 205    ;[/B][/FONT][/COLOR]
[COLOR=#000000]    [FONT=Times New Roman][B]Jobpending= 1  ;[/B][/FONT][/COLOR]
[COLOR=#000000]    [FONT=Times New Roman][B]INTCON.TMR0IE= 1  ;    [COLOR=#009900]  // SetBit(INTCON, TMR0IE)// enableTimer0[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]    [FONT=Times New Roman][B]INTCON.TMR0IF= 1 ;       [COLOR=#009900]// setBit(INTCON, TMR0IF)   //Interrupt Timer0 Flag[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]    [FONT=Times New Roman][B]while(JobPending = 1) ;     [COLOR=#009900]  // Bitwait Jobpending, Reset     // Wait to Finish[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000]    [FONT=Times New Roman][B]Relays= 0b00001111 ;                           [COLOR=#009900]   //ALL OFF, INITIAL State[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000][FONT=Times New Roman][B]}    [COLOR=#009900]     //  wend       //  Goto Loopagain[/COLOR][/B][/FONT][/COLOR]
[COLOR=#000000][FONT=Times New Roman][B]}[/B][/FONT][/COLOR][/LEFT]
```
*بقى البرنامج باستخدام **PIC18 **لتغطية باقى الأربع أنواع المرة القادمة إن شاء الله*


----------



## ماجد عباس محمد (20 يوليو 2018)

*الغسالة باستخدام PIC18F و لغة C:*

*يمكننا للسهولة نسخ البرنامج السابق فى مشروع جديد للمتحكم الجديد و ننسخه ، سنحتاج لتعديلات طفيفة مثل **TMR0 **سيضاف لها حرف **L **كبير أو صغير و **Option_Reg **سيتغير إلى **INTCON2 **و تعدل الأرقام كما فى المثال السابق فيصبح هكذا*

```
[LEFT][SIZE=4][COLOR=#008080][B]// program WM18 Declarations section[/B]
[/COLOR]
[B]char Switches at PORTB ;[/B]
[B]char Leds at Portc ;[/B]
[B]char Relays at Portd ;[/B]

[B]sbit Fullled at Rc0_bit ;[/B]
[B]sbit Halfled at rc1_bit ;[/B]
[B]sbit Smallled at rc2_bit ;[/B]
[B]sbit Hotled at rc3_bit ;[/B]
[B]sbit Mildled at rc4_bit ;[/B]
[B]sbit Coldled at rc5_bit ;[/B]
[B]sbit Wateron at rc6_bit ;[/B]
[B]sbit Drainon at rc7_bit ;[/B]

[B]sbit HitemP at rd0_bit ;[/B]
[B]sbit MidtemP at rd1_bit ;[/B]
[B]sbit Waterfull at rd2_bit ;[/B]
[B]sbit Waterempty at rd3_bit ;[/B]
[B]sbit Run_nspin at rd5_bit ;[/B]
[B]sbit Motoron at rd6_bit ;[/B]
[B]sbit Heateron at rd7_bit ;[/B]

[B]sbit Dooropen at rb0_bit ;[/B]
[B]sbit Run at rb1_bit ;[/B]
[B]sbit Cold at rb2_bit ;[/B]
[B]sbit Mild at rb3_bit ;[/B]
[B]sbit Hot at rb4_bit ;[/B]
[B]sbit SmallLoad at rb5_bit ;[/B]
[B]sbit Half at rb6_bit ;[/B]
[B]sbit Full at rb7_bit ;[/B]

[B]bit Jobpending ;[/B]

[COLOR=#008080][B]// VARIABLES[/B]
[/COLOR][B]unsigned int Runtime ;[/B]
[B]char Rinse , Cntr ;[/B]

[B]void Timer0_int() iv 0x0018 ics ICS_AUTO {[/B]
[B]if (INTCON.TMR0IF =1 ) {[/B]
[B]// dec (Runtime)[/B]
[B]if (--Runtime = 0 ) {[/B]
[B]Jobpending = 0 ;[/B]
[B]INTCON.TMR0IF =0 ;[COLOR=#008080]      // ClearBit(INTCON, TMR0IF) ; // Clear flag[/COLOR][/B]
[B]INTCON.TMR0Ie = 0 ;    [COLOR=#008080]// ClearBit(INTCON, TMR0Ie) // Disable timer[/COLOR][/B]
[B]} [COLOR=#008080]// End If[/COLOR][/B]
[B]INTCON.TMR0IF =0 ; [/B]
[COLOR=#008080][B]// ClearBit(INTCON, TMR0IF) // clear Interrupt Timer0 to receive another[/B]
[/COLOR][B]}[/B]
[B]}[/B]

[B]void main() {[COLOR=#008080]  // Main program[/COLOR][/B]
[B]INTCON2 = 0 ; [COLOR=#008080]// setting RB Pull up clearing bit RBPU all rising edge.[/COLOR][/B]
[B]INTCON = 0B10100000 ; [/B]
[COLOR=#008080][B]// 7Interrupt Control GIE All,6Peie disabledg, 5Timer0 OV Enable[/B]
[B]// External disable , RBIF port changeenable, Timr0Flag,Exter Flag, PB change flag[/B]
[/COLOR][B]TRISB = 255 ;[/B]
[B]TRISC = 0 ;                     [COLOR=#008080]// out[/COLOR][/B]
[B]Leds = 0b00100100 ;[COLOR=#008080]    //small Cold[/COLOR][/B]
[B]TRISD = 0b00011111 ;[COLOR=#008080]  // some in and some out[/COLOR][/B]
[B]Relays = 0b00001111 ;[/B]
[B]Heateron = 0 ;[/B]
[B]Motoron = 0 ;[/B]
[B]Run_nspin = 0 ;[/B]
[B]INTCON.TMR0IF =0 ;[COLOR=#008080]   // ClearBit(INTCON, TMR0IF) // Interrupt Timer0 Flag[/COLOR][/B]
[B]INTCON.TMR0IE =0 ;  [COLOR=#008080]// ClearBit(INTCON, TMR0IE) // Stop Interrupt Timer0[/COLOR][/B]

[B]while (Run = 1 )[COLOR=#008080]            // Bitwait Run , Set[/COLOR][/B]
[B]{} [COLOR=#008080]// wend // Run button release[/COLOR][/B]
[B]while (1) {         [COLOR=#008080]// Loopagain:[/COLOR][/B]
[B]do {[/B]
[B]if (Full = 0) { // Then[/B]
[B]Leds = Leds | 0B00000111 ;[COLOR=#008080]     // Leds OR 00000111[/COLOR][/B]
[B]Fullled = 0 ; }[/B]
[B]else if ( Half = 0) {                  [COLOR=#008080] // Then[/COLOR][/B]
[B]Leds = Leds | 0b00000111 ;[COLOR=#008080]    // Leds = Leds Or %00000111[/COLOR][/B]
[B]Halfled = 0 ; }[/B]
[B]else if ( SmallLoad = 0 ){        [COLOR=#008080]// Then[/COLOR][/B]
[B]Leds = Leds | 0b00000111 ;   [COLOR=#008080]//Leds = Leds Or %00000111[/COLOR][/B]
[B]Smallled = 0 ; }                       [COLOR=#008080]// end if[/COLOR][/B]

[B]if ( Hot = 0) {[COLOR=#008080]                         // Then[/COLOR][/B]
[B]Leds = Leds | 0B00111000 ;[COLOR=#008080]  //Leds = Leds Or %00111000[/COLOR][/B]
[B]Hotled = 0 ; }[/B]
[B]else if (Mild = 0) {[COLOR=#008080]                  // Then[/COLOR][/B]
[B]Leds = Leds | 0b00111000 ;  [COLOR=#008080]//Leds = Leds Or 0b00111000[/COLOR][/B]
[B]Mildled = 0 ; }[/B]
[B]else if (Cold = 0)[COLOR=#008080]                       // Then[/COLOR][/B]
[B]{ Leds = Leds | 0b00111000 ;[/B]
[B]Coldled = 0 ;[/B]
[B]}  [COLOR=#008080]// end if   [/COLOR][/B]
[B]} while (Run = 1) ;[COLOR=#008080]             // loop until run = 0 // Wait Run Press[/COLOR][/B]

[B]while ( DoorOpen = 1 ) ;[COLOR=#008080]   // Bitwait Dooropen , Reset // Wait Door to close[/COLOR][/B]
[B]WaterOn = 1 ;                   [COLOR=#008080]// Set Wateron Open Water Valve[/COLOR][/B]
[B]while (Waterfull = 1 ) ;    [COLOR=#008080]// Bitwait Waterfull , Reset // Wait full Tank[/COLOR][/B]
[B]WaterOn = 0 ;  [COLOR=#008080]    // ReSet Wateron // Close water Valve[/COLOR][/B]

[B]if (Coldled = 1)[COLOR=#008080]   // Then // not Cold then[/COLOR][/B]
[B]{ Heateron = 1 ;[COLOR=#008080]    // Heater on[/COLOR][/B]
[B]if (Mildled = 0) [/B]
[B]{[/B]
[B]while ( Midtemp = 1 );      [COLOR=#008080]// Bitwait Midtemp , Reset[/COLOR][/B]
[B]} [COLOR=#008080]// wend[/COLOR][/B]
[B]else[/B]
[B]{ while (Hitemp = 1 ) ;[COLOR=#008080]        // Bitwait Hitemp , Reset[/COLOR][/B]
[B]}  [COLOR=#008080]//end if[/COLOR][/B]
[B]HeaterOn = 0 ;               [COLOR=#008080]// reSet Heateron // Turn off heater[/COLOR][/B]
[B]}[COLOR=#008080]  // End if // Now Start Washing[/COLOR][/B]

[B]if (Fullled = 0)                       [COLOR=#008080]// Then[/COLOR][/B]
[B]Runtime = 20 * 60 ;[/B]
[B]else if (Halfled = 0)[COLOR=#008080]                // Elseif Halfled = 0 Then[/COLOR][/B]
[B]{ Runtime = 480 ; }[/B]
[B]else[/B]
[B]{ Runtime = 300 ; }[COLOR=#008080]           // end if[/COLOR][/B]

[COLOR=#008080][B]// Runmotor:[/B]
[/COLOR][B]Jobpending = 1 ;[COLOR=#008080]             // Set Jobpending // Timing flag[/COLOR][/B]
[B]Motoron = 1 ;[COLOR=#008080]                 // Motoron = 0 // Start Motor[/COLOR][/B]
[B]TMR0l = 205 ;                  [COLOR=#008080]// Load Tomer0[/COLOR][/B]
[B]INTCON.TMR0IE = 1 ;    [COLOR=#008080]// enable Timer0[/COLOR][/B]
[B]INTCON.TMR0IF = 1 ;[COLOR=#008080]     // Interrupt Timer0 Flag[/COLOR][/B]
[B]while (jobPending = 1) ;[COLOR=#008080]  // Bitwait Jobpending , Reset // Wait to Finish[/COLOR][/B]
[B]motorOn = 0;                    [COLOR=#008080]// Set Motoron // stop motor[/COLOR][/B]

[B]for (Cntr =0; Cntr < Rinse; Cntr++)[COLOR=#008080]  // for Cntr = 1 To Rinse[/COLOR][/B]
[B]{ Drainon = 1 ;[COLOR=#008080]                         // Reset Drainon // Open Drain[/COLOR][/B]
[B]while (Waterempty = 1) ;    [COLOR=#008080]// Bitwait Waterempty , Reset // Wait Drain[/COLOR][/B]
[COLOR=#008080][B]// wend[/B]
[/COLOR][B]DrainOn = 0 ;                      [COLOR=#008080]// Set Drainon // Close Drain[/COLOR][/B]
[B]WaterOn = 1 ;                     [COLOR=#008080]// Reset Wateron // Fill again[/COLOR][/B]
[B]while (WaterFull = 1) ;[COLOR=#008080]     // Bitwait Waterfull , Reset[/COLOR][/B]
[COLOR=#008080][B]// wend[/B]
[/COLOR][B]WaterOn = 0 ;                    [COLOR=#008080]// Set Wateron // Close Water[/COLOR][/B]
[B]Runtime = 300 ;[COLOR=#008080]                // Rinse Time[/COLOR][/B]
[B]TMR0l = 205 ;[/B]
[B]Jobpending = 1 ;              [COLOR=#008080]// Set Jobpending[/COLOR][/B]
[B]Motoron =1 ;[COLOR=#008080]                   // Reset Motoron // Start Rinse[/COLOR][/B]
[B]INTCON.TMR0IE = 1 ;    [COLOR=#008080]// SetBit(INTCON, TMR0IE)// enable Timer0[/COLOR][/B]
[B]INTCON.TMR0IF = 1 ;    [COLOR=#008080]// setBit(INTCON, TMR0IF) // Interrupt Timer0 Flag[/COLOR][/B]
[B]while (Jobpending = 1) ;   [COLOR=#008080]// Bitwait Jobpending , Reset // Wait to Finish[/COLOR][/B]
[B]Motoron = 0 ;[COLOR=#008080]                    // Set Motoron // Stop Rinse[/COLOR][/B]
[B]}  [COLOR=#008080]// Next cntr[/COLOR][/B]

[B]MotorOn = 0 ;                 [COLOR=#008080]// Set Motoron // Stop Rinse[/COLOR][/B]
[B]DrainOn = 1 ;                    [COLOR=#008080]// Reset Drainon // Open Drain second cycle[/COLOR][/B]
[B]while (Waterempty = 1 );  [COLOR=#008080]// Bitwait Waterempty , Reset // Wait Drain[/COLOR][/B]
[B]Runtime = 180 ;[COLOR=#008080]            // SPIN[/COLOR][/B]
[B]JobPending = 1 ;[COLOR=#008080]            // Set Jobpending[/COLOR][/B]
[B]motorOn = 1 ;                [COLOR=#008080]// Reset Motoron // Start Spin[/COLOR][/B]
[B]Run_nSpin = 1 ;             [COLOR=#008080]// Reset Run_nspin // SPIN[/COLOR][/B]
[B]TMR0L = 205 ;[/B]
[B]Jobpending = 1 ;[/B]
[B]INTCON.TMR0IE = 1 ;[COLOR=#008080]   // SetBit(INTCON, TMR0IE)// enable Timer0[/COLOR][/B]
[B]INTCON.TMR0IF = 1 ;   [COLOR=#008080]// setBit(INTCON, TMR0IF) // Interrupt Timer0 Flag[/COLOR][/B]
[B]while (JobPending = 1) ;[COLOR=#008080]   // Bitwait Jobpending , Reset // Wait to Finish[/COLOR][/B]
[B]Relays = 0b00001111 ;    [COLOR=#008080]// ALL OFF, INITIAL State[/COLOR][/B]
[B]}  [COLOR=#008080]// Goto Loopagain[/COLOR][/B]
[B]}[/B]
[/SIZE][/LEFT]
```
*فى الأمثلة السابقة فصلنا كثيرا لتوضيح الفروق بين اللفات و المترجمات لذا أرى أنه من الأفضل فيما يلى أن نعتمد الأسيمبلى لعائلة **C51 **و البيزك **/ **باسكوم لعائلة **AVR **و لغة **C **من ميكروإلكترونيكا للبيك اختصارا للوقت و أصبح لدينا القدرة للترجمة حسبما تقود الحاجة**.*

*المرة القادمة إن شاء الله سنتحدث عن برنامج ميكروويف منزلى ثم برنامج آخر لمعالجة المحول تماثلى رقمى و ربما PWM*


----------



## ماجد عباس محمد (21 يوليو 2018)

*برنامج ميكروويف*

[h=1]برنامج ميكروويف[/h][h=2]التركيب الداخلى:[/h]*ألميكروويف يحتوى على ماجنيترون وهو صمام إلكترونى يحتوى فتيلة لتسخين المصعد **"**كاثود**" **فيشع إلكترونات يجذبها المصعد **"**أنود**" **بجهد عالى يبدأ حسب الطراز من **3000 **فولت مستمر لتوليد موجات ذات تردد عالى جدا فى نطاق ألميكروويف و التى توجه للحيز داخله فيمتصها الجسم الموجود فيسخن**. **الفتيلة قد تحتاج لخمس ثوانى لتسخن ومن ثم التحكم به عن طريق قطع التغذية العالية **. **قطع و توصيل جهود عالية هكذا ليس ميسورا لذا تقطع تغذية دائرة توليد الجهد العالى ، كما أن الإشعاع ضار بالأشخاص لذا تتخذ احتياطات كافية لمنع تسربه نهائيا للخارج من خلال شبكة معدنية وراء زجاج الباب تتيح ألرؤية للداخل و تمنع الإشعاع من التسرب ، لذا يوجد مفتاح **switch **على الباب لو لم يغلق جيدا يمنع الجهاز من العمل**.*
*معظم الأجهزة تعمل بأزرار كنموذج الغسالة و للتغيير فقط سنستخدم لوحة الأرقام **:Key Pad **مع **4 **مبينات **7 **شرائح **7 segment display **و لدينا حساس الباب مفتوح و حساس للجهد ألعالى حيث لو انخفض عن حد معين سيتوقف الماجنيترون**. **ستقول يمكن وضع مثبت فولت لكن أى مثبت له مدى يؤدى وظيفته فيه ولو خرج عنه لا يستجيب**.*
*سته مخارج الأول للفتيلة و الثانى للجهد ألعالى و الثالث لمروحة التبريد و الرابع للإضاءة و الخامس للزمور و السادس لموتور التقليب *
*منفذ كامل **8 **طرف للوحة الأرقام **Key Pad **و المدخل الأول لحساس الباب و الثانى الجهد ألعالى *
*بقى كيف نتحكم فى مبينات الشرائح السبعة**.*
[h=2]السبع شرائح و الحل – ليس ضائع:[/h][h=3]ما هو مبين 7 شرائح؟[/h]بدأ منذ عهد ألصمامات الإلكترونية للحاجة لبناء أجهزة قياس تردد أو قياسات أخرى و عرضها بصورة رقمية لكونها أكثر دقة و أسرع استيعابا من المؤشر ألتقليدى ، و ظهرت عدة صور منها و كانت صورة سبعة شرائح على أركان رقم 8 العربى هى التى لاقت نجاحا كبيرا كما فى الصورة التالية الجزء الأيسر ، و لاحقا ظهرت الحاجة لكتابة أحرف فأضيف لها عدة أقسام أخرى لتكمل كتابة الأحرف اللاتينية كما فى الجزء الأوسط من الصورة .






*لاحقا استخدمت للشاشات الكبيرة شرائح معدنية ملونة لتكوين الشاشات الكبيرة كما فى المطارات و مواقف القطارات و السيارات الخ وكانت تحرك بملف مغناطيسى كما تحرك تلامسات الريلاى ثم صممت مصفوفة النقاط كما فى الشكل الأيمن لتتيح رسم الحروف كافة اللغات و بعض الرسوم البسيطة مثل الأسهم و الدوائر و المثلثات و غيرها**.**و توجد أيضا وحدات ليد كبيرة الحجم تعمل على فولت أعلى **12 **فولت **, **اكثر كما توجد أيضا وحدات غازية تعمل بجهود أعلى و لونها برتقالى أنسب للاستخدام الخارجى كما فى محطات الوقود الخ**.*
*فى مشروعنا هذا سنستخدم النوع التقليدى كما بالشكل الأيسر و باستخدام المتحكم فلدينا طريقان لا ثالث لهما، الأول استخدام محلل أكواد مثل **7447,7448,7449,CD4511 - **أو أرقام مثل **DM9368 DM9370 **و المعروفة باسم **Hex to 7Seg **وهى تعطى الأرقام العربية العشرة و أيضا **CA3161- **التى تستطيع كتابة الأحرف **HELP **أو استخدام المتحكم كمحلل كود**.*
*استخدام المتحكم توفر مال بعدم استخدام متكاملات إضافية على حساب عدد الأطراف المستخدمة حيث تضع **7 **أطراف للشرائح و طرف لكل مبين وفى مثالنا هذا نحتاج **13 **طرف و قد نحتاج آخر للعلامة العشرية و قد تثبت فلا تحتاج لطرف**. **هذا قرابة **2 **منفذ وهذا كثير**. **لو لديك تطبيق يتطلب مبينات أكثر كميزان مثلا فلن تجد أطراف تكفى **.*
*لذا نأخذ فكرة عن كل نوع مما سبق فإن تطلب الأمر ستكون لديك فكرة أن هذا متاح**.*
*الأرقام **7447,7448,7449 **هى الأكثر شيوعا و بعضها يناسب الشاشة ذات الكاثود المشترك **(**عمومى متصل بالأرض**) Common Cathode CC **و منها ذات الأنود المشترك **(**عمومى متصل بالموجب**) Common Anode CA **و فيما عدا ذلك فلا فرق**. **لإضاءة الأولى تحتاج جهد موجب يمرر تيار مناسب حوالى **5 **إلى **10 **مللى أمبير للطرف المعنى بينما الثانية تحتاج توصيل الطرف المعنى بالأرض **(**طبعا من خلال مقاومة**) **ليسحب هذه القيمة من التيار**. **أيضا هذه القيمة تخص الليدات العادية أما الوحدات الكبيرة و غيرها فيرجع للداتاشيت لمعرفة الفولت و التيار المناسبين**.*
*طالما التيار يمر فالطرف مضاء لذا لتوصيل مجموعة معا ستحتاج لوضع ترانزستور سويتش أو مفتاح على الطرف العمومي لتفعيل هذا المبين دون سواه ثم توصيل أطراف الأحرف لكتابة ما تريد**. **لهذا نرى المشكلة وهى ضرورة تتابع العرض حتى لا يتوقف ظهور الأرقام و يبدو غير لائق**. **لحل هذه المشكلة حينما نحتاج قدرة المتحكم لمهام أهم من تحديث المبينات، يمكننا أولا أن نستخدم المقاطعة ولكن هذا يسبب لنا مشكلة الحاجة للمؤقت أن يعمل على زمن عرض الرقم و زمن التحديث بعد اكتمال المبينات كلها لذا و لتحرير المتحكم كليا، يمكن وضع مساكة **Latch (**كورس الدوائر المنطقية**) **حيث يحتفظ بالرقم المراد عرضه لحين الحاجة لتعديله **. *



*كما بالرسم يمكن استخدام المساكة ذات **8 **بت **Latch **رقم **74373 **ذات القدح بالمستوى **(=1) **أو **74374 **ذات القدح بالحافة الصاعدة بين خرج المتكاملة المحلل للشفرة و العارض ، ولكن هذا يحتاج أن تحفظ الأرقام كلها **(**هنا اربع أرقام**) **أى تحتاج لبايت لحفظهم أما لو أضفت محلل من **4 **إلى **16 **ستحفظ **16 **رقم و تحتاج **5 **متكاملات كما بالرسم الأيسر**.*
*أو تضع المساكة بين الميكرو و محلل الأكواد وهنا تستطيع كتابة رقمين معا و لكن ستحتاج متكاملات أكثر**.*
*يبدو أن الحل الأيسر أفضل لكن لو لا تحتاج لكتابة حروف مع الأرقام فلدينا حل أفضل باستخدام **CD4511 **فهى محلل كود و معه مساكة **Latch **ولا أدرى لماذا لا يستغلها أحد، وهكذا تكون الدائرة ، أربعة خطوط للرقم و خط لكل شاشة*




*لو احتاجنا لعدد كبير مثل الموازين مثلا فقد تحتاج محلل شفرة **4:16 **لتتعامل مع **16 **شاشة و البعض استخدم محلل **4 **إلى **16 **مثل **4514 **أو **4017 4022 **من **4 **إلى **10 **أو **74138 **أو **74154 **كلها تتحكم فى حتى **16 **مبين من **4 **أطراف فقط أى لم نضيف شيئ**.*
*المشكلة هنا أنك تحتاج فى البرنامج أن تكرر إضاءة كل المبينات على الأقل **10 **مرات كل ثانية و تبقى كل منها مضاء لفترة تكفى لتراه العين وهذا يشكل عبئ كبير على البرنامج*

*البعض استخدم التسلسلى الشهير **74595 **و لكنك ستحتاج واحد لكل مبين أى **16 **متكاملة و لكن شركة صينية قدمت حلا عبقريا بمتكاملة رقمها **TM1640 **تتحكم فى **16 **مبين **16 display **من خلال خطين تسلسليين فقط وهى فى أغلب الموازين لدى البقالة **. **حيث تجد شاشة أمامك للوزن و أخرى أمامه ليضع الأشياء على الميزان و ثالثة تعرض السعر أو أشياء أخرى بمجموع **16 **مبين*

*شرح مفيد لكن كان به خطأ واحد ربما غير مقصود، تقول الأرقام العربية و لعلك تقصد الإنجليزية**..*
*معذرة و ما هى الأرقام الإنجليزية؟ لا شيء بهذا الاسم هناك أرقام لاتينية مثلا **I II III IV V VI VII IIX IX X **وهى من **1 **إلى عشرة و كانت لا تصلح للحساب ولا تعبر عن الصفر و الأرقام الهندية التى اعتادنا عليها جميعا بمسمى خاطئ **"(**عربية**)” **و لكن نذكر أنه عالم عربى من اخترع الصفر**.*
*إذا ماذا فى الصفر ليخترع؟ *
*الأرقام العربية كانت تعد الزوايا و طبقا لما فى الصورة*




*فالشكل باللون الأسود شكل الرقم العربى و عدد الزوايا وضعت بها نقط حمراء للتوضيح**.*
*و بقى الصفر كيف يجدون له شكل بدون زوايا ، فاقترح عالم عربى الدائرة فهى شكل بدون زوايا أى صفر**.*

*أما كيف نستخدم الميكرو كمحلل للشفرة فأغلب دوائر الهواة على المنتديات تتبنى هذه الفكرة نظرا لعدم الحاجة لتشغيل المتحكم فى وظائف أخرى مثل الدائرة التالية*




*المرة القادمة إن شاء الله نضع رسم الجهاز *


----------



## ماجد عباس محمد (22 يوليو 2018)

*دائرة جهاز الميكرو ويف*

*دائرة جهاز الميكرو ويف*

*سنبدأ كما تعودنا بالمتحكم **AT89x52 **و لغة الآلة أو الأسيمبلى **.*
*وضعنا مفتاح الباب على طرف **INT0 **و الأعلى أولوية و لأهمية إيقاف الماجنيترون سنرفع أولويته أيضا عن سواه حتى يستجاب له أثناء تنفيذ أى مقاطعة أخرى أو يمكنك ذلك بإتاحة المقاطعة فى كود باقى المقاطعات**.*
*استخدمنا ذات الطريقة لحساب الزمن و بالتالى لدينا مقاطعة كل ثانية و ذات الطريقة مع الريلايات لتجنب لحظة التفعيل أثناء البدء**.*
*بالنسبة للزمور فمنه نوعان أحدهما ميكانيكى فقط و يحتاج لدائرة مهتز لينتج صوت وآخر شامل دائرته وهو الأفضل وهو ما نستخدمه ، أما لو تنوى استخدام نغمات متعددة فيمكنك استخدام دائرة مكبر مثل **LM386 **و سماعة مناسبة**.*
*بالنسبة للعارض ، فسنستخدم أربعة متكاملات **CD4511 **واحد لكل مبين **. **المتكاملة لها **4 **طرف دخول للعد من صفر إلى **9 **و طرف دخول **LT **اختصار**Lamp Test **وهى فى كل المحللات لاختبار المبين فتضاء كل أجزاءه، و طرف دخول باسم **BI **وهى اختصار **Blanking Input **وهى لإطغاء الشاشة وهذه تستخدم لتوفير طاقة البطارية عند عدم الحاجة أو تعديل شدة الإضاءة بتعديل عرض النبضة **. **و أخيرا **LE **اختصار **Latch Enable **وهى عندما **= **صفر يحلل الدخل و يظهر على المبين و عندما **= 1 **يحتفظ المبين بآخر قيمة عرضها و بهذا نضع الثوانى على الحافلة ثم نفعل طرف **LE ** الثوانى بنبضة سالبة ثم نضع الدقائق و نفعل طرف **LE** الدقائق بنبضة أخرى**.*
*بقى لوحة المفاتيح وهى بضع أزرار مرصوصة فى صفوف و أعمدة وفى الوحدة ذات **16 **زرار تكون أربعة صفوف و أربعة أعمدة كما يلى*




*فى الصورة على اليسار تركيب الأزرار كما بالداخل حيث لدينا صف **1 **أى **R1 **و صف **2 **و صف **3 **و صف **4 **و أيضا عامود **1 **أى **Column 1 **و اختصارا **C1 **و **C2 **و **C3 **و **C4 . **الطرف رقم **1 **باللون القرمزى **(**الرسم الأيمن**) **متصل بالأحرف **A,B,C,D **و عندما تضع **+5 **فولت عليه لن يظهر فى أى مكان حتى تضغط على أحد الأزرار السابقة فإن كان **A **سيظهر على الخط الأحمر العلوى و الخارج من طرف **8 **و إن كان **B **سيخرج من الأزرق رقم **7 **و هكذا، الآن نبدل الفولت **+5 **من الطرف **1 **إلى **2 **ولا معنى إطلاقا لإبقاؤه على أكثر من عامود ، الآن سيستجيب للضغط على الأرقام **3**،**6**،**9**،علامة الشباك **# **و هكذا*
*إذن علينا أن نضع جهد على طرف من الأعمدة ثم نفحص من أى صف خرج أو العكس نضعه على صف و نبحث من أى عامود قد خرج**. *

*بقى أن نحدد هل الجهد ألعالى مسموح به أم انخفض عن المسموح ،أعلم أن الكثير قد أكمله بالمكبر **LM741 **و اختبره على محاكى ووصل لتمام الأمور، لكن للأسف واقعيا **LM741 **لا يعمل بتغذية أقل من **9 **فولت كما أن خرجه يعلو عن جهد **VEE **بقيمة **2 **فولت و يقل عن **Vcc **بقيمة **2 **فولت أخرى أى لم يبقى – بفرض أنع سيعمل – سوى واحد فولت فقط وهذا لا يناسب دوائر المنطق عموما العاملة على **5 **فولت **. **البعض ذهب خطوة أخرى أفضل باستخدام **LM358 **وهذا موفق من جهتين أنه يعمل من **3 **فولت فصاعدا و يصل لجهد الأرضى أو على أقصى تقدير **0.2 **فولت لكن مشكلة **Vcc **ما زالت قائمة و **3 **فولت مع تباين درجات الحرارة الخ غير مأمونة النتائج لذا نستخدم مقارن **LM393 **و هو يعالج هذه الخاصية لآنه فى وضع خرج **= 1 **يكون مفتوح **Open Collector **و يترك للدائرة أن تحدد قيمها، و بوضع مقاومة جذب لأعلى يمكنك أن ترفع الخرج حتى **30 **فولت لو شئت و ما زلت كما أنت تستخدم تغذية **+5 **فولت و تقارن جهود أقل من **5 **فولت**.*




*الجهد المقوم بفرض أنه من مصدر **9 **فولت سيكون قرابة **13 **فولت و نحتاج منه قيمة أقل من **+5 **فولت لذا سنأخذ ثلثها أو ربعها من خلال مقاومتى **R3,R4 **على الطرف الموجب الغير عاكس و على الطرف السالب بمجزئ جهد نضع جزء من **5 **فولت**. **طالما **220 **فولت بخير سيكون الطرف الغير عاكس أعلى من العاكس و الخرج **= 1 **بسبب المقاومة **R7 **و لو هبط الجهد **220 **نستطيع أن نحدد أى قيمة نضبط عليها المقاومة المتغيرة **POT **فيهبط الخرج إلى صفر*
*المقاومة**R5 **لمنع الاهتزاز حول نقطة الانقلاب ، و ندخل هذا على المقاطعة **INT1 **لأهميتها أيضا فلو انخفض الجهد ألعالى لن تتولد موجات الميكرو ويف و من ثم تظل الطاقة تفقد داخله تيار **× **فولت دون سحب منها للخارج و من ثم ترتفع حرارته وقد يتلف**. **نظرا لأن المتكاملة بها **2 **مقارن فيمكن توصيل الثانى كحساس للحرارة كما بالدائرة و نظرا لهدم توافر مدخل مقاطعة ثالث فيمكن جمعه مع حساس الفولت وهذه ميزة المقارن أنه لا يحتاج دايودات كمكبرات العمليات ، و يبقى هذا الأمر جدلا علميا فقط لأن واقعيا يوضع حساس كهروميكانيكى على الماجنيترون يقطع التيار عند ارتفاع الحرارة مثل ألذى فى مكوى الملابس و أجهزة مسخنات الهواء و تجفيف الشعر الخ كما أن الفولت يجب تثبيته بمثبت لو يتغير بمدى أوسع من المسموح له فتوقف العمل فى منتصف التسوية غالبا ما يفسد مذاق الطعام ، لذا لا جدوى منه عمليا**.*

*الآن لدينا الدائرة هكذا و نبدأ التفكير فى هيكل البرنامج و حتى المرة القادمة إن شاء الله حيث نبدأ البرمجة**.*


----------



## ماجد عباس محمد (23 يوليو 2018)

*هيكل برنامج الميكرو ويف*

*هيكل برنامج الميكرو ويف*

*بعد تهيئة المنافذ و المقاطعات و المتغيرات، نحدث المبينات ثم نقضى الوقت فى قراءة لوحة المفاتيح ، إن كان هناك رد ، نستجيب له و إلا نكرر العمل ، حسنا هيا نبدأ**.*

*حسنا الآن عندما يحدث **INT0 **الخاص بالباب سنوقف الماجنيترون**. **و المؤقت لكننا نريد أن نراقب الباب أيضا حتى يغلق فنعيد الأمور كما كانت**. **نعلم انه سيكون **1 **و عند فتح الباب يصبح صفر بفعل السويتش*
*حسنا هناك قاعدة فى الصناعة تقول انزع التحكم يجب أن تستقر الأمور ولو نزعنا السويتش سيمكن فتح الباب و تعريض المستخدم للخطر**. **لا أقول نزع المفتاح حرفيا ولكن لو قطع السلك الذاهب إليه مثلا**... **إذن ما الحل؟ علاج هذا الموقف صعب و غير آمن فمن المعلومات الأولية عن أى حاسب أنه **"**يهنج**" **وهى مشتقة من كلمة **Hang **بمعنى **"**يعلق**" **لأنه يدخل فى دورة لانهائية **.*
*البعض سيقول مؤقت الحماية **Watch Dog Timer **أو مؤقت كلب الحراسة، حسنا رغم أنه غير مدعوم بهذا الطراز إلا أنه يمكن إضافته خارجيا بعداد **CD4060 **لكن ماذا يحدث لو لم يستجيب؟*
*لذا و رغم أن كل الأجهزة فى السوق تعتمد ميكرو إلا أنها تستخدم مفتاح لقطع التغذية عن الماجنيترون طالما الباب مفتوح**.*
*هذه دائرته من مواقع على النت*




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




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



التهيئة:*

سنحتاج لتهيئة البرنامج ليتواءم مع هذه الطلبات و *هكذا تصبح التهيئة كما يلى*
*سنوقف كل المخارج**. **وتهيئه المقاطعة كما فى الجهاز السابق فقط نعدل خطوة هى رفع أولوية **INT0 **بجعل **IP=1 **ونعدل **TCON **ليجعل قدح بالحافة أيضا*

```
[LEFT][B][SIZE=3]MOV TCON,#3    [COLOR=#008080]; Clear All interrupts, SETB IT0 IT1 Edge triggered[/COLOR]
بهذا تصبح التهيئة
;INCLUDE 89s52.mc
[COLOR=#008080];=====================================
[/COLOR]; DEFINITIONS
[COLOR=#008080];=====================================
[/COLOR]Relays EQU P0
Displays Equ P1
KeyPad EQU P2
Controls EQU P3
HIv_Off Equ Relays.0
Off_Non EQU Relays.1
Buzzer EQU Relays.2

Col4 EQU KeyPad.0
Col3 EQU KeyPad.1
COl2 Equ KeyPad.2
Col1 Equ KeyPad.3
Row4 EQU KeyPad.4
Row3 EQU KeyPad.5
Row2 Equ KeyPad.6
Row1 Equ KeyPad.7

SecLatch Equ Controls.0
MinLatch Equ Controls.1
DoorOpen Equ Controls.2

[COLOR=#008080];=====================================
[/COLOR]; VARIABLES
[COLOR=#008080];=====================================
[/COLOR]SecLeft EQU 10
MinLeft EQU 11
PowerSel Equ 12
CurrPwr Equ 13
LowHeat Equ PSW.1
JobPending Equ F0
KeyValue EQU B
NoKey Equ B.7
[/SIZE][/B][/LEFT]
```

*كما سبق مسميات المنافذ و الأطراف و لاحظ هنا أننا أعطينا **P1 **اسم **Displays **فهو سيعطى البيانات لكل رقمين معا أى الثوانى آحاد و عشرات فى مرة ثم الدقائق فى مرة**. **الآحاد فى البت من صفر إلى **3 **و العشرات من **4 **إلى **7. **و أيضا لوحة الأزرار **KeyPad **و أعطينا كل طرف اسم من واقع تركيبه صف **Row **أو عامود **Col **و رقمناهم **1**،**2**،**3**،**4 **و استخدمنا كثير من الخيارات السابقة للتايمر و الزمن مستمر أم منتهى**. **يلى ذلك خانة للثوانى و أخرى للدقائق كما سبق و حددنا المراكم **B **فيه قيمة الزر ألذى ضغط عليه و نريد أن نعلم هل تم ذلك أم لا فوضعنا البت **NoKey **و سيلى ذلك تفصيلا إن شاء الله فى شرح برنامج الأزرار**. **عرفنا أيضا ثلاث أطراف واحد **Off_Non **وهو **=1 **لقفل الجهاز و صفر للتشغيل وهو من الرسم يوثر على الريلاى الرئيسى ألذى يوقف كل شيئ و الثانى **Hiv_Off **لقطع الجهد العالى بينما باقى الجهاز يعمل **.
المرة القادمة إن شاء الله نكمل*


----------



## ماجد عباس محمد (24 يوليو 2018)

*فى خانة صفر وهى الريست انتقال لبدء البرنامج **Startit **أى **Start-It **فكما سبق كلمة **start **محجوزة**. **و أيضا متغير لنعلم كم نسبة تخفيض الطاقة **PowerSel **و حساب الطاقة الحالية فى **CurrPwr **و لو تم اختيار هذا النسق من عدمه الراية **LowHeat **فى مسجل حالة البرنامج البت **1 **أى **PSW.1 
*

```
[LEFT][B][SIZE=3][COLOR=#008080]
;=====================================
[/COLOR]; RESET and INTERRUPT VECTORS
[COLOR=#008080];===================================== 
[/COLOR]org 000h                       [COLOR=#008080] ; Reset Vector[/COLOR]
SJMP Startit
org 003h                   [COLOR=#008080]  ; Adress of INT0 (IE0)Emergency[/COLOR] 
SETB Off_Non            [COLOR=#008080] ; stop Outs and motors etc[/COLOR] 
CLR TR0                     [COLOR=#008080]  ; Stop counter[/COLOR]
JB doorOpen, $
AJMP EmrgSub

org 00Bh                 [COLOR=#008080]  ; Adress of Interrupt Timer 0 (TF0) 
[/COLOR]MOV A,SecLeft            [COLOR=#008080] ; sec[/COLOR]
JZ DEC_Min                 [COLOR=#008080] ; if zer then correct[/COLOR]
ADD A,#99h               [COLOR=#008080]  ; Dec jump if not zero[/COLOR]
DA A
MOV SecLeft,A
SJMP TOUT

DEC_Min:
MOV A,MinLeft 
JZ AllDone            [COLOR=#008080]   ; Sec =0 and Min = 0[/COLOR]
ADD A,#99h
DA A                   [COLOR=#008080]     ; decrement min[/COLOR]
MOV MinLeft,A
MOV SecLeft,#59h

TOUT:
JNB LowHeat,ShowAndRet
INC CurrPwr
MOV A,CurrPwr
CJNE A,#11,NotYet
Mov CurrPwr,#0
NotYet: 
MOV A,PowerSel
SUBB A,CurrPwr 
Mov HIv_Off,C
SJMP ShowAndRet
AllDone:
CLR Jobpending
CLR TR0                   [COLOR=#008080] ; Stop counter[/COLOR]
Clr LowHeat             [COLOR=#008080] ; Clear if selected[/COLOR]
Setb Off_Non        [COLOR=#008080]   ; Power Off[/COLOR] 
SETB HIv_Off        [COLOR=#008080]    ; Turn Off HI Voltage
[/COLOR]Clr Buzzer
Mov R7,#0
Loop1:
Mov R6,#0
Loop2: nop
nop
DJNZ R6,Loop2
DJNZ R7,Loop1
SETB Buzzer 
ShowAndRet: 
ACALL ShowTime [COLOR=#008080]      ; display New Time[/COLOR]
RETI


[COLOR=#008080];=====================================
[/COLOR]; CODE SEGMENT
[COLOR=#008080];=====================================
[/COLOR]

Startit: 

[/SIZE][/B][/LEFT]
```
*يلى ذلك الخانة **3 **وهى **INT0 (IE0)Emergency **حال فتح الباب ، قلنا أن كل شيء سيتوقف بالمفاتيح لكن نحتاج إيقاف التايمر ثم نراقب غلق الباب **(**كما سبق فى الغسالة**) **ثم نعيد التشغيل**. **لو لاحظنا أن هذه الخطوات أكثر من **8 **خانات لذا نحتاج لأمر قفز لأى مكان لاستكمال الكود بتشغيل التايمر و تشغيل الموتور ثم ننهيه **RETI **أى العودة من المقاطعة**. **هذا الكود الإضافى يمكن وضعه فى أى مكان فى الذاكرة لذا وضعناه مثلا بعد كل البرنامج حيث نضع باقى الوظائف أو حيثما شئت*

```
[LEFT][SIZE=3]EmrgSub:
[B]CLR[/B] [B]TR0[/B] ; Start counter
[B]CLR[/B] Off_Non ; Resetart All 
[B]RETI[/B][/SIZE][/LEFT]
```
*
نلاحظ هنا أن الانتقال من الجزء الأول للثانى لا يعنى شيئ للمقاطعة – فقط أمر آخر للتنفيذ و يظل فى نمط المقاطعة حتى يجد أمر **RETI **ولا يهم أين**. **يلى ذلك فى الخانة**11 **أى هيكسا **B **مقاطعة التايمر صفر وهى عد الوقت، و نذكر أننا فى المرة الماضية لم نتمكن من عد آخر **59 **ثانية لتبسيط الكود لذا سنجرى تعديلات لنصحح الوضع**.*

*سنبدأ أولا باختبار الثوانى فإن لم تكن **= **صفر إذن هناك وقت ما للتشغيل ، فننقص الثوانى بواحد ثم نختبر إن كان يعمل بطاقة مخفضة فننفذها كما سيلى لاحقا و أخيرا ننتقل لعرض الزمن و العودة**.*
*فإن كانت الثوانى **= **الصفر ، سننتقل للعنوان **DEC_Min **اختصار **Decrement Minutes **حيث سنختبر الدقائق ، لو أيضا **= **صفر إذن انتهى الوقت و ننتقل للعنوان **All Done **حيث نعيد الأمور لبدايتها و نغلق الطاقة و نطلق الزمور ثم ندخل فى دورة داخل أخرى للحصول على زمن طويل ثم نوقف الزمور و نعود**. **أما لو الدقائق لا تساوى صفر إذن سننقصها بواحد و نعيد الثوانى **59 **ثانية ثم نعرض الوقت و نعود**.*
*الآن كيف نقلل الطاقة للفرن؟؟ مما سبق علمنا أن الماجنيترون لا يقبل تغير فى الجهد العالى و لا يقبل تعديل تسخين الفتيلة لذا لم يعد لدينا سوى تقطيع الجهد العالى**. **ستفكر فورا فى عرض النبضة **PWM **وهو أمر منطقى إلا أن المشكلة كيف فى جهد بضع الآف من الفولت و إبقاء السعر مناسب للاستخدام المنزلى ؟؟*
*لحسن الحظ أن انتقال الحرارة بطيء جدا فى الطعام و ظهور أثره يحتاج بعض الوقت و من المشاهدات العملية نجد أن البعض يرفع الإناء ثم يعيده ، حسنا هذا ما نفعله بالضبط**. **نطلق الطاقة ثوانى و نغلقها ثوانى فالثواني تناسب وحدة التقويم ذات الجهد العالى لتكتمل طاقتها فى جزء من الثانية و تفرغ أيضا عند قطعها فى جزء من الثانية، لذا سنختار وحدة زمنية و لتكن **10 **ثوانى و نطلق الطاقة ثانية و نوقفها **9 **ثوانى لطاقة **10% **أو نطلقها ثانيتين و نغلقها **8 **وهكذا**.*
*لهذا وضعنا متغير باسم **PowerSel **و فيه نختار كم ثانية نطلق الطاقة و آخر لنعد كم من هذه الثوانى العشرة قد انقضى**. **أظن الفكرة أصبحت واضحة الآن ، مع كل ثانية تحدث مقاطعة و بعد تعديل الزمن المتبقى ، سنذهب عند عنوان **TOUT **وهو فقط للتذكرة فإن كانت راية الطاقة المخفضة مرفوعة **LowHeat **سنزيد **CurrPwr **بواحد بالأمر **INC CrurPwr **ولاحظ أنه أمر مباشر على الذاكرة ولا يمر بالمراكم **(**لا مثيل له فى ميكروتشيب**) **ثم نضع الناتج فى **A **ونرى هل **=11 **أى عددنا الثوانى العشرة بالأمر **CJNE A,#11,NotYet **فإن كان **=11 **نجعله **= **صفر **(**لآحظ هنا أننا نغير ما فى الذاكرة و ليس المراكم وبهذا سنوفر أوامر الحفظ للذاكرة مرة أخرى**) **ثم نكمل فنأخذ القيمة المختارة **PowerSel **للمراكم **A **و نطرح منها القيمة الحالية و بالتالى سيكون **C = 1 **أو **= **صفر طبقا لما إن كان الوقت قد انتهى فننسخه مباشرة لطرف الخاص بتفعيل الجهد العالى بالأمر **Mov Hiv_Off,C*

*الآن كيف سننقص واحد من متغير الثوانى أو الدقائق؟*
*هل هذا سؤال؟ نطرح واحد أو الأفضل أيضا **Dec **اختصار **Decrement..**مهلا نريد معرفة أمر أو إثنين بخصوص الأرقام بالكود العشرى **BCD **اختصار **Binary Coded Decimal *
*الأرقام بالكود العشرى BCD :*

*تحفظ هذه الأرقام كما العادية فى بايت أو أكثر لكن كل بايت تحفظ فى النظام الثنائى من صفر إلى **255 **لكن فى هذا النظام من صفر إلى **99 **ولا يوجد أحرف فيه و يماثل النظام العشرى العادى المعتاد و هو وضع لتسهيل التعامل مع المبينات و الطباعة الخ**. **أى محاولة طباعة لرقم فسواء علمت بهذا أم استخدمت أمر لغة عالية تخفى عنك الخطوات، سيتم تحويله إلى أرقام **BCD **أولا ثم كل رقم مثلا **61 **فى بايت واحدة و تريد طباعته من اليسار لليمين ستأخذ العشرات أولا بحذف الآحاد **= 60 **ثم تبدله فيتحول إلى **06 **ثم تضيف إليه **030h **ثلاثون هيكسا ليتحول من عدد لحرف آسكى **ASCII Code **تفهمه الطابعة أو شاشة **LCD **أو أى جهاز آخر**.*
*مشكلة هذا العد أن تنفيذه سيكون بعدادات ثنائية أصلا فيها بعد **9 **يوجد **A **ثم **B **إلى **F **و هو لا يجوز فى هذا النظام فيجب أن تعلم ما إن كان العد أكبر من **9 **تصححه ، أيضا المشكلة الثانية أن من الآحاد للعشرات فالمحمول **= 16 **بينما يجب أن يساوى **10*
*فى الميكرو بروسيسور به مجموعة من الأعلام مخصصة لهذا الحساب و من ثم بعد الجمع أو الطرح كانت هذه الأعلام تفيد لتصحيح الناتج بتعليمه واحدة هى **DAA **اختصار **Decimal Adjust Accumulator .*
*هل تذكر بداية الحوار حول المتحكم و ذكرنا أنه **RISC **؟ حسنا من ضمن هذه الأمور التى اختصرت فى تركيبه عملية الطرح و بذلك أصبح ليس لدينا سوى الجمع **ADD **أو الجمع بالمحمول **ADDC **اختصار **Add with Carry*
*الآن أصبح إنقاص واحد ينفذ بإضافة **99 **هيكسا لأن مثلا **49 + 99 = 148 **بينما الواحد سيكون فى خانة **Carry **و الباقى **48 **فى المراكم **A **أى **48 **أقل من **49 **بواحد**. **ولا ننسى أن نضيف الأمر **DA A **للتصحيح بعد الجمع، *

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

*لكى نعرض الوقت نحتاج لعمل **Subroutine **لأننا سنطلبه كثيرا لذا نكتبه و نضعه فى أى مكان ولكن عادة ما تكون هذه صغيرة و تحتاج مراجعة و تأكد من سلامتها ثم ننساها لذا لو وضعت فى البدء لن تكون ذات تأثير على سير الأمور لكن ستهتم بكتابة باقى الكود ألذى يودى الوظيفة الرئيسية و من ثم ستظل أغلب الوقت تعبر هذه الأكواد التى تمت ولا حاجة لها أن تكون فى الطريق لذا من الأفضل دوما وضعها فى آخر البرنامج و الكود ألرئيسى فى الأول**. **لذا سنعرضه الآن لكن مكانه فى البرنامج فى آخره**.*
*لنكتب على الشاشات و طبقا للداتاشيت نحتاج وضع البيانات على المداخل ، و لو كان طرف **LE **اختصار **Latch Enable = **صفر ، ستظهر البيانات محلله على الشاشات و تتبع تغيرات الدخول و عندما تصير **= 1 **ستبقى آخر قيمة ظاهرة ولا تتغير بتغير الدخول**. **لذا نضع الثوانى على الحافلة ثم نخفض الطرف **seconds **للصفر ثم نعيده فتظهر الثوانى و تثبت ثم نضع الدقائق و نكرر و بديهى أن الترتيب لا يفرق**. **و سنجده لاحقا و الكود هكذا
*

```
[LEFT][B]ShowTime: ; ======== Display Time ========[/B]
[B]MOV Displays,Minutes[/B]
[B]CLR MinLatch[/B]
[B]nop[/B]
[B]Setb MinLatch[/B]
[B]MOV Displays,Seconds[/B]
[B]CLR SecLatch[/B]
[B]nop[/B]
[B]SETB SecLatch[/B]
[B]RET[/B][/LEFT]
```
*أول أمر ضع الدقائق على الحافلة ثم الأمر الثانى ضع صفر على **MinLatch **وهو من الرسم المتصل بطرف **LE **لوحدتى الدقائق و الأمر الثالث **NOP **اختصار **No Operation **أى فقط يستهلك بعض من الوقت حتى تثبت الدوائر الخارجية ثم نضع عليه واحد مرة أخرى حتى لا يقبل أى تعديلات**. **ثم بعد ذلك نضع الثوانى و نكرر مع **SecLatch **لتظهر الثوانى و تثبت ثم الأمر **RET **وهو للعودة من **Subroutine .*

*ولو أنت من عشاق استخدام الميكرو لفك الشفرة فيمكنك استبدال محللات الشفرة **CD4511 **و استخدام مسجلات إزاحة **74HC595 **و بذلك تحتاج لأقل عدد من الأطراف ثلاثة فقط و هنا يمكننى أن اقدم **AT89S4051 **وهو متحكم من ذات العائلة ولكنه صغير الحجم و يمكنه أن يكون أسرع من الأخريات لأن به خاصية **X2 **التى تمكنه من العمل على نصف تردد الكريستال بدلا من **1/12 **كما أنه يعمل من **2.7 **فولت و حتى **5 **فولت و به ريست مع انخفاض التغذية و من ثم لا حاجة لعمل دائرة لها و به **3 **عدادات **16 **بت و مقارن تماثلى يسبب مقاطعة عند عدة أحوال يفاضل بينها بتعديل فى مسجل خاص منها أن يعالج تأثير الأزرار**. **و من عدد الأطراف نجد لدينا طرف واحد أقل من المطلوب و يمكن أن نستغنى عن كاشف انخفاض الجهد ألعالى أو الإبقاء عليه و الاستغناء عن دائرة حساب الزمن من **50 **ذ**/**ث و تستخدم العدادات الداخلية للحساب باستخدام تايمر**2 **فى وضع **16 **بت ذاتى التحميل**. **و باستخدام الكريستال سيكون أدق من **50 **ذ**/**ث **. **المتحكم أيضا به **PWM **يعمل بدقة **8 **بت**. **و له **6 **مصادر للمقاطعة مع **4 **مستويات للأولوية بدلا من مستويين و به ذاكرة برنامج **4 **ك**.*
*باستخدامه تصبح الدائرة هكذا*





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

*كل الدوائر السابقة لم تختلف فى جزئية لوحة المفاتيح **Keypad **فهى غالبا غير متباينة و نادرا ما تتفاقم الأمور للحد ألذى يجعلنا نفكر كيف نستخدم محللات شفرة **Decoders **لتخفيض الأطراف من **8 **لأربعة أطراف فقط ولكن للضرورة أحكام لذا سيكون من المفيد أن نعلم كيفية قراءتها و بالأسيمبلى أولا و هو ما يسهل تقليده بأى من اللغات العالية وهذا موضوعنا القادم إن شاء الله**.*


----------



## ماجد عباس محمد (25 يوليو 2018)

*كود المفاتيح keyPad*

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

*كما سبق القول فمنافذ أتميل عندما تكون دخل أى وضع آحاد عليها، فهى فى الواقع توصل الطرف من خلال مقاومة جذب لأعلى ضعيفة وهذا سبب عدم قدرتها على الإمداد بتيار و حاجتنا لهذه الدائرة الخاصة لنتمكن من تفعيل الريلاى **. **بهذا لو وضعنا **FF **أو **255 **على منفذ سيكون كل الأطراف عليها **5 **فولت ولا حاجة لتوصيل مقاومات خارجية**. *
*الآن ضع صفر على طرف ما سيكون قادر على أن يبتلع مئات المرات التيار ألذى يصدره أى من الأطراف الباقية ، حسنا ما بقى أن نضغط الزر و نرى أين خرج هذا الصفر**.*

*قبل أن نفكر فى أى شيئ يجب تحديد وظائف الأزرار، فلدينا عادة عشرة أزرار متفق عليها من صفر إلى **9 **و لدينا سته متباينة لكن سنرقمهم من أعلى لأسفل بالأرقام **10 **، **11 **، **12 **، **13 **، **14 **ثم **15*




â€‹*هذه الأزرار يكتب عليها أى شيء فكما فى المثال السابق تكون **A,B,C,D **حيث **A=10 **و هكذا أو أحيانا **F1,F2,F3,F4 **حيث **F1 = 10 **وهكذا و يليها **# **قبل الصفر ثم *** **بعده و أحيانا **F1,F2,F3 **ثم **Enter **ورقمه **13 **ثم **Cancel **برقم **14 **ثم الصفر و أخيرا أى كلمة أخرى مثل **Mode **برقم **15*
*لنتفق مع أى لوحة أزرار قد نجدها سنجعل وظيفة **13 **هى **Enter **و تكون تشغيل الجهاز ثم **14 Cancel **بمعناها و تلغى فقط ما سبق إدخاله قبل التشغيل و أثناء التشغيل تكون إيقاف مؤقت كما فى حال فتح الباب و الأخير إيقاف تام أى إلغاء ما بقى من وقت و العودة للبدء**.*
*يبقى لدينا ثلاث أزرار أكواد **10 **و **11 **و **12 **فيمكننا جعل الأول أثناء العمل يزيد **10 **ثوانى و الثانى يزيد دقائق و الثالث يزيد **10 **دقائق و نظرا لعدم وجود زر آخر لتنقيص الرقم سنجعل كل منهم دوار بمعنى يتحرك من صفر إلى **9 **ثم صفر مرة أخرى ولا يحدث أى من الأرقام الأخرى فمثلا لو لديك **3:45 **ثم حركت الدقائق تصبح **3:55 **ثم **3:05 **وهكذا كما لو أنك أنقصت الرقم**. **و هكذا**.*
*هنا أيضا نحتاج أن نحدد كيف ندخل الطاقة المخفضة التى تحدثنا عنها**. **المشكلة أنه لم يعد لدينا أزرار لذا سنجعل زر **10 **مزدوج الأداء بمعنى لو ضغط قبل التشغيل يتولى ضبط نسبة الطاقة و إن ضغط أثناء التشغيل يزود الزمن **10 **ثوانى كما اتفقنا**.*
*هذا الكود يحتاج بضع احتياطات مثلا لو ضغطت على زر سيقرأه المتحكم عدة مرات لسرعته فى تنفيذ الأوامر ، لذا سنحتاج أن نتأكد من أن الزر قد ترك قبل أن نعيد القراءة و أبسط حل إضاعة نصف ثانية حتى يرفع الشخص يده و لهذا ميزة و عيب أنه يمكنك من تكرار الإدخال دون الحاجة لرفع الأصبع لكن عيبه أنه يختلف من شخص لآخر، و هناك من يضع دورة يقرأ ذات الكود حتى يتغير و لكن لدينا إمكانيه المقارنة و القفز عند التساوى وهى تحتاج **3 **بايت **.*

*حل ثالث هو أننا نبدأ بوضع **255 **أو **FF **على الخرج فإن كان هناك كود تحول إلى قيمة من صفر إلى **15 **أى **0F **و من ثم نستشعر البت رقم **7 **و نستخدمها **Flag **، طالما هناك كود سيكون **= **صفر أما لو رفع الإصبع سيكون **=1 *
*بهذا و بمجرد إضافة تعريف بلا كود نستطيع أن نختبر هذه البت بدلا من أمر قارن و اقفز **CJNE **و هكذا نضع عنوان*

```
[LEFT][SIZE=3]
ReadAndChk:
[B]ACALL[/B] ReadKPD
[B]JNB[/B] NoKey[B],[/B]ReadAndChk [COLOR=#008080]          ; Wait key released[/COLOR]
RAC:
[B]ACALL[/B] ReadKPD
[B]JB[/B] NoKey[B],[/B]RAC                       [COLOR=#008080]    ; wait Key pressed[/COLOR]
[B]MOV[/B] [B]A[/B][B],#[/B]9                      [COLOR=#008080]           ; Put 9 in Accumulator[/COLOR]
[B]CLR[/B] [B]C                            [/B][COLOR=#008080] ; clear carry[/COLOR]
[B]SUBB[/B] [B]A[/B][B],[/B][B]B                     [/B][COLOR=#008080] ; Command Or Number[/COLOR]
[B]RET[/B]
[/SIZE][/LEFT]
```
*
ثم نقرأ الأزرار ونختبر البت رقم **7 **و التى أسميناها *NoKey *بالأمر **JNB **و طالما هى بصفر أى يوجد رقم سابق فننتقل للعنوان و بهذا ننتظر رفع الأصبع عن الأزرار و بعدها يدخل فى الاختبار التالى لانتظار رقم بالضغط على زرار و ألذى بدوره يجعلها **= **صفر ، بهذا نقرأ الرقم**. **بعد ذلك نضع فى المراكم **9 **و نطرح منه كود الزرار فلو كان من صفر إلى **9 **لن يكون هناك **C **أى رقم و إلا سيكون **C=1 **أى أمر من الستة و هكذا حللنا كل البيانات المطلوبة**.*
*قراءة الأزرار KeyPad*

*بقى كود قراءة الأزرار وهو ببساطة كما ذكرنا نضع **FF **كخرج ثم صفر على أى طرف و نقرا أين ظهر و منه نحدد الكود ثم نعود*

```
[LEFT][B][SIZE=4]
ReadKPD:
MOV KeyValue,#255 ; No key code
Mov R4,#5  ; Read 5 times
KPDLOOP:
MOV KeyPad, #254 ; 1111 1110 COL4
JB ROW1,C4R2
MOV KeyValue,#10 ; F1 or A pressed ret 0xA = 10
RET
C4R2: JB ROW2,C4R3
MOV KeyValue,#11 ; F2 or B pressed ret 0xB = 11
RET
C4R3: JB ROW3,C4R4
MOV KeyValue,#12 ; F3 or C pressed ret 0xC = 12
RET
C4R4: JB ROW4,C3R1
MOV KeyValue,#13 ; Enter Pressed ret 0xD = 13
RET
C3R1: MOV KeyPad,#11111101b ; Col3
JB ROW1,C3R2
MOV KeyValue,#3 ; 3 pressed ret 3
RET
C3R2: JB ROW2,C3R3
MOV KeyValue,#6 ; 6 pressed ret 6
Ret 
C3R3: JB ROW3,C3R4
MOV KeyValue,#9 ; 9 pressed
Ret 
C3R4: JB ROW4,C2R1
MOV KeyValue,#14 ; "cancel" btn pressed
Ret 
C2R1: MOV KeyPad,#11111011b ; Col2
JB ROW1,C2R2
MOV KeyValue,#2 ; 2 pressed
Ret 
C2R2: JB ROW2,C2R3
MOV KeyValue,#5 ; 5 pressed
Ret 
C2R3: JB ROW3,C2R4
MOV KeyValue,#8 ; 8 pressed
Ret 
C2R4: JB ROW4,C1R1
MOV KeyValue,#0 ; 0 pressed
Ret 
C1R1: MOV KeyPad,#11110111b ; Col1
JB ROW1,C1R2
MOV KeyValue,#1 ; 1 pressed
Ret 
C1R2: JB ROW2,C1R3
MOV KeyValue,#4 ; 4 pressed
Ret 
C1R3: JB ROW3,C1R4
MOV KeyValue,#7 ; 7 pressed
Ret 
C1R4: JB ROW4,CR00
MOV KeyValue,#15 ; Mode pressed
RET
CR00: DJNZ R4,KPDLOOP
RET[/SIZE][/B]
[/LEFT]
```
*طبعا ستسأل من أين أتينا بهذه الأكواد أى عندما نضع كذا و نقرأ كذا يكون الرد هو **5 **وليس **7*
*ببساطة من الرسم حيث تجد الصفوف و الأعمدة ثم تفترض أنك ستضع على صف **1 **فأين سيخرج بالضغط على عامود **1 **و هكذا**.*
*لو اتبعت الخطوات بدقة مع الرسم الصحيح على البوردة و مطابقتها من لوحة الأزرار لا يجب أن تجد مشاكل لكن ماذا نفعل لو حدثت؟ لن نلقى بالمشروع فى القمامة**! **أولا جرب قلب المدخل فلوحة الأزرار لها **8 **طرف و ستضعها على مشط من **8 **طرف و ربما عكسته أثناء الإدخال**.*
*لم يأتى بالكثير إذا ماذا نفعل؟ فرضا اللوحة مختلفة كليا عما توقعناه و رسمناه**..*
*الحل بسيط جدا ،ـ ورقة و قلم و اضغط على زر **1 **و اقرأ ما ظهر و ليكن **5 **مثلا، اكتب فى الورقة **1 > 5 **مثلا ثم كرر مع زر**2 **ثم **3 **وهكذا*
*الآن فى المترجم ستجد جملة *
*MOV* KeyValue*,#*1 ; 1 pressed
*لكنها الآن أعطت **5 **فنغير كل واحد بخمسة فتصبح*
*MOV* KeyValue*,#*5 ; 5 pressed *
*و الآن أضفنا نجمة لنتذكر أن هذا السطر قد تم تعديله أو تصحيحه وهكذا حتى تصحح الستة عشر زرار**.*

*المرة القادمة إن شاء الله نتحدث عن باقى البرنامج*


----------



## ماجد عباس محمد (26 يوليو 2018)

*برنامج الميكرو ويف*

*أول البرنامج هو العنوان **StartIt **حيث نبدأ أولا بالتهيئة وكل تعليماته سبق شرحها فى برنامج الغسالة و الجديد فقط هو تصفير الدقائق و الثوانى ثم نطلب برنامج عرض الوقت**.
*

```
[LEFT][B][SIZE=3][COLOR=#008080];=====================================
; CODE SEGMENT
;=====================================
[/COLOR]
Startit: 
MOV IE,#10000011b  [COLOR=#008080]    ; Enable T0 & INT0 external[/COLOR]
MOV TH0,#205 [COLOR=#008080]              ; Auto reload[/COLOR]
MOV TL0,#205 
MOV TMOD,#00000110b[COLOR=#008080] ; T0 8bit counter auto reload[/COLOR]
MOV TCON,#1[COLOR=#008080]                  ; Clr All interrupts, Set INT0 Edge trigger[/COLOR]
MOV SP,#70[COLOR=#008080]                    ; Move stack away[/COLOR]
MOV Relays,#0[COLOR=#008080]                 ; Reset All PORTS! select Small cold cycle[/COLOR]
MOV Relays,#255
MOV Controls,#255
MOV MinLeft,#0
Mov SecLeft,#0
ACALL ShowTime


[/SIZE][/B][/LEFT]
```
*بعد عرض الوقت تأتى الدورة التكرارية وهى قسمين الأول لمعالجة الأعداد و الثانى لمعالجة الأوامر**.*
*تبدأ بعنوان العودة للبدء باسم *LoopAll *ثم نطلب كود قراءة الأزرار و اختبارها وهو كما سبق سيعيد قيمة هذا الزرار فى المراكم **B **وهذا لسبب أن المراكم **A **و المراكم **B **فقط يمكن أن تشير إلى بت واحدة منهم و السبب لو تذكر فى مسجل الوظائف الخاصة يمكنك الإشارة لأى بت من العمود الأول فقط و به المنافذ كاملة و كل من **A **و **B . **لكن و بسبب **RISC **أيضا لا تستطيع الإشارة لأى بت فى الذاكرة – فقط بايت كاملة**.
*

```
[LEFT][B][SIZE=3]LoopAll: 
ACALL ReadAndChk
JC LoopAll[COLOR=#008080]                       ; Number first[/COLOR]
MOV SecLeft,B  [COLOR=#008080]              ; Add SecLeft[/COLOR]
ACALL ShowTime [COLOR=#008080]            ; Display it[/COLOR]
TenSec:
[/SIZE][/B]
[/LEFT]
```
*الآن أيضا نعرف هل هو رقم من صفر إلى **9 **أم هو أمر من **10 **إلى **15 **من الراية **C **فلو **=1 **يكون أمر ، إذن نستخدم **Jc و**هو يعنى **Jump If Carry set **لنعود للبدء مرة أخرى و ذلك لسبب أنك لا تدخل أمرا الأول فلا يجوز تشغيل الجهاز بدون وضع وقت التشغيل أولا**.*
*لو كان هذا رقم ستعتمده كآحاد للثوانى بحفظه فى الثوانى ثم تطلب عرض الأرقام ليراه المستخدم ثم تعود لتبحث ماذا بعد**.*
*سيكون التالى إما أمر للتنفيذ أو رقم للإضافة 
*

```
[LEFT][B][SIZE=3]
TenSec:
ACALL ReadAndChk
JC ChkCmnd       [COLOR=#008080]      ; Command[/COLOR] 
MOV A,SecLeft
SWAP A
ADD A,B  [COLOR=#008080]                    ; Add SecLeft[/COLOR]
MOV SecLeft,A[COLOR=#008080]            ; save[/COLOR]
ACALL ShowTime[COLOR=#008080]        ; Display it[/COLOR]
ReadMin:[/SIZE][/B][/LEFT]
```
*أول أمر لقراءة واختبار الأزرار ثم اختبار لو أمر نذهب لكود تحليل الأوامر و إلا نعتبر هذا الرقم تعديل للثوانى أى ما سبق سيصبح عشرات ثوانى و الجديد آحاد**. **الآن نقرأ الثوانى فتكون مثلا **03 **للمراكم **A **ثم ننفذ الأمر *
*SWAP* *A*
*و ألذى يبدل النصفين معا فيصبح **30 **و الآن نضيف القيمة الجديدة و بفرض أنها **6 **ستكون **36 **ثم نحفظ الناتج فى ثوانى مرة أخرى**.*
*يلى ذلك قراءة الدقائق و جدير بالذكر أن هذه العناوين لا حاجة لها فى البرنامج ولكنها تعرفك ما هذا الجزء**. **البعض يستخدم تعليق فى صورة جمالية مثل**;************** Read Minutes ******************​*وهذا أفضل لأنه يتيح لك إضافة ما تشاء من تعليقات للتوضيح**. **يلى ذلك قراءة الدقائق حيث نبدأ كما سبق بقراءة و تحليل الأزرار فإن كان أمرا نذهب لتحليله و إلا كرقم نضيفه**.
*

```
[LEFT][B][SIZE=3]ReadMin:
ACALL ReadAndChk
JC ChkCmnd[COLOR=#008080]               ; Command [/COLOR]
MOV A,SecLeft 
SWAP A [COLOR=#008080]                       ; Keep ten SecLeft to make it MinLeft[/COLOR]
ANL A,#0Fh[COLOR=#008080]                 ; now it is units[/COLOR]
MOV MinLeft,A[COLOR=#008080]            ; save MinLeft [/COLOR]
Mov A,SecLeft  [COLOR=#008080]            ; get SecLeft and save tens[/COLOR]
ANL A,#0Fh [COLOR=#008080]                 ; Keep units[/COLOR]
Swap A
ADD A,B 
Mov SecLeft,A[COLOR=#008080]               ; save[/COLOR]
ACALL ShowTime [COLOR=#008080]        ; Display it [/COLOR]
TenMinLeft:[/SIZE][/B][/LEFT]
```
*لكى نضيف الرقم كثوانى نحتاج تعديل ما سبق، فنقرأ الثوانى أولا للمراكم و كانت **36 **ثم بالأمر **SWAP **سيصبح **63 **و بالأمر **AND “**مع**" **السابق شرحه نبقى منه **03 **و نحفظها فى الدقائق**. **بعدها نعيد قراءة الثوانى **36 **و نبقى **06 **ثم نبدله ليصبح **60 **ثم نجمع عليه الرقم الجديد و ليكن **1 **فتصبح **61 **نحفظها فى الثوانى**.*

```
[LEFT][B][SIZE=3]
TenMinLeft:
ACALL ReadAndChk
JC ChkCmnd    [COLOR=#008080]                   ; A Command[/COLOR]
Mov A, SecLeft
Swap A           [COLOR=#008080]                    ; Make it tens [/COLOR]
ANL A,#0F0h    [COLOR=#008080]                   ; get tens[/COLOR]
ADD A,B        [COLOR=#008080]                       ; add new units[/COLOR]
Xch A,SecLeft 
ANL A,#0F0h    [COLOR=#008080]                   ; delete units[/COLOR]
ADD A, MinLeft  [COLOR=#008080]                  ; Make 2 digits swapped[/COLOR]
Swap A
MOV MinLeft,A  [COLOR=#008080]                  ; save it [/COLOR]
ACALL ShowTime
Wait4Command:
ACALL ReadAndChk
JNC Wait4Command  [COLOR=#008080]          ; not A Command[/COLOR]
ChkCmnd:
[/SIZE][/B][/LEFT]
```

*الأمر الأول و الثانى كما سبق و الآن لدينا الرقم الرابع للقيمة **361 **، نقرأ الثوانى **61 **و نبدلها **16 **و نبقى **10 **و نجمع عليه الجديد وليكن خمسة فيصبح **15 **الآن نريد حفظه فى الثوانى دون تغيير قيمتها لنأخذ منها للدقائق**. **حسنا لدينا الأمر **XCH **وهو بمعنى **Exchange **أى تبديل و فى أمر واحد نضع ما فى **A **فى الثوانى و نأخذ ما فى الثوانى فى **A **و يذلك تصبح الثوانى **15 **و **A **به **61 **فنحذف الآحاد لتصبح **60 **فنضيف عليها الدقائق و كانت **03 **فتصبح **63 **ثم نبدله لتصبح **36 **و نحفظها فى الدقائق**. **ممكن استخدام هذا الأمر فى جزء الدقائق السابق إلا أنه بهدف التعليم نتعرض لأكثر من طريقة**.*
*لو ادخلنا **4 **أرقام إذن لا بد من أمر لذا ننتظر وصول أمر وهو من العنوان *Wait4Command *ثم نقرأ ونختبر الأزرار فإن كان رقم نكرر حتى يأتى أمر ننتقل لتحليل الأوامر فى الجزء *ChkCmnd *وهذا موضوعنا القادم إن شاء الله*


----------



## ماجد عباس محمد (27 يوليو 2018)

*تحليل الأوامر :*

*لدينا كما ذكرنا سته أوامر بأرقام من **10 **إلى **15 **و **10 **له أكثر من وظيفة ، لذا و برغم التسلسل المنطقى أن نحلل بالترتيب إلا أننى أفضل البدء بالرقم **13 **وهو **Enter **أى بدء التشغيل**. **جدير بالذكر أنه لا فرق أين تضع ماذا فالأمر هنا خمسة تعليمات **CJNE **لفحص خمسة أوامر منها و إن لم يكن كذلك فلا جدوى من اختبار الأمر السادس**. *
*فى العنوان الأول **ChkCmnd **سننقل القيمة من **B **إلى **A **لنجرى عليه اختباراتنا ثم **CJNE **بقيمة **10 **أو ننتقل للعنوان **ADD10 **برقم **11 **حيث نكرر الاختبار بالرقم **11 **و ننتقل لو مختلف للعنوان **ADD10Min **و هناك نختبر بالرقم **12 **فننتقل للرقم **13 **بعنوان **Enter **و هنا للتوضيح*

```
[LEFT][B][SIZE=4]
Enter:    [COLOR=#008080]                     ; 13 = Enter or Run[/COLOR]
CJNE A,#13,Cancel
MOV A,SecLeft
Add a,MinLeft [COLOR=#008080]           ; Sum = F2 max[/COLOR]
JZ Nothing   [COLOR=#008080]               ; Time not set[/COLOR]
SETB JobPending
SETB TR0    [COLOR=#008080]                ; Start Timer/Counter[/COLOR]
CLR OFF_Non  [COLOR=#008080]            ; power on[/COLOR]
CLR HIv_Off    [COLOR=#008080]            ; Turn On Hi voltage[/COLOR]
Nothing:
SJMP Back 
Cancel: 

[/SIZE][/B][/LEFT]
```
*
حيث نقارن بالرقم **13 **فإن اختلف ننتقل لأمر *Cancel *أو نكمل حيث نقرأ الثوانى فى **A **ثم نجمع عليها الدقائق و ننتقل لو الناتج **= **صفر لعنوان **Nothing **و ألذى ينقلنا لعنوان **Back **وهو من اسمه نعرض الأرقام ثم نعود لأول البرنامج أى لأن الزمن **= **صفرا فلا تفعيل لأى أمر**. * ربما فكرت أن الدالة المطلوبة هى دقائق =0 مع AND ثوانى = 0 لكن فكر كم خطوة ستحتاج، لذا فكرة مختلفة غير نمطيه توفر الكثير. *طبعا ستسأل لماذا لم نكتب*
*JZ Back*
*من الممكن ذلك لكن هكذا لم تضيف أى أمر و يمكنك نقل الكتلة البرمجية دون خشية تعدى حدود **128 **خطوة**.*
*أما لو كان هناك زمن لا يساوى صفر فسنقيم الراية *JobPending *وهى الدالة على أن الجهاز الآن فى حال التشغيل ثم نفعل البت **TR0 **لتشغيل التايمر و نجعل كل من **OFF_Non و Hiv_Off = **صفر لتشغيل الماجنيترون و يظل الوضع هكذا حتى ينتهى الوقت و فى كود المقاطعة ستنعكس حالة هذه البت الأربع**. **هكذا سنعلم ما إن كان الماجنيترون يعمل أم لا*
*الآن نأخذ باقى الأوامر بالترتيب**. **أولا الرقم **10 **وهو لو كان الماجنيترون يعمل يؤدى وظيفة تغيير الزمن **10 **ثوانى كل مرة أما لو الماجنيترون لا يعمل فسيحدد نسبة الطاقة*

```
[LEFT][B][SIZE=4]
ChkCmnd:   [COLOR=#008080]        ; If 10 then either ADD 10 secinds or set Low Power[/COLOR]
MOV A,B
CJNE A,#10,AddMinLeft [COLOR=#008080]       ; 10 = Add 10 sec[/COLOR]
JB JobPending,Add10 [COLOR=#008080]          ; It is Running, so increase time[/COLOR]
Mov Displays,#0FFh  [COLOR=#008080]           ; Display Blank MinLeft[/COLOR]
CLR MinLatch
nop
Setb MinLatch
MOV Displays,#0
CLR SecLatch
nop
SETB SecLatch[COLOR=#008080]                    ; Show -- 00[/COLOR]

Acall ReadAndChk
JC ChkCmnd [COLOR=#008080]                      ; if Command, cancel Low Power [/COLOR]
SetLow: Mov PowerSel,B
Setb LowHeat
MOV A,B
Swap A
Mov Displays,A
CLR SecLatch
nop
SETB SecLatch  [COLOR=#008080]                   ; Show -- x0[/COLOR]
MOV CurrPwr,#0
Acall ReadAndChk
JC ChkCmnd
sjmp SetLow
Add10:

[/SIZE][/B][/LEFT]
```
*
هنا نختبر لو الأمر لا يساوى **10 **ننتقل للأمر التالى و إلا نفحص **JobPending **و لو **=1 **إذن الماجنيترون يعمل و ننتقل لزيادة الزمن و إلا نطلب من المستخدم تحديد النسبة**. **سنضع على **Displays **القيمة **FF **وهى **= 255 **و هذه تجعل محلل الشفرات لا يعطى أى شيئ و يجعل الشاشات مطفأة ، وهذه علامة للمستخدم**. **لو تستخدم رقم غير **4011 **يمكنك اختيار أى كود يلائمك**. **بعد ذلك تضع نبضة على خط **MinLatch **فتظهر شاشتين مطفأتين ثم نضع صفر على **Displays **و نضع نبضة على **SecLatch **فيظهر صفرين**. **و عندها نقرأ الأزرار و نختبر **C **فإن كان رقم فهو النسبة ولو كان أمر نلغى خيار القدرة المخفضة ونعود من جديد فى انتظار أمر**.*
*لو كان رقم سننسخ ما فى **B **لمتغير **PowerSel **كما سبق الشرح أننا سنشغل الجهد العالى بضع ثوانى و نوقفه باقى الثوانى العشرة**. **بعد ذلك نقيم الراية **LowHeat **لنعلم ذلك أثناء كود المقاطعة و حساب الزمن ثم ننسخ هذا الرقم من **B **إلى **A **و لو كان مثلا **4 **سنقلبه ليصبح **40 **و نضعه على **Displays **و نضع نبضة على **SecLatch **فيظهر الرقم **40 **ثم نصفر **CurrPwr **الذى يحدد أين نحن من الثوانى العشرة ثم نقرأ مرة أخرى الأزرار **. **الآن لو عدد سنعيد الكرة أى أن المستخدم بعد أن اختار **40% **عاد و اختار **60% **مثلا أما لو كان أمر سننتقل لتحليله من جديد**.*

```
[LEFT][B][SIZE=4]
Add10: 
MOV A,SecLeft
ADD A,#10h [COLOR=#008080]                   ; Add 10 sec[/COLOR]
DA A 
MOV SecLeft,A [COLOR=#008080]                ; Save it Back[/COLOR]
SJMP Back
AddMinLeft
[COLOR=#008080]هنا سيكون الوضع الماجنيترون يعمل و المطلوب زيادة الثوانى ، نقرأ الثوانى ثم نضيف هيكسا 10 و الأمر DAA ثم نحفظه[/COLOR]
AddMinLeft: [COLOR=#008080]                    ; 11 = Add MinLeft[/COLOR]
CJNE A,#11,Add10Min
JNB JobPending,Back [COLOR=#008080]     ; if not running do nothing[/COLOR]
MOV A,MinLeft
ANL A,#0F0h  [COLOR=#008080]                  ; Keep tens[/COLOR]
MOV B,A   [COLOR=#008080]                        ; save it[/COLOR]
MOV A,MinLeft
ANL A,#00Fh  [COLOR=#008080]                 ; Keep ones[/COLOR]
ADD A,#1
DA A
ANL A,#00Fh [COLOR=#008080]                   ; Keep ones[/COLOR]
ADD A,B
MOV MinLeft,A 
SJMP Back 
Add10Min:[COLOR=#008080]              ; 12 = Add 10 MinLeft[/COLOR]
[/SIZE][/B][/LEFT]
```
*
هنا الأمر مكرر إلا أننا نعدل الدقائق بدلا من عشرات الثوانى فنقارن لو لا يساوى **11 **ننتقل للتالى أو نفحص **JobPending **فلو لا يعمل الماجنيترون نعود لنكرر الدورة أو لو كان يعمل نكمل إذن بقراءة الدقائق **. **لا توجد وسيلة لزيادة الرقم دون التأثير على العشرات فإما نقارن بالعدد **9 **إلا أننا لا نعلم العشرات فقد تكون من **0x **إلى **9x **لذا سنستخدم **AND **لحذف الآحاد و الإبقاء على العشرات فقط و نحفظها فى **B **ثم نعيد قراءة الدقائق و نحذف العشرات هذه المرة و نجمع لها **1 **ثم **DA **و بعد ذلك نعيد حذف العشرات لأن **9 **بإضافة **1 **ستصبح **A **و الأمر **DAA **سيحولها إلى **10 **لذا وجب حذف العشرات**. **ثم نجمع ما حفظناه فى **B **و نعيده للدقائق*
*


كود:


[/SIZE][/B][LEFT][B][SIZE=4]Add10Min:
CJNE A,#12,Enter 
JNB JobPending,Back [COLOR=#008080]          ; if not running do nothing[/COLOR]
MOV A,MinLeft
ADD A,#10h
DA A
MOV MinLeft,A
SJMP Back 
Enter:         [COLOR=#008080]                           ; 13 = Enter or Run[/COLOR]
CJNE A,#13,Cancel
MOV A,SecLeft
Add a,MinLeft  [COLOR=#008080]                       ; Sum = F2 max[/COLOR]
JZ Nothing      [COLOR=#008080]                       ; Time not set[/COLOR]
JB DoorOpen,$[COLOR=#008080]                      ; Wait Door Close[/COLOR]
SETB JobPending
SETB TR0   [COLOR=#008080]                            ; Start Timer/Counter[/COLOR]
CLR OFF_Non[COLOR=#008080]                        ; power on[/COLOR]
CLR HIv_Off  [COLOR=#008080]                        ; Turn On Hi voltage[/COLOR]
Nothing:
SJMP Back 
Cancel:      [COLOR=#008080]                              ; 14 = Cancel[/COLOR]
CJNE A,#14,StopAll [COLOR=#008080]                 ; enter, run oven[/COLOR]
JB DoorOpen,$  [COLOR=#008080]                       ; Wait Door Close[/COLOR]
JNB JobPending,Back [COLOR=#008080]            ; If not running , Do nothing[/COLOR]
CPL TR0  [COLOR=#008080]                 ; stop if runnuig or run if stopped Timer/Counter[/COLOR]
CPL OFF_Non     [COLOR=#008080]                  ; Reverse On / Off[/COLOR] 
Ajmp Back 
StopAll: 
ajmp StartIt 
Back: 
ACALL ShowTime
AJMP LoopAll 
[/SIZE][/B][/LEFT]

الأمر Enter سبق شرحه و بقى الأمر Cancel وهو إيقاف مؤقت. فنقارن بالرقم 14 فإن لم يتساوى فهو 15 أى إلغاء تام وهو بدء من جديد. أما لو تساوى فننتظر غلق الباب لو مفتوح فربما أثناء الإيقاف تم فتح الباب لأى سبب ثم نعكس وضع التشغيل بالأمر CPL أى Complement فإن كان متوقفا سيعمل و إن كان يعمل سيتوقف.
إضافات كودية

لو لا تتقبل حسابات BCD فيمكنك ببساطة استخدام الحساب الثنائى العادى و كل ما هنالك ستحتاج لتحليل البايت سواء ثوانى أو دقائق لمكونيها الآحاد و العشرات ثم تضعها على Displays للعرض
ذلك بأمر بسيط جدا وهو DIV ِAB وهو يقسم محتوى A على محتوى B و يكون المراكم A به الرقم الصحيح و الباقى فى B لذا ببساطة ضع فى A الثوانى أو الدقائق و ضع فى B الرقم 10 عشرى أى A هكس و بتنفيذ الأمر تقسم ما فى A على 10 فيبقى فى A عشرات الثوانى و فى B أحاد الثوانى
و إن شئت تجميعهما مرة أخرى أيضا استخدم الأمر MUL AB فيمكنك وضع عشرات الثوانى مثلا فى A و الرقم 10 فى B و بتنفيذ الأمر سيتم ضرب عشرات الثوانى فى 10 ثم تجمع عليها الآحاد.
هنا نقطة يجب ذكرها أن ناتج ضرب 8 بت فى 8 بت = 16 بت تكون الثمانية الأعلى منها فى B و الأقل فى A لكن أقصى رقم فى هذا التطبيق هو  ضرب 9 فى 10 = 90 أقل من بايت واحدة 255 لذا سيكون بكامله فى A
المرة القادمة غن شاء الله نستخدم AVR مع بيزك ثم ميكرو تشيب مع C*


----------



## ماجد عباس محمد (28 يوليو 2018)

*استخدام AVR مع البيزك*

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




*نأتى للكود و طبعا كل مترجم له مكتبة أساسية تعتمد لوحة الأزرار و تدعم الشاشات بأنواعها و يمكننها استخدامها ولكن مشكلة الأزرار حقيقة لو لم تعمل فلا حيلة لديك لكى تقوم بالتصحيح ألذى قمنا به فى الأسيمبلى **. **طبعا يمكن عمل ما يسمى **Lookup Table **أو جدول البحث حيث تضع فيه كم من المدخلات و مقابلها من القيم المطلوبة فيكون لو كان واحد فتبحث فى الجدول عن القيمة واحد فتجد الصواب هو **3 **و هذا يكون فى صورة مصفوفة من البيانات وهى مستهلكة للكود و الذاكرة**. **أيضا كما سبق تبنينا الدائرة التقليدية فى تفعيل الريلاى أى **1 = **تشغيل و صفر إيقاف**. *

```
[LEFT][SIZE=4]$regfile = "m16adef.dat"
$crystal = 4000000
$hwstack = 40
$swstack = 16
$framesize = 32

Displays Alias Porta : Controls Alias Portb : Keypad Alias Portc : Relays Alias Portd
Keyread Alias Pinc

Dooropen Alias Relays.2 : Buzzer Alias Relays.4 : Off_non Alias Relays.5 : Hiv_on Alias Relays.6
Seclatch Alias Controls.1 : Minlatch Alias Controls.2
Const Adigit = 0 : Const Acmnd = 1

[COLOR=#008080]' VARIABLES[/COLOR]
Dim Lowheat As Bit , Jobpending As Bit , Nokey As Bit , Cmd_ndgt As Bit
Dim Secleft As Byte , Minleft As Byte , Powersel As Byte , Currpwr As Byte
Dim Keyvalue As Byte , Cntr As Byte , Tmp As Byte

Declare Sub Showtime() : Declare Sub Readandchk() : Declare Sub Readkpd()[/SIZE][/LEFT]
```
*
البنود الخمسة الأولى لتحديد مجال العمل للمترجم وسبق شرحها فى البرنامج السابق الخاص بالغسالة ، يليه التعريفات و نلاحظ هنا أننا لم نعرف أطراف الأزرار فقط حددنا المنفذ **PORT **و أيضا استخدمنا تعريفين للأزرار واحد للقراءة وهو للمنفذ **PORTC **و الآخر للأطراف بهدف القراءة منها و يخص **PINC **و أضفنا ثابت **"**رقم**" adigit **ويساوى صفر و آخر **"**أمر**"ACMD = 1 **وهذا للتسهيل فبعد قراءة الأزرار نبحث إن كان رقم أم أمر وهو صفر أم **1 **و هذا أسهل للتذكرة **.*

```
[LEFT][SIZE=4]Startit:
Config Displays = Output : Config Keypad = &H0F : Config Controls = 254
Config Relays = &HF0
Config Timer0 = Counter , Edge = Falling
Timer0 = 205                   [COLOR=#008080]                ' Was Th0 = 205[/COLOR]
Enable Interrupts : Enable Int0
Relays = &H0F : Controls = 255 [COLOR=#008080]    ' Pulup for Door Open Sw
[/COLOR]On Int0 Emergency , Nosave
On Timer0 Counttime
Minleft = 0 : Secleft = 0 : Showtime
[/SIZE][/LEFT]
```
*يلى ذلك أول البرنامج وهو التهيئة حيث أوامر تهيئة المنافذ كدخول أو خروج أو كما فى لوحة الأزرار نصفها دخول و ألنصف خروج**. **يلى ذلك كما فى الأسيمبلى جزء الدورة ألمستديمة ثم دورة قراءة الأزرار مع الفحص و التكرار حتى تقرأ رقم كما سبق تماما و فى كود القراءة نفس الخطوات **(**وليس الأوامر**) **لمتابعة القراءة و فحص كونها رقم أو أمر الخ**. **و هنا يعتمد الرقم كثوانى مثلا **6 **ثم تعرض ثم تعيد القراءة والفحص، لو أمر تذهب لعنوان فحص الأوامر و إلا نكرر نفس الخطوات السابقة لعمل عشرات الثوانى**. **نضرب الثوانى فى **10 **تصبح **60 **و نضيف لها الجديد مثلا **5 **فتصبح **65 **ثم نعرض و نعيد القراءة مع الفحص**.*
*هنا وجب التنويه عن نقطة هامة وهى أن الضرب فى **10 **و الجمع يجب أن يكونا فى خطوة واحدة هكذا*
*SecLeft = (SecLeft * 10) + KeyValue*
*لكنها قصور المترجم النسخة المجانية*

```
[LEFT][SIZE=4]Do
Do
Readandchk
Loop Until Cmd_ndgt = Adigit
Secleft = Keyvalue : Showtime : Readandchk
If Cmd_ndgt = Acmnd Then Goto Chkcmnd
Secleft = Secleft * 10 'make 10 seconds
Secleft = Secleft + Keyvalue
Showtime
Readandchk
If Cmd_ndgt = Acmnd Then Goto Chkcmnd
Minleft = Secleft \ 10
Tmp = Secleft Mod 10   [COLOR=#008080]    ' a digit, make minutes[/COLOR]
Secleft = Keyvalue + Tmp : Showtime : Readandchk
If Cmd_ndgt = Acmnd Then Goto Chkcmnd
Tmp = Secleft \ 10 : Minleft = 10 * Minleft
Minleft = Minleft + Tmp     [COLOR=#008080]    ' adigit make ten minutes[/COLOR]
Readandchk
If Cmd_ndgt = Acmnd Then Goto Chkcmnd
Tmp = Secleft / 10
Minleft = Minleft * 10           [COLOR=#008080]    ' a last digit, make 10 min[/COLOR]
Minleft = Minleft + Tmp : Tmp = Secleft Mod 10
Secleft = Secleft + Keyvalue
Do     [COLOR=#008080]    ' wait For command[/COLOR]
Readandchk
Loop Until Cmd_ndgt = Acmnd[/SIZE][/LEFT]
```
*
الآن لو أمر ننتقل أو نكون الدقائق و ذلك بأن نقسم الثوانى على **10 **فنحصل على عشرات الثوانى **65 ÷ 10 = 6 **و نضعه كدقائق ثم نستخدم الدالة **Mod **اختصار **Modulus **وهى المتبقى من القسمة فالأمر *Tmp *=* Secleft *Mod* 10 
*يضع فى المتغير **Tmp **باقى القسمة وهو **5 **ثم نضربه فى **10 **ليصبح **50 **و نضيف الجديد وليكن **4 **لتصبح **54 **و نعرض ثم نعيد القراءة مع الفحص و إن كان أمر ننتقل أو نكون عشرات الدقائق بضرب الدقائق فى **10 **لتكون **60 **ثم نقسم الثوانى على **10 **لنحصل على **5 **نجمعها مع الدقائق لتكون **65 **ثم نحصل على المتبقى من الثوانى **4 **نضربه فى **10 **أى **40 **و نضيف له الجديد و ليكن صفرا فتصبح **40 **و الزمن الكلى الآن **65 **دقيقة و **40 **ثانية و الآن بعد أربعة أرقام سنقرأ و ننتظر أمر و ليس رقم**. العدد** من **10 **إلى **15 **لنحلله**. **و ننفذه وهذا موضوعنا القادم إن شاء الله*


----------



## ماجد عباس محمد (29 يوليو 2018)

لو الأمر القادم هو 10 فإما نزود 10 ثوانى أو نحدد به نسبة تخفيض القدرة. أى أن الزر الأول له وظيفتين متباينتين ومن ثم نحتاج تحديد ما يحدد هذه الوظيفة أو تلك.
لو الجهاز يعمل أى الماجنيترون يطلق الطاقة ستوقف خاصية تعديل الطاقة لذا سنغير الثوانى أما لو لا يطلق الطاقة سنسأل عن النسبة و نرفع راية طاقة مخفضة. أنسب تعليمه هنا هى Select Case أو فى اللغات الأخرى Switch حيث نفاضل بين قيم متعددة لناتج قراءة الأزرار. إن كانت = 10 سنسأل هل Jobpending = 1 إذن الماجنيترون يعمل فنزيد 10 للثوانى و إن تعدت 59 نطرح منها 60 لنبقى على الآحاد كما هى.
أما لو = صفرا أى الماجنيترون لا يعمل و لكننا هنا فى هذا الجزء من البرنامج أتممنا تحديد الزمن، سنعرض فى الدقائق ما ينبه المستخدم لذا بوضع أى رقم أعلى من 9 ستعرض الشاشة لا شيء. يمكنك أيضا اختيار طرف آخر لإنارة علامة عشرية أو ليد آخر أو لو تستخدم رقم غير المحلل 4511 سيعطى أشكال طبقا للداتاشيت. 
نضع 255 ثم صفر على MinLatch ثم نعيده للواحد. هنا كان ممكنا استخدام الأمر
PULSEOUT PORT , PIN , PERIOD
PULSEOUT Controls , Seclatch , 1
حيث الفترة PERIOD تحسب بالدورة و هى ربع الكريستال. و لكن يجب التأكد من البداية الصحيحة لأنها تنفذ بتبديل البت مرتين فلو بدأت بصفر ستنتج نبضة موجبة و إن بدأت بواحد تنتج نبضة سالبة
بعد ذلك نضع صفر و تكرر للثوانى لتظهر صفرين علامة انتظار نسبة التخفيض ثم نقرأ مع الفحص. فإن كان أمر ننتقل لفحصه أو لو رقم نضعه فى خانة Powersel أى القيمة المختارة و نقيم راية الحرارة المنخفضة ثم نضرب القيمة فى 10 و نستخدم الدالة Makebcd والتى تحول الناتج لما يناسب الشاشات و نعرضه و نضع صفرا فى Currpwr قيمة البدء ثم نقرا مع الفحص . من الممكن انتظار أمر كما سبق لكن نفكر قليلا سنجد أن لو كان رقم يمكن أن نعدل الخيار السابق، ولم لا فنعود للتعديل فى عنوان Setlow أو لو أمر ننتقل لتحليله

```
[LEFT][B][SIZE=4]
[COLOR=#0000cd]Chkcmnd:[/COLOR]
    Select Case Keyvalue
        Case 10 [COLOR=#008080]            ' If 10 then either ADD 10 seconds or set Low Power[/COLOR]
            If Jobpending = 1 Then[COLOR=#008080]                      ' running , add ten[/COLOR]
               Secleft = Secleft + 10
               If Secleft > 59 Then Secleft = Secleft - 60 :
            Else    [COLOR=#008080]                          ' Set low power[/COLOR]
               Displays = 255 [COLOR=#008080]           ' Display Blank MinLeft[/COLOR]
               Reset Minlatch : Nop : Set Minlatch : Waitus 1
               Displays = 0 : Reset Seclatch : Nop 
            Set Seclatch[COLOR=#008080]                ' Show -- 00[/COLOR]
               Readandchk
               If Cmd_ndgt = Acmnd Then Goto Chkcmnd[COLOR=#008080]       ' if a 2nd Command, cancel Low Power
[/COLOR]              [COLOR=#0000ff] Setlow:[/COLOR]
               Powersel = Keyvalue : Set Lowheat [COLOR=#008080]               ' Setlow[/COLOR]
               Tmp = Keyvalue * 10 : Displays = Makebcd(tmp)
               Reset Seclatch : Nop : Set Seclatch  [COLOR=#008080]        ' Show -- x0[/COLOR]
               Currpwr = 0 : Readandchk
               If Cmd_ndgt = Adigit Then
                   Goto Setlow[COLOR=#008080]                      ' a digit, replace the old one[/COLOR]
               Else
                   Goto Chkcmnd
               End If
            End If
        Case 11 [COLOR=#008080]                                  ' 11 = Add MinLeft[/COLOR]
            If Jobpending = 1 Then[COLOR=#008080]         ' if not running do nothing[/COLOR]
               Tmp = Minleft \ 10 : Incr Minleft : Cntr = Minleft \ 10
               If Cntr > Tmp Then Minleft = Minleft - 10
            End If
        Case 12  [COLOR=#008080]                                 ' 12 = Add 10 MinLeft[/COLOR]
            If Jobpending = 1 Then[COLOR=#008080]         ' if not running do nothing[/COLOR]
               Minleft = Minleft + 10
               If Minleft > 100 Then Minleft = Minleft - 100
            End If
        Case 13   [COLOR=#008080]                               ' 13 = Enter or Run[/COLOR]
            If Minleft <> 0 Or Secleft <> 0 Then
                  Bitwait Dooropen , Reset [COLOR=#008080]      ' Wait Door Close[/COLOR]
            Set Jobpending : Start Timer0 : Set Off_non : Set Hiv_on
            End If
        Case 14   [COLOR=#008080]                                ' 14 = Cancel[/COLOR]
            Bitwait Dooropen , Reset [COLOR=#008080]      ' Wait Door Close[/COLOR]
            If Jobpending = 1 Then
                Toggle Timer0 : Toggle Off_non
            End If
        Case Else   [COLOR=#008080]                     ' 15 stop all[/COLOR]
           Goto Startit
    End Select
    Showtime
    Loop
[/SIZE][/B][/LEFT]
```
يلى ذلك باقى الأكواد وهى أسهل لكونها تنفذ أمرا واحدا فقط فنجد الأمر 11 وهو نضيف دقائق وهذا الأمر و التالى حقيقة ضرورى فقد تجد أنك تحتاج لزيادة الوقت لإكمال الطهى ولو انتظرت ستحتاج لإعادة ضبط نسبة الحرارة مرة ثانية وهى نسبة لو زادت قد لا تكون جيدة فبعض الأشياء تحتاج حرارة منخفضة و بعض الأشياء تحتاج وقت لتوزيع الحرارة على الجسم كله خاصة لو تفك شيئ مجمدا و رفعت الحرارة ستسوى جزء و يبقى آخر مجمدا.
لتنفيذ هذا نسأل لو Jobpending =1 فهذا يعنى أنه يعمل فنقسم الدقائق المتبقية على 10 ثم نزيد الدقائق بواحد ثم نقسم الناتج على 10 . المشكلة هنا اننا نريد بعد 39 العدد 30 و ليس 40 لعدم توافر زرار آخر للنقصان و الحل بسيط فالقسمة الأولى ستعطى 3 و الثانية 4 لذا سنطرح 10 أما لو كلاهما 3 فلا نطرح.
الكود 12 نضيف 10 دقائق فإن كان الرقم أكبر من 100 سنطرح 100 لأن الأرقام الأكبر من 99 لن تعرض جيدا
ثم الكود 13 للتشغيل فلو يوجد زمن سبق تحديده نتأكد من غلق الباب ثم نشغل الجهاز و المؤقت و ننصب راية Jobpending أى مهمة قيد التنفيذ.
الكود 14 نتأكد من غلق الباب ثم نعكس حال التشغيل و الكود الأخير لإلغاء كل شيئ و التوقف التام و العودة للبدء
يلى ذلك كود المقاطعتين الأولى للطوارئ أى الباب مفتوح و الثانية لحساب الوقت التايمر.
وهو موضوعنا القادم بإذن الله


----------



## ماجد عباس محمد (30 يوليو 2018)

*كود مقاطعة الطوارئ بسيط و يبدأ بعنوان **Emergency **حيث نوقف الطاقة و نوقف المؤقت و ننتظر حتى غلق الباب و عندها نطلق التايمر و نطلق الطاقة ثم نعود و الميكرو آليا يعيد إتاحة المقاطعة**.*

```
[LEFT]
[B][SIZE=4]Emergency: [COLOR=#008080]' Adress of INT0 (IE0)Emergency[/COLOR]
Reset Off_non [COLOR=#008080]' stop Outs and motors etc[/COLOR]
Stop Timer0[COLOR=#008080] ' Stop counter[/COLOR]
Bitwait Dooropen , Reset
Start Timer0[COLOR=#008080] ' Start counter[/COLOR]
Set Off_non[COLOR=#008080] ' Resetart All[/COLOR]
Return

Counttime:
Decr Secleft
If Secleft = 0 Then
If Minleft <> 0 Then
Decr Minleft
Secleft = 59
Else[COLOR=#008080] ' Sec = 0 and Min = 0[/COLOR]
Reset Jobpending [COLOR=#008080]' All Done[/COLOR]
Stop Timer0[COLOR=#008080] ' Stop counter[/COLOR]
Reset Lowheat[COLOR=#008080] ' Clear if selected[/COLOR]
Reset Off_non[COLOR=#008080] ' Power Off[/COLOR]
Reset Hiv_on[COLOR=#008080] ' Turn Off HI Voltage[/COLOR]
Reset Buzzer
Waitms 1000
Set Buzzer
End If
End If
Showtime[COLOR=#008080] ' display New Time[/COLOR]
If Lowheat <> 0 Then
Incr Currpwr
If Currpwr > 10 Then Currpwr = 0[COLOR=#008080] ' loop again[/COLOR]
If Currpwr > Powersel Then Reset Hiv_on Else Set Hiv_on
End If
Return

[/SIZE][/B][/LEFT]
```
*يلى ذلك كود مقاطعة حساب الوقت التايمر وهى باسم **Counttime **حيث ننقص الثوانى الباقية فإن كان الباقى لا **= **صفر فسنعرض الوقت و إن كانت راية الطاقة المخفضة مرفوعة نزيد عداد الطاقة الحالية بواحد فإن كان اكثر من **10 **نعيده للصفر ثم نختبر هل أكثر من النسبة المحددة نوقف الطاقة و إلا نطلقها ثم نعود **.*
*فى حال الثوانى **= **صفر نختبر الدقائق، لو لا تساوى صفر ننقصها بواحد و نعيد الثوانى **59 **أما لو أيضا تساوى صفر نوقف المؤقت و نوقف الطاقة و نلغى كل الرايات و نطلق الزامور لمده ثانية ثم نعرض الوقت و نعود **.
*

```
[LEFT][SIZE=4]
Sub Showtime():[COLOR=#008080] ' ======== Display Time ========[/COLOR]
Set Minlatch
Displays = Makebcd(minleft)
Reset Minlatch
nop
Set Minlatch
Set Seclatch
Displays = Makebcd(secleft)
Reset Seclatch
nop
Set Seclatch
End Sub


[/SIZE][/LEFT]
```
*المرة القادمة إن شاء الله نكمل*


----------



## ماجد عباس محمد (31 يوليو 2018)

للتعامل مع الكى باد

```
[LEFT][SIZE=4]Sub Readandchk()
Do
Readkpd
Nokey = Keyvalue.7
Loop Until Nokey = 1 [COLOR=#008080]    ' Wait key released[/COLOR]
Do
Readkpd
Nokey = Keyvalue.7
Loop Until Nokey = 0 [COLOR=#008080]    ' Wait key Pressed[/COLOR]
If Keyvalue > 9 Then Cmd_ndgt = 1 Else Cmd_ndgt = 0[COLOR=#008080]' Command Or Number
[/COLOR]End Sub[/SIZE][/LEFT]
```
*
يلى ذلك كود عرض الوقت و أظنه سهلا فقد سبق التعرض لمثيله سابقا**. **نضع على المنفذ نتيجة الدالة **Makebcd **فهى تحول الرقم الثنائى لأرقام عشرية مناسبة للعرض فنضع الدقائق على المنفذ ثم نحرك طرف **MinLatch **من **1 **إلى صفر ثم عودة للواحد ثم نضع الثوانى و نكرر مع **SecLatch **و هكذا يتم عرض الوقت**.*
*يلى ذلك – و أذكر أنك تضع هذه الأكواد فى أى مكان يروق لك و ألدوال بأى ترتيب فلا يهم أن كانت هذه الدالة قبل تلك أم العكس – يلى ذلك كود القراءة مع الفحص حيث نطلب دالة قراءة الأزرار و التى تعيد القيمة فى متغير بحجم بايت باسم **Keyvalue **ثم نجعل البت باسم **NOKEY **تساوى البت رقم **7 **من **Keyvalue **و التى **= **صفر لو ضغط على أى زرار و تساوى **1 **لو لم يضغط **. **نكرر الدورة حتى تصير **NoKey = **صفر أى لا أزرار مضغوطة و عندها ندخل فى دورة حتى يتم الضغط على زرار**. **بعد الضغط نفحص النتيجة فإن كانت أكبر من **9 **فهو أمر و *Cmd_ndgt * = 1 **و إلا فهى **= **صفر *

```
[LEFT][B]
Sub[/B] Readkpd()
Keyvalue [B]=[/B] 255  [COLOR=#008080]            ' No key code[/COLOR]
[B]For[/B] Cntr [B]=[/B] 1 [B]To[/B] 5  [COLOR=#008080]          ' Read 5 times[/COLOR]
Keypad [B]=[/B] 254        [COLOR=#008080]            ' 1111 1110 COL4[/COLOR]
Tmp [B]=[/B] Keyread [B]And[/B] &B11110000
Select [B]Case[/B] Tmp
[B]Case[/B] &B01110000 : Keyvalue [B]=[/B] 10[COLOR=#008080]    ' F1 or A pressed ret 0xA = 10[/COLOR]
[B]Return[/B] ' Row1 = 0
[B]Case[/B] &B10110000 : Keyvalue [B]=[/B] 11[COLOR=#008080]    ' F2 or B pressed ret 0xB = 11[/COLOR]
[B]Return[/B]
[B]Case[/B] &B11010000 : Keyvalue [B]=[/B] 12[COLOR=#008080]    ' F3 or C[/COLOR]
[B]Return[/B]
[B]Case[/B] &B11100000 : Keyvalue [B]=[/B] 13[COLOR=#008080]   ' Enter Pressed ret 0xD = 13[/COLOR]
[B]Return[/B]
[B]End[/B] Select
Keypad [B]=[/B] &B11111101          [COLOR=#008080]              ' Col3[/COLOR]
Tmp [B]=[/B] Keyread [B]And[/B] &HF0


Select [B]Case[/B] Tmp
[B]Case[/B] &B01110000 : Keyvalue [B]=[/B] 3    [COLOR=#008080]      ' 3[/COLOR]
[B]Return[/B]
[B]Case[/B] &B10110000 : Keyvalue [B]=[/B] 6    [COLOR=#008080]       ' 6[/COLOR]
[B]Return[/B]
[B]Case[/B] &B11010000 : Keyvalue [B]=[/B] 9   [COLOR=#008080]      ' 9[/COLOR]
[B]Return[/B]
[B]Case[/B] &B11100000 : Keyvalue [B]=[/B] 14   [COLOR=#008080]    ' Cancel Btn[/COLOR]
[B]Return[/B]
[B]End[/B] Select
Keypad [B]=[/B] &B11111011 ' Col2
Tmp [B]=[/B] Keyread [B]And[/B] &HF0

Select [B]Case[/B] Tmp
[B]Case[/B] &B01110000 : Keyvalue [B]=[/B] 2[COLOR=#008080] ' 2[/COLOR]
[B]Return[/B]
[B]Case[/B] &B10110000 : Keyvalue [B]=[/B] 5[COLOR=#008080] ' 5[/COLOR]
[B]Return[/B]
[B]Case[/B] &B11010000 : Keyvalue [B]=[/B] 8[COLOR=#008080] ' 8[/COLOR]
[B]Return[/B]
[B]Case[/B] &B11100000 : Keyvalue [B]=[/B] 0[COLOR=#008080] ' 0[/COLOR]
[B]Return[/B]
[B]End[/B] Select
Keypad [B]=[/B] &B11110111         [COLOR=#008080]         ' Col1[/COLOR]
Tmp [B]=[/B] Keyread [B]And[/B] &HF0

Select [B]Case[/B] Tmp
[B]Case[/B] &B01110000 : Keyvalue [B]=[/B] 1[COLOR=#008080] ' 1[/COLOR]
[B]Return[/B]
[B]Case[/B] &B10110000 : Keyvalue [B]=[/B] 4 [COLOR=#008080]' 4[/COLOR]
[B]Return[/B]
[B]Case[/B] &B11010000 : Keyvalue [B]=[/B] 7 [COLOR=#008080]' 7[/COLOR]
[B]Return[/B]
[B]Case[/B] &B11100000 : Keyvalue [B]=[/B] 15[COLOR=#008080] ' Mode[/COLOR]
[B]Return[/B]
[B]End[/B] Select
[B]Next[/B]
[B]End[/B] Sub[/LEFT]
```


```

```
*
أخيرا كود قراءة الأزرار وهو بسيط جدا **. **نذكر أننا نسقنا المنفذ النصف الأدنى بت صفر،**1**،**2**،**3 **خروج و الأعلى **4**،**5**،**6**،**7 **دخول**. **الآن نضع فى قيمة الزرار **KeyValue **القيمة **255 **أى لا زرار ثم بعد ذلك ننشئ دورة من خمسة مرات نضع على المنفذ القيمة **11111110 **حيث سبعة آحاد اربع منها العليا تذهب للدخول و ربما تذكر أن هذا يفعل مقاومات الجذب لأعلى فقط أما الأربعة الدنيا فتذهب لخرج و منها **3 **آحاد وواحدة صفر وذلك من خلال **Keypad **وهو يذهب إلى **PORTC.*
*الآن نقرأ المنفذ من المسجل **PINC **من خلال المتغير **KeyRead **وهو يقرأ حالة الأزرار الأربع العليا أما الدنيا فهى ما وضعناها نحن**. **نتخلص من الدنيا بالأمر **"**مع**" AND **فنضع فى **Tmp **نتيجة هذه الدالة بين النتيجة مع **F0 **فتبقى الأربع العليا فقط ثم بالتعليمه **select case **نفاضل و إن كانت رقم **4 **فالناتج كذا أو لو البت **5 **يكون كذا الخ ثم نعيد الكرة مع البت **1 **و نقارن بالأربع ثم البت **2 **وهكذا*
*بقى أن نكرر هذا البرنامج بلغة ميكرو سي المرة القادمة إن شاء الله*


----------



## ماجد عباس محمد (1 أغسطس 2018)

*الميكرو ويف باستخدام PIC16C877A و لغة ميكروسى :*

*هناك تعديلات طفيفة سنحتاج لتنفيذها كما سبق وهى بسبب تواجد طرف المقاطعة **INT **على منفذ **B **الطرف صفر و هذا يجبرنا على استخدام أزرار **4×3 **مما يفقدنا أربعة من الوظائف الستة ولذا سنضطر لوضع الأزرار على منفذ آخر و ليكن **D **مع وضع مقاومات خارجية على أطراف الدخول و كما سبق الشرح إما تكون متصلة بالأرض و نضع واحد على الطرف و نختبر أين ظهر أو تتصل بالموجب و نكرر ذات الروتين **. **كانت أمامنا فرصة توفيرها فى النظم السابقة ولكننا هنا سنضطر لإستخدامها و ها هى فرصة لندرس الحل الآخر، لذا سنوصلها بالأرضى**. **أيضا التايمر يجب أن يوصل بالطرف **PORTA.4 **كما سبق الشرح **, **و الشاشات على المنفذ **C **و هكذا تصبح الدائرة كما يلى**:*



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

```
[LEFT]
[COLOR=#008080][B]// program Microwave16 Declarations section[/B]
[/COLOR]char Controls at PORTB [B];[/B] char Displays at Portc [B];[/B] char Keypad at Portd [B];[/B]


sbit Dooropen at rb0_bit [B];[/B] sbit Seclatch at rb1_bit [B];[/B] sbit Minlatch at rb2_bit [B];[/B]
sbit Hiv_on at rb3_bit [B]; [/B] sbit Off_non at rb4_bit [B];[/B] sbit Buzzer at rd0_bit [B];[/B]


sbit MidtemP at rd1_bit [B];[/B] sbit Waterfull at rd2_bit [B];[/B]  sbit Waterempty at rd3_bit [B];[/B] 
sbit Run_nspin at rd5_bit [B];[/B] sbit Motoron at rd6_bit [B];[/B] sbit Heateron at rd7_bit [B];[/B]


sbit SmallLoad at rb5_bit [B];[/B] sbit Half at rb6_bit [B];[/B] sbit Full at rb7_bit [B];[/B]


bit Jobpending [B],[/B] BoKey [B],[/B] Lowheat [B],[/B] Cmd_ndgt [B];[/B]


[COLOR=#008080]// VARIABLES[/COLOR]
unsigned int Runtime [B];[/B]
char Rinse [B],[/B] Cntr [B],[/B] Secleft [B],[/B] Minleft [B],[/B] Powersel [B],[/B] Currpwr [B],[/B] Keyvalue [B],[/B] Tmp [B];[/B]
int Adigit [B]=[/B] 0 [B];[/B] int Acmnd [B]=[/B] 1[B];[/B]


void Showtime[B]()[/B] [B]{[/B]
Minlatch [B]=[/B] 1[B];[/B] Displays [B]=[/B] Dec2Bcd[B]([/B]minleft[B])[/B] [B];[/B] Minlatch [B]=[/B] 0 [B];[/B]
Delay_us[B]([/B]1[B]);[/B] Minlatch [B]=[/B] 1 [B];[/B]
Seclatch [B]=[/B] 1[B];[/B] Displays [B]=[/B] Dec2Bcd[B]([/B]secleft[B])[/B] [B];[/B] Seclatch [B]=[/B] 0 [B];[/B]
Delay_us[B]([/B]1[B]);[/B] Seclatch [B]=[/B]1 [B];[/B]
[B]}[/B]

void interrupt[B]()[/B]
[B]{[/B]
[B]if[/B] [B]([/B]INTCON[B].[/B]TMR0IF [B])[/B][COLOR=#008080]                             // Counttime:[/COLOR]
[B]{[/B] [B]if[/B] [B](--[/B]Secleft [B]=[/B] 0 [B])[/B]
[B]{[/B] [B]if[/B] [B]([/B] Minleft [B]!=[/B] 0 [B])[/B]
[B]{[/B] [B]--[/B]Minleft[B];[/B]
Secleft [B]=[/B] 59 [B];[/B]
[B]}[/B]
[B]else[/B]
[B]{[/B] Jobpending [B]=[/B] 0 [B];[/B]
INTCON[B].[/B]TMR0IF [B]=[/B]0 [B];[/B]     [COLOR=#008080]                            // Clear timer flag[/COLOR]
INTCON[B].[/B]TMR0Ie [B]=[/B] 0 [B];    [/B][COLOR=#008080] // Disable timer[/COLOR]
Lowheat [B]=[/B] 0 [B];[/B] Off_non [B]=[/B] 0 [B],[/B] Hiv_on [B]=[/B] 0 [B];[/B][COLOR=#008080] // All off[/COLOR]
Buzzer [B]=[/B] 1[B];[/B] Delay_ms[B]([/B]1000[B]);[/B] Buzzer [B]=[/B] 1[B];[/B]
[B]}[/B]
[B]}[/B]
INTCON[B].[/B]TMR0IF [B]=[/B] 0[B];[/B] Showtime[B]()[/B] [B];[/B][COLOR=#008080]     // Clear timer flag and display Time[/COLOR]

[B]if[/B] [B]([/B]Lowheat [B]=[/B]1[B])[/B]
[B]{[/B] [B]++[/B]Currpwr[B];[/B]
[B]if[/B] [B]([/B]Currpwr [B]>[/B] 10[B])[/B] Currpwr [B]=[/B] 0 [B];[/B] [COLOR=#008080]// loop again[/COLOR]
[B]if[/B] [B]([/B]Currpwr [B]>[/B] Powersel[B])[/B] Hiv_on [B]=[/B]0 [B];[/B] [B]else[/B] Hiv_on [B]=[/B]1 [B];[/B]
[B]}[/B]
[B]}[/B]
[B]else[/B] [B]if[/B] [B]([/B]INTCON[B].[/B]INTF [B]) [/B][COLOR=#008080] // External interrupt door open[/COLOR]
[B]{[/B]
Off_non [B]=[/B] 0 [B];    [/B][COLOR=#008080] // stop Outs and motors etc[/COLOR]
INTCON[B].[/B]TMR0Ie [B]=[/B] 0 [B];[/B][COLOR=#008080] // Disable timer[/COLOR]
[B]do[/B] [B]{[/B]
[B]}[/B] [B]while[/B] [B]([/B] Dooropen [B]=[/B] 1 [B])[/B] [B];[/B][COLOR=#008080] // Wait door close[/COLOR]
INTCON[B].[/B]TMR0Ie [B]=[/B] 1 [B]; [/B][COLOR=#008080] // Enable timer[/COLOR]
Off_non [B]=[/B] 1 [B];[/B]    [COLOR=#008080]                 // Resetart All[/COLOR]
[B]}[/B]
[B]}
[/B][/LEFT]
```
*كود عرض الوقت كما سبق الشرح سنستخدم وظيفة **Dec2Bcd **وهى تعيد الرقم فى الصورة المناسبة و نضعها على المنفذ و نتأكد أن طرف التفعيل فى وضع **= 1 **لكى نتمكن من وضع نبضة سالبة بأن نجعله **= **صفر ثم **1 **مرة أخرى**. **نكرر هذا الفعل مرة بوضع الدقائق على المنفذ و مرة بوضع الثوانى تماما كما فعلنا مع **AVR*
*يلى ذلك كود المقاطعة حيث نسأل إن كان سبب المقاطعة من المؤقت سنكرر ذات الخطوات السابقة مع التايمر بفحص إن كانت الثوانى لا تساوى صفر فننقصها و نعرض الوقت و نرى إن كانت الطاقة المخفضة فنعالجها كما سبق و إلا ننقص الدقائق و إن كان كلاهما **= **صفر فنوقف الكل و نطلق الزمور و نلغى الرايات و نعود**. **أما لو المقاطعة الخارجية فنوقف الطاقة و التايمر و ننتظر غلق الباب لنعيد التايمر و الطاقة ثم نعود**.*

*المرة القادمة نكمل إن شاء الله*


----------



## ماجد عباس محمد (2 أغسطس 2018)

*رغم أنه من الممكن إعلان الوظائف و كتابتها لاحقا كأن نقول **char Readkpd();*​*لاحظ أنها تنتهى بالمقدسة ثم لاحقا فى أى مكان نعيد التعريف مع الكود كاملا كالتالى ولاحظ أنها بدون المقدسة إلا أننا سنكتفى بواحدة فقط و سنجعل قراءة الأزرار دالة تعيد قيمة الزرار المضغوط وهذا من قبيل التنوع حيث من الممكن تنفيذها فى البيزك أيضا بنفس الخطوات**. **هيكل الدالة هو نفس الخطوات
*

```
[LEFT][B][SIZE=3]
char Readkpd()
{ for (Cntr = 1 ;Cntr = 5 ; ++Cntr) [COLOR=#008080]   // Read 5 times[/COLOR]
{
Keypad = 254 ; // 1111 1110 COL4
Tmp = Keyvalue & 0B11110000 ;
switch (Tmp) {
case 0B01110000 : return 10; [COLOR=#008080]        // F1 or A pressed ret 0xA = 10[/COLOR]
case 0B10110000 : return 11; [COLOR=#008080]         // F2 or B pressed ret 0xB = 11[/COLOR]
case 0B11010000 : return 12; [COLOR=#008080]          // F3 or C[/COLOR]
case 0B11100000 : return 13 ; [COLOR=#008080]        // Enter Pressed ret 0xD = 13[/COLOR]
}
Keypad = 0B11111101 ; [COLOR=#008080]                  // Col 3[/COLOR]
Tmp = Keyvalue & 0xF0 ;
switch (Tmp) {
case 0B01110000 : return 3;    [COLOR=#008080]       // F1 or A pressed ret 0xA = 10[/COLOR]
case 0B10110000 : return 6;    [COLOR=#008080]       // F2 or B pressed ret 0xB = 11[/COLOR]
case 0B11010000 : return 9;   [COLOR=#008080]        // F3 or C[/COLOR]
case 0B11100000 : return 14 ;  [COLOR=#008080]      // Cancel Btn[/COLOR]
}
Keypad = 0B11111011 ;          [COLOR=#008080]         // Col 2[/COLOR]
Tmp = Keyvalue & 0xF0 ;
switch (Tmp) {
case 0B01110000 : return 2;
case 0B10110000 : return 5;
case 0B11010000 : return 8;
case 0B11100000 : return 0 ;
}
Keypad = 0B11110111 ; // Col 1
Tmp = Keyvalue & 0xF0 ;
switch (Tmp) {
case 0B01110000 : return 1;
case 0B10110000 : return 4;
case 0B11010000 : return 7;
case 0B11100000 : return 15 ;   [COLOR=#008080]        // Mode[/COLOR]
}
}
return 255 ;                                     [COLOR=#008080]    // No key code[/COLOR]
}


char Readandchk()
{ do {
Keyvalue = Readkpd();
} while (Keyvalue != 255) ;               [COLOR=#008080]   // Wait key released[/COLOR]
do {
Keyvalue = Readkpd();
} while (Keyvalue = 255) ;                  [COLOR=#008080] // Wait key Pressed[/COLOR]
if (Keyvalue > 9) Cmd_ndgt = 1; else Cmd_ndgt = 0 ;
}[/SIZE][/B][/LEFT]
```
*ننشئ دورة من **5 **مرات و إن شئت أكثر فلا بأس ثم تضع على المنفذ صفرا على أحد الأطراف و الباقى أحاد و تقرأ المنفذ ثم تحذف المصف المقنن كخروج و تبقى الدخول فقط و بالتعليمه **switch **تستطيع أن تعيد الرقم المناسب لكل ضغطة زر**.*
*باقى دالة القراءة و الفحص حيث نقرأ الأزرار و فى دورة **do **نتأكد من أنه لا زرار مضغوط ثم ندخل دورة مشابهة لننتظر ضغطة زرار فإن كان أكبر من **9 **فهو أمر وإلا فهو عدد*


*المرة القادمة إن شاء الله نكمل البرنامج*


----------



## ماجد عباس محمد (3 أغسطس 2018)

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

```
[LEFT][SIZE=3]
void main[B]()[/B]
[B]{[/B]

Startit[B]:[/B]
TRISC [B]=[/B] 0 [B];[/B] TRISD [B]=[/B] 0X0F [B];[/B] TRISB [B]=[/B] 1 [B];[/B] TRISA [B]=[/B] 255[B];[/B]
Minleft [B]=[/B] 0 [B];[/B] Secleft [B]=[/B] 0 [B];[/B] Showtime [B];[/B]
OPTION_REG [B]=[/B] 0b00111111 [B];[/B][COLOR=#008080] // setting RB Pull up clearing bit RBPU (OPTION_REG<7>).
// INTEDG = falling ,TOCS counter not timer, Count Falling Edge Prescale to WDT , ratio
[/COLOR]INTCON [B]=[/B] 0B10100000 [B];[/B] [COLOR=#008080]// Interrupt Control GIE All,Peie edge falling, T01E Enable
// INTE External disable , T01 Ov flag,intf ext flag , RBIF port change flag[/COLOR]
TRISB [B]=[/B] 255 [B];[/B]
Controls [B]=[/B] 0 [B];[/B]
INTCON[B].[/B]TMR0IF [B]=[/B]0 [B];[/B] [COLOR=#008080]// Interrupt Timer0 Flag[/COLOR]
INTCON[B].[/B]TMR0IE [B]=[/B]0 [B];[/B][COLOR=#008080] // Stop Interrupt Timer0[/COLOR]

[B]while[/B] [B]([/B]1[B])[/B] 
[B]{[/B] [B]do[/B] Readandchk[B];[/B] [B]while[/B] [B]([/B]Cmd_ndgt [B]=[/B] 1[B]);[/B] [COLOR=#008080]// wait a digit[/COLOR]
Secleft [B]=[/B] Keyvalue [B];[/B] Showtime [B];[/B] Readandchk [B];[/B][COLOR=#008080] // seconds[/COLOR]
[B]if[/B] [B]([/B]Cmd_ndgt [B])[/B] [B]goto[/B] Chkcmnd [B];[/B]
Secleft [B]=[/B] [B]([/B]Secleft [B]*[/B] 10[B])[/B] [B]+[/B] Keyvalue [B];[/B] [COLOR=#008080]// make ten seconds[/COLOR]
Showtime [B];[/B] Readandchk [B];[/B]
[B]if[/B] [B]([/B]Cmd_ndgt [B])[/B] [B]goto[/B] Chkcmnd [B];[/B]
Minleft [B]=[/B] Secleft [B]/[/B] 10 [B];[/B][COLOR=#008080] // a digit, make minutes[/COLOR]
Secleft [B]=[/B] [B]([/B]Secleft [B]%[/B] 10[B])+[/B] Keyvalue [B];[/B] Showtime [B];[/B] Readandchk [B];[/B]
[B]if[/B] [B]([/B]Cmd_ndgt [B])[/B] [B]goto[/B] Chkcmnd [B];[/B]
Tmp [B]=[/B] Secleft [B]/[/B] 10[B];[/B] Minleft [B]=[/B] [B]([/B]10 [B]*[/B] Minleft[B])[/B] [B]+[/B] Tmp[B];[/B] [COLOR=#008080]// adigit make ten [/COLOR]minutes
Readandchk [B];[/B]
[B]if[/B] [B]([/B]Cmd_ndgt [B])[/B] [B]goto[/B] Chkcmnd [B];[/B]
Tmp [B]=[/B] Secleft [B]/[/B] 10[B];[/B] Minleft [B]=[/B] [B]([/B]Minleft [B]*[/B] 10[B])+[/B]Tmp[B];[/B][COLOR=#008080] // a last digit, make 10 [/COLOR]min
Tmp [B]=[/B] Secleft [B]%[/B] 10 [B];[/B] Secleft [B]=[/B] Tmp [B]+[/B] Keyvalue[B];[/B]
[B]do[/B] Readandchk[B];[/B] [B]while[/B] [B]([/B] Cmd_ndgt [B]=[/B] 0[B]);[/B] [COLOR=#008080]// wait a command[/COLOR][/SIZE][/LEFT]
```
*
تم تحديد الزمن و الآن جاء أمر و مطلوب تحليله، أسهل طريقة أن نستخدم **switch **و من ثم لو **10 **نسأل لو الماجنيترون يعمل؟ إذن نزيد الزمن **10 **ثوانى و إلا نكرر ما سبق فى تمهيد الشاشة لقراءة النسبة المطلوبة لتخفيض الطاقة ثم ننتظر رقم و نعرضه و ننتظر أمر للتنفيذ أو عدد نعدل الرقم السابق**.*

```
[LEFT][SIZE=3]
Chkcmnd[B]:[/B]
[B]switch[/B] [B]([/B]Keyvalue[B])[/B]
[B]{[/B] [B]case[/B] 10 [B]:[/B] [COLOR=#008080]// either ADD 10 seconds or set Low Power[/COLOR]
[B]{[/B] [B]if[/B] [B]([/B]Jobpending [B]=[/B] 1[B])[/B] [COLOR=#008080]// running , add ten[/COLOR]
[B]{[/B] Secleft [B]=[/B] Secleft [B]+[/B] 10[B];[/B]
[B]if[/B] [B]([/B]Secleft [B]>[/B] 59[B])[/B] [B];[/B] Secleft [B]=[/B] Secleft [B]-[/B] 60 [B];[/B]
[B]}[/B]
[B]else[/B]
[B]{[/B] Displays [B]=[/B] 255 [B];[/B] Minlatch[B]=[/B]0 [B];[/B] Delay_us[B]([/B]1[B]);[/B] Minlatch [B]=[/B]1 [B];[/B]
Delay_us[B]([/B]1[B]);[/B] Displays [B]=[/B] 0[B];[/B] Seclatch[B]=[/B]0 [B];[/B][COLOR=#008080] // Display Blank MinLeft[/COLOR]
Delay_us[B]([/B]1[B]);[/B] Seclatch [B]=[/B] 1[B];[/B] Readandchk[B];[/B][COLOR=#008080] // Show -- 00[/COLOR]
[B]if[/B] [B]([/B]Cmd_ndgt [B]=[/B] 1[B])[/B] [B];[/B] [B]goto[/B] Chkcmnd[B];[/B][COLOR=#008080] // if a 2nd Command, cancel Low Power[/COLOR]
Setlow[B]:[/B]
Powersel [B]=[/B] Keyvalue [B];[/B] Lowheat[B]=[/B]1[B];[/B][COLOR=#008080] // Setlow[/COLOR]
Displays [B]=[/B] Dec2bcd[B]([/B]Keyvalue [B]*[/B] 10[B]);[/B]
Seclatch [B]=[/B] 0 [B];[/B] Delay_us[B]([/B]1[B])[/B] [B];[/B] Seclatch[B]=[/B] 1 [B];[/B][COLOR=#008080] // Show -- x0[/COLOR]
Currpwr [B]=[/B] 0 [B];[/B] Readandchk [B];[/B]
[B]if[/B] [B]([/B]Cmd_ndgt [B]=[/B] 0[B])[/B] [B]goto[/B] Setlow[B];[/B] [B]else[/B] [B]goto[/B] Chkcmnd [B];[/B][COLOR=#008080] // a digit, replace the old one[/COLOR]
[B]}[/B]
[B]}[/B]
[B]case[/B] 11 [B]:[/B] // 11 = Add MinLeft
[B]{[/B] [B]if[/B] [B]([/B]Jobpending [B]=[/B] 1[B])[/B][COLOR=#008080] // if not running do nothing[/COLOR]
[B]{[/B]Tmp [B]=[/B] Minleft [B]/[/B] 10 [B];[/B] [B]++[/B]Minleft [B];[/B] Cntr [B]=[/B] Minleft [B]/[/B] 10[B];[/B]
[B]if[/B] [B]([/B]Cntr [B]>[/B] Tmp[B])[/B] Minleft [B]=[/B] Minleft [B]-[/B] 10[B];[/B]
[B]}[/B]
[B]}[/B]
[B]case[/B] 12 [B]:[/B] [B];[/B][COLOR=#008080] // 12 = Add 10 MinLeft[/COLOR]
[B]{[/B] [B]if[/B] [B]([/B]Jobpending [B]=[/B] 1[B])[/B][COLOR=#008080] // if not running do nothing[/COLOR]
Minleft [B]=[/B] Minleft [B]+[/B] 10[B];[/B]
[B]if[/B] [B]([/B]Minleft [B]>[/B] 100[B])[/B] Minleft [B]=[/B] Minleft [B]-[/B] 100[B];[/B]
[B]}[/B]
[B]case[/B] 13 [B]:[/B] [B];[/B][COLOR=#008080] // 13 = Enter or Run[/COLOR]
[B]{[/B] [B]if[/B] [B]([/B]Jobpending [B]=[/B] 1[B])[/B] [COLOR=#008080]// if not running do nothing[/COLOR]
[B]{[/B] Jobpending [B]=[/B] 1 [B];[/B] Off_non [B]=[/B] 1[B];[/B] Hiv_on [B]=[/B] 1 [B];[/B][COLOR=#008080] // power On[/COLOR]
TMR0 [B]=[/B] 205 [B];[/B][COLOR=#008080] // Load Tomer0[/COLOR]
INTCON[B].[/B]TMR0IE [B]=[/B] 1 [B];[/B] [COLOR=#008080]// enable Timer0[/COLOR]
INTCON[B].[/B]TMR0IF [B]=[/B] 1 [B];[/B] [COLOR=#008080]// Interrupt Timer0 Flag[/COLOR]
[B]while[/B] [B]([/B]jobPending [B]=[/B] 1[B])[/B] [B];[/B] [COLOR=#008080]// Bitwait Jobpending , Reset // Wait to Finish[/COLOR]
Hiv_on [B]=[/B] 0[B];[/B][COLOR=#008080] // Power Off[/COLOR]
[B]}[/B]
[B]}[/B]
[B]case[/B] 14 [B]:[/B] [B];[/B]
[B]{[/B] [B]while[/B] [B]([/B]Dooropen [B]=[/B]1[B]){};[/B]
[B]if[/B] [B]([/B]Jobpending [B]=[/B] 1[B])[/B] [COLOR=#008080]// if not running do nothing[/COLOR]
[B]{[/B]
INTCON[B].[/B]TMR0IE [B]=[/B] [B]![/B]INTCON[B].[/B]TMR0IE [B]=[/B] 1 [B];[/B]
Off_non [B]=[/B] [B]![/B]Off_non [B];[/B]
[B]}[/B]
[B]}[/B]
[B]case[/B] 15 [B]:[/B] [B]goto[/B] Startit[B];[/B]
[B]}[/B]
[B]}[/B]
[B]}[/B][/SIZE]
[/LEFT]
```

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


----------



## ماجد عباس محمد (4 أغسطس 2018)

*التحكم فى سرعة موتور تيار مستمر*

*التحكم فى سرعة موتور تيار مستمر*

*لماذا التحكم فى موتور تيار مستمر؟ ببساطة للحاجة لقياس فولت أو تيار أو كلاهما و من ثم نستخدم **ADC **و أيضا نتحكم فى عرض النبضة وهو يتعرض لموضوع **PWM **و القلق من عدم إيقاف الموتور فى الوقت المناسب و من ثم وحدة مؤقت **"**كلب الحراسة**" **و اختصارا نكتفى بمؤقت الحماية و أيضا قد نحتاج لتثبيت السرعة و من ثم نتعرض للكتابة فى الذاكرة الغير متطايرة **EEPROM . **طبعا سنعرض هنا باستخدام عارض **LCD **و بهذا نكون قد غطينا معظم خواص الميكروكونترولر **.*
*ما هو موتور التيار المستمر؟*

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




*لكى نوضح الخلاف فلدينا ملف من السلك و سنمرر به تيار من مصدر مستمر وهو بالمناسبة يسمى **"**بوبينه**" **من الكلمة **bobbin **أى ملف على بكرة أو مكوك و ليست بحرف الميم كما هو منتشر فكلمة **mob **تعنى غوغاء **. **من الطبيعى أننا لن نستخدم دوما أرفع سلك مطلوب من الحسابات فقد يكون السلك الأرفع أغلى ثمنا أو أصعب فى الاستخدام أو ببساطة غير متوافر فلو تحتاج **0.2 **أمبير مثلا سيكون السلك رفيع جدا و ما هو أقل من **1 **دوزيم أى اقل من **0.1 **مللي متر يكون عادة مكلفا جدا و صعب توافره الخ**.*
*إذن لو وصلنا الموتور بالمصدر و أوقفنا العضو الدوار فلم يتلف الموتور فهو من النوع الصغير الآمن و ذلك يرجع لكونه من سلك يتحمل فضلا عن أن مصادر التغذية الصغيرة أصلا لا تستطيع أن تمد بتيار كافى لإتلاف الحمل وهذا ما سنسميه موتور صغير لكون لو استخدمت بطارية سيارة و إن كانت **6 **فولت ولكنها قادرة على حرق و إتلاف الموتور فهذا ذو نظام كبير أى تياره كبير أعلى من تحمل الأحمال و من ثم تحتاج الدوائر لمزيد من الحماية و التأمين*
*التركيب الداخلى كما بالصورة من مغناطيس و ملف ولكن هناك طرفى توصيل عبر ما يسمى الموزع ألذى يتولى تغذية الملف المناسب فى الوقت المناسب وهو من الكربون المضغوط و لذا عند قياس طرفى التوصيل ستجد بينهما نصف أوم فى القدرات الكبيرة أو أقل مثلا **0.01 **أوم أو أقل بالكاد قيمة هذه القطع الكربونية و قد تكون صفر فى الموتورات الأصغر حيث تستخدم وصلات من سبيكة النحاس المقسى المرن**. **الآن لو وصلنا **12 **فولت سيكون التيار فى **0.01 **أوم هو **1200 **أمبير و بطارية سيارة كبيرة تستطيع توفير هذا القدر إذن هذا خطر**.*
*ثانيا كيف يكون أثناء التشغيل التيار لا يزيد عن **1 **أمبير فقط**. **و الأغرب كيف لو أضفنا له حمل يشعر بذلك و يزداد التيار؟*
*الفكرة ببساطة فى الاسم أنه آله وليس موتور فهو عندما يوصل بالفولت سيدور و تقطع اللفات المجال المغناطيسى مولدة جهد عكسى يكاد يساوى الجهد المطبق أى فى مثالنا السابق يكون **11.99 **فولت و الفرق **0.01 **فولت مقسوما على **0.01 **أوم **= 1 **أمبير**.*
*الآن الموتور لا يشعر و لكن عند إضافة الحمل ستقل سرعة دورانه و من ثم يقل الجهد المتولد من **11.99 **إلى **11.9 **فولت أى **0.1 **فولت **÷ 0.01 **أوم **= 10 **أمبير و هكذا حتى تصل إلى **100 **أمبير الخ**.*

*إذن مع الحمل لابد من أن تنخفض السرعة و أركز على هذه النقطة لأصحاب فكر **555 **مناسبة أو **PWM **كافى لتغيير سرعة الموتور فى المطلق**.*
*ما سبق يسمي موتور المغناطيس الثابت ولكننا يمكن أن نستخدم ملف نمرر به تيار لتوليد مجال مغناطيسى قوى جدا وهذا يسمى أله المغناطيس الكهربى و هنا أصبح من الممكن تغيير السرعة بتغيير المجال و هذا يوفر ميزة أن تيار المجال عادة لا يقارن بتيار العضو الدوار **Armature **فقد يصل إلى من **4 **إلى **10 **أمبير فقط بينما تيار العضو الدوار **Armature **فقد يصل مئات من الأمبير و التحكم هنا سيكون أقل كلفة بكثير لو تتحكم فى **10 **أمبير من أن تتحكم فى **200 **أمبير مثلا**.*

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

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


----------



## ماجد عباس محمد (5 أغسطس 2018)

*تعديل عرض النبضة Pulse Width Modulation أو PWM*

*ما هو معدل عرض النبضة؟ و فيم يستخدم؟*
*ببساطة هو تكرار دورة معينة بحيث نوصل القدرة جزء من هذه الدورة و نقطع القدرة باقى الدورة**. **و نسبة التوصيل للقطع يسمى الدوام **Duty Ratio **و التكرار هو التردد و عادة فى الموتورات تكون من **10 **إلى **500 **ذ**/**ث و ذلك لأن تقليل التردد قد يسبب رجة أو اهتزاز فى سرعة الموتور و زيادة التردد يتداخل مع حث الملفات و لكن يمكن زيادة التردد مع موتورات التوالى الخاصة بالمركبات لكون لفاتها قليلة **.*
*أبسط وسيلة لتغيير عرض النبضة باستخدام **555 **الشهيرة حيث نستخدم واحدة لتوليد نبضات حادة تحدد التردد ثم تغذى أخرى لتوليد نبضة نتحكم فى عرضها من خلال طرف التحكم رقم **5*





*فقط نلاحظ أن م**1 **تكون أكبر بكثير من م**2 **ليكون الخرج نبضة قصيرة لقدح التالية أو تستخدم الطريقة التقليدية بالربط بمكثف مع مقاومة على طرف **2 **للثانية**.*
*حل ثانى ابتكرته أن آخذ الخرج من على المكثف مباشرة فيكون موجة مثلثة و يمكن استخدام مقارن لتوليد موجة ذات عرض متغير و من المعروف أن على مكثف **555 **تتكون موجة مثلثة بقيمة ثلث التغذية لذا لو **12 **فولت ستحصل على **4 **فولت فقط وهو لا بأس به لكن يمكنك إضافة مكبر بنسبة **1.5 **أو **2 **لرفع الموجة إلى **8 **فولت ثم نغذى المقارن .**لاحظأن تكون م**4**أكبربكثير من م**2.**إنفضلت تكبير أكبر من أو يساوى **2**فيمكنكجعل المكبر غير عاكس **.*






*و أخيرا دائرتين باستخدام مكبر عمليات العليا تعطى موجة مربعة تحولها الثانية لمثلثة ثم نأخذ الموجة المثلثة لمقارن كما سبق و السفلى دائرة توليد موجة مربعة و يأخذ الخرج من خرج مكبر العمليات موجة مربعة و تعديل العرض من خلال جهد تحكم على الطرف **Vin **أعلى يسار الرسم**.
*




*قبل أن نترك هذا المجال يجب ألا ننسى المتكاملات الرائعة المستخدمة كمثبت جهد مثل **3525 **و **3846 **و**494 **وغيرهم و كلهم يولدوا موجات مربعة يمكن استخدامها لكن ليس الهدف أن ندرس تفاصيل الدوائر فهى فى سلسلة تصميم الدوائر و سلسلة دوائر التغذية لكن ما أريد توضيحه هنا حقيقة بسيطة وهى أن الدخول لكل هذه الدوائر و ألذى يتحكم فى عرض النبضة هو من مكبر عمليات**. **و التأخير هنا هو مدى استجابة مكبر العمليات ولو أردت استجابة أسرع استخدم مكبر أسرع و من ثم لو زاد التيار المار فى الحمل سيكون رد فعل المكبرات فى بضع ميكرو ثانية و نتيجة هذه الاستجابة مباشرة فى خلال بضع ميكرو ثانية ، أى ببساطة لو زاد التيار لن أكمل هذه النبضة و سأقتطع ما بقى منها**.*
*أما استخدام متحكم بسرعة **20 **ميجا سيقرأ التيار أولا ثم يحسب كم من الخرج يجب تعديله ثم يضع هذا التعديل فى العداد الخاص بتعديل عرض النبضة و ينتظر تأثيره على النبضة التالية**. **البعض يرى هذا ليس بالأمر الجلل و البعض يرى أنه لو لم تحتاج لحسابات متطورة مثل تعديل القدرة مع تغيير التردد المستخدمة فى انفيرتر التيار المتردد فربما يكون التحكم الخطى أكثر أمنا و أقل تعقيدا و ايسر فى الصيانة**.*
*فى المتحكم نختار عداد مناسب و نختار له مصدر النبضات ألذى يوفر لنا التردد المطلوب ثم نجعله يعد و نجعل طرف ما **=1 **وهذا يمد الحمل بالتيار و عند حد معين نجعل الطرف **= **صفر وهذا يوقف التيار**.*
*حسنا ماذا يحدث لو لم يستجيب المتحكم و كلنا نعلم انه قد يغيب فى دورة لا نهائية و لا أدعى خطأ منك فى البرمجة ولكن قد تدخل نبضة ما من مصدر ما فتربك تنفيذ ألتعليمه الحالية، هنا قد يتوقف فجأة وهذا قد يكون خطرا، و الأسوأ أن تفتح الطاقة ولا تقفل فلا يتحكم فيها **افلا ننسى أن الأوساط الصناعية معروفةبأنها عالية الضوضاء – لا أقصد الصوت فقطولكن ضوضاء النبضات و التداخلاتالكهرومغناطيسية عامة ، **وهنا دور كلب الحراسة أو مؤقت الحراسة وهو موضوعنا القادم إن شاء الله*


----------



## ماجد عباس محمد (6 أغسطس 2018)

*مؤقت الحراسة Watchdog Timer أو WDT*

*مؤقت الحراسة Watchdog Timer أو WDT*

*لمعالجة الحالة السابقة يمكن وضع عداد يعد أى نبضات لفترة ما تختارها طبقا لبرنامجك من حيث عدد الدورات و زمن استجابة الموتور أى كم ثانية يحتاجها لتصبح سرعته غير مقبولة أو متر ترتفع التيار لحد يسبب خطر على الدوائر**. **لا تستهين بمسألة التيار هذه فبالنسبة لموتورات أغلب تطبيقاتنا تكون **1 **إلى **5 **أمبير أو حتى **10 **أمبير لكن هناك ماكينات تسحب **25 **أو **100 **أو حتى أعلى**. **هذه الماكينات عادة تكون موتوراتها ذلت حث أقل من الصغيرة و من ثم معدل ارتفاع التيار لا تتجاوب معه الفيوزات العادية و من ثم تتلف المكونات سواء ثايرستور أو تراياك أو موسفيت أولا ثم يحترق الفيوز لاحقا ولذا تستخدم نوعية خاصة من الفيوزات تسمى سريعة القطع و للأسف ثمنها مع هذه التيارات العالية يدعو للتفكير مرتين**.*
*لذا نشأت الحاجة لهذا العداد و ألذي لو اكمل العد يعنى الفترة الزمنية انقضت و من ثم يسبب إعادة تشغيل كاملة للجهاز**.*
*طبعا يجب أن تأخذ فى الاعتبار أن زمن إعادة بدء تشغيل المتحكم هو من صلب الزمن ألذى تحاول أن تتفادى مروره**. **و الآن نحتاج لوسيلة لتصفير هذا العداد كل فترة قصيرة أقل من ذلك الزمن الحرج**.*
*أبسط طريقة لو لم يكن المتحكم مجهز بهذا العداد أن نضيفه خارجيا باستخدام **4060 **هكذا*




*ببساطة **4060 **هو عداد من **14 **مرحلة أى يعد **16384 **و به **2 **عاكس يمكن استخدامهما كمولد ذبذبات يعتمد تردده على قيمة م**1 **و س**1 R1C1 **أما **R2 **فيفضل أن تكون **10 **أمثال **R1 **و تردده **= 1/(2.2*R1*C1)*
*و زمن النبضة **2.2 * R1*C1*
*إذن بالقيم فى الدائرة زمن النبضة **= 2.2 * 10000*0.1 **ميكرو أى **0.0022 **ثانية و بهذا يبقى الخرج رقم **14 = **صفر **18 **ثانية ثم يبقى **1 **لمدة **18 **ثانية و يمكنك أخذ النصف أو الربع أو الثمن أو تعدل التردد كما تشاء لتحدد الزمن**. **و تختار أى طرف من أى منفذ يتولى تصفير العداد**.*

*وضعت الشركات المنتجة للمتحكمات عداد مخصص لهذه الوظيفة داخل المتحكمات مثل **AT89S8252 **من عائلة **C51 **و غيره و كامل عائلة **AVR **و أغلب منتجات ميكروتشيب ، عندما يصل للحد الأقصى يسبب إعادة بدء ريسيت **Reset **للمتحكم وهذا يتطلب إتاحة لو تنوى استخدامه فهو عادة غير متاح و تهيئة تحدد بها زمن انتظاره و لا تنسى أن تستخدم أمر التصفير حتى لا يسبب إعادة التشغيل**. *




*كمثال فى متحكم **AT89S8252 **نجد له مسجل مستقل للتحكم فيه كما بالصورة حيث يعمل على مهتز خاص به لضمان استقراره و يحدد مدته ثلاث بيت على اليسار باللون الأصفر **PS2,PS1,PS0 **و يتراوح ما بين **16 **مللى ثانية لأكثر قليلا من ثانيتين**. **الإثنين بت اقصى اليمين رقمى صفر وواحد فالأولى إتاحة و الثانية للتصفير*

*البت **3**،**4 **لإتاحة الذاكرة **EEPROM **و إتاحة الكتابة و البت باللون الأخضر لتحديد أى من المسجلين نستخدم حيث كل متحكم به مسجل مؤشر البيانات وهو عادة **16 **بت لتعيين أى مكان فى البرنامج أو التعامل مع ذاكرة خارجية وهذا يسهل التعامل مع الجداول و سبق الإشارة إليه و هذا المتحكم به زوج ليسهل التعامل مع شيئين معا**.*




*المنحكم **AT89S8253 **أضاف ميزات لهذا العداد و لكنه استخدم الكريستال الخارجية و أصبح كعداد للتعليمات وهو يمكنه العمل على **X2 **و من ثم يكون الجدول السابق سارى مع كريستال **12 **ميجا**. **ومن ضمن الإضافات التى أتاحها هذا المتحكم أن العداد يمكنه عمل ريسيت داخلى فقط أو يمكنه أن يظهر على طرف الريسيت الخارجى ليؤدى الوظيفة على كافة البوردة الخارجية**.*

*المرة القادمة إن شاء الله نكمل النوعين الآخرين*


----------



## ماجد عباس محمد (7 أغسطس 2018)

*مؤقت الحراسة فى متحكمات AVR*

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





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

*فى عائلة **PIC16 **تعمل من مولد منفصل و لها فترة **18 ms **و يمكن زيادتها كما سبق باستخدام المقسم السابق **pre scalar **وهو كما سبق يمكن تخصيصه للتايمر أو **WDT **و ليس للإثنين معا**. **أما فى عائلة **18 **فتأخذ من المولد العام و يمكن برمجته لفترات طويلة و اللغات العالية يجب أن تقوم بهذا الدور عنا*

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




*الفتحات كما بالصورة **64 **فتحة و عادة ما تكون ثنائية العد أى **64 **أو **128 **أو **256 **و ذلك لتسهيل التعامل الرقمى معها**.*
*الآن إضافة هذا التاكو يحتاج لدوائر تعريف ما إن كان يدور مع أم عكس عقارب الساعة و أيضا لحساب عدد الدورات الفعلية لنصحح القيم **. **لذا سيكون هذا أكثر تعقيدا و بالتالى سنستخدم الطريقة الثانية أى مقاومة متغيرة تحدد السرعة المطلوبة**.*
*أعلم أن البعض معترض على الاسم و الآخر يصحح **"**إنكودر**" **، حسنا نترجم الاسم لنفهم الأمور**. **تاكو هو تاكو ميتر أى عداد نبضات وهذا الجهاز به فتحات تحدد فقط عدد نبضاتها فى الثانية و إن كانت مع أو عكس عقارب الساعة لكن لو توقف فلا تعلم عنه شيئا سوى أنه متوقف**. **الإنكودر على النقيض يعنى مشفر أى يعطى شفرة عن معلومات معينه لذا فبه قرص مكود بشفرة **Gray Code **أى شفرة العالم جراى و عدد ليدات مساوى لعدد النبضات فلو بدقة **10 **بت مثلا يكون به **10 **ليد قراءة و يرسل العشر بت معا على التسلسل ولو توقف يظل يرسل معلومات الزاوية المتوقف عندها، لذا يحتاج لنبضة أخرى تسمى نبضة الشمال **North Pulse **وهى تمثل نقطة الأصل التى يبدأ عندها العد و ترتيب الكود أو نبضة أخرى لتحديد اتجاه الدوران و لذا فهو مكلف و يستخدم فى هوائيات الرادار و كثير من الأجهزة الدقيقة المكلفة**. **لذا نستخدم هنا مقياس سرعة و ليس إنكودر**.*

*و لكى نقيس الخرج لنعرف المطلوب و ما يحدث علينا بالمحول ألتماثلى الرقمى وهو موضوعنا القادم إن شاء الله*


----------



## ماجد عباس محمد (8 أغسطس 2018)

*المحول التماثلى الرقمى*

*هناك أنواع مشروحة فى سلسلة الدوائر الرقمية ولكن هنا نهتم بما هو موظف فى وحدات الميكرو و المسمى **SAR اختصار Successive Approximation Register **وهى ببساطة لو أننا نريد **10 **بت مثلا سنستخدم محول بالعكس من رقمى لتماثلى سنقارن قيمة **9 **بت آحاد بالدخل فإن كان الدخل أعلى تكون البت **10 = 1 **و إلا **= **صفر ثم نقارن الفرق بنصف القيمة أى **8 **بت و هكذا *




*أى أننا نحول من تماثلى لرقمى باستخدام العكس أى وحدة تحويل من رقمى لتماثلى و هنا يجب أن نفهم ثلاثة أشياء هامة جدا قبل أن نبحث الدقة وهذه هى*
*1- **ما معنى **Vref **و أثره على النتيجة*
*2- **ما هو **Vin **و ما هى حدوده*
*3- **ما دور **Clock **هنا*
*وهنا يجب أن نوه على أن الرسم المرفق تقريبى و الدقيق يتباين من وحدة لأخرى لكنه دقيق بالقدر الكافى لتوضيح الأمور**. **نعلم أن المحول من رقمى لتماثلى وهو المربع الأوسط باللون الأصفر عبارة عن مجموعة سويتشات توصل و تفصل حسب البت المناظرة **= 1 **أم صفر و من ثم تحتاج لجهد يحدد لها كل نقله **= **كم فولت لذا وجب أن يكون لديها ما يسمى **Vref **أو الجهد المرجعى ألذى يحدد القيمة التى يكون عليها الخرج عندما تكون كل المداخل **=1 **أى كل البتات **= 1 **و من هنا نجد أن أعلى قيمة للخرج الرقمى لا توازى فولت معين و لكنها تساوى **Vref **أى لو غيرت **Vref **ستغير قيمة كل بت و من ثم العد الثنائى الناتج**. **ببساطة لو الدخل مثلا **1 **فولت و غيرت **Vref **ليساوى **2.048 **فولت فكل بت **= 2 **مللى فولت ولو غيرته إلى **4.069 **ستصبح البت **= 4 **مللى فولت ولو **1.024 **ستصبح **= 1 **مللى فولت ولا نحتاج لحسابات وهذه نقطه يغفلها كثير إن لم يكن كل من رأيتهم يتعاملوا مع **ADC **و يربكون أنفسهم فى حسابات معقدة ولو عدلوا قليلا فى قيمة **Vref **لأصبحت الأمور أسهل و ما أسهل من أن كل **1 **يساوى **1 **أو **2 **أو **3 **أو **4 **أو **5 **بدلا من **1.024 **و اقسم و اضرب و اطرح بعد ذلك**.*
*هل نعقد الأمور فى مكان لنسهل الأمور فى مكان آخر؟؟*
*أظن البعض نسى وجود مقاومة متغيرة كهذه**.*




*ألأن نعود لما تفعله الدائرة هو تضع **9 **آحاد أى نصف القيمة كدخل للمحول فيعطى نصف **Vref **و بمقارنته بالدخل سيكون لو الدخل أعلى إذن هو فى النصف الأعلى و لتسهيل الفهم نفترض أرقام بسيطة و سهلة ولو غير واقعية لكن الرياضيات لا تعتمد على الأرقام بل المعادلات**. **فلو **Vref = **عشرة فولتات للسهولة فإن ما سبق سيحدد ما إن كانت قيمة الدخول **4.999999 **فولت أو اقل و تكون البت رقم **10 = **صفرا أم **5.000001 **فولت أو أعلى مثلا فتكون البت رقم **10 = واحد.*
*مهلا لم لا تقول **5 **فولت؟ معذرة وهل فى الدائرة طرف “**=” **أو هل للمقارن خرج اسمه يساوى؟؟ هذا ما يسمى بالخطأ الكامن لأنه كامن فى نظام العمل**. **ليس هذا الخطأ مرتبطا بالفولت ولكنه أى قيمة للدخل لا تستطيع عدد البتات أن تعبر عنه بدقة**. **لكن يمكن تقريب الخطأ بفحص البت التالية ، نعم بمكن ذلك *
*الآن حددنا ما إن كانت بت **10 = 1 **أم صفر فنثبتها و نكمل بصفر و **8 **آحاد أى **1011111111 **أو **0011111111 **حسب النتيجة السابقة ونقارن خرج المحول بالدخول لنحدد البت التاسعة و هكذا**. *
*لتثبيت البت يجب و ضعها فى ماسك **Latch **و تحتاج نبضة لحفظها و تعديل الدخل لذا نحتاج نبضة أو نبضتين من **Clock **لكل بت و من ثم لعشرة بت سنحتاج على الأقل لعشرة نبضات غير نبضات أخرى للتمهيد و إخطار النظام أن القيمة جاهزة للقراءة**. **أما التهيئة فالدخل لن يثبت طوال زمن النبضات لذا وجب استخدام دائرة احتفاظ بعينة **Sample And Hold **وهى موسفيت يخزن الدخل فى مكثف صغير تقرأ منه الدائرة وهى المسماة **S/H .*
*الآن أصبح لدينا عدة عوامل نحتاط لها و أولها هى أن لدينا **10 **بت إذن ستقرب القراءة حتى تصبح البت رقم صفر غير دقيقة**. **ثم نزيد عدد البتات من **10 **إلى **12 **ستتكرر مع البت صفر أيضا وهكذا دوما ولذا تجد كل الأجهزة الرقمية تضع الدقة مثلا **1 % +/- 1 **عد أى أن العد الأدنى غير معتمد**. **المشكلة أن لو أضفنا عدم خطية الدوائر و غيره من مسببات الخطأ سيكون لدينا بت أو **2 **تنحصر فيهم كمية أخطاء النظام**.*
*ثانى هذه العوامل أن دائرة الاحتفاظ بالعينة تستخدم مكثف مصنوع من السيليكون و أكسيده كعازل**.**حقا لن تجد أفضل من هذا لكنك لن تجد مساحة كافية لمكثف كبير لذا يكون بضع بيكوفاراد فقط لذا يجب أن تكون معدل النبضات **Clock **سريعة بالقدر الكافى للتحليل قبل أن تتغير القيمة على هذا المكثف نتيجة للتسريب فى المكثف أو دوائر التحويل المتصلة به**. *
*ثالث هذه العوامل هى المصدر ألذى ينقل الجهد المقاس لدائرة الدخول إذ يجب أن تكون مقاومته الداخلية صغيرة جدا حتى لا تسبب فى خطأ نتيجة زمن الشحن كما أن مقاومته فى الاتجاهين تكون متساوية حتى لا يختلف زمن الشحن عن التفريغ و يسبب ذلك خطأ فى القياس**. *
*رابع هذه العوامل هو ثبات كافة الفولتات سواء فولت التغذية أو فولت **Vref **وهنا لا تقول أنه ثابت**... **فأنت تتكلم عن **10 **بت أى **1024 **عد أى **1:1000 **من الفولتات المذكورة وهى **5 **مللى فولت فى التغذية قيمة تعرجات من أى تداخل ، و قيمة **Vref / 1000 **و هذا ببساطة بدلا من القسمة على **1024 **فالفرق **2% **فقط**.*
*أيضا هل الضوضاء الناجمة عن الميكرو ذاته تؤثر على عمل وحدة المحول؟؟*
*من هنا أقول اقرأ الداتاشيت جيدا و اعرف حدود ما لديك ولا تطلب أكثر منها**. **إن شئت دقة أعلى فليكن باستخدام وحدة مستقلة فمثلا وحدات **AVR **تنص صراحة على أنها **10 **بت و نسبة خطأ **+/- 2LSD **أى أن أقل **2 **بت بهما خطأ ، حسنا لا نستطيع الاعتماد إذن على ما هو أكثر من **8 **بت و ميكرو تشيب لا توضع صراحة نسبة الخطأ و لكنها تحسب لك كثير من الأنواع و تترك لك مهمة الحساب**. **شخصيا لو أريد أكثر من **8 **بت الجأ لوحدة خارجية**.*
*قبل أن نترك هذا الموضوع فلدينا **5 **فولت على **1024 **خطوة أى كل عد **= 4.8828125 **مللى فولت**. **السؤال هل ستضع المتحكم على قاعدة لتتمكن من رفعه و برمجته حتى تضبط البرنامج أو تغير المتحكم عند الضرورة؟؟؟ أكيد نعم إذن هل سمعت عن ظاهرة الإلكتروليسيس وهى ظهور فرق جهد عند تماس معدنين مختلفين فى وجود أى سائل بينهما (لاتتعجب فالرطوبة فى الجو هى سائل موجود الآن وبعد ساعة قد يختفى) و هى ظاهرة البطارية و الثانى ظاهرة الثيرمو كابل  حيث عند تماس معدنين مختلفين يكون بين الطرفين المتلامسين فرق جهد يعتمد على الحرارة؟ فلو لم يكن المتحكم ملحوما على البوردة فهذه الظواهر تسبب فرق جهد و مهما كان قليلا فهو ليس ثابتا و سيؤثر على ثبات القراءة و ليس فقط دقتها و لذا يلجأ الكثير للقراءة عدة مرات ثم أخذ المتوسط**.*
*هنا أيضا نقطة هامة وهى أنه ينص فى أى وحدة على أن الدقة **1% +/- 1 **بت**. **لنكن صرحاء هنا **1% **من أقصى قيمة و ليس من قيمة القياس فلو **8 **بت ستكون **2.5 **لأن **8 **بت تعطى **255 **و **1% = 2.55 **وهذا أكثر من **+/- 1 **بت لذا فالأكثر دقة تعطى نتائج أفضل و كلما زاد عدد البت ستحتاج لدقة أعلى ففى هذا المثال لو نطبقه على **10 **بت أى **1024 **سيكون الخطأ **10.24 **وهذا **4 **بت**.*
*المرة القادمة إن شاء الله نتحدث عن الحفظ فى **EEPROM*


----------



## ماجد عباس محمد (9 أغسطس 2018)

*الذاكرة الغير متطايرة EEPROM*

*سبق شرح تركيبه و باقى الأنواع فى سلسلة الدوائر المنطقية و هنا نكتفى بخواصها التى تتمثل فى احتفاظها بالبيانات ربما لعشرة أعوام فى غياب التيار و يمكن الكتابة فيها و التعديل أيضا عليها عشوائيا و تم التعديل عليها بحيث لا تحتاج لمحو كلى قبل إعادة الكتابة لذا تحتاج لمحو الخانة ثم إعادة الكتابة مما يجعلها بطيئه نوعا ما**. **و لست فى حاجة لعمل هذه الخطوات فالمتحكم يتولاها لكنك تضطر لانتظار تمام هذه العملية قبل التعامل معها مرة أخرى سواء بالقراءة أو الكتابة**.*
*حسنا ماذا نكتب فيها؟ وهل هذا سؤال؟ طبعا أى معلومة أود الحفاظ عليها**... **حسنا مهلا لنعود للداتاشيت حيث نجد للمتحكم ثلاث أنواع من الذاكرة**.*
*ذاكرة فلاش للبرنامج و معدل الكتابة فيها **1000 **مرة إلى **100000 **مرة فى أتميل بينما لم تذكر ميكروتشيب عدد المرات فى **16 **و ذكرت **100000 **أيضا فى **18*
*ذاكرة **EEPROM **و معدل الكتابة **100000**مرة فى أتميل و **1000000 **فى ميكروتشيب *
*ذاكرة رام و لم تذكر أى شركة أى شيئ عن عدد المرات وهذا منطقى**. **ففى فترة تشغيل لمدة ساعة قد تكتب و تقرأ اكثر من بضع الملايين من المرات فى الذاكرة العشوائية رام لكنك لن تبرمج المتحكم ربما أكثر من مئة مرة لذا اعتماد من ألف لعشرة الآف مرة للبرمجة هو أمر رائع لكن الذاكرة المحفوظة **EEPROM **من مئة ألف فى أتميل لمليون فى ميكروتشيب لابد أن يقرع لنا جرسا تنبيهيا هنا**. **المقصود أن تحتفظ بالبيانات الموضعية التى لا تتغير كثيرا**.. **أى ما تحتاج فى هذا المكان أن تضبط عليه أو هذا المستخدم يحتاجه لذا استخدامنا هذه الذاكرة لحفظ قيمة التشغيل هو من هذا القبيل**.*
*أحد المصممين قام بتصميم جهاز لف محولات و استخدم متحكم للتشغيل و حفظ فى الذاكرة فيم اللفات وهذا أمر جيد جدا حيث يمكنك أن تحدد **10 **أنماط من المحولات تستدعى أيها للتنفيذ **. **و أضاف ميزة أخرى لو انقطع التيار سيحتفظ بقيمة العد الحالى لاستكماله حال عودة التيار وهى فكرة أخرى رائعة و لكنه ليفعل ذلك حفظ فى **EEPROM **كل عد يقوم به العداد و بحسبة بسيطة نعلم أن محول **1 **أمبير عادى يحتاج **3500 **لفه إذن بقسمة مليون على **3500 = 285 **محول ثم قد يتعرض المتحكم لعدم الاستجابة و ربما التعطل**. **لذا حتى استخدام ذاكرة خارجية كان بالتأكيد سيكون أفضل من حيث أن تغيير الذاكرة أهون من تغيير المتحكم لكنه ما كان ليحل هذه المشكلة كليا فهذه الكمية من المحولات قد تتم فى يومين أو ثلاثة فمن يقوم بلف السلك ** فى الإنتاج الكمى **ليس هو من يلحم السلك و كلاهما لا يضع الحديد فى القلب**. **و الحل كان باستخدام مقارن مثل **311 **أو **393 **و عندما ينخفض الفولت عن **4.5 **فولت يحفظ العد و ينتظر**.*

*فى عائلة **51 **لدينا المتحكم **AT89S8253 **و به **2 **ك ذاكرة **EEPROM **و متوافر و يمكن أيضا استخدام **24c00 **ذاكرة خارجية **16 **بايت أو **24c01 **أو **24c02 **أو **24c04 **أو **24c08 **أو **24c16 **بسعة **1**ك و**2**ك و**4**ك و**8**ك و**16**ك بت **(**وليست بايت**) **وهى من **8 **طرف متفقة فى كافة الأطراف حيث بها **3 **طرف عنوان لتتمكن من توصيل **8 **ذواكر معا و لكل منها عنوان من صفر لثمانية**. **لو تريد التعامل مع الأولى ترسل عنوان صفر ثم تكتب و تقرأ ما شئت ثم ترسل عنوان **5 **مثلا للتعامل مع الذاكرة رقم **5 **وهكذا و بوصل **8 **من **24c16 **تحصل على **16*8=92 **ك بت أى **16 **ك بايت*




*أيضا طرف **SCL **وطرف **SDA **للتعامل بطريقة **I2C **وهى جيدة لتطبيقات مثل محطات الأطباق حيث توجه الطبق لقمر ما فتحفظ رقم القمر و العد المناظر له**. **و طرف **WP **اختصار **Write Protect **حماية ضد الكتابة الخطأ خاصة عند بدء التشغيل أو قطع التيار**. **عندما يكون **WP= 1 **فيمكن القراءة ولكن لا يمكن الكتابة**.*
*نشرح ببساطة طريقة **I2C **لكى تفعل ما تشاء وقت الحاجة وهى تعتمد على **9 **بت و وضع بدء وآخر انتهاء.
*




*نعلم كلنا أن أجهزة **I2C **لها عنوان تعريفى لذا يكون أسلوب التفاهم **"**البروتوكول**" **أن ترسل أولا من المتحكم أمر به العنوان و ما إن كنت تنوى القراءة أو الكتابة ولو تكتب فنوع الكتابة أمر أم بيانات**.*
*طرف **SCL **يحدد متى تبدأ إذ يجب أن يكون **=1 **حتى تتلقى أمرا من **SDA **و عندما يكون **=1 **فإن انتفال **SDA **من **1 **إلى صفر يعنى ذلك بداية التراسل و إن كان من صفر إلى **1 **تعنى نهاية التراسل حتى لو كانت التغيرات متتالية لهذا لا نقل بيانات طالما **SCL =1*
*الآن وضعنا **1 **على **SCL **ثم غيرنا **SDA **من **1 **لصفر هذا يعنى لنبدأ الحوار**. **ولنكمل الحوار يجب وضع **SCL = **صفر **. **الآن أى تغيير على خط **SDA **لا يعتد به**. **ضع عليه ما تشاء صفر أم واحد و الآن ضع نبضة موجبة على **SCL **مع إبقاء الآخر بلا تغيير **. **هذا ينقل ما وضعت سواء صفر أم واحد لداخل القطعة **. **سنقول قطعة لكونها ذاكرة أو أى حساس آخر يعمل بذات النسق**. **الآن نضع البيان الجديد أو لو شئت إبقاء القديم للتشابه ثم نبضة **SCL **و هكذا **8 **بت و الآن تقلب وضع **SDA **من خروج لدخول و تضع نبضة على **SCL **يجب أن تتلقى أثنائها صفر على خط **SDA **وهذا يخبرك أن القطعة تلقت بايت كاملة لذا تسمى **Acknowledge **أى **"**علم**" **أو **"**عرف**" **هنا يجب أن نذكر أنه لكى يمكن للقطعة أن ترد بصفر و باعتبار وجود أكثر من واحدة على ذات المسار فيجب أن يكون هذا الطرف من نوع **Open Drain **أى مصب مفصول و بذلك يجب أن توصله أنت خارجيا بمقاومة واحدة فقط للمجموعة كلها قدرها **5 **ك أوم للمصدر **+5 **فولت**. *
*الآن ماذا نرسل فى هذه البايت؟ كما بالصورة*




*فورا يلى البدء **Start **العنوان وهو من **7 **بت**. **أول أربعة هى **1010 **أى هيكسا **A **و الثلاثة التالية هى وضع الثلاث أطراف بذات اللون و المسماة **A0,A1,A2 **على متكاملة الذاكرة و هكذا تختار واحدة من ثمانية يمكن وضعها على الخط**. **أما لو قطعة من نوع آخر مثل ساعة أو غيرة سيكون لها عنوان مختلف من **7 **بت أيضا**. **و البت الثامنة لو **1 **تعنى قراءة للمتحكم ولو صفر تعنى كتابة فى القطعة**. **و هنا أذكر بالمبدأ المتكرر لو تلف ماذا يحدث، على هذا الطرف مقاومة **5 **كيلو للموجب أى ستفرض **1 **أو قراءة حتى لا تكتب بالخطأ و تفسد ما عليها**. **البت التاسعة **ACK **و بعد ذلك تتوالى البيانات ببساطة حتى نبضه توقف **Stop **كما يلى**.*




*عندما تريد الكتابة سترسل بايت التحكم بعد نبضة البدء و فيها البت **8 = **صفر أى تريد الكتابة و هنا تستجيب الوحدة بنبضة **ACK **ثم ترسل بايت بها العنوان حيث تريد الكتابة فترد القطعة ثم ترسل بايت لتكتبها أو أكثر من بايت متتالية بحد أقصى صفحة واحدة وهذا الصفحة تختلف يحسب رقم الذاكرة من**2 **إلى **8 **بايت **(**ارجع للداتاشيت **) **ثم ترسل **Stop **فتتولى القطعة الكتابة و ترسل **ACK **عند انتهائها من الكتابة**.*
*لو تريد كتابة بايت واحدة فقط ارسل بعدها **Stop **و رغم أن الكتابة التالية ستكون فى العنوان التالى إلا أن نسق الوحدة هو أن ترسل بعد كل أمر كتابة عنوان ثم البيانات**. **لذا قد يكون من الأفضل أحيانا أن تجمع بيانات صفحة كاملة قبل البدء فى الكتابة**.*

*لو تريد القراءة سترسل **Start **ثم بايت تحكم فيها بت **8 = 1 **قراءة فتستمر فى القراءة حيثما كنت**. **هذا بالطبع ليس دوما مرغوبا لذا يمكنك أن تبدأ بايت تحكم مع كتابة ثم تكتب عنوان حيث تريد بدء القراءة ثم **Start **مرة أخرى دون الحاجة لإرسال **Stop **مع بايت أمر قراءة فتقرأ حيث حددت المكان**. **و هكذا تقرأ بلا حدود فإن شئت تغيير العنوان لتقرأ من مكان آخر ضع **Start **أخرى مع كتابة عنوان جديد أو تضع **Stop **لإنهاء العملية**.*




*المرة القادمة إن شاء الله سنضع كود اسيمبلى لعائلة **C51 **تستخدمه حيث تريد*


----------



## ماجد عباس محمد (10 أغسطس 2018)

*كود اسيمبلى لقراءة وحدة I2C :*

*الوحدة تحتاج ثلاثة برامج فرعية **Sub **واحد لقراءة بايت و تستخدمه لأى عدد وهو يتطلب تحديد عنوان البدء لذا نضع رابع لتحديد البدء**. *
*إذن هنا نبدأ بالتعريفات و يجب ملاحظة أنها قد تتشارك مع كثير من التعريفات المطلوبة لباقى الكود وليست بالضرورة تتخصص لقراءة وحدات **I2C .**أول تعريف قد يكون مفيدا لكثير من المبرمجين و يوفر كثير من الوقت و الكود**. **تعريف **HW_Err **حيث يخصص خانة من الذاكرة باسم أعطال المكونات وهى تستطيع أن تحوى بيانات **8 **أجهزة و بتعليمه وضع صفر يكون الكل بخير و يلى ذلك تعريف كل بت منهم باسم أخر كقولنا مثلا*
*MemErr = HW_ERR.0*
*ADCErr=HW_ERR.1*
*الخ ثم **SETB **تعرف أن هذه القطعة لا تعمل و من ثم لاحقا لديك الأمر **JB **لتضع رسالة خطأ مناسبة للمستخدم**. **لو تركت هذا للمترجم سيخصص بايت كاملة لكل بت منهم أى **8 **بايت**.*


```
[LEFT]; Definitions
;HW_Err EQU 20h
Dev_Add EQU 21h
ByteCount EQU 22h
BitCount EQU 23h
PgAddress EQU 24H 
AckDel EQU 25h
DelTime1 EQU 26h
DelTime2 EQU 27h

SDA EQU [B]P0[/B][B].[/B]2 [COLOR=#008080]; Mem[/COLOR]
SCL EQU [B]P0[/B][B].[/B]3
[/LEFT]
```
*يلى ذلك تعريف **Dev_Add **أى عنوان القطعة و يمكنك تخصيص مكان فى الذاكرة كما هو مكتوب أو تكتفى بأن تضعه فى المراكم **A **و تنفذ ما شئت فقط لا تنسى أن تغير التعريف أو التعريف و الكود حسب المترجم لديك**.*
*تعريف **ByteCount **فقط ليذكرك كم بايت كتبت من الصفحة **Page **لو ستكتب صفحة كل مرة**. **تعريف **BitCount **يمكنك حقيقة استبداله بأى متغير متاح لديك فالفكرة أن البايت بها **8 **بت و انت تحتاج لعدهم وهنا للتوضيح فقط خصص لها مكان فى الذاكرة لكن يمكنك استخدام مسجل من **0 **إلى **7 **أو أى خانة تسميها **Count **تعد بها كل الدورات الموجودة فى البرنامج**.*
*PgAddress **أيضا مجرد خانة لتحفظ فيها أين تريد بدء الكتابة داخل الوحدة**.*
*AckDel **لو تستخدم قطع كثيرة متنوعة على ذات الخط قد يختلف زمن انتظار الرد **ACKNOWLEDGE **من طراز لآخر وقد تحتاج أن تجعل الزمن متباين و إلا يمكنك استخدام رقم ثابت و نستغنى عنه**.*
*DelTime1,2 **خانتان لعد زمن تأخير سواء قليل حتى اكثر من **256 **أو اكثر حتى اكثر من **65536 **بهما معا و يمكنك دمجهما مع أى خانات مخصصة لما يسمى **Scratch Pad **أو كشكول المسودة حيث تحسب أشياء وقتية**.*
*SDA,SCL **مطلوبان للنظام**.*


```
[LEFT]

Mem_Init:           [COLOR=#008080]    ; RESET ATMEL memory, a dummy write[/COLOR]
; MOV HW_ERR,#0  [COLOR=#008080] ; Clear all errors[/COLOR]
[B]ACALL[/B] MemStart   [COLOR=#008080] ; the 24C01 reply erroneously IF uP is reset, and needs [/COLOR]write cycle
[B]MOV[/B] [B]A[/B][B],[/B]Dev_Add   [COLOR=#008080] ; Device address 1010,page 000 and write bit[/COLOR]
[B]ACALL[/B] WriteMemByte
[B]ACALL[/B] SendPgAdd
[B]ACALL[/B] MemStop
[B]ACALL[/B] Wait_10ms
[B]RET[/B]

CalcMemAdd:      [COLOR=#008080]    ; Calculates Page Address by PageNu in A * 8[/COLOR]
[B]MOV[/B] [B]B[/B][B],#[/B]8
[B]MUL[/B] AB
[B]MOV[/B] PgAddress[B],[/B][B]A[/B]
[B]RET
[/B][/LEFT]
```


*الكود التالى خاص بالذاكرة **24C01 **من إنتاج أتميل فقط حيث بعد ريسيت قد لا تستجيب كما يجب لذا يجب تهيئتها باستخدام دورة 
كتابة كاذبة بطلب كود البدء **MemStart **ثم نضع العنوان **1010000 **و بت كتابة ثم نرسل الأمر و نختار صفحة مثلا صفر و نرسله و نرسل نبضة إيقاف **MemStop **و ننتظر **10 **مللى ثانية**.*
*الكود التالى يمكنك الاستغناء عنه فقط احسب العنوان كما تشاء و حسب ما لديك من عتاد**.*


```
[LEFT]MemStart:  [COLOR=#008080] ; Send start code, ret w/ SCL,SDA low[/COLOR]
[B]SETB[/B] SDA
[B]NOP[/B]
[B]SETB[/B] SCL
[B]ACALL[/B] Wait_9
[B]CLR[/B] SDA   [COLOR=#008080]; Start [/COLOR]
[B]ACALL[/B] Wait_9
[B]CLR[/B] SCL [COLOR=#008080]; ready for clock[/COLOR]
[B]ACALL[/B] Wait_9
[B]RET[/B][/LEFT]
```

*يلى ذلك كود إرسال نبضة البدء حيث يجب أن يكون **SDA,SCA=1 **ثم بعد ذلك ينتقل **SDA **للصفر**. **النبضة **Clock **يجب أن تكون صاعدة لذا و حال **SDA=**صفر ننقل **SCL = **صفر فى انتظار النبضة**. **السبب فى هذا أنك لو أردت قراءة **100 **بايت مثلا لن تحتاج **Start **أخرى مادام العنوان متتالى و تحتاجه فقط عند تغيير العنوان**.*
*يلى ذلك إرسال نبضة **MemClk **و إرسال توقف **MemStop*


```
[LEFT]MemClk:
[B]ACALL[/B] Wait_9
[B]SETB[/B] SCL
[B]ACALL[/B] Wait_9
[B]CLR[/B] SCL
[B]ACALL[/B] Wait_9
[B]RET[/B]

MemStop:
[B]CLR[/B] SCL[COLOR=#008080] ; just in case , prepare for stop[/COLOR]
[B]NOP[/B]
[B]CLR[/B] SDA[COLOR=#008080] ; Ready for stop[/COLOR]
[B]NOP[/B]
[B]SETB[/B] SCL [COLOR=#008080]; Command mode[/COLOR]
[B]ACALL[/B] Wait_9
[B]SETB[/B] SDA [COLOR=#008080]; Stop[/COLOR]
[B]ACALL[/B] Wait_9
[B]CLR[/B] SCL[COLOR=#008080] ; End of Command mode[/COLOR]
[B]RET
[/B][/LEFT]
```


*إرسال نبضة **MemClk **يبدأ بوضع **SCL=1 **ثم إعطاء الوقت الكافى ثم إعادته للصفر و أيضا اعطاء الوقت الكافى و إرسال توقف **MemStop **رغم أننا مفترض أن نأتى و **SCL=**صفر ولكن احتياطيا نجعله بصفر ثم وقت ثم **SDA=**صفر و انتظار وهنا نجعل **SCL=1 **ليترجم الطرف الآخر كأمر و ننتظر ثم نضع **SDA=1 **كأمر بالتوقف ثم ننتظر و أخيرا نضغ **SCL = **صفر حتى لا يترجم مزيد من الأوامر**.*
*أول ما نحتاجه هو كتابة بايت لتحديد البداية وهذا موضوعنا القادم إن شاء الله*


----------



## ماجد عباس محمد (11 أغسطس 2018)

*أول ما نحتاجه هو كتابة بايت لتحديد البداية و كما ذكرنا فنعد **8 **بت فى خانة أو مسجل أو ما تريد تسميته **BitCount **ولو لديك متغير باسم **Cntr **مثلا تعد به كل ما تحتاجه فلا بأس ثم تستخدم الأمر **RLC A **وهو **Rotate Left through Carry **وهو ببساطة يزيح كل البتات فى المراكم **A **يسارا خطوة واحدة و البت **7 **تذهب إلى **C **و ما كان فى **C **يذهب إلى بت صفر فى **A **و السبب أننا لا نستطيع نقل بت من المنافذ أو الذاكرة إلا لخانة **C **و منها فقط**. **لذا طبيعى أن تكون الخطوة التالية هى **MOV SDA,C **حيث تنقل البت إلى طرف **SDA . **نستخدم **Left **لكى ننقل البت العليا أولا كشروط نظام **I2C **و مقابلها **RRC **وهى لليمين**. **بعد ذلك نطلب الأمر **MemClk **لإعطاء نبضة ثم ننقص عدد البت واحد و نقفز لنكرر باقى **8 **بت وهنا لا نعطى بدء **Start **ولا توقف **Stop **فقد نحتاج إرسال بايت جديدة**.*
*الآن لدينا بت قادمة من القطعة تقول **ACK **و قد اعتمدت حقيقة طريقتين مختلفتين فيما نفذت من برامج*
*الأولى أن افحصها مرة واحدة فى البدء أثناء التهيئة فإن لم تأتى أعطى رسالة خطأ و أتوقف و إن كانت موجودة فهى بخير و أفترض سلامتها طوال وقت التشغيل مكتفيا بإعطاء نبضة لترد بنبضة **ACK **ولا أقرأها ولا أفحصها و هذا أوفر قليلا فى الكود و السرعة و يناسب الأجهزة التى تغلق و يعاد تشغيلها كثيرا لكنه لا يناسب الخدمة الشاقة حيث تعمل **24 **ساعة وبدون رقابة فقد تعطل و يظل الجهاز يعمل على خطأ بلا توقف و ليست ذاكرة فقط ولكنها قد تكون ساعة وقت حقيقى أو مقياس حرارة أو غيره وهنا وجب أن التزم بالكتاب كما يقولون و أختبرها آخر كل بايت لأتأكد من وجودها بخير**.*

```
[LEFT][B][SIZE=3]
WriteMemByte:[COLOR=#008080] ; Writes 8 bit in A to mem and reads ack then back, no Stop[/COLOR]
MOV BitCount,#8
WMB00:
RLC A[COLOR=#008080] ; MSD first[/COLOR]
MOV SDA,C[COLOR=#008080] ; put data, setup delay in MemClk[/COLOR]
ACALL MemClk [COLOR=#008080]; clock it 3 wait loops in clk[/COLOR]
DJNZ BitCount,WMB00
ACALL ReadEEAck
RET

ReadEEAck:
ACALL Wait_9
SETB SDA[COLOR=#008080] ; make it input[/COLOR]
ACALL Wait_9 
SETB SCL[COLOR=#008080] ; Start Clk[/COLOR]
MOV AckDel,#0
RAloop:
JNB SDA,EndAck
ACALL Wait_9
DJNZ AckDel,RAloop
[COLOR=#008080]; CLR ERRLED[/COLOR]
EndAck:
CLR SCL [COLOR=#008080]; end clk[/COLOR]
NOP
SETB SDA [COLOR=#008080]; Make it input again[/COLOR]
ACALL Wait_9
RET

[/SIZE][/B][/LEFT]
```
*
هذا كود قراءة نبضة "اعلم" وهى أن تقول القطعة **"**تمام أو علم و جارى التنفيذ**" **و هذه إحدى الطرق و لو لديك مؤقت خالى يمكنك استخدامه فى انتظارها و الفكرة ننتظر قليلا لاستيعاب ما سبق ثم **SDA=1 **و تنتظر الاستيعاب و **SCL=1 **ثم تنشئ دورة من **256 **لفه و تفحص لو **SDA = **صفر إذن وصلت المعلومة فنقفز خارج الدورة و إلا نكرر فإن نفذ العد يمكنك أن ترفع علما بحدوث خطأ أو عطل و تسجله فى بايت الأخطاء و تنير ليد أيضا أو تكتب رسالة الخ**.*
*لو خرجت من الدورة مبكرا يعنى أنها سليمة و يمكنك استئناف العمل**.*
*الآن لنكتب فى القطعة نحتاج أن نرسل لها أمر كتابه يشمل عنوان تعريف القطعة **(**أى واحدة هى المعنية بهذا التخاطب**) **ثم عنوان الكتابة الفعلى داخلها ثم ترسل بعدها ما نريد كتابته من بيانات **. **هذا الكود يمكنك أن تستخدمه منفصلا أو غالبا من خلال الكتابة المتعددة**.*

```
[LEFT][B][SIZE=3]
SendPgAdd:[COLOR=#008080] ; send start Mem page adress from location PgAddress, no stop[/COLOR]
ACALL MemStart[COLOR=#008080] ; send start command[/COLOR]
MOV A,#10100000b[COLOR=#008080] ; Device address 1010,page 000 and write (0) bit[/COLOR]
ACALL WriteMemByte
MOV A,PgAddress [COLOR=#008080]; Get EE address[/COLOR]
ACALL WriteMemByte
RET

[/SIZE][/B][/LEFT]
```
*هذا الكود لإرسال المطلوب فنبدأ بنبضة بدء **Start **ثم عنوان القطعة وهو هنا ثابت لكنك تستطيع تعرف خانة باسم **Dev_Add **تضع فيها عنوان أى قطعة تود محادثتها و تغير هذه الخطوة إلى **MOV A,Dev_Add **ثم تطلب كود **WriteMemByte **السابق شرحه لإرساله للقطعة ثم تضع فى **A **العنوان الذى تود الكتابة عنده ثم تطلب الكود مرة أخرى لإرساله ثم نعود أيضا بدون **Stop .*
*الآن هذا الكود يمكننا كتابة صفحة كاملة من **8 **بايت بتحديد **8 **بايت كما فى القراءة و لكن إحذر يجب أن تكون فى عداد آخر لذا سميت الأول عداد البت و الثانى عداد البايت لأن كل بايت ستستخدم عداد البت ذاتيا لعد **8 **بت**.*
*الآن بعد تجهيز عداد **8 **بت ترسل باستخدام الكود السابق عنوان القطعة ثم عنوان الكتابة و نعود هنا بدون **Stop . **و الآن ستكون قد جهزت الثمانية بايت فى مجموعة من **8 **خانات متتالية فى أى مكان فى الذاكرة تختاره مثلا **41 **أو ما شئت أفضل البدء برأس العد مثل **40 **فيكون من **40 **إلى **47 **و هنا أضع **40 **فى المسجل **R0 **و المسجلان **R0,R1 **بهما خاصية أنك تستطيع استخدام محتوى أي منهما كعنوان لذا نضع **40 **وهى تشير لأول بايت و من ثم فالأمر **MOV A,@R0 **تجعله يأخذ خانة الذاكرة المشار إليها بالمسجل **R0 **فالعلامة **@ **هذه تعنى **"**غير مباشر**" **أى المحتوى عنوان البيان و ليس البيان ذاته**. **أخذنا أول بايت فى **A **ثم نطلب كود **WriteMemByte **السابق شرحه لإرساله للقطعة ثم نزود **R0 **بواحد فيحتوى **41 **و يشير للبايت الثانية ثم ننقص العداد بواحد و نقفز لو لا يساوى صفر للتكرار**.*
*أعلم أنك تقول أن هنا خطوات زائدة فبدلا من إنقاص عداد فضلا عن استخدامه أصلا كان من الممكن مقارنة **R0 **بنهاية العنوان **47 **وهذا صحيح **100% **عندما تتعامل مع قطعة واحدة لا تحتاج تجهيز أكثر من مصفوفة بيانات واحدة لكن لو لديك ذاكرتين لنوعين من البيانات أو حتى صفحتين مختلفتين أو ذاكرة مع ساعة أو وظيفة أخرى فستختلط الأمور**.*
*بعد إكمال الصفحة نرسل **Stop **و نتوقف **10 **مللى ثانية لضمان الكتابة و لو لديك شيء ما أفضل من دورة إضاعة الوقت كتحديث للشاشة أو قراءة **ADC **أو غيره فالأفضل قضاء الوقت فيما هو مفيد فلا يؤثر ذلك على القطعة طالما المتحكم بعيدا عن أوامر **I2C.*

```
[LEFT][B][SIZE=3]Write2Mem: [COLOR=#008080]; Writes 8 memory locations to EEprom add in PgAddress from [/COLOR]RAM in R0 
MOV ByteCount,#8 [COLOR=#008080]     ; loop counter, 8 bytes[/COLOR]
ACALL SendPgAdd  [COLOR=#008080]     ; start adress and ack[/COLOR]
W2m:
MOV A,@R0              [COLOR=#008080]    ; get byte[/COLOR]
ACALL WriteMemByte
INC R0                      [COLOR=#008080]    ; Point 2 next[/COLOR]
ACALL Wait_9 
DJNZ ByteCount,W2m
ACALL Wait_9
ACALL MemStop
ACALL Wait_10ms    [COLOR=#008080]    ; Write wait time[/COLOR]
RET 
[/SIZE][/B][/LEFT]
```
*لا جدوى من الكتابة ما لم نستطيع القراءة وهو موضوعنا القادم إن شاء الله*


----------



## ماجد عباس محمد (12 أغسطس 2018)

*الآن كتبنا و نريد أن نقرأ و يمكننا أن نقرأ بايت واحدة أو أى عدد من البيتات بلا حد أقصى فلووصلت لنهاية القطعة سيعود المؤشر للصفر ليبدأ من أول الذاكرة مرة أخرى **. **نحتاج إرسال عنوان هذه القطعة مع أمر قراءة **. **ولقراءة عدد من البايت سنحتاج قراءة العدد كله ماعدا الأخيرة و نرسل بعد كل منهم **Ack **للقطعة و إلا لن تستجيب**. **ثم تقرأ الأخيرة و يرسل بعدها **Stop **و هكذا الكود حيث نضع فى عداد للبايت العدد ناقص واحد وهنا نريد قراءة **8 **فنضع **7 **و يمكنك استخدام متغير باسم **ByteNu **و تطرح منه واحد أو تضع فى **ByteCount **عدد البايت و تبدأ الكود بالأمر **DEC ByteCount **ثم تنتظر و تطلب كود **SendPgAdd **السابق لإرسال العنوان للقطعة و عنوان الكتابة و هكذا حددت العنوان ثم ترسل **STOP **ثم عنوان القطعة و تكتب بايت مع أمر قراءة و هنا نبدأ الدورة**.*

```
[LEFT][B][SIZE=3]
ReadMem: [COLOR=#008080]; Read 8 memory locations from EEprom Address in PgAddress to RAM address in R0[/COLOR]
MOV ByteCount,#7[COLOR=#008080] ; loop counter, send only 7 bytes with ack, then one with stop
[/COLOR]ACALL Wait_9
ACALL SendPgAdd  [COLOR=#008080]    ; send start command,PgAddress,no stop[/COLOR]
ACALL MemStop   [COLOR=#008080]     ; Send stop to read sequentially at current location[/COLOR]
ACALL Wait_9
ACALL MemStart   [COLOR=#008080]       ; send start command[/COLOR]
MOV A,#10100001b [COLOR=#008080]   ; Device address 1010,page 000 and Read bit[/COLOR]
ACALL WriteMemByte
NxtRead:
ACALL ReadMemByte  [COLOR=#008080]    ; result in A[/COLOR]
ACALL SendEEAck
MOV @R0,A
INC R0
DJNZ ByteCount,NxtRead
ACALL ReadMemByte [COLOR=#008080]     ; read the 8th[/COLOR]
MOV @R0,A 
ACALL MemStop
RET

[/SIZE][/B][/LEFT]
```
*
طبعا يجب أن نضع فى **R0 **أو **R1 **عنوان الذاكرة حيث نريد أن نبدأ حفظ ما نقرأ ثم نطلب كود قراءة بايت التالى شرحة ثم نرسل نبضة **ACK **كما سيلى شرحة فنجد نتيجة القراءة فى المراكم **A **و من ثم نحفظه فى العنوان المشار إليه بالمسجل المختار سواء **R0 **أو **R1 **ثم ننقص عد البايت و ننتقل لو لا **= **صفر لنكرر القراءة و عندما ينتهى العد نقرأ الأخيرة ثم نحفظها ثم نرسل **STOP **و نعود**.*
*الآن كيف نقرأ بايت واحدة؟*
*طبعا عدد البت **=8 **ثم ننشئ دورة من ننتظر ثم نرسل نبضة برفع **SCL =1 **و الانتظار ثم ننقل الرد من طرف **SDA **إلى **C **لأنه لا غيره يمكن النقل منه و إليه**. **ثم ننفذ الأمر **RLC **أى **Rotate Left with Carry **لنضعه فى البت صفر و التى باستمرار الإزاحة ستصبح فى النهاية رقم **7 **ثم ننهى النبضة بخفض **SCL **ثم ننقص العد واحد ونكرر لنهاية **8 **بت ثم ننتظر و نعود دون نبضة توقف **Stop **لنتمكن من قراءة التالية إن أردنا**.*

```
[LEFT][B][SIZE=3]
ReadMemByte:[COLOR=#008080] ; Reads 8 bit from mem to A, neither Ack nor stop pulse[/COLOR]
MOV BitCount,#8
RMB00:
ACALL Wait_9
SETB SCL  [COLOR=#008080]            ; send clock[/COLOR]
ACALL Wait_9
MOV C,SDA  [COLOR=#008080]         ; Get data, MSD first[/COLOR]
RLC A     [COLOR=#008080]               ; MSD first[/COLOR]
CLR SCL[COLOR=#008080]                ; clock end[/COLOR]
DJNZ BitCount,RMB00
ACALL Wait_9
RET

SendEEAck: [COLOR=#008080]         ; Send ACK code, ret w/ SCL low [/COLOR]
CLR SDA
ACALL Wait_9
ACALL MemClk
SETB SDA[COLOR=#008080]             ; make it input again[/COLOR]
ACALL Wait_9
RET

[/SIZE][/B][/LEFT]
```
*
طبعا بعد استقبال **8 **بت لابد هنا من أن ترسل **ACK **للقطعة لتستقبل البايت التالية وهى بتصفير **SDA **و الانتظار ثم نطلب كود إرسال نبضة ثم نضع **SDA=1 **ليصبح دخول للمتحكم مرة أخرى و ننتظر ثم نعود*
*لم يبقى سوى دورات التأخير أو قضاء الوقت أو الانتظار وهى إما مجموعة من **NOP **وهى تستهلك دورة أو دورات من العد باستخدام مسجل أو خانة ذاكرة*

```
[LEFT][B][SIZE=3]
[COLOR=#008080]; Delay routines at 11.059Mhz Xstal has 1.085 uS per cycle, clk rate = 0.92 MHz=920KHz
; ---------------------------------------------------------
' time: 9 cyc. (incl. ACALL/RET)=9.765 uSec 
' stack: 2 (incl. ACALL/RET)=4
[/COLOR]Wait_9: 
NOP
NOP
NOP
NOP
NOP
RET 

[COLOR=#008080]; -----------------------------------------
; destroys: Nothing
; time: 9326 cyc. (incl. ACALL/RET)=10.11871 ms
; stack: 4 (incl. ACALL/RET)=4[/COLOR]
Wait_10ms: 
MOV DelTime1,#20
_W10ms: MOV DelTime2,#231
DJNZ DelTime2,$
DJNZ DelTime1, _W10ms
RET
[/SIZE][/B][/LEFT]
```
*القراءة و الكتابة فى ذاكرة المتحكم سهلة نوعا ما بكود الأسيمبلى و لذا سنستخدم المتحكم **AT89S5283 **ذو **2 **ك ذاكرة داخلية **EEPROM **فيمكن الكتابة و القراءة فيها**.*
*الآن نحتاج عرض البيانات على الشاشة وهو موضوعنا القادم إن شاء الله**.*


----------



## ماجد عباس محمد (14 أغسطس 2018)

[h=2]الشاشة LCD ما هى و كيف تبرمج لها:[/h]*الشاشات نوعين نوع رسومية و هى خارج نطاق هذا الشرح لأنها تعتمد برامج متخصصة لمعالجة الرسوم و معظم اللغات العالية توفر دعم لها لكنها أكثر ملائمة للمتحكمات من نوع **AVR **لحاجتها لذاكرة كبيرة نوعا ما**.*
*النوع الثانى نصية حيث تكتب على صف أو صفين أو أربعة صفوف و فى كل صف **16 **حرف و ظهرت أنواع بها **20 **حرف لكنها تعتمد ذات المتحكم ألذى يوائم بين الشاشة و الدوائر التى نصممها لذا نجد الشاشة ذات **16×1 **مكونه من سطرين الأول يكتب فى الثمان أحرف اليسرى بعنوان من صفر إلى **8 **و سطر ثان يكتب فى الأحرف الثمان اليمنى بعنوان يبدأ من **40 **هيكسا إلى **48 **هيكسا و الشاشة ذات **16×2 **تحتوى أيضا سطرين السطر الأول للكتابة فى الستة عشر حرف العليا بعنوان من صفر إلى **15 **أى صفر إلى **F **هيكسا و السطر الثانى للكتابة فى الستة عشر حرف السفلى بعنوان من **40 **هيكسا و حتى **4F **هيكسا و الشاشة ذات **16×4 **أيضا سطرين لكن الستة عشر الأولى كما سبق من صفر إلى **15 **أى صفر إلى **F **هيكسا و السطر الثانى للكتابة فى الستة عشر حرف السفلى بعنوان من **40 **هيكسا و حتى **4F **هيكسا أما الستة عشر الثالثة فهى امتداد الستة عشر الأولى أى بعنوان من **16 **إلى **31 **او **10_Hex **إلى **1F_hex **و الأخيرة امتداد الثانى أى من **50_HEX **إلى **5F_HEX **وهذه هامة لأنك لو تريد جعل الكتابة متحركة فهكذا ستبدو أى ما فى السطر الثالث سينتقل للأول و ما فى الثانى للرابع**.*
*الشاشات ذات الأرقام أعلى من **16 **فهى بذات الترتيب إلا أن الستة عشر تصبح **20 **أو اكثر**.*
*الآن ذكرنا أن للشاشة متحكم وفى الحقيقة أكثر من واحد بحسب عدد الصفوف من الأحرف و لو نظرت فى ظهرها ستجد لطعة سوداء هى ذاك المتحكم**. **لا يهمنا كثيرا ما هو ولكن يهمنا كيف يتصرف لنتواءم معه*
*عند توصيل التيار يبدأ فى التهيئة و يحتاج **50 **مللى ثانية لإنهائها لذا لا تتعامل مع الشاشة خلال هذا الوقت ، و الأفضل أن تكتب الكود لينهى بعض أو كل مهامه الأخرى أولا من تهيئه المنافذ و الأجهزة الأخرى المحيطة و إن شئت فهناك وسيلة لتعرف إن كانت قد أتمت تهيئتها أم لا لكنه سيكلفك مخرج من مخارج المتحكم لذا عادة ما أقدر الوقت ثم أعطل المتحكم باقى هذا الوقت فلو حاولت التعامل معها قد لا يعمل ولا تكتب إطلاقا لأنها ببساطة لم تتلقى منك أمر التشغيل**.*
*الآن بعد هذه الفترة تصبح مهيأة ذاتيا للعمل على النسق الآتى*
*عرض البيانات **8 **بت*
*المعروض سطر واحد و الثانى مخفى*
*مساحة الحرف **5×8 **نقطة وهى ذات العدد الكامل من الأحرف حيث النمط الآخر **5×11 **لا يحتوى إلا عدد محدود جدا من الأحرف**.*
*الشاشة مطفأة و ربما هذا لتقليل الاستهلاك و السبب غير مذكور فى الداتاشيت**.*
*المؤشر مطفأ وهو خط يكون أسفل الحرف ألذى ستتم كتابته تاليا*
*الوميض مطفأ وهو المؤشر إما ثابت أو يظهر و يختفى **"**يومض**"*
*تزايد بواحد وهو بعد الكتابة يزيد رقم المؤشر بواحد ليشير للحرف التالى وهو يمكن أن يكون سالب **1 **ليشير للحرف السابق**.*
*بلا إزاحة و هذه الإزاحة تحرك الكتابة بدلا من أن يتحرك المؤشر *

*الآن أول شيء أن نكمل التهيئة**. **نلاحظ أن التهيئة تخيرنا ما بين استخدام **8 **بت بما فيها من سرعة و خطوات أقل على حساب عدد الخطوط أو **4 **بت توفر **4 **خطوط لكن ضعف الوقت و ضعف الكود وهذا خيارك أنت**. **الآن ربما تريد تحويل الشاشة لنظام **4 **بت ، معنى هذا أن الأوامر كلها يجب أن تكون على **4 **بت فقط و هنا سيكون التعامل مع الأربعة بت العليا فقط بينما الأربعة السفلى أصفار و تدخل الأمر على مرتين وهذا سبب البطء**.*
*كيف تتعامل معها؟ الأمر بسيط ، ضع ما تشاء على مجموعة البيانات و اختار بطرف **R/S **ما تريد**. **لو **R/S=0 **فستترجم الشاشة ما وضعت على مجموعة البيانات كأمر للتنفيذ و إن كان **R/S = **واحد ستعتبره حرف يجب كتابته و هذا فور تحريك الطرف **E **من صفر إلى **1 **و إعادته للصفر مرة أخرى **. **هذا يتيح لك توصيل أكثر من شاشة معا و تضع ما تشاء على ذات البيانات المشتركة و تضع **R/S **للمجموعة كلها و المعنية فقط تصدر لها الأمر **E .*
*الآن ماذا نضع؟ هذا الجدول يبين كافة الأوامر المتاحة و يلى شرحها حيث **"-” **تعنى لا يهم و الواحد مثل الصفر لا أثر له**. **أيضا الجدول به عديد من الأوامر ، ما يحدد هو أين يقع أول **1 **فى الآمر فدوما الأعلى أصفار**.*




*الأمر **1 **هو أطولهم تنفيذا حيث يمحو الشاشة بكتابة مسافة بيضاء **(20h) **فى كل الخانات و يصفر العداد و يبدأ من أول خانة*
*الأمر **1X **يعود للأول لكن مع الإبقاء على محتوى الشاشة لذا فهو أسرع*
*الأمر فى الخانة الثالثة فالبت صفر باسم **S **تحدد هل سيتم إزاحة الشاشة لو **=1 **أما لو **= **صفر فلا تزاح الشاشة ويزاح المؤشر**. **و البت التالية رقم **1 **باسم **I/D **لو **= 1 **تحدد زيادة المؤشر بواحد فتكون الإزاحة لليسار أو لو هى **= **صفر تحدد نقص المؤشر بواحد فتكون الإزاحة لليمين**.*
*الأمر فى الخانة الرابعة البت صفر باسم **B =0 **المؤشر لا يومض ولو **=1 **المؤشر يومض، و البت **1 **باسم **C **المؤشر **Cursor **لو **= 1 **يظهر المؤشر ولو **= **صفر يختفى المؤشر دون التأثير على الكتابة**. **البت **2 **باسم **D **أو **Display **لو **= 1 **تشغل الشاشة و لو**= **صفر تطفئ الشاشة **.*
*الأمر فى الخانة الخامسة بعد أن اكمل الأوامر الخاصة بالتهيئة أصبح الآن فى الشكليات و ذلك حتى يكون المستخدم قد أتم التعديلات الأساسية لو أراد أن يعمل بنظام **4 **بت الخ**. **البت صفر وواحد لا أثر لهما و البت **2 **باسم **R/L **أى **Right/Left **وهى تحدد اتجاه الحركة يمين أم يسار ثم البت **3 **باسم **S/C **أى **Screen/Cursor **فلو **=1 **الشاشة تتحرك ولو بصفر فالشاشة ثابتة و المؤشر يتحرك**. **المقصود بالشاشة طبعا هو الكتابة**.*
*الأمر فى الخانة السادسة البت **2 **باسم **F **أى **Font **لتحديد **5*8 **أم **5*11 **ثم البت **3 **باسم **N **أى **Number **لو **= 1 **تعنى سطرين ولو **= **صفر تعنى سطر واحد **(**فى الشاشة **16*1 **تكون **8 **حرف أو **16 **و الشاشة **4*16 **تكون خط **1**،**3 **أم الأربعة**) **و البت رقم **4 **باسم **D **أى **Data Line **لو **=1 **فالتعامل مع **8 **بت ولو **= **صفر تكون **4 **بت**.*

*المرة القادمة بإذن الله نكمل*


----------



## ماجد عباس محمد (14 أغسطس 2018)

*باقى الكود*
*قبل أن نكمل الأكواد يجب أن نعلم نقطة حول تركيب الشاشة فبها نوعين من الذاكرة **CG **أى **Character Generator **منها **ROM **قراءة فقط حيث تتولى توليد أكواد الحروف المطبوعة على الشاشة و منها **RAM **تحتوى **64*8 **خانة للمستخدم يستخدمها كذاكرة عشوائية أو يضع فيها حتى ثمانية أحرف خاصة يود طباعتها**. **أيضا بها نوع قابل للقراءة و الكتابة تسمى **DD **أى **Display Data **و التى تحتوى المعروض فعليا الآن على الشاشة و من المفيد أن نعلم ماذا تعرض الشاشات مقابل كل كود من صفر و حتى **FF *




*و لهذا فائدة كبيرة حيث يمكنك طباعة علامة درجة الحرارة باستخدام الكود **0FDh **أو علامة الأوم أو ميكرو و النسبة التقريبية و أكواد العملات وعلامة القسمة و الجذر التربيعى الخ**.*
*الأمر يمكنك من تحديد العنوان فى ذاكرة توليد الأحرف لتكتب فيها أو تقرأ منها، هناك بضع خانات يمكنك الكتابة فيها لتشكل أحرفك الخاصة**.*
*الأمر الثامن يمكنك من وضع العنوان للخانة التى تريد الكتابة عليها فيمكنك مثلا أن تكتب أول الشاشة رقمين ثم تنتقل لمنتصف الشاشة بدلا من كتابة عدد من المسافات البيضاء و هناك تكتب الوحدات المطلوبة**.*
*الأمر العاشر هو كتابة بايت لأى من الذاكرتين السابقتين بفرض أنك قد حددت العنوان سابقا**. **لو عنوان **CG **ستحفظ حيث حددت أما لو **DD **ستترجم لحرف يعرض على الشاشة**. *
*الأمرين التاسع و الحادى عشر للقراءة من الشاشة و ذلك بفرض أنك وظفت الطرف المسمى **R/W **فى الشاشة وهو رقم **5 **من أطراف الشاشة**. **الأمر التاسع لمعرفة هل الشاشة أنهت ما تقوم به و تنتظر جديد فتعلمه من البت **7 **و الباقى هو العنوان الحالى**. **الأمر الحادى عشر للقراءة من الذاكرة **CG **للأغراض السابقة**.*
*الآن الأطراف بالترتيب للشاشة ووظائفها هى**:*
*1 – **أرضى للشاشة لزوم التشغيل مع الطرف رقم **2 **يغذى من **+5 **فولت للتشغيل**.*
*3- **طرف **Vo **للتغذية و التباين و تقترح الشركة توصيله بمقاومة تحدد الفولت قدرها **5 **ك وهى للتباين و تغير خانات الشاشة من بيضاء بدون كتابة إلى سوداء بلا تفاصيل مرورا بالوضع الصحيح حيث تكون القراءة واضحة**. **شخصيا استبدلتها بمقاومة **100 **أوم فى كل الشاشات الخضراء بلا مشاكل أما الزرقاء فقد تحتاج تعديل طفيف**.*
*4 – R/S **وهى تحكم فى ما تفعل الشاشة بالبيانات ، لو **=1 **تكتبها على الشاشة و لو **= **صفر تنفذها كأمر*
*5 – **طرف **R/W **حيث يمكنك من القراءة و الكتابة للشاشة ولو لا تستخدم خاصية القراءة أوصلها بالأرضى لتكون على وضع الكتابة دوما**.*
*6- **طرف **E **اختصار **Enable **وهو يفعل الشاشة لكى تنفذ المطلوب*
*7 : 14 **البيانات حيث **7 **هى **D0 **و الطرف **14 **هو **D7*
*15 **طرف موجب لإضاءة خلفية الشاشة بمجموعة من **LEDs **والطرف **16 **هو السالب أو الأرضى و يمكنك التوصيل المباشر ب**+5 **فولت و أرضى أو من خلال مقاومة لتقليل الإضاءة أو التحكم فيها **PWM **أو تضع مفتاح لتوفير الطاقة لأجهزة البطارية فعلى أى حال لو ضبطت التباين على طرف **3 **جيدا ستكون الشاشة مقروءة بدون إضاءة الخلفية**. **التيار يختلف بحسب حجم الشاشة و الطراز، ارجع للداتاشيت**.*

*كود التهيئة موضوعنا القادم بإذن الله*


----------



## ماجد عباس محمد (15 أغسطس 2018)

*خطوات التهيئة **:*
*أربعة خطوات لتهيئة الشاشة**.**ا *
*الأولى لا تحتاجها لو ستستخدم نصف الشاشة فقط لكن لجعلها تظهر سطرين يجب وضع **1 **مكان **N **و ستكرر اختيار **8 **بت لترسل*
*00111000*




*الثانية ضرورة لكون الشاشة مطفئه و يجب تفعيلها بهذا الأمر و لو تريد إظهار المؤشر أضف **1 **ولو يومض أضف **1*
*00001100 **الشاشة فقط*
*00001110 **المؤشر ظاهر و ثابت*
*00001111 **المؤشر ظاهر و يومض**.*
*يلى ذلك محو الشاشة و العودة للعنوان صفر بالأمر **"1”*
*و أخيرا هل تريد تحريك الشاشة أم المؤشر و غالبا لو تريد حركة المؤشر من اليسار لليمين فلا حاجة لهذا الأمر*

*الكود**:*
*طبعا تسمى الطرف **RS **لأى منفذ و طرف و تسمى **Ena **لأى منفذ و طرف و تسمية **Ena **بدلا من **E **فقط مجرد إضافة توضيح خاصة لكود كبير و به متغيرات عديدة فضلا عن أن بعض المترجمات يشترط أن الاسم على الأقل ثلاثة أحرف**.*
*نلاحظ أن كل خطوة لها زمن تحتاجه الشاشة لكى تنفذ هذا الأمر و بديهى أنه لا علاقة له بتردد الكريستال فلا رابط بينهما**.*

```
[LEFT][B][SIZE=4]
CLR RS
MOV LCD_Data,#00111000b
Setb Ena
NOP
CLR Ena
MOV LCD_Data,#00001100b
Setb Ena
NOP
CLR Ena
MOV LCD_Data,#1
Setb Ena
NOP
CLR Ena
MOV LCD_Data,#00000110b
Setb Ena
NOP
CLR Ena
Setb RS[/SIZE][/B][/LEFT]
```
*فقط **18 **خطوة بعضها قد لا يكون ضروريا ، أما لو تريد التهيئة لأربعة بت فالأمر معقد و سأشرحه هنا لا بهدف أن تستخدمه و لكن لتعلم كم تضحى من السرعة و الكود مقابل **4 **بت توفرها وهذا موضوعنا القادم بإذن الله*


----------



## ماجد عباس محمد (16 أغسطس 2018)

*التعامل بنسق 4 بت*




*قد تبدو المسألة سهلة أن نضع **4 **بت الأعلى على **4 **بت من الحافلة حيث تكون أطراف الشاشة لكن مهلا لنأخذ الأمر الأول سنضع القيمة **0010 **على أربعة بت**.*
*أى أربعة بت؟ سأفترض الحسنى و أن المصمم قد وضعهم إما من صفر إلى **3 **أو من **4 **إلى **7 **، حسنا أى منفذ؟ *
*فى بيك تجد منفذ **5 **طرف أو سته طرف وهذا ملائم لهذه القضية لكن فى أتميل كل المنافذ **8 **طرف**.*
*بسيطة أضع القيمة و الباقى أصفار**.. **ولكن هذا الباقى متصل بشيء ما و قد لا يريد أن يكون صفرا الآن**!!*
*أصبحنا فى مشكلة ، يجب قراءة المنفذ و التعديل عليه ثم إعادة كتابته ثانيا**.*
*هذا أمر صعب لكن قد يهون قليلا من المعاناة لو وضعنا **RS,E **معا على ذات المنفذ و من ثم يتبقى طرفين للتعامل معهما*
*خطوات التعامل مع **4 **بت هى أن سنستخدم الأطراف الأربعة العليا من الشاشة **DB4B7 **و الباقى يمكن توصيلهم بالأرضى**. **الآن تحدد **R/S **ثم تضع النصف العلوى من البيان أولا على الشاشة و نبضة على طرف **E **ثم تضع النصف السفلى من البيان و نبضة **E **ثم تنتظر وقت تنفيذ الأمر أو الانتهاء من الكتابة**.*
*لذا فى التهيئة لا توجد مشاكل فى وضع القيمة حسب الجدول ثم تفعيلها ووضع الثانية و تفعيلها ثم الانتظار لكن المشكلة عندما تحتاج أن تكتب حرفا و ليكن **"A” **وهو هيكسا **14 **و المشكلة أنك لا تعرف أصلا أنه الحرف كذا و لذلك نحتاج قراءة المنفذ و نلغى منه **4 **بت المخصصة للشاشة ثم نضيف الجزء الأعلى من **A **وهو واحد ثم نعيده على المنفذ و نبضة **E **ثم نضع الجزء الأدنى وهو **4 **و نضعه على المنفذ طبعا سنحتاج الأمر **Swap **ألذي يبدل النصفين معا **(**لا حاجة لإعادة قراءة المنفذ**)**، هذه قصة طويلة **.*
*أتميل وضعت كود مخصص لهذا الألم وهى **XCHD **واختصار **Exchange Digit **و تعرضنا سابقا لمثيلة **XCH **و كانت تستبدل محتوى **A **بمحتوى أى مكان و الآن هذه تعتبر أى مسجل من **R0:R7 **حامل للعنوان المطلوب و تستبدل الأربعة الدنيا بالأربعة الدنيا ثم نعيده للمنفذ مرة أخرى **. **كان الخيار بين أمرين أن يستخدم مع الأربعة الدنيا فقط و ترسل مباشرة للمنفذ أو ترسل لذاكرة و بإضافة أمر **Swap **تكتب فى ألأربعة العليا**.*
*لذا و كما فى كل الطرز ذاكرة المنافذ تشارك الذاكرة العادية ذات العنوان و كيفية الكتابة مباشرة أو غير مباشرة تحدد أيها ، فقد اختير الحل الثانى ليكون هذا الأمر غير مباشر ليكتب فى الذاكرة و إن شئت بأمر **Swap **تنقلها للأربعة البت العليا**.*

*هل خطر على بالك للحظة أن تستخدم المنفذ **P03 **يوفر فى الكود عن استخدامك **P47**؟ لقد أثبتها لك بالكود هنا لكن لو لم تظهر معك فى المترجم فهو قد اعتمد الحل الأسهل الأكثر كلفة **.*
*وهنا أيضا لا يفوتنى ذكر الرائع المسمى الأردوينو و ألذى يتعامل مع البت ولا يتعامل مع منفذ كامل و لإدخال بايت كاملة كم أمر ستحتاج، ما لم تعتمد نظام تسلسلى**. **و ألذى لن يوفر لك أى كود أو وقت**.*
*هذا كود للكتابة فى الشاشة بنظام **4 **بت**. **سنحتاج خانة مؤقته أو متغير إن شئت نسميه **Temp **و يمكنك استخدام أى خانة أخرى سبق تخصيصها كما ذكرنا كمسودة**. **أول أمر يضع عنوانها فى المسجل **R0 **ثم نضع نسخة من المنفذ **LCD_Data **فى **Temp **وهذا حتى تتجنب أى تعديل فى الأربعة بت الغير مستخدمة للشاشة و قد تكون موظفه لغيرها ، ثم تضع ما تريد إرساله للشاشة **Chr2prn **فى **A **ثم تبدل نصفيه لإرسال النصف العلوى أولا ثم بالأمر **XCHD **تستبدل الأربعة بت الأدنى فى **A **بالأربعة الأدنى فى العنوان المشار إليه فى المسجل **R0 **وهو هنا **Temp **ثم تعيد **Temp **للمنفذ 
*

```
[SIZE=4]
[/SIZE][LEFT][SIZE=4][B]MOV[/B] [B]R0[/B][B],#[/B]temp
[B]MOV[/B] temp[B],[/B]LCD_data    [COLOR=#008080]; To preserve the other 4 bits[/COLOR]
[B]MOV[/B] [B]A[/B][B],[/B]Chr2prn        [COLOR=#008080]     ; Put in temporary location[/COLOR]
[B]Swap[/B] [B]A[/B]       [COLOR=#008080]                   ; Put the High nibble as low nibble[/COLOR]
[B]Xchd[/B] [B]A[/B][B],@[/B][B]R0[/B] [COLOR=#008080]                  ; replace a with temporary[/COLOR]
[B]MOV[/B] Lcd_DATA[B],[/B]temp
[B]SETB[/B] Ena
[B]NOP[/B]
[B]CLR[/B] Ena                      [COLOR=#008080]; Clock it[/COLOR]
[B]Swap[/B] [B]A                     [/B] [COLOR=#008080]; get back the low nibble[/COLOR]
[B]XCHD[/B] [B]A[/B][B],@[/B][B]R0              [/B][COLOR=#008080] ; replace a with temporary[/COLOR]
[B]MOV[/B] Lcd_DATA[B],[/B]temp
[B]Setb[/B] Ena
[B]NOP[/B]
[B]CLR[/B] Ena [COLOR=#008080]; Clock it[/COLOR]

[/SIZE][/LEFT]
```
​*ثم نبضه تفعيل وهى **Ena=1 **ثم صفر و نكرر بتبديل **A **لنستعيد الأربعة الأخرى و نكرر**. **و بعد إرسال الدفعتين أى **8 **بت تنتظر تنفيذ هذا الأمر أى أن الشاشة لا تعامل كل نصف على حدة**.*


*طبعا للسهولة نستخدم **8 **بت و من ثم يكون لدينا بضع دوال بسيطة و تكون التهيئة كاملة موضوعنا القادم إن شاء الله*


----------



## ماجد عباس محمد (17 أغسطس 2018)

*لتهيئة الشاشة نحتاج بضع تعريفات وهى أى منفذ تستخدمه و أى بت تكون **RS **و أى بت تكون **Ena **و تكتب الثوابت التالية لتحديد السطر ألذى تود الكتابة فيه لكن أذكرك أن فى الشاشة **16×1 **الثمانية اليسرى هى سطر رقم **1 **بعنوان صفر و الثمانية اليمنى هى سطر رقم **2 **بعنوان **40 **هيكسا و أى كتابة بيتهما لن تظهر إلا فى حال إزاحة الشاشة لليسار سيختفى الحرف الأيسر و يدخل بدلا منه ما هو فى خانة **8 **وهكذا وهذه هى التهيئة كاملة بالتعريفات لنسق **8 **بت **.*
*بعد التهيئة سنحتاج دوما للكتابة فى الشاشة و إصدار أوامر لها لذا سيكون من الأفيد لو نجعل التفعيل و تحديد أمر أو كتابة فى كود مستقل لذا سنعدل التهيئة السابقة و نستغل وظيفتين إحداهما **Do_LCD **لتنفيذ أمر و الأخرى **Writ_LCD **لكتابة حرف و تصبح التهيئة *

```
[LEFT][SIZE=4]Line1 EQU $0[COLOR=#008080] ; 00h :0fh[/COLOR]
Line2 EQU $40[COLOR=#008080]  ; 40H :4FH[/COLOR]
Line3 EQU $10[COLOR=#008080]  ; 10H :1FH[/COLOR]
Line4 EQU $50  [COLOR=#008080]; 50H :5FH [/COLOR]


INCLUDE 89s8253.MC
RS EQU p3.0
ENA EQU p3.1
LCD_Data EQU p2
Chr2prn EQU 12h
Temp EQU 13h


MOV LCD_Data,#00111000b
ACALL Do_Lcd
MOV LCD_Data,#00001100b
ACALL Do_Lcd
MOV LCD_Data,#1
ACALL Do_Lcd
MOV LCD_Data,#00000110b
ACALL Do_Lcd

[/SIZE][/LEFT]
```
*الآن لتنفيذ أمر سنضعه على المنفذ ثم نستخدم الكود **Do_LCD **حيث نحدد **RS = **صفر ليكون أمر ثم ننتظر و نرفع **ENA =1 **ثم ننتظر و نعيده مرة أخرى و نطلب كود انتظار تمام التنفيذ طبقا للجدول السابق و لكتابة حرف سنضعه أيضا على المنفذ و نستخدم الكود **Writ_LCD **حيث نجعل **RS=1 **ليكون كتابة و نفعل **ENA **و لمزيد من الاختصار يمكنك جعل كل منهما فقط تضع قيمة **RS **ثم تنتقل لكود يسمى **CLOCK **مثلا يحتوى باقى الكود لتطابقه**.*

```
[LEFT][SIZE=4]Do_LCD:   [COLOR=#008080]        ; writes a Command to LCD [/COLOR]
CLR LCD_RS [COLOR=#008080]     ; Command Reg[/COLOR]
NOP            [COLOR=#008080]       ; 5 ns delay
[/COLOR]SETB LCD_Ena [COLOR=#008080];[/COLOR]
NOP       [COLOR=#008080]            ; DELAY > 175 ns[/COLOR]
CLR LCD_Ena
LCALL Wait_50 [COLOR=#008080]; Wait Execution time 43 us[/COLOR]
RET


Writ_LCD:     [COLOR=#008080]; writes a character to LCD @ current location[/COLOR]
SETB LCD_RS [COLOR=#008080]; Data Reg[/COLOR]
NOP
SETB LCD_Ena 
NOP 
CLR LCD_Ena
LCALL Wait_50 [COLOR=#008080]; Wait Execution time 43uS[/COLOR]
RET
[/SIZE][/LEFT]
[SIZE=4]
كثيرا ما تحتاج للتعامل مع سطرا كاملا من 16 حرف حيث تكتب فى جزء منه قيمة ما ثم تترك مسافة و تكتب الوحدات أو تنسق السطر كما تشاء لذا ستحتاج فى التعريفات أن تضيف 16 خانة متسلسلة و بدورة تكتب 16 حرف مرة واحدة


[/SIZE]
[LEFT]


Disp1 EQU $10 [COLOR=#008080]; LCD line text, LCD address in B reg, next 16 location till 5F
[/COLOR]Disp2 EQU $11
Disp3 EQU $12
Disp4 EQU $13
Disp5 EQU $14
Disp6 EQU $15
Disp7 EQU $16
Disp8 EQU $17
Disp9 EQU $18
Disp10 EQU $19
Disp11 EQU $1A
Disp12 EQU $1B
Disp13 EQU $1C
Disp14 EQU $1D
Disp15 EQU $1E
Disp16 EQU $1F


Wait_50:
MOV Del1,#47 [COLOR=#008080]; 1 cycle[/COLOR]
DJNZ Del1,$ 
RET 
[/LEFT]
```

*دورة التأخير المطلوبة بالطبع بحسب الكريستال المستخدمة ولو بطيئة تستغنى عن كثير من **NOP **المستخدمة*
*هكذا راجعنا أساسيات الدائرة و نبدأ المرة القادمة بإذن الله التصميم بعائلة **C51 **و التى لا تحتوى كثير مما ذكرنا و تحايلنا لذلك*


----------



## ماجد عباس محمد (18 أغسطس 2018)

[h=2]الدائرة بمتحكم C51 و لغة الأسيمبلى[/h]*الآن نبدأ تصميم الدائرة و سنختار **AT89S8253 **لاحتوائه على ذاكرة **EEPROM **و متاح بالسوق المحلى و لكن للأسف هذه العائلة لا تحتوى **PWM **لذا سنتحايل على هذا الأمر و لدينا طريقين ، إما إضافة عتاد كما فعلنا فى **WDT **أو نتحايل بالموجود**. **وهذا هو الحل المناسب**. **أيضا لا يحتوى على **ADC **لذا يمكن استخدام **ADC **خارجى وهو بسيط و سهل و كما فهمنا مما سبق فالكل لا يعطى دقة أكثر من **8 **بت **. **و لذا نستخدم **ADC0808 **وهو متوافر و بدقة **1% +/- 1 **بت وخرج **8 **بت ولا حاجة لنا باللجوء لوحدات **14 **بت أو أعلى**.*
*سنحدد السرعة باستخدام مقاومة متغيرة تثبيت واجهة و يمكنك استخدام لفه واحدة أو **10 **لفات للدقة**. **سنقرأ الفولت عليها ثم نستخدمه لتحديد عرض النبضة**. **و لكون المحول له **8 **دخول فيمكننا استخدام آخر لقراءة التيار و عرض القيمتين على الشاشة **.*
*ADC0808 **يحتاج لنبضات **Clock **و أعلى معدل مسموح به حتى تقريبا **600 **ك هرتز و لذا نحتاج مولد نبضات منفصل لكن كل عائلة **C51 **مصممة للتعامل مع ذاكرة إضافية خارجية حتى **64 **ك لذا فهى مزودة بطرف يسمى **ALE/**PROG* *هذا الطرف يعطى نبضة كل ستة نبضات من الكريستال لهذا الغرض و من ثم تردده يكون سدس الكريستال ولو أمكن استخدام كريستال **3 **ميجا لكانت الأمور أسهل لكن للأسف فى أسواقنا **3 **ميجا تعنى **3.518 **ميجا لذا نستخدم **4 **ميجا و تعطى **666 **ك هرتز و لذا نستخدمها مع المحول**. *
*هذا المحول به عيب أنك لو أردت تغيير **Vref+ **يجب أن تغير **Vref- **بنفس القدر حتى يبقى جهد المنتصف دوما **2.5 **فولت لذا سنبقى المدى **5 **فولت و نعدل قيمة الدخل بحيث يعطى النسب الصحيحة**. **الآن ستكون الدائرة هكذا*




*نلاحظ هنا أن الموتور فرضيا يعمل على **24 **فولت أو حتى **36 **فولت وهو ما يتحمله دخول المثبت **7812 **و يعطى **12 **فولت لتغذية مكبر العمليات **LM358 **و ألذى يستخدم لتمرير جهد المقاومة المتغيرة و أيضا لتكبير جهد قياس التيار**. **خرج مكبر العمليات يوفر المقاومة الصغيرة المطلوبة لدخول محول **ADC **كما أن وجود مكثف بين الخرج و الأرض يقلل من التعاريج و يخفض المقاومة**. **تغذية مكبر العمليات يجب أن تزيد عن **7 **فولت لأن الداتاشيت تنص على أن الخرج يصل للأرض لكن لا يرتفع أعلى من **VCC-2 **فولت**.*
*نأخذ من **12 **فولت من خلال مرشح لمثبت **5 **فولت لتغذية المتحكم و من خلال مرشح آخر لتغذية المحول لتقليل أثر المتحكم على المحول**.*
*المحول ببساطة يمر فى دورة من **8 **نبضات فإن وجد **1 **على طرف البداية **Start **يتوقف وفى نهاية نبضة **Start ** يكمل **8 باقى **نبضات الدوره الثمانية ثم يبدأ التحويل و ألذى يمتد حتى **64 **نبضة تالية**. **لذا قبل البدء يجب أن يتم تحديد العنوان أى يتم اختيار أى مدخل يراد تحويله و ذلك بنبضة على طرف **ALE **وهى تحفظ القيمة على خطوط العنوان **A0,A1,A2 **أو يمكن جمع الطرفين معا **RESET,ALE **كما بالرسم و بنبضة أكبر من **3 **ميكرو ثانية تحفظ العنوان و تبدأ التحويل**. **و نظرا لكوننا نستخدم كريستال **4 **ميجا فيكفى **NOP **لتغطية هذا الزمن **.*
*للتحكم فى سرعة الموتور سنقرأ قيمة المقاومة المتغيرة كما ذكرنا و نضبط منها السرعة أو نحفظ هذه القيمة لنستخدمها لاحقا فى كل مرة وهنا زر توقف للموتور عند الضغط عليه يسبب مقاطعة للتوقف الفورى، و لن يحدث هذا إلا بفرملة وهذا موضوع آخر لذا سنكتفى بقطع التيار عن الموتور و تركه يتهادى للتوقف**. **و أيضا نقرأ التيار المار فى مقاومة صغيرة و نكتبه على الشاشة**.*
*التحكم فى عرض النبضة يطبق على الموتور باستخدام موسفيت و نظرا لكون الوحدات التى تقبل **5 **فولت محدودة فمن الممكن استخدام رافع للفولت و سنحتاج** دائرة قيادة** لو عدد الموسفيت كبير لكن مع واحد فقط يكفى استخدام أوبتو**PC817*
*لاحظ أن مسارات التيار العالى و الخاصة بالموتور تسير فى مسارات مستقله حتى مدخل البوردة حتى لا تتشارك مع الإلكترونيات و تسبب تداخلات غير مرغوب فيها**.*
*من المرة القادمة إن شاء الله نبدأ فى البرمجة بالأسيمبلى*


----------



## ماجد عباس محمد (19 أغسطس 2018)

*التعريفات:*

*طبعا كما هو معتاد نبدأ بالتعريفات و سنلاحظ هنا أننا لا نجد تعريفات لتغيير عرض النبضة، لذا نحتاج أن نبتكر وسيلة لفعل ذلك**. **نظرية تغيير عرض النبضة شرحناها سابقا و يمكننا تنفيذها كما فى المتحكمات الأخرى إلا أننا فقط لا نملك العتاد و نحتاج لتكوينه**.*
*كيف تفعله المتحكمات الأخرى؟ ببساطة أنها تقارن بين عداد و قيمتين واحدة لتفعيل النبضة أى الخرج **= 1 **و الأخرى لإبطالها أى الخرج **= **صفر و دورة العداد **(**أقصى عد له**) **تحدد التردد**.*
*حل آخر هو أن من عد **= **صفر للقيمة الأولى نجعل الخرج **= 1 **و من هذا العد للعد الثانى نجعله **= **صفر و العد الثانى يعيد العداد للصفر و بذلك يحدد التردد**.*
*ليست لدينا هذه الرفاهية و لكن يمكننا أن نقارن أى عداد بقيمة من قيمتين ، بل يمكننا أن نجعل **T0 **مثلا ذو تحميل ذاتى و حفظ هذه القيمة كما سبق أن فعلنا فى **TH0 **و هى التى ستحدد التردد و من ثم نقارن **TL0 **بالقيمة المطلوب إنهاء النبضة عندها و عندما يصل إلى نهاية العد **255 **سيعود آليا لقيمة البدء **. **فكرة جيدة لكن لن تتيح لك المدى الواسع فى تغيير التردد فكلما زاد التردد قلت عدد النبضات لكل دورة و من ثم أصبح التحكم أقل دقة فلو لديك **100 **نبضة ستتحكم من **1% **إلى **99% **لكن لو زدنا السرعة لتصبح **10 **نبضات لن يتاح لدينا سوى **10% **ثم **20% **ثم **30% **حتى **90% *
*الحل طبعا الانتقال لعداد **16 **بت ليتيح لك مدى ترددات أوسع و إن لم يكفى فالعودة للطرق التماثلية التقليدية فمثلا **ICL8038 **تعطيك تردد من **0.01 **هرتز و حتى **100**ك مع تحكم فى الدوام لا يتأثر بالتردد و **XR2206 **ترفع المدى لأعلى من واحد ميجا**.*
*طبعا فى هذا المنهج لا نقدم حلولا **100% **ولكن نتعلم كيف نتحايل على المشكلات و نبتكر لها حلول ودوما هى قابلة للتحسين و التطوير**. **وقد يفيد هذا فى استخدام متحكم أقل كلفة ما دامت المهمة ليست بهذه الدقة ، فى هذا التطبيق لدينا ميزة أن التردد غير مطلوب تغييره لذا فلا بأس من استغلال العتاد المتاح لأقصى حد**. **طريقة المقارنة لها مشكلتين الأولى استهلاك الوقت فى الاختبار و التنفيذ و الثانية أنها ليست آليه و تعمل تحت تصرف البرنامج و ألذى قد يتأخر عنها فى تنفيذ أمر آخر موكل إليه مما سيؤثر مباشرة على عرض النبضة لذا سنبتكر طريقة تجعل العملية بكاملها تحت تصرف المقاطعة و من ثم أداء البرنامج لشؤون أخرى لا يؤثر على عرض النبضة**.*
*نفترض أن المفتاح موضوع على نسبة ما و قرأها المحول لتكون **7 **أى ثنائى00000**111 **حسنا نجعل الخرج فاعلا أى **=1 **لمدة **7 **نبضات ثم نحمل العداد بالمكمل **255-7 **أى **248 **نبضه خلالها الخرج **= **صفر فإن زاد المستخدم المفتاح ليصبح **20 **سنجعل الخرج **=1 **لمدة **20 **ثم نجعله **= **صفر لمدة **255-20 = 235 **و هكذا و كل ما علينا هو أن نوجد المكمل أو المتمم للقيمة و لحسن الحظ لدينا أمر لهذا **CPL A **و لكنه فقط للمراكم **A **ولا يتعامل مع الذاكرة و على أى حال سنحتاجه فقط عند المقاطعة و لدينا أيضا XRL وهو OR المطلق يصلح للذاكرة**.*
*الأمر ليس بهذه السهولة فقط سنتذكر أن مع أتميل خرج **= 1 **هو الافتراضى عند البدء و من ثم نحتاج لجعله يوقف الموتور عوضا عن تشغيله ولكن الفكرة لم تتغير**.*
*ماذا نحفظ فى الذاكرة إذن، يمكننا أن نحفظ قيمة السرعة حتى نبدأ عندها كل مرة دون الحاجة لإعادة الضبط من جديد، و من ثم نحتاج لبايت أخرى تقول هل سنعمل آليا عند هذه السرعة أم تحول النظام الآن للنسق اليدوى حيث تحدد السرعة من خلال المقاومة المتغيرة**.*
*سنبدأ بتعريف المنافذ للمحول و ليدات الإخبار بالحالة و شاشة العرض و أزرار الأوامر و تخصيص لكل ليد طرف و اسم حيث لدينا واحد للنسق الآلى والآخر لليدوى و ثالث ينير أثناء الحفظ للتأكيد للمستخدم و رابع عند التوقف و خامس عند التشغيل**. **و أخيرا طرف أمر من المتحكم للمحول ليبدأ دورة تحويل وسابع للخيار ما بين تحويل قيمة الفولت أم قيمة التيار و الأخير هو النبضة الخارجة لتحديد سرعة الموتور**. **يلى هذه المجموعة الأزرار وواحد للتشغيل و الثانى للحفظ فى الذاكرة و الثالث للتوقف وهو متصل بالمقاطعة وواحد للتحويل من آلى ليدوى وواحد من المحول يفيد باكتمال تحويل البيانات ثم طرفى التحكم فى الشاشة **RS,E*


```
[LEFT][B][SIZE=4][COLOR=#008080]; This program Controls A DC motor according to a Volume setting.
;$NOMOD51
;$INCLUDE (89S8253.MCU)
INCLUDE 89S8253-MOD.mc 
[/COLOR]
ADC EQU P0
LEDS EQU P1
LCD Equ P2
Cmnds Equ P3

AutoLED Equ LEDS.0
ManLED Equ LEDS.1
SaveLed Equ LEDS.2
StopLed EQU LEDS.3
RUNLed Equ LEDS.4
ADCStrt EQU LEDS.5
InotV EQU LEDS.6
PWMout EqU LEDs.7

RunSW EQU P3.0
SaveSW Equ P3.1
StopSW Equ P3.2
ManAuto Equ P3.3
EOC EQU P3.5
LCD_RS Equ P3.6
LCD_Ena EQU P3.7

Man_Nauto EQU 10h[COLOR=#008080]          ; FF Manual, 0 Auto[/COLOR]
SavedSpeed EQU 11h
ReqSpeed EQU 12H
CurrSpeed EQU 13h   [COLOR=#008080]         ; Duity Ratio[/COLOR]
Sscntr EQU 14H    [COLOR=#008080]              ; Slow Start Counter[/COLOR]
Del1 EQU 15h
Del2 EQU 16h


Disp00 EQU 20h
Disp01 Equ 21h
Disp02 Equ 22h
Disp03 Equ 23h
Disp04 Equ 24h
Disp05 Equ 25h
Disp06 Equ 26h
Disp07 Equ 27h
Disp08 Equ 28h
Disp09 Equ 29h
Disp10 Equ 2Ah
Disp11 Equ 2Bh
Disp12 Equ 2Ch
Disp13 Equ 2Dh
Disp14 Equ 2Eh
Disp15 Equ 2Fh


SlowStart Equ 5
Line1 EQU $0       [COLOR=#008080]    ; 00h :0fh[/COLOR]
Line2 EQU $40      [COLOR=#008080]   ; 40H :4FH[/COLOR]
Line3 EQU $10      [COLOR=#008080]      ; 10H :1FH[/COLOR]
Line4 EQU $50          [COLOR=#008080]; 50H :5FH [/COLOR]

OutLo EQU F0[/SIZE][/B][/LEFT]
```
*يلى ما سبق **16 **خانة متتالية وهى فى اللغات العالية تسمى مصفوفة **Array **و هى بعدد الأحرف فى كل سطر من الشاشة أى لو استخدمت شاشة **16*1 **سيكونون ثمانية فقط ولو **20*2 **نستخدم **20 **و هكذا**. **يلى ذلك بايت أسميتها آلى لا يدوى أى **Man_Nauto **وهى يدوى **Manual **و لا آلى **Not Auto **بمعنى لو صفر تكون آلى أما أى قيمة فتعنى يدوى و السبب أن القيمة الفرضية للذاكرة هى **FF **و من ثم فى حال الخطأ لن تقرأ **8 **أصفار و بالتالى يكون العمل يدويا أسلم*

*يلى ذلك بايت أسميتها **SavedSpeed **وهى السرعة المخزونة فى الذاكرة للاستخدام المتكرر ثم **ReqSpeed **وهى القيمة المطلوب التشغيل عندها الآن وهى إما المحفوظة **SavedSpeed **أو تقرأ من المقاومة المتغيرة بحسب اختيار المستخدم بالزر **ManAuto **و مبينه بالليدات **MANled, AutoLed . **يلى ذلك **CurrSpeed **أى السرعة الحالية لأنك لو أردت تقليل السرعة ستكون القيمة الجديدة هى **ReqSpeed **بينما الحالية ستكون **CurrSpeed . *
*عند زيادة السرعة قد لا تكون الزيادة الفجائية ملائمة لذا استخدمت خانة عداد يمكنك استخدام أى متغير تشاء و هنا وضعت اسم **Sscntr **أى عداد بطء التشغيل **Slow Start Counter **و قيمة بخمسة باسم **SlowStart **لكن لو لديك لوحة مفاتيح يمكنك استخدام متغير تعدل به معدل تغير البدء**. **الفكرة هنا أنك لو فى حال التوقف ثم تبدأ آليا أو زدت السرعة فجأة ، لو فتحت التيار بالقيمة المطلوبة فجأة سيرتفع و يتلف كل شيئ لذا دوما يكون لو انخفضت السرعة تكون الاستجابة فورية لكن لو ارتفعت تكون تدريجية بمعدل يناسب الماكينة المدارة بالموتور**. **و أخيرا أربعة ثوابت بعنوانين بدء كل سطر من أسطر الشاشة**. *
*التعريف الأخير سنأتى له لاحقا إن شاء الله**.*
*بعد ذلك نبدأ الكود نعرف المقاطعة وهو موضوعنا القادم إن شاء الله*


----------



## ماجد عباس محمد (20 أغسطس 2018)

*بداية الكود:*

*حددنا سابقا أننا فى حاجة لمؤقت حراسة وهذا هو المسجل الخاص به*





*وسنجد الثلاثة بت العليا **5**،**6**،**7 **تحدد الزمن ألذى بعده يسبب إعادة تشغيل **RESET **و هذه طبقا لجدول نعرضه لاحقا**. **يلى ذلك البت **4 **باسم **WDIDLE **اختصار **WD IDLE **أى لو **=1 **سيظل يعمل حتى خلال فترة الكمون **Sleep **ولو **= **صفر فسيتوقف خلال هذه الفترة **. **البت رقم **3 **باسم **DISRTO **أى **DIS**ABLE **R**ese**t O**utput **لو **= **صفر فعند نهاية العد ستخرج نبضة **RESET **على ذلك الطرف لتفعيل البوردة بالكامل ولو **= 1 **توقف هذه الخاصية و تصبح داخل المتحكم فقط**. **البت رقم **2 **تحدد من إن كان يعمل بالطريقة العتا**دية **Hardware **لو **= 1 **أما لو كانت **= **صفر سيصبح بالطريقة السهلة بتفعيل البت صفر أو إيقافها**. **لو اخترت الطرقة الصعبة فلتفعيل المؤقت يجب أن تكتب **1E **ثم **E1 **فى المسجل **WDTRST register -with address 0A6H * *و عندها لا توقفه إلا بإعادة التشغيل**. **و لمنع عمل **RESET **للبوردة تكرر ذات التتابع فى مسجل **WDTRST SFR* *قبل انقضاء الوقت **. *
*البت رقم **1 **باسم **WSWRST **أى **SW reset **عند جعلها **= 1 **فالعداد يتم تصفيره فى الدورة التالية مباشرة و تعود للصفر آليا و طبعا يجب أن تكون البت **2 **على الطريقة السهلة أى **= **صفر**. **و جعلت بهذه الطريقة لأن تعليمات الأوامر لا يوجد بها أمر للتصفير ولو أضيف لن تكون متوائمة مع السابقات لذا جعلت هكذا**.*
*لاحظ أمر هام هنا أن المسجل مكتوب عليه على اليسار **Not Bit Addressable **وهذا هام جدا لأن الأمر **Setb **وكذا الأمر **CLR **لن يفعلا شيئ هنا لذا يجب قراءة المسجل فى **A **ثم تعديلها و إعادتها أو الأفضل استخدام الأمر **ORL WDTCON,#2 **لتفعيلها*
*البت رقم صفر هى التى تشغل المؤقت لو **= 1 **و توقفه لو **= **صفر لذا للتشغيل نستخدم الأمر **ORL WDTCON,#1 **و للإيقافه نستخدم الأمر **ANL WDTCON,#254 **حيث **254 = FE = 11111110b*
*وقت العداد يحدد كما ذكرنا بالبيت **7,6,5 **و هى طبقا للجدول*




*و نلاحظ باللون الأحمر أن الوقت يعتمد على تردد الكريستال لذا فالقيمة المدونة هنا تناسب **12 **ميجا و نحن نستخدم **4 **ميجا لذا سيكون الزمن الفعلى ثلاث أمثال المدون بالجدول**.*
*لذا سنحتاج فى التهيئة الأمر*

*MOV WDTCON, #01100010b ; Set WDT 7,6,5 scale 128 ms, 4 Ena idel,3 ena rst out, 2 Software WDT ena,1 wdT reset,0 Run/Stop*

*و نرى النسبة **128 **مللى ثانية *** 3 = 384 **مللى ثانية ثم لا يعمل فى حال الكمون ، نبضة **RESET **غير متاحة غيل السهل بالبرمجة **SW **ثم تنفيذ تصفير للعداد و يتوقف أى لا يكون متاحا**. **لاحقا نستخدم الأمر*
*ORL WDTCON,#2 ; clear WDT*
*و أمرى التشغيل و الإيقاف السابقين**. **و أيضا*
*ORL WDTCON,#3 ; Start and clear WDT*

*المرة القادمة إن شاء الله ندرس كيف نكتب و نقرأ فى ذاكرة المتحكم**..*


----------



## ماجد عباس محمد (21 أغسطس 2018)

*القراءة و الكتابة فى EEPROM للمتحكم 5283*

*الآن نريد أن نقرأ من الذاكرة، حسنا العائلة لا تحتوى أمر يقول بهذا و إضافة أمر جديد سيلغى الموائمة مع السابق و قد يسبب مشاكل بنيوية فى محلل الأكواد، لذا سنستغل أمر موجود مسبقا و نجعله يتعامل مع الذاكرة**. **فى أول المنهج عند مقارنة أتميل بالميكروتشيب ذكرنا أن أتميل يقرأ من **64**ك ذاكرة خارجية سواء برنامج أو بيانات ولم نتحدث كثيرا عن هذا، حسنا بالتوصيل المناسب يمكنك استخدام الأمر **MOVX **وهذا الأمر مضاف إليه حرف **X **اختصار لكلمة **External **و هى تستخدم صورة غير مباشرة للعنوان فإما تستخدم **MOVX A,@Ri **أى تستخدم **R0 **أو **R1 **ليحمل عنوان من **8 **بت للسرعة و تنقل من الخارج للمراكم **A **أو العكس لتنقل من **A **للذاكرة الخارجية أو تستخدم الأمر **MOVX A,@DPTR **حيث تستخدم المسجل **DATA Pointer DPTR **به عنوان من **16 **بت خارجى أيضا للقراءة أو العكس للكتابة**. **و هناك طرف لو نذكر باسم **ALE/PROG **قلنا أنه يعطى نبضة كل **1/6 **من الكريستال لتزامن الذاكرة الخارجية**.. **ولو لا تريد ذاكرة استخدم أجهزة أكثر من عدد المنافذ**.*
*يمكننا استخدام ذات الأمر باستخدام **DPTR **للكتابة و القراءة من **EEPROM **بتغيير بت واحدة فقط**.*




*هذا هو المسجل الخاص بالتحكم فى الذاكرة **EEPROM **حيث نجد البت صفر قراءة فقط و عندما تهبط التغذية عن الحد المسموح تصبح **= **صفر و تمنع الكتابة حتى لا تتلف البيانات**. *
*البت رقم **1 **تكون **= 1**عندما تكون جاهزة للعمل و **= **صفر أثناء الكتابة حيث لا تقبل أى أمر حتى تنتهى من الحالى**.*
*طبعا سنستخدم الأمر السابق مع **DPTR **للتعامل مع كم كبير من البيانات لكن هناك مشكلة أنك تحتاج لتحميلة بعنوان ثم تغير العنوان للتعامل مع شيء آخر مثل الشاشة أو غيره وهذا يستهلك وقت و كود لذا وضعت الشركة زوج من **DPTR **لتتمكن من تخصيص واحد لهدف و آخر لهدف مغاير و بأمر واحد تبدل بينهما وهنا أتت البت رقم **2 **حيث تضعها بصفر لتستخدم **DPTR0 **أو **=1 **لتستخدم **DPTR1 **ولا تغيير فى الأوامر سواء للتعامل مع **DPTR **أو التعامل مع الذاكرة**. *
*البت رقم **3 **باسم **EEMEN **أى **EE Memory Enable **هى البت التى تحدد ما إن كان الأمر **MOVX **يذهب للخارج أم للذاكرة فلو **= 1 **تكون الكتابة فى الذاكرة ولو **= 0 **ستذهب للخارج**. **الذاكرة **2 **ك لذا لو كان العنوان أكبر من **2 **ك فهذه البت لا أثر لها و سيكون خارجيا على أى حال**.*
*البت **4 **تحدد أن الأمر التالى سينفذ كتابة فهى باسم **EEMWE **أى **EE Memory Write Enable **و يجب جعلها **= 1 **قبل الكتابة و إعادتها للصفر بعد الانتهاء**.*
*البت الأخيرة رقم **5 **تحدد ما إن كنت تريد كتابة صفحه حتى **32 **بت معا أم خانة كل مرة، فإن كانت **= 1 **، تكرار الأمر لا يكتب في الذاكرة متجنبا البطء وعوضا عن ذلك تكتب فى مخزن داخلى **Buffer **و عند إرجاع هذه البت للصفر ينفذ الأمر التالى كتابة كل المخزون مع آخر بايت و يحتاج **4 **مللى ثانية للتنفيذ**. **تتابع البايت فى الرسم التالى**.*




*ترفع البت بالترتيب ثم تخفض قبل الأخيرة**.*
*تذكر أن هذا المسجل لا يقبل الكتابة على مستوى البت لذا فاستخدام **ORL **كما سبق*
*لسنا فى حاجة لتغيير **DPTR **لذا يمكننا استخدام واحد للشاشة و الذاكرة **. **القراءة تبدأ بوضع العنوان فى **DPTR **و استخدام الأمر **MOVX **وهو مستخدم فى التحضير فقط حيث تقرأ الذاكرة ولا يكتب فيها إلا بالضغط على زر الحفظ و ذلك للحفاظ على عمرها**.*
*أول أمر لإضاءة ليد ليبين للمستخدم أن الأمر قد بدأ ثم الأمر الثانى لإتاحة كتابة صفحة و إتاحة الكتابة و إتاحة الذاكرة بدلا من الخارجى ثم نحدد العنوان باستخدام الأمر **MOV DPTR,#0 **للبدء فى العنوان صفر أول خانة ثم نضع أول قيمة فى المراكم **A **ثم ننفذ الأمر **MOVX **و هذه القيمة **Man_Nauto **التى تحدد آلى أم يدوى**.
*

```
[LEFT][SIZE=4]WriteEEPROM:               [COLOR=#008080]   ; Address in DPTR[/COLOR]
CLR SaveLED
ORL EECON,#00111000b [COLOR=#008080]; set page write mode[/COLOR]
MOV DPTR,#0
MOV A,MAN_Nauto
MOVX  @DPTR,A
INC DPTR
ANL EECON,#11011111b [COLOR=#008080]; End page write[/COLOR]
MOV A,ReqSpeed 
MOVX  @DPTR,A
MOV Del1,#5
ACALL Wait_n_ms
ANL EECON,#11000111b[COLOR=#008080] ; End write cycle[/COLOR]
SETB SaveLED
RET[/SIZE][/LEFT]
```
*البايت السابقة كتبت فى الحافظ أو الواقى **Buffer **بعد ذلك نزود **DPTR **بواحد و نستخدم الأمر**ANL **لكى ننهى أمر الكتابة فى صفحة فالكتابة التالية تنفذ مع ما سبق للذاكرة ثم نقرأ القيمة الثانية وهى السرعة المضبوط عليها المقاومة المتغيرة و نكرر الكتابة و ننتظر **5 **مللى ثانية بدلا من **4 **للاحتياط و إظهار ألليد أيضا ثم ننهى باقى الخيارات و نطفئ ألليد و نعود**.*


----------



## ماجد عباس محمد (23 أغسطس 2018)

*أنظمة التأخير Delay Loops*

*وضعنا فى التعريفات خانتين باسم **Del1,Del2 **وهما كمتغيرين لحساب أزمنة التأخير**. **نحتاج بضع قيم متباينة للتأخير بعضها بالميكرو ثانية و بعضها بالمللي ثانية و لذلك نحتاج لحسابات بسيطة لتحديد هذه الدورات**.*
*نستخدم كريستال **4 **ميجا إذن النبضة **¼ **أى **0.25 **ميكرو ثانية**. **دورة الأمر تحتاج **12 **نبضة إذن **12*0.25 = 3 **ميكرو ثانية**. **و من ثم عندما نريد مثلا **120 **ميكرو ثانية نقسم **120 / 3 = 40 **دورة*
*أى نكتب **DJNZ Del1,40 **لكن طلب هذا الأمر سيحتاج دورتين و ذلك لو نسيت الأمر **Acall Delay120 **مثلا و العودة أيضا **RET, RETI **كلاهما يأخذ دورتين إذن لدينا **4 **دورات يمكن حذفهم لتصبح **36 **فقط**.*

```
[LEFT][B][SIZE=4]
Wait_120: [COLOR=#008080]; 3usec per inst[/COLOR]
MOV Del2,#36
DJNZ Del2,$ 
RET 
[/SIZE][/B][/LEFT]
```
*الآن لتأخير زمن طويل سنحتاج لدورة تكرر عدد من المرات أى فى داخل دورة أخرى وهى تسمى **Nested **أى متداخلة و النسق التقليدى لهذا هو*

```
[LEFT][B][SIZE=4]
[COLOR=#008080];---------------------------
; time: 10060 cyc. (incl. ACALL/RET) 0.054 sec
; stack: 2 (incl. ACALL/RET)
[/COLOR]wait_20ms: 
MOV Del1,#107 [COLOR=#008080]; Del1 = 107[/COLOR]
_wait_20: MOV Del2,#45[COLOR=#008080] ; Del2 = 45[/COLOR]
DJNZ Del2,$ [COLOR=#008080]; Del2--: If (Del2 > 0) repeat[/COLOR]
DJNZ Del1,_wait_20[COLOR=#008080] ; Del1--: If (Del1 > 0) _wait_20[/COLOR]
RET
[/SIZE][/B][/LEFT]
```
*عنوان**Wait_20ms **ثم حفظ فى الخانة الأولى **107 **لتكرر الدورة الداخلية **107 **من المرات ثم عنوان ثانى للدورة الداخلية حيث تحفظ فى الخانة الثانية **45 **مرة و تنقصها حتى الصفر مع الاختبار ثم تنقص الخارجية مع الاختبار لتكرر الداخلية **45 **مرة لتعود فتنقص الخارجية و هكذا**. **بسيطة و سهلة و لكن لو أردت **47 **مللى ستنشئ أخرى و ثالثة وهكذا وهو استهلاك للذاكرة فيما لا يجدى ، لذا هيأت الداخلية لتكفى **1 **مللى ثانية و جعلت الخارجية للمستخدم يحدد فيها كم مللى ثانية يحتاج و من ثم لو أردت **1 **مللى ضع **1 **فى **Del1 **و اطلب هذا الكود و ألذى أسميته *

```
[LEFT][B][SIZE=4]
Wait_n_ms:  ; 333 instruction / ms[COLOR=#008080] ; Time in ms saved in Del1 [/COLOR]
MOV Del2,#165
_wait_n: 
nop
DJNZ Del2,_Wait_n 
DJNZ Del1,Wait_n_ms 
RET [/SIZE][/B][/LEFT]
```
*
هنا أطلت زمن التقليل مع الاختبار بإضافة **NOP **قبلها و بذلك أصبحت **3 **بدلا من **2 **فقط ولو أردت أكواد أكبر فيمكنك تنفيذ أوامر ملغية مثل **PUSH A **ثم **PULL A **وهى أن تحفظ المراكم فى المصفوفة و تستهلك دورتين ثم تسترجعه فى دورتين و فى خانتى ذاكرة استهلكت ما يوازى **4 **أوامر **NOP **و عندما كانت الذاكرة حرجة كان حفظ كل من **A,B **فى المصفوفة **PUSH A , PUSH B **ثم **بعد ذلك الأمر **MUL AB **أى اضرب محتوى **A **فى محتوى **B **وهو يستهلك **4 **دورات ولكن بايت واحدة فقط و قبل العودة استرجع **B,A **مرة أخرى PULL B ثم PULL A ما حفظ أخيرا يسترجع أولا فلا **يغير أى شيئ**.*
*وهذه الأكواد مطلوبة للذاكرة و للشاشة و للمحول التماثلى الرقمى أيضا *


----------



## ماجد عباس محمد (24 أغسطس 2018)

*أكواد الشاشة*

*درسنا سابقا أكواد التهيئة و قمنا بضبطها على **8 **بت **5*8 **الخ**. **الآن ندرس الكتابة فيها**. **ستقول الأمر سهل بأن نضع الحرف على المنفذ ثم نضع **RS =1 **ثم نضع **E=1 **ثم ننتظر ثم نضع **E=**صفر **. **أجل هذا صحيح لكن كم مرة سنكتبه؟ هذا هو السؤال فبدلا من هذا بما يستهلكه من جهد و خانات بلا جدوى من الذاكرة،نضعه فى كود نطلبه عند كل كتابة و نكتب مثيل له بوضع **RS= **صفر لتنفيذ الأوامر و من ثم يكون لدينا كود باسم **Do_LCD **وآخر باسم **Writ_LCD **ولو لاحظنا سنجد أننا نعامل الطرف **E **ذات المعاملة فى الحالتين و يمكن تسميته مثلا **LCD_CLK **و يصبح الكود المشترك هكذا وهو مثال لكون أو **Subroutine **له مدخلين مختلفين ، المدخل الأول هو **Writ_LCD **حيث نضع **RS =1 **ثم عنوان للنبضه **LCD_CLK **حيث نضع **E=1 **ثم ننتظر ثم نضع **E=**صفر و الانتظار فيما سبق غير ضرورى مع هذا الكريستال البطيء لكنه هنا للصورة العامة**. **ثم فى النهاية الانتقال لتأخير **120 **ميكرو ثانية و هذه ميزة أخرى حيث لا نكرر كتابة هذا الأمر مع كل مرة نحتاج للتعامل مع الشاشة**. **يمكن تغيير هذه القيمة بحسب ما يتطلبه كل أمر وهذا سيأتى لاحقا فى كود التأخير إن شاء الله**.*
*المدخل الثانى هو **Do_LCD **حيث نجعل **RS = **صفر ثم ننتقل للنبضة أيضا **.*

```
[LEFT][B][SIZE=4]Do_LCD:
CLR LCD_RS[COLOR=#008080]                   ; Command Reg[/COLOR]
SJMP LCD_CLK


Writ_LCD:
SETB LCD_RS                [COLOR=#008080]; Data Reg[/COLOR]
NOP
LCD_CLK:
[COLOR=#008080]SETB LCD_Ena ;
[/COLOR]NOP                               [COLOR=#008080]; DELAY > 175 ns[/COLOR]
CLR LCD_Ena
ACALL wait_120[COLOR=#008080]          ; Wait Execution CurTime[/COLOR]
RET [/SIZE][/B][/LEFT]
```

*الآن نحتاج لكتابة سطر كامل على الشاشة وهنا نفرق بين سطر ثابت ككتابة رسالة ترحيب أو سطر خطأ فعند اكتشاف عطب المحول فلا جدوى من الاستمرار فنكتب رسالة خطأ و نتوقف أو جزء من السطر كإضافة الوحدات مثل **RPM **أو **Amp **مثلا و كلمة **Manu **و كلمة **Auto **و بين سطر متغير حيث تحسب هذه القيم و تضعها على الشاشة**.*
*السطر الثابت أسميته هكذا لكونه لا يتغير وهو جزء من الكود وهو رسالة تضعها فى اللغات العالية كثابت تطبعه على الشاشة وهو حقيقة سيضاف كجزء من الكود**. *
*كل مترجم بالأسيمبلى يتيح لك تعريف جدول ثوابت تضعه حيث شئت لكن الأفضل وضعة فى نهاية الكود حتى لا تضطر للالتفاف حوله وهو بالكلمة **DB **أو **Data Byte **وهو مجموعة من القيم كل منها بايت كاملة بأى نسق مقبول مثل الثنائى أو العشرى أو الثمانى أو هيكسا أو **DW **أو **Data Word **وهى قيم من **2 **بايت أى **16 **بت**. **كل منها تبدأ بعنوان ثم الكلمة **DB **أو **DW **أ و ما شئت من قيم حتى تكتب عنوان آخر و تعريف آخر هكذا*

```
[LEFT][B][SIZE=4]Testing: DB "Testing Pls Wait"
ADCErr: DB "ADC: No Responce"
MemFlt: DB "Mem Err,MAN Def "
Auto4: DB "Auto"
Man4: DB "Manu"
ByteExample:  DB  24,“A”,255,0Fh,0011b
WordExample:  DW 12300,0FFFFh,2,65500[/SIZE][/B][/LEFT]
```
*الأسطر الخمسة الأولى مستخدمة فى برنامجنا كرسائل و تعريف و السطرين الأخيرين مثالين يحتويان أرقام و حروف نصية**. **العنوان هنا هام لكونه يحدد بدء المجموعة فهى أسبه بمصفوفة تبدأ بالعنوان و هنا الرسائل كلها **16 **حرف لكونها تكتب فى سطر واحد ولو استخدمت شاشة أكبر **20 **أو **24 **حرف يمكنك الزيادة لما يناسبها**. **الآن كيف ننقلها للشاشة؟*

*لدينا الأمر باستخدام **DPTR **و سبق شرحة وهنا لدينا العنوان **WriteMsg **و أول أمر فقط للتأكيد على استخدامنا **DPTR0 **و إن كان حقيقة هنا لا يهم فلم نحتاج لتبديل **DPTR **و أى منهما سيكون فاعلا فلا بأس ثم نضع فى **R7 **أو أى خانة تختارها كعداد الرقم **16 **لكوننا سننقل **16 **حرف ثم عنوان **NextC **أى الحرف التالى
*

```
[LEFT][B][SIZE=4]
WriteMsg:                         [COLOR=#008080]; Writes a message on LCD, start in[/COLOR] 
ANL EECON,#11111011b          [COLOR=#008080]; Clear DPS bit in EECOM to select DPTR0[/COLOR]
MOV R7,#16             [COLOR=#008080] ; 16 character[/COLOR]
NextC:
CLR A
MOVC A,@A+DPTR[COLOR=#008080]           ; Read 1st byte[/COLOR]
MOV LCD,A                        [COLOR=#008080]; put on lcd data[/COLOR]
ACALL Writ_LCD 
INC DPTR
DJNZ R7,NextC
RET 
[/SIZE][/B]
[/LEFT]
```
*الأمر المستخدم هو **MOVC A,@A+DPTR **و هو يعنى **MOVC **اختصار انقل كود ولهذا الحرف **C **إلى المراكم **A **من خانة البرنامج المشار إليها بمجموع محتوى **DPTR + **محتوى المراكم **A **و هذا يتيح لك التعامل مع جداول شتى**. **هنا سنشير بالمؤشر **DPTR **فقط لذا نلغى محتوى **A **ثم ننفذ الأمر و جدير بالذكر أننا وضعنا عنوان الرسالة فى **DPTR **قبل طلب هذا الكود و من ثم سيؤشر المؤشر على أول حرف و نتيجة الأمر ينسخ الحرف فى المراكم **A **و من ثم نضعه من **A **على المنفذ ثم نكلب كود الكتابة على الشاشة السابق شرحه ثم نزود المؤشر **DPTR **بواحد ليشير للحرف التالى ثم ننقص العداد **R7 **بواحد فإن كان بصفر نكون اتممنا **16 **حرف و إلا نعود للنقل الحرف التالى فى عنوان **NextC **و أخيرا نعود*
*السطر المتغير موضوعنا القادم بإذن الله**:*


----------



## ماجد عباس محمد (26 أغسطس 2018)

*السطر المتغير*

*السطر المتغير هو ببساطة حيث تقوم بحساب ما تريد ثم تجمع النتائج معا و تكتبها على الشاشة مرة واحدة و يمكنك الكتابة مباشرة من الحساب لكن لو تطلب الأمر تعديل القيم لن يكون لديك الحرية فى تهيئة السطر كما تريد لذا كثيرا أفضل تخصيص **16 **خانة أكتب فيها ما أريد طباعته و عندما أقرر تحديث الشاشة أنقلها معا**.*
*فى المقدمة خصصت **Disp00 **إلى **Disp15 **لتدوين نتائج الحساب فيها بصورة **ASCII **أى الرقم **5 **يكون **035h **وهى بصورة أخرى إضافة **030h **تقابل **48 **عشرى أى أن الرقم **"7” = 037h **وهى **55 **بالعشري و فى النهاية استخدم الكود **WriteLine **لكتابة هذا السطر على الشاشة**.*
*لو أردت كتابة رقم ما أو إشارة ما فببساطة استخدم الأمر **MOV Dispxx,#NewValue **و ذلك عوضا عن الحاجة لاستخدام الأمر **goto character **وهو **080h+Address **لتوجيه الشاشة حيث اريد الكتابة ثم أبدأ**.*


```
[LEFT][B][SIZE=4]
WriteLine: [COLOR=#008080]; Put Line number on buss then call[/COLOR]
ACALL Do_Lcd  
MOV R0,#Disp00
LineLoop:
MOV LCD,@R0
ACALL Writ_LCD
INC R0
CJNE R0,#Disp11,LineLoop
RET[/SIZE][/B][/LEFT]
```
*يبدأ بفرض أنك وضعت رقم السطر على المنفذ فيطلب تنفيذ الأمر ثم يضع العنوان الخاص بأول حرف وهو **Disp00 **فى **R0 **وبذا يكون **R0 **به **020h **ثم عنوان تكرارى للسطر و يلى ذلك الأمر ينقل غير مباشر باعتبار **R0 **حاملا العنوان ما يشير إليه **R0 **للمنفذ **LCD **مباشرة ثم يطلب كود **Writ_LCD **لكتابته ثم نزيد **R0 **بواحد ليشير للتالى و نقارن محتواه بعنوان الخانة **Disp11 **و نكرر لو لا يتساوى إذن سنكتب عشرة أحرف فقط من الستة عشر و ذلك لكتابة **Manu/Auto **ولا حاجة لتكرار كتابتها إلا عند تغيير الوضع من يدوى لآلى أو العكس**.*
*سنضع عنوان أى من الرسالتين فى **DPTR **ثم نطلب هذا الكود فنضع عنوان الكتابة بالأمر الخاص بها على المنفذ ثم نطلب تنفيذ الأمر ثم نحفظ عدد الأحرف **4 **فى العداد **R7 **المستخدم فى كتابة رسالة و المشروح المرة الماضية لننتقل لعنوان **NextC **الحرف التالى وهذا أيضا كود ذو نقطتين مختلفتين**.*

```
[LEFT]
[B][SIZE=4]LCD4:
MOV LCD,#13+80H  [COLOR=#008080]    ; 80H is Goto Command + address 13[/COLOR]
ACALL Do_LCD
MOV R7,#4     [COLOR=#008080]              ; write 4 chrs[/COLOR]
SJMP NextC
WriteMsg:   [COLOR=#008080]                 ; Writes a message on LCD, start in [/COLOR]
ANL EECON,#11111011b    [COLOR=#008080]; Clear DPS bit in EECOM to select DPTR0[/COLOR]
MOV R7,#16          [COLOR=#008080]              ; 16 character[/COLOR]
NextC:
CLR A
MOVC A,@A+DPTR     [COLOR=#008080]         ; Read 1st byte[/COLOR]
MOV LCD,A       [COLOR=#008080]                  ; put on lcd data[/COLOR]
ACALL Writ_LCD 
INC DPTR
DJNZ R7,NextC
RET [/SIZE][/B]
[/LEFT]
```
*لتطوير هذا الكود لو لديك عدد متباين من الحروف كل مرة، يمكنك وضع عدد الأحرف فى **R7 **أو العداد ألذى تختاره و بدء الكتابة على المنفذ و تطلب الكود فقط تحذف السطرين حيث **MOV R7,#4 **و السطر **MOV R7,#16*


```
[LEFT]
[B][SIZE=4]
WriteMsg: ; Writes a message on LCD, start on port, count in R7
ANL EECON,#11111011b ; Clear DPS bit in EECOM to select DPTR0
ACALL Do_LCD
NextC:
CLR A
MOVC A,@A+DPTR ; Read 1st byte
MOV LCD,A ; put on lcd data
ACALL Writ_LCD 
INC DPTR
DJNZ R7,NextC
RET 
لو شئت لأى سبب محو الستة عشر خانة خاصة لو تريد كتابة قليلة مع بقاء الباقى خاليا يمكنك استخدام هذا الكود


ClrTxt: MOV R0,#Disp00
TTT: MOV @R0,#20h
INC R0
CJNE R0,#30h,TTT
RET
[/SIZE][/B]
[/LEFT]
```
*بقى لدينا كود القراءة من المحول وهذا موضوعنا القادم بإذن الله*


----------



## ماجد عباس محمد (28 أغسطس 2018)

كود المحول
*درسنا كيف يعمل المحول التماثلى رقمى و عرفنا بعض الأشياء عن المتكاملة **ADC0808 **و علمنا أن هناك كثير غيرها بدقة أعلى من **8 **بت**. **على أى حال هذه المتكاملة تعمل فى دورة من **8 **خطوات لو أصدرنا لها أمر لبدء التحويل لن تبدأ فيه قبل تمام الدورة لذا لها طرف اسمه **EOC **اختصار **End Of Count **لن يصبح بصفر مباشرة إلا صدفة أو يكمل ثمانية نبضات وهى فى طريقتنا فى التوصيل تكافئ **8 **أوامر **NOP **أو اربعه من ذات الدورتين كحد أقصى**. **لذا لبدء القراءة نضع أولا العنوان و هنا لدينا **3 **خطوط لكونها تقرأ من **8 **مداخل إلا أننا نستخدم **2 **فقط لذا وصلنا الخطين الباقيين للأرضى و بذلك أصبحنا نقرأ من مدخل صفر و مدخل **1 **فقط و نختار بينهما و هذا الطرف باسم **I_NV **أى التيار لو **= 1 **ولو **= **صفر يقيس الفولت على المقاومة المتغيرة المستخدمة لضبط السرعة**.*





*بعد تحديد العنوان نضع **1 **على خط **ADCStart **لبدء دورة قياس ثم نعيده للصفر و هنا تبدأ داخليا تتهيأ لقياس كما باللون الأزرق مع ملاحظة أن **ALE **بحسب الدائرة متصل بالخط **START **و يتغيران معا**.*





```
[LEFT][B][SIZE=5][SIZE=4]GetADC:          [COLOR=#008080]           ; Set ADC adress, reply in A[/COLOR]
SETB ADCStrt
NOP
CLR ADCStrt
MOV Del1,#20
DJNZ DEL1,$       [COLOR=#008080]            ; Now EOC should be zero[/COLOR]
JB EOC,Fault    [COLOR=#008080]                 ; if still one, it is defective[/COLOR]
MOV DEL1,#100
ADCloopChk:
JB EOC,ADCOK                 [COLOR=#008080]; if EOC = Hi again it is ok[/COLOR]
DJNZ DEL1,ADCloopChk  [COLOR=#008080] ; did not responde[/COLOR]
Fault: 
AJMP ADCFault
ADCOK:
MOV A,ADC
RET
[/SIZE]
[/SIZE][/B][/LEFT]
```
*نظرا لكوننا غير قادرين على تحديد متى ننتظر الخط **EOC **أن يصبح صفر فهو كما بالسهم الأحمر عند اكتمال من صفر إلى **8 **نبضات ، لذا ننشئ دورة تكفى أن تكون **8 **لكن للاحتياط جعلتها **20 **فلا تأخير هنا سيحتسب لأن الوقت مشاركة بين هذه النبضات الثمانية و اللازمة للتحويل وهى حتى **64 **بحسب القيمة لذا بعدها يجب أن يكون **EOC = **صفر **.*
*نختبر لو **=1 **إذن المتكاملة تالفه و نقفز لعنوان **Fault **أى عطل و إلا لو قبل انتهاء العد عادت للقيمة **1 **طبقا للخط البنفسجى يكون التحويل قد اكتمل فننتقل للعنوان **ADCOK **أى المحول أوكي حيث نضع القيمة من المنفذ للمراكم **A **ثم نعود طبعا بالأمر **RET **لكن لو انتقلنا للعنوان حيث يوجد عطل ستجد أمر انتقال **AJMP ADCFault **و هناك فى أول الكود ستجده حيث تكتب رسالة أن المحول لا يعمل ثم تتوقف نهائيا فلا جدوى من العمل بدونه**.*
*الكود من صفر حتى **255 **لذا المرة القادمة إن شاء الله نحوله لأعداد لكتابتها على الشاشة*


----------



## ماجد عباس محمد (30 أغسطس 2018)

*التحويل من ثنائى لعشرى و الكتابة*

*الآن قرأنا من المحول و نريد تحويل القراءة لنص على الشاشة**. **تعرضنا سابقا لأمر الضرب **MUL AB **حيث نضرب رقمين كل منهما من **8 **بت موجب أحدهما فى **A **و الآخر فى **B **و النتيجة ستكون **16 **بت البايت الصغرى فى **A **و الكبرى فى **B **و لو الناتج أكبر من **255 **فالعلم **OV =1 **و هذا لسبب أن فى حالة **= **صفر فالناتج أقل من **256 **و بالتالى يكون كله فى المراكم **A **ولا حاجة للتعامل مع **B **فهو **= **صفر**.*
*الآن نتعامل مع الآمر المكمل له وهو **DIV AB **حيث يقسم الرقم الموجب فى **A **على الرقم الموجب فى **B **و يكون الرقم الصحيح فى **A **و الباقى فى **B **و هنا لو كان المقسوم عليه **B = **صفر فالناتج غير محدد و العلم **OV=1 **كدلالة على خطأ فى الحساب**.*
*الكود هنا يفترض الرقم فى **A **و يعطى الناتج فى مسجلات **R7,6,5*

```
[LEFT][B][SIZE=3]
Bi2BCD_Ascii: ; converts data in Acc to 3 digits Ascii in R5(units) and R6(tens),R7(Hundred)
MOV B,#100
DIV AB               [COLOR=#008080]; Devide A/100, Hunderds in A, remainder in B [/COLOR]
ORL A,#30h [COLOR=#008080]        ; Convert to ascii[/COLOR]
MOV R7,A       [COLOR=#008080]   ; save 100's [/COLOR]
MOV A,B      [COLOR=#008080]       ; Get remainder[/COLOR]
MOV B,#10d [COLOR=#008080]; 
[/COLOR]DIV AB           [COLOR=#008080]     ; Devide A/10, Tens in A, remainder in B[/COLOR]
ORL A,#30h         [COLOR=#008080]     ; Convert to ascii[/COLOR]
MOV R6,A         [COLOR=#008080]   ; save Units [/COLOR]
ORL B,#30h
MOV R5,B         [COLOR=#008080]   ; put result [/COLOR]
RET[/SIZE][/B][/LEFT]
```
*نبدأ بوضع **100 **فى **B **و نقسم الرقم بالأمر **DIV AB **فيكون العدد الصحيح **0 **أو **1 **أو **2 **فى **A **و الباقى حتى **99 **فى **B. **و نحول الرقم المئات لحرف بإضافة **030H **أو **48 **عشرى و كثير من البرامج تستخدم **ORL **بدلا من **ADD **و لكن كلاهما سيان فى الميكرو لكن مع المتحكم سترى**. **ثم ننقل الحرف الأول للمسجل **7 **ثم ننقل الباقى من **B **إلى **A **و نضع الآن **10 **فى **B **لنقسم على **10 . **نتيجة القسمة العشرات فى **A **و الآحاد فى **B **و نضيف على العشرات **48 **للتحويل لحرف و نحفظه فى **R6 **و الآحاد لنضيف بالأمر **ADD **لوضع أحدهما فى **A **و لكن بالأمر **ORL **نستطيع أن ننفذه مباشرة على **B **دون نقل ثم بعد ذلك نحفظه فى **R5 **لنعود**.*
*الآن نريد الكتابة على الشاشة فنبدأ بتحويل قيمة السرعة الحالية **CurrSpeed **لحروف ثم نعرضها و هنا يجب أن نذكر أمر قبل أن تعترض**. **من أين نعلم أن سرعة الموتور مطابقة للمدى من صفر إلى **255**؟ هنا للسهولة افترضنا ذلك لكن فى الواقع ستحتاج لإضافة أمرين فقط*
*القراءة القصوى **255 **و السرعة القصوى مثلا **6000 **أعيد لذهنك الحقيقة أنك لو لم تستخدم تاكو كعداد فالمسألة كلها تقريبية لذا فلا بأس من نسبة خطأ ولو وصلت **10% *
*سنقول **6000 / 250 = 24 **أى تحتاج لضرب القراءة فى **24 **لكن على أى مقياس لن تقرأ حقيقة سرعة**3521 **و سرعة **3522 **و هكذا فأنت أصلا تقفز مع كل بت **24 **عد أى ستقرأ **3480 **ثم **3504 **ثم **3528 **إذن إما تستخدم محول ذو عدد بت أكبر و هنا ستعانى من الفرق فى الدقة بين ما يكون فى الواقع من سرعة نتيجة الحمل الخ و بين ما تقوله الحسابات**.*
*لذا أقترح أن تستخدم صفرين و تكتب الرقمين فقط**. **بقى أن نحول هذه **255 **إلى **600 **وهى النسبة **2.4 **ولدينا أمرى الضرب و القسمة فنقسم أولا على **10 **ثم نضرب فى **24 **دون الحاجة لحسابات الأرقام الكسرية*
*الآن استخدمنا **CurrSpeed **لأنه معبر عن السرعة المطلوبة الحالية سواء من الذاكرة أو من المقاومة و لكنها ما نحتاجه الآن**. **نحوله لحروف ثم ننقلها من **R7,6,5 **لخانات **Disp00,01,02 **ثم نضيف الصفر و مسافة و حروف **RPM **ثم نقطة و حرف **& **لأنه يعنى **"**و**" **لنضيف لاحقا كلمة **Auto **أو **Manu **ثم نضع **2 **على منفذ الشاشة للعودة لأول الشاشة و نطلب كود كتابة سطر و الذى سبق شرحه وهو ينفذ الأمر بالتوجه للسطر السابق وضعه وهو **00 **أى الأول ثم أمر تصفير مسجل الحراسة **WDT *

```
[LEFT][B][SIZE=3]
ShowValues:
MOV A,CurrSpeed
ACALL Bi2BCD_Ascii
MOV Disp00,R7
MOV Disp01,R6
MOV Disp02,R5
MOV Disp03,#"0"
MOV Disp05,#" "
MOV Disp06,#"R"
MOV Disp07,#"P"
MOV Disp08,#"M"
MOV Disp09,#"."
MOV Disp10,#26h         [COLOR=#008080] ; Type "&" [/COLOR]

MOV LCD,#2         [COLOR=#008080]                 ; Goto HOME[/COLOR]
ACALL WriteLine          [COLOR=#008080]        ; Line no 1 = 00, it has goto line nu[/COLOR]
ORL WDTCON,#2         [COLOR=#008080]           ; clear WDT[/COLOR]
SETB InotV                   [COLOR=#008080]        ; Get Current Reading[/COLOR]
ACALL GetADC
ACALL Bi2BCD_ASCII
MOV Disp00,R7
MOV Disp01,R6
MOV Disp02,#"."
MOV Disp03,R5
MOV Disp05,#"A"
MOV Disp06,#"m"
MOV Disp07,#"p"
MOV Disp08,#"s"
MOV Disp09,#" "
MOV Disp10,#" "
MOV LCD,Line2+080H     [COLOR=#008080]  ; 80H to create Goto Location in LCD memory[/COLOR]
ACALL WriteLine                [COLOR=#008080] ; Line no 1 = 00[/COLOR]

AJMP Looping[/SIZE][/B][/LEFT]
```
*يلى ذلك تغيير الفولت و التيار لقياس التيار بالأمر **GetADC **ثم نحول لأحرف و نكرر و نضع السطر **2 **و نكتب**.*
*الآن نبدأ فى كتابة كود البرنامج*


----------



## ماجد عباس محمد (1 سبتمبر 2018)

*كود البرنامج:*

*أتممنا المخدمات التى تكمل أداء المهام و الآن نبدأ فى كود صلب البرنامج**. **البداية من جزأين الأول تهيئه العتاد ثم الجزء الثانى التهيئة للتشغيل**.*
*كشأن كل الميكرو عادة يكون عنوان صفر هو البدء **Reset **و لذا و لأن عنوان المقاطعة الخارجية هو خانة **3 **فلا يسعنا إلا الانتقال للبدء فنجد **AJMP BeginP **و يليه العنوان **3 **حيث المقاطعة الخارجية من زر **STOP **أو التوقف وهذا طارئ يجب التوقف فورا ثم نفكر لاحقا فنوقف التايمر و نوقف الموتور ثم ننتقل لتهيئه ظروف التشغيل**. **يلى ذلك مقاطعة التايمر وهى الخاصة بموضوع **PWM .*

```
[LEFT][B][SIZE=3]
org 000
AJMP BeginP 
org 003h          [COLOR=#008080]       ; Adress of INT0 (IE0)Emergency [/COLOR]
SETB PWMout     [COLOR=#008080]    ; HI = Stop[/COLOR]
CLR TR0              [COLOR=#008080]     ; Stop counter[/COLOR]
SJMP Emrgncy  
org 00Bh          [COLOR=#008080]       ; Adress of Interrupt Timer 0 (TF0) [/COLOR]
XRL TH0,#255    [COLOR=#008080]      ; Complement Timer Hi [/COLOR]
CPL OutLo
MOV C,OutLo
MOV PWMout,C ; 
RETI[/SIZE][/B][/LEFT]
```

*فى جزء التهيئة السابق تحدثنا عن **PWM **و ذكرنا أنه يتم بأن نجعل العد المناسب في تايمر **TL0 **و المتمم أو المكمل له وهو **255-**العد فى **TH0 **و بذلك سنتحرك حسب العد حتى يصل **255 **وهنا تحدث مقاطعة فنأتى هنا و المطلوب فقط أن نعكس الخرج وهو **PWMout **وهذا سهل بالأمر **CPL bit **لكن هذا الأمر يجب أن يعرف قيمة البت أولا ثم يعكسها و مخارج كل متحكم قد تتأثر بالحمل ولذا البعض جهز بمسجل واقى **Buffer **لهذا الغرض**. **حسنا وفرنا هذا الواقى بالبت **OUTLo **و من ثم سنتمم أى جعل الآحاد أصفار و العكس هذه البت ثم ننقلها لمخرج **PWM **ولا ننسى أن نسخ بت لا يكون إلا بين **C **و أى بت أخرى ، و أيضا سنتمم محتوى **TH0 **لأنه لو يحتوى العد الآن فالتالى بعد المقاطعة يجب أن يكون تمامه و العكس بالعكس**.*

*العنوان التالى هو بداية الكود وهذا الجزء للتهيئه حيث نهيئ المقاطعات كلها و التايمر صفر و الخارجى ثم تهيئة التايمر **8 **بت ذاتى التحميل ثم تهيئه المقاطعة قدح بالحافة ثم ننتظر **20 **مللى ثانية للشاشة لتكمل البدء ثم اربعه أوامر للشاشة لتعمل **8 **بت سطرين **5*8 **و تفعيل الشاشة و إخفاء المؤشر و ثبات الشاشة مع حركة المؤشر لليمين و أخيرا محو الشاشة و البدء من الصفر**.*

```
[LEFT][B][SIZE=3]

BeginP: 
CLR LCD_Ena                [COLOR=#008080]   ; Clear LCD ENA bit Init_LCD[/COLOR]
MOV IE,#10000011b    [COLOR=#008080] ; Enable T0 & INT0 external [/COLOR]
MOV TMOD,#00000110b [COLOR=#008080]; T0 8bit counter auto reload[/COLOR]
MOV TCON,#1      [COLOR=#008080] ; Clr All interrupts, Set INT0 Edge trigger #5 for INT0,INT1[/COLOR]
mov Del1,#20            [COLOR=#008080]     ; call del with 20 ms[/COLOR]
ACALL wait_n_ms        [COLOR=#008080] ; Wait LCD [/COLOR]
MOV LCD,#00111000b [COLOR=#008080] ; 8bit, 2line, 5X8 display[/COLOR]
LCALL Do_LCD            [COLOR=#008080]; Execute: WAIT IS ADDED TO STORE_CMD [/COLOR]
MOV LCD,#00001100b[COLOR=#008080] ; Set display on,cursor off, blinking off[/COLOR]
LCALL Do_LCD 
MOV LCD,#00000110b[COLOR=#008080] ; Set Increment +1 mode, move screen off[/COLOR]
LCALL Do_LCD 
MOV LCD,#00010100b[COLOR=#008080] ; Shift Cursor, dcn=right[/COLOR]
LCALL Do_LCD 
MOV LCD,#1               [COLOR=#008080]; clear entire display[/COLOR]
LCALL Do_LCD 
ORL EECON,#00001000b    [COLOR=#008080]; XX,EELD Page/nbyte, mem Write ena,MOVX w dptr to 
;eeMem DPS=0 Bank1 or 1 bank2' 1 = ready 0 busy, if VDD << it is ZERO (Read only) Write_Inh
[/COLOR]MOV DPTR,#Testing
ACALL WriteMsg       [COLOR=#008080] ; write testing pls wait[/COLOR]
ACALL GetADC          [COLOR=#008080] ; if error will ret to ADC Fault[/COLOR]
SJMP OKey
ADCFault:
SETB PWMout          [COLOR=#008080] ; HI = Stop[/COLOR]
MOV DPTR,#ADCErr
ACALL WriteMsg
SJMP $
OKey:
[/SIZE][/B][/LEFT]
```
*يلى ذلك تهيئة الذاكرة **EEPROM **داخله حيث يجب وضع **1 **لتوجيه الأمر **MOVX A,@DPTR **للذاكرة بدلا من الخارج**. **ثم نحمل **DPTR **مؤشر البيانات بعنوان الرسالة **Testing **لإخبار المستخدم بالانتظار**. **ثم نطلب كود كتابة رسالة ثم نطلب كود القراءة من المحول ، فإن أتم القراءة سيعود بأمر **RET **و ألذى يقوده للخطوة التالية وهى القفز لعنوان **OKEY **و إلا سيعود من هناك بأمر القفز للعنوان **ADCFault **حيث نوقف الموتور أولا ثم نحمل مؤشر البيانات بعنوان الرسالة **ADCErr **و نطلب كود كتابة رسالة ثم يدخل فى دورة لا منتهية فلا يعمل شيئ حتى يوقف الجهاز و يتم إصلاحه ومن ثم إعادة تشغيله**.*


----------



## ماجد عباس محمد (4 سبتمبر 2018)

تهيئة القيم:
*الآن الوحدة سليمة و عدنا للعنوان **Okey **سنجد كود تهيئه القيم المطلوبة للعمل و تبدأ بالعنوان **Emergncy **وهو نفس الموقع **Okey **فقط تكون أوضح حينما تنتقل من كذا لكذا ثم تضع منفذ **Cmnds **كله آحاد ماعدا **RS,E **يجب أن يكونا صفرين لتشغيل الشاشة و إطفاء الليدات كلها ماعدا **Stop, Manual **كحالة افتراضية للبدء و خرج **PWM **أيضا **=1 **لأن عائلة **C51 **تبدأ هكذا ولذا جعلناه يقطع التيار عن الموتور**. **ثم ننقل مؤشر الرصة بعيدا و نهيئ مؤقت الحراسة و شرح كل بت بجواره للتذكرة وهى **7**و**6**و**5 **لزمن **128 **مللى فى **4 **لأننا نستخدم كريستال ربع التردد ثم نبطل فى حال التوقف ثم لا ريسيت للبوردة و التعامل بالبرنامج ثم تصفير و إتاحة **. **يلى ذلك تحميل مؤشر البيانات **DPTR **بصفر و نستخدم الأمر **MOVX A,@DPTR **لنقرأ الخانة صفر و فيها هل نعمل آليا أم يدويا و القيمة ستكون فى المراكم **A **و نحفظها فى المتغير **MAN_NAUTO **ثم نقفز لو **= **صفر للعنوان **Auto **فالقيمة صفر تعنى آليا أما أى قيمة أخرى تعنى يدوى وهنا فقط نضىء ألليد المناسب و نطفئ الآخر ثم نزود مؤشر البيانات **DPTR **بواحد ليشير للخانة التالية حيث القيمة المختارة للسرعة الآلية و نقرأ بذات الأمر **MOVX A,@DPTR **و نحفظ الناتج فى متغير **SavedSpeed **أى السرعة المحفوظة*


```
[LEFT][B][SIZE=3]


Emrgncy:
MOV Cmnds,#00111111b[COLOR=#008080] ; All Off RS,E low [/COLOR]
MOV ADC,#255
MOV LEDs,#11110101b[COLOR=#008080] ; PWM off,InV=I,ADC start,RUN off,Stop On,Save [/COLOR]off,Manual On,Auto Off
MOV SP,#70[COLOR=#008080] ; Move stack away[/COLOR]
MOV WDTCON,#01100010b[COLOR=#008080] ; 7,6,5 time,WDTidle=0,DISRTO(dis Rst out)=no 
; out,HWDT Hard wdt=noWSWRST soft reset ,WDTEN read only disabled low power[/COLOR] 
MOV DPTR,#0 [COLOR=#008080]; Read Mem 00[/COLOR]
MOVX A,@DPTR
MOV MAN_Nauto,A [COLOR=#008080]; MAN_Nauto[/COLOR]
JZ Auto
CLR MANLED
SETB AutoLED
SJMP GoOn
Auto:
CLR AutoLED
SETB ManLED
GoOn: 
INC DPTR
MOVX A,@DPTR
MOV SavedSpeed,A[COLOR=#008080] ; Value [/COLOR]
MOV SScntr,#SlowStart
MOV TL0,#254 [COLOR=#008080]; Hi=1 and low = 254[/COLOR]
MOV TH0,#1
SETB OutLo [COLOR=#008080]; Zero =Motor Run, 1= Motor Off. OutLo = PWMout[/COLOR]
MOV CurrSpeed,#0 [COLOR=#008080]; Start from zero[/COLOR]
JNB STOPsw,$   [COLOR=#008080] ; Wait while sw pressed[/COLOR]

MOV A,MAN_NAuto
SUBB A,#1Fh     [COLOR=#008080] ; C if zero or 0f, otherwise defective[/COLOR]
JC Looping
MOV DPTR,#MemFlt
ACALL WriteMsg 
MOV DEL1,#0     [COLOR=#008080]; delay 255 ms[/COLOR]
ACALL Wait_n_ms 
ACALL Wait_n_ms
ACALL Wait_n_ms
MOV LCD,#1
ACALL DO_LCD  [COLOR=#008080]  ; Clear display[/COLOR]
[/SIZE][/B][/LEFT]
```
*بعد قراءة السرعة وضعنا فى متغير **SlowStart **قيمة **5 **كما سبق الذكر أننا خاصة فى الموتورات الكبيرة نحتاج الزيادة ببطء و التوقف مفاجئ و سبق أن قلنا لو لدينا لوحة أزرار يمكننا اختيار هذه القيمة و حتى فى وجود فرملة يمكن التحكم فى قدرها**.*
*سنبدأ بالعد **254 **فى **TL0 **أى تشغيل **1 **فقط و العد **1 **فى **TH0 **أى التوقف من **1 **وحتى **255 **ثم نحمل **CurrSpeed=**صفر لتبدأ دوما من صفر سرعة مهما كانت الظروف**.*
*إن كان مازال الزر **StopSw **مضغوطا **"**تذكر البرامج السابقة**" **ننتظر تركه حرا ثم نضع فى **A **قيمة **MAN_NAuto **وهى للتذكرة إما صفر أو **0FH **أى **15 **ثم نطرح منها قيمة **1FH **أى**31 **فلو نتج **C **كانت القيمة صحيحة و إلا فهى أكبر من **1Fh **أى أن الذاكرة لم تحفظ القيمة و أعطت بدلا عنها **255 **أى **0FFh **و هنا سنضع عنوان رسالة الخطأ فى مؤشر البيانات **DPTR **و نكتب رسالة الخطأ لكن لن نوقف العمل فما زلنا نستطيع العمل يدويا**. **نضع صفرا فى **DEL1 **و نطلب كود الانتظار فينتظر **256 **مللى ثانية لأنه سيقلل الصفر قبل الاختبار فيجعله **255 **ثم نكرر التأخير لضمان رؤية الرسالة ثم نمسح الشاشة**.*
*يلى ذلك كود الدورة المستديمة وهى موضوعنا القادم إن شاء الله*


----------



## ماجد عباس محمد (16 سبتمبر 2018)

*ألدورة المستتديمة
بعد التجهيزات السابقة نبدأ الدورة التى سنكررها دوما وهى ببساطة تراقب الأزرار و تستجيب لها **. **أول الدورة أمر تصفير مؤقت الحراسة بالأمر **ORL WDTCON,#2 **ثم نفحص زر **ManAuto **فإن كان **=1 **يعنى ذلك أنه لم يضغط فننتقل لفحص التالى وهو **Save **و إلا سنعكس حالة ليدات **MANLED,AUTOLED **فتتغير من آلى ليدوى أو العكس ثم ننتظر فى دورة مغلقة حتى ترك زر آلى **/ **يدوى ثم نختبر ليد **MANLED **فإن كان **= **صفر أى اليدوى مضاء إذن الخيار هو يدوى فننتقل لعنوان **SETMAN **وإلا فالخيار هو آلى**. **و نكمل حيث **"**نضىء ليد اليدوى**" **تأكيدا و نطفئ ليد آلى و نصفر المتغير **MAN_Nauto **كعلامة للاختيار ثم نضع فى مؤشر البيانات **DPTR **عنوان رسالة **Auto4 **وهى رسالة من **4 **حروف **أ„uto **ثم ننتقل لعنوان **WriteIt **وهو عنوان وسطى لتجنب كود الخيار اليدوى**. **أما لو كان يدوى سننتقل لعنوان **SetMan **حيث نضىء و نطفئ الليدات و نضع فى المتغير **MAN_Nauto **القيمة **15 **وهى ما سنحفظه فى الذاكرة كقيمة مغايرة للفرضية **255 **، للتأكد أن الذاكرة قد حفظت صفرا أو قيمة أقل من **255. **و نضع فى مؤشر البيانات **DPTR **عنوان رسالة **Man4 **وهى رسالة من **4 **حروف **"Manu” **ثم ننتقل لكود كتابة هذه الرسالة على ألسطر العلوى أقصي اليمين فتكون الكتابة مثلا **4500RPM Manu*
*بعد تغيير يدوى **/ **آلى نجد كود **Save **فإن كان زر **Save **مضغوطا ننتقل لكود الحفظ فى الذاكرة السابق شرحة و يلى ذلك زر التشغيل*

```
[LEFT][B][SIZE=3]

Looping: 
ORL WDTCON,#2     [COLOR=#008080]; clear WDT[/COLOR]
JNB MANAuto,Save
CPL MANLED            [COLOR=#008080]; Switch AutuMan[/COLOR]
CPL AutoLED
JNB MANAuto,$       [COLOR=#008080]; Wait Sw released[/COLOR]

JNB MANLED,SetMan [COLOR=#008080]; MAN off, set man on[/COLOR]
CLR AutoLED     [COLOR=#008080]         ; Auto On[/COLOR]
MOV MAN_Nauto,#0[COLOR=#008080] ; MAN_Nauto =0[/COLOR]
MOV DPTR,#Auto4
SJMP WriteIT
SetMan:
CLR MANLED   [COLOR=#008080]           ; Man On[/COLOR]
SETB AutoLED    [COLOR=#008080]          ; Auto Off[/COLOR]
MOV MAN_Nauto,#0Fh[COLOR=#008080] ; MAN_Nauto = 0F mem default[/COLOR]
MOV DPTR,#Man4
WriteIt:
ACALL LCD4
Save: 
JB SaveSw,RUN      [COLOR=#008080]        ; Save Not Pressed[/COLOR]
ACALL WriteEEPROM 

[/SIZE][/B][/LEFT]
```
*سنأتى هنا أولا فى حال التوقف مع بدء التشغيل ، لذا نختبر إن كان طرف زر التشغيل **=**صفر فقد تم الضغط عليه للبدء فننتقل للعنوان **GoNow **حيث سننتظر حتى يحرر الزر ثم نضىء **RUNled **و نطفئ **StopLed **ثم نكمل فى كود **Running **و إلا لو حال وصولنا كان زر التشغيل **=1 **إذن هو حر ولم يضغط عليه فنتأكد أن ليد **Stop **مضاء أى أننا فى حال التوقف فننتقل لبدء الدورة من جديد**.*
*فى كود **Running **نقوم بالأمر **ORL WDTCON,#3 **بتصفير عداد الحراسة و تشغيله معا ثم نضع المتغير **Man_NAuto **فى المراكم **A **فإن لم يكن بصفر نقفز للتحكم اليدوى وإلا نكمل فى كود التحكم الآلى**. *

```
[LEFT][B][SIZE=3]Run:
JNB RUNSW,GoNow        [COLOR=#008080]            ; RUN pressed[/COLOR]
JNB STOPled,ShowValues    [COLOR=#008080]    ; Stop Mode do nothing[/COLOR]
SJMP Running
GoNow:
JNB RUNSW,$              [COLOR=#008080]              ; Wait release[/COLOR]
CLR RUNLed
SETB STOPLed 
Running:  [COLOR=#008080]                               ; Runing [/COLOR]
ORL WDTCON,#3      [COLOR=#008080]               ; Start and clear WDT [/COLOR]
MOV A,Man_Nauto
JNZ ManualControl
MOV ReqSpeed,SavedSpeed [COLOR=#008080]   ; Set required Speed as saved[/COLOR]
SJMP SetMotor
ManualControl:
CLR InotV
ACall GetADC
MOV ReqSpeed,A [COLOR=#008080]  ; Set required speed as ADC[/COLOR]
SetMotor:     [COLOR=#008080]           ; set pwm[/COLOR]
MOV A,ReqSpeed 
SUBB A,CurrSpeed[COLOR=#008080] ; If Curr > Req in A then a carry and needs to slow down[/COLOR]
JNC SpeedUP  
MOV CurrSpeed,ReqSpeed
SJMP AdjSpeed
SpeedUP:

[/SIZE][/B][/LEFT]
```
فى كود التحكم الألى سننسخ القيمة المحفوظة SavedSpeed فى المتغير ReqSpeed فهذه هى القيمة التى نريد بلوغها ثم ننتقل لعنوان SetMotor أى ضبط الموتور ، و إلا سنكون فى التحكم اليدوى فنصفر InotV لنختار قياس الفولت ثم نطلب كود GetADC لقراءة المحول وهو لو سليم سيعود بأمر RET لهذه الخطوة وإلا سيتوقف كليا و عند عودته ننسخ القيمة المضبوطة عليها المقاومة المتغيرة فى ReqSpeed فهذه هى القيمة التى نريد بلوغها.
يلى ذلك كود SetMotor حيث ننسخ ReqSpeed فى المراكم و نطرح منها السرعة الحالية CurrSpeed فلو كانت السرعة الحالية أقل من أو تساوى المطلوبة فلا يتطلب ذلك Carry و من ثم C = صفر أى نحتاج لزيادة السرعة فنقفز لعنوان SpeedUP اى زيادة السرعة ، و إلا سيكون C=1 وهنا يجب خفض السرعة فورا للقيمة المطلوبة.

نفعل ذلك المرة القادمة إن شاء الله


----------

