3.2. תזמון

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

3.2.1. שינה

שלוש פונקציות שינה חוסמות את הסקריפט למשך הזמן המבוקש:

  • time.sleep(s) – השהיה למשך s שניות. מקבל מספר ממשי, כך ש-time.sleep(0.5) ממתין חצי שנייה.

  • time.sleep_ms(ms) – השהיה למשך ms מילישניות. הארגומנט חייב להיות מספר שלם.

  • time.sleep_us(us) – השהיה למשך us מיקרו-שניות.

import time

print("now")
time.sleep_ms(500)
print("half a second later")

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

שינה היא קריאה חוסמת. בזמן שהסקריפט ישן, הוא אינו עושה דבר אחר – אינו קורא פין, אינו משרת UART, אינו מעדכן LED. השתמשו ב-sleep כאשר חסימה היא מה שאתם רוצים; השתמשו בדפוס הלא-חוסם שלהלן כאשר זה לא המצב.

3.2.2. קריאת השעון

כדי למדוד כמה זמן אורך קטע קוד, קראו את השעון לפני ואחרי:

import time

start = time.ticks_ms()
do_work()
elapsed = time.ticks_ms() - start
print("took", elapsed, "ms")

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

Number line from 0 to MAX with a start tick near MAX and an end tick near 0; a dashed wrap-around arrow shows that after MAX the counter returns to 0.

מונה ה-tick גולש חזרה לאפס כשהוא מגיע לגבול המספר השלם. חיסור פשוט על פני הגלישה הזו שגוי.

3.2.3. ticks_diff

כדי לקבל את ה-tick-ים שחלפו באופן נכון, אפילו על פני גלישה, השתמשו ב-time.ticks_diff():

import time

start = time.ticks_ms()
do_work()
elapsed = time.ticks_diff(time.ticks_ms(), start)
print("took", elapsed, "ms")

סדר הארגומנטים הוא ticks_diff(later, earlier) – הביטוי נקרא ”כמה רחוק later אחרי earlier”. התוצאה היא מספר שלם בעל סימן; חיובי פירושו ש-later הוא אכן מאוחר יותר, שלילי פירושו שהוא בעבר. הפונקציה מטפלת בגלישה באופן פנימי.

טיפ

תמיד צמדו את time.ticks_ms() / time.ticks_us() עם time.ticks_diff(). החיסור הגולמי נכון רוב הזמן; הפעם שבה הוא שגוי היא כשסקריפט רץ זמן רב – בדרך כלל הזמן הגרוע ביותר לאתר באגים בתקלת תזמון.

3.2.4. תזמון לא-חוסם

סקריפט מיקרו-בקר בדרך כלל צריך לעשות יותר מדבר אחד ”בו-זמנית“: לקרוא לחצן, להבהב LED, לדגום חיישן, לשרת UART. sleep אינו טוב לכך – בזמן ש-sleep אחד רץ, המשימות האחרות נתקעות.

הדפוס הסטנדרטי הוא לשמור מועד אחרון (deadline) לכל משימה, ולבדוק בכל לולאה האם המועד האחרון חלף. ההחלטה לפעול בנויה על time.ticks_diff(), ולעולם לא על sleep:

import time

next_blink = time.ticks_ms()
next_poll  = time.ticks_ms()
state = False

while True:
    now = time.ticks_ms()

    if time.ticks_diff(now, next_blink) >= 0:
        state = not state
        # update LED here
        next_blink = time.ticks_add(next_blink, 500)

    if time.ticks_diff(now, next_poll) >= 0:
        # read sensor here
        next_poll = time.ticks_add(next_poll, 100)

ה-LED מתחלף כל 500 ms, החיישן נדגם כל 100 ms, ואף משימה אינה חוסמת את האחרת. time.ticks_add() מקדם מועד אחרון בתוספת ידועה מבלי להיתקל בגלישה.

מבנה זה – לולאה יחידה, מספר משימות מתוזמנות, ללא sleep בגוף – מופיע בכל מקום שבו רץ קוד חומרה: התייצבות תוכנתית (debouncing) של מתגים, רצף הנעת מנועים, פסקי זמן לקריאת UART. אותן שלוש פונקציות (time.ticks_ms(), time.ticks_diff(), time.ticks_add()) מכסות כל מקרה.