Need an efficient "1 of 16" routine

Started by jmarkwolf, Nov 29, 2022, 12:25 AM

Previous topic - Next topic


Haven't done any coding in a while, nor have I used the Positron compilers. Looking forward to it.

Part of my new project is to mimic a 74HCT4067 chip (16-channel analog mux/demux). The chip is currently only available in a TSSOP24 package, and I don't want to have to solder such a fine pitch package down. On the other hand, 40-pin dip pics are still available (PIC18F4321_DIP40).

The function input would be a 4-bit input (0 - 15 nibble) and a 1 of 16 output (word), with only one of the 16 outputs enabled at a time.

Should I implement a simple lookup table, or an On Goto construct, or....?

Any input gratefully received.


PIC solutions might be possible but in terms of sheer richness of peripherals STM32 leaves PIC's far behind in a slightly higher price bracket.The arm core is fast, the ADC has 12 bit resolution and 16 channels.
Have a look at Nucleo STM32L0538.
You will find a lot of other variants.
Programming is dead simple using ST's HAL(hardware abstraction layer)


Quote from: jmarkwolf on Nov 29, 2022, 12:25 AMAny input gratefully received.

Do the output ports have all 8 bits? With other words are you going to use two 8-bit ports?

Stephen Moss

First you cannot directly duplicate the 74HCT4067 as it is analogue, so if you intention is to switch analogue signals you either have to...
  • Make a 16 channel selector the single active output of which drives an FET configured as an analogue switch (or quad anaglogue switch device), or
  • Use a PIC that had 16 ADC channels and a DAC, sampling the input of the selected channel and sending it straight to the DAC for restoration to Analogue output, although the time that times may be impractical depending on the end application.

However if anaglogue signals are not required and you just want to make a straight 4 input to one of 16 output conversion then an PIC24 would be slightly easier as it has 16bit wide IO ports, otherwise you have to kind of cobble one together yourself, i.e.
Dim IO_Selection as Word
Dim IO_Low as IO_Selection.LowByte
Dim IO_High as IO_Selection.Highbyte

Then you just set the new value of IO_Selection and PortX = IO_Low, PortY = IO_High, the problem with doing it this way is that unless you know the selection will be sequential you are likely to have two outputs active at the same time (albeit briefly) as obviously data will be written to one I/O port and then the other for device with only 8bit ports so the new active output may be enabled before the old on is disabled (set low or pin set to input) hence a PIC24 would be better as theoretically both output will change at the same time.
Although to be sure no two are active at the same time you could turn off/deactivate all outputs before setting making the new output active.

As for whether to use a lookup table or On Goto, personally I would set up an array of 16 word values, your 4 bit input is used as the index to point the element in the array that holds relevant data to copy to IO_Selection to make the required I/O pin active. Alternatively you could use Select-Case, which effectively does the same thing but may be simpler to grasp if not familar with using arrays, i.e.
Select Set_Channel   'Varable storing you 4bit channel selction value
   Case = 0
   IO_Selection = %0000000000000000
   Case = 1
   IO_Selection = %0000000000000001
  Case = 15
  IO_Selection = %1000000000000000


No Disrespect but why even do this? There are reasons why devices like these are still in production.

For digital signal propagation you will need to continually read the input port and transfer the logic state to 1 of 16 output pins and this can only be one-way only either 16:1 or 1:16. This device effectively connects 1 pin to any of the 16 via the select bits using an analog switch and not a logic state transfer.  The whole process will suffer from latency in the input to output logic transfer due to the code flow/speed.  Analog will be even slower and can only be used 16:1 like Stephen has described unless you have 16 DACS or use external devices and will be severely limited.

For the digital case you would have to create a very tight loop and run the processor as fast as possible to reduce latency, interrupt on the select bits for any change in state and change the input to output pin mapping in your tight loop. 

Alternatively if you do not want to solder the device, design a PCB with TSSOP - DIP and use the a company such as JLCPCB that can SMT the board for you with the IC and header pins fitted!


John Lawton

The CD74HC4067E (PDIP) is apparently available from some stockists.

Also on Ebay and some adaptor boards:


OP here:

I should've clarified my objective a little better.

While the 74HCT4067 is an analog chip, I don't use it for anything other than to light one of 72 LED's. Hence moving the 1 of 16 function to a PIC. The PIC can source and sink 25mA, perfect for LED's.

Nowadays I don't trust web sources for chips fearing they'll be counterfeit. The PIC will serve my purpose well, just a little uncertain as to a viable software approach.

Latency is not an issue for my application. And yes, I will be using 2 8-bit ports.

Thanks for the responses.


That makes is much clearer. Depending on whether you are looking for a direct replacement or an alternative, you could use SPI, I2C or just plain serial for that matter to a number of PICs using a single I/O plus Gnd (serial). Might be much easier to wire up using serial.  I have used this method to control over 1300 WS2812B in panels of 64 LED's.  Preamble, address, command, command running at 9600 baud. 

For replacement I would likely opt for

1. Check enable line
2. if enable is true, read the select bits
2. Use select case / End select and set/clear the I/O

Alternative is to store the 16bit combinations in flash memory, starting at an offset location then add the select to the offset and return the 16bit port value.  Look at Lread16 command in the manual



Assuming you are using PORTA as nibble input and PORTB and PORTD as outputs I'd something like this, or it's variations:

Dim wPin As Word

Output PORTB
Output PORTD

    wPin = 1 << PORTA
    PORTB = wPin.Byte0
    PORTD = wPin.Byte1

With this code there's a brief possibility to have Pin ON at PORTD and Pin ON at PORTB while updating PORTB, therefore you can turn OFF PORTD before setting PORTB:

Dim wPin As Word

Output PORTB
Output PORTD

    wPin = 1 << PORTA
    PORTD = 0
    PORTB = wPin.Byte0
    PORTD = wPin.Byte1



Probably be a good idea to mask off the 4 bits of PORTA so that you have 0-15 before shifting 1<<


Quote from: jmarkwolf on Nov 29, 2022, 12:25 AMShould I implement a simple lookup table, or an On Goto construct, or....?

Any input gratefully received.

I Have done something similar. I only send to the 4067 a binary value, 0 to 15 by masking the pins. It was in my early days using PDS and some one gave me the code. I will try to find it and come back.



Found it! Just load a variable to the output required.

I have another example somewhere where I can alter any pin on a port but cannot find it. Even different pins from different ports using same method, i.e.: - load a variable with my required output.

To give you an idea, I needed 12 outputs from different port and used the same method of loading a variable according to my required output.

The example below is to use the lower nibble of the PORT.

Hopes this helps!

QuoteTemp = PORTx & $F0

PORTx = Temp | variable or constant 

The above works as follows: -

First we need to & (And), the higher nibble by masking the PORT with $F0 and place the value to a variable, i.e. as above, Temp. In this way we saved the state of the higher nibble.

Then we | (Or), the Temp variable with another variable or a constant number. Note: - As we masked the higher nibble, the variable must not exceed the number 15, or binary %00001111. Then the resulting value with the masked PORT Or variable will be loaded to PORTx.