در این آموزش تصمیم دارم که مبحث وقفه Interrupt رو بصورت کامل،توسط رجیسترهای مختص وقفه Interrupt در محیط Codevision پیش بریم.همچنین به خاطر سادگی مطلب،آخرسر فعال کردن وقفه Interrupt خارجی توسط Codewizard رو نیز آموزش دادم.امیدورام ک ازین آموزشم لذت برده باشین و ما رو نیز از دعای خیرتون بی نصیب نفرمایین:)
به دو روش می توان داده ها را پردازش کرد:
1)روش سرکشی(Polling)
در روش سرکشی،میکروکنترلر دائما در حال خواندن دستورات بصورت ترتیبی بوده و اونا رو به فاصله ی زمانی معین و به نوبت اجرا میکنه و بدون رسیدن نوبت دستورات،اجرای اونا ممکن نیس.دراین روشCPU باید منتظر رسیدن نوبت اتفاق موردنظر باشه نه اینکه منتظر خود اتفاق که در این حین که CPU منتظر اتفاق افتادن کاری هس،این کار اتفاق بیفته و قبل از رسیدن نوبتش،این کار اتمام شده باشه.مثلا در برنامه ایی که شامل 2000خط دستور هس،دستور زده شدن کلیدی در خط اول گفته شده که بعد ازین دستور،کلید بلافاصله زده میشه و میکرو هم دار خطوط بقیه رو بررسی میکنه کلید برداشته بشه و میکرو به دستور کلید برسه در حالیکه کلید قطع شده در اون صورت برنامه بدون متوجه شدن این کار به کار خودش ادامه میده.
همچنین ایراد این روش اینه که CPU باید بطور مداوم سرکشی کنه و بیت های پرچم المان هارو بررسی کنه که این کار باعث ازدس رفتن زمان بررسی المان های دیگه میشه.
2)روش وقفه
برای رفع مشکل سرکشی، CPU باید به انجام وظیفه ی اصلی خود بپردازه و در آن حین ،اتفاق مورد نظر به هنگام وقوع، به صورت خودکار به CPU گزارش بشه برای همین امکانی در میکروکنرلر تعبیه شده که اتفاقات مهم توسط برنامه به اطلاع CPU برسه.در این روش CPU دستورات برنامه رو بطور عادی انجام میده و المانی که تحت عنوان وقفه به CPU معرفی شده درصورت تحریک پایه وقفه،سیگنال وقفه،روال عادی CPU رو متوقف کرده و آدرس دستور بعدی رو ذخیره کرده و دستورات زیرتابع وقفه رو اجرا میکنه و پس از اتمام دستورات زیرتابع وقفه ،به ادامه کار خودش(به آدرسی که ذخیره کرده) برمیگرده.اگه بطور خلاصه بگم اینطوری میشه که وقفه پیامی است که از طرف یک وسیله جانبی تولید می شود تا از CPU درخواست سرویس کندCPU با دریافت یک سیگنال وقفه،کارهای جاری را متوقف کرده و به وسیله مورد نظر سرویس می دهد.
در کارهای روزمره،همچین کاری زیاد اتفاق میفته مثلن تو خونه در حال انجام کارهای خودمون هستیم که زنگ در زده میشه که در اون صورت کارهامونو متوقف کرده و در رو باز میکنیم.
این مثالو اگه به زبان برنامه نویسی بگم اینطوری میشه که:
- انجام کارهای خود=>در حال انجام کارهای عادی خود
- زنگ در زده میشه=>درخواست وقفه
- توقف کارهای خود=>متوقف شدن کار خود و ذخیره دستورالعمل بعدی
- به سمت در یا آیفون میرین=>رجوع به آدرس وقفه
- در رو باز میکنین=>انجام دستورت زیرتابع وقفه
- برمیگردید و ادامه کار خودتونو انجام میدین=>بازگشت به آدرس ذخیره شده و ادامه برنامه
این روش باعث میشه تا زمان cpu برای بررسی رخ دادن یک وضعیت تلف نشه.
[ads1]
انواع وقفه:
وقفه ها در میکرو کنترلر به دو دسته وقفه های داخلی و خارجی تقسیم میشه و با توجه به نوع میکرو تعداد آن ها متفاوته
1)وقفه داخلی
همانطور که از اسمش پیداست المان های داخل میکرو،سیگنال های وقفه رو ایجاد میکنن. تقریبا تمام امکانات داخلی میکرو دارای وقفه بوده و اکثر این سیگنال ها از وسایل جانبی خود میکرو مانند تایمر/کانتر ها،سنکرون،پروتکل ارتباطی،مقایسه کننده ها ، ADC و … تولید می شوند. این سیگنال ها همان درخواست سرویس از CPU می باشند.
2)وقفه خارجی (وقفه Interrupt)
وقفه های Interrupt، وقفههایی هستند که منبع آنها خارج از میکرو قرار دارد و با ارسال سیگنالی به پایه های مخصوصی(int0,int1,int2) در میکروکنترلر، وقفه ایجاد می کنند.یعنی زمانی که پایه های INTx تحریک بشه،درخواست وقفه Interrupt میشه و میکرو به تابع وقفه رفته و زیربرنامه های اونو اجرا میکنه.
وقفه Interrupt با یک لبه بالا رونده یا پایین رونده و یا یک منطقی تحریک میشن که توضیحات تکمیلی در قسمت های بعدیه.
*نکته : هنگامی که یک پایه به عنوان وقفه استفاده بشه دیگه نمی تونیم از آن پایه به عنوان ورودی یا خروجی استفاده کنیم.
این نکته هم فراموش نشه که معمولا به وقفه ایی که توسط تایمر/کانتر ایجاد میکنیم،وقفه ی تایمر/کانتر میگن و یا به وقفه ایی که توسط USART ایجاد میشه،وقفه یوزارت میگن ولی در عموم به وقفه ی خارجی،بیشتر وقفه Interrupt میگن…
برای استفاده از وقفه های خارجی باید بصورت زیر عمل کنیم:
1-ابتدا پایه مربوط به وقفه Interrupt را ورودی کرده و pull-up یا pull-down می کنیم.
2-وقفه مورد نظر را فعال می کنیم.
3-مشخص می کنیم نسبت به چی حساس باشه.
4-وقفه سراسری را فعال می کنیم.
اگه حساس به سطح منطقی صفر و لبه پایین رونده باشه pull-up و اگه حساس به سطح منطقی یک و لبه بالارونده باشه pull-down میکنیم.
[ads1]
بردار وقفه
هر وقفهای در AVR خونه ای رو تو ROM (حافظه FLASH) به خود اختصاص داده و زمانی که درخواست وقفه صادر بشه بسته به نوع وقفه، CPU بعد از اجراکردن دستور جاری به آن خانه مراجعه می کنه این خانه محتوی آدرس برنامه ای است که به وقفه سرویس میده. به مجموعه این خانه ها که هرکدام مربوط به یک نوع وقفه هستند جدول بردار وقفه و به برنامه ای که به وقفه سرویس می دهد روال سرویس وقفه(ISR) میگن.
ممکنه تو یه برنامه چن تا وقفه داشته باشیم که هرچی عدد بردارهای وقفه کمتر باشد اولویت وقفه بالاتره که همانطور که از جدول بالا مشخصه وقفه های خارجی(وقفه Interrupt) عدد بردار وقفه ای کمتری دارن پس اولویت بالاتری نسبت به وقفه های داخلی دارن.
به لحاظ اولویت بندی ، وقفه ها به دو دسته تقسیم می شوند:
1-تک سطحه(single stage):اولویت وقفه ها ثابت و توسط کارخانه یکبار تعیین می شود.(avr)
2-چند سطحه(multi stage):اولویت وقفه ها می تواند در هر پروژه ای تعین وتغییر یابد.(ARM)
فعال کردن پاسخ گویی به وقفهها
وقفهها در AVR به صورت Default غیر فعال هستن و با روشن شدن میکرو هیچ وقفهای کار نمی کنه و باید با برنامه نویسی، وقفههایی را که میخواهیم ایجاد شوند رو فعال کنیم. در AVR معمولا هر وسیلهای به طور اختصاصی دارای بیتی به نام بیت فعال ساز وقفه می باشد. با یک شدن این بیت اجازه پاسخ گویی به وقفهی مربوط به آن وسیله فعال و با صفر شدن بیت مذکور اجازه پاسخ گویی به وقفه غیر فعال می شود. مکان این بیت برای هروقفهای دربیت هفتم ثبات SREG هستش.
آدرس های بردار وقفه فقط ۲ بایت فضا دارند. پس باید ISR را در محل دیگری نوشت و آدرس آن را در محل بردار وقفه قرار داد.
این مورد هم نکته ی مهمیه که در هنگام اجرای روال سرویس وقفه ای ،وقفه ای دیگری رخ بده در اون صورت طبق دستوراتی که توسط برنامه نویس در روال سرویس وقفه نوشته شده،حالت مختلفی داره.در هنگام ایجاد وقفه،AVR بصورت خودکار ،بیت فعال ساز وقفه ی عمومی رو پاک میکنه.اگه ما بخواییم در حین سرویس دهی به یک وقفه،وقفه ی دیگه ایی رو در صورت ایجاد،سرویس دهی بشه باید در روال سرویس وقفه ی قبلی بیت فعالساز وقفه ی عمومی رو یک کنیم اما چنین کاری به دقت نیاز داره چون که ممکنه باعث گیر کردن برنامه درون یک وقفه بشه.مثلن اگه یه وقفه ی خارجی حساس به سطح فعال باشه و بیت I در حالیکه هنوز پایه وقفه در حال تحریکه،یک بشه باعث میشه تا بطور بی نهایت وارد ISR شده و اتفاقات غیرقابل پیش بینی بوجود بیاره.
لازم به ذکره که بیت وقفهی اختصاصی یک وسیله جانبی در صورت درخواست وقفه توسط آن وسیله و پرش به جدول بردار وقفه برخلاف بیت فعال ساز وقفهی عمومی هیچ تغییری نمی کنه.
[ads1]
معرفی رجیسترهای وقفه Interrupt:
رجیستر SREG:
بیت هفتم این ثبات ،بیت “I” یا فعال ساز وقفهی عمومی (Interrupt Enable) نام دارد. به وسیله ی این بیت می توان کلیه وقفهها را فعال ویا غیرفعال کرد. به این صورت که اگر این بیت را یک کنیم وقفهها فعال و اگر آن را صفر کنیم وقفهها غیرفعال می شوند. با صفر شدن این بیت حتی اگر بیت فعال ساز وقفه برای وسیله ای یک باشد، وقفه ایجاد نمی شود. پس برای رخ دادن یک وقفه لازم است بیت فعال ساز وقفهی عمومی و بیت فعال ساز وقفهی اختصاصی، همزمان یک باشند. درواقع بیت فعال ساز وقفهی عمومی با بیت های فعال ساز وقفههای اختصاصی AND شده است.
در محیط برنامه نویسی کدویژن،دستورات زیر باعث فعال سازی و غیرفعال سازی وقفه عمومی میشن.
#asm (“sei”) //فعال سازی وقفه ی عمومی
#asm (“cli”) //غیر فعال سازی وقفه ی عمومی
رجیستر GICR:
Global Interrupt Control Register
بیت های ۲ تا ۴ رزرو هستند و از آن ها استفاده ای نمی شه و بیت ۰ و ۱ نیز برای تغییر مکان بردارهای وقفه مورد استفاده قرار می گیره و بیت های 5 و 6 و 7 برای وقفه Interrupt به کار میره.
بیت 5 (INT2):با یک شدن این بیت وقفه Interrupt دو (int2)یعنی PORTB.2 فعال میشه.
بیت 6 (INT1): با یک شدن این بیت وقفه Interrupt یک(int1) یعنی PORTD.2 فعال میشه.
بیت 7 (INT0): با یک شدن این بیت وقفه Interrupt صفر(int0) یعنی PORTD.3 فعال میشه.
این سه تا بیت وقفه ی اختصاصی هر کدام از وقفه های Interrupt دو و یک و صفر رو فعال یا غیر فعال میکنن که همونطوری که مشاهده میکنین مقدار اولیه شون(Initial Value)صفره و یعنی غیرفعالن.
این نکته رو هم قبلن گفتم که که برا فعال شدن هر وقفه Interrupt،هم باید بیت هفت از رجیستر SREG یک باشه و هم بیت های متناظر با هر وقفه Interrupt در رجیستر GICR یک بشه.
خب تا اینجا تونستیم فقط وقفه Interrupt رو فعال کنیم اما برای اجرای وقفه باید نوع درخواست وقفه(Mode) رو نیز تنظیم کنیم که توسط رجیستر های MCUCR برای وقفه های صفر و یک و رجیستر MCUCSR برای وقفه دو تنظیم میشه.
[ads1]
رجیستر MCUCR:
MCU Control register
توسط چهار بیت اول این رجیستر میتونیم مد های وقفه ی صفر و یک رو تنظیم کنیم یعنی نحوه ی تحریک پایه های وقفه(نحوه ی فعال و غیر فعال شدن وقفه) رو تنظیم کنیم.
ISCxy،عدد xنشون دهنده ی وقفه ی x و yنشون دهنده بیت اول و دوم هستش یعنی
ISC00 وقفه ی صفر و بیت اول
ISC01 وقفه ی صفر و بیت دوم
ISC10 وقفه ی یک و بیت اول
ISC11 وقفه ی یک و بیت دوم
چون دو بیت برای int1 و دو بیت برای هدفint0 اختصاص داده شده پس چهار مد میتونیم برای این وقفه ها داشته باشیم ولی برای int2 یک بیت در رجیستر بعدی اختصاص داده شده که دو حالت میتونه داشته باشه.
وقفه صفر و یک همونطوری که گفته شد چهار حالت داشت ولی وقفه ی دو،دو حالت حساس به لبه ی بالارونده و پایین رونده داره که توسط رجیستر زیر بیان میشه.
[ads1]
رجیسترMCUCSR:
MCU Control and Status Register
با توجه به توضیحاتی که در بالا گفته شد برای وقفه دو (INT2)فقط یه بیت (بیت ششم(ISC2)) اختصاص داده شده که فقط دو حالت بالارونده (هنگامی که این بیت یک هستش)و پایین رونده(هنگامی که این بیت صفره) داره.
[ads1]
رجیستر GIFR:
Global interrupt flag register
این سه تا بیت،پرچم رخ دادن وقفه های خارجی رو نشون میده یعنی اگه وقفه یک رخ بده، در این بیت(پرچم) عدد یک نوشته میشه و اگه رخ نده عدد صفر ثبت میشه بعبارتی این رجیستر پرچم وقوع وقفههای خارجیه و هر وقت یک وقفهی خارجی رخ بده، پرچم متناظر با آن یک میشه.
ازین رجیستر هنگامی که میخواییم از رخ دادن یا ندادن وقفه ای مطلع شویم استفاده میکنیم.
در صورت فعال کردن بیت های رجیستر GICR و با وقوع وقفه و پرش به آدرس بردار وقفه،پرچم های متناظر با اون وقفه در این رجیستر بصورت خودکار پاک میشه ولی اگه اون بیت های رجیستر GICR رو فعال نکرده باشیم باید خودمون با دادن مقدار یک به پرچم مربوطه در این رجیستر،مقدارشونو پاک کنیم(پرچم ها با دادن یک بهشون(در بخش کدنویسی)،مقدارشون پاک میشه)
فعال کردن وقفه در کدویژن(کدویزارد):
فعال کردن وقفه توسط کدویزارد کار سادیه ،اینطوری که پروژه جدیدی میسازین و تو قسمت کدویزارد، تو پیج External Interrupt با تیک زدن و انتخاب وقفه ی مورد نظر و انتخاب مد تحریک(درخواست وقفه)،وقفه مورد نظر رو فعال میکنیم و در قسمت ایجاد شده دستور مورد نظرمون رو مینویسیم.
همون طور که تو شکل مشخصه،یا تیک زدن هر کدام از وقفه ها،وقفه مورد نظر فعال شده و گزینه ی مد مربوطه در جلوی آن ظاهر میشه که چهار حالت حساس به تغییر و بالارونده و پایین رونده و حساس به سطح داره.
در جلسات قبلی هم گفته بودم که برای انتخاب مد،حتمن باید به pull up و pull down بودن پایه وقفه توجه کنیم.اگه پایه مون pull upبود میتونیم از یکی از حالات low level و falling Edge و Any change استفاده کنیم و برای pull down از حالات Rising Edge و Any change استفاده کنیم.
با فعال کردن وقفه تو قسمت کدویزارد،کد های زیر ایجاد میشه که مقدار این کدها بسته به انتخاب مد و انتخاب وقفه متفاوته.
در شکل زیر تونیم در قسمت گفته شده کد های اجرای در زمان وقفه رو بنویسیم.
چون وقفه صفر رو فعال کرده بودم در تابع وقفه،EXT_INT0 نوشته شده که حالت کلی آن شکل زیره.
در کد بالا باید به جای Vector No شماره وقفه مورد نظر که در جدول وقفه ها که در ابتدای صفحه موجوده، نوشته بشه و بجای function_name یک نام اختیاری برای تابع انتخاب بشه.
که طبق جدول بجای Vector No اگه وقفه صفر رو استفاده کنیم باید EXT_INT0 و یا عدد 2 قرار بدیم و در وقفه یک EXT_INT1 و یا3 و در وقفه دو باید EXT_INT2 یا عدد 19قرار بدیم.
این حروفاتی که در Vector No نوشته میشه در هدر میکرو تعریف شده ان که بصورت زیره:
کار با وقفه Interrupt در محیط کدویژن رو با در قالب آموزش پروژه ی ماشین حساب ساده با وقفه در AVR رو براتون آماده کردم،برای مشاهده اینجا کلیک کنین…
دیدگاهتان را بنویسید