This is an old version of the documentation. View the latest version here.
Control Surface  1.0.0
MIDI Control Surface library for Arduino


This example demonstrates the use of push buttons and LEDs and how to use shift registers and analog multiplexers to save pins.

AVR, AVR USB, Teensy 3.x, ESP32


Connect 16 momentary push buttons between the input pins of the multiplexer and ground.
The internal pull-up resistor for the buttons will be enabled automatically, so no external resistors are necessary.

Connect 16 LEDs (and series resistors) between the eight outputs of the two shift registers and ground.

Remember to connect the enable pins of both the multiplexer and the shift registers to ground in order to enable them. Also connect the master reset pin of the shift registers to Vcc.
Connect the serial data output of the first shift register (QH' or Q7S) to the serial input of the second shift register.


Pressing the first button will turn on the first LED. Pressing it again will turn it off again. Pressing the second button will turn on the second LED. Pressing it again will turn it off again, and so on.



Written by PieterP, 2018-08-28

#include <Control_Surface.h> // Include the Control Surface library.
// Instantiate a multiplexer
CD74HC4067 mux = {
2, // input pin
{3, 4, 5, 6}, // Address pins S0, S1, S2, S3
// 7, // Optionally, specify the enable pin
// Alternatively, if you have a 3-bit mux:
// CD74HC4051 mux = {
// 2,
// {3, 4, 5},
// // 7, // Optional
// };
// Instantiate a shift register with the SPI slave select pin as latch pin, most
// significant bit first, and a total of 16 outputs.
SPIShiftRegisterOut<mux.length()> sreg = {SS, MSBFIRST};
// Instantiate an array of momentary push buttons.
// It generates an array of Buttons on pins:
// {, ... }
// For each button it creates, it increments the pin number by 1,
// and it starts counting from
auto buttons = generateIncrementalArray<Button, mux.length()>(;
void setup() { // Initialize everything
for (Button &button : buttons)
void loop() { // Check if a button is pressed, if so toggle the LED
for (uint8_t i = 0; i < mux.length(); ++i)
if (buttons[i].update() == Button::Falling)
sreg.digitalWrite(i, !sreg.digitalRead(i));
< Input went from high to high (1,1)
Definition: Button.hpp:53
A class for serial-in/parallel-out shift registers, like the 74HC595 that are connected to the SPI bu...
Definition: SPIShiftRegisterOut.hpp:23
A class for reading and debouncing buttons and switches.
Definition: Button.hpp:15
Array< T, N > generateIncrementalArray(U start=0, V increment=1)
Generate an array where the first value is given, and the subsequent values are calculated as the pre...
Definition: ArrayHelpers.hpp:152
The main header file that includes all Control-Surface header files.
A class for reading multiplexed analog inputs.
Definition: AnalogMultiplex.hpp:25
void begin() override
Initialize the multiplexer: set the pin mode of the address pins and the enable pin to output mode.
Definition: AnalogMultiplex.hpp:178
pin_t pin(pin_t pin) const
Get the extended IO pin number of a given physical pin of this extended IO element.
Definition: ExtendedIOElement.cpp:26
static constexpr uint16_t length()
Definition: StaticSizeExtendedIOElement.hpp:28