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 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<<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!

Friday, August 26, 2011

Tutorial: Maximising your Arduino’s I/O ports

This is chapter forty-one 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!

In this article we discuss how to use the Microchip MCP23017 16-bit serial expander with I2C serial interface. This 28-pin IC offers sixteen inputs or outputs – and up to eight of the ICs can be used on one I2C bus… offering a maximum of 128 extra I/O ports. A few people may be thinking “Why not just get an Arduino Mega2560?” – a good question. However you may have a distance between the Arduino and the end-point of the I/O pins – so with these ICs you can run just four wires instead of a lot more; save board space with custom designs, and preserve precious digital I/O pins for other uses. Plus I think the I2C bus is underappreciated! So let’s get started…

Here is our subject of the article in DIP form:

At this point you should also download yourself a copy of data sheet – it will be referred to several times, and very useful for reference and further reading. Furthermore if you are not familiar with Arduino and the I2C bus, please familiarise yourself with the I2C tutorials parts oneand two. The MCP23017 can be quite simple or complex to understand, so the goal of this article is to try and make it as simple as possible. After reading this you should have the knowledge and confidence to move forward with using a MCP23017.

First, let’s look at the hardware basics of this IC. Consider the pinouts:

The sixteen I/O ports are separated into two ‘banks’ – A (on the right) and B (on the left. Pin 9 connects to 5V, 10 to GND, 11 isn’t used, 12 is the I2C bus clock line (Arduino Uno/Duemilanove analogue pin 5, Mega pin  21), and 13 is the I2C bus data line (Arduino Uno/Duemailnove analogue pin 4, Mega pin 20). External pull-up resistors should be used on the I2C bus – in our examples we use 4.7k ohm values. Pin 14 is unused, and we won’t be looking at interrupts, so ignore pins 19 and 20. Pin 18 is the reset pin, which is normally high – therefore you ground it to reset the IC. So connect it to 5V!

Finally we have the three hardware address pins 15~17. These are used to determine the I2C bus address for the chip. If you connect them all to GND, the address is 0×20. If you have other devices with that address or need to use multiple MCP23017s, see figure 1-2 on page eight of the data sheet. You can alter the address by connecting a combination of pins 15~17 to 5V (1) or GND (0). For example, if you connect 15~17 all to 5V, the control byte becomes 0100111 in binary, or 0×27 in hexadecimal.

Next, here is a basic schematic illustrating how to connect an MCP23017 to a typical Arduino board. It contains the minimum to use the IC, without any sensors or components on the I/O pins:

Now to examine how to use the IC in our sketches. As you should know by now most I2C devices have several registers that can be addressed. Each address holds one byte of data that determines various options. With the MCP23017 the registers can be ordered in one of two ways – see tables 1.3 and 1.4 on page nine of the data sheet. In our examples we will use the addresses listed on table 1.4. So the first command to use in void setup() is:

Wire.beginTransmission(0x20); Wire.send(0x12); Wire.send(0x20); // use table 1.4 addressing Wire.endTransmission();

The next is to set the I/O ports as inputs or outputs. First we will work with outputs. When the MCP23017 is turned on or reset, it defaults to inputs so we need to change them. So we use:

Wire.beginTransmission(0x20); Wire.send(0x00); // IODIRA register Wire.send(0x00); // set all of bank A to outputs Wire.send(0x00); // set all of bank B to outputs Wire.endTransmission();

Go back to the data sheet and see table 1.4. Notice how we started with the IODIRA (“I/O direction, bank A”) register at 0×00 and sent two bytes? You can do this without having to separate address the second register. This only works when the registers have sequential addresses, as in this example we wanted a byte to go to 0×00 then 0×01. We sent zero which in binary is 00000000 – each bit refers to one output of the bank and refers to I/O pins 7~0.

So now we are in void loop()  or a function of your own creation and want to control some output pins. To control bank A, we use:

Wire.beginTransmission(0x20); Wire.send(0x12); // address bank A Wire.send(??);  // value to send Wire.endTransmission();

… replacing ?? with the binary or equivalent hexadecimal or decimal value to send to the register. To calculate the required number, consider each I/O pin from 7 to 0 matches one bit of a binary number – 1 for on, 0 for off. So you can insert a binary number representing the output levels. Or if binary does your head in, convert it to hexadecimal. So for example, you want pins 7 and 1 on. In binary that would be 10000010, in hexadecimal that is 0×82, or 130 decimal. (Using decimals is convenient if you want to display values from an incrementing value or function result).

If you had some LEDs via resistors connected to the outputs, you would have this as a result of sending 0×82:

Now if you want to address all the outputs at once, just send the byte for bank B after bank A. For example, we want bank A to be 11001100 and bank B to be 10001000 – so we send the following:

Wire.beginTransmission(0x20); Wire.send(0xCC); // address bank A Wire.send(0x88); // address bank B Wire.endTransmission();

… with the results as such (bank B on the left, bank A on the right):

You can also just address bank B, if so bank A does not change. Now let’s put all of this output knowledge into a more detailed example. From a hardware perspective we are using a circuit as described above, with the addition of a 560 ohm resistor followed by an LED thence to ground from on each of the sixteen outputs. Here is the sketch (download):

Example 41.1

/* Example 41.1 - Microchip MCP23017 with Arduino http://tronixstuff.wordpress.com/tutorials > chapter 41 John Boxall | CC by-sa-nc */  // pins 15~17 to GND, I2C bus address is 0x20  #include "Wire.h"  void setup() { Wire.begin(); // wake up I2C bus  // setup addressing style Wire.beginTransmission(0x20); Wire.send(0x12); Wire.send(0x20); // use table 1.4 addressing Wire.endTransmission();  // set I/O pins to outputs Wire.beginTransmission(0x20); Wire.send(0x00); // IODIRA register Wire.send(0x00); // set all of bank A to outputs Wire.send(0x00); // set all of bank B to outputs Wire.endTransmission(); }  void binaryCount() { for (byte a=0; a<256; a++) { Wire.beginTransmission(0x20); Wire.send(0x12); // GPIOA Wire.send(a);    // bank A Wire.send(a);    // bank B Wire.endTransmission(); delay(100); } }  void loop() { binaryCount(); delay(500); }

And here is the example blinking away:

Although that may have seemed like a simple demonstration, it was created to get theSo now you know how to control the I/O pins set as outputs. Note that you can’t source more than 25 mA of current from each pin, so if switching higher current loads use a transistor and an external power supply and so on.

Now let’s turn the tables and work on using the I/O pins as digital inputs. The MCP23017 I/O pins default to input mode, so all we need to do is set the addressing method as such in void setup()

// setup addressing style Wire.beginTransmission(0x20); Wire.send(0x12); Wire.send(0x20); // use table 1.4 addressing Wire.endTransmission();

Then in the void loop() or other function all we do is set the address of the register to read and receive one byte of data. For our next example, we have our basic sketch as described at the start of this article using four normally-open buttons (once again using the ‘button board‘) which are connected to bank B inputs 0~3. Consider the first five lines of void loop() in the following example (download);

Example 41.2

/* Example 41.2 - Microchip MCP23017 with Arduino http://tronixstuff.wordpress.com/tutorials > chapter 41 John Boxall | CC by-sa-nc */  // pins 15~17 to GND, I2C bus address is 0x20 #include "Wire.h" byte inputs=0;  void setup() { Serial.begin(9600); Wire.begin(); // wake up I2C bus  // setup addressing style Wire.beginTransmission(0x20); Wire.send(0x12); Wire.send(0x20); // use table 1.4 addressing Wire.endTransmission(); }  void loop() { Wire.beginTransmission(0x20); Wire.send(0x13); // set MCP23017 memory pointer to GPIOB address Wire.endTransmission(); Wire.requestFrom(0x20, 1); // request one byte of data from MCP20317 inputs=Wire.receive(); // store the incoming byte into "inputs"
if (inputs>0) // if a button was pressed { Serial.println(inputs, BIN); // display the contents of the GPIOB register in binary delay(200); // for debounce } }

In this example void loop() sends the GPIOB address (0×13) to the IC. Then using Wire.requestFrom() it asks for one byte of data from the IC – the contents of the register at 0×13. This byte is stored in the variable inputs. Finally if inputs is greater than zero (i.e. a button has been pressed) the result is sent to the serial monitor window and displayed in binary. We display it in binary as this represents the state of the inputs 0~8. Here is an example of pressing the buttons 1, 2, 3 then 4 – three times:

And as we are reading eight inputs at once – you can detect multiple keypresses. The following is an example of doing just that:

As you can see pressing all four buttons returned 1111, or the first and third returned 101. Each combination of highs and lows on the inputs is a unique 8-bit number that can also be interpreted in decimal or hexadecimal. And if you wanted to read all sixteen inputs at once, just request and store two bytes of data instead of one.

For our last example – a demonstration of using bank A as outputs and bank B as inputs. Four LEDs with matching resistors are connected to bank A outputs 0~3, with the buttons connected as per example 41.2. Here is the sketch (download):

Example 41.3

/* Example 41.3 - Microchip MCP23017 with Arduino http://tronixstuff.wordpress.com/tutorials > chapter 41 John Boxall | CC by-sa-nc */  // pins 15~17 to GND, I2C bus address is 0x20 #include "Wire.h" byte inputs=0;  void setup() { Serial.begin(9600); Wire.begin(); // wake up I2C bus  // setup addressing style Wire.beginTransmission(0x20); Wire.send(0x12); Wire.send(0x20); // use table 1.4 addressing Wire.endTransmission();  Wire.beginTransmission(0x20); Wire.send(0x00); // IODIRA register Wire.send(0x00); // set all of bank A to outputs Wire.endTransmission(); }  void loop() { // read the inputs of bank B Wire.beginTransmission(0x20); Wire.send(0x13); Wire.endTransmission(); Wire.requestFrom(0x20, 1); inputs=Wire.receive();  // now send the input data to bank A Wire.beginTransmission(0x20); Wire.send(0x12); // GPIOA Wire.send(inputs);    // bank A Wire.endTransmission(); delay(200); // for debounce }

By now there shouldn’t be any surprises in the last example – it receives a byte that represents bank B, and sends that byte out to bank A to turn on the matching outputs and LEDs. For the curious, here it is in action:

So there you have it… another way to massively increase the quantity of digital I/O pins on any Arduino system by using the I2C bus.

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!

Wednesday, August 24, 2011

August 2011 Competition

Hello Readers

Time for another competition! To enter is very easy. There will be six questions hidden within articles published at tronixstuff.com the month of August (but not this one!). Once you have answers to all six, email them to competition at tronixstuff dot com with “August 2011″ in the subject line before 2359h GMT September 4th. On the 5th of September, I will compile a list of people with the correct answers, and randomly select two winners. Please note competition rules at the end of this article.

The first winner drawn will receive a brand new Freetronics EtherTen!

This is the mother of all Arduino-compatible boards. Designed in Australia and manufactured to the highest quality standards the EtherTen replaces three boards – consider having an Arduino Uno SMD, Ethernet shield with PoE, and a microSD shield – all on the one board. From the Freetronics website:

The EtherTen is a 100% Arduino compatible board that can talk to the world. Do Twitter updates automatically, serve web pages, connect to web services, display sensor data online, and control devices using a web browser. The Freetronics EtherTen uses the same ATmega328P as the Duemilanove and the same Wiznet W5100 chip used by the official Arduino Ethernet Shield, so it’s 100% compatible with the Ethernet library and sketches. Any project you would previously have built with an Arduino and an Ethernet shield stacked together, you can now do all in a single, integrated board.

We’ve even added a micro SD card slot so you can store web content on the card, or log data to it.

All the good things about the Eleven and the Ethernet Shield have been combined into this one device so please see those pages for all the specific details, but the highlights include:

  • Gold-plated PCB.
  • Top and bottom parts overlays.
  • Top-spec ATmega328P MCU.
  • Mini-USB connector: no more shorts against shields!
  • D13 pin isolated with a MOSFET so you can use it as an input.
  • Power-over-Ethernet support, both cheapie DIY or full 802.3af standards-compliant.
  • Ethernet activity indicators on the PCB and the jack.
  • 10/100base-T auto-selection.
  • Fully compatible with standard Ethernet library.
  • Reset management chip.
  • Fixed SPI behavior on Ethernet chipset.
  • Robust power filtering.
  • Sexy rounded corners.

Note that just like our Ethernet Shield with PoE support, the EtherTen provides a number of options for different Power over Ethernet. You can use the supplied jumpers and feed 7-12Vdc down the wire for cheap DIY version, or you can fit our PoE Regulator 24V and feed a bit more voltage down the wire, or you can use our PoE Regulator 802.3AF along with a proper commercial PoE injector or switch. It’s up to you.

And of course there is a second prize – the Freetronics LCD & Keypad shield

This LCD and Keypad Shield gives you a handy 16-character by 2-line display, 5 buttons and a controllable backlight, plug it straight in on top of your Arduino board or other project shields.
The display is set behind the shield for a low profile fitment and nice look and we’ve included panel mounting screw holes in the corners.

It’s great when you want to build a stand-alone project with its own user interface that doesn’t require a computer attached to send commands to your Arduino.

Works perfectly in 4-bit mode with the “LiquidCrystal” library included with the Arduino IDE, allowing you to control the LCD with a total of just 6 digital I/O lines. We’ve deliberately picked D4-D9 so that it doesn’t interfere with pins required by other popular products such as the Ethernet Shield and EtherTen, so you can stack this on top of other shields to give you a local display.

The buttons provide “left”, “right”, “up”, “down”, and “select” while using just one analog input. That leaves the other analog inputs free for you to use in your projects.

The LCD backlight is connected to D3 and can be controlled for on/off, brightness and flashing effects.

Features:

  • 16×2 LCD using HD44780-compatible display module (white characters on blue background).
  • 5 buttons on one analog input (A0).
  • LCD backlight with current limiting, brightness and on/off controllable by D3, can be moved to D2, D10, A1, A2, A3, A4 or A5 for easy project pin compatibility.
  • Recessed LCD, panel mount screw holes and button layout suitable for panel or cabinet mounting if desired.
  • Reset button.
  • Power supply smoothing capacitor.
  • Gold-plated PCB for maximum durability.
  • Overlay printed on both the top and the bottom.
  • Pins used by shield clearly marked, LiquidCrystal library setup reference is on the bottom of the pcb for convenience.

As with any other competition, there needs to be some rules:

  • Prizes will be delivered via Australia Post domestic or regular international air mail. Winners may elect for other methods upon payment of real cost;
  • Winners outside of Australia will be responsible for any taxes, fees or levies imposed by your local Governments (such as import levies, excise, VAT, etc.) upon importation of purchased goods;
  • Prizes may take up to 45 days to be received;
  • If you have met me John Boxall in person, or you have won a previous competition you cannot enter;
  • The Judge’s decision is final with regards to any dispute;
  • Entries will be accepted until 2359h GMT on 4th September 2011.

And of course thanks to our generous competition sponsor Freetronics!

Visit the Freetronics website or resellers to see their full range of quality Arduino-related products.

So have fun and keep checking into tronixstuff.com. Why not follow things on twitter, 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.

Tuesday, August 23, 2011

Review: Gravitech 7-Segment Arduino Shield

Hello Readers

In this article we examine the “7-Segment Arduino Shield” received for review from the team at Gravitech in the United States. This is an Arduino Uno/Duemilanove-type compatible shield that contains four very useful items:

  • Four 7-segment LED numerical displays – driven by the NXP SAA1064 LED display driver IC;
  • A large 10mm RGB LED;
  • A Microchip 24LC128 EEPROM, and
  • A TI TMP75 digital temperature sensor.
Apart from the LED all the other components are controlled via the I2C bus. So as well as being generally useful for experimenting, monitoring temperature and so on, this is an ideal board for Arduino and I2C bus practice. (If you have not done so already, consider reading our I2C tutorial,part one and two). Let’s look at the hardware, then move on to using the features.
As with other Gravitech products, the shield arrives in a reusable static shielding bag:
and here we have it:
The IC at the top-left of the shield is the TMP75 temperature sensor, bottom-left is the 24LC128 EEPROM, and the whopper below the first two digits is the NXP SAA1064. The shield layout is very neat and clean, and the white finish is a pleasant change compared to the usual black or green Arduino shields out there. The PWR LED is a blue colour. The only issue from a hardware perspective was that the component leads were not trimmed at the factory, which caused an issue when the shield was inserted into an Ethernet shield. This is easily solved by clipping the leads yourself:
Here is the shield in operation using the supplied demonstration sketch. The temperature is displayed in Celsius, with the LED changing colour depending on the temperature:

That is all very good, but how do we use the features of the board? Let’s look at each of the aforementioned features individually. First of all, the numeric display. The four seven-segment LED displays are controlled by the NXP SAA1064 LED display driver (data sheet (.pdf)). I have written a separate tutorial on how to use this IC, and it is completely compatible with this shield. So visit the tutorial here and put the numbers to work! Please note the I2C bus address for the SAA1064  is 0×38.

Next we have the RGB LED. Red, green and blue are connected to digital pins 3, 5 and 6 respectively. These are also pulse-width modulation pins, so you can have altering the brightness. Here is a simple demonstration sketch (download):

/* PWM LED example sketch for Gravitech 7-segment Shield - http://www.gravitech.us/7segmentshield.html */  int red = 3; // the pins for the LED int green = 5; int blue = 6; int i = 0; // for loops int j = 0;  void setup() { pinMode(red, OUTPUT); // tell Arduino LED is an output pinMode(green, OUTPUT); pinMode(blue, OUTPUT); } void loop() { // first, cycle up each primary colour twice for (j = 1; j < 2; j++) {  // loop 5 times for (i = 0; i < 255; i++) { // loop from 0 to 254 (fade in) analogWrite(red, i);      // set the LED brightness delay(20); // Wait 10ms because analogWrite isn't instant } analogWrite(red,0); delay (20); for (i = 0; i < 255; i++) { // loop from 0 to 254 (fade in) analogWrite(green, i);      // set the LED brightness delay(20); // Wait 10ms because analogWrite isn't instant } delay (20); analogWrite(green,0); for (i = 0; i < 255; i++) { // loop from 0 to 254 (fade in) analogWrite(blue, i);      // set the LED brightness delay(20); // Wait 10ms because analogWrite isn't instant } delay (20); analogWrite(blue,0); } // psychadelic time for (j = 1; j < 10000; j++) { analogWrite(red,random(255)); // set red at random brightness between 0 and 254 delay (random(21)+100);           // wait for a random duration between 10 and 30 milliseconds analogWrite(green,random(255)); delay (random(21)+100); analogWrite(blue,random(255)); delay (random(21)+100); } }

And for the curious, here it is in action:

Next, the Microchip 24LC128 EEPROM. It has 128kbit storage space, which translates to 16 kilobytes. The I2C bus address is 0×50. Once again there is a complete explanation of how to use this sort of EEPROM in another tutorial – check it out. But for quick reference the following demonstration sketch writes the numbers 0~255 to memory locations 0~255 (download):

/* 24LC128 EEPROM example sketch for Gravitech 7-segment Shield - http://www.gravitech.us/7segmentshield.html */  #include      // for I2C #define chip1 0x50    // device address for 24LC128  // always have your values in variables unsigned int pointer = 69; // we need this to be unsigned, as you may have an address > 32767 byte d=0; // example variable to handle data going in and out of EERPROMS  void setup() { Serial.begin(57600); // for screen output Wire.begin();   // wake up, I2C! }  void writeData(int device, unsigned int add, byte data) // writes a byte of data 'data' to the chip at I2C address 'device', in memory location 'add' { Wire.beginTransmission(device); Wire.send((int)(add >> 8));   // left-part of pointer address Wire.send((int)(add & 0xFF)); // and the right Wire.send(data); Wire.endTransmission(); delay(10); }  byte readData(int device, unsigned int add) // reads a byte of data from memory location 'add' in chip at I2C address 'device' { byte result;  // returned value Wire.beginTransmission(device); //  these three lines set the pointer position in the EEPROM Wire.send((int)(add >> 8));   // left-part of pointer address Wire.send((int)(add & 0xFF)); // and the right Wire.endTransmission(); Wire.requestFrom(device,1); // now get the byte of data... result = Wire.receive(); return result; // and return it as a result of the function readData }  void loop() { Serial.println("Writing data..."); for (int a=0; a<255; a++) { writeData(chip1,a,a); } Serial.println("Reading data..."); for (int a=0; a<255; a++) { Serial.print("EEPROM pointer "); Serial.print(a); Serial.print(" holds "); d=readData(chip1,a); Serial.println(d, DEC); } }
Although there is 16 kilobytes of memory the sketch only writes and reads to the first 255 locations. Each location can store a byte of value between zero and 255. Here is a screen shot of the serial monitor results (click to enlarge):

And now time to work with the Texas Instruments TMP75 temperature sensor (data sheet.pdf). It has a reasonable operating temperature range of between -40 and 125 degrees Celsius – however this would exceed the range in which your Arduino is capable of working, so no leaving the shield on the car dashboard during a hot summer’s day. The I2C bus address for the TMP75 is 0×49. We will deconstruct the Gravitechdemonstration sketch to explain how the temperature works.

The TMP75 needs to be initialised before measurement can take place, by sending the following data:

Wire.beginTransmission(0x49);
Wire.send(1); Wire.send(B01100000); Wire.endTransmission(); Wire.beginTransmission(0x49); Wire.send(0); Wire.endTransmission();

The temperature data is received in two bytes of data, as it spans 12 bits. Thankfully the demonstration sketch has done the work for us. Have a look at the Cal_temp() function, which converts the two raw bytes of data from the TMP75. There is some bitwise arithmetic in there, however if you are not keen on going down to that level, it is easy enough to cut and paste the temperature and numeric display functions.  Here is a quick video of the demonstration sketch in action:

So there you have it – another useful and educational shield for use with your Arduino. If you have any questions or enquiries please direct them to Gravitech via their contact page. Gravitech products including the 7-segment shield are available directly from their website or these distributors.

As always, thank you for reading and I look forward to your comments and so on. Furthermore, don’t be shy in pointing out errors or places that could use improvement. Please subscribe using one of the methods at the top-right of this web page to receive updates on new posts, follow on twitterfacebook, or join our Google Group.

[Disclaimer - the shield reviewed in this article was a  promotional consideration made available by Gravitech]

High resolution photos are available on flickr.

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

Monday, August 15, 2011

Tutorial: Arduino and Push-wheel switches

This is 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!

In this article we go back to the past via the use of push-wheel switches with out Arduino systems. Here are some examples sourced from somewhere on eBay:

For the uninitiated, each switch is one vertical segment and they can be connected together to form various sizes. You can use the buttons to select from digits zero through to nine. There are alternatives available that have a wheel you can move with your thumb instead of the increase/decrease buttons. Before the days of fancy user interfaces these switches were quite popular methods for setting numerical data entry. However they are still available today, so let’s see how they work and how we can use them.

The switch’s value is made available via binary-coded decimal. Consider the rear of the switch:

We have common on the left, then contacts for 1, 2, 4 and 8. If you apply a small voltage (say 5V) to common, the value of the switch can be measured by adding the values of the contacts that are in the HIGH state. For example, if you select 3 – contacts 1 and 2 will be at the voltage at common. The values between zero and nine can be represented as such:

By now you should realise that it would be easy to read the value of a switch – and you’re right, it is. We can connect 5V to the common,  the outputs to digital input pins of our Arduino boards, then use digitalRead() to determine the value of each output. In the sketch we use some basic mathematics to convert the BCD value to a decimal number. So let’s do that now.

From a hardware perspective, we need to take into account one more thing – the push-wheel switch behaves electrically like four normally-open push buttons. This means we need to use pull-down resistors in order to have a clear difference between high and low states. So the schematic for one switch would be (click image to enlarge):

Now it is a simple matter to connect the outputs labelled 1, 2, 4, and 8 to (for example) digital pins 8, 9, 10 and 11. Connect 5V to the switch ‘C’ point, and GND to … GND. Next, we need to have a sketch that can read the inputs and convert the BCD output to decimal. Consider the following sketch (download):

Example 40.1

/* Example 40.1 - display single thumbwheel switch data http://tronixstuff.wordpress.com/tutorials > chapter 40 | cc v3.0 by-sa-nc Uses Gravitech SAA1064 numerical display shield http://www.gravitech.us/7segmentshield.html Uses serial monitor if you don't have the SAA1064 shield */  #include    #define q1 8 #define q2 9 #define q4 10 #define q8 11  void setup() { Serial.begin(9600); Wire.begin();        // join i2c bus (address optional for master) delay(500); pinMode(q1, INPUT); // thumbwheel '1' pinMode(q2, INPUT); // thumbwheel '2' pinMode(q4, INPUT); // thumbwheel '4' pinMode(q8, INPUT); // thumbwheel '8' }   void dispSAA1064(int Count) // sends integer 'Count' to Gravitech SAA1064 shield { const int lookup[10] = { 0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F  }; int Thousands, Hundreds, Tens, Base; Wire.beginTransmission(0x38); Wire.send(0); Wire.send(B01000111); Wire.endTransmission(); Wire.beginTransmission(0x38); Wire.send(1); Thousands = Count/1000; Hundreds = (Count-(Thousands*1000))/100; Tens = (Count-((Thousands*1000)+(Hundreds*100)))/10; Base = Count-((Thousands*1000)+(Hundreds*100)+(Tens*10)); Wire.send(lookup[Base]); Wire.send(lookup[Tens]); Wire.send(lookup[Hundreds]); Wire.send(lookup[Thousands]); Wire.endTransmission(); delay(10); }   int readSwitch() { int total=0; if (digitalRead(q1)==HIGH) { total+=1; } if (digitalRead(q2)==HIGH) { total+=2; } if (digitalRead(q4)==HIGH) { total+=4; } if (digitalRead(q8)==HIGH) { total+=8; } return total; }  void loop() { dispSAA1064(readSwitch()); // sends switch value to display shield Serial.println(readSwitch()); // sends switch value to serial monitor box }

The function readSwitch()  is the key. It calculates the value of the switch by adding the numerical representation of each switch output and returns the total as its result. For this example we used a numerical display shield that is controlled by the NXPSAA1064. If you don’t have one, that’s ok – the results are also sent to the serial monitor. Now, let’s see it in action:

Ok it doesn’t look like much, but if you need numerical entry it saves a lot of physical space and offers a precise method of entry. Now let’s repeat the exercise, however using four digits instead of one. This will be somewhat more complex, but is certainly achievable. It is a mess to describe using Fritzing, so instead I will narrate the schematic for you…

All the 1, 2, 4, and 8s of the thumb wheel switches connect together and thence to digital 8~11 respectively, with a 10k ohm pull-down resistor to GND as normal. However – we need to activate one switch at a time, so we use a 74HC4066 to electrically isolate the common for each switch. Please read this now if you are unfamiliar with the 74HC4066.

We connect digital pins 12, 7, 2 and 4 to 74HC4066 pins 13, 5, 6 and 12 respectively. 74HC4066 pins 1, 4, 8, 11 and 14 connect to 5V; pin 7 to GND, and pins 2, 3, 9 and 10 to the commons of the thumb wheel switches from left to right.

Now consider the sketch (download):

Example 40.2

/* Example 40.2 - display four thumbwheel switch data http://tronixstuff.wordpress.com/tutorials > chapter 40 | cc v3.0 by-sa-nc Uses Gravitech SAA1064 numerical display shield http://www.gravitech.us/7segmentshield.html Uses serial monitor if you don't have the SAA1064 shield */  #include    // digital pins for BCD output #define q1 8 #define q2 9 #define q4 10 #define q8 11  //digital pins for each thumbwheel's 5V int s1=12; int s2=7; int s3=2; int s4=4;  void setup() { Serial.begin(9600); Wire.begin();        // join i2c bus delay(500); pinMode(q1, INPUT); // thumbwheel '1' pinMode(q2, INPUT); // thumbwheel '2' pinMode(q4, INPUT); // thumbwheel '4' pinMode(q8, INPUT); // thumbwheel '8'    pinMode(s1, OUTPUT); // thumbwheel #1~4 pinMode(s2, OUTPUT); pinMode(s3, OUTPUT); pinMode(s4, OUTPUT);  digitalWrite(s1, LOW); digitalWrite(s2, LOW); digitalWrite(s3, LOW); digitalWrite(s4, LOW); }   void dispSAA1064(int Count) // sends integer 'Count' to Gravitech SAA1064 shield { const int lookup[10] = { 0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F    }; int Thousands, Hundreds, Tens, Base; Wire.beginTransmission(0x38); Wire.send(0); Wire.send(B01000111); Wire.endTransmission(); Wire.beginTransmission(0x38); Wire.send(1); Thousands = Count/1000; Hundreds = (Count-(Thousands*1000))/100; Tens = (Count-((Thousands*1000)+(Hundreds*100)))/10; Base = Count-((Thousands*1000)+(Hundreds*100)+(Tens*10)); Wire.send(lookup[Base]); Wire.send(lookup[Tens]); Wire.send(lookup[Hundreds]); Wire.send(lookup[Thousands]); Wire.endTransmission(); delay(10); }   int readSwitch() { int total=0; if (digitalRead(q1)==HIGH) { total+=1; } if (digitalRead(q2)==HIGH) { total+=2; } if (digitalRead(q4)==HIGH) { total+=4; } if (digitalRead(q8)==HIGH) { total+=8; } return total; }  int readSwitches() { int ones=0; int tens=0; int hundreds=0; int thousands=0; int final=0;  digitalWrite(s1, HIGH); thousands=readSwitch(); digitalWrite(s1, LOW);  digitalWrite(s2, HIGH); hundreds=readSwitch(); digitalWrite(s2, LOW);  digitalWrite(s3, HIGH); tens=readSwitch(); digitalWrite(s3, LOW);  digitalWrite(s4, HIGH); ones=readSwitch(); digitalWrite(s4, LOW); final=(thousands*1000)+(hundreds*100)+(tens*10)+ones; return final; }  void loop() { dispSAA1064(readSwitches()); // sends switch value to display shield Serial.println(readSwitches()); // sends switch value to serial monitor box }

Note the new function readSwitches(). It “activates” each thumbwheel switch one at a time, from left to right. Each switch is read using readSwitch() and the value used to calculate the total displayed on the four switches. As another resident here borrowed my normal camera, here are some still demonstration images:

So there you have it. Would you actually use these in a project? For one digit – yes. For four? Maybe – perhaps it would be easier to use a 12-digit keypad. There’s an idea…  But for now I hope you enjoyed reading this as much as I did writing it for you.

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!

 

Monday, August 8, 2011

Tutorial: Gravitech Arduino Nano MP3 Player

Hello readers

In this article we will introduce playing MP3 files using the Gravitech Arduino Nano and MP3 add-on board as shown earlier. This board utilises the VLSI VS1053B decoder IC, which is quite well specified (download the data sheet [.pdf]). However in the interests of keeping things simple we will look at the most popular use – playback of MP3 files. The MP3 files can be in stereo, see the data sheet for more information with regards to bit rate etc. Here again is our board, both top:

… and bottom:

Using this board we can initiate playback to a pair of earphones, or an external amplifier. There is also a tiny speaker connected to the left audio channel, however it is not made for loud broadcasting! Some of you may be thinking “oh wow!, let’s make our own MP3 player” – which is a pretty normal thought after seeing this shield for the first time. However due to the size of the system, portability may be an issue. However, after some thought there are many uses for the shield, such as:

  • Event-driven recording playback. For example, you could standardise PA announcements by playing back pre-recorded messages at the press of a button instead of attempting to train staff to articulate themselves in an understandable manner (e.g. railway annoucements);
  • Modification of devices for the vision-impaired – a recording could be played after a particular event has occurred with the device;
  • Adding voice or music output to an art installation;
  • Etcetera

You get the idea. From a hardware perspective, you will need the Arduino Nano, the MP3 add-on board, and a microSD card. It is recommended that you not use a microSDHC card as they can be somewhat unreliable in this situation. Furthermore, please format the card with the FAT16 or FAT32 file system. Finally, to prepare for our first example – please copy the MP3 files downloadable from here onto your microSD card.

Now some preliminary software work needs to be done. Please download and install the SdFat library. The VLSI 1053B decoder chip uses the SPI bus (SPI? See my tutorials, parts one and two) – and so does the microSD card. Generally the CS (chip select) line is connected to digital 10 on Arduino – but our MP3 board uses 4. So we need to slightly modify the SdFat library to take this into account. Let’s do this now. First of all, locate and open in a text editor the file Sd2PinMap.h. It will be located in the library folder as shown below:

Now, scroll down to line number 279 in the file, and change the parameter uint8_t const SS_PIN from 10 to 4 – as such:

Finally, save and close the file. If you are working with other products that use the SPI bus and an SD card reader, you may want to run two separate Arduino IDE/library installations. At this point ensure your microSD card is formatted, contains the initial demonstration MP3 files, and inserted into the card socket underneath the board. Finally – insert your Nano into the MP3 board, plug in some headphones (or move the volume knob to mid-postion) and the USB lead. Then download and install this demonstration sketch. You will hear some bells (track001.mp3) and drums (track002.mp3).

A brief look at that sketch reveals much code that to the beginner or intermediate user could be somewhat confusing. But don’t let this worry you, we can rearrange a few things to make using the MP3 shield very easy. For our next example, we will learn how to alter the headphone output volume, and select which track to play. Download and open this sketch, and also download and copy these example sound files to your microSD card.

You can ignore everything except for the void loop() section of the sketch – there are two functions of note. The first being:

Mp3SetVolume(0,0);

This sets the output volume for the left and right audio channel. 0 is maximum volume, and the minimum is over 250. You should call this function every time if you need a default volume lower than 100% after every system reset/power cycle. The other function to note is:

playMP3("news.mp3");

This function is the goal of the exercise – just insert the file name of the MP3 you want to play. Note that file names must be in the old 8.3 character format (e.g. “evie123.mp3″ and not “Evie – Parts 1, 2 and 3.mp3″). Now you can have your sketch fire up the MP3 player on request – you can insert your code into this sketch and modify as required.

At this point you may be considering the output options of the MP3 board apart from a pair of earphones. Things are not entirely as they seem, and some thought does need to go into the hardware connections. Do not connect anything else apart from normal stereo “walkman”-style earphones to the socket on the board. Doing so will risk damaging the decoder IC. Furthermore, if you wish to connect the output from the board to an external amplifier, some extra circuitry is required. Some of this is included on the board, and some is not. First, please download and view the VS1053 output guide (.pdf). Turn to page eight to find the following schematic:

In order to connect to a line-out input of an amplifier via the earphone socket, you will need to recreate the circuit above. Some of this has been done on the board – resistors R7~R9 and C3~C5 are preinstalled. You can see this in the MP3 shield schematic. So do the right thing and reap the rewards!

Now you can go forth and musify your creations with MP3 music and other recordings. Please note that this article would not have been possible without the example Arduino  sketches provided by Nathan Seidle, the founder and CEO of Sparkfun. If you meet him, buy him a beer.

If you have any further hardware questions or enquiries relating to the Arduino Nano or MP3 board, please direct them to Gravitech via their contact page. The Gravitech Arduino Nano and MP3 board used in this article were promotional considerations provided by Gravitech, whose products including the Arduino Nano family are available directly from their website or these distributors.

As always, thank you for reading and I look forward to your comments and so on. Furthermore, don’t be shy in pointing out errors or places that could use improvement. Please subscribe using one of the methods at the top-right of this web page to receive updates on new posts, follow on twitterfacebook, or join our Google Group.

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