Cheng & RubyCircuit
RubyCircuit RubyCircuit
Cheng, I've been tinkering with the idea of a microcontroller driven puzzle that lets you solve logic gates by wiring LEDs, think of it as a hardware escape room. I’m thinking of using an ESP32 with an OLED, and I need to iron out the timing of the state machine for the solver. You up for debugging this together?
Cheng Cheng
Sounds like a fun challenge, let’s dive in—first things first, make sure your clock source is stable, otherwise the state machine will act like a squirrel on espresso. Then we can lock down the debounce windows for the button inputs, because nobody wants a flaky circuit that thinks it’s a game of Simon. Ready to sketch out the state diagram together?
RubyCircuit RubyCircuit
Sure, let's nail it down. Start with a 32 MHz external crystal for the ESP32, lock it in, and use the internal RC for low‑power mode if needed. Then map the state machine: IDLE → READ_INPUT → EVAL_GATES → OUTPUT_LED. Keep each transition bounded by a 10 ms debounce on the buttons. Once you’ve drafted that, send me the code and I’ll spot any race conditions.
Cheng Cheng
```c #include <Arduino.h> #include <Wire.h> #include <Adafruit_SSD1306.h> #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 #define OLED_RESET -1 Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); #define BUTTON_PIN 15 #define LED_PIN 2 enum State {IDLE, READ_INPUT, EVAL_GATES, OUTPUT_LED}; volatile State currentState = IDLE; unsigned long lastDebounce = 0; const unsigned long debounceDelay = 10; // ms bool buttonPressed = false; // Simple gate example: AND of two inputs bool inputA = false; bool inputB = false; bool result = false; // Pin setup void setupPins() { pinMode(BUTTON_PIN, INPUT_PULLUP); pinMode(LED_PIN, OUTPUT); digitalWrite(LED_PIN, LOW); } // Read button with debounce void checkButton() { bool reading = !digitalRead(BUTTON_PIN); // active low if (reading != buttonPressed) { lastDebounce = millis(); buttonPressed = reading; } if ((millis() - lastDebounce) > debounceDelay && buttonPressed) { buttonPressed = false; // reset flag // toggle one of the inputs inputA = !inputA; } } // State machine loop void loopStateMachine() { switch (currentState) { case IDLE: if (digitalRead(BUTTON_PIN) == LOW) { // button pressed currentState = READ_INPUT; } break; case READ_INPUT: checkButton(); currentState = EVAL_GATES; break; case EVAL_GATES: // Example: AND gate result = inputA && inputB; currentState = OUTPUT_LED; break; case OUTPUT_LED: digitalWrite(LED_PIN, result ? HIGH : LOW); // Show status on OLED display.clearDisplay(); display.setTextSize(1); display.setTextColor(SSD1306_WHITE); display.setCursor(0,0); display.print("A:"); display.print(inputA ? "1" : "0"); display.print(" B:"); display.print(inputB ? "1" : "0"); display.print(" OUT:"); display.println(result ? "1" : "0"); display.display(); currentState = IDLE; break; } } void setup() { Serial.begin(115200); // Configure crystal oscillator (assumed set in SDK) // Switch to internal RC for low-power when needed via sleep routines (not shown) setupPins(); if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { Serial.println(F("SSD1306 allocation failed")); for(;;); } display.clearDisplay(); display.display(); } void loop() { loopStateMachine(); } ```