#include <TimerOne.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// Inicializa el LCD en la dirección 0x27 (puede variar)
LiquidCrystal_I2C lcd(0x27, 16, 2); // 16 columnas y 2 filas
// Definición de pines para los botones
const int buttonUp = 2; // Botón para subir en el menú
const int buttonDown = 3; // Botón para bajar en el menú
const int buttonSelect = 4; // Botón para seleccionar opción
// Definición de los pines de los LEDs
const int ledPinBobinaPura = 6; // Pin donde está conectado el LED de Bobina Pura
const int ledPinBobinaTrans = 7; // Pin donde está conectado el LED de Bobina Trans
const int ledPinInyectores = 8; // Pin donde está conectado el LED de Inyectores
const int ledPinPWM = 9; // Nuevo LED para PWM
const int potPin = A0; // Pin donde está conectado el potenciómetro y duty cycle (20% a 60%)
const int potPinFreq = A1; // Potenciómetro para frecuencia (1hz - 500hz)
int menuIndex = 0;
int subMenuIndex = 0;
bool inSubMenu = false;
bool executing = false; // Variable para controlar la ejecución
int freqValue;
int dutyCicle;
const char* menuItems[] = {
"Bobina Pura",
"Bobina Trans",
"Inyectores",
"C. Acel TAC"
};
const char* subMenuBobina[] = {
"3ms a 1Hz",
"3ms - RPM",
"Salir"
};
const char* subMenuInyectores[] = {
"3ms a 15Hz",
"3ms a 70Hz",
"250ms a 1Hz",
"3ms a 15hz-3s",
"Salir"
};
const char* subMenuBTI[] = {
"f & D Variable",
"Salir"
};
// Prototipos de funciones
void mostrarMenu();
void entrarSubmenu();
void seleccionarOpcionSubmenu();
int obtenerNumeroOpciones();
const char* obtenerOpcionSubmenu(int index = -1);
void mostrarMensajeInicial();
void rutinaBobinaPura();
void rutinaBobinaTrans();
void rutinaBobinaPuraRPM();
void rutinaBobinaTransRPM();
void rutinaInyectores();
void rutinaPWM();
void mostrarEjecutando();
unsigned long previousMillisBobinaPura = 0; // Almacena el tiempo anterior Bobina Pura
unsigned long previousMillisBobinaTrans = 0; // Almacena el tiempo anterior Bobina Trans
unsigned long previousMillisInyectores = 0; // Almacena el tiempo anterior Inyectores
bool ledStateBobinaPura = false; // Estado del LED de Bobina Pura
bool ledStateBobinaTrans = false; // Estado del LED de Bobina Trans
bool ledStateInyectores = false; // Estado del LED de Inyectores
unsigned long ledOnTime = 3; // Tiempo en milisegundos que el LED estará encendido
unsigned long ledOffTime = 997; // Tiempo en milisegundos que el LED estará apagado para "3ms a 1Hz"
void setup() {
Timer1.initialize(1000); // Inicializa com 1 milisegundo
int freqValue = map(analogRead(potPinFreq), 0, 1023, 1, 500); // Mapea el potenciómetro a frecuencia
//double periodo = 1000000.0 / freqValue; // Calcula el período en microsegundos
int rawDutyCycle = analogRead(potPin); // Lee el valor del potenciómetro para el duty cycle
int dutyCicle = map(rawDutyCycle, 0, 1023, 20, 60); // Mapea el valor a un rango de 0 a 100
lcd.begin(16, 2);
lcd.backlight();
// Configura los pines de los botones como entrada
pinMode(buttonUp, INPUT_PULLUP);
pinMode(buttonDown, INPUT_PULLUP);
pinMode(buttonSelect, INPUT_PULLUP);
// Configura los pines de los LEDs como salida
pinMode(ledPinBobinaPura, OUTPUT);
pinMode(ledPinBobinaTrans, OUTPUT);
pinMode(ledPinInyectores, OUTPUT); // Inicializa el pin de inyectores
mostrarMensajeInicial(); // Mostrar mensaje inicial
mostrarMenu(); // Mostrar menú después del mensaje
}
void loop() {
// Comprobar si se está ejecutando una rutina
if (!executing) {
if (digitalRead(buttonUp) == LOW) {
if (inSubMenu) {
subMenuIndex = (subMenuIndex - 1 + obtenerNumeroOpciones()) % obtenerNumeroOpciones();
} else {
menuIndex = (menuIndex - 1 + 4) % 4; // Navega en el menú principal
}
mostrarMenu();
delay(200); // Debounce
}
if (digitalRead(buttonDown) == LOW) {
if (inSubMenu) {
subMenuIndex = (subMenuIndex + 1) % obtenerNumeroOpciones();
} else {
menuIndex = (menuIndex + 1) % 4; // Navega en el menú principal
}
mostrarMenu();
delay(200); // Debounce
}
}
if (digitalRead(buttonSelect) == LOW) {
if (executing) {
// Detener la rutina
executing = false; // Detener ejecución
digitalWrite(ledPinBobinaPura, LOW); // Asegúrate de apagar el LED de Bobina Pura
digitalWrite(ledPinBobinaTrans, LOW); // Asegúrate de apagar el LED de Bobina Trans
digitalWrite(ledPinInyectores, LOW); // Asegúrate de apagar el LED de Inyectores
digitalWrite(ledPinPWM, LOW); // Asegúrate de apagar el LED PWM
mostrarMenu(); // Regresar al menú
} else {
if (inSubMenu) {
seleccionarOpcionSubmenu();
} else {
entrarSubmenu();
}
}
delay(200); // Debounce
}
// Ejecutar rutina si está en ejecución
if (executing) {
switch (menuIndex) {
case 0:
if (subMenuIndex == 1) {
rutinaBobinaPuraRPM(); // Lógica para "3ms - RPM" de Bobina Pura
} else if (subMenuIndex == 0) {
rutinaBobinaPura(); // Lógica para "3ms a 1Hz" de Bobina Pura
}
break;
case 1:
if (subMenuIndex == 1) {
rutinaBobinaTransRPM(); // Lógica para "3ms - RPM" de Bobina Trans
} else if (subMenuIndex == 0) {
rutinaBobinaTrans(); // Lógica para "3ms a 1Hz" de Bobina Trans
}
break;
case 2:
rutinaInyectores(); // Ejecutar rutina de inyectores
break;
case 3:
rutinaPWM(); // Ejecutar rutina de PWM para el menú BTI
break;
// Agregar otras rutinas según el menú principal
}
}
}
// Función para mostrar el mensaje inicial
void mostrarMensajeInicial() {
lcd.clear();
lcd.setCursor(2, 0); // Centrar "PROBADOR"
lcd.print("--PROBADOR--");
lcd.setCursor(1, 1); // Centrar "SCOPERAUTO"
lcd.print("--SCOPERAUTO--");
delay(1000); // Esperar 5 segundos
lcd.clear(); // Limpiar la pantalla
}
// Función para mostrar el menú
void mostrarMenu() {
lcd.clear();
if (inSubMenu) {
// Mostrar el nombre del menú seleccionado en la primera línea
lcd.setCursor(0, 0);
lcd.print(menuItems[menuIndex]); // Nombre del menú
lcd.setCursor(0, 1);
lcd.print(">");
lcd.setCursor(1, 1);
lcd.print(obtenerOpcionSubmenu()); // Mostrar opción seleccionada
} else {
// Mostrar menú principal con selección
lcd.setCursor(0, 0);
lcd.print(">");
lcd.setCursor(1, 0);
lcd.print(menuItems[menuIndex]);
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(1, 1);
lcd.print(menuItems[(menuIndex + 1) % 4]); // Muestra la siguiente opción
}
}
// Función para entrar en el submenú
void entrarSubmenu() {
inSubMenu = true;
subMenuIndex = 0; // Regresa al inicio del submenú
mostrarMenu();
}
// Función para seleccionar una opción del submenú
void seleccionarOpcionSubmenu() {
const char* opcionSeleccionada = obtenerOpcionSubmenu();
// Mostrar el nombre del ítem seleccionado y "Ejecutando..."
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(opcionSeleccionada); // Mostrar la opción seleccionada
mostrarEjecutando(); // Mostrar "Ejecutando..."
// Lógica para ejecutar la rutina correspondiente
if (menuIndex == 0 || menuIndex == 1) {
if (subMenuIndex == 2) { // Opción "Salir"
inSubMenu = false; // Salir del submenú
executing = false; // Detener ejecución
digitalWrite(ledPinBobinaPura, LOW); // Asegúrate de apagar el LED de Bobina Pura
digitalWrite(ledPinBobinaTrans, LOW); // Asegúrate de apagar el LED de Bobina Trans
mostrarMenu(); // Regresar al menú
} else {
executing = true; // Iniciar ejecución
}
} else if (menuIndex == 2) { // Submenú de Inyectores
if (subMenuIndex == 4) { // Opción "Salir"
inSubMenu = false; // Salir del submenú
executing = false; // Detener ejecución
digitalWrite(ledPinInyectores, LOW); // Asegúrate de apagar el LED de Inyectores
mostrarMenu(); // Regresar al menú
} else {
executing = true; // Iniciar ejecución
}
} else if (menuIndex == 3) { // Submenú de BTI
if (subMenuIndex == 1) { // Opción "Salir"
inSubMenu = false; // Salir del submenú
executing = false; // Detener ejecución
digitalWrite(ledPinPWM, LOW); // Asegúrate de apagar el LED PWM
mostrarMenu(); // Regresar al menú
} else {
lcd.clear();
lcd.print("Freq: Hz ");
lcd.print(freqValue); // Valor de frecuencia
lcd.setCursor(0, 1);
lcd.print("Duty: % ");
lcd.print(dutyCicle); // Valor de duty cycle
executing = true; // Iniciar ejecución
//rutinaPWM(); // Llama a la rutina para mostrar valores de PWM
}
}
}
// Función para mostrar que se está ejecutando
void mostrarEjecutando() {
lcd.setCursor(0, 1);
lcd.print("Ejecutando...");
}
// Rutina para "3ms a 1Hz" de Bobina Pura
void rutinaBobinaPura() {
unsigned long currentMillis = millis(); // Obtiene el tiempo actual
// Encender el LED de Bobina Pura
if (ledStateBobinaPura == false && currentMillis - previousMillisBobinaPura >= ledOffTime) {
ledStateBobinaPura = true; // Cambia el estado a encendido
digitalWrite(ledPinBobinaPura, HIGH); // Enciende el LED
previousMillisBobinaPura = currentMillis; // Guarda el tiempo actual
}
// Apagar el LED de Bobina Pura
if (ledStateBobinaPura == true && currentMillis - previousMillisBobinaPura >= ledOnTime) {
ledStateBobinaPura = false; // Cambia el estado a apagado
digitalWrite(ledPinBobinaPura, LOW); // Apaga el LED
previousMillisBobinaPura = currentMillis; // Guarda el tiempo actual
}
}
// Rutina para "3ms - RPM" de Bobina Pura
void rutinaBobinaPuraRPM() {
unsigned long currentMillis = millis(); // Obtiene el tiempo actual
// Leer el valor del potenciómetro y mapearlo
int potValue = analogRead(potPin);
unsigned long delayTime = map(potValue, 0, 1023, 997, 67); // Mapea el valor del potenciómetro
// Encender el LED de Bobina Pura durante 3 ms
if (ledStateBobinaPura == false && currentMillis - previousMillisBobinaPura >= delayTime) {
ledStateBobinaPura = true; // Cambia el estado a encendido
digitalWrite(ledPinBobinaPura, HIGH); // Enciende el LED
previousMillisBobinaPura = currentMillis; // Guarda el tiempo actual
}
// Apagar el LED de Bobina Pura
if (ledStateBobinaPura == true && currentMillis - previousMillisBobinaPura >= ledOnTime) {
ledStateBobinaPura = false; // Cambia el estado a apagado
digitalWrite(ledPinBobinaPura, LOW); // Apaga el LED
previousMillisBobinaPura = currentMillis; // Guarda el tiempo actual
}
}
// Rutina para "3ms a 1Hz" de Bobina Trans
void rutinaBobinaTrans() {
unsigned long currentMillis = millis(); // Obtiene el tiempo actual
// Encender el LED de Bobina Trans
if (ledStateBobinaTrans == false && currentMillis - previousMillisBobinaTrans >= ledOffTime) {
ledStateBobinaTrans = true; // Cambia el estado a encendido
digitalWrite(ledPinBobinaTrans, HIGH); // Enciende el LED
previousMillisBobinaTrans = currentMillis; // Guarda el tiempo actual
}
// Apagar el LED de Bobina Trans
if (ledStateBobinaTrans == true && currentMillis - previousMillisBobinaTrans >= ledOnTime) {
ledStateBobinaTrans = false; // Cambia el estado a apagado
digitalWrite(ledPinBobinaTrans, LOW); // Apaga el LED
previousMillisBobinaTrans = currentMillis; // Guarda el tiempo actual
}
}
// Rutina para "3ms - RPM" de Bobina Trans
void rutinaBobinaTransRPM() {
unsigned long currentMillis = millis(); // Obtiene el tiempo actual
// Leer el valor del potenciómetro y mapearlo
int potValue = analogRead(potPin);
unsigned long delayTime = map(potValue, 0, 1023, 997, 67); // Mapea el valor del potenciómetro
// Encender el LED de Bobina Trans durante 3 ms
if (ledStateBobinaTrans == false && currentMillis - previousMillisBobinaTrans >= delayTime) {
ledStateBobinaTrans = true; // Cambia el estado a encendido
digitalWrite(ledPinBobinaTrans, HIGH); // Enciende el LED
previousMillisBobinaTrans = currentMillis; // Guarda el tiempo actual
}
// Apagar el LED de Bobina Trans
if (ledStateBobinaTrans == true && currentMillis - previousMillisBobinaTrans >= ledOnTime) {
ledStateBobinaTrans = false; // Cambia el estado a apagado
digitalWrite(ledPinBobinaTrans, LOW); // Apaga el LED
previousMillisBobinaTrans = currentMillis; // Guarda el tiempo actual
}
}
// Rutina para inyectores
unsigned long tiempoEncendido;
unsigned long tiempoCiclo;
void rutinaInyectores() {
unsigned long currentMillis = millis(); // Obtiene el tiempo actual
static unsigned long tiempoInicio = 0; // Inicializa el tiempo de inicio
int var=0;
switch (subMenuIndex) {
case 0: // 15Hz
// Encender el LED de Inyectores durante 3 ms
if (ledStateInyectores == false && currentMillis - previousMillisInyectores >= (1000 / 15) / 2) {
ledStateInyectores = true; // Cambia el estado a encendido
digitalWrite(ledPinInyectores, HIGH); // Enciende el LED
previousMillisInyectores = currentMillis; // Guarda el tiempo actual
}
// Apagar el LED de Inyectores
if (ledStateInyectores == true && currentMillis - previousMillisInyectores >= 3) {
ledStateInyectores = false; // Cambia el estado a apagado
digitalWrite(ledPinInyectores, LOW); // Apaga el LED
previousMillisInyectores = currentMillis; // Guarda el tiempo actual
}
break;
case 1: // 70Hz
tiempoEncendido = 3; // 3 ms
tiempoCiclo = 1000 / 70; // Ciclo total para 70 Hz
if (ledStateInyectores == false && currentMillis - previousMillisInyectores >= tiempoCiclo / 2) {
ledStateInyectores = true; // Cambia el estado a encendido
digitalWrite(ledPinInyectores, HIGH); // Enciende el LED
previousMillisInyectores = currentMillis; // Guarda el tiempo actual
}
if (ledStateInyectores == true && currentMillis - previousMillisInyectores >= tiempoEncendido) {
ledStateInyectores = false; // Cambia el estado a apagado
digitalWrite(ledPinInyectores, LOW); // Apaga el LED
previousMillisInyectores = currentMillis; // Guarda el tiempo actual
}
break;
case 2: // 1Hz
tiempoEncendido = 250; // 250 ms
tiempoCiclo = 1000; // Ciclo total para 1 Hz
if (ledStateInyectores == false && currentMillis - previousMillisInyectores >= tiempoCiclo) {
ledStateInyectores = true; // Cambia el estado a encendido
digitalWrite(ledPinInyectores, HIGH); // Enciende el LED
previousMillisInyectores = currentMillis; // Guarda el tiempo actual
}
if (ledStateInyectores == true && currentMillis - previousMillisInyectores >= tiempoEncendido) {
ledStateInyectores = false; // Cambia el estado a apagado
digitalWrite(ledPinInyectores, LOW); // Apaga el LED
previousMillisInyectores = currentMillis; // Guarda el tiempo actual
}
break;
case 3: // 3s
static unsigned long tiempoInicioParpadeo = 0; // Inicializa el tiempo de inicio
static bool estadoLed = false; // Estado del LED
static unsigned long tiempoParpadeo = 0; // Tiempo total de parpadeo
if (tiempoParpadeo == 0) {
tiempoInicioParpadeo = millis(); // Guarda el tiempo de inicio al entrar a la rutina
}
// Calcula el tiempo transcurrido
tiempoParpadeo = millis() - tiempoInicioParpadeo;
if (tiempoParpadeo < 3000) { // Si han pasado menos de 3 segundos
unsigned long tiempoActual = millis() % (70); // Ciclo de 70 ms (3 ms encendido + 67 ms apagado)
if (tiempoActual < 3) { // Si han pasado menos de 3 ms
estadoLed = true;
digitalWrite(ledPinInyectores, HIGH); // Enciende el LED
} else {
estadoLed = false;
digitalWrite(ledPinInyectores, LOW); // Apaga el LED
}
} else {
tiempoParpadeo = 0;
executing = false; // Detener ejecución
digitalWrite(ledPinInyectores, LOW); // Asegúrate de apagar el LED después de 3 segundos
mostrarMenu(); // Regresar al menú
}
break;
}
}
// Variables para almacenar los valores anteriores
//int lastFreqValue = -1;
//int lastDutyCycle = -1;
// Función para la rutina PWM
void rutinaPWM() {
int freqValue = map(analogRead(potPinFreq), 0, 1023, 1, 500); // Mapea el potenciómetro a frecuencia
double periodo = 1000000.0 / freqValue; // Calcula el período en microsegundos
int rawDutyCycle = analogRead(potPin); // Lee el valor del potenciómetro para el duty cycle
int dutyCicle = map(rawDutyCycle, 0, 1023, 20, 60); // Mapea el valor a un rango de 0 a 100
// Solo actualizar el LCD si los valores han cambiado
//if (freqValue != lastFreqValue) {
lcd.setCursor(0, 0);
lcd.print("Freq: Hz ");
lcd.print(freqValue);
lcd.print(" "); // Espacios para limpiar posibles caracteres residuales
//lastFreqValue = freqValue; // Actualiza el valor anterior
//}
//if (dutyCicle != lastDutyCycle) {
lcd.setCursor(0, 1);
lcd.print("Duty: % ");
lcd.print(dutyCicle); // Imprime el duty cycle
lcd.print(" "); // Espacios para limpiar posibles caracteres residuales
//lastDutyCycle = dutyCicle; // Actualiza el valor anterior
//}
delay(10);
Timer1.pwm(9, map(dutyCicle, 0, 100, 0, 1023), periodo); // Genera la señal
}
// Función para obtener el número de opciones del submenú
int obtenerNumeroOpciones() {
switch (menuIndex) {
case 0: // Bobina Pura
return sizeof(subMenuBobina) / sizeof(subMenuBobina[0]);
case 1: // Bobina Trans
return sizeof(subMenuBobina) / sizeof(subMenuBobina[0]);
case 2: // Inyectores
return sizeof(subMenuInyectores) / sizeof(subMenuInyectores[0]);
case 3: // BTI
return sizeof(subMenuBTI) / sizeof(subMenuBTI[0]);
default:
return 0;
}
}
// Función para obtener la opción del submenú
const char* obtenerOpcionSubmenu(int index) {
if (index == -1) {
index = subMenuIndex;
}
switch (menuIndex) {
case 0:
case 1:
return subMenuBobina[index];
case 2:
return subMenuInyectores[index];
case 3:
return subMenuBTI[index];
default:
return "";
}
}