Frecuenciometro con pic16f874?

Hola que tal, alguien podria ayudarme a entablar mis ideas, estoy tratando de hacer un frecuenciometro con un pic16f874, èste debe contar pulsos digitales externos, estoy usando 2 timers del pic, uno como contador de eventos y el otro como contador de tiempo de muestreo. Mi problema es que al llegar a frecuencias de 600Hz el rango de error es muy alto. El frecuenciometro debe medir un rango de 1 a 600Hz. toda la información capturada en tiempo real la envio al puesrto serial. Saludos
 
Alberth, cuál es la precisión que necesitás en la medición de la frecuencia? Acordate siempre que para medir con una precisión de X Hz necesitás contar ciclos durante 1/X segundos. Por ejemplo, si necesitás un resolución de 0.1Hz vas a tener que contar ciclos de entrada durante 10s.
Por qué decís que el error es muy alto? con qué fijás la frecuencia del PIC, con un cristal?

Con esos datos te voy a poder dar una mejor mano.

Slds...
 
Como usas mcu , en bajas frecuencias te conviene medir periodo y hacer la division.

Ojo, si no sincronizas el contador local con el primer pulso vas a seguir teniendo demasiado error.
 
hOLA gracias por escribir, lo que estoy haciendo es conabilizar pulsos con un TMR1 durante un determinado tiempo (30mseg). El tiempo lo divido entre el numero total de pulsos obtenidos y eso me da el periodo, solo que tengo un error de 2 a 3 Hz.. A q te refieres con sincronizar el contador local con el primer pulso? Saludos
 
Meta dijo:
Si te hace falta 600 Hz. Utiliza un oscilador externo con el 555.
?

600KHz +-3Hz, no esta mal. es un error de apenas 0,0005%!

A q t refieres con demasiado error?

Si te fijas, la tolerancia de un cristal tipico es aproximadamente el mismo error q estas obteniendo: 0,0005%.

Salu2.
 
macraiq, 600Hz, no 600kHz, jejeje. O sea que el error es del 0.5%.

Alberth, qué frecuencia de reloj usás en el PIC? Te aconsejo que lo hagas andar a la mayor frecuencia posible (20MHz) por medio de un cristal.
Por otro lado, si contás pulsos de una señal de 600Hz durante 30ms sólo vas a contar 18 ciclos, lo que te va a dar una precisión de 33.3Hz como máximo, el error debería ser mucho mayor.
Contá pulsos durante 1/precisión en Hz que necesites. Como te dije arriba en otro post, si querés tener una precisión de 1Hz tenés que contar pulsos durante 1 segundo inevitablemente.

La otra es medir período como dice Eduardo, que a bajas frecuencias te va a andar mejor.

Slds...
 
Gracias a todos. SigmaOrion, modifique mi programa a un tiempo de muestreo de 0.5seg lo que me da una resolucion de 2Hz, estoy trabajando con un XT de 4MHz. y efectivamente introdusco 100 Hz de señales digitales y el pic mide de 100 a 101 Hz invariadamente, como puedo hacer para que sea super exacto? Obviamente si quiero mayor presicion debo de aumentar mi tiempo de muestreo: 10 seg. Pero eso ya no seria tiempo real.

Saludos.
 
Tal como lo miro tu problema radica en que necesitas gran precision pero al mismo tiempo necesitas periodos de muestreo cortos. No es asi Alberth?

De entrada se me ocurre que lo que puedes hacer es un pequeño analisis estadistico de las lecturas de frecuencia. La idea seria tomar lecturas de frecuencias individuales a intervalos cortos, pero en vez de descartar cada lectura medida la envias por el puerto, te quedas con digamos, las ultimas 5 lecturas. Asi, la salida del frecuencimetro podria ser el promedio de las 5 ultimas lecturas, lo que te daria gran precision y al mismo tiempo te permitiria agilizar la tasa de actualizacion.

Con tomar varias lecturas y promediarlas estarias elevando indirectamente el tiempo de muestreo, pero al enviar el promedio de las ultimas lecturas a medida que se generan elevas la tasa de actualizacion. Adicionalmente la tecnica estadistica de promediado tiende a elevar la precision al minimizar el error por desviacion de cada lectura. Esta tecnica te funcionaria muy bien siempre y cuando la frecuencia medida sea MUY estable, es decir, que varie muy poco con el tiempo.

Otra tecnica que puedes utilizar es la de medicion del periodo de cada pulso y luego calcular el reciproco. Con esto tendrias lecturas tan rapidas como lo que dura cada ciclo de la señal medida, y si usas una fuente precisa de referencia (como un cristal) puedes tener lecturas bastante aceptables. Lo malo de este metodo es que para altas frecuencias (y con altas me refiero a "comparables a las de tu contador de referencia") el error simplemente se elevaria mucho. Necesitaras un contador de referencia de gran velocidad para compensar, y junto con ello una precision numerica bastante elevada, que podria provocar que el PIC se tome su pequeño tiempo para hacer los calculos de reciproco.

Imagino que con respecto a este ultimo metodo (sugerido por _Eduardo_ por cierto), el mayor problema seria el de "sincronizarte" a la señal de entrada, es decir, iniciar la cuenta de tiempo del periodo tan rapidamente como sea posible en cuanto el flanco inicial se presente. Usualmente los microcontroladores tienen un tiempo de retardo para reaccionar a eventos externos (una interrupcion por ejemplo), pero esa problematica puede arreglarse con un pequeño truco:

Digamos que al generarse el flanco se interrumpe el MCU, digamos ademas que el MCU tarda 20 clocks (por inventarme un numero) desde que se genera la interrupcion hasta que el mismo hecha a andar el contador. Esto te pondria en plena desventaja, puesto que has perdido parte del periodo de la señal al iniciar la lectura y naturalmente te generara un error sustancial. Que hacer? La solucion es simple: La siguiente interrupcion determinara que el ciclo de la señal se ha terminado, por lo que simplemente se vuelve a interrumpir al MCU y hace un proceso similar con la leve diferencia que ahora detiene el contador en vez de iniciarlo... pero para ajustar las cosas, deliberadamente provocamos que se tarde EXACTAMENTE la misma cantidad de tiempo que al principio (es decir, los 20 clocks). Lo que ocurriria es mas o menos algo asi:

Señal -----|Inicio----------------------------------------------|Fin--------------------------
MCU ----------|Contador arranca-------------------------------|Contador para-----

Espero que el diagrama simplificado no se deforme con tu fuente. La idea basica es que aunque el MCU se atrasa, el periodo medido es siempre el mismo, porque se atrasa la misma cantidad de tiempo con cada interrupcion.

Yo use este metodo alguna vez cuando hice un proyecto muy similar al tuyo, y debo agregar que produjo una precision impresionante (+/- 1 LSB de 4 digitos que habia disponibles). Sin embargo usaba la tecnica de medidion de pulsos a un intervalo fijo, pero el concepto es el mismo.

En cuanto al "baile" de +/- un conteo en las lecturas sucesivas, creo que se puede hacer algo al respecto. Pero primero que nada, a que se debe? Bueno, ese mas o menos 1 con cada lectura se origina precisamente porque cuando se interrumpe la "medicion" para enviar el dato, inevitablemente parte del ciclo en curso de la señal de entrada queda inconcluso, y cuando se inicia la lectura nuevamente, el resto del ciclo inconcluso se mete a la siguiente medicion y agrega uno mas a la cuenta cuando no ha ocurrido en su totalidad desde el inicio de la medicon... digamos que es una especie de residuo (o puedes verlo tambien como un corrimiento de fase entre tu periodo de medicion y la señal de entrada al no ser de frecuencias con multiplos exactos). Lo mismo podria ocurrir en un siguiente ciclo de medicion pero en sentido inverso, con lo que ahora perderiamos una cuenta de la señal de entrada.

Se puede solventar? Claro que si: Eliminando los "residuos variables" por medio de esperar a que ocurra el siguiente flanco de la señal de entrada (positivo o negativo, no importa), y a continuacion echa a andar el contador. Uno pensaria que eso podria agregar cierto error en la lectura ya que el MCU tiene que responder a un evento externo... pero en realidad, eso no importa, ya que aunque existe retardo, el corrimiento de fase sera constante asi como el periodo de medicion, y tus lecturas seran casi tan estables como la frecuencia de entrada.

Eso seria todo, espero mis comentarios te sean utiles ^_^
Suerte con tu proyecto.
 
Tenes que iniciar el intervalo de conteo junto con el flanco ascendente (o descendente) de la señal, si no siempre vas a tener una incertidumbre de una cuenta (como ya dijo f_point).
Eso vale tanto para la medicion de frecuencia clasica (intervalo de conteo fijo) como para la de periodo clasica (intervalo de conteo variable)

Con PIC, podes usar TMR0 para conteo y TMR1 para medir el intervalo.

* La sincronizacion de inicio la haces cargando TMR0 con FF, cuando llegue el primer pulso pasa a 00 y te genera una interrupcion -> ahi reseteas TMR1.

* A TMR1 lo tenes programado con el valor de prescaler apropiado de manera que te de Overflow en un tiempo razonable (por ejemplo entre 100ms y 500ms) , ahi te va a generar otra interrupcion.

* Generada la interrupcion, lees la cuenta de TMR0 (nro de pulsos que han entrado) y le escribis FF, de manera que ahora se produzca otra interrupcion en el siguiente pulso.

* En esta interrupcion final, lees la cuenta de TMR1 y todo lo que queda es hacer la cuenta:
Frec = k*(nTMR0+1)/(nTMR1+65536) (con los recaudos numericos apropiados)
Tambien, si el valor va a ser leido por una PC, puedo mandar solamente el valor de los contadores (8+16 bits en total) y que la division se haga afuera.


Comentarios.

* Fijate que la secuencia puede modificarse para que sea un bucle continuo sin necesidad de cargar dos veces FF en TMR0.

* Hay que tomar precauciones de soft para el caso frecuencias estremadamente bajas o cero (continua) porque si no te vas a morir esperando un flanco ascendente.

* En el codigo hay que tratar que los retardos del PIC entre el evento y la lectura de los contadores sean lo mas iguales (o bajos) posibles para disminuir el error.
En caso de necesitar mas precision se puede agregar algunas compuertas y dos flipflop D para habilitar/inhibir los contadores (TMR1 pasa a contar de un reloj externo).

* Este metodo tambien sirve en frecuencias altas, con la salvedad que como TMR0 (8 bits) dara overflow a cada rato, hay que ir incrementando por soft un registro y refinar el manejo de la interrupcion.
 
Hola

El medir el periodo para saber la frecuencia, teoricamente esta muy bien.
Con el micro es muy facil medir ese tiempo, pero para proceder a calcular la frecuencia (F=1/p), lo veo algo complejo. ¿se puede realizar con el microcontrolador? ¿o bien necesitamos un procesador matematico?
 
Leyendo el enlace q te di, se me ocurrio una idea... Para aumentar la precision, lo que necesitas es una senal de mayor frecuencia... Entonces, en lugar de usar el micro como timer durante el cual cuentas los pulsos de la senal, que sea alrevez.

En otras palabras, generas una senal de alta frecuencia con el micro, y cuentas cuantos pulsos de esta senal pasan durante un pulso de la otra senal, la senal de interes.

Salu2.
 
Edité porque en el tiempo en que escribí esto postearon macraiq y pepechip, así que dejo el post original y abajo agrego algo:

******

Alberth, no estoy seguro de que la pregunta sea para mi, si no lo era pido disculpas. Creo que el único que habló de 33.3Hz fui yo en algún momento, así que contesto.

Pongamos un ejemplo:
Tu frecuencia de entrada es de 200Hz entonces vos contás pulsos durante 30ms. Al cabo de 30ms contaste 200Hz*30ms = 6 pulsos, cuando hacés la cuenta f=6/30ms=200Hz. En este caso particular el error de la medición es nulo.
Ahora tu frecuencia es de 210Hz, al cabo de 30ms contaste 210*30ms = 6.3 pulsos? no, sólo vas a contar números enteros de pulsos, así que vas a haber contado 6 pulsos. Al hacer la cuenta obtenés f=6/30ms=200Hz!
Tu circuito va a dar otro valor cuando f=233.333Hz, justo cuando tu contador cuente 7 pulsos. Entonces tu frecuencímetro va a medir de a saltos de 33.333Hz. La razón es el período de medición de 30ms. Al aumentarlo a 500ms obtuviste una resolución de 2Hz, lo cual es correcto.
Hablando rigurosamente lo que va a suceder es que tu lectura va a cambiar de 200Hz a 233.33Hz aleatoriamente. Para solucionar esto podés usar la los promedios móviles que planteó f_point y te va a andar muy bien.
Si usás los promedios la resolución que vas a lograr será 1/(CANTIDAD DE PROMEDIOS*tiempo de cuenta de ciclos). Por ejemplo, si usás 100ms para obtener 10 lecturas por segundos y mostrás el promedio de las últimas 20 lecturas entonces tu resolución será de 1/(20*100ms)=0.5Hz!
Si seguís todo lo que dijo f_point, con quien concuerdo 100%, hizo un muy buen post, creo que vas a obtener buenos resultados. Si tenés dudas para la implementación preguntá nomás!

Slds...

Mariano

*********

Agregados:
Para hacer la cuenta f=1/p lleva lo suyo pero no es imposible. Microchip tiene montones de notas de aplicación y estoy seguro de haber visto alguna en la que se hacía eso. Es más, hay una rutina para calcular FFT con un 16Fxxx!
macraiq, me equivoco o lo que estás planteando termina siendo lo mismo que la técnica de medir el período de la señal? al fin y al cabo es un contador que cuenta rápido durante un período de la otra.

Y con esto se me ocurre algo más, se podría usar una técnica híbrida (mucho nombre para poca cosa, je). Qué pasa si medimos un múltiplo del período de la señal de entrada? con esto aumentamos la precisión en altas frecuencias a expensas de alargar un poco el período de lectura, pero si lo hacemos adaptivo podemos medir, por ejemplo, 1 período para frecuencias de menos de 50Hz, 5 períodos para frecuencias de menos de 500Hz y 10 períodos para frecuencias de menos de 1kHz.
Por ahí me fui por las ramas, pero bueno... es posible hacerlo, habría que evaluarlo matemáticamente para ver los beneficios/perjuicios.

Saludos a todos.

Mariano
 
pepechip dijo:
Hola

El medir el periodo para saber la frecuencia, teoricamente esta muy bien.
Con el micro es muy facil medir ese tiempo, pero para proceder a calcular la frecuencia (F=1/p), lo veo algo complejo. ¿se puede realizar con el microcontrolador? ¿o bien necesitamos un procesador matematico?

Se puede, ventajas de C.

Tambien en assembler, pero debes buscar librerias para el calculo numerico. (Implementarlas por tu cuenta te llevaria tiempo)

Salu2
 
En efecto un compilador de C para PIC puede ayudar a resolver los calculos de reciproco, ya que los mismos generan el codigo para esas operaciones automaticamente. Muy buena la observacion de macraig. Alternativamente puedes enviar los datos en bruto a la PC (es decir, sin procesar) y aprovechar la capacidad de computo de la PC para hacer tus calculos, tal como _Eduardo_ lo menciono.

Ambas alternativas son igualmente utiles, anque el metodo de calculo en PC seria el mas facil de implementar (el codigo del MCU se simplifica) y tambien el mas eficiente en cuanto a velocidad de computo.

En muchos microcontroladores de la serie PIC16 cuentas con 2 o 3 Timers. Mas especificamente en el PIC16F874 cuentas con Timer0, Timer1 y Timer2. Cada uno posee sus capacidades especiales y se emplea mejor en algunos casos:

Timer0 - Es un contador basico de 8 bits, permite generar interrupciones a intervalos especificos y puede servir como base de tiempo constante para periodos de medicion definidos. Tambien puede contar eventos externos pero su limite de frecuencia depende de tu cristal porque posee una etapa de sincronizacion de señal. Su mayor desventaja radica en que no se puede programar su periodo de forma arbitraria (interrumpe unicamente cuando ocurre sobreflujo) y lo unico que hay a la mano para controlar su periodo es el mismo prescaler del WDT, que solo permite ser ajustado en potencias de 2.

Timer1 - Se trata de un contador de 16 bits, el cual puede ser operado en modo sincrono o asincrono. El modo asincrono es perfecto para contar eventos externos (en este caso los ciclos de la señal medida) y permite frecuencias de entrada tan altas como 10MHz y quiza aun mas. Su unica desventaja radica en que es dificil leer sus dos bytes y obtener lecturas validas mientras este corre, pero eso se puede solvertar facilmente si apagagamos el contador (para que deje de contar) y luego leemos el dato. La precision amplificadorada de 16 bits es definitivamente una ventaja que no hay que pasar por alto.

Timer2 - Es un muy amigable contador de 8 bits. Similar a Timer0, con la excepcion que no puede contar eventos externos de forma sincrona, ya que su unica fuente de entrada es el oscilador primario. Personalmente, opino que es PERFECTO para generar bases de tiempo extremadamente estables (tan estables como el cristal del oscilador primario) y su capacidad de definir periodos arbitrarios es simplemente admirable. Quieres contar exactamente 1000 ciclos con el y no 1024 como con Timer0? No hay problema: Pones PR2 = 249 (para 250 conteos) y el prescaler a 4, con lo que obtienes 250*4 = 1000 ciclos. Con cristal de 4MHz, obtienes un periodo de exactamente 1ms en este ejemplo, y como la interrupcion es un evento interno (y sincrono) la latencia de interrupcion es exactamente 4 ciclos todas las veces.

Ahora, las combinaciones de timers a usar bien puede ser:
- Para metodo de medicion de pulsos a intervalos definidos: Timer1 como contador de señal externa, Timer2 como generador de periodo de medicion.
- Para metodo de medicion de duracion de periodo (reciproco: F = 1/T): Timer1 como contador de tiempo elapsado (aprovechando la resolucion de 16 bits y usando el oscilador interno) y una interrupcion externa (RB0/INT) para detectar los flancos de la señal.

Podrias reemplazar Timer2 por Timer0 en el primer metodo, pero entonces tus opciones de eleccion de periodo se reducen (al elegir tus periodos arbitrariamente puedes jugar con los numeros para acomodar tus calculos). Asimismo, podrias reemplazar Timer1 por Timer0 en el segundo metodo, pero entonces pierdes resolucion y corres mayor riesgo de sobreflujo para señales de baja frecuencia.

Espero que la breve descripcion te ayude a elegir parametros de diseño.
Buena suerte Alberth.
 
es mejor utilizar el PIC16F884,PIC16F886 ó PIC16f887 ya que es mas economico trae oscilador interno y demas mejoras a un precio menor al PIC16F87X...

muy buena explicacion de los timers...
 
Hola buen día.. es la primera vez que utilizo este foro así que disculpen si posteé mal jeje...
en fin....
veo que están tratando con el TMR1 y pues entra en una duda que tengo....
actualmente estoy utilizando el TMR1 para medir frecuencias con el desbordamiento del TMR0....
sin embargo quería optimizar el tiempo de medicion de las frecuencias haciendo más rápido el desbordamiento de mi TMR0 y del mismo modo implementando un Xtal de 16 MHZ... pero pues entro en la duda de cuanto tiempo necesita el TMR1 para poder obtener un dato estable que sea un valor real y pues ya he revisado la literatura ( datashets y hojas de aplicación)
y no comentan nada sobre el tiempo que le toma al TMR1 estabilizarse con un dato real...

espero me puedan ayudar
saludos
 
Atrás
Arriba