Here are some PIC assembly codes I have compiled over the years. If you’d like some explanation over how these codes work, check out my tutorials page.
1. Blink One LED
2. Blink All LEDs
3. Using a Switch
4. Count Button Press (w/ Seven Segment Display)
5. Timer Interrupt
6. RBO Interrupt
7. RB Change Interrupt
8. EEPROM Write Complete Interrupt
9. PWM
10. USART Communication
11. USART – Display a Rabbit
12. Using Parallel LCD
13. Dual Seven Segment w/ Lookup
Beginner:
Blink One LED:
Toggle the state of RB0.
list p=16f84a include COUNT1 EQU 08h COUNT2 EQU 09h org 0x00 goto start start bsf STATUS, RP0 ;bank 1 movlw 0xFE movwf TRISB ;set all PORTB input except for RB0 bcf STATUS, RP0 ;bank 0 main bsf PORTB, 0 ;make RB0 high call delay ;delay subroutine bcf PORTB, 0 ;make RB0 low goto main delay loop1 decfsz COUNT1,1 ;decrement COUNT1 variable until zero goto loop1 decfsz COUNT2,1 ;decrement COUNT2, if not zero, go back to loop1 goto loop1 return end
Blink All LED:
All pins of PORTB simultaneously turns on and then turns off on a loop.
list p=16f84a include COUNT1 EQU 08h COUNT2 EQU 09h org 0x00 start start bsf STATUS, RP0 ;bank 1 movlw 0x00 movwf TRISB ;make all PORTB output bsf STATUS, RP1 ;bank 0 main movlw 0xFF movwf PORTB ;make all PORTB pins high call delay ;delay subroutine movlw 0x00 movwf PORTB ;make all PORTB pins low call delay goto main delay loop1 decfsz COUNT1,1 ;decrement COUNT1 variable until zero goto loop1 decfsz COUNT2,1 ;decrement COUNT2, if not zero, go back to loop1 goto loop1 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.
list p=16f84a include COUNT1 EQU 08h COUNT2 EQU 09h 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 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 ;delay subroutine goto main sub1 bsf PORTB,0 ;make RB0 high call delay goto main delay loop1 decfsz COUNT1,1 ;decrement COUNT1 variable until zero goto loop1 decfsz COUNT2,1 ;decrement COUNT2, if not zero, go back to loop1 goto loop1 return end
Count Button Press (w/ Seven Segment Display):
Display on a common cathode seven segment display (with decoder connected to PORTB) the number of button presses on RA0. If the number of presses exceeds nine, the counter goes back to zero.
list p=16f84a include 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 btfsc PORTA,0 ;check if RA.0 button is pressed call delay ;for debounce call delay call delay btfsc PORTA,0 ;check again goto main ;if not pressed, go back to main incf PORTB,1 ;if pressed increment PORTB movlw 0x09 ;for checking if PORTB = 9: put 0x09 to W subwf PORTB,0 ;subtract 0x09 from W register btfss STATUS, 2 ;check if zero was the result of the last operation goto main ;if not zero (PORTB is not equal to 0x09), go back to main clrf PORTB ;if zero (PORTB is equal to 0x09), set PORTB to zero goto main ;go back and check the button again delay loop1 decfsz COUNT1,1 ;decrement COUNT1 variable until zero goto loop1 decfsz COUNT2,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.
list p=16f84a include cblock 0x0c COUNT1 COUNT2 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 ;Prescaler set to maximum bcf STATUS, RP0 ;switch to Bank 0 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 rrf PORTB ;Complement PORTA call delay ;Delay subroutine bcf INTCON,T0IF ;Clear TMR overflow bit bsf INTCON,GIE ;Re-enable interrupts retfie ;Return from interrupt ;---------------main routine main movf PORTA,1 ;Dummy commands clrf PORTA goto main ;---------------delay subroutine delay loop1 decfsz COUNT1,1 goto loop1 decfsz COUNT2,1 goto loop1 return end
RBO Interrupt:
Turn off blinking when RB0 is pressed.
list p=16f84a include cblock 0x0c 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 goto main ;-----------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.
list p=16f84a include cblock 0x0c 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 goto main ;-----------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 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 goto start end
PWM:
Generate hardware PWM at RB3 using PIC16F628A.
list p=16F628A include 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 D'128' ;Set PR2 to 128 decimal; PWM period = 2064uS => PWM frequency = 484Hz movwf PR2 bcf STATUS, RP1 ;Bank 0 clrf CCPR1L ;Set PWM starting duty cycle comf CCPR1L movlw B'00001100' ;Set PWM mode, bits 5 and 4 are the two LSBs of the 10-bit duty cycle register movwf CCP1CON ;SET PWM PIN TO OUTPUT MODE;;; 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.
list p = 16F628A INCLUDE 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
list p = 16F628A INCLUDE 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 (16×2). Data pins are connected to PORTB. E=RA2, RW=RA1, RS=RA0
list p=16f84a #include cblock 0x0c TEMP TEMP2 DADDR COUNT1 COUNT2 CHAR1 CHAR2 CHAR3 CHAR4 CHAR5 CHAR_COUNT endc LCD_DATA equ PORTB #define LCD_E PORTA,2 #define LCD_RW PORTA,1 #define LCD_RS PORTA,0 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, RP1 call LCD_prep call delay movlw 0x80 call LCD_cmd call delay main goto LCD_sendchr LCD_sendchr movf CHAR1,W call delay call send_it movf CHAR2,W call delay call send_it movf CHAR3,W call delay call send_it movf CHAR4,W call delay call send_it movf CHAR5,W call delay call send_it send_it call LCD_putch call delay decfsz CHAR_COUNT,f return call LCD_prep call delay movlw 0x80 call LCD_cmd call delay goto end_here LCD_poll bsf STATUS, RP0 clrf TRISB comf TRISB bcf STATUS, RP0 bcf LCD_RS bsf LCD_RW bsf LCD_E movf LCD_DATA, TEMP2 nop bcf LCD_E btfsc TEMP2,7 goto LCD_poll bsf STATUS, RP0 clrf TRISB bcf STATUS, RP0 return LCD_cmd movwf TEMP call LCD_poll bcf LCD_RS bcf LCD_RW bsf LCD_E movf TEMP, W movwf LCD_DATA nop bcf LCD_E 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 bcf STATUS, RP0 bcf LCD_RS bsf LCD_RW bsf LCD_E movf LCD_DATA, W nop bcf LCD_E movwf DADDR return LCD_putch movwf TEMP call LCD_poll movf TEMP,W bsf LCD_RS bcf LCD_RW bsf LCD_E movwf LCD_DATA nop bcf LCD_E return chk_0x53 movlw 0x53 subwf DADDR 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 LCD_RS bcf LCD_RW bsf LCD_E movwf LCD_DATA nop bcf LCD_E return chk_0x27 movlw 0x27 subwf DADDR btfsc STATUS,Z return movlw 0xD4 call LCD_cmd call LCD_poll movf TEMP, W bsf LCD_RS bcf LCD_RW bsf LCD_E movwf LCD_DATA nop bcf LCD_E 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.
list p=16f84a include cblock 0x0c 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 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