LCD_STROBE: ; LCD_STROBE: Assert the LCD's enable signal for at least 1us bsf PORTA, E ; Set enable signal nop ; Wait for 1us (200ns * 5) nop nop nop nop bcf PORTA, E ; Clear the enable signal return LCD_DELAY: ; LCD_DELAY: Pause for ~1ms to allow command execution to complete movlw 0xE7 ; Load counters for delay movwf DelayL movlw 0x04 movwf DelayH LCD_DELAY_LOOP: decfsz DelayL, F ; Decrement low byte of delay counter... goto $+2 ; ...if not zero, then skip decrement of high byte decfsz DelayH, F ; Decrement high byte of counter on underflow of low byte goto LCD_DELAY_LOOP ; Loop back until high byte reaches zero return LCD_INIT: ; LCD_INIT: Initialize LCD movlw 0x4F ; Load 50ms delay movwf DelayL movlw 0xC4 movwf DelayH INIT_DELAY: ; Run in circles fo 50ms, this gives the LCD time to power up decfsz DelayL, F goto $+2 goto DelayH, F goto INIT_DELAY ; Loop back until delay counters reach zero movlw 0x0F ; Clear the upper nibble of PORTB andwf PORTB movlw 0x02 ; And load it with 02h, the first nibble of the "wakeup" sequence addwf PORTB call LCD_STROBE ; Send nibble to display, without using LCD_CMD movlw 0x22 ; Send the second two nibbles of the "wakeup" sequence call LCD_CMD movlw 0x28 ; Send the function set: 4 bits, 2 lines, 5x7 font call LCD_CMD movlw 0x0C ; Setup display: Display on, no cursors call LCD_CMD movlw 0x06 ; Set entry mode: Auto increment, no display shifting call LCD_CMD movlw 0x01 ; Clear display call LCD_CMD LCD_CMD: ; LCD_CMD: Send WREG to LCD as a command movwf TempF ; Save byte to be sent into temporary register bcf PORTA, RS ; Set Register Select to address the instruction register movlw 0x0F ; Clear the upper nibble of PORTB (data bus) andwf PORTB, F movf TempF, W ; Move the upper nibble of the byte to be sent to PORTB... andlw 0xF0 addwf PORTB, F ; ...without changing the lower nibble of PORTB call LCD_STROBE ; Pulse the Enable signal to write this nibble movlw 0x0F ; Clear data lines again andwf PORTB, F swapf TempF, W ; Move the lower nibble of the byte to be sent to PORTB... andlw 0xF0 addwf PORTB, F ; ...without changing the rest of PORTB call LCD_STROBE ; Send second nibble to display call LCD_DELAY ; Wait for the data to be processed by the display return LCD_OUT: ; LCD_OUT: Send WREG to LCD as data movwf TempF ; Save byte to be sent into temporary register bsf PORTA, RS ; Set Register Select to address the data register movlw 0x0F ; Clear the upper nibble of PORTB (data bus) andwf PORTB, F movf TempF, W ; Move the upper nibble of the byte to be sent to PORTB... andlw 0xF0 addwf PORTB, F ; ...without changing the lower nibble of PORTB call LCD_STROBE ; Pulse the Enable signal to write this nibble movlw 0x0F ; Clear data lines again andwf PORTB, F swapf TempF, W ; Move the lower nibble of the byte to be sent to PORTB... andlw 0xF0 addwf PORTB, F ; ...without changing the rest of PORTB call LCD_STROBE ; Send second nibble to display call LCD_DELAY ; Wait for the data to be processed by the display return