Increase the Number of Analog Inputs with an Analog Multiplexer

One of the most used micrcontroller in my DIY projects is the ESP8266. But all ESP8266 boards like the ESP8266 NodeMCU or the WeMos D1 Mini have one mayor downside:

They have only 1 analog input pin.

But you can increase the number of analog inputs with an analog multiplexer. In this tutorial I show you how to increase the number of analog inputs to 4, 8 or 16 with an analog multiplexer.

Analog Multiplexer Thumbnail

Table of Contents

How does a Multiplexer work?

In my opinion the best explanation of a multiplexer is a big switch which connects all inputs with one output. Which input is connected to the output is defined by the state of the select lines pins.
Because only one input is connected to the output, all other lines loose the connection. This is important because devices that require a continuous signal (like a servo motor) will not work in combination with a multiplexer.

Multiplexer Schema

A multiplexer of 2^n inputs has n select lines which is shown in the following table.

 

Number of inputsNumber of select lines
21
42
83
164

In this tutorial I use the CD74HC4051 analog multiplex from Texas Instruments

Microcontroller Datasheet eBook

The 35 pages Microcontroller Datasheet Playbook contains the most useful information of 14 Arduino, ESP8266 and ESP32 microcontroller boards.

74HC4051 Data Sheet and Pins

Before we start with the practical example, let us quickly summarize the data sheet of the CD74HC4051.
The 74HC4051 is an 8 bit analog multiplexer / demultiplexer and therefore build up with bidirectional switches that allow any analog input to be used as an output and the way around.

The most important value is the maximum input voltage with is 5V for the analog multiplexer. The 5V fits well with all Arduino and the EPS8266 based microcontroller. You find the whole data sheet here.

CD74HC4051
74HC4051 pinDescription and Connection
A0...A7Analog inputs for multiplexing and demultiplexing (in our example connected to the analog inputs: photoresistor and potentiometer)
GNDConnect to ground on the microcontroller
VCCConnect to 5V on the microcontroller (2V...6V)
S0...S23 select lines for the 8 bits
AAnalog output is connected to an analog pin on the microcontroller (in our example A0 on the NodeMCU)
EEnable state to enable or disable the functionality (active when LOW)
VEENegative power input to operate on negative voltages (0...-6V)

The functionality of the CD74HC4051 as analog multiplexer is easy explained in two steps:

  1. The multiplexer gets the select line signal from the 3 digital outputs of the microcontroller.
  2.  If the enable state is set to LOW, the corresponding analog input (A0…A7) is connected with the analog output (A)

The following table shows the input states of the CD74HC4051 and the corresponding analog output channel.

If Enable (E) is HIGH the multiplexer is disabled independent of the select line signals.

Input StatesAnalog Output
Enable (E)S2S1S0
LOWLOWLOWLOWA0
LOWLOWLOWHIGHA1
LOWLOWHIGHLOWA2
LOWLOWHIGHHIGHA3
LOWHIGHLOWLOWA4
LOWHIGHLOWHIGHA5
LOWHIGHHIGHLOWA6
LOWHIGHHIGHHIGHA7
HIGHXXXNone

Increase the Analog Inputs on the ESP8266 with a Multiplexer

In the following example we increase the number of analog inputs of the ESP8266 NodeMCU and WeMos D1 Mini, which have only one analog input pin. The analog inputs I choose are:

  • 1 photoresistor
  • 1 potentiometer

But you can choose any other analog device.

The following pictures show the wiring between all components and the ESP8266 microcontroller.

The photoresistor is connected to the 74HC4051 via a voltage divider with a 10kΩ resistor on pin A1. The potentiometer is directly connected to the multiplexer on pin A0. All other analog pins are connected to ground. Moreover the pins VEE and E are also connected to ground. The address select pins are connected to the ESP8266 like the following: 

  • S0 -> D3
  • S1 -> D2
  • S2 -> D1

Now lets dive in to the program code.

const int selectPins[3] = {D3, D2, D1};
const int analogInput = A0;

void setup() 
{
  Serial.begin(9600);
  // Set up the select pins as outputs:
  for (int i=0; i < 3; i++)
  {
    pinMode(selectPins[i], OUTPUT);
    digitalWrite(selectPins[i], HIGH);
  }
  
  // Create header table
  Serial.println("Y0\tY1\tY2\tY3\tY4\tY5\tY6\tY7");
  Serial.println("---\t---\t---\t---\t---\t---\t---\t---");
}

void loop() 
{
  // Loop through all eight pins.
  for (byte pin=0; pin <= 7; pin++)
  {
      for (int i=0; i < 3; i++) {
          digitalWrite(selectPins[i], pin & (1 << i)?HIGH:LOW);
      }
      int inputValue = analogRead(analogInput);
      Serial.print(String(inputValue) + "\t");
  }
  Serial.println();
  delay(1000);
}

First we have to define the connected pins. As mentioned before we connected the 3 digital pins D3, D2, D1 as well as the analog input A0. For the digital pins we create an array to loop through the pins easily during later stages in the code.

In the setup function we first set the baud rate to 9600 which must match to the rate in the serial monitor. Then we loop through the selectPins array and set every digital pin as output
The last part of the setup function is more an optical preference. We create a virtual table in the serial monitor by setting a tabulator space between all possible 8 analog values.

In the loop function we loop over all 8 possible analog pins and set the select pins HIGH and LOW with a little bit confusing formula. But the following table shows all the different combinations to get the selected pins set correct.

We calculate the state of each select pin in 3 steps:

  1. 1<bit-shift of each 3 select pins
  2. pin & (1<<i): bitwise AND with the selected analog output which should be selected
  3. pin & (1<<i)?HIGH:LOW: calculate the ternary conditional which is in this case very easy. If pin & (1<<i) is 0, then set the condition to LOW and otherwise HIGH.
pini1<pin & (1<pin & (1<Input stateAnalog Output
0 (0000)110 (0000)0S0A0
0 (0000)2100 (0000)0S1
0 (0000)31000 (0000)0S2
1 (0001)111 (0001)1S0A1
1 (0001)2100 (0000)0S1
1 (0001)31000 (0000)0S2
2 (0010)110 (0000)0S0A2
2 (0010)2102 (0010)1S1
2 (0010)31000 (0000)0S2
3 (0011)111 (0001)1S0A3
3 (0011)2102 (0010)1S1
3 (0011)31000 (0000)0S2
4 (0100)110 (0000)0S0A4
4 (0100)2100 (0000)0S1
4 (0100)31004 (0100)1S2
5 (0101)111 (0001)1S0A5
5 (0101)2100 (0000)0S1
5 (0101)31004 (0100)1S2
6 (0110)110 (0000)0S0A6
6 (0110)2102 (0010)1S1
6 (0110)31004 (0100)1S2
7 (0111)111 (0001)1S0A7
7 (0111)2102 (0010)1S1
7 (0111)31004 (0100)1S2

After we set the select pins, the analog multiplexer is configured to read the desired output. We read the analog value with the build in function analogRead and print the value to the serial monitor. Each value is separated with a tabulator like the header we created in the setup function.

Now the program is reading all analog input values. In the following picture you see a screenshot of the serial monitor

Analog Multiplexer Serial Output

The first value Y0 is the potentiometer. You see from the picture that I increase and decrease the resistance and therefore the analog value. The second value Y1 is the photoresistor which I influence by holding my hand on it to make it dark and change the analog value.

One thing that surprises me is that all other analog values Y2…Y7 are not always 0 although I connected all other analog input pins on the multiplexer with ground. My assumption is that there are some back coupling between the analog signals but I do not know how to remove the noise in the analog signals which are connected to ground. If you know why the other analog values are not zero, write your suggestion in the comment section below.

I also installed a decoupling capacitor between VCC and ground on the 74HC4051 because I saw this circuit for the sparkfun 74HC4051 multiplexer breakout board. But after the installation of the decoupling capacitor there was no change in the serial monitor.

In my opinion, either you know which analog signals from the multiplexer are connected and only read for example the first three or you can set a threshold > 10 to read all analog signals.

I hope you like this tutorial how you can increase the analog inputs on your ESP8266 NodeMCU or WeMos D1 Mini for your next project. If you have any questions you can use the comment section below and I will ask your questions as soon as possible.

If you are also interested how to increase the number of digital outputs with a shift register, then I can recommend this article.

17 thoughts on “Increase the Number of Analog Inputs with an Analog Multiplexer”

  1. Wow! thanks a lot! just what i been looking for!
    I’ve just changed “const int selectPins[3] = {D8, D7, D6};” to const int selectPins[3] = {D3, D2, D1};” on my code and it works great!

    Reply
  2. I am using NodeMCU amd i want to connect different gas sensors
    And all the gas sensors have analog outputs, so by using the above logic, can i interface those sensors with nodemcu

    Reply
  3. Can I use the multiplexer as a relay? when I select certain input signal with the select lines , it will appear on the output? do I need to have an analog singal or even if there is no signal a hard wire will be between the input and the output?

    Reply
    • Do you mean that you want to have not only multiple analog inputs but also analog outputs? Only the ESP32 has two build in digital-to-analog converters but for the ESP8266 and Arduino, there are options with an IC.

      Reply
  4. Hii.. May i ask, why is that my serial monitor gives all values the same? (all 9 to 10 for all pin). Did the wiring exact like the schematic, however potentiometer or any other is not detecting. Is it code/wiring/board problem? Been having these slump for days already.. Thanks..
    🙁

    Reply
    • Hi Mus,
      you can try not to use a potentiometer or other electronic devices but to connect one analog pin either to ground or to the 3.3V pin of the NodeMCU. The value should be switching to 0 or 1023 which is the minimum and maximum value of the analog input.
      If this does not work and you are sure that you connected all wires like in my example, it has to be a code problem or you have to try another 74HC4051

      Reply
  5. Hi, I’ve already tried this one and it works. thanks a lot. may I ask something about using two 74HC4051 in NodeMcu which can control analog and digital? could it possible?

    Reply
  6. Good day! I am so glad I found this tutorial. Question: You mentioned that the VIN pin on the ESP8266 NodeMCU is a 5V output, however, I have tried it with 4 different ESP8266 NodeMCU’s I have, but I only measure anything between 0.9V and 2.9 Volt. The ESP32 Dev Kit C, however outputs 4.6 Volt on its VIN pin. I am using a charger cable from my laptop USB to power up the NodeMCU. Am I missing something? Kind regards

    Reply
    • Hi Marie,
      you are right, because I did not go into details.
      – ESP8266 NodeMCU V2: The USB’s power is first fed through a diode and then to the VIN pin. Therefore you get around 4.7V
      – The ESP8266 NodeMCU V3: The USB is directly connected to the VV pin and not to the VIN pin. For the V3, the input and output pin are separated and from the VV pin you get 5V.

      Reply

Leave a Comment