⏱ Waktu & Kode Non-Blocking

millis(), kenapa delay() itu musuh, dan cara membuat program yang responsif.

πŸ“Œ 1. Masalah delay(): Program "Tidur"

Perbandingan delay dan millis
Dengan delay() program β€œtidur”; dengan millis() program tetap aktif

Saat delay(1000) berjalan, MCU tidak melakukan apa-apa selama 1 detik. Tombol tidak bisa dibaca, sensor tidak bisa diukur, LED lain tidak bisa diubah.

// BURUK: selama delay(1000), tombol diabaikan total void loop() { digitalWrite(13, HIGH); delay(1000); // MCU tidur 1 detik digitalWrite(13, LOW); delay(1000); // MCU tidur lagi }

Solusinya: kode non-blocking β€” program terus berputar, dan setiap putaran mengcek apakah waktunya sudah tiba untuk melakukan sesuatu.

πŸ“Œ 2. millis(): Jam Internal MCU

millis() mengembalikan jumlah milidetik sejak program mulai, sebagai unsigned long. Di simulator, setiap putaran loop() menambah 1 ms, dan setiap delay(ms) melompatkan ms sebanyak itu.

⚠️ millis() akan wrap (kembali ke 0) setelah ±49,7 hari. Cara aman menghitung selang waktu (tahan wrap):
unsigned long sekarang = millis(); if (sekarang - terakhir >= 1000) { // sudah lewat 1 detik sejak "terakhir" terakhir = sekarang; }
Jangan pakai if (millis() == 1000) β€” bisa terlewat, dan gagal saat wrap.
Output:

πŸ“Œ 3. Debounce Tombol

Tombol mekanik terbuat dari dua lempeng logam. Saat ditekan, lempeng itu memantul (bouncing) beberapa kali dalam Β±50 ms sebelum stabil. Bagi MCU, satu penekanan terbaca sebagai belasan perubahan HIGH/LOW.

Tombol ditekan: HIGH ──┐ β”Œβ”€β” β”Œβ”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β””β”€β”€β”˜ β””β”€β”˜ β””β”€β”€β”˜ ... β”˜ |< bounce Β±50 ms >| lalu stabil LOW selama tombol ditahan

Solusi software: saat mendeteksi perubahan, tunggu 50 ms lalu baca lagi. Jika masih sama β†’ penekanan asli.

Output:

Tanpa debounce, getar 50 ms di atas akan terhitung sebagai banyak penekanan. Dengan delay(50) + baca ulang, satu penekanan hanya terhitung satu kali.

πŸ“Œ 4. State Machine: Pola Kode Serius

Program yang "melakukan banyak hal terjadwal" biasanya ditulis sebagai state machine: program punya state (keadaan), dan setiap putaran loop memeriksa state + kondisi untuk berpindah.

IDLE --(tombol)--> AKTIF --(5 detik)--> IDLE | +--(sensor bahaya)--> ALARM --(reset)--> IDLE
Output:

πŸ“Œ 5. micros() untuk Pengukuran Presisi

micros() seperti millis() tapi dalam mikidetik β€” dipakai untuk mengukur durasi pulsa (misal sensor ultrasonik, encoder). delayMicroseconds(us) untuk jeda sangat pendek (misal pulsa TRIG 10 Β΅s).

digitalWrite(TRIG, HIGH); delayMicroseconds(10); // pulsa 10 mikidetik digitalWrite(TRIG, LOW); unsigned long mulai = micros(); while (digitalRead(ECHO) == HIGH) { } // tunggu gema unsigned long durasi = micros() - mulai; // us float jarak = durasi / 58.0; // cm (kecepatan suara)

Detail sensor ultrasonik dibahas di Sensor-Sensor Umum.

🧠 Latihan

  1. Buat 3 LED (pin 13, 12, 11) berkedip dengan periode berbeda (1 dtk, 2 dtk, 3 dtk) β€” semua non-blocking.
  2. Buat "stopwatch": tombol pin 2 mulai/stop, tombol pin 3 reset. Cetak waktu berjalan tiap detik. (Non-blocking!)
  3. Jelaskan kenapa if (millis() - terakhir >= 1000) aman terhadap wrap, sedangkan if (millis() > 1000) tidak.
  4. Ubah state machine di atas: tambahkan state ALARM yang aktif 3 detik jika sensor A0 < 100 (simulasikan sendiri).