16-channel mux or switch register for reading keyswitches

Status
Not open for further replies.

skybrian

Active member
Hi, I'd like to design a simple circuit board that holds 16 switches and some way to read them, preferably without needing 16 wires to Teensy pins. In previous prototyping I used a keyboard matrix with one diode per switch, but I'm thinking it might be easier to solder if I used a 16-channel mux or maybe a switch register, to avoid soldering all the diodes.

I remember reading a web page on the Teensy website about using a mux to read buttons, but can't find it now. Anyone know where it is?

Alternately, I'm wondering how I select a good chip for this. When narrowing things down using Digikey or Mouser, there seem to be few 16 channel through-hole mux chips and they're pretty expensive? Maybe my search query narrowed things too far.
 
Assuming the switches are just on/off switches, one way be to use an i2c device like the MCP23017, such as Adafruit sells:

You will likely need to add 2 pull-up resistors (2.2K is typical) in order to get I2C to work on Teensy (unless you have something like the prop shield or audio shield that already provides the resistors). Wiring would be:
  • Teensy 3.3v -> MCP23017 VDD
  • Teensy Ground -> MCP23017 VSS
  • Teensy Pin 19 -> two connections: 1 to MCP23017 SCL, and the other to a 2.2K resistor that is connected to 3.3v;
  • Teensy Pin 18 -> two connections: 1 to MCP23017 SDA, and the other to a 2.2K resistor that is connected to 3.3v.

The switches would be connected on one end to the MCP23017 GP pin and on the other end ground (or 3.3v, depending on how you setup the MCP23017 device).
 
The Teensy MIDI page shows how to use 74HC4051 (8:1 multiplexer); the 74HC4067 (16:1 multiplexer) is otherwise similar, but uses four address lines instead of three. Both seem to be available at typical stores (Digikey, Mouser, LCSC) at less than a dollar/euro apiece.

However, the MCP23017 MichaelMeissner suggested is in many ways superior, because you only need to connect four pins (I2C SCL, I2C SDA, 3.3V, and GND) for up to 128 buttons (8 MCP23017 chips). It too seems to be available at those same stores, at about a dollar/euro apiece, or slightly over.

The idea is that instead of using digitalReadFast() to obtain the button states, you communicate with the MCP23017 chips using I2C, using the Wire library. Essentially, after you setup the Wire and initialize the chip, to check the button states you do
Code:
uint8_t b0to7, b8to15;

Wire.begintransmission(32 + address); /* address = 0..7, depending on MCP23017 A0,A1,A2 pins */
Wire.write(0x12);
Wire.requestfrom(32 + address, 2); /* Same as above! */
if (Wire.available() > 0) {
    b0to7 = Wire.read();
    if (Wire.available() > 0)
        b8to15 = Wire.read();
}
Wire.endtransmission();
for each chip, to get the first 8 button states in b0to7, and the second 8 button states in b8to15, for that particular chip.

There is also a SPI version of the same chip, MCP23S17, which is used in a very similar way, except with the SPI bus (and SPI library). (I didn't know this chip existed, only found out about it in the MCP23017 datasheet!)
This chip is interesting in that if one wants to isolate the button circuits, it is rather easy to do with say an ADuM1401 and an isolated DC-DC converter (to supply current to the button circuits). I don't know why anyone would need to isolate the button circuits from the microcontroller, but with this chip it is quite cheap (< $10) and simple. (Each MCP23s17 needs their own chip select pin, so to use multiple chips, you need more isolated channels. With a Si8661, you can use three MCP23s17 chips, for a total of 48 isolated buttons/digital inputs.)

Depending on your use case, you may also wish to debounce the buttons in software.
 
In terms of optimization note that there are various speed levels for I2C, and it defaults to the slowest speed (100Khz), you might be able to boost it up to a higher speed, depending on the device you are talking to, how many devices you have on the I2C bus, and the length of the entire I2C bus.

There are two interrupt pins that can be attached to Teensy pins,and you can use that to skip a group of buttons that weren't pressed in the last cycle.

While the Adafruit MCP23017 library gives you access to each individual button, you probably should get 8 buttons at once to minimize the I2C traffic.

If you are using the Teensy LC, 3.2, 3.5, or 3.6 (but not the Teensy 4.0 or 2.x) there is a library 'i2c_t3.h' that has various advantages over the standard Wire library. The downside is it is incompatible with the standard Wire library, so you have to make sure every library you call does not include Wire.h (it it wants to do I2C, it should be using 'i2c_t3.h' as well). Another downside is at the present, it does not support the Teensy 4.0 processor.
 
Okay, good to know. I'm hoping I don't need to worry too much about that since it doesn't seem likely that I need to poll the keyboard more than 100 times a second, probably less. The MCP23017 will do higher speeds, though, according to the datasheet.
 
Okay, good to know. I'm hoping I don't need to worry too much about that since it doesn't seem likely that I need to poll the keyboard more than 100 times a second, probably less. The MCP23017 will do higher speeds, though, according to the datasheet.

Yeah, human reaction times are fairly slow compared to computer times, but if you decide to go for more buttons, then the problem scales up. :p

Note however, if you do go for higher number of buttons, then you have to pay more attention to proper wiring, and having things be modular can really help.
 
I forgot to mention that the keyswitches will be on two separate boards that need to be wired to the Teensy which is off-board.

It looks like Sparkfun's Qwiic and Adafruit's Stemma QT are pretty similar standards for 4-pin JST SH connectors that carry i2c, power and ground. If I use i2c, I guess I might as well use the same connectors and pinouts on the boards? Maybe compatibility will come in handy someday.
 
I forgot to mention that the keyswitches will be on two separate boards that need to be wired to the Teensy which is off-board.

It looks like Sparkfun's Qwiic and Adafruit's Stemma QT are pretty similar standards for 4-pin JST SH connectors that carry i2c, power and ground. If I use i2c, I guess I might as well use the same connectors and pinouts on the boards? Maybe compatibility will come in handy someday.

Actually, Adafruit specifically says their Stemma QT connectors are compatible with the Sparkfun Qwiic connectors:

What is STEMMA QT?

We like the JST PH 2.0mm pitch cables because they are cross-compatible with Grove/Gravity. But they're a bit large for smaller breakout boards and wearables. So, for smaller I2C devices, we'll use the JST SH that SparkFun Qwiic uses, so that Qwiic & STEMMA QT sensors are cross-compatible!

STEMMA QT devices keep the level shifting/regulator, so you can use STEMMA QT with Grove/Gravity/STEMMA/Qwiic controllers at any voltage range, safely!
 
Status
Not open for further replies.
Back
Top