You are on page 1of 28

Programming the PIC16F877 in

PIC MPASM Assembly Language

11/21/22 ECE331 PIC Assembly (KEH) 1


PIC16xxx Family Instruction Set
• Each instruction is a single 14-bit word
• THREE basic categories:
– Byte Oriented
– Bit Oriented
– Literal (Immediate Constant) and Control
• One instruction cycle consists of FOUR clock
oscillator periods. Hence for a 20 MHz clock, an
instruction takes 4/20MHz = 200 ns to execute.
• Any transfer of control (call, jump, conditional
test, or goto) instruction takes two 200 ns cycles
to allow the instruction queue to be refilled.
11/21/22 ECE331 PIC Assembly (KEH) 2
PIC 16xxx Family
Instruction Format

11/21/22 ECE331 PIC Assembly (KEH) 3


PIC16XXX Byte-Oriented Instructions

11/21/22 ECE331 PIC Assembly (KEH) 4


PIC16xxx Bit-oriented and Literal
and Control Instructions

11/21/22 ECE331 PIC Assembly (KEH) 5


Setting the directional bit “d”
• If you add the include file to your assembly
program:

#include "p16f877A.inc“

Then the directional bit “d” value is pre-defined


as “w equ 0” and “f equ 1”. So we may write

mydat equ 0x20


addwf mydat,f ;mydat  mydat + W
addwf mydat,w ;W  mydat + W

11/21/22 ECE331 PIC Assembly (KEH) 6


Some examples
• MOVLW 0x12 ;Move $12 into accumulator “W”
;”Literal” => Immediate constant
• MOVWF mydat ;Move W into reg file “mydat”
• MOVF mydat,w ;Move reg file “mydat” into W
• MOVF mydat,f ;What good is this instruction?
;(It sets the Z flag, allowing us to
;see if reg file “mydat” contains 0)
• BSF mydat,3 ;Set Bit #3 of mydat |
;(Bit #0 is the LSB on right)

11/21/22 ECE331 PIC Assembly (KEH) 7


Branch to location “TARGET” if
W =< mydat
(in an unsigned sense)
SUBWF mydat,f ;mydat – W
BTFSC 3,0 ;Test Bit #0 of STATUS reg (the C flag) and
;skip next instruction if C is clear
;implying that a borrow was requested,
;thus implying that mydat is less than W in
;an unsigned sense.
;Remember on PIC the borrow flag is the
;inverse of the C flag (unlike the HC12).
GOTO Target
....EXECUTE THESE INSTRUCTIONS IF W>mydat...
Target NOP ;Branch here if W =< mydat
11/21/22 ECE331 PIC Assembly (KEH) 8
Status Register

11/21/22 ECE331 PIC Assembly (KEH) 9


Example #1 LED Flasher using Software Delay Loops
;***** PIC16F877A MPASM Example #1 *****
;NOTE: When setting up the project, be sure to choose the active
;toolsuite to be "Microchip MPASM Toolsuite" instead of the
;"Hi-Tech PICC Toolsuite" as you did with C programs.
;
;This is a simple I/O Example. When input RA0 goes HIGH,
;LED connected to output RA1 will FLASH ON/OFF at 1 s rate
;1 second delay obtained using two nested software timing loops
;**************************
list p=16F877A
#include "p16f877A.inc" ;include register definitions file
;also W is defined to equal 0 and
;F is defined to equal 1, so the
;destination bit(D)can be set using
;the W and F symbols. (W => result in
;working register w, while F => result
;in indicated register file location.

radix dec ;make default numbers decimal values


org 0 ;Reset vector is at prog loc 0x00.
goto start ;Skip over INT vector at prog loc 0x04.

CBLOCK 0x20 ;Use CBLOCK and ENDC to reserve a block of register file locations
;starting at address 0x20 in register file space
count1 ;count1 = 0x20
count2 ;count2 = 0x21
count3 ;count3 = 0x22
count4 ;count4 = 0x23
ENDC

11/21/22 ECE331 PIC Assembly (KEH) 10


org 0x05 ;Start assembling program at location 5 in program space.
start
clrf PORTA ;Initialize port A by zeroing
;output data latches.
banksel ADCON1 ;This directive switches to data bank that
;ADCON1 is found in (Bank 1). It results in
;the assembly of the following instruction:
;"bsf STATUS,5" (Set RP0 = 1)
movlw 0x06
movwf ADCON1 ;Configure PORTA for digital I/O (out of reset, PORTA is analog)
movlw 0x01 ;Set RA0 for input, RA1 for output
movwf TRISA

banksel PORTA ;This directive switches to data bank


;that is found in (Bank 0) in following
;instruction: "bcf STATUS,5" Set RP0 = 0.
waitsw btfsc PORTA,0 ;check RA0
goto waitsw ;wait until switch on RA0 pressed down (RA0 goes low).
movlw 5 ;Flash LED 5 times.
movwf count4
flshagn bsf PORTA,1 ;turn ON LED on RA1 (LED cathode tied to ground)
call wait_swloop
bcf PORTA,1 ;turn OFF LED on RA1
call wait_swloop
decfsz count4,f
goto flshagn
done goto waitsw
;
11/21/22 ECE331 PIC Assembly (KEH) 11
;Subroutine wait_swloop -- delays about 1 second using nested
; software delay loops.
wait_swloop
movlw 80 ;all three loops count to 80
movwf count1 ;thus doubling this number
loopout movwf count2 ;increases delay time by 2^3 = 8!
loopmid movwf count3
loopinr decfsz count3,f
goto loopinr
decfsz count2,f
goto loopmid
decfsz count1,f
goto loopout
return
end

11/21/22 ECE331 PIC Assembly (KEH) 12


Example 2. LED Flasher using Timer 0
;***** PIC16F877 MPASM Example #2 *****
;Simple I/O Example. When input RA0 goes HIGH,
;LED connected to output RA1 will FLASH ON/OFF at 1 s rate
;1 second delay obtained using TMR0 to wait out 100 ten-ms intervals
;**************************
list p=16F877
#include "p16f877.inc" ;include register definitions file
;also W is defined to equal 0 and
;F is defined to equal 1, so the
;destination bit(D)can be set using
;the W and F symbols. (W => result in
;working register w, while F => result
;in indicated register file location.

radix dec ;make default numbers decimal values


org 0 ;Reset vector is at prog loc 0x00.
goto start1 ;Skip over INT vector at prog loc 0x04.

CBLOCK 0x20 ;Reserve reg file locns, starting at adr 0x20 in reg file
space
count3 ;count3 = 0x20
count4 ;count4 = 0x21
ENDC

11/21/22 ECE331 PIC Assembly (KEH) 13


org 0x05 ;Start assembling program at location 5 in program space.
start1
banksel OPTION_REG
movlw b'00000111'
movwf OPTION_REG ;timer tick period = (4/10E6)*256 = 75.85 microseconds
banksel PORTB ;note that 10 ms / 75.85 = 131.8, so 132 timer ticks lasts about 10 ms
clrf PORTB ;Initialize port A by zeroing
;output data latches.
banksel TRISB ;This directive switches to data bank that
;TRISB is found in (Bank 1). It results in
;the assembly of the following instruction:
;"bsf STATUS,5" (Set RP0 = 1)
movlw 0x01 ;Set RA0 for input, RA1 for output
movwf TRISB
banksel PORTB ;This directive switches to data bank
;that PORTB is found in (Bank 0) in following
;instruction: "bcf STATUS,5" Set RP0 = 0.
waitsw btfsc PORTB,0 ;check RA0
goto waitsw ;wait until switch on RA0 pressed down (RA0 goes low).
movlw 5 ;Flash LED 5 times.
movwf count4
flshagn bsf PORTB,1 ;turn ON LED on RA1 (LED cathode tied to ground)
call wait_1s_tmr0
bcf PORTB,1 ;turn OFF LED on RA1
call wait_1s_tmr0
decfsz count4,f
goto flshagn
done goto waitsw
;

11/21/22 ECE331 PIC Assembly (KEH) 14


;Subroutine wait_swloop -- delays about 1 second using nested sw delay loops
;
wait_1s_tmr0
movlw 100
movwf count3 ;repeat 10 ms loop 100 times to wait 1 second
wait_loop
movlw 256 - 132;
movwf TMR0 ;schedule TMR0 to wrap (overflow) in 10 ms.
bcf INTCON,2 ;clear TMR0IF flag (bit #2 of INTCON reg)
wt10ms
btfss INTCON,2 ;Wait till TMR0 overflows.
goto wt10ms
decfsz count3,f
goto wait_loop
return
end

11/21/22 ECE331 PIC Assembly (KEH) 15


Example 3. 220 Hz Square Wave using TMR0 Interrupts

;***** PIC16F877 MPASM Example #3 *****


;Interrupt Example. 220 Hz square wave generated on RB1
;**************************
list p=16F877 ;change to 16F877A if necessary
#include "p16f877.inc"
radix dec ;make default numbers decimal values
org 0 ;Reset vector is at prog loc 0x00.
goto startpgm ;Skip over INT vector at prog loc 0x04.
org 4 ;Interrupt Vector
goto int_service
CBLOCK 0x20 ;Reserve reg file locns, starting at adr 0x20
w_temp ;w_temp = 0x20
status_temp ;status_temp = 0x21
ENDC
org 0x05 ;Start assembling program at location 5 in program space.
startpgm
banksel OPTION_REG
movlw b'00000111‘ ;Prescale TMR0 by 256. Assuming a 13.5 MHz crystal osc freq,
;timer tick = (4/13.5 Mhz)*256 = 75.85 microseconds
movwf OPTION_REG

11/21/22 ECE331 PIC Assembly (KEH) 16


banksel PORTB
clrf PORTB ;Initialize port B by zeroing
;output data latches.
banksel TRISB
movlw 0xFD ;Set RB1 for output
movwf TRISB
banksel TMR0
movlw 256 – 30 ;(1/440.)/75.85 microseconds = 30.0
movwf TMR0 ;Schedule Timer0 to interrupt in 1/440th of a second.
bcf INTCON,2 ;clear TMR0IF flag
movlw b'10100000'
movwf INTCON ;enable TMR0 interrupts
idle_loop
goto idle_loop
;
; ***** END OF MAIN PROGRAM ******

11/21/22 ECE331 PIC Assembly (KEH) 17


; ************* Start of INTERRUPT SERVICE ROUTINE *******
int_service
movwf w_temp ;save w and status regs in temp locns
swapf STATUS,w
movwf status_temp
banksel TMR0
bcf INTCON,2 ;clear TMR0IF flag (shut the baby up)
movlw 256 - 30
movwf TMR0 ;schedule next TMR0 interrupt
movf PORTB,W ;get PORTB into W
xorlw 0x02 ;invert Bit #1 of W
movwf PORTB ;Send inverted result out to RB1
swapf status_temp,w ;restore w and status flags fm temp locns
movwf STATUS
swapf w_temp,f
swapf w_temp,w
retfie
end

11/21/22 ECE331 PIC Assembly (KEH) 18


Ex 4. Light Show: Indirect Addressing
;***** PIC Example #4 *****
;Use of Indirect Addressing
;(via FSR and INDF register) to
;implement a simple
;Light Sequencer. Recall that
;the INDF register (at locn
;0x00, 0x80, 0x100, 0x180)
;actually is no register at all, but
;rather it becomes whatever register
;whose addr is loaded into FSR
;(at locn 0x04, 0x84, 0x104, 0x184). If
;FSR contains 0x20, then writing to INDF
;to the register at 0x20, and reading
;from INDF reads from the register at 0x20.
;
;When SW on RA0 goes HIGH,
;4 LEDs connected to outputs
;RA1, RA2, RA3, and RA4
;are sequenced according to
;entries in a table placed
;in RAM.
;**************************
11/21/22 ECE331 PIC Assembly (KEH) 19
list p=16F877A
#include "p16F877A.inc"
radix decimal

CBLOCK 0x20 ;start allocating RAM at first free locn (0x20)


count1 ;count1 = 0x20
count2 ;count2 = 0x21
count3 ;count3 = 0x22
iter_cnt ;inter_cnt = 0x23
seq_tbl: 10 ;table with 10 light pattern entries
;seq_tbl = 0x24 (starting adr of table)
temp ;temp = 0x2E
ENDC
org 0 ;Reset vector is at prog loc 0x00.
goto beginpgm ;Skip over INT vector at prog loc 0x04.
org 0x05

11/21/22 ECE331 PIC Assembly (KEH) 20


beginpgm
banksel ADCON1
movlw 6
movwf ADCON1
banksel PORTA
clrf PORTA ;initialize port A by zeroing
;output data latches.
banksel TRISA
movlw 0x01 ;Set RA0 for input, rest outputs
movwf TRISA
banksel PORTA ;switch back to bank 0

11/21/22 ECE331 PIC Assembly (KEH) 21


;*** initialize RAM table
movlw B'0001'
movwf seq_tbl+0
movlw B'0010'
movwf seq_tbl+1
movlw B'0100'
movwf seq_tbl+2
movlw B'1000'
movwf seq_tbl+3
movlw B'1100'
movwf seq_tbl+4
movlw B'1110'
movwf seq_tbl+5
movlw B'1111'
movwf seq_tbl+6
movlw B'0000'
movwf seq_tbl+7
movlw B'1001'
movwf seq_tbl+8
movlw B'0110'
movwf seq_tbl+9
11/21/22 ECE331 PIC Assembly (KEH) 22
waitsw btfss PORTA,0 ;check RA0
goto waitsw ;wait until switch on RA0 is UP.
movlw 5
movwf iter_cnt
wrap_to_top
movlw seq_tbl ;initialize fsr reg to point to start of table
movwf FSR
get_next_pattern
movf INDF,w ;get next light pattern from table
movwf temp
rlf temp,f ;rotate temp one bit to left, since LEDs are on RA1 - RA4
movf temp,w
movwf PORTA ;put out new light pattern
call wait_swloop
incf FSR,f
movf FSR,w
sublw seq_tbl+10
btfss STATUS,2 ;Skip next instruction if Z = 1
goto get_next_pattern
decfsz iter_cnt,f
goto wrap_to_top
done goto done
;
11/21/22 ECE331 PIC Assembly (KEH) 23
;Subroutine wait_swloop -- delays about 1 second using nested sw loop
;
wait_swloop
movlw 80
movwf count1
loopout movwf count2
loopmid movwf count3
loopinr decfsz count3,f
goto loopinr
decfsz count2,f
goto loopmid
decfsz count1,f
goto loopout
return
end

11/21/22 ECE331 PIC Assembly (KEH) 24


Ex 5. Light Show with Table in Program Memory

;Use of Lookup Table (in program memory)


;to implement a simple Light Sequencer.
;
;When SW on RA0 goes HIGH, 4 LEDs connected to outputs
;RA1, RA2, RA3, and RA4 are sequenced according to
;entries in a table placed in Program ROM
;**************************
list p=16F877
#include "P16F877.inc"
radix decimal
CBLOCK 0x20 ;first free Reg File locn
;data locations 0x00 - 0x0B.
count1
count2
count3
iter_cnt
tbl_ptr
temp
ENDC

11/21/22 ECE331 PIC Assembly (KEH) 25


org 0 ;Reset vector is at prog loc 0x00.
goto beginpgm ;Skip over INT vector at prog loc 0x04.

org 0x05

beginpgm
banksel ADCON1
movlw 6
movwf ADCON1
banksel PORTA
clrf PORTA ;initialize port A by zeroing
;output data latches.
banksel TRISA
movlw 0x01 ;Set RA0 for input, RA1 for output
movwf TRISA
banksel PORTA

11/21/22 ECE331 PIC Assembly (KEH) 26


waitsw btfss PORTA,0 ;check RA0
goto waitsw ;wait until switch on RA0 is UP.
movlw 5
movwf iter_cnt
wrap_to_top
movlw 0
movwf tbl_ptr
get_next_pattern
call pattern_subroutine
movwf temp
rlf temp,f ;rotate temp one bit to left,
movf temp,w ;since LEDs are on RA1 - RA4

movwf PORTA ;put out new light pattern


call wait_swloop
incf tbl_ptr,f
movf tbl_ptr,w
sublw 10
btfss STATUS,2 ;Skip next instruction if Z = 1
goto get_next_pattern
decfsz iter_cnt,f
goto wrap_to_top
done goto done

11/21/22 ECE331 PIC Assembly (KEH) 27


;Subroutine wait_swloop -- delays about 1 second using nested sw loop
wait_swloop
movlw .80
movwf count1
loopout movwf count2
loopmid movwf count3
loopinr decfsz count3,f
goto loopinr
decfsz count2,f
goto loopmid
decfsz count1,f
goto loopout
return
;Pattern lookup table - part of program space the "Define Table" (DT) directive assembles
;a series of "retlw" instructions. The table below consists of retlw 1, retlw 2, retlw 4, retlw 8,
; etc. Upon return from this routine, w contains the looked up "light pattern" value.
pattern_subroutine
movf tbl_ptr,w
addwf pcl,f ;compute index into table and jump there and execute
;the appropriate retlw instruction!
seq_tbl dt B'0001',B'0010',B'0100',B'1000',B'1100',B'1110',B'1111',B'0000'
dt B'1001',B'0110'
end

11/21/22 ECE331 PIC Assembly (KEH) 28

You might also like