Xinyuan-LilyGO / T-Display-S3

MIT License
733 stars 174 forks source link

ADC fluctuation #152

Closed 369Martin369 closed 11 months ago

369Martin369 commented 1 year ago

Hi, for a project I use now the built in ESP ADC. But I'm disappointed about its stability. Even with 1000 multisamples and dismissing 80% of extreme values, it is unstable as hell!

=> Seems that the reference voltage is not stable at all and flickers heavily depending on CPU load. A 100nF capacity from ADC Pin to Ground did not solve problem, so it must be therefore the reference voltage.

Can you give me hints where I can solder add'l 10uF and 100nF to stabilize ref voltage? Any schematics to offer??

Thanks a lot!

teastainGit commented 1 year ago

What value of resistors are you using for the voltage divider? As I'm sure you've heard...the ESP32 ADC is atrocious. If ADC is critical to your design might I suggest a discrete ADC? Like the Adafruit ADS1115 16-Bit ADC that communicates over i2c.

krupis commented 1 year ago

Dont bother with the ESP built in ADC. Its one of the worst out of all MCU's (NRF,STM,Atmegas). You should not expect better accuracy than +-50mV.

If you need high accuracy, use external ADC chip. For most projects I use ADS7828. I can get down to +-5mV accuracy with that one which is more than accurate for most projects

GaryInSanDiego commented 6 months ago

I tried working with the reference voltage on the LILYGO T-Display-S3 LCD along with the LM4040. I tried using a diode in both directions. I came to the conclusion that the external reference pin was always connected somehow, and I could measure current flow going in both directions. I gave up using an external reference, and instead used a hard coded value (const float referenceVoltageConst = 3.2804;). Using my own voltage divider (20K & 5K resistors), I could measure somewhat decent voltage values of hybrid battery modules (up to 9.0 volts, etc.). Also, I don't think the LM4040 was providing a voltage of 4.096 like it should have either.

teastainGit commented 6 months ago

What pin is the reference voltage? I am interested in what you are trying to do!

GaryInSanDiego commented 6 months ago

Oops... I was referring to the AREF pin on the Arduino boards. The LILYGO T-Display-S3 does not have an AREF pin. I worked on this 14 months ago and forgot that I switched to using the LILYGO T-Display-S3 LCD. Back then, I was using the Arduino NANO, which today I confirmed only supports an internal reference voltage, which explains what I experienced with the NANO board. https://support.arduino.cc/hc/en-us/articles/360018922239-About-the-AREF-pin Other Arduino boards do support an external AREF. Still, on the T-Display-S3 board, I find it beneficial to hard code the reference voltage to something like 3.2804. Every 10 seconds, my project tracks the voltage and amps of a single Panasonic Hybrid car module with the load of a single headlight (about 3.5 amps), and the battery voltage is usually between 6.9 and 8.40 volts. I use a voltage divider of 20K & 4K resistors which lets me track the voltage up to 13.2 volts (3.3 volts * 4). I use an ACS712 5A Hall Effect Current Sensor Modules to track up to 5 amps. I supply the ACS712 with 3.3v and measure the 3.3v analog value (using a hard coded voltage of 3.2804v) and 12 bits of ADC accuracy (4,096 values). The ACS712 module provides a voltage which you then convert to amps using a formula. I find that I need to keep this sensor away from other wires to get consistent values. I use it to captures amps, but use my voltage divider (20K & 5K) to capture voltage. I am thinking of using your suggestion to use the ADS1115 16-Bit ADC to capture more accurate ADC values. Here is my code for capturing ACS712 amp values. I floats and doubles in the calculations, which returns more refined results.

const float AnalogToDigitalResolution = 4096.0; // 10-Bits = 1024, 12-Bits = 4096 const float referenceVoltageConst = 3.2804; // 3.2804 3.28 3.38555 3.3888 const float ACS712_scale_factor = 0.181; // ACS712 5A current sensor 0.185 double ACS712_zeroPoint = referenceVoltageConst / 2.0; // The sensor voltage is 3.3 Volts, the ADC is 3.28 volts double resADC = referenceVoltageConst / AnalogToDigitalResolution;

double readAmperage(int analogPin) { int sampleSize = 100; long analogValue = 0; double avgAnalogValue = 0.0; double ACS712_Voltage = 0.0; double ACS712_Current = 0.0; float voltageDifference = 0.0;

for (int i=0; i < sampleSize; i++) { analogValue += analogRead(analogPin); delay(1); } avgAnalogValue = analogValue / float(sampleSize); // calculate avg analog value

ACS712_Voltage = avgAnalogValue * resADC; // convert analog value to voltage

voltageDifference = ACS712_Voltage - ACS712_zeroPoint; // report both negative amps and positive amps as positive values if (voltageDifference < 0.0) voltageDifference = voltageDifference * -1.0; // convert negative amp flow to positive amp flow

// Convert ACS712_Voltage into Current using Scale Factor ACS712_Current = voltageDifference / ACS712_scale_factor * 2.0; ACS712_Current -= 0.25; // fudge to zero when no current if (ACS712_Current < 0.0) { ACS712_Current = 0.0; }

return (ACS712_Current); }

teastainGit commented 6 months ago

Thanks for getting back. Cool project, the ADS1115 is well respected. -Terry