View Full Version : Using VREF pins for pots that don't reach ADC=0 or 255
Demon
- 28th February 2025, 08:17
If my pots don't go quite down to 0V or up to 5V, can I just use the VREF pins and tweak what the ADC uses as lower and upper limits with 2 voltage dividers?
(sorry, never done this stuff before)
It seems to me that trying to fudge the ADC values in software is not the best approach; especially if it can be fixed with 4 resistors.
HenrikOlsson
- 28th February 2025, 15:54
Bloody hell, you're making it complicated for some user input knobs :-)
But to answer you question,yes. The datasheet has the answers, one part MAY differ from another so best to check but using the 25K22 as an example VRef- van range from 0.3 below Vss uo whatever voltage is applied to VRef+ which in turn can range Vdd/2 to Vss+0.3V.
Using voltage dividers for VRef provides a high(ish) impedance voltage source at the VRef inputs, which will be suspectable to noise. 20mV noise on any of the Vref pins is the same as 20mV noise on the ADC input pin (about 4 counts @5V).
I think we've been over this but I might have missed something....
Sample the input 16 times, sum all values and divide by 4. Now you have a somewhat filtered 12bit result. Use this value to apply offset and gain formula to get the final value to what you want. For example, lets say the 12bit value ranges from 17 to 3996.
Value = Value - 17 ' Value is now 0-3979
If value > 32000 then Value = 0 ' Make sure to not underflow in case start value is <17
Value = Value **16850 ' Value is now 0-1023
Demon
- 28th February 2025, 22:44
16F18855 at 5VDC
Yeah, you get what you pay for in pots:
B5K pots:
4.70K <--- ADC reading goes 2 - 254
4.84K
4.98K
5.01K
5.06K
5.15K
B5K pots with switch:
4.96K
4.98K
5.01K
5.06K
5.07K
5.11K
(the others go from 0 - 255)
I was thinking of bumping up VREF- to 0.5V with 470R/30R voltage divider.
I'm already using FVR 4x at 4.096V, so thinking of leaving that AS-IS.
I'm really liking your idea:
Sample the input 16 times, sum all values and divide by 4. Now you have a somewhat filtered 12bit result
richard
- 28th February 2025, 22:46
1. Would a lower resistance pot (like 1K-2K) be easier/cheaper to get tighter tolerances?
define tolerance its not a general parameter for pot ratings, resistance should not be relevant
Resistance:
The total resistance of the potentiometer, measured from one terminal to the other
Rated power :
The maximum amount of power the potentiometer can handle without overheating or failing
Resolution :
The accuracy of the potentiometer's resistance changes
Expressed as a percentage of the total resistance
Temperature coefficient :
How the resistance of the potentiometer changes with temperature
Mechanical life:
The expected lifespan of the potentiometer
Usually expressed as the number of cycles it can endure
Taper :
The relationship between the mechanical position and resistance ratio
The most common types are linear and logarithmic
2. Is there a physical work-around for "weak" pots? (hardware trick)
what is a weak pot
3. Would lower resistance pots actually be "better" for ADC? I remember Richard saying a 1K pot could "in theory" have 1 ohm resolution at 10 bits (or something to that effect).
only that acquisition time is lower, a 10k pot could have 10 ohm resolution
in order to have "stable" 10bit result from a 10 bit ADC you would need 16 times over sampling.
This flight simulator really wants a range of 0 to 1023 to be able to use the full range of motion on a control (imagine a choke that's always partially ON, or a flap, not good).
to begin with you would need 16 times over sampling or use a 12 bit adc.
are you using 10 turn pots? i cannot see how 0.25 degree resolution is useful for a 270 degree pot, most humans would be lucky to move it accurately in 2.00 degree increments
It seems to me that trying to fudge the ADC values in software is not the best approach; especially if it can be fixed with 4 resistors.
how is that going to work if the pots are not all identical, i have not encountered a pot that has a wiper that doesn't read 0 ohms to an end terminals at extreme rotation on my multimeter low ohms scale. how badly off are these pots . it would be easier to get better stock
in c i usually use a map function to get desired result range from an expected input range, about 1000 times easier and vastly more flexible than any hardware solution
int16_t map(int16_t x, int16_t in_min, int16_t in_max, int16_t out_min, int16_t out_max)
{
return (long) (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
Demon
- 28th February 2025, 23:14
define tolerance its not a general parameter for pot ratings, resistance should not be relevant... [/[QUOTE]
I meant would a 1K or 2K pot be "generally" better for ADC on a 16F18855.
[QUOTE]...Resistance:
The total resistance of the potentiometer, measured from one terminal to the other... [/[QUOTE]
5K, linear
[QUOTE]...Rated power :
The maximum amount of power the potentiometer can handle without overheating or failing...[/[QUOTE]
Rated power: 0.05W
Switch rated power: 12 VDC at 1.0A max
[QUOTE]...Resolution :
The accuracy of the potentiometer's resistance changes
Expressed as a percentage of the total resistance...[/[QUOTE]
I don't see this spec in the datasheet
[QUOTE]...Temperature coefficient :
How the resistance of the potentiometer changes with temperature...[/[QUOTE]
20℃-75℃:△R/R≤±5%
-25℃-20℃:△R/R≤±4.5%
[QUOTE]...Mechanical life:
The expected lifespan of the potentiometer
Usually expressed as the number of cycles it can endure...[/[QUOTE]
10,000 Cycles min.
[QUOTE]...Taper :
The relationship between the mechanical position and resistance ratio
The most common types are linear and logarithmic...[/[QUOTE]
Linear, (1B);B1 on Bourns pot specs
[QUOTE]...what is a weak pot...[/[QUOTE]
A noisy piece of crap that doesn't go anywhere near the full range of 0-5000ohms.
[QUOTE]...only that acquisition time is lower, a 10k pot could have 10 ohm resolution
in order to have "stable" 10bit result from a 10 bit ADC you would need 16 times over sampling.
to begin with you would need 16 times over sampling or use a 12 bit adc.
are you using 10 turn pots?...[/[QUOTE]
1 turn, 300 degrees
[QUOTE]...i cannot see how 0.25 degree resolution is useful for a 270 degree pot, most humans would be lucky to move it accurately in 2.00 degree increments
how is that going to work if the pots are not all identical, i have not encountered a pot that has a wiper that doesn't read 0 ohms to an end terminals at extreme rotation on my multimeter low ohms scale. how badly off are these pots . it would be easier to get better stock...[/[QUOTE]
I'm solo in this venture, so money is not unlimited, unfortunately.
[QUOTE]...in c i usually use a map function to get desired result range from an expected input range, about 1000 times easier and vastly more flexible than any hardware solution
int16_t map(int16_t x, int16_t in_min, int16_t in_max, int16_t out_min, int16_t out_max)
{
return (long) (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
1. I could have a QC test and fail any pot below a certain spec.
2. I could add code to calibrate each pot after assembly, and store a "conversion formula" in memory.
3. I'm hoping a combination of:
- raising VREF- to 0.5V,
- FVRx4,
- Henrik's idea in previous post can produce acceptable results.
There's only so much you can do on a limited budget.
Demon
- 28th February 2025, 23:17
AAAH CRAP!
My end quotes are whacked ( [/[QUOTE]), and it won't let me edit the post...
richard
- 28th February 2025, 23:35
whether your pot is 4.7k or 5.2k should make zero difference , an adc reading of a pot is ratio metric
if both pots are at 50% reading is vdd/2 no matter what the resistance is
Demon
- 1st March 2025, 00:15
whether your pot is 4.7k or 5.2k should make zero difference , an adc reading of a pot is ratio metric
if both pots are at 50% reading is vdd/2 no matter what the resistance is
I set at 200ohm on multimeter to get more accurate reading:
left pin to wiper = 2.5R
right pin to wiper = 2.6R
left to right = 4K7
It doesn't go all the way down to 0, or up to 5K.
ADC readings for this pot are 2 - 254 (I had removed 2 bottom bits).
EDIT: I was using 20K setting for all readings before.
Demon
- 1st March 2025, 00:23
I went back and did same readings at 200 ohms on the other pot that had ADC from 0 - 255:
left pin to wiper = 2.5R
right pin to wiper = 1.9R
left to right = 5.05K (at 20K ohms)
richard
- 1st March 2025, 00:48
10 bit adc with vref of 4.048 v = 3.95mV / step
2.6 ohm/4700ohm * 5.00 v vdd = 2.76 mV
the error does not match , your figures are out by 400%
Ioannis
- 1st March 2025, 09:37
That 2.5ohms is just OK. You should read 0 or 255 at the ends of the pot.
Ioannis
Demon
- 3rd March 2025, 01:57
[U]...ADC readings for this pot are 2 - 254 ([I]I had removed 2 bottom bits...
I'm an idiot. I thought I was being smart by ignoring any ADC variation under 3, turns out I was causing my own problem.
if ADCinput <> oldADC1 then
ADCinput = ADCinput >> 2
if ADCinput < oldADC1 then
ADCdiff = oldadc1 - adcinput
else
ADCdiff = adcinput - oldadc1
endif
IF ADCdiff > 2 THEN
...process ADC,,,
...
If ADC falls on 1-2 or 253-254 as turned fully, it would never update when hitting 0 or 255.
It was just random luck it was always THAT pot that did it, and not the 2nd pot.
I should change my sig to:
"I'm my worst enemy"
Demon
- 12th March 2025, 06:13
16F18855 with 5K pot
So I have 2 rotary pots that refuse to go down to ADC=0. So I thought it was a perfect occasion to practice using Vref-.
I've gutted my code so there's only 1 pot being scanned:
#CONFIG
__config _CONFIG1, _FEXTOSC_OFF & _RSTOSC_HFINT32 & _CLKOUTEN_OFF & _CSWEN_OFF & _FCMEN_ON
__config _CONFIG2, _MCLRE_ON & _PWRTE_OFF & _LPBOREN_OFF & _BOREN_ON & _BORV_LO & _ZCD_OFF & _PPS1WAY_OFF & _STVREN_ON & _DEBUG_OFF
__config _CONFIG3, _WDTCPS_WDTCPS_11 & _WDTE_OFF & _WDTCWS_WDTCWS_7 & _WDTCCS_LFINTOSC
__config _CONFIG4, _WRT_OFF & _SCANE_available & _LVP_OFF
__config _CONFIG5, _CP_OFF & _CPD_OFF
#ENDCONFIG
DEFINE OSC 32
DEFINE ADC_BITS 10 ' 10-bit Analog to digital
DEFINE ADC_SAMPLEUS 5 ' Set sampling time in uS
DEFINE HSER_RXREG PORTC
DEFINE HSER_RXBIT 7
DEFINE HSER_TXREG PORTC
DEFINE HSER_TXBIT 6
DEFINE HSER_RCSTA 90h ' Enable serial port & continuous receive
DEFINE HSER_TXSTA 24h ' Enable transmit, BRGH = 1
Define HSER_BAUD 115200
DEFINE HSER_CLROERR 1 ' Clear overflow automatically
DEFINE HSER_SPBRGH 0
DEFINE HSER_SPBRG 68
;--- Setup registers -----------------------------------------------------------
BAUDCON.3 = 1 ' Enable 16 bit baudrate generator
FVRCON = %0000000 ' FIXED VOLTAGE REFERENCE CONTROL REGISTER
ADCON0 = %10000100 ' ADC CONTROL REGISTER 0
' bit 7 ADON: ADC Enable bit
' 1 = ADC is enabled
' bit 2 ADFRM0: ADC results Format/alignment Selection
' 1 = ADRES and ADPREV data are right-justified
ADCON2 = %00000000 ' ADC CONTROL REGISTER 2
' bit 2-0 ADMD<2:0>: ADC Operating Mode Selection bits(1)
' 000 = Basic (Legacy) mode
ADCLK = %00001111 ' ADC CLOCK SELECTION REGISTER
' bit 5-0 ADCCS<5:0>: ADC Conversion Clock Select bits
' 1111 = FOSC/32
ADREF = %00010000 ' ADC REFERENCE SELECTION REGISTER
' bit 4 ADNREF: ADC Negative Voltage Reference Selection bit
' 1 = VREF- is connected to VREF- pin
' 0 = VREF- is connected to AVSS
' bit 1-0 ADPREF: ADC Positive Voltage Reference Selection bits
' 11 = VREF+ is connected to FVR_buffer 1
' 10 = VREF+ is connected to VREF+ pin
' 00 = VREF+ is connected to VDD
WPUA = %11110011
WPUB = %11111111
WPUC = %00111111
ANSELA = %00010111 ' Pin A4 = ADC (B10K) ... not implemented
' Pin A3 = SW input 3
' Pin A2 = Vref-
' Pin A1 = ADC (B5K w/SW)
' Pin A0 = ADC (B5K)
ANSELB = %00000000
ANSELC = %00000000
TRISA = %00011111 ' Pin A4 = ... not implemented
' Pin A3 = ... not implemented
' Pin A2 = Vref-
' Pin A0 = ADC input 0
TRISB = %00000000 ' Pin B7 = ...not available, ICSPDAT
' Pin B6 = ...not available, ICSPCLK
TRISC = %11000000 ' Pin C7 = RX *** Datasheet requirement, INPUT ***
' Pin C6 = TX *** Datasheet requirement, INPUT ***
SW var PORTA.3 ' ... not implemented
MsgData var byte[3]
MsgCode VAR BYTE
ADCinput var WORD
ADCcalc var WORD
ADCdiff var WORD
OldADC var WORD
OldADC0 var WORD
OldADC1 var WORD
Pause 1500 ' Let PIC and LCD stabilize
OldADC0 = 9999
goto Mainloop
;--- Subroutines ---------------------------------------------------------------
SendData:
MsgData[0] = MsgCode : MsgData[1] = ADCcalc.byte1 : MsgData[2] = ADCcalc.byte0
hserout [ MsgData[0], MsgData[1], MsgData[2] ]
while TX1STA.1 = 0 ' Check TRMT bit
wend
oldADC0 = ADCcalc
RETURN
Mainloop:
rem ADC A0 test
MsgCode = 0 ' Record type
adcin 0, ADCinput
ADCcalc = ADCinput >> 2
if ADCcalc < oldADC0 then
ADCdiff = oldADC0 - ADCcalc
else
ADCdiff = ADCcalc - oldADC0
endif
IF ADCdiff > 2 then ' Check for Diff over 2
if ADCcalc <> oldADC0 then ' ADC value changed
GOSUB SendData
endif
ELSE
IF ADCdiff > 0 then ' Check for Diff over 0
if ADCcalc = 0 then ' Reached end of rotation
GOSUB SendData
ELSE
if ADCcalc = 255 then ' Reached end of rotation
GOSUB SendData
endif
endif
endif
endif
GOTO Mainloop
end
I've added banks of caps on the wiper-to-VSS, as well as just before the VDD pin to the pot (0.1uF, 0.01uF and 0.001uF).
I shift right only 2 digits and that seems to have stabilized things quite a lot; no noticeable jitter so far tonight. 256 seems like a workable range for me so far.
The pot has a reading of 2.0mV when full right:
9934
The Vref- pin reads at 15.7mV (used voltage divider 1K (0.985R really) / 3R:
9935
Pot 0 does not go below ADC=12,and is transmitted on the Saleae probe:
9936
And shows up nicely on LCD on 2nd PIC:
9937
I don't get it. I thought setting Vref- at 15.7mV meant that anything reading below that would read as 0...? I thought I was essentially raising the VSS lower range for ADC.
ADREF = %00010000 ' ADC REFERENCE SELECTION REGISTER
' bit 4 ADNREF: ADC Negative Voltage Reference Selection bit
' 1 = VREF- is connected to VREF- pin
' 0 = VREF- is connected to AVSS
I'm obviously missing something stupid again, but I don't see what. Or I totally misunderstood what Vref- does in life.
richard
- 12th March 2025, 06:59
The pot has a reading of 2.0mV when full right:
each adc step is 4.88mV therefore it should read zero
you get a reading of 12 , after un-dividing by 4 that's a count of 48 or 0.234 volts
it virtually has to be power supply noise.
no amount of dicking around with reference voltage's is going to eliminate that much noise
eliminate your power supply as the culprit by using 3x fresh AA batteries in its place
Acetronics2
- 12th March 2025, 07:42
It would be nice to see the electrical scheme of your test circuit ...
pics lead me to think it's a hardware / wiring problem ... as Richard nailed it :rolleyes:
Alain
Demon
- 12th March 2025, 08:19
I'll try the batteries tomorrow.
Here's a view of the breadboard. I removed a 2nd pot with switch, and left just the essentials.
9938
I still don't understand how 15mV at VREF- is not able/sufficient to deal with 1.5mV at the pot...?
Acetronics2
- 12th March 2025, 10:09
@ first, I do not see the " magic " decoupling caps that have to be located just close to the µP ...
richard
- 12th March 2025, 10:22
I still don't understand how 15mV at VREF- is not able/sufficient to deal with 1.5mV at the pot...?
15mV pales into insignificance with respect to 0.234 volts of noise
Demon
- 12th March 2025, 17:15
ADC still only goes down to 12 even when battery-powered and other breadboard disconnected (3 new alcaline 1.5V).
Vref- of 15mV still connected.
https://youtu.be/wE1g1mFauHc?si=Iout6AhRGko73MdA
I always thought battery-power was essentially noise-free (in a "clean" environment); either a straight line going up when charged, or slowly down when powering a circuit, or even much slower down over time when disconnected.
I don't get it.
Demon
- 12th March 2025, 17:16
I will add 2 other caps now.
EDIT: 0.1uF, 0.01uF and 0.001uF right at the pin, no difference, ADC stops at 12.
Demon
- 12th March 2025, 17:40
Oh god..... (smacks-face)
I cleaned up the WPU, I think I had one on ADC.
WPUA = %11111010 ' Pin A2 = Vref-
' Pin A0 = ADC (B5K)
WPUB = %11111111
WPUC = %00111111 ' Pin C7 = RX
' Pin C6 = TX
ANSELA = %00000101 ' Pin A2 = Vref-
' Pin A0 = ADC (B5K)
ANSELB = %00000000
ANSELC = %00000000
I just tried again with the batteries and it went down to ADC=0.
Arrrgggghhhhh.......
Demon
- 12th March 2025, 18:15
I've removed all caps, and this pot works perfect. The TPS56637 circuit is that clean when it comes to noise.
WPU was fighting with the ADCin pin, trying to pull it up.
Now the slider pots might still be a problem; I'll test those later. But right now I'm putting back the 2nd pot with switch.
https://youtu.be/8oDoYFbhC-A?si=NCh7zJ_GsgGlN1S1
I'll probably put several of those caps back on, I'll see (like at ADCin pin).
Unfreakingreal... :bangheadinwall:
EDIT: Oh yeah, definitely had to put the caps back on. The 2nd ADCin started affecting the 1st.
I put all the caps back in, everything is stable.
richard
- 12th March 2025, 22:37
I cleaned up the WPU, I think I had one on ADC.
more proof that blindly setting pin registers is bad practice and serves no purpose .
the safe setting is to leave them as default unless you need them to be different
if you use mcc its perfectly clear how each pin is set and self documenting
9940
Demon
- 13th March 2025, 21:58
I'm still using MCS+.
Can we use MCC standalone? Or do we have to "create a project" and do the entire process within MPLAB?
I have both the MeLabs USB programmer and PK4. I suppose I could set up an older PC with MCS+ and Melabs pgmer, and use PK4 with MPLAB on this more powerful PC.
Ioannis
- 13th March 2025, 22:14
Yes you can install a stand alone application. No need to have the complete IDE.
https://ww1.microchip.com/downloads/aemDocuments/documents/DEV/ProductDocuments/SupportingCollateral/mcc-installer-5.5.1-windows.exe
Ioannis
richard
- 13th March 2025, 22:19
Or do we have to "create a project" and do the entire process within MPLAB?
mcc stand alone is ok it works for all the chips i typically use. i don't know if they keep it UpToDate.
the latest mcc with mplabx6 is wildly different and i don't like the look of it so i don't use it
creating a project takes 2 or 3 minutes tops , its excellent for setting any and all modules including the osc not just the pins
you are only interested in the mcc generated files , they translate into pbp fairly easily with a bit of practice. the project has no other role other than documentation.
it matters not between mcc standalone and mplabx5.xx the effort and time are virtually identical
Ioannis
- 14th March 2025, 07:50
There is a much simpler tool under GCB (Great Cow Basic project) called PPS Tool. It is used for setting the PPS registers with ease.
This free compiler has great potential and good support (forum and YouTube videos).
In general it is easier to setup a PIC with GCB than PBP. Have not used it much to have a detailed opinion.
Ioannis
Powered by vBulletin® Version 4.1.7 Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.