Reading analog frequency input and generate digital output

Good morning, I write this because I’ve been all morning searching the code that I need, and I almost have it.

All I need is to read the frecuency of an analog signal and write a tone to a digital pin to have audio output to a small buzzer. I found a bunch of codes that almost suit to this application but write the data into the serial port of the arduino, and I’m not very good at programming so I need your help. I post the codes here in case its useful.

/*
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;
   }
     
}

source

#include "TimerOne.h"  // Se incluye la utilizacion del timmer para hacer uso del ADC
void setup() {
  Serial.begin(2000000);//según el core de Arduino la doble velocidad se activa siempre.
Timer1.initialize(50);          //microsegungos del timer, en este caso obtenemos 20khz de frecuencia de muestreo. con 
40khz da problemas
  Timer1.attachInterrupt(lecturaEnvio);        // la función que haremos cada 50ns
  //Prescaler
  //ADPS2 - ADPS1 - ADPS0 - Division Factor
  //0        - 0       - 0        ->2
  //0        - 0       - 1        ->2
  //0        - 1       - 0        ->4
  //0        - 1       - 1        ->8
  //1        - 0       - 0        ->16
  //1        - 0       - 1        ->32
  //1        - 1       - 0        ->64
  //1        - 1       - 1        ->128

  //Configuraremos el preescalar del Microcontroladorcon el factor de division de 8  bitWrite(ADCSRA,ADPS2,0);
  bitWrite(ADCSRA,ADPS1,1);
  bitWrite(ADCSRA,ADPS0,1);
 //Entrada A5
  ADMUX=(1<<ADLAR)|(0<<REFS1)|(1<<REFS0)|(0<<MUX3)|(1<<MUX2)|(0<<MUX1)|(1<<MUX0);
}
void loop(){   
// no hacemos nada, pero podríamos.
}
char fastADC(){
  cli();
 ADCSRA|=(1<<ADSC);//iniciar conversion
 // ADSC es limpiado cuando la conversion termina
 loop_until_bit_is_clear(ADCSRA, ADSC);
        return ADCH;//leer bit alto
   sei();
}
void lecturaEnvio(){
//escribimos en el serial
loop_until_bit_is_set(UCSR0A ,  UDRE0);
    UDR0 =fastADC();
}

source

I used a the FreqCount library for measurement of the speed of a flow sensor (paddle wheel type), the rest of the sketch drives visual and audible alarms if the flow was too low (too high is REM’d out). It was an alarm for low water flow rate in a fish pool filtration system…

#include <FreqCounter.h>

// define the pins used
#define freq_in   5                       // this is fixed in FreqCounter.h
#define Buzzer    6                       // Buzzer output
#define LED_Low   7                       // "Low Flow" LED
#define LED_OK    8                       // "Normal Flow" LED
#define LED_High  9                       // "High Flow" LED
#define Pot       A0

//global variables
int Deadband =    100;                    // hysteresis value for SP
int Setpoint;                             // read by analog input
int SP_Low;                               // calculated
int SP_High;                              // calculated
int frq;                                  // derived from the function

void setup() {

// define the pin modes
  pinMode(LED_High, OUTPUT);
  pinMode(LED_OK, OUTPUT);
  pinMode(LED_Low, OUTPUT);
  pinMode(Buzzer, OUTPUT);

  Serial.begin(115200);                   // connect to the serial port
  Serial.println(F("Pump Flow Monitor"));

// LED Test and Buzzer sign-on
  digitalWrite(LED_High, HIGH);
  digitalWrite(LED_OK, HIGH);
  digitalWrite(LED_Low, HIGH);
  digitalWrite(Buzzer, HIGH);
  delay(150);
  digitalWrite(Buzzer, LOW);
  delay(350);
  digitalWrite(Buzzer, HIGH);
  delay(150);
  digitalWrite(Buzzer, LOW);
  delay(350);
  digitalWrite(Buzzer, HIGH);
  delay(150);
  digitalWrite(Buzzer, LOW);
  digitalWrite(LED_High, LOW);
  digitalWrite(LED_OK, LOW);
  digitalWrite(LED_Low, LOW);

  
} // end setup

//** LOOP ** LOOP ** LOOP ** LOOP ** LOOP ** LOOP ** LOOP  

void loop() {

  // update the dynamic variables
  Setpoint = map(analogRead(Pot), 0, 1023, 0, 300);
  SP_Low = Setpoint - (Deadband/2);
  SP_High = Setpoint + (Deadband/2);
 
  FreqCounter::f_comp= 8;               // Set compensation value
  FreqCounter::start(1000);             // Start counting with gatetime of {spec} ms
  while (!FreqCounter::f_ready)         // wait until counter ready
 
  frq=FreqCounter::f_freq;              // read result
  
  Serial.print(F("  Actual = "));
  Serial.print(frq);                    // print result
  Serial.print(F(" : Setpoint = "));
  Serial.println(Setpoint);             // print setpoint


  // drive the LEDs and buzzer

//  // High Flow
//  if(frq > SP_High) {
//    digitalWrite(LED_High, HIGH);
//    digitalWrite(LED_OK, LOW);
//    digitalWrite(LED_Low, LOW);
//    digitalWrite(Buzzer, HIGH);
//  }

  // Low Flow
  if(frq < SP_Low) {
    digitalWrite(LED_High, LOW);
    digitalWrite(LED_OK, LOW);
    digitalWrite(LED_Low, HIGH);
    digitalWrite(Buzzer, HIGH);
  }

  // Normal Flow
  if((frq >= SP_Low) && (frq <= SP_High)) {
    digitalWrite(LED_High, LOW);
    digitalWrite(LED_OK, HIGH);
    digitalWrite(LED_Low, LOW);
    digitalWrite(Buzzer, LOW);
  }
  
  delay(500);
   
} // void loop()

@DamiToo: Do you realize that the first code is for a Due? Which Arduino do you use?
Registers and bits are different for Due and other Arduinos.