#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <math.h>
// =========================================================================
// CONFIGURAÇÕES DO PROJETO - AJUSTE AQUI OS SEUS DADOS
// =========================================================================
const int NUMERO_CILINDROS = 4; // Opções: 1, 2, 4, 6 ou 8 cilindros
// Configurações do sensor NTC 10k
const float TERMISTOR_NOMINAL = 10000.0;
const float TEMP_NOMINAL = 25.0;
const float FATOR_BETA = 3950.0;
const float RESISTOR_DIVISOR_NTC = 10000.0;
// Configurações do Divisor de Tensão da Bateria
const float R1 = 10000.0; // Resistor de 10k ohms (ligado ao +12V)
const float R2 = 4700.0; // Resistor de 4.7k ohms (ligado ao GND)
// =========================================================================
LiquidCrystal_I2C lcd(0x27, 20, 4);
// Pinos de entrada
const byte pinoInterrupcao = 2; // Platinado (Digital 2)
const byte pinoNTC = A0; // Temperatura (Analógico A0)
const byte pinoBateria = A1; // Voltagem (Analógico A1)
// Variáveis do RPM (Adicionado volatile para segurança das interrupções)
volatile unsigned int contadorPulsos = 0;
volatile unsigned long ultimoTempoPulso = 0;
unsigned long tempoAnterior = 0;
float rpm = 0;
float pulsosPorVolta = 0;
// Variáveis de Cálculo
unsigned long tempoAtual;
int rpmExibir, leituraBateria, leituraNTC;
float tensaoPortaV, tensaoBateria, resistenciaNTC, temperaturaCelsius;
unsigned int copiaPulsos;
void setup()
{
pinMode(pinoInterrupcao, INPUT_PULLUP); // Recomendado usar PULLUP para sinal de platinado/ignição
pulsosPorVolta = (float)NUMERO_CILINDROS / 2.0;
lcd.init();
lcd.backlight();
// Tela de Inicialização
lcd.setCursor(0, 0);
lcd.print(" MULTIMETER PANEL ");
lcd.setCursor(0, 2);
lcd.print("Config: ");
lcd.print(NUMERO_CILINDROS);
lcd.print(" Cylinders");
lcd.setCursor(0, 3);
lcd.print("Calib. System");
for (int i = 14; i < 20; i++)
{
lcd.setCursor(i, 3);
lcd.print(".");
delay(500);
}
lcd.clear();
// Desenha o layout fixo nas 4 linhas do display
lcd.setCursor(0, 0);
lcd.print("ROTACAO: RPM");
lcd.setCursor(0, 1);
lcd.print("TENSAO : V");
lcd.setCursor(0, 2);
lcd.print("TEMP. : oC");
lcd.setCursor(0, 3);
lcd.print("STATUS : OK");
attachInterrupt(digitalPinToInterrupt(pinoInterrupcao), contarPulsoComFiltro, FALLING);
}
void loop()
{
tempoAtual = millis();
// Atualiza tudo a cada 500ms
if (tempoAtual - tempoAnterior >= 500)
{
calculaRPM();
calculaBateria();
calculaTemp();
mostraRPM();
mostraBateria();
mostraTemp();
tempoAnterior = tempoAtual;
}
}
void contarPulsoComFiltro()
{
unsigned long tempoAgora = micros(); // Variável local, liberando memória global
// 3000 microssegundos = Bloqueia ruídos acima de ~20.000 RPM em 4 cil. Perfeito.
if (tempoAgora - ultimoTempoPulso > 1000)
{
contadorPulsos++;
ultimoTempoPulso = tempoAgora;
}
}
void calculaRPM()
{
noInterrupts();
copiaPulsos = contadorPulsos;
contadorPulsos = 0;
interrupts();
if (copiaPulsos == 0)
{
rpm = 0;
}
else
{
rpm = (copiaPulsos * 120.0) / pulsosPorVolta;
}
rpmExibir = (int)rpm;
}
void calculaBateria()
{
leituraBateria = analogRead(pinoBateria);
tensaoPortaV = (leituraBateria * 5.0) / 1023.0;
// Correção matemática do divisor de tensão: R2 / (R1 + R2)
float divisorProporcao = R2 / (R1 + R2);
tensaoBateria = tensaoPortaV / divisorProporcao;
}
void calculaTemp()
{
leituraNTC = analogRead(pinoNTC);
// Evita divisão por zero se a leitura for 1023
if (leituraNTC >= 1023) leituraNTC = 1022;
if (leituraNTC <= 0) leituraNTC = 1;
resistenciaNTC = RESISTOR_DIVISOR_NTC / ((1023.0 / leituraNTC) - 1.0);
temperaturaCelsius = resistenciaNTC / TERMISTOR_NOMINAL;
temperaturaCelsius = log(temperaturaCelsius);
temperaturaCelsius /= FATOR_BETA;
temperaturaCelsius += 1.0 / (TEMP_NOMINAL + 273.15);
temperaturaCelsius = 1.0 / temperaturaCelsius;
temperaturaCelsius -= 273.15;
}
void mostraRPM()
{
lcd.setCursor(9, 0);
if (rpmExibir < 10) { lcd.print(" "); }
else if (rpmExibir < 100) { lcd.print(" "); }
else if (rpmExibir < 1000) { lcd.print(" "); }
else if (rpmExibir < 10000){ lcd.print(" "); }
lcd.print(rpmExibir);
}
void mostraBateria()
{
lcd.setCursor(9, 1);
if (tensaoBateria < 10.0) { lcd.print(" "); } // Dois espaços se for menor que 10V (ex: " 9.50")
//else { lcd.print(" "); } // Um espaço se for maior que 10V (ex: "12.60")
lcd.print(tensaoBateria, 2);
}
void mostraTemp()
{
lcd.setCursor(9, 2);
// Mantém o cursor fixo na posição 9 e limpa com espaços baseado no tamanho do número
if (temperaturaCelsius >= 100.0) { lcd.print(""); } // Sem espaços extras (ex: "105.2")
else if (temperaturaCelsius >= 10.0) { lcd.print(" "); } // 1 espaço (ex: " 85.4")
else if (temperaturaCelsius >= 0.0) { lcd.print(" "); } // 2 espaços (ex: " 5.1")
else { lcd.print(" "); } // 1 espaço para temperaturas negativas (ex: "-5.2")
lcd.print(temperaturaCelsius, 1);
}