Ya he modificado el esquema y ayer hice unas pequeñas pruebas y, a falta de profundizar más, parece que la cosa funciona más o menos de la forma prevista. Hoy me ha llegado todo el material que me faltaba, por lo que seguramente mañana haré las pruebas de todo.
De momento, dejo enlace al esquema definitivo con -creo- todos los errores subsanados. Lo pongo también en cómo adjunto.
Pues al fin me ha llegado todo y he hecho las primeras pruebas según el último esquema (excepto por la fuente de energía suplementária para los relés, lo he hecho todo con los 5V del Arduino) y compilando el último código.
La verdad es que ha sido un éxito a medias, ya que aunque he podido comprobar que se me encendían y apagaban los relés y leds conectados a las salidas digitales y se registraban las lecturas de las entradas digitales, a la hora de funcionar la doble condicional, lo hacía correctamente o no según el estado de OONOFF. Releyendo mi código, usando el sentido común y elaborando una tabla, he logrado dar con el problema y -espero, no he compilado- solucionarlo.
El código inicialmente decía lo siguiente:
int valor4 = digitalRead(OONOFF) ; // Leemos el valor de la orden paro/marcha
if ( valor4 == true ) { // esto es que hay solicitud de marcha
int valor5 = digitalRead(OFRICALOR) ; // Leemos si estamos en modo frio o calor
if (valor5 == true ) { // Esto es que estamos en modo calor
digitalWrite( RONOFF, true) ; // Se enciende el rele RONOFF encendiendo la bomba de calor en modo invierno (calor)
digitalWrite( LEDCALOR, true) ; // Se enciende el led rojo
}
else {
digitalWrite( RONOFF, false) ; // Se apaga el rele RONOFF encendiendo la bomba de calor en modo verano (frío)
digitalWrite( LEDFRIO, true) ; // Se enciende el led azul
}
}
else {
int valor6 = digitalRead(OFRICALOR) ; // Leemos si estamos en modo frio o calor
digitalWrite( LEDCALOR, valor6) ; // Encendemos led rojo si esta en modo calor apagamos en modo frio
digitalWrite( LEDFRIO, !valor6) ; // Encendemos led azul si esta en modo frio apagamos en modo calor
digitalWrite( RONOFF, !valor6) ; // Apagamos el rele en modo calor y lo encendemos en modo frio
digitalWrite( RFRICALOR, !valor6) ; // Indicamos al rele de cabio frio(true)/calor(false) de la bomba de calor cómo debe operar
}
}
Me he dado cuenta de que, según este código, si OONOFF es False, definía de forma clara e inequívoca los 4 valores en juego LEDCALOR, LEDFRIO, RONOFF y RFRICALOR dependiendo del estado de OFRICALOR, pero si OONOFF era True, entonces -y dependiendo del estado de OFRICALOR- definía únicamente el estado de 2 de los 4 valores en juego, por lo que el comportamiento del Arduino era confuso. He definido los 4 valores en todas las variables posibles para que no haya nunca ningún valor sin definir, por lo que esa parte del código queda así:
int valor4 = digitalRead(OONOFF) ; // Leemos el valor de la orden paro/marcha
if ( valor4 == true ) { // esto es que hay solicitud de marcha
int valor5 = digitalRead(OFRICALOR) ; // Leemos si estamos en modo frio o calor
if (valor5 == true ) { // Esto es que estamos en modo calor
digitalWrite( RONOFF, true) ; // Se enciende el rele RONOFF encendiendo la bomba de calor en modo invierno (calor)
digitalWrite( LEDCALOR, true) ; // Se enciende el led rojo
digitalWrite( LEDFRIO, false) ; // Se apaga el led azul
digitalWrite( RFRICALOR, false) ; // Indicamos al rele de cabio frio(true)/calor(false) de la bomba de calor cómo debe operar
}
else {
digitalWrite( RONOFF, false) ; // Se apaga el rele RONOFF encendiendo la bomba de calor en modo verano (frío)
digitalWrite( LEDCALOR, false) ; // Se apaga el led rojo
digitalWrite( LEDFRIO, true) ; // Se enciende el led azul
digitalWrite( RFRICALOR, true) ; // Indicamos al rele de cabio frio(true)/calor(false) de la bomba de calor cómo debe operar
}
}
else { // esto es que hay solicitud de paro
int valor6 = digitalRead(OFRICALOR) ; // Leemos si estamos en modo frio o calor
digitalWrite( RONOFF, !valor6) ; // Apagamos el rele en modo calor y lo encendemos en modo frio
digitalWrite( LEDCALOR, valor6) ; // Encendemos led rojo si esta en modo calor apagamos en modo frio
digitalWrite( LEDFRIO, !valor6) ; // Encendemos led azul si esta en modo frio apagamos en modo calor
digitalWrite( RFRICALOR, !valor6) ; // Indicamos al rele de cabio frio(true)/calor(false) de la bomba de calor cómo debe operar
}
Entiendo que ahora, además de compilarme, el Arduino debería comportarse conforme a esta tabla:
(Todas las conexiones a los relés se realizarán en posición normalmente cerrado). Pongo el código completo para referencia: (Siguiente mensaje por exceder caracteres)
(Recordemos que esta tabla define el encendido y apagado y el modo de funcionamiento de una bomba de calor para calefacción contra un depósito de inercia)
int RFRICALOR = 2 ;
int RBOMBA1 = 3 ;
int RBOMBA2 = 4 ;
int RBOMBA3 = 5 ;
int RONOFF = 6 ;
int LEDFRIO = 7 ;
int LEDCALOR = 8 ;
int OFRICALOR = 9 ;
int OONOFF = 10 ;
int OBOMBA3 = 11 ;
int OBOMBA2 = 12 ;
int OBOMBA1 = 13 ;
void setup() {
pinMode( RFRICALOR , OUTPUT); // Rele cambio de temporada (abieto invierno, cerrado verano), entrada 1 Tarjeta regulación unidad interior
pinMode( RBOMBA1 , OUTPUT); // Rele bomba planta 1
pinMode( RBOMBA2 , OUTPUT); // Rele bomba planta 2
pinMode( RBOMBA3 , OUTPUT); // Rele bomba planta 3
pinMode( RONOFF , OUTPUT); // Rele Paro / Marcha, entrada 6 Tarjeta de regulación unidad interior
pinMode( LEDFRIO , OUTPUT); // Led modo frio
pinMode( LEDCALOR , OUTPUT); // Led modo calor
pinMode( OFRICALOR , INPUT); // Cambio modo frio / calor
pinMode( OONOFF , INPUT); // Orden Paro / Marcha
pinMode( OBOMBA3 , INPUT); // Orden bomba planta 3
pinMode( OBOMBA2 , INPUT); // Orden bomba planta 2
pinMode( OBOMBA1 , INPUT); // Orden bomba planta 1
}
void loop() {
int valor1 = digitalRead(OBOMBA1) ; // Leemos el valor de la primera planta
digitalWrite( RBOMBA1, valor1) ; // Escribimos valor en RBOMBA1
int valor2 = digitalRead(OBOMBA2) ; // Leemos el valor de la segunda planta
digitalWrite( RBOMBA2, valor2) ; // Escribimos valor en RBOMBA3
int valor3 = digitalRead(OBOMBA3) ; // Leemos el valor de la tercera planta
digitalWrite( RBOMBA3, valor3) ; // Escribimos valor en RBOMBA3
int valor4 = digitalRead(OONOFF) ; // Leemos el valor de la orden paro/marcha
if ( valor4 == true ) { // esto es que hay solicitud de marcha
int valor5 = digitalRead(OFRICALOR) ; // Leemos si estamos en modo frio o calor
if (valor5 == true ) { // Esto es que estamos en modo calor
digitalWrite( RONOFF, true) ; // Se enciende el rele RONOFF encendiendo la bomba de calor en modo invierno (calor)
digitalWrite( LEDCALOR, true) ; // Se enciende el led rojo
digitalWrite( LEDFRIO, false) ; // Se apaga el led azul
digitalWrite( RFRICALOR, false) ; // Indicamos al rele de cabio frio(true)/calor(false) de la bomba de calor cómo debe operar
}
else {
digitalWrite( RONOFF, false) ; // Se apaga el rele RONOFF encendiendo la bomba de calor en modo verano (frío)
digitalWrite( LEDCALOR, false) ; // Se apaga el led rojo
digitalWrite( LEDFRIO, true) ; // Se enciende el led azul
digitalWrite( RFRICALOR, true) ; // Indicamos al rele de cabio frio(true)/calor(false) de la bomba de calor cómo debe operar
}
}
else { // esto es que hay solicitud de paro
int valor6 = digitalRead(OFRICALOR) ; // Leemos si estamos en modo frio o calor
digitalWrite( RONOFF, !valor6) ; // Apagamos el rele en modo calor y lo encendemos en modo frio
digitalWrite( LEDCALOR, valor6) ; // Encendemos led rojo si esta en modo calor apagamos en modo frio
digitalWrite( LEDFRIO, !valor6) ; // Encendemos led azul si esta en modo frio apagamos en modo calor
digitalWrite( RFRICALOR, !valor6) ; // Indicamos al rele de cabio frio(true)/calor(false) de la bomba de calor cómo debe operar
}
}
Si todo va cómo debe, y no veo razón para que no sea así, el siguiente paso será pasar de la protoboard a montar de una forma un poco más elegante con la ayuda de un Screw Shield 1.0 y en una caja IP65 para su instalación en la sala de calderas.
Deseadme suerte con esas soldaduras, que soy muy novato, y gracias por seguir este hilo y ayudarme en lo que creáis oportuno.
Un error que veo en tu código que no luce como error es que el tuyo aunque sea un ambiente hogareño o semi industrial, puede presentar problemas con los pulsadores.
Los pulsadores suelen rebotar. Y eso genera problemas en el accionamiento de equipos grandes.
Si hasta el momento no has visto comportamientos erráticos, olvidalo pero ten presente este comentario.
Si ocurre, te voy a sugerir una librería que hace lo que se llama una rutina antirebote. Se llama Bounce2 y solo le dices el tiempo que quieres que un valor se confirme en un estado y listo... el devuelve el estado cuando éste esta confirmado.
tu lees esto
int valor4 = digitalRead(OONOFF) ;
Dicho sea de paso es una exageración usar una variable int para leer el estado 0 1 de un switch/pulsador.
Con bool sobra
Cómo no podía ser de otra forma, ya que hay que saber reconocer la experiencia y el conocimiento cuando sobrepasan por tanto los propios, he seguido tu consejo y me he puesto en plan "programador mamporrero" y le he metido un tute al código que ya no lo reconozco ni yo. Admito que no entiendo todo lo que he modificado, pero la cuestión es que me compila, que es mucho más de lo que esperaba. La cosa ha quedado así:
#include <Bounce2.h> // Incluimos biblioteca Bounce para eliminar el debouncing producido por los pulsadores / reles de entrada
bool RFRICALOR = 2 ;
bool RBOMBA1 = 3 ;
bool RBOMBA2 = 4 ;
bool RBOMBA3 = 5 ;
bool RONOFF = 6 ;
bool LEDFRIO = 7 ;
bool LEDCALOR = 8 ;
bool OFRICALOR = 9 ;
bool OONOFF = 10 ;
bool OBOMBA3 = 11 ;
bool OBOMBA2 = 12 ;
bool OBOMBA1 = 13 ;
Bounce debouncer1 = Bounce(); // Iniciado un objeto Bounce
Bounce debouncer2 = Bounce(); // Iniciado un objeto Bounce
Bounce debouncer3 = Bounce(); // Iniciado un objeto Bounce
Bounce debouncer4 = Bounce(); // Iniciado un objeto Bounce
Bounce debouncer5 = Bounce(); // Iniciado un objeto Bounce
void setup() {
pinMode( RFRICALOR , OUTPUT); // Rele cambio de temporada (abieto invierno, cerrado verano), entrada 1 Tarjeta regulacion unidad interior
pinMode( RBOMBA1 , OUTPUT); // Rele bomba planta 1
pinMode( RBOMBA2 , OUTPUT); // Rele bomba planta 2
pinMode( RBOMBA3 , OUTPUT); // Rele bomba planta 3
pinMode( RONOFF , OUTPUT); // Rele Paro / Marcha, entrada 6 Tarjeta de regulación unidad interior
pinMode( LEDFRIO , OUTPUT); // Led modo frio
pinMode( LEDCALOR , OUTPUT); // Led modo calor
pinMode( OFRICALOR , INPUT_PULLUP); // Cambio modo frio / calor
debouncer1.attach(OFRICALOR);
debouncer1.interval(50); // intervalo en ms, mas alto por ser un interruptor manual
pinMode( OONOFF , INPUT_PULLUP); // Orden Paro / Marcha
debouncer2.attach(OONOFF);
debouncer2.interval(25); // intervalo en ms
pinMode( OBOMBA3 , INPUT_PULLUP); // Orden bomba planta 3
debouncer3.attach(OBOMBA3);
debouncer3.interval(25); // intervalo en ms
pinMode( OBOMBA2 , INPUT_PULLUP); // Orden bomba planta 2
debouncer4.attach(OBOMBA2);
debouncer4.interval(25); // intervalo en ms
pinMode( OBOMBA1 , INPUT_PULLUP); // Orden bomba planta 1
debouncer5.attach(OBOMBA1);
debouncer5.interval(25); // intervalo en ms
}
void loop() {
debouncer1.update(); // Actualizar los estados Bounce
debouncer2.update(); // Actualizar los estados Bounce
debouncer3.update(); // Actualizar los estados Bounce
debouncer4.update(); // Actualizar los estados Bounce
debouncer5.update(); // Actualizar los estados Bounce
bool valor1 = debouncer5.read(); // Leemos el valor de la primera planta
digitalWrite( RBOMBA1, valor1) ; // Escribimos valor en RBOMBA1
bool valor2 = debouncer4.read(); // Leemos el valor de la segunda planta
digitalWrite( RBOMBA2, valor2) ; // Escribimos valor en RBOMBA3
bool valor3 = debouncer3.read(); // Leemos el valor de la tercera planta
digitalWrite( RBOMBA3, valor3) ; // Escribimos valor en RBOMBA3
bool valor4 = debouncer2.read(); // Leemos el valor de la orden paro/marcha
if ( valor4 == true ) { // esto es que hay solicitud de marcha
bool valor5 = debouncer1.read(); // Leemos si estamos en modo frio o calor
if (valor5 == true ) { // Esto es que estamos en modo calor
digitalWrite( RONOFF, true) ; // Se enciende el rele RONOFF encendiendo la bomba de calor en modo invierno (calor)
digitalWrite( LEDCALOR, true) ; // Se enciende el led rojo
digitalWrite( LEDFRIO, false) ; // Se apaga el led azul
digitalWrite( RFRICALOR, false) ; // Indicamos al rele de cabio frio(true)/calor(false) de la bomba de calor como debe operar
}
else {
digitalWrite( RONOFF, false) ; // Se apaga el rele RONOFF encendiendo la bomba de calor en modo verano (frio)
digitalWrite( LEDCALOR, false) ; // Se apaga el led rojo
digitalWrite( LEDFRIO, true) ; // Se enciende el led azul
digitalWrite( RFRICALOR, true) ; // Indicamos al rele de cabio frio(true)/calor(false) de la bomba de calor cómo debe operar
}
}
else { // esto es que hay solicitud de paro
bool valor6 = debouncer1.read(); // Leemos si estamos en modo frio o calor
digitalWrite( RONOFF, !valor6) ; // Apagamos el rele en modo calor y lo encendemos en modo frio
digitalWrite( LEDCALOR, valor6) ; // Encendemos led rojo si esta en modo calor apagamos en modo frio
digitalWrite( LEDFRIO, !valor6) ; // Encendemos led azul si esta en modo frio apagamos en modo calor
digitalWrite( RFRICALOR, !valor6) ; // Indicamos al rele de cabio frio(true)/calor(false) de la bomba de calor como debe operar
}
}
He actualizado tras eliminar todas las tildes de los comentarios (por si acaso)
Verás que he dado 25ms a todas entradas provinientes de un relé (en el esquema muchos los represento con pulsadores, pero todo son relés excepto el interruptor basculante) y al interruptor basculante le he dado 50ms.
La verdad es que, siguiendo con mi constante abuso de tu tiempo, me gustaría que revisases este nuevo código a ver si te percatas de algún disparate.
Por mi parte, parece que hasta mediados de la próxima semana no podré cargarlo en mi Arduino, así que no podré probarlo físicamente hasta dentro de unos días, pero si tengo un código seguro y estable para entonces, habré avanzado mucho.
Por fin he podido compilar el nuevo código en el Arduino y, ¡sorpresa!, no funcionaba.
Por probar, y porque estaba seguro de que todo lo referente a la biblioteca antirebote lo había hecho bien, he probado de modificar todos los "bool" por "int" otra vez y ¡sorpresa!, ahora funciona perfectamente. No se si tú surbyte le verás la lógica a esto, pero la cuestión es que ahora esto chuta, mientras que del otro modo estaba muerto.
Ya sólo me queda comprar los Display AKO, la caja para montarlo y liarme a soldar el shield y montar cablecitos. Gracias mil por la ayuda, seguiré posteando sobre la marcha del proyecto.
De modo que debería funcionar.
Sin embargo el ejemplo dice
// Get the updated value :
int value = debouncer.read();
No se que responderte. Debo revisar mis casos.
Yo no uso definiciones como tu dentro del mismo código, las hago locales al comienzo del void loop o globales.
Ya he montado la caja con el Arduino y mañana o pasado iré a colocarla en su lugar. En las siguientes fotos puede verse cómo ha quedado por dentro (a falta de conectar todo lo externo al sistema, la señal de los fancoils, las bombas, la maniobra de paro/marcha y el cambio de temporada de la bomba de calor) y cómo queda por fuera a falta de colocar el segundo display Ako (en el momento de montar, sólo tenía uno). Podéis ver cómo al mover el interruptor se apaga o enciende el led correspondiente y el display que le corresponde.
Una vez montado, el sistema respondía a las pruebas según lo esperado, por lo que supongo que no dará mayores problemas una vez instalado.
Gracias por las felicitaciones, la verdad es que estoy bastante orgulloso con los resultados obtenidos por el momento.
No he probado el sistema completo a falta de la puesta en marcha del sistema aerotérmico por parte del SAT oficial, pero de momento he conseguido que los radiadores de cada planta me activen / desactiven la bomba correspondiente a su planta y que los relés marcha/paro y cambio de temporada actúen con el interruptor o los displays Ako; sólo falta verificar que estas dos últimas órdenes hagan lo que corresponde a la bomba de calor aerotérmica.
Paso las fotos de todo instalado:
Desde luego son muchos cables, pero es todo más sencillo de lo que parece.
Ya comentaré cómo va el sistema cuando lo tenga todo encendido y funcionando, pero preveo un éxito absoluto, ya que de momento todo me ha funcionado a la primera según lo revisto.
Nuevamente gracias surbyte por hacerlo posible, sin tu ayuda este proyecto no habría salido adelante. Admito que cómo primer proyecto de Arduino y primer contacto en el mundo de la electrónica, tal vez ha sido demasiado ambicioso; espero que no sea la última vez que me meto en uno de estos fregados.
Cuando las últimas pruebas estén hechas, intentaré compilar toda la información del proyecto de forma cuidada y ordenada en un último post para simplificar la labor a quien sea que encuentre útil este proyecto.