adc woes
-
I'm trying to measure the voltage of a 16v DC supply by applying it to an analog pin via a 100k/4k7 voltage divider. My multimeter shows the pin sitting at exactly 721mV. But when I run
import time, machine adc=machine.ADC() for i in range(9): val=adc.channel(pin='P20'); v=val.voltage(); print(v, ' ', end='')
I'm seeing 10mV of variation
693 691 701 692 702 701 691 700 701 >
Averaging
import time, machine for i in range(10): Vav=0 adc=machine.ADC() for i in range(10): val=adc.channel(pin='P20'); v=val.voltage(); Vav+=v print(Vav/10, ' ', end='')
helps
694.1 696.2 695.7 694.6 693.5 695.4 695.5 692.6 694.6 694.4 >
but still 3.5mV (0.5%) variation. I really need 3 significant figures for this, what am I missing?
-
@kjm So you are averaging over 1000 values. You can also use a low pass filter, which is a little bit simpler
See also the lessons and analysis by Bernd Boser:
https://github.com/bboser/IoT49
and especially
https://github.com/bboser/IoT49/blob/master/doc/analog_io.md
which shows a noise of about 25 LSB. So your averaging of 1024 values (25*25=625) matches that. B.t.w: good ADCs have a noise <= 1 LSB.
-
I couldn't get any improvement with a 100nF ceramic across the 4k7 but did better with brutish code
import time, machine adc=machine.ADC() for i in range(8): Vav2=0 for i in range(128): Vav1=0 for i in range(128): val=adc.channel(pin='P20'); v=val.value(); Vav1+=v av=Vav1/128#; print(av, ' ', end='') Vav2+=av x=Vav2/128; print('%.0f' % x, ' ', end='')
2687 2687 2687 2687 2687 2688 2687 2687 >
-
@kjm You miss nothing. The ADC of the ESP32 is bad. It helps a little bit, if you add a low impedance capacitor (e.g. 10 nF Ceramic) with short leads as close as possible to the ADC input you are using.
Besides that: If you need low noise, good precision and linearity, use an external ADC.Note: You do not have to re-init the channel in the loop all the time.