Saturday, August 27, 2011

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.

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 theMCP23017.

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 asreviewed 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 just shift the bits from bank B << 4 to remove the switch four bits, then shift the remaining bits back to positions 3~0 – 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:

Question - What was the CPU speed of the original MITS Altair 8800 computer?

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 | 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<<4; dig3=dig3>>4; dig2=GPIOA >> 4; dig1=GPIOA<<4; dig1=dig1>>4;  // 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!

If you have any questions about the processes or details in this article, please ask in our Google Group – dedicated to the projects and related items on this website. Sign up – it’s free, there is the odd competition or give-away –  and we can all learn something. Or follow tronixstuff on twitter and facebook. High resolution images available on flickr.

Otherwise, have fun, stay safe, be good to each other – and make something!

No comments:

Post a Comment