Thursday, 27 December 2007

Controlling LCD With PIC Microcontroller

Getting The PIC to talk to the LCD

As mentioned in my last post, I have succeeded in getting the PIC to talk successfully with the LCD and write sensible characters on to the screen. And as promised here is how to do it, and more importantly how not to do it.

My first attempt

When I first bought the LCD I spent quite a while reading message boards, hobbyist sites and ‘tutorials’ in hope of learning how to interface it. This helped up to a point but I was unable to find a single site that showed how to put everything together, so I went back to the data sheet. Fortunately the data sheet for the display I bought was very comprehensive, if a little daunting. This is why I will now proceed to put together a series of pages explaining in steps how to go about connecting a PC via the serial port to an LCD screen, via a programmable chip.

About LCDs

There are two broad categories of LCD, the first are those without a controller. These are little more than a plate of the LCD material with a mass of connections around the outside. These give pixel perfect control over the displayed image/characters and allow the user to alter individual pixels independently. These as you can imagine, from the number of pixels present, require complex control logic to achieve such custom displays and are therefore much harder to work with. The second group of LCDs are those with a built in controller or MPU. These have an inbuilt processor which handles the difficult process of constructing characters from individual pixels, and allows you to simply present the ASCII code for the desired characters at the pins. This second type of LCD is by far the best choice.

Having chosen an LCD with a controller, you need to ensure that the controller is of the type HD44780 (Hitachi), as this is the most common and straightforward to use.

Connecting the LCD to other stuff

On the front of most LCDs is a strip of solder pads contacts, onto which wire connections must be soldered. It is important to be careful when placing the soldering iron near to the thin polymer coating on the surface of the screen, as it is very easily scratched and warped. Although there are many makes of LCD the interface, providing it is HD44780 will be similar. The pins available are:

  • Vss is the ground terminal for the module

  • Vdd is the positive supply for terminal (2.7V to 5.5V)

  • Vo is the power supply for the liquid crystal drive but should be grounded

  • RS is Register select; it should be logic 0 for sending instructions, but 1 for sending data

  • R/W is Read / Write; it should be logic 1 for reading data, and 0 for writing data

  • E is the Enable pin; when this pin goes from logic 1 to 0 the data is read from the data pins DB0..DB7 these are the 8 pins for data transfer; ACSI codes are presented one byte at a time

4-Bit or 8-Bit

Because of the ‘byte-wide’ data bus on the LCD module, a whole ASCI code can be sent to the device with just one clock cycle of the enable pin. However in the real world we use microcontrollers to control such devices, and these have a finite and often small number of IO pins to play with. Using the 8 Bit interface to control the screen would require 8 pins for the data line alone, and a further 3 pins for the control lines (enable, RS, RW). Taking the ubiquitous PIC16F84, we have 8 IO pins on PORTB and a further 5 on PORTA. This leaves just two spare pins on the microcontroller. It is likely that we will need the display to be dynamic and depend on other stimuli, perhaps a keypad, for which we will need more spare inputs. The solution is to use only half the available data lines in what is known as a 4-Bit interface. DB3..DB0 are grounded and only DB7..DB4 are used to send data. Instead of sending a whole byte at once, we send the upper nibble first and then the lower nibble, this obviously requires twice as many clock cycles to achieve but means only 7 pins are required to control the screen. I will use the 4-Bit interface in this project.

Don’t do this!

I read somewhere that it was possible to test a LCD by hard wiring it on prototype board and then using a push switch on the ENABLE input to latch the data/instruction. I tried to do this using a bank of switches but had no success. Looking back on it, its hardly surprising since the electrical bounce must have been tremendous. However it’s always worth proving the principle before introducing something as complex as a microcontroller into the equation.

Microcontroller – LCD communication

Before you can begin writing characters to an LCD, you must initialise it correctly. On power-up the device ‘self-initialises’ and takes all the default settings, therefore it is necessary to manually initialise it the way you want it. The default configuration is 8-Bit mode and must be changed before sending any other instructions as the device must be told to ignore the pins DB4..DB3. Once this is done there are many options which can be selected, such as whether the on screen cursor should be visible or blink, how the cursor should increment or decrement after each character and also the screen must be cleared and the cursor returned to the home position. There are special binary codes for each of there instructions which are given in the data sheet for the device. The circuit I used for this project was:

The capacitors shown were standard ceramic ones with the same value. The exact value is not important.

To achieve the 5V supply, use a household transformer such as a phone charger with variable voltage output. These are ideal for bench work as they supply sufficient current and a constant voltage. I began by using batteries which required an additional voltage regulator to achieve the 5V however the performance of the regulator was far from satisfactory for this project. Unfortunately the only transformer I could find around the house was a very old one which offered 4.5V or 6V. Being too lazy to go out and buy a 5V one I made do with the 4.5V which for the first part of the project worked just fine.

The assembler code for the PIC didn’t take too long to write and can be split up into just a few sections. Firstly it runs through an ‘INIT’ subroutine which writes to the display, the instructions to: 1) use the 4-bit interface 2) display the cursor and make it blink 3) clear the display 4) increment cursor position automatically 5) return the cursor to the home position. The next stage in the program is to load into the work register the ASCII value of the desired character, then the ‘WRITE’ subroutine is called. This splits the 8 bit binary value into its upper and lower nibbles so that it can be sent to the LCD using the 4-bit interface. Finally a ‘WAIT’ subroutine is called which prevents the microcontroller from attempting to write more data, until the display has had time to read/load the character into its memory.

Get the Assembler Source Code

Memory organisation

It is convenient to think of the LCD as a RAM chip which has a screen showing you the value of each data cell (or its ASCII equivalent). When writing to it you must specify the address (the position of the character on the display) as well as the actual data (the character to display). If, as suggested, you enable the auto-increment option, the RAM address (cursor position) is increased by one after each write instruction. This saves the need for repositioning the cursor with every write instruction. However, there are more data addresses than character spaces on the screen. The address of the top left character is h’00’, and that of the top right character is h’0F’ (for a 16x2 display). Unfortunately the bottom left character (the next logical position for text) is at address h’40’ and the bottom right is h’4F’. This means in the PIC program, it is necessary to realign the cursor to the next line when you reach the end of the first, else the next characters won’t be displayed.

Other Points:

The current consumption of the LCD and PIC was 1.7mA when the display was static and rose to 1.9mA when the display was changing. When using the MOVF operation in assembler it is necessary to specify after the operand that the result is to be stored in the W register, by writing a ‘,0’ after it. Since the function of MOVF is to copy a file to the work register I assumed this extra operand was unnecessary and therefore wasted a lot of time changing/breaking other stuff before realising my mistake.

If your supply the display with a voltage above 5V the display will go completely black, i.e. all the pixels are turned on. Don’t do this, its not good for the device, I did it by mistake.
The display needs at least 40uS in between each instruction in order for it to register properly. After an instruction to clear the whole screen, it requires 1.53ms. I created two subroutines called WAIT (~30ms) and PAUSE (~0.5s).

1 comment:

Gavin, ECS said...

Glad to see you have got it all working Chris, its always good when a project develops into something that actually works
My PVR, however, is somewhat broken atm I think I accidentally short circuited the JCASE connector and now the mobo is FUBARd Ah well, looking forward to seeing this project