Introduction: ESP8266 ADC - Multiple Analog Sensors

Although the ESP8266 -07 and -12 only have one ADC pin, it doesn't mean that you are limited to only one analog sensor per module. You can use many!

However, in order to use multiple sensors you will need to 'multiplex' the sensors. Multiplexing simply means that you will turn a sensor on, read the sensor, then turn the sensor off then move to the next sensor.

Here is a quick, down and dirty Instructable that should get you started with multiple analog sensors.

Lets begin!

Step 1: Connect Your Sensors.

For this project I am using three analog sensors. A photoresistor, a thermistor and a sliding rheostat.

These are what I had in the parts box. Feel free to substitute.

I used:

ESP8266-12, a -07 will also work. Three available GPIOs are needed for this project.
ESP Flashed with NodeMCU, required for this demo.
2 10K resistors
1 680R resistor
3.3v voltage regulator (if necessary)
1 Photoresistor (LDR)
1 10K Thermistor
1 10K Slider
3 Diodes (I'm using 1N4007s)

The values of the resistors used are dependent on the analog sensors. Notice I am using no resistor with the slider.

There is considerable trial and error in setting this up, trim pots come in very handy.

The Diodes are the key to isolating the sensor circuits not being read. Diodes restrict current to one direction. Without diodes the sensors still work, however they interact with each other. For instance, shining a light on the LDR will raise the value at its GPIO, however it will also reduce the value of the other sensors. Diodes isolate the circuits.

Step 2: The Multiplexing Script.

In order to multiplex, only one sensor can have a complete circuit at a time. By setting the the GPIO to HIGH, we are sending ~3.0v to that sensor and completing the circuit. The others, being set to LOW send no voltage. This essentially creates a ground to ground connection. No current.

After we send the voltage, we read the ADC pin and print out the value. We can also save that value in a variable.
This code 'var1 = adc.read(0)' will work. We can then manipulate the value and convert as required.

After we read or save the reading from the sensor, we turn it off and move to the next sensor.

The delay is not necessary, but it makes me feel better.

All the GPIOs being used with analog sensors should be set to LOW except when reading them.

There is no special reason for using GPIOs 16, 14 and 12. Any three would do. Avoid using GPIO0.

Source file here.

___________________________________

-- multisensor.lua
-- ---------------

--configure pins
gpio.mode(0,gpio.OUTPUT) -- GPIO 16
gpio.mode(5,gpio.OUTPUT) -- GPIO 14
gpio.mode(6,gpio.OUTPUT) -- GPIO 12

--set all pins to LOW - no voltage
gpio.write(0,gpio.LOW)
gpio.write(5,gpio.LOW)
gpio.write(6,gpio.LOW)

-- print the ADC value with all pins low
print("\nADC: Both GPIOs LOW start: "..adc.read(0))
-- Send voltage to GPIO 16 completing the circuit for this sensor.
gpio.write(0,gpio.HIGH)
-- short delay before reading, 100ms
tmr.delay(100000)
-- Read the ADC pin or assign to varable var = adc.read(0)
print("\nADC: GPIO 16 HIGH LDR: "..adc.read(0))
-- Return GPIO 16 to LOW, no voltage.
gpio.write(0,gpio.LOW)
-- short delay 100ms
tmr.delay(100000)
-- repeat for the other two sensors.
gpio.write(5,gpio.HIGH)
tmr.delay(100000)
print("ADC: GPIO 14 HIGH Temp: "..adc.read(0))
gpio.write(5,gpio.LOW)
tmr.delay(100000)
gpio.write(6,gpio.HIGH)
print("ADC: GPIO 12 HIGH Slider: "..adc.read(0))
gpio.write(6,gpio.LOW)
-- again read ADC, this reading should be very close to the 'start reading'
print("\nADC: Both GPIOs LOW end: "..adc.read(0))

Step 3: Fine Tuning.

Upload this script to your ESP and 'dofile'.

You should see values for the sensors! Each time you run the script the sensors are read and the results printed.

I put a flashlight on the LDR and ran the script. The LDR registered 1024. In the last run I had moved the slider.

As I mentioned earlier, finding the right combination of resistor values is crucial. Keep in mind that adding sensors, including diodes and resistors will alter the voltage across other sensors. This will test your 'Tweak and peak' skills.

There is a discussion about voltage and voltage measurements at the ADC pin here:

https://www.instructables.com/id/ESP8266-ADC-Analog-Sensors/

For those of you reading this that possess advanced electronics skills and are able to calculate correct values for these variables, I applaud your skills and apologize for my lack of knowledge! Perhaps you can share with us?

So, here is a good jumping off point. Thank you for reading this and good luck with your projects!

Comments

author
gepd (author)2016-08-01

Hey breagan, do you think is possible to measure the battery level and other sensor with your method? you can give me a clue on that?

author
breagan22 (author)gepd2016-08-02

You could certainly measure the voltage output of a battery. By 'level', if you are referring to the amount of charge remaining, that may be a bit more difficult.

Don't forget that ESPs are only 3.3v tollerant AND the ADC reference is 1.0v.

For example; if you wanted to check/monitor the output voltage of a common AA battery, you might use a simple voltage divider with R1 220ohm and R2 440ohm.

This should divide the AA's max voltage from 1.5v to 1.0v.

The ESP ADC would read the 1.0v as ~1023.

As the battery discharges, its current and output voltage will reduce, and so will the ADC reading.

With a load, the AA will discharge to a 'dead' state, however the AA will still be outputting some voltage. Depending on your application that 'dead' level could be just about any voltage below 1.5v.

With the above Rvalues. It would appear that the AA outputting .75v will read ~512 at the ESP's ADC pin. So, the usable ADC range is less than optimum. The arduino folks have a nice map() function. You may have to code your own.

author
gepd (author)breagan222016-08-03

I've a doubt, I've a voltage divider with 10k and 32k at 3.3v, it gives me 0.77v in the division and the ADC reads 221, at 1.0v it will read 295 approx. Why?

It's not taking 1.0v as reference? I'm using Nodemcu v2

author
breagan22 (author)gepd2016-08-03

Something always overlooked in these discussions; amperage.

I'm guessing 10K and 32K is way too much resistance for your 3.3v source.

Try 100ohm and 320ohm . Same ratio. Lets more current flow to the ADC pin.

author

interesting question - how much current is needed? We don't want the act of measuring a battery voltage to drain it!

author

How much current is needed? Great question!

I looked around for more information on current draw. Without much luck.

Current is directly related to Voltage and Resistance on a load, as per Mr Ohm.

An answer to your question relies on some variables.

However in the interest of discovery, I pushed forward and measured some data.

In order to measure Voltage, the ADC pin must sink some voltage to create a load.

I put my trusty voltage meter in series with the ESP8266's v3.3 and the ADC and measured the current. My result was 9.8 Micro-amperes.

This seemed to be constant whether I was reading the pin (adcread) or not.

That makes sense to me.

Next I hooked up a v1.5 AAA. My result was 4.9 Micro-amperes.

Finally I hooked up a v1.5 LR44. Result was 4.8 Micro-amperes.

So yes, the ADC will drain your battery.

BUT it is going to take a while.

A typical LR44 is rated at ~200mAh

1 mAh for 200 hours and its dead.

1MicroAh for 200,000 hours and its dead.

200,000/4.8

So consuming 4.8 Micro-amperes, the ESP8266's ADC pin will kill the LR44 in about 41,666 hours.

Or, 4.75 years.

IF the ADC pin is the ONLY current draw from the battery.

Caution your mileage will vary greatly with batteries!!

That was fun :)

author
gepd (author)breagan222016-08-07

Weird thing, same result with 100-320ohm... But first, I want to know if your method will allow me to have the voltage divider and the lecture of one sensor. I've the doubt with voltage divider because I can't connect one pin to the gpio, so I don't know how to do it, can you help me about that?

author
breagan22 (author)gepd2016-08-09

Can you upload a schematic?

author
gepd (author)breagan222016-08-02

Thanks for your great explanation, I had readed about this, however, you pointed to something I was not considering; ADC only reads up to 1.0v

Knowing this, the way to wiring this voltage divider and the other sensor will be same as you posted above?

author
HenryLi (author)2016-10-24

Great work!

author
breagan22 made it! (author)2016-07-25

Chad, You are on the right track. The sensor needs to be in series with your circuit. Either side should work. R1 and R2 are fine. Here is an example:

tmp.png
author
breagan22 (author)2016-07-24

Greetings Chad,
That 680 is part of the output voltage divider for the ldr and the thermistor.
Can you show us a schematic of your project? I'm sure someone here will point you in the right direction.

author
chadtheintern (author)breagan222016-07-24

Hmm, wouldn't the 680 resistor divide the sliders voltage then? For my project, the sensor acts a resistor (R1) and I think I need to experiment with R2 so that the range of voltages stays in between 0-1.

Attached is the incorrect schematic I drew up without thinking of the thevenin equivalent. I also have not incorporated the second temperature sensor I wanted to use yet.

Thanks!

Screen Shot 2016-07-24 at 2.25.30 PM.png
author
chadtheintern (author)2016-07-23

Hello breagan22,

Why do you have the 680 ohm resistor at the left end of the board near the adc pin out.

I am also creating a a soil moisture sensor that already uses a voltage divider and it still needs to be stepped down to the 0-1 volt range. Having two voltage dividers will cause some interactions with the resistors (add in parallel), any suggestions on how to overcome this issue? I have tried using a transistor as a voltage buffer but I am a noobie at electronics so I was not getting anywhere.

Thank you so much

- Chad

author
dadlovespi (author)2016-05-12

Thank you very much for this. My garden monitoring project requires multiple soil moisture sensors, and this makes perfect sense.

author
Akin Yildiz (author)2016-03-16

can you update the sketch to be used on arduino language instead of LUA. becase now you can easily program ESP8266 with arduino language using IDE; https://www.instructables.com/id/Programming-the-ES...

author
breagan22 (author)Akin Yildiz2016-04-01

Greetings Akin

Sorry, I don't plan on using an Arduino with the ESP in any of my projects at this time.

Arduinos are great microcontrollers and adding an ESP to access the WiFi capabilities of the ESP is certainly a inexpensive way to accomplish communication.

There are some good Instructables already written for this.

author
Ingenerare (author)breagan222016-04-23

Hi, I had the same problem with the NodeMcu and written a sketch in IDE based on this instructable. Feel free to use it or adjust it: https://www.instructables.com/id/Multiple-Analog-Inputs-on-Only-One-Analoge-Pin/

author
Akin Yildiz (author)Ingenerare2016-04-23

amazing work my friend. i understand you used UNO as an example but the same is applied to any arduino board, including ESP8266 and nodemcu :) genius

author
Ingenerare (author)Akin Yildiz2016-04-23

Yes, you can program the NodeMcu board within the arduino environment, just like an arduino. Sketches made for the arduino work also on this board :) For that reason I used an arduino for testing

author
Noorm17 (author)2016-04-15

i'm using soil moisture , humidity sensor,lm35 and ldr sensor. im getting temp and humidity value constant but while ldr and soil value changes . so i need help how to make soil and humidity sensor constant along with these above sensor in ESP8266E.

author
breagan22 (author)Noorm172016-04-16

Hmm...
Do you have a schematic we could look at?

author
SoniaE4 (author)2016-04-05

New to the ESp8266, so bear with me. I do of course want these values available over wifi. Is this instruction just to view the values in the dev tool, or am I missing something?

author
breagan22 (author)SoniaE42016-04-06

No you aren't missing anything.

These values are being sent to the dev tool via serial output. This is similar to serial.print() in the Arduino world.

Yes, the point of using the ESP8266 is to connect and transfer data to the internet via WiFi.

So, instead of print(adc.read(0)). We can assign the value of the ADC pin to a variable.

For instance while working with a temperature sensor, we may use the line: temp = adc.read(0)

The variable "temp" now holds the value at the ADC pin.

We can now add that variable to a URL such as: http://www.somewebsite.com/?temperature=temp

The website "somewebsite.com" could then decode via GET the value.

PHP code: $temperature = $_GET['temperature'];

The value from "temp" in the url is now assigned to the PHP variable $temperature and can be manipulated by the script for saving, graphing or displaying.

There are many great Instructables on how to send data to and from ESP8266s and internet infrastructure in general.

author
JavierM92 (author)2016-03-29

Hi! Nice job and very well explained. I only have a question: the diodes have a forward voltage drop. Small, but important on such small voltages. I haven't seen how handle that voltage drop on your code. Do you add it somehow to the reading?

Thanks!

author
breagan22 (author)JavierM922016-03-31

Yes the voltage drop from a diode makes a significant impact when it comes to planning your circuit.
The reference voltage for the ESP is 1.0v.
The goal is to provide voltage to the ADC pin in a range from 0 to 1.0v.
Your analog sensor or variable resistor (pot) should have enough range to allow the full 1.0v or when adjusted to MAX it should stop all voltage and present the ADC with 0v.
So yes, in this situation the diodes have a forward voltage drop of about .6v.  That means that we would want to present the diode with about 1.6v  1.6 - .6 = 1v.
So adjusting the voltage divider resistors, using 220ohm and ~210ohm with a 3.3v source should provide ~1.612v to the diodes and ~1.0 to the sensor or directly to the ADC pin for a ~1023 reading.

Software wise, one could certainly deal with 0 to .4v.  Arduino has a very useful map() function to expand these kinds of readings.  One could certainly employ something similar in LUA.   However, for my money providing usable voltage is preferable.

author
JavierM92 (author)breagan222016-03-31

Thanks for your greatly useful answer!!! Have a nice weekend!!

author
JouleJafryM (author)2016-03-13

Hi breagan,
I already done the sensor using dht11 but i found that only firmware version 20150127 can be used.. If i used other version of firmware the output will become - 128 degree and 0% RH.. Why did this happen?

For co2 MQ135 sensor, i still not manage to find the coding in lua that can be used. The signal from the sensor should be connected to analog input at the NodeMCU or digital input?

And can you help me by give the link or sample coding for the co2 sensor? I want to display the reading in ppm using web server.

Your help will be very meaning full to me because this project will be my final year project for my bachelor.. Thank you once again..

author
breagan22 (author)JouleJafryM2016-03-16

Greetings,
Using the DHT11 you may need to experiment with both the Float and Int versions.
I would recommend building an INT version using the latest build.
Also, make sure you have a delay in your loop. The DHTs can not be read too fast.

You wont fine a NodeMcu library for the MQ135 sensor.
This sensor has an analog output. Some modules have a digital TTL that could be used.
You will need to connect the analog output of the MQ135 to the ADC pin of the ESP.
Read this via TOUT() command.
The MQ135 will put out a voltage between 0 and 5v.
The ESP will be convert it to a 10bit value '0-1023'.

You will need to calibrate the readings against a known CO2 concentration.
Pure CO2 saturation should be at or near '1023' (10bit)
Pure O2 or other gas should be near '0'.
If you are within +-100, that would be very good.

Normal air : 350 - 450 ppm should be somewhere in between.
I suspect the the ppm saturation from 0 to 100% is not linear.

You may need to do many calibrations at know levels to make an algorithm that works.

The goal is to convert that 10bit reading back to PPM.

author
JouleJafryM (author)2016-03-05

Hi there. I would like to integrate 3 analog sensor into my nodemcu ESP 12E.

The sensors are humidity, temperature and CO2 gas sensor. I want to send the reading for each sensors after being converted into their respective units(degree, %RH and ppm) into web server using ESP.

Is it possible to conduct it using only nodemcu ESP12E as the controller?

author
breagan22 (author)JouleJafryM2016-03-06

Greetings!

The short answer is, yes.

This instructable is doing part of process, collecting the data. Once the data is collected, there are a few ways to send the data to a server depending on your specific needs and internet accessibility.

An easier was to collect temp and humidity is with a DHT22.

A DHT22 will provide temp and humidity. NodeMcu has a library for this sensor and the temp can be output in C or F. Of course simple math can provide K. This is a very easy solution and works well. I have a couple of these uploading data to a server every 30 mins. Works flawlessly.

I haven't used a CO2 sensor, yet. Can you be specific on the sensor you intend to use? A sensor that sends an analog signal would be very easy to use concurrently with the DHT22.

A digital CO2 sensor, depending on the interface (1-wire,SPI,I2c) can also work but may need some more intense programming to work with a DHT22.

If you have an analog CO2 sensor than any ESP with an ADC pin will work fine.

Sending the data to a web server is pretty straight forward. I find that sending the data as part of the URL and letting the server parse the header via GET is simple and effective. There are some Instructables that cover this.

Good luck!!

author
JouleJafryM (author)breagan222016-03-06

For CO2 sensor, i intend to use MQ135 gas sensor. It has analog input signal and also use library if implement in arduino. Where can i find the library for dht22 and also this MQ135?.

I also want to know the resistor needed for each of this sensor. Can I use 10k resistor like the example you provided for my sensors?

author
breagan22 made it! (author)JouleJafryM2016-03-06

Ok, for the DHT22, NodeMcu has the DHT module (library) built in. If you build your own .bin file, just ensure that the DHT module is included, then you are good to go.

The MQ135 dosn't need a library or NodeMcu module. This is strictly an analog sensor and the voltage can be read via TOUT. HOWEVER, the MQ135 is a 5.0v module. It needs the 5v to heat the sensor element. Therefore the analog output from the sensor would be from 0v to 5v.

ESP8266 is strictly 3.3v. You will need a voltage divider for that analog output. A couple of resistors and a zener to be safe. The upper level of the analog output needs to be 3.3v. And you want to maintain the full 10bit voltage range.

Since the MQ135 requires some serious calibration for any environment, perhaps you could try to run it at 3.3v, it may give results that meet your needs. However the datasheet is clear about 5v.

No resistors needed for the DHT22, this is a digital sensor.

You will need a 10k to ground for the MQ135.

Calibration for the MQ135, as stated in the datasheet involves a range of recommend R values and trial and error.

AirQualityMQ135.png
author
sumondigi (author)2016-01-05

many many thanks for reply...
serial-value is nothing but some serial data ("hallow world ",etc )
i wanna add up these two (force & bend) sensors and plot their serial data in a web browser.after that i will try for make excel file with these data.

download (1).jpgdownload.jpg
author
breagan22 (author)sumondigi2016-01-05

Ok, There two ways to do this.

1. Collect the data and write that data to a file in the ESP. Simply open a file to w+ and write the TOUT for each sensor. Perhaps:

file.open("adcvalue.lua","w+")
w = file.writeline
w("adc value"..adc.read(0).."\n")
file.close()

Do this every time you loop.

2. If you plan on having many,many readings (data sets) perhaps you should send it to a real server that can save the data.

Send a header to your server with the readings. Perhaps:

header = "http://www.yourserver.com/?adc1value="..adc.read(0).."&adc2value="..adc.read(0).."

Then send the header and have your server parse this "get" request.

author
sumondigi (author)breagan222016-01-06

Thanks again..

Is there any way to see serial readings of arduino via ESP8266?

more clearly, i want to setup a wi-fi enabled arduino for serial readings.

expecting coding,schematics,links whatever u can share!!

author
sumondigi (author)2016-01-04

i want to see these serial-value in any serial monitoring s/w.i need to plot these data wirelessly.can u help me!!??

Thanks..

author
breagan22 (author)sumondigi2016-01-04

Can you be more specific about 'serial-value'? The ESP can send ADC or any other internal data via WIFI. The ESP can 'post' to a webserver or have a browser send a request to the ESP and exchange data.

author
HagaiW (author)2015-09-26

if i used the adc in the esp8266 the wifi is working?

author
breagan22 (author)HagaiW2015-09-27

Can you be more specific?

author
maxbul (author)breagan222015-12-12

As far as I know, WiFi and ADC can't be used simultaneousely on ESP8266

author
breagan22 (author)maxbul2015-12-12

Using NodeMcu, I find that the ADC and WiFi work together with no issues. Perhaps some internal chip timing disables one or the other during a cycle. The esp is single threaded. At 80 or 160Mhz it would be hard to detect.

author
maxbul (author)breagan222015-12-12

Thanks a lot for your info!

author
Akin Yildiz (author)2015-04-07

i'm making huge progress.. wiring is done, now working on the code. check it out, thank you so much for your help.!!

rev_12_connections.JPG
author
dougstrickland (author)2015-03-31

This is a really interesting and creative approach. Is there any measurable interaction between the sensors readings? Meaning if I have a large resistance on one of the three sensors, and a high capacitive load on another, a third measuring smaller resistances... Are there parts that suffer in accuracy?

author
breagan22 (author)dougstrickland2015-04-01

The diodes do a very good job isolating the sensors. With the above schematic, I see less than 2% variance between readings. I don't see any interaction based on the readings of individual sensors. That is for example, shinning a light on the LDR and bringing it up to 1024 does not change the others. The sensors are isolated from each other. I mostly attribute this small variance to less than optimal breadboard connections. Soldered connections are optimal.

Without diodes all the sensors act as one. Applying voltage to one sensor connects the circuits in the other sensors. I believe its doubtful that one could create an algorithm to determine the correct reading not knowing the resistance presented at the other sensors.

Even with diodes, adding more sensors will change the capacitance of the circuit and will change the readings. However, this would be a fixed calculable change and will affect all sensors attached. Adding more sensors would require more fine tuning. I would start with the pull down resistor on the ADC wire.

As for accuracy, the sensors are extremely accurate. That is, presented with a constant voltage and stimulus, they provide constant results.

I do find some oddities that I believe are causing issues. One being the ADC pin outputs about +1.5v. I would like to see no voltage at an 'input' pin. Another is that the GPIOs output 3.0v when set HIGH rather than 3.3v. However, I suspect that the module is acting correctly, its probably my knowledge and understanding of this module that needs to catch up. :)

About This Instructable

73,879views

121favorites

License:

More by breagan22:ESP8266 WiFi OTA Remote File ManagementESP8266 - NodeMCU - CPU Speed TestESP8266 Irrigation Controller / Echo Alexa integration
Add instructable to: