miércoles, 24 de octubre de 2007

PWM de Ancho Variable con PIC 16F877A

Variando el ancho del pulso PWM

Si variamos el valor del registro CCPR1L, estaremos variando el ciclo de trabajo del PWM. En este programa variamos ese registro usando un convertidor AD en la entrada AN0; el modulo PWM al igual que el programa anterior esta configurado a 250Hz y el ADC trabaja a 8 bit usando justificacion a la izquierda (ya visto antes).





En el Video se observa la variacion en la intencidad de luz conforme variamos el potenciometro del AD, de la misma manera se puede controlar la velocidad de un motor DC pues se esta controlando la energia que se le aplica por unidad de tiempo, lo que hace a esta tecnica muy eficiente pues no se disipa calor como en otras tecnicas de control.

09/Nov/07 Nota:Como se ve en el video, el LED esta un poco iluminnado debido a que los ultimos bit del Byte de configuracion (CCPCON1<5:4>) estan en 1, puedes cambiarlos a 00 sinproblema alguno en el ciclo de trabajo debido a que son los LSB, no cambia de manera significativa el ciclo, quedando practicamente a 50%.







En el Segundo video se observa como el Led actua sobre el sensor de la camara digital A95, lo que hace ver de una manera diferente la forma de onda de un PWM variando.



Baja el programa ASM, el esquematico de la entrada y salida para este programa es el siguiente:



Entrada y salida del programa PWM_MODULE_250Hz.asm

Programa Hex:

:020000040000FA
:1000000002201F2883160313F93092008312031372
:100010007C3095003C30970083160313071188014C
:1000200083120313073092008312031341309F00A1
:10003000831603130E309F008312031308008312EC
:1000400003131F151F1D22281E08950088001F2856
:00000001FF


Formas de Onda:


Forma de onda PWM a aprox. 50%





Forma de onda PWM a aprox. 90%


Saludos.


.

18 comentarios:

Toni Diaz dijo...

Estoy empezando a aprender el uso de los pic, concretamente el 16f84a y el 16f877a.

Me gustaria ponerme en contacto contigo por e-mail para hacerte unas consultas, mas precisas

Muchas gracias

tonidiaz@hotmail.com

Ivan S. dijo...

Claro, aqui puedes poner tus dudas mediante comentarios o usando mi mail iess2600@gmail.com

Quiroz Fred dijo...

como se supone que obtuviste los 250HZ si la fmax de PWM es 244.14HZ?????????
de donde sacaste el calculo???.

Ivan S. dijo...

Los calculos estan aqui mismo en la entrada anterior. De hecho 250 Hz es una frecuencia muy baja para lo que el PIC puede hacer, asi que 244.14 Hz no es la Fmax. Saludos.

Alejandro Amaya dijo...

Hola, estoy trabajando una aplicacion con LabView para controlar un pendulo invertido. Mi 16F877A funciona como ADC para leer la posicion del pendulo, gestiona la Tx y Rx, y debe enviar una señal PWM para controlar la velocidad del motor y el sentido del giro.

Estoy trabajando con CC5X y ya logré manejar el PWM, pero presenta un comportamiento anomalo: va aumentando gradualmente el ciclo util, pero en algunos puntos se devuelve y vuelve a aumentar, esto hace que no acelere de manera constante sino que "ande a trancazos".

Uso un XT de 4MHz, y configure el modulo a 100KHz. Las instrucciones de configuracion del PWM son:

PR2 = 0b00001001; // Establece el periodo PWM 00011000
CCPR1L = 0b00000000; // Bits mas significativos del ciclo de trabajo **** OJO
CCP1CON = 0b00001100; // Bits menos significativos del ciclo de trabajo y habilitacion del PWM
T2CON = 0b00000100; // Prescaler y TIMER2 ON

Las instrucciones de variacion del ciclo util estan en una seccion de interrupciones:

interrupt inerrupciones(void)
{
uns8 altos, bajos;
uns16 temp;


int_save_registers

if (RCIF)
{
temp=RCREG;

if (temp<=127)
{
temp=128-temp;
temp=temp*2;
PORTB=1;
}
else
{
temp=temp-128;
temp=temp*2;
PORTB=2;
}

// Como labview envia datos entre 0 y 255, 0 debe mover el motor a maxima velocidad en un sentido, y 255 a maxima velocidad en el otro sentido. 127 es el punto de reposo (ciclo util 0%).

temp=temp*16;
temp=temp/100;
altos=temp/4;
bajos=temp-altos;
bajos=bajos*16;
bajos=bajos+12;
CCPR1L=altos;
CCP1CON=bajos;
RCIF=0;
}

int_restore_registers
}

Para convertir los datos recibidos por el pic (enteros entre 0 y 255) en calcule un factor (0.1568627451), pero me fue imposible operar enteros sin signo con flotantes para tener los valores a pasar al CCP1RL y CCP1CON, entonces aproxime multiplicando x 16, y luego dividiendo entre 100 (0.16). Eso da un valor aproximado.

Creo que el error que provoca los saltos esta en la conversion para pasar al CCPR1L y al CCP1CON.

Cualquier ayuda es bienvenida.

Saludos

Alejandro

Alejandro Amaya dijo...

Hola, estoy trabajando una aplicacion con LabView para controlar un pendulo invertido. Mi 16F877A funciona como ADC para leer la posicion del pendulo, gestiona la Tx y Rx, y debe enviar una señal PWM para controlar la velocidad del motor y el sentido del giro.

Estoy trabajando con CC5X y ya logré manejar el PWM, pero presenta un comportamiento anomalo: va aumentando gradualmente el ciclo util, pero en algunos puntos se devuelve y vuelve a aumentar, esto hace que no acelere de manera constante sino que "ande a trancazos".

Uso un XT de 4MHz, y configure el modulo a 100KHz. Las instrucciones de configuracion del PWM son:

PR2 = 0b00001001; // Establece el periodo PWM 00011000
CCPR1L = 0b00000000; // Bits mas significativos del ciclo de trabajo **** OJO
CCP1CON = 0b00001100; // Bits menos significativos del ciclo de trabajo y habilitacion del PWM
T2CON = 0b00000100; // Prescaler y TIMER2 ON

Las instrucciones de variacion del ciclo util estan en una seccion de interrupciones:

interrupt inerrupciones(void)
{
uns8 altos, bajos;
uns16 temp;


int_save_registers

if (RCIF)
{
temp=RCREG;

if (temp<=127)
{
temp=128-temp;
temp=temp*2;
PORTB=1;
}
else
{
temp=temp-128;
temp=temp*2;
PORTB=2;
}

// Como labview envia datos entre 0 y 255, 0 debe mover el motor a maxima velocidad en un sentido, y 255 a maxima velocidad en el otro sentido. 127 es el punto de reposo (ciclo util 0%).

temp=temp*16;
temp=temp/100;
altos=temp/4;
bajos=temp-altos;
bajos=bajos*16;
bajos=bajos+12;
CCPR1L=altos;
CCP1CON=bajos;
RCIF=0;
}

int_restore_registers
}

Para convertir los datos recibidos por el pic (enteros entre 0 y 255) en calcule un factor (0.1568627451), pero me fue imposible operar enteros sin signo con flotantes para tener los valores a pasar al CCP1RL y CCP1CON, entonces aproxime multiplicando x 16, y luego dividiendo entre 100 (0.16). Eso da un valor aproximado.

Creo que el error que provoca los saltos esta en la conversion para pasar al CCPR1L y al CCP1CON.

Cualquier ayuda es bienvenida.

Saludos

Alejandro

Anónimo dijo...

Buenos días:

¿Podría publicar el esquema de este circuito?

Me gustaría probarlo y experimentar con el para usarlo como base para un balastro electrónico para los fluorescentes de un acuario.

Muchas gracias.

frncsko dijo...

hola !! me gustaron los temas que pusiste me son de mucha ayudada, nomas quiciera sime podrias proporcionar el diagrama electrico completo.

mi e-mail es frncsko.mancera@gmail.com

Ivan S. dijo...

Hola, publicare el diagrama completo tan pronto como me sea posible, sin embargo puedo decir que varia muy poco a comparacion de los otros diagramas publicados en otros entradas. Buen dia para todos.

Juan José dijo...

¡Hola! Muy interesantes tus artículos. Te cuento que implementé el programa PWM_MODULE_250Hz.asm y anduvo de maravillas. Ahora bien, cuando intenté llevar a frecuencias mas elevadas (mi idea es trabajar con 25KHZ) el rango de variación del potenciometro se reducía considerablemente, de manera tal que, sin llegar a los 5V ya tenía el duty casi al 100%. Incluso antes de llegar a 1 volt, ya lo tenía. Trabajo con un Xtal de 4MHz. No le encuentro explicación alguna. Si pudieras ayudarme te lo agradecería... Gracias! Juan

Anónimo dijo...

que tal buen dia: este es un gran articulo que me intereso mucho yo soy estudiante de la carrera de Ing. en electronica estoy realizando mis residencias profecionales en un proyecto en el cual tengo que aplicar diferentes tecnologias en controladores estaticos de potencia asi que me gustaria controlarlo mediante un PWM pero con un pic y en vdd me ayudaria mucho este gran proyecto que publicaste y quisiera ver la forma de que me pudieras proporcionar el circuito completo para ponerlo en practica. thnks espero tu respuesta atte david nava mi correo es davdinc_2001@hotmail.com

GRUPO 5, 41 MELI dijo...

amigo muy interesante su programa me podria colaborar con el assembler del micro, para poder aplicarlo a otra situacion gracias

javixl dijo...

Hermano te escribo desde venezuela en esta oportunidad no para preguntar alguna duda, solo para felicitarde por estos aporte que sirven de mucho a la comunidad. Muy bien tu material con videos y diagramas. Te anímo a seguir con este interesante blog.

Pipo dijo...

Super interesante, lleno de info tu blog, muy buenooo gracias!!

Jose Luis Navarrete Ojeda dijo...

heey, amigo, ya no esta bien el link de descarga para el programa en .asm, me podrias mandar el link o el programa a navarretejl@hotmail.com o sube de nuevo el link

Marcelo Taraborelli dijo...

alguien seria tan amable de subir nuevamente el ASM??Gracias

quike dijo...

buenas tardes. alguien podria brindarme el codigo en ASM. a nigme41@hotmail.com

J-andres dijo...

Buenas noches, yo estoy trabajando el lo del PWM, y estoy teniendo problemas... utilizo el MPLAB con el compilador HI-TECH, y pues hago toda la configuracion necesaria del pwm para el pic16f877a, el PR2, el registro de control del timer T2CON, y el registro CCP1CON. Entonces vario siempre el registro CCPR1L, en dos pequeños ciclos que aumentan y disminuyes el ultimo registro mencionado. Pero el problema es que en la simulacion no me arroja ningun resultado. aqui adjunto el codigo, cualquier ayuda es valiosa para poder lograr el pwm. gracias.
#include
#include "delay.c"
#include "delay.h"

// configuracion de los fuses del pic
__CONFIG(XT&WDTDIS&PWRTDIS&BOREN&LVPDIS&WRTEN&DEBUGDIS&DUNPROT&UNPROTECT);

// programa principal
void main(void)
{
unsigned int ipwm;

TRISB=0b00000000;
TRISC=0b00000000;

/* Init PWM for Single Output */

PR2 = 0b01111100 ;
T2CON = 0b00000101 ;
CCP1CON = 0b00001100 ;
// ciclo infinito
do{
ipwm=0;
do{
CCPR1L = ipwm+1; // se aumenta el ciclo util
delayMs(5); // Delay 5 millisecond
}while (ipwm<250);

ipwm=250;
do{
CCPR1L = ipwm-1; // se disminuye el ciclo util
delayMs(5); // Delay 5 millisecond
}while (ipwm>0);

delayMs(100); // Delay 100 millisecond

}while (1);


}

Google