وقفه یا اینتراپت Interrupt برای مدیریت بخشی از برنامه در پایتون و میکروپایتون فراخوانی میشود. تصور کنید چندین کلید برای فرمان به یک خروجی لامپ در محلی تعبیه شده است. اگر هر شخص به صورت چداگانه کلید را بزند، پردازنده بایستی به روش پولینگ Polling مدام بررسی کند که کدام کلید زده شده است و به همین روش تمامی منابع میکروکنترلر مصرف میشود. اما راه حل جایگزین چیست؟ در ادامه به معرفی و کاربرد تابع وقفه در برنامه نویسی میکروپایتون خواهیم پرداخت. در ادامه وقفه میکروپایتون با مرجع تخصصی میکروپایتون با رزبری پای به زبان فارسی، دیجی اسپارک همراه باشید.
کاربرد Handler Interrupt
Interrupt Handler یک فانکشن پایتون است که زمانی فراخوانی میشود که یک عملی را انجام داده شود. ISR بهترین راه برای شناسایی این رخدادهای خارجی هستند و در مقایسه با متد پولینگ Polling که ناکارآمد است، ارجحیت داده میشود. در روش پولینگ polling تصور کنید، یک کلید و یک ال ای دی دارید، برای مدیریت هر کلید بایستی مدام بررسی کند که آیا کلید زده شده است یا خیر و با تکرار اینکار مدام منابع میکروکنترلر مصرف خواهد شد. در روش Interrupt هر کلید پس از تغییر وضعیت، وضعیتش را به CPU اطلاع میدهد و سرعت انتقال پیام بسیار بالا است.
معرفی تابع وقفه Handler Interrupt
جهت معرفی تابع وقفه در کد میکروپایتون در برد رزبری پای پیکو بایستی ۳ اصل را رعایت و با توجه به نیاز پروژه در کد اضافه کنیم. متد IRQ که مخفف Interrupt Request است، به اولویت پاسخ دهی به درخواست ها جهت پردازش توسط CPU اشاره میکند. با فراخوانی متد IRQ به پردازنده اعلام میکنیم به تمامی درخواست های ارسالی واکنش نشان داده و بر اساس نوع درخواست تریگر کند. چهار روش برای تریگر پایه وقفه در کد برنامه قابل تعریف است.
def handler_Interrupt(pin) input = Pin(2, Pin,IN) input.irq(trigger = Pin.IRQ_RISING, or trigger = Pin.IRQ_FALLING, or trigger = Pin.IRQ_LOW_LEVEL, or trigger =Pin.IRQ_HIGH_LEVEL trigger= Pin.IRQ_FALLING || Pin.IRQ_RISING, handler = handler_Interrupt)
- LEVEL HIGH
- LEVEL LOW
- POSITIVE EDGE
- NEGATIVE EDGE
- تریگر در لبه بالارونده RISING
اگر بخواهیم وقفه زمانی رخ دهد که سطج پالس پین از LOW به HIGH حرکت کند و تغییر کند از RISING EDGE استفاده میکنیم. روش فراخوانی به صورت زیر است:
Pin.IRQ_RISING
- تریگر در لبه پایین رونده FALLING
اگر بخواهیم وقفه زمانی رخ دهد که سطج پالس پین از HIGH به LOW حرکت کند و تغییر کند از FALLING EDGE استفاده میکنیم. روش فراخوانی به صورت زیر است:
Pin.IRQ_FALLING
- تریگر در لبه بالارونده یا پایین رونده
اگر بخواهیم وقفه زمانی رخ دهد که سطج پالس هر تغییری را تشخیص داد، به عنوان وقفه شناسایی کند، از هردو استفاده خواهیم کرد:
Pin.IRQ_FALLING || Pin.IRQ_RISING
- تریگر در سطح صفر LOW
اگر بخواهیم وقفه در سطح صفر LOW رخ دهد، به صورت زیر تعریف میکنیم:
Pin.IRQ_LOW_LEVEL
- تریگر در سطح VCC HIGH
اگر بخواهیم وقفه در سطح VCC HIGH رخ دهد، به صورت زیر تعریف میکنیم:
Pin.IRQ_HIGH_LEVEL
آرگومنت بعدی فراخوانی تابع وقفه نوشته شده است که به صورت زیر اضافه میشود:
handler: Handler_Interrupt()
تست کد وقفه در میکروپایتون
جهت تست از Thonny IDE استفاده خواهیم کرد. برد رزبری پای پیکو را به سیستم متصل کرده و از نصب فریمور میکروپایتون بر روی برد اطمینان داشته باشد. سپس کد را کپی و به IDE انتقال دهید. سپس آن را با یک نام و پسوند py در کامپیوتر یا رزبری پای پیکو ذخیره و اجرا کنید. برای تست به یک کلید نیاز داریم. کلید را به پایه شماره GP14 از برد رزبری پای پیکو متصل کنید.
from machine import Pin import time buttonstate = 0 def handler_interrupt(change): global buttonstate buttonstate +=1 button= Pin(14, Pin.IN) button.irq(trigger = Pin.IRQ_FALLING, handler = handler_interrupt) lastbutton = 0 while True: if lastbutton != buttonstate: print('button', buttonstate) lastbutton = buttonstate
تحلیل کد میکروپایتون وقفه
در قدم اول بایستی از ماژول machine پایه Pin را فراخوانی کنیم. برای زمان بندی به Time نیاز داریم.
from machine import Pin import time
هدف در این کد این است که با هر بار زدن کلید، .وقفه رخ داده و یک واحد به عدد قبلی کلید اضافه کرده و تعداد کلیک شدن را شمارش کند. برای این منظور یک متغیر برای وضعیت کلید در برنامه تعریف میکنیم.
buttonstate = 0
مهترین بخش نوشتن تابع وقفه برای معرفی Interrupt به برنامه است. تابع وقفه را در برنامه وارد میکنیم.
def handler_interrupt(change): global buttonstate buttonstate +=1 button= Pin(14, Pin.IN) button.irq(trigger = Pin.IRQ_FALLING, handler = handler_interrupt) lastbutton = 0
در قدم بعدی میخواهیم با هر بار زدن کلید، وضعیت جدید اضافه شده و سپس یک واحد به مقدار قبلی اضافه کرده و هر بار وضعیت کلید را آپدیت کند.
while True: if lastbutton != buttonstate: print('button', buttonstate) lastbutton = buttonstate
برای تست برنامه کلید را به صورت زیر به یکی از پایه های رزبری پای پیکو متصل کنید.
به روز رسانی کد وقفه میکروپایتون
با اجرای کد متوجه خواهید شد که در بعضی مواقع پالس از حالت پایدار به حالت ناپایداری میرسد و ممکن است تا رسیدن به سطح پایدار بعدی مدت زمانی سپری شود که عملا در روند اجرای پروژه نویز و خطا ایجاد میکند. برای رفع این مشکل بایستی از بازه ی زمانی استفاده کنیم. زمان رو محاسبه کرده و سپس شمارشگر بر حسب میلی ثانیه را برمیگرداند.
import utime from machine import Pin buttonstate = 0 lasttime = 0 button = Pin(16, Pin.IN, Pin.PULL_DOWN) def button_pressed_handler(pin): global buttonstate, lasttime newtime = utime.ticks_ms() if (newtime - lasttime) > 200: buttonstate +=1 lasttime = newtime button.irq(trigger=Pin.IRQ_FALLING, handler = button_pressed_handler) lastpress = 0 while True: if lastpress != buttonstate: print('button', buttonstate) lastpress = buttonstate
مجدد کد را بررسی کنید. با هر زدن کلید، یک عدد به کلید اضافه شده و تعداد دفعات کلیک شدن بر روی shell نمایش داده میشود. مدت زمان شروع را محاسبه کردیم و سپس ۲۰۰ میلی ثانیه فرصت داده شد، تا توسط پردازنده بررسی شود، آیا کلید فشرده شده است یا خیر و سپس اقدامات بعدی صورت گیرد.
اتصال کلید به رزبری پای پیکو
جهت اتصال کلید به رزبری پای پیکو همانند تصویر کلید را در مرکز برد بورد قرار دهید. سپس پایه اول از سمت چپ را به پایه ۳٫۳ ولت رزبری پای پیکو متصل کنید. پایه کناری در همان ردیف کلید را با یک سیم دیگر به پایه GP که در کد مشخص کرده اید، متصل کنید.
وسایل مورد نیاز
جمع بندی لیدی پای
در بخش دهم از سری آموزش های میکروپایتون با رزبری پای پیکو یکی از سرفصل های مهم در کدنویسی میکروکنترلرها یعنی اجرای وقفه را تست و اجرا کردیم.عملا بدون استفاده از وقفه کدی که برای اجرای یک تسک در برنامه مینویسیم ممکن است با خطاهای بسیاری رو به رو باشد و هیچ وقت متوجه روش حل مشکل نشویم. با وارد کردن تابع وقفه در برنامه و استفاده از بازه های زمانی عملکرد ورودی و خروجی دقیق تر شده و منابع کمتری از CPU به هدر خواهد رفت.
چنانچه در مراحل راه اندازی و انجام این پروژه با مشکل مواجه شدید، بدون هیچ نگرانی در انتهای همین پست، به صورت ثبت نظر سوالتان را مطرح کنید. من در سریعترین زمان ممکن پاسخ رفع مشکل شما را خواهم داد. همچنین اگر ایرادی در کدها و یا مراحل اجرایی وجود دارند میتوانید از همین طریق اطلاع رسانی کنید.
کاربرد وقفه در میکروپایتون با کاری که در آردوینو میکردیم یکی هست؟
با سلام
از نظر مفاهیم یکسان است اما برای فراخوانی تابع ها متفاوت هستند.
سلام
یکی از سخت ترین کارها برای میکروپایتون ایجاد اینتراپت در برنامه برای من بود چون سورسی وجود نداره و حتی سایت اصلی هم یک نمونه پروژه نداره و هیچوقت تست نکردم بابت انتشار این آموزش ممنونم
با سلام
کاربر گرامی سپاس از همراهی شما
امیدوارم مفید واقع شده باشد.
سلام خانم مهندس
این کد را تست کردم اما با هر باز کلیک کردن، به جای یک بار شمارش متغیر بین ۲ تا ۳ تا حساب میشود.
با سلام
در این خصوص دو کد در برنامه ضممیه شده است که کد دوم اصلاح شده است و میتوانید با اضافه کردن بازه زمانی باگ ورودی را برطرف کنید.
عالی خسته نباشید
با سلام
سپاس از همراهی شما کاربر گرامی
با سلام همیشه استم تابع باید همین باشه؟ چون من تغییر دادم اما ارور داد!
با سلام
خیر میتوانید از هر اسمی استفاده کنید دقت داشته باشید در تابع وقفه هم بایستی اسم را تغییر دهید.
سلام
آیا همین کد را میشه با سنسور تاچ هم اجرا کرد؟
با سلام
بله تفاوتی در اجرا وجود ندارد.
سلام
لطفا پروژه های بیشتری با میکروپایتون منتشر کنید.
با سلام
سپاس از همراهی شما کاربر گرامی
حتما آموزش های جدید منتشر خواهد شد.
از کجا در پروژه باید تشخیص بدیم که از کدام سطح ترگیر باید استفاده کنیم؟
با سلام
این مورد تنها وابسته به نیاز پروژه است.