3.2. Timing

Modul time mengelompokkan fungsi-fungsi untuk tidur (menjeda skrip selama durasi tertentu) dan untuk mengukur berapa lama sesuatu berlangsung. Pada mikrokontroler, ini bukan sekadar fitur tambahan; ini adalah cara skrip mengatur interaksi dengan dunia luar -- berapa lama menahan pin pada kondisi tinggi, berapa lama menunggu antar sampel, berapa lama sejak tombol terakhir ditekan.

3.2.1. Sleeping

Tiga fungsi sleep memblokir skrip selama durasi yang diminta:

import time

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

Gunakan time.sleep_ms() untuk kebutuhan "tunggu sebentar" biasa dan time.sleep_us() hanya ketika timing harus ketat. time.sleep() biasa juga baik-baik saja, tetapi varian argumen integer menghindari konversi floating-point dan lebih mudah dibaca untuk interval pendek.

Sleep adalah panggilan pemblokiran. Selama skrip sedang tidur, skrip tidak melakukan hal lain -- tidak membaca pin, tidak melayani UART, tidak memperbarui LED. Gunakan sleep ketika pemblokiran adalah yang Anda inginkan; gunakan pola non-blocking di bawah ini ketika bukan itu yang Anda inginkan.

3.2.2. Membaca jam

Untuk mengukur berapa lama suatu bagian kode berlangsung, baca jam sebelum dan sesudahnya:

import time

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

Ini bekerja sebagian besar waktu. Penghitung tick bergulir (kembali ke nol) setelah sejumlah besar tick yang terbatas, dan pengurangan sederhana di sekitar guliran tersebut menghasilkan angka negatif atau positif yang sangat salah.

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.

Penghitung tick kembali ke nol ketika mencapai batas integer. Pengurangan sederhana di sekitar guliran tersebut adalah salah.

3.2.3. ticks_diff

Untuk mendapatkan tick yang telah berlalu dengan benar, bahkan di sekitar guliran, gunakan time.ticks_diff():

import time

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

Urutan argumen adalah ticks_diff(later, earlier) -- ekspresi ini dibaca "seberapa jauh later setelah earlier". Hasilnya adalah integer bertanda; positif berarti later memang lebih belakangan, negatif berarti ia ada di masa lalu. Fungsi ini menangani guliran secara internal.

Tip

Selalu pasangkan time.ticks_ms() / time.ticks_us() dengan time.ticks_diff(). Pengurangan mentah benar sebagian besar waktu; waktu di mana ia salah adalah ketika skrip telah berjalan lama -- biasanya saat yang paling buruk untuk men-debug masalah timing.

3.2.4. Timing non-blocking

Skrip mikrokontroler biasanya memiliki lebih dari satu hal yang harus dilakukan "pada saat yang sama": membaca tombol, mengedipkan LED, melakukan polling sensor, melayani UART. sleep tidak berguna untuk itu -- selama satu sleep berjalan, tugas-tugas lain terhenti.

Pola standarnya adalah menyimpan deadline per tugas, dan memeriksa setiap loop apakah deadline telah terlewati. Keputusan untuk bertindak dibangun di atas time.ticks_diff(), bukan pada 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 berkedip setiap 500 ms, sensor di-polling setiap 100 ms, dan tidak ada tugas yang memblokir yang lain. time.ticks_add() memajukan deadline dengan kenaikan tertentu tanpa masalah dengan guliran.

Bentuk ini -- satu loop, beberapa tugas berjadwal, tanpa sleep di dalam tubuhnya -- muncul di mana-mana dalam kode perangkat keras: debouncing perangkat lunak pada sakelar, sekuensing motor, timeout baca UART. Tiga fungsi yang sama (time.ticks_ms(), time.ticks_diff(), time.ticks_add()) mencakup setiap kasus.