// Week 08 — board functionality test (Week 06 XIAO RP2040 breakout). // One button cycles the LED through three modes: OFF -> SLOW -> FAST -> OFF... // Non-blocking (millis-based). Button is active-HIGH (external 10k pull-down). // // Pin mapping note (XIAO RP2040, Earle Philhower core): // silk D9 = GPIO4 -> the LED // silk D10 = GPIO3 -> the button // Using the D9/D10 macros instead of raw integers keeps the code aligned with // the board silk and removes the silk-vs-GPIO confusion entirely. const int LED_PIN = D9; // silk D9 (GPIO4) const int BUTTON_PIN = D10; // silk D10 (GPIO3), external pull-down -> pressed = HIGH const unsigned long DEBOUNCE_MS = 30; // stable window before a reading counts const unsigned long SLOW_INTERVAL_MS = 500; // half-period of the slow blink const unsigned long FAST_INTERVAL_MS = 125; // half-period of the fast blink enum Mode { MODE_OFF, MODE_SLOW, MODE_FAST }; Mode currentMode = MODE_OFF; bool ledState = false; // current LED output level unsigned long lastBlinkTime = 0; // last LED toggle timestamp unsigned long lastDebounceTime = 0; // last raw-reading change timestamp int lastButtonReading = LOW; // previous raw reading (for change detection) int buttonState = LOW; // debounced, stable button state void setup() { pinMode(LED_PIN, OUTPUT); pinMode(BUTTON_PIN, INPUT); // external pull-down: do NOT use INPUT_PULLUP digitalWrite(LED_PIN, LOW); Serial.begin(115200); } void loop() { handleButton(); // detect a debounced press and advance the mode updateLed(); // drive the LED according to the current mode } // --- button: debounce + rising-edge detection --- void handleButton() { int reading = digitalRead(BUTTON_PIN); if (reading != lastButtonReading) { lastDebounceTime = millis(); // input moved: restart the debounce timer } if (millis() - lastDebounceTime > DEBOUNCE_MS) { // the reading has been stable long enough to be trusted if (reading != buttonState) { buttonState = reading; if (buttonState == HIGH) { // LOW -> HIGH transition = a real press advanceMode(); } } } lastButtonReading = reading; } void advanceMode() { switch (currentMode) { case MODE_OFF: currentMode = MODE_SLOW; break; case MODE_SLOW: currentMode = MODE_FAST; break; case MODE_FAST: currentMode = MODE_OFF; break; } // start the new mode from a clean phase lastBlinkTime = millis(); ledState = false; digitalWrite(LED_PIN, LOW); Serial.print("Mode -> "); Serial.println(currentMode == MODE_OFF ? "OFF" : currentMode == MODE_SLOW ? "SLOW" : "FAST"); } // --- LED: non-blocking blink according to the current mode --- void updateLed() { if (currentMode == MODE_OFF) { if (ledState) { // make sure it ends up off ledState = false; digitalWrite(LED_PIN, LOW); } return; } unsigned long interval = (currentMode == MODE_SLOW) ? SLOW_INTERVAL_MS : FAST_INTERVAL_MS; if (millis() - lastBlinkTime >= interval) { lastBlinkTime = millis(); ledState = !ledState; digitalWrite(LED_PIN, ledState ? HIGH : LOW); } }