• # ADC with “built-in” Scaling on PIC with FVR

To increase resolution and have a “beefier” ADC result, it is common to scale the input to an ADC with external
components, dividers, amplifiers, etc.

On some of the new PICs (I tried it with 18F1XK22 and 16F1823) you can scale the ADC without any external components
by changing the internal fixed voltage reference.
These new devices have fixed voltage reference (FVR) with a “multiplier” that can set FVR to X1 = 1.024V, X2 = 2.048V
or X3 = 4.096V.
The fixed reference for the ADC is controlled from the 2 LSB of the FVRCON (on 18F1XK22 called FVR1S and on 16F1823

Here is an example:
ADC has to be configured to use FVR as reference.
FVR has to be enabled.
To use the entire FVR range 1.024 – 4.096V the supply voltage needs to be above 4.1V
Because FVR value changes in multiplier of 2, using three FVR values has “effectively” the same affect as adding two
bits to the ADC. We add a bit to the ADC result for each increase in the FVR value. The nice thing is with a 10bit
ADC we will have a resolution of 1mV (0.001V) from 0V to 4.096V. This also means that the decimal value of the ADC
result will be in mV so a lot could be done without ever using Float variables. Code example:
Code:
```ADC_BEEFUP:
ADFVR = FVRCON & 3             ' Get the curret ADFVR value from FVRCON
i = ADFVR - 1                  ' shifting factor
ADRESULT = ADRESULT << i       ' shift the ADC result according to scaling factor
GoSub FLOATVOLT                ' Optional - get the voltage in a float variable
GoSub STRVOLT                  ' Optional Print the voltage without using a float
'---[Scale by shifted ADC result]-------
If ADRESULT < 1020 Then        ' threshold must be less then 10bit full scale
ADFVR = 0x01                ' ADFVR = 1 FVR = 1.024V
ElseIf ADRESULT > 2040 Then    ' threshold must be less then 11bit full scale
ADFVR = 0x03                ' ADFVR = 3 FVR = 4.096V
Else
ADFVR = 0x02                ' ADFVR = 2 FVR = 2.048V
EndIf
FVRCON = 0x80 | ADFVR          ' FVREN = 1 + ADFVR
While FVRRDY = 0 : Wend        ' wait for FVR stable
Return

FLOATVOLT:
VOLT = ADRESULT * 0.001        ' VOLT is a Float
'Print or do something with this value
Return

STRVOLT:
Str VOLTSTR = Str\$(Dec4 AVGRESULT) ' VOLTSTR is a byte array
j = 4
Repeat                             ' move one byte to the right
VOLTSTR[j] = VOLTSTR[j - 1]
Dec j
Until j = 1
j = 0
VOLTSTR[1] = "."                  ' insert a decimal point
'Print
Return```