Tutorial: Arduino and multiple thumbwheel switches

This is an addendum to chapter forty of a series originally titled “Getting Started/Moving Forward with Arduino!” by John Boxall – a series of articles on the Arduino universe. The first chapter is here, the complete series is detailed here. Any files from tutorials will be found here.

Updated 24/11/2012

This article continues with the push-wheel switches introduced in chapter 40. In the previous article, we learned how to read the value of a single digit using the digital pins of our Arduino. With this instalment we will examine how to read four digits – and not waste all those digital pins in the process. Instead, we will use the Microchip MCP23017 16-bit port expander IC that communicates via the I2C bus. It has sixteen digital input/output pins that we can use to read the status of each switch.

Before moving forward, please note that some assumed knowledge is required for this article – the I2C bus (parts one and two) and the MCP23017.

We first will describe the hardware connections, and then the Arduino sketch. Recall the schematic used for the single switch example:


When the switch was directly connected to the Arduino, we read the status of each pin to determine the value of the switch. We will do this again, on a larger scale using the MCP23017. Consider the pinout diagram:

We have 16 pins, which allows four switches to be connected. The commons for each switch still connect to 5V, and each switch contact still has a 10k pull-down resistor to GND. Then we connect the 1,2,4,8 pins of digit one to GPBA0~3; digit two’s 1,2,4,8 to GPA4~7; digit three’s 1,2,4,8 to GPB0~3 and digit four’s 1,2,4,8 to GPB4~7. For demonstration purposes we are using the Gravitech 7-segment shield as reviewed in the past.

Now how do we read the switches? All those wires may cause you to think it is difficult, but the sketch is quite simple. When we read the value of GPBA and B, one byte is returned for each bank, with the most-significant bit first. Each four bits will match the setting of the switch connected to the matching I/O pins.

For example, if we request the data for both IO banks and the switches are set to 1 2 3 4 – bank A will return 0010 0001 and bank B will return 0100 0011. We use some bitshift operations to separate each four bits into a separate variable – which leaves us with the value of each digit. For example, to separate the value of switch four, we shift the bits from bank B >> 4. This pushes the value of switch three out, and the blank bits on the left become zero. To separate the value for switch three, we use a compound bitwise & – which leaves the value of switch three.

Below is a breakdown of the binary switch values – it shows the raw GPIOA and B byte values, then each digit’s binary value, and decimal value:

So let’s see the demonstration sketch :

And for the non-believers … a video demonstration:

So there you have it. Four digits instead of one, and over the I2C bus conserving Arduino digital I/O pins. Using eight MCP23017s you could read 32 digits at once. Have fun with doing that!


Have fun and keep checking into tronixstuff.com. Why not follow things on twitterGoogle+, subscribe  for email updates or RSS using the links on the right-hand column, or join our Google Group – dedicated to the projects and related items on this website. Sign up – it’s free, helpful to each other –  and we can all learn something.

The following two tabs change content below.

John Boxall

Person. Founder and original author for tronixstuff.com. VK3FJBX

2 thoughts on “Tutorial: Arduino and multiple thumbwheel switches

  1. Norbert

    I managed to read 4 (four) push-wheel switches on 8 io lines.

    My trick uses additional 4 diodes at each pushwheel switch (so 16 diodes for 4 wheels)
    and connects
    4 output lines directly select the “digit” by pulling it’s common line low.
    I used the high nibble bits for this purpose.

    Each diode cathode is connected to the pins 1 2 4 8 of an individual pushwheel.

    All pin 1 anodes are connected together and are connected to an input line.
    I used bit0 for all pin1 cathodes.

    All pin 2 anodes are connected together and are connected to an input line.
    I used bit1 for all pin2 cathodes.

    All pin 4 anodes are connected together and are connected to an input line.
    I used bit2 for all pin4 cathodes.

    All pin 8 anodes are connected together and are connected to an input line.
    I used bit3 for all pin8 cathodes.

    The read process is done the following way:
    1. Enable all pullups on the four input lines
    loop across 4 pushwheels
    2. Select the pushwheel you want to read by setting only the corresponding output line to low
    3. read the four input lines (do some masking and xor-ing) and store the value
    loop end

    Thats all!
    If you want to expand and add one more wheel you just need
    1 wheel, 4 diodes, 1 outputline

    I used the above trick on a attiny2313 on port B0..B7 to create a special serial message when INT0 is happening (uses 30% of the 2K attiny2313 )

    Have fun with it
    Regards Norbert

  2. John Smith

    You can have as many bcd switches as you like,I use CD4017 counters, with just 6 arduino pins ( 1,2,4,8 from the switches via a diode on each, clock and reset for the CD4017s ) each output of the 4017 is connected to the common of one switch, and the 4017s are “daisy-chained”.

    I often have 19 bcd switches connected like this for cricket scoreboards.

    The code is simple, reset the 4017s, take the clock high, read the four data pins, save as a byte, take the clock low again and repeat above for each switch.

    digitalWrite(reset4017, HIGH); // make sure 4017s are reset,
    digitalWrite(reset4017, LOW);

    for ( int j = 0; j <= 18; j++ ){
    digitalWrite(clock4017, HIGH);
    scan ();
    digitalWrite(clock4017, LOW);
    msg[j] = address;

    void scan () {
    address = 0;
    add3 = digitalRead(SW3);
    add3 = add3 << 3;
    add2 = digitalRead(SW2);
    add2 = add2 << 2;
    add1 = digitalRead(SW1);
    add1 = add1 << 1;
    add0 = digitalRead(SW0);
    address = address|add3;
    address = address|add2;
    address = address|add1;
    address = address|add0;


Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.