Demultiplexing with a 4067 problem

:slight_smile: Hello, I'm simply trying to use the 4067 to add 16 leds to my project but I cant really find anything that will explain to a total ass, how to do this :frowning:

but I cant really find anything that will explain to a total ass, how to do this

Nor will you because you can't (or should not) drive LEDs through an analogue multiplexer. Use two shift registers instead.

Hmm, I accidentally posted this before i had finished but I began messing with Tom Igoe's sketch

/*

 Multiplexer output example
 Controls 16 outputs, one at a time, using a CD4067B multiplexer.
 
 This sketch loops over the 16 channels of a CD4067 multiplexer, switching
 the input to each output channel in turn.  It then fades up and down the 
 input channel using analogWrite().
 
 The circuit:
 * CD4067 multiplexer attached as follows:
 - address pin A: digital I/O 2
 - address pin B: digital I/O 3
 - address pin C: digital I/O 4
 - address pin D: digital I/O 5
 - input pin: digital I/O pin 6
 - LEDs attached from each of the CD4067's output channels
 to ground
 
 created 21 May 2009
 by Tom Igoe
 
 http://www.tigoe.net/pcomp/code/category/arduinowiring/540 for more
 
 */

// put the address pin numbers in an array
// so they're easier to iterate over:
const int channel[] = {
  2, 3, 4, 5};

// the output pin channel (mux's input):
const int outputPin = 6;

void setup() {
  // set up all pins as output:
  for (int thisPin = 2; thisPin < 7; thisPin++) {
    pinMode(thisPin, OUTPUT);
  }
}

void loop() {
  // iterate over the 16 channels of the multiplexer:
  for (int thisChannel = 0; thisChannel < 16; thisChannel++) {
    // set the channel pins based on the channel you want:
    muxWrite(thisChannel);

    // fade the current channel up:
    for (int brightness = 0; brightness < 256; brightness++) {
      analogWrite(outputPin, brightness);
      delay(5);
    }
  }
}

void muxWrite(int whichChannel) {
  // iterate over the number of pins you're using:
  for (int thisPin = 0; thisPin < 4; thisPin++) {
    // calculate the state of this pin based on 
    // its bit value in whichChannel:
    int pinState = bitRead(whichChannel, thisPin);
    // turn the pin on or off:
    digitalWrite(channel[thisPin],pinState);
  }
}

Is this then totally wrong??? It worked but why shouldn't I use the 4067 for a demultiplexer?

What I wanted to do was take this sketch that I have

int val; 
byte ledPin[] = { 2, 4, 6, 7, 8, 9, }; //pins used for LED's


void setup()
{
  for (int x = 0; x < 6; x++) {
   pinMode (ledPin[x], OUTPUT); } 
}

void loop() {
  
  val = analogRead(4);	// reads the value of the potentiometer

  {
     if (val < 170) 
    {
	digitalWrite(ledPin[0], HIGH);
    }
    else
    {
	digitalWrite(ledPin[0], LOW);
    }
  
  if((val > 170) && (val < 340))
  {
    digitalWrite(ledPin[1], HIGH);  // <- "i" out of scope here.
    digitalWrite(ledPin[0], LOW);
  }
  else
  {
    digitalWrite(ledPin[1], LOW);  // <- and here.
    
  }
  
   if((val > 340) && (val < 510))
  {
    digitalWrite(ledPin[2], HIGH);  // <- "i" out of scope here.
    digitalWrite(ledPin[1], LOW);
    
  }
  else
  {
    digitalWrite(ledPin[2], LOW);  // <- and here.

  }
  
   if((val > 510) && (val < 680))
  {
    digitalWrite(ledPin[3], HIGH);  // <- "i" out of scope here.
    digitalWrite(ledPin[2], LOW);
  }
  else
  {
    digitalWrite(ledPin[3], LOW);  // <- and here.
  }
  
   if((val > 680) && (val < 850))
  {
    digitalWrite(ledPin[4], HIGH);  // <- "i" out of scope here.
    digitalWrite(ledPin[3], LOW);
  }
  else
  {
    digitalWrite(ledPin[4], LOW);  // <- and here.
  }
  
   if((val > 850) && (val < 1024))
  {
    digitalWrite(ledPin[5], HIGH);  // <- "i" out of scope here.
    digitalWrite(ledPin[4], LOW);
  }
  else
  {
    digitalWrite(ledPin[5], LOW);  // <- and here.

  }
  }
}

and be able to output to any of 16 leds through the 4067! Is this a bad idea? I can't see how to adapt Tom's code to do this.

Is this then totally wrong?

Yes totally and utterly, the man is a fool to do this.

why shouldn't I use the 4067 for a demultiplexer?

Because the output is only connected through for the instant of time that channel is selected. Thus you can only have one output on at any one time. Yes sure you can multiplex them, that is flash them so fast that it looks like they are on all the time but you burn up software time doing this. Also as they are only on one sixteenth of the time they are only one sixteenth of the brightness. So two penalties for no gain as there are plenty of correct parts you can use.
You need something with an output latch so that once set the output stays in that state. Shift registers are good and cheap but have the disadvantage of having to load them all in when ever you want to change anything.
The 74LS259 has a multiplexer and a latch and so you can address individual outputs but it uses more lines than a shift resister.

I am not sure how you get:-
digitalWrite(ledPin[1], HIGH); // <- "i" out of scope here.
Because you don't use or define i

This line is wrong:-
byte ledPin[] = { 2, 4, 6, 7, 8, 9, }; //pins used for LED's
there should be no comer after the 9

Although, I only need to have one led on at a time. It would have full brightness no? It's just that I have a bunch of them and thought it would be easier than hooking up two separate chips. I have some 4051's and some 595's i could try instead. What do you you think Mike?
Yes, my code is all over the shop and incorrect for many reasons but it does work. Sorry Mike, the "i" is a leftover comment from previous code.

Yes if only one LED were on at a time you could have "full" brightness. I put that in comers because the analogue multiplexer has it's own series resistance (see the data sheet) and there is also a lowish current limit (again see data sheet).

:)Thanks Mike!! Does this code make any sense to you???

/*
16 Channel Analog Extender for Arduino
*/

// Set Analog I/O pin to use for reading channel values from multiplexer.
int ComIOpin = 6;  // HEF4067BP(X)(ICpin-01)

// Set which pins tell the multiplexer which input to read from.
int DpinA0 = 2;  // HEF4067BP Address Input A0 (A)(ICpin-10)
int DpinA1 = 3;  // HEF4067BP Address Input A1 (B)(ICpin-11)
int DpinA2 = 4;  // HEF4067BP Address Input A2 (C)(ICpin-14)
int DpinA3 = 5;  // HEF4067BP Address Input A3 (D)(ICpin-13)

void setup() {

// Set the digital pins to outputs.
pinMode(DpinA0, OUTPUT);  // HEF4067BP Address Input A = pin10
pinMode(DpinA1, OUTPUT);  // HEF4067BP Address Input B = pin11
pinMode(DpinA2, OUTPUT);  // HEF4067BP Address Input C = pin12
pinMode(DpinA3, OUTPUT);  // HEF4067BP Address Input D = pin13
Serial.begin(9600); // Set Serial COM
}

void loop() {
digitalWrite(DpinA0, HIGH);
digitalWrite(DpinA1, LOW);
digitalWrite(DpinA2, LOW);
digitalWrite(DpinA3, LOW);
analogWrite(ComIOpin, HIGH);
delay(500);
digitalWrite(DpinA0, LOW);
digitalWrite(DpinA1, LOW);
digitalWrite(DpinA2, LOW);
digitalWrite(DpinA3, LOW);
analogWrite(ComIOpin, LOW);
delay(500);
}

Could you see how it might work with my code as such? If not I'll have to try those shift registers you mentioned :slight_smile:

Well it looks like the code is a long winded way of setting output 1 high then setting output 0 low.
This is a bit silly because if the outputs are connected to an LED then it will go out as soon as you don't address it.
Even that is mixed up because the line:-
analogWrite(ComIOpin, HIGH);
Is using a PWm signal but setting it to 255, is that what you mean to do?

To just turn on the LEDs in turn, set the ComIOpin output high with a digital write in setup and then address each of the outputs in turn. The LED will be on for as long as the output is addressed.

This is a much better way of turning all the LEDs on in turn:-

/*
16 Channel Analog Extender for Arduino but a demo only it is silly using a multiplexer like this
*/

// Set Analog I/O pin to use for reading channel values from multiplexer.
int ComIOpin = 6;  // HEF4067BP(X)(ICpin-01)

// Set which pins tell the multiplexer which input to read from.
int DpinA0 = 2;  // HEF4067BP Address Input A0 (A)(ICpin-10)
int DpinA1 = 3;  // HEF4067BP Address Input A1 (B)(ICpin-11)
int DpinA2 = 4;  // HEF4067BP Address Input A2 (C)(ICpin-14)
int DpinA3 = 5;  // HEF4067BP Address Input A3 (D)(ICpin-13)

void setup() {

// Set the digital pins to outputs.
pinMode(DpinA0, OUTPUT);  // HEF4067BP Address Input A = pin10
pinMode(DpinA1, OUTPUT);  // HEF4067BP Address Input B = pin11
pinMode(DpinA2, OUTPUT);  // HEF4067BP Address Input C = pin12
pinMode(DpinA3, OUTPUT);  // HEF4067BP Address Input D = pin13
pinMode(ComIOpin, OUTPUT); // you forgot this
digitalWrite(ComIOpin, HIGH);

Serial.begin(9600); // Set Serial COM
}

int led = 0;
void loop() {
addressOutput(led);
led++;
if(led>15) led=0;
delay(500);
}

void addressOutput(int i){
digitalWrite(DpinA0, i & 1);
digitalWrite(DpinA1, (i >>1) & 1);
digitalWrite(DpinA2, (i >>2) & 1);
digitalWrite(DpinA3, (i>>3) & 1);
}

Thanks Mike!! That looks awesome. I'll give it a spin now! How might I incorporate that in my code where I wish for led 15 to be high at a cert value reached by the pot? {
if (val < 170)
{
digitalWrite(ledPin[0], HIGH);
}
else
{
digitalWrite(ledPin[0], LOW);
}

Simply:-
if (val < 170) addressOutput(15); else addressOutput(0);
Will light up LED 15 or LED 0 depending on the value of val.

Remember not addressing the channel turns it off.

If you want all the lights off then:-
digitalWrite(ComIOpin, LOW);
will even turn off the channel that is addressed.

If you want belt and braces and only have LED 15 on and no other:-
if (val < 170){ addressOutput(15);digitalWrite(ComIOpin, HIGH);} else digitalWrite(ComIOpin, LOW);;

:)Thanks Mike, I'm getting closer with your set up but it still isn't working correctly.
Here's my code so far. Trying all your methods, it's the only one that will turn led 15 & 14 on full brightness.However, all the other leds are kind of on half brightness at the same time. Nothing I try will allow 14 or 15 to be on with all the others off. Thanks for your help so far :slight_smile:

int val; 
int ComIOpin = 6;  // HEF4067BP(X)(ICpin-01)
// Set which pins tell the multiplexer which input to read from.
int DpinA0 = 2;  // HEF4067BP Address Input A0 (A)(ICpin-10)
int DpinA1 = 3;  // HEF4067BP Address Input A1 (B)(ICpin-11)
int DpinA2 = 4;  // HEF4067BP Address Input A2 (C)(ICpin-14)
int DpinA3 = 5;  // HEF4067BP Address Input A3 (D)(ICpin-13)

void setup()
{
 // Set the digital pins to outputs.
pinMode(DpinA0, OUTPUT);  // HEF4067BP Address Input A = pin10
pinMode(DpinA1, OUTPUT);  // HEF4067BP Address Input B = pin11
pinMode(DpinA2, OUTPUT);  // HEF4067BP Address Input C = pin12
pinMode(DpinA3, OUTPUT);  // HEF4067BP Address Input D = pin13
pinMode(ComIOpin, OUTPUT); // you forgot this
digitalWrite(ComIOpin, HIGH); 
}

int led;
void loop() {
  

  val = analogRead(4);	// reads the value of the potentiometer

  {
    if (val < 510) { addressOutput(15);digitalWrite(ComIOpin, HIGH);} 

  }
 
  {
    if((val >= 510) && (val < 1024)) { addressOutput(14);digitalWrite(ComIOpin, HIGH);} 

  }
}      

 
 void addressOutput(int i){
digitalWrite(DpinA0, i & 1);
digitalWrite(DpinA1, (i >>1) & 1);
digitalWrite(DpinA2, (i >>2) & 1);
digitalWrite(DpinA3, (i>>3) & 1);
    
   }

Nothing wrong with the code or circuit that I can see, there are a few surplus {} in there but that won't do any harm I think.

How about forgetting the input logic and trying with hard-coded values to see if you have proper control independent of the pot position.


Rob

:slight_smile: I tried that Greynomad and it didn't work. The only thing that came close was to comment this "pinMode(ComIOpin, OUTPUT);" then all the leds are off and only the ones I need are on but very very faint! Maybe I have to use a transistor??

WHERE ARE THE CURRENT LIMITING DIODES ON THE LEDs?

There's a scary question! I haven't used any Mike! I mean, they're all straight from the chip running off the Arduino from usb.

Then you might have killed the chip.

:slight_smile: I just discovered what the problem was! She wasn't getting enough juice! The whole thing was running off 3.3volts on account of my ridiculous use of the 3.3v FTDI breakout for the Bare Bones Board that I'm using. I meant to upgrade it to 5volts but it seems to work fine for programming! However, I imagine that the 4067 needs at least 5volts to function correctly no? I should have looked at the chips's specs
Happy days!! Thanks for your time Mike!! I really appreciate it as always!! :slight_smile: