Skip to content

PICAXE Clock Exercise: LCD driver

The LCD driver is standard stuff for a 4 bit parallel data feed to an LCD display. A complication is the mapping between the PICAXE 401 and Arduino shield compatibility. That requires the data pins to be addresses independently. There is also a hassle in the PICAXE nomenclature and how it differs for various operations depending upon what you are doing to the output port. That is one reason for the program setup to define variables.

Since I was using a very old LCD display, I also put the command enable pulse time and the delay time for the LCD to react to commands as symbolic constants. That makes it easier to experiment with the LCD response. I haven’t yet seen anyone do status reads on the LCD for command acceptance. It is much easier to just add a bit of delay.

Symbol LCD_datab0 = outpinB.1    ; S.4  - 4 bits parallel data bus
Symbol LCD_datab1 = outpinB.5    ; S.5
Symbol LCD_datab2 = outpinB.6    ; S.6
Symbol LCD_datab3 = outpinB.7    ; S.7
Symbol LCD_RS_Pin = S.8          ; C.0 Register Select: 0=Instruction; 1=data
Symbol LCD_Enable_Pin = S.9      ; C.1 LCD Enable pin
Symbol LCD_cmd_time = 4          ; pulseout time
Symbol LCD_cmd_pause = 2         ; delay between commands

Initializing the LCD is a clearly defined process in the chipset datasheet. Part of the problem is putting the chipset into four bit data mode. Here is the step through the sequence with necessary delays. It is a part of the program initialization section.

    Low LCD_Enable_Pin  ; assure low to pulse high
    pause 30            ; assure at least 15 ms to power up LCD
    LCD_datab0 = 1      ; first nibble to send = %0011
    LCD_datab1 = 1      ; RS=0 and RW=0
    LCD_datab2 = 0
    LCD_datab3 = 0
    PulsOut LCD_Enable_Pin, LCD_cmd_time
    Pause 60            ; 50 wait > 4.1mS (all clock speeds)
    PulsOut LCD_Enable_Pin, LCD_cmd_time    ; same nibble second time
    Pause 6             ; 4 wait > 100uS (all clock speeds)
    b0 = %00110010      ; send nibbles 3&4
    Gosub LCD_Send_Instruction  ; and set to 4 bit data
                                ; bit 5 => function set command
    b0 = %00101000      ; 5&6  to set rows (2) and font (5x7)
    Gosub LCD_Send_Instruction
    b0 = %00001000      ; 7&8 display OFF
    Gosub LCD_Send_Instruction
    b0 = %00000001      ; clear display
    Gosub LCD_Send_Instruction
    b0 = %00000110      ; increment, no shift
    Gosub LCD_Send_Instruction  ; this is Entry Mode Set
    Gosub LCD_Reset     ; clear, pause, and set cursor type

The clock doesn’t need much fancy footwork from the LCD. A reset clears the display and sets the cursor type and position. Set position is needed to update only those clock values that have changed. The LCD instruction entry point is only used by the LCD routines. The final entry point, LCDsend_data takes the value in register B0 and puts it on the display at the current cursor position. The B0 register is used because it is easy to address its individual bits and this makes setting the output pins easier.

; **** set LCD display memory position for Write (or read) ****
; position specified in scratch pad LCD_DDRAM_pos
; 80 bytes of Display Data RAM
; x00-x27 (0-39) for line 1; x40-x67 (64-103) line 2
; only 1st 16 or 20 on display for each line (re Entry Mode Set command)
; command bit 7 set followed by address

LCD_set_position:
; check for valid position usually only needed for debug
;	If b0 > 20 AND b0 < $40 Then
		; SerTxd ("invalid LCD pos ",#b0,cr,lf)
;		Return		; ignore invalid address
;	EndIf
;	If b0 > 84 Then	; past displayable end of 2nd line
		; SerTxd ("invalid LCD pos ",#b0,cr,lf)
;		Return
;	EndIf
	bit7 = 1		; drop through to send command

LCD_Send_Instruction:
    Low LCD_RS_Pin      ; set register select as command
    pause LCD_cmd_pause
    Goto LCD_Send_Nibbles

LCD_Send_Data:
    High LCD_RS_Pin     ; Register select as data

LCD_Send_Nibbles:
    Low LCD_Enable_Pin      ; make sure it is low
    LCD_datab0 = bit4       ; High nibble is sent first
    LCD_datab1 = bit5       ; shield LCD nibble is bits B.1,5,6,7
    LCD_datab2 = bit6
    LCD_datab3 = bit7
    PulsOut LCD_Enable_Pin, LCD_cmd_time
    Pause LCD_cmd_pause
    LCD_datab0 = bit0       ; Followed by the low nibble
    LCD_datab1 = bit1
    LCD_datab2 = bit2
    LCD_datab3 = bit3
    PulsOut LCD_Enable_Pin, LCD_cmd_time
    Pause LCD_cmd_pause
Return

If you ditched the shield compatability idea, you could use LCD data pins more suitable for port logic operations and simplify the code a bit. The code provided here seems to work as it should for the clock.

Post a Comment

You must be logged in to post a comment.