Chemcool Electronics

Chemcool Electronics Blog

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// OLED display settings
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// Pin assignments
const int incrementButton = 2;
const int decrementButton = 3;
const int setButton = 4;
const int buzzer = 5;

// Timer variables
unsigned int timeMinutes = 0;
bool timerActive = false;

// Debounce variables
const long debounceDelay = 50; // milliseconds
unsigned long lastDebounceTime = 0;

void setup() {
  // Initialize OLED display
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  // Set the contrast
  setDisplayContrast(0xFF); // Max contrast
  display.setTextSize(2); // Smaller text for the startup message
  display.setTextColor(SSD1306_WHITE);

  // Show startup message
  display.clearDisplay();
  display.setCursor(10,30);
  display.print("CHEM EGG");
  display.display();
  delay(3000); // Show message for 3 seconds

  // Set text size for timer display
  display.setTextSize(4);

  // Initialize buttons
  pinMode(incrementButton, INPUT_PULLUP);
  pinMode(decrementButton, INPUT_PULLUP);
  pinMode(setButton, INPUT_PULLUP);

  // Initialize buzzer
  pinMode(buzzer, OUTPUT);

  // Initial timer display
  displayTime();
}

void loop() {
  if (!timerActive) {
    checkButtons();
  }
}

void checkButtons() {
  if (millis() - lastDebounceTime > debounceDelay) {
    // Read button states
    int incrementState = digitalRead(incrementButton);
    int decrementState = digitalRead(decrementButton);
    int setState = digitalRead(setButton);

    // Increment time
    if (incrementState == LOW && timeMinutes < 20) {
      timeMinutes++;
      beep();
      displayTime();
      lastDebounceTime = millis();
    }

    // Decrement time
    if (decrementState == LOW && timeMinutes > 0) {
      timeMinutes--;
      beep();
      displayTime();
      lastDebounceTime = millis();
    }

    // Set time and start countdown
    if (setState == LOW && timeMinutes > 0) {
      beepShort();
      timerActive = true;
      lastDebounceTime = millis();
      initiateCountdown();
    }
  }
}

void initiateCountdown() {
  unsigned long startMillis = millis();
  unsigned long currentMillis;
  unsigned long prevSec = 0;
  unsigned int remainingTime = timeMinutes * 60;

  while (timerActive) {
    currentMillis = millis();
    unsigned long elapsedSec = (currentMillis - startMillis) / 1000;
    if (elapsedSec != prevSec) {
      prevSec = elapsedSec;
      remainingTime = timeMinutes * 60 - elapsedSec;
      if (remainingTime == 0) {
        timerActive = false;
        playMelody();
        timeMinutes = 0;
        displayTime();
        break;
      } else {
        displayCountdown(remainingTime);
      }
    }

    // Pre-warnings
    if (timeMinutes > 0) {
      if (remainingTime == 120) { // 2 minutes before
        interruptedBeep();
      } else if (remainingTime == 60) { // 1 minute before
        fasterInterruptedBeep();
      }
    }

    delay(100); // Small delay to prevent blocking
  }
}

void displayTime() {
  display.clearDisplay();
  display.setCursor(0,0);
  if (timeMinutes < 10) display.print("0");
  display.print(timeMinutes);
  display.print(":00");
  display.display();
}

void displayCountdown(unsigned int seconds) {
  int mins = seconds / 60;
  int secs = seconds % 60;
  display.clearDisplay();
  display.setCursor(0,0);
  if (mins < 10) display.print("0");
  display.print(mins);
  display.print(":");
  if (secs < 10) display.print("0");
  display.print(secs);
  display.display();
}

void beep() {
  tone(buzzer, 1000, 100); // 1kHz tone for 100ms
  delay(150); // Delay to prevent immediate repeat
}

void beepShort() {
  tone(buzzer, 2000, 50); // 2kHz tone for 50ms
  delay(100); // Delay to prevent immediate repeat
}

void interruptedBeep() {
  for (int i = 0; i < 10; i++) {
    tone(buzzer, 1000, 250); // 1kHz tone for 250ms
    delay(500); // On-off pattern
  }
}

void fasterInterruptedBeep() {
  for (int i = 0; i < 20; i++) {
    tone(buzzer, 1000, 125); // 1kHz tone for 125ms
    delay(250); // Faster on-off pattern
  }
}

void playMelody() {
  // Simple melody
  int melody[] = {262, 294, 330, 349, 392, 440, 494, 523, 523, 494, 440, 392, 349, 330, 294, 262}; // C4, D4, E4, F4, G4, A4, B4, C5 notes

  int noteDurations[] = {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}; // Note durations: 1/4

  for (int thisNote = 0; thisNote < 16; thisNote++) {
    int noteDuration = 1000 / noteDurations[thisNote];
    tone(buzzer, melody[thisNote], noteDuration);

    int pauseBetweenNotes = noteDuration * 1.30;
    delay(pauseBetweenNotes);
    noTone(buzzer);
  }
}

void setDisplayContrast(uint8_t contrast) {
  display.ssd1306_command(SSD1306_SETCONTRAST);
  display.ssd1306_command(contrast);
}

Introduction: The Unlikely Hero in Your Kitchen

In a world where every second counts, especially when it comes to the perfect soft-boiled egg, enter the Arduino Uno Egg Timer, the unsung hero of breakfast time. Let's embark on a quirky and technological journey to transform a simple Arduino Uno into the most versatile and reliable egg timer you never knew you needed.

The Birth of an Idea

The project started with a simple yet ambitious goal: to create an egg timer not just for timing eggs, but for making a statement about the joy of DIY electronics. We began with a breadboard, an Arduino Uno, a buzzer for auditory feedback, an OLED screen for visual elegance, and a couple of buttons to give the user control over this culinary timekeeper.

Pseudo Code: The Blueprint of Innovation

Our adventure began with outlining the logic and flow of the program through pseudo code. It's like drawing a treasure map, where 'X' marks the spot for perfectly timed eggs.

  1. Initialize System: Our journey starts by setting up the OLED screen with a font size of 4, initializing buttons for various time settings, and waking up our buzzer, ready to sing the song of its people.

  2. Display Initial Screen: The screen lights up, showing "00:00" - a canvas of time waiting to be painted with minutes and seconds.

  3. User Interaction:

    • Press the increment button: Time leaps forward by one minute, up to 20, as the buzzer beeps in approval.
    • Press the decrement button: Time retreats, but never below zero, accompanied by a confirming beep.
    • Press the set button: The chosen time is locked in, and the buzzer hums a short note of acknowledgment.
  4. Countdown and Warnings:

    • The countdown starts, displaying the remaining time.
    • Over 5 minutes? Receive a gentle reminder with a beep sequence at 3 and 2 minutes remaining.
    • Time’s up: A 10-second melody plays, a symphony signaling the end of the countdown.
  5. Reset: Like a Phoenix rising from the ashes, the display resets to the initial screen, ready for another round.

  6. Accuracy: Precision is key. We ensure that the beep and warning sequences are like a ninja - present, but never interfering with the countdown.

From Breadboard to Breakfast

As the project evolved from a nest of wires on a breadboard to a fully functional egg timer, it became clear that this was no ordinary kitchen gadget. It was a statement, a testament to the joy of creating something uniquely yours.

The Symphony of the Kitchen

Replacing the monotonous beep with a melody was a stroke of genius, transforming the end of the countdown into a moment of triumph, a small celebration of a task completed. Who knew that an egg timer could bring a dash of whimsy into the kitchen?

Conclusion: More Than Just an Egg Timer

The Arduino Uno Egg Timer is not just a tool; it's a story of creativity, fun, and the endless possibilities of DIY electronics. It's for the tinkerer, the hobbyist, the chef who loves a bit of tech with their toast. As this little device sits on your kitchen counter, remember: it's not just counting seconds. It's counting moments of joy in the journey from idea to reality.