در قسمت قبلی از آموزش وقفه ها در میکروکنترلرها به شرح دقیق عملکرد interrupt پرداختیم.اکنون در این قسمت قصد داریم به آموزش وقفه خارجی در پلت فرم آردوینو بپردازیم ، در ادامه با مرجع تخصصی آردوینو ، دیجی اسپارک همراه باشید.
در صورتی که بخش اول آموزش وقفه را مطالعه ننمودهاید ، به شما پیشنهاد میکنیم قبل از مطالعه این پست ، بخش اول آموزش را در لینک زیر مشاهده کنید.
آموزش وقفه interrupt بخش اول
در قلب هر پردازندهی آردوینو دو نوع وقفه داخلی و خارجی وجود دارد. تعداد وقفههای خارجی در مدل های مختلف آردوینو متفاوت است و تعداد و پینهای آن به صورت میباشد. پینهای وقفه خارجی با پیشوند INT در آردوینو شناخته میشوند.
پینهایی که میتوان از آنها به عنوان پین وقفه استفاده نمود | مدل آردوینو |
۲, ۳ | Uno, Nano, Mini, other 328-based |
۲, ۳, ۱۸, ۱۹, ۲۰, ۲۱ | Mega, Mega2560, MegaADK |
۰, ۱, ۲, ۳, ۷ | Micro, Leonardo, other 32u4-based |
تمام پینهای دیجیتال به جز پین شماره ۴ | Zero |
تمام پینهای دیجیتال | Due |
توضیح توابع
attachInterrupt(interrupt, ISR, mode);
به وسیله این تابع پینهایی از آردوینو که قابلیت استفاده به عنوان وقفه را داردند ، به عنوان وقفه خارجی معرفی میکنیم.
interrupt : شماری وقفه ایست که میخواهیم از آن استفاده کنیم.
تذکر:بهجای آرگمان interrupt باید شماره وقفه را وارد نمود ، نه شمارهی پینی که میخواهیم از آن به عنوان وقفه خارجی از آن استفاده کنیم.
شماره وقفهها در آردوینو به صورت زیر میباشد:
مدل آردوینو | int.0
(وقفه شماره ۰) |
int.1
(وقفه شماره ۱ ) |
int.2
(وقفه شماره ۲ ) |
int.3
(وقفه شماره ۳) |
int.4
(وقفه شماره ۴) |
int.5
(وقفه شماره ۵) |
Uno, Ethernet | ۲ | ۳ | ||||
Mega2560 | ۲ | ۳ | ۲۱ | ۲۰ | ۱۹ | ۱۸ |
۳۲u4 based (e.g Leonardo, Micro) | ۳ | ۲ | ۰ | ۱ | ۷ | |
Due, Zero | (see below) |
آردوینو Due درر وقفههای خارجی بسیار قدرتمند عمل میکند و میتوان از ۵۴ پین ورودی/خروجی دیجیتال آن به عنوان وقفه خارجی استفاده نمود.
آردوینو Zero نیز همانند آردوینو Due میباشد با این تفاوت که از پین شماره ۴ آن نمیتوان به عنوان وقفه خارجی استفاده نمود.
برای دو آردوینو Due و Zero میتوان مستقیما از شماره پین به جای آرگمان interrupt در هنگام استفاده از تابع attachInterrupt استفاده نمود.
ISR : نام تابع وقفه میباشد که به صورت اختیاری انتخاب میشود ، و پس از تحریک شدن پین وقفهی مربوطه ، کدهای درون این تابع اجرا میشود. این تابع دارای خروجی نمیباشد ( از نوع void میباشد ) و نمیتواند آرگمان ورودی داشته باشد.
نکاتی پیرامون تابع وقفه :
- تابع millis برای شمردن متکی به وقفه ها میباشد و مقدار آن هیچوقت درون تابع وقفه (ISR) افزایش پیدا نمیکند.
- تابع delay برای کار کردن نیاز به وقفهها دارد از این رو دستور delay هیچگاه درون تابع وقفه (ISR) اجرا نمیشود.
- تابع micros در ابتدای کار ، درون تابع وقفه (ISR) به درستی عمل میکند ولی بعد از گذشت ۱-۲ میلیثانیه به طور نامنظم کار میکند.
- تابع delayMicroseconds برای افزایش مقدار خود به هیچشمارندهای وابسته نمیباشد بنابراین دستورdelayMicroseconds درون تابع وقفه (ISR) به درستی عمل میکند.
- توجه کنید هیچگاه در تابع وقفه (ISR) پردازشهای سنگین قرار داده نشود.
- هیچ گاه دو تابع وقفه همزمان اجرا نمیشوند و به ترتیب اولویت موجود در جدول بردار وقفه اجرا میشوند.
- هنگامی که یک متغیر را به طور سراسری تعریف میکنید و تمایل دارید مقدار متغیر درون تابع وقفه نیز بتواند تغییر کند باید قبل از تعریف متغیر از کلمه کلیدی volatile استفاده شود. با انجام این کار به کامپایلر یادآوری میکنیم که مقدار متغیر را در حافظه RAM و نه در یک رجیستر ذخیره کند و مقدار این متغیر می تواند خارج از برنامه (زیربرنامه وقفه یا سایر زیربرنامه ها) تغییر نماید.
mode : توسط این آرگمان نوع تحریک شدن وقفه مشخص میشود.دارای چهار حالت زیر میباشد :
- LOW : هرگاه وضعیت پین interrupt در حالت LOW ( صفر منطقی) قرار داشته باشد ، تابع وقفه اجرا میشود.
- HIGH : هر گاه وضعیت پین interrupt در حالت HIGH ( یک منطقی ) قرار داشته باشد ، تابع وقفه اجرا میشود. درست عکس حالت فوق.
- CHANGE : هر گاه وضعیت پین INTERRUPT از حالت صفر منطقی به یک منطقی تغییر کند یا هرگاه از حالت ۱ منطقی به صفر منطقی تغییر کند، تابع وقفه اجرا میشود.
RISING : هنگامی که وضعیت پین INTERRUPT از صفر منطقی به یک منطقی تغییر کند تابع وقفه اجرا میشود.
FALLING : هنگامی وضعیت پین INTERRUPT از یک مطقی به صفر منطقی تغییر کند ، تابع وقفه اجرا میشود.
attachInterrupt(digitalPinToInterrupt(pin), ISR, mode);
این تابع همانند تابع فوق میباشد با این تفاوت که در آرگمان اول از یک تابع دیگر به نام digitalPinToInterrupt استفاده شده است که به کمک آن میتوانیم به جای شماره وقفه ، شمارهی پین وقفه را وارد کنیم به عنوان مثال برای استفاده از وقفه صفر طبق تابع قبلی باید مطابق کد زیر عمل میکردیم:
attachInterrupt(0, ISR, FALLING);
ولی با استفاده از تابع جدیدی که هم اکنون معرفی کردیم باید مطابق کد زیر عمل کنیم :
attachInterrupt( digitalPinToInterrupt(2) , ISR, FALLING);
detachInterrupt()
این تابع وقفه مورد نظر را غیرفعال میکند و آن پایه که وقفه به آن نسبت داده شده بود به ورودی / خروجی تغییر میدهد. این تابع دارای ساختارهایی به صورت زیر میباشند.
detachInterrupt (interrupt); //شماره وقفه را وارد می کنیم detachInterrupt (digitalPinToInterrupt (pin)); //شماره پین وقفه را وارد میکنیم detachInterrupt (pin); //می توان از این ساختار استفاده نمود Zero و Due فقط در آردوینو
noInterrupts()
از این تابع برای غیر فعال کردن وقفه استفاده میشود.
interrupts()
بعد از غیر فعال کردن وقفه میتوان با این دستور ، وقفه را دوباره فعال نمود.
مثالی از وقفه در Arduino :
int ledPin = 13; // LED is attached to digital pin 13 volatile int x = 0; // variable to be updated by the interrupt void setup() { //enable interrupt 0 (pin 2) which is connected to a button //jump to the increment function on falling edge attachInterrupt(0, increment, FALLING); Serial.begin(9600); //turn on serial communication } void loop() { digitalWrite(ledPin, LOW); delay(3000); //pretend to be doing something useful Serial.println(x, DEC); //print x to serial monitor } // Interrupt service routine for interrupt 0 void increment() { x++; digitalWrite(ledPin, HIGH); }
دستتون باپاتون دردنکنه
باسلام و تشکر بابت مطالب ارائه شده
لطفا در مورد مد اسلیپ و ترکیب اون با وقفه خارجی هم آموزش بدید یا لینک معرفی کنید.
باسپاس فراوان
[…] آموزش وقفه بخش دوم […]
void setup(){
// put your setup code here, to run once:
pinMode(0,INPUT_PULLUP);
pinMode(1,INPUT_PULLUP);
pinMode(2,INPUT_PULLUP);
pinMode(3,INPUT_PULLUP);
pinMode(4,INPUT_PULLUP);
pinMode(5,INPUT_PULLUP);
pinMode(6,INPUT_PULLUP);
pinMode(7,INPUT_PULLUP);
pinMode(8,OUTPUT);
pinMode(9,OUTPUT);
pinMode(10,OUTPUT);
pinMode(11,OUTPUT);
pinMode(12,OUTPUT);
}
void loop(){
// put your main code here, to run repeatedly
bool bac=digitalRead(0);
bool AUTO=digitalRead(1);
bool MANU=digitalRead(2);
bool mic1= digitalRead(3);
bool mic2= digitalRead(4);
bool mic3= digitalRead(5);
bool mic4= digitalRead(6);
bool mic5= digitalRead(7);
bool valv1=digitalRead(8);
bool pump1 = digitalRead(9);
bool pump2 =digitalRead(10);
bool valv2= digitalRead(11);
bool memory1=digitalRead(12);
if(AUTO==LOW&mic1==LOW&mic2==LOW&mic3==LOW||MANU==LOW){
digitalWrite(12,HIGH);
digitalWrite(8,HIGH);
delay(4000);
digitalWrite(9,HIGH);
}
else
{
digitalWrite(12,LOW);
digitalWrite(8,LOW);
digitalWrite(9,LOW);
}
if(mic5==LOW&memory1==HIGH){
delay(5000);
digitalWrite(10,HIGH);
digitalWrite(11,HIGH);
delay(1000);
digitalWrite(11,LOW);@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
}
if(bac==LOW)
{digitalWrite(8,HIGH);
digitalWrite(9,HIGH);
}
}
سوالی در مورد این پروژه که نوشتم داشتم چه طور میتونم مطرح کنم
با سلام
کاربر گرامی ضمن تشکر از شما، امکان بررسی کدهای متفرقه در بخش کامنت ها فراهم نیست. موضوع سوال خود را مطرح کنید تا به لینک های مناسب هدایت شوید.
سلام
چرا انقدر این وقفه محدودیت داره !!!
تابع pulsein رو تو ISR اجرا نمیکنه باید چیکار کنم؟ راه دیگه نداره؟
من در کل نظر نمیدم ولی این مطالب انقدر مفید و عالی توضیح داده شده بودن که حیفم اومد نظرمو نگم
امیدوارم همشیه موفق باشی
ممنون بابت مطالب مفیدی که ارائه دادید. در یک پروژه به وسیله آردوینوuno از هردو وقفه خارجی استفاده می کنم. یکی از وقفه ها به یک انکودر ۴۰۰ پالس متصل هست و دومی به یک سنسور مغناطیس جهت شمارش. به نظرم وقفه متصل به انکودر فرصتی به وقفه دو نمیده که بتونه اجرا بشه! این مشکل رو چطور رفع کنم؟
اگه یکی از پین هایی رو انتخاب کنیم که اینتراپت نباشه چی میشه
با سلام
ضمن تشکر از توجه شما، بررسی کنید، اطلاع دهید!
با سلام به دست اندرکاران دیجی اسپارک
در برنامه ای که بنده نوشتم تابع وقفه اجرا میشه اما شروط موجود در ان به هیچ وجه اجرا نمی شوند به نظر شما مشکل از کجا میتواند باشد
کانفیک وقفه
pinMode(2, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(2), Interrupt, LOW);
digitalWrite ( ledPin1 , HIGH ) ;
//————-
void Interrupt() {
delayMicroseconds(20);
Serial.println(“Interrupt”);
if (Key == LOW) { // این قسمت کار نمیکند
if (m == 1) {
m = 2 ;
Serial.print(“mode = 2”);
digitalWrite ( ledPin1 , HIGH ) ;
digitalWrite ( ledPin2 , LOW ) ;
}
if (m == 2) {
mode = 1 ;
Serial.print(“mode = 1”);
digitalWrite ( ledPin1 , LOW ) ;
digitalWrite ( ledPin2 , HIGH ) ;
}
}
}
سلام
من با ارنج پای one و نرم افزار node-red میخوام با فعال سازی اینتراپت یک ورودی رو بخونم ؛ تو خوده تنظیمات پین فعال سازی اینتراپت رو انجام می دم ولی وقتی ورودی رو فعال می کنم هیچ اتفاقی نمی افتد و با دیباگ هم چک کردم پین هیچ خروجی نداره برای فعال سازی وقفه روی پین PA6 تنظیم دیگر رو هم باید انجام بدم ؟
با سلام
کاربر گرامی این مورد تست نشده است. از دیگر کاربرانی که در این خصوص اطلاعاتی دارندف تقاضا میکنم در بحث شرکت کنند.
با تشکر
ایراد کار از تنظیم مقدار دیبانس بود که با اصلاح آن مشکل برطرف گردید .
سپاس از همراهی شما