Manajemen Waktu Non-Blocking

Mempelajari cara mengelola waktu pada Arduino tanpa menggunakan fungsi delay(), memungkinkan beberapa tugas berjalan bersamaan dengan millis().

90 Menit
Modul 4: Logika Pemrograman Menengah
Pertemuan 12

TPTujuan Pembelajaran

  1. Peserta didik dapat mengimplementasikan pola non-blocking timer menggunakan millis()
  2. Peserta didik dapat menjalankan multiple task secara simultan tanpa delay()
  3. Peserta didik dapat memahami konsep cooperative multitasking pada sistem embedded
  4. Peserta didik dapat membangun sistem yang membaca sensor, blink LED, dan cek tombol secara bersamaan

Masalah Fungsi delay()

Selama ini, kita sering menggunakan delay(1000); untuk membuat Arduino menunggu selama 1 detik. Namun, pernahkah kalian mencoba membaca sensor atau mendeteksi tombol DITENGAH-TENGAH fungsi delay() tersebut?

Pola Timer dengan millis()

Lalu, bagaimana cara menunggu tanpa menggunakan delay? Solusinya adalah dengan millis(). Fungsi millis() mengembalikan jumlah milidetik yang telah berlalu sejak Arduino dihidupkan (mirip seperti stopwatch).

Berikut adalah pola standar untuk menggunakan millis (Non-Blocking Timer):

PolaMillis.ino
cpp
unsigned long waktuSebelumnya = 0;   // Waktu terakhir event terjadi
const long INTERVAL = 1000;          // Interval waktu (1 detik)

void setup() { }

void loop() {
  unsigned long waktuSekarang = millis(); // Cek 'jam' saat ini

  // Apakah selisih waktu sudah lebih dari interval?
  if (waktuSekarang - waktuSebelumnya >= INTERVAL) {
    waktuSebelumnya = waktuSekarang; // Catat waktu sekarang untuk iterasi berikutnya
    
    // --> Lakukan aksi di sini <--
  }
}

Menjalankan Multiple Tasks

Keuntungan utama pola millis() adalah kita bisa memiliki banyak timer sekaligus! Kita bisa mengatur jadwal yang berbeda untuk tugas-tugas yang berbeda di dalam loop().

Cooperative Multitasking

Teknik ini dikenal dengan Cooperative Multitasking. Fungsi loop() akan berjalan berputar dengan sangat cepat (ribuan kali per detik). Setiap modul akan "kooperatif" hanya menjalankan tugasnya JIKA sudah saatnya tiba, lalu menyerahkan sisa waktu ke modul lain tanpa menahan program.

Studi Kasus Sistem Simultan

Mari kita terapkan dalam program nyata. Kita akan membuat program yang melakukan 3 hal sekaligus:

  1. Membaca sensor DHT setiap 2 detik.
  2. Mengedipkan LED setiap 0.5 detik (500ms).
  3. Mengecek tombol ditekan dengan respons instan (setiap 50ms untuk debounce).
MultitaskMillis.ino
cpp
// ── Task 1: Baca sensor DHT setiap 2 detik ──
unsigned long prevSensor = 0;
const long INTERVAL_SENSOR = 2000;

// ── Task 2: Blink LED setiap 500ms ──  
unsigned long prevLED = 0;
const long INTERVAL_LED = 500;
bool statusLED = false;

// ── Task 3: Cek tombol setiap 50ms (debounce) ──
unsigned long prevTombol = 0;
const long INTERVAL_TOMBOL = 50;

const int LED_PIN = 13;
const int BTN_PIN = 7;
bool tombolSebelumnya = HIGH;

void setup() {
  pinMode(LED_PIN, OUTPUT);
  pinMode(BTN_PIN, INPUT_PULLUP);
  Serial.begin(9600);
  Serial.println("Multi-Task Non-Blocking Demo");
}

void taskSensor(unsigned long sekarang) {
  if (sekarang - prevSensor >= INTERVAL_SENSOR) {
    prevSensor = sekarang;
    // Simulasi baca sensor
    Serial.print("[SENSOR] t=");
    Serial.print(sekarang);
    Serial.println("ms | Suhu: 28.5C | RH: 72%");
  }
}

void taskLED(unsigned long sekarang) {
  if (sekarang - prevLED >= INTERVAL_LED) {
    prevLED = sekarang;
    statusLED = !statusLED;
    digitalWrite(LED_PIN, statusLED);
  }
}

void taskTombol(unsigned long sekarang) {
  if (sekarang - prevTombol >= INTERVAL_TOMBOL) {
    prevTombol = sekarang;
    bool tombolSekarang = digitalRead(BTN_PIN);
    if (tombolSebelumnya == HIGH && tombolSekarang == LOW) {
      Serial.println("[TOMBOL] Tombol ditekan!");
    }
    tombolSebelumnya = tombolSekarang;
  }
}

void loop() {
  // Ambil waktu saat ini HANYA SEKALI di awal loop
  unsigned long sekarang = millis();
  
  // Semua task berbagi waktu 'sekarang' yang sama
  taskSensor(sekarang);
  taskLED(sekarang);
  taskTombol(sekarang);
  
  // loop() tidak pernah terhenti - selalu cek semua task!
}
Serial Monitor Output
Multi-Task Non-Blocking Demo [SENSOR] t=2000ms | Suhu: 28.5C | RH: 72% [TOMBOL] Tombol ditekan! [SENSOR] t=4000ms | Suhu: 28.5C | RH: 72% [SENSOR] t=6000ms | Suhu: 28.5C | RH: 72% [TOMBOL] Tombol ditekan!

Troubleshooting

Masalah:Waktu (timer) berantakan dan LED berkedip tak karuan.

Solusi:Pastikan variabel waktu sebelumnya (misal prevLED) bertipe unsigned long, bukan int. Tipe data int hanya sampai 32.767, yang akan habis (overflow) dalam 32 detik saja!

Kuis

Jika variabel penampung millis() dideklarasikan menggunakan tipe data 'int' alih-alih 'unsigned long', apa yang akan terjadi?

Tantangan

Latihan Praktik

Tantangan Lampu Lalu Lintas dan Pejalan Kaki

Buatlah program sistem lampu lalu lintas tanpa menggunakan delay(), lalu tambahkan satu task terpisah untuk menyalakan bunyi buzzer (tut...tut...tut...) setiap 1 detik terus menerus!

Syarat:

  • Lampu lalu lintas: Hijau (5 detik) - Kuning (1 detik) - Merah (5 detik)
  • Buzzer menyala secara independen dari lampu.
  • DILARANG MENGGUNAKAN DELAY()!
Kesimpulan Pertemuan Ini
  • Fungsi delay() menghentikan seluruh program (blocking).
  • Fungsi millis() memungkinkan kita membuat pola timer (non-blocking).
  • Variabel pencatat waktu wajib menggunakan tipe data unsigned long.
  • Pemisahan tugas menjadi fungsi-fungsi kecil (Modular) sangat disarankan saat menggunakan metode Multitasking.

RRefleksi

Luangkan 2–3 menit untuk menjawab pertanyaan di bawah secara jujur.

Kejutan & Penemuan

Apa yang paling mengejutkan atau menarik hari ini?

Kapan saatnya delay() masih boleh digunakan?

Masih Membingungkan

Apa yang masih membingungkan atau ingin kamu pahami lebih dalam?

Apakah penggunaan memori RAM meningkat jika menggunakan metode millis() yang banyak?

Rencana Selanjutnya

Apa yang ingin kamu coba atau pelajari minggu depan?

Tantang dirimu untuk membersihkan kode-kode lamamu dari fungsi delay() mulai dari sekarang!

Refleksi tidak dinilai — ini adalah ruang jujurmu untuk berpikir.