Tuesday, February 16, 2021

(#39) NodeMCU Analog Multiplexer

Sharing is Caring

There's but one analog input on the NodeMCU V3 board I purchased some months ago. And I'd like to connect two (or more) analog sensors.

NodeMCU V3 Lolin Board


 

This is where an Analog Multiplexer, like the Sparkfun 16 Channel Analog/Digital Multiplexer/Demultiplexer can help. Quoting from their product's webpage:

This chip is like a rotary switch - it internally routes the common pin (COM in the schematic, SIG on the board) to one of 16 channel pins (CHANxx). It works with both digital and analog signals (the voltage can't be higher than VCC), and the connections function in either direction. To control it, connect 4 digital outputs to the chip's address select pins (S0-S3), and send it the binary address of the channel you want (see the datasheet for details). This allows you to connect up to 16 sensors to your system using only 5 pins!


See (https://www.sparkfun.com/products/9056).

Wiring Diagram

As a quick test, I wired the multiplexer to the NodeMCU and sensors as depicted:


Wiring Diagram


Note I'm using pins D0 through D3 for controlling the multiplexer - these may not be the best pins to choose for a production application. But they worked for the test.

Pin D0 on the NodeMCU connects to pin S3 on the multiplexer, D1 to S2, D2 to S1, D3 to S0.

The Signal (S) pin on Voltage Sensor 1 connects to pin C0 on the multiplexer. For Voltage Sensor 2, the S pin connects to C1.

VCC is connected to the 3.3V pin on the NodeMCU and the grounds are tied together.

Note that I had to connect the ground on the Voltage Sensor GND input to the NodeMCU's ground too to get an accurate reading.

The Code

Selecting the channels on the multiplexer is easy. First ensure the pins are enabled for output:

{

   Serial.println("Setting up the Output pins");

   pinMode( D0, OUTPUT );

   pinMode( D1, OUTPUT );

   pinMode( D2, OUTPUT );

   pinMode( D3, OUTPUT );

}

Consult the Chip's documentation for a Truth Table on how to toggle the pins to select a channel.

CD74HC4067, CD74HCT4067 Truth Table

Note that I did not connect the "E" pin on the board, so I cannot turn off all channels. One will always be connected.

Selecting Channels is straightforward. To pick Channel 0, set all four S pins low (to zero):

void selectChannel0 ()

{

   setS0( 0 );

   setS1( 0 );

   setS2( 0 );

   setS3( 0 );

}


To select Channel 5, S0 and S2 are set to high, the others are set to low:

void selectChannel5()

{

  setS0( 1 );

  setS1( 0 );

  setS2( 1 );

  setS3( 0 );

}


The code to drive a S pin High or Low is also easy:

// ---------------------------------------------------------------

void setS0 (int value)

{

   // S0 is connected to D3/GPIO 0

   if (value == 1)

     digitalWrite( D3, HIGH );

   else

     digitalWrite( D3, LOW );

}

// ---------------------------------------------------------------

void setS1 (int value)

{

   // S1 is connected to D2/GPIO 4

   if (value == 1)

     digitalWrite( D2, HIGH );

   else     

   digitalWrite( D2, LOW );

}

// ---------------------------------------------------------------

void setS2 (int value)

{

   // S2 is connected to D1/GPIO 5

   if (value == 1)

     digitalWrite( D1, HIGH );

   else

     digitalWrite( D1, LOW );

}

// ---------------------------------------------------------------

void setS3 (int value)

{

   // S3 is connected to D0/GPIO 16

   if (value == 1)

      digitalWrite( D0, HIGH );

   else

     digitalWrite( D0, LOW );

}


Code is intentionally verbose. Feel free to save a few bytes and collapse the functions into bit manipulation ones. Reassigning the order of the D0 to D3 pins would be helpful too.


Finally, a little bit on reading voltages from these sensors. There are a lot of examples on the 'net, but bear in mind many of these examples are for a 5V Arduino based board. The NodeMCU as I'm using it, is 3.3V. Thus the voltage calculation needs to change slightly:


float readVoltage ()

{

const float R1 = 30000.0; // Resistor 1 Ohm value on the voltage senso

const float R2 = 7500.0; // Resistor 2 Ohm value on the voltage sensor

const float adjustment = -0.6; // Voltage off when compared to                                         // an accurate voltmeter

int analogValue = analogRead( A0 ); // Read the Analog Port 0

float Vout = (analogValue * 3.3) / 1024.0; // 3.3 is because we're a 3.3V                                         // device, not 5V like an Arduino

float Vin = Vout / (R2/(R1+R2));

Vin += adjustment;

return Vin;

}



No comments :

Post a Comment