Add toothbrush-timer.ino
This commit is contained in:
199
toothbrush-timer.ino
Normal file
199
toothbrush-timer.ino
Normal file
@@ -0,0 +1,199 @@
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Adafruit_SSD1306.h>
|
||||
#include <math.h>
|
||||
|
||||
#define SCREEN_WIDTH 128
|
||||
#define SCREEN_HEIGHT 32
|
||||
#define OLED_RESET -1
|
||||
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
|
||||
|
||||
// Button and buzzer pins
|
||||
const int buttonPin = 7;
|
||||
const int buzzerPin = 8;
|
||||
|
||||
unsigned long lastUpdate = 0;
|
||||
int remaining = 0;
|
||||
bool running = false;
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Draw a star-shaped sparkle
|
||||
// ------------------------------------------------------------
|
||||
void drawStar(int x, int y) {
|
||||
display.drawPixel(x, y, SSD1306_WHITE);
|
||||
display.drawPixel(x - 1, y, SSD1306_WHITE);
|
||||
display.drawPixel(x + 1, y, SSD1306_WHITE);
|
||||
display.drawPixel(x, y - 1, SSD1306_WHITE);
|
||||
display.drawPixel(x, y + 1, SSD1306_WHITE);
|
||||
|
||||
display.drawPixel(x - 1, y - 1, SSD1306_WHITE);
|
||||
display.drawPixel(x + 1, y - 1, SSD1306_WHITE);
|
||||
display.drawPixel(x - 1, y + 1, SSD1306_WHITE);
|
||||
display.drawPixel(x + 1, y + 1, SSD1306_WHITE);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Celebration animation with glow + sparkles
|
||||
// ------------------------------------------------------------
|
||||
void showSmiley() {
|
||||
int cx = 64;
|
||||
int cy = 16;
|
||||
|
||||
unsigned long startTime = millis();
|
||||
|
||||
// --- 1. Sparkle burst at the start ---
|
||||
for (int burst = 0; burst < 12; burst++) {
|
||||
display.clearDisplay();
|
||||
|
||||
int sx, sy, dx, dy, dist;
|
||||
|
||||
// Keep sparkles OUTSIDE the face radius
|
||||
do {
|
||||
sx = random(0, 128);
|
||||
sy = random(0, 32);
|
||||
|
||||
dx = sx - cx;
|
||||
dy = sy - cy;
|
||||
dist = sqrt(dx * dx + dy * dy);
|
||||
|
||||
} while (dist < 22);
|
||||
|
||||
drawStar(sx, sy);
|
||||
|
||||
display.display();
|
||||
delay(60);
|
||||
}
|
||||
|
||||
// --- 2. Main 15-second animation ---
|
||||
while (millis() - startTime < 15000) {
|
||||
display.clearDisplay();
|
||||
|
||||
// Pulsing glow radius
|
||||
float t = (millis() - startTime) * 0.008;
|
||||
int pulse = 2 + (sin(t) * 3);
|
||||
|
||||
// Glow ring
|
||||
display.drawCircle(cx, cy, 14 + pulse, SSD1306_WHITE);
|
||||
|
||||
// Face outline
|
||||
display.drawCircle(cx, cy, 14, SSD1306_WHITE);
|
||||
|
||||
// Eyes
|
||||
display.fillCircle(cx - 6, cy - 4, 2, SSD1306_WHITE);
|
||||
display.fillCircle(cx + 6, cy - 4, 2, SSD1306_WHITE);
|
||||
|
||||
// Smile (correct orientation)
|
||||
for (int angle = 20; angle <= 160; angle += 5) {
|
||||
float rad = angle * 0.0174533;
|
||||
int x = cx + cos(rad) * 10;
|
||||
int y = cy + sin(rad) * 10;
|
||||
display.drawPixel(x, y, SSD1306_WHITE);
|
||||
}
|
||||
|
||||
// --- Twinkling sparkles (outside the face) ---
|
||||
for (int i = 0; i < 5; i++) {
|
||||
int sx, sy, dx, dy, dist;
|
||||
|
||||
do {
|
||||
sx = random(0, 128);
|
||||
sy = random(0, 32);
|
||||
|
||||
dx = sx - cx;
|
||||
dy = sy - cy;
|
||||
dist = sqrt(dx * dx + dy * dy);
|
||||
|
||||
} while (dist < 22); // keep sparkles OUTSIDE the face + glow
|
||||
|
||||
drawStar(sx, sy);
|
||||
}
|
||||
|
||||
display.display();
|
||||
delay(120);
|
||||
}
|
||||
|
||||
// Turn off the display after animation
|
||||
display.clearDisplay();
|
||||
display.display();
|
||||
display.ssd1306_command(SSD1306_DISPLAYOFF);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Draw the horizontal countdown bar + digits
|
||||
// ------------------------------------------------------------
|
||||
void drawTimer() {
|
||||
display.clearDisplay();
|
||||
|
||||
// Bar dimensions
|
||||
int barHeight = 32;
|
||||
int barWidth = 96;
|
||||
|
||||
// Map remaining seconds to bar width
|
||||
int currentWidth = map(remaining, 0, 90, 0, barWidth);
|
||||
|
||||
// Draw bar left → right
|
||||
display.fillRect(0, 0, currentWidth, barHeight, SSD1306_WHITE);
|
||||
|
||||
// Digits on the right
|
||||
display.setTextSize(2);
|
||||
display.setTextColor(SSD1306_WHITE);
|
||||
|
||||
int digitX = 100;
|
||||
int digitY = 10;
|
||||
|
||||
display.setCursor(digitX, digitY);
|
||||
display.print(remaining);
|
||||
|
||||
display.display();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Setup
|
||||
// ------------------------------------------------------------
|
||||
void setup() {
|
||||
pinMode(buttonPin, INPUT_PULLUP);
|
||||
pinMode(buzzerPin, OUTPUT);
|
||||
|
||||
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
|
||||
display.clearDisplay();
|
||||
display.setRotation(0); // horizontal
|
||||
display.display();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Main loop
|
||||
// ------------------------------------------------------------
|
||||
void loop() {
|
||||
// Start timer on button press
|
||||
if (!running && digitalRead(buttonPin) == LOW) {
|
||||
remaining = 90;
|
||||
running = true;
|
||||
display.ssd1306_command(SSD1306_DISPLAYON);
|
||||
|
||||
delay(200); // debounce
|
||||
}
|
||||
|
||||
if (running) {
|
||||
unsigned long now = millis();
|
||||
|
||||
// Update once per second
|
||||
if (now - lastUpdate >= 1000) {
|
||||
lastUpdate = now;
|
||||
remaining--;
|
||||
|
||||
// Final 5-second countdown beeps (higher pitch)
|
||||
if (remaining > 0 && remaining <= 5) {
|
||||
tone(buzzerPin, 3000, 150); // 3 kHz beep
|
||||
}
|
||||
// Regular 10-second interval beeps
|
||||
else if (remaining > 0 && remaining % 10 == 0) {
|
||||
tone(buzzerPin, 2000, 150); // 2 kHz beep
|
||||
}
|
||||
|
||||
if (remaining <= 0) {
|
||||
running = false;
|
||||
showSmiley();
|
||||
}
|
||||
}
|
||||
|
||||
drawTimer();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user