Enfriador para acuario casero con Arduino

En un acuario comunitario de agua caliente la temperatura adecuada para los peces está en el rango de 24 a 28 Grados Celsius. En invierno no hay problema, con el calentador se mantiene a la temperatura adecuada, pero en verano necesita un enfriador.
He construido uno que voy a mostrar. Se trata de un ventilador que se pondrá en marca cuando la temperatura pase de un umbral. El ventilador saca el aire por un extremo de la tapa del acuario hacia el exterior y entra por otra obertura en el extremo opuesto, se puede ver en el vídeo siguiente, lo que hará que el aire se cargue de humedad y al ser expulsado al exterior provoque la bajada de la temperatura debido a la evaporación.
La temperatura de activación se programa por medio de dos botones y la velocidad del ventilador es proporcional a la necesidad de la refrigeración, es decir, cuanto más alta la temperatura del agua con respecto a la de activación con más fuerza gira el ventilador, de 0 a 20, siendo 0 apagado y 20 la velocidad máxima.
Primeras pruebas ya instalado en el acuario:


Componentes utilizados comprados en ebay baratos, pongo los enlaces para el que quiera verlos o comprarlos en ebay:
Manejamos el ventilador con una salida digital de Arduino en modo PWM conectada a los transistores que lo accionan mediante 12 voltios, este es el esquema:

En un principio utilicé un módulo IRF520, como éstos  como estos que se pueden comprar en ebay, pero lo quemé en las primeras pruebas, aunque creo que fue culpa mía que lo conecté mal por descuido. De todas formas queda mejor como lo he hecho, con el mosfet canal P, el NPN y las dos resistencias. Ojo con el patillaje de los transistores, hay que mirar el datasheet y no fiarse del dibujo anterior, cambian según la referencia que usemos, en este caso es un c33725. Estas dos páginas me han ayudado para diseñar esta parte:
Como conectar un mosfet de potencia a un microcontrolador
Controladores básicos (Drivers)

El diodo lo ponemos como protección y el condensador, aunque no es absolutamente necesario, hace que la señal de PWM se aplane y se parezca más a una media del voltaje entre picos, de forma que no se produzcan ruidos parásitos desagradables para los oídos en el ventilador.

El sensor de temperatura, que realmente es un termómetro digital con unas prestaciones asombrosas (véase el datasheet) sobre todo por el precio, está conectado en modo parásito porque así ahorramos circunfería, alimentado por la salida del Nano de 3V, que a su vez está alimentado por su entrada Vin mediante un alimentdor de 12 V, enlace para comprarlo en ebay. El sensor puede funcionar con 5V pero para qué gastar más.
Esquema de conexión del termómetro:

Hay que tener cuidado con el Nano cuando lo conectamos con una fuente externa por Vin y al mismo tiempo a través del USB, ya que se nos puede quemar el regulador de voltaje en los momentos de conexión y desconexión. Cuando conectamos el USB es más seguro tener desconectada la entrada Vin y al revés, si conectamos por Vin es más seguro tener desconectado el USB. En caso de necesitar las dos conexiones yo alimento por el pin de 5V, mediante un alimentador de 5V claro.
Por supuesto también hay que tener todas las tierras de diferentes voltajes conectadas en común.

En cuanto al display hay mucha información en la red al respecto, véase display 7 segmentos anodo comun 3 digitos. Lo alimento directamente de las salidas digitales del Arduino. Lo más correcto sería poner 8 resistencias de unos 220 Ω para los siete segmentos y el punto decimal, pero para simplificar yo lo he hecho poniendo tres resistencias de 100 Ω al común de cada dígito, de esa manera también puede funcionar y simplificamos la circuitería.
Estuve probando al pricipio alguna librería, pero no me convencieron, así que lo he programado yo mismo. Hay que activar sucesivamente cada dígito, solamente un dígito activo en cada instante, apagamos uno y encendemos el siguiente, configurando en cada instante los segmentos correcpondientes. Aquí se puede ver un display manejado por un PIC 16f84.
En el código, que pongo a continuación, se pueden ver los pines utilizados. Está redactado intentando que sea didáctico, muy comentado y con nomenclatura lo más afín posible a su cometido.

La temperatura de activación se edita mediante los pulsadores y se guarda en la propia eeprom del micro usando la librería EEPROM. Se usa la librería OnWire para comunicar con el termómetro y también la DallasTemperature para ortener la temperatura, ésta última se usa en modo asíncrono para no apagar el display durante mucho tiempo.

El código:

#include <EEPROM.h>
#include <OneWire.h>
#include <DallasTemperature.h>

const int pintermometro = A0;
const int pulsador1 = A1;
const int pulsador2 = A2;
const int pinventilador = 11;
const int se = 6;        //segmento e      pata 1
const int sd = 5;        //segmento d      pata 2
const int sp = 4;        //segmento pundo  pata 3
const int sc = 3;        //segmento c      pata 4
const int sg = 2;        //segmento g      pata 5
const int sb = 7;        //segmento b      pata 7
const int d3 = 8;        //digito 3        pata 8
const int d2 = 9;        //digito 2        pata 9
const int sf = 10;       //segmento f      pata 10
const int sa = A3;       //segmento a      pata 11
const int d1 = 12;       //digito 1        pata 12
const int tempmax = 340; 
const int tempmin = 250;  
int tempdisparo = 280;   
int direeprom = 0;          //guardaremos tempdisporo en la eeprom
float temperatura = 0;
int decimal, unidad, decena = 0;
unsigned long tiempo, tiempoaux, tiempoboton;
int nivel, decenanivel, unidadnivel = 0;      //nivel de fuerza del ventilador, 0 apagado
int retardoboton = 300;     //evita rebotes del boton
int aux , aux2;

OneWire buslectura(pintermometro);
DallasTemperature medidor(&buslectura);

void setup() {
  //Serial.begin(9600);           // para adepuracion
  //pinMode(pulsador1,INPUT);      //no es necesario, es el estado por defecto
  //pinMode(pulsador2,INPUT);      //no es necesario, es el estado por defecto
  digitalWrite(pulsador1, HIGH);   //esto activa las resistencias internas de pull up
  digitalWrite(pulsador2, HIGH);
  // Asignación de las salidas digitales
  pinMode(se, OUTPUT);   //segmento e      (1)
  pinMode(sd, OUTPUT);   //segmento d      (2)
  pinMode(sp, OUTPUT);   //segmento pundo  (3)
  pinMode(sc, OUTPUT);   //segmento c      (4)
  pinMode(sg, OUTPUT);   //segmento g      (5)
  pinMode(sb, OUTPUT);   //segmento b      (7)
  pinMode(d3, OUTPUT);   //digito 3        (8)
  pinMode(d2, OUTPUT);   //digito 2        (9)
  pinMode(sf, OUTPUT);  //segmento f     (10)
  pinMode(sa, OUTPUT);  //segmento a     (11)
  pinMode(d1, OUTPUT);  //digito 1       (12)
  analogWrite(pinventilador,0);       //lo inicializamos como salida y ponemos a 0, ventilador parado
  //inicializamos digitos en apagado
  digitalWrite (d1, 0);
  digitalWrite (d2, 0);
  digitalWrite (d3, 0);

  medidor.begin();
  medidor.setWaitForConversion(false);  //no esperamos, lo hacemos asincrono
  preparatemperatura();   //llamamos al sensor para leer la temperatura
  //saludamos para dar tiempo al sensor
  tiempoaux = millis();
  do  {
    digitalWrite (sp, 1);    //desactivado punto dcimal
    activa(1, 0, 0, 1, 0, 0, 0); //escribe H
    enciendeyapaga(1);
    activa(0, 1, 1, 0, 0, 0, 0); //escribe E
    enciendeyapaga(2);
    activa(1, 0, 1, 1, 0, 0, 0); //escribe Y
    enciendeyapaga(3);
  } while (millis() - tiempoaux < 1000);
  miratemperatura();      //leemos la temperatura
  tiempo = millis();
  EEPROM.get(direeprom,aux);
  if (aux < tempmin || aux > tempmax) {   //miramos si teníamos tempdisparo guardada
    EEPROM.put(direeprom,tempdisparo);
  } else  {
    tempdisparo = aux; 
  }
}

void loop() {
  //muesra la temperatura
  escribe(decena);
  enciendeyapaga(1);       //visualiza digito1
  escribe(unidad);
  digitalWrite (sp, 0);    //pone punto decimal
  enciendeyapaga(2);      //visualiza digito2
  digitalWrite (sp, 1);    //quita punto dcimal
  escribe(decimal);
  enciendeyapaga(3);      //visualiza digito3
  if (millis() - tiempo >= 900)  {     //damos tiempo al sensor
    miratemperatura();    //leemos la temperatura
    tiempoaux = millis();
    // mostramos F y nivel o OFF
    if (nivel != 0) {
      do  {
        activa(0,1,1,1,0,0,0); //escribe F
        enciendeyapaga(1);
        if (decenanivel > 0)   {
          escribe(decenanivel);            //decena de nivel
          enciendeyapaga(2);
        }
        escribe(unidadnivel);            //unidad de nivel
        enciendeyapaga(3);
      } while ((millis() - tiempoaux < 400) && (digitalRead(pulsador1))); //mas tiempo para el sensor
    } else {
      do  {
        activa(0, 0, 0, 0, 0, 0, 1); //escribe O
        enciendeyapaga(1);
        activa(0, 1, 1, 1, 0, 0, 0); //escribe F
        enciendeyapaga(2);
        activa(0, 1, 1, 1, 0, 0, 0); //escribe F
        enciendeyapaga(3);
      } while ((millis() - tiempoaux < 400) && (digitalRead(pulsador1))) ;  //mas tiempo para el sensor
    }
    preparatemperatura();       //llamamos al sensor para nueva lectura
    tiempo = millis();
  }
  sienfriamos();       //se activa o desactiva el ventilador
  if (!digitalRead(pulsador1) || !digitalRead(pulsador2))  {      //editamos temperatura de activacion
    tiempoboton = millis();        //para retardo pulsacion boton
    pidetempactivacion();
    EEPROM.put(direeprom,tempdisparo);//solo graba si el dato es diferente del guardado no malgasta eeprom
  }
}

void preparatemperatura()  {      //preparamos lectura
  medidor.requestTemperatures();
}

void miratemperatura()  {         //leemos
  //Serial.print("Temperatura:");
  temperatura = medidor.getTempCByIndex(0);
  //Serial.print(temperatura);
  //serial.println("ºC");
  temperatura = temperatura * 10;   //tratamos tres digitos
  decena = temperatura / 100;
  unidad = (temperatura - (decena * 100)) / 10;
  decimal = temperatura - (decena * 100) - (unidad * 10);
  //Serial.println(decena);
  //Serial.println(unidad);
  //Serial.println(decimal);
}

void escribe(int n) {           //configura cada numero para activarlo en un digito
  switch (n) {
    case 0:
      activa(0, 0, 0, 0, 0, 0, 1);
      break;
    case 1:
      activa(1, 0, 0, 1, 1, 1, 1);
      break;
    case 2:
      activa(0, 0, 1, 0, 0, 1, 0);
      break;
    case 3:
      activa(0, 0, 0, 0, 1, 1, 0);
      break;
    case 4:
      activa(1, 0, 0, 1, 1, 0, 0);
      break;
    case 5:
      activa(0, 1, 0, 0, 1, 0, 0);
      break;
    case 6:
      activa(0, 1, 0, 0, 0, 0, 0);
      break;
    case 7:
      activa(0, 0, 0, 1, 1, 1, 1);
      break;
    case 8:
      activa(0, 0, 0, 0, 0, 0, 0);
      break;
    case 9:
      activa(0, 0, 0, 1, 1, 0, 0);
      break;
    default:
      activa(1, 1, 1, 1, 1, 1, 1);
  }
}

void activa(boolean a, boolean b, boolean c, boolean d , boolean e, boolean f, boolean g) {
  //activa los leds de un digito
  digitalWrite (sa, a);
  digitalWrite (sb, b);
  digitalWrite (sc, c);
  digitalWrite (sd, d);
  digitalWrite (se, e);
  digitalWrite (sf, f);
  digitalWrite (sg, g);
}

void enciendeyapaga(int n) {    //enciende y apaga cada digito
  switch (n) {
    case 1:
      digitalWrite (d1, 1);
      digitalWrite (d1, 0);
      break;
    case 2:
      digitalWrite (d2, 1);
      digitalWrite (d2, 0);
      break;
    case 3:
      digitalWrite (d3, 1);
      digitalWrite (d3, 0);
      break;
  }
}

void pidetempactivacion() {
  int decenadisparo, unidaddisparo, decimaldisparo = 0;
  int parpadeo = 170;                 //tiempo de encendido
  int parpadeo2 = 130;                //tiempo de apagado
  int contador = 0;
  int veces = 8;                      //veces que realizamos el parpadeo
  boolean salir = false;
  do  {
    contador++;
    if (contador > veces) {
      salir = true;
    }
    decenadisparo = tempdisparo / 100;
    unidaddisparo = (tempdisparo - (decenadisparo * 100)) / 10;
    decimaldisparo = (tempdisparo - (decenadisparo * 100) - (unidaddisparo * 10));
    //muesra la temperatura de disparo parpadeando rápido
    tiempoaux = millis();
    do  {
      escribe(decenadisparo);
      enciendeyapaga(1);       //visualiza digito1
      escribe(unidaddisparo);
      digitalWrite (sp, 0);    //pone punto decimal
      enciendeyapaga(2);      //visualiza digito2
      digitalWrite (sp, 1);    //quita punto dcimal
      escribe(decimaldisparo);
      enciendeyapaga(3);      //visualiza digito3
      if (miraboton())  {
        contador = 0;
        break;
      }
    } while (millis() - tiempoaux < parpadeo);
    tiempoaux = millis();
    do  {
      escribe(10);              //esto escrive el default (nada,efecto apagado)
      if (miraboton())  {
        contador = 0;
        break;
      }
    } while (millis() - tiempoaux < parpadeo2 && (millis() - tiempoboton > retardoboton));
    //durante la pulsacion del boton (su retardo), no parpadea, queda fijo
    sienfriamos();        //que se active o apague el ventilador aunque estemos editando la temperatura
  } while (!salir) ;
}

bool miraboton() {        // comprobamos qué botón se ha pulsado para aumentar o disminuir tempdisparo
  if (millis() - tiempoboton > retardoboton) {    //hay que eliminar rebotes del boton
    if (!digitalRead(pulsador1)) {
      tiempoboton = millis();        //vovemos a retardar pulsacion boton
      if (tempdisparo < tempmax) {
        tempdisparo++;
      }
      return true;
    }
    if (!digitalRead(pulsador2)) {
      tiempoboton = millis();        //vovemos a retardar pulsacion boton
      if (tempdisparo > tempmin) {
        tempdisparo--;
      }
      return true;
    }
  }
  return false;
}
void sienfriamos() {
  aux = (int)temperatura ;
  if (aux > tempdisparo && aux < 400) {    //Activa ventilador si temperatura pasa umbral y si es coherente < 40;
    if (aux > tempdisparo + 20) {
      aux2 = 255;         //acotamos hasta 255
    } else   {
      aux2 = map(aux, tempdisparo, tempdisparo + 20, 0, 255); //pone en marcha el ventilador
    }
    analogWrite(pinventilador, aux2);
    nivel = map(aux2, 1, 255, 1, 20);  //nivel de fuerza del ventilador para mostrarlo en el display
    decenanivel = nivel / 10;
    unidadnivel = nivel - (decenanivel * 10);
    //Serial.println(aux2);            //para depuracion
  } else {
    analogWrite(pinventilador, 0);    //para el ventilador;
    nivel = 0;                        //nivel a mostrar 0
    decenanivel = 0;
    unidadnivel = 0;
  }
}


Código para descargar: Refrescator.ino

Estas son las últimas pruebas antes de montarlo en placa:


Fotos una vez montado en placa:




Últimas pruebas antes de ponerlo en el acuario:


Haciendo las últimas mejoras:


Finalmente, una vez instalado en el acuario, ha funcionado tan bien que me ha sorprendido gratamente. Le he dejado puesto un ventilador de PC sencillo que casi no hace ruido y me mantiene el acuario a 27 grados:



Con las librerías que facilitan tanto el trabajo de programación y los componentes electrónicos que tenemos al alcance tan económicos, resulta muy fácil hacer cosas como ésta, que pueden ser muy útiles y además pasarlo muy bien creándolas, como ha sido mi caso.

Ya tengo una nueva versión de este circuito: Refrescator 3.0

Comentarios

Escríbeme, comenta o pregúntame lo que quieras:

Nombre

Correo electrónico *

Mensaje *

Entradas populares