آموزش وقفه ها در AVR به زبان C قسمت ۱۰

وقفه ها در میکروکنترلر ها برای واکنش لحظه ای برای برخی وقایع طراحی شده اند.

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

وقفه ها در میکرو کنترلر به دو دسته وقفه های داخلی و خارجی تقسیم می شود و با توجه به نوع میکرو تعداد آن ها متفاوت می باشد،مراحل اجرای یک وقفه بصورت زیر است:

وقتی وقفه ها فعال باشد و وقفه ای رخ دهدمیکرو عملیات زیر را بصورت خودکار انجام میدهد:

دستوری که در حال اجرا باشد کامل شده و ادرس دستور بعدی ذخیره میشود

یافتن آدرس وقفه و انجام دستورات نوشته شده برای وقفه مورد نظر تا پایان

خواندن آدرس ذخیره شده مرحله اول و ادامه اجرای برنامه

در جدول زیر تعداد و نوع وقفه های میکرو کنترلر Atmega32 را مشاهده میکنید:

برای نمایش در ساز بزرگتر بر روی عکس کلیک کنید

وقفه ها در مگا 32
وقفه ها در مگا ۳۲

Atmel Mega32 Pin

همان طور که مشاهده میکنید این میکرو دارای ۲۱ وقفه داخلی و خارجی می باشد مثلا هنگامی که وقفه INT0 رخ دهد (پایه ۱۶ میکرو تحریک شود) CPU به آدرس ۰۰۱H مراجعه کرده و برنامه را از آن خط اجرا خواهد کرد در آدرس مورد نظر حداکثر ۱ بایت برای برنامه در نظر گرفته شده که میتوان با دستور اسمبلی LJMP برنامه را در نقطه ای دیگر از حافظه ادامه داد.

در این آموزش خود را با دستورات اسمبلی و آدرس های وقفه درگیر نخواهیم کرد و با تنظیم رجیستر های وقفه براحتی به نوشتن برنامه خواهیم پرداخت

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

رجیستر GICR در مگا ۳۲

mega32GICR

با یک کردن بیت ۵ و ۶ و۷ رجیستر فوق وقفه های فوق که به پایه ها ۱۷ و ۱۶ و ۲ میکرو متصل هستند فعال خواهند شد.

وقفه های فوق وقفه های خارجی میکرو هستند که باید تنظیمات دیگری نیز روی آن انجام داد بطور مثال هنگامی که وقفه INT0 فعال شد چهار حالت را برای اجرای وقفه می توان برای آن تنظیم کرد:

۱ – وقتی پایه مورد نظر در سطح low level(به خط GND وصل) باشد.

۲-وقتی که یک لبه بالا رونده به پایه اعمال شود.

۳- وقتی که یک لبه بالا رونده اعمال شود.

۴- وقتی که هر نوع تغییری روی پایه مورد نظر اعمال شود.

این تنظیمات در ریجستر های زیر می باشد:

تنظیمات مربوط به INT0 و INT1 که به ترتیب به پایه های ۱۶ و ۱۷ میکرو متصل هستند در اینجا فقط با چهار بیت اول سروکار خواهیم داشت و بیت های ۴ الی ۷ کاری نداریم:

int0int1

همان طور که دیدید int0 و int1 دارای چهار حالت بودن اما INT2 فقط دارای دو حالت میباشد یعنی یا با لبه پایین رونده و یا با لبه بالا رونده ولتاژ فعال خواهد شد این تنظیم در رجیستر MCUCSR بیت ششم می باشدint2

همان طور که در جدول فوق مشاهده می کنید اگر در بیت ISC2 صفر نوشته شود وقفه با لبه پایین رونده فعال خواهد شد و اگر یک نوشته شود با لبه بالا رونده فعال خواهد شد.

رجیستر General Interup Flag) GIFR)

GIFR

۳ بیت آخر این رجیستر پرچم وقفه خارجی وقفه های INT0 و INT1 و INT2 می باشد . در زمان وقوع وقفه پرچم مربوطه در این رجیستر فعال میشود.

حال بعد از یاد گیری رجیستر ها شروع به برنامه نویسی در کدویژن میکنیم

در کد ویژن برای نوشتن زیر برنامه وقفه باید برنامه بصورت زیر نوشته شود:

در کد بالا باید به جای Vector No شماره وقفه مورد نظر که در جدول وقفه ها که در ابتدای همین صفحه موجو می باشد نوشته شود و بجای function_name یک نام اختیاری برای تابع انتخاب شود.

 

مثال ها:

می خواهیم برنامه ای بنویسیم که زمانی که وقفه INT0 فعال شد یک LED را روشن و خاموش کنیم:

اول از همه طبق آموزش های قبل یک پروژه ایجاد کرده و کد زیر را مینویسیم:

توضیحی کوتاه در مورد برنامه بالا: پس از وارد کردن فایل هدر میکرو و فایل هدر تاخیر پایه خروجی که به یک LED وصل شده است را تعریف کردیم(پایه PORTB.0)

سپس در خط ۱۱ وقفه INT0 را فعال کردیم

در خط ۱۲ با توجه به Table35 در بالای همین صفحه وقفه را به لبه بالا رونده سیگنال حساس کردیم

در خط ۱۳ پرچم وقفه INT0 را فعال کردیم

در خط ۱۶ با دستور اسمبلی sei سیستم وقفه ها را فعال کردیم.

در خط ۲۲ تابع وقفه را نوشته ایم همان طور که در جدول ابتدای صفحه مشاهده میکنید عدد ۲ مربوط به INT0 هست که بجای Vector No قرار دادیم و نام تابع را Myfunc_int0 قرار داده ایم.

در خط ۲۴ سیستم وقفه را خاموش کرده ایم تا برنامه دچار مشکلات احتمالی نشود سپس LED را با تاخیر ۵۰۰ میلی ثانیه روشن و خاموش کرده و دوباره وقفه ها را فعال کردیم

شماتیک بصورت زیر است:

با اجرای کد بالا در فایل شبیه سازی شده با فشار دادن کلید سطح ولتاژ پایه ۱۶ از صفر ولت به ۵ ولت تغییر کرده و یک لبه بالا رونده ایجاد می شود که باعث فعال شدن وقفه شده و برنامه به زیربرنامه مورد نظر پرش میکند که در زیربرنامه LED چشمک خواهد زد.

این پروژه با فایل شبیه سازی پروتئوس در آخر این آموزش جهت دانلود موجود است.

sample1

مثال دوم:

در این مثال هرسه وقفه خارجی میکرو را به صورت زیر فعال کرده ایم:

INT0:این وقفه زمانی رخ خواهد داد که پایه مورد نظر در سطح صفر ولت باشد.

INT1: زمانی فعال می شود که  لبه پایین گذر سیگنال به پایه مورد نظر برسد.

INT2: زمانی فعال می شود که  لبه بالاگذر سیگنال به پایه مورد نظر برسد.

در این برنامه هر وقفه شمارش شده و در نمایشگر گرافیکی با درایور KS0108 نمایش داده میشود (راه اندازی این نمایشگر در اینجا آموزش داده شده است)

در ضمن زمانی که وقفه INT0 رخ دهد LED نیز که به پایه ۸ پورت B وصل شده روشن و خاموش خواهد شد.

برنامه واضح و ساده می باشد اما درصورتی مشکل یا سوالی در مورد برنامه بالا دارید از قسمت نظرات مطرح کنید.

شاید برایتان سوال پیش آمده باشد که چرا در برنامه بالا به در vector No بجای عدد حروفی نوشته شده ؟بله این ها متغییر های ثابتی هستند که در فایل هدر میکرو تعریف شده و حاوی همان اعداد می باشند این متغییر ها در خطوط ۸۳ تا ۸۴ فایل mega32a.h بصورت زیر تعریف شده است:

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

sample2

در شکل زیر یک سیگنال سینوسی ۲ هرتز با دامنه ۲ ولت وحداقل ولتاژ ۲ و ولتاژ پیک ۴ ولت به پایه INT1 و INT2 متصل شده و چون وقفهINT1 به هر تغییر سطح ولتاژ حساس شده پس هنگامی که ولتاژ از حدود ۳ ولت پایین بیاد وقفه فعال خواهد شد و هم زمانی که ولتاژ از ۳ ولت بالا رود وقفه فعال خواهد شد ولی چون INT2  فقط به لبه بالا گذر حساس شده ،زمانی موج از ۳ولت شروع به افزایش کند میکرو وقفه مورد نظر را فعال خواهد کرد و چون میکرو وقفه های رخ داده را شمارش میکندتعداد شمارش وقفه یک دو برابر وقفه دوم خواهد بود.

موج سینوسی
موج سینوسی

دانلود این پروژه و پروژه قبلی با فایل شبیه سازی پروتئوس از اینجا (لینک کمکی)

این آموزش به پایان رسید و آموزش وقفه های داخلی مانند وقفه های تایمر های پورت سریال و … در قسمت های بعد در بخش خودشان آموزش داده خواهد شد.

موفق باشید.

28 دیدگاه در “آموزش وقفه ها در AVR به زبان C قسمت ۱۰

      1. سلام خسته نباشید
        میخواستم خواهش کنم اگه امکانش براتون هست اموزش های AVR رو ادامه بدین.
        مطالب این وبسایت به صورت خیلی ساده بیان شده و نسبت به خیلی از دیگر وب سایت ها و کتاب ها یادگیریش سریع تر هست پس اگه امکانش هست این اموزش ها رو ادامه بدین.
        ممنون

  1. باسلام . میخواستم بدونم که تو ساخت میکرو یه برنماه نوشتم که تو اون یه تابع رو به عنوان کتابخانه در هدر کد ها نوشتم و در پایین اینتراپت نوشتم . حالا مشکلم اینه که اون تابع رو کجا بنویسم( دیعنب فراخوانی کنم ؟ ) بالا یا پایین اینتراپت

  2. سلام.خیلی مطلب عالی بود.
    یک سوال داشتم.میخوام برنامه ای بنویسم که led به ترتیب از چپ به راست روشن خاموش بشه و زمانی که یک کلید رو فشار بدم led از راست به چپ بشه.باید از چه دستوری استفاده کنم که AVR پایه کلید رو همیشه چک کنه حتی زمان delay.مچکرم

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

  4. سلام استاد عزیز خسته نباشید
    آیا امکان داره با دستور اینتراپت با زدن یه کلید یه led روشن کرد و فشردن مجدد همان کلید led رو خاموش کرد ؟؟
    اگه میشه لطفا راهنمایی کنید با تشکر

  5. سلام و خسته نباشید و تشکر از مطلبتون.
    یه سوال در زمینه وقفه ها داشتم
    میخواستم بدونم چطور میشه، یه وقفه از همون ابتدای برنامه کار کنه؟
    مثلا میخواستم داخل پروتئوس، زمانیکه کلید از همون ابتدا، فعاله، لامپ، چشمک بزنه. در حالیکه فقط زمانی چشمک زدن رو شروع میکنه که کلید در حین اجرای برنامه زده بشه. نه از همون اول.

  6. سلام و تشکر به خاطر مطالب مفیدتون
    من مشغول نوشتم برنامه ای هستم که با استفاده از کیپد برنامه تعریف شده برای منو های تعریف شده ۱تا۴ انجام میده
    مشکل من اینجاست که مثلا با فشردن کلید ۱ برنامه به منو ۱ میره ولی وقتی میخوام که داخل همون منو از کیپد استفاده کنم جواب نمیده چون برنامه حالت while داره
    کیپد من یه پایه داره که میتونه به int خارجی متصل بشه . من به INT1 وصل کردم .
    باید تو هر منو تابع INT فراخوانی بشه؟
    شکل فراخوانی به شکل ;()interrupt [EXT_INT1] void int1_is هست؟

    1. ۱-بهتره که زیاد از حلقه while استفاده نکنید.
      ۲-نیازی نیست تابع مربوط به int هر منو فراخوانی بشه
      تابع int زمانی که وقفه روی بده خود به خود برنامه هر کجا باشه فراخوانی میشه و دستورات داخل تابع انجام میشه و بر میگرده به ادامه برنامه
      فکر کنم مطلب بالا رو کامل نخوندید

  7. دوستان کد زیر رو یکی توضیح میده به من ایرادش چیه؟

    int c=0;
    char s[12];

    interrupt [EXT_INT0] void ext_int0_isr(void)
    {
    c++;

    }
    #asm(“sei”)

    while (1)
    {
    delay_ms(1000);
    sprintf(s,”%d”,c) ;
    lcd_gotoxy(1,0);
    lcd_puts(s);
    c=0;

    }
    برای روشن کردن یک lcd که به یک پالس مربعی وصله و میخوام بدونم چند تا فرکانس تو ثانیه داره
    ممنون

  8. سلام خیلی عالی بود.
    می خواسم اگه امکان داره لینک تمام جلسات از یک تا اخرین جلسه را در جای از سایتتون جا بدید برا آردیونم همین کا را انجام بدیم با تشکر .

  9. سلام خسته نباشید جدول اولی که گذاشتین مربوط به atmeag32 نیست احتمالا مربوط به atmeag16 است. چونvector No اینتراپت ۲ در این میکرو ۴ است در حالی که تو اون جدول ۱۹ ست.

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

  11. یک موج مربعیبا دوره تناوب۱میکرو ثانیه به کمک تایمر کانتر ایجاددکند که دیوتی ساییکل ان با هر بار قشار دادن یک دکمه متصل ب پورت A0 10درصد افزایش برنامه نوشته شود و رجیستر ها تنظیم شود نوشتن برنامه رو کمک کنید امتحان دارم

    وقفه صفر را ب صورت حساس ب لبه بالا رونده تنظیم کنیدروند در برنامه کد ویژن توضیح داده شود

  12. سلام.
    یه سوالی داشتم در مورد تاخیر.
    من چنتا ال ای دی دارم میی خوام که متفاوت از هم روشن بشن. ولی مشکل اینجاس که وقتی ال ای دی اول روشن می شه تا بر نامه برسه به روشن کردن ال ای دی ۴ تاخیرا باعث می شه که فواصل زمانی بهم بخوره.
    چاره چیه؟ (:unknw:)

  13. هنگ میکنه!
    من داخل اینتراپتم تعریف کردم A++
    بعد داخل while سطراخر تعریف کردم if A من شد صفر led منو خاموش کن اگر یک شد کلا روشن کن ای ای دی رو و دو شد چشمک زن شو و سه شد A منو صفر کن یعنی برگرد اول کد!
    یکم کار میکنه بعد هنگ میکنه مشکل از چیه؟

    1. اینم بگم که تعریف کردم اینتراپتم پایین رونده باشه int0 یعنی وقتی دکمه من از یک به صفر میره A من ++ میشه ولی هنگ میکنه بعد چند بار دکمه رو زدن atmega8

  14. سلام
    خسته نباشید
    ببخشید من تازه کارا AVR شروع کردم میخاستم ب یه بر نامه بنویسم که کلید حساس به لبه بالارونده و پایین رونده باشه یعنی با لبه بالارونده یه LED روشن بشه و با لبه پایین رونده یهLED دیگه ما با دستورات PIN وضعیت قطع و وصل بودن کلید مشخص میکنیم و با متغیر edge که از نوع bitتعریف شده هم وضعیت سطح را مشخص میکنیم با دستور if. چطور میشه این برنامه را نوشت

دیدگاهتان را بنویسید

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