Frequency Reading

I got a project and will take ideas from a programing point of view as well as from an electronics.

I have a device which only has 2 wires connected to it, the device powers it self and also feeds back data from the same 2 wires. The data is just a sine-wave of around 5k-6k running on top of the 24V. The sine-wave it self is roughly about 5V from top to bottom.

I like to interface the Arduino to this "data" or sine-wave riding on top of the 24V, all I need to know is the Frequency of this Sine-Wave at least once a second.

So far for what I have read, I can read a frequency with a frequency counter library on pin 5 of the Arduino.

I also need some electronics help or ideas figuring out how to get the sine-wave to be read on the Arduino.

Thanks

As it is sitting on top of 24V you need to AC couple it, that means putting it through a capacitor. Then you need to turn the AC into DC with a rectifying diode. This will give you half a sin wave with a peak of 2.5V so next you need to square it up. Use a transistor, feed the base through a 1K resistor to your rectified signal, emitter to ground and collector to arduino input pin.
Finally turn on the internal pull up resistors by setting the pin as an input then writing high to it.

OK, thanks to your input, I managed to get a +2.5V to -2.5 volt sine-wave with a 100uf capacitor and a 10kOhm resistor to ground. I will update as I go ..

you may want to also use a 'schmitt trigger' to buffer your signal.

Ok, I now have a good TTL Low to High signal 0 - 5V going into Pin 5 of my Arduino, I need to read the frequency of this TTL pulse, I don't seem to find the right coding....is the frequency counter library a part of Arduino 18? Any tips...?

So far I have this:

#include <FreqCounter.h>
void setup() {
  Serial.begin(9600);                    // connect to the serial port
  Serial.println("Frequency Counter");
}

long int frq;
void loop() {

 FreqCounter::f_comp= 8;             // Set compensation to 12
 FreqCounter::start(100);            // Start counting with gatetime of 100ms
 while (FreqCounter::f_ready == 0)         // wait until counter ready

 frq=FreqCounter::f_freq;            // read result
 Serial.println(frq);                // print result
 delay(1000);
}

And what I get is a 1 a second read. The read out is about 3.5Khz when it should be about 5 Khz or so, every reading is about 100Hz off from the last second so it doesn't seem accurate, I wonder what f_comp and f_ready do, also the 100ms one...

I figured it out, I used a different approach, counting the amount of pulses (Low to High) on Pin 5 in 1 second and printing it over serial.

const int frqPin = 5; //Input Pin
const int oneSecond = 1000; //Meassured time
int frqPinState = LOW;
int frq = 0;
int prevFrqPinState = LOW;
unsigned long timer = 0;
void setup()
{
  Serial.begin(9600);
  pinMode(frqPin, INPUT); //Declared Pin 5 as Input
}

void loop()
{
  frqPinState = digitalRead(frqPin); //Reads State of Input Pin
  if (frqPinState == LOW) //Creates a previos state
  {
    prevFrqPinState = LOW;
  }
  if (frqPinState == HIGH && prevFrqPinState == LOW) //Pulses Counter
  {
    prevFrqPinState = frqPinState;
    frq++;
  }
  if (millis() - timer > oneSecond) //Time Counter
  {
    timer = millis(); //Resets Time
    Serial.println(frq); //Prints Frequency
    frq = 0; //Resets Frequency
  }
}

I still have a long way to finish my actual project but this phase is out of the way now :slight_smile:

The readings are very precise, yet I have a issue...
I need to provide a 1 a second reading to a serial port, this is crucial.
Now, I see there is a certain fluctuation on the readings that affect my readings, enough to be a problem.

5695
5672
5666
5672
5665
5671
5664
5671
5664
5670
5665
5672
5671
5671
5670
5664
5671
5665
5670
5665

It is roughly about 5+ and then 5- almost all the time...
I'm guessing that the issue lies on the micro being halted/busy transmitting over the slower serial port and while it does it looses some of the changing state readings on Pin 5. Is there a better approach to this ???

After lots of filtering I got it more stable, yet it still jumps exactly 6Hz up and down constantly...I really think is related to the micro being busy during the reading...I tried a 500ms intead of 1000ms but I still got the same issue...ideas?

You might want to use some kind of interupt for this, but I'm no expert on the subject.

But why didn't you pursue the "FreqCounter" approach? Why didn't that work???

I need to make a freq counter as well, and I am just starting to gather info myself

I've done something somewhat similar.. I had to take readings from an anemometer for a school project. The anemometer output a sine wave with about 1.5V p-p. Converted it to a TTL square wave and used an interrupt to record the time elapsed between pulses and calculated the frequency an thus the wind speed from there. Worked very well.

P_Wood, could you share the code?
I think it'll help...

I apologize in advance for my crappy programming. This was one of my first big projects and it was done out of necessity. There is a lot more to it, but I tried to scrape away all of the irrelevant stuff. The "void measure()" part is what you want.

int hz;
int mph;

unsigned long startTime;
unsigned long stopTime;

unsigned long pulseHigh;
unsigned long pulseLow;
unsigned long period;

unsigned long periodOld;

void setup() {

  Serial.begin(9600); 

  attachInterrupt( 1, measure, CHANGE);
  
}

void loop() {

  if (period != periodOld) {  
    if( period > 20000 && period < 1500000) {            //effort to eliminate false(ridiculous) readings
      hz = 1000000 / period;            //converts the period into freq.(hz)
    }
    else
    {
      hz = 0;
    }


    mph = (hz * 1.711) + 0.78;            //converts freq. to mph for NRG-40 anemometer

    if(mph < 1)                                    //for displaying purposes
    {
      mph = 0;
    }
    else 
    {
      mph = mph;
    }
    periodOld = period;
  }
  
  if (micros() - startTime > 750000 || micros() - stopTime > 750000)    //I think I did this to ignore measurement if the period was > 3.5seconds(which happens with anemometers)
  {
    period = 0;
  }
  //measuring wind speed 

}

void measure() {                        //measures the period of the signal in microseconds

  if(digitalRead(3) == HIGH) {            
    startTime = micros();    
    pulseLow = startTime - stopTime;
  }
  if(digitalRead(3) == LOW) {
    stopTime = micros();
    pulseHigh = stopTime - startTime;
  }
  period = pulseLow + pulseHigh;

}

I'm not trying to be critical as a teacher, but these two lines in your code need to be swapped orders. By having them the order they're in now, you're counting the communication time in your calculations.

timer = millis(); //Resets Time
Serial.println(frq); //Prints Frequency

By the way, use 115200 baud rate if you want to save time. It's 12 times quicker than 9600.

You should really put the timer=millis() right around when the signal becomes high for the first time. From what you're doing now, you could miscount half of a cycle. BTW, use microsecond(). One millisecond off means 5 more pulses. :slight_smile:

I realize now I never posted the final code so in case anyone ever reads this

const uint8_t frqpin = 5; // digital pin #5
const uint32_t oneSecond = 1000;
uint32_t timer = 0;
uint32_t sts = 0;
const uint32_t c = 3000; // wait for 3000 pulses
uint32_t ets = 0;
void setup() {
  Serial.begin(9600);
  pinMode(frqpin,INPUT);
  digitalWrite(frqpin,HIGH); // pullup
}
void loop() {
  pulseIn(frqpin,LOW);
  sts = micros(); // start time stamp
   for (uint32_t i=c; i>0; i--)
    pulseIn(frqpin,HIGH);
  ets = micros(); // end time stamp
  Serial.print("$");
  Serial.println((c*1e6/(ets-sts))); // output Hz
}

This works flawlessly! Just make sure you wait time is less than a second, for me 3000 pulses was less than a second but for other applications other numbers should be used.