Talking Electronics PIC Theory

Programming PIC Chips


This chapter should be read AFTER you have done the experiments in the 5x7 Display project. It covers some of the things we have discussed already but it is worth going over them again.
The 5x7 Display experiments show how to write a program and you can see how instructions are laid out to produce sub-routines and how these are combined to produce a program.

Our approach to writing a program is very linear. Many writers produce very small sub-routines with GOTO’s from one sub-routine to another that produce “jumps all over the place.”
The micro is perfectly capable of jumping up and down a program but this type of layout is very difficult for the reader to follow.
With ours, it is much easier to follow the sequence of events and you will very soon be able to write programs similar to those in the projects section.

The items you will need are:
1. The Library of Terms and Routines chapter,
2. The Instruction Sets for  ‘508A and F84
3. The Hex file at the back of this book,
4. Some or all of the following development tools:
18 Pin to 8 Pin adapter Type A
18 Pin to 8 Pin adapter Type B
5x7 Display for programming F84 chips
Pseudo 508A Module for developing a ‘508A program
Experimenter Board MkIII
PIC12c508A 6v Express Module
PIC16F84 Express Module
5. Any project with an 8-pin socket for a ‘508A chip.

The question you will be asking is: "Where do I start?"
This book is the starting point. It covers two of the smallest and simplest microcontrollers in the PIC range, the 508A, and F84, and with our development tools you can get into programming at the lowest cost.
The two micros are almost identical except for a couple of minor differences. The ‘508A has 5 in/out lines and one input-only line, while the F84 has 13 in/out lines. The ‘508A has 511 locations for a program while the F84 has 1024 locations. But apart from that, if you follow our rules, you can write a program that can be loaded into either device. There is one other small difference. The ‘508A is a One Time Programmable device while the F84 can be re-programmed up to 1,000 times.
There are differences between the two but to keep things simple, you can consider the F84 to be about twice the size of the ‘508A.
If you follow this line, you will be able to glide from one device to the other according to the complexity of the project.
Both microcontrollers have the same instruction-set (there are very minor differences as shown on the two Instruction-Set pages at the back of this book) and you only have to learn about 33-36 instructions to be able to create a program.
These 33/36 instructions expand into more than 2,000 instructions when you consider every bit in each file can be SET, CLEARed or TESTed, but you only have to remember 33 “English-like” words (called mnemonics) to create a program.
One of the advantages of the PIC range of microprocessors is the security feature. It means the program you down-load into a chip cannot be read by anyone else. At best they can only get a garbled set of figures.
A PIC microcontroller is similar to an exercise book - a book with blank pages. It has an area where your program is placed. The program is created by you and loaded into the chip via a device called a burner or programmer. We have called ours: “Multi-Chip Programmer.”
As already mentioned in the introduction, we have worked out a way to allow '508A programs to be developed without wasting any chips. It uses a module called the Pseudo'508A.
The Pseudo'508 module allows you to write programs in stages and test them in a Module called the 12c508A 6v Express.
The Pseudo'508A module is really an F84 wired so that it performs exactly like a '508A and this means you can re-program it as many times as needed, during the development of a program.
The F84 chip in the Pseudo ‘508A module is taken out and burnt on the “5x7 Display” project or “Multi-Chip Programmer."
Once you develop and perfect the program it can be burnt into a low-cost OTP '508A, and fitted into a project you have developed, and YOU hold the key to its operation.
That's why programming PICs can be a very rewarding venture.

 "What Do I Need?"
To create a program for a '508A microcontroller, the items you need have been listed above.
Programs can be written in an exercise book or on blank paper. From there they are transferred to a Notepad program on your computer. Each line is written in mnemonics, a half-English, half computer language that both you and the compiler understands.
The program is then converted to Hexadecimal code via a program called MPASM. This is available for downloading from this website.
The .hex file is sent to the microcontroller in the form of binary 1's and 0's to be “burnt” into memory.
Don't worry about the small programming space of 1FF locations for the '508A. This is equal to over 500 lines of code and if you write 50 instructions on a page of paper, this represents more than 10 pages! In reality, only about 255 locations can be used but this is still a fairly lengthy program.
One point to remember: - as you write and develop a program, it will consist of many SUB-ROUTINES followed by a MAIN ROUTINE. These sub-routines will be called one or many times. Thus, as a program gets longer, you may find you can use sub-routines that have already been written and so your program becomes more efficient.

THE ‘508A
These notes have been written for the ‘508A, however everything you write for the ’508A can be instantly transferred to a PIC16F84.
It works this way. Suppose you are designing a project requiring one or two input lines and two or three output lines. This is ideal for the ‘508A. Suppose you are half-way through the project and realise you need an extra 7 output lines for a 7-segment display. The project is possibly too big for the ‘508A, but nothing is lost. All the code you have written will apply to the F84. The reason is we are only suggesting you use instructions and files that are common to both devices. All the files have the same names and the input/output lines for the ’508A: GP0, GP1, GP2, GP3, GP4 and GP5 are changed to RB0, RB1, RB2, RB3, RB4 and RB5.
It’s more difficult to go from an F84 to a ’508A but it’s not impossible.
Obviously it’s best to select the most suitable microcontroller in the first place, but this course shows the interchangeability of the two devices.

ll the values in our programs are written in Hex. This makes writing a program more complex but understanding hex gets you one step closer to seeing how the program operates and allows you to work out the values to make the individual port lines input or output.
The program values are loaded into a register called the working register (the W register). These values are called LITERALS. A Literal is simply another name for Value or Number.
The Hex code has a base of sixteen numbers and these are: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A = ten, B = eleven, C = twelve, D = thirteen, E = fourteen, F = fifteen.
For instance, twelve is 0C and fifteen is 0F. It's easy to see 3E is a hex value (equal to sixty-two), but to make it easy to recognise hex values such as 23 or 41 or 82, a small "h" is placed after the value thus: 23h, 41h, 82h.
A file is capable of holding a value from 00 to FF and this represents a value from zero to two hundred and fifty-five in decimal or ordinary numbers. See the page of Hex values from 00 to 1FF at the back of this book and look through them to see how Hex notation is structured.
It will take time to understand hex but while we are here, there is another concept you must understand. It is: BINARY-TO-HEX.
The binary code consists of only two values "0" and "1."
All the files in the '508A and F84 are made up of 8 "cells" in which a "zero" or "one" is placed in each cell. The 8 cells are separated into a group of 4 upper cells and 4 lower cells. The 4 upper cells are called the HIGH nibble and the 4 lower cells are called the LOW nibble.
To read the complete (or total or full) Hex value in a file, the HIGH nibble and LOW nibble are combined.
Each GP line (A GP line is a General Purpose input/output line) corresponds to a bit in file 06. Line GP0 corresponds to the Least Significant Bit (LSB) and GP1 corresponds to the next bit (bit1).
Now, here comes the hard bit to understand, but it's logical.
To make GP0 an output line, the LSB in file 06 must be 0. "0" stands for Output.
To make GP0 an input line, the LSB in file 06 must be 1. "1" stands for Input.
Suppose you want to make GP0, GP1 and GP2 input. The three low bits must be "1." This makes the file = 0000 0111 = 07.
Suppose you want to make GP3 input. The file value will be = 0000 1000 = 08.
Suppose you want to make GP3 and GP5 input. The file value will be 0010 1000 = 28h.
Any combination of lines can be input or output and it's essential to understand hex notation to create the value to load into file 06.
File 06 has only six functional bits but all the other files contain 8 bits. You need to know hex when loading a file because you may need to know: (a) when a certain bit is SET in a file being incremented, or (b) the maximum a file can hold for a table, or (c) the output pattern when a counter has been "clocked."
Binary values are involved in all stages of program writing and hex is simply a short-form of showing the binary value, using 2-digits. Hex is easy to see and easy to read. In addition, you can mentally convert binary-to-hex and hex-to-binary very quickly. 

The '508A contains thirty-two files or registers of which the first seven (00h to 06h) are called Special Function Registers (SFR's) and the next twenty-five (07h to 1Fh) are General Purpose Registers or Files (GPR's).
The F84 has twelve Special Function Register (SFR’s) (00h to 0Bh) and the next sixty-eight (0Ch to 4Fh) are called “Files.”
Twenty files are common to both the ’508A and F84. They are: 0C, 0D, 0E, 0F, 10h, 11h, 12h, 13h, 14h, 15h, 16h, 17h, 18h, 19h, 1A, 1B, 1C, 1D, 1E, 1F. These are the files we will be using.
Each file has 8 bits which can be made "0" or "1." When all the bits are zero (0000 0000), the file has a value of zero.
When the LSB is "1," the file has a value of 1. We have already shown how the low nibble in the file increments to F (see Hex Notation at beginning of article). The next increment after 0F produces 0001 0000 = 10h, followed by 0001 0001 = 11h. The file increments to 1111 1111 = FF then "rolls over" to 0000 0000.
Before leaving hex, there's one more skill you will need. It's converting binary to hex so you can SET bits in a file.

Setting single bits is easy. Here is the table:
0000 0001 = 01h = bit0
0000 0010 = 02h = bit1
0000 0100 = 04h = bit2
0000 1000 = 08h = bit3
0001 0000 = 10h = bit4
0010 0000 = 20h = bit5
0100 0000 = 40h = bit6
1000 0000 = 80h = bit7

To set TWO or MORE BITS in the high or low nibble, read on. Remember, the lowest bit is called bit0 and the highest is bit7.
To set bit2 and bit3, the binary value is: 0000 1100. From the table above we see this is 08h plus 04h. How do you add 08h and 04h together?
Simple. Take the highest value and ADD four counts to it as follows:
oh nine, oh aye, oh bee, oh cee. The answer is 0Ch.
To set bit6, bit5 and bit4, the procedure is: 0111 000. This is 40h plus 20h plus 10h. We take the high nibble as 4h + 2h + 1h to make things simple. This is 7h and so the answer is 70h.
To set bit7, bit6, bit5 and bit4, the procedure is: 1111 0000 = 80h + 40h + 20h + 10h. This is 8h + 4h + 2h + 1h (in the high nibble). Start with 8 and increment it four counts thus: nine, aye, bee, cee.
Then increment it two counts: dee, eee. Then increment it one count: "eff." The answer is F0.
It will take time to become proficient but work on it.

The Working register is the most important (most busy) register in the chip. It operates like a basket in a super-market, picking up a value from the program, such as a Literal, or a data byte from a table, a value from any of the files or data bits from the input port and delivering it/them to another file, or the output port. The output port is file 06 and any value delivered to this file via W, is available for outputting.
It also works in reverse. Any value presented to this file from the outside world is delivered to file 06 and from file 06 it can be passed to the working register. The working register can be cleared (zeroed) or loaded with a number (called a literal).
Bits in the working register cannot be tested, cleared or set, or the nibbles swapped. It cannot be incremented, decremented or the bits rotated. These operations have to be done on a value in a file.
The Working register is merely the "carrier" or "helper" in the system.
It does not have an address location, it is merely called "W" in an instruction.

There are features in the PIC instruction set that make it "very powerful." By this we mean a single instruction incorporates two or three things. In the early microprocessors, an instruction did only one thing. That's why you needed a lot of instructions in the instruction-set.
One of the clever features of the PIC instruction-set is the designator. It's the number 1 or 0 added to the instruction to tell the micro where to put the result of the operation.
If we take the instruction ANDWF 0C,1 the result is placed in file 0C. If we use the instruction ANDWF 0C,0 the result is placed in the W register. There is an obvious importance in selecting the correct instruction as the first instruction changes the contents of file 0C while the second instruction does not change 0C and we may not want 0C changed.
With some instructions it is more difficult to see the purpose of the designator. For instance, MOVF 0C,1 merely moves the contents of file 0C in and out of 0C and alters the flags. It DOES NOT put the contents in W. To put the contents in W, the instruction MOVF 0C,0 must be used.
When writing a program it is important to include the designator. If you forget, the compiler (MPASM) will add a default designator and report the condition.
You must check this as the fault designator may not produce the required result. For instance: 
MOVF 0C,1 does not put the contents of 0C in W - it merely moves the contents in and out of 0C. 

he program for a '508A starts at address 000 and extends to 1FF. This is a hexadecimal number and corresponds to 512 locations (512 lines of code). We can only use up to 511 address locations as the top location is used by the micro as a calibration value. (OSCCAL).
For the applications are will be talking about (such as games, displays, timers, counters, etc.), 511 lines of code is a good-size program especially when you consider the chip is capable of taking the place of 5 or more standard chips in a project.
Before writing a program, you should look through the projects we have included in this book as well as the Library of Terms and Routines to get some idea of what the micro can do.
This will also give you an idea of how the instructions are written and the type of instruction required for a particular operation.
The easiest way to learn is by example and spending time with the projects and looking through the routines in the Library will get you to the "starting blocks."
Most of the thinking that goes into writing a program cannot be seen in the final version of the project so let's find out what the programmer is thinking when he produces a routine.
Firstly he has to work out what he wants the project to do. He doesn't worry about the program or the micro for the moment. He just thinks about what he wants to SEE the project do.
All the timing, pin numbers, LED colours and types of sounds will come later.
Firstly produce an overall description in the form of an essay, set of notes or a flow diagram.

Some schools of thought think a flow chart is essential for successful programming.
If you are not up with flow-chart symbols or how to produce such a chart, don't worry. Other schools consider them to be absolutely un-necessary!
For those who are keen, there are only three flowchart symbols you need to know.
They are the start and stop ovals, the rectangle in which an operation is performed and the decision diamond where a "yes" or "no," "on" or "off," decision is made.
These shapes are connected with lines and the arrows indicate the direction of flow of the program.

A flowchart helps others to understand what the program is doing and gives an idea of its complexity.
The best way of starting a new project is to write a description of the entire operation. Then separate it into sections and place each step in an "operations" rectangle. Any decision-making stages are placed in a diamond then linked with lines and arrows and - hey presto! You have produced your own flow chart!
Next take each section and convert it into steps that can be carried out by the microcontroller. This is where knowledge of programming comes in. To do this you need to understand the instruction-set so you can write the correct instructions.
It is also very important to put them in the correct order so the outcome is exactly as you intend.

The simplest program will load the working register with the value "1" and output it to GP0.
If a LED (in series with a 470R to 2k2 resistor) is connected to GP0, it will illuminate when this instruction is executed.

But before we can run this very simple program, we have to "set-up" the port so that GP0 is an output.
So, lets' go back to the start.



MOVLW 3E ;GP0 output, GP3 input
TRIS 06 ;Load TRISB file


MOVLW 01 ;Load W with 1
MOVWF 06h ;Make GP0 HIGH

GP0 is one of the input/output lines of the chip. Before a program can output a value on this line,
the port must be "set up" so that GP0 is an output. GP0 is bit0 of the TRIS register and it must be "0" to be an output. The other bits can be anything. We will make them "1" (input) to highlight the fact that the '508A port has only 6 lines. Thus the TRIS register will be: 0011 1110 = 3Eh
Since we are using the Pseudo'508A for program development, the instructions for "set-up" are as follows: 


MOVLW 3E ;Make GP0 output
TRIS 06h ;Load TRISB file

GP0 is now an output line. It will deliver a HIGH to the outside world when "1" is loaded into bit0 of file 06. The instructions for this are:

 MOVLW 01 ;Load W with 1
 MOVWF 06h ;Move W to file 06

The GP0 line will produce a HIGH and a LED connected to this line will illuminate when the above two instructions plus the set-up instructions are executed.
When this program is loaded into a chip on the Pseudo'508 module , you can think of an imaginary pointer starting at the first instruction and passing it to the central processing unit for execution.
The "pointer" is the Program Counter (PC). It starts at 000 and increments one location at a time and feeds the code (at the address) to the central processing unit where it is acted upon.
Once the micro is set into operation, it does not stop. It continues down the program.
In the program above, the Program Counter will "run off the end of the program." To prevent this from happening, additional instructions are needed to "guide" the program counter. The complete program is shown above.
The first 06h in the program is not the port file. It is the TRISB register. The second 06h is the input/output port.
The GOTO instruction creates a loop to make the micro go to the "Out0" label.
Once the micro enters this loop, it never comes out, unless the power is switched off.

Let's explain the "Simplest Program" in English!
The instructions to make the LSB in the TRIS register an output are:

 MOVLW 3E ; Put 0011 1110 into W to make GP0 an output
 TRIS 06

The binary value 0011 1110 shows bits 6 and 7 are not needed as the '508A has only 6 port lines and all the other lines will be input lines (as shown by the value "1") except the lowest bit, which will be an output. In other words we only have to make bit0 a zero!
The value in W is moved into the TRIS register and this will make the Least Significant Bit in TRIS an output. The port is now set up with the LSB (least significant line) an output. This line is called GP0 (General Purpose in/out line 0).


 Line 3 moves (loads) W with 1:
MOVLW 01 ;Load W with 1
MOVWF 06 ;Move W to the port file
 The instruction in line 5:

tells the micro to go to the label Out0 at line 3 and the micro executes a loop of lines 3, 4 and 5. This is called an ENDLESS loop as the micro will continue to execute these three instructions until the power is removed.

Programs are written using the 33/36 PIC instructions on a Notepad program and saved with the extension .asm (dot ASM). When a program is written as shown in the "Simplest Program," it is called ASSEMBLER CODE and saved with the extension .asm

In other words it is written for an assembler. The assembler we use is called MPASM and it will locate all the tags and labels and convert them to an address and convert the instructions to Machine Code. The result is a file with the extension .hex

o add to our simplest program, we can include a push button.
The button has been added to the circuit so that when it is pressed, GP3 sees a HIGH. This is called POSITIVE LOGIC. 
The program is now required to "turn on a LED when a button is pressed." This statement must be converted into a set of instructions that can be executed by the '508A.

The program needs to be in the form of a loop so the button can be detected when pressed and the LED turned on. When the button is released, the LED must turn off.


TRIS 06 ;GP0 output, GP3 input


BTFSS 06,3 ;Test GP3
GOTO Released
GOTO Pushed


BSF 06,0 ;Make GP0 HIGH


BCF 06,0 ;Make GP0 LOW

All programs from now on consist of a LOOP. The simplest program above is the only program using a "dead-end" loop.
A normal program is in the form of a complete FUNCTIONAL loop, and since the micro is executing instructions at the rate of approximately one million per second, the loop will be executed many times per second.
The instructions in the loop must include looking at the switch to see if it is pressed or not pressed and outputting a HIGH or LOW on a line to turn the LED ON or OFF.
Set up the TRIS register so that GP0 is an output and GP3 is an input. This is the same as for the simplest program.

 MOVLW 3E ;GP0 output, GP3 input
 TRIS 06
The next instruction looks at the switch on GP3. The instruction is:


BTFSS 06,3 ;Test GP3

The instruction above tests bit 3 of file 06 (the port file). The micro "reads" the port and tests bit 3 to see if it is SET (HIGH).
The micro will jump (i.e. skip or NOT CARRY OUT) the next instruction in the program if the bit is SET. When the switch is pressed, the line will be HIGH and bit 3 will be SET. If the bit is SET - the switch is pressed, the micro will execute the instruction GOTO Pushed.

The next two instructions are:

 GOTO Released
 GOTO Pushed

We have created two branches in the program. The Released branch (for not pressed) and the Pushed branch (for switch pressed).
If the bit is SET, the switch will be pressed. The instructions for the "Set" mini-routine are: Make GP0 HIGH then go to "Sw" to look at the input:


BSF 06,0 ;Make GP0 HIGH

If the bit is Clear, it will be LOW and thus the switch will not be pressed. We now need to produce one or more instructions for the mini-routine "Clear." The instructions for "Clear" will clear bit0 of the port so that line GP0 is LOW and the LED will turn off.


BCF 06,0 ;Make GP0 LOW

The micro must now be sent back to test the port again to see the condition of the switch. The instruction is:


The program is constantly looping (polling) the instruction to look at the switch and turn the LED on or off. 

If you want to make the LED turn on and off automatically, a different set of instructions are needed.
Firstly you need instructions to turn the LED on, then a routine to keep it on for a period of time (this is called a DELAY routine), then instructions to turn the LED off and finally a delay routine.

The program must then loop back to where the LED is turned on. The result is a flashing LED.

A flow chart can be produced for this sequence using the symbols shown previously.
This will help to show the number of steps involved in the program.
From the flow chart we can produce a layout for the program:


 - - - - - Set-up instructions go here
- - - - - Set-up instructions go here


- - - - - Delay instructions go here 
 - - - - - Delay instructions go here 


 - - - - - Turn on LED instructions go here
 - - - - -
CALL Delay
- - - - - Turn off LED instructions go here
- - - - - Turn off LED instructions go here
CALL Delay