Home / PIC Microcontroller Programming Tutorials / PIC Assembly Code Examples
pcbway

PIC Assembly Code Examples

Here are some PIC assembly codes I have compiled over the years. If you'd like some explanation of how these codes work, check out my tutorials page.


Beginner:

Blink One LED

Toggle the state of RA0.

run this code in PICSimulator.com

; Blink LED Example
; Simple LED blinking program for PIC16F84A
; LED connected to RA0, blinks every 500ms

    list p=16f84a
    include <p16f84a.inc>
    
    ; Configuration bits
    __CONFIG _FOSC_HS & _WDTE_OFF & _PWRTE_ON & _CP_OFF
    
    ; Variables
    cblock 0x20
        delay1
        delay2
    endc
    
    org 0x00
    goto start
    
    org 0x04
    ; Interrupt vector (not used in this example)
    retfie
    
start:
    ; Set RA0 as output
    bsf STATUS, RP0      ; Select Bank 1
    bcf TRISA, 0         ; Set RA0 as output
    bcf STATUS, RP0      ; Select Bank 0
    
    ; Main loop
main_loop:
    bsf PORTA, 0         ; Turn LED on
    call delay_500ms     ; Wait 500ms
    bcf PORTA, 0         ; Turn LED off
    call delay_500ms     ; Wait 500ms
    goto main_loop       ; Repeat
    
delay_500ms:
    ; 500ms delay at 4MHz crystal
    movlw 0x82
    movwf delay1
    movlw 0x7A
    movwf delay2
delay_loop:
    decfsz delay1, f
    goto delay_loop
    decfsz delay2, f
    goto delay_loop
    return
    
    end

Blink All LED

All pins of PORTB simultaneously turn on and then turn off on a loop.

run this code in PICSimulator.com

; Blink LED Example
; Simple LED blinking program for PIC16F84A
; LED connected to PORTB pins, blinks every 200ms

    list p=16f84a
    include <p16f84a.inc>
    
    ; Configuration bits
    __CONFIG _FOSC_HS & _WDTE_OFF & _PWRTE_ON & _CP_OFF
    
    ; Variables
    cblock 0x20
        delay1
        delay2
    endc
    
    org 0x00
    goto start
    
    org 0x04
    ; Interrupt vector (not used in this example)
    retfie
    
start:
    ; Set RA0 as output
    bsf STATUS, RP0      ; Select Bank 1
    movlw 0x00
    movwf TRISB          ; Make all PORTB pins output
    bcf STATUS, RP0      ; Select Bank 0
    
    ; Main loop
main_loop:
    movlw 0xFF
    movwf PORTB			 ; Make all PORTB pins high
    call delay_500ms     ; Wait 500ms
    movlw 0x00
    movwf PORTB          ; Make all PORTB pins low
    call delay_500ms     ; Wait 500ms
    goto main_loop       ; Repeat
    
delay_500ms:
    ; 500ms delay at 4MHz crystal
    movlw 0x82
    movwf delay1
    movlw 0x7A
    movwf delay2
delay_loop:
    decfsz delay1, f
    goto delay_loop
    decfsz delay2, f
    goto delay_loop
    return
    
    end

Using a Switch

A switch is connected normally high at RA0. If the switch is pressed, RB0 is pulled low, otherwise, RB0 stays high.
run this code in PICSimulator.com

list p=16f84a
    include <p16f84a.inc>

   ; Configuration bits
    __CONFIG _FOSC_HS & _WDTE_OFF & _PWRTE_ON & _CP_OFF

   ; Variables
    cblock 0x20
        delay1
        delay2
    endc

    org 0x00
    start

start:
    bsf STATUS,RP0 		;bank 1
    movlw 0x01
    movwf TRISA 		;make all PORTA output except RA0
    movlw 0x00
    movwf TRISB 		;make all PORTB output
    bcf STATUS,RP0 		;bank 0

main_loop:
    btfss PORTA,0  		;check RA0 if high, if it is, skip the next line
    goto sub1 			;program goes here if RA0 is low
    bcf PORTB,0 		;program goes here if RA0 is high; make RBO low
    call delay_loop		;delay subroutine
    goto main_loop 

sub1:
    bsf PORTB,0 		;make RB0 high
    call delay_loop
    goto main_loop

delay_loop:
    loop1 decfsz delay1,1 ;decrement COUNT1 variable until zero
    goto delay_loop
    decfsz delay2,1 	;decrement COUNT2, if not zero, go back to loop1
    goto delay_loop
    return
end

Count Button Press (w/ Seven Segment Display):

Display on a common cathode seven segment display the number of button presses on RA0. If the number of presses exceeds nine, the counter goes back to zero.
run this code in PICSimulator.com

list p=16f84a
include <p16f84a.inc>

   ; bit order: 0b0gfedcba
   ; RB0=a, RB1=b, RB2=c, RB3=d, RB4=e, RB5=f, RB6=g

   ; Configuration bits
    __CONFIG _FOSC_HS & _WDTE_OFF & _PWRTE_ON & _CP_OFF

   ; Variables
    cblock 0x20
        delay1
        delay2
    endc

    org 0x00
    goto start

start:
    bsf STATUS, 5 	;goto bank 1
    movlw 0x00 		;clear TRISB - set all PORTB as output
    movwf TRISB
    movlw 0x1F 		;set all PORTA as input
    movwf TRISA
    bcf STATUS, 5 	;goto bank 0
    clrf PORTB ;	initialize PORTB to 0

main_loop:
    btfsc PORTA,0        ; check if RA0 button is pressed
    goto main_loop       ; if not pressed, go back to main_loop

    call delay           ; debounce
    call delay
    call delay

    btfsc PORTA,0        ; check again
    goto main_loop       ; if not pressed, go back to main_loop

    ; Check current display pattern and move to next digit

    movf PORTB, W
    xorlw b'00000000'    ; blank / initial state
    btfsc STATUS, Z
    goto show_0

    movf PORTB, W
    xorlw b'00111111'    ; currently 0
    btfsc STATUS, Z
    goto show_1

    movf PORTB, W
    xorlw b'00000110'    ; currently 1
    btfsc STATUS, Z
    goto show_2

    movf PORTB, W
    xorlw b'01011011'    ; currently 2
    btfsc STATUS, Z
    goto show_3

    movf PORTB, W
    xorlw b'01001111'    ; currently 3
    btfsc STATUS, Z
    goto show_4

    movf PORTB, W
    xorlw b'01100110'    ; currently 4
    btfsc STATUS, Z
    goto show_5

    movf PORTB, W
    xorlw b'01101101'    ; currently 5
    btfsc STATUS, Z
    goto show_6

    movf PORTB, W
    xorlw b'01111101'    ; currently 6
    btfsc STATUS, Z
    goto show_7

    movf PORTB, W
    xorlw b'00000111'    ; currently 7
    btfsc STATUS, Z
    goto show_8

    movf PORTB, W
    xorlw b'01111111'    ; currently 8
    btfsc STATUS, Z
    goto show_9

    movf PORTB, W
    xorlw b'01101111'    ; currently 9
    btfsc STATUS, Z
    goto show_0

    goto show_0          ; fallback if PORTB has unknown value


show_0:
    movlw b'00111111'
    movwf PORTB
    goto wait_release

show_1:
    movlw b'00000110'
    movwf PORTB
    goto wait_release

show_2:
    movlw b'01011011'
    movwf PORTB
    goto wait_release

show_3:
    movlw b'01001111'
    movwf PORTB
    goto wait_release

show_4:
    movlw b'01100110'
    movwf PORTB
    goto wait_release

show_5:
    movlw b'01101101'
    movwf PORTB
    goto wait_release

show_6:
    movlw b'01111101'
    movwf PORTB
    goto wait_release

show_7:
    movlw b'00000111'
    movwf PORTB
    goto wait_release

show_8:
    movlw b'01111111'
    movwf PORTB
    goto wait_release

show_9:
    movlw b'01101111'
    movwf PORTB
    goto wait_release


wait_release:
    btfss PORTA,0        ; wait until button is released
    goto wait_release

    call delay           ; debounce release
    call delay
    goto main_loop

delay:
    loop1 decfsz delay1,1 	;decrement COUNT1 variable until zero
    goto loop1
    decfsz delay2,1 		;decrement COUNT2, if not zero, go back to loop1
    goto loop1
    return
    
end

Intermediate

Timer Interrupt

Strobe lights from RB7 to RB0 and back using timer overflow interrupt.
run this code in PICSimulator.com

list p=16f84a
include <p16f84a.inc>

	; Variables
	cblock 0x20
		COUNT1
		COUNT2
		W_T
		ST_T
	endc

    org 0x00
    goto start
    org 0x04
    goto isr

start:
	bsf STATUS, RP0 	; Switch to Bank 1
	movlw 0x00
	movwf TRISA 		; PORTA all output
	movlw 0x00
	movwf TRISB 		; PORTB all output
	movlw 07h
	movwf OPTION_REG 	; Timer0 internal clock, prescaler assigned to TMR0, 1:256
	bcf STATUS, RP0 	; Switch to Bank 0
	bcf INTCON,T0IF     ; Clear Timer0 overflow flag first
	bsf INTCON,GIE 		; Enable all interrupts
	bsf INTCON,T0IE 	; Enable timer overflow interrupt
	movlw 0x80
	movwf PORTB

goto main

;---------------interrupt handler
isr:
	bcf INTCON,GIE 		;Disable interrupt inside handler
	movwf W_T			; Save W and STATUS reg inside the ISR
    swapf STATUS,W	
    movwf ST_T
    
    btfss INTCON,T0IF
    goto isr_done

    bcf STATUS,C         ; clear Carry first
    btfsc PORTB,0        ; check if RB0 is 1
    bsf STATUS,C         ; if yes, wrap it back to RB7
    
    rrf PORTB,1          ; rotate PORTB right

    bcf INTCON,T0IF      ; clear Timer0 overflow flag
    
isr_done:
    swapf ST_T,W
    movwf STATUS
    swapf W_T, 1
    swapf W_T,W
    bsf INTCON,GIE 		;Re-enable interrupts

    retfie

;---------------main routine
main:
	goto main

;---------------delay subroutine
delay:
	movlw d'255'
	movwf COUNT1
	movlw d'255'
	movwf COUNT2
loop1:
	decfsz COUNT1,1
	goto loop1
	decfsz COUNT2,1
	goto loop1
	return
end

RBO Interrupt:

Turn off blinking when RB0 is pressed.
run this code in PICSimulator.com

list p=16f84a
include <p16f84a.inc>

	cblock 0x20
		COUNT1
		COUNT2
	endc

	org 0x00
		goto start
	org 0x04
		goto isr

start:
	bsf STATUS, RP0 	; bank 1
	movlw 0x00
	movwf TRISA 		; make all PORTA output
	movlw 0x01
	movwf TRISB 		; make all PORTB output except RB0
	bcf STATUS, RP0 	; bank 0
	movlw b'10010000'
	movwf INTCON 		; enable GIE, INTE
	goto main

;-----------interrupt handler
isr:
    bcf INTCON, GIE 	; disable all interrupt inside handler
    bcf PORTA,0 		; make RA0 low
    call delay 			; multiple calls to delay for longer pause
    call delay
    call delay
    bcf INTCON,INTF 	; clear the interrupt flag
    bsf INTCON, GIE 	; enable interrupt
    retfie

;-----------main routine
main:
	call delay
	bsf PORTA,0 ;make RA0 high
	call delay
	bcf PORTA,0 ;make RA0 low
	call delay
	goto main

;-----------delay subroutine
delay:
	loop1 decfsz COUNT1,1
	goto loop1
	decfsz COUNT2,1
	goto loop1
	return
end

RB Change Interrupt:

Similar to the code above except interrupt is triggered when changes to RB4, RB5, RB6 or RB7 is made.
run this code in PICSimulator.com

list p=16f84a
include <p16f84a.inc>

	cblock 0x20
		COUNT1
		COUNT2
	endc

	org 0x00
		goto start
	org 0x04
		goto isr

start:
	bsf STATUS, RP0 		; bank 1
	movlw 0x00
	movwf TRISA 			; make all PORTA output
	movlw 0x01
	movwf TRISB 			; make all PORTB output except RB0
	bcf STATUS, RP0 		; bank 0
	movlw b'10001000'
	movwf INTCON 			; enable GIE, RBIE
	goto main

;-----------interrupt handler
isr: 
	bcf INTCON, GIE 		; disable all interrupt inside handler
	bcf PORTA,0 			; make RA0 low
	call delay 				; multiple calls to delay for longer pause
	call delay
	call delay
	bcf INTCON, RBIF 		; clear the interrupt flag
	bsf INTCON, GIE 		; enable interrupt
	retfie

;-----------main routine
main:
	call delay
	bsf PORTA,0 			; make RA0 high
	call delay
	bcf PORTA,0  			; make RA0 low
	call delay
	goto main

;-----------delay subroutine
delay:
	loop1 decfsz COUNT1,1
	goto loop1
	decfsz COUNT2,1
	goto loop1
	return
end

EEPROM Write Interrupt:

Triggers an interrupt when the data to EEPROM has been written.

list p=16f84a
include <p16f84a.inc>

	org 0x00
		goto start
	org 0x04
		goto isr

start:
	bsf STATUS, RP0 ; Bank 1
	clrf TRISA
	bsf EECON1, WREN ; Enable Write
	; this is a required sequence according to the datasheet
	movlw 55h
	movwf EECON2 ; Write 55h
	movlw AAh ;	
	movwf EECON2 ; Write AAh
	bsf EECON1,WR ; Set WR bit
	; end of required sequence
	bcf STATUS, RP0 ; Bank 0
	bcf PORTA,0 ;clear RA0
	movlw 0FFh ;write 0FFh to EEDATA
	movwf EEDATA
	movlw b'11000000' ;enable EEPROM write interrupt
	movwf INTCON
	goto main

;-----------interrupt handler
isr: 
	bcf INTCON, GIE
	bcf INTCON, EEIE
	bsf PORTA,0
	bsf INTCON, EEIE
	bsf INTCON, GIE
	retfie
end

PWM:

Generate hardware PWM at RB3 using PIC16F628A.
run this code in PICSimulator.com

list p=16F628A
include <p16f628a.inc>

	cblock 0x20
		COUNT1
		COUNT2
	endc

	org 0x00
		goto init

init:

	movlw .50
	movwf COUNT1
	movwf COUNT2
	;-------SET PWM FREQUENCY
	bsf STATUS, RP0 			; Bank 1
	movlw .64 					; Set PR2 to 64 decimal; PWM frequency = 961 Hz at 4 MHz
	movwf PR2
	bcf STATUS, RP0 			; Bank 0
    movlw .32					; Set PWM starting duty cycle to 50%
    movwf CCPR1L
    movlw b'00101100'
    movwf CCP1CON

	bsf STATUS, RP0 			; Bank 1
	bcf TRISB, 3 				; Set RB3 as output for PWM
	bcf STATUS, RP0 			; Bank 0
	movlw b'00000010' 			; Set Timer2 prescale value to 16
    							; so the PWM period = 2064uS => PWM frequency = 484Hz
	movwf T2CON
	clrf TMR2 					; Clear Timer2 module
	bsf T2CON, TMR2ON 			; Enable Timer2 module

main:
	call delay
	goto main

delay:
	loop1 decfsz COUNT1,1
	goto loop1
	decfsz COUNT2,1
	goto loop1
	return
end

Advanced

USART Communication:

Send "!" character to serial port.
run this code in PICSimulator.com

list p = 16F628A
include <p16f628a.inc>

 cblock 0x20
    	char0
    	COUNT1
    	COUNT2
    endc

    org 0x00
    	goto init

init:
	clrf PORTB
	clrf PORTA
	bsf STATUS, RP0 		; Bank 1
	clrf TRISB 				; all PORTB pins are output
	movlw 01h
	movwf TRISA 			; make all PORTA pins output except RA0
	movlw 07h
	movwf CMCON 			; disable comparator modules
    
    ;---CONFIGURE SPBRG FOR DESIRED BAUD RATE
    movlw d'25' 			; baud rate = 9600bps
    movwf SPBRG 			; at 4MHZ
    
    ;---CONFIGURE TXSTA
    movlw b'00100100'
    movwf TXSTA
    ; Configures TXSTA as 8 bit transmission, transmit enabled, async mode, high speed baud rate
    bcf STATUS, RP0 		; Bank 0
    movlw b'10000000'
    movwf RCSTA 			; Enable serial port receive
    movlw 0x21
    movwf char0 			; Put ! (ascii code 21) character to char0 register

main:
    btfsc PORTA, 0 			; Check if button at RA0 is pressed
    goto main 				; If not, wait
    						; Else transmit a byte
    movf char0, W
    movwf TXREG 			; Place the ! character to TXREG
    goto wthere
    call delay
    goto main

wthere:
    btfss TXSTA, TRMT 		; Check if TRMT is empty
    goto wthere 			; If not, check again
    bcf STATUS, RP0 		; Bank 0, if TRMT is empty then the character has been sent
    return

delay:
    loop1 decfsz COUNT1,1
    goto loop1
    decfsz COUNT2,1
    goto loop1
    return
    end

USART - Display a Rabbit:

run this code in PICSimulator.com

list p = 16F628A
include <p16f628a.inc>

    cblock 0x20
        charOpPa
        charClPa
        charBlash
        charSlash
        charUnSc
        charEq
        charSQ
        charDQ
        charPrd
        spc
        lf
        COUNT1
        COUNT2
    endc

    org 0x00
    	goto init

init:
    clrf PORTB
    clrf PORTA
    bsf STATUS, RP0 ;bank 1
    clrf TRISB ;all PORTB pins are output
    movlw 01h
    movwf TRISA ;make all PORTA pins output except RA0
    movlw 07h
    movwf CMCON ;disable comparator modules
    ;---CONFIGURE SPBRG FOR DESIRED BAUD RATE
    movlw D'25' ;baud rate = 9600bps
    movwf SPBRG ;at 4MHZ
    ;---CONFIGURE TXSTA
    movlw B'00100100'
    movwf TXSTA
    ;Configures TXSTA as 8 bit transmission, transmit enabled, async mode, high speed baud rate
    bcf STATUS, RP0 ;bank 0
    movlw B'10000000'
    movwf RCSTA ;enable serial port receive
    movlw .40 ;(
    movwf charOpPa
    movlw .41 ;)
    movwf charClPa
    movlw .92 ;\
    movwf charBlash
    movlw .47 ;/
    movwf charSlash
    movlw .95 ;_
    movwf charUnSc
    movlw .61 ;=
    movwf charEq
    movlw .39 ;'
    movwf charSQ
    movlw .34
    movwf charDQ
    movlw .46 ;.
    movwf charPrd
    movlw .32
    movwf spc
    movlw .13
    movwf lf

main:
    btfsc PORTA, 0 ;check if button at RA0 is pressed
    goto main ;if not, wait
    ;else transmit a byte
    ;------------line1
    movf spc, W
    movwf TXREG ;TO TXREG
    call wthere
    movf spc, W
    movwf TXREG ;TO TXREG
    call wthere
    movf charOpPa, W
    movwf TXREG ;TO TXREG
    call wthere
    movf charBlash, W
    movwf TXREG ;TO TXREG
    call wthere
    movf charUnSc, W
    movwf TXREG ;TO TXREG
    call wthere
    movf charUnSc, W
    movwf TXREG ;TO TXREG
    call wthere
    movf charUnSc, W
    movwf TXREG ;TO TXREG
    call wthere
    movf charSlash, W
    movwf TXREG ;TO TXREG
    call wthere
    movf charClPa, W
    movwf TXREG
    call wthere
    movf lf, W ;line feed
    movwf TXREG ;TO TXREG
    call wthere
    ;-------------line2
    movf spc, W
    movwf TXREG ;TO TXREG
    call wthere
    movf spc, W
    movwf TXREG ;TO TXREG
    call wthere
    movf charOpPa, W
    movwf TXREG ;TO TXREG
    call wthere
    movf charEq, W
    movwf TXREG ;TO TXREG
    call wthere
    movf charSQ, W
    movwf TXREG ;TO TXREG
    call wthere
    movf charPrd, W
    movwf TXREG ;TO TXREG
    call wthere
    movf charSQ, W
    movwf TXREG ;TO TXREG
    call wthere
    movf charEq, W
    movwf TXREG ;TO TXREG
    call wthere
    movf charClPa, W
    movwf TXREG
    call wthere
    movlw .13 ;line feed
    movwf TXREG ;TO TXREG
    call wthere
    ;------------line3
    movf spc, W
    movwf TXREG ;TO TXREG
    call wthere
    movf spc, W
    movwf TXREG ;TO TXREG
    call wthere
    movf charOpPa, W
    movwf TXREG ;TO TXREG
    call wthere
    movf charDQ, W
    movwf TXREG ;TO TXREG
    call wthere
    movf charClPa, W
    movwf TXREG ;TO TXREG
    call wthere
    movf charUnSc, W
    movwf TXREG ;TO TXREG
    call wthere
    movf charOpPa, W
    movwf TXREG ;TO TXREG
    call wthere
    movf charDQ, W
    movwf TXREG ;TO TXREG
    call wthere
    movf charClPa, W
    movwf TXREG ;TO TXREG
    call wthere
    movlw .13 ;line feed
    movwf TXREG ;TO TXREG
    call wthere
    call delay
    goto last

wthere:
    loop22 bsf STATUS,RP0
    btfss TXSTA, TRMT ;check if TRMT is empty
    goto loop22 ;if not, check again
    bcf STATUS, RP0
    return

delay:
    loop1 decfsz COUNT1,1
    goto loop1
    decfsz COUNT2,1
    goto loop1
    return

    last nop ;so that the display will stay
    nop
    sleep
end

Using Parallel LCD:

Displays HELLO on a parallel LCD (16x2). Data pins are connected to PORTB. E=RA2, RW=RA1, RS=RA0
run this code in PICSimulator.com

list p=16f84a
include <p16f84a.inc>

    cblock 0x0c
        TEMP
        TEMP2
        DADDR
        COUNT1
        COUNT2
        CHAR1
        CHAR2
        CHAR3
        CHAR4
        CHAR5
        CHAR_COUNT
    endc

	LCD_DATA equ 0x06		; LCD_DATA wired to PORTB

    org 0x00
    	goto init	

init:
    movlw 0x05
    movwf CHAR_COUNT
    movlw 0x48 ;H
    movwf CHAR1
    movlw 0x45 ;E
    movwf CHAR2
    movlw 0x4C ;L
    movwf CHAR3
    movlw 0x4C ;L
    movwf CHAR4
    movlw 0x4F ;O
    movwf CHAR5
    bsf STATUS, RP0
    clrf TRISB
    clrf TRISA
    bcf STATUS, RP0
    call LCD_prep
    call delay
    movlw 0x80
    call LCD_cmd
    call delay

main:
    call LCD_sendchr
    goto end_here

LCD_sendchr:
    movf CHAR1, W
    call send_it
    movf CHAR2, W
    call send_it
    movf CHAR3, W
    call send_it
    movf CHAR4, W
    call send_it
    movf CHAR5, W
    call send_it
    return

send_it:
    call delay
    call LCD_putch
    call delay
    return

LCD_poll:
    bsf STATUS, RP0
    clrf TRISB
    comf TRISB, F
    bcf STATUS, RP0
    bcf PORTA, 0
    bsf PORTA, 1
    bsf PORTA, 2
    movf LCD_DATA, W
    movwf TEMP2
    nop
    bcf PORTA, 2
    btfsc TEMP2,7
    goto LCD_poll
    bsf STATUS, RP0
    clrf TRISB
    bcf STATUS, RP0
    return

LCD_cmd:
    movwf TEMP
    call LCD_poll
    bcf PORTA, 0
    bcf PORTA, 1
    bsf PORTA, 2
    movf TEMP, W
    movwf LCD_DATA
    nop
    bcf PORTA, 2
    return
    
LCD_prep:
    clrf PORTA
    movlw 0x3C ;Configure to 2 x 40, 8-bit mode
    call LCD_cmd
    movlw 0x0F ;Turn on display and cursor
    call LCD_cmd
    movlw 0x14 ;Shift cursor right
    call LCD_cmd
    movlw 0x01 ;clear cursor and return to home position
    call LCD_cmd
    return
    
get_DDRAM:
    bsf STATUS, RP0
    clrf TRISB
    comf TRISB, F
    bcf STATUS, RP0
    bcf PORTA, 0
    bsf PORTA, 1
    bsf PORTA, 2
    movf LCD_DATA, W
    nop
    bcf PORTA, 2
    movwf DADDR
    return
    
LCD_putch:
    movwf TEMP
    call LCD_poll
    movf TEMP,W
    bsf PORTA, 0
    bcf PORTA, 1
    bsf PORTA, 2
    movwf LCD_DATA
    nop
    bcf PORTA, 2
    return
    
chk_0x53:
    movlw 0x53
    subwf DADDR, F
    btfsc STATUS,Z
    goto chk_0x27
    movlw 0x94 ;Set DDRAM address to 0x14 (start of 3rd line)
    call LCD_cmd
    call LCD_poll
    movf TEMP,W
    bsf PORTA, 0
    bcf PORTA, 1
    bsf PORTA, 2
    movwf LCD_DATA
    nop
    bcf PORTA, 2
    return
    
chk_0x27:
    movlw 0x27
    subwf DADDR, F
    btfsc STATUS,Z
    return
    movlw 0xD4
    call LCD_cmd
    call LCD_poll
    movf TEMP, W
    bsf PORTA, 0
    bcf PORTA, 1
    bsf PORTA, 2
    movwf LCD_DATA
    nop
    bcf PORTA, 2
    return
    
delay:
    loop1 decfsz COUNT1,1
    goto loop1
    decfsz COUNT2,1
    goto loop1
    return

end_here:
	nop
	nop
end

Dual Seven Segment w/ Lookup:

Uses persistence of vision (POV) to digits on a dual seven segment display.
run this code in PICSimulator.com

list p=16f84a
include <p16f84a.inc>

    cblock 0x20
        COUNT1
        COUNT2
    endc

    org 0x00
    	goto start

start:
    bsf STATUS,5
    movlw 0x00
    movwf TRISA
    movlw 0x00
    movwf TRISB
    bcf STATUS,5
    movlw .100
    movwf COUNT1
    movwf COUNT2

main:
    movlw 0x02
    movwf PORTA
    movlw 0x00
    call table
    movwf PORTB
    call delay
    movlw 0x01
    movwf PORTA
    movlw 0x00
    call table
    movwf PORTB
    call delay
    call delay
    call delay
    call delay
    movlw 0x02
    movwf PORTA
    movlw 0x00
    call table
    movwf PORTB
    call delay
    movlw 0x01
    movwf PORTA
    movlw 0x01
    call table
    movwf PORTB
    call delay
    call delay
    call delay
    call delay
    movlw 0x02
    movwf PORTA
    movlw 0x00
    call table
    movwf PORTB
    call delay
    movlw 0x01
    movwf PORTA
    movlw 0x02
    call table
    movwf PORTB
    call delay
    call delay
    call delay
    call delay
    movlw 0x02
    movwf PORTA
    movlw 0x00
    call table
    movwf PORTB
    call delay
    movlw 0x01
    movwf PORTA
    movlw 0x03
    call table
    movwf PORTB
    call delay
    call delay
    call delay
    call delay
    movlw 0x02
    movwf PORTA
    movlw 0x00
    call table
    movwf PORTB
    call delay
    movlw 0x01
    movwf PORTA
    movlw 0x04
    call table
    movwf PORTB
    call delay
    call delay
    call delay
    call delay
    movlw 0x02
    movwf PORTA
    movlw 0x00
    call table
    movwf PORTB
    call delay
    movlw 0x01
    movwf PORTA
    movlw 0x05
    call table
    movwf PORTB
    call delay
    call delay
    call delay
    call delay
    movlw 0x02
    movwf PORTA
    movlw 0x00
    call table
    movwf PORTB
    call delay
    movlw 0x01
    movwf PORTA
    movlw 0x06
    call table
    movwf PORTB
    call delay
    call delay
    call delay
    call delay
    movlw 0x02
    movwf PORTA
    movlw 0x00
    call table
    movwf PORTB
    call delay
    movlw 0x01
    movwf PORTA
    movlw 0x07
    call table
    movwf PORTB
    call delay
    call delay
    call delay
    call delay
    movlw 0x02
    movwf PORTA
    movlw 0x00
    call table
    movwf PORTB
    call delay
    movlw 0x01
    movwf PORTA
    movlw 0x08
    call table
    movwf PORTB
    call delay
    call delay
    call delay
    call delay
    movlw 0x02
    movwf PORTA
    movlw 0x00
    call table
    movwf PORTB
    call delay
    movlw 0x01
    movwf PORTA
    movlw 0x09
    call table
    movwf PORTB
    call delay
    call delay
    call delay
    call delay
    goto main

delay:
    loop1 decfsz COUNT1,1
    goto loop1
    decfsz COUNT2,1
    goto loop1
    return

table:
    addwf PC,F
    retlw b'00111111' ;digit 0
    retlw b'00000110' ;digit 1
    retlw b'01011011' ;digit 2
    retlw b'01001111' ;digit 3
    retlw b'01100110' ;digit 4
    retlw b'01101101' ;digit 5
    retlw b'01111101' ;digit 6
    retlw b'00000111' ;digit 7
    retlw b'01111111' ;digit 8
    retlw b'01101111' ;digit 9
end
Index