ESP8266 ADC - Multiple Analog Sensors

178K16772

Intro: 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!

57 Comments

Actually, it is possible to multiplex the analog pin without using any additional electronic components. Just by setting all other pins (that are used to power up other sensor probes) to INPUT to turn off the current (so as to shut off the sensor probe) should do.
Hi I've used this for a pair of inputs : a rotary switch with multiple resistors that can be defined as different switches, and a rotary potentiometer. When its all electrically connected and I use one or the other independently, (i.e. the code doesnt multiplex) it works fine. When it is multiplexed the rotary potentiometer range is limited to the maximum that is defined by the current switch setting. Is there anything I should be looking for on the circuit? I'm not strong on the electronics side. Thanks. (if anyone sees this )
How do you convert the ADC value considering the diode voltage drop into Lumen ?

The LDR is usually not linear, hence how do you represent illuminance properly based on the readings and the voltage drop ?
Hi! What about the voltage drop across the diode? There is 1.1Volt.
less than .7 if you used a shottky, but the resistor tweak seem to compensate somehow, I would like to see a worked graph.
I would use a CD 4066. its MOS so will function down to 3.3V, and then no need to mess with the resistor tweaking because it's a solid state analog switch. Not tried it in here, but have used it in similar situations, and found that it did not suffer too badly on the upper/lower limits. mileage may differ, worth a shot if you are anitstatic device ready and have used CMOS before.
Nice one but you could lessen the pin count by using sipo shiftregisters to activate the sensors.
One clock pin, one data pin and a virtually unlimited amount of sensors attached to them.

Thank god for the interwebs and its memory. Geez, in order to read 3 soil moisure sensors in close proximity, and not wanting to burn an IP address for each one, I was going to concoct some messy multiplexing comm system to a Wifi connected ESP8266. Messy. Thanks for taking the time to post this obvious (but not to me) and well-explained solution.

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?

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.

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

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.

Actually, current doesn't matter to read the voltage (within limits, of course. 20A would fry your ESP8266 and 1pa (pico-amp) may not be enough to register at all.)

What's probably happening is that he's got one of the newer NodeMCU's with a 1v ADC pin (top/left when holding it with the USB at the top) and also a 3.3v ADC pin (right below it.) The 3.3v actually has a voltage divider on it so that you can measure from 0-3.3v and then the center of the divider feeds into the 1v pin. 1/3.3 gives .3030.... and 1024*0.303 gives....wait for it.......310 (which is pretty close to the 295 reported by gepd. It's also possible he's only got one ADC pin but it's the newer board that puts the divider on the one ADC pin and thus the same 0-3.3v range. See the schematic at https://raw.githubusercontent.com/nodemcu/nodemcu-devkit/master/Documents/NODEMCU_DEVKIT_SCH.png and look at the middle-row/right-side. In this case, you'd simply add your OWN divider, connecting the middle to the ADC pin, realizing the range is 0-3.3v and not 0-1v.

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

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 :)

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?

Can you upload a schematic?

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?

can we use cd4016 swich in case of three pin sensors
Of course you can. The cd4016 is a binary switch. You can use this on any IO pin. Reading the ADC would be 0 to 255 depending on the voltage switched by the cd4016.
More Comments