Having a display in your robot can very helpful in developing and
debugging the hardware and software of the robot. My first Maze Runner
used a 16 character 2 line display to debug the range sensors, calibrate
the servos, wheel encoders, and floor sensors.
You could do a similar
operation with a serial port and a PC, but you are limited to the
location of the PC and your cable length (unless you have a laptop).
Another use for the display is a menu system that selected the operating
mode you wish to run, i.e. "Left wall follow", "Right wall follow", as
well as enabling different turn algorithms and sensors.
An LCD display can be very inexpensive and use very little current, no
need to worry about the battery life. I've seen serial display modules
go for $49 (text) or $99 (graphic)which is a big dent in the wallet. A
better approach is to buy the displays from surplus centers such as B.G.
Micro or All-Electronics, where a 2x16 display with backlight will cost
you $5. Then either connect it directly to your micro or you could even
use a 2nd micro just to control the display. Now with a little software
development you have the equivalent to that $49 serial display, for
under $10.
The majority of these LCD displays use the Hitachi HD44780 or equivalent
controller, so the rest of this article will be based on the use of this
type of display. One thing to watch out for is the contrast circuit on
the display. Some of the display units you can get are "temperature
compensating" or "Extended temperature". These units require a negative
voltage for the contrast input, so unless you have multiple power
supplies on your robot, make sure you don't get this type of display.
The regular display unit will work by simply grounding the contrast
input (pin 3).
Hardware Interface
Ok, now you have a display module, let's see how to use it. The typical
interface is a 14-pin connector with the following pinout:
1 = GND
2 = VCC (typically 5 volts)
3 = VEE (contrast voltage)
4 = RS register select - H = data input, L = instruction input
5 = R/W Read/Write - H = read data from display, L = write data to display
6 = CE Chip Enable - H = interface enabled, L = interface disabled
7 = DB0 data bit 0
8 = DB1 data bit 1
9 = DB2 data bit 2
10 = DB3 data bit 3
11 = DB4 data bit 4
12 = DB5 data bit 5
13 = DB6 data bit 6
14 = DB7 data bit 7
The display interface can support either a 4-bit or 8-bit mode. In 8-bit
mode you send one byte at a time to the display and require a minimum of
10 I/O bits. The 4-bit mode uses only 6 I/O bits, but runs a little
slower since it takes 2 write cycles to send each byte to the display
(sends a 4-bit nibble each time).
Here's the minimum hookup you can do, which uses 4 data bits, the CE,
and the RS lines. I show all 6 bits connected to port D of a
microcontroller, but you can use whatever ports you have available.
Note that in 4-bit mode you will actually use the upper data bits of the
display interface, while the lower 4 are grounded. By tying the R/W
line to ground, the display is always in write mode and you save one
more I/O line. The only drawback to this approach is you can't read
back the status to see if the display is busy, but must rely on a blind
delay to determine when you can send more data to the display. Not a
big deal for most applications.
|
|
If you can afford the extra I/O pins and want to write as fast as you
can, then 8-bit mode is the way to go. Now you hook up all 8 data bits,
plus the CE, RS, and R/W lines. Now you write 1 whole byte at a time
and can monitor the status register to determine when the display is not
busy.
|
|
|
Some microprocessor use an external bus for all I/O instead of port
pins. This is a typical method for using the display on a databus.
Note that the R/W mode is determined by the processor WR line, and that
CE and RS are mapped into various memory locations.
|
|
Software Interface
Ok now your display is wired up and ready to go. If you apply power to
it, nothing will happen because we need to initialize it. The
initialize sequence will vary slightly depending on whether you use 4 or 8
bit access. Note that during the initialization routine the Busy Flag is
not available for readback, so delays must be used between write
operations. You don't need to use the minimum delay shown, you could
use 15ms for each of the delays if it makes the code writing simpler.
Also note that newer display designs may have faster chips and don't
require the same delays as the HD44780 chipset. Please consult the
specs for your display to determine the actual delays required.
8-bit Initialization
Display powers up
Wait at least 15ms for display startup
write 0x30 with RS=0
Wait at least 4.1ms
write 0x30 with RS=0
Wait at least 100us
write 0x30 with RS=0
Wait at least 40us
write 0x30 with RS=0 ;8-bit mode
Wait at least 40us
write 0x38 with RS=0 ;5x7 font, 2 line mode
Wait at least 40us
write 0x0C with RS=0 ;display on, cursor off
Wait at least 40us
write 0x06 with RS=0 ;cursor moves right, no shift
Wait at least 40us
4-bit Initialization
Display powers up
Wait at least 15ms for display startup
write 0x3 with RS=0
Wait at least 4.1ms
write 0x3 with RS=0
Wait at least 100us
write 0x3 with RS=0
Wait at least 40us
;after the first 3 writes all commands
;must now be 8-bits sent as 2 4-bit nibbles.
write 0x2 with RS=0 ;4-bit mode
write 0x0 with RS=0
Wait at least 40us
write 0x2 with RS=0 ;5x7 font, 2 line mode
write 0x8 with RS=0
Wait at least 40us
write 0x0 with RS=0 ;display on, cursor off
write 0xC with RS=0
Wait at least 40us
write 0x0 with RS=0 ;cursor moves right, no shift
write 0x6 with RS=0
Wait at least 40us
At this point the display should be active and you can send ASCII
characters to it (RS=1), or commands that clear the display or move the
cursor around (RS=0). One thing to keep in mind is the display's memory
map. The same controller is used for all displays, regardless of whether
you have a 1x12 character display, or a 4x40 character display. So when
you write characters to the display, it won't know when you've reached
the end of a line and wrap to the next line for you. Instead your
software must keep track of where the cursor is and when you need to
move to a new line. The memory map for 4 lines of display is as
follows:
Line 1 offset = 0
Line 2 offset = 0x40
Line 3 offset = 0x14
Line 4 offset = 0x54
So if you wanted to move the cursor to the beginning of line 2 you would
write the value 0xC0 to the display with RS=0. If you break down this
command, we set bit 7 which means we're doing a DDRAM address set and
0x40 is the value we want to set the address to (or the cursor
location). Here's the command format used to send commands to the
display and read back status.
|
Instruction |
RS |
R/W |
DB7 |
DB6 |
DB5 |
DB4 |
DB3 |
DB2 |
DB1 |
DB0 |
Description |
Executed
Time |
|
Clear Display |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
Clears display and returns cursor to the home position. |
1.64ms |
|
Home Cursor |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
* |
Returns the cursor to home position (address 0) |
1.64ms |
|
Entry Mode Set |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
I/D |
S |
Sets the cursor move direction and display shift option. |
40us |
|
Display On/Off |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
D |
C |
B |
Sets the display on/off (D), Cursor on/off (C), Blink on/off (B) |
40us |
|
Cursor Shift Display Shift |
0 |
0 |
0 |
0 |
0 |
1 |
S/C |
R/L |
* |
* |
Moves the cursor and shifts the display |
40us |
|
function set |
0 |
0 |
0 |
0 |
1 |
DL |
N |
F |
* |
* |
Sets the interface data length (DL), number of display lines (N),
and character font (F) |
40us |
|
cgram address set |
0 |
0 |
0 |
1 |
CGRAM Address |
Sets the CGRAM address |
40us |
|
DDRAM address set |
0 |
0 |
1 |
DDRAM Address |
Sets the DDRAM address (cursor position) |
40us |
|
Busy Flag Address Read |
0 |
1 |
BF |
Address Counter |
Reads the busy flag (BF) and address counter contents |
0us |
|
CGRAM/DDRAM Data Write |
1 |
0 |
write data |
Writes data into DDRAM or CCRAM |
40us |
|
CGRAM/DDRAM Data Read |
1 |
1 |
Read Data |
Reads data from DDRAM or CCRAM |
40us |
The datasheet for the display will cover all the bit-mapped
commands that you can perform, as well as the timing diagrams, font
table, and electrical specs. Here's a typical datasheet for a
DMC16205 display .
Direct Display Control
Now that you've seen how you can use an LCD display with your robot or
other projects, you need to decide how to implement one. If you have
the required I/O pins, you could connect the display directly to your
processor. Keep in mind that writing to the display is slow and
requires some though as to how to support the display without bogging
down other tasks. If you don't plan to write to the display while the
robot is actually running, then you don't have any real issues. If you
do plan to write to the display while running, you might consider using
a background task to handle the display, so you don't bog things down.
Controllers like the BX24 are well suited to the task since it features
a multi-tasking environment. For other platforms you could make use of
the on-board timers and use an interrupt service routine to move data to
the display.
Indirect Display Control
If you're short on I/O pins or don't want to mess with fancy background
routines, then consider using a 2nd processor dedicated to running the
display. This is exactly what those $49 serial display modules do. A
small processor like an AT90S2313 or various PIC controllers are well
suited to receiving data from a master processor via a serial interface
and writing the data to the display using it's own port pins. The
interface between the 2 micros can use 2-wire for bi-directional
communication, or 1-wire if you just want to send data to the display
micro without any type of feedback. Most micro-controllers have an
internal UART which can be used to connect the 2 micros together. Using
the fastest supported speed i.e. 115K insures that the master processor
doesn't get bogged down sending data to the display processor. The
display processor must be able to receive this fast data stream, buffer
it, and send it to the display, without losing any incoming data (buffer
overrun). In a future article I'll discuss my development of a serial
based display module using an Atmel AT90S2313 and a 4x20 HD44780 based
display module.
Go to Part 2