Frecuencímetro con Arduino de 1Hz a 3Khz

Aquí os dejo un programa que hace del arduino un frecuencímetro de 1Hz a 3Khz.

Con este programa se puede hacer también un detector de tono, un tacómetro óptico, cuenta revoluciones y lo que la imaginación os de.

Puede trabajar con tensiones analógicas o digitales. Con señales analógicas puede trabajar con tensiones de entrada alterna de entre 0,0097v a 2,5v o digitales de entre 0v a 5v.

Tiene un filtro que discrimina las amplitudes de señal menores, esto sirve para evitar que el frecuencímetro detecte frecuencias de fondo, producidas por ejemplo en proyectos donde hay ruido eléctrico, como por ejemplo, sistemas en los que se empleen motores, que generan ruido eléctrico. También es útil para detectar tonos en señales de audio, en las que estén presentes otros sonidos de fondo, siempre de menos amplitud que el tono a detectar.

Saludos.

/*
FRECUENCIMETRO

  Este frecuencímetro puede leer frecuencias de 1Hz a 3Khz.
  
  El error puede rondar el +/- 1Hz.

  Muestra las lecturas a través del puerto serie a intervalos de 1 segundo.
  
  Este frecuencímetro dispone de un ajuste automático de ganancia, que le permite ajustarse a la mayor señal y eliminar así, lecturas correspondientes a ruidos de fondo de algún tipo.

PLATAFORMA

 Este programa a sido probado en un arduino duemilanove y a sido comprobado su correcto funcionamiento.

CONEXIONADO

  El pin analógico CERO, es el pin de entrada de frecuencias. 
  
Si se quieren medir corrientes alternas, será necesario poner dos resistencias de entorno a 1000 ohmios en serie y conectar un extremo de las resistencias en serie a masa y el otro extremo al polo positivo. De entre las dos resistencias puestas en serie, se conectaría al pin cero analógico y del pin cero analógico sacaríamos un terminal, que sería por el que entraría la señal a medir. Las resistencias se conectan de este modo para hacer un divisor de tensión, que haga que la entrada analógica del arduino esté a un voltaje intermedio entre masa y el positivo. También se podría poner en serie un condensador entre el pin cero analógico y el terminal por el que va a entrar la señal alterna, para separar el arduino de las corrientes continuas.

NOTA IMPORTANTE:

  La entrada analógica solo puede entrar una señal de como mucho 5v, de lo contrario, podríamos romper el arduino. Se podría poner un diodo zener de algo menos de 5v, para cortocircuitar los picos te tensión superiores a 5V, entre el terminal cero analógico y masa.

AUTOR: Mario R.P - mariorp@terra.es - 13-6-2012

*/

long rango=2; // este es el rongo por el que se disparará la salida 2 y pasa a estado lógico 1
long ultimamedicion; // contiene el valor de la última medición que disparó a lógico 1, la salida 2
int ciclo=0; // 1=alto 0=bajo
int cambiodeciclo=0;
int picodetension;
int valledetension=1023;
long contadorvisualizacion;
long contadorciclo;

void setup() {

  Serial.begin(9600);
  pinMode(A0, INPUT); // Se establece el pin analógico 0 como pin de lectura de datos.
}

void loop() {
  
  long sensorValue = analogRead(A0); // Se vuelca a la varibla sensorValue el valor de la tensión medida por el pin 0 analógico
  
    if (micros()>contadorvisualizacion+1000000) // Muestra por el puerto serie los resultados, transcurrido un segundo
    
    {
      
         // AQUÍ SE IMPRIME EN EL PUERTO SERIE LOS RESULTADOS

         Serial.print(" Hz=");
         Serial.println(contadorciclo);
         
         rango=(2+((picodetension-valledetension)/5)); // SE CALCULA EL GANGO MÁS ADECUADO PARA LA SEÑAL, CON EL FIN, DE REDUCIR ERRORES EN SEÑALES CON RUIDO DE FONDO
         contadorvisualizacion=micros();//SE ASIGNA A LA VARIABLE CONTADORVISUALIZACIÓN EL TIEMPO EN MICROSENGUNDOS QUE LLEVA EL PROGRAMA EN EJECUCIÓN
         picodetension=sensorValue;//SE ASIGNA A LA VARIABLE PICODETENSIÓN EL VALOR DE LA TENSIÒN LEIDA POR EL PUERTO ANALÓGICO CERO
         valledetension=sensorValue;//SE ASIGNA A LA VALLEDETENSION EL VALOR DE LA TENSIÒN LEIDA POR EL PUERTO ANALÓGICO CERO
         contadorciclo=0; // SE PONE A CERO LOS CICLOS CONTADOS O HERCIOS.
    }   
    



  if (sensorValue >= ( ultimamedicion+rango) ) // La salida 2 pasa a 1 logico si la tensión medida en la entrada analógica 0 es mayor que la anterior lectura + latensión de RANGO

  {

    ultimamedicion = sensorValue;  // SE ASIGANA A LA VARIABLE ULTIMAMEDICION EL VALOR LEIDO POR LA ENTRADA ANALÓGICA CERO 
    ciclo=1;
    
    if (sensorValue>picodetension) // SI LA TENSIÓN MEDIDA POR LA ENTRADA CERO, ES LA MAYOR DETECTADA, SE ASIGNA A LA VARIABLE PICODETENSIÓN EL VALOR LEYDO POR AL ENTRADA CERO ANALÓGICA
    
    {
    picodetension=sensorValue; // SE ASIGNA EL VALOR LEYDO POR LA ENTRADA CERO ANALÓGICA A LA VARIABLE PICODETENSIÓN.
    }
    
  }
    

  
  if (sensorValue <= ( ultimamedicion-rango))  // La salida 2 pasa a 1 lógico si la tensión medida en la entrada analógica 0 es menor que la anterior lectura - la tensión de RANGO

  {

    ultimamedicion = sensorValue; // SE ASIGNA A LA VARIABLE ULTIMAMEDICIÓN LA LECTURA MEDIDA POR EL PUERTO ANALÓGICO CERO
    ciclo=0; // EL CICLO SE PONE A CERO, ES DECIR, QUE EL VOLTAJE EMPIEZA A BAJAR DESDE EL PICO DE TENSIÓN MÁS ALTA
    
    if (sensorValue<valledetension) // SE CUMPLE LA CONDICIÓN SI LA TENSIÓN DETECTADA POR EL PUERTO ANALÓGICO CERO ES MENOR QUE LA CONTENIDA EN LA VARIABLE VALLEDETENSIÓN
    {
    valledetension=sensorValue; //Se asigna a la variable valledetensión el valor medido por la entrada analógica cero
    }
    
  }
    
  
if (ciclo==1 && cambiodeciclo==0)
    
    {
      cambiodeciclo=1;
      contadorciclo++;
    }
    
if (ciclo==0 && cambiodeciclo==1)
    
    {
      cambiodeciclo=0;
    }
      
}

4 MHz?? con analogRead ?

Pero si la conversión del ADC son unos 13 ciclos, y como viene configurado en Arduino, creo recordar que tiene el prescaler de 128... si haces las cuentas, estamos hablando de khz..... luego que si Nyquist más todo el código que tienes....
Diría que el ADC como máximo puede ir a una frecuencia de 1 Mhz... es decir, el mínimo tiempo serían unos 13 microsegundos en hacer una conversión.

¿estás seguro de la frecuencia que pones?

Saludos

Igor R.

Pues seguramente tienes razón, como no tengo una fuente de señal para comprobarlo, puse 4 Mhz un poco por aproximación, así que seguramente como mucho tendrá 1 Mhz como bien dices.

Ese código mide muchísimo menos de 1 MHz.... como te he puesto, sin cambiar los registros del micro, sólo la conversión ya le cuesta un rato (16Mhz/128 y 13 ciclos)....
Luego cuenta con el teorema de Nyquist para saber cual es el máximo que puedes capturar.... Por no decir, que si es una onda cuadrada lo que quieres medir, será menor la frecuencia ...

Lo mejor para hacer un frecuencímetro sería usar timer y/o interrupciones (con una entrada digital).

Saludos

Igor R.

Pues nuevamente tienes razón, desconozco el funcionamiento interno del arduino. Solo llevo unos días trasteando con el arduino y de programación se un poco, pero a nivel hardware y concretamente del arduino se bastante poco. Como dije, es muy posible que tengas razón y este programa solo pueda medir como mucho 100Khz y como mucho digo, pero como te comenté, no dispongo de generador de señal de AF y me resulta imposible a ciencia cierta saber hasta donde llega la frecuencia máxima de lectura de este programa.

Tienes bastantes ejemplos como hacer frecuencímetros por la red para ojear. Yo diría que el método que has utilizado no es el más acertado para dicha aplicación.

Para que te hagas una idea de cifras, un pin digital creo que puede teóricamente como máximo medir Frec_reloj/2 aunque se recomienda 2.5. Es decir, Arduino usa un cristal de 16 Mhz/2.5=6.4 Mhz. Esto sin hacer absolutamente nada de código, y para una señal cuadrada de 50% duty cycle. Creo recordar que era algo así las limitaciones (mejor es mirarlo en el datasheet).

Por lo que para medir 4 Mhz, te lo tienes que currar.... :wink:

Saludos

Igor R.

El frecuencímetro que he puesto en este hilo, es un frecuencímetro más para aplicaciones analógicas que digitales, pero puede funcionar de ambas formas de forma automática.

Este frecuencímetro puede trabajar con señales digitales o analógicas de entre 0,0097v a 2,5v en corriente alterna o de 0v ó 5v en continua o pulsatoria, con lo que es un frecuencímetro muy apto para implementar en cualquier proyecto, que no requiera altas velocidades, pero sí que maneje señales de una amplitud eléctrica muy variable. Además dispone de un filtro que discrimina otras frecuencias de menos amplitud, con lo que se evitan medidas erróneas por ruidos de fondo dentro de la señal a medir. Es decir, este frecuencímetro es algo más complejo que contar los pulsos de una señal digital cuadrada de entre 0 a 5v, que para eso no hace falta un código tan complejo. Yo he usado este código para hacer un tacómetro óptico, un detector de tonos de audio, frecuencímetro óptico y unas cuantas cosas más y siempre me ha funcionado correctamente, apenas colocando un o 2 resistencias y un sensor del tipo que sea.

Pero sí, el problema de este programa es que no va a alcanzar una frecuencia tan alta como de 4Mhz, pero para aplicaciones que requieran menores frecuencias, es muy apto.

Bueno pues sí, teníais razón, he probado este programa con una fuente de señal y efectivamente, ni de broma llega a los 4Mhz prometidos. Al final se a quedado en unos escuálidos 3,2 Khz, que limitan este frecuencímetro muy mucho y que solo lo hace apto para trabajar con señales de muy baja frecuencia. De todos modos funciona bien como detector de tonos de audio, cuenta revoluciones, puede que como tacómetro óptico de asta 180.000 Rpm, detectores de proximidad para robótica usando infrarrojos y alguna cosa más.

Pero bueno, me voy a poner manos a la obra y voy a ampliar el programa, para que pueda trabajar con señales analógicas de 1 a 3Khz como hace hasta ahora y además voy a implementarle la opción de que mida señales digitales de 1 a 1Mhz, usando solo la entrada digital del arduino y no solo la analógica como hasta ahora, que debido a la lenta velocidad de muestreo, limitaba mucho la frecuencia a determinar.

También voy a intentar que mida frecuencias por debajo del Hz, que puede ser útil, para proyectos en los que se requieran largos periodos por ciclo.

Un saludo a todos y gracias por las críticas constructivas que ayudan a mejorar y a aprender.

Si quieres medir una senyal analogica, puedes "convertirla" a digital y/o usar un trigger schimitt.... Al final, lo que te interesa es "detectar" el paso por cero (2.5v). Si que es cierto, que segun como sea la senyal, puede que tengas que adaptarla...

Mira esta nota tecnica de atmel => http://www.atmel.com/Images/doc2508.pdf
Para configurar la velocidad del ADC, mira esto que escribi => Tinkering with Electronics...: Arduino ADC: Muestreo alta velocidad

Tengo una curiosidad, cuando dices que mide 3.2 khz.... era una onda senoidal? Es que me cuesta creer que midas esa frecuencia con precision.... Para medirla con precision, deberias tener que estar muestreando al menos al doble (Nyquist), es decir, 6.4 khz, cosa que no creo que este pasando.... En tu codigo, como tienes que cuando sea mayor que una valor y cosas de esas, pues en algun momento activara el "trigger" de cronometrar, por decirlo de una manera, pero yo creo que puede pasar en sitios completamente diferentes de la onda....

Saludos

Igor R.

Nota- ni acentos ni enyes

He probado el frecuencímetro con un programa llamado Multisine, que se puede descargar gratuitamente de: http://softsolutions.sedutec.de/

Las pruebas las hice con este programa, que entre otras muchas funciones tiene la de generar señales de audio. La frecuencia máxima con un error de +/- 2Hz a una amplitud mínima de tensión de 0,092v a la entrada del pin analógico del arduino, me dio que la máxima frecuencia de lectura era de 3446 Hz, con una onda senoidal.

Por cierto es muy interesante tú comentario, no sabía que se podía cambiar la velocidad de muestreo del arduino.

Muchas gracias por tus comentarios.

Un saludo.

Si se puede cambiar, aunque dentro de un límite y teniendo en cuenta que pierdes resolución. Para entrar en ese tipo de detalles, no queda otra que tirar de datasheet del micro.

Por ejemplo, el microcontrolador dispone de una función llamada ANALOG COMPARATOR. Tiene un AO en el que la entrada AIN0 (PD6) va al positivo y otra analógica que puede ser configurable al negativo (AIN1 o ADC0-7). Cuando la salida del comparador esta activa, puedes lanzar una interrupción, el timer 1, etc.
Con esto podrías conseguir también buenos resultados y mucho más rápido.

Eso si, nada de esto viene implementado en el core de Arduino.

Saludos

Igor R.

Sabéis de algún chip conversor A/D de más de 1Mhz de muestreo y que funcione por I2C o algo así, para usarlo con el arduino y que no sea muy caro???.

Que el Arduino te pueda procesar 8Mbits de datos por segundo, creo que está un poco complicado, de todas maneras:

Alguien a usado el presscaler U664.

¿La salida es analógica o digital?
¿Se pueden poner en cadena, para dividir un rango más amplio de frecuencias?
¿Sabéis de alguno que divida por más de 64?

Yo creo que puedes sacar mas ideas, diferentes puntos de vista, etc si planteas lo que quieres hacer.... no crees?

Pues el prescaler es para aumentar el rango de frecuencias del frecuencímetro de este hilo, ya que este chip puede dividir una frecuencia, hasta en 64 veces, con lo que podría usar a la entrada del frecuencímetro para aumentar el rango de frecuencias, hasta los 200Khz usando la entrada analógica o hasta 128MHz solo usando una entrada digital del arduino.

Lo que no se es si la salida del prescaler es una salida digital o analógica y no me queda tampoco muy claro si el chip tiene un prescaler o dos.

Gracias por el programa, me será muy útil en un proyecto que estoy trabajando... Un Multimetro digital por así decirlo, probablemente cuando lo termine publique el código por aca. Ademas de los diagramas utilizados.

Perfecto, va perfecto, lo he estado provando otra vez, muchas gracias.

hola se que es un tema viejo pero no encuentro nada por la red y estoy desesperado, quiero hacer un frecuencimetro capaz de medir por lo menos un Mhz ,
mediria pulsos digitales
alguien me podria ayudar?

Buenas:

Tengo Arduino UNO r3, por lo que veo necesito medir frecuencias de unos 25 KHz y mostrarlo en un LCD 20x4.
¿Será suficiente rápido y preciso para que funcinoe bien lo que quiero?

A lo mejor como piden arriba más MHz, pues usen cuando salga Arduino ZERO.

¿Funcionará a más de 4 MHz como piden alguien más arriba?

Saludo.