پنج شنبه , ۲ آذر ۱۳۹۶
آخرین نوشته‌ها

منابع وقفه در AVR(جلسه ۲)

سلام می کنم به شما کاربر محترم میکرولرن 🙂

در جلسه دهم آموزش AVR به مبحث پورت های ورودی خروجی پرداختیم و دیدیم که چطوری میشه دنیای داخل میکروکنترلر را به دنیای بیرونی ارتباط داد و چند مثال را بررسی کردیم. امروز یکی دیگه از این کاربردها را بررسی می کنیم و می بینیم که این پایه ها چه استفاده هایی دارن. البته موضوع جلسه امروزمون یکی دیگه از امکانات بسیار قوی AVR هست که بهش میگن وقفه یا interrupt ولی چون تا حدی به پورت ها ارتباط داشت، مناسب دیدم که یه یادآوری کوچولو 😉 هم انجام بدم. حالا بریم سراغ وقفه ها و ببینیم به چه دردی میخورن.

تعریف وقفه

وقفه پیامی است که از طرف یک وسیله جانبی تولید می شود تا از CPU درخواست سرویس کند(به زبون ساده: به CPU بگه به منم توجه کن باهات کار دارم). CPU با در یافت یک سیگنال وقفه کارهای جاری را متوقف کرده و به وسیله مورد نظر سرویس می دهد. درست شبیه زمانی که فردی در حال انجام کارهای روزمره است و با زنگ خوردن تلفن کارها را رها کرده تا به تلفن پاسخ دهد. در این مثال فرد مورد نظر نقش CPU، کارهای روزمره نقش برنامه اصلی، تلفن نقش وسیله جانبی و صدای زنگ آن نقش سیگنال وقفه را دارند.

مزیت استفاده از وقفه

به دو روش می توان به وسایل جانبی سرویس دهی کرد:

۱) سرکشی دوره ای یا polling:

سرکشی دوره ای به این صورت است که در خلال برنامه بیت های پرچم وسیله جانبی جهت آگاهی از وضعیت آن، توسط cpu بررسی می شود و اگر آن وسیله نیاز به سرویس دهی داشت این کار توسط cpu انجام می شود. در این روش cpu باید به طور مداوم به این وسایل سرکشی کند که این کار باعث کندی برنامه و از دست رفتن زمان برای بررسی وسایل دیگر می شود.

۲) استفاده از وقفه یا interrupt:

در روش وقفه، cpu در حال اجرای روال عادی برنامه است. اما زمانی که یک وسیله جانبی نیاز به توجه cpu دارد با ارسال سیگنال وقفه باعث می شود تا cpu روال عادی برنامه را متوقف کرده و به آن توجه کند. این روش باعث می شود تا زمان cpu برای بررسی رخ دادن یک وضعیت تلف نشود.

انواع وقفه در AVR

معمولا در میکرو کنترلرها وقفه‌ها به دوسته کلی تقسیم می شوند:

  • وقفه‌های خارجی: وقفه‌هایی هستند که منبع آنها خارج از میکرو قرار دارد و با ارسال سیگنالی به پایه های مخصوصی در میکروکنترلر، وقفه ایجاد می کنند.
  • وقفه‌های داخلی: همانطور که از اسمش پیداست این وقفه‌ها سیگنال هایی هستند که داخل میکرو ایجاد می شوند. اکثر این سیگنال ها از وسایل جانبی خود میکرو مانند تایمر/کانتر ها ، ADC و … تولید می شوند. این سیگنال ها همان درخواست سرویس از CPU می باشند.

بردار وقفه

هر وقفه‌ای در AVR خانه ای  را در ROM (حافظه فلش) به خود اختصاص می دهد. زمانی که وقفه ایجاد می شود بسته به نوع وقفه، CPU بعد از اجراکردن دستور جاری به آن خانه مراجعه می کند. این خانه محتوی آدرس برنامه‌ای است که به وقفه سرویس می دهد. به مجموعه این خانه ها که هرکدام مربوط به یک نوع وقفه هستند جدول بردار وقفه و به برنامه ای که به وقفه سرویس می دهد روال سرویس وقفه(ISR) میگویند. در جدول زیر می توانید آدرس وقفه‌های مختلف در ATmega32 را مشاهده کنید:

برای باز شدن تصویر روی جعبه زیر کلیک کنید.

جدول بردار وقفه

جدول بردار وقفه

فعال کردن پاسخ گویی به وقفه‌ها

وقفه‌ها در AVR به صورت پیش فرض غیر فعال هستند.یعنی با روشن شدن میکرو هیچ وقفه‌ای کار نمی کند و باید به وسیله برنامه نویسی، وقفه‌هایی را که میخواهیم ایجاد شوند فعال کنیم. در AVR معمولا هر وسیله‌ای به طور اختصاصی دارای بیتی به نام بیت فعال ساز وقفه می باشد. با یک شدن این بیت اجازه پاسخ گویی به وقفه‌ی مربوط به آن وسیله فعال و با صفر شدن بیت مذکور اجازه پاسخ گویی به وقفه غیر فعال می شود. مکان این بیت برای هروقفه‌ای در ثبات خاصی از ثبات های I/O می باشد. اگر نیاز به یادآوری رجیسترهای I/O دارید مقاله سازماندهی حافظه در AVR را مطالعه کنید.

اگر از مباحث مربوط به ثبات وضعیت به یاد داشته باشید یکی از بیت های این ثبات “I” یا فعال ساز وقفه‌ی عمومی (Interrupt Enable) نام دارد. به وسیله ی این بیت می توان کلیه وقفه‌ها را فعال ویا غیرفعال کرد. به این صورت که اگر این بیت را یک کنیم وقفه‌ها فعال و اگر آن را صفر کنیم وقفه‌ها غیرفعال می شوند. با صفر شدن این بیت حتی اگر بیت فعال ساز وقفه برای وسیله ای یک باشد، وقفه ایجاد نمی شود. پس برای رخ دادن یک وقفه لازم است بیت فعال ساز وقفه‌ی عمومی و بیت فعال ساز وقفه‌ی اختصاصی، همزمان یک باشند. درواقع بیت فعال ساز وقفه‌ی عمومی با بیت های فعال ساز وقفه‌های اختصاصی AND شده است. در شکل زیر می توانید ثبات یا رجیستر وضعیت را مشاهده کنید:

در کد زیر می توانید نحوه فعال و غیر فعال کردن بیت I در کدویژن را مشاهده کنید:

مراحل اجرای یک وقفه

  1.  هنگامی که یک وقفه اتفاق می افتد cpu دستور در حال اجرا را به پایان برده و آدرس دستور بعدی (این آدرس درون رجیستر pc یا program counter قرار دارد) را بر روی پشته ذخیره می کند.
  2. بسته به نوع وقفه، میکروکنترلر به خانه ثابتی از حافظه فلش واقع در جدول بردار وقفه پرش می کند.
  3. در این خانه، آدرس روال سرویس وقفه یا ISR وجود دارد و میکرو با پرش به این آدرس، شروع به اجرای دستورات موجود در روال سرویس وقفه می کند تا به دستور آخر روال  یعنی RETI برسد.
  4. این دستور شمارنده برنامه یا pc را با آدرس دستوری که در مرحله یک در پشته ذخیره شده بود بارگذاری می کند. این کار با برداشتن دو بایت بالای پشته و قرار دادن آن در PC انجام می شود. سپس میکرو شروع به اجرای دستورات از این آدرس می کند.

این موضوع اهمیت مدیریت پشته را در حین نوشتن روال سرویس وقفه برای ما آشکار می کند. بهتر است در ابتدای هر روال سرویس وقفه‌ای محتویات ثبات های همه منظوره ای را که می خواهیم در این روال استفاده کنیم به وسیله دستور push در پشته ذخیره شده و در آخر روال به وسیله دستور pop از پشته بازیابی شود. به این کار ذخیره سازی محتوا گویند. این مورد به طور کلی در مورد پورت ها و ثبات هایی که نیاز است محتوایشان ذخیره شود صدق می کند. می توان به جای پشته از هر فضایی در RAM برای این کار استفاده کرد. برای چگونگی استفاده از دستورات push و pop می توانید این مقاله را مطالعه کنید.

روال سرویس وقفه برنامه ای است که توسط برنامه نویس نوشته می شود تا عملیاتی را با ایجاد وقفه انجام دهد. اما چرا این برنامه را در آدرسی که مربوط به بردار وقفه است نمی نویسیم؟

آدرس های بردار وقفه فقط ۲ بایت فضا دارند. پس باید ISR را در محل دیگری نوشت و آدرس آن را در محل بردار وقفه قرار داد.

مواردی که در مورد پشته و دستورات push و pop و نوشتن ISR در آدرسی دیگر گفته شد مخصوص زبان اسمبلی می باشد. اما در زبان C کامپایلر این کارها را مدیریت می کند و نیازی به نگرانی برنامه نویس وجود ندارد. تنها کافی است یک تابع برای روال وقفه نوشته شود.

شاید بپرسید در صورتی که در طول پردازش روال سرویس وقفه‌ای، وقفه‌ی دیگری رخ دهد چه اتفاقی می افتد؟

در جواب این سوال باید بگویم که این بستگی به برنامه نویس و دستورات موجود در روال سرویس وقفه جاری دارد. همان طور که گفتم در صورت ایجاد وقفه، AVR به طور اتوماتیک بیت فعال ساز وقفه‌ی عمومی را پاک می کند. اگر ما بخواهیم در حین سرویس دهی به یک وقفه، وقفه‌ی دیگری در صورت ایجاد سرویس دهی شود باید در روال سرویس وقفه‌ی قبلی بیت فعال ساز وقفه عمومی را یک کنیم. اما باید چنین کاری با احتیاط انجام شود چون ممکن است باعث گیر کردن برنامه درون یک  وقفه شود. مثلا اگر یک وقفه‌ی خارجی حساس به سطح فعال باشد و بیت I در حالی که هنوز پایه وقفه در حالت تحریک است، یک شود باعث می شود تا به طور بی نهایت وارد ISR شده و سرریز پشته و اتفاقات غیر قابل پیش بینی رخ دهد. در ادامه درباره وقفه‌ی خارجی و حساس به سطح صحبت می کنیم.

لازم به ذکر است که بیت وقفه‌ی اختصاصی یک وسیله جانبی در صورت درخواست وقفه توسط آن وسیله و پرش به جدول بردار وقفه برخلاف بیت فعال ساز وقفه‌ی عمومی هیچ تغییری نمی کند.

اولویت وقفه

ممکن است این سوال در ذهن شما ایجاد شود که اگر دو وقفه به طور هم زمان رخ دهند به کدام وقفه پاسخ داده می شود؟ در جواب باید بگوییم که در جدول بردار وقفه، هر وقفه‌ای که آدرس کمتری دارد(هر چه در جدول بالاتر باشد) اولویت بیشتری هم در پاسخگویی خواهد داشت. پس در صورت وقوع چنین حالتی آن وقفه‌ای که اولویت بالاتری دارد پاسخ داده خواهد شد.

وقفه‌های خارجی

بعد از توضیح موارد کلی و اصول وقفه‌ها حال وقفه‌های خارجی را به صورت خاص بررسی می کنیم.

یک وقفه‌ی خارجی در اثر سیگنالی از یک وسیله جانبی خارج از میکرو که وارد پایه خاصی از میکرو می شود اتفاق می افتد. برای مثال در میکروکنترل ATMEGA32 سه پایه برای وقفه‌ی خارجی با نام های INT0 ,INT1 ,INT2 وجود دارد که به ترتیب روی پین های PD2  و PD3 و PB2 قرار گرفته اند.

هر پایه در میکرو ممکن است برای چند کاربرد طراحی شده باشد که می توان در یک زمان از یک قابلیت آن طبق نیاز استفاده کرد. از سه پایه ای که برای سه وقفه خارجی استفاده می شوند به عنوان ورودی و خروجی معمولی هم می توان استفاده کرد. برای اینکه بتوانیم از هرکدام از این پایه ها به عنوان وقفه خارجی استفاده کنیم باید در رجیسترهای مربوطه تنظیمات خاصی را انجام دهیم که در ادامه توضیح داده می شود.

رجیستر GICR

نام این رجیستر از Global interrupt control register گرفته شده است. با استفاده از بیت های شماره ۵، ۶ و ۷ که در تصویر زیر قابل مشاهده است می تواند قابلیت پاسخ گویی به وقفه های خارجی ۰ تا ۲ را فعال کرد. INT0 برای وقفه خارجی صفر استفاده می شود و سایر وقفه های خارجی نیز به همین ترتیب فعال می شوند. البته باید توسط رجیستر SREG بیت فعال ساز وقفه عمومی فعال شود و توسط رجیستر MCUCR حساسیت به لبه یا سطح مشخص شود که در ادامه توضیح داده می شود.

بیت های ۲ تا ۴ رزرو هستند و از آن ها استفاده ای نمی شود. بیت ۰ و ۱ نیز برای تغییر مکان بردارهای وقفه مورد استفاده قرار می گیرد که خارج از بحث جلسه امروز است.

رجیستر MCUCR

نام این رجیستر از MCU Control register گرفته شده است.

همان طور که گفتیم، وقفه های سخت افزاری یا حساس به سطح هستند یا حساس به لبهبا تنظیم بیت های رجیستر MCUCR می توان نوع حساسیت را تعیین کرد. برای INT0 از بیت های ۰ , ۱ و برای INT1 از بیت های ۲ و ۳ استفاده می شود. در تصویر زیر این رجیستر را مشاهده می کنید:

درتصویر زیر نحوه تنظیم حساسیت به سطح یا لبه برای INT0 توضیح داده شده است:

تمام موارد گفته شده درباره INT0 در مورد INT1 هم صدق می کند.برای تنظیم نوع حساسیت INT1کافیست در جدول بالا بیت های ISC10 و ISC11 را به همین شیوه برای INT1 اعمال کنید.

رجیستر MCUCSR

نام این رجیستر از MCU Control and Status Register گرفته شده است.

نحوه حساسیت وقفه‌ی خارجی دو یا INT2 در ATMEGA32 توسط بیت ISC2 در ثبات MCUCSR تنظیم می شود. وقفه‌ی خارجی دو فقط در دو حالت تنطیم می شود.

  • اگر ISC2 صفر باشد INT2 حساس به لبه پایین رونده می شود.
  • اگر ISC2 یک باشد INT2 حساس به لبه بالا رونده می شود.

رجیستر GIFR

نام این رجیستر از Global interrupt flag register گرفته شده است. این رجیستر پرچم وقوع وقفه‌های خارجی است. هر وقت یک وقفه‌ی خارجی رخ دهد، پرچم متناظر با آن یک می شود. همان طور که در شکل زیر می بینید، پرچم متناظر با وقفه‌ی خارجی صفر INTF0 است و برای وقفه‌های یک و دو نیز به همین ترتیب.

اما نکته ی مهمی که در رابطه با این پرچم ها وجود دارد صفر شدن آن ها است. اگر پاسخ گویی به وقفه را فعال کرده باشیم، با وقوع وقفه و پرش به آدرس بردار وقفه، پرچم متناظر هم صفر می شود. اما اگر به صورت نرم افزاری بخواهیم آن را صفر کنیم باید روی آن ۱ نوشته شود. این قانون برای تمامی پرچم های AVR صادق است.

مثال:

فرض کنید در میکروکنترلر ATmega32 پایه INT0 به یک کلید فشاری متصل است. برنامه ای بنویسید که با فشرده شدن کلید فشاری، LED متصل به پایه صفر PORTA  روشن شود و در صورت رها شدن کلید فشاری LED خاموش شود.

زبان C در کدویژن:

برای دیدن این کد باید عضو باشید. با مراجعه به قسمت حساب کاربری در ستون سمت چپ با نام کاربری خود وارد شوید یا ثبت نام کنید.

توصیه می شود برای تمرین بیشتر مباحث امروز حتما پروژه وقفه، که مربوط به یک رقص نور می باشد را تمرین کنید. برای مشاهده این مقاله اینجا کلیک کنید.

جلسه منابع وقفه هم به پایان رسید. چند باری مرور لازمه تا خوب بهش مسلط بشید. البته برای وقفه‌ها داخلی می تونید به پست های تایمرها، ارتباط سریال، پروتکل SPI، پروتکل I2C و مبدل آنالوگ به دیجیتال سری بزنید و با وقفه‌ها داخلی هم آشنا بشید. البت اصول کلی اون ها به همین شکل هست. در آخر اگه ما رو از طریق لینک شبکه های اجتماعی که همین پایین وجود داره به دوستاتون معرفی کنید خیلی کارتون بیسته. 😉

درباره‌ی احسان

کارشناس الکترونیک و کارشناس ارشد مخابرات سیستم | زمینه ی تحقیقاتی : هوش مصنوعی و شبکه های عصبی عمیق (CNN)، پردازش تصویر و ویدیو، تعقیب اشیا متحرک |‌برنامه نویس میکروکنترلرهای AVR و ARM و بردهای رزبری پای | مسلط به زبان های برنامه نویسی C و Python

۳۲ ديدگاه

  1. سلام. تمامی تصویرها قابل مشاهده نمی باشند. ممنون از اینکه دانش خودتون را به اشتراک می گذارید.

  2. سلام برای من هنوز تصویرها نیومدن !!

پاسخ دهید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

Time limit is exhausted. Please reload CAPTCHA.