#include <Arduino.h>
#include <U8g2lib.h>
#include <Wire.h>
// Inicializace displeje SSD1306 128x64 přes I2C
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
// Definice pinu pro tlačítko
const int BUTTON_PIN = 12;
// Nastavení časů pro stisk tlačítka (v milisekundách)
const unsigned long DEBOUNCE_DELAY = 50;
const unsigned long LONG_PRESS_TIME = 800; // Držení nad 0.8 sekundy je dlouhý stisk
// Proměnné pro stav tlačítka
bool lastButtonState = HIGH;
unsigned long buttonPressedTime = 0;
bool isPressing = false;
bool longPressHandled = false;
// Stavy obrazovek (0: Rychlost, 1: Otáčky, 2: Teplota oleje, 3: Tlak Turba)
int currentScreen = 0;
const int TOTAL_SCREENS = 4;
// Jednotky (false = Metrické, true = Imperiální)
bool unitImperialSpeed = false; // false = km/h, true = mph
bool unitImperialTemp = false; // false = °C, true = °F
bool unitImperialTurbo = false; // false = bar, true = psi
// Simulovaná data z CAN BUSu
float simSpeed = 90.0; // km/h
int simRPM = 2500; // RPM
float simOilTemp = 92.5; // °C
float simTurbo = 1.15; // bar
unsigned long lastDataUpdate = 0;
void setup() {
pinMode(BUTTON_PIN, INPUT_PULLUP); // Použití interního pull-up rezistoru
u8g2.begin();
}
// Funkce pro zpracování krátkého stisku (Přepnutí obrazovky)
void handleShortPress() {
currentScreen = (currentScreen + 1) % TOTAL_SCREENS;
}
// Funkce pro zpracování dlouhého stisku (Přepnutí jednotek podle obrazovky)
void handleLongPress() {
switch (currentScreen) {
case 0: // Rychlost
unitImperialSpeed = !unitImperialSpeed;
break;
case 1: // Otáčky (zde neměníme jednotky, ale můžeme dát efekt)
break;
case 2: // Teplota oleje
unitImperialTemp = !unitImperialTemp;
break;
case 3: // Tlak turba
unitImperialTurbo = !unitImperialTurbo;
break;
}
}
// Čtení tlačítka s rozlišením krátkého/dlouhého stisku
void checkButton() {
bool currentButtonState = digitalRead(BUTTON_PIN);
if (currentButtonState == LOW && lastButtonState == HIGH) {
// Tlačítko bylo právě stisknuto
buttonPressedTime = millis();
isPressing = true;
longPressHandled = false;
}
else if (currentButtonState == LOW && lastButtonState == LOW) {
// Tlačítko je stále drženo dole
if (isPressing && !longPressHandled && (millis() - buttonPressedTime > LONG_PRESS_TIME)) {
handleLongPress();
longPressHandled = true; // Označíme, že dlouhý stisk byl vykonán a nebudeme ho opakovat
}
}
else if (currentButtonState == HIGH && lastButtonState == LOW) {
// Tlačítko bylo právě uvolněno
if (isPressing && !longPressHandled && (millis() - buttonPressedTime > DEBOUNCE_DELAY)) {
handleShortPress();
}
isPressing = false;
}
lastButtonState = currentButtonState;
}
// Simulace měnících se dat z auta (pro efekt v simulátoru)
void simulateCanBusData() {
if (millis() - lastDataUpdate > 100) {
lastDataUpdate = millis();
// Rychlost mírně kolísá
simSpeed += random(-10, 11) * 0.1;
if (simSpeed < 0) simSpeed = 0;
if (simSpeed > 250) simSpeed = 250;
// Otáčky kopírují rychlost
simRPM = 1000 + (simSpeed * 25);
if (simRPM > 6500) simRPM = 6500;
// Teplota oleje se pomalu zahřívá/kolísá
simOilTemp += random(-2, 3) * 0.05;
// Tlak turba reaguje na otáčky
simTurbo = (simRPM > 2000) ? ((simRPM - 2000) * 0.0003) : 0.0;
}
}
void drawScreen() {
u8g2.clearBuffer();
// Horní stavový řádek (ukazuje, kde se nacházíme)
u8g2.setFont(u8g2_font_5x7_tr);
u8g2.setCursor(0, 8);
u8g2.print("CAN DATA MONITOR");
u8g2.drawHLine(0, 10, 128);
switch (currentScreen) {
case 0: // OBRAZOVKA: RYCHLOST
u8g2.setFont(u8g2_font_6x12_tr);
u8g2.drawStr(0, 22, "VEHICLE SPEED");
u8g2.setFont(u8g2_font_logisoso32_tn); // Velké písmo
u8g2.setCursor(10, 58);
if (!unitImperialSpeed) {
u8g2.print((int)simSpeed);
u8g2.setFont(u8g2_font_8x13_tr);
u8g2.drawStr(90, 54, "km/h");
} else {
int mph = simSpeed * 0.621371;
u8g2.print(mph);
u8g2.setFont(u8g2_font_8x13_tr);
u8g2.drawStr(90, 54, "mph");
}
break;
case 1: // OBRAZOVKA: OTÁČKY
u8g2.setFont(u8g2_font_6x12_tr);
u8g2.drawStr(0, 22, "ENGINE RPM");
u8g2.setFont(u8g2_font_logisoso32_tn);
u8g2.setCursor(10, 58);
u8g2.print(simRPM);
u8g2.setFont(u8g2_font_8x13_tr);
u8g2.drawStr(100, 54, "rpm");
// Spodní grafický "otáčkoměr" linka
u8g2.drawFrame(0, 61, 128, 3);
u8g2.drawBox(0, 61, map(simRPM, 1000, 6500, 0, 128), 3);
break;
case 2: // OBRAZOVKA: TEPLOTA OLEJE
u8g2.setFont(u8g2_font_6x12_tr);
u8g2.drawStr(0, 22, "OIL TEMPERATURE");
u8g2.setFont(u8g2_font_logisoso32_tn);
u8g2.setCursor(10, 58);
if (!unitImperialTemp) {
u8g2.print((int)simOilTemp);
u8g2.setFont(u8g2_font_8x13_tr);
u8g2.drawStr(90, 54, "\xb0""C"); // \xb0 vykreslí znak stupně °
} else {
int tempF = (simOilTemp * 1.8) + 32;
u8g2.print(tempF);
u8g2.setFont(u8g2_font_8x13_tr);
u8g2.drawStr(90, 54, "\xb0""F");
}
break;
case 3: // OBRAZOVKA: TLAK TURBA
u8g2.setFont(u8g2_font_6x12_tr);
u8g2.drawStr(0, 22, "TURBO BOOST");
u8g2.setFont(u8g2_font_logisoso32_tn);
u8g2.setCursor(10, 58);
if (!unitImperialTurbo) {
// Tlak na dvě desetinná místa
u8g2.print(simTurbo, 2);
u8g2.setFont(u8g2_font_8x13_tr);
u8g2.drawStr(95, 54, "bar");
} else {
float psi = simTurbo * 14.5038;
u8g2.print(psi, 1);
u8g2.setFont(u8g2_font_8x13_tr);
u8g2.drawStr(95, 54, "psi");
}
break;
}
u8g2.sendBuffer();
}
void loop() {
checkButton(); // Kontrola tlačítka
simulateCanBusData(); // Simulace dat z auta
drawScreen(); // Vykreslení aktuální obrazovky
}