I2C vs. Shift Registers, and I/O shift registers

Hi folks - I am using a NodeMCU and I have the following:

  • 8 output ports controlling my main loads
  • 1 analog input port monitoring state of how many of the loads are plugged in to the circuit
  • 5 dipswitches I need to read the value of

Clearly I don't have enough pins on the NodeMCU. Been reading about I2C and shift registers; seems like I2C only takes 2 pins but is harder to use; shift registers are easier but take 4 pins.

I'm thinking I'll want to cascade two shift registers together, so I'd have 16 pins on the shift registers controlled from 4 NodeMCU pins, plus the remaining NodeMCU pins.

However -- is it possible to cascade two shift registers and use some of the pins for input and some for output? I know the popular shift registers I need to choose which chip I use.

What is a good way to go here to get the shift registers working? Would the best/simplest just be to eat 8 pins off the NodeMCU and have two distinct shift registers, one for input and one for output?

If possible I'd really like to control the 8 load outputs from native nodeMCU pins.

74HC595 only needs 3 pins.
You can put all 5 dip-switches into 1 ADC pin, just use staggered resistors.

So your project now just needs 5 pins?

How is I2C problematic?

Slumpert - can you tell me more what you mean by staggered resistors?

WRT I2C - very open to thoughts I've just not used it or shift registers before and the latter seemed simpler based on my research. Maybe not though?

The I2C port extenders such as PCF8574 and MCP23017 work very much like the internal pins: input, output, internal pull-up resistor, and with the libraries that exist for them allow you to read/set each pin individually. Two pins control up to 128 I/O. Very easy to control.

Shift registers are input only or output only depending on the type (the 595 is output), and you have to do more work in code to keep track of all the pins and very time write them all at the same time. Three pins control virtually unlimited inputs or outputs; limits are mostly practical

Shift registers are cheaper and faster.

By staggered resistors do you mean different values of resistors on each switch such that based on resultant analog voltage I can calculate which switches are on?

If so I love it but I'm not sure how the math would work so I definitively know each. Hmmmm maybe only of each resistor wqs a different order of magnitude? But with 5, I think that would be too many orders of magnitude to be able to measure?

The search keyword you're looking for is "resistor ladder".

wvmarle:
The search keyword you're looking for is "resistor ladder".

I'm curious how you would hook this up to use for reading multiple switches. (not individual buttons)
I haven't thought about it enough and like larrywal32 mentioned, I assume it is theoretically possible, but typically ladder networks are used for multiple buttons, where only a single button is pressed at a time.

--- bill

larrywal32:
By staggered resistors do you mean different values of resistors on each switch such that based on resultant analog voltage I can calculate which switches are on?

For 5v Arduino you could use common 5% resistors 9100, 4700, 2200, 1100, and 560ohm.
Connected in parallel between 5v, dip switch, and the ADC pin.
Say
Switch 1 was on = 9100ohm resistance,
Switch 1 and 2 are on (9100 + 4700) / 2 = 6900ohm
All switched on = 17660 / 5 = 3532ohm

Granted pre-populating a 25 place array with the truth table lookup was bit hassle of hassle, this is about condensing pins, not code.

I have not played with 3volt attempting this, possible just need to stagger starting at 4700 and use 220ohm as last.

This is fantastic. I think I can build a quick spreadsheet with the mapping values... will give that a shot and post back

A word of caution for using the ADC pin.
I ran into issues on a project where I was wanting to create my own external voltage divider.
It took me a while to figure out what the problem was.

The NodeMCUs and Wemos Minis I have don't bring out the processors ADC pin directly.
They have voltage divider circuitry on the PCB.

The A0 pin on the D1 mini PCB wired to a 220k resistor,
The actual ADC pin on the ESP8266 is wired to the 220k resistor and a 100k resistor to gnd.

This is what the ADC circuit on the PCB looks like on the boards I have:

A0 pin ------[ 220k ] ---+---[ 100k ] ---- GND
                         |
ESP8266 ADC -------------+

So you can see the A0 pin you get access to on the PCB is not the actual ADC pin since there is some additional onboard circuitry between pin you get access to and the actual ACD pin on the processor.

I'm guessing that this was to allow using 5V signals directly.

Just be aware that this added circuitry can potentially cause issues and/or prevent certain types of designs from being used.

--- bill

@slumpert – I made the calculations – the Ohm differences between some of the possible values between 0 and 32 are really small (like 5 ohms difference between decimal value 23 and decimal value 12).

If what bperrybap says doesn’t affect things, then presumably at 3.3V for the NodeMCU and these differing Ohm values, the voltage difference at constant current of 100mA with only a difference of 5 ohms would be 0.2. That seems like it would clearly be insignificant based on error rates of resistors and components?

Is that the right way to think about it?

(see attached screenshot for my calculations)

bperrybap:
The NodeMCUs and Wemos Minis I have don't bring out the processors ADC pin directly.
They have voltage divider circuitry on the PCB.

That is to bring the ADC range to 3.3V, which is Vcc for those processors.

Still confusing as the ESP8266's ADC is not ratiometric, it uses a fixed internal reference of about 1V. This in contrast to the Atmel processors which by default are ratiometric (reference to Vcc), but have the option to use one or more internal reference voltages, and most also offer the option of an external reference voltage on the Vref pin.

I think the general rule of thumb is that the port expanders (I2C) are easier to code, but run at I2C speed that makes them in the 100Kbps (400Kbps)

port expanders give your GPIO pins. the PCA8574 you get on the LCD serial to parallel module gives you GPIO pins. can be daisy chained, so only 2 pins, but limited to available addresses. 4 total I think for the PCA8574 (64 GPIO pins)

google IIC/I2C/TWI/SPI Interface Module

the other option is a shift register

shift registers use the SPI bus, so 10Mbsp
shift registers are typically all input, or all output the 595 is all output, the 165 is all input.
you can get a more powerful TPIC6B595 that can handle 150mA per channel.

Port expanders cost a bit more
shift registers cost a bit less.

choose wisely.

dave-in-nj:
the PCA8574 you get on the LCD serial to parallel module

I think you mean the PCF8574. It has 8 I2C addresses; just like the MCP23008 and MCP23017.

It's important to note that the PCF8574 (and it's 16-port version the PCF8575) can not source current from its pins, so to drive LEDs for example you have to wire them active low, and they're not suitable to drive n-channel MOSFETs or NPN transistors.

larrywal32:
@slumpert -- I made the calculations

I don't understand your calculations. Part of it is I don't understand how you have assumed things have been wired up so I don't know what '0' vs '1' actually means in terms of altering the circuit paths.

However, the spreadsheet table says "Ohms from parallel resistors" and
the final resistance of resistors in parallel is not the average of the individual resistance values. It is the product divided by the sum of the resistance values.
i.e. if you put a 560 ohm resistor in parallel with a 220 ohm resistor, you won't get a Resistance 390 which would be higher than 220 ohms but rather a resistance of 157.95 ohms.

wvmarle:
I think you mean the PCF8574. It has 8 I2C addresses; just like the MCP23008 and MCP23017.

It's important to note that the PCF8574 (and it's 16-port version the PCF8575) can not source current from its pins, so to drive LEDs for example you have to wire them active low, and they're not suitable to drive n-channel MOSFETs or NPN transistors.

The PCF8574 can be used with NPN transistors. On PCF8574 based i2c LCD backpacks, some use PNP transistors and some use NPN. This is why some backpacks need an active high vs active low signal on the PCF8574 pin to turn on the backlight.

NPN transistors are actually more common as it allows the backlight to be on by default even before the i2c lcd library has a chance to initialize things as the PCF8574 defaults to "input" mode which puts a high output level on the backlight control pin.

--- bill

bperrybap:
The PCF8574 can be used with NPN transistors.

It can source only about 300µA of current... indeed may be just enough for switching the 10 mA that backlight needs. OTOH if you connect the backlight cathode to the pin it's active low and you don't even need that transistor, as the chip can sink 10 mA or even a little more.

wvmarle:
It can source only about 300µA of current... indeed may be just enough for switching the 10 mA that backlight needs. OTOH if you connect the backlight cathode to the pin it's active low and you don't even need that transistor, as the chip can sink 10 mA or even a little more.

Sure.
I was just pointing out that the PCF8574 can be and is used to control NPN transistors.

--- bill