על תשאולים ופסיקות

פסיקות עם ארדואינו

פסיקות

פסיקות הן מה שנקרא interrupts ונותנות לנו לבצע פונקציות "ברקע" בלי לעצור את הקוד על פי שינוי שהתרחש בפין מסוים או לפי זמנים קבועים.

הדרך שעבדנו איתה עד עתה להבין אם מצב של פין השתנה היא על ידי תשאול(polling). הקוד שמחפש את השינוי רץ כל כמה מילישניות בצורה הבאה:

if(digitalRead(pin) == HIGH)

הקוד הזה הוא בסדר גמור ברוב הפרויקטים הפשוטים אבל יהיו מקרים שבהם נצטרך לכתוב פסיקה שהיא פונקצייה שמחכה ברקע ומופעלת ברגע ששינוי כלשהו התרחש בפין. לפסיקה יש עדיפות גבוהה יותר משאר הקוד, גם מdelay ולולאות, ולכן כל הקוד עוצר והפסיקה מופעלת.

כאנלוגיה לפסיקה אפשר לחשוב למשל על בנאדם שעובד בנגריה ויש לו שני טלפונים , אחד טלפון שמדליק נורת חיווי כשמישהו מתקשר וטלפון אחר משמיע צלצול כמו שאנחנו מכירים. בגלל שהטלפון הראשון רק מדליק נורת חיווי הנגר יצטרך כל כמה שניות ללכת אליו ולבדוק אם הנורה מופעלת, ודבר זה נקרא תשאול. לעומת זאת בטלפון שמצלצל הנגר יכול להמשיך לעבוד בחדר וכשיש צלצול הוא יעזוב הכל ויגש לענות וזוהי פסיקה.

מקרה שכיח שקיים  בקוד הוא למשל לולאה ולחיצה על כפתור כמו למשל בקוד הבא:

void setup() {
  pinMode(9, OUTPUT);
  pinMode(2, INPUT);
}

void loop() {
  if (digitalRead(2) == HIGH){
     // do something
}

for (int i = 0; i < 256; i++){
  analogWrite(9, i);
  delay(10);
}

for (int i = 255; i > 0; i--){
  analogWrite(9, i);
  delay(10);
 }
}

פה אנחנו מעמעים נורה בעזרת PWM בשתי לולאות שרצות כל הזמן. חישוב קצר מראה ששתי הלולאות ביחד לוקחות 5 שניות ובזמן זה כל שאר הקוד קופא ולכן אם נלחץ על הכפתור יכול להיות שנצטרך לחכות 5 שניות עד שהוא יעבוד.

הקוד שפותר את הבעיה הזו משתמש בפסיקה:

void setup() {

  pinMode(9, OUTPUT); // led

  pinMode(13, OUTPUT); // buzzer

  pinMode(2, INPUT_PULLUP); // pullup pin2 to high

  attachInterrupt(0, buzzer, FALLING); // when pin 2 is low, execute buzzer function

}

void buzzer(){

  tone(13, 200, 1000);

}

void loop() {

  for (int i = 0; i < 256; i++){

  analogWrite(9, i); delay(10);

}

for (int i = 255; i > 0; i--){

  analogWrite(9, i); delay(10);

  }

}

עכשיו אפשר ללחוץ על הכפתור תוך כדי הלולאות והוא יעבוד כמו שצריך.

הפונקציה attachInterrupt מקבלת שלושה ערכים:

  • הראשון קובע באיזה פסיקה נשתמש כשפסיקה 0 משויכת לפין2 ופסיקה 1 משויכת לפין 3. בארדואינו אונו יש רק שתי פינים שמסוגלים להיות משויכים לפסיקות, בארדואינו מגה יש יותר.
  • הערך השני הוא שם הפונקציה שתופעל במקרה של פסיקה.
  • הערך השלישי הוא התנייה מתי תתרחש הפסיקה ויש כמה אפשרויות:
  1. LOW – הפסיקה מתרחשת כשהפין ב LOW
  2. HIGH – הפסיקה מתרחשת כשהפין ב HIGH
  3. FALLING – מתרחשת כשהפין יורד מ HIGH ל LOW
  4. RISING – מתרחשת כשהפין עולה מ LOW ל HIGH
  5. CHANGE – מתרחשת בכל פעם שיש שינוי בפין של עלייה או ירידה

עוד כמה הערות על פסיקות:

  • בפונקציה שמופעלת בזמן פסיקה אין להפעיל השהיות(delay)
  • אם יש נתון שמשתנה בתוך הפונקציה צריך להצהיר עליו בתחילת הקוד כמשתנה נדיף(volatile)
  • מטרת הפסיקה להיות קצרה ולעניין אז עדיף לא לכתוב מגילות בתוך הפונקציה

פסיקות טיימר

אפשר להשתמש באחד הטיימרים שנמצאים בארדואינו לבצע פסיקה כל זמן קבוע ובכך לבצע פונקציה קבועה שרצה כל זמן מסוים. זה נותן הרגשה של ריבוי משימות, אבל ריבוי המשימות שהבקר מבצע היא אשליה כי בסופו של דבר הוא מסוגל לעשות פעולה אחת בזמן נתון כמו מחשב ביתי.

ככל שהבקר יהיה יותר מהיר האשליה תיראה יותר אמיתית. כדי ליצור פסיקות טיימר נשתמש בספריה timerone שניתן להתקין מסביבת הפיתוח של ארדואינו. נעמעם את הנורה וכל שנייה נפעיל את הזמזם ברקע וזה יצור אשלייה ששתי הדברים קורים באותו זמן. כדי שזה יעבוד צריך להחליף את פין 9 לפין אחר כי אחרת אנחנו חוסמים את הטיימר שמשמש גם ל- PWM בפין 9.

#include <TimerOne.h>

void setup(){

  pinMode(3, OUTPUT);

  Timer1.initialize(1000000); // 1000000 microseconds = 1 second

  Timer1.attachInterrupt(buzz); //execute buzz function

} 
void loop(){

  for (int i = 0; i < 256; i++){

    analogWrite(3, i);

    delay(10);

  }

  for (int i = 255; i > 0; i--){

    analogWrite(3, i); delay(10);

  }

}

//Timer interrupt function

void buzz(){

  tone(13, 4000,5);

}

אפשר בבירור לראות שהנורה מקרטעת קצת ועוצרת לכמה מילישניות אבל התוצאה עדיין טובה יותר מקוד ללא פסיקה.

כתיבת תגובה

האימייל לא יוצג באתר.