# Deteccion de cruce por cero para controlar un triac



## eserock (Ene 27, 2008)

Hola tengo que controlar el funcionamiento de un Triac en forma parecida a un dimmer pero con voltajes menores a la red electrica, con aproximadamente 24 volts, hasta ahora no se me ocurre como detectar el cruce por cero para mandar el pulso de activacion del Triiac, esto es para realizar una fuente variable de entre 12 y 24 volts controlada por solo 4 pines del pic aumenta, disminuye, detector de cruce por cero y pulso de activacion del pic, ojala a alguien se le ocurra  algo gracias por la ayuda


----------



## Fogonazo (Ene 27, 2008)

https://www.forosdeelectronica.com/f16/dimmer-controlado-corriente-continua-11998/


----------



## pepechip (Ene 27, 2008)

hola.
puedes utilizar un optoacoplador  que ya lleva el control de paso por cero incorporado
MOC3041


----------



## El nombre (Ene 27, 2008)

Cuando se busca ese tipo de deteccion es para pode controlar la potencia. ¿de que sirve que el integrado lo detecte si el disparo lo quiero a los 5ms de su paso? el opto no informaciónrma del paso.

Saludos

PD no te enfades pe2chip, cuanto mas se participa mas contestaciones se tienen


----------



## pepechip (Ene 27, 2008)

ok. no me enfado, aqui en el foro unas veces enseño y otras me toca aprender.
en cuanto al detector de paso por cero se puede hacerde varias formas por ejemplo como el de la figura. 
tambien se podia quitar la puerta NAND y poner en su lugar un optoacoplador.
el diodo que lleva es un zener, colocarlo de una tension similar a la de alimentacion, el simbolo esta mal representado pero es que lo tenia mas a la mano
saludos


----------



## Saint_ (Ene 28, 2008)

hola que tal,  por mi parte sujiero que se utilice un comparador como el LM393 asi se compara la señal de entrada AC con 0v y se obtiene el "detectos de cruse por cero".


----------



## vayadespiste (Ene 28, 2008)

Yo utilicé este circuito que encontré en internet para usarlo con un pic y un triac (sin cruce por cero) y me funcionó perfectamente. El origen no se de quien es así le pido disculpas a su autor.

Un saludo. 

(a  ver si soy capaz de subir una imagen al foro).


----------



## Fogonazo (Ene 28, 2008)

Ya que antes no lo hicieron, por que no se dan una vuelta por aqui:

https://www.forosdeelectronica.com/f16/dimmer-controlado-corriente-continua-11998/#post68183


----------



## freddy_03 (Oct 12, 2010)

Cual es la funcion del circuito de detector cruce por cero, sera que es recomendable emplear en un semaforo este circuito.


----------



## Fogonazo (Oct 12, 2010)

freddy_03 dijo:


> Cual es la funcion del circuito de detector cruce por cero, sera que es recomendable emplear en un semaforo este circuito.


El cruce por 0V del que estamos ablando es para lograr la regulación de la intensidad de una lámpara, en el caso de un semáforo esto es innecesario.

Peroooooooo, las lámparas incandescentes duran sustancialmente mas si son activadas en el momento en el que la tensión pasa por 0V, cosa que hace un opto-aislador tipo *MOC3041*


----------



## edjhr11 (Mar 28, 2011)

Buenas, he leido sobre lo del cruce por cero, podre utilizar el MOC3041? la señal sinuidal la obtendre de un generador de señales, de unos 10vpp cuando mucho, podre obtener en la salida solamente los pulsos cada vez que pase por cero obviamente.? gracias de antemano.


----------



## mecaingetronico (Sep 6, 2012)

Tengo una duda, el cruce por cero se hace solamente con un microcontrolador y los circuitos que aquí se muestran o se puede omitir la parte del micro?


----------



## Scooter (Sep 6, 2012)

Se hace con cualquier circuito que quieras sincronizar con la red. Básicamente todos los dimmers y en los controles todo/nada en los que quieras garantizar una conexión "suave".


----------



## miglo (Sep 3, 2015)

Hola, estoy intentando hacer un cruce por cero para iluminar una lampara y no consigo hacer que me funcione, parte del esquema lo he sacado de internet algunas cosas las he añadido yo pero no hay manera de conseguir que me funcione.

No se si es el esquema del circuito o el codigo para hacer 2 efectos.

Alguien me puede hechar un cable y explicarme que es lo que tengo mal y el por que para entenderlo.  

Adjunto archivo:


----------



## papirrin (Sep 3, 2015)

Vi el diagrama y no me gusto, por lo que ya no revise el codigo...

yo tengo armado este:



y funciona mmuy bien.. visto con oscilocopio en lo real (obviamente le falta lo del triac despues del MOC3021., principalmente me enfoco a la deteccion de cruce por cero.)


----------



## miglo (Sep 3, 2015)

Papirrin te agradezco tu respuesta, pero con eso no me sirve.

Me parece bien que no te guste, pero si no me dices donde tengo el error, segun tu opinion, no me ayudas en nada ya que lo bueno es corregir los errores y saber el por que.

Por otra parte el circuito que pones veo que funciona a 12Ac ya que la bombilla que hay es de 12Ac y claro yo lo quiero para una bombilla de 230Ac con triac, que es la tension con la que trabajo.

Aun con todo gracias.



Un añadido, como no se poner con proteus el alternador y que funcione he puesto los 12Ac a mi manera.


----------



## papirrin (Sep 3, 2015)

> no me ayudas en nada ya que lo bueno es corregir los errores y saber el por que.



me parece muy bien que no te ayude XD... y no me gusta porque no esta totalmente aislado.



> Por otra parte el circuito que pones veo que funciona a 12Ac ya que la bombilla que hay es de 12Ac y claro yo lo quiero para una bombilla de 230Ac con triac, que es la tension con la que trabajo.


no se si no leiste lo ultimo que puse, pero dale una reeleida a mi mensaje. 

y claro que por eso no revise el codigo, si no te sirve, para que pierdo mi tiempo XD


----------



## pandacba (Sep 3, 2015)

Si queres el encendio en el cruce por cero utilza un MOC3041, que dispara el triac directamente en el cruce por cero


----------



## miglo (Sep 3, 2015)

Papirrin. Cuando digo; "con eso no me sirve", me refería a la manera de responder, que me ha parecido un poco seca.
En ningún momento pretendo ir de sobrado, no a que tu circuito no me sirva, claro que me sirve, de hecho me sirven todos, si no, cómo voy a aprender si cometo errores.

Lo de leer, tienes más razón que un santo. No había prestado atención a lo del triac. Mea culpa.

Y en lo referente a lo de aislado. *[Término innecesariamente vulgar]* Error mío.
Con tanta modificación, cuando he hecho el archivo no me había fijado de que estaba mal lo de los 12 VAC.
No sé cómo me he despistado, está claro que *ahí *va el puente rectificador, pero por algún despiste he borrado líneas. Cosas que pasan.


----------



## papirrin (Sep 3, 2015)

MIGLO:

 y aclara si lo que quieres es encender y apagar o dimerizar, porque creo que el MOC3041 no te sirve para dimerizar.


----------



## miglo (Sep 3, 2015)

pandacba dijo:


> Si queres el encendio en el cruce por cero utilza un MOC3041, que dispara el triac directamente en el cruce por cero



Pandacba tengo el MOC3041 pero como he leido tantas cosas al final puse el MOC 3023 por que aunque es un prueba lo que quiero es que se ilumine poco a poco y luego se apague poco a poco tambien, de hay las 2 funciones que puesto en el programa.

Es que quiero quitar los interruptores que tengo en algunas zonas de la casa por que algunos me estan fallando y asi en vez de tener interruptores pondre pulsadores.



papirrin dijo:


> MIGLO:
> 
> y aclara si lo que quieres es encender y apagar o dimerizar, porque creo que el MOC3041 no te sirve para dimerizar.



Eso es Papirrin las 2 cosas


----------



## papirrin (Sep 3, 2015)

Le di una revizada a tu codigo por curiosidad y tampoco me gusta  (porque usas delays en la interrupcion, entre otras cosas)


mira yo los que he hecho, ya sea en basic, C o ASM, para dar el angulo de disparo utilizo un timer y la interrupcion externa, para darte una idea hice este codigo en C


```
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#include <stdbool.h>
#define _XTAL_FREQ 4000000

#pragma config FOSC = INTRCIO  
#pragma config WDTE = OFF       
#pragma config PWRTE = ON      
#pragma config MCLRE = OFF      
#pragma config CP = OFF   
#pragma config CPD = OFF       
#pragma config BOREN = OFF     
#pragma config IESO = OFF       
#pragma config FCMEN = OFF     

unsigned char BUFFER=127;

void interrupt isr(void){
 if(INTCONbits.T0IF==true){
  INTCONbits.T0IF=false; 
  PORTCbits.RC0=1;
  __delay_us(6);
  PORTCbits.RC0=0;
  INTCONbits.T0IE=false;}
 else if (PIR1bits.RCIF==true){
  PIR1bits.RCIF=false;
  BUFFER=RCREG;}
 else if (INTCONbits.INTF==true){
  INTCONbits.INTF=false; 
  TMR0=BUFFER;
  INTCONbits.T0IE=true;
  OPTION_REGbits.INTEDG=!OPTION_REGbits.INTEDG;}
}

void PIC_Init(void){
//Config
 OPTION_REGbits.INTEDG=true;
 OPTION_REGbits.T0CS=false;
 OPTION_REGbits.PS0=false;
 OPTION_REGbits.PS1=false;
 OPTION_REGbits.PS2=true;
 OPTION_REGbits.PSA=false;
 OSCCON=0x61;

//Interrupt Config
 PIE1bits.RCIE=true;
 INTCONbits.INTE=true;
 INTCONbits.PEIE=true;
 INTCONbits.GIE=true;

//Ports Config
 ANSEL=0;
 ANSELH=0;
 TRISA=0b100;
 TRISB=0b100000;
 TRISC=0b0;
 PORTA=0;
 PORTB=0;
 PORTC=0;
 
//TX_RX Config
 TXSTAbits.TXEN=true;
 TXSTAbits.TRMT=true;
 TXSTAbits.TX9=false;
 TXREG=0;
 RCSTAbits.CREN=true;
 RCSTAbits.RX9=false;

//Baud Rate Config
 RCSTAbits.SPEN=true;
 TXSTAbits.SYNC=false;
 TXSTAbits.BRGH=true;
 BAUDCTLbits.SCKP=false;
 BAUDCTLbits.BRG16=false;
 SPBRG=25;
 SPBRGH=0;
} 

void main(void)
{
 PIC_Init();
 while(true);
}
```

nada mas que en ese proyecto no utilice el mismo diagrama del puente rectificador que detecta el cruce por cero, en ese codigo tenia que cambiar el flanco porque fue un diagrama diferente, por eso te recominedo que definas bien que diagrama vas a utilizar.

Aclaro que en gustos se rompen generos y puede que tampoco te sirva y ese codigo lo hice en mikro C para un pic 16F690y supongo que tu estas usando PIC CCS


----------



## miglo (Sep 4, 2015)

Asi es Papirrin yo uso Ccs, y gracias que me voy defendiendo poco a poco.

Sobre los delays de la interrupcion, pues como que se me atragantan y entonces a mi manera la hago, voy aprendiendo el tema de las interrupciones pero me cuesta mucho.  

Como harias tù esa interrupcion?.


----------



## papirrin (Sep 4, 2015)

Mira a ver si hoy tengo un poco de tiempo y pongo un video del que tengo armado, el problema es que el codigo lo tengo en basic , vere si tambien tengo chance de migrarlo a ccs.


----------



## miglo (Sep 4, 2015)

Ok, Papirrin. ¿Te importaría hacerme un ejemplo del manejo de una interrupción sin delay?
En este caso la int_ext, o la de int_rb, que son las que suelo manejar,  con su explicación para que lo pueda entender.
Esto ya me lo explicó D@rbytes en su día, pero no me matizó lo de los delays.

Haber, yo de hacerlas, se hacerlas pero sencillas.
Esto es por ejemplo: Pulsar RB0 "int_ext" y que realice una función o instrucción. 

Me gusta comprender las cosas, así yo me suelto haciendo mis pinitos.
Lo que pasa es que las interrupciones las tengo atragantadas, y mira que leo, pero de momento no termino de aclararme.


----------



## papirrin (Sep 4, 2015)

Bueno aqui va el video prometido del que tengo armado y segun yo explicado del porque me gusto ese diseño que puse:





NOTA:en el video dije que era un MOC3041 pero me equivoque es un MOC3021 el que estoy utilizando XD.


----------



## pandacba (Sep 4, 2015)

No te sirve el MOC3041 para dimerizar, ya que solo se activa en el cruce por cero, en cuyo caso no tiene sentido el cruce por cero


----------



## miglo (Sep 5, 2015)

Eso es lo que quiero hacer, me gusta la idea del 4N37.

El transformador que yo tengo es de 220 a 12Ac, voy a ponerme manos a la obra haber si encuentro un 4N37 y hago purebas.

Las bombillas que yo tengo son de leds, pero como no llevan regulador va bien, lo que llevan es el clasico puente con resistencia de limitacion y condensador de filtro y los leds van en serie.

Esa manera de encender la luz para la habitacion va de perlas.


----------



## papirrin (Sep 5, 2015)

ya hice la migracion de mi codigo de PBP a CCS....

Let's pray in C


```
#include <16F877A.h>

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES XT                       //Crystal osc <= 4mhz
#FUSES PUT                     //Power Up Timer
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD                    //No EE protection
#FUSES NOWRT                    //Program memory not write protected

#use delay(clock=4000000)

#define TRIAC  PIN_B3
#define F_MAX  PIN_B1
#define F_MED  PIN_B2

int VTO=240;


#int_RTCC
void RTCC_isr() 
{

 output_high(TRIAC);
 delay_us(10);
 output_low(TRIAC);
 disable_interrupts(INT_RTCC);
}

#int_EXT
void EXT_isr() 
{
 set_timer0(VTO);
 enable_interrupts(INT_RTCC);
}



void main()
{
   
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);
   setup_psp(PSP_DISABLED);
   setup_spi(FALSE);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_64);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
   enable_interrupts(INT_RTCC);
   enable_interrupts(INT_EXT);
   enable_interrupts(GLOBAL);
   set_tris_B(0b111);
   
   while(true)
   {
    if (input(F_MAX))
          { 
       vto++;   
        delay_ms(10); // antirrebote si puedes usar otro metodo que no use delay mejor.
          }
          
    
    if (input(F_MED))
          {
          vto--;
           delay_ms(10); // antirrebote si puedes usar otro metodo que no use delay mejor.
          }   
   };

}
```

Obviamente es solo la parte importante. lo ajustas como quieras usando los menos delays posibles.

Video de funcionamiento:


----------



## miglo (Sep 6, 2015)

Hola papirrin, estoy haciendo unas pruebas en proteus y se me satura el programa, te comento el transformador que yo tengo es 220 a 12, no lo tengo con toma central, lo normal es poner las conexsiones en el puente como se corresponde, pues si lo hago asi no me va ni para atras pero si le pongo como en el esquema que pusiste tu si va, esto es devido a proteus?, es mas tengo que poner el triac tambien una toma a tierra.

Otra pregunta, no tengo, de momento, ningun 4nxx ya que tu circuito me gusta mas que el mio pero si tengo un EL817 que es lo mismo que el PC817, este puede servir para hacer pruebas?.

Y por ultimo te agradezco el programa, lo entiendo todo, ya te digo que si lo hubiese tenido que hacer yo no me hubiese aclarado pero ahora me ha facilitado mas la comprension para en el futuro hacer mis pequeños pinitos, aunque se me siguen atragantando las interrupciones, yo creo que poco a poco ire cogiendo el tranquillo.

Me corrigo he probado el PC817 que aparece en proteus y en principio si que parace ser es bueno.


----------



## papirrin (Sep 6, 2015)

> Hola papirrin, estoy haciendo unas pruebas en proteus y se me satura el programa, te comento el transformador que yo tengo es 220 a 12, no lo tengo con toma central, lo normal es poner las conexsiones en el puente como se corresponde, pues si lo hago asi no me va ni para atras pero si le pongo como en el esquema que pusiste tu si va, esto es devido a proteus?, es mas tengo que poner el triac tambien una toma a tierra.



bueno yo por eso no utilice el triac en el esquema que puse, porque no lo hace como en la realidad, en pocas palabras proteus a mi me sirve solo para ir probando el programa del pic sin tener que estar quemandolo en lo real a cada rato, y proteus si tiene que tener una toma a tierra como punto de referencia, pero en lo real no lo necesita, en lo real si puse una una toma a tierra pero solo para efectos de poner el osciloscopio pero no la va a llevar para que este completamente aislado el pic de la corriente alterna.

casi cualquier opto te sirve, todos son muy parecidos, o por lo menos los que yo he comparado(obviamente que sea un opto-transistor)

y de las interrupcciones no te hagas tanto lio, velo asi... un pic tiene diferentes modulos usart, timers, pwm, etc, esos modulos que son como los perifericos en una PC (mouse, teclado, impresora, etc) son independientes del CPU y casi todos tiene una interrupcion al programa principal o sea que se interrumpe el programa para ejecutar una subrutina, el cpu tiene asignada un seccion de programa en donde se coloca esa subrutina que se ejecuta al recibir esa interrupcion.

todas esos modulos modifican un registro para que sepas cual fue el que causo esa interrupcion, y esos registros de interrupcion se ven en la ficha tecnica, y cada modulo de cada pic tiene una manera particular de hacerlo por eso muchos no las comprenden y no es facil de explicarlas, se tiene que estudiar la ficha tecnica de como funciona cada una.


----------



## miglo (Sep 6, 2015)

papirrin dijo:


> un pic tiene diferentes modulos usart, timers, pwm, etc, esos modulos que son como los perifericos en una PC (mouse, teclado, impresora, etc) son independientes del CPU y casi todos tiene una interrupcion al programa principal o sea que se interrumpe el programa para ejecutar una subrutina, el cpu tiene asignada un seccion de programa en donde se coloca esa subrutina que se ejecuta al recibir esa interrupcion.
> 
> todas esos modulos modifican un registro para que sepas cual fue el que causo esa interrupcion, y esos registros de interrupcion se ven en la ficha tecnica, y cada modulo de cada pic tiene una manera particular de hacerlo por eso muchos no las comprenden y no es facil de explicarlas, se tiene que estudiar la ficha tecnica de como funciona cada una.



No lo habia visto de esa manera, gracias.


----------



## papirrin (Sep 6, 2015)

Lo que sucede cuando el aburrimiento me abruma XD:






bueno mejor me voy a poner briago en lugar de hacer tonterias


----------



## miglo (Sep 7, 2015)

Jeje, lo que hace el aburrimiento aveces, jeje.

Te quiero hacer unas preguntas si no te importa.

setup_timer_0(RTCC_INTERNAL|RTCC_DIV_64); esta configuracion es para 50 ciclos o para 60? es que no me aclaro con la equacion para sacar el tiempo.

Despues de haber configurado y montado el protoboard y haber resuelto 4 o 5 errores de montage tales como poner al reves el opto o conectar mal el pin Rb0 o equibocarme en el cristal ya que lo puse de 10 en vez de 4Mhz, ya me funciona el programa, pero he notado un problema que no se si es devido a la frecuencia, que es de 50ciclos, a la bombilla, esta es de leds como te comente, o a la tension que aqui es de 230Ac, el caso es que cuando conecto como esta configurado la variable VTO=240, no se me enciende pero al bajarla a 236 si, cuando llega a 107, la variable, entonces se apaga, yo lo habia modificado para que empieze en 100 y asi al ir subiendo que se valla encendiendo poco a poco, pues si empiezo en 100 no me funciona el programa pero si lo empiezo en 240, como lo tienes tu si, es mas si le pongo limitaciones al programa tales como que no baje de 100 o no supere 240 tampoco me funciona el programa y claro ya empiezo haber fantasmas por todos lados. 

A que crees que puede ser devido?.

Por cierto, bonito video.



Por cierto, se me olvidaba, tengo el osciloscopio pero como lamentablemente perdi una sonda no veo como tu las señales, cosas que traen los años por no usarlo, jeje.


----------



## papirrin (Sep 7, 2015)

mira primero lo de la div de 64

la formula para eso es:
Temporización = (4 * (255-TMR0) * PreScaler)/Fosc

como tu frecuencia es de 50Hz el tiempo del ciclo es de 20mS, pero como gatillas a medio ciclo seria 10mS y despejando la formula seria:

TMR0=255-((tiempo*fosc)/4/64) o sea

TMR0=255-((.01*4000000)/4/64)=99

tu rango va de 99 a 255 , peroo como la onda de la frecuencia no es cudrada, el opto tarda unos microsegundos en saturar el transistor asi que puede fallar a los 99 y tendras que recorrerlo un poco como 100, 101... etc...

del otro lado de los 255 es mas o menos lo mismo a demas que no se puede lograr un desborde hasta los 255 porque el pic corre a una frecuencia de 4MHz y se tiene que considerar tiempos de ejecucion de cada instruccion, asi que es imposible llegar a los 255 asi que tambien tendras que bajar ese valor a doscientos cuarenta y tantos. o meter un cristal de 20Mhz o de plano usar un DSPIC si quieres que te abarque el 99.9% del rango. para mi hacer eso es excesivo pues de cualquier manera el ojo humano y el filamento ni se van a percatar.

en pocas palabras busca el rango que funcione bien y ten en cuenta que ningun metodo va a llegar al 100% del ciclo.


 ahora bien si publicas tu codigo puedo decirte si existe algun otro error.


----------



## locodelafonola (Sep 7, 2015)

hola 





papirrin dijo:


> bueno yo por eso no utilice el triac en el esquema que puse, porque no lo hace como en la realidad, en pocas palabras proteus a mi me sirve solo para ir probando el programa del pic sin tener que estar quemandolo en lo real a cada rato, y proteus si tiene que tener una toma a tierra como punto de referencia, pero en lo real no lo necesita, en lo real si puse una una toma a tierra pero solo para efectos de poner el osciloscopio pero no la va a llevar para que este completamente aislado el pic de la corriente alterna.
> 
> casi cualquier opto te sirve, todos son muy parecidos, o por lo menos los que yo he comparado(obviamente que sea un opto-transistor)
> 
> ...


 No vi el post antes ., sino aportaba  disculpen​ Bueno papirrin ., algo como esto., es lo que yo uso ., y me da muy buen resultado​ La señal de ZC ., la ingreso al micro por la entrada de la interupcion extena​ luego que se da el cruze por cero habilita el dimmer ., lo he probado concrgas inductivas y resistivas ., va OK​


----------



## papirrin (Sep 7, 2015)

pero asi como esta la deteccion del cruce por cero, solo detecta el ciclo completo no?

como gatillas en el ciclo negativo?
necesitas cambiar de flanco no? similar al codigo que puse de mikro C mensaje # 22

me explico?


----------



## locodelafonola (Sep 7, 2015)

papirrin dijo:


> pero asi como esta la deteccion del cruce por cero, solo detecta el ciclo completo no?
> 
> como gatillas en el ciclo negativo?
> 
> ...


 aver si queres te subo el ejemplo pero es en C ., para atmega​ ., segun entiendo yo ., habilita el dimer cuando cruza por cero ., o sea va cambiando el PWM (aumenta o disminuye de acuerdo al comando )​EDITO:si papairrin es como en el mensaje numero 22​


----------



## papirrin (Sep 7, 2015)

si me gustaria verlo, segun yo tiene que cambiar de flanco... si lo he probao asi pero consume un poco de tiempo al estar cambiando el flanco de interrupcion, y por eso me gusta mas el del puente rectificador.


----------



## locodelafonola (Sep 7, 2015)

OK 





papirrin dijo:


> si me gustaria verlo, segun yo tiene que cambiar de flanco... si lo he probao asi pero consume un poco de tiempo al estar cambiando el flanco de interrupcion, y por eso me gusta mas el del puente rectificador.


 bueno aca te pongo el que uso en la maquina de humo DMX​ (uno esta para la bomba inductivo y el otro resistivo ., que es el calentador) tiene deteccion de temperatura tambien​ par que no te pierdas con el codigo la entrada de interupcion es PD3 (INT1)​

```
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <stdlib.h>

typedef int8_t	s08;
typedef int16_t	s16;
typedef int32_t	s32;
typedef uint8_t	u08;
typedef uint16_t u16;
typedef uint32_t u32;

#define XTAL				8000000

#define DMX_StartCode		0 // DMX512 start code to react to (0 is for dimmers)
#define DMX_UART_Speed		250000	// standard DMX512 mode
#define DMX_UART_Div		(u16) (XTAL / 16 / DMX_UART_Speed - 1)
#define DMX_NUM_CHANNELS	3
#define DMX_INDICATOR_TIME	3

#define DIMMER_TimerStart	0xD8EF
#define DIMMER_AngleWidth	38
#define DIMMER_PORT			PORTA
#define DIMMER_PORT_DIR		DDRA

#define LED_PORT			PORTE
#define LED_PORT_DIR		DDRE
#define LED_Green			PE1
#define LED_Red				PE2

#define BLINK_Counter		25

#define PIN_Ext				PA0
#define PIN_Pump			PA1
#define PIN_Heater			PA2

#define PIN_Temp			ACO
#define PIN_ManFog			PA3

volatile u08 g_DMX_Status;		 				// current DMX status (global to be resettable)
volatile u08 g_DMX_Values[DMX_NUM_CHANNELS];
volatile u08 g_DMX_BaseAddress = 1;
volatile u08 g_DMX_IndicatorCounter = DMX_INDICATOR_TIME - 1;

volatile u08 g_DIMMER_PhaseCount;

volatile u08 g_DIMMER_PumpVal = 0;
volatile u08 g_DIMMER_PumpVal2 = 0;
volatile u08 g_DIMMER_ExtVal = 0;

volatile u08 g_TempState = 1;

volatile u16 g_CycleTime = 0;
volatile u08 g_OnTime = 0;

void DMX_ReadBaseAddress(void) {
 u08 temp;

 temp = PINC;
 g_DMX_BaseAddress=255-temp;
}

void DMX_init(void) {
 u08 i;
 // - UART mode
 UCSRC = (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0); // 8n1
 UCSRB = (1<<RXCIE) | (1<<RXEN) | (1<<TXEN); // receive int and receiver enabled
 UBRRH = (u08) (DMX_UART_Div >> 8); // set baud rate
 UBRRL = (u08) (DMX_UART_Div);
 for (i=0; i<DMX_NUM_CHANNELS; i++) {
  g_DMX_Values[i] = 0;
 }
 g_DMX_Status = 0; // reset status to let ISR wait for next BREAK before doing anything
 DMX_ReadBaseAddress();
}

void DIMMER_init(void) {
 TCCR1B = 0b00000010; 					// set timer1 to ck/8
 // set interrupt 1 for phase zero-crossing control
 MCUCR |= (1 << ISC11);				// interrupt by falling edge
 MCUCR &= ~(1 << ISC10);				// <-^
 GICR |= (1 << INT1);					// enable interrupt0
 GIFR |= (1 << INTF1);					// clear interrupt0 flag
}

void init(void) {
 //ports
 DDRC = 192;
 PORTC = 255;
 DDRD = 4;
 PORTD = 8;
 LED_PORT_DIR = 255;
 LED_PORT = 255;

 DIMMER_PORT_DIR = 0b11110111;
 DIMMER_PORT =     0b00001111;

 ACSR = 0b01000000;								// bandgap reference (1.23V)

 TCCR0 = 0b00000101;							// set clk/1024
 TIMSK |= (1 << TOIE0);						// enable timer0 overflow interrupt
}

int main(void) {
 init();
 DMX_init();
 DIMMER_init();
 sei();										// Interrupts erlauben
 for (;;) {								// Endlosschleife
  g_DIMMER_ExtVal = g_DMX_Values[2];
  if (g_DMX_Values[0] > 7) {
   DIMMER_PORT &= ~(1 << PIN_Heater);			// LED an (Bit aus)
   if (g_TempState == 0) {
  DIMMER_PORT &= ~(1 << PIN_Heater);			// LED an (Bit aus)
    g_OnTime = 0;
    g_DIMMER_PumpVal = 0;
   } else {
    DIMMER_PORT |= 1 << PIN_Heater;				// LED aus (Bit an)
	if (bit_is_clear (PINA, PIN_ManFog)) {
     g_OnTime = 0;
     g_DIMMER_PumpVal = 255;	
	} else {
	 if (g_DMX_Values[0] < 21) {
	  g_OnTime = 0;
      g_DIMMER_PumpVal = 0;
	 } else if (g_DMX_Values[0] < 41) {
      g_CycleTime = 310;
	  g_OnTime = 10;
	 } else if (g_DMX_Values[0] < 61) {
      g_CycleTime = 370;
	  g_OnTime = 20;
	 } else if (g_DMX_Values[0] < 81) {
      g_CycleTime = 230;
	  g_OnTime = 30;
	 } else if (g_DMX_Values[0] < 101) {
      g_CycleTime = 190;
	  g_OnTime = 40;
	 } else if (g_DMX_Values[0] < 121) {
      g_CycleTime = 150;
	  g_OnTime = 50;
	 } else if (g_DMX_Values[0] < 141) {
      g_CycleTime = 135;
	  g_OnTime = 60;
	 } else if (g_DMX_Values[0] < 161) {
      g_CycleTime = 120;
	  g_OnTime = 70;
	 } else if (g_DMX_Values[0] < 181) {
      g_CycleTime = 120;
	  g_OnTime = 80;
	 } else if (g_DMX_Values[0] < 201) {
      g_CycleTime = 120;
	  g_OnTime = 90;
	 } else if (g_DMX_Values[0] < 221) {
      g_CycleTime = 120;
	  g_OnTime = 100;
	 } else if (g_DMX_Values[0] < 141) {
      g_CycleTime = 120;
	  g_OnTime = 110;
	 } else {
	  g_OnTime = 0;
      g_DIMMER_PumpVal = g_DMX_Values[1];
     }
	} 
   }	
  } else { 
   DIMMER_PORT |= 1 << PIN_Heater;				// LED aus (Bit an)
   g_DIMMER_PumpVal = 0;
  } 
 }
}

// LED-BLINKEN
SIGNAL (SIG_OVERFLOW0) {
 static u08 WaitTime = BLINK_Counter;
 static u08 SecTimer = 100;
 static u16 SecTimerPos = 0;
 static u08 TempStateCycles = 0;
 static u08 LastTempState = 0;

 if (g_OnTime > 0) {
  DIMMER_PORT |= 1 << 4;
  SecTimer--;
  if (SecTimer == 0) {
   SecTimerPos++;
   SecTimer = 100;
   if (bit_is_set (DIMMER_PORT, 7)) {
    DIMMER_PORT &= ~(1 << 7);
   } else { 
    DIMMER_PORT |= 1 << 7;
   } 
  }
  if (SecTimerPos < g_OnTime) {
   if (g_TempState == 0) {
    g_DIMMER_PumpVal = 0;
   } else {
    g_DIMMER_PumpVal = g_DMX_Values[1];
   }  
  } else {
   g_DIMMER_PumpVal = 0;
  }
  if (SecTimerPos >= g_CycleTime) {
   SecTimerPos = 0;
  }
 } else {
  DIMMER_PORT &= ~(1 << 4);
 }

 WaitTime--;
 if (WaitTime == 0) {
  // Basisadresse lesen
  DMX_ReadBaseAddress();
  if (bit_is_set (ACSR, PIN_Temp)) {
   // Heizen
   if (LastTempState == 1) {
    TempStateCycles++;
	if (TempStateCycles == 5) {
	 g_TempState = 0;
	}
   } else {
    LastTempState = 1;
    TempStateCycles = 0;
   }
  } else {
   // Temperatur erreicht
   if (LastTempState == 0) {
    TempStateCycles++;
	if (TempStateCycles == 5) {
	 g_TempState = 1;
	}
   } else {
    LastTempState = 0;
    TempStateCycles = 0;
   }
  } 
   
  // Grüne LED für Heizen / OK
  if (g_DMX_Values[0] > 7) {
   if (g_TempState == 0) {
    // Grüne LED blinken lassen = heizen
    if (bit_is_set (LED_PORT, LED_Green)) {
     LED_PORT &= ~(1 << LED_Green);			// LED an (Bit aus)
    } else { 
     LED_PORT |= 1 << LED_Green;				// LED aus (Bit an)
    } 
   } else {
    // Grüne LED an = Temperatur erreicht
    LED_PORT &= ~(1 << LED_Green);				// LED an (Bit aus)
   }   
  } else {
   // Grüne LED aus = Gerät aus
   LED_PORT |= 1 << LED_Green;				// LED aus (Bit an)
  } 
  // Rote LED für Fehler
  if (g_DMX_IndicatorCounter > 0) {
   g_DMX_IndicatorCounter--;
   LED_PORT &= ~(1 << LED_Red);				// LED an (Bit aus)
  } else {
   g_DMX_Values[0] = 255;
   g_DMX_Values[1] = 0;
   // Rote LED blinken lassen
   if (bit_is_set (LED_PORT, LED_Red)) {
    LED_PORT &= ~(1 << LED_Red);			// LED an (Bit aus)
   } else { 
    LED_PORT |= 1 << LED_Red;				// LED aus (Bit an)
   } 
  }
  WaitTime = BLINK_Counter; 
 } 
 TCNT0 = 0xb2; // 10ms
}

// DIMMER ZEROCROSSING
SIGNAL (SIG_INTERRUPT1) {
 static u08 PumpTimerPos = 255;

 TCNT1 = DIMMER_TimerStart;				// clear angle-timer
 TIFR |= (1 << OCF1A) + (1 << TOV1);		// clear compare flag; clear overflow-flag
 TIMSK |= (1 << OCIE1A) + (1 << TOIE1);	// enable timer1 compare interrupt A; enable timer1 overflow interrupt
 GICR &= ~(1 << INT1);						// disable ext-interrupt
 g_DIMMER_PhaseCount = 0xff;
 OCR1A = DIMMER_TimerStart + DIMMER_AngleWidth;
 
 PumpTimerPos=PumpTimerPos-2;
 if (PumpTimerPos < g_DIMMER_PumpVal) {
  PumpTimerPos = 255;
  DIMMER_PORT |= 1 << 5;
  g_DIMMER_PumpVal2 = 255;
 } else {
  DIMMER_PORT &= ~(1 << 5);
  g_DIMMER_PumpVal2 = 0;
 } 
}

// DIMMER ZEROCROSSING OVERFLOW
SIGNAL (SIG_OVERFLOW1) {
 TCNT1 = DIMMER_TimerStart;				// clear angle-timer
 TIMSK |= (1 << OCIE1A);					// enable timer1 compare interrupt A
 TIMSK &= ~(1 << TOIE1);					// disable timer1 overflow interrupt
 GIFR &= ~(1 << INTF1);					// clear interrupt1 flag
 g_DIMMER_PhaseCount = 0xff;
 OCR1A = DIMMER_TimerStart + DIMMER_AngleWidth;
}

// DIMMER (TIMER COMPARE)
SIGNAL (SIG_OUTPUT_COMPARE1A) {
 u16 Temp = 0;
 u16 Current;

 if (g_DIMMER_PumpVal2 > g_DIMMER_PhaseCount) {
  DIMMER_PORT &= ~(1 << PIN_Pump);			// LED an (Bit aus)
 } else {
  DIMMER_PORT |= 1 << PIN_Pump;				// LED aus (Bit an)
 }

 if (g_DIMMER_ExtVal > g_DIMMER_PhaseCount) {
  DIMMER_PORT &= ~(1 << PIN_Ext);			// LED an (Bit aus)
 } else {
  DIMMER_PORT |= 1 << PIN_Ext;				// LED aus (Bit an)
 }
 
 do {
  g_DIMMER_PhaseCount--;
  if (g_DIMMER_PhaseCount == 0) {
   break;
  }
  Temp = OCR1A;
  Temp += DIMMER_AngleWidth;
  Current = TCNT1;
 } while (Current >= Temp);	// test if next timer1-compare-value isn't already gone
 if (g_DIMMER_PhaseCount == 0) {
  TIMSK &= ~(1 << OCIE1A);					// disable timer1 compare interrupt
  DIMMER_PORT |= (1 << PIN_Ext) | (1 << PIN_Pump);				// LED aus (Bit an)
  DIMMER_PORT = 0b00001111;						// turn Dimmer port off (safe)
  if ((TIMSK & (1 << TOIE1)) == 0) {		// check for timer-overflow-interrupt; if timer1 overflow interrupt is enabled
   GIFR |= (1 << INTF1);					// clear interrupt1 flag
   GICR |= (1 << INT1);					// enable external interrupt1
  }
 } else {
  OCR1A = Temp;
 }
}

SIGNAL (SIG_UART_RECV) { // UART received one byte - highest priority
 static u16 DMX_Frame = 0;
 u08 Status = UCSRA; // status register must be read prior to UDR (because of 2 byte fifo buffer)
 u08 Byte = UDR; // immediately catch data from i/o register to enable reception of the next byte

 if ((Byte == 0) && (Status & (1<<FE))) { // BREAK detected (Framing Error)
  g_DMX_Status = 1;
  DMX_Frame = 0;
 } else if (DMX_Frame == 0) { // SC test
  if ((Byte == DMX_StartCode) && (g_DMX_Status == 1)) { // valid SC detected
   g_DMX_Status = 2;
  }
  DMX_Frame = 1;
 } else {
  if ((g_DMX_Status == 2) && (DMX_Frame >= g_DMX_BaseAddress) && (DMX_Frame < (g_DMX_BaseAddress + DMX_NUM_CHANNELS))) { // addressed to us
   u08 Channel = DMX_Frame - g_DMX_BaseAddress;
   if (Channel < DMX_NUM_CHANNELS) {
    g_DMX_Values[Channel] = Byte;
   }
   g_DMX_IndicatorCounter = DMX_INDICATOR_TIME - 1;
  }
  DMX_Frame++;
 }
}
```
No se como andas econ ASM ., pero siqueres tengo tambien (es lo mismo ., pero solo dimer )​ Pero tambien al igual que el anterior ., recontra probados y sin problemas​


----------



## miglo (Sep 8, 2015)

Creo que empiezo a comprender las interrupciones, aunque me cuesta.
Te adjunto el código, y el esquema se me olvido ponerlo.

Como te decía, si pongo limitaciones proteus se me satura y el programa con la bombilla no me tira, si se las quito va.
La pena es que en mi casa todas las bombillas son de leds y no tengo ninguna de filamento, voy a ver si consigo una de filamento y te cuento.  



```
#include <16f877A.h>
#fuses XT,NOWDT,NOBROWNOUT,NOCPD,NOLVP,NOPROTECT

#use delay(clock=4M)

#use fast_io(B)

#define TRIAC  PIN_B3
#define F_MAX  PIN_B1
#define F_MED  PIN_B2

#include <lcd.c>

  int VTO=240; 

#int_RTCC
void RTCC_isr() 
   {
 
 output_high(TRIAC);
 delay_us(10);
 output_low(TRIAC);
 disable_interrupts(INT_RTCC);
     } 
     
#int_EXT
void EXT_isr() 
   {
 set_timer0(VTO);
 enable_interrupts(INT_RTCC); 
     }
 
  void main()
     {
   set_tris_B(0x07);
   output_b(0x00);
   
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_64);
  
   enable_interrupts(INT_RTCC);
   enable_interrupts(INT_EXT);
   enable_interrupts(GLOBAL);
  
   lcd_init();
 
   lcd_gotoxy(1,1);
   lcd_putc(" Iniciando FASE ");
   lcd_gotoxy(1,2);
   printf(lcd_putc," FASE:  %3.0u",VTO);
  
   lcd_gotoxy(1,1);
   lcd_putc(" FASE  Activada ");
   
 while (true)
     {
     
  if (input(F_MAX))
          { 
       delay_ms(100);   
        VTO++;  
      lcd_gotoxy(1,2);
    printf(lcd_putc," FASE:  %3.0u",VTO);  
          }          
    
    if (input(F_MED))
          { 
       delay_ms(100);   
        VTO--;
       lcd_gotoxy(1,2);
    printf(lcd_putc," FASE:  %3.0u",VTO); 
          }
          
    if(VTO>=240)
       {
     VTO=240;
       }
       
     if(VTO<=107)
        {
       VTO=107;        
        }
        
      }
    }
```

Edito que me dado cuenta que el documento estaba en blanco.
No sé cómo se borra el archivo en blanco, jeje.


Bueno, pues me corrijo a mi mismo.
He vuelto a cargar el programa con las limitaciones y ahora si funciona.





locodelafonola dijo:


> OK  bueno aca te pongo el que uso en la maquina de humo DMX​ (uno esta para la bomba inductivo y el otro resistivo ., que es el calentador) tiene deteccion de temperatura tambien​ par que no te pierdas con el codigo la entrada de interupcion es PD3 (INT1)​
> No se como andas econ ASM ., pero siqueres tengo tambien (es lo mismo ., pero solo dimer )​ Pero tambien al igual que el anterior ., recontra probados y sin problemas​



Papirrin no se perderá leyendo el código pero yo me he perdido por completo.
Bueno, por completo no, es una manera de decirlo, por ejemplo  µ08 no sé lo que es.

Tendrías algún problema en lo básico para poder entenderlo, ponerlo en C pero para un 876 o 877 por ejemplo.



papirrin dijo:


> mira primero lo de la div de 64
> 
> la formula para eso es:
> Temporización = (4 * (255-TMR0) * PreScaler)/Fosc
> ...


 Ahora empiezo a entenderlo mejor después de leerlo y releerlo.
Mi falta  de comprensión estaba en que yo mezclaba 2 conceptos, y son que el timer0  es de 8 bits o lo que es lo mismo de 0 a 255 y el timer1 y timer2 es de  16, en este caso por que hablamos del PIC16F877A.
Con lo que yo hacía  la fórmula mal, en vez de (255-tmr0) que es el del tmr0, ponía la del  timer1(65535-tmr0) con lo que no daba una a derechas.


----------



## locodelafonola (Sep 8, 2015)

Hola 





miglo dijo:


> Papirrin no se perdera leyendo el codigo pero yo me perdido por completo, bueno por completo no, es una manera de decirlo, por ejemplo  µ08 no se lo que es, tendrias algun problema en lo basico para poder entenderlo, ponerlo en C pero para un 876 o 877 por ejemplo.


 Bueno ., lamento no poder ayudarte en nada querido amigo​ Poque de programacin de PIC ., yo no se nada ., el ejemplo que subi es para ATMEGA​ Lo puse para que viera papirrin ., como se usa la interupcion externa ., del crusze por cero​ Y como se que papirrin sabe., podria adaptar las funciones al PIC ., pero la parte de electronica que subi ., sirve para el PIC tambien​ Si no tenes una lampara de filamento podes conectar una "plancha"(es resistiva)​


----------



## papirrin (Sep 8, 2015)

> Ahora empiezo a entenderlo mejor despues de leerlo y releerlo, mi falta de comprension estaba en que yo mezclaba 2 conceptos y son que el timer0 es de 8 byts o lo que es lo mismo de 0 a 254 y el timer1 y timer2 es de 16, en este caso por que hablamos del pic 16f877a, con lo que yo hacia la formula mal, en vez de (255-tmr0) que es el del tmr0 ponia la del timer1(65535-tmr0) con lo que no daba una a derechas.



Asi es, los timers funcionan diferente, suponiendo el tmr2 si se utiliza el modulo CCP, se configura diferente, y creo que tambien es de 8 bits, el unico de 16 es el tmr1.

como te menciono que aunque funcionan de manera similar uno tiene funciones diferentes a las del otro y se tiene que seleccionar el que mejor se ajuste a las necesidades, me parece que seleccione el TMR0 porque es el que tiene div entre 64 y es el que en el rango de 0 a 255 da el tiempo necesario.

me falto aclarar que en un modulo sea cual sea puede, y segun la aplicacion, no es forzosamente necesario utilizar su interrupcion, y solo se puede tomar su valores de registro.

en el caso de CCS aparentemente se usan subrutinas distintas para las interrupciones pero a la hora de compilar las pone en la misma subrutina asignada por el CPU (unidad central de procesamiento) del PIC.

para saber a detalle como funciona un pic, casi es necesario tener nociones de ASM, puesto que los lenguajes de alto nivel como Basic o C ya tienen muchas algoritmos prefabricados.

y otra cosa que se me olvidaba, si vas a dejar el transformador de 12v, es conveniente que las resistencias no sean de 10K sino de 1k, puesto que las de 10K estan calculadas para 110V, y como mencione yo puse un tranformador porque no tengo las resistencias de 1W. en el esquema de locodelafonola se ve que para 220V se necesitan resistencias de 27K a 1W si se toma directamente de la red electrica.


----------



## locodelafonola (Sep 8, 2015)

hola 





papirrin dijo:


> Asi es, los timers funcionan diferente, suponiendo el tmr2 si se utiliza el modulo CCP, se configura diferente, y creo que tambien es de 8 bits, el unico de 16 es el tmr1.
> 
> como te menciono que aunque funcionan de manera similar uno tiene funciones diferentes a las del otro y se tiene que seleccionar el que mejor se ajuste a las necesidades, me parece que seleccione el TMR0 porque es el que tiene div entre 64 y es el que en el rango de 0 a 255 da el tiempo necesario.
> 
> ...


 bueno si queres ., como dije tengo en ASM ., pero lo que no entiendo es porque nesesitas cambiar el  "gatillado"., del ciclo negativo ., (perdona mi ignoracia )​ Aca te subo el programa en ASM.,  que funciona​

```
;***************************************************************************/

.include "m8515def.inc"


/* ***** pin definitions */

#define LED1		PD7
#define LED2		PE0
#define	BIT9		PE2
#define OPTION		PE1
#define USA_MODE	PD4

/* ***** constants */

#define	TABLE_A		0x200
#define TABLE_B		0x400

.equ DMX_FIELD=     0x60 			/* SRAM-Beginn */
.equ DMX_CHANNELS=  8
.equ F_OSC=         8000

#define DMX_EXT

.equ BlinkPos=		0x70
.equ ShtDwnTemp=	0x71			/* Temperature to shut down */
.equ SwitchCh=		0x72			/* Mask of switched channels */


/* ***** special Flags */

#define VALID_DMX 		1 
#define VALID_ZC		2
#define SIGNAL_COMING 	3 
	
#define HOT				6
#define DATA_REFRESHED 	7 


/* ***** global register variables */

#define	tempL		R24			
#define	tempH		R25						
#define	Flags 		R16
#define DMXstate	R17			

#define	null		R2
#define	SREGbuf		R3
#define blink 		R4
#define LEDdelay 	R5				/* prescaler */

#define	status		R6				/* status bits for portc */
#define	SwitchMask  R7

#define	currentL	R18
#define	currentH	R19

#define	dimm_count	R20				/* counter */

#define	timer_startH	R8
#define	timer_startL	R9

/* ***** set time tables for firing angles */ 

.org TABLE_A	/*  50Hz */
	.dw	0x2710, 0x2472, 0x2346, 0x228F, 0x2204, 0x2190, 0x212C, 0x20D2, 0x2081, 0x2037, 0x1FF2, 0x1FB1, 0x1F74, 0x1F3A, 0x1F03, 0x1ECE 
	.dw	0x1E9B, 0x1E6B, 0x1E3C, 0x1E0E, 0x1DE2, 0x1DB8, 0x1D8E, 0x1D66, 0x1D3E, 0x1D18, 0x1CF2, 0x1CCE, 0x1CAA, 0x1C86, 0x1C64, 0x1C42 
	.dw	0x1C21, 0x1C00, 0x1BE0, 0x1BC0, 0x1BA1, 0x1B82, 0x1B64, 0x1B46, 0x1B28, 0x1B0B, 0x1AEE, 0x1AD2, 0x1AB6, 0x1A9A, 0x1A7E, 0x1A63 
	.dw	0x1A48, 0x1A2E, 0x1A13, 0x19F9, 0x19DF, 0x19C6, 0x19AC, 0x1993, 0x197A, 0x1961, 0x1949, 0x1930, 0x1918, 0x1900, 0x18E8, 0x18D1 
	.dw	0x18B9, 0x18A2, 0x188A, 0x1873, 0x185C, 0x1846, 0x182F, 0x1818, 0x1802, 0x17EB, 0x17D5, 0x17BF, 0x17A9, 0x1793, 0x177E, 0x1768 
	.dw	0x1752, 0x173D, 0x1727, 0x1712, 0x16FD, 0x16E8, 0x16D2, 0x16BD, 0x16A9, 0x1694, 0x167F, 0x166A, 0x1655, 0x1641, 0x162C, 0x1618 
	.dw	0x1603, 0x15EF, 0x15DB, 0x15C6, 0x15B2, 0x159E, 0x158A, 0x1576, 0x1562, 0x154E, 0x153A, 0x1526, 0x1512, 0x14FE, 0x14EA, 0x14D6 
	.dw	0x14C2, 0x14AE, 0x149B, 0x1487, 0x1473, 0x1460, 0x144C, 0x1438, 0x1424, 0x1411, 0x13FD, 0x13EA, 0x13D6, 0x13C2, 0x13AF, 0x139B 
	.dw	0x1388, 0x1374, 0x1360, 0x134D, 0x1339, 0x1325, 0x1312, 0x12FE, 0x12EB, 0x12D7, 0x12C3, 0x12AF, 0x129C, 0x1288, 0x1274, 0x1261 
	.dw	0x124D, 0x1239, 0x1225, 0x1211, 0x11FD, 0x11E9, 0x11D5, 0x11C1, 0x11AD, 0x1199, 0x1185, 0x1171, 0x115D, 0x1149, 0x1134, 0x1120 
	.dw	0x110C, 0x10F7, 0x10E3, 0x10CE, 0x10BA, 0x10A5, 0x1090, 0x107B, 0x1066, 0x1052, 0x103D, 0x1027, 0x1012, 0x0FFD, 0x0FE8, 0x0FD2 
	.dw	0x0FBD, 0x0FA7, 0x0F91, 0x0F7C, 0x0F66, 0x0F50, 0x0F3A, 0x0F24, 0x0F0D, 0x0EF7, 0x0EE0, 0x0EC9, 0x0EB3, 0x0E9C, 0x0E85, 0x0E6D 
	.dw	0x0E56, 0x0E3E, 0x0E27, 0x0E0F, 0x0DF7, 0x0DDF, 0x0DC6, 0x0DAE, 0x0D95, 0x0D7C, 0x0D63, 0x0D49, 0x0D30, 0x0D16, 0x0CFC, 0x0CE1 
	.dw	0x0CC7, 0x0CAC, 0x0C91, 0x0C75, 0x0C59, 0x0C3D, 0x0C21, 0x0C04, 0x0BE7, 0x0BC9, 0x0BAB, 0x0B8D, 0x0B6E, 0x0B4F, 0x0B2F, 0x0B0F 
	.dw	0x0AEE, 0x0ACD, 0x0AAB, 0x0A89, 0x0A65, 0x0A41, 0x0A1D, 0x09F7, 0x09D1, 0x09A9, 0x0981, 0x0957, 0x092D, 0x0901, 0x08D3, 0x08A4 
	.dw	0x0874, 0x0841, 0x080C, 0x07D5, 0x079B, 0x075E, 0x071D, 0x06D8, 0x068E, 0x063D, 0x05E3, 0x057F, 0x050B, 0x0480, 0x03C9, 0x029D 



.org TABLE_B	/*  60Hz */
	.dw 8333, 7402, 7224, 7086, 6970, 6870, 6781, 6701, 6627, 6559, 6495, 6436, 6379, 6325, 6274, 6225 
	.dw 6178, 6133, 6090, 6048, 6007, 5968, 5930, 5892, 5856, 5821, 5786, 5753, 5720, 5687, 5656, 5625 
	.dw 5595, 5565, 5536, 5507, 5478, 5451, 5423, 5396, 5370, 5343, 5317, 5292, 5267, 5242, 5217, 5193 
	.dw 5169, 5145, 5122, 5098, 5076, 5053, 5030, 5008, 4986, 4964, 4942, 4921, 4899, 4878, 4857, 4836 
	.dw 4816, 4795, 4775, 4755, 4735, 4715, 4695, 4676, 4656, 4637, 4617, 4598, 4579, 4560, 4541, 4523 
	.dw 4504, 4486, 4467, 4449, 4431, 4412, 4394, 4376, 4358, 4341, 4323, 4305, 4288, 4270, 4253, 4235 
	.dw 4218, 4201, 4183, 4166, 4149, 4132, 4115, 4098, 4081, 4065, 4048, 4031, 4014, 3998, 3981, 3964 
	.dw 3948, 3931, 3915, 3899, 3882, 3866, 3849, 3833, 3817, 3801, 3784, 3768, 3752, 3736, 3720, 3704 
	.dw 3688, 3672, 3655, 3639, 3623, 3607, 3591, 3575, 3559, 3543, 3527, 3511, 3496, 3480, 3464, 3448 
	.dw 3432, 3416, 3400, 3384, 3368, 3352, 3336, 3320, 3304, 3288, 3272, 3256, 3240, 3224, 3208, 3192 
	.dw 3176, 3159, 3143, 3127, 3111, 3095, 3078, 3062, 3046, 3029, 3013, 2997, 2980, 2964, 2947, 2930 
	.dw 2914, 2897, 2880, 2864, 2847, 2830, 2813, 2796, 2779, 2762, 2745, 2728, 2710, 2693, 2675, 2658 
	.dw 2640, 2623, 2605, 2587, 2569, 2551, 2533, 2515, 2496, 2478, 2459, 2441, 2422, 2403, 2384, 2365 
	.dw 2345, 2326, 2306, 2286, 2266, 2246, 2226, 2205, 2185, 2164, 2142, 2121, 2099, 2078, 2056, 2033 
	.dw 2010, 1987, 1964, 1941, 1917, 1892, 1867, 1842, 1816, 1790, 1764, 1736, 1708, 1680, 1650, 1620 
	.dw 1589, 1558, 1524, 1490, 1455, 1418, 1379, 1338, 1294, 1247, 1196, 1140, 1077, 1002, 905,  670

/* ****set interrupt-routines */

.org 0
	
	rjmp reset 				/* reset vector address */
	reti					/* External Interrupt0 Vector Address */
	rjmp zero_crossing		/* External Interrupt1 Vector Address */
	reti					/* Input Capture1 Interrupt Vector Address */
	rjmp compare			/* Output Compare1A Interrupt Vector Address */
	reti					/* Output Compare1B Interrupt Vector Address */
	rjmp zero_crossing_overflow	/* Overflow1 Interrupt Vector Address */
	rjmp LED_indicator		/* Overflow0 Interrupt Vector Address */
	reti					/* SPI Interrupt Vector Address */
	rjmp get_byte			/* UART Receive Complete Interrupt Vector Address */
	reti					/* UART Data Register Empty Interrupt Vector Address */
	reti					/* UART Transmit Complete Interrupt Vector Address */
	reti 					/* Analog Comparator Interrupt Vector Address */
	reti					/* External Interrupt2 Vector Address */
	reti					/* Output Compare0 Interrupt Vector Address */
	reti					/*  EEPROM Interrupt Vector Address */
	reti					/*  SPM complete Interrupt Vector Address */
	reti					/*  SPM complete Interrupt Vector Address */	

reset:

cli

/* ***** set stackpointer */
	ldi	tempL,low(RAMEND)
	ldi tempH,high(RAMEND)
	out	SPL,tempL
	out SPH,tempH

/* ***** WATCHDOG */
	wdr
	ldi tempL, (1<<WDE)|(1<<WDCE)
	out WDTCR, tempL
	ldi tempL, (1<<WDE)|(1<<WDCE)|(1<<WDP2)|(1<<WDP1)
	out WDTCR, tempL
	wdr

/* ***** set Ports */
/*  PortE */
	ldi tempL, 0b00000001
	out DDRE, tempL
	ser	tempL
	out PortE, tempL 					/* LED2 off, BIT9 & OPTION Pullup */

/*  PortA */
	ser tempL
	out DDRA, tempL
	out PortA, tempL 					/* high Outputs */

/*  PortB */
	ldi tempL, 0b00000000
	out	DDRB,  tempL
	ldi tempL, 0b00000011	
	out	PortB, tempL

/*  PortC */
	clr tempL
	out DDRC, tempL
	ser tempL
	out PortC, tempL  					/* Inputs with PullUp for DipSwitch */

/*  PortD */
	ldi tempL, 0b10000100
	out DDRD, tempL
	ldi tempL, 0b01111000
	out PortD, tempL 					/* DMX & Spare , LED1 off */

/* ***** get phase-time for phase zero-crossing control */
		sbis	PinD, USA_MODE
		rjmp	init_phs60

		ldi		tempH,0xD8				//50Hz
		ldi		tempL,0xF2
		rjmp 	init_phs1
  	   init_phs60:
  		ldi		tempH,0xDF				//60Hz
		ldi		tempL,0x75
   	   init_phs1:
		mov		timer_startH,tempH		/* store value */
		mov		timer_startL,tempL

/* ***** initial timer 0 */
		ldi 	tempL,0b00000101		/*  set timer0 to ck/1024 */
		out 	TCCR0,tempL			
				
/* ***** initial timer 1 */
		clr		tempL
		out		TCCR1A, tempL
		ldi 	tempL,0b00000010		/* set timer1 to clk/8 */
		out 	TCCR1B,tempL		 
				
/* ***** initial timer interrupts */
 		ldi 	tempL,0b00000000		/* enable timer0 overflow interrupt */
		sbr		tempL, (1<<TOIE0)	 
		out 	TIMSK,tempL			 
				
/* ***** set interrupt 1 for phase zero-crossing control */
		in 		tempL,MCUCR				/* interrupt by falling edge */ 
		sbr		tempL,(1<<ISC11)		 
		cbr		tempL,(1<<ISC10)		 
		out 	MCUCR,tempL			 

		in 		tempL,GIMSK				/* enable interrupt1 */
		sbr		tempL,(1<<INT1)				 
		out 	GIMSK,tempL 		 
	
		in 		tempL,GIFR				/* initial GIFR */
		sbr		tempL,(1<<INTF0)		/* clear interrupt0 flag */
		sbr		tempL,(1<<INTF1)		/* clear interrupt1 flag */
		out 	GIFR,tempL			 

/* ***** Analog Comparator */
		ldi		tempL, 0b01010010 		/* (bandgap on, ac on, irq on falling edge, irq flag cleared, irg disabled) */
		out 	ACSR,  tempL
		
/* ***** initial var */

		clr 	Flags
		clr 	Flags
		clr 	null

		ldi		tempL, 8
		sts		BlinkPos, tempL
		ldi		tempL, 25
		mov		LEDdelay, tempL

		SWITCHread:
		sbic	EECR, EEWE
		rjmp	SWITCHread
		ldi		tempL, 1
		out		EEARH, null
		out		EEARL, tempL
		sbi		EECR, EERE
		in		SwitchMask, EEDR		/* load switch mask from EE */

		sbic	PinE, OPTION			/* should store new switch pattern? */
		rjmp	initv1
		in		tempH, PinC
		cp		SwitchMask, tempH
		breq	initv_wait
		mov		SwitchMask, tempH

		SWITCHwrite:
		sbic	EECR, EEWE
		rjmp	SWITCHwrite
		out		EEARH, null
		ldi		tempL, 1
		out		EEARL, tempL
		out		EEDR, SwitchMask
		sbi		EECR, EEMWE
		sbi		EECR, EEWE

		initv_wait:
		wdr
		sbis	PinE, OPTION			/* wait till switch cleared */
		rjmp	initv_wait

	   initv1:
	    sts		SwitchCh, SwitchMask
		rcall	init_dmx
		
		cbi     PortD, LED1

/* ***** start working... */

		sei
		wdr								/* enable global interrupt */

forever:

	rjmp	forever	
		
/* ***************************************************************************
 *
 * external interrupt caused by phase-zero-crossing (idle:4.88us, BREAK:6.38us, 
 *
 *************************************************************************** */
zero_crossing:

		in		SREGbuf, SREG			/* save global status */
		push 	tempL
		push	tempH
			
		out 	TCNT1H,timer_startH		/* clear angle-timer */
		out 	TCNT1L,timer_startL		

		sbr 	Flags, (1<<VALID_ZC)	/* message for indicator */

		in		tempL,TIFR				 
		sbr		tempL,(1<<OCF1A)		/* clear compare flag */
		sbr		tempL,(1<<TOV1)			/* clear overflow-flag  */
		out	    TIFR,tempL				

  		in		tempL,TIMSK				
		sbr		tempL,(1<<OCIE1A)		/* enable timer1 compare interrupt */
		sbr		tempL,(1<<TOIE1)		/* enable timer1 overflow interrupt */
		out	    TIMSK,tempL				

		in 		tempL,GIMSK				/* disable ext-interrupt */
		cbr		tempL,(1<<INT1)		
		out 	GIMSK,tempL 			

   zero_common:	
		ser		dimm_count				/* clear counter */

		sbis	PinD, USA_MODE
		rjmp	z_common60
		ldi		ZH,((high(TABLE_A) *2)+0x01)	/* set first compare value */
		rjmp	Z_common1
	   z_common60:
	    ldi		ZH,((high(TABLE_B) *2)+0x01)	/* set first compare value */
 	   Z_common1:
		ldi		ZL,0xfe					
		lpm		tempL, Z+						/* low byte */				
		lpm		tempH, Z						/* high byte */
		add		tempL,timer_startL		/* add start-offset */
		adc		tempH,timer_startH		/* add start-offset */
		out		OCR1AH,tempH			
		out 	OCR1AL,tempL			

		pop		tempH
		pop 	tempL					/* restore global status */
		out 	SREG, SREGbuf
		reti							/* return */	

/* ***************************************************************************
 *
 * T1-overflow interrupt caused by phase-zero-crossing
 *
 *************************************************************************** */
zero_crossing_overflow:	

		in		SREGbuf, SREG			/*  save global status */
		push 	tempL
		push	tempH

		out 	TCNT1H,timer_startH		/* clear angle-timer */
		out 	TCNT1L,timer_startL		

  		in		tempL,TIMSK				 
		sbr		tempL,(1<<OCIE1A)		/* enable timer1 compare interrupt */
		cbr		tempL,(1<<TOIE1)		/* disable timer1 overflow interrupt */
		out		TIMSK,tempL				

		in 		tempL,GIFR				/* clear interrupt0 flag */
		sbr		tempL,(1<<INTF1)		 
		out 	GIFR,tempL				

		rjmp	zero_common

/* ***************************************************************************
 *
 * check next firing angle
 *
 *************************************************************************** */
compare:
		in		SREGbuf, SREG			/*  save global status */
		push 	tempL
		push	tempH

		ldi		tempL,DMX_CHANNELS
		clr		status
		ldi		ZH,high(DMX_FIELD)		/* set data-pointer */	
		ldi		ZL,low(DMX_FIELD)			

  test_stat:	
  		ld		tempH,Z+				/* get data  */
		cp		tempH, dimm_count
		ror		status
		dec		tempL					/* goto next channel */
		breq	finish					 
		rjmp	test_stat

  finish:
  		sbrs	Flags, HOT				/* if too hot -> shut down! */
		rjmp	cf_1
		clr		status 
		com		status
      cf_1:
		out 	PORTA,status
		
  get_value:
		dec		dimm_count
		breq	end_time

		sbis	PinD, USA_MODE
		rjmp	gv_60
		ldi		ZH,(high(TABLE_A) *2)	/* compare value */
		rjmp	gv_1
	   gv_60:
	    ldi		ZH,(high(TABLE_B) *2)	/* compare value 60Hz */
 	   gv_1:
		mov		ZL, dimm_count
		lsl		ZL			 
		adc		ZH,null					  
	
		lpm		tempL, Z+				/* load next timer1-compare-value */				 
		lpm		tempH, Z						 				 

		add		tempL,timer_startL		/* add start-offset */
		adc		tempH,timer_startH		 

		sbiw	tempL,0x03				/* test if next timer1-compare-value  (next angle -3) */
		in		currentL,TCNT1L			/* isn't already gone */
		in		currentH,TCNT1H
		cp		tempL,currentL
		cpc		tempH,currentH
		brge	compare_ok
		rjmp	get_value				/* else get next value */

  compare_ok:
  		adiw	tempL,0x03				/*  (next angle +3)  */
		out 	OCR1AH,tempH			/* set next timer1-compare-value */
		out		OCR1AL,tempL			 
		
		rjmp	exit_compare

  end_time:
  		in		tempL,TIMSK				/* disable timer1 compare interrupt */
		cbr		tempL,(1<<OCIE1A)		 
		out		TIMSK,tempL				 

		ldi		tempL,0xff				/* turn portA off (safe) */
		out		PORTA,tempL				

		in		tempL,TIMSK				/* check for timer-overflow-interrupt */
		sbrc	tempL,TOIE1				/* if timer1 overflow interrupt is enabled */
		rjmp	exit_compare			/*   return */

		in 		tempL,GIFR				/* clear interrupt1 flag */
		sbr		tempL,(1<<INTF1)		
		out 	GIFR,tempL				

		in 		tempL,GIMSK				/* enable external interrupt1 */
		sbr		tempL,(1<<INT1)			
		out 	GIMSK,tempL 			/* wait for next zero-crossing */

	exit_compare:
		pop		tempH
		pop		tempL
		out		SREG, SREGbuf
		reti							



/* ***************************************************************************
 *
 * manipulation of dmx data
 *
 *************************************************************************** */
 clc_dmx:
 		lsr		SwitchMask				/* should this ch be switched? */
		brcs	clc_dmx_finish			/* no */
		cpi		tempH, 127
		brsh	clc_dmx_hi
		clr		tempH					/* ch off */
		rjmp	clc_dmx_finish
	  clc_dmx_hi:
		ser		tempH					/* ch on */
	  clc_dmx_finish:
	    cpi		XL, low(DMX_FIELD +DMX_CHANNELS -1)
		brne	clc_dmx_exit
		lds		SwitchMask, SwitchCh	/* reload switch mask */
	  clc_dmx_exit:
		ret		
			
 			

/* ***************************************************************************
 *
 * LED INDICATOR 
 *
 *************************************************************************** */
LED_indicator:
		wdr								/* reset Watchdog */
		in		SREGbuf, SREG
		push	tempL

		dec	  	LEDdelay				/* clk/(256*1024*2) => 20Hz */			
		brne  	no_ind
		ldi   	tempL, 2
		mov   	LEDdelay, tempL		

working_LED:
		sbrc	Flags, DATA_REFRESHED	/* should flash? */
		rjmp	data_flash	
		sbi		PortE, LED2				/* LED off */	


Error_LED:
		lsr   	blink
		sbrc  	blink, 0				/* wenn 1st bit HI */
		rjmp  	on
		sbi   	PortD, LED1
		rjmp  	ind_tst
	 on:
	 	cbi  	PortD, LED1

     ind_tst:
	    lds		tempL, BlinkPos
		dec	  	tempL					/* ist blink durchrotiert? */
		breq	change_pat
		sts		BlinkPos, tempL
		rjmp	no_ind
	 		 	
/* wenn durchrotiert (blink = 0) */
	 change_pat:
	    ldi		tempL, 8
		sts		BlinkPos, tempL	
		clr		tempL		
		sbrs 	Flags, VALID_DMX
		ldi	 	tempL, 0b00001010
		sbrs 	Flags, SIGNAL_COMING
		ldi	 	tempL, 0b00000010
		sbrs 	Flags, VALID_ZC
		ldi  	tempL, 0b10101010

/* *** Temperature Monitoring */
	  	sbic	ACSR, ACO
		rjmp	too_hot
		cbr		Flags, (1<<HOT)			/* temp is OK */
		rjmp	tm1
	too_hot:							/* temp is too high */
		ser		tempL
		sbr		Flags, (1<<HOT)
		
   tm1: mov  	blink, tempL

		cbr		Flags, (1<<VALID_DMX)|(1<<VALID_ZC)|(1<<SIGNAL_COMING)
	no_ind:
		pop		tempL
		out		SREG, SREGbuf
		reti

    data_flash:
		cbr		Flags, (1<<DATA_REFRESHED)
	    sbis 	PortE,LED2				/* blinken green */
		rjmp 	off
		cbi		PortE,LED2
		rjmp 	Error_LED
		off:
		sbi 	PortE,LED2
		rjmp 	Error_LED



.include "lib_dmx_in.asm"

nix: rjmp nix
```



papirrin dijo:


> y otra cosa que se me olvidaba, si vas a dejar el transformador de 12v, es conveniente que las resistencias no sean de 10K sino de 1k, puesto que las de 10K estan calculadas para 110V, y como mencione yo puse un tranformador porque no tengo las resistencias de 1W. en el esquema de locodelafonola se ve que para 220V se necesitan resistencias de 27K a 1W si se toma directamente de la red electrica.


Bueno ., en realidad fijate ., el detalle del diodo a la inversa (1n4007) ya con eso no nesesita puente rectificador​ con respecto a las ressistencias de 27k x 1W ., yo le coloque de mas wataje ., porque calentaban mucho ahora tiene de 5W (no consegui de 2W)​ En cuanto al TIC 2XXX ., lo remplaze por el Q4010 TL o Q4020TL (de 10A o 20A .,respectivamente y  son aislados)​


----------



## papirrin (Sep 8, 2015)

> pero lo que no entiendo es porque necesitas cambiar el "gatillado"., del ciclo negativo ., (perdona mi ignoracia )


Una imagen dice mas que mil palabras:


Con puente rectificador en cada semiciclo genera un pulso en el cruce.

Sin puente rectificador, en el semiciclo positivo hay un flanco positivo y en el negativo hay un flanco negativo, por lo que se tiene que detectar si es flanco de subida o de bajada para saber ambos cruces por cero.

Me estoy refiriendo a que se tiene que cambiar el falling edge o el rising edge del pin de interrupción externa, o por lo menos así es en PIC, en Atmega no sé si funcione igual pero supongo que si por lo que vi en tu código.
Espero haberme explicado.


----------



## locodelafonola (Sep 8, 2015)

Bueno. 





papirrin dijo:


> Una imagen dice mas que mil palabras:
> Ver el archivo adjunto 134369
> 
> Con puente rectificador en cada semiciclo genera un pulso en el cruce.
> ...


Bien eso si lo entiendo. Ahora, ¿para qué necesitas diferenciar los semi ciclos?​ Porque según tengo entendido, al cruzar por cero, es el estado ideal de conmutación (encendido y apagado de la lámpara) y de este modo se evita que se queme.
​ O sea, el PWM de continua que acciona el  diac que a su vez acciona el triac.​ Si no aprendí mal (digo, porque uno solo a veces lo interpreta erróneamente)
Trabaja unicamente cuando es detectado el cruce y en los flanco de subida o de bajada no trabaja.​ Claro que la señal de esa manera tiene mayor amplitud, y no te olvides que lo que es usado es el "PICO", y no la subida ni bajada de esa detección.

Me pasó que tuve que reformar el circuito de la bomba (maquina de humo) porque la bomba funciona con 12 VCC y yo dimerizaba el trafo que la alimenta.​ Pero al hacer eso, me quedaba sin alimentación estable en los otros circuito.​ Entonces, cambie el circuito del diac y tic por un opto-trancistor y un IRFZ​ Pero ahora dimerizo la bomba con cruce por cero.
El beneficio es, que a pesar de eso el trafo no calienta tanto al aumentar el consumo (bomba)​ También fijate el detalle de la última librería que subí,  trabaja con una tabla y están definidos los dos tipos, 50Hz y 60Hz.​


----------



## papirrin (Sep 8, 2015)

Bueno, cada aplicación es diferente y no quiere decir que no funcione el circuito que pones.
Para mi la diferencia es que no consumes más tiempo del necesario en el microcontrolador, que tampoco es una cantidad  barbara, si acaso unas 10 instrucciones  a lo mucho.
Pero insisto, a mi me gusta más con puente, aunque en términos generales sea casi lo mismo.



> ¿¿¿¿ paraque nesesitas diferenciar los semi ciclos????


Se necesita diferenciar para que se dispare el triac en cada semiciclo.
Si sólo disparas en un semiciclo es como si estuvieras rectificando a media onda, o sea, la mitad de la potencia o cómo le quieras decir.


----------



## miglo (Sep 8, 2015)

Termino de llegar del trabajo y veo que el tema va muy bien, yo opino como papirrin me gusta mas lo del puente, y como bien dice "vale mas una imagen que mil palabras".

Papirrin voy a usar el transformador para obtener los 12voltios, seguire tu consejo, una vez lo tenga bien definido seguramente lo haga directamente desde los 230Ac con las resistencias de mayor valor, asi me resultara mas facil para meterlo dentro de las cajas de la corriente electrica.

Locodelafonola agradecido por tu ayuda aunque como en este caso no la entienda, lo de ASM ya me lo dijo en su momento D@rkbytes pero de momento me voy defendiendo mejor con C aunque voy leyendo tambien ASM, lo que no quiero es liarme con los 2, prefiero intentar aprender mejor C y luego ASM.


----------



## locodelafonola (Sep 8, 2015)

Hola. Pon el osiloscopio a la salida de los dos circuitos, así ves

Yo tengo entendido que el puente se usa para aplicaciones sin micro, porque como vos decís, nesesitas el semiciclo negativo.​ Ahora si te fijas, lo que postee  no tiene sentido, puesto que el micro te detecta estado alto no estado bajo (al menos en el programa no hay diferencia a eso)
​ Ahí está el detalle, por eso lo de la tabla de lectura de 50 y 60 Hz.​ Y perdona que no se explicarme bien, no soy técnico sólo mal aprendido jajajajajajajajajajajaja.​


miglo dijo:


> Termino de llegar del trabajo y veo que el tema va muy bien, yo opino como papirrin me gusta mas lo del puente, y como bien dice "vale mas una imagen que mil palabras".
> 
> Papirrin voy a usar el transformador para obtener los 12voltios, seguiré tu consejo, una vez lo tenga bien definido seguramente lo haga directamente desde los 230Ac con las resistencias de mayor valor, así me resultara mas fácil para meterlo dentro de las cajas de la corriente eléctrica.
> 
> Locodelafonola agradecido por tu ayuda aunque como en este caso no la entienda, lo de ASM ya me lo dijo en su momento D@rkbytes pero de momento me voy defendiendo mejor con C aunque voy leyendo tambien ASM, lo que no quiero es liarme con los 2, prefiero intentar aprender mejor C y luego ASM.


Bueno, yo aprendí más o menos, pero es muy cierto lo que dice el maestro papirrin, hay que saber ASM.​ Aunque con atmega se usa un solo compilador para los dos lenguajes, y en C se pueden usar sentencias de ASM.​ Es medio "loco" lo que digo pero es cierto, en ASM "no doy pie con bola"
No lo entiendo, por eso uso C.​


----------



## papirrin (Sep 8, 2015)

> Yo temgo entendido que el puente se usa para aplicaciones sin micro ., porque como vos desis ., nesesitas el semiciclo negativo


Ambos circuitos lo he probado con micro y ambos funcionan.
La diferencia, reitero, es que la programación es diferente.

Ahora ya tengo desarmado el circuito porque estoy intentando una comunicación UART entre varios PIC, que por cierto me estaba sacando canas verdes, pero puedo poner la simulación de proteus de ambos métodos.
De hecho, el código que puse en el mensaje 22, lo hice para usarlo con el esquema que pusiste.

{Offtopic_On}
Por cierto y cosa aparte, si no fuera por los errores garrafales que tiene el proteus en algunas cosas, sería imposible para mi aprenderme casi de memoria los registro y los procedimientos de configuración de los pics.
Para lo que estoy haciendo del UART el proteus no lo hace como en la realidad y ya llevaba casi 6 horas intentándolo en simulación.
Lo armé en la realidad y si funciona como debe ser y en no más de 20 minutos. 
{offtopic_Off}


----------



## locodelafonola (Sep 8, 2015)

Gracias.
La verdad, que aparte de la explicación y aplicación, me gusta como  te tomas el tiempo para explicar el funcionamiento  de las cosas.
​ En cuanto a lo otro, yo también lo uso. En mi caso es la USART.​ Al principio me mareo un poco, pero una vez que entendí cómo funciona, ya no tuve más problemas graves.​


----------



## miglo (Sep 9, 2015)

Buenas Papirrin te comento, termino de montar todo otra vez y tienes mas razon que un santo, en proteus cuando no se me atasca el programa va lento de narices, y mas aun para los que estamos haciendos nuestros pinitos, aunque como bien dices para ver como funcionan todos los componentes ayuda y de que manera.

Pues bien como te dicho lo he montado, perooooooo, con una bombilla de casquillo E27, como no encontraba de las clasicas por que por aqui se estan dejando de fabricar por no decirte que creo que ya no se fabrican, pero si he conseguido una que dentro lleva el sistema alogeno que para el caso sirve, dspues de conectarlo todo cambiar el refrigerador del triac, por que tenia uno enorme, para pruebas, esto gracias a un colega que es tecnico en televison y me pasa casi de todo lo que necesito por la cara, que no es poco, tambien hay que decir que cuando necesita que le heche un cable le ayudo en la reparacion y luego con unas cervezas todo resuelto, pues eso que con esta bombilla va de perlas el programa, lo que biene a decirme que seguramente las bombillas leds al llevar dentro su circuiteria con mas o menos componentes no reacciona igual, de hay el comentario que te hice sobre si podria ser la bombilla.

Por otro lado, aunque me digiste lo de las resistencias de 10k por 1k, al no llevar las gafas y no medir su valor puse las de 10k y funciona perfecto todo, me dado cuenta al cambiar los diodos por puentes reptificadores, cosas que pasan jejeje. 

Locodelafonola ya lo miro con el osciloscopio pero como solo tengo una sonda pues no puedo disfrutar de ver las 2 señales, ya estoy mirando para comprarme la segunda sonda y asi poder ver las señales, todo esto me pasa por despistado, pierdo la cosas que da gusto.

Una pregunta Papirrin ya que no le veo explicacion, estoy haciendo pruebas y todo va bien menos cuando bajo a 100 la luz, si luego le doy a subir no se enciende ni aunque llegue a 240.

He reprogramado para que empieze en 100 y no va pero si lo pongo en 240 como pusiste tu entonces si, luego lo he modificado para que no baje de 103 y va perfecto, pero claro una bombilla en una habitacion esta apagada y cuando pulsamos se enciende, de esta manera esta encendida y hay que apagarla, es al reves, esta claro que son pruebas pero me gustaria saber el por que cuando llego a 100 ya no se enciende o por que si empiezo desde 100 tampoco se enciende. No he probado empezar desde 103.

Termino de probar desde 103 y va perfecto, pero si lo bajo ya no.


----------



## papirrin (Sep 9, 2015)

> Por otro lado, aunque me digiste lo de las resistencias de 10k por 1k, al no llevar las gafas y no medir su valor puse las de 10k y funciona perfecto todo, me dado cuenta al cambiar los diodos por puentes reptificadores, cosas que pasan jejeje.


si puede funcionar, de echo yo tambien lo tengo con 10K y transformador, pero como esta pasando muy poca corriente en el diodo LED del opto puede que si habiese un bajon de luz por algo, ya no sature el fototransistor del optoy se apague el foco o sea erratico. bueno eso tambien es cuestion de gustos en diseño, lo normal para 12V seria algo aproximado a 1K.



> Una pregunta Papirrin ya que no le veo explicacion, estoy haciendo pruebas y todo va bien menos cuando bajo a 100 la luz, si luego le doy a subir no se enciende ni aunque llegue a 240.
> 
> He reprogramado para que empieze en 100 y no va pero si lo pongo en 240 como pusiste tu entonces si, luego lo he modificado para que no baje de 103 y va perfecto, pero claro una bombilla en una habitacion esta apagada y cuando pulsamos se enciende, de esta manera esta encendida y hay que apagarla, es al reves, esta claro que son pruebas pero me gustaria saber el por que cuando llego a 100 ya no se enciende o por que si empiezo desde 100 tampoco se enciende. No he probado empezar desde 103.
> 
> Termino de probar desde 103 y va perfecto, pero si lo bajo ya no.



Cuando preguntes algo que estes modificando o programando en el codigo, ponlo aqui, si no no tengo idea de lo que hablas.

mira los limites se ponen mas o menos asi.


```
#include <16F877A.h>

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES XT                       //Crystal osc <= 4mhz
#FUSES PUT                     //Power Up Timer
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD                    //No EE protection
#FUSES NOWRT                    //Program memory not write protected

#use delay(clock=4000000)

#define TRIAC  PIN_B3
#define F_MAX  PIN_B1
#define F_MED  PIN_B2

int VTO=240;


#int_RTCC
void RTCC_isr() 
{

 output_high(TRIAC);
 delay_us(10);
 output_low(TRIAC);
 disable_interrupts(INT_RTCC);
}

#int_EXT
void EXT_isr() 
{
 set_timer0(VTO);
 enable_interrupts(INT_RTCC);
}



void main()
{
   
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);
   setup_psp(PSP_DISABLED);
   setup_spi(FALSE);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_64);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
   enable_interrupts(INT_RTCC);
   enable_interrupts(INT_EXT);
   enable_interrupts(GLOBAL);
   set_tris_B(0b111);
   
   while(true)
   {
    if (input(F_MAX))
          { 
      if(vto<=240) vto++;   
        delay_ms(10); // antirrebote si puedes usar otro metodo que no use delay mejor.
          }
          
    
    if (input(F_MED))
          {
          if(vto>=100) vto--;
           delay_ms(10); // antirrebote si puedes usar otro metodo que no use delay mejor.
          }   
   };

}
```

y toma en cuenta que con ese tipo de proyectos en donde se utilizan tiempos, vas contra reloj, cada instruccion que le aumentes o proceso o delay, tiene que ser perfectamente estudiado para que no afecte a las interrupciones. cada instruccion que pongas es tiempo.

por ejemplo si pones un LCD que quien sabe como este echa la libreria, puede ser que al estar ejecutando la rutina del LCD haga que el foco haga destellos erraticos. pero no es que este mal... es que el microcontrolador no tiene tiempo de hacer todo.

por eso a los microcontroladores los  hacen de varias velocidades y de echo es por eso que estoy intentando hacer una comunicacion serial (UART) entre varios micros, para dejar como esclavo al micro que va a controlar el dimer y un servo, y el maestro va a controlar un LCD y otras funciones.

con respecto a las lamparas LED, no tengo idea de como esten echas, lo que si se es que no todos los focos se pueden dimmerizar como por ejemplo los ahorradores (por su circuiteria) o bueno si hay una forma de dimerizarlos pero no recuerdo como y este no es el metodo XD


----------



## papirrin (Sep 9, 2015)

esta es la simulacion de ambos circuitos con el mismo codigo que *no* detecta el flanco de subida y bajada y si deberia funcionar asi en la realidad mas o menos.



el primer oscilograma (el de arriba) corresponde al del puente rectificador, y el segundo (el de abajo) corresponde al del diodo.

la linea amarilla, corresponde a la oscilacion de la corriente alterna, la linea azul es la deteccion del cruce por cero, la linea rosa es el gatilleo, y la linea verde es el TRIAC.

como se puede observar en el del puente rectificador el triac se dispara en ambos semiciclos, y el del diodo, solo gatillea en el semiciclo negativo.

es por eso que en el del diodo se tiene que cambiar el flanco de la interrupcion externa en el microcontrolador para que gatille en ambos semiciclos, tambien puede ser que en el Atmega se pueda configurar que se desborde la interrupcion en el cambio de estado y podria funcionar, pero no se, nunca he utilizado esos microcontroladores.

de una vez pongo el codigo en Picbasic pro para quien le sirva, y es para usarse con el diagrama del puente rectificador.


```
Define Osc 4


OPTION_REG = %11000101 
INTCON     = %11010000 
CMCON      = %111
TRISD      = %00000000
TRISB      = %000111


VT0     Var byte

ON INTERRUPT GOTO int

PORTB.3=0

VT0=200
main:
 if PORTB.1=1 then
  if VT0<249 then VT0=VT0+1
  while PORTB.1
  wend
 endif
 if PORTB.2=1 then 
  if VT0>134 then VT0=VT0-1
  while PORTB.2
  wend
 endif 
Goto main

DISABLE 
Int:
 if INTCON.2=1 then
  INTCON.2=0
  PORTB.3=1
  pauseus 1
  PORTB.3=0
  INTCON.5=0
 endif 
 if INTCON.1 then
  INTCON.1=0
  TMR0=VT0
  INTCON.5=1
 endif
RESUME
ENABLE
```


----------



## miglo (Sep 9, 2015)

Yo siempre habia hecho los limtes diferentes, me gusta como lo pones tu.


----------



## locodelafonola (Sep 9, 2015)

Hola 





papirrin dijo:


> esta es la simulacion de ambos circuitos con el mismo codigo que *no* detecta el flanco de subida y bajada y si deberia funcionar asi en la realidad mas o menos.
> 
> Ver el archivo adjunto 134414
> 
> ...


 Bueno gracias a vos ., ahora veo la diferencia (yo no tengo ociloscopio ) solo el de PC​ Lo que quiero explicar es como se usan los dos codigos que subi​ El primero ., se usa en la maquina de humo ( no es comercial ., la fabrique yo )., donde maneja 4 recistencia de plancha (serie-paralelo)., y la bomba de liquido (la que use originalmente era de 220v) la actual es de 12v​ La verdad ., que lo que hace con el calefactor.,  es una especie de "pirometro"​ Los pirometros .,  trabajan por aproximacion de temperatura programada​ Bueno el mio trabaja mas o menos asi ., con la diferencia que aparte de conectar y desconectar​ Tiene PWM (dimer)., que una vez llegada la temperatura no lo desconecta ., sino que la alimentacion es pequeña y costante​ Y porque digo esto., bueno en este caso no estan importante controlar el angulo de la face​ En el segundo ejemplo que subi ., alli si se controla eso  No es importante la detecion de cruze por cero ., porque lo que en realidad se aplica a la salida ., es una tabla de ondulacion  del PWM (50 o 60 HZ)​ Tal vez la solucion sea aplicarla ., pero alli ya no te podria dar idea ., de ASM no tengo practica​


----------



## papirrin (Sep 9, 2015)

No entendi mucho eso del pirometro,  segun yo un pirometro solo mide altas temperaturas, pero creo que se por donde va, y lo mismo o muy parecido quiero hacer yo, a diferencia de que en lugar de programarlo en una tabla, voy ha controlar la temperatura con integrales y derivadas (PID), algo asi como se controlan los servomotores, es decir, que empiezan en lo maximo y cuando se va acercando, en este caso a la temperatura, va disminuyendo la tension (por dimmer) y por ende va calentando menos, al enfriarse empieza a subir la tension para aumentar la temperatura poco a poco y asi sucesivamente, y en teoria debe mantener una temperatura estable.

bueno esa es la idea a ver si sale.... XD


----------



## locodelafonola (Sep 9, 2015)

hola 





papirrin dijo:


> No entendi mucho eso del pirometro,  segun yo un pirometro solo mide altas temperaturas, pero creo que se por donde va, y lo mismo o muy parecido quiero hacer yo, a diferencia de que en lugar de programarlo en una tabla, voy ha controlar la temperatura con integrales y derivadas (PID), algo asi como se controlan los servomotores, es decir, que empiezan en lo maximo y cuando se va acercando, en este caso a la temperatura, va disminuyendo la tension (por dimmer) y por ende va calentando menos, al enfriarse empieza a subir la tension para aumentar la temperatura poco a poco y asi sucesivamente, y en teoria debe mantener una temperatura estable.
> 
> bueno esa es la idea a ver si sale.... XD


 Bueno, algo así es lo que está en el primer ejemplo que puse, pero no usa tabla.​ Un pirómetro industrial, es ésto.​




Y sip. Maneja altas temperaturas (dependiendo del elemento sensor o termocupla)​ En mi caso, de190° a 250°, pero podría ser más.​ A eso me refería cuando te dije la diferencia de una compilación y otra, por más que una sea ASM y otra C.​ También entiendo lo que querés hacer, y es usar PID (un lazo cerrado) y con los servos generar el movimiento para regular la temperatura. (¿Serán llaves de paso?)
​ El primer ejemplo, el set de la temperatura se leen llaves mini-dips pero bien se podría adicionar las tablas del segundo ejemplo.
​ La parte de electrónica de entrada y salida  del primer y segundo ejemplo, son las mismas. (Es el mismo autor de las dos)​ Ojalá pudiera ayudarte más. Ahora, si necesitas que te explique algo más del código,  avisa, conozco de memoria sus partes y como funciona cada una de ellas.​ Tal vez de esa manera puedas aplicarlo a los PIC.
​


----------



## papirrin (Sep 10, 2015)

> Un pirometro industrial es esto


Ah! Ok. Supongo que en esos se puede programar una temperatura y activa un relé o algo así, no? La verdad no los conocía.



> generar el movimiento para regular la temperatura (¿¿¿ seran llaves de paso ??? )


No. El servo es para otra cosa.
Estoy automatizando la selladora de bolsas y en el transcurso estoy aprendiendo otras técnicas, como el UART con direccionamiento por Hardware y control de un servo con retroalimentación.

Bueno, o sea, ésto:







> Hojala pudiera ayudarte mas., ahora si nesesitas que te explique algo mas del codigo ., avisa ., los conozco de memora su partes ., y como funciona cada una de ellas
> Tal vez de esa manera ., puedas aplicarlo a los PIC


Primero voy a intentar lo del PID, si de plano no me funciona o no puedo, entonces si acepto tu ofrecimiento de ayuda.
Y en ASM me defiendo, no soy un experto pero si he hecho un par de proyectos, aunque casi siempre termino por hacerlos o en Basic o C.

Gracias.


----------



## locodelafonola (Sep 10, 2015)

Hola





papirrin dijo:


> aaah Ok, supongo que en esos se puede programar una temperatura y activa un rele o algo asi no? la verdad no los conocia.
> 
> 
> no el servo es para otra cosa, estoy automatizando la selladora de bolsas XD, y en el transcurso estoy aprendiendo otras tecnicas, como el UART Direccionado por Hardware, control de un servo con retroalimentacion... bueno o sea esto:
> ...


Bueno, ese proyecto está buenísimo. Ya entiendo que querés hacer.​ Querés automatizar la selladora y está genial la idea.​ Si precisas algo, pedilo nomás, no hay problema.​


----------



## miglo (Sep 10, 2015)

Papirrin te quiero preguntar lo siguiente, en teoria al usar triac se deve poner una red snuber acorde para proteger, segun tengo entendido al triac. Para una bombilla, en este caso la que uso de pruebas que es de 40W al ser resistiva se debe poner o no es necesaria y si es necesaria como se calcula el condensador y la resistencia?.

Te comento esto por que he leido varios temas y al final no lo tengo del todo claro y segun lo que leido he puesto una red snuber como prueba y cuando se ilumina vastante empieza a sonar como cuando entra en resonancia y si lo quito va perfecto.

Por cierto muy bueno lo de plastificar o sellar, pero eso de usar 2 pic o mas para mi es mucho, todabia me falta mucho.


----------



## papirrin (Sep 10, 2015)

> si es necesaria como se calcula el condensador y la resistencia?.



si se como se calcula el condensador y la resistencia pero no me acuerdo en este momento, y ademas de que no se necesita la snubber para cargas resistivas, solo para cargas inductivas como motores, relays y etc.



> Por cierto muy bueno lo de plastificar o sellar, pero eso de usar 2 pic o mas para mi es mucho, todabia me falta mucho.



pues depende el proyecto, en mi caso como va estar haciendo calculos medio complejos, un solo pic queda corto en tiempos, se puede pero no me agrada hacerlo.


----------



## miglo (Sep 10, 2015)

papirrin dijo:


> si se como se calcula el condensador y la resistencia pero no me acuerdo en este momento, y ademas de que no se necesita la snubber para cargas resistivas, solo para cargas inductivas como motores y etc.



Ajam, entonces no pondre red snubber, nada mas tenga terminado subire un video de como me queda el tema. Esto es otro tema aprender a subir video a youtube, jejeje.


----------



## papirrin (Sep 10, 2015)

Parece que va bien eso del control de temperatura XD....


----------



## miglo (Sep 11, 2015)

Esta muy majo, va bien, el sistema de las neveras es similar aunque con margenes de temperatura mayor, la que tengo yo es de +-5º el margen y la controlo con un DS18B20. 

Papirrin el codigo en que lenguaje lo tienes hecho?.

Te comento que tambien le añadido un bucle for para que suba y baje la luminosidad al que estoy probando y va perfecto, me a tocado hacer unos pequeños ajustes pero bien.


----------



## papirrin (Sep 11, 2015)

> el sistema de las neveras es similar aunque con margenes de temperatura mayor, la que tengo yo es de +-5º el margen y la controlo con un DS18B20.


Bueno, segun yo y en teoria, en la plancha de mi selladora que es de aluminio, la incandecendia de la resistencia debe ser mas estable, en el foco como enfria o calienta muy rapido parece que estuviera haciendo malabarismos para mantenerlo en una misma temperatura, en algo que sostenga la temperatura debera ser menos rapido... supongo, y pienso que en las neveras deberia ser difernete... mas bien con una histeresis porque el motor del compresor no se puede dimerizar.

voy a ver como funciona ese integrado por curiosidad.



> Papirrin el codigo en que lenguaje lo tienes hecho?.



todo el proyecto lo estoy haciendo en el poderoso y menospreciado BASIC XD.


> Te comento que tambien le añadido un bucle for para que suba y baje la luminosidad al que estoy probando y va perfecto, me a tocado hacer unos pequeños ajustes pero bien.


----------

