Reading and writing from an analog multiplexer

Through the Multiplexer

Now that you've seen how to read from analog sensors one by one, I'll show you how to read from a number of sensors, all through one analog pin on the Arduino.

The multiplexer I'll use for this is an MC14051B [2]. This is a good option because it's very cheap and easy to find. It's also relatively easy to wire and make work (it doesn't need any external libraries), and each chip gives you a whopping eight new analog pins to play with. Figure 4 shows how the pins are mapped. The black spot represents the dimple you can see on the surface of the chip in the photo in Figure 1. This helps you locate pin 1.

Figure 4: Pin map for MC14051B.

The analog ports are numbered X0 through X7, and you have four on each side (in order, pins 13, 14, 15, 12, 1, 5, 2, and 4). You will connect X0 (pin 13) to the signal pin (the central prong) on your potentiometer, X1 (pin 14) to your temperature sensor, and X2 (pin 15) to your light sensor.

X (pin 3) is the pin that connects to your analog pin on your Arduino. If you are using the MC14051B for input from sensors, as in this example, data will flow from the Xn ports through X to the Arduino. Connect X to A0 on your Arduino.

A (pin 11), B (pin 10), and C (pin 9) are used to determine what port to read or write to on the multiplexer. You connect these ports to three digital pins on your Arduino (in this case, connect A to 8, B to 9, and C to 10). You feed a combination of 0s and 1s to A, B, and C (as described in Table 1) to tell the MC14051B which port you're going read from.

Table 1

A, B, and C Combinations

C

B

A

Port

0

0

0

X0

0

0

1

X1

0

1

0

X2

0

1

1

X3

1

0

0

X4

1

0

1

X5

1

1

0

X6

1

1

1

X7

For example, if you want to grab data from the sensor on X2, you would do what is shown in Listing 3.

Listing 3

How to Read Data from X2

01 .
02 .
03 .
04 int A = 8; // Pin 8 on the Arduino is connected to pin 11 \
   on the MC14051B
05 int B = 9; // Pin 9 connected to pin 10
06 int C = 10; // Pin 10 connected to pin 9
07 int X = A0;
08 .
09 .
10 .
11 digitalWrite(A, 0); // 0,1,0 = X2
12 digitalWrite(B, 1);
13 digitalWrite(C, 0); val = analogRead(X);
14 .
15 .
16 .

The INH (inhibit, pin 6) acts like a reset button. When it's set to LOW, data can flow through the chip, and when set to HIGH, the flow of data is stopped. To reset the chip, you would typically set INH to HIGH, wait a few milliseconds, and then set INH back to LOW to read the next value from the sensors. Connect INH to digital pin 7 on your Arduino.

Finally, to power the chip, connect the 5V pin on your Arduino to VDD (pin 16) and connect VEE (pin 7) to GND. Your setup should look like Figure 5.

Figure 5: Connecting your sensors and Arduino to the MC14051B.

It must be said that your setup will be a little less pretty in real life: Take a look at Figure 6.

Figure 6: Hooking up three sensors to the MC14051 in real life can lead to a mess.

Code

The simplest test you can make is to read from the three sensors and pipe the results one after another to the serial monitor. The code in Listing 4 does exactly that.

Listing 4

Testing the Multiplexer

01 int controlPin = 7;
02 int A = 8;
03 int B = 9;
04 int C = 10;
05 int X = A0;
06
07 void setup()
08 {
09   pinMode(controlPin, OUTPUT);
10   resetMultiplexer();
11
12   pinMode(A, OUTPUT);
13   pinMode(B, OUTPUT);
14   pinMode(C, OUTPUT);
15
16   Serial.begin(9600);
17 }
18
19 void loop() {
20
21   // X0 > Potentiometer
22   int resist = getX(0, 0, 0);
23   debug("Resistance", resist);
24   delay(100);
25
26   // X1 > Temperature
27   int temp = getX(0, 0, 1);
28   float mv = (temp / 1024.0) * 5000;
29   float cel = mv / 10;
30   debug("Temperature", cel);
31   delay(10);
32
33   // X2 > Light Sensor
34   int light = getX(0, 1, 0);
35   debug("Light Intensity", light);
36   delay(100);
37
38   resetMultiplexer();
39   delay(2000);
40 }
41
42 }///////////////////////////////
43 // MC14051 specific functions
44 //
45 void resetMultiplexer() {
46   digitalWrite(controlPin, HIGH);
47   delay(10);
48   digitalWrite(controlPin, LOW);
49 }
50
51 int getX(int valC, int valB, int valA) {
52   digitalWrite(A, valA);
53   digitalWrite(B, valB);
54   digitalWrite(C, valC);
55
56   return (analogRead(X));
57 }
58
59 void debug(char label[], int val) {
60   Serial.print(label);
61   Serial.print(" = ");
62   Serial.println(val);
63   Serial.println("----------");
64 }

From lines 1 to 5, you set the pins from the Arduino you are going to use. If you have wired the MC14051B as suggested, then controlPin (pin 7 on the Arduino), which is used to reset the multiplexer, is connected to the INH pin (pin 6) on the multiplexer.

A, B, and C (pins 8, 9, and 10 on the Arduino) are connected to A, B, and C (pins 11, 10, and 9) on the multiplexer. Finally, you read the data in through analog pin 0 on the Arduino, so you connect A0 to pin X (pin 3) on the multiplexer.

In the setup() section of the script, you set all the pins you want to write to OUPUT and initiate the MC14051B by resetting it. For the sake of clarity, I have moved most of the "work" code out to functions you can see from line 42 onward. The resetMultiplexer() function (lines 45--49) switches the multiplexer off by sending a HIGH to INH, waits a very short while, and then switches it back on again with a LOW to INH. You also initiate the serial monitor in the setup() function so a human can later see what the sensors have to say.

Moving on to the loop() section, the code is divided into three blocks, one per sensor, plus the bit of code needed to reset the multiplexer (lines 38 and 39).

Proceeding in order, you see the block you use to read data from the potentiometer. Again, the getX() function (lines 51--57) … well … gets X. This function takes the values you want to pipe to A, B, and C on the multiplexer to tell it which port you want to read from. To be more precise, it takes C, B, and A, in that order.

So, if you do getX(0, 0, 0), you are requesting data from the MC14051B's port 0 (X0). If you do getX(0, 0, 1), you are requesting data from the MC14051B's port 1 (X1), with 001 in binary being 1 in decimal.

If you do getX(1, 1, 0), you are requesting data from the MC14051B's port 6 (X6), with 110 binary being 6 decimal. For me, it's a useful mnemonic that helps keep me from being confused about which port I am requesting.

The getX() function itself is very simple. It pushes the values for A, B, and C over to the MC14051B (lines 52--54) and then reads in and returns the value given by X, which comes from the designated port (line 56).

Finally, you write the value take from the potentiometer to the serial monitor using the debug() function (line 23). The debug() function (lines 59--64) takes the array of chars (i.e., a string) to label the output and the value collected from the sensor through the multiplexer and prints both to the serial monitor (Figure 7).

Figure 7: Results are printed to the serial monitor every 2 seconds.

The debug() function is so named because you probably wouldn't just want to print the values to the serial monitor in this way. In fact, you would only want to print the values to check that everything is working correctly.

More likely, you would use the values to, for example, control the environment in your house – switching on heaters or AC units, or turning lights on and off. You could also use a setup with a multiplexer like this for a portable weather station and log information from dozens of environmental sensors without ever running out of analog pins on your Arduino.

My own proof of concept project (Figure 8) is a bit sillier. I decided to combine the digital multiplexer described previously [1] and the analog multiplexer discussed here and create a sketch to show the values on a line of LEDs.

Figure 8: Proof of concept.

Of course, there are trade-offs to using an analog multiplexer compared with just connecting the sensors directly to the Arduino. For one thing, the MC14051B itself needs some power to run, so the setup on the whole is more power hungry. Then, you need a slight pause between reading from one sensor and the next. However, I cannot see how waiting a few milliseconds between readings could affect most projects negatively.

It is true that you have to sacrifice four digital pins for every MC14051B. In return, however, you get eight analog pins. On most Arduino models, you have many more digital pins than analog pins anyway, and you can always combine a digital multiplexer with your analog multiplexer and free up some digital pins.

Another disadvantage is how little documentation can be found online about how to use this multiplexer. When you look up analog multiplexers on Google, most hits refer to shields manufactured by the likes of Sparkfun and Adafruit. This is fine, but these shields, I think, dumb down something that doesn't need dumbing down. The multiplexer shown here is as easy to understand as they come. The sketch used in Listing 4 is only 64 lines long with whitespace and comments and does not require that you include any external libraries. That's how simple this thing is.

Finally, there's a bigger trade-off. The sketch here is quite straightforward and does not contain much repeated code, agreed. However, as soon as you move onto even slightly more complex projects, that changes, and code repetition becomes a real problem. This device is begging for its own library, and as far as I can see, there isn't one yet.

Because writing code for the MC14051B is pretty simple, I predict that creating an Arduino library for it won't be that difficult either. I am so sure, in fact, that I'll be looking at how to do just that in the next issue of Raspberry Pi Geek. Stay tuned.

Infos

  1. "Modding the Robosapien, II" by Paul Brown, Raspberry Pi Geek, issue 10, pg. 46: http://www.raspberry-pi-geek.com/Archive/2015/10/Bring-old-toys-back-to-life-with-Arduino-Part-II
  2. MC14051B analog multiplexer: http://www.onsemi.com/pub_link/Collateral/MC14051B-D.PDF
  3. How to measure light with a photocell: https://learn.adafruit.com/photocells/using-a-photocell

Buy this article as PDF

Express-Checkout as PDF

Pages: 6

Price $2.95
(incl. VAT)

Buy Raspberry Pi Geek

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content