facebook pixel מדריך: פסיקות - Interrupts - www.4project.co.il
Main logo www.4project.co.il
כל הרכיבים לפרוייקט שלכם
עגלת קניות

העגלה ריקה

פסיקות - Interrupts


2024-07-18 15:00:59

מבוא

כמי שכותב קוד למיקרו-בקרים ב-35 השנים האחרונות, אני לא יכול לדמיין פרוייקט שהוא קצת יותר רציני ממשהו לימודי, שלא משתמש בפסיקות (Interrupts).

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

מה זה Interrupt - פסיקה?

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

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

הסרט מתנגן (ה-()loop של התוכנית), אתם יושבים על הספה בסלון וכעבור כמה דקות שומעים את ה-beep-beep של המיקרוגל שמציין לכם שהפופקורן מוכן. אתם עוצרים את הסרט וניגשים למיקרוגל כדי להוציא את השקית של הפופקורן.

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

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

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

מיד אחרי זה אתם מחליטים להשתיק את הטלפון שלכם כדי שאף אחד לא יפריע יותר לראות את הסרט, לפחות לא בערוץ הזה… זה נקרא "למסך פסיקה" - Interrupt Masking. נחזור גם לזה בהמשך.

ההסבר נשמע די הגיוני, נכון? אבל מה הייתם עושים כדי לטפל בכל האירועים האלה בלי שימוש בפסיקות?

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

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

והדברים רק מסתבכים יותר ויותר כשמוסיפים גורמים נוספים (רכיבים נוספים לפרוייקט).

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

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

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


סוגי פסיקות

בהסברים שונים אתם יכולים להיתקל בפסיקות חומרתיות (Hardware interrupts) ופסיקות תוכנתיות (Software interrupts). במדריך זה נעסוק רק בפסיקות חומרתיות כי רוב המיקרובקרים בעולם הארדואינו לא תומכים בפסיקות אחרות.

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

בתוך שבבים של מיקרובקר יש הרבה מודולים חומרתיים שמבצעים פעולות שונות. אחד המודולים הוא ה-CPU שמריץ את התוכנית שלכם. ישנם מודולי תקשורת UART, SPI, I2C, מודול שמספק גישה לקווי ה-IO, מודול שעונים (Timers), מודול ניהול צריכת זרם, מודול ממיר אנלוגי לדיגיטלי (ADC) ורבים אחרים.

לרוב המודולים (אם לא לכולם) יש קו פסיקה שמגיע ל-CPU. בתוך ה-CPU לרוב יש יחידה מיוחדת לבקרת פסיקות שמרכזת את כל הטיפול בהן, הידועה בשם Interrupt Controller.

זהי תמונה של דיאגרמת בלוקים של מיקרובקר SAMD21 שמדגימה את כמות המודולים הפנימיים שיש בתוכו:
"דיגרמת בלוקים של מיקרובקר SAMD21"

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

בשרטוט של ה-SAMD21 אתם יכולים למצוא גם את מודול ה-EIC - External Interrupt Controller שאחראי על כל הקווים החיצוניים (ה-digital inputs) שיכולים לייצר פסיקה. למיקרובקר זה כל הקווים הדיגיטליים יכולים לגרום לפסיקה, כך שהיה צורך לרכז את כל הטיפול במודול מיוחד. ל-ATMega328 של UNO יש רק שני קווים דיגיטליים שמסוגלים לייצר פסיקה, כך שבמקרה הזה לא היה צורך במודול מיוחד והיה אפשר לחבר את שני הקווים האלה ישירות ל-CPU.

זוכרים את זה שהזכרתי שאת המיקרוגל אתם הפעלתם והוא גרם לפסיקה בעקבות זה, וזה שהשליח צלצל ביוזמתו, אבל אתם הייתם מודעים לכך שמישהו יכול לצלצל בדלת?
זה מתקשר לפסיקות הפנימיות והחיצוניות… השליח הוא גורם חיצוני שאין לנו שליטה עליו. אם כפתור מחובר לקו דיגיטלי, הוא יכול לייצר פסיקה חיצונית כשמישהו ילחץ עליו. לעומת זאת, אנחנו יכולים להפעיל מודול שעון כדי שייצר פסיקה בעוד 300 מילי-שניות כדי להבהב בלד. אפשר להפעיל מודול ADC שיבצע המרה מכניסה אנלוגית לנתון דיגיטלי, ובזמן הזה להספיק לבצע עוד כמה פעולות חשובות שאי אפשר לעצור לזמן ארוך (לדוגמה, לספק עוד מידע לרכיב שמנגן מוזיקה, הרי אנחנו לא רוצים לשמוע הפסקות בנגינה בזמן שאנחנו בודקים את מצב בורר ה-volume של המכשיר שמחובר לכניסה אנלוגית).

טיפול בפסיקות

פונקציות ISR

כשהמעבד מקבל פסיקה, הוא מפסיק את התוכנית הרגילה וקורא לפונקציה מיוחדת שנקראת ISR - Interrupt Service Routine. מבחינת המשתמש זוהי פונקציה רגילה, שאפשר לבצע בה פעולות, לקרוא או לשנות מצב הקווים החיצוניים של הבקר, להפעיל מודולים פנימיים שונים… אבל צריך לזכור שבזמן שפונקציית ISR מתבצעת, שום פסיקה אחרת לא מטופלת. חשוב מאוד שפעולות שאתם מבצעים יהיו קצרות ולא יציפו מודולים אחרים בכמויות מידע שהם לא יוכלו לטפל בו (קריאות ל-Serial היא הדוגמה הנפוצה ביותר).

בסביבת ארדואינו קורים הרבה מאוד דברים ברקע, שאנשים לא מודעים להם. הנה רק 2 דוגמאות:
  • ישנו שעון שמייצר פסיקה כל מילי-שניה שמקדמת את המונה שבסופו של דבר מוחזר מתוך פונקציית ()millis, כך שאם נבצע פעולה ארוכה מאוד בתוך פונקציית ISR, פסיקה של ספירת הזמן תפוספס וייחוס הזמן ישתנה עבור דברים אחרים בתוכנית.
  • כשאתם כותבים משהו לערוץ התקשורת הטורית עם פונקציה כמו ()Serial.print, המחרוזת שסיפקתם לפונקציה מועתק לחוצץ זמני, ממנו נשלח תו-תו (או ליתר דיוק byte-byte) למודול התקשורת הטורית בתוך הבקר. המעבד מקבל פסיקה כל פעם שהמודול סיים לשלוח את ה-byte הקודם ומוכן לקבל את ה-byte הבא. אם תעשו ()Serial.print מתוך ה-ISR, פסיקות של מודול התקשורת לא יטופלו והמידע ששלחתם אליו יכול ללכת לאיבוד.

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

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

לדוגמה, אם הפסיקה נוצרה ע"י קו שאליו מחובר כפתור Volume UP בנגן המוזיקה, ה-ISR יוכל לסמן עם איזה שהוא דגל בזכרון שמציין שהכפתור נלחץ והריצה הרגילה של התוכנית תבדוק את מצב הדגל הזה ותשנה את ההגברה של המוזיקה.

אתם יכולים להגיד - אבל רגע… מה ההבדל בין לבדוק את קו ה-digital input לבין לבדוק את הדגל ששונה בתוך ה-ISR?
והתשובה היא - תגובתיות! צריך לזכור שהמעבד לא תמיד פנוי לבדוק את הכפתור. לפעמים הוא עושה דברים נסתרים כמו לשלוח עוד נתונים לערוץ התקשורת, או לקבל מידע דרך ערוץ אחר. גם אם אתם עושים לולאה שרק דוגמת את הקו הדיגיטלי עם פונקציה ()digitalRead, עדיין יש אפשרות לפספס שינוי קצר על הקו. כמו שהזכרתי קודם, יש הרבה דברים שמתבצעים ברקע…

ואם אתם משתמשים בפונקצית ()delay בקוד שלכם, אז הבעיה עוד יותר גדולה… כל מה שהפונקציה הזו עושה זה להסתובב סביב עצמה עד שיעבור הזמן שציינתם. בזמן הזה המשתמש היה יכול ללחוץ ולשחרר את כפתור ה-volume והייתם מפספסים את השינוי.

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

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

שינוי משתנים זה לא כל מה שאפשר לעשות בתוך ISR. למעשה אפשר לעשות הכל בהנחה שאתם יודעים מה אתם עושים. אפשר לשלוח נתונים דרך ערוצי תקשורת שונים, לשנות קווים חיצוניים של הבקר, להפעיל מודולים פנימיים וכו'.

בחלק מההסברים ברשת תמצאו איסור מוחלט להדפיס דרך Serial מתוך ה-ISR, מה שכמובן לא נכון. מה ש-()Serial.print עושה זה בסך הכל העתקה את הנתונים שאתם שולחים לחוצץ זמני. לחוצץ זה יש גודל מסויים (לרוב 64 בתים אם לא שיניתם כלום בסביבת הארדואינו). אם תעבירו מחרוזת מספיק ארוכה שתגרום לנתונים לגלוש מעבר ל-64 תווים של החוצץ, התוכנית שלכם תתקע או נתונים ילכו לאיבוד כי פסיקה שמפנה את החוצץ לא יכולה להתבצע בגלל שאתם בתוך ה-ISR. אבל זה לגמרי בסדר להדפיס משהו קצר, שאתם יודעים שלא יגלוש מעבר לגודל החוצץ.

לדוגמה, כשאתם מנסים לעשות debug לתהליך בעזרת הדפסות וצריכים להדפיס משהו מתוך ה-ISR כדי לוודא שאכן מתקבלת פסיקה, תעשו:
קוד: בחר הכל
Serial.println(“ISR”);

ולא
קוד: בחר הכל
Serial.println(“Oh yeah! I finally got that Interrupt!”);



סיבה לפסיקה

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

כדי לראות את הסיבות שבגללם מודולים פנימיים של מיקרובקר מייצרים פסיקות צריך יהיה לקרוא את המפרט של הבקר המפרט את המודול המדובר. כדוגמה קצרה, למשל המודול של השעונים (Timers) יכול לייצר פסיקה כשהמונה שלו גולש (Overflow), כלומר כשהוא סופר מעלה והמונה מגיע למספר המקסימלי האפשרי. יש שעונים שיכולים לספור מטה, אז אפשר לקבל גם פסיקה כשהם מגיעים ל-0. אותם מודולים לרוב יכולים לספק גם פסיקות כשהערך של המונה שווה לערך שציינתם, לפעמים אפילו לשני ערכים שונים (לטובת יצירת פולס PWM באורכים שונים). אלה פסיקות השוואה (Compare).

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

כל מודול והפונקציונליות שלו, עם סיבות שונות לפסיקות.

פסיקה חיצונית מגיעה דרך קווי כניסה דיגיטלית, אבל יש יותר מסיבה אחת או שתיים שיכולה לגרום לפסיקה במעבד. זאת רשימה של כל הסיבות שבדרך כלל אפשר להגדיר למיקרובקר לייצר פסיקה ממקור חיצוני. יש מיקרובקרים שתומכים רק בחלק מהרשימה:
  • LOW - פסיקה נוצרת כל עוד הקו במצב “0” לוגי
  • HIGH - פסיקה נוצרת כל עוד הקו במצב “1” לוגי
  • RISING - פסיקה נוצרת בעליה של הקו
  • FALLING - פסיקה נוצרת בירידה של הקו
  • CHANGE - פסיקה נוצרת בכל שינוי של הקו

כשחושבים על מקרה של ספירת פולסים של מקודד, בו צריך לספור כל עליה וירידה של הקו, צריכים לעבוד במצב ה-CHANGE כדי לזהות את כל השינויים:
"פולסים של מקודד סיבובי"

ללחיצת כפתור יהיה מספיק לקבל פסיקה כשהקו עולה (RAISING) או יורד (FALLING) (תלוי בחיבור החשמלי של הכפתור והצורך לזהות לחיצה או עזיבה).

ברוב המקרים של עבודה עם רכיבים חיצוניים, כמו חיישנים, תראו שהם עובדים במצב Active LOW, כלומר במקרה שהם רוצים לייצר פסיקה, הם מורידים את הקו ל-"0" לוגי. אתם יכולים לראות את זה גם במעגלים רבים המציינים את חיבור ה-INT עם קו מעל הכיתוב, שמסמל לוגיקה הפוכה:
"חיישן טמפרטורה TMP117"

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

שימו לב לנקודה הבאה: כל עוד קו הפסיקה של רכיב חיצוני שמחובר למיקרובקר יהיה במצב "0" לוגי, הוא ייצר פסיקה אם הקו מוגדר לעבוד במצב LOW. כלומר המעבד לא יוכל לעשות שום דבר אחר חוץ מלטפל בפסיקה הזו עד שהרכיב החיצוני לא יפסיק את החיווי (יעלה את הקו ל-"1" לוגי). אם נחזור לדוגמה של מוצר שמנטר טמפרטורה, שמוגדר לתת פסיקה מעל 30 מעלות, כל עוד הטמפרטורה תהיה מעל רף זה, קו הפסיקה יהיה ב-"0" לוגי, אלא אם מנקים את הפסיקה (Clear the interrupt) בתוך החיישן.

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

מיסוך פסיקות

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

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

בסביבת ארדואינו חוסמים או מאפשרים את כל הפסיקות בעזרת פונקציות ()noInterrupts ו-()interrupts בהתאמה. כמו שאתם מבינים פונקציות אלה גורמות לתופעה דומה למה שקורה כשאתם נמצאים בתוך ISR, שום פסיקה לא תגיע. גם במקרה זה חשוב לסיים את הפעולה מהר ככל האפשר ולאפשר את הפסיקות.

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

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

למיקרובקר SAMD21 יש רגיסטר INTENSET במודול EIC:
"רגיסטר סינון פסיקות חיצוניות ב-SAMD21"

בנוסף למיסוך/סינון, לפסיקות חיצוניות יש עוד רגיסטר שמציין איזה קו דורש פסיקה. הביטים ברגיסטר זה ננעלים ברגע שהם מזהים מצב פסיקה (קו יורד, קו עולה, שינוי, רמה לוגית) וצריך לנקות/לאפס אותם אחרי שמטפלים בפסיקה, אחרת הפסיקה תגרום לפונקציית ISR לרוץ שוב ושוב.

במיקרובקר ATMega328 יש רגיסטר EIFR:
"רגיסטר פסיקות חיצוניות ב-ATMega328"

במיקרובקר SAMD21 יש רגיסטר INTFLAG:
"רגיסטר פסיקות חיצוניות ב-SAMD21"

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

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

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

הסביבה גם מנקה את הביט של הפסיקה אחרי שהיא טופלה. כל זה שקוף למשתמש. כל מה שצריך לעשות זה להירשם לפסיקה על קו הרצוי בעזרת קריאה לפונקציה ()attachInterrupt ולספק מצביע לפונקציה שלכם שתקרא כשתגיע הפסיקה.

למתקדמים:
לחלק מהמיקרובקרים ישנו גם קו פסיקה מיוחד שאי אפשר למסך, שיקרא גם כשאתם בתוך ה-ISR. קו כזה בדרך כלל נקרא NMI - Non Maskable Interrupt. קו זה בדרך כלל שמור למקרים מאוד מאוד מיוחדים שדורשים טיפול קיצוני, כמו למשל אם המעגל מזהה שהוא הולך להישרף בגלל טמפרטורה גבוהה במיוחד, אפשר יהיה לדווח על כך למעבד דרך קו ה-NMI, שיכבה כל דבר אפשרי וילך לישון כדי לקרר את עצמו.

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

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

אקח כדוגמה את חיישן טמפרטורה STTS22H:


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

נניח שקו הפסיקה של החיישן מחובר לכניסה דיגיטלית שמוגדרת לקרוא לפונקציה שלנו כשקו הפסיקה הוא ב-LOW. החיישן מוריד את הקו כשהטמפרטורה חוצה את הגבולות המוגדרים, הפסיקה מטופלת ופונקציה שלכם נקראת… נניח שאתם רוצים לדווח למשתמש על המצב ע"י הדלקת לד שמחובר ליציאה דיגיטלית, עשיתם את זה מתוך פונקציית ה-ISR שלכם שסביבת הארדואינו קראה. חזרתם מהפונקציה. סביבת ארדואינו ניקתה (Cleared) את הביט של קו הפסיקה… אבל… קו הפסיקה הפיזי עדיין ב-LOW ומיקרובקר שוב מזהה את זה כמצב שצריך לטפל בפסיקה, שוב קורא ל-ISR וכך הלאה בלולאה…

יש כמה דרכים לטפל במצב זה.

אפשרות אחת היא להגיד את סיבת הפסיקה ל-FALLING, כלומר המעבד יזהה רק את הירידה הראשונית של הקו מ-"1" לוגי ל-"0" לוגי, כך שפונקציית ה-ISR תקרא רק פעם אחת, עד שהטמפרטורה תחזור לרמה שלא דורשת פסיקה ואז תצא שוב מהגבולות.

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

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

אפשרות שלישית היא לשלוט על קו הפסיקה בחיישן עצמו. קריאה של המפרט מגלה שקריאת רגיסטר STATUS של החיישן מאפסת את קו הפסיקה:
"רגיסטר סטטוס של חיישן טמפרטורה STTS22H"

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

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

סיכום

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

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


מדריכים נוספים:

  • מדריך מחלקת מודולי GPS

    מחלקת מודולי GPS

    2024-02-20 12:09:16

    במדריך זה נסביר על מודולי GPS השונים שאפשר למצוא באתר www.4project.co.il ועל התכונות שלהם. מקווים שהמדריך יעזור לכם לבחור את המודול הנכון לפרוייקט שלכם.

  • מדריך איך לקרוא סכמות חשמליות

    איך לקרוא סכמות חשמליות

    2024-02-07 20:46:44

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

  • מדריך מעגלים מודפסים

    מעגלים מודפסים

    2024-01-14 13:19:18

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

  • מדריך מחברים

    מחברים

    2023-07-17 08:58:12

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

  • מדריך כפתורים ומפסקים

    כפתורים ומפסקים

    2023-06-28 16:23:24

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