#include <U8g2lib.h>
#include <Wire.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
// Define new pins for SDA and SCL
#define OLED_SDA A2
#define OLED_SCL A3
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, OLED_SCL, OLED_SDA, U8X8_PIN_NONE);
#define sensor_pin 2
#define battery_pin A0 // Analog pin to read battery voltage
const float wheel_circumference = 0.125; // Wheel circumference in meters (adjust as needed)
volatile unsigned long lastPulseTime;
volatile unsigned long currentPulseTime;
volatile float speed = 0;
void sensorIsr() {
currentPulseTime = micros();
unsigned long interval = currentPulseTime - lastPulseTime;
if (interval > 5000) { // Ignore very short intervals to avoid noise
float timeInSeconds = interval / 1000000.0; // Convert microseconds to seconds
speed = (wheel_circumference / timeInSeconds) * 3.6; // Speed in km/h
lastPulseTime = currentPulseTime;
}
}
void setup() {
Serial.begin(115200);
delay(500);
pinMode(sensor_pin, INPUT);
attachInterrupt(digitalPinToInterrupt(sensor_pin), &sensorIsr, FALLING);
lastPulseTime = 0;
// Initialize U8g2 library
u8g2.begin();
}
void drawBatteryIndicator() {
int batteryLevel = analogRead(battery_pin);
float voltage = batteryLevel * (5.0 / 1023.0); // Convert ADC reading to voltage
// Draw smaller battery outline with increased top margin
u8g2.drawFrame(108, 3, 14, 7);
u8g2.drawFrame(122, 5, 2, 3); // Battery terminal
// Fill battery level in 3 segments
int segmentWidth = 4; // Width of each segment
int batteryWidth = map(voltage, 3.0, 4.2, 0, 12); // Assuming 3.0V to 4.2V range
for (int i = 0; i < 3; i++) {
if (batteryWidth > i * segmentWidth) {
int fillWidth = min(segmentWidth, batteryWidth - i * segmentWidth);
u8g2.drawBox(110 + i * segmentWidth, 5, fillWidth, 3);
}
}
}
void drawSpeedArc(float speed) {
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_5x8_tr); // Use a smaller font for the numbers
int centerX = SCREEN_WIDTH / 2;
int centerY = SCREEN_HEIGHT - 1; // Position the speedometer at the very bottom
int radius = 30; // Increase radius for a bigger arc
int startAngle = 210; // Start angle for the arc (wider arc)
int endAngle = map(speed, 0, 100, 210, -30); // Adjust the end angle accordingly
// Draw the arc with a gradient effect
for (int angle = startAngle; angle >= endAngle; angle--) {
int x = centerX + radius * cos(radians(angle));
int y = centerY - radius * sin(radians(angle));
u8g2.drawPixel(x, y);
}
// Draw a border around the arc
for (int angle = startAngle; angle >= -30; angle--) {
int x = centerX + (radius + 1) * cos(radians(angle));
int y = centerY - (radius + 1) * sin(radians(angle));
u8g2.drawPixel(x, y);
}
// Add numbers along the arc
for (int i = 0; i <= 100; i += 20) {
int angle = map(i, 0, 100, 210, -30);
int x = centerX + (radius + 12) * cos(radians(angle)); // Move numbers further out
int y = centerY - (radius + 12) * sin(radians(angle));
u8g2.setCursor(x - 3, y - 3); // Adjust position to center the numbers
u8g2.print(i);
}
// Ensure the "100" text is displayed
int angle = map(100, 0, 100, 210, -30);
int x = centerX + (radius + 12) * cos(radians(angle)); // Move numbers further out
int y = centerY - (radius + 12) * sin(radians(angle));
u8g2.setCursor(x - 3, y - 3);
u8g2.print(100);
// Add speed ticks along the arc
for (int i = 0; i <= 100; i += 10) {
int angle = map(i, 0, 100, 210, -30);
int x1 = centerX + radius * cos(radians(angle));
int y1 = centerY - radius * sin(radians(angle));
int x2 = centerX + (radius - 5) * cos(radians(angle));
int y2 = centerY - (radius - 5) * sin(radians(angle));
u8g2.drawLine(x1, y1, x2, y2);
}
// Draw the needle
int needleAngle = map(speed, 0, 100, 210, -30);
int needleX = centerX + radius * cos(radians(needleAngle));
int needleY = centerY - radius * sin(radians(needleAngle));
u8g2.drawLine(centerX, centerY, needleX, needleY);
// Draw the needle base
u8g2.drawDisc(centerX, centerY, 2);
// Draw the battery indicator
drawBatteryIndicator();
// Display the numerical speed value in the upper left corner
u8g2.setCursor(4, 8); // Adjust for margin
u8g2.setFont(u8g2_font_ncenB08_tr);
u8g2.print("Speed:");
u8g2.setFont(u8g2_font_ncenB14_tr);
u8g2.setCursor(4, 28); // Adjust for margin
u8g2.print(speed, 1); // Display speed with one decimal place
u8g2.setFont(u8g2_font_5x8_tr); // Use a smaller font for "km/h"
u8g2.print(" km/h");
u8g2.sendBuffer();
}
void loop() {
drawSpeedArc(speed);
delay(500);
}