Autor Tema: Problema con interrupcion timer1 en C18  (Leído 4171 veces)

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

Desconectado MrAlber11

  • PIC10
  • *
  • Mensajes: 7
Problema con interrupcion timer1 en C18
« en: 06 de Octubre de 2010, 06:23:36 »
Muy buenas,soy nuevo en el foro,estoy realizando mi pfc programando un pic(18F2580) con MPLAB ICD. El asunto es que pretendo sacar por un pin del micro una señal periódica que tenga un primer pulso a nivel alto durante un tiempo determinado y despues generar una señal cuadrada de 2,5 MHz durante otro tiempo y así constantemente. Para ello he creado el código que aqui adjunto ayudandome del genial tutorial de c18 de suky, y la interrupción salta bien y se hace bien el pulso a nivel alto y la señal cuadrada, pero el problema es que esta señal cuadrada me la genera siempre de 16 KHz, ponga el valor que ponga como carga del timer a través de la función WriteTimer1().

Para calcular el valor de carga del timer he usado la ecuación también usada en este foro:

periodo del desborde =  4  x  Prescaler  x  (65535 - valor cargado en timer0)
                                       cristal oscilador
Tengo un cristal de 20MHz y si utilizo el timer1 en modo 16 bits con prescaler a 1 obtendría una carga de 65532.

El caso es que lo he intentado todo, cambiar el timer 0 por el 1, escribir la carga directamente en los registros TMR1H y TMR1L, cambiar los prescalers, modo de 8 bits, de 16 bits, y ya no se que hacer , estoy atascadisimo y sin esto no puedo avanzar ya que necesito esta señal para excitar un sensor del que tengo que leer datos.

Código:

#include <usart.h>
#include <p18f2580.h>
#include <p18cxxx.h>
#include <timers.h>
#include <stdio.h>
#include <stdlib.h>
#include <delays.h>
#include <pwm.h>



#pragma config OSC =HS ,FCMEN = OFF,IESO = OFF //CONFIG1H
#pragma config PWRT = ON,BOREN =OFF ,BORV = 3 //CONFIG2L
#pragma config WDT = OFF,WDTPS = 32768 //CONFIG2H
#pragma config MCLRE = ON,LPT1OSC = OFF,PBADEN = OFF//CONFIG3H
#pragma config STVREN = ON,LVP = OFF,XINST = OFF,DEBUG = ON //CONFIG4L
#pragma config CP0 = OFF,CP1 = OFF,CP2 = OFF//CONFIG5L
#pragma config CPB = OFF,CPD = OFF//CONFIG5H
#pragma config WRT0 = OFF,WRT1 = OFF,WRT2 = OFF//CONFIG6L
#pragma config WRTB = OFF,WRTC = OFF,WRTD = OFF//CONFIG6H
#pragma config EBTR0 = OFF,EBTR1 = OFF,EBTR2 = OFF,EBTR3 = OFF//CONFIG7L
#pragma config EBTRB = OFF//CONFIG7H
#pragma config BBSIZ = 1024 // 1K words (2K bytes) Boot Block

volatile int tiempo;

void temporizador(void);

//
//******************************************************//
// Vector de Interrupcion
//******************************************************//
//
 #pragma code interrupcion = 0X0008 // Creamos una nueva seccion de codigo a partir de la direccion 0x08.

void vectorinterrupcion (void){

_asm goto temporizador _endasm

}

#pragma code  // Cerramos seccion.

// **********Rutina de Interrupcion******************

#pragma interrupt temporizador

void temporizador(void){



if (PIR1bits.TMR1IF==1){

tiempo++;
if (tiempo<6){
PORTCbits.RC2 =1;
}
else{
   if (tiempo==48){
   PORTCbits.RC2 =~PORTCbits.RC2;
   tiempo=0;
            }
   else{
   PORTCbits.RC2 =~PORTCbits.RC2;
   
   }
}

WriteTimer1(65532);

PIR1bits.TMR1IF==0;






}
}

void main(void) {

TRISCbits.TRISC2 = 0; //configuramos l pin RC2 como salida.

RCONbits.IPEN=0; // Deshabilitamos Prioridades
INTCONbits.PEIE=1; // Habilitamos interrupcion de perifericos.-
INTCONbits.GIE=1; // Habilitamos interrupcion Global.

OpenTimer1( TIMER_INT_ON    & T1_16BIT_RW      & T1_SOURCE_INT   & T1_PS_1_1       &

           T1_OSC1EN_OFF   &

            T1_SYNC_EXT_OFF );  

      

WriteTimer1(65532);


}



Muchas gracias de antemano, sois unos cracks!

PD.: Les adjunto en el .rar el proyecto entero por si lo quieren compilar, gracias!
« Última modificación: 06 de Octubre de 2010, 06:25:45 por MrAlber11 »

Desconectado Tisco

  • PIC16
  • ***
  • Mensajes: 108
Re: Problema con interrupcion timer1 en C18
« Respuesta #1 en: 06 de Octubre de 2010, 07:25:15 »
buenas,
no he revisado mucho el codigo, pero si lo que quieres es crear una señal cuadrada deberias emplear el modulo PWM pues seria mucho mas preciso.
En cuanto a tu codigo, estaria bien que tratases de ser mas ordenado, te evitaras muchos problemas en cuanto empiezes a hacer programas un poco complejos.
Algunos fallos que he visto en el codigo es que en la rutina de interrupcion, justo al final, haces "PIR1bits.TMR1IF==0;" cuando deberias hacer una asignacion: PIR1bits.TMR1IF=0;
Si no vas a emplear el modulo PWM deberias refrescar el timer justo despues de comprobar si flag esta a 1.
al terminar el programa principal deberias de poner un bucle infinito o algo que impida que el programa vuelva a comenzar "while(1);" por ejemplo.

Ya me contaras si modificando eso te funciona, un saludo!

Desconectado MrAlber11

  • PIC10
  • *
  • Mensajes: 7
Re: Problema con interrupcion timer1 en C18
« Respuesta #2 en: 06 de Octubre de 2010, 09:56:48 »
Hola Tisco, ante todo muchas gracias por responder tan rápido.

Lo de la pwm tienes razón sale una señal muy limpia de 2,5 MHz, ya la hice pero no me vale porque necesito antes de de la señal cuadrada un pulso de comienzo que mantenga a 1 la señal durante un tiempo y luego genera la señal cuadrada y despues otra vez el pulso y asi sucesivamente. Tambien estoy intentando algo por ese lado, creando primero una señal de ciclo de trabajo del 100& y luego otra de frecuencia 2,5 MHZ y 50& de ciclo de trabajo, pero de esta manera no consigo que se repita en el tiempo. Te pongo también este código para que lo veais.
Respecto al programa de la interrupción decirte que he cambiao el bit de asignación como me has dicho, he añadido el while(1) al final del main y he introducido el writetimer también despues de comprobar el flag. Aqui te muestro como está ahora el código después de los cambios,pero ahora me genera la señal de 38 Hz ponga el valor que ponga en writeTimer1. Por más vueltas que le doy no se que puede estar mal,estoy desesperado con esto, muchas gracias,

Un saludo

Código:

#include <usart.h>
#include <p18f2580.h>
#include <p18cxxx.h>
#include <timers.h>
#include <stdio.h>
#include <stdlib.h>
#include <delays.h>
#include <pwm.h>



#pragma config OSC =HS ,FCMEN = OFF,IESO = OFF //CONFIG1H
#pragma config PWRT = ON,BOREN =OFF ,BORV = 3 //CONFIG2L
#pragma config WDT = OFF,WDTPS = 32768 //CONFIG2H
#pragma config MCLRE = ON,LPT1OSC = OFF,PBADEN = OFF//CONFIG3H
#pragma config STVREN = ON,LVP = OFF,XINST = OFF,DEBUG = ON //CONFIG4L
#pragma config CP0 = OFF,CP1 = OFF,CP2 = OFF//CONFIG5L
#pragma config CPB = OFF,CPD = OFF//CONFIG5H
#pragma config WRT0 = OFF,WRT1 = OFF,WRT2 = OFF//CONFIG6L
#pragma config WRTB = OFF,WRTC = OFF,WRTD = OFF//CONFIG6H
#pragma config EBTR0 = OFF,EBTR1 = OFF,EBTR2 = OFF,EBTR3 = OFF//CONFIG7L
#pragma config EBTRB = OFF//CONFIG7H
#pragma config BBSIZ = 1024 // 1K words (2K bytes) Boot Block

volatile int tiempo;

void temporizador(void);

//
//******************************************************//
// Vector de Interrupcion
//******************************************************//
//
 #pragma code interrupcion = 0X0008 // Creamos una nueva seccion de codigo a partir de la direccion 0x08.

void vectorinterrupcion (void){

_asm goto temporizador _endasm

}

#pragma code  // Cerramos seccion.

// **********Rutina de Interrupcion******************

#pragma interrupt temporizador

void temporizador(void){



if (PIR1bits.TMR1IF=1){
WriteTimer1(65532);
tiempo++;
if (tiempo<6){
PORTCbits.RC2 =1;
}
else{
   if (tiempo==48){
   PORTCbits.RC2 =~PORTCbits.RC2;
   tiempo=0;
            }
   else{
   PORTCbits.RC2 =~PORTCbits.RC2;
  
   }
}

WriteTimer1(65532);

PIR1bits.TMR1IF=0;


}
}

void main(void) {

TRISCbits.TRISC2 = 0; //configuramos l pin RC2 como salida.

RCONbits.IPEN=0; // Deshabilitamos Prioridades
INTCONbits.PEIE=1; // Habilitamos interrupcion de perifericos.-
INTCONbits.GIE=1; // Habilitamos interrupcion Global.

OpenTimer1( TIMER_INT_ON    & T1_16BIT_RW      & T1_SOURCE_INT   & T1_PS_1_1       &

           T1_OSC1EN_OFF   &

            T1_SYNC_EXT_OFF );  

WriteTimer1(65532);

while(1);
}


///Código de las señales PWM////

void main (void)
{

TRISCbits.TRISC2 = 0; //el pin CCP1 como salida

OpenTimer2(TIMER_INT_OFF & T2_PS_1_1 & T2_POST_1_1);


OpenPWM1(0x08); // configuramos período/frecuencia de la señal PWM a 625 KHz, ya que quiero que esté a 1 durante 1,6 us.
SetDCPWM1(8) ; // elegimos ciclo de trabajo de la señal PWM al 100%. es un 8.
OpenPWM1(0x01); // configuramos período/frecuencia de la señal PWM a 2,5 Mhz.
SetDCPWM1(4); //50% ciclo de trabajo



return 0;
}
« Última modificación: 06 de Octubre de 2010, 10:05:26 por MrAlber11 »

Desconectado Tisco

  • PIC16
  • ***
  • Mensajes: 108
Re: Problema con interrupcion timer1 en C18
« Respuesta #3 en: 06 de Octubre de 2010, 13:08:54 »
A la entrada de la rutina de interrupcion has puesto unha asignacion en vez de una comparacion "if (PIR1bits.TMR1IF=1){".
Ademas, el programa principal en el ejercicio del PWM tiene un "return 0;" que no tiene logica.
Te recomiendo que repases algun buen manual de lenguaje C para evitar esa clase de fallos.

ahora centremonos en el ejercicio.
con el TMR1 en modo timer te va a resultar imposible conseguir una frecuencia de 2.5MHz, pues tienes que tener en cuenta que a 20MHz el uC realmente esta trabando a 5MHz, por lo que entre desbordes del TMR1 solo podrias ejecutar dos instrucciones simples (que este caso ya te lo consume el salto a la interrupcion).

Mi consejo es que lo hagas, como ya te comente antes, con el modulo PWM. Tu fijas una frecuencia de 2.5MHz para la salida y pones un DC del 0%, activando la interrupcion del timer 2 para asi saber cuando deberias dejar de generar el retardo y generar la señal cuadrada. eso si, tienes que tener en cuenta que el valor de recarga del DC tardara un PWM period mas a partir de que hayas refrescado su nuevo valor en verse reflejado en la salida.

Otra opcion seria hacerlo con el TMR1 en modo comparacion, lo cual te daria algo mas de juego que como lo estas intentando actualmente.

De todas formas, tienes que tener en cuenta que al tener que generar ese retardo inicial andas algo justo de velocidad, por lo que si yo fuese tu haria el programa en ensamblador, pues es bien sencillito, ocuparias mucha menos memoria y tendrias mas control sobre los tiempos de ejecucion.

Ya me contaras que tal progresa el asunto, un saludo.

Desconectado MrAlber11

  • PIC10
  • *
  • Mensajes: 7
Re: Problema con interrupcion timer1 en C18
« Respuesta #4 en: 06 de Octubre de 2010, 14:41:51 »
Hola de nuevo Tisco, vale voy a centrarme en intentar hacer lo que me has dicho con la señal PWM, porque como ya me habian comentado y tu me confirmas ahora va a ser imposible generar 2,5 MHz con la interrupción del timer.

Voy a intentar hacer lo que me has dicho, pr aqui te iré diciendo como lo llevo, muchas gracias!!

Un saludo

Desconectado MrAlber11

  • PIC10
  • *
  • Mensajes: 7
Re: Problema con interrupcion timer1 en C18
« Respuesta #5 en: 17 de Octubre de 2010, 07:19:32 »
Hola Tisco, después de darle muchas vueltas, hice lo más parecido a lo que me dijiste y cambiando una vez el ciclo de trabajo de la señal de 0 al 50% parece que es suficiente para excitar al sensor y ya parece que tiene algo de vida. Ahora tengo una dudilla con respecto a la lectura del puerto serie.

El tema es que yo recojo en una variable tipo char la lectura del sensor y visualizando la variable en mplab veo que le llegan unos y ceros, pero el caso es que ahora quiero acceder individualmente a los bits de ese char, pero es que en C18 no se hacerlo o no se si se puede, como por ejemplo se puede hacer con un bit de un puerto determinado(TRISCbits.TRISC2 = 0;). ¿Sabrías como acceder individualmente a los bits de esa varaible char?

Muchas gracias de antemano!

Un saludo!!

Desconectado Tisco

  • PIC16
  • ***
  • Mensajes: 108
Re: Problema con interrupcion timer1 en C18
« Respuesta #6 en: 17 de Octubre de 2010, 11:20:40 »
Pues hay varias maneras de hacerlo.
Puedes probar con mascaras, por ejemplo:
Código: C
  1. char variable;
  2. ...
  3. variable = RCREG;
  4. if(variable && 0x01) ...
  5. if(variable && 0x02) ...
  6. if(variable && 0x04) ...
Otra forma seria con uniones de estructuras, que es como lo que tu comentas:
Código: C
  1. union
  2. {
  3.         unsigned char   BYTE;
  4.         struct
  5.         {
  6.                 unsigned        B0:1;
  7.                 unsigned        B1:1;
  8.                 unsigned        B2:1;
  9.                 unsigned        B3:1;
  10.                 unsigned        B4:1;
  11.                 unsigned        B5:1;
  12.                 unsigned        B6:1;
  13.                 unsigned        B7:1;
  14.         };
  15. }REGISTRObits;
  16. ...
  17. REGISTRObits.BYTE = RCREG;
  18. if(REGISTRObits.B0) ...
  19. if(REGISTRObits.B1) ...
  20. if(REGISTRObits.B2) ...
Ademas, si quieres nombrar los bits o el char "sin tener que acceder a la estructura", podrias hacer lo siguiente:
Código: C
  1. #define REGISTRO        REGISTRObits.BYTE
  2. #define BIT0            REGISTRObits.B0
  3. ...

Espero que te sirva, un saludo!

Desconectado MrAlber11

  • PIC10
  • *
  • Mensajes: 7
Re: Problema con interrupcion timer1 en C18
« Respuesta #7 en: 18 de Octubre de 2010, 15:20:03 »
Muchas gracias Tisco, eres un crack, me pongo con ello!! muchas gracias!!

Desconectado MrAlber11

  • PIC10
  • *
  • Mensajes: 7
Re: Problema con interrupcion timer1 en C18
« Respuesta #8 en: 18 de Octubre de 2010, 16:06:44 »
hola Tisco,

¿es posible crear una variable de 20 bits? es que el sensor manda la información en paquetes de 20 bits, los 4 primeros me dicen si la lectura es del eje de fuerza fx, fy o fz, y los 16 siguientes son los datos de fuerza, y por esto quería hacer bit a bit a la variable, para decirle que si los 4 primeros bits son ceros, guarda la información en la variable fx, si es 0001 en la variable fy,etc..

pero como dos char son 16 y tres 24, siempre tengo 4 bits colgando, conoces algun método para hacer esto??

muchas gracias y perdón por las molestias.

Desconectado Tisco

  • PIC16
  • ***
  • Mensajes: 108
Re: Problema con interrupcion timer1 en C18
« Respuesta #9 en: 19 de Octubre de 2010, 06:47:53 »
Pues la verdad, siempre que he necesitado una variable de 20 bits he empleado el tipo de dato "short long int" (24 bits) o "long int" (32 bits) dependiendo del compilador. que yo sepa no hay ninguna manera directa de hacerla de 20 bits.
Un saludo!

Desconectado MrAlber11

  • PIC10
  • *
  • Mensajes: 7
Re: Problema con interrupcion timer1 en C18
« Respuesta #10 en: 04 de Noviembre de 2010, 15:07:51 »
Hola Tisco,

aqui sigo con el dichoso código este para separar las variables, ahora el problema que tengo es el siguiente:

ya tengo mi lectura de datos en la variable JR3 bits (declarada como tu me dijiste), y ahora quiero guardar los datos de fuerza de cada eje en una variable distinta, para ello primero creo una variable de 24 bits, la cual relleno con 3 lecturas de 8 bits, y luego los bits del 4 al 20 de esta variable de 24 bits(que son los 16 bits de datos puros que me interesan, ya que los 4 primeros indican la dirección,fx o fy,etc)los guardo en otra variable de 16 bits. El caso es que tengo un for para ir rellenando la variable de 24 bits y luego una asignación de variables que el caso es que tiene muy mala pinta, porque al final los valores que se visualizan no son los correctos. Aquí te dejo el código a ver si me puedes echar una mano con algo que veas mal o darme algun consejillo,muchas gracias por todo como siempre!

Saludos!

Código: [Seleccionar]
void main(void) {
char c2JR3;
char variable2[3];
int i;
union
{
char byte;
struct
{
unsigned B0:1;
unsigned B1:1;
unsigned B2:1;
unsigned B3:1;
unsigned B4:1;
unsigned B5:1;
unsigned B6:1;
unsigned B7:1;
};
}JR3bits;

union
{
short word;
struct
{
unsigned B0:1;
unsigned B1:1;
unsigned B2:1;
unsigned B3:1;
unsigned B4:1;
unsigned B5:1;
unsigned B6:1;
unsigned B7:1;
unsigned B8:1;
unsigned B9:1;
unsigned B10:1;
unsigned B11:1;
unsigned B12:1;
unsigned B13:1;
unsigned B14:1;
unsigned B15:1;

};
}fxbits;
union
{
short long tres_bytes;
struct
{
unsigned B0:1;
unsigned B1:1;
unsigned B2:1;
unsigned B3:1;
unsigned B4:1;
unsigned B5:1;
unsigned B6:1;
unsigned B7:1;
unsigned B8:1;
unsigned B9:1;
unsigned B10:1;
unsigned B11:1;
unsigned B12:1;
unsigned B13:1;
unsigned B14:1;
unsigned B15:1;
unsigned B16:1;
unsigned B17:1;
unsigned B18:1;
unsigned B19:1;
unsigned B20:1;
unsigned B21:1;
unsigned B22:1;
unsigned B23:1;
};
}variablebits;
//char JR3;
TRISB=0x00;   // puerto B configurado de salida
TRISAbits.TRISA3 = 0; //pin conectado al led cofig como salida
PORTAbits.RA3  = 0;

RCSTAbits.SPEN=1; // Configuro RX/DT y TX/CK como pines del puerto serie

BAUDCONbits.SCKP=1; // Modo síncrono: Estado de reposo para reloj a nivel alto.
//********************PWM******************************************
TRISCbits.TRISC2 = 0; //el pin CCP1 como salida

OpenTimer2(TIMER_INT_OFF & T2_PS_1_1 & T2_POST_1_1);

OpenPWM1(0x01); // configuramos período/frecuencia de la señal PWM a 2 Mhz, he puesto 2 pero es 2,5.
SetDCPWM1(4);
//while(1){
//Delay10TCYx(1);//2us
//SetDCPWM1(16); // elegimos ciclo de trabajo de la señal PWM al 100%


//}
//******************************************************************

OpenUSART( USART_TX_INT_OFF  &

            USART_RX_INT_OFF  &

            USART_SYNCH_MODE  &

            USART_SYNC_MASTER &

            USART_EIGHT_BIT   &

            USART_CONT_RX     &

            USART_BRGH_HIGH,

            86                ); // 57600 baud, 8n1, Modo sincrono con recepción continua


// programa principal
while (1) {
while ( !DataRdyUSART() ); // Espera a que haya un dato listo
     //    PORTAbits.RA3  = 0;
    //PORTAbits.RA3  = 0;
      //Delay10KTCYx(100);//1 seg
    JR3bits.byte=getcUSART();
//c2JR3 = getcUSART();           // Lee el caracter nuevo
    //PORTAbits.RA3  = 1;
         //getsUSART(c2JR3,1);
     
   
        //c2JR3 = c2JR3 - 0x01;
    //JR3bits.byte = ~c2JR3; //Binary number
              // Cambia el estado del LED
       // JR3 = ~c2JR3;
//if((c2JR3 & 11110000)==01010000){
if(JR3bits.B7==0 & JR3bits.B6==1 & JR3bits.B5==1 & JR3bits.B4==1){
 PORTAbits.RA3  = 1;
for(i=0;i<3;i++){
//variable2[i]=c2JR3;
variable2[i]=JR3bits.byte;
//variablebits.tres_bytes[i]=c2JR3;
//c2JR3 = getcUSART();
JR3bits.byte=getcUSART();


}
variablebits.tres_bytes=(short long)variable2;

fxbits.B0=variablebits.B4;
fxbits.B1=variablebits.B5;
fxbits.B2=variablebits.B6;
fxbits.B3=variablebits.B7;
fxbits.B4=variablebits.B8;
fxbits.B5=variablebits.B9;
fxbits.B6=variablebits.B10;
fxbits.B7=variablebits.B11;
fxbits.B8=variablebits.B12;
fxbits.B9=variablebits.B13;
fxbits.B10=variablebits.B14;
fxbits.B11=variablebits.B15;
fxbits.B12=variablebits.B16;
fxbits.B13=variablebits.B17;
fxbits.B14=variablebits.B18;
fxbits.B15=variablebits.B19;


}
}

}

Desconectado Tisco

  • PIC16
  • ***
  • Mensajes: 108
Re: Problema con interrupcion timer1 en C18
« Respuesta #11 en: 05 de Noviembre de 2010, 07:16:33 »
Hola MrAlber11,
como te dije en una respuesta anterior, te recomiendo que aprendas primero a programar en lenguaje C. Yo te podria sequir dando las soluciones a tus problemas, pero son cosas basicas que deberias saber hacer, mas si estas haciendo el PFC, pues se supone que ya has terminado todas las asignaturas y la tematica de este foro es compartir y aprender, no que te lo den hecho.
Hay buenos manuales por internet o si no te gustan siempre puedes mirar un buen libro. Te recomiendo que mires sobre todo los apartado de vectores (arrays), punteros y mascaras, pues lo que pretendes hacer se consigue facilmente con una mascara.
Yo y los demas foreros estaremos atentos a tus avances encantados de echarte una mano para resolver tus dudas en cuanto lo necesites.
Un saludo!



 

anything