PIC Tutorial Four - Joysticks


For this tutorial you require the Main Board, LCD Board and the Joystick Board, as written the tutorials use the LCD Board on PortA and the Joystick Board on PortB - although these could easily be swapped over, as the Joystick Board doesn't use either of the two 'difficult' pins for PortA, pins 4 and 5. Download zipped tutorial files.

Tutorial 4.1 - requires Main Board, LCD Board and Joystick Board.

This program uses the LCD module to give a hexadecimal display of the values of the X and Y resistors in the joystick, and an indication if the buttons are pressed or not. It uses the LCD subroutines from the previous tutorial, and subroutines written to read the joystick.

;Joystick routines with LCD display
;Nigel Goodwin 2002

	LIST	p=16F628		;tell assembler what chip we are using
	include "P16F628.inc"		;include the defaults for the chip
	ERRORLEVEL	0,	-302	;suppress bank selection messages
	__config 0x3D18			;sets the configuration settings (oscillator type etc.)




		cblock	0x20			;start of general purpose registers
			count			;used in looping routines
			count1			;used in delay routine
			counta			;used in delay routine
			countb			;used in delay routine
			tmp1			;temporary storage
			tmp2
			templcd			;temp store for 4 bit mode
			templcd2
			HiX			;result for X pot
			LoX
			HiY			;result for Y pot
			LoY
			Flags	
		endc

LCD_PORT	Equ	PORTA
LCD_TRIS	Equ	TRISA
LCD_RS		Equ	0x04			;LCD handshake lines
LCD_RW		Equ	0x06
LCD_E		Equ	0x07

JOY_PORT	Equ	PORTB
JOY_TRIS	Equ	TRISB
PotX		Equ	0x06			;input assignments for joystick
PotY		Equ	0x03
SW1		Equ	0x07
SW2		Equ	0x02
SW1_Flag	Equ	0x01			;flags used for key presses
SW2_Flag	Equ	0x02

		org	0x0000
		goto	Start

;TABLES - moved to start of program memory to avoid paging problems,
;a table must not cross a 256 byte boundary.
HEX_Table  	ADDWF   PCL       , f
            	RETLW   0x30
            	RETLW   0x31
            	RETLW   0x32
            	RETLW   0x33
            	RETLW   0x34
            	RETLW   0x35
            	RETLW   0x36
            	RETLW   0x37
            	RETLW   0x38
            	RETLW   0x39
            	RETLW   0x41
            	RETLW   0x42
            	RETLW   0x43
            	RETLW   0x44
            	RETLW   0x45
            	RETLW   0x46


Xtext		addwf	PCL, f
		retlw	'J'
		retlw	'o'
		retlw	'y'
		retlw	'-'
		retlw	'X'
		retlw	' '
		retlw	0x00

Ytext		addwf	PCL, f
		retlw	'J'
		retlw	'o'
		retlw	'y'
		retlw	'-'
		retlw	'Y'
		retlw	' '
		retlw	0x00

presstext	addwf	PCL, f
		retlw	'C'
		retlw	'l'
		retlw	'o'
		retlw	's'
		retlw	'e'
		retlw	0x00

nopresstext	addwf	PCL, f
		retlw	'O'
		retlw	'p'
		retlw	'e'
		retlw	'n'
		retlw	' '
		retlw	0x00

;end of tables

Start		movlw	0x07
		movwf	CMCON			;turn comparators off (make it like a 16F84)

Initialise	clrf	count
		clrf	PORTA
		clrf	PORTB
		bcf	Flags,	SW1_Flag	;clear button pressed flags
		bcf	Flags,	SW2_Flag



SetPorts	bsf 	STATUS,		RP0	;select bank 1
		movlw	0x00			;make all LCD pins outputs
		movwf	LCD_TRIS
		movlw	0xff			;make all joystick pins inputs
		movwf	JOY_TRIS
		bcf 	STATUS,		RP0	;select bank 0

		call	JOY_Init		;discharge timing capacitors
		call	Delay100		;wait for LCD to settle
		call	LCD_Init		;setup LCD module

Main
		call	ReadX			;read X joystick
		call	ReadY			;read Y joystick
		call	ReadSW			;read switches

		call	LCD_Line1		;set to first line
		call	XString			;display Joy-X string
		movf	HiX,	w		;display high byte
		call	LCD_HEX	
		movf	LoX,	w		;display low byte
		call	LCD_HEX	
		movlw	' '
		call	LCD_Char
		call	DisplaySW1

		call	LCD_Line2		;set to second line
		call	YString			;display Joy-Y string
		movf	HiY,	w		;display high byte
		call	LCD_HEX	
		movf	LoY,	w		;display low byte
		call	LCD_HEX
		movlw	' '
		call	LCD_Char
		call	DisplaySW2
		goto	Main			;loop for ever


		

;Subroutines and text tables

DisplaySW1	btfsc	Flags,	SW1_Flag
		goto	Press_Str	
		btfss	Flags,	SW1_Flag
		goto	NoPress_Str
		retlw	0x00

DisplaySW2	btfsc	Flags,	SW2_Flag
		goto	Press_Str	
		btfss	Flags,	SW2_Flag
		goto	NoPress_Str
		retlw	0x00

XString		clrf	count			;set counter register to zero
Mess1		movf	count, w		;put counter value in W
		call	Xtext			;get a character from the text table
		xorlw	0x00			;is it a zero?
		btfsc	STATUS, Z
		retlw	0x00			;return when finished
		call	LCD_Char
		incf	count, f
		goto	Mess1

YString		clrf	count			;set counter register to zero
Mess2		movf	count, w		;put counter value in W
		call	Ytext			;get a character from the text table
		xorlw	0x00			;is it a zero?
		btfsc	STATUS, Z
		retlw	0x00			;return when finished
		call	LCD_Char
		incf	count, f
		goto	Mess2

Press_Str	clrf	count			;set counter register to zero
Mess3		movf	count, w		;put counter value in W
		call	presstext		;get a character from the text table
		xorlw	0x00			;is it a zero?
		btfsc	STATUS, Z
		retlw	0x00			;return when finished
		call	LCD_Char
		incf	count, f
		goto	Mess3

NoPress_Str	clrf	count			;set counter register to zero
Mess4		movf	count, w		;put counter value in W
		call	nopresstext		;get a character from the text table
		xorlw	0x00			;is it a zero?
		btfsc	STATUS, Z
		retlw	0x00			;return when finished
		call	LCD_Char
		incf	count, f
		goto	Mess4

;LCD routines

;Initialise LCD
LCD_Init	movlw	0x20			;Set 4 bit mode
		call	LCD_Cmd

		movlw	0x28			;Set display shift
		call	LCD_Cmd

		movlw	0x06			;Set display character mode
		call	LCD_Cmd

		movlw	0x0d			;Set display on/off and cursor command
		call	LCD_Cmd

		call	LCD_Clr			;clear display

		retlw	0x00

; command set routine
LCD_Cmd		movwf	templcd
		swapf	templcd,	w	;send upper nibble
		andlw	0x0f			;clear upper 4 bits of W
		movwf	LCD_PORT
		bcf	LCD_PORT, LCD_RS	;RS line to 1
		call	Pulse_e			;Pulse the E line high

		movf	templcd,	w	;send lower nibble
		andlw	0x0f			;clear upper 4 bits of W
		movwf	LCD_PORT
		bcf	LCD_PORT, LCD_RS	;RS line to 1
		call	Pulse_e			;Pulse the E line high
		call 	Delay5
		retlw	0x00

LCD_CharD	addlw	0x30			;convert numbers to ASCII values
LCD_Char	movwf	templcd			;display character in W register
		swapf	templcd,	w	;send upper nibble
		andlw	0x0f			;clear upper 4 bits of W
		movwf	LCD_PORT
		bsf	LCD_PORT, LCD_RS	;RS line to 1
		call	Pulse_e			;Pulse the E line high

		movf	templcd,	w	;send lower nibble
		andlw	0x0f			;clear upper 4 bits of W
		movwf	LCD_PORT
		bsf	LCD_PORT, LCD_RS	;RS line to 1
		call	Pulse_e			;Pulse the E line high
		call 	Delay5
		retlw	0x00

LCD_Line1	movlw	0x80			;move to 1st row, first column
		call	LCD_Cmd
		retlw	0x00

LCD_Line2	movlw	0xc0			;move to 2nd row, first column
		call	LCD_Cmd
		retlw	0x00

LCD_CurOn	movlw	0x0d			;Set block cursor on
		call	LCD_Cmd
		retlw	0x00

LCD_CurOff	movlw	0x0c			;Set block cursor off
		call	LCD_Cmd
		retlw	0x00

LCD_Clr		movlw	0x01			;Clear display
		call	LCD_Cmd
		retlw	0x00

LCD_HEX		movwf	tmp1			;display W as hexadecimal byte
		swapf	tmp1,	w
		andlw	0x0f
		call	HEX_Table
		call	LCD_Char
		movf	tmp1, w
		andlw	0x0f
		call	HEX_Table
		call	LCD_Char
		retlw	0x00

Pulse_e		bsf	LCD_PORT, LCD_E
		nop
		bcf	LCD_PORT, LCD_E
		retlw	0x00

;end of LCD routines

;joystick routines

JOY_Init				;setup joystick port
	bsf 	STATUS,		RP0	;select bank 1
	bcf	JOY_TRIS,	PotX	;make PotX an output
	bcf	JOY_PORT,	PotX	;discharge capacitor
	bcf	JOY_TRIS,	PotY	;make PotY an output
	bcf	JOY_PORT,	PotY	;discharge capacitor
	bcf 	STATUS,		RP0	;select bank 0
	retlw	0x00

ReadX
	clrf	HiX			;reset counter registers
	clrf	LoX	
	bsf 	STATUS,		RP0	;select bank 1
	bsf	JOY_TRIS,	PotX	;make PotX an input
	bcf 	STATUS,		RP0	;select bank 0	

x1	
	btfsc	JOY_PORT,	PotX	;keep going until input high
	goto	EndX
	incfsz	LoX,f
	goto	x1
	incfsz	HiX,f
	goto	x1

EndX	bsf 	STATUS,		RP0	;select bank 1
	bcf	JOY_TRIS,	PotX	;make PotX an output
	bcf	JOY_PORT,	PotX	;discharge capacitor
	bcf 	STATUS,		RP0	;select bank 0
	retlw	0x00

ReadY
	clrf	HiY			;reset counter registers
	clrf	LoY
	call	Delay5	
	bsf 	STATUS,		RP0	;select bank 1
	bsf	JOY_TRIS,	PotY	;make PotY an input
	bcf 	STATUS,		RP0	;select bank 0	

y1	
	btfsc	JOY_PORT,	PotY	;keep going until input high
	goto	EndY
	incfsz	LoY,f
	goto	y1
	incfsz	HiY,f
	goto	y1

EndY	bsf 	STATUS,		RP0	;select bank 1
	bcf	JOY_TRIS,	PotY	;make PotY an output
	bcf	JOY_PORT,	PotY	;discharge capacitor
	bcf 	STATUS,		RP0	;select bank 0
	retlw	0x00

ReadSW	btfss	JOY_PORT,	SW1
	call	Sw1On
	btfss	JOY_PORT,	SW2
	call	Sw2On
	btfsc	JOY_PORT,	SW1
	call	Sw1Off
	btfsc	JOY_PORT,	SW2
	call	Sw2Off
	retlw	0x00

Sw1On	bsf	Flags,	SW1_Flag
	retlw	0x00

Sw2On	bsf	Flags,	SW2_Flag
	retlw	0x00

Sw1Off	bcf	Flags,	SW1_Flag
	retlw	0x00

Sw2Off	bcf	Flags,	SW2_Flag
	retlw	0x00

;end of joystick routines

;Delay routines

Delay255	movlw	0xff		;delay 255 mS
		goto	d0
Delay100	movlw	d'100'		;delay 100mS
		goto	d0
Delay50		movlw	d'50'		;delay 50mS
		goto	d0
Delay20		movlw	d'20'		;delay 20mS
		goto	d0
Delay5		movlw	0x05		;delay 5.000 ms (4 MHz clock)
d0		movwf	count1
d1		movlw	0xC7			;delay 1mS
		movwf	counta
		movlw	0x01
		movwf	countb
Delay_0
		decfsz	counta, f
		goto	$+2
		decfsz	countb, f
		goto	Delay_0

		decfsz	count1	,f
		goto	d1
		retlw	0x00

;end of Delay routines


		end      
      

Tutorial 4.2 - requires Main Board, LCD Board and Joystick Board.

This second program is very similar to the previous one, except it uses a different method of counting the time taken to charge the capacitor. Whereas the first example used a simple software counter, this one uses a hardware timer for the lower byte, and an interrupt driven routine for the upper byte. This has the major advantage of being more accurate, giving 1uS resolution.

;Joystick routines with LCD display
;Nigel Goodwin 2002

	LIST	p=16F628		;tell assembler what chip we are using
	include "P16F628.inc"		;include the defaults for the chip
	ERRORLEVEL	0,	-302	;suppress bank selection messages
	__config 0x3D18			;sets the configuration settings (oscillator type etc.)




		cblock	0x20			;start of general purpose registers
			count			;used in looping routines
			count1			;used in delay routine
			counta			;used in delay routine
			countb			;used in delay routine
			tmp1			;temporary storage
			tmp2
			templcd			;temp store for 4 bit mode
			templcd2
			HiX			;result for X pot
			LoX
			HiY			;result for Y pot
			LoY
			Timer_H
			Flags	
		endc

LCD_PORT	Equ	PORTA
LCD_TRIS	Equ	TRISA
LCD_RS		Equ	0x04			;LCD handshake lines
LCD_RW		Equ	0x06
LCD_E		Equ	0x07

JOY_PORT	Equ	PORTB
JOY_TRIS	Equ	TRISB
PotX		Equ	0x06			;input assignments for joystick
PotY		Equ	0x03
SW1		Equ	0x07
SW2		Equ	0x02
SW1_Flag	Equ	0x01			;flags used for key presses
SW2_Flag	Equ	0x02

		org	0x0000
		goto	Start

            	ORG     0x0004
            	BCF     INTCON,		T0IF
            	INCF    Timer_H,	f
            	RETFIE



Start		movlw	0x07
		movwf	CMCON			;turn comparators off (make it like a 16F84)

Initialise	clrf	count
		clrf	PORTA
		clrf	PORTB
		bcf	Flags,	SW1_Flag	;clear button pressed flags
		bcf	Flags,	SW2_Flag



SetPorts	bsf 	STATUS,		RP0	;select bank 1
		movlw	0x00			;make all LCD pins outputs
		movwf	LCD_TRIS
		movlw	0xff			;make all joystick pins inputs
		movwf	JOY_TRIS
		MOVLW   0x88			;assign prescaler to watchdog
            	MOVWF   OPTION_REG
		bcf 	STATUS,		RP0	;select bank 0
		CLRF	INTCON
            	BSF     INTCON    , T0IE	;enable timer interrupts

		call	JOY_Init		;discharge timing capacitors
		call	Delay100		;wait for LCD to settle
		call	LCD_Init		;setup LCD module

Main
		call	ReadX			;read X joystick
		call	ReadY			;read Y joystick
		call	ReadSW			;read switches

		call	LCD_Line1		;set to first line
		call	XString			;display Joy-X string
		movf	HiX,	w		;display high byte
		call	LCD_HEX	
		movf	LoX,	w		;display low byte
		call	LCD_HEX	
		movlw	' '
		call	LCD_Char
		call	DisplaySW1

		call	LCD_Line2		;set to second line
		call	YString			;display Joy-Y string
		movf	HiY,	w		;display high byte
		call	LCD_HEX	
		movf	LoY,	w		;display low byte
		call	LCD_HEX
		movlw	' '
		call	LCD_Char
		call	DisplaySW2
		goto	Main			;loop for ever


		

;Subroutines and text tables

DisplaySW1	btfsc	Flags,	SW1_Flag
		goto	Press_Str	
		btfss	Flags,	SW1_Flag
		goto	NoPress_Str
		retlw	0x00

DisplaySW2	btfsc	Flags,	SW2_Flag
		goto	Press_Str	
		btfss	Flags,	SW2_Flag
		goto	NoPress_Str
		retlw	0x00

XString		clrf	count			;set counter register to zero
Mess1		movf	count, w		;put counter value in W
		bsf 	PCLATH, 1
		call	Xtext			;get a character from the text table
		bcf 	PCLATH, 1
		xorlw	0x00			;is it a zero?
		btfsc	STATUS, Z
		retlw	0x00			;return when finished
		call	LCD_Char
		incf	count, f
		goto	Mess1

YString		clrf	count			;set counter register to zero
Mess2		movf	count, w		;put counter value in W
		bsf 	PCLATH, 1
		call	Ytext			;get a character from the text table
		bcf 	PCLATH, 1
		xorlw	0x00			;is it a zero?
		btfsc	STATUS, Z
		retlw	0x00			;return when finished
		call	LCD_Char
		incf	count, f
		goto	Mess2

Press_Str	clrf	count			;set counter register to zero
Mess3		movf	count, w		;put counter value in W
		bsf 	PCLATH, 1
		call	presstext		;get a character from the text table
		bcf 	PCLATH, 1
		xorlw	0x00			;is it a zero?
		btfsc	STATUS, Z
		retlw	0x00			;return when finished
		call	LCD_Char
		incf	count, f
		goto	Mess3

NoPress_Str	clrf	count			;set counter register to zero
Mess4		movf	count, w		;put counter value in W
		bsf 	PCLATH, 1
		call	nopresstext		;get a character from the text table
		bcf 	PCLATH, 1
		xorlw	0x00			;is it a zero?
		btfsc	STATUS, Z
		retlw	0x00			;return when finished
		call	LCD_Char
		incf	count, f
		goto	Mess4

;LCD routines

;Initialise LCD
LCD_Init	movlw	0x20			;Set 4 bit mode
		call	LCD_Cmd

		movlw	0x28			;Set display shift
		call	LCD_Cmd

		movlw	0x06			;Set display character mode
		call	LCD_Cmd

		movlw	0x0d			;Set display on/off and cursor command
		call	LCD_Cmd

		call	LCD_Clr			;clear display

		retlw	0x00

; command set routine
LCD_Cmd		movwf	templcd
		swapf	templcd,	w	;send upper nibble
		andlw	0x0f			;clear upper 4 bits of W
		movwf	LCD_PORT
		bcf	LCD_PORT, LCD_RS	;RS line to 1
		call	Pulse_e			;Pulse the E line high

		movf	templcd,	w	;send lower nibble
		andlw	0x0f			;clear upper 4 bits of W
		movwf	LCD_PORT
		bcf	LCD_PORT, LCD_RS	;RS line to 1
		call	Pulse_e			;Pulse the E line high
		call 	Delay5
		retlw	0x00

LCD_CharD	addlw	0x30			;convert numbers to ASCII values
LCD_Char	movwf	templcd			;display character in W register
		swapf	templcd,	w	;send upper nibble
		andlw	0x0f			;clear upper 4 bits of W
		movwf	LCD_PORT
		bsf	LCD_PORT, LCD_RS	;RS line to 1
		call	Pulse_e			;Pulse the E line high

		movf	templcd,	w	;send lower nibble
		andlw	0x0f			;clear upper 4 bits of W
		movwf	LCD_PORT
		bsf	LCD_PORT, LCD_RS	;RS line to 1
		call	Pulse_e			;Pulse the E line high
		call 	Delay5
		retlw	0x00

LCD_Line1	movlw	0x80			;move to 1st row, first column
		call	LCD_Cmd
		retlw	0x00

LCD_Line2	movlw	0xc0			;move to 2nd row, first column
		call	LCD_Cmd
		retlw	0x00

LCD_CurOn	movlw	0x0d			;Set block cursor on
		call	LCD_Cmd
		retlw	0x00

LCD_CurOff	movlw	0x0c			;Set block cursor off
		call	LCD_Cmd
		retlw	0x00

LCD_Clr		movlw	0x01			;Clear display
		call	LCD_Cmd
		retlw	0x00

LCD_HEX		movwf	tmp1			;display W as hexadecimal byte
		swapf	tmp1,	w
		andlw	0x0f
		bsf 	PCLATH, 1
		call	HEX_Table
		bcf 	PCLATH, 1
		call	LCD_Char
		movf	tmp1, w
		andlw	0x0f
		bsf 	PCLATH, 1
		call	HEX_Table
		bcf 	PCLATH, 1
		call	LCD_Char
		retlw	0x00

Pulse_e		bsf	LCD_PORT, LCD_E
		nop
		bcf	LCD_PORT, LCD_E
		retlw	0x00

;end of LCD routines

;joystick routines

JOY_Init				;setup joystick port
	bsf 	STATUS,		RP0	;select bank 1
	bcf	JOY_TRIS,	PotX	;make PotX an output
	bcf	JOY_PORT,	PotX	;discharge capacitor
	bcf	JOY_TRIS,	PotY	;make PotY an output
	bcf	JOY_PORT,	PotY	;discharge capacitor
	bcf 	STATUS,		RP0	;select bank 0
	retlw	0x00

ReadX	clrf    Timer_H			;clear timer hi byte
	bsf 	STATUS,		RP0	;select bank 1
	bsf	JOY_TRIS,	PotX	;make PotX an input
	bcf 	STATUS,		RP0	;select bank 0
        clrf    TMR0
        bcf     INTCON, 	T0IF	;start timer
        bsf     INTCON, 	GIE	;start interrupts
        btfss   JOY_PORT, 	PotX
        goto    $-1			;loop until input high
        clrw
        iorwf   TMR0,		f	;stop timer (for 3 cycles)
        movf    TMR0,		W
        movwf   LoX			;and read immediately
        movf    Timer_H, 	W
        movwf   HiX
	bcf     INTCON,		GIE	;turn off interrupts
        btfsc   INTCON,		GIE
        goto    $-2
	bsf 	STATUS,		RP0	;select bank 1
	bcf	JOY_TRIS,	PotX	;make PotX an output
	bcf	JOY_PORT,	PotX	;discharge capacitor
	bcf 	STATUS,		RP0	;select bank 0
        retlw	0x00

ReadY	clrf    Timer_H			;clear timer hi byte
	bsf 	STATUS,		RP0	;select bank 1
	bsf	JOY_TRIS,	PotY	;make PotY an input
	bcf 	STATUS,		RP0	;select bank 0
        clrf    TMR0
        bcf     INTCON,		T0IF	;start timer
        bsf     INTCON,		GIE	;start interrupts
        btfss   JOY_PORT,	PotY
        goto    $-1			;loop until input high
        clrw
        iorwf   TMR0,		f	;stop timer (for 3 cycles)
        movf    TMR0,		W
        movwf   LoY			;and read immediately
        movf    Timer_H,	W
        movwf   HiY
	bcf     INTCON,		GIE	;turn off interrupts
        btfsc   INTCON,		GIE
        goto    $-2
	bsf 	STATUS,		RP0	;select bank 1
	bcf	JOY_TRIS,	PotY	;make PotY an output
	bcf	JOY_PORT,	PotY	;discharge capacitor
	bcf 	STATUS,		RP0	;select bank 0
        retlw	0x00

ReadSW	btfss	JOY_PORT,	SW1
	call	Sw1On
	btfss	JOY_PORT,	SW2
	call	Sw2On
	btfsc	JOY_PORT,	SW1
	call	Sw1Off
	btfsc	JOY_PORT,	SW2
	call	Sw2Off
	retlw	0x00

Sw1On	bsf	Flags,	SW1_Flag
	retlw	0x00

Sw2On	bsf	Flags,	SW2_Flag
	retlw	0x00

Sw1Off	bcf	Flags,	SW1_Flag
	retlw	0x00

Sw2Off	bcf	Flags,	SW2_Flag
	retlw	0x00

;end of joystick routines

;Delay routines

Delay255	movlw	0xff		;delay 255 mS
		goto	d0
Delay100	movlw	d'100'		;delay 100mS
		goto	d0
Delay50		movlw	d'50'		;delay 50mS
		goto	d0
Delay20		movlw	d'20'		;delay 20mS
		goto	d0
Delay5		movlw	0x05		;delay 5.000 ms (4 MHz clock)
d0		movwf	count1
d1		movlw	0xC7			;delay 1mS
		movwf	counta
		movlw	0x01
		movwf	countb
Delay_0
		decfsz	counta, f
		goto	$+2
		decfsz	countb, f
		goto	Delay_0

		decfsz	count1	,f
		goto	d1
		retlw	0x00

;end of Delay routines

	ORG	0x0200

;TABLES - moved to avoid paging problems,
;a table must not cross a 256 byte boundary.
HEX_Table  	ADDWF   PCL       , f
            	RETLW   0x30
            	RETLW   0x31
            	RETLW   0x32
            	RETLW   0x33
            	RETLW   0x34
            	RETLW   0x35
            	RETLW   0x36
            	RETLW   0x37
            	RETLW   0x38
            	RETLW   0x39
            	RETLW   0x41
            	RETLW   0x42
            	RETLW   0x43
            	RETLW   0x44
            	RETLW   0x45
            	RETLW   0x46


Xtext		addwf	PCL, f
		retlw	'J'
		retlw	'o'
		retlw	'y'
		retlw	'-'
		retlw	'X'
		retlw	' '
		retlw	0x00

Ytext		addwf	PCL, f
		retlw	'J'
		retlw	'o'
		retlw	'y'
		retlw	'-'
		retlw	'Y'
		retlw	' '
		retlw	0x00

presstext	addwf	PCL, f
		retlw	'C'
		retlw	'l'
		retlw	'o'
		retlw	's'
		retlw	'e'
		retlw	0x00

nopresstext	addwf	PCL, f
		retlw	'O'
		retlw	'p'
		retlw	'e'
		retlw	'n'
		retlw	' '
		retlw	0x00

;end of tables

		end      
      

The first change in this program is the main program start address, previously we started as immediately after the reset vector (0x0000) as possible, but the interrupt vector is located at 0x0004 so we need to skip over this with a 'goto Start' command. The small interrupt routine itself is located an 0x0004 and simply increments the high byte counter every time the hardware low byte counter overflows. The other two lines in the interrupt routine re-enable interrupts (they are cancelled automatically when called) and the return from the routine, this time using 'retfie' (Return From Interrupt) rather than 'retlw'.