PICAXE LCD Interfacing



Connecting a PICAXE processor to an LCD is easy; if you know how.



LCD's are often one of the most useful interfaces which can be added to a microcontroller, either as part of a self-contained project, or as a sub-system of a larger project.

Connecting an LCD to a PICAXE provides a simple and easy mechanism to provide a low-cost serially driven LCD display which can be connected to other PICAXE's, microcontrollers and even PC's and PDA's.

The code detailed here has been specifically written for LCD's which use the Hitachi HD44780 driver chips, which is by far the great majority of LCD's which I have encountered.

All LCD's I have tested, in a variety of display size formats ( from 1 x 8 to 4 x 20 ), from a number of different manufacturers, which all use the HD44780 chip have worked with the code and 100% compatible driver chips should also work, but the code is not guaranteed to work with all HD44780-based devices, or those which do not use the genuine Hitachi chip.

Note that the code will not work with 4 x 40 LCD's because they are internally constructed from two 2 x 20 controllers and require an additional control line.

The program code has been highly optimised, requiring just two dedicated byte variables and uses just 51 bytes of program code space.


Index

Important Notes

Hardware Interface

Software

LCD Control


Important Notes

PICAXE Documentation Errors

It should also be noted that there is an error in the instructions on how an LCD should be connected to the PICAXE in the Electronics Interfacing Circuits datasheet as provided with the Programming Editor software version 4.1.16 and earlier.

On some pages the connection instructions indicate that DB4 of the LCD is connected to Output Pin 7 of the PICAXE, and correspondingly through to DB7 being connected to Output Pin 4.

This is not correct. The connections described result in a 'swapped nibble' which will prevent the LCD from working as expected. The correct connections should be DB4 to Output Pin 4 through to DB7 to Output Pin 7. The wiring connections on this page are, and always have been, correct in this respect.

The instructions provided in the Electronics Interfacing Circuits datasheet also indicate that the unused DB0 through DB4 lines "should be" connected to 0V. This may not be necessary for all models of LCD, and most datasheets for devices using the HD44780 driver indicate that the unused lines can be left unconnected, or 'floating', as they are in the circuits given later.

It is recommended that you consult your LCD datasheet to check the requirements for connecting DB0 through DB3 in 4-bit mode, but conncting them directly to 0V via low value resistors should not do any harm, nor should connecting them directly to 0v providing that the LCD R/W line is always connected to 0v.

Additionally, as recommended by Revolution Education Limited, the connections to the LCD, DB4 to DB7, RS and E, can be made through 660R resistors.

LCD Pin Numbering

Note that the pin numbering shown for the LCD in the diagrams in this document is that which is usually found on HD44780-based LCD modules, but it is not the only scheme used.

Most LCD modules will have a single 14-way connector, and 16-way if backlit, and are normally numbered as shown, with Pin 1 being 0V ( or "Vdd" ). The numbering can however be reversed, and some modules are fitted with 2x7 and 2x8-way connectors, again with varying pin numbering schemes.

Although not common, some LCD modules may have entirely different pinouts to those shown.

You must determine the correct pinout and numbering scheme and the connections required by the LCD from the user manual or other documentation provided with the LCD before connecting the LCD, as incorrect connection may cause permanent damage to the LCD, PICAXE or both.

The connection information is provided as is and I cannot be held repsonsible for the consequences arising from any incorrect connection of an LCD.

Circuit Changes

The information on this page was changed in May 2004 and the wiring configuration and software is different to that used before then. The earlier software will not work with the current wiring specified, and the latest software will not work with the earlier wiring configuration.

The modification necessary to the old wiring configuration to be compatible with the latest software is very simple to implement, involving the swapping of two connection signals.

It came to my attention that the wiring configuration I was using was different to that used in the Electronics Interfacing Circuit datasheet ( AXE001_pic_electronics.pdf ) provided by Revolution Education Limited - the connections for RS and E were swapped - which meant that hardware had to be changed to use my own code in place of Revolution Education Limited's.

In order to allow my code to simply replace theirs, I have rewritten my software to be compatible and have changed my wiring configuration to match this.

If you have previously used the information on this page to create an LCD interface, it is recommended that you rewire your interface, swapping RS with E, and modify your software accordingly.


PICAXE-18, 18A and 18X Hardware Interface

The complete LCD interface for a PICAXE-18, 18A or 18X, which can be controlled by the software examples given later, is shown below ...

+5V --------.--------------------.------.------.
           .|.     PICAXE-18     |      |      |
           | |    .----.----.    |      |      |
       4K7 |_|    | 1    18 |    |      |      |
            |     | 2    17 |    |      |      |                 LCD
      ......|....>| 3    16 |    |      |      |             .---------.
      :     `---->| 4    15 |    |      |      |             |         |
      }-----------| 5    14 |----'      |      |           .-^--.      |
      |           | 6    13 |-----------|------|---------->| 14 | DB7  |
      |           | 7    12 |-----------|------|---------->| 13 | DB6  |
      |    .------| 8    11 |-----------|------|---------->| 12 | DB5  |
      |    |  .---| 9    10 |-----------|------|---------->| 11 | DB4  |
      |    |  |   `---------'           |      |           | 10 | DB3  |
      |    |  `-------------------------|------|------.    |  9 | DB2  |
      |    `----------------------------|------|---.  |    |  8 | DB1  |
      |                                 |      |   |  |    |  7 | DB0  |
      |                                 |      |   |  `--->|  6 | E    |
      |                                .|.     |   |  .--->|  5 | /WR  |
      |                           10K  | |<-.  |   `--|--->|  4 | RS   |
      |                           Pot  |_|  `--|------|--->|  3 | Vo   |
      |                                 |      `------|--->|  2 | Vcc  |
0v ---^---------------------------------^-------------^--->|  1 | Vdd  |
                                                           `-.--'      |
               100nF Power Supply                            |         |
              decoupling not shown                           `---------'

Note that in this, and the following circuits, the Serial In line is permanently connected to 0V. This is to simplify the circuit diagram; you would normally include a Program Download interface for Serial In and Serial Out connections.


PICAXE-28, 28A and 28X Hardware Interface

The complete LCD interface for a PICAXE-28, 28A or 28X, which can be controlled by the software examples given later, is shown below ...

+5V -------------------.-------------------.--------.-----.
                      .|.                  |        |     |                 LCD
                      | |                  |        |     |             .---------.
                  4K7 |_|     PICAXE-28    |        |     |             |         |
                       |     .---------.   |        |     |           .-^--.      |
                       `---->| 1    28 |---|--------|-----|---------->| 14 | DB7  |
                             | 2    27 |---|--------|-----|---------->| 13 | DB6  |
                             | 3    26 |---|--------|-----|---------->| 12 | DB5  |
                             | 4    25 |---|--------|-----|---------->| 11 | DB4  |
                             | 5    24 |---|--------|-----|------.    | 10 | DB3  |
      ......................>| 6    23 |---|--------|-----|---.  |    |  9 | DB2  |
      :                      | 7    22 |   |        |     |   |  |    |  8 | DB1  |
      }----------------------| 8    21 |   |        |     |   |  |    |  7 | DB0  |
      |     .----------------| 9    20 |---'        |     |   |  `--->|  6 | E    |
      |     |   XTAL   .-----| 10   19 |---.        |     |   |  .--->|  5 | /WR  |
      |     |  | .. |  |     | 11   18 |   |       .|.    |   `--|--->|  4 | RS   |
      |     }--| || |--{     | 12   17 |   |  10K  | |<---|------|--->|  3 | Vo   |
      |     |  | `' |  |     | 13   16 |   |  Pot  |_|    `------|--->|  2 | Vcc  |
      |   __|__      __|__   | 14   15 |   |        |            }--->|  1 | Vdd  |
      |   --.--      --.--   `---------'   |        |            |    `-.--'      |
      |     |          |                   |        |            |      |         |
0V ---^-----^----------^-------------------^--------^------------'      `---------'

                           100nF Power Supply
                          decoupling not shown


PICAXE-40X Hardware Interface

The complete LCD interface for a PICAXE-40X, which can be controlled by the software examples given later, is shown below ...

+5V --------.----------.-------------------.--------.-----.
            |         .|.                  |        |     |                 LCD
            |         | |                  |        |     |             .---------.
            |     4K7 |_|     PICAXE-40X   |        |     |             |         |
            |          |     .---------.   |        |     |           .-^--.      |
            |          `---->| 1    40 |---|--------|-----|---------->| 14 | DB7  |
            |                | 2    39 |---|--------|-----|---------->| 13 | DB6  |
            |                | 3    38 |---|--------|-----|---------->| 12 | DB5  |
            |                | 4    37 |---|--------|-----|---------->| 11 | DB4  |
            |                | 5    36 |---|--------|-----|------.    | 10 | DB3  |
      ......|...............>| 6    35 |---|--------|-----|---.  |    |  9 | DB2  |
      :     |                | 7    34 |   |        |     |   |  |    |  8 | DB1  |
      :     |                | 8    33 |   |        |     |   |  |    |  7 | DB0  |
      :     |                | 9    32 |---'        |     |   |  `--->|  6 | E    |
      :     |                | 10   31 |---.        |     |   |  .--->|  5 | /WR  |
      :     `----------------| 11   30 |   |       .|.    |   `--|--->|  4 | RS   |
      }----------------------| 12   29 |   |  10K  | |<---|------|--->|  3 | Vo   |
      |     .----------------| 13   28 |   |  Pot  |_|    `------|--->|  2 | Vcc  |
      |     |          .-----| 14   27 |   |        |            }--->|  1 | Vdd  |
      |     |   XTAL   |     | 15   26 |   |        |            |    `-.--'      |
      |     |  | .. |  |     | 16   25 |   |        |            |      |         |
      |     }--| || |--{     | 17   24 |   |        |            |      `---------'
      |     |  | `' |  |     | 18   23 |   |        |            |
      |   __|__      __|__   | 19   22 |   |        |            |
      |   --.--      --.--   | 20   21 |   |        |            |
      |     |          |     `---------'   |        |            |
      |     |          |                   |        |            |
0V ---^-----^----------^-------------------^--------^------------'

                           100nF Power Supply
                          decoupling not shown


LCD Power Supply

Many LCD's are very sensitive with regards to their power supply which is an important point to take into account when trying to get an LCD interface to wor correctly.

The LCD is likely to be irreparably damaged by voltages which exceed 5V by any considerable amount and especially when operated from a 6V power supply, such as when using a 4 x 1.5V battery supply.

The LCD, although probably avoiding damage, may fail to operate correctly ( and the display may appear blank or very faint ) when the supply is much less than 5V, and problems may be observed when operated from a 4.5V power supply, such as when using a 3 x 1.5V battery supply.

It is recommended that all LCD's are powered through a regulated 5V power supply, preferably the same supply which is used to power the PICAXE, but it may also be powered by a separate supply. When operating with a separate supply, special consideration should be given to the PICAXE power supply voltage as this will affect the voltages delivered on the PICAXE Output Pins; if the voltage is too low, the PICAXE may not be able to control the LCD correctly.

Take care not to inadvertently connect reverse power to the LCD as this will almost certainly destroy the device.


Contrast Control

The contrast of the LCD is controlled by a 10K potentiometer wired across +5V and 0V but in practice you will often find that the best contrast is when the potentiometer is near or at the 0V end.

You may therefore find that the LCD contrast is acceptable when the 'Vo' pin is wired directly to 0V or through a low value resistor; this makes the LCD even simpler to wire-up and uses the minimum amount of board space.

Note that some LCD's may be permanently damaged if 'Vo' is taken up to 5V or close to it, so check the datasheet and start with the contrast pot set to provide 0V. If the contrast is externally adjustable, it would be a wise precuation to put an additional resistor ( probably 2K2 ) between the top of the 10K potentiometer and the +5V supply to limit 'Vo'.


Output Pin Definitions

The following interface definitions are common for all hardware configurations shown in the circuit diagrams above ...

        SYMBOL  RS        = 2         ; 0 = Command   1 = Data
        SYMBOL  E         = 3         ; 0 = Idle      1 = Active
        SYMBOL  DB4       = 4         ; LCD Data Line 4
        SYMBOL  DB5       = 5         ; LCD Data Line 5
        SYMBOL  DB6       = 6         ; LCD Data Line 6
        SYMBOL  DB7       = 7         ; LCD Data Line 7

        SYMBOL  RSCMDmask = %00000000 ; Select Command register
        SYMBOL  RSDATmask = %00000100 ; Select Data register


LCD Variable Definitions

The following variables need to be defined ..

        SYMBOL  get   = b11
        SYMBOL  byte  = b12
        SYMBOL  rsbit = b13

Note that the 'get' variable is only used within the 'InitialiseLcd' routine and therefore 'b11' can be re-used with your own program after the LCD has been initialised.

The 'byte' variable is only used in the 'InitialiseLcd' routine and to specify the data which is to be sent using the 'SendDataByte' and 'SendCommandByte' routines, and therefore 'b12' can be re-used within your own program, although it will have its value changed when any of these routines are called.

The 'rsbit' variable must be preserved intact during the operation of the program and so 'b13' ( and consequently 'w6' ) must not be used by your own code unless placed somewhere else and restored after use.


LCD Control

There are three routines which are used to initialise and control the LCD ...

        GOSUB InitialiseLcd     ; Initialise the LCD

        byte = ...              ; Send byte to LCD Data Register
        GOSUB SendDataByte

        byte = ...              ; Send byte to LCD Command Register
        GOSUB SendCmdByte

The 'InitialiseLcd' routine must be called once, at the start of the program.

The 'SendDataByte' and 'SendCmdByte' routines are used to send data bytes to the LCD data and command registers respectively. This allows data to be displayed on the LCD and the cursor and other attributes of the LCD and its display to be altered. Before calling either of the two routines, the data byte to be sent must be placed in the 'byte' variable. The value put into the 'byte' variable is not changed when the routines are called.

Examples

        GOSUB InitialiseLcd     ; Initialise the LCD

        byte = "A"              ; Display "A" on the LCD
        GOSUB SendDataByte

        byte = $80 | $00        ; Put cursor at start of Line 1
        GOSUB SendCmdByte

        byte = $80 | $40        ; Put cursor at start of Line 2
        GOSUB SendCmdByte

        byte = 2 * 8 | $40      ; Program User Defined Character 2
        GOSUB SendCmdByte
        byte = %00100 : GOSUB SendDataByte    ;   #
        byte = %01110 : GOSUB SendDataByte    ;  ###
        byte = %11111 : GOSUB SendDataByte    ; #####
        byte = %00100 : GOSUB SendDataByte    ;   #
        byte = %00100 : GOSUB SendDataByte    ;   #
        byte = %00100 : GOSUB SendDataByte    ;   #
        byte = %00100 : GOSUB SendDataByte    ;   #
        byte = %00000 : GOSUB SendDataByte    ;

        byte = 2                ; Display User Defined Character 2
        GOSUB SendCmdByte


LCD Initialisation

    InitialiseLcd:

        FOR get = 0 TO 5
          READ get,byte
          GOSUB SendInitCmdByte
        NEXT

        ' Nibble commands - To initialise 4-bit mode

        EEPROM 0,( $33 )    ; %0011---- %0011----   8-bit / 8-bit
        EEPROM 1,( $32 )    ; %0011---- %0010----   8-bit / 4-bit

        ' Byte commands - To configure the LCD

        EEPROM 2,( $28 )    ; %00101000 %001LNF00   Display Format
        EEPROM 3,( $0C )    ; %00001100 %00001DCB   Display On
        EEPROM 4,( $06 )    ; %00000110 %000001IS   Cursor Move

                            ; L : 0 = 4-bit Mode    1 = 8-bit Mode
                            ; N : 0 = 1 Line        1 = 2 Lines
                            ; F : 0 = 5x7 Pixels    1 = N/A
                            ; D : 0 = Display Off   1 = Display On
                            ; C : 0 = Cursor Off    1 = Cursor On
                            ; B : 0 = Cursor Steady 1 = Cursor Flash
                            ; I : 0 = Dec Cursor    1 = Inc Cursor
                            ; S : 0 = Cursor Move   1 = Display Shift

        EEPROM 5,( $01 )    ; Clear Screen

        RETURN


LCD Interfacing Routines

    SendInitCmdByte:

        PAUSE 15                        ; Delay 15mS at 4MHz

    SendCmdByte:

        rsbit = RSCMDmask               ; Send to Command register

    SendDataByte:

        pins = byte & %11110000 | rsbit ; Put MSB out first
        PULSOUT E,1                     ; Give a 10uS pulse on E
        pins = byte * %00010000 | rsbit ; Put LSB out second
        PULSOUT E,1                     ; Give a 10uS pulse on E

        rsbit = RSDATmask               ; Send to Data register next

        RETURN

As can be seen, the three routines are tightly integrated, which is the key to the compactness of the program code.

The 'rsbit' variable is used to keep track of which register will be written to next; the LCD Command or Data Register, and must be preserved between calls to the 'SendDataByte:' routine. The 'SendCmdByte:' routine simply sets the 'rsbit' varaible so the data written goes to the LCD Command Register. The 'SendDataByte:' routine relies upon 'rsbit' being set correctly when it is called, and always sets the 'rsbit' variable so a subsequent call to the routine will send further data bytes to the LCD Data Register.

The 'SendInitCmdByte:' routine is used solely to send nibble and byte commands to the LCD Control Register during initialisation of the LCD. The initialisation routines for an LCD are very clearly defined, and those familiar with them will observe that the initialisation used in this code does not conform entirely to the sequence and timing specified. This has not been shown to be a problem in practice, and all HD44780-based LCD's which I have tested have initialised and worked fine with the code, although it may not work with all HD44780-based devices or non-Hitachi chipsets, even those which claim to be 100% compatible.

In most LCD initialisation code, you will see a variety of delays used which decrease as initialisation progresses. This code uses a fixed delay of 15mS between each byte sent ( and very little delay between the two nibbles of each byte ). Although this adds unneccessary delay to initialisation, it amounts to less than 100mS overall, and is a price worth paying for the huge reduction in program code it achieves.

The 'PAUSE 15' delay is fine at 4MHz, but will usually need to be extended to 'PAUSE 30' when operating at 8MHz and to 'PAUSE 60' at 16MHz. The two 'PULSOUT E,1' statements are suitable for any speed operation.

The routines rely upon their own execution times to ensure that data is not sent before the LCD is ready for the next data sent, which is fine for all but two commands sent to the LCD Command Register - Clear Display ($01) and Return Home ($02 and $03). The speed of PICAXE execution should mean that there is no problem with these commands at even 16MHz operation, but should any problems be encountered using these commands, it may be necessary to add a 2mS delay after they are issued. It is worthwhile trying your code without the delays first, as it is unlikely you will have a program which causes a problem. The Return Home command can usually be replaced by a command which explicitly sets the next character position to be written to - Set DDRAM Address 0 ($80) - which requires no delay after execution. The only time this may not be possible is if you are deliberately shifting or scrolling the display under program control to achieve some desired effect.


Using Output Pins 0 and 1

A problem which may occur with the use of the above routines is when Output Pins 0 or 1 are used within your program. Because of the use of the 'pins =' assignments, these two bits are always set low whenever the 'SendCmdByte:' or 'SendDataByte:' routines are called.

If it is not desirable to have these two bits cleared while interacting with the LCD, the rouines can be modified as follows ...

    SendInitCmdByte:

        PAUSE 15                        ; Delay 15mS at 4MHz

    SendCmdByte:

        PEEK $30,rsbit                  ; Recover Out0 and Out1
        rsbit = rsbit & %11             ; Send to Command register
        GOTO SendCmdOrDataByte

    SendDataByte:

        PEEK $30,rsbit                  ; Recover Out0 and Out1
        rsbit = rsbit & %11 | RSDATmask ; Send to Data register

    SendCmdOrDataBye:

        pins = byte & %11110000 | rsbit ; Put MSB out first
        PULSOUT E,1                     ; Give a 10uS pulse on E
        pins = byte * %00010000 | rsbit ; Put LSB out second
        PULSOUT E,1                     ; Give a 10uS pulse on E

        RETURN

The trick used is to recover the contents of SFR at location $30 which is a copy of the current output pin levels. This allows the levels of Output Pins 0 and 1 to be recovered and then set as they were previously when the 'pins =' assignments are performed.

The routines require slightly more code space than the best optimised versions, but it is no longer necessary to preserve the 'rsbit' variable between calls to the 'SendCmdByte:' and 'SendDataByte:' routines. This variable can be used outside the routines but it will be corrupted whenever the routines are called.


Complete Example Program

The following example code will display "Hello World!" on a two line LCD in the following format ...

        .-------------.
        | Hello       |
        | World!      |
        `-------------'

For the program to work correctly, the LCD must be attached to the PICAXE as shown in the diagrams at the top of the page.

        SYMBOL  RS        = 2         ; 0 = Command   1 = Data
        SYMBOL  E         = 3         ; 0 = Idle      1 = Active
        SYMBOL  DB4       = 4         ; LCD Data Line 4
        SYMBOL  DB5       = 5         ; LCD Data Line 5
        SYMBOL  DB6       = 6         ; LCD Data Line 6
        SYMBOL  DB7       = 7         ; LCD Data Line 7

        SYMBOL  RSCMDmask = %00000000 ; Select Command register
        SYMBOL  RSDATmask = %00000100 ; Select Data register

        SYMBOL  get       = b11
        SYMBOL  byte      = b12
        SYMBOL  rsbit     = b13

    PowerOnReset:

        GOSUB InitialiseLcd

    DisplayTopLine:

        EEPROM 6,("Hello")

        FOR get = 6 TO 10
          READ get,byte
          GOSUB SendDataByte
        NEXT

    MoveCursorToStartOfSecondLine:

        byte = $C0
        GOSUB SendCmdByte

    DisplayBottomLine:

        EEPROM 11,("World!")

        FOR get = 11 TO 16
          READ get,byte
          GOSUB SendDataByte
        NEXT

        END

    InitialiseLcd:

        FOR get = 0 TO 5
          READ get,byte
          GOSUB SendInitCmdByte
        NEXT

        ' Nibble commands - To initialise 4-bit mode

        EEPROM 0,( $33 )    ; %0011---- %0011----   8-bit / 8-bit
        EEPROM 1,( $32 )    ; %0011---- %0010----   8-bit / 4-bit

        ' Byte commands - To configure the LCD

        EEPROM 2,( $28 )    ; %00101000 %001LNF00   Display Format
        EEPROM 3,( $0C )    ; %00001100 %00001DCB   Display On
        EEPROM 4,( $06 )    ; %00000110 %000001IS   Cursor Move

                            ; L : 0 = 4-bit Mode    1 = 8-bit Mode
                            ; N : 0 = 1 Line        1 = 2 Lines
                            ; F : 0 = 5x7 Pixels    1 = N/A
                            ; D : 0 = Display Off   1 = Display On
                            ; C : 0 = Cursor Off    1 = Cursor On
                            ; B : 0 = Cursor Steady 1 = Cursor Flash
                            ; I : 0 = Dec Cursor    1 = Inc Cursor
                            ; S : 0 = Cursor Move   1 = Display Shift

        EEPROM 5,( $01 )    ; Clear Screen

        RETURN

    SendInitCmdByte:

        PAUSE 15                        ; Delay 15mS

    SendCmdByte:

        rsbit = RSCMDmask               ; Send to Command register

    SendDataByte:

        pins = byte & %11110000 | rsbit ; Put MSB out first
        PULSOUT E,1                     ; Give a 10uS pulse on E
        pins = byte * %00010000 | rsbit ; Put LSB out second
        PULSOUT E,1                     ; Give a 10uS pulse on E

        rsbit = RSDATmask               ; Send to Data register next

        RETURN


LCD Control Commands

The commonest commands that will be sent to the LCD are as follows -

Clearing the display ...

        byte = $01 : GOSUB SendCmdByte  ; Clear Display
        PAUSE 2                         ; Delay may not be needed

Specifying where to write to ..

        byte = $80 : GOSUB SendCmdByte  ; Start of Line 1
        byte = $C0 : GOSUB SendCmdByte  ; Start of Line 2
        byte = $A0 : GOSUB SendCmdByte  ; Start of Line 3
        byte = $E0 : GOSUB SendCmdByte  ; Start of Line 4

Programming User-Defined Charaters ...

        byte = $40 : GOSUB SendCmdByte  ; User-Defined Character 0
        byte = $48 : GOSUB SendCmdByte  ; User-Defined Character 1
        byte = $50 : GOSUB SendCmdByte  ; User-Defined Character 2
        byte = $58 : GOSUB SendCmdByte  ; User-Defined Character 3
        byte = $60 : GOSUB SendCmdByte  ; User-Defined Character 4
        byte = $68 : GOSUB SendCmdByte  ; User-Defined Character 5
        byte = $70 : GOSUB SendCmdByte  ; User-Defined Character 6
        byte = $78 : GOSUB SendCmdByte  ; User-Defined Character 7


LCD Character Addressing

A character can be written to any position on the LCD by setting the Character Address before sending the character. When a character is written, the Character Address is automatically incremented.

Character Addresses are sent to the LCD by using the following code ...

        byte = ...                      ; Set Character Address
        GOSUB SendCmdByte

The value assigned to the 'byte' variable will determine the Character Address and will depend upon the character position where you wish to place the character and the size of the display ...

8 x 1 - 8 characters x 1 line

    Line 1 : $80 .. $87

8 x 2 - 8 characters x 2 lines

    Line 1 : $80 .. $87
    Line 2 : $C0 .. $C7

16 x 1 - 16 characters x 1 line

    Line 1 : $80 .. $87 then $C0 .. $C7

    Note that the 16 x 1 display is actually an 8 x 2 internally which is re-arranged to give the correct display. After writing the 7th character, the character address has to be changed to the start of Line 2 to write the 8th character.

16 x 2 - 16 characters x 2 lines

    Line 1 : $80 .. $8F
    Line 2 : $C0 .. $CF

16 x 4 - 16 characters x 4 lines

    Line 1 : $80 .. $8F
    Line 2 : $C0 .. $CF
    Line 3 : $A0 .. $AF
    Line 4 : $E0 .. $EF

20 x 1 - 20 characters x 1 line

    Line 1 : $80 .. $93

20 x 2 - 20 characters x 2 lines

    Line 1 : $80 .. $93
    Line 2 : $C0 .. $D3

20 x 4 - 20 characters x 4 lines

    Line 1 : $80 .. $93
    Line 2 : $C0 .. $D3
    Line 3 : $A0 .. $B3
    Line 4 : $E0 .. $F3


User-Defined Characters

User defined characters are exactly like other characters which can be displayed on the LCD but rather than have their 'image' defined in unchangeable Read Only Memory, the image is defined as a 'pixel bitmap' which is held in writeable memory.

There are eight User-Defined Characters which can be displayed by simply telling the LCD to display the charcters $00 to $07 ...

        GOSUB InitialiseLcd     ; Initialise the LCD
        FOR b0 = $00 to $07     ; Display user defined characters
          byte = b0
          GOSUB SendDataByte
        NEXT

If you run this program, you will most likely find that the display shows little but gibberish; this is because the character bitmaps have not been defined and have no meaningful values whenever the LCD is powered-up.

Every User-Defined Character is made up from a 7x5 bitmap; seven lines of five bits, and these are held in eight consecutive bytes of memory within the LCD chip. Each byte of memory holds one line's worth of pixels; the three most significant bytes are zero, the remaining five bits per byte, left to right, make up that charcter's line display, also left to right, when displayed. The eigth byte of the image map should be set to zero.

The data values to define a User-Defined Character have a bit set to represent where a pixel is on in the image, and a cleared (zero) bit when off. The following shows the data values to create a better looking 'g' that the one which is normally displayed ..

        Line 1     %00000     -----
        Line 2     %00000     -----
        Line 3     %01110     -###-
        Line 4     %10001     #---#
        Line 5     %01111     -####
        Line 6     %00001     ----#
        Line 7     %01110     -###-
        Line 8     %00000     -----

To program the bitmap for a User-Defined Character into the LCD, a command must be sent to the LCD Command Register to indicate which User-Definded Character is to be programmed, followed by the bitmap which is sent to the LCD Data Register.

The command needed to specify the character to program the bitmap for has the following format -

        %01ccc000

Where 'ccc' is the number of the User-Defined Character, 0 to 7. The value for the command can either be determined before writing the code or may be calculated at runtime.

The following code demonstrates how to program the bitmap to be used as User-Defined Character number 3, and displays it on the LCD ...

        GOSUB InitialiseLcd     ; Initialise the LCD

        byte = 3 * 8 | $40      ; Program User Defined Character 3
        GOSUB SendCmdByte
        byte = %11111 : GOSUB SendDataByte    ; #####
        byte = %10001 : GOSUB SendDataByte    ; #   #
        byte = %11111 : GOSUB SendDataByte    ; #####
        byte = %00100 : GOSUB SendDataByte    ;   #
        byte = %10101 : GOSUB SendDataByte    ; # # #
        byte = %01110 : GOSUB SendDataByte    ;  ###
        byte = %00100 : GOSUB SendDataByte    ;   #
        byte = %00000 : GOSUB SendDataByte    ;

        byte = $80              ; Display at start of Line 1
        GOSUB SendCmdByte

        byte = $03              ; Display User Defined Character 3
        GOSUB SendDataByte

An alternative, and less program code hungry solution to programming User-Defined Characters is to store the character definitions in Eeprom as follows ...

        GOSUB InitialiseLcd     ; Initialise the LCD

        EEPROM $40,(3)          ; Program User Defined Character 3

        EEPROM ( %11111 )       ; #####
        EEPROM ( %10001 )       ; #   #
        EEPROM ( %11111 )       ; #####
        EEPROM ( %00100 )       ;   #
        EEPROM ( %10101 )       ; # # #
        EEPROM ( %01110 )       ;  ###
        EEPROM ( %00100 )       ;   #
        EEPROM ( $80 )          ;

        get = $40               ; Point to Eeprom
        GOSUB ProgramCgRam      ; Define User-Define Character

        byte = $80              ; Display at start of Line 1
        GOSUB SendCmdByte

        byte = $03              ; Display User Defined Character 3
        GOSUB SendDataByte

        END

    ProgramCgRam:
        READ get,byte
        byte = byte * 8 | $40
        GOSUB SendCmdByte
    ProgramCgRamLine:
        get = get + 1
        READ get,byte
        GOSUB SendDataByte
        IF byte < $80 THEN ProgramCgRamLine
        RETURN

Note that in both cases it is necessary to re-position the cursor before sending data for display to the screen having completed a User-Defined Character definition. For this reason, it is usually common to have User-Defined Character Definitions at the start of the program, immediately after initialisation, knowing that the cursor will be positioned before any data is written for display.

One of the great uses for User-Defined Characters is in re-defining the displayed images for lower-case 'g', 'p' 'q' and 'y' characters. Because the bottom, eight, line of the character can be displayed, it is possible to create a 'true descender'. In some cases this may clash with the rest of the display's appearance, but the display can still often be improved.

The following profgram will display five 'g' characters, the first, third and fith are the normal 'g', the second is the improved version ( using User-Defined Character 1 ) and the fourth with a true descender ( using User-Defined Character 2 ) ...

        GOSUB InitialiseLcd     ; Initialise the LCD

        EEPROM $40,(1)          ; Program User Defined Character 1

        EEPROM ( %00000 )       ;
        EEPROM ( %00000 )       ;
        EEPROM ( %01111 )       ;  ####
        EEPROM ( %10001 )       ; #   #
        EEPROM ( %01111 )       ;  ####
        EEPROM ( %00001 )       ;     #
        EEPROM ( %01110 )       ;  ###
        EEPROM ( $80 )          ;

        EEPROM $50,(2)          ; Program User Defined Character 2

        EEPROM ( %00000 )       ;
        EEPROM ( %00000 )       ;
        EEPROM ( %01111 )       ;  ####
        EEPROM ( %10001 )       ; #   #
        EEPROM ( %10001 )       ; #   #
        EEPROM ( %01111 )       ;  ####
        EEPROM ( %00001 )       ;     #
        EEPROM ( $8E    )       ;  ###

        get = $40               ; Point to Eeprom
        GOSUB ProgramCgRam      ; Define User-Define Character

        get = $50               ; Point to Eeprom
        GOSUB ProgramCgRam      ; Define User-Define Character

        byte = $80              ; Display at start of Line 1
        GOSUB SendCmdByte

        byte = "g"              ; Display Default 'g'
        GOSUB SendDataByte
        byte = $01              ; Display User Defined Character 1
        GOSUB SendDataByte
        byte = "g"              ; Display Default 'g'
        GOSUB SendDataByte
        byte = $02              ; Display User Defined Character 2
        GOSUB SendDataByte
        byte = "g"              ; Display Default 'g'
        GOSUB SendDataByte


PICAXE is a trademark of Revolution Education Ltd. PICmicro is a registered trademark of Microchip Inc.





Associated Articles

  The PICAXE Processors
  PICAXE News
  PICAXE Questions & Answers
  PICAXE Comparisons
  PICAXE Pinouts
  PICAXE Serial Interfacing
  PICAXE Serial Interfacing
  PICAXE Infra-Red Interfacing
  PICAXE Wireless Interfacing
  PICAXE LCD Interfacing
  A Real-Time Clock for the PICAXE-18X
  PICAXE Optimisations
  The PICAXE Birthday Box Project
  PICAXE Telephone Exchange Simulator
  The Brainf**ked PICAXE
  The PICAXE Extended Programming Interpreter
  Build Your Own Basic Stamp
  Tech Toys



Sites to Visit

  PICAXE Home Page
  Revolution Education Ltd

  Tech-Supplies Ltd



Site Navigation

  Home Page
  What's New
  Search
  Add Bookmark
  Have Your Say
  Guestbook




First published on Wednesday the 3rd of December, 2003 at 18:09:58
Last upload was on Tuesday the 18th of January, 2005 at 01:49:59