Projeto HUD Arduino Ago/25

 HUD_T_U_Display_Led_AtMegaTacoTermoparV12_3

/*
========================================================================================================
Projeto: HUD Car - Display LED, AtMega, Termopar, AHT10 e Bússola
  Wilson R. Bueno - 27/08/25
  Base: Usina Info e WR Kits:Indicador de Nível de Bateria com Display OLED!https://www.makerguides.com/arduino-tachometer-a3144-hall-effect-sensor/
========================================================================================================
  V0 Baseado na V1.3 * V1.0 - Incluído cartão SD-NOK ** V1.1 - Retirado cartão SD - ok **  V1.2 - Colocado Max6675 - termopar - nok
    V1.3 - otimização - ok **  V2.0 - Inclusão de bara de progresso - ok ** V2.1 - progressivo - ok
    V2.2 - inclusão de condicionais para temperatura * V3.0 - inclusão de tacômetro * V3.1 - reinclusão do termopar ok
    V5.0 - troca por diplay 0,96" - duas cores * V7.0 - baseado na V5.0 - Ok * V7.1 - otimização Maya
    V7.2 - otimização apresentação dos dados no display, mesmo sem rotação - NOK - o consumo da placa de SD é muito alto
    V7.3 - Maya otimização apresentação dos dados no display, mesmo sem rotação - Ok * V8.0 - retirado condicional para temperatura e inclusão de seleção da tela - Ok
    V8.1 - progressivo tela inicial - Ok * V8.2 - alteração para Km/h e resolver problema de início sem cabo USB //while (!Serial) {} //se habilitado, impede a inicialização até conectar o cabo USB
    V9.0 - inclusão de encoder para seleção de menus * V9.1 - alteração menus pela Maya * V9.2 - nada * V9.3 - ajustes menu
    V9.4 - ajustes menu - Ok * V9.5 - progressivo - Ok * V10.0 - inclusão bússola e acelerômetro - Ok
    V10.1 - condicional para bússola - Ok * V10.2 - progressivo - Ok * V10.3 - progressivo com iclusão do acelerômetro - Ok * V10.4 - inclusão menu - NOk * V10.5 - inclusão menu, com Maya - Ok
    V10.6 - progressivo - Ok * V10.7 - progressivo menu de abertura - Ok * V11.0 - inclusão temperatura da placa - Não disponível
    V12.0 - progressivo - Ok * V12.1 - progressivo - Ok * V12.2 - mostrar o tempo desde início - Ok
    V12.3 - inclusão de dias
*/

#include <Adafruit_SSD1306.h>
#include <Adafruit_AHT10.h>
#include <max6675.h>
#include <Encoder.h>
#include <Wire.h>
#include <LSM303.h>

// Constants for pins and display
#define thermoSCK 18
#define thermoCS 19
#define thermoSO 20
#define OLED_RESET 4
#define hallPin 7
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64

Encoder myEnc(5, 6);
MAX6675 thermocouple(thermoSCK, thermoCS, thermoSO);
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Adafruit_AHT10 aht;
LSM303 compass;  // Cria um objeto para o sensor

volatile int cnt = 0;
long oldPosition = -999;

//Mostrar a hora no menu
unsigned long previousMillis = 0;  // Armazena o último momento em que o tempo foi atualizado
const long interval = 1000;        // Intervalo para incrementar o relógio (1 segundo)
int seconds = 0;
int minutes = 0;
int hours = 0;
int days = 0;


void setup() {
  Serial.begin(9600);
  Wire.begin();
  compass.init();
  compass.enableDefault();

  inicializaDisplay();
  inicializaGeral();
}

void loop() {
  sensors_event_t humidity, temp;
  aht.getEvent(&humidity, &temp);
  float tempC = thermocouple.readCelsius();
  int rpm = calculateRPM();

  displayData(temp.temperature, humidity.relative_humidity, tempC, rpm);
}

void displayData(float temp, float humidity, float thermoTemp, int rpm) {
  display.clearDisplay();
  display.drawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SSD1306_WHITE);

  long newPosition = myEnc.read();
  if (newPosition != oldPosition) {
    oldPosition = newPosition;
    Serial.println(newPosition);
  }

  switch (newPosition) {
    case -4:
      // display.display();
      casedefault();
      casemenostres();
      break;
    case -3:
      // display.display();
      caseContador();
      break;
    case -2:
      mostrarBussola();
      break;
    case -1:
      mostrarRPMMenor(temp, humidity, thermoTemp, rpm);
      break;
    case 0:
      mostrarKmHGrande(temp, humidity, thermoTemp, rpm);
      break;
    case 1:
      mostrarTEGrande(temp, humidity, thermoTemp, rpm);
      break;
    case 2:
      mostrarBussola();
      break;
    case 3:
      casedefault();
      casetres();
      break;
    default:
      casedefault();
      break;  // Adiciona break para garantir fluxo claro
  }

  display.display();
}

void caseContador() {
  unsigned long currentMillis = millis();

  // Verifica se um segundo se passou
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;

    seconds++;  // Incrementa os segundos

    if (seconds >= 60) {
      seconds = 0;
      minutes++;
    }
    if (minutes >= 60) {
      minutes = 0;
      hours++;
    }
    if (hours >= 24) {
      hours = 0;
      days++;
    }

    display.clearDisplay();
    display.setTextSize(2);
    display.setCursor(0, 0);
    display.print("START TIME");

    display.setCursor(12, 25);
    //display.print(F("|"));
    if (hours < 10) display.print('0');
    display.print(hours);
    display.print(F(":"));
    if (minutes < 10) display.print('0');
    display.print(minutes);
    display.print(F(":"));
    if (seconds < 10) display.print('0');
    display.print(seconds);

    display.setCursor(22, 45);
    display.print(F("Day:"));
    display.print(days);

    display.display();
  }
}

void casetres() {
  display.setTextSize(2);
  display.setCursor(8, 2);
  display.print(F("======>>>"));
}

void casemenostres() {
  display.setTextSize(2);
  display.setCursor(8, 2);
  display.print(F("<<<======"));
}

void casedefault() {

  Serial.println(F("default"));
  display.clearDisplay();

  display.setTextSize(2);
  display.setCursor(8, 20);
  display.print(F("VOLTE UMA"));
  display.setCursor(18, 40);
  display.print(F("SELECAO"));

  /* Invert and restore display, pausing in-between
      display.invertDisplay(true);
      delay(1000);
      display.invertDisplay(false);
      delay(1000);
      */


  for (int16_t i = 0; i < max(display.width(), display.height()) / 2; i += 5) {
    display.drawTriangle(
      display.width() / 2, display.height() / 2 - i,
      display.width() / 2 - i, display.height() / 2 + i,
      display.width() / 2 + i, display.height() / 2 + i, SSD1306_WHITE);
    display.display();
    delay(1);
  }
}

void mostrarBussola() {
  compass.read();
  float heading = atan2(compass.m.y, compass.m.x) * 180 / PI;
  if (heading < 0) heading += 360;

  String direction = calcularDirecao(heading);
  Serial.print(F("Ponto Cardeal: "));
  Serial.println(direction);
  Serial.println(heading);

  float ax = compass.a.x / 16384.0;
  float ay = compass.a.y / 16384.0;
  float az = compass.a.z / 16384.0;
  Serial.print(F("Acelerômetro em g -> X: "));
  Serial.print(ax, 4);
  Serial.print(F(" Y: "));
  Serial.print(ay, 4);
  Serial.print(F(" Z: "));
  Serial.println(az, 4);

  display.setCursor(10, 2);
  display.setTextSize(1);
  display.print(F(":"));
  display.print(ax, 2);
  display.print(F(":"));
  display.print(ay, 2);
  display.print(F(":"));
  display.print(az, 2);
  display.print(F(":"));
  display.setCursor(4, 30);
  display.setTextSize(4);
  display.print(direction);
  display.setCursor(43, 30);
  display.print(F(":"));
  display.setCursor(60, 35);
  display.setTextSize(3);
  display.print(heading, 0);
}

String calcularDirecao(float heading) {
  if (heading >= 337.5 || heading < 22.5) return "N";
  if (heading >= 22.5 && heading < 67.5) return "NE";
  if (heading >= 67.5 && heading < 112.5) return "L";
  if (heading >= 112.5 && heading < 157.5) return "SE";
  if (heading >= 157.5 && heading < 202.5) return "S";
  if (heading >= 202.5 && heading < 247.5) return "SO";
  if (heading >= 247.5 && heading < 292.5) return "O";
  return "NO";
}

void mostrarRPMMenor(float temp, float humidity, float thermoTemp, int rpm) {
  mostrarTemperaturas(temp, humidity, thermoTemp);
  display.setTextSize(2);
  display.setCursor(42, 20);
  display.print(thermoTemp, 0);
  display.setTextSize(2);
  display.setCursor(92, 23);
  display.print(F("oC"));
  display.setTextSize(3);
  display.setCursor(10, 40);
  display.print(rpm * 60);
  display.setTextSize(2);
  display.setCursor(90, 42);
  display.print(F("rpm"));

  SerialOutput(temp, humidity, thermoTemp, rpm);
}

void mostrarKmHGrande(float temp, float humidity, float thermoTemp, int rpm) {
  mostrarTemperaturas(temp, humidity, thermoTemp);
  display.setTextSize(2);
  display.setCursor(42, 20);
  display.print(thermoTemp, 0);
  display.setTextSize(2);
  display.setCursor(92, 23);
  display.print(F("oC"));
  display.setTextSize(3);
  display.setCursor(10, 40);
  display.print(rpm);
  display.setTextSize(2);
  display.setCursor(75, 42);
  display.print(F("km/h"));

  SerialOutput(temp, humidity, thermoTemp, rpm);
}

void mostrarTEGrande(float temp, float humidity, float thermoTemp, int rpm) {
  mostrarTemperaturas(temp, humidity, thermoTemp);
  display.setTextSize(3);
  display.setCursor(42, 20);
  display.print(thermoTemp, 0);
  display.setTextSize(2);
  display.setCursor(92, 23);
  display.print(F("oC"));
  display.setTextSize(2);
  display.setCursor(10, 45);
  display.print(rpm);
  display.setCursor(72, 46);
  display.print(F("km/h"));

  SerialOutput(temp, humidity, thermoTemp, rpm);
}

void mostrarTemperaturas(float temp, float humidity, float thermoTemp) {
  display.setCursor(4, 2);
  display.setTextSize(2);
  display.print(temp, 0);
  display.print(F("oC "));
  display.setCursor(65, 2);
  display.print(humidity, 0);
  display.print(F("%HR"));
  display.setCursor(4, 23);
  display.print(F("TE:"));
}

void SerialOutput(float temp, float humidity, float thermoTemp, int rpm) {
  Serial.print(rpm);
  Serial.println(F(" km/h"));
  Serial.print(temp, 1);
  Serial.print(F(" oC <> "));
  Serial.print(humidity, 1);
  Serial.print(F(" %HR <> "));
  Serial.print(thermoTemp, 1);
  Serial.println(F(" oC"));
}

void inicializaDisplay() {
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 Fail"));
    for (;;)
      ;
  }

  display.clearDisplay();
  display.drawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SSD1306_WHITE);
  testscrolltext();  // Draw scrolling text
}

void inicializaGeral() {
  if (!aht.begin()) {
    Serial.println(F("AHT Fail"));
    while (1)
      ;
  }

  //Serial.println(F("---------------------"));
  Serial.println(F("Marelli GTS Amparo"));
  Serial.print(__TIME__);
  Serial.print(" - ");
  Serial.println(__DATE__);
  //Serial.println(F("-------------------"));
  Serial.println(F("Projeto HUD Car V12.3"));
  //Serial.println(F("---------------------"));

  pinMode(hallPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(hallPin), count, FALLING);
}

int calculateRPM() {
  unsigned long start = millis();
  cnt = 0;
  while ((millis() - start) < 1000) {
    // Waiting for 1 second
  }
  return cnt;  // Reutilizar já como km/h
}

void count() {
  cnt++;
}

void testscrolltext(void) {
  display.clearDisplay();
  display.setTextSize(2);  // Draw 2X-scale text
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(1, 0);
  display.println(F("Marelli"));
  display.setTextSize(1);
  display.setCursor(18, 24);
  display.println(F("Testing"));
  display.setCursor(10, 34);
  display.println(F("Engineering"));
  display.setCursor(8, 44);
  display.println(F("HUD Car V12.3"));
  display.setCursor(1, 54);
  display.println(F("IDE2.3.5-AGO/25"));

  display.display();  // Show initial text

  // Scroll in various directions, pausing in-between:
  display.startscrollright(0x00, 0x07);
  delay(2000);
  display.stopscroll();
  delay(1000);
  display.startscrollleft(0x00, 0x07);
  delay(2000);
  display.stopscroll();
  delay(1000);
}


Comentários