TODOPIC

Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: bigluis en 27 de Noviembre de 2010, 14:19:10

Título: Libreria para manejar Frecuencia PWM en CCS.
Publicado por: bigluis en 27 de Noviembre de 2010, 14:19:10
En muchos casos necesitamos que nuestra señal PWM  tenga una frecuencia específica, el problema consiste en que necesitamos determinar el valor del Prescaler T2DIV y del registro PR2 a partir de la siguiente Fórmula.

$$Tpwm = 4\,Tosc\,\,T2DIV\,\left( {PR2 + 1} \right)

es decir:

$$Fpwm = {{Fosc} \over {4\,T2DIV\,\left( {PR2 + 1} \right)}}

Por ejemplo, queremos que Fpwm=1khz para un PIC16F887 que tiene Fosc=8MHz, y sabemos que este PIC posee 3 prescaler T2DIV=1, 4 y 16, por lo tanto el primer paso será despejar el valor de PR2 de la formula anterior.

$$PR2 = {{Fosc} \over {4\,Fpwm\,T2DIV}} - 1

el segundo paso sera sustituir valores y probar con T2DIV = 1.

$$PR2 = {{8MHz} \over {4\, \times 1kHz \times 1}} - 1 = 1999

Como el valor anterior es mayor al valor máximo de PR2, es decir 255, debemos aumentar el valor de T2DIV.

$$PR2 = {{8MHz} \over {4\, \times 1kHz \times 4}} - 1 = 499

Como aún el valor anterior es mayor al valor máximo de PR2, es decir 255, debemos aumentar el valor de T2DIV.

$$PR2 = {{8MHz} \over {4\, \times 1kHz \times 16}} - 1 = 124

En este caso si podemos darle este valor a PR2.

Muchas veces resulta tedioso estar calculando este valor, por eso he realizado la siguiente librería que realizará esto por nosotros.
Código: [Seleccionar]
/////////////////////////////////////////////////////////////////////////////////
//Autor: Luis Alberto Vargas Tijerino.
//Alias: Bigluis.
//Fecha: 26-Nov-2010.
//Pais:  Nicaragua.
/////////////////////////////////////////////////////////////////////////////////
//                                    PWM_FREQ.C
//    Libreria para ingresar la frecuencia PWM sin necesidad de calcularla.
//
//    Para utilizarla es necesario definir al inicio del programa Fosc
//
//Ejemplo:
//!#define Fosc 8000000
//
//    Luego es posible utilizar la funcion
//          set_pwm_freq(Fpwm)  Esta configurara T2DIV y PR2 para obtener
//                              Fpwm.
/////////////////////////////////////////////////////////////////////////////////

#ifndef Fosc
   #define Fosc 8000000
#endif

#use delay (clock=Fosc)

#if !defined(__PCD__)                                                            //Si no se ha definido un pic de 24 bits
   #define set_pwm_freq(Fpwm)                                                    /*definimos el macro set_pwm_freq(Fpwm) de la siguiente manera
   */(Fosc/(Fpwm*1*4)-1<0xFF)?                                                   /*Si (Fosc/(Fpwm*1*4)-1 es menor a 0xFF
   */    setup_timer_2(T2_DIV_BY_1, (int8)(Fosc/(Fpwm*1*4))-1, 1):               /*el macro set_pwm_freq(Fpwm) sera igual a setup_timer_2(T2_DIV_BY_1, Fosc/(Fpwm*1*4)-1, 1)
   */(Fosc/(Fpwm*4*4)-1<0xFF)?                                                   /*De lo contrario si (Fosc/(Fpwm*4*4)-1 es menor a 0xFF
   */   setup_timer_2(T2_DIV_BY_4, (int8)(Fosc/(Fpwm*4*4))-1, 1):                /*el macro set_pwm_freq(Fpwm) sera igual a setup_timer_2(T2_DIV_BY_4, Fosc/(Fpwm*4*4)-1, 1)
   */(Fosc/(Fpwm*16*4)-1<0xFF)?                                                  /*Si (Fosc/(Fpwm*16*4)-1 es menor a 0xFF
   */    setup_timer_2(T2_DIV_BY_16, (int8)(Fosc/(Fpwm*16*4))-1, 1):             /*el macro set_pwm_freq(Fpwm) sera igual a setup_timer_2(T2_DIV_BY_16, Fosc/(Fpwm*16*4)-1, 1)
   */    setup_timer_2(T2_DIV_BY_16, 0xFF, 1);                                   //De lo contrario el macro set_pwm_freq(Fpwm) sera igual a setup_timer_2(T2_DIV_BY_1, 0xFF, 1)
#else                                                                            //Si no se ha definido un pic de menos de 24 bits
   #define set_pwm_freq(Fpwm)                                                    /*Definimos el macro set_pwm_freq(Fpwm) de la siguiente manera
   */(Fosc/(Fpwm*1*4)-1<0xFFFF)?                                                 /*Si (Fosc/(Fpwm*1*4)-1 es menor a 0xFFFF
   */    setup_timer2(TMR_INTERNAL | TMR_DIV_BY_1, (int16)(Fosc/(Fpwm*1*4))-1):  /*el macro sera igual a setup_timer2(TMR_INTERNAL | TMR_DIV_BY_1, (Fosc/(Fpwm*1*4))-1)
   */(Fosc/(Fpwm*8*4)-1<0xFFFF)?                                                 /*Si (Fosc/(Fpwm*8*4)-1 es menor a 0xFFFF
   */    setup_timer2(TMR_INTERNAL | TMR_DIV_BY_8, (int16)(Fosc/(Fpwm*8*4))-1):  /*el macro sera igual a setup_timer2(TMR_INTERNAL | TMR_DIV_BY_8, (Fosc/(Fpwm*8*4))-1)
   */(Fosc/(Fpwm*64*4)-1<0xFFFF)?                                                /*Si (Fosc/(Fpwm*64*4)-1 es menor a 0xFFFF
   */    setup_timer2(TMR_INTERNAL | TMR_DIV_BY_64, (int16)(Fosc/(Fpwm*64*4))-1):/*el macro sera igual a setup_timer2(TMR_INTERNAL | TMR_DIV_BY_8, (Fosc/(Fpwm*16*4))-1)
   */    setup_timer2(TMR_INTERNAL | TMR_DIV_BY_64, 0xFFFF);                     //De lo contrario el macro sera igual a setup_timer2(TMR_INTERNAL | TMR_DIV_BY_8, 0xFFFF)
#endif

Y a continuación muestro el código de Ejemplo para usar la librería.
Código: [Seleccionar]
///////////////////////////////////////////////////////////////////////////////
//Autor:   Luis Alberto Vargas Tijerino.
//Alias:   Bigluis.
//Pais:    Nicaragua.
//Fecha:   24-Nov-10.
///////////////////////////////////////////////////////////////////////////////
#include <16f887.h>//pic a utilizar

#FUSES NOWDT       //No Watch Dog Timer
#FUSES HS          //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES NOPUT       //No Power Up Timer
#FUSES MCLR        //Master Clear pin enabled
#FUSES NOPROTECT   //Code not protected from reading
#FUSES NOCPD       //No EE protection
#FUSES NOBROWNOUT  //No brownout reset
#FUSES IESO        //Internal External Switch Over mode enabled
#FUSES FCMEN       //Fail-safe clock monitor enabled
#FUSES NOLVP       //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NODEBUG     //No Debug mode for ICD
#FUSES NOWRT       //Program memory not write protected
#FUSES BORV40      //Brownout reset at 4.0V
#FUSES RESERVED    //Used to set the reserved FUSE bits

#define Fosc 8000000         //Fosc=8Mhz
#include <PWM_FREQ.c>

#include <Puertos.c>

void main(){
   signed int sel_Fpwm=0;
   unsigned int Duty=127;
   TRISB=0XFF;                         //Todos los pines de PORTB seran entradas.
   setup_comparator(NC_NC);            //Desconectamos los comparadores Analogicos
   SETUP_ADC_PORTS(NO_ANALOGS);        //Solo AN0 sera analogico los demas digitales.
   SETUP_ADC(ADC_OFF);                 //Apagamos el ADC
   setup_ccp1(CCP_PWM);                //Configuramos CCP1 en modo PWM simple.
   while(TRUE){                        //Inicio del ciclo Infinito
      while(!PORTB);                   //Espera a que se active un pin del PORTB.
      delay_ms(10);                    //Retardo de 10ms para eliminar rebotes.
      if(RB0)                          //Si se activo RB0
         if(++sel_Fpwm>3)              //preincrementamos sel_Fpwm y si es mayor que 3
            sel_Fpwm=0;                //igualamos sel_Fpwm a 0.
      if(RB1)                          //Si se activo RB1
         if(--sel_Fpwm<0)              //predecrementamos sel_Fpwm y si es menor que 0
            sel_Fpwm=3;                //igualamos sel_Fpwm a 2.
      if(RB2)Duty+=4;                  //Si se activo RB2 incrementamos Duty en 5.
      if(RB3)Duty-=4;                  //Si se activo RB3 decrementamos Duty en 5.
      
      
      set_pwm1_duty(duty);             //El %DT de la senial sera Duty.
      
      switch(sel_Fpwm) {              
         case 0 :                      //Si sel_Fpwm es 0
            set_pwm_freq(500);         //Fpwm sera 500
            break;
         case 1 :                      //Si sel_Fpwm es 1
            set_pwm_freq(1000);        //Fpwm sera 1000
            break;
         case 2 :                      //Si sel_Fpwm es 2
            set_pwm_freq(1500);        //Fpwm sera 1500
            break;
         default:                      //De lo contrario
            set_pwm_freq(2000);        //Fpwm sera 2000
      }
      while(PORTB);                    //Espera a que se desactiven los pines de PORTB
   }
}

La librería "Puertos.c" la pueden encontrar aquí (http://www.todopic.com.ar/foros/index.php?topic=30662.0)

Y finalmente adjunto los archivos de la simulación y el código.