I’ve been attempting to control an LCD using my brand new Arduino and a 74HC595N shift register, in which I failed (for now). I also tried the MCP23016 pin expander, which I got working after quite some experimentation. I even wrote a library for it!
The shift register
Yesterday, while I was waiting for an extra delivery of sensors and a servo, I started playing with an IC, 74HC595N, which is a so-called shift register.
Now I haven’t done much with electronics in the past, and I’ve never used an IC (integrated circuit) before. Fortunately many people have been using these chips in their own projects and have documented it well. I found numerous examples of how to use it with an Arduino, and it didn’t take long before I got 8 leds glowing, and was able to toggle them using only 3 wires.
So, the next thing I wanted to use it for, was to control an LCD (liquid crystal display). LCDs use 6 wires at least, so controlling them through an IC that only needs two is quite efficient. I feel I’ll be otherwise be out of I/O ports soon if I start using LCD’s. Unfortunately, despite the examples I found, I couldn’t get it to work, so after a couple of hours of feeble attempts, I gave up and put it aside for the time being.
The I2C I/O expander
But I also recieved an order with some more sensors, and another IC. A ‘pin expander’ as it was called, which sounded interestingly enough, and because it was cheap as well, I bought it, reasoning that I could figure out how to use it once I got it.
It turned out to be the MCP23016 I/O expander. So I decided to try it in the same way as I tried the other IC: Google for examples. 😉
People seemed to agree on how to wire it. It needs an extra resistor and a capacitator, so it didn’t take long to get this result:
Basic wiring: Red and Black are +5V and GND. White (=SDA, Serial Data) and Yellow (=SCL, Serial Clock) go to analogue pins 4 and 5 on the Arduino.
Unfortunately, you need to hook up three more pins to either GND ( = ground, or 0V) or +5V to give the chip an address between 0 and 7. After that, you can wire up 16 LEDs, resulting in a board that looks like this:
A crowded board, partially due to grounding the 3 address pins, pins 1 and 19 and the capacitator.
A tad crowded, but that is a small price for controlling up to 128 leds (using 8 ICs) with only two pins on the Arduino! Pretty impressive, but also quite messy, so I tried to eliminate some of the wires, by soldering the components onto the IC. Et voilá:
Much cleaner: Only add +5V, GND, SCL and SDA. And the I/O connectors of course.
Pin 1 is wired to pin 19 (hard to see on the picture, because the wire is black as well as the chip).
The capacitator of 33pF is wired between pins 9 and 19
The 3.9k Ω resistor links pin 9 to pin 20.
With a small block of four header pins soldered together, I can easily address this IC as chip ‘0’, while still leaving me the option of adding others. I could as well have soldered pins 16 to 19 together, but is scares me a little to do so, so I chose for this separate block.
(Image by Lewis Loflin)
In some configurations, I saw pin 8 being grounded, but others they were not connected at all. I chose the latter option, which seemed to work fine.
Counting to 65535 using 16 LEDs.
LCD again
So far so good. Now, I wanted to attempt –again- to get the LCD screen working through the IC. Fortunately, I found a couple of examples for that too, including some complete replacement libraries for the LiquidCrystal library that comes with Arduino. Unfortunately I couldn’t get any of these to work.
Finally, I stumbled upon an example by Lewis Loflin that did work: http://www.bristolwatch.com/arduino/mcp23016_lcd_display.htm.
Now, while this code did work, it didn’t resemble in any way the LiquidCristal library. Instead it implements a bunch of loose functions, which isn’t bad per se, but I liked a more or less drop-in replacement for the existing library.
Therefore, I made my own attempt to write an LiquidCrystal_I2C library. I’ve found a couple of those, but like I said, none of them did the trick for me, so here is mine. It’s my first Arduino library, although not much of it is mine indeed. Most of it is from the Arduino LiquidCrystal library. The gaps are filled in using the code from bristolwatch.com.
I haven’t fully tested the library, although a couple of functions seem to work fine, including moving the cursor, showing and blinking it and defining custom characters. Some methods from the original library I haven’t implemented at all:
[sourcecode]
void printLeft();
void printRight();
void leftToRight();
void rightToLeft();
void shiftIncrement();
void shiftDecrement();
void noBacklight();
void backlight();
[/sourcecode]
Usage:
[sourcecode]
#include
#include <LiquidCrystal_I2C_GT.h>
// 0x20 is the I2C address for the first IC. You should be able to link them
// together, using addresses 0x20 to 0x27, though I haven’t tried.
LiquidCrystal_I2C_GT lcd(0x20, 16, 2); // Address, columns, lines
// If you want to define your own character, you can do it as described in
// the Create Char reference:
// http://arduino.cc/en/Reference/LiquidCrystalCreateChar
byte smiley[8] = {
B00000,
B10001,
B00000,
B00000,
B10001,
B01110,
B00000,
};
void setup()
{
// Don’t call begin (which is done in the constructor, but you’ll have to call
// init to initialize the LCD. I’ll try to improve this.
lcd.init();
lcd.createChar(0, smiley);
lcd.clear();
// Print two lines to the LCD
lcd.print("Hello world!! It");
lcd.setCursor(0, 1);
lcd.print("seems to work! ");
lcd.write(0); // Smiley
}
void loop()
{
}
[/sourcecode]
Download the source code for the LiquidCrystal_I2C_GT library.
The text and the custom character (smiley)
Is it finished? No it’s not.
Although it works so far, I do have some question to answer for myself:
- How can I use the remaining pins? I used only 10 of the 16 I/O pins I gained.
- Why didn’t the other libraries work? Same for the attempts using the shift register.
- The LCD now runs in 8 bit mode instead of the 4 bit text mode that the LiquidCrystal library uses by default. How can I exploit the extra features that come with that mode?
Apart from that, I need to..
- Do some testing and debugging.
- Do some cleaning up.
- Implement the missing functions.
Nevertheless, I feel I’ve made some progress today. I hope you’ve enjoyed reading this post, and that it will be of use to you.