G6EJD / ESP32-ADC-Accuracy-Improvement-function

A function that improves the default ADC reading accuracy to within 1%
Other
200 stars 34 forks source link

How can I map 0-5 adc range to ESP32 0-3.3v range #3

Closed futechiot closed 6 years ago

futechiot commented 6 years ago

Hello there,

This is not an issue but I need your help to complete my product.so I'm posting here.

I have 8 analog sensors for water quality measurement. They all have metering circuit to measure electrode readings. For example https://www.dfrobot.com/wiki/index.php/Analog_ORP_Meter(SKU:SEN0165)

these sensors and metering circuits are design for an ARDUINO for 5volt and for 10 bit resolution.( 5v AREF that gives 0-1023 range) all the codes are design for Arduino. So they all are giving me proper output.

But I want send those 8 sensors data over WiFi..and ESP32 has more analog pins..

Using your functions I'm able to change the resolution to 10 bit... But the problem is this gives me 10 bit resolution for 3.3 volt(for 0 it goves 0 and for 3.3 it gives 1023) all the codes and output depends on ADC counts And ESP32 gives 1023 on 3.3v so i will never get output for voltage greater then 3.3.

So how can I achieve same result as Arduino.. I want same 5v 10 bit resolution as Arduino.. because changing all the code is time consuming and may be I will not getting proper results..

So how can I achieve this.. Any suggestions appreciated.

futechiot commented 6 years ago

Obviously In ESP32 for above 3.3v I get 1023. So is there anything to change AREF of ESP32 !? Or Is there anything to map 5volt 10 bit resolution to 3.3v

Please help me

G6EJD commented 6 years ago

The maximum input to any ESP32 input is Vdd+10% of Vdd =3.3 volts, but really you should not exceed volts. Changing the reference value will not help as the input has clamping diodes. Like most ESP8266 boards which have a 220K+100K voltage divider you should add something similar for the ESP32. You need to divide the input voltage from 5 to 3 so that would require a divider value of 3/5 =0.6. So connect a 10K series resistor to your 5volt source, then connect the other end to a 15K resistor to ground and then wire the ADC input to their intersection. You will then read 0-5 volts or 0-1023 or 4096 if you varied the values. Look up voltage divider on google there are usually online calculators if your not sure

futechiot commented 6 years ago

@G6EJD Thank you for your quick response. but I'm little confused can u please explain sir. according to your answer by that resistor divider can I able to measure voltage above 3.3?????

sorry but I'm stuck and confused.

G6EJD commented 6 years ago

Yes, if you place two resistors in series for on 5v to gnd and the ADC is connected to their intersection then at 5v input the ADC will measure 3v I’ve calculated the values so you don’t go over Vdd or 3v.

If you wanted you could measure many more volts perhaps 0-10v by varying the values.

https://learn.sparkfun.com/tutorials/voltage-dividers

The top value for you is 10K and the bottom value 15K

Any problems please ask

G6EJD commented 6 years ago
Vdc (+5v)
10K --------------------- ADC (VP or VN) or ESP32 15K
--------------------- Gnd OF ESP32

Gnd

Vout at ADC = 5 x 15 / (10+15) = 3 volts when input is 5volts

futechiot commented 6 years ago

@G6EJD hello sir I got same answers to use the voltage divider. but by using voltage divider the ADC conversion counts change. when I'm giving 5 volts I get (1023) counts on 3v3 i get (665) counts on 2.27 I get 456-457 counts

now if im using voltage divider i get 1023 counts instead of 665 that is obvious. so is there any logic to achieve these using MAP or anything..??

because i need same count and LATER ON IM using that counts for calculation for parameter value in that equation there is 5volts in calculation

G6EJD commented 6 years ago

You could map the ADC reading straight to volts if that’s what you mean, example: Int millivolts = map(adcreading, 0,1023,0,5000);

Why milli volts because the map function is an integer function.

So, for ADC Readings: 0 then millivolts = 0 500 then millivolts = 2500 1023 then millivolts = 5000 Then float volts = millivolts/1000;

G6EJD commented 6 years ago

float Volts = map(ADC_reading,0,1023,0,5000)/1000;

futechiot commented 6 years ago

@G6EJD thank you for your support dude😇. I'm able to read my sensor full range on my ESP32 board using voltage divider.. but the counts are different now.. But can you give me one more advise please..

Now, is there any mapping logic (in code) to get 5v ADC count = 3.3v ADC count.

Again thank you for all your support

G6EJD commented 6 years ago

I'm not really understanding what your trying to achieve, do you mean in two different environments? 0-1023 will equate to 0 - 5 volts with the current resistor voltage divider. So I think you would like to make it such that 0-1023*3.3/5 = 0-5 volts? In other words over scale the input so that 0-675 = 0-5volts? If so then: if (board_1 ) float Volts = map(ADC_reading,0,675,0,5000)/1000; else float Volts = map(ADC_reading,0,1023,0,5000)/1000;

futechiot commented 6 years ago

@G6EJD using voltage divider I'm able to step down my sensor output voltage (0-5 to 0-3.3v). by achieving this I'm able to read into my esp32 (cause it can read up to 0-3.3) now, I'm getting 0 ADC COUNT on 0volts and 1023 counts on 3.3v.

I mentioned earlier I have codes for 5v ADC, and those counts are used for calculation.

SIR, I WANT TO ACHIEVE THIS:
now I'm getting 0 to 1023 on my esp32 as a 3.3-volt reference can I convert or manipulate those counts as 5V ADC?? see this sir for better understanding------> if the OUTPUT of my sensor is 3.3, then I'm getting 1023 on esp32 but I want 675counts like 5v ADC

and then I want to use in the calculation so that calculation goes on 5v ADC count. so that means in "CODING" I have to convert those count same as 5volt ADC counts(LIKE ARDUINO) and then I want to use for calculation.

3.3V ADC COUNTS(ESP32 ANALOG COUNTS) == 5V ADC COUNT (LIKE) I think this is possible in coding. can u help me out there.??

G6EJD commented 6 years ago

Have you solved this now?

Marco5424350 commented 4 years ago

no :c

G6EJD commented 4 years ago

What are you @Marco5424350 trying to do?

Marco5424350 commented 4 years ago

i'm not a professional about the topic, but i'm trying to get data of a PH sensor "4502C", the problem is that the sensor works with 5v and my calculate for get the PH is (valor)/1023*5.0v, im trieding to conect 5v in the vin port of esp32, to do more precis the measurement, but i have a problem with the resolution how i can see, :(

Marco5424350 commented 4 years ago

the objective of the project is send the data to firebase :c but this is my problem :C and i dont know how resolve it

G6EJD commented 4 years ago

What board type are you using? What ADC input pin? the default resolution of the ADC is 4096, so you need to use that value, unless you have adjudged the ADC input range down to 1v, unlikely. If the ESP32 has no voltage divider fitted, then you must fit one, us say 220k resistors like this Sensor output —-220K—-ADC input pin——220k——Gnd Now measurement = (ADC reading/4096)*2

Because of the loading applied to the voltage divider by the ADC input you may find it necessary to adjust the constant 2 either up or down to calibrate your reading, say 2.1 if the reading is too low or 1.9 if too high. Ideally measure the sensor output voltage and adjust the constant value 2 until you get the same value.

Marco5424350 commented 4 years ago

im using only a ESP32 , the PH SENSOR "4502C" have 6 outputs, but the most important are 3 (VCC, GND and Po) the last is a PH signal analog, im not a proffesional in electronic but i readed about this class that im implementing in the code that i leave in the end of the message,

the temperature sensor its work, because works with 3.3v. I connect the output of the esp32 rith the sensor and all its ok

And i trying to conect 5v to the input "VIN" of the esp32, and next i take the 5v and GND of the esp32 and conect to PH sensor, and apparently all its ok, but when i run de program appear me this

include

include

OneWire ourWire(2); //Se establece el pin 2 como bus de comunicacion OneWire DallasTemperature sensorTemp (&ourWire); // variable para sensor

void setup() { delay(1000); Serial.begin(115200); sensorTemp.begin(); //inicializacion sensor de temperatura pinMode(36,INPUT); //Sensor de PH VP /*

void loop() { int val = analogRead(36); float volt = float(val)/1023*5.0; Serial.print("PH = "); Serial.println(volt); //VP delay(1000); //TEMPERATURA sensorTemp.requestTemperatures(); //comando para leer temperatura float temp = sensorTemp.getTempCByIndex(0); //temperatura en Celsius Serial.print("temperatura = "); Serial.print(temp); Serial.println(" C"); }

Marco5424350 commented 4 years ago

img arduino

Marco5424350 commented 4 years ago

sorry for my bad english, i speak spanish and my english no is the best

G6EJD commented 4 years ago

In some respects it would be better to leave the ADC as default and cut out all of the ADC setup you have it’s not required and you’d get 4096 bit resolution.

You cannot input more than 3.3v to the ADC input so you must fit a voltage divider, from your readings your getting a maximum ADC reading of 1023 and so 1023/1024*5=5 add a voltage divider of 2 equal value resistors then your reading would be 2.5v.

Do you have two resistors of equal value? If so wire them as: PO—-Resistor—-ADCpin— Resistor— Gnd

Marco5424350 commented 4 years ago

ohhhh ok ok i understand better, so the best would be that leave the programming as it is and only applicate a voltage divider as you say, obviously change the calculate for (float volt = float(val)/4096*5), because as far as i understand in the input of the PH sensor are 5 volts, but in the output with the voltagger divider would be 3.3v, but I'm still not sure if this affects the calculations :c

G6EJD commented 4 years ago

Yes, for now leave the code alone and add the resistors as a voltage divider then the maximum 5v output of your sensor would be 2.5v then ideally adjust the *5 value to match a reading taken with a DVM.

In your calculation the voltage is 3.3v max so ADC Reading / 1024 3.3 2 (6.6) if you use two equal value resistors. Then your reading is absolute but it will need to be calibrated eg 6.6 or 6.5 or 6.7 depending on whether the reading is too high or low.

kalkulate commented 4 years ago

Hi! I know it is a bit late to bring this back up, but I followed your instructions for a similar problem of mine @G6EJD but have a couple questions if you have a minute.

I am using a 5v capacitive moisture sensor on an ESP32. I figured I would use a voltage divider of R1 1000 Ohms and R2 of 2000 Ohms to bring voltage from 5v to 3.3v. Is this incorrect and I should rather be using the same resistor value for R1 and R2?

When I did it with R1 is 1,000 Ohms and R2 is 2,000 Ohms I got really low number (~210). Then I tried it with 50 Ohms and 100 Ohms and just got 0 as a readout.

When I did R1 5,000 Ohms and R2 10,000 Ohms I got ~ 990 When I did R1 500,000 Ohms and R2 1,000,000 Ohms I got ~ 2400

Off the AOUT on the 5V sensor I am reading 3.65V with Multimeter before the voltage divider, and 2.26V after voltage divider.

So even the closest figures, which are the ones with the 500,000 Ohms and 1,000,000 Ohms are still way too low. (2400/4096*3.3=1.93V

Am I missing something? Clearly there is something going wrong, but I thought resistors just reduce current and not voltage, so I am surprised.

`int sensorpin = 25;

void setup(){

Serial.begin(9600); }

void loop(){

Serial.print("Moisture Sensor Value:@ "); Serial.print(float(analogRead(sensorpin))); delay(500); }`

G6EJD commented 4 years ago

Your problem is almost certainly the very high output impedance of your sensor, what type is it? You need to be using high values say 100K and 100K to divide the output in two then measure the voltage. What your seeing is the resistors you were using loading the sensor. To give you a better idea of how to solve this I need to know the type so I can look it up.

kalkulate commented 4 years ago

Hi,

Thanks for getting back to me.

This is what I have. It seems that most take 3.3v to 5v and look EXACTLY the same but mine only take 5v...

https://www.az-delivery.de/en/products/bodenfeuchte-sensor-modul-v1-2

https://cdn.shopify.com/s/files/1/1509/1638/files/Hygrometer_Modul_V1.2_Datenblatt_AZ-Delivery_Vertriebs_GmbH_d24d33d6-9496-4b26-8819-476bcb7184e8.pdf?82942

G6EJD commented 4 years ago

Ok I’ve found the schematic and see it’s output impedance is ~1MOhm, so very high, this is why you’ve had difficulty reading it. The problem is there is a loading from the ESP32 ADC input and any additional voltage divider will further add to the load. Another factor is getting enough input current to drive the ESP32 ADC input, the ADC input impedance is about 200K. So I recommend you use 2x 100K resistors and now we need to know what board your using, does it have an on-board voltage divider or what ADC input pin are you using?

kalkulate commented 4 years ago

Wahoo, super exciting to be moving forward! I'm wiring it up now but in the meantime I have an ESP32 DevKitC v4. I have it going into pin 25.

esp32_devkitc_v4-sch.pdf ESP_-_32_NodeMCU_Developmentboard_Pinout_Diagram

https://www.az-delivery.de/en/products/esp-32-dev-kit-c-v4

kalkulate commented 4 years ago

20201015_202136

I have it running now with only "0" readings coming out. If I hook up without the voltage divider it reads "4095".

The read the voltage on the AOUT of the sensor and get 0.031V when voltage divider is active. If I read it without voltage divider the AOUT is reading 3.76V.

Also, I don't really know what it means, but reading the resistance directly off the sensor:

kalkulate commented 4 years ago

could it be that I want a higher resistance, so that I use an R2 that has a similar resistance to my sensor, so 1 million ohms?

G6EJD commented 4 years ago

You can’t do that as the ESP32 ADC input current will be too low to give correct operation, it may work but you will get erratic readings and huge variations. The minimum input current is approached when the output impedance of the device being measured is ~470K, for successful operation you would need to fit an intermediate buffer say an op-amp to lower the impedance, but this affects power consumption if battery operated.

kalkulate commented 4 years ago

Ok I’ve found the schematic and see it’s output impedance is ~1MOhm, so very high, this is why you’ve had difficulty reading it. The problem is there is a loading from the ESP32 ADC input and any additional voltage divider will further add to the load. Another factor is getting enough input current to drive the ESP32 ADC input, the ADC input impedance is about 200K. So I recommend you use 2x 100K resistors and now we need to know what board your using, does it have an on-board voltage divider or what ADC input pin are you using?

So without an Amp it seems this these are only good for the Arduino Nano... I'll just get a sensor that runs on 3.3v.. simple enough. Thanks

Last question, though - how did you get this info about 1 MOhm impedance... I look everywhere on data sheet and didn't see it.

G6EJD commented 4 years ago

The schematic is here: https://how2electronics.com/interface-capacitive-soil-moisture-sensor-arduino/

You can see the output is across a 1M resistor, it’s a bad / poor design. Better to use one of the many two prove types that have an on-board buffer amplifier and will give much better performance. The clue was also in the readings you were getting as you increased your voltage divider resistor values the load on the sensor became less and it started to get more accurate but then you ran into ESP32 ADC reading issues due to insufficient input current.

kalkulate commented 4 years ago

Thanks.

Fyi, I got a new set of capacitive moisture sensors and despite them listing 3.3v capability, they seem to only work with 5v input... pity. I would love to get the prong ones, but they are supposedly getting corroded even faster than these do and I need them to last... I have read that graphite probes can work though. Is that what you mean?

I played around longer with these and seem to get a stable and consistent readings

The output current to the sensor is 10mA and the AOUT sensor reading gives off about 150 µA... so about 105µA after the voltage divider and into the ESP32 when using 5k and 10k resistors, and down to 28-45 µA when using the 100k resistors.

So, I suppose less resistance means less heat loss, so I should use as low a resistance as I can get away with, but at the same time the higher resistance gives me a larger wet/dry spread, so that gives me more precision..?

I've attached my readings, for the good of science :)

Seriously, thanks a lot for being my sounding board here. Screen Shot 2020-10-26 at 19 13 51

G6EJD commented 4 years ago

Yes to get the best results you have to use the highest practical resistor values on the ESP32 ADC input say 470k and 470k. I think what I would do is buy two of these (example only): XLUX T10 Soil Moisture Sensor Meter - Soil Water Monitor, Hydrometer for Gardening, Farming, No Batteries Required https://www.amazon.co.uk/dp/B014MJ8J2U/ref=cm_sw_r_cp_api_i_dlC_p4ZLFbWMN26ES Because they use a stainless steel probe body and are designed to last. They don’t use a battery but by some chemical process they generate a current to drive the meter. For the meter to be driven a potential difference has to be generated and if you replace the meter with a resistor you will get a voltage that can be measured. Use the second device to calibrate the readings. It will take done work, but not much and you get a long lasting sensor. There may be a need to use a buffer op-amp but these are cheap and can be purchased from AliExpress too.

ranjanpal111 commented 3 years ago

Hi, can the analog inputs of ESP32 measure bipolar signal i.e. signals with both positive and negative half cycles oscillating about mean of "0" volts?

G6EJD commented 3 years ago

To do this you’d need to fit let’s call it an artificial ground made of two resistors like this and then to AC couple the input: I’ll try to draw it here:

                         3.3v
                           |
                          R1
                           |
Input —— ——ADC pin
                          R2
                           |
                         Gnd 

R1=R2=100K C=1uF

In words, R1 to 3.3v, then to ADC input pin, the R2 from ADC input pin to ground. Input signal from source to capacitor C then to the ADC pin.

Well the value of C is a function of the lowest frequency you want to measure in its simplest terms it’s C = 1/(2.pi.f) where pi is 3.141 and f is the frequency of measurement. Another complication is the output impedance of the circuit being measured, if very high say 100K then it won’t be able to drive the measurement circuit but if low (usually the case) no problems.

G6EJD commented 3 years ago

A strict answer to your question is no, only from 0 to 3v, or depending on setting

kalkulate commented 3 years ago

Since this thread is still kicking, and since I am today happening to be deconstructing as per your suggestion - I thought I'd post a picture. Now, you say resistor between the two main terminals? (the wires below go to a 3-way switch between light sensor, pH, and moisture.

And then I try to pick up a voltage reading? You said the gauge itself, which I will will replace, is the resistor? I have put the voltage/ current meter all over and didn't get any readings 0.0000

20201211_195000 20201211_195005 20201211_195008

G6EJD commented 3 years ago

You wont' get much of a potential difference with that meter maybe a few milli-volts; if that, they work at very low voltages as they are passive. The meter will deflect when a small current flows.

kalkulate commented 3 years ago

I think what I would do is buy two of these (example only): XLUX T10 Soil Moisture Sensor Meter - Soil Water Monitor, Hydrometer for Gardening, Farming, No Batteries Required https://www.amazon.co.uk/dp/B014MJ8J2U/ref=cm_sw_r_cp_api_i_dlC_p4ZLFbWMN26ES Because they use a stainless steel probe body and are designed to last. They don’t use a battery but by some chemical process they generate a current to drive the meter. For the meter to be driven a potential difference has to be generated and if you replace the meter with a resistor you will get a voltage that can be measured. Use the second device to calibrate the readings. It will take done work, but not much and you get a long lasting sensor. There may be a need to use a buffer op-amp but these are cheap and can be purchased from AliExpress too.

Isn't this basically what you had mentioned?

G6EJD commented 3 years ago

Yes but I expect to get a usable voltage you will need a high value resistance and then this will be loaded by the esp32 voltage divider leading to readings that are non-linear, but as you mention the addition of an isolating buffer amplifier will solve that, actually you could use that across the meter terminals and leave the meter running. You will need to carefully select the op-amp to enable it to read from 0 to 3.3 volts on a single supply rail of 5v. LM324 might work you need to check the data sheet.