Autores- Ing. Luis Vargas (Coordinador)
- Ing. Jessica Leiva
- Ing. María José Soza Lopez
- Msc. Ing. Manuel Arcia (Tutor)
En esta ocasión hablaré sobre como desarrollar un controlador para Calentador de Agua con Mando Automático. El sistema de control consta de un PIC12F675 y una Resistencia eléctrica como la siguiente:

el sistema que se propone es similar al que usan las duchas ecosmart como la siguiente

El circuito de control se muestra a continuación
Etapa de PotenciaLa etapa de Potencia consta del calentador de agua y un TRIAC de entre 20 a 40 amperios. Esto último se debe a que el TRIAC debe soportar la corriente que pasará por la Resistencia.
AcoplamientoEl acoplamiento está compuesto por un optoacoplador MOC3021 que se encarga de activar el TRIAC cada vez que se envía un pulso desde el PIC.
Fuente de AlimentaciónEsta se encarga de convertir el voltaje alterno 120VAC o 240VAC a 5VDC. En este caso se utiliza una fuente sin transformador de Onda completa Tipo capacitiva que puede ser fácilmente sustituida por una fuente Resistiva.
El Diodo Zener D1 se encarga de rectificar el voltaje durante el semiciclo negativo cargando al Capacitor de entrada C1 y regulando el Voltaje a 5.1VDC durante el semiciclo Positivo. Mientras que el Capacitor de salida C2 se encarga de Rizar el voltaje.
Etapa de RetroalimentacionEsta está compuesta por un sensor de temperatura NTC (el cuál puede ser cambiado por un LM35, pero se deberá modificar el código). El Objetivo de este NTC es convertir la temperatura a un valor resistivo con una pendiente negativa. Es decir, si la temperatura aumenta la resistencia del NTC disminuye. Por lo tanto es necesario crear un Divisor de Voltaje con la Resistencia R5. Esto hará que las variaciones de resistencia sean convertidas en variaciones de Voltaje. Finalmente, este voltaje es leído por una entrada Analógica del ADC del PIC.
Detector de Cruce por CeroEste está compuesto por la resistencia R6 de 4.7Mohms (Puede ser cambiada por una de 2M). Esta resistencia se encarga de disminuir la corriente que ingresará al PIC. Por otro lado, el PIC tiene internamente un circuito compuesto por 2 diodos superpuestos que se encargan de recortar el voltaje a 5.5V siempre y cuando exista un sobrevoltaje. Es decir se convierte el voltaje entrante de 120VDC o 240VDC a una señal cuadrada de 5V con la misma frecuencia de la señal AC. Así el PIC sabrá si el voltaje es 5V entonces es el semisiclo positivo y si el voltaje es 0V es el semisiclo negativo. Por ello, en el programa será necesario determinar cuando ocurre el cambio de Voltaje. Lo cual puede ser Mediante una Interrupcion o mediante Polling.
Etapa de ControlEsta está compuesta por el PIC12F675. Este contiene el código necesario para el funcionamiento del circuito. Lo que realiza este PIC es modular mediante posición de pulso (PPM) el Voltaje RMS de la resistencia similar a un Dimmer. A continuación se muestran las graficas de salida
RegulaciónPara regular la temperatura que tendrá el calentador será necesario modificar el valor del potenciometro RV1. La ecuación utilizada para el control es similar a la siguiente:
Tiempo de Encendido del TRIAC = Valor del potenciometro RV1 - Valor del termistor RT1 (Temperatura) + offset.
Si la temperatura supera el valor del potenciometro entonces el sistema se apaga.
La línea Amarilla es el voltaje de entrada, mientras que la linea Verde es el Voltaje suministrado a la Resistencia. Por otro lado la línea roja muestra los pulsos de 1us que se envían al TRIAC cada para encenderlo. La línea Azul muestra el inicio del pulso de encendido y el final del tiempo de encendido durante el cruce por cero.
El código se muestra a continuación:
#include <12F675.h>
#device adc=10
#FUSES NOWDT //No Watch Dog Timer
#FUSES INTRC_IO //Internal RC Osc, no CLKOUT
#FUSES CPD //Data EEPROM Code Protected
#FUSES PROTECT //Code protected from reads
#FUSES NOMCLR //Master Clear pin used for I/O
#FUSES NOPUT //No Power Up Timer
#FUSES NOBROWNOUT //No brownout reset
#FUSES BANDGAP_HIGH
#FUSES RESERVED //Used to set the reserved FUSE bits
#use delay(clock=4M)
#include <Puertos.c>
//*******************Declaracion de Variables**********************************
signed long
Error=0, //Variable que almacena la diferencia entre el set_point y Temp
Set_Point=0,//Valor al cual deseamos poner la temperatura
Temp=0; //Valor de temperatura medida en un instante de tiempo
/***************************************************************************
Esta funcion se realiza por la interrupcion del timer0, se utiliza el
Timer0 para determinar el tiempo necesario que transcurre despues del cruce por
cero para variar el angulo de disparo del Triac
***************************************************************************/
int1 int_flag;
#int_GLOBAL
void TIMER0_isr(void){
if(int_flag){
delay_us(135);
disable_interrupts(INT_TIMER0);
}
set_timer0(0);
GP4=1; //Se pone a 0 GP4 para encender el optoacoplador
GP5=1;
delay_us(50); //Se hace que el ancho del pulso de disparo sea de 50us
GP4=0; //Se pone a 1 GP4 para apagar el optoacoplador (el Triac queda encendido)
clear_interrupt(INT_TIMER0);
//Limpiamos el flag TIMR0 para evitar reingreso a la interrupcion
int_flag=1;
}
void RA_isr(void){
if(Error>=255){ //Si Error es igual a 255 se debe encender el Triac justo despues del cruce por cero
int_flag=0;
delay_us(50);
TIMER0_isr(); //para ello saltamos a la funcion TIMER0_isr() que envia un pulso de 30us al triac
enable_interrupts(INT_TIMER0); //desabilitamos la interrupcion del timer0 para no reingresar
goto L1; //Saltamos al label L1
}
else{ //Si Error es distinto a 255
GP5=0;
setup_adc_ports(sAN0 | sAN1 | VSS_VDD); //Seleccionamos AN0 y AN1 como analogicos
}
if(Error<=0) //y si la temperatura es mayor o igual al set_point
disable_interrupts(INT_TIMER0); //Desabilitamos la Interrupcion Timer0 para apagar el Triac
else{ //de lo contrario
clear_interrupt(int_timer0); //limpiamos el flag del timer0 por seguridad
int_flag=0;
set_timer0(Error); //cargamos el valor del error en Timer0
enable_interrupts(INT_TIMER0); //Habilitamos la interrupcion Timer0
}
L1:
Delay_us(20); //Retardo de 20us para evitar errores
Temp=read_adc();
set_adc_channel(0); //Multiplexamos el ADC al canal 0 para leer Temperatura
Temp=Temp-435; //Leemos el valor de la temperatura instantanea
delay_us(40);
Set_Point=read_adc()/4; //Leemos el valor del pin correspondiente al Set_Point
set_adc_channel(1); //Multiplexamos el ADC al canal 1 para leer Temperatura
Error = Set_Point - Temp; //El error es la diferencia entre Set_point y Temp.
}
void main(){
GP4=0; //Ponemos en 1 GP4 para desactivar el optoacoplador
setup_adc_ports(sAN0 | sAN1 | VSS_VDD);
//Seleccionamos AN0 y AN1 como analogicos
setup_comparator(NC_NC); //Apagamos los comparadores
TRISIO=0B001111; //GP6 y 7 como salidas los demas como entradas.
setup_adc(ADC_CLOCK_DIV_8);//Seteamos Tadc=Tosc/8 debido a que fosc=4MHz
setup_vref(FALSE); //Apagamos el Voltaje de referencia interno
setup_timer_0(T0_INTERNAL|T0_DIV_32);
//Seteamos que el desborde ocurra (256-Timer0)*Tosc/4*32
//si Timer0=0 el desborde ocurrira a 8.192ms
setup_timer_1(T1_DISABLED);//Desabilitamos el Timer1
enable_interrupts(GLOBAL); //Habilitamos las interrupciones globales
set_adc_channel(1); //Multiplexamos el ADC al canal 1 para leer Temperatura
for(;;){
while(GP2); //Esperar que GP2 cambie de 1 a 0
delay_ms(1);
while(!GP2); //Esperar que GP2 cambie de 0 a 1
RA_isr(); //Hacer la funcion RA_isr
}
}
y a continuación está la librería para controlar puertos.
/*****************************************************
Autor: Luis Alberto Vargas Tijerino.
Nickname: Bigluis.
Fecha: 1/06/10
Version: 2.0
*****************************************************/
#nolist
//**********************Puertos***********************
#ifdef getenv("SFR:GPIO")
#byte GPIO = getenv("SFR:GPIO")
#bit GP0 = GPIO.0
#bit GP1 = GPIO.1
#bit GP2 = GPIO.2
#bit GP3 = GPIO.3
#bit GP4 = GPIO.4
#bit GP5 = GPIO.5
#byte TRISIO = getenv("SFR:TRISIO")
#endif
#ifdef getenv("SFR:PORTA")
#byte PORTA= getenv("SFR:PORTA")
#bit RA0 = PORTA.0
#bit RA1 = PORTA.1
#bit RA2 = PORTA.2
#bit RA3 = PORTA.3
#bit RA4 = PORTA.4
#bit RA5 = PORTA.5
#bit RA6 = PORTA.6
#bit RA7 = PORTA.7
#byte TRISA= getenv("SFR:TRISA")
#endif
#ifdef getenv("SFR:PORTB")
#byte PORTB= getenv("SFR:PORTB")
#bit RB0 = PORTB.0
#bit RB1 = PORTB.1
#bit RB2 = PORTB.2
#bit RB3 = PORTB.3
#bit RB4 = PORTB.4
#bit RB5 = PORTB.5
#bit RB6 = PORTB.6
#bit RB7 = PORTB.7
#byte TRISB= getenv("SFR:TRISB")
#endif
#ifdef getenv("SFR:PORTC")
#byte PORTC= getenv("SFR:PORTC")
#bit RC0 = PORTC.0
#bit RC1 = PORTC.1
#bit RC2 = PORTC.2
#bit RC3 = PORTC.3
#bit RC4 = PORTC.4
#bit RC5 = PORTC.5
#bit RC6 = PORTC.6
#bit RC7 = PORTC.7
#byte TRISC= getenv("SFR:TRISC")
#endif
#ifdef getenv("SFR:PORTD")
#byte PORTD= getenv("SFR:PORTD")
#bit RD0 = PORTD.0
#bit RD1 = PORTD.1
#bit RD2 = PORTD.2
#bit RD3 = PORTD.3
#bit RD4 = PORTD.4
#bit RD5 = PORTD.5
#bit RD6 = PORTD.6
#bit RD7 = PORTD.7
#byte TRISD= getenv("SFR:TRISD")
#endif
#ifdef getenv("SFR:PORTB")
#byte PORTE= getenv("SFR:PORTE")
#bit RE0 = PORTE.0
#bit RE1 = PORTE.1
#bit RE2 = PORTE.2
#bit RE3 = PORTE.3
#bit RE4 = PORTE.4
#bit RE5 = PORTE.5
#bit RE6 = PORTE.6
#bit RE7 = PORTE.7
#byte TRISE= getenv("SFR:TRISE")
#endif
#list
Pueden encontrar más información de esta librería en esta dirección
http://www.todopic.com.ar/foros/index.php?topic=30662.0y descargar el código aquí
http://www.todopic.com.ar/foros/index.php?action=dlattach;topic=30662.0;attach=12611Parte MecánicaControlador | Resistencia | Terminal T de 1-1/2" | Nipple de 1-1/2" por 8 a 12" | Adaptador de 1-1/2" a 1/2" |
 |  |  |  |  |
| | Bunshing de 1-1/2" a 1/2" |
| |  |
| | Shower Head |
| |  |
| | Tu |
| |  |
Notas:No estoy muy seguro si la tubería es de 1" o de 1-1/2" eso depende de la resistencia.
El costo aproximado de esto sería de alrededor de U$30 a U$45 lo que representa una fracción del costo de otros calentadores de agua que por lo general cuestan entre U$80 hasta U$200
Finalmente el código fuente con los esquemas aparece a continuación
no es necesario desconectar el sistema durante te duchas ya que ese tipo de resistencia tiene una cubierta ceramica interna. Es decir, la electricidad no toca el agua. La cubieta metalica exterior que se observa es para proteger la cubierta ceramica de los efectos quimicos o mecanicos del agua.
Por otro lado a diferencia de las resistencias de membrana, no tendras q cambiar la resistencia cada 6 meses. Esto se debe a que estas reaistencias te pueden durar hasta 10 años