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 VDDOSC1/CLK IN And OSC2/CLKOUT
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
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: ;
; ;
; ;
; ;
; ;
; ;
; ;
; ;
; ;
; ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 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.
Subroutines
In the next tutorial, we will look at reading from the ports. Reading from the I/O ports.
movlw 01h ;Set the Port A pins movwf TRISA ;to input. bcf STATUS,5 ;Switch back to Bank 0
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
Start movlw 02h ;Turn the LED on by first putting it movwf PORTA ;into the w register and then on the port
movlw 00h ;Turn the LED off by first putting it movwf PORTA ;into the w register and then on the port
goto Start ;go back to Start and turn LED on again
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.
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:
Let us now look to what happens if we make B the same as our previous output, and just changing the value of A:
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:
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:
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:
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:
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
Start xorwf PORTA,1 ;Toggle the LED
goto Start ;go back to Start and turn LED on again
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
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
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
goto Start ;go back to Start and turn LED on again
| ||