#include <OneWire.h>
/*01012024
***se agrega el control de la resistencia Heater con salida pwm haci un SSR con una entrada digital de enable,
cuando la resistencia esta encendida por mas de 600 segundos se apaga y es necesario quitar y poner el switch
para habilitar nuevamente.
***se agrega un case para el despliegue de mensajes en LCD
***se agrega control de operacion de la bomba, cuando sobre pasa el tiempo se apaga la bomba sin importar la temperatura
pasado el tiempo de apagado nuevamente se habilita la bomba y si hay temperatura se acciona.
***Cosas a futuro: integracion de kwh de consumo de la bomba y del Heater, que el Heater entre automaticamente cuando
la razon de cambio de la temperatura del tanque sea rapida lo que indica que se esta utilizando el agua en duchas.
***Se utiliza la libreria elapsedMillis.h para el control de tiempos y eliminar los delays()
*/
//NOTA el sensor ds18 tiene un numero id, tener cuidado de que no se confundan
//de posicion, de pasar esto, cambie la variable del colector por la del tanque
//NOTAS: tomar en cuenta que el case necesita siempre usar Break, de lo contrario evalua todos los case al mismo
//tiempo, ademas las funciones de comparacion son & (and) || (or) para los if u otras.
//programa genera una salida de alarma como indicador en el led interno (pin 13) del arduino, esto es falla de rango
//de lectura de sensores, despues de 6 cuentas de falla, se hace un reset de software.
//ademas utilizamos una maquina de estados para la rutina de control.
#include <DallasTemperature.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display
#include <elapsedMillis.h>
elapsedSeconds TempReaderSeg;
elapsedSeconds MaxRunPumpSeg;
elapsedSeconds MaxStopPumpSeg;
elapsedSeconds Led1blinkSeg;
elapsedSeconds MaxHeaterTime;
elapsedSeconds LCDDisplayTime;
unsigned int TempReader_Seg = 2;
unsigned int MaxRunPump_Seg = 60;
unsigned int Led1blink_Seg = 1;
unsigned int MaxStopPump_Seg = 60;
unsigned int MaxHeater_Time = 600;
unsigned int LCDDisplay_Time=2;
unsigned int EstadoLCD=10;
//int ColectorTemp=A0;
//int TanqueTemp=A1;
bool InhibitRunbyTime=false;
bool OSRise = LOW;
bool OSLast = LOW;
int EstadoBomba = 10;
int estado = 0;
int SumaValue = 1;
int Selector =0;
bool InhibitHeater = false;
//int Selector=0;
//float Ganancia=0.1f;
float CelciosCol = 0.0f;
float CelciosTanque = 0.0f;
//Arranque para dallas temperature, sensor DS18b20 (sensor digital)
const byte PinDataTemp = 7;
const byte PinDataTemp2 = 6;
const byte PinSelectorHeater = 2;
const byte PinPWMHeaterOut = 3;
OneWire OneWireObjeto(PinDataTemp);
DallasTemperature SensorTemperatura(&OneWireObjeto);
OneWire OneWireObjeto2(PinDataTemp2);
DallasTemperature SensorTemperatura2(&OneWireObjeto2);
//antigua funcion de promedio, sensor analogo lm 35, deberia de funcionar todavia
//float xn;// temperatura
//float xnanterior=0; // x(n-1)
//int tempdigital;
//float ynanterior=0; // y(n-1)
//float xntanque;// temperatura Tanque
//float xnanteriortanque=0; // x(n-1)
//int tempdigitaltanque;
//float ynanteriortanque=0; // y(n-1)
void(* resetFunc) (void) = 0;
void setup() {
Serial.begin(9600);
pinMode(LED_BUILTIN, OUTPUT);
lcd.init();
lcd.backlight();
//Arranque de la comunicacion del sensor
SensorTemperatura.begin();
SensorTemperatura2.begin();
SensorTemperatura.setResolution(12);
SensorTemperatura2.setResolution(12);
pinMode(EstadoBomba, OUTPUT);
pinMode(PinPWMHeaterOut, OUTPUT);
pinMode(PinSelectorHeater, INPUT_PULLUP);
//Proceso de suma del tiempo de operacion con Reloj
}
void loop()
{
if (TempReaderSeg >= TempReader_Seg){
TempReaderSeg=0;
SensorTemperatura.requestTemperatures();
SensorTemperatura2.requestTemperatures();
CelciosCol = SensorTemperatura.getTempCByIndex(0);
CelciosTanque = SensorTemperatura2.getTempCByIndex(0);
}
switch (estado)
{
case 1:
//estado inicial, evalua si los sensores tienen valores fuera de rango
Serial.println("estado");
Serial.println(estado);
delay(250);
if (CelciosCol<10.0f||CelciosCol>120.0f||CelciosTanque<10.0f||CelciosTanque>120.0f) {
estado=10;
}
else {
// envia al estado 2 para evaluar las lecturas de los sensores
estado=2;
}
break;
case 2:
//evalua sensores
Serial.println("estado");
Serial.println(estado);
Serial.print("MaxRunTime=> ");
Serial.println(MaxRunPumpSeg);
Serial.print("EstadoBomba=> ");
Serial.println(digitalRead(EstadoBomba));
Serial.print("InhibitRunbyTime=> ");
Serial.println(InhibitRunbyTime);
delay(250);
//compara el tiempo que la bomba esta en stop por tiempo y la habilita nuevamente
if ((MaxStopPumpSeg>=MaxStopPump_Seg) && (InhibitRunbyTime))
{
InhibitRunbyTime=false;
MaxStopPumpSeg=0;
MaxRunPumpSeg=0;
}
//compara el tiempo que la bomba a funcionado y la detiene por tiempo
if ((MaxRunPumpSeg>=MaxRunPump_Seg) && (digitalRead(EstadoBomba)==HIGH ))
{
MaxRunPumpSeg=0;
digitalWrite(EstadoBomba, LOW);
InhibitRunbyTime = true;
MaxStopPumpSeg=0;
}
//compara si la temperatura se encuentra en rango para activar la bomba
if ((CelciosCol>(CelciosTanque+7.0f)) && (CelciosCol>37.0f) && !(InhibitRunbyTime))
{
digitalWrite(EstadoBomba, HIGH);
OSRise = (EstadoBomba & !(OSLast) );
OSLast=EstadoBomba;
if (OSRise)
{
MaxRunPumpSeg=0;
}
SumaValue=0;
estado=1;
}
else {
// envia al estado 3 para evaluar las lecturas de los sensores
estado=3;
}
break;
case 3:
//evalua si la temperatura esta en rangos para mantener la bomba
Serial.println("estado");
Serial.println(estado);
delay(250);
if ((CelciosCol<(CelciosTanque+3.0f)) || (CelciosCol<33.0f ))
{
digitalWrite(EstadoBomba, LOW);
estado=1;
}
else {
// envia al estado 1 para evaluar las lecturas de los sensores
estado=1;
}
break;
case 10:
//Se detectaron valores fuera de rango en las lecturas de los sensores
Serial.println("estado");
Serial.println(estado);
delay(250);
digitalWrite(LED_BUILTIN, HIGH);
if (Led1blinkSeg>=Led1blink_Seg){
Led1blinkSeg=0;
digitalWrite(LED_BUILTIN, LOW);
}
SumaValue++;
Serial.println(SumaValue);
delay(100);
if (SumaValue>5) {
estado=20;
}
else {
estado=1;
}
break;
case 20:
//auto reset
Serial.println("estado");
Serial.println(estado);
delay(250);
resetFunc();
break;
default:
Serial.println("default");
estado=1;
break;
}
//Arranque de resistencia por selector manual ()
String TextoHeater;
//lee el selector
Selector =digitalRead(PinSelectorHeater);
Serial.print("Selector=> ");
Serial.println(Selector);
if (Selector & !(InhibitHeater))
{
analogWrite(PinPWMHeaterOut,65);
TextoHeater="Heater ON";
Serial.println("Heater ON ");
delay(550);
if (MaxHeaterTime>=MaxHeater_Time)
{
InhibitHeater=true;
analogWrite(PinPWMHeaterOut,0);
TextoHeater="Heater OFF ";
MaxHeaterTime=0;
Serial.println("Heater OFF ");
Serial.print("InhibitHeater ");
Serial.println(InhibitHeater);
delay(550);
}
}
if (!(Selector)){
analogWrite(PinPWMHeaterOut,0);
TextoHeater="Heater OFF ";
InhibitHeater=false;
MaxHeaterTime=0;
Serial.println("Heater OFF ");
Serial.print("InhibitHeater ");
Serial.println(InhibitHeater);
delay(550);
}
//PwmON
//}
//switch case para las impresiones
switch (EstadoLCD)
{
case 10:
lcd.clear();
lcd.print ("Temp Col "+ String(CelciosCol) );
lcd.setCursor(0,1);
lcd.print ("Temp Tan "+ String(CelciosTanque) );
if (LCDDisplayTime>LCDDisplay_Time)
{
EstadoLCD = 20;
LCDDisplayTime=0;
}
break;
case 20:
lcd.clear();
lcd.print ( TextoHeater);
if (LCDDisplayTime>LCDDisplay_Time)
{
EstadoLCD = 10;
LCDDisplayTime=0;
}
break;
default:
break;
}
}