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;
}