Week 9

Output Devices


Part 1: Designing the PCB

The assignment for this week was to add an output device to a microcontroller board you've designed and program it to do something. My goal was to make a stopwatch, with buttons to start, clear, and increase time on the stopwatch, an OLED screen to display the countdown timer, and an LED light that turns on when the timer reaches zero.

I started off with designing the PCB board in KiCad. This was a bit more complicated than some of the previous boards I've done, and I had some problems with routing initially that led me to change which pins some of the buttons were using. I ended up with this schematic:

I also added some decorative traces as icons for the different buttons (start, clear, add time). That gave me this final PCB:

Part 2: Milling

For milling, I exported the PCB from KiCad to an SVG file, and then used Illustrator to invert the colors and export the edges and traces as PNG files:

I used the Mods milling software (here) with the directions here.

After running the traces and the edge cuts and cleaning up the board / cleaning up the dust from the milling, I ended up with this board:

Part 3: Soldering

Next, I soldered the components onto the board. I used an XIAO Esp32-c3 microcontroller, three buttons, an OLED screen, and an LED light. To secure the OLED screen, I used female headers. Soldering went faster this time than the last time, and I ended up with this board:

Part 4: Programming

Finally, I needed to write code to upload to the microcontroller to get the OLED to display the timer behavior I wanted. I started with a simple version, just trying to get the OLED screen to work and display a count down (without using interaction from the buttons). This was the code to get that functionality:


              
    #include <Wire.h>
    #include <Adafruit_GFX.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);
    
    int countdownTime = -1; // Initialize with an invalid countdown time to avoid accidental starts
    
    void setup() {
      // Initialize Serial Monitor for input
      Serial.begin(115200);
      Serial.println("Enter countdown time in seconds:");
    
      // Initialize the OLED display with I2C address 0x3C
      if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
        Serial.println("OLED initialization failed!");
        while (true);
      }
    
      display.clearDisplay();
      display.setTextSize(2);      
      display.setTextColor(SSD1306_WHITE);
      
      // Display prompt on OLED to enter time
      display.setCursor(0, 0);
      display.print("Enter time:");
      display.display();
    }
    
    void loop() {
      // Check if there's any input from the Serial Monitor
      if (Serial.available() > 0) {
        // Read the input as an integer
        int newTime = Serial.parseInt();
        
        // Only start countdown if the input is greater than 0
        if (newTime > 0) {
          countdownTime = newTime;
          Serial.print("Starting countdown from: ");
          Serial.println(countdownTime);
    
          // Start the countdown
          for (int i = countdownTime; i >= 0; i--) {
            display.clearDisplay();     // Clear the display at the start of each loop
            display.setCursor(0, 0);    // Set the cursor to the top-left corner
            display.print("Countdown:"); 
            display.setCursor(0, 30);   // Set cursor below the title
            display.print(i);           // Print the current countdown number
            display.display();          // Display the text on the OLED
    
            Serial.print("Countdown: "); // For debugging in Serial Monitor
            Serial.println(i);
    
            delay(1000);  // Wait for 1 second
          }
    
          // After countdown, display "Done" on OLED and prompt for new input
          display.clearDisplay();
          display.setCursor(0, 0);
          display.print("Countdown:");
          display.setCursor(0, 30);
          display.print("Done!");
          display.display();
    
          // Serial prompt for next countdown
          Serial.println("Enter countdown time in seconds:");
    
          // Display "Enter time" on OLED to prompt new input
          delay(3000);  // Keep "Done!" on screen for a moment
          display.clearDisplay();
          display.setCursor(0, 0);
          display.print("Enter time:");
          display.display();
    
          // Reset countdownTime to -1 to wait for a valid new input
          countdownTime = -1;
        }
      }
    
      delay(100); // Small delay to avoid excessive polling
    }
                

This code prompts the user to enter a time in seconds, then counts down from that time to zero. After the countdown is done, it prompts the user to enter a new time. This gave me this simple countdown timer: