Autor Tema: TMR1 para medir microsegundos  (Leído 3053 veces)

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

Desconectado echo_ordie

  • PIC10
  • *
  • Mensajes: 3
TMR1 para medir microsegundos
« en: 07 de Octubre de 2018, 23:27:13 »
Hola , estoy trabajando con un PIC18F4550 y necesito usar el TMR1 como un temporizador , ademas necesito poder medir 1 us . Estoy usando un cristal de 4Mhz externo y  un FOSC de 48Mhz .Segun lo que he leido con un preescalador de 1:1 deberia ser capaz de medir el us sin embargo. Aqui mi configuracion:

Código: [Seleccionar]
void timer1config(void){
//TMR1 Config Registros   
T1CONbits.RD16 = 1;
T1RUN = 0;//Usar reloj interno
TMR1CS = 0; // FOSC / 4
T1CKPS1:T1CKPS0 = 00;
T1OSCEN = 0;
}

 void wait_in_us(long time){
    long segundos = 0;
    TMR1H = 0xff;
    TMR1L = 0xf4;
    TMR1IF = 0;
     TMR1ON = 1;
    while(segundos < time){
        if(TMR1IF){
            TMR1H = 0xff;
            TMR1L = 0xf4;
            TMR1IF = 0;
            segundos ++;
        }         
    }
 }

Y aqui mi main :
Código: [Seleccionar]
void main(void) {
    configPIC();
    timer1config();
    while(1){
    LED = _ON;   
    wait_in_us(1000000);
    LED = _OFF;
    wait_in_us(1000000);
    }
}

Mi idea es decirle a la funcion que espere 1000000 de micro segundos es decir 1 segundo , pero cuando mido el tiempo que el Led se enciende estoy midiendo 2.80 s casi 3 s. Si me pueden ayudar con el calculo o si saben si es posible medir micro segundos seria de mucha ayuda.Aclaro que quiero micro segundos porque necesito usar el CCP1 para medir la frecuencia de una señal externa y considero que entre mas presicion tenga el TMR1 , mayores frecuencias podre medir.

Desconectado isfan

  • PIC16
  • ***
  • Mensajes: 145
Re:TMR1 para medir microsegundos
« Respuesta #1 en: 08 de Octubre de 2018, 07:41:09 »
Hola, es necesario para garantizar la correcta definición de _XTAL_FREQ, para que no tenga problema con la macro de retardos . Asegura también los guiones bajos adecuados, por ejemplo:

 #define _XTAL_FREQ 20000000

#include <xc.h>
#include <p18f4550.h>
...
void main(void) {
   __delay_us(10);
   __delay_ms(10);
}
 

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:TMR1 para medir microsegundos
« Respuesta #2 en: 08 de Octubre de 2018, 07:50:56 »
Si te entiendo pero son 2 cosas distintas lo tuyo..

Primero que aca tenes una buena cantidad de instrucciones antes de entrar al while, que no estas contando:

Código: C
  1. void wait_in_us(long time){
  2.     long segundos = 0;
  3.     TMR1H = 0xff;
  4.     TMR1L = 0xf4;
  5.     TMR1IF = 0;
  6.      TMR1ON = 1;
  7.     while(segundos < time){
  8.         if(TMR1IF){
  9.             TMR1H = 0xff;
  10.             TMR1L = 0xf4;
  11.             TMR1IF = 0;
  12.             segundos ++;
  13.         }        
  14.     }
  15.  }

Luego en cada overflow tenes otra cantidad. Encima despues de todo lo cargas con 0xFFF4 por lo que los overflow ocurren BASTANTE seguido. Y ese error se multiplica por 1.000.000 de veces que ocurre.
Para lo que estas haciendo te conviene mas usar un delay, que va a ser lo mismo, ya que es bloqueante la funcion.

Citar
Aclaro que quiero micro segundos porque necesito usar el CCP1 para medir la frecuencia de una señal externa y considero que entre mas presicion tenga el TMR1 , mayores frecuencias podre medir

Y para este caso lo estarias usando mal... En realidad lo estas encarando mal al problema.
Si quisiera medir la frecuencia, me quedan 2 opciones, la primera es medir cuantos pulsos tengo en cierto tiempo. Y la otra es medir el periodo de la señal. Hace poco se hable sobre un frecuencimetro en el foro, y se concluyo que mejor era la ultima. ¿Entonces como procedes?
Configuras el CCP para CAPTURAR flancos ascendentes, y dejas tu Timer1 corriendo libre. La primera ves que entre a la interrupcion del CCP guardas el valor, y aca te quedan varias posibilidades.
- La segunda ves que entra, tomas el valor del TMR1 ( recorda que necesitas tomar el valor de TMR1L primero asi el TMR1H se actualiza) lo restas con el anterior y de alli calculas
o
- Esperas mas ciclos, ejemplo 2 ciclos, 4, 8, recien ahi tomas el valor del TMR1 y calcuclas tu frecuencia.

¿Como calcular la frecuencia?

Sabes que cada uno que suma el TMR1 es :  4/Fosc
El tiempo que paso entre ciclos va a depender de cuantos ciclos tomaste, por ejemplo si tomas te un ciclo es directo. Pero si tomaste 2,4 u 8, vas a tener que dividir el resultado por esa cantidad  (Resultado de la resta de TMR1)/4  (por ejemplo con 4 )

De alli es multiplicar para obtener el periodo:

        4/Fosc  * Resta TMR1 / 4  = (Resta TMR1) / Fosc = Tseñal

Si quisiera la frecuencia
     1 / Tseñal = Fosc / (Resta TMR1)

Y lo tenes.

Desconectado echo_ordie

  • PIC10
  • *
  • Mensajes: 3
Re:TMR1 para medir microsegundos
« Respuesta #3 en: 08 de Octubre de 2018, 19:43:38 »
Gracias por la ayuda ,ya tengo el TMR1 funcionando pero creo que aun no comprendo del todo el uso del CCP1.Asi tengo configurado el CCP1 :

Código: [Seleccionar]
void ccp1_config(void){
TRISCbits.RC2 = INPUT;
T3CCP2:T3CCP1 = 01; //TMR1 para CCP1   
CCP1M0 = 0; //Captura flancos de subida
CCP1M1 = 1;
CCP1M2 = 0;
CCP1M3= 1;
CCP1IF = 0 ; //Bandera de Captura CCP1*/
}

Tengo mi rutina de interrupcion asi:

Código: [Seleccionar]
void __interrupt() isr(void){
    //Medir periodo de la señar
    if(CCP1IF){
        count++;
        frec = count;
    }
     }

frec es una variable que uso para imprimir el valor en un LCD. La idea es que cada flanco que reciba el CCP cause  una interrupcion  y asi con un contador yo puedo medir la frecuencias.No tengo el generador de funciones a la mano , pero no estoy seguro de la logica de mi programa

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:TMR1 para medir microsegundos
« Respuesta #4 en: 08 de Octubre de 2018, 23:52:42 »
Necesitas ponerlo como CAPTURE.

El CAPTURE hace que al producirse el flanco ( o 4 flancos ) dispara la interrupcion, y guarda en los registros CCPRxH:CCPRxL el valor del Timer1.

Para configurarlo como capture cambias el registro CCP1CON, para 4 ciclos por ejemplo en caso de que tu frecuencia sea grande. Deberias poner CCP1CON = 0b0110

Y como te escribi antes... La idea es que cuando entre a la interrupcion, guardes en una variable el valor de los CCPRx, y luego en la proxima interrupcion restas el valor de CCPRx con lo que habias guardado. Ese resultado te va a indicar tu frecuencia.

PD: Para configurar los registros usas el nombre del registro, si queres modificar 1 bit, usas el nombre del registro + bits. + nombre del bit. Asi como tenes el TRISC

Desconectado echo_ordie

  • PIC10
  • *
  • Mensajes: 3
Re:TMR1 para medir microsegundos
« Respuesta #5 en: 10 de Octubre de 2018, 16:21:46 »
Gracias de nuevo , estoy teniendo problemas al entrar en la interrupcion del por CCP :

Asi tengo configurado el CCP1 :

Código: [Seleccionar]
void ccp1_config(void){
TRISCbits.RC2 = INPUT;
T3CCP2:T3CCP1 = 01; //TMR1 para CCP1   
CCP1M3:CCP1M0 = 0101;//Captura Flancos de subida
CCP1IF = 1 ; //Bandera de Captura CCP1*/
}

GIE y PEIE estan ambos en 1

Y mi rutina de interrupcion :

Código: [Seleccionar]
void __interrupt() isr(void){
    //Medir periodo de la señar
    if(CCP1IF){
        dato1= CCPR1;
        LED = ~LED;
        CCP1IF = 0;
    }
}

Aun no estoy calculando la frecuencia , quiero saber si efectivamente esta entrando en la rutina de interrupcion . Para eso le estoy diciendo que cambie el estado de un Led cada vez que entra. El TMR1 funciona bien y estoy metiendo una señal cuadrada de 2Hz por CCP1 pero no veo el cambio del Led