Chaitu Tech Bits

What is PIC micro controller ? How to write program for PIC micro controller ( complete PIC tutriol)

Friday, December 31, 2010

Welcome to the start of the PIC Tutorial.  These pages will take you form the basic structure of the device, right through to programming methods and techniques.  Also, there will be suggestions on how to modify the code so that you can adapt the PIC to suit your applications within Cybot.  I will not be including any internal architecture diagrams, as this may only lead to confusion.  If you want to look at the datasheet, then this can be downloaded from Microchips' web site.
To start, let us take a look at the PIC.
Microchip PIC 16F84 Microcontroller
Microchip manufacture a series of microcontrollers called PIC.  You can see the range of their microcontrollers here.  There are many different flavours available, some basic low memory types, going right up through to ones that have Analogue - To- Digital converters and even PWM built in.  I am going to concentrate on the 16F84 PIC.  Once you have learnt how to program one type of PIC, learning the rest is easy.
There are several ways of programming the PIC - using BASIC, C, or Assembly Language.  I am going to show you the Assembly Language.  Don't be put off by this.  There are only 35 instructions to learn, and it is the cheapest way to program the PICs, as you do not need any extra software other than the freebies.

The 16F84 Pins
Below is a diagram showing the pin-outs of the PIC 16F84.  I will go through each pin, explaining what each is used for.
RA0 To RA4
RA is a bidirectional port.  That is, it can be configured as an input or an output.  The number following RA is the bit number (0 to 4).  So, we have one 5-bit directional port where each bit can be configured as Input or Output.
RB0 To RB7
RB is a second bidirectional port.  It behaves in exactly the same way as RA, except there are 8 - bits involved.
VSS And VDD
These are the power supply pins.  VDD is the positive supply, and VSS is the negative supply, or 0V.  The maximum supply voltage that you can use is 6V, and the minimum is 2V
OSC1/CLK IN And OSC2/CLKOUT
These pins is where we connect an external clock, so that the microcontroller has some kind of timing.

MCLR
This pin is used to erase the memory locations inside the PIC (i.e. when we want to re-program it).  In normal use it is connected to the positive supply rail.

INT
This is an input pin which can be monitored.  If the pin goes high, we can cause the program to restart, stop or any other single function we desire.  We won't be using this one much.

T0CK1
This is another clock input, which operates an internal timer.  It operates in isolation to the main clock.  Again, we won't be using this one much either.

How To Program The PIC
OK, so you haven't been put off so far.  Now, you want to know how to program the PIC, but apart from learning the assembly code instructions, how do you go about actually programming the information in?  Well, there are two ways - the easy way, and the DIY way.  The easy way is to buy a PIC programmer (around £35), which will connect to your PC and you can program your PIC using the software provided.  The DIY way is to build your own programmer (cheapest is just under £20) and use free software from the Internet and program it that way.
If you want to go for a DIY method, then I thoroughly recommend this site, and click on 'Supported Programmers' for circuits.  The cheapest is TAIT Classic Programmer.  Software for programming the PIC can also be downloaded from this site, under Download
If you want to go down an easier route, then check out this site.  Here you can either buy a kit of parts or a ready made unit.
Another good site for some FREE software is here  This software allows you to use any programmer, as the software is fully configurable.
Either method will do, as they both result in the same thing - program a PIC.
The next thing you will need is an assembler.  This converts the program that you write into a format that the PIC understands.  The best one around is from Microchip themselves, called MPLAB.  It is windows based, and includes an editor, simulator, and assembler.  This is the de-facto software, as it is written by the manufacturers of the PIC, and above all it is FREE!
I also recommend using Breadboard to make your circuits up, while you are playing with the PIC.  There are various sizes available, which come with their own costs.  Check out the Maplin Electronics links on the home page for more details of prices etc.
Next, we will look at how to connect up a simple circuit for PIC development.

Good Programming Techniques.

Before we get to the nitty gritty of programming the PIC, I think now is a good time to explain some good programming techniques.
If you type a ; (semicolon) anywhere in your program, the compiler will ignore anything after it until the carriage return.  This means we can add comments in our program to remind us of what on earth we were doing in the first place.  This is good practice, even for the simplest programs.  You may well fully understand how your program works now, but in a few months time, you may be scratching your head.  So, use comments wherever you can – there is no limit.
Secondly, you can assign names to constants via registers (more about these later).  It makes it far easier to read in English what you are writing to, or what the value is, rather than trying to think of what all these numbers mean.  So, use real names, such as COUNT.  Notice that I have put the name in capitals.  This makes it stand out, and also means that (by convention) it is a constant value.

Thirdly, put some kind of header on your programs by using the semi-colons.  An example is below:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Author :                                                                     ;
; Date :                                                                        ;
; Version:                                                                    ;
; Title:                                                                          ;
;                                                                                   ;
; Description:                                                             ;
;                                                                                   ;
;                                                                                   ;
;                                                                                   ;
;                                                                                   ;
;                                                                                   ;
;                                                                                   ;
;                                                                                   ;
;                                                                                   ;
;                                                                                   ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Notice that I have made a kind of box by using the semi-colons.  This just makes it look neat.

Finally, try and document the program on paper as well.  You can either use flow charts or algorithms or anything else you want.  This will help you in writing your program, step by step.
 Right, that’s the lecture over with, lets move on to the real stuff.
Writing To the Ports.


In the last tutorial, we I showed you how to set up the IO port pins on the PIC to be either input or output.  In this tutorial, I am going to show you how to send data to the ports.  In the next tutorial, we will finish off by flashing an LED on and off which will include a full program listing and a simple circuit diagram so that you can see the PIC doing exactly what we expect it to.  Don’t try and compile and program your PIC with the listings here, as they are examples only.


First, let us set up Port A bit 2 as an output:




bsf                    03h,5              ;Go to Bank 1
movlw              00h                  ;Put 00000 into W
movwf              85h                  ;Move 00000 onto TRISA – all pins set to output
bcf                   03h,5               ;Come back to Bank 0


This should be familiar from the last tutorial.  The only difference is that I have set all of the pins on Port A as output, by sending 0h to the tri-state register.


Now what he have to do is turn an LED on.  We do this by making one of the pins (the one with the LED connected to it) high.  In other words, we send a ‘1’ to the pin.  This is how it’s done (note the comments for an explanation of each line):




movlw              02h      ;Write 02h to the W register.  In binary this is 00010, which
                                     ;
puts a ‘1’ on bit 2 (pin 18) while keeping the other pins to ‘0’

movwf              05h      ;Now move the contents of W (02h) onto the PortA, whose
                                     ;address is 05h


So, now our LED is on, we now need to turn it off:




movlw              00h      ;Write 00h to the W register.  This puts a ‘0’ on all pins.

movwf              05h      ;Now move the contents of W (0h) onto the Port A, whose
                                     ;address is 05h


So, what we have done is turn the LED on then off once.


What we want is for the LED to turn on then off continuously. We do this by getting the program to go back to the beginning.  We do this by first defining a label at the start of our program, and then telling the program to keep going back there. 


We define a label very simply.  We type a name, say START, then type the code:



Start                movlw              02h      ;Write 02h to the W register.  In binary this is
                                                              ;00010, which puts a ‘1’ on pin 2 while keeping
                                                              ;the other pins to ‘0’

movwf              05h      ;Now move the contents of W (02h) onto the
                                                 ;PortA, whose address is 05h

movlw              00h      ;Write 00h to the W register.  This puts a ‘0’ on
                                                 ;all pins.

movwf              05h      ;Now move the contents of W (0h) onto the Port
                                                 ;A, whose address is 05h
                                            goto               Start      ;Goto where we say Start


As you can see, we first said the word ‘Start’ right at the beginning of the program.  Then, right at the very end of the program we simply said ‘goto Start’.  The ‘goto’ instruction does exactly what it says.


This program will continuously turn the LED on and off as soon as we power up the circuit, and will stop when we remove power.


I think we should look at our program again:


             bsf                    03h,5
                         movlw              00h
                         movwf              85h
                         bcf                   03h,5
Start                 movlw              02h
                         movwf              05h
                         movlw              00h
                         movwf              05h
                         goto                 Start

OK, I know I have left the comments off.  But, do you notice that all we can see are instructions and numbers?  This can be a little confusing if you are trying to debug the program later, and also when you write the code you have to remember all of the addresses.  Even with the comments in place, it can get a bit messy.  What we need is to give these numbers names.  This is accomplished by another instruction: ‘equ’.


The ‘equ’ instruction simply means something equals something else.  It is not an instruction for the PIC, but for the assembler.  With this instruction we can assign a name to a register address location, or in programming terms assign a constant.  Let us set up some constants for our program, then you will see how much easier to read the program is.




STATUS          equ  03h           ;this assigns the word STATUS to the value of 03h,
                                                   ;which is the address of the STATUS register.

TRISA             equ 85h            ;This assigns the word TRISA to the value of 85h,
                                                  ;which is the address of the Tri-State register for PortA

PORTA           equ 05h            ;This assigns the word PORTA to 05h which is the
                                                  ;address of Port A.


So, now we have set up our constant values, let us put these into our program.  The constant values must be defined before we can use them, so to be sure always put them at the start of the program.  I will re-write the program without comments again, so that you can compare the previous listing to the new one:




STATUS          equ 03h
TRISA              equ 85h
PORTA            equ 05h

                         bsf                    STATUS,5
                         movlw              00h
                         movwf              TRISA
                         bcf                   STATUS,5

Start                 movlw              02h
                         movwf              PORTA
                         movlw              00h
                         movwf              PORTA
                         goto                 Start

Hopefully, you can see that the constants make following the program a little easier, even though we still have not put the comments in.  However, we are not quite finished.

Delay Loops.




There is one slight drawback to our flashing LED program.  Each instruction takes one clock cycle to complete.  If we are using a 4MHz crystal, then each instruction will take 1/4MHz, or 1uS to complete.  As we are using only 5 instructions, the LED will turn on then off in 5uS.  This is far too fast for us to see, and it will appear that the LED is permanently on.  What we need to do is cause a delay between turning the LED on and turning the LED off.


The principle of the delay is that we count down from a previously set number, and when it reaches zero, we stop counting.  The zero value indicates the end of the delay, and we continue on our way through the program.

So, the first thing we need to do is to define a constant to use as our counter.  We will call this constant COUNT.  Next, we need to decide how big a number to start counting from.  Well, the largest number we can have is 255, or FFh in hex.  Now, as I mentioned in the last tutorial, the equ instruction assigns a word to a register location.  This means that whatever number we assign our COUNT, it will equal the contents of a register. 


If we try and assign the value FFh, we will get an error when we come to compile the program.  This is because location FFh is reserved, and so we can’t access it.  So, how do we assign an actual number?  Well, it takes a little bit of lateral thinking.  If we assign our COUNT to the address 08h, for example, this will point to a general purpose register location.  By default, the unused locations are set to FFh.  Therefore, if COUNT points to 08h, it will have the value of FFh when we first switch on. 

But, I hear you cry, how do we set COUNT to a different number?  Well, all we do is ‘move’ a value to this location first.  For example, if we wanted COUNT to have a value of 85h, we can’t say COUNT equ 85h because that is the location of out Tri-State register for Port A.  What we do is this:






movlw  85h                  ;First put the value of 85h in the W register

movwf  08h                  ;Now move it to our 08h register.




Now, when we say COUNT equ 08h, COUNT will equal the value 85h.  Subtle, isn’t it!

So, first we define our constant:






COUNT          equ       08h




Next we need to decrease this COUNT by 1 until it reaches zero.  It just so happens that there is a single instruction that will do this for us, with the aid of a ‘goto’ and a label.  The instruction we will use is:






DECFSZ        COUNT,1




This instruction says ‘Decrement the register (in this case COUNT) by the number that follows the comma.  If we reach zero, jump two places forward.’  A lot of words, for a single instruction. Let us see it in action first, before we put it into our program.






COUNT          equ 08h
LABEL           decfsz   COUNT,1
                        goto LABEL
                        Carry on here.
                        :
                        :
                        :

What we have done is first set up our constant COUNT to 255.  The next line puts a label, called LABEL next to our decfsz instruction.  The decfsz COUNT,1 decreases the value of COUNT by 1, and stores the result back into COUNT.  It also checks to see if COUNT has a value of zero.  If it doesn’t, it then causes the program to move to the next line.  Here we have a ‘goto’ statement which sends us back to our decfsz instruction.  If the value of COUNT does equal zero, then the decfsz instruction causes our program to jump two places forward, and goes to where I have said ‘Carry on here’.  So, as you can see, we have caused the program to stay in one place for a predetermined time before carrying on.  This is called a delay loop.  If we need a larger delay, we can follow one loop by another.  The more loops, the longer the delay.  We are going to need at least two, if we want to see the LED flash..




Let us put these delay loops into our program, and finish off by making it a real program by adding comments:





;*****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 

;****Turn the LED on**** 

Start               movlw               02h                   ;Turn the LED on by first putting
                       movwf               PORTA            ;it into the w register and then                                                                            ;on the port 

;****Start of the delay loop 1**** 

Loop1          decfsz              COUNT1,1       ;Subtract 1 from 255
                    
goto                  Loop1              ;If COUNT is zero, carry on.
                     decfsz             COUNT2,1        ;Subtract 1 from 255
                     goto                 Loop1                ;Go back to the start of our loop.                                                                          ;This delay counts down from                                                                           ;255 to zero, 255 times

;****Delay finished, now turn the LED off**** 

                    movlw              00h                     ;Turn the LED off by first putting
                    movwf              PORTA              ;it into the w register and then on                                                                         ;the port 

;****Add another delay**** 

Loop2        decfsz             COUNT1,1           ;This second loop keeps the
                   goto                 Loop2                   ;LED turned off long enough for
                   decfsz             COUNT2,1           ;us to see it turned off
                   goto                 Loop2                   ; 

;****Now go back to the start of the program

                   goto                 Start                       ;go back to Start and turn LED                                                                            ;on again 

;****End of the program**** 

end                                                                   ;Needed by some compilers,                                                  ;and also just in case we miss                                                  ;the goto instruction.




You can compile this program and then program the PIC.  Of course, you will want to try the circuit out to see if it really does work.  Here is a circuit diagram for you to build once you have programmed your PIC.







Congratulations, you have just written your first PIC program, and built a circuit to flash an LED on and off.  So far, if you have followed these tutorials, you have learnt a total of 7 instruction out of 35, and yet already you are controlling the I/O ports!




Why not try and alter the delay loops to make the LED flash faster – what is the minimum value of COUNT to actually see the LED flash?  Or, why not add a third or even more delay loops after the first one to slow the LED down.  You will need a different constant for each delay loop.  You could then even adjust your delay loops to make the LED flash at a given rate, for example once a second.




In the next tutorial we will see how we can use a thing called a subroutine to help keep the program small and simple.

Subroutines


 A subroutine is a section of code, or program, than can be called as and when you need it.  Subroutines are used if you are performing the same function more than once, for example creating a delay.  The advantages of using a subroutine are that it will be easier to alter the value once inside a subroutine rather than, say, ten times throughout your program, and also it helps to reduce the amount of memory your program occupies inside the PIC.




Let us look at a subroutine:


ROUTINE                               COUNT          equ 255
LABEL                                   decfsz             COUNT,1
                                                Goto                LABEL
                                                RETURN 

First, we have to give our subroutine a name, and in this case I have chosen ROUTINE.  We then type the code that we want to perform as normal.  In this case, I have chosen the delay in our flashing led program.  Finally, we end the subroutine by typing the RETURN instruction.


To start the subroutine from anywhere in our program, we simply type the instruction CALL followed by the subroutine name.


Let us look at this in slightly more detail.  When we reach the part of our program that says CALL xxx, where xxx is the name of our subroutine, the program jumps to wherever the subroutine xxx resides.  The instructions inside the subroutine are carried out.  When the instruction RETURN is reached, the program jumps back to our main program to the instruction immediately following our CALL xxx instruction.


You can call the same subroutine as many times as you want, which is why using subroutines reduces the overall length of our program.  However, there are two things you should be aware of.  First, as in our main program, any constants must be declared before they are used.  These can be either declared within the subroutine itself, or right at the start of the main program.  I would recommend that you declare everything at the start of your main program, as then you know that everything is in the same place. Secondly, you must ensure that the main program skips over the subroutine.  What I mean by this is if you put the subroutine right at the end of your main program, unless you use a ‘Goto’ statement to jump away from where the subroutine is, the program will carry on and execute the subroutine whether you want it to or not.  The PIC does not differentiate between a subroutine and the main program. 

Let us look at our flashing led program, but this time we will use a subroutine for the delay loop.  Hopefully, you will see how much simpler the program looks, and also you will see how the subroutine works for real.




;*****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 

;****Turn the LED on**** 

Start            movlw              02h                  ;Turn the LED on by first putting it
                    movwf              PORTA           ;into the w register and then on the port 

;****Add a delay 


          call                   Delay 


;****Delay finished, now turn the LED off****

movlw              00h                  ;Turn the LED off by first putting it
movwf              PORTA           ;into the w register and then on the port 

;****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.
 

Hopefully, you can see that by using a subroutine for our delay loop, we have reduced the size of the program.  Each time we want a delay, either when the LED is on or off, we simply call the delay subroutine.  At the end of the subroutine, the program goes back to the line following our ‘Call’ instruction.  In the example above, we turn the LED on.  We then call the subroutine.  The program then returns so that we can turn the LED off.  We call the subroutine again, and when the subroutine has finished, the program returns and the next instruction it sees is ‘goto Start’.


For those of you who are interested, our original program was 120 bytes long.  By using the subroutine, we have reduced our program size down to 103 bytes.  This may not seem to be that great, but seeing that we only have 1024 bytes in total inside the PIC, every little bit helps.

In the next tutorial, we will look at reading from the ports.

Reading from the I/O ports.




Up to now, we have been writing to Port A so that we can turn an LED on and off.  Now, we are going to look at how we can read the I/O pins on the ports.  This is so that we can connect an external circuit, and act on any outputs it gives.


If you recall from our previous tutorials, in order to set up the I/O ports, we had to switch from Bank 0 to Bank 1.  Let us do that first:





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
bsf                    STATUS,5                               ;Switch to Bank 1 

Now, to set up the port to be an output, we sent a 0 to the TrisA register.  To set a pin on a port to be an input, we send a 1 to the TisA register.

movlw              01h                  ;Set the Port A pins
            movwf              TRISA             ;to input.
            bcf                   STATUS,5      ;Switch back to Bank 0 


Now we have set bit 0 of Port A to input.  What we need to do now is to check if the pin is high or low.  For this, we can use one of two instructions: BTFSC and BTFSS.

The BTFSC instruction means ‘Do a bit test on the register and bit we specify.  If it is a 0, then we skip the next instruction’.  BTFSS means ‘Do a bit test in the register and bit we specify.  If it is set to a 1, then we skip the next instruction.’ 

Which one we use, depends on how we want our program to react when we read the input.  For example, if we are simply waiting for the input to be a 1, then we could use the BTFSS instruction like this:


Code here
:
BTFSS             PortA,0
Goto start
Carry on here
:

The program will only move onto ‘Carry on here’ only if bit 0 on PortA is set to a 1.


Let us now write a program which will flash an LED at one speed, but if a switch is closed it will flash the LED twice as slow.  You can probably work this program out for yourself, but I have included the listing anyway.  You could try and write the whole program, just to see if you have grasped the concepts.  We are using the same circuit as before, with the addition of a switch connected RA0 of the PIC and the positive rail of our supply.

;*****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 


;****Turn the LED on**** 

    Start                 movlw              02h               ;Turn the LED on by first putting it
    movwf              PORTA                                 ;into the w register and then on the port
 


;****Check if the switch is closed



BTFSC            PORTA,0             ;Get the value from PORT A
                                                       ;BIT 0.  If it is a zero
call                   Delay                    ;a zero, carry on as normal.
                                                       ;If is is a 1, then add an
                                                       ;extra delay routine
 

;****Add a delay 


call       Delay 

;****Delay finished, now turn the LED off****

     movlw              00h                  ;Turn the LED off by first putting it
                 movwf              PORTA           ;into the w register and then on the port 


;****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. 

What I have done here is to turn the LED on.  I then check to see if the switch is closed.  If it is closed, then I make a call to our delay subroutine.  This gives us the same delay as before, but we are now calling it twice.  The same goes for when the LED is off.  If the switch is not closed, then we have our old on and off times.

You can compile and run this program.  However a word of warning.  The final circuit and code will look un-impressive to someone who is not interested in programming microcontrollers.  So, don’t be upset if, when you show your family and friends how you can change the speed of a flashing LED with a switch, they show very little interest – I am talking from personal experience, here!

If you have been following these tutorials from the start, then you may be interested to know that you have now learnt 10 of the 35 instructions for the PIC 16F84!  And all of these have been learnt just by simply turning an LED on and off.


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!




 


 
 

Share/Bookmark

Related Posts Plugin for WordPress, Blogger...