Desde la publicación del dimmer, he recibido muchos correos preguntando ciertas particularidades del software que lo controla. Esta es la razón por la cual he decidido crear esta serie de entradas con la intención de facilitar la tarea a todos aquellos que prefieren crear su propio software y hardware en vez de usar alguno de otro proyecto disponible en la red.
El firmware básicamente realiza las siguientes tareas:
- Monitorea el pin de detección de cruce por cero y carga el valor apropiado en un timmer del PIC, para que este se desborde en algún momento del semiciclo y disparar entonces el Triac.
- Esta atento a los cambios de estado del pin en el que esta conectado el receptor infrarrojo, si se detecta un cambio en este pin se inicia la captura del tiempo del pulso (recordar que el protocolo IR de sony utiliza codificación por ancho de pulsos.
- Detecta y reconoce las pulsaciones cortas y largas del pulsador para el control manual del dimmer.
En esta primera parte me voy a concentrar en la detección de cruce por cero y el disparo del triac.
Detección de los cruces por cero.
Utilizaremos la interrupción externa del PIC para detectar cuando el voltaje se aproxima a cero y por lo tanto cuando debe comenzar el conteo para disparar el TRIAC.
Hablaremos entonces sobre la función void vInterruptZeroCross()
que esta asociada a la interrupción externa. La variable iIntControl sirve para recordar que flanco queremos detectar en la siguiente interrupción externa, mientras que la variable global iLampBrightness contiene el valor a cargar en el timer y es modificada por las funciones que desean cambiar el brillo de la lámpara.
Por otra parte, iTriacFlag se utiliza como auxiliar para generar un pulso de corta duración en la interrupción de desbordamiento del timer0 y se explicará más adelante.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #INT_EXT void vInterruptZeroCross() { static int iIntControl = 0; output_low( _TRIAC_CONTROL ); // Turn triac output to low level, just in case it is still high iTriacFlag = FALSE; // Set triac status flag to off status set_timer0( iLampBrightness ); // Prepare timer to trigger the triac on the next TMR0 interrupt if( iIntControl== 0 ) // Change the external interrupt edege alternately { iIntControl = 1; ext_int_edge( H_TO_L ); } else { iIntControl = 0; ext_int_edge( L_TO_H ); } return; } |
En esta interrupción se realiza la carga del valor necesario al timer0 para que se desborde dentro de un intervalo de tiempo que corresponda con el periodo del semiciclo de corriente alterna.
Para esto hay que configurar los prescalers para obtener un desbordamiento del timer un cada poco más de 8 milisegundos (1/(2*60)) para la red eléctrica de 60 Hz. El tiempo de incremento del timer determinara cuantos Tics nos caben en cada semiciclo de la red y por lo tanto la resolución con la que podremos controlar el brillo de la lámpara.
Idealmente tendríamos 256 posibles niveles de intensidad, que corresponden a los posibles valores que podemos cargar al timer, sin embargo, hay factores prácticos que limitan este rango: como la precisión del detector de cruce por cero, la corriente mínima requerida para encender el triac y mantenerlo en estado de conducción, etc.
Por lo tanto, de todos los valores posibles a cargar en el timer hay que descartar los primeros y los últimos. En mi caso, mediante experimentación con un osciloscopio y mi depurador ICD2 decidí limitar los valores a cargar en el timmer con las siguientes definiciones en el código fuente.
1 2 | #define _LAMP_TOP 225 #define _LAMP_MIN 40 |
Siempre se puede jugar con este valor hasta obtener un funcionamiento óptimo. Estas definiciones me dejan con 186 valores útiles para cargar al timer.
Hay que recordar que _LAMP_TOP representa el brillo máximo y por lo tanto el timer se debe cargar con un valor grande que haga que se desborde prácticamente al comienzo del semiciclo, mientras que _LAMP_MIN representa la mínima salida lumínica y si se carga ese valor al timer la interrupción de este ocurrirá prácticamente al final del semiciclo, permitiendo que el triac conduzca durante solamente un breve periodo de tiempo.
Concluimos que para aumentar el brillo hay que incrementar el valor de la variable iLampBrightness, mientras que para disminuir el brillo hay que decrementarlo. Dicho esto podemos elaborar las funciones que controlan el brillo a través de las teclas + / -, por ejemplo para aumentar el nivel de brillo:
1 2 3 4 5 6 7 8 | void vLampBright() { output_high( _STATUS_LED ); iLampBrightness = ( iLampBrightness + 5 < _LAMP_TOP ) ? iLampBrightness + 5 : _LAMP_TOP; delay_ms( 20 ); output_low( _STATUS_LED ); return; } |
Disparo del Triac
Cuando ocurre una interrupción del timer0, el microcontrolador envía un pulso al gate del Triac para que este comience a conducir, una vez que el triac se ha disparado, podemos interrumpir el pulso al terminal de compuerta y el dispositivo seguirá conduciendo hasta que la corriente a través de los terminales MT1 y MT2 cae por debajo de cierto valor umbral, que es una característica propia de cada dispositivo.
Al deshabilitar rápidamente el pulso en la compuerta evitamos consumir energía de manera innecesaria (hay que recordar que estamos limitados en este aspecto por la fuente capacitiva).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #INT_TIMER0 void vInterruptTimer0() { if( !iTriacFlag ) //If the triac pin is low we change the state and prepare the timer { if( iLampBrightness > _LAMP_MIN ) // Do not trigger if level is set to min output_high( _TRIAC_CONTROL ); // Turn on triac set_timer0( 250 ); // Next timer overflow will clear the triac pin iTriacFlag = TRUE; // Flag now signals that we need to turn off the triac output pin } else { //The triac has been triggered, cut the pulse output_low( _TRIAC_CONTROL ); set_timer0( 0 ); //Set timer period to maximum, timer should not overflow untill next zero cross interrupt iTriacFlag = FALSE; //Change Triac Flag status, triac pin is now low } return; } |
Este código genera un pulso en el pin definido como _TRIAC_CONTROL. La primera interrupción coloca un 1 lógico en el pin del triac, cambia el valor de la variable iTriacFlag a 1 y coloca un valor grande en el registro del timer, lo cual produce una interrupción poco después de que se envío el pulso al terminal gate.
Esta segunda interrupción del timer0, desactiva el pulso de gate al triac. Cambiando el valor cargado al timer en la primera interrupción (cuando !iTriacFlag se evalúa como verdadero) se pueden lograr pulsos más largos o más cortos para manejar la compuerta del triac.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #INT_TIMER0 void vInterruptTimer0() { if( !iTriacFlag ) //If the triac pin is low we change the state and prepare the timer { if( iLampBrightness > _LAMP_MIN ) // Do not trigger if level is set to min output_high( _TRIAC_CONTROL ); // Turn on triac set_timer0( 250 ); // Next timer overflow will clear the triac pin iTriacFlag = TRUE; // Flag now signals that we need to turn off the triac output pin } else { //The triac has been triggered, cut the pulse output_low( _TRIAC_CONTROL ); set_timer0( 0 ); //Set timer period to maximum, timer should not overflow untill next zero cross interrupt iTriacFlag = FALSE; //Change Triac Flag status, triac pin is now low } return; } |
Conclusión
Con los fragmentos de código anteriores, es posible construir un dimmer basado en PIC, tal vez no a control remoto, pero se pueden colocar un par de botones, los cuales aumenten y/o disminuyan la intensidad de la luz.
Hay que recordar que trabajar con equipos conectados directamente a la red de 120 o 220 volts es peligroso y en la medida de lo posible hay que evitarlo. Conviene hacer las pruebas con un generador de funciones o alguna otra fuente que nos permita obtener una señal de 60 Hz para aplicar al PIC, o con un transformador y una lámpara de 12 volts.
Si finalmente deciden conectarlo a la red eléctrica queda advertirles que es completamente bajo su responsabilidad.
Che…pongan un poco de uds. para poder hacer el dimmer. Les está sirviendo el proyecto en bandeja…que mas quieren? Saludos.
Pues me gustaria que subieras mas fragmentos de codigo para realizar el dimer con dos pulsadores
Oigan pongan mas datos para terminar el dimmer ya que no lo he podidod relizar
Hola Rubén me siento muy orgulloso de que tu genialidad sobre la eletrónica sea tratada tan bien por un joven brillante y mexicano… he leido poco pero lo suficiente para decir esto de tu blog, espero podamos colaborar juntos, ya que mi mejor hobby es la electrónica, te dire que soy autodidacta y tu historia es muy similar a la mía… desarmando aparatos de casa… después intuí que debería tener una memoria sobre cuanto aparato o dispositivo electrónico “cayera” en mis manos, por lo que me hice “adicto” a sacarles el diagrama electrónico, entendiendo de alguna manera tan solo por el diagrama; de que dispositivo se trataba, ahora con el manejo de sistemas microcontrolados… pués existe una enorme potencialización de los dispositivos, que también me ha gustado diseñar, sin embargo no me había dado por compartir, como tu lo haces, el acervo o pasión que tenemos por la electrónica espero en esto, poder colaborar contigo, aportaciones, dudas o sugerencias que en ambos sentidos se generen,de nuevo mis saludos y reconocimientos.
Atte.
Juan Angel M.G.