//************************************************************//
// UNIVERSAL VACUUM CLEANER CONTROL //
// Version: 0.86 (250220-0947) //
// [email protected] //
//************************************************************//
/*
ChangeLog:
- Agregado control de modo carga y modo trabajo.
- Agregado control carga de batería.
- Agregado control de leds indicadores de carga.
- Agregado control de leds indicadores de descarga.
- Agregado control descarga de batería.
- Agregado control de modos de voltaje (16V y 24V).
- Agregado control de PWM para el motor.
- Agregado control de advertencias por voltaje fuera de rango.
- Agregado control de advertencias por voltaje bajo.
- Agregado control y calculo de porcentaje de carga.
- Agregado control y calculo de voltaje de batería.
*/
/* Notas:
- Calculadora divisor de voltajes: https://tinyurl.com/divisor-voltaje
- SIMULADOR WOKWI https://wokwi.com/projects/423337618875781121
*/
#include <Arduino.h>
// Pines:
const byte pinAnalogico = A0; // Pin analógico conectado al divisor de tensión
const byte pinEnable = 8; // Pin digital para indicar modo carga (1) o trabajo (0)
const byte pinModo1 = 3; // Pin digital para el primer modo del interruptor
const byte pinModo2 = 4; // Pin digital para el segundo modo del interruptor
const byte pinLed1 = 5; // Pin digital para el LED 1
const byte pinLed2 = 6; // Pin digital para el LED 2
const byte pinLed3 = 7; // Pin digital para el LED 3
const byte pinPWM = 9; // Pin PWM conectado a la puerta del MOSFET
// Constantes:
const byte vModo1 = 16; // Voltaje objetivo Modo1
const byte vModo2 = 24; // Voltaje objetivo Modo2
const float R1 = 46500.0; // Resistencia 1 del divisor de tensión (en ohmios)
const float R2 = 6458.0; // Resistencia 2 del divisor de tensión (en ohmios)
const float Vref = 5.0; // Voltaje de referencia del ADC
const int resolucionADC = 1024; // Resolución del ADC (10 bits, valores de 0 a 1023)
const float factorCalibracion = 1; // Factor de calibración para ajustar lecturas de voltaje
// Rango configurable de voltaje para el cálculo del porcentaje de carga
const float voltajeMinimo = 22.4; // Voltaje mínimo de la batería (V) 3.2*7 elementos
const float voltajeMaximo = 29.4; // Voltaje máximo de la batería (V) 4.2*7 elementos
// Rango aceptable de voltaje para la batería
const float rangoVoltajeMinimo = 22.4; // Voltaje inferior aceptable
const float rangoVoltajeMaximo = 32.0; // Voltaje superior aceptable
// Contador y flag para advertencias
int contadorAdvertencias = 0; // Contador de advertencias consecutivas
bool advertenciaActiva = false; // Bandera para indicar si hay una advertencia activa
// Variables para control millis():
unsigned long tiempoAnteriorAdvertencia = 0; // Tiempo de la última advertencia
const unsigned long intervaloAdvertencia = 1000; // Intervalo entre advertencias (en ms)
unsigned long tiempoAnteriorLoop = 0; // Tiempo del último ciclo
const unsigned long intervaloLoop = 333; // Intervalo del ciclo principal (en ms)
// Prototipos de funciones:-----------------------------------------------------
void inicializarHardware() {
pinMode(pinPWM, OUTPUT); // Configurar el pin PWM como salida
pinMode(pinModo1, INPUT); // Configurar el pin para el modo 1 con (resistencia Pull-Down)
pinMode(pinModo2, INPUT); // Configurar el pin para el modo 2 con (resistencia Pull-Down)
pinMode(pinLed1, OUTPUT); // Configurar el pin para el LED 1 como salida
pinMode(pinLed2, OUTPUT); // Configurar el pin para el LED 2 como salida
pinMode(pinLed3, OUTPUT); // Configurar el pin para el LED 3 como salida
pinMode(pinEnable, INPUT); // Configurar el pin para el modo de carga (resistencia Pull-Down)
Serial.begin(9600); // Inicializar comunicación serie
Serial.println("Inicializando programa...");
}
float leerVoltajeBateria() {
int lecturaADC = analogRead(pinAnalogico); // Leer el valor del ADC (0 a 1023)
Serial.print("Lectura ADC: ");
Serial.println(lecturaADC);
float Vmedido = (lecturaADC * Vref) / resolucionADC;
Serial.print("Voltaje medido: ");
Serial.println(Vmedido);
float Vbateria = Vmedido * (R1 + R2) / R2 * factorCalibracion;
Serial.print("Voltaje real de la batería: ");
Serial.println(Vbateria);
return Vbateria;
}
float calcularPorcentajeCarga(float Vbateria) {
// if (Vbateria < voltajeMinimo) return 0.0;
// if (Vbateria > voltajeMaximo) return 100.0;
float porcentaje = ((Vbateria - voltajeMinimo) / (voltajeMaximo - voltajeMinimo)) * 100.0;
return porcentaje;
}
bool verificarRangoVoltaje(float Vbateria) {
if (Vbateria < rangoVoltajeMinimo || Vbateria > rangoVoltajeMaximo) {
unsigned long tiempoActual = millis();
if ((!advertenciaActiva || contadorAdvertencias < 3) && (tiempoActual - tiempoAnteriorAdvertencia >= intervaloAdvertencia)) {
Serial.print("Advertencia: Voltaje fuera de rango aceptable (");
Serial.print(rangoVoltajeMinimo);
Serial.print("-");
Serial.print(rangoVoltajeMaximo);
Serial.println(" V). Verifique la conexión.");
contadorAdvertencias++;
advertenciaActiva = true;
tiempoAnteriorAdvertencia = tiempoActual;
}
Serial.println("Saliendo del loop debido a voltaje fuera de rango.");
analogWrite(pinPWM, 0); // Apagar el PWM
return false;
}
advertenciaActiva = false;
contadorAdvertencias = 0;
return true;
}
void pararMotor (){
analogWrite(pinPWM, 0);
}
void configurarPWM(float voltajeObjetivo, float Vbateria) {
int pwmValor = 0;
if (Vbateria >= voltajeObjetivo) {
if (Vbateria != 0) {
pwmValor = int((voltajeObjetivo / Vbateria) * 255.0);
} else {
Serial.println("Error: División por cero detectada en cálculo de PWM.");
pwmValor = 0;
}
} else {
pwmValor = 255; // Máximo duty cycle si el voltaje es menor o igual al objetivo
}
pwmValor = constrain(pwmValor, 0, 255); // Limitar el valor a rango permitido
analogWrite(pinPWM, pwmValor);
Serial.print("Voltaje objetivo: ");
Serial.println(voltajeObjetivo);
Serial.print("PWM Valor aplicado: ");
Serial.println(pwmValor);
}
void SeleccionarMarcha(float Vbateria) {
if (digitalRead(pinModo1) == HIGH && digitalRead(pinModo2) == LOW) {
configurarPWM(vModo1, Vbateria); // Configurar PWM para 16V
} else if (digitalRead(pinModo1) == LOW && digitalRead(pinModo2) == HIGH) {
configurarPWM(vModo2, Vbateria); // Configurar PWM para 24V
} else if (digitalRead(pinModo1) == HIGH && digitalRead(pinModo2) == HIGH) {
configurarPWM(vModo2, Vbateria); // Configurar PWM para 24V si ambos están activos
} else {
analogWrite(pinPWM, 0); // Apagar el motor
Serial.println("Motor apagado.");
}
}
void monitorearEstadoBateria(float porcentajeCarga) {
if (porcentajeCarga >= 84.0) digitalWrite(pinLed3, HIGH);
else if (porcentajeCarga >= 70.0) digitalWrite(pinLed3, millis() % 1000 < 500 ? HIGH : LOW);
else digitalWrite(pinLed3, LOW);
if (porcentajeCarga >= 56.0) digitalWrite(pinLed2, HIGH);
else if (porcentajeCarga >= 42.0) digitalWrite(pinLed2, millis() % 1000 < 500 ? HIGH : LOW);
else digitalWrite(pinLed2, LOW);
if (porcentajeCarga >= 28.0) digitalWrite(pinLed1, HIGH);
else if (porcentajeCarga >= 14.0) digitalWrite(pinLed1, millis() % 1000 < 500 ? HIGH : LOW);
else digitalWrite(pinLed1, millis() % 500 < 250 ? HIGH : LOW);
}
void imprimirEstado(float Vbateria) {
float porcentajeCarga = calcularPorcentajeCarga(Vbateria);
Serial.print("Voltaje batería: ");
Serial.print(Vbateria);
Serial.print(" V | Porcentaje de carga: ");
Serial.print(porcentajeCarga);
Serial.println(" %");
monitorearEstadoBateria(porcentajeCarga);
}
void setup() {
inicializarHardware();
}
void loop() {
unsigned long tiempoActual = millis();
if (tiempoActual - tiempoAnteriorLoop >= intervaloLoop) {
tiempoAnteriorLoop = tiempoActual;
if (digitalRead(pinEnable) == LOW) {
Serial.println("Modo Carga: Monitoreando estado de la batería.");
pararMotor();
float Vbateria = leerVoltajeBateria();
if (verificarRangoVoltaje(Vbateria)) {
imprimirEstado(Vbateria);
}
} else if (digitalRead(pinEnable) == HIGH) {
Serial.println("Modo Trabajo: Operando motor y monitoreando batería.");
float Vbateria = leerVoltajeBateria();
if (verificarRangoVoltaje(Vbateria)) {
SeleccionarMarcha(Vbateria);
imprimirEstado(Vbateria);
}
}
}
}