Pues vamos viendo......
Supongamos que se desea una frecuencia de 1KHz a un ciclo de trabajo de 50% con una frecuencia del oscilador de 4MHz.
Lo primero es revisar la hoja de datos (en mi caso el 16F887 o cualquiera que tenga CCP).
Establece una fórmula
PWM Period = [(PR2)+ 1]•4•TOSC •(TMR2 Prescale Value)
Pero es menos complicado si se contempla en función de la frecuencia (recordar que f=1/t):
Fpwm= [(Fosc)/(PR2+1)*(TMR2 Prescale Value)*(4)]
Lo que interesa es el PR2 ya que es el registro del periodo para la frecuencia (revisar fórmula de hoja de datos):
PR2= [(Fosc)/(Fpwm)*(TMR2 Prescale Value)*(4)]-1
PR2 debemos recordar que es de 8 bits, por lo que el valor máximo no debe exceder 255 (muy importante).
Si se desea 1KHz tenemos básicamente dos opciones:
- 1.- Se cambia de frecuencia de oscilación (no recomendable, ya que todo el programa se altera)
- 2.- Se cambia de preescalador para el Timer2
Si tomamos la segunda entonces tenemos tres opciones: 1, 4 y 16.
Con 1:PR2= [(4MHz)/(1KHz)*(1)*(4)]-1
PR2=1000
-1 <---bien importante no olvidarse del -1
PR2=999
Con 1 no sirve, ya que se pasa de los 8 bits.
Con 4:PR2= [(4MHz)/(1KHz)*(4)*(4)]-1
PR2=249
Con 4 sirve.
Con 16:PR2= [(4MHz)/(1KHz)*(16)*(4)]-1
PR2=62.5
Con 16 podría servir pero..... el registro no almacena decimales, solo enteros; lo anterior nos proporciona dos posibles caminos:
Si PR2=62, entonces la Fpwm será:
Fpwm= [(Fosc)/(PR2+1)*(TMR2 Prescale Value)*(4)]
Fpwm= [(4MHz)/(62+1)*(16)*(4)]
Fpwm= 992.0634 Hz
Lo anterior entrega un error de 0.8% aproximadamente.
Si PR2=63, entonces la Fpwm será:
Fpwm= [(Fosc)/(PR2+1)*(TMR2 Prescale Value)*(4)]
Fpwm= [(4MHz)/(63+1)*(16)*(4)]
Fpwm= 976.5625 Hz
Lo anterior entrega un error de 2.4% aproximadamente.
La ideal es PR2=249 con preescalador a 4; cabe señalar que solo estamos en la frecuencia.
Para el PWM es algo similar pero, el CCS utiliza funciones donde el comportamiento no es tan transparente como se desearía.
Recordar que
Pulse Width =(CCPRxL:CCPxCON<5:4>) •TOSC • (TMR2 Prescale Value)
y que
Duty Cycle Ratio= (CCPRxL:CCPxCON<5:4>)
--------------------------------
4(PR2 + 1)
El ciclo de trabajo ya se conoce (es el deseado), por lo que interesa es el valor de CCPRxL:CCPxCON<5:4>. En C o en BASIC es relativamente sencillo colocar ese valor, en ensamblador no tanto. Lo anterior debido a que los bits 5 y 4 de CCPxCON son los de menor peso y se debe realizar un corrimiento con todo CCPRxL.
Aquí es donde se torna algo confuso (para la mayoría):
suponiendo un ciclo de trabajo de 50%, significa que el valor donde se repite el periodo (PR2+1) es 250, el valor medio sería 125, por lo que CCPRxL deberá tomar ese valor.
CCPRxL toma el valor ya que es el registro de mayor peso para el ciclo de trabajo, los otros dos bits no afectan.
Lo anterior es si deseas utilizar el PWM en "modo de 8 bits" (no existe tal modo, pero trabaja asi). Si deseas utilizar los 10 bits de resolución, deberás utilizar esos dos bits de menor peso.
Esos dos bits de menor peso siempre producirán 4 combinaciones adicionales (00,01,10,11) a las 256 del CCPRxL y, como sabemos 10bits=1024. El máximo valor que tendrás será 1023.
Si PR2 es 249, y PR2+1 =250, entonces el valor para el ciclo de trabajo crece de 250 a 1000, dando 4 veces el original (debido a esos dos bits).
Aqui está la situación:
para utilizar los 10 bits de resolución el CCS debe saber que el parámetro de
set_pwm_duty() es un entero de 16 bits (INT16 o LONG), de otra manera lo tomará como 8 bits (solo tomará el CCPRxL).
Coloca esto:
setup_ccp1(ccp_PWM);
setup_timer_2(t2_div_By_4,249,1);
set_pwm_duty(125);
Coloca esto:
setup_ccp1(ccp_PWM);
setup_timer_2(t2_div_By_4,249,1);
set_pwm_duty(500L);
Verás que no hay cambio.
Si tu micro cuenta con dos CCP, coloca uno con 125 y otro con 500.
Te mandaría la simulación en registros del MPLAB pero me son las 3:10 AM aquí y ya casi entro a trabajar.
Cualquier cosa estamos siguiendo el hilo.