#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
// OLED pins
#define OLED_SDA 8
#define OLED_SCL 9
// Stopwatch pins
#define START_STOP_PIN 1
#define LAP_PIN 2
#define RESET_PIN 5
// Speedometer pin
#define PROXIMITY_PIN 6
// Create display object
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// SEMAR Bitmap
static const unsigned char PROGMEM image_data_Saraarray[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xf0, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3f, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x03, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1f, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0x00, 0x1f, 0xfe, 0x3f, 0xf8, 0x3f, 0xff, 0xc1, 0xff, 0xc1, 0xff, 0x80,
0x00, 0x07, 0xff, 0xf8, 0x00, 0x3f, 0xff, 0x7f, 0xfc, 0x7f, 0xff, 0xe3, 0xff, 0xe7, 0xff, 0xc0,
0x00, 0x1f, 0xff, 0xc0, 0x00, 0x7f, 0xfe, 0xff, 0xfc, 0xff, 0xff, 0xe1, 0xff, 0xef, 0xff, 0x80,
0x00, 0x3f, 0xfe, 0x00, 0x00, 0x78, 0x00, 0xf0, 0x39, 0xe1, 0xe0, 0xe0, 0x03, 0xcf, 0x00, 0x00,
0x00, 0x7f, 0xf8, 0x00, 0x00, 0xf0, 0x01, 0xe0, 0x7b, 0xc1, 0xc1, 0xe0, 0x03, 0x9e, 0x00, 0x00,
0x01, 0xff, 0xe0, 0x00, 0x00, 0xff, 0xe1, 0xff, 0xf3, 0x83, 0x83, 0xcf, 0xff, 0xbc, 0x00, 0x00,
0x03, 0xff, 0x80, 0x00, 0x00, 0xff, 0xf3, 0xff, 0xe7, 0x87, 0x83, 0x9f, 0xff, 0x38, 0x00, 0x00,
0x07, 0xfe, 0x00, 0x00, 0x00, 0x7f, 0xf7, 0xff, 0xcf, 0x07, 0x07, 0xbf, 0xfe, 0x78, 0x00, 0x00,
0x0f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x0e, 0x0e, 0x0f, 0x78, 0x1e, 0xf0, 0x00, 0x00,
0x0f, 0xe0, 0x00, 0x00, 0x00, 0x01, 0xef, 0x00, 0x1e, 0x1e, 0x0e, 0x70, 0x3c, 0xe0, 0x00, 0x00,
0x1f, 0xc0, 0x00, 0x00, 0x0f, 0xff, 0xcf, 0xff, 0x3c, 0x1c, 0x1e, 0xff, 0xf9, 0xe0, 0x00, 0x00,
0x1f, 0xf8, 0x00, 0x00, 0x0f, 0xff, 0x8f, 0xff, 0xb8, 0x38, 0x1c, 0xff, 0xf9, 0xc0, 0x00, 0x00,
0x1f, 0xff, 0x80, 0x00, 0x07, 0xff, 0x07, 0xff, 0x10, 0x18, 0x08, 0x7f, 0xe0, 0x80, 0x00, 0x00,
0x07, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3f, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x40, 0x08, 0x00, 0x00, 0x80,
0x00, 0x01, 0xff, 0xff, 0xff, 0x80, 0x00, 0x02, 0xec, 0xdd, 0x02, 0x40, 0x54, 0x6a, 0xe5, 0x58,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xfb, 0x4c, 0xc7, 0x29, 0xf4, 0xea, 0x6f, 0x78,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x40, 0x00, 0x42, 0x09, 0x00, 0x00, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// Stopwatch variables
bool running = false;
unsigned long startTime = 0;
unsigned long elapsedTime = 0;
unsigned long lapTime = 0;
int lapCount = 0;
// Debounce variables
const unsigned long debounceDelay = 1000; // 1000ms debounce delay
unsigned long lastDebounceTime[] = {0, 0, 0}; // For start/stop, lap, and reset buttons
// Speedometer variables
const float wheelCircumference = 0.785; // Wheel circumference in meters
volatile unsigned long lastInterruptTime = 0; // Last interrupt time
volatile float speed = 0.0; // Speed in km/h
void IRAM_ATTR startStop() {
unsigned long currentMillis = millis();
if (currentMillis - lastDebounceTime[0] > debounceDelay) {
running = !running;
if (running) {
startTime = millis() - elapsedTime;
} else {
elapsedTime = millis() - startTime;
}
lastDebounceTime[0] = currentMillis;
}
}
void IRAM_ATTR lap() {
unsigned long currentMillis = millis();
if (currentMillis - lastDebounceTime[1] > debounceDelay) {
if (running) {
lapTime = millis() - startTime;
lapCount++;
}
lastDebounceTime[1] = currentMillis;
}
}
void IRAM_ATTR reset() {
unsigned long currentMillis = millis();
if (currentMillis - lastDebounceTime[2] > debounceDelay) {
running = false;
elapsedTime = 0;
lapTime = 0;
startTime = millis();
lapCount = 0;
lastDebounceTime[2] = currentMillis;
}
}
void IRAM_ATTR updateSpeed() {
unsigned long currentTime = millis();
unsigned long timeDifference = currentTime - lastInterruptTime;
lastInterruptTime = currentTime;
// Calculate speed in km/h
if (timeDifference > 0) {
speed = (wheelCircumference / (timeDifference / 1000.0)) * 3.6;
}
}
void resetSpeedIfNeeded() {
unsigned long currentTime = millis();
if (currentTime - lastInterruptTime > 3000) { // If no interrupt for 3 seconds
noInterrupts();
speed = 0.0;
interrupts();
}
}
void setup() {
Serial.begin(115200);
// Initialize OLED display
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;);
}
display.clearDisplay();
// Initialize stopwatch pins
pinMode(START_STOP_PIN, INPUT_PULLUP);
pinMode(LAP_PIN, INPUT_PULLUP);
pinMode(RESET_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(START_STOP_PIN), startStop, RISING);
attachInterrupt(digitalPinToInterrupt(LAP_PIN), lap, RISING);
attachInterrupt(digitalPinToInterrupt(RESET_PIN), reset, RISING);
// Initialize speedometer pin
pinMode(PROXIMITY_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(PROXIMITY_PIN), updateSpeed, FALLING);
// Welcome message
// Text under image
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(20, 47);
// Display static text
display.println("speedo.by proto");
// Draw bitmap on the screen
display.drawBitmap(0, 8, image_data_Saraarray, 128, 37, 1);
display.display();
delay(2000);
display.clearDisplay();
}
void loop() {
resetSpeedIfNeeded();
// Stopwatch logic
unsigned long displayTime;
if (running) {
displayTime = millis() - startTime;
} else {
displayTime = elapsedTime;
}
int seconds = (displayTime / 1000) % 60;
int minutes = (displayTime / 60000) % 60;
int milliseconds = (displayTime % 1000) / 10;
// Display logic
display.clearDisplay();
// Display stopwatch
display.setTextSize(2);
display.setCursor(16, 2);
display.printf("%02d:%02d:%02d", minutes, seconds, milliseconds);
if (lapTime >= 0) {
int lapSeconds = (lapTime / 1000) % 60;
int lapMinutes = (lapTime / 60000) % 60;
int lapMilliseconds = (lapTime % 1000) / 10;
display.setTextSize(2);
display.setCursor(16, 18);
display.printf("L%d:%02d:%02d", lapCount, lapMinutes, lapSeconds);
}
// Display speed
display.setTextSize(4);
display.setCursor(17, 34);
display.printf("%.2f", speed);
display.display();
delay(50);
}
Loading
esp32-s3-devkitc-1
esp32-s3-devkitc-1