לולאות

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

דוגמא ללולאה פשוטה היא הלולאה הבאה:

תיאור פשוט של אופן פעולת הרכיב

1 דוגמה ראשונה.PNG

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

הלולאות המרכזיות בארדואינו

הלולאות המרכזיות בארדואינו, שאותן אסקור במאמר זה, הן לולאות ()void loop, לולאות ()for ולולאות ()while. כל אחת מהן משומשת במקרים שונים ויעילה בהפיכת הקוד שלכם לפשוט ומדויק יותר. 

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

3.png
2 סביבת פיתוח ארדואינו.PNG

אמנם רוב הקוד בארדואינו חוזר על עצמו שוב ושוב, אבל ישנה פונקציה מאד משמעותית - ()void setup - שהקוד שבה מתקיים רק פעם אחת. ב()void setup נעשות פעולות הנחוצות לקוד שלנו רק פעם אחת: 

   :הגדרות של מספר הפין ומעבר החשמל בו  

.1

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

:פתיחת והגדרת סוג תקשורת   

.2

    ב()void setup אתם תרשמו את הפקודה ()Serial.begin, שפותחת את התקשורת עם המסך הסיריאלי. 

:הרצת בדיקת מערכות  

.3

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

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

לולאת ()void loop

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

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

6.png
no.png
3 מבנה לולאת וויד לופ.PNG

מבנה לולאת void loop:

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

דוגמה לשימוש בלולאת ()void loop - תפתחו שניה את הפרוקייט האחרון שעבדתם עליו? סתם. הינה דוגמה:

4 דוגמה לולאת וויד לופ.PNG

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

טעויות נפוצות בשימוש בלולאת ()void loop

ישנם שני סוגים של שגיאות בקוד: שגיאות שפה ושגיאות לוגיות. 

nc.png

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

דוגמות לשגיאות לוגיות:

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

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

True and False - אמת ושקר

לפני שנעבור ללולאות הבאות, כדאי שנעשה חזרה על שני מונחים: "נכון True" ו "לא נכון - False". כאמור, לולאות הינן איסופיות, אלא אם כן הוגדר להן תנאי יציאה. תנאי היציאה מבוסס על תנאי בינארי. נכון ולא נכון, כן או לא, 1 או 0. הקוד בארדואינו מסתמך בהמון צורות על תנאים לוגיים - תנאי, שיכול להיות נכון (1) או לא נכון (0). 5V או 0V. תדפיס HIGH או LOW, יש חשמל או אין חשמל. 

בלולאות, לרוב, הלולאה נכנסת לפעולה אם התנאי שבסוגריים שלה מתקיים (פסוק אמת), ולא נכנסת לפעולה אם הוא איננו מתקיים (פסוק שקר).

דוגמה ללולאה שתמיד תיושם בקוד:

5 תנאי אמת ושקר.PNG

1 שווה ל1, אז התנאי תמיד מתקיים. הלולאה הזאת תרשום "on" שוב ושוב לנצח ותתקע את הקוד.

דוגמא לולאה שאף פעם לא תיושם בקוד:

6 תנאי אמת ושקר שתיםם.PNG

0 לא שווה ל1, לכן הקוד לא יכנס ללולאה הזאת והפקודות שבה לא יבואו לידי ביטוי אף פעם. 

תנאים לוגיים

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

7 טבלת תנאים לוגיים.PNG

לולאת ()for

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

בניגוד ללולאת void loop שחוזרת על עצמה אין סוף פעמים, לולאת for נועדה לחזור על הפקודות שבתוכה מספר פעמים מוגדר, ואז הקוד ממשיך הלאה. כלומר, לולאת FOR היא הדרך שלנו לומר: בצעי את קבוצת הפקודות הללו 5 פעמים, או 10 פעמים, או 1000 פעמים, לפי מה שנגיד לה. היא מצויינת בעיקר לפעולות קטנות שחוזרות על עצמן, למשל בשליטה על מנוע סרבו. במקום לרשום 180 פעמים "זוז מעלה אחת", לולאת for תגיד "זוז מעלה 1, 180 פעמים", ותחסוך את העבודה.

מבנה לולאת for 

8 for 1.PNG

    אתחול

  • קורה פעם אחת בתחילת הלולאה. 

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

  • באתחול, הלולאה קולטת מהו הערך ההתחלתי של המשתנה. בדרך כלל נכריז על המשתנה כ0, אבל הוא לא חייב להיות. 

  • המשתנה משמש מעין מונה של מספר ההרצות של הלולאה. בדרך כלל ישנו אותו ב1 בספירה.

    תנאי

  • כל "סיבוב" של הלולאה, היא בודקת אם התנאי מתקיים או לא מתקיים. כלומר אם המשתנה שאותחל עונה על התנאי שהוגדר (למשל, אם הוא גדול מ50) או לא. 

  • בזמן שהוא מתקיים (true) - הקוד נכנס ללולאה ותתבצע ספירה.

  • ברגע שהתנאי לא מתקיים (false) - הלולאה תסתיים והקוד ימשיך הלאה. 

    גדילה: קצב השינוי

  • שינוי של ערך המשתנה.

  • יכולה להיות להחסיר אותו ב1, להוסיף 1, להכפיל ב13,000, או כל דרך שניתן לשנות בה מספר.

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

  • ברגע שערך המשתנה יהפוך לערך שגוי, הלולאה תסתיים.

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

דוגמא ללולאת for פשוטה:

9 for 2.PNG

בדוגמה זו, הקוד ידפיס את ערך המשתנה num, כל עוד num קטן מ10, ויוסיף 1 לnum כל פעם. התוצאה תהיה שהוא ידפיס 10 מספרים, 0,1,2,3,4,5,6,7,8,9, כי אלו המספרים בסדרה החשבונית שמתחילה ב0, ההפרש בין איבר לאיבר שאחריו הוא 1 והיא נגמרת ב 10-1 שזה 9. 

אפשר גם להחסיר את המשתנה ב1: שימו לב, במצב כזה הint צריך להיות int num = 10 כדי שהוא יוכל לרדת ממשהו, אחרת הוא ירד ישר למספרים שליליים. 

10 for 3.PNG
11 for 4.PNG

בספירה, אפשר לעשות יותר מ++ (להעלות את num ב1) או -- (להוריד את num ב1). אפשר גם - 

להוסיף לו 3!

להעלות אותו בריבוע!

​​

לעשות שהוא יהיה שווה לקלט מחיישן כלשהו! 

12 for 5 להעלות בריבוע.PNG
13 for 6 קלט מחיישן כלשהו.PNG

שימושים נפוצים בלולאת for

לולאות for נפוצות מאד, כאשר ידוע כמה פעמים אתם רוצים שהפקודות ירוצו. 

דוגמא פשוטה ללולאת for היא הדוגמה הבאה:

14 for 7 דוגמה לשימוש בלולאת for.PNG

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

שימו לב: בדוגמות הקודמות לא הכרזתי על num כמשתנה גלובלי (מעל ה ()void setup ) אלא ישר בתוך הfor וכאן כן. שתי הדרכים עובדות. יכולה להיות לכם תוכנה שבה תרצו להשפיע על משתנה בכמה לולאות. במקרה כזה, אני ממליצה להגדיר אותו כגלובלי ולא בתוך הלולאה.

טעויות נפוצות ואזהרות בשימוש בלולאות for

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

   - Num != num. המלצה: תבחרו שמות פשוטים - "n" זה מספיק, ואם אתם משתמשים במשהו מסובך - תעתיקו אותו כל פעם ואל

   תקלידו אותו כל פעם מחדש.

.1

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

   למשל כאן:

.2

15 for 8 טעויות 1.PNG
16 for 9 טעויות 2.PNG

כאן הטעות נמצאת בnum > 10. אמרתי ללולאה לפעול כל עוד num גדול מ10, ובתחילת הלולאה הגדרתי את num כ 10. num שווה ל10 והתנאי מתקיים רק כשnum = 11 ומעלה, אז התנאי לא מתקיים והקוד מיד יוצא מהלולאה.

הפתרון לכך יהיה לעשות:

שיניתי את התנאי כך שבמקום לבדוק אם num גדול מ10, הלולאה תבדוק אם num קטן או שווה ל10, ואז הלולאה כן יכולה להתקיים כאשר num = 10.

 

התוצאה של לולאה זו היא הדפסה בסדר יורד מ10 עד ∞- , במרווחים של 1 בין כל ערך.

3. חילוף בסימנים:

17 for 10 טעויות 3.PNG

הלולאה לא תעבוד אם ה = יגיע לפני ה>. 

 

 

 

 

הפתרון יהיה להחליף ביניהם:

16 for 9 טעויות 2.PNG

לולאת ()while

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

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

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

מבנה בסיסי של לולאת while

19 while 1 מבנה.PNG

   תנאי:

   מצב כלשהוא, שבזמן שהוא מתקיים הלולאה תפעל. מצב יכול להיות בזמן שמשתנה = 0, בזמן שכפתור לחוץ, בזמן שחיישן מראה

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

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

   מתקיים.

שימושים של לולאת while:

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

 

דוגמות לשימושים של לולאת while:

1. הצבת גבולות

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

20 while 2.PNG

בדוגמה זו, לולאת הwhile תבוא לידי ביטוי כל עוד ערך המשתנה x קטן או שווה ל5. ברגע שערכו יותר גדול מ 5, הקוד ידלג על הלולאה.

2. תקשורת עם המסך הסיריאלי

while (Serial.available);

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

פקודות של תקשורת בין הארדואינו למסך הסיריאלי (מתוך המצגת של גבי שמעוני):

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

;Serial.begin(9600)        

  • הבקר זמין לקבלת מידע המגיע מהמחשב

 

Serial.available();

  • אם הגיע מידע, הבקר קורא את המידע ועושה בו שימוש - יעני הופך אותו למספר ושומר את המספר הזה בתוך משתנה (num). 

num = Serial.parseInt();

או               

num = Serial.read();

אם לא הגיע מידע, ממשיכים להאזין.

ככה הן נראות בקוד:

21 while 3.PNG

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

Break

שבירה של הלולאה

ניתן לשבור את הלולאה ולצאת מהקוד שלה באמצעות תנאי break, שמסיים את הלולאה באותה השורה שבה היא נמצאת. איך עושים את זה? מגדירים משתנה, ואם מתקיים תנאי מסויים בתוך הלולאה - תעשה ברייק.

לדוגמה:

22 break שבע בום.PNG

מה שקורה פה הוא שהקוד משחק 7 בום.

הוא סופר מ0 עד 9, ומכריז במסך הסיריאלי על הספירה. כאשר הוא סופר 3, הוא נכנס לתנאי שאומר לו "תמשיך". הגעת ל3? תמשיך לספור הכל טוב. כשהוא מגיע ל 7 הוא נכנס לתנאי נוסף אבל הפעם הוא מודרך שלא להגיד 7, אלא להגיד "בום!" ולעשות ברייק. הוא יוצא מהספירה ומהלולאה, מסיים את לולאת הvoid loop וחוזר מחדש על הספירה. 

השוואה בין לולאות 

23 טבלת השוואה בין לולאות.PNG

ביביליוגרפיה:

לוגו חוף השרון.png