**Download this article in PDF format.**

When you need to convert a measurement signal from the digital to the analog domain, this design is a suitable solution with only two chips. Frequency-to-voltage conversion has many applications in instrumentation circuits.

This design *(Fig. 1)* is based on the 14-pin PIC Microcontroller 16F753, which has an embedded 16-bit counter and a 9-bit digital-to-analog converter (DAC). The input frequency range for this design is within 0 to 50 KHz, and its output voltage is within the range of 0 to 4.99 V, with a resolution of 10 mV.

To achieve the conversion, the input frequency is separated into four scales, which are manually selected by the inputs SEL1 and SEL2 *(Fig. 2)*.

The DAC can deliver a maximum value of 4.99 V when its input code is 1FFh (511d), and 0.000V for a 000h input value. For the first scale, we get maximum and minimum values that are substituted in the following conversion equation:

Substituting those values, we get two equations:

Solving both equations we get:

And solving for M, we get:

Substituting both values in Equation 1, we get the offset value, and the result is Equation 3:

Now Equation 3 can be implemented in PIC basic code. But first, we need to measure the input frequency in 1.00 second intervals using TIMER1 as follows:

TMR1L = 0; Clearing TIMER1 registers

TMR1H = 0;

T1CON.0 = 1; TIMER 1 Enabled

PAUSE 1000; for 1.00 Seconds

T1CON.0 = 0; TIMER 1 Disabled

COUNTER.BYTE0 = TMR1L; Storing both register in two bytes

COUNTER.BYTE1 = TMR1H;

Now we can apply Equation 3 as follows:

DIV = COUNTER *1000

DAC = DIV32 9784

DAC = DAC + offset ; freq offset = 0;

If we get 2,500 pulses in TIMER1, for example, we can get the DAC’s value by dividing the pulses read by the constant 9.784 that we found previously:

Then, converting this to the software code, we get:

Now we can determine how many pulses are equivalent to each bit measured *(Fig. 3)*.

For each scale, it’s necessary to obtain the constants by doing the same method used for Equations 1, 2, and 3. Thus, for the second scale (5-10 kHz),** **we get Equation 4:

Then we determine how many pulses are equivalent to each bit *(Fig. 4)*.

For the third scale (10-15 kHz), we get** **Equation 5:

Then, we determine how many pulses are equivalent to each bit *(Fig. 5)*.

For the fourth scale (10-50 kHz), we get Equation 6:

Then, finally, we determine how many pulses are equivalent to each bit in *Figure 6*.

*Figures 7 and 8*** **show two cases in the scope for different input frequencies with their respective voltage output. The code listing below shows the software code implemented in the PIC16F753.

*Ricardo Jimenez** holds a Master’s degree in electronics. He is the author of the book “The PIC Microcontroller Notebook, Vol 3,” ISBN: 978-1-7325906-1-8.*

*Gabriel Lee Á**lvarez is** an Electronics Engineering student at ITM. *

**Software Code for the Frequency-to-Voltage Converter Based on the PIC16F753**

‘* Name : FREQ-TO-VOLTAGE.BAS

‘* Authors : Ricardo Jimenez and Gabriel Lee Alvarez

‘* Version : 1

; PIC16F753

; Frequency to Voltage Converter

; 0hz – 5khz = 0v – 5 v; 1st Scale

;5khz – 10khz = 0 – 5v; 2nd Scale

;10khz – 15khz = 0 – 5v; 3rd Scale

;10khz – 50khz = 0 – 5v; 4th Scale

;pic16f753

; Oscillator and PORTS Configuration

OSCCON = $26; = $26; Clock set to 4 MHz

OSCTUNE = 0;

TRISA = %111110; RA0 IS A OUTPUT, RA1:RA5 AS INPUTS

ANSELA = %000010; RA0:RA5 DIGIITALS

TRISC = %0000000; RC0:RC2 AS INPUTS, RC3:RC5 AS OUTPUTS

ANSELC = %000000; RC0:RC5 AS DIGITALS

WPUA = %011100; RA2,RA3 PULL IS ENABLE

WPUC = %000000

DEFINE LCD_DREG PORTC ‘ PORTC is LCD data port

DEFINE LCD_DBIT 0 ‘ PORTC.0 is the data LSB

DEFINE LCD_RSREG PORTC ‘ RS is connected to PORTC.4

DEFINE LCD_RSBIT 4

DEFINE LCD_EREG PORTC ‘ E is connected to PORTC.5

DEFINE LCD_EBIT 5

DEFINE LCD_BITS 4 ‘ 4 data line are used

DEFINE LCD_LINES 2 ‘ It is a 2-line display

DEFINE LCD_COMMANDUS 1500 ‘ Use 1500uS command delay

DEFINE LCD_DATAUS 44 ‘ Use 44uS data delay

;———SETTING UP LCD——————————————————–

LCDOUT $FE,$28; $28 FUNCTION SET, 4 BITS

LCDOUT $FE,$10; $10 SHIFT DISPLAY

LCDOUT $FE,$0C; $0C DISPLAY ON

LCDOUT $FE,$06; $06 ENTRY MODE SET

;————TIMER CONFIG ———-

T1CON = %10000100; $84 TIMER 1 DISABLE

;—HPWM SET to 250 Hz, when needed remove semicolons —

;CCP1CON = %00001100; PWM mode selection and CCPx enabled

;PR2 = 79; Value obtained from equation

;T2CON = %00000100; enabling timer 2, PRESCALER 16

;CCP1CON.5 =0

;CCP1CON.4 =0

;CCPR1L = %000101000;

;ADC ENABLED

ADCON0 = %10000111; ENABLE ADC

ADCON1 = %00000000;FOSC/2

;——– DAC CONFIG —————————————

DAC1CON0 = %11100000;$E0, DAC ENABLED RIGHT JUSTIFIED

;———DECLARING VARIABLES

COUNTER VAR WORD; DECLARING COUNTING VARIABLES

;COUNTER.BYTE0 VAR TMR1L

;COUNTER.BYTE1

DAC VAR WORD; VARIABLE TO BE USED BY DAC

SEL VAR BYTE; SCALE SELECTOR

HZ VAR BYTE[5]; DIGITS FOR HERTZ

DIV VAR WORD;

IN VAR BYTE;

VBE var word

OUT VAR BYTE;

I VAR WORD;

I2 VAR WORD;

ID VAR BYTE[3];

VIN VAR WORD;

VID VAR BYTE[4];

VED VAR BYTE[4];

VIN2 VAR WORD;

INVERT VAR PORTA.2; PIN FOR INVERTING DATA

x var byte;

VO VAR WORD[4];

OPTION_REG.7 = 0;

;——–PROGRAM STARTING —————-

RPT:

;FIRST TEST, LET’S DO THE FIRST SCALE

;QUANTITY OF BITS IN THE DAC = 511, SO 5KHZ/511

;5KHZ/511 = 9.7843

;K=9.7843

FOR X = 0 TO 5; STARTING LOOPS

HZ[X] = “0”;

VO[X] = “0”;

VIN = 0; CLEARING VARIABLES

IN = 0;

OUT = 0;

SEL = 0;

DAC = 0;

DIV = 0;

DAC = 0;

VID[X] = “0”;

ID[X] = “0”

NEXT X;

LCDOUT $FE,$C0,”WAITING FOR SCALE “

OBTAIN_PULSES:;

LCDOUT $FE,$80,”HZ= “,HZ[4],HZ[3],HZ[2],HZ[1],HZ[0],” Vout= “,VO[2],”.”,VO[1],VO[0];

TMR1L = 0; CLEARING REGISTERS IN TIMER1

TMR1H = 0;

T1CON.0 = 1; TIMER 1 ENABLED

PAUSE 1000;

T1CON.0 = 0; TIMER 1 DISABLED

COUNTER.BYTE0 = TMR1L; STORING LOW BYTE REGISTERS

COUNTER.BYTE1 = TMR1H; STORING HI-BYTE REGISTERS

FOR X = 0 TO 4;

IN = COUNTER DIG X; GETTING DIGITS

LOOKUP IN,[“0123456789”],OUT; DECODING EACH DIGIT

HZ[X] = OUT; STORING DIGITS

NEXT X;

LCDOUT $FE,$80,”HZ= “,HZ[4],HZ[3],HZ[2],HZ[1],HZ[0],” Vout= “,VO[2],”.”,VO[1],VO[0];

;—–SELECTION————

;FOR X= 0 TO 255

SEL = (PORTA & %011000)>>3; READING PORTA ANS SHIFT RIGHT BITS 3 SPACES

;SELECTING SCALE

IF SEL = %00 THEN GOSUB ESC1; 0-5KHZ

IF SEL = %01 THEN GOSUB ESC2; 10K-50K

IF SEL = %10 THEN GOSUB ESC3; 10KHZ-15KHZ

IF SEL = %11 THEN GOSUB ESC4; 5KHZ-10KHZ

IF INVERT = 0 THEN DAC = 511-DAC; INVERT DATA IF = 0

GOSUB V_DAC;

LCDOUT $FE,$80,”HZ= “,HZ[4],HZ[3],HZ[2],HZ[1],HZ[0],” Vout= “,VO[2],”.”,VO[1],VO[0];

GOSUB DAC_OUT;

GOTO OBTAIN_PULSES; GO TO LABEL OBTAIN_PULSES;

;—————— FIRST SCALE ——————————

ESC1:; 0HZ A 5KHZ

; getting Scale values

DIV = COUNTER *1000

DAC = DIV32 9784

IF (COUNTER >5000) THEN DAC = 0; ; EQUAL TO ZERO IF NOT IN RANGE

LCDOUT $FE,$C0,”0-5KHZ DAC= “,dec dac,” “

RETURN;

;———————-4th SCALE——————-

ESC4:; 10KHZ-50KHZ

DIV = COUNTER*100

DAC = DIV32 7827

DAC = DAC – 127;

IF (COUNTER >50000) OR (COUNTER

LCDOUT $FE,$C0,”10-50KHZ DAC= “,DEC DAC,” “

RETURN;

;———————–3rd scale—————–

ESC3: ; ESCALA 10KHZ – 15KHZ

DIV = COUNTER*1000

DAC = DIV32 9784

DAC = DAC – 1022;

IF (COUNTER >15000) OR (COUNTER

LCDOUT $FE,$C0,”10-15KHZ DAC= “,DEC DAC,” “

RETURN;

;——————————————————————————

ESC2:; SCALE 5KHZ – 10KHZ

; ————–getting the values for this Scale

IF (COUNTER >10000) OR (COUNTER

LCDOUT $FE,$C0,”5-10KHZ DAC= “,DEC DAC,” “

DIV = COUNTER*1000

DAC = DIV32 9784

DAC = DAC – 511;

IF (COUNTER >10000) OR (COUNTER

LCDOUT $FE,$C0,”5-10KHZ DAC= “,DEC DAC ,” “

RETURN;

;–VOLTAJE DAC———

V_DAC:

DISABLE

VO[1]= DAC*976; GETTING VOLTAGE FROM DAC

VO[3]= DIV32 100; WITH RESPECT TO NUMBER

ENABLE

FOR X = 0 TO 2;

IN = VO[3] DIG (X+1); FIND THE RESPECTIVE DIGITS

LOOKUP IN,[“0123456789”],OUT;DECODING DIGITS

VO[X] = OUT; STORE DIGITS

NEXT X;

RETURN;

;——————————————————————————-

DAC_OUT:

DAC1REFL = DAC.BYTE0; modifying the DAC0 register

DAC1REFH = DAC.8; modifying DAC0-bit 8

RETURN;

;——————————

END;