Autor Tema: Problema urgente con PWM + interrupcion en un 12F683  (Leído 2437 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado ancor

  • PIC10
  • *
  • Mensajes: 5
Problema urgente con PWM + interrupcion en un 12F683
« en: 11 de Mayo de 2011, 08:41:12 »
Saludos a todos los foreros. Soy novato aquí, así que espero hacer las cosas bien.

También soy algo novato en el mundo de los PIC, por eso os pido ayuda por favor. Llevo tres días volviéndome loco con un programa y no sé dónde está el problema.

El programa debería general una señal PWM de frecuencia 16 KHz, que es llamada por una interrupción (por overflow de Timer 0) cada 2ms.

Para monitorizar en el osciloscopio la interrupción, conmutamos el puerto GPIO.0 cada vez que se ejecuta, con lo que deberíamos obtener también una señal cuadrada en este pin.

La interrupción por si sola funciona bien, el problema es que cuando llama a la función “configuracion1_PWM” (que es la que activa el PWM), la interrupción cae de golpe y solo genera unos pequeños pulsitos de vez en cuando en GPIO.0. Es como si algo la forzase a cero.

El PWM tampoco es del todo estable y de vez en cuando pierde algún pulso, además, debería estar activo solo cuando la interrupción le llama, en cambio, no se para nunca.

El programa está hecho en CC5X. Os paso el listado, he intentado comentar todo para que sea más comprensible. Por favor ¿alguién me puede ayudar?. Muchísimas gracias de antemano.

LISTADO DEL PROGRAMA:

   
//****************************************************************************************************************************
//************************************** D E C L A R A C I Ó N   D E   V A R I A B L E S  ************************************
//****************************************************************************************************************************

uns16 ancho_pulso, configurar_M;
char i, j;

//****************************************************************************************************************************
//************************************ D E C L A R A C I Ó N   D E   F U N C I O N E S  **************************************
//****************************************************************************************************************************

void retardo_20m (void);
void configurar_puertos  (void) ;   
void configuracion1_PWM  (void) ;                      
void configuracion2_PWM  (void);   
void retardo_20u         (void) ;

//****************************************************************************************************************************
//************************************************ I N T E R R U P C I O N E S ***********************************************
//****************************************************************************************************************************

#pragma origin 0x04                                          // Indicamos la posición de origen de los datos.     
#include "int16CXX.H"                                       // Cabecera de interrupciones en C.

interrupt captura_datos (void)                                 // Interrupción por overflow de TMR0 cada 2ms (para 4 MHz).
{
   int_save_registers                                        // Guarda W, STATUS (y  PCLATH)   
   T0IF   =  0;                                            // Reset del flag.
   TMR0   = -255;                                           // Preparamos la siguiente interrupción.
   GPIO.0 = !GPIO.0;                                       // Conmuto para generar una señal pulsatoria para la monitorización.                                                      
   configuracion1_PWM ();                                    // Cada 2ms la rutina de interrupción ejecutará el proceso.   
   int_restore_registers                                     // Restaura W, STATUS y PCLATH
}       
           

//****************************************************************************************************************************
//******************************************* P R O G R A M A   P R I N C I P A L ********************************************
//****************************************************************************************************************************

void main (void)
{
   configurar_puertos ();         
   OSCCON     = 0b.0.110.0.11.1;       // Configuración oscilador: 4 MHz, OS interno como OS de sistema.                           
   OPTION_REG = 0b.10010.010;   
   
   while (1)
   {
      ancho_pulso = 124;             // Corresponde a una señal cuadrada.
      configuracion2_PWM ();
      retardo_20m ();
   }   
}

//****************************************************************************************************************************
//******************************* C Ó D I G O   D E   F U N C I O N E S   A U X I L I A R E S ********************************
//****************************************************************************************************************************

void configurar_puertos (void)
{   
   TRISIO = 0b.00.101010;            // GP0/AN0: Out, GP1/AN1: In, GP2/AN2/CCP1: Out, GP3: In, GP4/AN3: Out, GP5: In.
   CMCON0 = 0b.111;                // Desactiva el comparador.
   GPIO   = 0;                     // Todo el puerto incicializado a 0.
   GIE    = 1;                     // Activa interrupciones en general.
   PEIE   = 1;
   T0IE   = 1;                     // Activa interrupción T0IO. Las tres últimas equivalen a: INTCON = 0b.1110.0000;
}

void configuracion1_PWM (void)
{   
   T2CON   = 0b.0.0000.1.00;         // Fijamos el valor del preescalador a 1 (calculado previamente).
   PR2     = 61;                  // Valor de N (periodo) para f=16 KHz;
   CCP1CON = 0b.00.00.1100;          // CCP1: modo PWM.   
   TMR2IF = 0;   
   TMR2ON = 1;
}

void configuracion2_PWM (void)
{      
   configurar_M = ancho_pulso;
   // (La variable configurar_M es de 10 bits (de valor entre 0 y 1023), pasaremos los 8 bits de mayor peso a CCPR1L y los dos de menor peso a CCP1CON.5 y CCP1CON.4).
   for (i = 1; i < 7; i++)  configurar_M = rl (configurar_M);   // Desplazo a la izquierda el contenido de la variable para cargar la parte alta en CCPR1L.
   CCPR1L    = configurar_M.high8;    // Guardamos la parte alta de la variable.
   CCP1CON.5 = configurar_M.7;         // Guardamos los dos bits de menor peso en CCP1CON<5:4>.
   CCP1CON.4 = configurar_M.6;   
}

void retardo_20u (void)               // Calculado para f = 4MHz.
{
    char PDel0;
   
   #asm
      DEMORA  movlw     .3        ; 1 set numero de repeticion
              movwf     PDel0     ; 1 |
      PLoop0  clrwdt              ; 1 clear watchdog
              decfsz    PDel0, 1  ; 1 + (1) es el tiempo 0?
              goto      PLoop0    ; 2 no, loop
      PDelL1  goto PDelL2         ; 2 ciclos delay
      PDelL2  clrwdt              ; 1 ciclo delay
    #endasm
   
   return;         


void retardo_20m (void)             
{
    char PDel0, PDel1; 
   
   #asm
      DEMORA  movlw     .6        ; 1 set numero de repeticion  (B)
              movwf     PDel0     ; 1 |
      PLoop1  movlw     .207      ; 1 set numero de repeticion  (A)
              movwf     PDel1     ; 1 |
      PLoop2  clrwdt              ; 1 clear watchdog
              decfsz    PDel1, 1  ; 1 + (1) es el tiempo 0  ? (A)
              goto      PLoop2    ; 2 no, loop
              decfsz    PDel0, 1  ; 1 + (1) es el tiempo 0  ? (B)
              goto      PLoop1    ; 2 no, loop
      PDelL1  goto PDelL2         ; 2 ciclos delay
      PDelL2  clrwdt              ; 1 ciclo delay
              return              ; 2+2 Fin.
    #endasm
   
   return;       
}

Desconectado DaYeS

  • PIC16
  • ***
  • Mensajes: 119
Re: Problema urgente con PWM + interrupcion en un 12F683
« Respuesta #1 en: 14 de Mayo de 2011, 16:35:35 »
Que tal, bueno, hay algunas cosillas que no entiendo, lo primero decirte que nunca he programado en CC5X, pero a lo que voy.

Mira los fuses, por si tienes algunos molestando, aquí no los pusiste, por lo que dices no creo que sea eso, pero por mirarlos.

Una cosa bastante importante, nunca metas una función dentro de una interrupción, si te fijas en la doumentación de programación de microchip, al compilar, si llamas a una función dentro de una interrupcion y también fuera de ella, se duplica el código, haciendo una carrera entra ellas a la hoar de las llamadas.

Fijate que en el main llamas tb a void configuracion2_PWM (void) a los pocos microsegundos, mira si eso te esta afectando.

¿En CC5X no tienes funciones de retardo? como delay_ms o por ciclos o algo de eso, más que nada para que te quedará el código limpio.

Yo lo que haría sería que main no hicierá nada, y que cuando la interrupción se produzca configura el pwm, pero sin bajar la bandera (T0IF), para ver si una vez en la interrupción la genera bien, si es así voy siguiendo, sino intento sacar soló el pwn únicamente, ya que esta metido el Timer2 por medio (8 bits), etc..

Salu2
Si buscas resultados distintos, no hagas siempre lo mismo. Albert Einstein.

Desconectado ancor

  • PIC10
  • *
  • Mensajes: 5
Re: Problema urgente con PWM + interrupcion en un 12F683
« Respuesta #2 en: 16 de Mayo de 2011, 12:13:07 »
Muchas gracias DaYeS por tu respuesta.

Es posible que sea por lo que dices de llamar a la función desde la interrupción, tiene su lógica que entre en conflicto con otras llamadas desde el main.

Aun estoy un poco verde en programación. No sé si en CC5X hay funciones de retardo, en principio siempre utilizo unas en assembler que incluyo en una cabecera aparte.

Probaré a programar en la forma que dices, me parece una buena forma de hacerlo.

De nuevo muchas gracias.

Saludos.