Para mi, con un simple:
Periodo = 0x00; // Esto puede ir de 0x00 hasta 0xFF, es decir lo que iria en PR2 del TMR2
// Valores a cargar en el CCPRxL + 2bits del CCPxCON:
Duty1 = ((50 * Periodo) / 100) << 2;
Duty2 = ((15 * Periodo) / 100) << 2;
Se podria simplificar estas ecuaciones en:
Duty1 = (2 * (uint16_t)Periodo);
Duty2 = (6 * (uint16_t)Periodo) / 10;
Ahi, cuando periodo (PR2) es por ejemplo 150, el duty al 50% deberia valer 300.
Por que esto ?, El periodo se genera con los 8bits del PR2 desplazado a la izquierda 2 veces. Es decir multiplicado por 4, Si tenemos 150 es 600.
Esto se hace para que la comparacion sea de 10 bits. Ahora si quisiera generar un duty de 50% deberia cargar la mitad, es decir 300. Si quisiera 15% de duty, es decir el 15% de 600 es de 90.
Fin.. Eso fue todo el calculo que debiste en lo que es llenar los registros. Observa que no afecta en nada los preescalers ni nada por el estilo.
Ahora si queres una conversion desde una frecuencia como estas planteando, entonces deberiamos Primero llegar al duty, que es algo parecido a lo que hiciste, pero hubiera intentado que se realizen menos veces las divisiones y multiplicaciones.
void SetearPWM(int16 Fpwm, int8 Duty){
int16 Periodo = (Fosc/4)/Fpwm;
int8 Preescaler = 1;
int8 DutyCalculado;
int8 i;
for(i=0;i<3;i++)
{
if( Periodo < 0x100)
{
break;
}
Periodo >>= 2
Preescaler <<= 2;
}
if( Preescaler > 16)
{
return; //Error, no hay valor posible
}
Periodo--;
DutyCalculado = (Duty*4*Periodo) / 100;
}
-------------------------------------
Segun la pagina que pasaste para 5000 Hz y 50% duty tendrias:
PR2 = Periodo = 149
Preescaler = 16
Duty = 299 ( Formado por CCPR1L + CCP1CON<5:4> )CCPR1L = 0b
01001010 ;
CCP1CON = 0b00
111100 ;
O 0b0100101011 = 299d
Segun el codigo que pase, tendriamos al comienzo del script:
Periodo = 2400
Preescaler = 1
Los pasos en el for quedarian los siguientes:
i=0 , pasa completamente por que Periodo es mayor que 0x100 ( 256 )
i=1 , los valores quedan culpa de la anterior vuelta:
Periodo = 600
Preescaler = 4
Aun es grande, asi que pasa.
i=2, los valores al comenzar esta vuelta es de
Periodo = 150
Preescaler = 16
Ahora entra al if y procede a ejecutar el break y salir del for, no ejecutandose las lineas que siguen.
Luego hay una "proteccion" por si es que ni con un Preescaler de 16 se puede realizar. Se decrementa 1 de Periodo dejandolo en 149, como queremos.
Finalmente el duty, tendria un valor de (50 * 4 * 149) / 100 = 298
Por lo tanto tendrias como salida:
Periodo = 149
Preescaler = 16
Duty = 298Bastante aproximado a lo que deberia ser.
-----------------------------------------------------------
Pero por supuesto, nada se compara respecto a velocidad a usar tablas, solo tendrias el trabajo de crearlas, que con un script de python lo harias en un ratito.
Y la otra creo que mi acercamiento es mas rapido que el tuyo, ya que no uso logaritmos ni nada raro, ademas trato de calcular lo menos posible. Asi es mas rapido.