זמן וטיימרים
כל התוכניות עד עכשיו ממתינות בעזרת הפקודה sleep, ובזמן ההמתנה התוכנית עיוורת: אינה רואה לחצן ואינה משרתת נורית אחרת. בפרק הזה נמדוד את הזמן במקום להמתין לו, ונשאיר לטיימר את מה שצריך לקרות בזמנו.
- נמדוד זמן בעזרת הפקודה
ticks_diff, ונפעיל שתי משימות בשני קצבים שונים בלי חסימה. - נשתמש בטיימר מחזורי ובטיימר חד-פעמי, ונדע מה ההבדל בין שני הלוחות.
- נמדוד רוחב פולס ותדר, ונחשב מרחק בעזרת החיישן HC-SR04.
4.1 השהיות ושעון הבקר (Delays and Ticks)
להמתנה יש time.sleep(s) בשניות, time.sleep_ms(ms) ו-time.sleep_us(us), כי לפי התיעוד בחלק מהלוחות sleep אינה מקבלת שבר. לקריאת השעון יש time.ticks_ms() ו-time.ticks_us(), שני מונים עולים שנקודת ההתחלה שלהם אינה מוגדרת, ו-time.ticks_diff(b, a) נותן את הזמן מ-a עד b.
ההמתנה היא רף תחתון: התיעוד מציין ש-sleep_ms עלולה להתארך, ולכן כדי לדעת כמה זמן עבר קוראים את השעון. המונה מוגבל, ולכן כשהוא מגיע לערך הגבוה ביותר הוא גולש וחוזר לאפס. אורך המחזור שלו הוא חזקה של 2 לפי התיעוד. בסימולטור הוא 230, ולכן מונה אלפיות השנייה גולש בערך כל 12.4 ימים:
import time
t1 = time.ticks_add(time.ticks_ms(), -100)
t2 = time.ticks_add(t1, 250)
print("t1 =", t1)
print("t2 =", t2)
print("ticks_diff =", time.ticks_diff(t2, t1))t1 = 1073741724 t2 = 150 ticks_diff = 250
ticks_diff נותן 250, בתנאי ששתי הנקודות אינן מרוחקות יותר ממחצית המחזור. תוכנית שמחסרת ישירות מצליחה ימים ואז טועה.4.2 למה sleep חוסמת? שתי משימות יחד
אנו רוצים שתי נוריות: הראשונה משתנה כל 500 ms, והשנייה כל 300 ms. אילו כתבנו sleep_ms(500) ואחריה sleep_ms(300), כל אחת מהן הייתה משתנה כל 800 ms: כל פקודת המתנה חוסמת את כל השאר. והפתרון: מסתובבים בלולאה מהר, ובכל סיבוב שואלים אם הגיע מועדה של הנורית הזאת.
from machine import Pin
import time
import board
led_a = Pin(board.LED, Pin.OUT)
led_b = Pin(board.LED_EXT, Pin.OUT)
start = time.ticks_ms()
last_a = start
last_b = start
while True:
now = time.ticks_ms()
if time.ticks_diff(now, last_a) >= 500:
last_a = time.ticks_add(last_a, 500)
led_a.value(not led_a.value())
print(time.ticks_diff(now, start), "A")
if time.ticks_diff(now, last_b) >= 300:
last_b = time.ticks_add(last_b, 300)
led_b.value(not led_b.value())
print(time.ticks_diff(now, start), "B")
time.sleep_ms(1)300 B 500 A 600 B 900 B ...
last_a בעזרת ticks_add, ולא מ-now, וכך האיחור אינו מצטבר.sleep_ms(2000) ונראה מה הולך לאיבוד.4.3 טיימר (Timer)
כאן שני הלוחות שונים. ב-ESP32 יש ארבעה טיימרי חומרה במספרים 0–3, וכותבים Timer(0). ב-Pico W יש טיימרי תוכנה שאינם צריכים מספר, והוא מקבל Timer(-1), ש-ESP32 אינו מקבל. את ההבדל הזה מחביאים ב-board.py: הפונקציה board.timer() מחזירה את הטיימר הנכון, והתוכנית אינה מזכירה מספר.
from machine import Pin, Timer
import time
import board
led = Pin(board.LED, Pin.OUT)
tim = board.timer()
def tick(t):
led.value(not led.value())
print("tick", led.value())
tim.init(period=500, mode=Timer.PERIODIC, callback=tick)
time.sleep_ms(1200)
tim.deinit()
print("main: stopped")
tim.init(period=1000, mode=Timer.ONE_SHOT, callback=tick)
time.sleep_ms(1500)tick 1 tick 0 main: stopped tick 1
board.timer() מחזירה בכל פעם את טיימר 0, ולכן אין להפעיל בו שתי משימות יחד. הפונקציה שהטיימר קורא לה קוטעת את התוכנית, ולכן שומרים אותה קצרה. הסיבות בפרק 5.4.4 מדידת רוחב פולס ותדר
רוחב פולס הוא הזמן שההדק נשאר ברמה מסוימת. הפקודה המוכנה למדידתו היא time_pulse_us(pin, level, timeout_us): היא ממתינה לתחילת הפולס ואז מחזירה את רוחבו במיקרו-שניות. היא מחזירה -2 אם הזמן שהוקצב נגמר לפני שהפולס התחיל, ו--1 אם נגמר באמצע המדידה. התוכנית עומדת כל הזמן הזה, ולכן בוחרים את הזמן המוקצב בקפידה. הדרך הפשוטה ביותר למדוד את התדר היא לספור עליות בשנייה שלמה:
from machine import Pin
import time
import board
sig = Pin(board.ECHO, Pin.IN)
count = 0
last = sig.value()
start = time.ticks_ms()
while time.ticks_diff(time.ticks_ms(), start) < 1000:
level = sig.value()
if last == 0 and level == 1:
count += 1
last = level
time.sleep_ms(1)
print("f =", count, "Hz")f = 50 Hz
ticks_diff את הזמן עד שאנו לוחצים על הלחצן בעכבר.4.5 פרויקט: מדידת מרחק (HC-SR04)
החיישן HC-SR04 שולח פולס קול שאינו נשמע, ואחר כך נותן פולס על ECHO שרוחבו הוא זמן ההלוך והשוב של הקול. מפעילים אותו בפולס קצר על TRIG, באורך 10 µs לפי גיליון הנתונים של היחידה הנפוצה.
| סמל | פירוש | יחידה |
|---|---|---|
| c | מהירות הקול: כ-0.0343 באוויר בכ-20 מעלות צלזיוס | cm/µs |
| t | רוחב פולס ההד | µs |
לדוגמה: פולס הד של 1200 µs פירושו d = 0.0343 · 12002 = 20.58 cm.
היחידה הנפוצה פועלת ב-5 V, ולכן פולס ECHO גבוה ממה שההדק עומד בו. לכן מציבים מחלק מתח, והמתח על ההדק הוא V = 5 · 20001000 + 2000 = 3.33 V.
TRIG הוא 27 ו-ECHO הוא 32. וב-Pico W: GP2 ו-GP3. והדק ה-5 V הוא VIN או VBUS לפי הלוח.את כל זה כותבים פעם אחת בספרייה. פסק הזמן 30000 µs שווה לכ-514 cm, יותר מן הטווח של היחידה הנפוצה, שהוא 4 m לפי גיליון הנתונים שלה.
# hcsr04.py - HC-SR04 ultrasonic distance sensor, the same on every board.
# (c) 2026 Fahed Ghanem - MIT License - fahed-lab.com
from machine import Pin, time_pulse_us
import time
SOUND_CM_PER_US = 0.0343
class HCSR04:
def __init__(self, trig, echo, timeout_us=30000):
self.trig = Pin(trig, Pin.OUT, value=0)
self.echo = Pin(echo, Pin.IN)
self.timeout_us = timeout_us
def distance_cm(self):
self.trig.value(1)
time.sleep_us(10)
self.trig.value(0)
us = time_pulse_us(self.echo, 1, self.timeout_us)
if us < 0:
return None
return us * SOUND_CM_PER_US / 2import time
import board
from hcsr04 import HCSR04
sensor = HCSR04(board.TRIG, board.ECHO)
while True:
d = sensor.distance_cm()
if d is None:
print("no echo")
else:
print("%.1f cm" % d)
time.sleep(1)20.0 cm no echo 100.0 cm ...
עיקרי הפרק:
- ההמתנה היא רף תחתון, והיא חוסמת הכול. כדי למדוד זמן קוראים את השעון בעזרת
ticks_diff, ואין מחסרים ישירות. - שתי משימות בשני קצבים: לולאה מהירה, ובכל סיבוב שואלים אם הגיע המועד.
board.timer()מסתירה את ההבדל בין הטיימרים של שני הלוחות, והפונקציה שהטיימר קורא לה נשארת קצרה.- רוחב הפולס נותן את המרחק, ומורידים את ה-5 V לפני שהם מגיעים להדק.
סיכום הכללים בפרק:
| הכלל | הנוסחה |
|---|---|
| המרחק מזמן ההד | d = c · t2 |
פקודות הפרק:
| פקודה | מה היא עושה |
|---|---|
| time.ticks_add(t, d) | מועד שמרחק d אחרי t. |
| tim.init(period=, mode=, callback=) | הפעלת הטיימר, ו-tim.deinit() עוצרת אותו. |
| time_pulse_us(pin, level, timeout_us) | רוחב פולס במיקרו-שניות. |
מילון מונחים:
| עברית | English | ערבית |
|---|---|---|
| טיימר | Timer | المؤقّت |
| גלישה | Wrap-around | الالتفاف |
| רוחב פולס | Pulse Width | عرض النبضة |
| תדר | Frequency | التردد |
שאלות לתרגול:
board.timer() ולא Timer(0)?Timer(0) אינו מתאים ל-Pico W.