#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// 🚨 NEW: Include the custom font header
#include <Fonts/FreeSansBold24pt7b.h>
// --- Pin Definitions ---
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define BUZZER_PIN 8
#define BUTTON_PIN 2
// Initialize the display object (same as before)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// --- Timer and State Variables (Same as before) ---
const unsigned long COUNTDOWN_DURATION = 10000;
unsigned long startTime = 0;
unsigned long timeRemaining = COUNTDOWN_DURATION;
enum TimerState { WAITING, COUNTING, TIMEOUT };
TimerState currentState = WAITING;
unsigned long lastTickTime = 0;
const int TICK_INTERVAL = 1000;
// --- Function Declarations (Same as before) ---
void buttonPressISR();
void updateDisplay(long remainingMs);
void playTickSound();
void playTimeoutTone();
void turnBuzzerOff();
// =================================================================
// SETUP (Same as before)
// =================================================================
void setup() {
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
for(;;);
}
display.display();
pinMode(BUZZER_PIN, OUTPUT);
pinMode(BUTTON_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), buttonPressISR, FALLING);
updateDisplay(COUNTDOWN_DURATION);
}
// =================================================================
// LOOP (Same as before)
// =================================================================
void loop() {
if (currentState == COUNTING) {
unsigned long currentTime = millis();
timeRemaining = COUNTDOWN_DURATION - (currentTime - startTime);
if (timeRemaining <= 0) {
currentState = TIMEOUT;
timeRemaining = 0;
playTimeoutTone();
updateDisplay(0);
} else {
if (currentTime - lastTickTime >= TICK_INTERVAL) {
updateDisplay(timeRemaining);
lastTickTime = currentTime;
playTickSound();
}
}
} else if (currentState == TIMEOUT) {
currentState = WAITING;
}
}
// =================================================================
// FUNCTIONS (Updated updateDisplay function)
// =================================================================
/**
* Updates the OLED display with the remaining time, using FreeSansBold18pt7b font.
*/
void updateDisplay(long remainingMs) {
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
if (currentState == WAITING) {
// Use a smaller font for status text
display.setFont();
display.setTextSize(2);
display.setCursor(10, 5);
display.print("READY");
display.setTextSize(1);
display.setCursor(0, 32);
display.print("Press button to start 10s");
} else if (currentState == TIMEOUT) {
// Use a smaller font for status text
display.setFont();
display.setTextSize(2);
display.setCursor(0, 20);
display.print("TIME'S UP!");
} else {
// --- Use the large custom font for the countdown ---
display.setFont(&FreeSansBold24pt7b);
display.setTextSize(1);
int seconds = (remainingMs + 999) / 1000; // Rounds up to ensure 10 is shown clearly
String timeStr = (seconds < 10 ? "0" : "") + String(seconds);
// Calculate text bounds to center the number
int16_t x1, y1;
uint16_t w, h;
display.getTextBounds(timeStr, 0, 0, &x1, &y1, &w, &h);
// Center the text: (Screen Width / 2) - (Text Width / 2)
display.setCursor((SCREEN_WIDTH - w) / 2, 45);
display.print(timeStr);
}
display.display();
}
// --- ISR, Tick, and Tone Functions (Same as before) ---
void buttonPressISR() {
static unsigned long lastInterruptTime = 0;
unsigned long interruptTime = millis();
if (interruptTime - lastInterruptTime > 100) {
startTime = millis();
lastTickTime = startTime;
timeRemaining = COUNTDOWN_DURATION;
currentState = COUNTING;
turnBuzzerOff();
}
lastInterruptTime = interruptTime;
}
void playTickSound() {
//digitalWrite(BUZZER_PIN, HIGH);
//delay(50);
//digitalWrite(BUZZER_PIN, LOW);
tone(8, 440, 50);
}
void playTimeoutTone() {
//digitalWrite(BUZZER_PIN, HIGH);
//delay(500);
//digitalWrite(BUZZER_PIN, LOW);
tone(8, 440, 500);
}
void turnBuzzerOff() {
digitalWrite(BUZZER_PIN, LOW);
}