Input capture with dedicated timer

Hola a todos,

Estoy intentando implementar la lectura de un anemómetro con un pic24fj64gb0002.

El anemómetro funciona con un reed switch. Funciona a través de un campo magnético de manera que cada vuelta cierra el switch 2 veces (equivale a enviar dos pulsos). El anemómetro tiene dos salidas. Una se conecta a tierra y la otra se conecta al pin del pic a la vez que a la tensión (a través de una resistencia).

En definitiva, la teoría es que normalmente en el pin del pic hay Vdd excepto cuando se cierra el switch que lo lleva a 0. El resultado es que a la entrada del pic hay un tren de pulsos a una frecuencia proporcional a la velocidad del viento (la relación la indica el fabricante del anemómetro).

Mi idea era realizar la medida utilizando el módulo input capture con timer dedicado.

El problema que me encuentro es que cuando conecto el anemómetro al pic, aunque el switch esté abierto, este me lleva la señal a 0 (sin conectar al pic en el extremo de la salida del anemómetro tengo Vdd, una vez lo conecto me baja a 0).

Imagino que no tendré bien configurado el puerto, pero me lo he estado mirando y no encuentro la razón.

Utilizo el pin RB3, he puesto todo el puerto digital (AD1PCFG = 0xffff), el trisb3 a '1' (salida) y por si a caso (aunque creo que no hace falta al tratarse de una salida) el _CN3PUE a '0' (pull-up interno desconectado) y el _ODB3 a '0' (salida no open drain).

Las parlabras de config

Código:
_CONFIG1 (JTAGEN_OFF & FWDTEN_OFF);                     //Mòdul JTAG deshabilitat (RB5-RB9 i/o digitals) i WDT desactivat
_CONFIG2 (POSCMOD_NONE & OSCIOFNC_ON & FNOSC_FRC);      //Oscil·lador primari desactivat, RA3 i/o digital, Oscil·lador FRC seleccionat (8MHz)
_CONFIG3 (SOSCSEL_IO);                                  //RA4 i RB4 i/o digitals
_CONFIG4 (RTCOSC_LPRC);                                 //Es selecciona el LPRC intern com a rellotge de referència del mòdul RTCC


El codigo de config:
Código:
  AD1PCFG = 0xffff;                           // Tots els ports digitals
    CNEN1 = 0x0000;                             // Totes les interrupcions per CN deshabilitades
    CNEN2 = 0x0000;
    _TRISB3 = 1;                                // RP3 (RB0) entrada
  
    _CN3PUE = 0;                                // Desactiva pull-up interna
    CNPU1 =0x0000;
    CNPU2 = 0x0000;

y la assignación del pin al módulo input capture 1
Código:
// Configurar Input Capture IC1

    __builtin_write_OSCCONL(OSCCON & 0xbf);     // Macro que realitza seqüencia de desbloquejament per assignació de RPn
    RPINR7 = 0x0003;                            // IC1 associat al port RP3 (RB3)
    __builtin_write_OSCCONL(OSCCON | 0x40);     // Macro que realitza seqüencia de bloquejament per assignació de RPn

    IC1CON1 = 0X1002;                           // Selecciona TIMER1, interrupció per cada event amb event a cada flanc descendent
    IC1CON2 = 0X0000;                           // No sincronitzat amb cap altre mòdul

// Configurar Timer1

    T1CON = 0x0010;                             // Timer en preescaler 1:1 (a 8MHz incrementa cada 0,25us)
    PR1 = 0xffff;
    _TON = 1;                                   // Activa timer1
    _IC1IF = 0;
    _IC1IE = 1;


No se, me lo estoy mirando pero no veo lo que no hago bien :confused:

Alguien sabe donde fallo?

Gracias
 
Hola, imagino que te refieres al esquema de la conexiones no?

Adjunto un croquis. El Reed Switch es el anemòmetro. Está normalmente abierto.

Sip.

. . . El problema que me encuentro es que cuando conecto el anemómetro al pic, aunque el switch esté abierto, este me lleva la señal a 0 (sin conectar al pic en el extremo de la salida del anemómetro tengo Vdd, una vez lo conecto me baja a 0). . . .

¿ Tomaste una medida de tensión en RB3 para comprobar que el Reed Switch funciona correctamente ?
 
Sip.



¿ Tomaste una medida de tensión en RB3 para comprobar que el Reed Switch funciona correctamente ?

En principio funciona bien. Sin conectarlo al pic (el esquema anterior tal qual pero sin la conexiona a RB3) funciona. Según la información de donde lo he comprado el reed switch es normalmente abierto pero no lo tengo muy claro, ya que su comportamiento me hace pensar que es lo contrario. Hago girar el anemómetro y cada "click" que se oye pone el extremo a Vdd, mientras que el resto de tiempo se mantiene a '0'.

Aunque fuera así no entiendo que si dejo el anemómetro en una posición para que en el extremo haya Vdd porqué al conectarlo al pic me lo lleva a '0', es como si el pin hiciera de tierra:confused:
 
Si al no tener el PIC conectado consigues los pulsos casi con seguridad tienes configurado el puerto RB3 como salida.
 
Si al no tener el PIC conectado consigues los pulsos casi con seguridad tienes configurado el puerto RB3 como salida.

(y)

Gracias, tu comentario me ha hecho ver la luz!!!!

Iba a decir que no podia ser ya que al principio ponía _TRISB3=1 (salida), pero entonces me he dado cuenta que tenía incluido en el programa una librería .h para manejar el LCD, y dentro de esta ponía todo el puerto B como salida :facepalm:

Ya lo he modificado y funciona.

Muchas gracias!!!!
 
Hola de nuevo.

Solucionado el tema de la entrada tengo una duda.

La idea es mediante el módulo input capture obtener la frecuencia de los pulsos del reed switch del anemómetro. Esto lo he hecho configurando el módulo para que me capturara los tiempos del 16 pulso ascendente y generando interrupción cada dos eventos. De esta manera restando un tiempo del otro obtengo el período de la señal y ahí la velocidad del viento.

El problema que me encuentro es que la velocidad obtenida no me cuadra demasiado. Haciendo rodar el anemómetro (conectado a un led) veo que me da contacto dos veces cada vuelta (el led se enciende dos veces). De ahí, considerando que capturo cada 16 eventos se debería deducir que el anemómetro ha dado 8 vueltas.

Como no me cuadraba demasiado he hecho una rutina sencilla que simplemente aumenta uj contador cada vez que entra en la rutina de interrupción del módulo input capture, cambiando la configuración de manera que me capture todos los flancos de subida, con interrupción a cada evento.

Teóricamente el contador debería aumentar cada vuelta dos veces pero no es así, me aumenta a veces seis, a veces 5, 4. Normalmente 6 o 5.

Puede ser que el el reed switch entre cerrar y abrir produzca ruido y eso genere más capturas de eventos? No se si los reed switch generan tal ruido o no. He probado de poner un retardo pero me siguen saliendo 4 capturas por vuelta (deberían ser 2 a mi entender). He aumentado el retardo pero aún con 100ms (que es mucho a mi entender) me siguen saliendo 4 capturas por vuelta.

Si no es eso no se que puede ser...

Código:
#include <p24FJ64GB002.h>
#include <stdio.h>
#include <stdlib.h>

#define FCY 4000000UL               // Definir FCY (meitat de freqüencia del rellotge (necessari per utilizar llibreria libpic per delays)
#include <libpic30.h>               // Llibreria amb funcions de retard
//#include "1wire_protocol.c"         // Funcions de comuniciació amb protocol 1wire (pel ds18b20)
#include "lcd_control.c"            // Funcions control LCD

/////// Paraules de configuració/////////

_CONFIG1 (JTAGEN_OFF & FWDTEN_OFF);                     //Mòdul JTAG deshabilitat (RB5-RB9 i/o digitals) i WDT desactivat
_CONFIG2 (POSCMOD_NONE & OSCIOFNC_ON & FNOSC_FRC);      //Oscil·lador primari desactivat, RA3 i/o digital, Oscil·lador FRC seleccionat (8MHz)
_CONFIG3 (SOSCSEL_IO);                                  //RA4 i RB4 i/o digitals
_CONFIG4 (RTCOSC_LPRC);                                 //Es selecciona el LPRC intern com a rellotge de referència del mòdul RTCC


/*
 * 
 */

float periode=0;
unsigned int t0, dt, t, i=0, contador;
unsigned int buf[4];

void _ISR _IC1Interrupt(void){

    contador++;
    __delay_ms(100);
    t0 = IC1BUF;
    t = IC1BUF;
    dt = (t-t0);
    periode = dt*0.000064;
    //_LATA1 = ~_LATA1;
    //t0 = IC1BUF;
    //t0 = IC1BUF;*/
    _IC1IF = 0;


}

main (){

// Declaració variables

    float velocitat;

// Inicialització pins

   // _PMPEN = 0;
    AD1PCFG = 0xffff;                           // Tots els ports digitals
    CNEN1 = 0x0000;                             // Totes les interrupcions per CN deshabilitades
    CNEN2 = 0x0000;
    _TRISB3 = 1;                                // RP3 (RB0) entrada
  
    _CN3PUE = 0;                                // Desactiva pull-up interna
    CNPU1 =0x0000;
    CNPU2 = 0x0000;


    ini_LCD_4bits();            //Inicialitza LCD en mode 4 bits
    __delay_ms(1000);           //Espera 1 minut


// Configurar Input Capture IC1

    __builtin_write_OSCCONL(OSCCON & 0xbf);     // Macro que realitza seqüencia de desbloquejament per assignació de RPn
    RPINR7 = 0x0003;                            // IC1 associat al port RP3 (RB3)
    __builtin_write_OSCCONL(OSCCON | 0x40);     // Macro que realitza seqüencia de bloquejament per assignació de RPn

    //IC1CON1 = 0x1025;                           // Selecciona TIMER1, interrupció per cada 2 events amb event a cada flanc descendent
    IC1CON1 = 0x1003;
    IC1CON2 = 0x0000;                           // No sincronitzat amb cap altre mòdul

// Configurar Timer1

    T1CON = 0x0030;                             // Timer en preescaler 1:256 (a 8MHz incrementa cada 64us)
    PR1 = 0xffff;
    _TON = 1;                                   // Activa timer1
    _IC1IF = 0;
    _IC1IE = 1;

_TRISB3 = 1;

    while (1){

        if (periode == 0)
            velocitat = 0;
        else
            velocitat = (8*0.67)/periode;
        sprintf (buf, "%.4f m/s", velocitat); //la temperatura
        escriure_txt(buf);//
        __delay_ms(500);
        sprintf (buf, "%d", contador); //la temperatura
        escriure_txt(buf);//
        __delay_ms(1000);
        escriure_cmd (0x01);                    //Borrar LCD
        escriure_cmd(0x02);                     //Cursor a l'inici


    }



}

Gracias
 
desconozco el funcionamiento del microcontrolador que estás empleando, pero tengo muy claro que dentro de una interrupción no se emplea delay... no se hacen operaciones matemáticas complejas, hay que minimizar el tiempo de permanencia DENTRO de la interrupción, a lo sumo incrementar un contador o un par de igualdades y listo.
 
desconozco el funcionamiento del microcontrolador que estás empleando, pero tengo muy claro que dentro de una interrupción no se emplea delay... no se hacen operaciones matemáticas complejas, hay que minimizar el tiempo de permanencia DENTRO de la interrupción, a lo sumo incrementar un contador o un par de igualdades y listo.

Hola, me parece muy interesante tu observación.

Mi idea era realizar la rutina de servicio a la interrupción sin el delay. Consideraba que el resto de código era suficientemente corto como parar ser aceptable, pero ya miraré si puedo hacerlo de otra manera y reducirlo.

El delay lo puse porque veía que me entraban muchas más interrupciones de lo que se suponía, por lo que por probar puse el delay para evitar el ruido.

Sino como lo harías para evitar el ruido o rebotes? Deshabilitando la interrupción fuera de la ISR y volviendola a habilitar? No lo acabo de ver :unsure:

Grácias



El problema de realizarlo fuera de la ISR es que entonces una interrupción de más bajo nivel podría pasar a ser más prioritaria que esa... a no ser que a la vez también las inhabilitara... no se :confused:
 
Última edición:
Hola de nuevo,

En principio ya he solucionado el problema del ruido.

He conectado un condensador de 100nF a Vcc (a parte de la resistencia) y parece que funciona (tengo pendiente acabar de realizar pruebas pero en principio parece que el condensador filtra los rebotes).

Muchas gracias.

P.D.: Evidentemente he eliminado el delay de la ISR
 
Hola

Estoy trabajando con el modulo input capture del pic24fj64gb002

Quiero medir una freqüencia en el pin RA0 (RP6).

Lo he configurado con interrupción en cada segunda captura y con captura cada 16 flancos de subida.

Lo curioso es que aunque cambie el preescaler del modulo (a 4 flancos de subida o a cada flanco de bajada) la diferencia entre las capturas siempre es la misma. No entiendo que pasa. Teóricamente al cambiar el preescaler las capturas deberían cambiar.

No se que hago mal. Si alguien puede echarme una mano me iria perfecto.

Adjunto el código

Código:
#include <p24FJ64GB002.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
//#include <timer.h>
//#include <PPS.h>

#define FCY 4000000UL               // Definir FCY (meitat de freqüencia del rellotge (necessari per utilizar llibreria libpic per delays
#include <libpic30.h>               // Llibreria amb funcions de retard
#include "lcd_control.c"            // Funcions control LCD

_CONFIG1 (JTAGEN_OFF & FWDTEN_OFF);                     //Mòdul JTAG deshabilitat (RB5-RB9 i/o digitals) i WDT desactivat

_CONFIG3 (SOSCSEL_IO);                                  //RA4 i RB4 i/o digitals
_CONFIG4 (RTCOSC_LPRC);                                 //Es selecciona el LPRC intern com a rellotge de referència del mòdul RTCC
_CONFIG2 (POSCMOD_NONE & OSCIOFNC_ON & FNOSC_FRC);
/*
 *
 */






unsigned int t0, dt, t, x;
float freq, irrad;
char buf[10];
unsigned int periode, periode16;
unsigned long  y;
unsigned char j;
float pf, tf, t0f;

void _ISR _IC1Interrupt(void)
{

    t0 = IC1BUF;
    t = IC1BUF;

    _IC1IF = 0;
}




int main(void) {


    unsigned char insolacio;
    float valors[8];

 // Inicialització pins

    AD1PCFG = 0xffff;       // Tots els ports digitals
    CNEN1 = 0x0000;         // Totes les interrupcions per CN deshabilitades
    CNEN2 = 0x0000;
    _TRISA1 = 1;            // RP3 (RB3) entrada
    _ODA1 = 0;              // RP3 Entrada digital (no open drain)

// Configurar Input Capture IC1

  __builtin_write_OSCCONL(OSCCON & 0xbf);     // Macro que realitza seqüencia de desbloquejament per assignació de RPn
   RPINR7 = 0x0006;                            // IC1 associat al port RP3 (RB3)
  __builtin_write_OSCCONL(OSCCON | 0x40);     // Macro que realitza seqüencia de bloquejament per assignació de RPn


    IC1CON1 = 0x0000;
    IC1CON1 = 0x1022;                           // Selecciona TIMER1, interrupció per cada 2 event amb event a cada 16è flanc ascendent
    IC1CON2 = 0x0000;                           // No sincronitzat amb cap altre mòdul

// Inicialitzar LCD en mode 4 bits


    ini_LCD_4bits();
    __delay_ms(1000);

// Configurar Timer1

    TMR1 = 0;
    T1CONbits.TON = 0;
    T1CONbits.TCS = 0; // Set Timer freq = Fcy/2
    T1CONbits.TCKPS= 0; // prescale 1:1
    T1CONbits.TGATE = 0; 
    T1CONbits.TSIDL = 0;
    T1CONbits.TON = 1;  //Timer 1 Enable


   _TRISA1 = 1;
   _IC1IE = 1;

  

   while (1){


            periode = t-t0;
     
            freq = (4000000*16)/((float)periode*1000);          //Frequencia en kHz

            tf = (float)t;
            t0f = (float)t0;




    
       escriure_cmd (0x01);                    //Borrar LCD
      escriure_cmd(0x02);                     //Cursor a l'inici
       
      escriure_txt ("Freq:");        //Mostrar per LCD
      sprintf (buf, "%.4f", freq);
     escriure_txt(buf);                     //
       
        __delay_ms(2000);
  

        if (IC1CON1bits.ICOV == 1)
        {
            IC1CON1bits.ICM = 0;
            IC1CON1bits.ICM = 5;
            x = IC1BUF;
            x = IC1BUF;
            x = IC1BUF;
            x = IC1BUF;
            
              escriure_cmd (0x01);                    //Borrar LCD
      escriure_cmd(0x02);                     //Cursor a l'inici
      escriure_txt("Hola");
       __delay_ms(2000);

        }

   
    }

}

En la interrupción cojo los dos valores capturasdos en t y t0. Pues aunque cambie el preescaler del mòdulo al restarlo siempre da la misma diferencia.

No se porque

Gracias
 
Atrás
Arriba