در این آموزش نحوه پیکرهبندی و مدیریت وقفهها را با استفاده از فریمور میکروپایتون و با برد ESP32 و ESP8266 یاد میگیرید. برای مثال، یک پروژه با سنسور حرکت PIR خواهیم ساخت.
پیشنیازها
برای دنبال کردن این آموزش، نیاز دارید که فریمور میکروپایتون در برد ESP32 یا ESP8266 فلش شده باشد. همچنین برای نوشتن و آپلود کد در بردتان به یک IDE نیاز دارید. ما پیشنهاد میکنیم از Thonny IDE یا uPyCraft IDE استفاده کنید.
معرفی وقفهها
وقفهها برای ایجاد اتفاقات خودکار در برنامه های میکروکنترلر مفید هستند و میتوانند به حل مشکلات زمانبندی کمک کنند. با وجود وقفهها نیازی به بررسی مداوم مقدار پین فعلی نیست. هنگامی که تغییری تشخیص داده میشود ، یک رویداد فعال میشود.(یک تابع فراخوانی میشود)
همانطور که در شکل میبینید، زمانی که یک وقفه ایجاد میشود، پردازنده اجرای برنامه اصلی را برای اجرای یک کار متوقف میکند و سپس به برنامه اصلی برمیگردد.
وقفه برای شروع یک فرآیند وقتی حرکتی تشخیص داده میشود و یا وقتی دکمه فشاری فشار داده میشود بدون نیاز به بررسی مداوم وضعیت آن، کارآمد است.
پینهای وقفه ESP32: تمام GPIOها میتوانند برای وقفه استفاده شوند به جز GPIO 6 تا GPIO 11.
پینهای وقفه ESP8266: تمام GPIOها میتوانند برای وقفه استفاده شوند به جز GPIO 16
تنظیمات یک وقفه در میکروپایتون
برای تنظیمات وقفه در میکروپایتنون، مراحل زیر را طی کنید.
۱- یک تابع مدیریت وقفه را تعریف کنید. تابع مدیریت وقفه باید تا حد ممکن ساده باشد؛ بنابراین پردازنده سریعا به اجرای برنامه اصلی باز میگردد. به عنوان مثال، بهترین رویکرد این است که با استفاده از یک متغیر global به کد اصلی که وقفه رخ داده است، سیگنال بدهید. تابع مدیریت وقفه پارامتری از نوع Pin را میپذیرد. این پارامتر به تابعی که بازفراخوانی میشود، برمیگردد و به GPIO که باعث وقفه شده است، اشاره دارد.
def handle_interrupt(pin):
۲- GPIO که به عنوان پین وقفه عمل میکند را به عنوان ورودی تنظیم کنید. برای مثال:
pir = Pin(14, Pin.IN)
۳- با فراخوانی تابع ()irq، وقفه را به آن پین اختصاص دهید.
pir.irq(trigger=Pin.IRQ_RISING, handler=handle_interrupt)
تابع ()irq آرگومانهای زیر را میپذیرد:
- trigger: حالت فعال شدن وقفه را مشخص میکند. سه حالت مختلف وجود دارد:
Pin.IRQ_FALLING: برای فعال کردن وقفه وقتی که پین از HIGH به LOW میرود.
Pin.IRQ_RISING: برای فعال کردن وقفه وقتی که پین از LOW به HIGH میرود.
۳: برای فعال کردن وقفه در هر دو حالت HIGH به LOW و LOW به HIGH. (یعنی وقتی که تغییری تشخیص داده میشود) - handler: تابعی است که زمانی که وقفه تشخیص داده میشود، فراخوانی میشود. در اینجا تابع ()handle_interrupt
مثال پروژه با سنسور PIR
برای نمایش عملی چگونگی مدیریت وقفهها، یک پروژه ساده با سنسور حرکت PIR میسازیم. هر وقت که حرکتی تشخیص داده شود، یک LED به مدت ۲۰ ثانیه روشن میشود.
قطعات مورد نیاز
لیستی از قطعاتی که برای ساخت مدار نیاز دارید:
ESP32 یا ESP8266
LED 5 mm
مقاوت ۳۳۰ اهم
سنسور حرکت (AM312) Mini PIR یا سنسور حرکت PIR (HC-SR501)
بردبرد
سیم جامپر
شماتیک – ESP32
اگر از برد ESP32 استفاده میکنید، از دیاگرام شماتیک زیر استفاده کنید.
شماتیک – ESP8266
اگر از برد ESP8266 استفاده میکنید، از دیاگرام شماتیک زیر استفاده کنید.
توجه: در این پروژه ما از سنسور حرکت Mini AM312 PIR استفاده میکنیم که در ۳.۳ ولت عمل میکند. اگر شما از سنسور حرکت دیگری مانند HC-SR501 استفاده میکنید، در ۵ ولت عمل میکند. شما میتوانید عملکرد آن را به ۳.۳ ولت هم تغییر دهید و یا به سادگی از پین Vin تغذیه بگیرید.
در شکل زیر، ما pinout سنسور حرکت Mini AM312 PIR را نشان میدهیم. اگر از سنسور حرکت دیگری استفاده میکنید، پیش از بستن مدار pinout آن را چک کنید.
کد
اسکریپت زیر حرکت را تشخیص میدهد و زمانی که حرکت تشخیص داده شود، یک LED روشن میشود. این کد با هر دو برد ESP32 و ESP8266 سازگار است.
from machine import Pin
from time import sleep
motion = False
def handle_interrupt(pin):
global motion
motion = True
global interrupt_pin
interrupt_pin = pin
led = Pin(12, Pin.OUT)
pir = Pin(14, Pin.IN)
pir.irq(trigger=Pin.IRQ_RISING, handler=handle_interrupt)
while True:
if motion:
print('Motion detected! Interrupt caused by:', interrupt_pin)
led.value(1)
sleep(20)
led.value(0)
print('Motion stopped!')
motion = False
کد چگونه کار میکند
برای استفاده از وقفهها، کلاس Pin از ماژول machine را وارد کنید. همچنین برای اضافه کردن تاخیر، متد sleep از ماژول time را وارد کنید.
from machine import Pin
from time import sleep
یک متغیر با نام motion بسازید که میتواند True یا False باشد. این متغیر نشان میدهد که حرکتی تشخیص داده شده است یا خیر.( این متغیر global است و در تابع مدیریت تابع تغییر خواهد کرد)
motion = False
سپس، یک تابع با نام handle_interrupt بسازید.
def handle_interrupt(pin):
global motion
motion = True
global interrupt_pin
interrupt_pin = pin
این تابع زمانی فراخوانی میشود که حرکتی تشخیص داده شود. تابع handle_interrupt یک پارامتر ورودی (pin) که یک شی از کلاس Pin است دارد و وقتی ارسال میشود که وقفه رخ دهد.(مشخص میکند کدام پین باعث وقفه شده است)
ما پینی که باعث وقفه شده است را در متغیر interrupt_pin ذخیره میکنیم. در اینجا خیلی کارآمد نیست چون ما فقط یک پین وقفه داریم. با این حال اگر چندین وقفه داشته باشیم که تابع وقفه یکسانی را فعال کنند و بخواهیم بدانیم کدام GPIO باعث وقفه شده است، مفید است.
در مثال ما، تابع handle_interrupt به سادگی متغیر motion را به True تغییر میدهد و پین وقفه را ذخیره میکند. تابع مدیریت وقفه شما باید تا حد امکان کوتاه باشد و داخل آن از تابع ()print استفاده نکنید. سپس، کد اصلی باید همه مواری که میخواهیم هنگام وقفه رخ دهد را داشته باشد.
توجه: اگر شما میخواهید متغیر motion داخل تابع و در تمام کد قابل استفاده باشد، نیاز است که به صورت global (سراسری) تعریف شود. در غیر این صورت، وقتی حرکتی تشخیص داده میشود، هیچ اتفاقی نمیافتد؛ چون متغیر motion فقط داخل تابع تغییر میکند، نه در بدنه اصلی کد.
در ادامه کد، باید دو آبجکت (شی) Pin ایجاد کنیم؛ یکی از برای LED در GPIO 12 و دیگری برای سنسور حرکت PIR در GPIO 14.
led = Pin(12, Pin.OUT)
pir = Pin(14, Pin.IN)
سپس با فراخوانی متد ()irq، یک وقفه در pir تظینم کنید.
pir.irq(trigger=Pin.IRQ_RISING, handler=handle_interrupt)
در ()loop، وقتی متغیر motion مقدار True دارد، LED را برای ۲۰ ثانیه روشن میکنیم و یک پیغام چاپ میکنیم که حرکت تشخیص داده شده است و کدام پین باعث وقفه شده است.
if motion:
print('Motion detected! Interrupt caused by:', interrupt_pin)
led.value(1)
sleep(20)
بعد از ۲۰ ثانیه، LED را خاموش کرده و پیغامی را چاپ کنید که نشان دهد حرکت متوقف شده است.
led.value(0)
print('Motion stopped!')
در آخر متغیر motion را False تنظیم کنید.
motion = False
متغیر motion تنها زمانی میتواند دوباره True َشود که حرکت تشخیص داده شود و تابع handle_interrupt فراخونی شود.
برای سادگی، در این مثال برای اینکه LED به مدت ۲۰ ثانیه روشن شود، از تاخیر استفاده کردیم. در حالت ایدهآل، باید از تایمرها استفاده کنید.
نمایش عملی
کد را در برد ESP32/ESP8266 آپلود کنید. وقتی حرکت تشخیص داده میشود، LED باید ۲۰ ثانیه روشن و پیغام نیز در Shell چاپ شود.
پس از ۲۰ ثانیه LED خاموش میشود.
توجه مهم : سنسور حرکت AM312 PIR به صورت پیشفرض زمان تاخیر ۸ ثانیه دارد. یعنی اگر ۸ ثانیه از آخرین باری که فعال شده است نگذشته باشد، مجددا فعال نمیشود.
جمعبندی
امیدواریم این آموزش برای شما جالب بوده باشد. در این آموزش یاد گرفتیم چگونه:
یک پین را به عنوان وقفه تنظیم کنیم.
وقفه در کد را مدیریت کنیم.
تشخیص دهیم کدام GPIO باعث وقفه شده است.
در این مثال، برای فعالسازی وقفه ما از سنسور حرکت PIR استفاده کردیم. این مثال میتواند برای تشخیص فشار دادن دکمه فشاری نیز استفاده شود.
عالی بود
سلام . ممنون دوست عزیز