This code allows us to use FVR feature of a PIC to measure Vdd voltage of a PIC, without using any external components or any pin of the PIC.
It uses internal FVR output voltage ; Output voltage is internally connected to ADC module directly.
Inside the code below, there is the short explanation how it works.
See the picture for some voltage tests and the accuracy of measurement.
This code is for PIC16F1503.
If you have a PIC with FVR and ADC features, it will be easy to do the same measurement with this code.
DEFINE OSC 16 ' Let the compiler know about OSC speed. DEFINE ADC_BITS 10 ' ADCIN resolution (Bits) DEFINE ADC_CLOCK 2 ' ADC clock source (Fosc/32) DEFINE ADC_SAMPLEUS 20 ' ADC sampling time (uSec) DEFINE LCD_DREG PORTC ' Set LCD Data port DEFINE LCD_DBIT 0 ' Set starting Data bit (0 or 4) if 4-bit bus DEFINE LCD_RSREG PORTC ' Set LCD Register Select port DEFINE LCD_RSBIT 4 ' Set LCD Register Select bit DEFINE LCD_EREG PORTC ' Set LCD Enable port DEFINE LCD_EBIT 5 ' Set LCD Enable bit
ADCON0 = 000000 ' Nothing selected here.
ADCON1 = 100000 ' Right Justified, Fosc32, VRPOS is connected to VDD ADCON2 = 0 ' No need.
' All pins are outputs. TRISA = 0
TRISC = 0'=== Since we connect FVR output directly to ADC input,
'we do not need to set any port pin to Analog.
' All pins Digital. ANSELA = 0
ANSELC = 0
' Take all pins low. LATA = 0
LATC = 0
PORTA = 0
PORTC = 0
'===== FVR is enabled, and ADC FVR Buffer Gain is 1x, with output voltage = 1x VFVR (1.024V nominal) FVRCON = 000001
PAUSE 1 ' Wait ...
'===== Variables for main loop ====== Volt VAR WORD
Adval VAR WORD
ADCRes VAR WORD
FVR VAR WORD
Temp VAR WORD
Begin:
'Example, FVR = 1.024 and we are using 8-bit resolution; and say that the ADC result is 78; then,
'Vdd = (1.024 * 255)/78
'Vdd = 3.347 V
'Example, FVR = 1.024 and we are using 10-bit resolution; and say that the ADC result is 326; then,
'Vdd = (1.024 * 1023)/326
'Vdd = 3.213 V' When it comes to floating point, for accuracy, we can use DIV32 function. ADCRes = 1023 ' 10-Bit Resolution is 1023 steps. FVR = 1024 ' 1024 is actually 1.024V. This is required for DIV32 accurate calculation. PAUSE 100
Start:
ADCIN 31,Adval ' Select channel 31; CH31 is FVR to ADC. See datasheet ADC section.
Temp = ADCRes * FVR ' For better accuracy, instead of 1.024V we use 1024; Thus, 1024 * 1023 = 1,047,552 and this is way over 16-bit variable.
Volt = DIV32 Adval ' There is already a division in the forumla above. We can use that division for the best accuracy in DIV32.
LCDOUT $fe,1,"Vdd:",DEC Volt/1000,".", DEC3 Volt //1000 ' Volt is now a multiplied big number. Extract its digits.
Re: K42 and Timer Interrupts
Thanks for the explanation.
Ioannis - 28th April 2025, 19:28I misinterpreted these paragraphs. My understanding was to have ASYNC cleared and use Fosc/4.
Ioannis