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: