PWM de 140HZ con PIC18F @ 20mhz.

Hola!

Estoy intentando sacar una señal PWM 140hz la cual tengo que variar el duty entre un 10% a un 95% en high.

Actualmente utilizo el pic18f46 con un cristal externo de 20mhz, puedo con el PLL disminuir hasta 1 o 2 mhz de alguna forma? para que el modulo PWM trabaje utilizando este clock.
 
Se me ha ocurrido hacerlo por soft algo asi:


Mediante el timer1(Controla periodo) y timer3(controla duty cicle) ambos de 16bit precargando la espera y interrupciones

Pero hasta ahora con mis calculos he llegado a esto

Señal 140hz, periodo p=7,14ms
Usar un timer de 16bits
Ttiempo = (65535-Vtmr0)* 4 * Tosc * Vpredivisor
7,14ms=(65535-VTmr0) * 4 * (1/20mhz) * 1
7,14ms=(65535-VTmr0) * 200ns
7,14ms/200ns = (65535-Vtmr0)
35700 = 65535 -Vtmr0
Vtmr0=29835

Valor precarga timer es 48886 valor correspondiente a 7,14ms es 35700.

Duty cycle de 0% el valor es 0 y 100% valor es 35700
cada 1% es :357

Tengo un inicializador de timer0:
T0PS0=1; //Prescaler is divide by 256
T0PS1=1;
T0PS2=1;
PSA=0; //Timer Clock Source is from Prescaler
T0CS=0; //Prescaler gets clock from FCPU (5MHz)
T08BIT=1; //8 BIT MODE
TMR0IE=1; //Enable TIMER0 Interrupt

Para timer1 y 3 deberia hacer esto tambien?
RD16=1
T1RUN=0
T1CKPS=00 (prescaler a 1:1)
T1OSCEN=0
T1SYNC=0
TMR1CS=1
TMR1ON=1
Timer 3
RD16=1
T3CCP=00
T3CKPS=00
T1SYNC=0
TMR3CS=1
TMR1ON=1

Y hacer una rutina de interrupcion para cada uno precargando el valor deseado?

void interrupt ISR(void) {
if((TMR1IF)&&(TMR1IE)) {//TMR1 Overflow ISR
counter1++;//Increment Over Flow Counter
if(counter1==xx) {//xx overflows = x msec
Pata del pwm a High
counter1 = 0; //Reset Counter
}
//Clear Flag
TMR1IF=0;
}
if((TMR3IF)&&(TMR3IE)) {//TMR3 Overflow ISR
counter3++;//Increment Over Flow Counter
if(counter3==xxx) {//xxxx overflows = x msec
Pata del pwm a Low
counter3 = 0; //Reset Counter
}
//Clear Flag
TMR3IF=0;
}

Como deberia hacerlo?
 
Bueno como no obtuve respuesta aqui voy a decir como lo hice buscando , para que otro que tenga mi mismo problema lo solucione.

El problema: no puedo generar una onda de 140hz mediante hardware a partir de un FOSC (oscilador) de 8MHZx4PLL=32mhz FOSC.

Uso el Timer0 como timer de Periodo de la onda de 140hz (ocupa unos 7,14ms) y luego el Timer2 como timer de Ciclo a 1 (duty cycle) de 0,0ms a 7.14ms -> 0% a 100% , ejemplo 5%->0,357ms.

Bien una vez definido como y cuales aqui es como los configuro.

Timer0:
// Temporización = [(256 - ValorprecargadoTMR0)*Prescalador+2]*4/Fosc= tiempo temporizado en seg
// Temporización = [(256 - 33)*256+2]*4/32000000=0,00713625 seg ->7,13625ms->1/0,00713625 =140,129hz
Código:
T0CS = 0;//Cojo señal del reloj del interno (FOSC).
T0SE = 0;//Conteo cuando estemos en el flanco de subida.
PSA = 0;//Asignar prescaler al timer0
T0PS2 = 1;T0PS1 = 1;T0PS0 = 1;//Prescalado a 1:256
TMR0 = 33;//Valor precargado para que la interrupcion salte cada 140hz(7,14ms) aprox.
TMR0IE=1;//Habilito interrupciones en timer0
TMR0ON=1;//Enciendo temp.

En la rutina de interrupcion:
Código:
 if((TMR0IF)&&(TMR0IE)) {   
    PORTBbits.RB0=1; //Pongo el pin RB0 a 5v (1)
    TMR2IF=0;//Limpio el flag interrupcion del timer2
    TMR2ON=1;//Inicio el timer2 del duty cicle
   //Limpio flag interrupcion del timer0
   TMR0IF=0;
 }


Ahora toca el reloj del duty cicle o tiempo a 1 que se encarga el timer2, preconfiguro el timer2 para tener un duty cicle que pueda variarlo en intervalos de 5% -> 0%,5%,10%....95%,100%.

Para ello divido el periodo de la señal de 140hz (1/140=7,14ms) con una regla de tres, si 100% es 7,14ms cuanto es 5% -> 5*7,14/100 =0,357ms es un 5%.

Entonces tengo que calcular el timer2 para que me genere una interrupción cada 0.357ms para poder tener saltos de 5% en la rutina de interrupcion y ya luego si quiero tener 50% de pwm, basta con esperar 10 interrupciones en la subrutina a ON y ya tendre 5%*10=50% = 0.357*10=3,57ms.

Como configuro timer2 para obtener 0.357ms:
//Quiero incrementos de 5%-> 100/5=20saltos ->Timer0 overflow cuando 256/20=12,8 de PR2
//Entonces 12,8 -> 13 entero , entonces 13 es el 5,078125%.
//Precarcamos para 5,078125% 256-PR2=13 ->243
// Temporización = [(256 - PR2)*Prescaler*Postcaler+2]*4/Fosc=Tiempo en seg
// Temporización = [(256 - 243)*16*14+2]*4/32000000=0,00036425seg ->0,36425ms
Código:
T2OUTPS3=1;T2OUTPS2=1;T2OUTPS1=0;T2OUTPS0=1;//Postscaler puesto a 14    
T2CKPS1 = 1;T2CKPS0 = 0;// Prescaler selecionado 16
PR2 = 243;         // Valor precargado PR2 para pwm 5.078125%.
TMR2IE=1; //Habilito interrupciones


Luego en la rutina:
Código:
if((TMR2IF)&&(TMR2IE)) {
    cont_overflw_duty++;//Contador de overflows de 5%
   if(cont_overflw_duty==10) {//10*5,07%=50,7%
   PORTBbits.RB0=0;   
   cont_overflw_duty = 0;  //Reset Contador
   }
   TMR2ON=0;//Deshabilito el timer ya que ya ha creado la onda
   TMR2IF=0;//Limpio el flag de interrupciones.
 }

Espero que haya sido de ayuda.
 
Atrás
Arriba