Buenas!
Queria compartir con todos un dimmer que hice a partir de toda la informacion que hay en el foro.
Es un dimmer de dos canales, aunque de momento solo me funciona uno

Controlado por mando a distancia RF. Lo utilizo para iluminar mis espectaculos mas pequeños en los que no me hace falta mas que luz blanca y luz de publico.
De momento, como no pude hacer funcionar los dos canales, un canal solo se enciende y se apaga, y el otro se puede dimmear.
En el canal "dimeable" hay dos botones, el de subir y el de bajar intensidad. Cuando se presiona uno, la intensidad empieza a subir/bajar progresivamente hasta que se vuelva a presionar el boton, y entonces la intensidad queda fija en esa posicion. Si no se presiona el boton la intensidad llegara al maximo/minimo.
El cruce por cero se hace con un optoacoplador PS2505-1 que es igual a un opto normal, pero en vez de tener solo un led emisor, tiene 2 en antiparalelo, por lo que al estar conectado a la corriente alterna en un semiciclo se enciende un emisor, y en siguiente se enciende el otro, pero justo en el cruce por cero ambos estan apagados. Esto es lo que detecta el fototransistor receptor.
El dispositivo es apto para 110v/220v y 50/60hz ya que el mismo programa se encarga de contar la duracion de los semiciclos, y la conversion de alterna a continua lo hago con un "modulo" que quite de un cargador de moviles, que como sabeis son universales y aceptan todo el rango de voltajes alternos disponibles. Por ultimo, para no quemar los leds del optoacoplador utilizo una resistencia en serie con la alterna, pero dependiendo si son 110v o 220v utilizo una resitencia diferente que se selecciona con un jumper.
Para conmutar la alterna utilizo un triac BTA12 con un pequeño disipador para soportar un maximo de 4A por canal. Y para disparar el triac utilizo un optotriac MOC3021 que se conecta al pic.
El diseño del esqumatico y como conectar el pic, optotriac y triac junto con la red snubber estan copiadas de otros diseños del foro.
Todas las pistas por donde circula alterna son de 40mils (1.016mm) y revestidas con una capa gordita de estaño para que soporten mejor la intensidad.
El receptor RF es un modulo de 4 canales. De sus 7 pines 2 son de alimentacion, uno es un avisador de recepcion de señal y los 4 restantes son los 4 canales que se ponen a 5v cuando se presiona el pulsador correspondiente del emisor.
El pic es un 16f648 y el codigo es el siguiente:
#include <16F648A.h>
#FUSES XT,INTRC_IO,NOWDT,PUT,NOMCLR,NOBROWNOUT,NOLVP,NOCPD,NOPROTECT
#use delay(clock=4000000)
#use fast_io(a)
#use fast_io(b)
//GPIO
#byte PORTA = 0x05
#byte PORTB = 0x06
#bit LAMP1 = PORTA.0
#bit LAMP2 = PORTA.1
#bit LED2 = PORTA.2
#bit LED1 = PORTA.3
#bit CRUCE = PORTB.0
#bit DWN2 = PORTB.1
#bit UP2 = PORTB.2
#bit DWN1 = PORTB.3
#bit UP1 = PORTB.4
//Constantes
#define LIMINF 2 //limite inferior de intensidad (de cero a cien)
#define LIMSUP 96 //limite superior de intensidad (de cero a cien)
#define ONOFF 5000 //tiempo que tarda en encenderse/apagarse completamenta la luz en mS
#define DELAY (ONOFF/LIMSUP) //tiempo de cada paso de dimmer
#define IGUAL 0
#define LAMPARA1 1
#define LAMPARA2 2
//Variables
short flagIntExt = FALSE; //flag de interrupcion externa
int Primero = 0; //establece que lampara tiene la intensidad mas baja
int Intensidad1 = LIMINF; //intensidad actual de la lampara1
int Intensidad2 = LIMINF; //intensidad actual de la lampara2
long IntensidadCCP1 = 0; //cuando tiene que saltar la interrupcion CCP
long IntensidadCCP2 = 0; //cuando tiene que saltar la interrupcion CCP
long Semiciclo = 0; //duracion del semiciclo
//Rutinas
void CalcularIntensidad(void);
#int_EXT
void INT_EXT_isr(void){
LAMP1 = FALSE;
//LAMP2 = FALSE;
Semiciclo = get_timer1(); //establece la duracion del semciclo
CalcularIntensidad();
set_timer1(0); //restablece timer
}
#int_CCP1
void CCP1_isr(void){
//if(Primero == LAMPARA1){
LAMP1 = TRUE; //enciendo lampara 1
//LED1 = TRUE;
/*CCP_1 = IntensidadCCP2; //establezco proximo CCP
}
else if(Primero == LAMPARA2){
LAMP2 = TRUE; //enciendo lampara 2
LED2 = TRUE;
CCP_1 = IntensidadCCP1; //establezco proximo CCP
}
else{
LAMP1 = TRUE;
LAMP2 = TRUE;
LED1 = TRUE;
LED2 = TRUE;
}*/
}
void main() {
short Luz2 = FALSE;
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
setup_timer_2(T2_DISABLED,0,1);
setup_ccp1(CCP_COMPARE_INT);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
enable_interrupts(INT_TIMER1);
enable_interrupts(INT_EXT);
enable_interrupts(INT_CCP1);
enable_interrupts(GLOBAL);
setup_oscillator(OSC_4MHZ);
set_tris_a(0b00000000);
set_tris_b(0b00011111);
ext_int_edge(0,L_TO_H); //configura INT para que solo se active a la subida
CalcularIntensidad();
LAMP1 = FALSE;
LAMP2 = FALSE;
LED1 = FALSE;
LED2 = FALSE;
do{
if((UP1 == TRUE) && (UP2 == FALSE) && (DWN1 == FALSE) && (DWN2 == FALSE)){
while(UP1 == TRUE){delay_ms(50);} //espera que se suelte
//subir luz 1
while((Intensidad1 < LIMSUP) && (UP1 == FALSE)){
Intensidad1++; //aumenta intensidad
delay_ms(DELAY);
}
while(UP1 == TRUE){delay_ms(50);} //espera que se suelte
}
/*
if((UP2 == TRUE)){// && (UP1 == FALSE) && (DWN1 == FALSE) && (DWN2 == FALSE)){
//subir luz 2
while((Intensidad2 < LIMSUP) && (DWN2 == FALSE)){
Intensidad2++; //aumenta intensidad
delay_ms(DELAY);
}
while(DWN2 == TRUE){delay_ms(50);} //espera que se suelte
}
*/
if((DWN1 == TRUE) && (UP1 == FALSE) && (UP2 == FALSE) && (DWN2 == FALSE)){
while(DWN1 == TRUE){delay_ms(50);} //espera que se suelte
//bajar luz 1
while((Intensidad1 > LIMINF) && (DWN1 == FALSE)){
Intensidad1--; //disminuye intensidad
delay_ms(DELAY);
}
while(DWN1 == TRUE){delay_ms(50);} //espera que se suelte
}
/*
if((DWN2 == TRUE)){// && (UP1 == FALSE) && (UP2 == FALSE) && (DWN1 == FALSE)){
//bajar luz 2
while((Intensidad2 > LIMINF) && (UP2 == FALSE)){
Intensidad2--; //aumenta intensidad
delay_ms(DELAY);
}
while(UP2 == TRUE){delay_ms(50);} //espera que se suelte
}
*/
if(UP2 == TRUE)
Luz2 = TRUE;
if(DWN2 == TRUE)
Luz2 = FALSE;
LAMP2 = Luz2;
LED2 = Luz2;
}while(TRUE);
}
void CalcularIntensidad(void){
long Step = 0;
if(Intensidad1 > LIMINF)
LED1 = TRUE;
else
LED1 = FALSE;
Step = Semiciclo / LIMSUP;
IntensidadCCP1 = Semiciclo - (Step * Intensidad1);
//IntensidadCCP2 = Semiciclo - (Step * Intensidad2);
//if(Intensidad1 < Intensidad2){
//Primero = LAMPARA1;
CCP_1 = IntensidadCCP1;
/*}
else if(Intensidad1 > Intensidad2){
Primero = LAMPARA2;
CCP_1 = IntensidadCCP2;
}
else{
Primero = IGUAL;
CCP_1 = IntensidadCCP1;
}*/
}
Como digo, solo se puede dimear el canal 1, el codigo lo hice para que funcionaron los dos canales, pero en la practica no va... por eso estan partes comentadas. Ademas el limite inferior y superior no son CERO y CIEN, porque parpadea. Creo que los problemas que tengo son por la velocidad a la que va el micro. Quizas deberia ponerlo a correr mas rapido. Probare con un 16F88 que tiene oscilador interno de 8Mhz a ver que tal.
Cualquier sugerencia es bienvenida ya que tengo varios proyectos en los que necesitare un dimmer y pretendo que funcionen bien

El esquema del circuito se puede descargar.
Salu2!