Testing 74HC4051 (MUX/DEMUX) with an Arduino Uno

Testing a 74HC4051

The 74HC4051 is an analogue multiplexer / de-multiplexer IC. To this this IC, an Arduino Uno can be used by hooking it up with two 74HC4051 ICs. The first one is used as a multiplexer, the second one as a de-multiplexer.

Pinout

For the correct pin numbering, keep the notch on the IC to the left side!!
The pin in the bottom left corner, is pin number 1.
Count to the right until pin number 8.
The pin on the top right, is pin number 9.
This time, count to the left until pin number 16.
The pin configuration of the 74HC4051 is like this:

PinLabelFunction
1A4Channel in/out
2A6Channel in/out
3ACommon in/out
4A7Channel in/out
5A5Channel in/out
6/EEnable (negative)
7VeeNegative power supply
8GNDGround (0V)
9VccPower supply (5V DC)
10A2Channel in/out
11A1Channel in/out
12A0Channel in/out
13A3Channel in/out
14S0Address line bit 0
15S1Address line bit 1
16S2Address line bit 2
74HC4051 pinout
74HC4051 pinout

Digital testing

The 74HC4051 is an analogue MUX/DEMUX, but with an Arduino Uno, it can not be tested analogue since the Uno has no analogue outputs (DAC). Later on in this article, an option is shown to test the IC analogue using a DAC breakout board. To test digital, only one Arduino Uno board and two ICs are required.

Hooking it up

Connect pin 16 (Vcc) of both ICs to 56VDC, pin 8 (GND) to 0V.
Connect pins 6 (~E) and 7 (VEE) of both ICs to 0V.
From one IC to the other, connect all channel in/out (A0..A7): pins 1,2,4,5,15,16,13,12.
Connect pin 11 (S0) of both ICs to the Arduino board at pin A0.
Connect pin 12 (S1) of both ICs to the Arduino board at pin A1.
Connect pin 13 (S2) of both ICs to the Arduino board at pin A2.
On IC 1 (MUX), connect pin 3 (A) to pin A4 on the Arduino board.
On IC 2 (DEMUX), connect pin 3 (A) to pin A5 on the Arduino board.

Arduino Uno a digital tester
Arduino Uno a digital tester

Arduino code

Upload the code below to the Arduino Uno for testing the ICs digital.

/****************************************************************
      Configuration
****************************************************************/
#define pinS0   A0 // Address select 0
#define pinS1   A1 // Address select 1
#define pinS2   A2 // Address select 2
#define pinA_mux  A4    // A pin on IC1 (MUX)
#define pinA_demux  A5  // A pin on IC2 (DEMUX)
/*****   END CONFIGUTATION    *****/

// Poll timer
unsigned long lastPoll;

/****************************************************************
      SETUP
****************************************************************/
void setup()
{
  Serial.begin(115200);
  while (!Serial) {
    ; // Wait for serial
  }
  Serial.println("--- Serial monitor started ---");

  // Configure pins as outputs
  pinMode(pinS0, OUTPUT);
  pinMode(pinS1, OUTPUT);
  pinMode(pinS2, OUTPUT);
  pinMode(pinA_mux, OUTPUT);
  // Configure pins as inputs
  pinMode(pinA_demux, INPUT);

  lastPoll = millis();
}

/****************************************************************
      LOOP
****************************************************************/
void loop()
{
  static byte byteCounter = 0;
  static bool writeBit;
  static bool readBit;
  String testResult;

  // Generate a random true or false
  writeBit = bool(random(0, 2));

  // Every 500ma
  if (millis() - lastPoll >= 500)
  {
    // Select the address
    selectAddress(byteCounter);

    // Write bit to MUX
    digitalWrite(pinA_mux, writeBit);

    // Read bit from DEMUX
    readBit = digitalRead(pinA_demux);

    // Evaluate result
    if (writeBit == readBit) {
      testResult = " -> OK";
    }
    else {
      testResult = " -> NOT OK";
    }

    // In the serial monitor, write bit must be read bit
    Serial.print("On address " );
    Serial.print(byteCounter, BIN);
    Serial.print(" is write (MUX) vs read (DEMUX): " );
    Serial.print(writeBit);
    Serial.print(" / ");
    Serial.print(readBit);
    Serial.print(testResult);
    Serial.println();

    // Select next address
    byteCounter++;
    if (byteCounter > 7) {
      byteCounter = 0;  // Reset counter at 1000 (count 0000 to 0111)
    }
    lastPoll = millis();
  }
}

/****************************************************************
      Set Sx address lines
****************************************************************/
void selectAddress(byte address) {
  // Lees adres bits
  bool S0 = bool(address >> 0 & 0x01); // Shift right ans mask with 0x01
  bool S1 = bool(address >> 1 & 0x01);
  bool S2 = bool(address >> 2 & 0x01);

  // Set address lines
  digitalWrite(pinS0, S0);
  digitalWrite(pinS1, S1);
  digitalWrite(pinS2, S2);
}
//END

The result should be something like this:

On address 0 is write (MUX) vs read (DEMUX): 1 / 1 -> OK
On address 1 is write (MUX) vs read (DEMUX): 0 / 0 -> OK
On address 10 is write (MUX) vs read (DEMUX): 0 / 0 -> OK
On address 11 is write (MUX) vs read (DEMUX): 1 / 1 -> OK
On address 100 is write (MUX) vs read (DEMUX): 0 / 0 -> OK
On address 101 is write (MUX) vs read (DEMUX): 0 / 0 -> OK
On address 110 is write (MUX) vs read (DEMUX): 1 / 1 -> OK
On address 111 is write (MUX) vs read (DEMUX): 0 / 0 -> OK
On address 0 is write (MUX) vs read (DEMUX): 0 / 0 -> OK
On address 1 is write (MUX) vs read (DEMUX): 1 / 1 -> OK
On address 10 is write (MUX) vs read (DEMUX): 1 / 1 -> OK
On address 11 is write (MUX) vs read (DEMUX): 0 / 0 -> OK

Analogue testing

To be able to test analogue, an analogue output is required. Unfortunately, the Arduino Uno hasn’t one by default. Luckily, it’s pretty easy to extend the Arduino board with a digital to analogue convertor (DAC) like the “Adafruit MCP4725 (12bit DAC)” breakout board.

Adafruit MCP4725 DAC
Adafruit MCP4725 DAC

Hooking it up

The previous connections need to be modified a little bit:
Connect pin 3 (A) of IC 1 to the output of MCP4725 (VOU) (instead of A5)
Connect pin 3 (A) of IC 2 to pin A3 of the Arduino Uno (instead of A4).
Connect pins A4 (SCA) and A5 (SCAL) of the Arduino board to the SDA and SCL pins of the MCP4725.
Connect VDD and GND of the MCP4725 to 5V and GNS.
Connect pin A0 of the MCP4725 to GND to select I2C address 0x62.
(Alternatively: A0 to 5V to select address 0x63.)

Arduino Uno as analogue tester
Arduino Uno as analogue tester

Arduino Code

Adafruit libraries

To control the Adafruit MCP4725 DAC, it is advised to download the Adafruit MCP4725 library. This can be found on Github by clicking here.

#include <Wire.h>               // I2C library
#include "Adafruit_MCP4725.h"   // Adafruit's MCP4725 DAC library
Adafruit_MCP4725 dac;

/****************************************************************
      Configuratie
****************************************************************/
#define pinS0   A0 // Address select 0
#define pinS1   A1 // Address select 1
#define pinS2   A2 // Address select 2
#define pinA_demux  A3    // A pin on IC 2 (DEMUX)
/*****   EINDE CONFIGUTATIE    *****/

// Poll timer
unsigned long lastPoll;

/****************************************************************
      SETUP
****************************************************************/
void setup()
{
  Serial.begin(115200);
  while (!Serial) {
    ; // Wait for serial
  }
  Serial.println("--- Serial monitor started ---");

  // Configure pins as outputs
  pinMode(pinS0, OUTPUT);
  pinMode(pinS1, OUTPUT);
  pinMode(pinS2, OUTPUT);

  dac.begin(0x62);  // MCP4725, pin A0 connected to GND
  // dac.begin(0x63);  // MCP4725, pin A0 connected to 5V

  lastPoll = millis();
}

/****************************************************************
      LOOP
****************************************************************/
void loop()
{
  static byte byteCounter = 0;
  uint16_t writeChannel; // 12 bit (0-4095)
  uint16_t readChannel;  // 10 bit (0-1023)
  String testResult;

  // Generate random analogue output value
  writeChannel = random(0, 4096); // random 0-4095 (!)

  // Every 500ms
  if (millis() - lastPoll >= 500)
  {
    // Select address
    selectAddress(byteCounter);

    // Write to DAC
    dac.setVoltage(writeChannel, false);

    // Read analogue value from DEMUX
    readChannel = analogRead(pinA_demux);

    // Convert values to voltage
    writeChannel = map(writeChannel, 0, 4095, 0, 500);
    readChannel = map(readChannel, 0, 1023, 0, 500);

    // Are both values equal ?
    if (writeChannel == readChannel) {
      testResult = " -> OK";
    }
    else {
      testResult = " -> NIET OK";
    }

    // In the serial monitor, write value must be equal to read value
    Serial.print("On address " );
    Serial.print(byteCounter, BIN);
    Serial.print(" is write (MUX) vs read (DEMUX): " );
    Serial.print(float(writeChannel)/100);
    Serial.print(" / ");
    Serial.print(float(readChannel)/100);
    Serial.print(testResult);
    Serial.println();

    // Select next address
    byteCounter++;
    if (byteCounter > 7) {
      byteCounter = 0;  // Reset counter at 1000 (count 0000 to 0111)
    }
    lastPoll = millis();
  }
}

/****************************************************************
      Set Sx address lines
****************************************************************/
void selectAddress(byte address) {
  // Lees adres bits
  bool S0 = bool(address >> 0 & 0x01); // Shift right ans mask with 0x01
  bool S1 = bool(address >> 1 & 0x01);
  bool S2 = bool(address >> 2 & 0x01);

  // Set address lines
  digitalWrite(pinS0, S0);
  digitalWrite(pinS1, S1);
  digitalWrite(pinS2, S2);
}
//END

The result on the serial monitor will look similar to this:

On address 100 is write (MUX) vs read (DEMUX): 2.15 / 2.15 -> OK
On address 101 is write (MUX) vs read (DEMUX): 1.10 / 1.10 -> OK
On address 110 is write (MUX) vs read (DEMUX): 0.84 / 0.84 -> OK
On address 111 is write (MUX) vs read (DEMUX): 0.86 / 0.86 -> OK
On address 0 is write (MUX) vs read (DEMUX): 2.16 / 2.16 -> OK
On address 1 is write (MUX) vs read (DEMUX): 2.95 / 2.95 -> OK
On address 10 is write (MUX) vs read (DEMUX): 3.40 / 3.40 -> OK
On address 11 is write (MUX) vs read (DEMUX): 4.21 / 4.21 -> OK
On address 100 is write (MUX) vs read (DEMUX): 0.08 / 0.08 -> OK
On address 101 is write (MUX) vs read (DEMUX): 1.54 / 1.54 -> OK
On address 110 is write (MUX) vs read (DEMUX): 1.53 / 1.53 -> OK
On address 111 is write (MUX) vs read (DEMUX): 4.02 / 4.02 -> OK
On address 0 is write (MUX) vs read (DEMUX): 0.82 / 0.82 -> OK
On address 1 is write (MUX) vs read (DEMUX): 0.93 / 0.93 -> OK
On address 10 is write (MUX) vs read (DEMUX): 3.72 / 3.72 -> OK
On address 11 is write (MUX) vs read (DEMUX): 1.35 / 1.35 -> OK
On address 100 is write (MUX) vs read (DEMUX): 2.64 / 2.64 -> OK
On address 101 is write (MUX) vs read (DEMUX): 1.29 / 1.29 -> OK
On address 110 is write (MUX) vs read (DEMUX): 2.89 / 2.88 -> NOT OK
On address 111 is write (MUX) vs read (DEMUX): 3.54 / 3.54 -> OK
On address 0 is write (MUX) vs read (DEMUX): 4.24 / 4.24 -> OK
On address 1 is write (MUX) vs read (DEMUX): 1.51 / 1.51 -> OK
On address 10 is write (MUX) vs read (DEMUX): 4.20 / 4.20 -> OK

Occasionally, little “errors” will popup due to rounding errors and. In the example above, 2.89 is not equal to 2.88, and therefore is considered as NOT OK. However, looking at al other results, and taking into account these inaccuracies and rounding errors, it is safe to assume this particular MUX and DEMUX are working fine.

Conclusion

Despite the slight inaccuracies and rounding errors, this way is a pretty easy way to test two 74HC4051 at the same time. If the 74HC4051 Is used for digital multiplexing only, the extra DAC is not required and the results will be perfectly consistent.

Arduino Uno as a 74HC4051 tester
Arduino Uno as a 74HC4051 tester