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!