When the Arduino’s inputs and outputs just aren’t numerous enough, a multiplexer saves the day.

A multiplexer’s basically just a soft switch — you send it a set of digital on / off values to specify which channel you want to read from, and take a look at the “common” pin with an analogRead() on the Arduino, and then rinse and repeat for the next channel (and the next…) until you have all the values you want.

In this way, you can collect readings from a bunch of sensors with the use of just one of the Arduino’s analog pins (plus three or four digital control pins. You can think of the multiplexer as a basic parallel to serial converter — it lets you take a bunch of different signals and put them into a single stream of data.

In short, it’s an easy way to add inputs and outputs to your Arduino.

It’s also possible to string several together to get control of even more inputs and outputs. More about this, including schematics, is available on the Arduino website.

Multiplexers come in a variety of flavors… 8 channel varieties (like the 4051) use a 3-bit digital channel picker, while 16 channel models like the 4067 shown below use a 4-bit channel picker. Everything you need to know about the pins and channel encoding is available in the data sheet.

The circuit I’m using for the media controller project looks like this. All of the sensors aren’t hooked up, but it gives the idea.

Multiplexer circuit overview

Note The resistor between the common pin and ground is critical — I was getting noisy readings at first; the resistor fixed it:

Multiplexer circuit detail

Here’s some Arduino code to read each channel from a multiplexer and then send each value out over serial in a comma-delimited format:

// 4067 16 Channel Multiplexer

// Based on the code for the 8 channel 4051 available here:
// https://playground.arduino.cc/Learning/4051/

// Here's a handy datasheet for the 4067:
// https://www.sparkfun.com/datasheets/IC/CD74HC4067.pdf

// How many of the 16 channels do we want to actually read?
// set this to a lower number to read a fraction of the channels
int activeChannels = 16;

// Keep count of which channel we're reading.
int channel = 0;

// Set the common input / output pin.
int pinCommon = 0;

// Set which pins tell the multiplexer which input to read from.
int pinS0 = 2;
int pinS1 = 3;
int pinS2 = 4;
int pinS3 = 5;

void setup() {
// Set the switch pins to output.
pinMode(pinS0, OUTPUT);
pinMode(pinS1, OUTPUT);
pinMode(pinS2, OUTPUT);
pinMode(pinS3, OUTPUT);

// Fire up the serial.
Serial.begin(9600);
}

void loop () {

// Loop through the channels and read each one.
for (channel = 0; channel < activeChannels; channel++) {

// Get the switch states from the channel number, and
// send the state to the multiplexer to read from that
// channel. This configuration covers all the channels,
// but doesn't read them in a sequence that matches the datasheet.
// (This works, but needs revision.)
digitalWrite(pinS0, (channel & 15) >> 3); // bit 4
digitalWrite(pinS1, (channel & 7) >> 2); // bit 3
digitalWrite(pinS2, (channel & 3) >> 1); // bit 2
digitalWrite(pinS3, (channel & 1)); // bit 1

// Read the common pin and send it out over serial.
Serial.print(analogRead(pinCommon), DEC);

if(channel < (activeChannels - 1)) {
// Separate each channel with a comma.
Serial.print(",");
}
else {
// If it's the last channel, skip the
// period and send a line feed instead.
Serial.println();
}

}

// Take a breath.
delay(10);
}