So far, we have made the PIC
flash an LED on and off. Then we were able to interact with our PIC by
adding a switch, and so altering the flash rate. The only problem is, the
program is very long and very wasteful of memory. It was fine when I was
introducing the commands for for the first time, but there must be a
better way of doing it. Well there is (you knew that was coming,
right?).
Let us examine how we were
actually turning the LED on and off.
movlw 02h
movwf PORTA
movlw 00h
movlw PORTA
First we loaded our w register
with 02h, then moved it to our PortA register to turn the LED on. To turn
it off, we loaded w with 00h and then moved it to our PortA register. In
between these routines we had to call a subroutine so that we could see
the LED flashing. So, we had to move two sets of data twice (once into
the w register then to PORTA) and call a subroutine twice (once for on and
once for off).
So, how can we do this more
efficiently? Simple. We use another instruction called XORF.
The XORF instruction performs
an Exclusive OR function on the register that we specify with the data we
give it. I think I need to explain what on earth an Exclusive OR is
before we go on.
If we have two inputs, and one
output, the output will only be a 1 if, and only if, the two inputs are
different. If they are the same, then the output will be 0. Here is a
truth table, for those who prefer to look at these:
A
B F
0
0 0
0 1 1
1 0 1
1 1 0
Let us now look to what
happens if we make B the same as our previous output, and just changing
the value of A:
A B F
0 0 0
0 0 0
1 0 1
1 1 0
1 0 1
If we keep the value of A
equal to 1, and we Exclusive OR it with the output, the output will
toggle. For those who can’t see this from the truth table, here it is
using binary:
0 Current Output
EX-OR With 1 1 New Output
EX-OR With 1 0 New Output
Hopefully you can see that by
exlusive ORing the output with 1, we are now toglling the output from 0 to
1 to 0.
So, to turn our LED on and off,
we just need two lines:
MOVLW 02h
XORWF PORTA,1
What we are doing is loading
our w register with 02h. We are then Exclusive ORing this number with
whatever is on our PortA. If bit 1 is a 1, it will change to a 0. If bit
1 is a 0, it will change to a 1.
Let’s run through this code a
couple of times, to show how it is working in binary:
PORTA
00010
xorwf 00000
xorwf 00010
xorwf 00000
xorwf 00010
We don’t even need to load the
same value into our w register each time, so we can do this once at the
beginning, and just jump back to our toggle command. Also, we don’t need
to set up a value on our PortA register. Why? Well, because if on power up
it is a 1, we will toggle it. I, on the other hand it is a 0 on power up,
we will still toggle it.
So, let us now see our new code.
The first one is our original flashing LED, and the second is where we added
a switch:
Flashing LED
;*****Set up the Constants****
STATUS equ
03h ;Address of the STATUS register
TRISA equ
85h ;Address of the tristate register for
port A
PORTA equ
05h ;Address of
Port A
COUNT1 equ
08h ;First counter for our delay loops
COUNT2 equ
09h ;Second counter for our delay loops
;****Set up the port****
bsf STATUS,5 ;Switch to Bank
1
movlw 00h
;Set the Port A pins
movwf TRISA
;to output.
bcf STATUS,5 ;Switch
back to Bank 0
movlw 02h
;Set up our w register with 02h
;****Turn the LED on
and off****
Start xorwf
PORTA,1 ;Toggle the LED
;****Add a delay
call Delay
;****Now go back to the start
of the program
goto
Start ;go back to Start and turn LED on
again
;****Here is our Subroutine
Delay
Loop1 decfsz
COUNT1,1 ;This second loop keeps the LED
goto
Loop1 ;turned off long enough for us to
decfsz
COUNT2,1 ;see it turned off
goto
Loop1 ;
return
;****End of the program****
end
;Needed by some compilers, and also
;just in case we miss the goto instruction.
Flashing LED With
Switch:
;*****Set up the Constants****
STATUS equ
03h ;Address of the STATUS register
TRISA equ
85h ;Address of the tristate register for
port A
PORTA equ
05h ;Address of Port A
COUNT1 equ
08h ;First counter for our delay loops
COUNT2 equ
09h ;Second counter for our delay loops
;****Set up the port****
bsf STATUS,5 ;Switch to Bank
1
movlw 01h
;Set the Port A pins:
movwf TRISA ;bit
1to output, bit 0 to input.
bcf STATUS,5 ;Switch back to Bank 0
movlw 02h ; Set up our w
register with 02h
;****Turn the LED on
and off****
Start xorwf
PORTA,1 ;Toggle the LED
;****Check if the switch is
closed
BTFSC
PORTA,0 ; Get the value from PORT A
;BIT 0. If it is a zero,
call
Delay ;carry on as normal.
;If is a 1, then add an
;extra delay routine
;****Add a delay
call Delay
;****Check if the switch is
still closed
BTFSC
PORTA,0 ;Get the value from PORT A
;BIT 0. If it is a zero,
call
Delay ;carry on as normal.
;If is a 1, then add an
;extra delay routine
;****Add another delay****
call Delay
;****Now go back to the start
of the program
goto
Start ;go back to Start and turn LED on
again
;****Here is our Subroutine
Delay
Loop1 decfsz
COUNT1,1 ;This second loop keeps the LED
goto
Loop1 ;turned off long enough for us to
decfsz
COUNT2,1 ;see it turned off
goto
Loop1 ;
return
;****End of the program****
end
;Needed by some compilers, and also
;just in case we miss the goto instruction.
I hope you can see that by just
using one simple instruction, we have reduced the size of our program. In
fact, just to show how much we have reduced our programs by, I have shown
the two programs, what changes were made, and their sizes in the table
below:
Program
Change Size (Bytes)
Flashing LED
Original 120
Flashing LED Subroutine Added 103
Flashing LED XOR Function Used 91
LED With Switch Original
132
LED With Switch XOR Function Used 124.
So, not only have we learnt
some new instructions, we have also reduced the size of our coding!