Autor Tema: Medida de tiempo entre dos pulsos en diferente pines  (Leído 3675 veces)

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

Desconectado mimecar

  • PIC10
  • *
  • Mensajes: 9
Medida de tiempo entre dos pulsos en diferente pines
« en: 11 de Abril de 2006, 08:56:17 »
Hola a todos.

Tengo dos sensores que me mandan un pulso a nivel alto cuando se activan. Quiero medir el tiempo que pasa entre la activación del primero y la activación del segundo:

Sensor 1:     _____|**********|______

Sensor 2:     ________|**********|______

Uso los dos módulos de captura de un PIC18F4550 (12 MIPS). Los dos módulos están asociados al Timer 3 (16 bits, 1:1). Cuando se activa el primer sensor, leo en la interrupción el valor del CCPR1. Cuando se activa el segundo, leo el valor del CCPR2  y:
- Si el 2º valor es mayor que el primero, el tiempo es la resta
- Si el 2º valor es menor que el primero, el timer se ha desbordado, el tiempo será: 65535-2ºvalor + 1ºvalor
- Mando los valores al PC.

El PC recibe los valores, pero existe mucha variacion entre ellos (por encima y por debajo del valor teorico).

¿Alguna sugerencia?

Gracias por vuestro tiempo.
« Última modificación: 11 de Abril de 2006, 08:58:45 por mimecar »

Desconectado maunix

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 4751
    • Mi Sitio Web Personal
Re: Medida de tiempo entre dos pulsos en diferente pines
« Respuesta #1 en: 11 de Abril de 2006, 10:44:43 »
Hola a todos.

Tengo dos sensores que me mandan un pulso a nivel alto cuando se activan. Quiero medir el tiempo que pasa entre la activación del primero y la activación del segundo:

Sensor 1:     _____|**********|______

Sensor 2:     ________|**********|______

Uso los dos módulos de captura de un PIC18F4550 (12 MIPS). Los dos módulos están asociados al Timer 3 (16 bits, 1:1). Cuando se activa el primer sensor, leo en la interrupción el valor del CCPR1. Cuando se activa el segundo, leo el valor del CCPR2  y:
- Si el 2º valor es mayor que el primero, el tiempo es la resta
- Si el 2º valor es menor que el primero, el timer se ha desbordado, el tiempo será: 65535-2ºvalor + 1ºvalor
- Mando los valores al PC.

El PC recibe los valores, pero existe mucha variacion entre ellos (por encima y por debajo del valor teorico).

¿Alguna sugerencia?

Gracias por vuestro tiempo.


A ver, para alguna sugerencia sería importante un poco mas de informacion.  No es lo mismo medir pulsos de 10useg con separacion de 1 o 2 useg, que medir pulsos de segundos con separacion de segundos también.  Es por esto que te hago las siguientes preguntas:

1. ¿Qué ancho pueden tener los pulsos?
2. ¿Que diferencia puede haber entre pulsos?
3. ¿Con qué frecuencia ocurre el alto y el bajo?
4. ¿El pulso que viene primero, es siempre el mismo?

Saludos


- La soberbia de un Einstein es entendible.. la de un salame es intolerable (A.Dolina)
- En teoría no hay diferencia entre la teoría y la práctica. En la práctica... si la hay.
- Lee, Lee, Lee y luego pregunta.(maunix)
- Las que conducen y arrastran al mundo no son las máquinas, sino las ideas (V. Hugo)
- Todos los hombres se parecen por sus palabras; solamente las obras evidencian que no son iguales.(Moliere)
- Todo debería ser hecho tan simple como sea posible pero no mas simple que eso.(A.Einstein)

Desconectado mimecar

  • PIC10
  • *
  • Mensajes: 9
Re: Medida de tiempo entre dos pulsos en diferente pines
« Respuesta #2 en: 20 de Abril de 2006, 07:28:58 »
Hola maunix

He estado muy liado y no he podido contestar el mensaje.  He conseguido solucionar el problema y se aproxima bastante al valor teórico.

Citar
1. ¿Qué ancho pueden tener los pulsos?
2. ¿Que diferencia puede haber entre pulsos?
3. ¿Con qué frecuencia ocurre el alto y el bajo?
4. ¿El pulso que viene primero, es siempre el mismo?
El sistema tiene que ser independiente del ancho del pulso. Entre los pulsos puede haber una separación entre 10 msec y 1 segundo. El PIC tiene suficiente tiempo para procesar los resultados entre las diferentes activaciones. El orden de los pulsos siempre es el mismo.

Receta:
- Inicializar los 2 módulos de captura para que se activen con un flanco de subida.
- Asociar los módulos de captura a uno de los Timers.
- En las interrupciones, guardar el valor medido cuando se activa el primer módulo de captura y operar cuando se recibe el segundo valor.
- Activar un FLAG para indicar dato procesado.
- En el bucle principal de programa  mirar el FLAG y actuar segun su valor.

De esta forma consigo un error de +/- 2 cuentas en la medida. En algunas ocasiones no coincide exactamente el valor. Puede ser causado por la activación simultanea de la interrupción del timer y la del módulo de captura.

Saludos

Desconectado maunix

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 4751
    • Mi Sitio Web Personal
Re: Medida de tiempo entre dos pulsos en diferente pines
« Respuesta #3 en: 20 de Abril de 2006, 08:12:23 »
Me alegro que lo hayas solucionado ;)


Saludos
- La soberbia de un Einstein es entendible.. la de un salame es intolerable (A.Dolina)
- En teoría no hay diferencia entre la teoría y la práctica. En la práctica... si la hay.
- Lee, Lee, Lee y luego pregunta.(maunix)
- Las que conducen y arrastran al mundo no son las máquinas, sino las ideas (V. Hugo)
- Todos los hombres se parecen por sus palabras; solamente las obras evidencian que no son iguales.(Moliere)
- Todo debería ser hecho tan simple como sea posible pero no mas simple que eso.(A.Einstein)

Desconectado mimecar

  • PIC10
  • *
  • Mensajes: 9
Re: Medida de tiempo entre dos pulsos en diferente pines
« Respuesta #4 en: 20 de Abril de 2006, 10:40:29 »
- Frecuencia de las señales: 1 KHz.
- Tiempo que pasa entre la activacion de los flancos de subida: 66usec (medido)

- Número de cuentas del PIC sin divisor: 66 usec * 12e6 = 792 cuentas
- Número de cuentas medidas por el PIC = 781-783 cuentas

Rutina del módulo de captura 1
   if (PIR1bits.CCP1IF == 1)
   {
      uiCuentaInicial = CCPR1;
      T3Overflow = 0;
      PIR1bits.CCP1IF = 0;
   }
Rutina del módulo de captura 2
   if (PIR2bits.CCP2IF == 1)
   {
      uiCuentaFinal = CCPR2;
      
      if (T3Overflow == 0)
      {
         uiNumeroCuentas = uiCuentaFinal - uiCuentaInicial;
      }
      else
      {
         ulNumeroCuentas = T3Overflow * (65535-1) + uiCuentaFinal + 65535 -  uiCuentaInicial;
      }
      T3Overflow_Latch = T3Overflow;
      FLAG_TX_CUENTA = 1;                  
      PIR2bits.CCP2IF = 0;

   }  // CCP2

Los valores los mando al salir de la interrupción (en el bucle de programa). ¿Cual puede ser la razon para medir menos cuentas que las reales?

Desconectado BrunoF

  • Administrador
  • DsPIC30
  • *******
  • Mensajes: 3865
Re: Medida de tiempo entre dos pulsos en diferente pines
« Respuesta #5 en: 20 de Abril de 2006, 16:14:21 »
Hola. Creo que se debe al tiempo de procesado del programa por parte del PIC, especialmente esta linea:

ulNumeroCuentas = T3Overflow * (65535-1) + uiCuentaFinal + 65535 -  uiCuentaInicial;
Recuerda que al PIC todo le lleva pequeños tiempos, y en aparatos rapidos, estos pequeños tiempos pueden afectar los resultados.
Exitos!
"All of the books in the world contain no more information than is broadcast as video in a single large American city in a single year. Not all bits have equal value."  -- Carl Sagan

Sólo responderé a mensajes personales, por asuntos personales. El resto de las consultas DEBEN ser escritas en el foro público. Gracias.

Desconectado maunix

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 4751
    • Mi Sitio Web Personal
Re: Medida de tiempo entre dos pulsos en diferente pines
« Respuesta #6 en: 20 de Abril de 2006, 20:42:13 »
mimecar creo que el problema que tienes es que se te está desbordando la variable.  Esto suponiendo que tu variable ulNumeroCuentas sea de 16 bits.

A mi modo de verlo, no hay inconvenientes en el tiempo en que demora el cálculo porque tu trabajas con valores 'tomados' por el hardware del PIC (es decir los módulos CCP).  Solo tienes que preocuparte en que los flancos no lleguen muy cerca uno de otro el resto funcionará sin problemas.

Usando un ejemplo extremo, el pic podría estar haciendo cualquier otra cosa, capturarse el 1er valor, luego capturarse el 2do valor (de hecho el pic automáticamente los habrá guardado en CCP1 y CCP2) y si tienes tiempo, hacer el cálculo que pretendes unos segundos despues (obviando el detalle del overflow del timer).

Más allá de eso, creo que el cálculo es inexacto y que se podría simplificar.

1) Porque no usas el evento especial con la interrupción del CCP1 y directamente haces que resetee el timer?  Con esto te alivias de muchos dolores de cabeza!  El flag del CCP1 lo puedes conservar hasta el cálculo en el bucle principal para saber que ese flanco ya lo tienes ;)

2) Sin observar tu bloqeu de programa, creo que no te hace falta usar interrupciones, si tienes tiempo entre flanco porque podrias directamente en el bucle ppal del programa verificar si CCP1IF y CCP2IF estan activadas.

3) Observa el siguiente cálculo. 

 ulNumeroCuentas  = T3Overflow * (65535-1) + uiCuentaFinal + 65535 -  uiCuentaInicial;

En la parte que dice  T3Overflow * (65535-1) , creo que debiera ser T3Overflow*65536
También No se porque sumas de nuevo 65535, si quieres tener en cuenta el overflow por si uiCuentaFinal es menor, ya lo habias hecho antes con el T3Overflow.
Además si T3Overflow esta en 0 o en 1, porque no pruebas el siguiente código.

Código: C
  1. if (T3Overflow)
  2.       {
  3.          uiNumeroCuentas = uiCuentaFinal - uiCuentaInicial;
  4.       }
  5.       else
  6.       {
  7.          ulNumeroCuentas = 65536 + uiCuentaFinal -  uiCuentaInicial;
  8.       }

Teniendo en cuenta que ulNumeroCuentas sea de 32 bits.  De todas formas, fijate que podrias modificar el prescaler en función del ancho de pulsos a sensar. 

Si encima usas la opcion de que el CCP1 resetee el timer, la uiCuentaInicial deja de tener sentido. :)

Espero haber sido esclarecedor.

Saludos
- La soberbia de un Einstein es entendible.. la de un salame es intolerable (A.Dolina)
- En teoría no hay diferencia entre la teoría y la práctica. En la práctica... si la hay.
- Lee, Lee, Lee y luego pregunta.(maunix)
- Las que conducen y arrastran al mundo no son las máquinas, sino las ideas (V. Hugo)
- Todos los hombres se parecen por sus palabras; solamente las obras evidencian que no son iguales.(Moliere)
- Todo debería ser hecho tan simple como sea posible pero no mas simple que eso.(A.Einstein)

Desconectado mimecar

  • PIC10
  • *
  • Mensajes: 9
Re: Medida de tiempo entre dos pulsos en diferente pines
« Respuesta #7 en: 21 de Abril de 2006, 06:25:15 »
Si uso 16 bits, las cuentas van desde 0 hasta 65535. Quiero cambiar el código
Código: [Seleccionar]
uiNumeroCuentas = 65535 - (uiCuentaInicial + uiCuentaFinal);por
Código: [Seleccionar]
uiNumeroCuentas = (1<<16)  - 1 - (uiCuentaInicial + uiCuentaFinal);Pero al PIC no le gusta el desplazamiento de 16 bits. De esa forma genera menos intrucciones, pero no opera como toca.


Citar
Porque no usas el evento especial con la interrupción del CCP1 y directamente haces que resetee el timer?  Con esto te alivias de muchos dolores de cabeza!  El flag del CCP1 lo puedes conservar hasta el cálculo en el bucle principal para saber que ese flanco ya lo tienes
Ya tengo el firmware configurado con 2 módulos de captura y haciendo la resta y no puedo cambiarlo ahora :p


Citar
ulNumeroCuentas  = T3Overflow * (65535-1) + uiCuentaFinal + 65535 -  uiCuentaInicial;
Esa línea es redundante y se podría simplificar:
Código: [Seleccionar]

// Incluimos el numero de 'Overflo' en los calculos
ulNumeroCuentas = 0;
ulNumeroCuentas = (T3Overflow<< 16) + uiNumeroCuentas ;
En T3Overflow tengo el numero de "desbordamientos". Supongamos que tengo 3, (T3Overflow<< 16) lo desplazaria para ocupar los bits superiores al 16 y asi completar la operación. Siempre será menos costoso un desplazamiento que un producto, pero no funciona  :-)

Gracias por las respuestas
« Última modificación: 21 de Abril de 2006, 06:29:38 por mimecar »

Desconectado maunix

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 4751
    • Mi Sitio Web Personal
Re: Medida de tiempo entre dos pulsos en diferente pines
« Respuesta #8 en: 21 de Abril de 2006, 09:38:49 »
Si uso 16 bits, las cuentas van desde 0 hasta 65535. Quiero cambiar el código
Código: [Seleccionar]
uiNumeroCuentas = 65535 - (uiCuentaInicial + uiCuentaFinal);por
Código: [Seleccionar]
uiNumeroCuentas = (1<<16)  - 1 - (uiCuentaInicial + uiCuentaFinal);Pero al PIC no le gusta el desplazamiento de 16 bits. De esa forma genera menos intrucciones, pero no opera como toca.


Claro que no le gusta, si usas una variable de 16 bits para desplazar 16 bits... además carece de sentido.  Sería complicado para el compilador hacer una rotacion de 16 bits cuando el dato que puede manejar un bit son 8 bits a la vez.  Yo que tu veo otra forma de hacer lo mismo, por ejemplo multiplicar por 16.  Si bien a priori es lo mismo (rotar a la izquierda tantas veces como el orden que se quiere multiplicar si este es multiplo de 2) no tiene porque ser lo mismo cuando el operando es mayor que la capacidad de 'bits a la vez' que puede procesar el microprocesador.

Me parece que estas yendo en un camino que se te está cerrando.  Quieres tener la precisión del timer 1:1 y encima hacer todo con un contador de 16 bits, es un planteo que no llevará a nada si quieres medir casi un segundo.  Porque no usas una variable de 32 bits y asunto solucionado.

Porque no usas el evento especial con la interrupción del CCP1 y directamente haces que resetee el timer?  Con esto te alivias de muchos dolores de cabeza!  El flag del CCP1 lo puedes conservar hasta el cálculo en el bucle principal para saber que ese flanco ya lo tienes
Ya tengo el firmware configurado con 2 módulos de captura y haciendo la resta y no puedo cambiarlo ahora :p
Citar
Jeje, pensé que tu mismo lo estabas programado... que problema hay en reprogramarlo ? ;) ;) :lol:



ulNumeroCuentas  = T3Overflow * (65535-1) + uiCuentaFinal + 65535 -  uiCuentaInicial;
Esa línea es redundante y se podría simplificar:
Código: [Seleccionar]

// Incluimos el numero de 'Overflo' en los calculos
ulNumeroCuentas = 0;
ulNumeroCuentas = (T3Overflow<< 16) + uiNumeroCuentas ;
En T3Overflow tengo el numero de "desbordamientos". Supongamos que tengo 3, (T3Overflow<< 16) lo desplazaria para ocupar los bits superiores al 16 y asi completar la operación. Siempre será menos costoso un desplazamiento que un producto, pero no funciona  :-)

Si usas un contador de desbordamientos o de cantidad de veces que el Timer3 tuvo un overflow, porque te la complicas tanto con las multiplicaciones? porque directamente no haces una suma de T3overflow veces de 65536 ?  Esto es mucho mas veloz.
Más alla de eso, fijate que uso 65536 no 65535.  de 0 a 65535 tienes 65536 valores ;) ojo con eso porque si tienes varios overflows ahi tendras tu error.

Saludos


- La soberbia de un Einstein es entendible.. la de un salame es intolerable (A.Dolina)
- En teoría no hay diferencia entre la teoría y la práctica. En la práctica... si la hay.
- Lee, Lee, Lee y luego pregunta.(maunix)
- Las que conducen y arrastran al mundo no son las máquinas, sino las ideas (V. Hugo)
- Todos los hombres se parecen por sus palabras; solamente las obras evidencian que no son iguales.(Moliere)
- Todo debería ser hecho tan simple como sea posible pero no mas simple que eso.(A.Einstein)

Desconectado mimecar

  • PIC10
  • *
  • Mensajes: 9
Re: Medida de tiempo entre dos pulsos en diferente pines
« Respuesta #9 en: 25 de Abril de 2006, 07:19:08 »
Jugando un poco con el código he conseguido reducir el tiempo que está el PIC en la interrupción. La parte critica aparece en este código:
Código: [Seleccionar]
ulNumeroCuentas = (65536 - uiCuentaInicial) + uiCuentaFinal ;
ulNumeroCuentas = ulNumeroCuentas + (T3Overflow-1)*65536;
Esas dos instrucciones hacen que el programa funcione a costa de estar 171 ciclos del PIC (un PIC funcionando a 12 MIPS).

Si en lugar de operar de esa forma trabajo con uniones, el rendimiento mejora radicalmente:
Código: [Seleccionar]
typedef union
{
unsigned char bytes[4];
        unsigned long valor;
} uMedidaCuentas;

aux = uMedida21bits.bytes[2];
uMedida21bits.valor = (65536 - uiCuentaInicial) + uiCuentaFinal;
uMedida21bits.bytes[2] = aux;

EL nuevo tiempo pasa a ser solo de 30 ciclos  :o. Solo un 21% del valor antiguo. Parece que el C18 trabaja mejor si le usas uniones que si trabaja a mas alto nivel.

Una pregunta mas  :-/
Las interrupciones del modulo de captura son seguidas, es decir, primero se activa un sensor y despues el otro.¿Valela pena  salvar los valores al entrar en la interrupcion? Si no los guardo (quedan almacenados en un registro hardware) ahorro 8 ciclos en la interrupcion.

Gracias por la ayuda
« Última modificación: 25 de Abril de 2006, 07:21:22 por mimecar »

Desconectado maunix

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 4751
    • Mi Sitio Web Personal
Re: Medida de tiempo entre dos pulsos en diferente pines
« Respuesta #10 en: 25 de Abril de 2006, 08:35:16 »
EL nuevo tiempo pasa a ser solo de 30 ciclos  :o. Solo un 21% del valor antiguo. Parece que el C18 trabaja mejor si le usas uniones que si trabaja a mas alto nivel.

No es solo el pic o el C18.  Es que que no es lo mismo multiplicar por 65536 que directamente incrementar en 1 el contador del 3er byte!  Si te imaginas el código en ensamblador te sería mas obvio.  Matemáticamente son lo mismo pero en tiempo de operacion no lo son. ;)  .  La rutina esa que hiciste tiene una demora que no es fija, depende del valor del overflow.  A mayor overflow, notarás que la relación de rendimiento del uso de la estructura es mucho mayor!   

Imaginemos el siguiente caso.
Las variables son de 32 bits.  Si b = 3,

Opcion 1:
a = b * 65536 = 196608


Opcion 2:
Si podemos direccionar el 3er byte directamente (seria el subindice 2 empezando de la posicion de memoria donde comienza la variable), como tu haces con la estructura se haria asi
a<2> = 3

Luego la variable total a, valdrá tambien 196608.


Como ves, uno lleva muchos ciclos de multiplicacion , el otro es más lento.  Esto es válido para cuanod usas como en tu caso, multiplos exactos de la base 8, pero si tuvieras que multiplicar por 13, no te servirían las estructuras. 

Siempre hay 'atajos' y 'trucos' para cuando se usa la base 2 o algun multiplo superior de ella.

Una pregunta mas  :-/
Las interrupciones del modulo de captura son seguidas, es decir, primero se activa un sensor y despues el otro.¿Valela pena  salvar los valores al entrar en la interrupcion? Si no los guardo (quedan almacenados en un registro hardware) ahorro 8 ciclos en la interrupcion.

A mi modo de verlo no vale de nada guardarlos en la rutina de interrupción, si estas completamente seguro que tu evento será asi y además que el 1er pulso no volverá a 'volver a comenzar' de inmediato sino que se tomará su tiempo para volver a ocurrir.  Como tu dices pierdes tiempo.  Lo mismo para el cálculo, lo podrias hacer en el bloque principal del programa una vez que hayas marcado que ambas banderas estan en 1.

Ahora bien, como observación prestaa tención que la rutina te funcionará excepto que dé la casualidad de que la cuenta del timer3 esté al borde del desborde!.  En ese caso... cuidado porque le habrás errado por nada mas y nada menos que 65536 valores.

Osea imaginemos que el timer3overflow=3 , y el timer3 está en 65530.  Si ahi capturas el evento, habrás guardado el 65530.  El problema es que unos pocos microsegundos despues el timer3 habra desbordado, mucho antes que tu ingreses al cálculo.  Con eso el timer3overflow será igual a 4, pero con el registro del ccpr2 almacenado como 65530!  Aquí es donde le habras errado por los 65536 valores.

Por eso sugiero que en la rutina de interrupcion si guardes el timer3overflow y luego no seguir incrementandolo mas (o bien guardalo en otra variable que no modifiques más).

Saludos

« Última modificación: 25 de Abril de 2006, 08:39:06 por maunix »
- La soberbia de un Einstein es entendible.. la de un salame es intolerable (A.Dolina)
- En teoría no hay diferencia entre la teoría y la práctica. En la práctica... si la hay.
- Lee, Lee, Lee y luego pregunta.(maunix)
- Las que conducen y arrastran al mundo no son las máquinas, sino las ideas (V. Hugo)
- Todos los hombres se parecen por sus palabras; solamente las obras evidencian que no son iguales.(Moliere)
- Todo debería ser hecho tan simple como sea posible pero no mas simple que eso.(A.Einstein)


 

anything