قسم الميكروكنترولر والروبوت ودوائر الاتصال بالحاسب الالي قسم المتحكمات الـ microcontroller و المعالجات microprocessor و التحكم الرقمي بالكمبيوتر CNC والانظمة الآلية والروبوت Robots

   

ماجد عباس محمد
:: نائب المشرف العام
::
تاريخ التسجيل: Jun 2009
الدولة: القاهرة - مصر
المشاركات: 11,652
نشاط [ ماجد عباس محمد ]
قوة السمعة:
قديم 18-08-2018, 08:47 AM المشاركة 113   
افتراضي




الدائرة بمتحكم C51 و لغة الأسيمبلى
الآن نبدأ تصميم الدائرة و سنختار 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
لاحظ أن مسارات التيار العالى و الخاصة بالموتور تسير فى مسارات مستقله حتى مدخل البوردة حتى لا تتشارك مع الإلكترونيات و تسبب تداخلات غير مرغوب فيها.
من المرة القادمة إن شاء الله نبدأ فى البرمجة بالأسيمبلى

اعلانات

ماجد عباس محمد
:: نائب المشرف العام
::
تاريخ التسجيل: Jun 2009
الدولة: القاهرة - مصر
المشاركات: 11,652
نشاط [ ماجد عباس محمد ]
قوة السمعة:
قديم 19-08-2018, 08:54 AM المشاركة 114   
افتراضي



التعريفات:

طبعا كما هو معتاد نبدأ بالتعريفات و سنلاحظ هنا أننا لا نجد تعريفات لتغيير عرض النبضة، لذا نحتاج أن نبتكر وسيلة لفعل ذلك. نظرية تغيير عرض النبضة شرحناها سابقا و يمكننا تنفيذها كما فى المتحكمات الأخرى إلا أننا فقط لا نملك العتاد و نحتاج لتكوينه.
كيف تفعله المتحكمات الأخرى؟ ببساطة أنها تقارن بين عداد و قيمتين واحدة لتفعيل النبضة أى الخرج = 1 و الأخرى لإبطالها أى الخرج = صفر و دورة العداد (أقصى عد له) تحدد التردد.
حل آخر هو أن من عد = صفر للقيمة الأولى نجعل الخرج = 1 و من هذا العد للعد الثانى نجعله = صفر و العد الثانى يعيد العداد للصفر و بذلك يحدد التردد.
ليست لدينا هذه الرفاهية و لكن يمكننا أن نقارن أى عداد بقيمة من قيمتين ، بل يمكننا أن نجعل T0 مثلا ذو تحميل ذاتى و حفظ هذه القيمة كما سبق أن فعلنا فى TH0 و هى التى ستحدد التردد و من ثم نقارن TL0 بالقيمة المطلوب إنهاء النبضة عندها و عندما يصل إلى نهاية العد 255 سيعود آليا لقيمة البدء . فكرة جيدة لكن لن تتيح لك المدى الواسع فى تغيير التردد فكلما زاد التردد قلت عدد النبضات لكل دورة و من ثم أصبح التحكم أقل دقة فلو لديك 100 نبضة ستتحكم من 1% إلى 99% لكن لو زدنا السرعة لتصبح 10 نبضات لن يتاح لدينا سوى 10% ثم 20% ثم 30% حتى 90%
الحل طبعا الانتقال لعداد 16 بت ليتيح لك مدى ترددات أوسع و إن لم يكفى فالعودة للطرق التماثلية التقليدية فمثلا ICL8038 تعطيك تردد من 0.01 هرتز و حتى 100ك مع تحكم فى الدوام لا يتأثر بالتردد و XR2206 ترفع المدى لأعلى من واحد ميجا.
طبعا فى هذا المنهج لا نقدم حلولا 100% ولكن نتعلم كيف نتحايل على المشكلات و نبتكر لها حلول ودوما هى قابلة للتحسين و التطوير. وقد يفيد هذا فى استخدام متحكم أقل كلفة ما دامت المهمة ليست بهذه الدقة ، فى هذا التطبيق لدينا ميزة أن التردد غير مطلوب تغييره لذا فلا بأس من استغلال العتاد المتاح لأقصى حد. طريقة المقارنة لها مشكلتين الأولى استهلاك الوقت فى الاختبار و التنفيذ و الثانية أنها ليست آليه و تعمل تحت تصرف البرنامج و ألذى قد يتأخر عنها فى تنفيذ أمر آخر موكل إليه مما سيؤثر مباشرة على عرض النبضة لذا سنبتكر طريقة تجعل العملية بكاملها تحت تصرف المقاطعة و من ثم أداء البرنامج لشؤون أخرى لا يؤثر على عرض النبضة.
نفترض أن المفتاح موضوع على نسبة ما و قرأها المحول لتكون 7 أى ثنائى 00000111 حسنا نجعل الخرج فاعلا أى =1 لمدة 7 نبضات ثم نحمل العداد بالمكمل 255-7 أى 248 نبضه خلالها الخرج = صفر فإن زاد المستخدم المفتاح ليصبح 20 سنجعل الخرج =1 لمدة 20 ثم نجعله = صفر لمدة 255-20 = 235 و هكذا و كل ما علينا هو أن نوجد المكمل أو المتمم للقيمة و لحسن الحظ لدينا أمر لهذا CPL A و لكنه فقط للمراكم A ولا يتعامل مع الذاكرة و على أى حال سنحتاجه فقط عند المقاطعة أو XRL وهى OR المطلق وهى تصلح للذاكرة.
الأمر ليس بهذه السهولة فقط سنتذكر أن مع أتميل خرج = 1 هو الافتراضى عند البدء و من ثم نحتاج لجعله يوقف الموتور عوضا عن تشغيله ولكن الفكرة لم تتغير.
ماذا نحفظ فى الذاكرة إذن، يمكننا أن نحفظ قيمة السرعة حتى نبدأ عندها كل مرة دون الحاجة لإعادة الضبط من جديد، و من ثم نحتاج لبايت أخرى تقول هل سنعمل آليا عند هذه السرعة أم تحول النظام الآن للنسق اليدوى حيث تحدد السرعة من خلال المقاومة المتغيرة.
سنبدأ بتعريف المنافذ للمحول و ليدات الإخبار بالحالة و شاشة العرض و أزرار الأوامر و تخصيص لكل ليد طرف و اسم حيث لدينا واحد للنسق الآلى والآخر لليدوى و ثالث ينير أثناء الحفظ للتأكيد للمستخدم و رابع عند التوقف و خامس عند التشغيل. و أخيرا طرف أمر من المتحكم للمحول ليبدأ دورة تحويل وسابع للخيار ما بين تحويل قيمة الفولت أم قيمة التيار و الأخير هو النبضة الخارجة لتحديد سرعة الموتور. يلى هذه المجموعة الأزرار وواحد للتشغيل و الثانى للحفظ فى الذاكرة و الثالث للتوقف وهو متصل بالمقاطعة وواحد للتحويل من آلى ليدوى وواحد من المحول يفيد باكتمال تحويل البيانات ثم طرفى التحكم فى الشاشة RS,E
كود:
; This program Controls A DC motor according to a Volume setting. ;$NOMOD51 ;$INCLUDE (89S8253.MCU) INCLUDE 89S8253-MOD.mc 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 ; FF Manual, 0 Auto SavedSpeed EQU 11h ReqSpeed EQU 12H CurrSpeed EQU 13h ; Duity Ratio Sscntr EQU 14H ; Slow Start Counter 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 ; 00h :0fh Line2 EQU $40 ; 40H :4FH Line3 EQU $10 ; 10H :1FH Line4 EQU $50 ; 50H :5FH OutLo EQU F0
يلى ما سبق 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 لكن لو لديك لوحة مفاتيح يمكنك استخدام متغير تعدل به معدل تغير البدء. الفكرة هنا أنك لو فى حال التوقف ثم تبدأ آليا أو زدت السرعة فجأة ، لو فتحت التيار بالقيمة المطلوبة فجأة سيرتفع و يتلف كل شيئ لذا دوما يكون لو انخفضت السرعة تكون الاستجابة فورية لكن لو ارتفعت تكون تدريجية بمعدل يناسب الماكينة المدارة بالموتور. و أخيرا أربعة ثوابت بعنوانين بدء كل سطر من أسطر الشاشة.
التعريف الأخير سنأتى له لاحقا إن شاء الله.
بعد ذلك نبدأ الكود نعرف المقاطعة وهو موضوعنا القادم إن شاء الله


اعلانات اضافية ( قم بتسجيل الدخول لاخفائها )

ماجد عباس محمد
:: نائب المشرف العام
::
تاريخ التسجيل: Jun 2009
الدولة: القاهرة - مصر
المشاركات: 11,652
نشاط [ ماجد عباس محمد ]
قوة السمعة:
قديم 20-08-2018, 02:30 PM المشاركة 115   
افتراضي



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

وسنجد الثلاثة بت العليا 5،6،7 تحدد الزمن ألذى بعده يسبب إعادة تشغيل RESET و هذه طبقا لجدول نعرضه لاحقا. يلى ذلك البت 4 باسم WDIDLE اختصار WD IDLE أى لو =1 سيظل يعمل حتى خلال فترة الكمون Sleep ولو = صفر فسيتوقف خلال هذه الفترة . البت رقم 3 باسم DISRTO أى DISABLE Reset Output لو = صفر فعند نهاية العد ستخرج نبضة 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

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


ماجد عباس محمد
:: نائب المشرف العام
::
تاريخ التسجيل: Jun 2009
الدولة: القاهرة - مصر
المشاركات: 11,652
نشاط [ ماجد عباس محمد ]
قوة السمعة:
قديم 21-08-2018, 11:14 AM المشاركة 116   
افتراضي




القراءة و الكتابة فى 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 التى تحدد آلى أم يدوى.
كود:

WriteEEPROM:            ; Address in DPTR
	CLR		SaveLED
	ORL		EECON,#00111000b	; set page write mode
	MOV		DPTR,#0
	MOV		A,MAN_Nauto
	MOVX		*DPTR,A
	INC		DPTR
	ANL		EECON,#11011111b	; End page write
	MOV		A,ReqSpeed 
	MOVX		*DPTR,A
	MOV		Del1,#5
	ACALL	Wait_n_ms
	ANL		EECON,#11000111b	; End write cycle
	SETB		SaveLED
	RET
البايت السابقة كتبت فى الحافظ أو الواقى Buffer بعد ذلك نزود DPTR بواحد و نستخدم الأمرANL لكى ننهى أمر الكتابة فى صفحة فالكتابة التالية تنفذ مع ما سبق للذاكرة ثم نقرأ القيمة الثانية وهى السرعة المضبوط عليها المقاومة المتغيرة و نكرر الكتابة و ننتظر 5 مللى ثانية بدلا من 4 للاحتياط و إظهار ألليد أيضا ثم ننهى باقى الخيارات و نطفئ ألليد و نعود.



ماجد عباس محمد
:: نائب المشرف العام
::
تاريخ التسجيل: Jun 2009
الدولة: القاهرة - مصر
المشاركات: 11,652
نشاط [ ماجد عباس محمد ]
قوة السمعة:
قديم 23-08-2018, 10:26 AM المشاركة 117   
افتراضي




أنظمة التأخير 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 فقط.
كود:

Wait_120:            ; 3usec per inst
	MOV Del2,#36
	DJNZ Del2,$	
	RET		
الآن لتأخير زمن طويل سنحتاج لدورة تكرر عدد من المرات أى فى داخل دورة أخرى وهى تسمى Nested أى متداخلة و النسق التقليدى لهذا هو
كود:

;---------------------------
; time:		10060 cyc.	(incl. ACALL/RET) 0.054 sec
; stack:	2		(incl. ACALL/RET)
wait_20ms:	
		MOV Del1,#107		; Del1 = 107
    _wait_20:	MOV Del2,#45		; Del2 = 45
		DJNZ Del2,$		; Del2--: If (Del2 > 0) repeat
		DJNZ Del1,_wait_20	; Del1--: If (Del1 > 0) _wait_20
	RET
عنوانWait_20ms ثم حفظ فى الخانة الأولى 107 لتكرر الدورة الداخلية 107 من المرات ثم عنوان ثانى للدورة الداخلية حيث تحفظ فى الخانة الثانية 45 مرة و تنقصها حتى الصفر مع الاختبار ثم تنقص الخارجية مع الاختبار لتكرر الداخلية 45 مرة لتعود فتنقص الخارجية و هكذا. بسيطة و سهلة و لكن لو أردت 47 مللى ستنشئ أخرى و ثالثة وهكذا وهو استهلاك للذاكرة فيما لا يجدى ، لذا هيأت الداخلية لتكفى 1 مللى ثانية و جعلت الخارجية للمستخدم يحدد فيها كم مللى ثانية يحتاج و من ثم لو أردت 1 مللى ضع 1 فى Del1 و اطلب هذا الكود و ألذى أسميته
كود:

Wait_n_ms:		; 333 instruction / ms	; Time in ms saved in Del1	
	MOV Del2,#165
	_wait_n:	
		nop
		DJNZ Del2,_Wait_n		
	DJNZ Del1,Wait_n_ms	
	RET	
هنا أطلت زمن التقليل مع الاختبار بإضافة 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 ما حفظ أخيرا يسترجع أولا فلا يغير أى شيئ .
وهذه الأكواد مطلوبة للذاكرة و للشاشة و للمحول التماثلى الرقمى أيضا



ماجد عباس محمد
:: نائب المشرف العام
::
تاريخ التسجيل: Jun 2009
الدولة: القاهرة - مصر
المشاركات: 11,652
نشاط [ ماجد عباس محمد ]
قوة السمعة:
قديم 24-08-2018, 08:41 AM المشاركة 118   
افتراضي




أكواد الشاشة
درسنا سابقا أكواد التهيئة و قمنا بضبطها على 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 = صفر ثم ننتقل للنبضة أيضا .
كود:

Do_LCD:
	CLR	LCD_RS		; Command Reg
	SJMP	LCD_CLK

Writ_LCD:
	SETB	LCD_RS		; Data Reg
	NOP
	LCD_CLK:
		SETB	LCD_Ena		;
		NOP			; DELAY > 175 ns
		CLR	LCD_Ena
		ACALL wait_120		; Wait Execution CurTime
	RET	
الآن نحتاج لكتابة سطر كامل على الشاشة وهنا نفرق بين سطر ثابت ككتابة رسالة ترحيب أو سطر خطأ فعند اكتشاف عطب المحول فلا جدوى من الاستمرار فنكتب رسالة خطأ و نتوقف أو جزء من السطر كإضافة الوحدات مثل RPM أو Amp مثلا و كلمة Manu و كلمة Auto و بين سطر متغير حيث تحسب هذه القيم و تضعها على الشاشة.
السطر الثابت أسميته هكذا لكونه لا يتغير وهو جزء من الكود وهو رسالة تضعها فى اللغات العالية كثابت تطبعه على الشاشة وهو حقيقة سيضاف كجزء من الكود.
كل مترجم بالأسيمبلى يتيح لك تعريف جدول ثوابت تضعه حيث شئت لكن الأفضل وضعة فى نهاية الكود حتى لا تضطر للالتفاف حوله وهو بالكلمة DB أو Data Byte وهو مجموعة من القيم كل منها بايت كاملة بأى نسق مقبول مثل الثنائى أو العشرى أو الثمانى أو هيكسا أو DW أو Data Word وهى قيم من 2 بايت أى 16 بت. كل منها تبدأ بعنوان ثم الكلمة DB أو DW أ و ما شئت من قيم حتى تكتب عنوان آخر و تعريف آخر هكذا

كود:

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
الأسطر الخمسة الأولى مستخدمة فى برنامجنا كرسائل و تعريف و السطرين الأخيرين مثالين يحتويان أرقام و حروف نصية. العنوان هنا هام لكونه يحدد بدء المجموعة فهى أسبه بمصفوفة تبدأ بالعنوان و هنا الرسائل كلها 16 حرف لكونها تكتب فى سطر واحد ولو استخدمت شاشة أكبر 20 أو 24 حرف يمكنك الزيادة لما يناسبها. الآن كيف ننقلها للشاشة؟

لدينا الأمر باستخدام DPTR و سبق شرحة وهنا لدينا العنوان WriteMsg و أول أمر فقط للتأكيد على استخدامنا DPTR0 و إن كان حقيقة هنا لا يهم فلم نحتاج لتبديل DPTR و أى منهما سيكون فاعلا فلا بأس ثم نضع فى R7 أو أى خانة تختارها كعداد الرقم 16 لكوننا سننقل 16 حرف ثم عنوان NextC أى الحرف التالى

كود:

WriteMsg:	; Writes a message on LCD, start in 
	ANL	EECON,#11111011b	; Clear DPS bit in EECOM to select DPTR0
	MOV	R7,#16			; 16 character
	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	
الأمر المستخدم هو MOVC A,*A+DPTR و هو يعنى MOVC اختصار انقل كود ولهذا الحرف C إلى المراكم A من خانة البرنامج المشار إليها بمجموع محتوى DPTR + محتوى المراكم A و هذا يتيح لك التعامل مع جداول شتى. هنا سنشير بالمؤشر DPTR فقط لذا نلغى محتوى A ثم ننفذ الأمر و جدير بالذكر أننا وضعنا عنوان الرسالة فى DPTR قبل طلب هذا الكود و من ثم سيؤشر المؤشر على أول حرف و نتيجة الأمر ينسخ الحرف فى المراكم A و من ثم نضعه من A على المنفذ ثم نكلب كود الكتابة على الشاشة السابق شرحه ثم نزود المؤشر DPTR بواحد ليشير للحرف التالى ثم ننقص العداد R7 بواحد فإن كان بصفر نكون اتممنا 16 حرف و إلا نعود للنقل الحرف التالى فى عنوان NextC و أخيرا نعود
السطر المتغير موضوعنا القادم بإذن الله:



ماجد عباس محمد
:: نائب المشرف العام
::
تاريخ التسجيل: Jun 2009
الدولة: القاهرة - مصر
المشاركات: 11,652
نشاط [ ماجد عباس محمد ]
قوة السمعة:
قديم 26-08-2018, 09:06 AM المشاركة 119   
افتراضي




السطر المتغير
السطر المتغير هو ببساطة حيث تقوم بحساب ما تريد ثم تجمع النتائج معا و تكتبها على الشاشة مرة واحدة و يمكنك الكتابة مباشرة من الحساب لكن لو تطلب الأمر تعديل القيم لن يكون لديك الحرية فى تهيئة السطر كما تريد لذا كثيرا أفضل تخصيص 16 خانة أكتب فيها ما أريد طباعته و عندما أقرر تحديث الشاشة أنقلها معا.
فى المقدمة خصصت Disp00 إلى Disp15 لتدوين نتائج الحساب فيها بصورة ASCII أى الرقم 5 يكون 035h وهى بصورة أخرى إضافة 030h تقابل 48 عشرى أى أن الرقم "7” = 037h وهى 55 بالعشري و فى النهاية استخدم الكود WriteLine لكتابة هذا السطر على الشاشة.
لو أردت كتابة رقم ما أو إشارة ما فببساطة استخدم الأمر MOV Dispxx,#NewValue و ذلك عوضا عن الحاجة لاستخدام الأمر goto character وهو 080h+Address لتوجيه الشاشة حيث اريد الكتابة ثم أبدأ.
كود:

WriteLine:		; Put Line number on buss then call
	ACALL	Do_Lcd		
	MOV		R0,#Disp00
	LineLoop:
	MOV		LCD,*R0
	ACALL	Writ_LCD
	INC		R0
	CJNE		R0,#Disp11,LineLoop
	RET
يبدأ بفرض أنك وضعت رقم السطر على المنفذ فيطلب تنفيذ الأمر ثم يضع العنوان الخاص بأول حرف وهو Disp00 فى R0 وبذا يكون R0 به 020h ثم عنوان تكرارى للسطر و يلى ذلك الأمر ينقل غير مباشر باعتبار R0 حاملا العنوان ما يشير إليه R0 للمنفذ LCD مباشرة ثم يطلب كود Writ_LCD لكتابته ثم نزيد R0 بواحد ليشير للتالى و نقارن محتواه بعنوان الخانة Disp11 و نكرر لو لا يتساوى إذن سنكتب عشرة أحرف فقط من الستة عشر و ذلك لكتابة Manu/Auto ولا حاجة لتكرار كتابتها إلا عند تغيير الوضع من يدوى لآلى أو العكس.
سنضع عنوان أى من الرسالتين فى DPTR ثم نطلب هذا الكود فنضع عنوان الكتابة بالأمر الخاص بها على المنفذ ثم نطلب تنفيذ الأمر ثم نحفظ عدد الأحرف 4 فى العداد R7 المستخدم فى كتابة رسالة و المشروح المرة الماضية لننتقل لعنوان NextC الحرف التالى وهذا أيضا كود ذو نقطتين مختلفتين.
كود:

LCD4:
	MOV		LCD,#13+80H	; 80H is Goto Command + address 13
	ACALL	Do_LCD
	MOV		R7,#4		; write 4 chrs
	SJMP		NextC
WriteMsg:	; Writes a message on LCD, start in 
	ANL	EECON,#11111011b	; Clear DPS bit in EECOM to select DPTR0
	MOV	R7,#16			; 16 character
	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	

لتطوير هذا الكود لو لديك عدد متباين من الحروف كل مرة، يمكنك وضع عدد الأحرف فى R7 أو العداد ألذى تختاره و بدء الكتابة على المنفذ و تطلب الكود فقط تحذف السطرين حيث MOV R7,#4 و السطر MOV R7,#16
كود:

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
بقى لدينا كود القراءة من المحول وهذا موضوعنا القادم بإذن الله



ماجد عباس محمد
:: نائب المشرف العام
::
تاريخ التسجيل: Jun 2009
الدولة: القاهرة - مصر
المشاركات: 11,652
نشاط [ ماجد عباس محمد ]
قوة السمعة:
قديم 28-08-2018, 10:45 AM المشاركة 120   
افتراضي




كود المحول
درسنا كيف يعمل المحول التماثلى رقمى و عرفنا بعض الأشياء عن المتكاملة ADC0808 و علمنا أن هناك كثير غيرها بدقة أعلى من 8 بت. على أى حال هذه المتكاملة تعمل فى دورة من 8 خطوات لو أصدرنا لها أمر لبدء التحويل لن تبدأ فيه قبل تمام الدورة لذا لها طرف اسمه EOC اختصار End Of Count لن يصبح بصفر مباشرة إلا صدفة أو يكمل ثمانية نبضات وهى فى طريقتنا فى التوصيل تكافئ 8 أوامر NOP أو اربعه من ذات الدورتين كحد أقصى . لذا لبدء القراءة نضع أولا العنوان و هنا لدينا 3 خطوط لكونها تقرأ من 8 مداخل إلا أننا نستخدم 2 فقط لذا وصلنا الخطين الباقيين للأرضى و بذلك أصبحنا نقرأ من مدخل صفر و مدخل 1 فقط و نختار بينهما و هذا الطرف باسم I_NV أى التيار لو = 1 ولو = صفر يقيس الفولت على المقاومة المتغيرة المستخدمة لضبط السرعة.

بعد تحديد العنوان نضع 1 على خط ADCStart لبدء دورة قياس ثم نعيده للصفر و هنا تبدأ داخليا تتهيأ لقياس كما باللون الأزرق مع ملاحظة أن ALE بحسب الدائرة متصل بالخط START و يتغيران معا.

كود:

GetADC:			; Set ADC adress, reply in A
	SETB	ADCStrt
	NOP
	CLR	ADCStrt
	MOV	Del1,#20
	DJNZ	DEL1,$		; Now EOC should be zero
	JB	EOC,Fault	; if still one, it is defective
	MOV	DEL1,#100
   ADCloopChk:
		JB	EOC,ADCOK		; if EOC = Hi again it is ok
		DJNZ	DEL1,ADCloopChk	; did not responde
   Fault:		
	AJMP	ADCFault
   ADCOK:
	MOV	A,ADC
	RET
نظرا لكوننا غير قادرين على تحديد متى ننتظر الخط EOC أن يصبح صفر فهو كما بالسهم الأحمر عند اكتمال من صفر إلى 8 نبضات ، لذا ننشئ دورة تكفى أن تكون 8 لكن للاحتياط جعلتها 20 فلا تأخير هنا سيحتسب لأن الوقت مشاركة بين هذه النبضات الثمانية و اللازمة للتحويل وهى حتى 64 بحسب القيمة لذا بعدها يجب أن يكون EOC = صفر .
نختبر لو =1 إذن المتكاملة تالفه و نقفز لعنوان Fault أى عطل و إلا لو قبل انتهاء العد عادت للقيمة 1 طبقا للخط البنفسجى يكون التحويل قد اكتمل فننتقل للعنوان ADCOK أى المحول أوكي حيث نضع القيمة من المنفذ للمراكم A ثم نعود طبعا بالأمر RET لكن لو انتقلنا للعنوان حيث يوجد عطل ستجد أمر انتقال AJMP ADCFault و هناك فى أول الكود ستجده حيث تكتب رسالة أن المحول لا يعمل ثم تتوقف نهائيا فلا جدوى من العمل بدونه.
الكود من صفر حتى 255 لذا المرة القادمة إن شاء الله نحوله لأعداد لكتابتها على الشاشة




الساعة معتمدة بتوقيت جرينتش +3 الساعة الآن: 06:59 AM
موقع القرية الالكترونية غير مسؤول عن أي اتفاق تجاري أو تعاوني بين الأعضاء
فعلى كل شخص تحمل مسئولية نفسه إتجاه مايقوم به من بيع وشراء وإتفاق وأعطاء معلومات موقعه
التعليقات المنشورة لا تعبر عن رأي موقع القرية الالكترونية ولايتحمل الموقع أي مسؤولية قانونية حيال ذلك (ويتحمل كاتبها مسؤولية النشر)