Tag Archive | "i/o"

Tutorial: Maximising your Arduino’s I/O ports with MCP23017

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.

[Updated 04/12/2014]

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 one and 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 ‘ports’ – 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 0x20. 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 0x27 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. So before using we need to set whether each port is an input or an output. First, we’ll examine setting them as outputs. So to set port A to outputs, we use:

Then to set port B to outputs, we use:

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

To control port B, we use:

… 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 status of each output pin. Or if binary does your head in, convert it to hexadecimal. Or a decimal number. So for example, you want pins 7 and 1 on. In binary that would be 10000010, in hexadecimal that is 0x82, 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 0x82:

For example, we want port A to be 11001100 and port B to be 10001000 – so we send the following (note we converted the binary values to decimal):

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

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:

And here is the example blinking away:

Although that may have seemed like a simple demonstration, it was created show how the outputs can be used. So 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 we just need to initiate the I2C bus. 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 port B inputs 0~3. Consider the first five lines of void loop() in the following example:

In this example void loop() sends the GPIOB address (0x13) to the IC. Then using Wire.requestFrom() it asks for one byte of data from the IC – the contents of the register at 0x13. 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~7. 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 port A as outputs and port B as inputs. Four LEDs with matching resistors are connected to port A outputs 0~3, with the buttons connected as per example 41.2. Here is the sketch:

By now there shouldn’t be any surprises in the last example – it receives a byte that represents port B, and sends that byte out to port 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. You can get the MCP23017 from Tronixlabs.

visit tronixlabs.com

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 forum – dedicated to the projects and related items on this website.

Posted in arduino, education, I2C, lesson, MCP23017, microcontrollers, tutorial

Kit review – nootropics design EZ-Expander Shield

Hello readers

Today we are going introduce an inexpensive yet useful kit for Arduino people out there – the nootropic design EZ-Expander shield. As the name would suggest, this is an Arduino shield kit that you can easily construct yourself. The purpose of the shield is to give you an extra 16 digital outputs using only three existing digital pins. This is done by using two 74HC595 shift registers – whose latch, clock and data lines are running off digital pins 8, 12 and 13 respectively. For more information about the 74HC595 and Arduino, read my tutorial here, or perhaps download the data sheet.

Before moving forward I would like to note that the kit hardware is licensed under Creative Commons by-sa v3.0, and the design files are available on the nootropic design website; the software (Arduino library) is licensed under the CC-GNU LGPL. Nice one.

However, there is a library written instead to make using the new outputs easier. More on that later… now let’s build it and see how the EZ-Expander performs. Packaing is simple and effective, like most good kits these days – less is more:

packagingss

Everything you need and nothing you do not. The design and assembly instructions can be found by visiting the URL as noted on the label. The parts are simple and of good quality:

partsss4

The PCB is great, a nice colour, solder-masked and silk-screened very well. And IC sockets – excellent. There has been some discussion lately on whether or not kit producers should include IC sockets, I for one appreciate it. However, what I did not appreciate was having to chop up the long header socket to make a six- and eight-pin socket, as such:

cuttingss

Why the producers did not include real 6 and 8 pin sockets is beyond me. I’m not a fan of chopping things up, but my opinion is subjective. However there are a few extra pin-widths for a margin of error, so life goes on. The instructions on the nootropic design website were well illustrated, however the design is that simple you can determine it from the PCB. First, in with the capacitors for power smoothing:

capsss

Then solder in those lovely IC sockets and the header sockets:

socketsinss

Then time for the shield pins themselves. As usual, the easiest way is to insert the pins into another socket, then drop the new shield on top and solder away:

liningupss

Finally, insert the shift registers, and you’re done:

finishedss6

The shield is designed to still allow access to the digital pins zero to seven, and the analogue pins. Here is a top-down view of the shield in use:

topdownfinishedss

From a software perspective, download the library from here and install it into your arduino-00xx\libraries folder. Then it is simple to make use of the new outputs (20 to 35) on the shield, just include the library in your sketch as such:

then create an EZexpander object:

with which you can control the outputs with. For example,

sets the new output pin number 20 high. You can also buffer the pin mode requests, and send the lot out at once. For example, if you wanted pins 21, 22 and 23 to be HIGH at once, you would execute the following:

What happened is that you set the pin status up in advance, then sent all the commands out at once using the expander.doShiftOut(); function. The maximum amount of current you can source from each new output according to the designers is theoretically six milliamps, which is odd as the 74HC595 data sheet claims that 25 milliamps is possible. In the following demonstration I sourced 10 milliamps per LED, and everything was fine. Here is the sketch for your reference:

And the demonstration in action:

Overall, this is an inexpensive and simple way to gain more outputs on an Arduino Duemilanove/Uno or 100% compatible board. Also good for those who are looking for a kit for basic soldering practice that has a real use afterwards. High resolution images are available on flickr.

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. Or join our Google Group.

Posted in arduino, kit review, notropicsComments (4)

Tutorial: Arduino and the I2C bus – Part Two

Part two of our Arduino and I2C bus tutorial.

[Updated 28/11/2014]

Today we are going to continue learning about the I2C bus and how it can work for us. If you have not already, please read and understand the first I2C article before continuing.

First of all, there are some limitations of I2C to take into account when designing your projects. One of these is the physical length of the SDA and SCL lines. If all your devices are on the same PCB, then there is nothing to worry about, however if your I2C bus is longer than around one metre, it is recommended that you use an I2C bus extender IC. These ICs reduce electrical noise over the extended-length bus runs and buffer the I2C signals to reduce signal degradation and chance of errors in the data. An example of such an IC is the NXP P82B715 (data sheet). Using a pair of these ICs, you can have cable runs of 20 to 30 metres, using shielded twisted-pair cable. Below is a good example of this, from the aforementioned NXP data sheet:

i2cbufferedss

Several applications come to mind with an extended I2C bus, for example remote temperature monitoring using the the ST Microelectronics CN75 temperature sensor from part one; or controlling several I/O ports using an I2C expander without the expense or worry of using a wireless system. Speaking of which, let’s do that now…

A very useful and inexpensive part is the PCF8574 I/O expander (data sheet.pdf). This gives us another eight outputs, in a very similar method to the 74HC595; or can be used as eight extra inputs. In fact, if you were to use more than one 74HC595 this IC might be preferable, as you can individually address each chip instead of having to readdress every IC in line as you would with shift registers. So how do we do this? First, let’s consult the pinout:

There should not be any surprises for you there. A2~A0 are used to select the last three bits of the device address, P0~P7 are the I/O pins, and INT is an interrupt output which we will not use. To address the PCF8574 we need two things, the device address, and a byte of data which represents the required output pin state. Huh? Consider:

pcf8574intdef

So if we set pins A0 to A2 to GND, our device address in binary will be 0100000, or 0x20 in hexadecimal. And the same again to set the output pins, for example to turn them all on we send binary 0 in hexadecimal which is 0; or to have the first four on and the second four off, use 00001111 which is Ox0F. Hopefully you noticed that those last two values seemed backwards – why would we send a zero to turn all the pins on?

The reason is that the PCF8574 is a current sink. This means that current runs from +5v, through into the I/O pins. For example, an LED would have the anode on the +5V, and the cathode connected to an I/O pin. Normally (for example with a 74HC595) current would run from the IC, through the resistor, LED and then to earth. That is a current source. Consider the following quick diagram:

sinksource1

In the example above, please note that the PCF8574N can take care of current limitation with LEDs, whereas the 74HC595 needs a current-limiting resistor to protect the LED.

Luckily this IC can handle higher volumes of current, so a resistor will not be required. It sounds a bit odd, but like anything is easy once you spend a few moments looking into it. So now let’s use three PCF8574s to control 24 LEDs. To recreate this masterpiece of blinkiness you will need:

  • Arduino Uno or compatible board
  • A large solderless breadboard
  • Three PCF8574 I/O extenders
  • Eight each of red, green and yellow (or your choice) LEDs, each with a current draw of no more than 20mA
  • Two 4.7 kilo ohm resistors
  • Hook-up wires
  • Three 0.1 uF ceramic capacitors

Here is the schematic:

exam21p1schemss

… and the example board layout:

example21p1boardss

and the example sketch. Note that the device addresses in the sketch match the schematic above. If for some reason you are wiring your PCF8574s differently, you will need to recalculate your device addresses:

 And finally our demonstration video:


That was a good example of controlling many outputs with our humble I2C bus. You could literally control hundreds of outputs if necessary – a quite inexpensive way of doing so. Don’t forget to take into account the total current draw of any extended circuits if you are powering from your Arduino boards.

LEDborder

The next devices to examine on our I2C bus ride are EEPROMs – Electrically Erasable Programmable Read-Only Memory. These are memory chips that can store data without requiring power to retain memory. Why would we want to use these? Sometimes you might need to store a lot of reference data for use in calculations during a sketch, such as a mathematical table; or perhaps numerical representations of maps or location data; or create your own interpreter within a sketch that takes instruction from data stored in an array.

In other words, an EEPROM can be used to store data of a more permanent use, ideal for when your main microcontroller doesn’t haven enough memory for you to store the data in the program code. However, EEPROMs are not really designed for random-access or constant read/write operations – they have a finite lifespan. But their use is quite simple, so we can take advantage of them.

EEPROMS, like anything else come in many shapes and sizes. The model we will examine today is the Microchip 24LC256 (data sheet.pdf). It can hold 256 kilobits of data (that’s 32 kilobytes) and is quite inexpensive. This model also has selectable device addresses using three pins, so we can use up to eight at once on the same bus. An example:

24lc256bb

The pinouts are very simple:

Pin 7 is “write protect” – set this low for read/write or high for read only. You could also control this in software if necessary. Once again we need to create a slave I2C device address using pins 1, 2 and 3 – these correlate to A2, A1 and A0 in the following table:

So if you were just using one 24LC256, the easiest solution would be to set A0~A2 to GND – which makes your slave address 1010000 or 0x50 in hexadecimal. There are several things to understand when it comes to reading and writing our bytes of data. As this IC has 32 kilobytes of storage, we need to be able to reference each byte in order to read or write to it. There is a slight catch in that you need more than one byte to reference 32767 (as in binary 32767 is 11111111 0100100 [16 bits]).

So when it comes time to send read and write requests, we need to send two bytes down the bus – one representing the higher end of the address (the first 8 bits from left to right), and the next one representing the lower end of the address (the final 8 bits from left to right) – see figure 6.1 on page 9 of the data sheet.

An example – we need to reference byte number 25000. In binary, 25000 is 0110000110101000. So we split that up into 01100001 and 10101000, then covert the binary values to numerical bytes with which to send using the Wire.send(). Thankfully there are two operators to help us with this. This first is >>, known as bitshift right. This will take the higher end of the byte and drop off the lower end, leaving us with the first 8 bits. To isolate the lower end of the address, we use another operator &, known as bitwise and. This unassuming character, when used with 0XFF can separate the lower bits for us. This may seem odd, but will work in the examples below.

Writing data to the 24LC256

Writing data is quite easy. But first remember that a byte of data is 11111111 in binary, or 255 in decimal. First we wake up the I2C bus with:

then send down some data. The first data are the two bytes representing the address (25000) of the byte (12) we want to write to the memory.

And finally, we send the byte of data to store at address 25000, then finish the connection:

There we have it. Now for getting it back…

Reading data from the 24LC256

Reading is quite similar. First we need to start things up and move the pointer to the data we want to read:

Then, ask for the byte(s) of data starting at the current address:

In this example, incomingbyte is a byte variable used to store the data we retrieved from the IC. Now we have the theory, let’s put it into practice with the test circuit below, which contains two 24LC256 EEPROMs. To recreate this you will need:

  • Arduino Uno or compatible board
  • A large solderless breadboard
  • Two Microchip 24LC256 EEPROMs (you can use 24LC512s as well)
  • Two 4.7 kilo ohm resistors
  • Hook-up wires
  • Two 0.1 uF ceramic capacitors

Here is the schematic:

examp21p2schemss

… the board layout:

exam21p2boardss

and the example sketch. Note that the device addresses in the sketch match the schematic above. If for some reason you are wiring your 24LC256s differently, you will need to recalculate your device addresses. To save time with future coding, we have our own functions for reading and writing bytes to the EEPROM – readData() and writeData(). Consider the sketch for our example:

And the output from the example sketch:

example21p2result

Although the sketch in itself was simple, you now have the functions to read and write byte data to EEPROMS. Now it is up to your imagination to take use of the extra memory.

If you enjoyed this article, or want to introduce someone else to the interesting world of Arduino – check out my book (now in a fourth printing!) “Arduino Workshop”.

visit tronixlabs.com

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 forum – dedicated to the projects and related items on this website.

Posted in 24LC256, arduino, I2C, learning electronics, lesson, microcontrollers, PCF8574, tutorialComments (17)


Subscribe via email

Receive notifications of new posts by email.

The Arduino Book

Arduino Workshop

Für unsere deutschen Freunde

Dla naszych polskich przyjaciół ...

Australian Electronics!

Buy and support Silicon Chip - Australia's only Electronics Magazine.

Use of our content…

%d bloggers like this: