• Pic® Basic


  • 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
    called ADFVR).

    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