variador de vrms_pic16f877a
DESCRIPTION
Aplicacion para implementar un dimmer para un foco de 220 WatsTRANSCRIPT
CURSO DE PROGRAMACION DE PIC EN LENGUAJE C
TAREA N° 3 VARIADOR DE VRMS
Objetivo. Controlar el valor eficaz de una onda sinusoidal que alimenta a una carga de potencia median-
te le microcontrolador PIC 16F877A.
El control del valor RMS se realiza mediante la variación
del ángulo α y esta variación será controlado por un mi-
crocontrolador. Se requiere de un circuito de acondicio-
namiento para obtener una referencia de medición de α.Esto se obtiene de un circuito de acondicionamiento, en
particular de un detector de cruce por cero que ira como
entrada al microcontrolador. Con esto se obtiene las refe-
rencias de donde medir α y la sincronización correspon-
diente.
Para no estar pendiente de la actividad de la señal de los cruces por cero, se tomara un pin de entrada
con interrupción, el PIN RB0. Se le debe configurar para un tipo de flanco, subida o bajada. Pero, de
acuerdo a la señal de salida del circuito de acondicionamiento, los flancos del cruce por ceo es alternante,
por lo que se deberá de configurar para que el flanco sea alternante, cambiando cada vez que se ha de-
tectado uno de los tipos (“toggle”, basculante). Usar un pin del PUERTO C (por ejemplo RC7) como sali-
da. Nota: Si se usa MOC con cruce por cero se tienen flancos de una sola dirección.
Un circuito sugerido para el acondicionamiento de señales seria el mostrado.
La duración de los pulsos para encender SCR, para efectos prácticos de frecuencia de 60 Hz, deberán
estar entre 0.5 ms y 1 ms. Para el trabajo se considerara la duración de 1 ms.
Toda vez que aun no se ha tratado la conversión ADC para un control continuo del ángulo α, se conside-
rar un control discreto. Se considerara 4 valores, por lo que se requiere de dos bits para su elección.
Así, se tendrá la Tabla 1 de casos de control de α.
Para el circuito de salida se sugiere el circuito mos-
trado, con el MOC 3041.
Zero
Crossing
1
2
6
4
U1
MOC3031M
R2
10k
Tabla 1
A1 A0 α Efecto final sobre la carga
0 0 0° Foco apagado (sin disparo)
0 1 135° Luz débil
1 0 90° Luz a mitad de la máxima
1 1 45° Luz con la máxima intensidad
Finalmente, para esta fase inicial, se debe de tener las señales a la entrada y salida del microcontrolador.
Un cálculo para los tiempos indicados y para cada elección de A0 y A1 se muestran en la Tabla 2, para
T=1/60 HZ= 16.67 ms
Diagramas de flujo
TABLA 2 TIEMPOS (ms)
A1 A0 α Efecto final sobre la carga �� �� ��
0 0 0° Foco apagado (sin disparo) 0 2 16.67
0 1 135° Luz débil 6.24 2 8.43
1 0 90° Luz a mitad de la máxima 4.16 2 10.51
1 1 45° Luz con la máxima intensidad 2.08 2 12.59
*********************************************
* Programa VRM1 para el PIC 16F877A
*********************************************
// Programa para detector las interrupciones externa y del Timer0, pudiéndose extendiéndose a mas
// interrupciones. El programa principal no realiza actividad alguna, salvo la de prender un led como
// indicativo que el programa esta en ejecución y detectar una anomalía en su funcionamiento.
#include <htc.h> #define _XTAL_FREQ 10000000
void MCU_init(void); // Declaracion de la funcion de inicializacion
void main(void){ MCU_init(); for(;;) { RC7=~RC7; __delay_ms(50); } } // Rutinas separadas del programa principal y dependientes de las interrupciones
void MCU_init(){ //Configura PUERTOS
PORTC=0x00; TRISC=0xFF; TRISB=0xFF;
//Configuración del Timer0 en OPTION_REG, registro de 8 bits
OPTION_REG=0b11000111;
TMR0=158;
//Activar Interrupciones GIE=1; // Activación global de las interrupciones INTE=1; // Para activar la interrupción externa de RB0 T0IE=1; // Para activar la interrupción por desborde de conteo del Timer 0
}
// Esta parte es independiente del programa principal, se divide en secciones que preguntan
// para determinar el origen de la interrupción. Se pregunta la negación para que continúe
// la interrogación. En caso de una respuesta negativa (¿no se activado?) se realiza la
// acción correspondiente a la interrupción
static void interrupt isr(void)//se usa un nombre usual, pero puede ser cualquier nombre para punte-
ros
Cabeceras que indican los archivos necesarios para el pro-
grama y definición de frecuencia del cristal. Ya no es necesa-
rio _CONFIG(FOSC_HS & WDTE_OFF & LVP_OFF)
Programa principal con solo la actividad de un led para
que sirva como señal de correcto funcionamiento o
anomalía en la ejecución del programa.
No hay otra actividad. Las actividades están en otra
sección de programas para las interrupciones.
Debido al latch de los puertos, se inicializa el PORTC, para fijarlo al
valor de cero, antes de establecer que el PORTC es de salida (reco-
mendable). Para salida no es necesario colocarlo a cero, ya que su
valor depende de la entrada física del PIC.
B7: pull-up de PORTB, B6: Flanco de control de la activación
externa, para RBO, B5: Reloj interno/externo, B4: tipo de flan-
co para la activación externa del Timer0 (RA4/T0CK1), B3:
Asignación del pre-escalador a Timer0/Osc interno, B2-B0:
valor de pre-escalamiento.
Valor de configuración de cuentas del TMR0 para establecer una
temporización, o ciclo de instrucción, cada 10 ms, para una fre-
cuencia del oscilador del cristal de f=10 MHz.
{ // Cada sección de if es para un tipo de interrupción
if(INTF==1){ // Esta es para la interrupción externa por RB0. __delay_ms(4);
RC0=1; __delay_ms(1); RC0=0;
INTF=0; // Después de salir de la rutina de interrupción, desactivarlo para
// una próxima activación, caso contrario, regresara nuevamente. }
if(T0IF==1){ // Esta es para la interrupción externa del Timer0 por desborde
TMR0=158; // de 158 255 (por el primer y sucesivos 10 ms) y vuelve a
// cero. Se debe de carga de nuevo con su valor establecido
// para 10 ms
RC6=~RC6; // Se alterna la señal cada 10 ms, salida por el pin RC7.
T0IF=0; // Después de salir de la rutina de interrupción, desactivarlo
}
// Se puede agregar otros if para otras interrupciones. }
Circuitos de cruce por cero El LED del opto recibe pulsos de CC.
EJEMPLO: Detector de paso por cero Como su propio nombre indica su
objetivo es detectar cuando el
circuito pasa por cero.
Viendo en el catálogo: Esta gráfica
solo se cumple en el caso de que
se esté en activa.
Ahora tenemos que saber donde
nos encontramos.
Hipótesis: Saturación.
Como vemos trabaja en Saturación (los Optoacopladores siempre trabajan
en Saturación, al diseñarlos hay que tener en cuenta esto).
En el pico de la onda de entrada Vsal = 0 V. Se le dan distintos valores hasta que se salga de saturación, que ocurrirá en
un punto cerca de 0 V. Después pasará a saturación y ya no emitirá luz.
En cada paso por cero hay un pico en el que pasa de saturación a corte y luego a saturación seguido. Con esto se de-
tecta el paso por cero. Además de aislar el circuito de la red.
Resumiendo: Este circuito es un detector de paso por cero y además está aislado de la red.
Aplicación: En osciloscopios, ya que en estos hay que saber cuando se pasa por cero
.
****************************************************************************** SIMULACIÓN DE LA LÓGICA DEL PROGRAMA PARA GENERAR PULSOS DE DISPARO PARA ACTIVAR EL TIRISTOR DE SALIDA.
****************************************************************************** Se muestra en la Figura 1, los elementos del circuito de simulación:
PIC16f877A
VSM Signal generator
Osciloscopio
Figura 1 Circuito de simulación
En el generador de señales simularemos la señal que generaría un circuito de cruce por cero, es decir,
una señal rectangular de 60 Hz, ciclo de trabajo del 50% y amplitud 5 voltios, para efectos de generar
como referencia los cruces por cero.
En RC7 (Canal D, de color verde) se tiene un oscilador, del programa principal, de anchos de pulso de
70 ms (no los programados de 50 ms), cuyo parpadeo nos indicara el funcionamiento del bucle principal.
En RC6 tenemos otro oscilador de ancho de pulso 11.5 ms, debido al Timer0, que en cada desbordamien-
to de su cuenta (programado para 10 ms), debería generar un ancho de pulso de 10 ms. En la figura 2 se
muestran las 4 señales (1 de salida y 3 entradas), estando con mas detalle del valor de sus periodos en
los canales D (RC6) y C (RC7).
Figura 2 Medición de los periodos de los dos osciladores en RC6 y RC7.
Anulamos los canales C y D para observar solo los canales A y B que muestran las señales de salida
del PIC (RC0), para el disparo del tiristor y la señal de entrada al PIC (RB0), que simula la señal genera-
da por un circuito de cruce por cero. Ver figura 3.
Se observa la señal de color azul con, una frecuencia de 60 Hz (T=18.67 ms) y ciclo de trabajo del
50%. En los flancos de subida se encuentran los cruces por cero (y no en los de subida y bajada) debido
a que la interrupción en RB0 se detecta solo en uno de los flancos. También se observa que se ha gene-
rado el pulso de disparo correspondiente a la salida del PIC en el pin RC0, con el ancho de pulso de 1 ms
y retardado cada 4 ms del cruce por cero (flanco de subida de la señal de color azul)
Figura 3 Señales de entrada RB0 (señal color azul, canal B)
y salida RC0 del PIC (señal de color amarillo, canal A).
Se ha verificado el resultado esperado de la lógica de generación de la señal de disparo debido a la
activación del flanco de subida de la señal de cruce por cero. Pero el algoritmo solo contempla un ángulo
de disparo de α=45° que corresponde a un retardo de�� ≅ 2��(ver Tabla 2).
Así, se requiere modificar la rutina de interrupción externo por RB0, para que tome en cuenta las 4 op-
ciones del ángulo de disparo y su correspondiente retardo para el pulso de disparo. Usaremos 2 bits
(22=4), y por exigencia de la tarea, debemos de usar las líneas RA0 y RA1 del PORTA del PIC 16F877A
como líneas de entrada para elegir un ángulo de disparo (ninguna, 45°, 90° y 135°).
Pero, como las líneas del PORTA también se pueden usar como entradas/salidas analógicas; debemos de
agregar en la rutina de inicialización, que las líneas del PORTA serán líneas digitales.
Se muestra el código del programa aumentado, con las modificaciones indicadas anteriormente.
*********************************************
* Programa VRM2 para el PIC 16F877A
********************************************* #include <htc.h> #define _XTAL_FREQ 10000000 // __CONFIG(FOSC_HS & WDTE_OFF & LVP_OFF)// !!!Cabecera para la grabación¡¡¡¡
void MCU_init(void); void main(void){
MCU_init(); for(;;) { RC7=~RC7; __delay_ms(50); } } void MCU_init(){ //Configura PUERTOS PORTC=0x00; TRISC=0x00; TRISB=0xFF;
ADCON1=0x06; // Se configura para indicar que las líneas de PORTA son de tipo digital
TRISA=0xFF; // Se configura para indicar que las líneas de PORTA son entradas //Configura TMR0 10ms
OPTION_REG=0b11000111; TMR0=158; //Activar Interrupciones INTE=1; // Para activar la interrupcion externa RB4 GIE=1; // Global T0IE=1; // Timer 0 } static void interrupt isr(void) { if(INTF==1){ switch(PORTA){ case 0: break; case 1: __delay_ms(6);break; case 2: __delay_ms(4);break; case 3: __delay_ms(2);break; } RC0=1; __delay_ms(1); RC0=0;
INTF=0; // se elimina la bandera de activación de la interrupción externa por RB0.
} if(T0IF==1){ TMR0=158; RC6=~RC6; T0IF=0; } }
Se carga el nuevo programa en al PIC del simulador ISIS de proteus, y se agrega al circuito dos STATE
LOGIC, para simular los unos y ceros de las entradas RA0 y RA1. Debemos de observar los tα para cada
ángulo de disparo, correspondiente a una combinación de RA0 y RA1.
Estado para Figura 5A Estado para Figura 5B Estado para Figura 5C Estado para Figura 5D
Añadido para poder
generar el tα corres-
pondiente a cada ángu-
lo de disparo.
Genera un pulso de disparo
de 1 ms de duración.
Figura 4 Estados de las entradas RA0 y RA1 para generar las señales de disparo en RC0
Figura 5A. Señal de cruce por cero (RB0), señal de disparo (RC0), para A1=0 y A0=0
Figura 5B. Señal de cruce por cero (RB0), señal de disparo (RC0), para A1=0 y A0=1
Figura 5C. Señal de cruce por cero (RB0), señal de disparo (RC0), para A1=1 y A0=0
Figura 5D. Señal de cruce por cero (RB0), señal de disparo (RC0), para A1=1 y A0=1
Se observa que los tiempos tα para cada ángulo de disparo no se cumple para la condición A0=0 y A1=0.
Para dicha condición no debe de existir ningún pulso de disparo en RC0. Esto se debe a que la señal de
cruce por cero, no empieza en el cero de la señal sinusoidal (existe un ligero retardo) que genera que
exista un pulso de salida en RC0. Para evitar este disparo incorrecto, estableceremos por software, que
cuando se presente esta condición, la salida es cero (CR0=0). Esto no es posible hacerlo, porque al salir
de Switch se genera el pulso.
Una solución es definir una función que genere el pulso de disparo. Se muestra los cambios a realizarse.
if(INTF==1){ switch(PORTA){ case 0: break; case 1: __delay_ms(6);break; case 2: __delay_ms(4);break; case 3: __delay_ms(2);break; } RC0=1; __delay_ms(1); RC0=0; INTF=0; }
. . . void pulsoDisparo (void) { RC0=1; __delay_ms(1); RC0=0; } void MCU_init(void);
.
.
.
.
if(INTF==1){ switch(PORTA){ case 0: RC0=0; break; case 1: __delay_ms(6); pusoDisparo();break; case 2: __delay_ms(4); pusoDisparo();break; case 3: __delay_ms(2); pusoDisparo(); break; } INTF=0; }
*********************************************
* Programa VRM3 para el PIC 16F877A
*********************************************
#include <htc.h> #define _XTAL_FREQ 10000000 // __CONFIG(FOSC_HS & WDTE_OFF & LVP_OFF)// !!!Cabecera para la grabación¡¡¡¡ void MCU_init(void); void pulsoDisparo(void){ RC0=1; __delay_ms(1); RC0=0; } void main(void){ MCU_init(); for(;;) { RC7=~RC7; __delay_ms(50); } }
Se define una
función que ge-
nera un pulso de
1 ms.
Se agrega la
función que ge-
nera el pulso
Se asegura que
para esta condi-
ción, RC0=0.
void MCU_init(){ //Configura PUERTOS
ADCON1=0x06; TRISA=0xFF; PORTC=0x00; TRISC=0x00; TRISB=0xFF; //Configura TMR0
OPTION_REG=0b11000111; TMR0=158; //Activar Interrupciones
GIE=1; INTE=1; T0IE=1; } static void interrupt isr(void) { if(INTF==1){ switch(PORTA){ case 0: RC0=0; break; // Se asegura que la salida de RC0=0. case 1: __delay_ms(6);pulsoDisparo(); break; case 2: __delay_ms(4);pulsoDisparo();break; case 3: __delay_ms(2);pulsoDisparo();break; } INTF=0; } if(T0IF==1){ TMR0=158; RC6=~RC6; T0IF=0; } }
Se ha simulado las entradas con dos fuentes DCLOCK, una de lenta variación (RA1) con 50 Hz y la otra
de más rápida variación (RA0), cuyo pulso de alto tiene un retardo de 6 ms. El resultado es:
Figura 6 Simulación con dos fuentes DCLOCK, para generar las cuatro opciones de tα.
Se observa en la Figura 6 que el valor de tαes correcto para cada caso. Lo que aun no esta resuelto es
que el disparo se realiza cada 16.6 ms; debiendo ser cada 8.3 ms. Esto se debe a que la interrupción de
RB0 solo detecta un flanco (de subida o de bajada ) y que en el programa esta establecido para el
flanco de subida (Bit 6 de OPTION_REG).
Alternativas de solución:
1) En cada caso de switch, cambiar el flanco de activación de la interrupción (INTEDG=~INTEDEG).
2) Usar otra entrada con interrupción por cambio de nivel: RB4 a RB7. Escogemos RB4.
Finalmente se obtiene el programa con la última corrección.
*********************************************
* Programa VRM4 para el PIC 16F877A
********************************************* #include <htc.h> #define _XTAL_FREQ 10000000 // __CONFIG(FOSC_HS & WDTE_OFF & LVP_OFF)// !!!Cabecera para la grabación¡¡¡¡ int Temporal; // se define una variable entera para leer PORTB
void MCU_init(void); void pulsoDisparo(void){ RC0=1; __delay_ms(1); RC0=0; } void main(void){ MCU_init(); for(;;) { RC7=~RC7; __delay_ms(50); } } void MCU_init(){ //Configura PUERTOS PORTC=0x00; TRISC=0x00;
PORTB=0b00010000; //Para evitar falsos disparos, las otras entradas se hacen cero
TRISB=0xFF; ADCON1=0x06; TRISA=0xFF; //Configura TMR0 10ms
OPTION_REG=0b11000111; TMR0=158; //Activar Interrupciones GIE=1; //Global RBIE=1; //Interupción del RB4...7; en remplazo de INTE=1 (para RB0). T0IE=1; //Timer 0 } static void interrupt isr(void) { // Se ha cambiado INTF por RBIF, para interrupciones // por las líneas RB4 a RB7 activadas por ambos flancos
if(RBIF==1){ Temporal=PORTB; // Se lee el PORTB para activar interrupciones // de RB4 a RB7; interrupciones por cambio de nivel, // es decir se activa por flanco de subida o bajada
switch(PORTA){ case 0: RC0=0; break; case 1: __delay_ms(6); pulsoDisparo(); break; case 2: __delay_ms(4); pulsoDisparo(); break; case 3: __delay_ms(2); pulsoDisparo(); break; } RBIF=0; // Se ha cambiado por INTF=0.
} if(T0IF==1){ TMR0=158; RC6=~RC6; T0IF=0; } }
Ha efecto de ver los tres casos, se alimentan RA0 y RA1 con las fuentes DCLOCK, que se muestran en la
Figura 7, como U1(RA0) y U1(RA1).
Figura 7 Simulación con fuentes DCLOCK para las entradas RA0 y RA1.
La configuración de dichas fuentes se muestra en la Figura 8. Se ha escogido las frecuencias de modo
que abarquen las combinaciones de RA0 y RA1. Para evitar la multiplicidad, se ha retardado la señal
U1(RA0) por 3 ms.
Figura 8 Valores de la configuración de las fuentes DCLOCK para las entradas RA0 y RA1.
El resultado de la simulación se muestra en la Figura 9. Allí se indican los flancos de referencia para me-
dir tα y los pulsos generados de acuerdo a los valores de RA0 y RA1.
Figura 9 Flancos de referencia para medir tα y pulsos generados de acuerdo a RA0 y RA1.
En la Figura 10 se ha señalizado el estado de RA0 y RA1, leídos un instante después de la detección del
flanco (de subida o bajada) en RB4. Se observa que los pulsos generados se dan para los tiempos calcu-
lados en la Tabla 1.
Figura 10 Flancos de referencia para medir tα y pulsos generados de acuerdo a RA0 y RA1.