// XIAO RP2040 - Week 4 (Fab Academy) // Interaction: Button starts LED sequence (input) // Output: 3 LEDs blink in a pattern (output) // Communication: USB Serial PC <-> XIAO (commands + logs) // // Pins used (change if needed): // LEDs: D0, D6, D7 // Button: D1 to GND (INPUT_PULLUP) const uint8_t LEDS[] = {D0, D6, D7}; const uint8_t NLEDS = sizeof(LEDS) / sizeof(LEDS[0]); const uint8_t BUTTON_PIN = D1; // button to GND // Sequence parameters bool running = false; int cyclesToRun = 7; int cycleCount = 0; int stepIndex = 0; // 0..(2*NLEDS-1) unsigned long lastStep = 0; unsigned long stepMs = 250; // animation speed // Button debounce / press-event int lastReading = HIGH; int stableState = HIGH; unsigned long lastDebounceTime = 0; const unsigned long DEBOUNCE_MS = 30; // Serial input buffer String cmd = ""; // ---------- helpers ---------- void allOff() { for (uint8_t i = 0; i < NLEDS; i++) digitalWrite(LEDS[i], LOW); } void allOn() { for (uint8_t i = 0; i < NLEDS; i++) digitalWrite(LEDS[i], HIGH); } // ---------- sequence ---------- void startSequence() { running = true; cycleCount = 0; stepIndex = 0; lastStep = millis(); allOff(); Serial.println("Button pressed -> sequence start"); } void updateSequence() { if (!running) return; unsigned long now = millis(); if (now - lastStep < stepMs) return; lastStep = now; // Pattern: turn ON LEDs forward, then turn OFF LEDs backward if (stepIndex < NLEDS) { digitalWrite(LEDS[stepIndex], HIGH); } else { int offIdx = (2 * NLEDS - 1) - stepIndex; digitalWrite(LEDS[offIdx], LOW); } stepIndex++; // End of one full cycle if (stepIndex >= 2 * NLEDS) { stepIndex = 0; cycleCount++; Serial.print("Cycle: "); Serial.println(cycleCount); if (cycleCount >= cyclesToRun) { running = false; allOff(); Serial.println("Sequence finished."); } } } // ---------- serial commands ---------- void handleCommand(String s) { // Debug: show what arrived Serial.print("RX: "); Serial.println(s); s.trim(); s.toLowerCase(); if (s == "on") { running = false; allOn(); Serial.println("OK: LEDs ON"); return; } if (s == "off") { running = false; allOff(); Serial.println("OK: LEDs OFF"); return; } if (s == "start") { if (!running) startSequence(); Serial.println("OK: start"); return; } if (s == "status") { Serial.print("running="); Serial.print(running ? "true" : "false"); Serial.print(" stepMs="); Serial.print(stepMs); Serial.print(" cyclesToRun="); Serial.println(cyclesToRun); return; } if (s.startsWith("blink ")) { int v = s.substring(6).toInt(); if (v < 50) v = 50; stepMs = (unsigned long)v; Serial.print("OK: stepMs="); Serial.println(stepMs); return; } Serial.println("ERR: try: on | off | start | status | blink 300"); } // ---------- setup / loop ---------- void setup() { Serial.begin(115200); delay(1200); // helps to see the first messages after reset for (uint8_t i = 0; i < NLEDS; i++) pinMode(LEDS[i], OUTPUT); pinMode(BUTTON_PIN, INPUT_PULLUP); allOff(); Serial.println("XIAO RP2040 ready."); Serial.println("Commands: on | off | start | status | blink "); Serial.println("Press the button to start the LED sequence."); } void loop() { // ---- Debounced button press event ---- int reading = digitalRead(BUTTON_PIN); if (reading != lastReading) { lastDebounceTime = millis(); lastReading = reading; } if (millis() - lastDebounceTime > DEBOUNCE_MS) { if (reading != stableState) { stableState = reading; // INPUT_PULLUP => pressed = LOW if (stableState == LOW) { if (!running) startSequence(); else Serial.println("Sequence already running..."); } } } // ---- Read serial command line (PC -> XIAO) ---- if (Serial.available()) { String line = Serial.readStringUntil('\n'); line.trim(); // removes \r if (line.length() > 0) handleCommand(line); } // ---- Run LED sequence (non-blocking) ---- updateSequence(); }