t r o n i x s t u f f

fun and learning with electronics

Tutorial: Arduino and multiple push-wheel 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.

Please note that the tutorials are not currently compatible with Arduino IDE v1.0. Please continue to use v22 or v23 until further notice. 

Welcome back fellow arduidans!

This article continues with the push-wheel switches introduced the other week. 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 (download):

Example 40a

/*
  Example 40a - Read four pushwheel BCD switches via MCP23017, display on SAA1064/4-digit 7-segment LED display
  http://tronixstuff.wordpress.com | John Boxall CC by-sa-nc
 */

// MCP23017 pins 15~17 to GND, I2C bus address is 0x20
// SAA1064 I2C bus address 0x38
#include "Wire.h"

// for LED digit definitions
int digits[16]={
  63, 6, 91, 79, 102, 109, 125,7, 127, 111, 119, 124, 57, 94, 121, 113};

byte GPIOA, GPIOB, dig1, dig2, dig3, dig4;

void initMCP23017()
{
  // setup MCP23017
  Wire.beginTransmission(0x20);
  Wire.send(0x12);
  Wire.send(0x20); // use table 1.4 addressing
  Wire.endTransmission();
}

void initSAA1064()
{
  //setup 0x38
  Wire.beginTransmission(0x38);
  Wire.send(0);
  Wire.send(B01000111); // 12mA output, no digit blanking
  Wire.endTransmission();
}

void setup()
{
  Serial.begin(9600);
  Wire.begin(); // start up I2C bus
  initMCP23017();
  initSAA1064();
}

void loop()
{
  // read the inputs of bank A
  Wire.beginTransmission(0x20);
  Wire.send(0x12);
  Wire.endTransmission();
  Wire.requestFrom(0x20, 1);
  GPIOA=Wire.receive(); // this byte contains the switch data for digits 1 and 2

  // read the inputs of bank B
  Wire.beginTransmission(0x20);
  Wire.send(0x13);
  Wire.endTransmission();
  Wire.requestFrom(0x20, 1);
  GPIOB=Wire.receive(); // this byte contains the switch data for digits 3 and 4
  // extract value for each switch
  // dig1 LHS, dig4 RHS
  dig4=GPIOB >> 4;
  dig3=GPIOB & B00001111;
  dig2=GPIOA >> 4;
  dig1=GPIOA & B00001111;
  // send all GPIO and individual switch data to serial monitor
  // for debug and interest's sake
  Serial.print("GPIOA = ");
  Serial.println(GPIOA, BIN);
  Serial.print("GPIOB = ");
  Serial.println(GPIOB, BIN);
  Serial.println();

  Serial.print("digit 1 = ");
  Serial.println(dig1, BIN);
  Serial.print("digit 2 = ");
  Serial.println(dig2, BIN);
  Serial.print("digit 3 = ");
  Serial.println(dig3, BIN);
  Serial.print("digit 4 = ");
  Serial.println(dig4, BIN);
  Serial.println();

  Serial.print("digit 1 = ");
  Serial.println(dig1, DEC);
  Serial.print("digit 2 = ");
  Serial.println(dig2, DEC);
  Serial.print("digit 3 = ");
  Serial.println(dig3, DEC);
  Serial.print("digit 4 = ");
  Serial.println(dig4, DEC);
  Serial.println();

  // send switch value to LED display via SAA1064
  Wire.beginTransmission(0x38);
  Wire.send(1);
  Wire.send(digits[dig4]);
  Wire.send(digits[dig3]);
  Wire.send(digits[dig2]);
  Wire.send(digits[dig1]);
  Wire.endTransmission();
  delay(10);
  delay(1000);
}

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.

August 27, 2011 - Posted by | arduino, education, I2C, microcontrollers | , , , , , , , , , , , , , , , ,

6 Comments »

  1. Nice example, especially for showing the hardware that exists. It happens too often that you make something difficult because you don’t know there’s already a piece out there that helps with something.
    I’ve programmed AVRs in Assembler and C, but never with sketches. Isn’t there a “swap” operation? It switches the “nibbles” (first/last 4 bits) in a byte. And instead of shifting forth and back I would just “&” 0b00001111 to it. Only three instructions instead of 12 (shifting by four places takes four instructions). I was counting clock cycles for some programs that needed every clock cycle in some parts, so I’m nitpicking here a little ;) .

    Comment by Lupin | August 27, 2011 | Reply

    • Hello Lupin
      Thank you for your reply. One of the ‘downsides’ with Arduino is the easy of lazy coding :) Especially when you’re in a rush to get something done. We don’t have swap, but we do have &. Will go back and change it in the next update.
      Thanks for your time
      john

      Comment by John Boxall | August 28, 2011 | Reply

  2. Hi John,
    Thanks for the series of great tutorials! I find them very helpful, but all video links simply appear as this:
    watch?v=nlQTTNYRRjw
    and I am unable to click on the link to watch it. My browser is Chrome running on Ubuntu 10.04. Thanks for any enlightenment!

    Carl

    Comment by Carl | August 28, 2011 | Reply

    • Hello Carl
      That is really odd – we’re running Ubuntu 11.04 and Chrome 13.0.782.215 and it’s fine. Have you got Adobe flash turned off in Chrome?
      In the meanwhile all the videos are at youtube.com/tronixstuff or vimeo.com/tronixstuff.
      cheers
      john

      Comment by John Boxall | August 28, 2011 | Reply

      • Hello again John,
        I left out a small detail in my previous post ;) . I should have said that the faulty links happened only when viewing the email newsletter while in gmail. All is fine when I visit http://tronixstuff.wordpress.com/. Sorry about that. Guess I should check my gmail settings! Thanks for your prompt reply.

        Carl

        Comment by Carl | August 30, 2011

      • Ah, fair enough. :-) Thank you for letting me know.
        Cheers
        John

        Comment by John Boxall | August 30, 2011


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 2,588 other followers