- מהי ריבוי משימות?
- מדוע לדלג על עיכוב () בארדואינו?
- מדוע להשתמש במיליס ()?
- רכיבים נדרשים
- תרשים מעגל
- תכנות Arduino UNO לריבוי משימות
ריבוי המשימות הובילו את מחשבי מהפכה שבו אחד או יותר תוכניות יכולות לרוץ בו זמנית אשר מגבירה יעילה, גמישות, יכולת הסתגלות ופרודוקטיביות. במערכות משובצות, מיקרו-בקרים יכולים גם להתמודד עם ריבוי משימות ומבצעים שתי משימות או יותר בו זמנית מבלי לעצור את ההוראות הנוכחיות.
כאן במדריך זה נלמד כיצד ארדואינו מבצע ריבוי משימות עם פונקציית ארדינו מיליס. בדרך כלל נעשה שימוש בפונקציית עיכוב () בארדואינו למשימה תקופתית כמו LED מהבהב אך פונקציית עיכוב זו () עוצרת את התוכנית למשך זמן סופי ולא מאפשרת לבצע פעולות אחרות. אז מאמר זה מסביר כיצד אנו יכולים להימנע משימוש בפונקציית עיכוב () ולהחליף אותה במיליס () כדי לבצע יותר ממשימות אחת בו זמנית ולהפוך את הארדואינו לבקר ריבוי משימות. לפני שנפרט לפרט, נתחיל בלדחות את ריבוי המשימות.
מהי ריבוי משימות?
ריבוי משימות פירושו פשוט לבצע יותר ממשימה או תוכנית אחת בו זמנית בו זמנית. כמעט כל מערכות ההפעלה כוללות ריבוי משימות. סוג זה של מערכות הפעלה מכונה MOS (מערכת הפעלה ריבוי משימות). ה- MOS יכול להיות מערכת הפעלה למחשב נייד או למחשב שולחני. הדוגמה הטובה לריבוי משימות במחשבים היא כאשר משתמשים מריצים את יישום הדוא"ל, דפדפן האינטרנט, נגן המדיה, משחקים, בו זמנית, ואם משתמשים לא רוצים להשתמש ביישום שהוא מריץ ברקע אם הוא לא סגור. משתמש הקצה משתמש בכל היישומים הללו בו זמנית, אך מערכת ההפעלה לוקחת את המושג הזה קצת אחר. בואו נדון כיצד מערכת ההפעלה מנהלת ריבוי משימות.
כפי שנראה בתמונה, המעבד מחלק את הזמן בשלושת החלקים השווים ומקצה כל חלק לכל משימה / יישום. כך מתבצעת ריבוי המשימות ברוב המערכות. הרעיון יהיה כמעט זהה עבור ריבוי המשימות של Arduino, למעט חלוקת הזמן תהיה קצת שונה. מכיוון שהארדואינו פועל בתדרים נמוכים וב- RAM בהשוואה למחשב נייד / נייד / מחשב, כך שהזמן הניתן לכל משימה יהיה גם שונה. ל- Arduino יש גם פונקצית עיכוב () המשמשת באופן נרחב. אך לפני שמתחילים בואו נדבר על הסיבה מדוע לא כדאי לנו להשתמש בפונקציית delay () בכל פרויקט.
מדוע לדלג על עיכוב () בארדואינו?
אם תיעוד הייחוס של Arduino נחשב אז ישנם שני סוגים של פונקציות עיכוב, הראשון הוא עיכוב () והשני הוא עיכוב מיקרו-שניות (). שתי הפונקציות זהות מבחינת יצירת עיכוב. ההבדל היחיד הוא שבפונקציה עיכוב (), הפרמטר השלם שעבר הוא באלפיות השנייה כלומר אם אנו כותבים עיכוב (1000) אז העיכוב יהיה 1000 אלפיות השנייה כלומר שנייה אחת. באופן דומה בפונקציה delayMicroseconds (), הפרמטר שהועבר הוא במיקרו-שניות כלומר אם אנו כותבים delayMicroseconds (1000), אז העיכוב יהיה של 1000 מיקרו-שניות כלומר 1 אלפיות השנייה.
כאן מגיע הנקודה, שתי הפונקציות מושהות את התוכנית למשך הזמן שעבר בפונקציית השהיה. אז אם אנו נותנים עיכוב של שנייה אחת, המעבד אינו יכול לעבור להוראות הבאות עד שתעבור שנייה אחת. באופן דומה, אם העיכוב הוא 10 שניות אז התוכנית תיפסק למשך 10 שניות והמעבד לא יאפשר ללכת להוראות הבאות עד שיעברו 10 השניות. זה מעכב את הביצועים של המיקרו-בקר במונחים של מהירות וביצוע ההוראות.
הדוגמה הטובה ביותר להסבר החיסרון בפונקציית השהיה היא שימוש בשני כפתורי לחיצה. שקול שאנחנו רוצים להחליף שני נוריות באמצעות שני כפתורי לחיצה. אז אם לחיצת כפתור אחת נלחצת אז נורית ה- LED המתאימה אמורה להאיר למשך 2 שניות, באופן דומה אם לחיצה שנייה נלחצת, ה- LED אמור להאיר למשך 4 שניות. אך כאשר אנו משתמשים בעיכוב (), אם המשתמש לוחץ על הכפתור הראשון התוכנית תפסיק למשך 2 שניות ואם המשתמש לוחץ על הכפתור השני לפני עיכוב של 2 שניות, אז המיקרו-בקר לא יקבל את הקלט כפי שהתוכנית היא בשלב עצירה.
התיעוד הרשמי של ארדואינו מציין זאת בבירור בתיאור הפונקציות הערות ואזהרות על עיכוב (). אתה יכול לעבור ולבדוק זאת כדי להבהיר יותר.
מדוע להשתמש במיליס ()?
כדי להתגבר על הבעיה הנגרמת על ידי שימוש בעיכוב, על מפתח להשתמש בפונקציה millis () שקל להשתמש בה לאחר שנהוג להשתמש בה, והיא תשתמש בביצועי מעבד של 100% מבלי ליצור עיכוב בביצוע ההוראות. millis () היא פונקציה המחזירה רק את כמות האלפיות השנייה שחלפו מאז שהוועד Arduino החל להפעיל את התוכנית הנוכחית מבלי להקפיא את התוכנית. מספר זמן זה יעלה על גדותיו (כלומר יחזור לאפס), לאחר כ- 50 יום.
בדיוק כמו ל- Arduino יש delayMicroseconds (), יש לה גם את גרסת המיקרו של millis () כמיקרו (). ההבדל בין מיקרו למיליס הוא שהמיקרו () יעלה על גדותיו לאחר כ- 70 דקות, בהשוואה למיליס () שזה 50 יום. אז תלוי ביישום אתה יכול להשתמש במיליס () או מיקרו ().
שימוש במילי () במקום עיכוב ():
כדי להשתמש במיליס () לתזמון ועיכוב, עליך לרשום ולאחסן את הזמן בו בוצעה הפעולה כדי להתחיל את השעה ואז לבדוק במרווחים אם הזמן שהוגדר עבר. אז כאמור, שמרו את הזמן הנוכחי במשתנה.
זרם ארוך לא חתום Millis = מילי ();
אנו זקוקים לשני משתנים נוספים כדי לברר אם הזמן הנדרש חלף. אחסנו את הזמן הנוכחי במשתנה currentMillis, אך עלינו לדעת כי מתי התחילה תקופת התזמון וכמה היא התקופה. אז מכריזים על המרווח והמיליס הקודמת . המרווח יגיד לנו את עיכוב הזמן ו- previos Millis ישמור את הפעם האחרונה בה אירע האירוע.
לא חתום ארוך קודם מיליס; תקופה ארוכה לא חתומה = 1000;
כדי להבין זאת, ניקח דוגמה לנורית מהבהבת פשוטה. התקופה = 1000 תגיד לנו שהנורית תהבהב למשך שנייה אחת או 1000ms.
const int ledPin = 4; // מספר הסיכה LED המחובר int ledState = LOW; // משמש לקביעת מצב ה- LED ללא חתום ארוך קודם מיליס = 0; // יאחסן בפעם האחרונה שהבהב נורית תקופת זמן ארוכה = 1000; // תקופה שבה יהבהב בהגדרת חלל ms () { pinMode (ledPin, OUTPUT); // הגדר ledpin כפלט } loop loop () { לא חתום currentMillis = millis (); // אחסן את השעה הנוכחית אם (currentMillis - previousMillis> = period) {// בדוק אם 1000 ms עברו את הקודם Millis = currentMillis; // שמור בפעם האחרונה שמצמצת את ה- LED אם (ledState == LOW) {// אם ה- LED כבוי הפעל אותו וההפך ledState = HIGH; } אחר { ledState = LOW; } digitalWrite (ledPin, ledState); // הגדר LED עם ledState כדי להבהב שוב } }
הנה, ההצהרה
הפרעות בארדואינו פועלות כמו במיקרו-בקרים אחרים. בלוח Arduino UNO יש שני סיכות נפרדות לחיבור הפרעות על סיכה GPIO 2 ו- 3. כיסינו אותו בפירוט במדריך Interrupts של Arduino, שם תוכלו ללמוד עוד על Interrupts וכיצד להשתמש בהם.
כאן נציג את Arduino Multitasking על ידי טיפול בשתי משימות בו זמנית. המשימות יכללו מהבהב של שתי נוריות בהשהיית זמן שונה יחד עם כפתור לחיצה שישמש לבקרת מצב ON / OFF של LED. אז שלוש משימות יבוצעו בו זמנית.
רכיבים נדרשים
- ארדואינו UNO
- שלוש נוריות (בכל צבע)
- עמידות (470, 10k)
- מגשרים
- קרש לחם
תרשים מעגל
דיאגרמת המעגל להדגמת השימוש בתפקוד Arduino Millis () קלה מאוד ואין לה הרבה רכיבים לחיבור כפי שמוצג להלן.
תכנות Arduino UNO לריבוי משימות
תכנות Arduino UNO לצורך ריבוי משימות ידרוש רק את ההיגיון שמאחורי העבודה של מיליס () כמוסבר לעיל. מומלץ לתרגל LED מהבהב באמצעות מיליס שוב ושוב כדי להבהיר את ההיגיון ולהפוך את עצמך בנוח עם מילי () לפני שתתחיל לתכנת את Arduino UNO לריבוי משימות. במדריך זה ההפרעה משמשת גם עם מילי () בו זמנית לריבוי משימות. הכפתור יהיה הפסקה. לכן בכל פעם שנוצר הפרעה כלומר לחיצה על כפתור, נורית הנורה תעבור למצב ON או OFF.התכנות מתחיל בהכרזה על מספרי סיכה שבהם מחברים נוריות LED ולחצן.
int led1 = 6; int led2 = 7; int toggleLed = 5; לחצן int int = 2;
בהמשך אנו כותבים משתנה לאחסון מצב הנוריות לשימוש עתידי.
int ledState1 = LOW; int ledState2 = LOW;
בדיוק כפי שהוסבר לעיל בדוגמה המהבהבת, המשתנים לתקופות ולמילי הקודם מוכרזים להשוות וליצור עיכוב עבור נוריות LED. נורית הנורית הראשונה מהבהבת אחרי כל שנייה אחת ונורית נוספת מהבהבת אחרי 200 מס.
לא חתום ארוך קודם Millis1 = 0; תקופה ארוכה const1 = 1000; לא חתום קודם הקודם Millis2 = 0; תקופה ארוכה const2 = 200;
פונקציה נוספת של מיליס תשמש להפקת עיכוב ההפצה כדי למנוע לחיצות כפתור מרובות. תהיה גישה דומה כנ"ל.
int debouncePeriod = 20; int debounceMillis = 0;
שלושה משתנים ישמשו לאחסון המעמד של לחיצת כפתור כמו פסיקה, Toggle LED והמדינה בלחיצת כפתור.
כפתור boolPushed = false; int ledChange = LOW; int lastState = HIGH;
הגדר את פעולת הסיכה שסיכה זו תפעל כ- INPUT או OUTPUT.
pinMode (led1, OUTPUT); pinMode (led2, OUTPUT); pinMode (toggleLed, OUTPUT); pinMode (pushButton, INPUT);
כעת הגדירו את סיכת ההפסקה על ידי הצמדת הפסקה עם הגדרת ISR ומצב הפסקה. שים לב שמומלץ להשתמש ב- digitalPinToInterrupt (pin_number) בעת הצהרת הפונקציה attachInterrupt () כדי לתרגם את הפין הדיגיטלי בפועל למספר ההפרעה הספציפי.
attachInterrupt (digitalPinToInterrupt (pushButton), pushButton_ISR, CHANGE);
תת- שגרת ההפסקה נכתבת והיא תשנה רק את הכפתור דגל כפתור. שים לב כי הפרעה תת-שגרתית צריכה להיות קצרה ככל האפשר, לכן נסה לכתוב אותה ולמזער את ההוראות הנוספות.
בטל pushButton_ISR () { buttonPushed = נכון; }
לולאה מתחילה באחסון ערך המיליס במשתנה currentMillis אשר יאחסן את ערך הזמן שעבר בכל פעם שהלולאה חוזרת.
זרם ארוך לא חתום Millis = מילי ();
בסך הכל יש שלוש פונקציות בריבוי משימות, מהבהב נורית אחת בשנייה אחת, נורית מהבהבת שנייה ב 200 ms ואם לחיצה על כפתור לחץ ואז כבה / כבה את נורית. אז נכתוב שלושה חלקים לביצוע משימה זו.
הראשונה היא מחליפה LED המדינה אחרי כל שניה 1 על ידי השוואת באלפיות השנייה שחלף.
אם (currentMillis - previousMillis1> = period1) { previousMillis1 = currentMillis; אם (ledState1 == LOW) { ledState1 = HIGH; } אחר { ledState1 = LOW; } digitalWrite (led1, ledState1); }
באופן דומה השני הוא מחליף את ה- LED אחרי כל 200ms על ידי השוואת המיליונים שעברו. ההסבר כבר מוסבר קודם לכן במאמר זה.
אם (currentMillis - previousMillis2> = period2) { previousMillis2 = currentMillis; אם (ledState2 == LOW) { ledState2 = HIGH; } אחר { ledState2 = LOW; } digitalWrite (led2, ledState2); }
לבסוף, הדגל buttonPushed מנוטר ואחרי יצירת עיכוב ההפעלה של 20ms הוא פשוט מחליף את מצב ה- LED המתאים ללחצן הלחיצה המחובר כפסיקה.
אם (buttonPushed = true) // בדוק אם ISR נקרא { if ((currentMillis - debounceMillis)> debouncePeriod && buttonPushed) // צור עיכוב של 20 ms ב- debounce כדי למנוע לחיצות מרובות { debounceMillis = currentMillis; // שמור את זמן עיכוב ההפעלה האחרון אם (digitalRead (pushButton) == LOW && lastState == HIGH) // שנה את ה- led לאחר לחיצה על כפתור הלחיצה { ledChange =! ledChange; digitalWrite (toggleLed, ledChange); lastState = LOW; } אחר אם (digitalRead (pushButton) == HIGH && lastState == LOW) { lastState = HIGH; } buttonPushed = false; } }
זה מסיים את ההדרכה של Arduino millis (). שים לב שכדי להתרגל למיליס (), פשוט תרגל ליישם את ההיגיון הזה ביישומים אחרים. ניתן גם להרחיב אותו לשימוש במנועים, מנועי סרוו, חיישנים וציוד היקפי אחר. במקרה של ספק, אנא כתוב לפורום או הערה למטה.
הקוד והווידאו המלאים להדגמת השימוש בתפקוד המיליס בארדואינו מופיעים להלן.