Frequency-to-Voltage converter without help of ICs.

I am in my first step to write a frequency to voltage generator without the help of ICs like LM2907/LM2917. That first step is to convert pulses into frequency. So far my code reads pulses from a digital input and estimates their frequency. I can read frequency values close to real ones between 4 to 400 Hz but I am getting problems when the frequency goes over 150 Hz. The reading starts to become unstable. I am generating those pulses using another Arduino. Should I use a pull up resistor in the digital input where the pulses arrive? Should I use timers? If so, how? Thank you for your help.

Here my code:

// Frequency to Voltage converter

int DigitalIn13 = 13; //Input of pulses
double Pulses = 0; //Counts while pulse is HIGH
float Frequency = 0; //Frequency of the pulses
int Status; // HIGH/LOW status of pulse

void setup() {
    pinMode(DigitalIn13, INPUT); 

void loop() {
   Status = digitalRead(DigitalIn13); // Reads status of pulse
    if (Status == 1)
    {Pulses = Pulses + 1;             // If status HIGH count
     Frequency = 1/(Pulses/6500);}    // Estimates frequency
    else{                             // If status LOW stop count
  Serial.println(Frequency);          // Shows estimated frequency
  Pulses = 0;                         // Resets pulses count
  delay(500);}                        // Delay for visualization of frequency
1 Like

I think I'd suggest using the pulseIn() function & measure the high time, then measure the low time, put the two together to get the period. 1/period = frequency. "Map" the period into the voltage you want. Or output it into an external DAC if want to create a voltage from it.

Would this be more suited to using an interrupt to count the pulse periods and do a rolling average (or spot) frequency calculation and then leave the main loop to report the value every second or so as needed. You could be loosing resolution with your current code when doing the Serial.print. As your aim is to convert the result to voltage without the aid of hardware I assume your going to use analogWrite. This is not a true analogue output.

Use your avr to measure the frequency and then use that frequency measurement to drive a pwm output. Through a low-pass filter, you get an analog voltage proportion to the frequency.

Thank you CrossRoads and dhenry. The pulseIn() function provided me more stable frequency readings and finally I was able to get a decent output voltage from the frequency using a low-pass filter as dhenry recommended. In the past, I've done this with PLCs using interrupts as Riva commented but I don't know yet how to used them in Arduino. I think it is time to do it but with help from the forum.

So here the code which allows Arduino to convert Frequency-to-Voltage without the aid of ICs. Regards!

// Arduino Frequency to Voltage converter without the aid of ICs - 2012

int DigitalIn13 = 13; //Input of pulses
int Voltage = 9; //Voltage from frequency conversion (output pin supporting PWM)
float Frequency = 0; //Frequency of the pulses
unsigned long HighTime; //the HIGH time of pulses
unsigned long LowTime; //the LOW time of pulses
unsigned long Period; //period = HighTime + LowTime
unsigned int volt = 0; // Variable to hold the voltage read

void setup() {
    pinMode(DigitalIn13, INPUT); //sets pulses pin as input
    pinMode(Voltage, OUTPUT); // sets voltage pin as output

void loop() {
  HighTime = pulseIn(DigitalIn13, HIGH); //the HIGH time of pulses in ms
  LowTime = pulseIn(DigitalIn13, LOW); //the LOW time of pulses
  Period = HighTime + LowTime; //period
  Frequency = 1/(Period * 0.000001); //Frequency
  volt = map(Frequency, 0, 242, 0, 255); //maps the frequency into voltage
  analogWrite(Voltage,volt); //writes voltage from frequency

The reading starts to become unstable.

Add a statement before the "Status = ..." line to wait out a low pulse.

Something like this:

  pulse = 0; //reset pulse / period counter
  while (!digitalRead(DigitalIn13)) continue; //wait out the low pulse
  while ( digitalRead(DigitalIn13)) pulse += 1; //increment pulse as long as DigitalIn13 is high. Make sure that pulse doesn't overflow
  //now, pulse is proportional to the duration of DigitalIn13's high pulse.
  while (!digitalRead(DigitalIn13)) pulse += 1; //increment pulse for DigitalIn13's low cycle. Make sure that pusel doesn't overflow
  //now pulse contains thewhole period for DigitalIn13.
  //do something with pulse

A more appropriate approach is to use input capture for low frequency cases like yours.

hi i need delay for 5min to output off only.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.