Talking Electronics PIC Theory

Programming PIC Chips


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:

SetUp        - - - - -
                  - - - - -
                  GOTO Main
Delay         - - - - -
                  - - - - -

 Main         Turn on LED  (The instructions to turn on a LED)
                 CALL Delay
                 Turn off LED  (The instructions to turn off a LED)
                 CALL Delay
                 GOTO Main

This introduces two new terms: Main Routine and Sub-routine. Programs are written as one or more sub-routines followed by a Main Routine. The sub-routines are CALLed from the Main routine and the Main routine is designed as a loop.
Since the micro is executing instructions at the rate of one million per second, a delay of 1/2 second will require a routine of 500,000 instructions. (See below for a more-accurate definition). Obviously
a 500,000 instruction routine must be some form of looping operation as the memory in a '508 is only 511 instructions long!
Secondly, if we make the ON time equal to the OFF time we can CALL the same delay routine.
A delay routine is also called a "do nothing" routine and is created by loading a file with a value and decrementing it to zero. An instruction in the "instruction-set" detects the zero condition of the file and
causes the program to exit the routine.
A single file will produce 255 loops (256 loops if the file starts with 00 as the file is decremented first then tested).
Each instruction takes one machine cycle or 1 microsecond, except when the program counter is altered as with GOTO, CALL, RETLW, RETURN and DECFSZ (when the file is zero) - these take 2 machine cycles.

A simple delay is as follows:

             MOVLW 00
             MOVWF 0C
DelA     DECFSZ 0C,1      ;1 machine cycle
            GOTO DelA         ;2 machine cycles

The loop consists of the instructions DECFSZ 0C,1 and GOTO DelA. Each loop will take 3 machine cycles. There are two machine cycles to enter the loop, 255 x 3 machine cycles in the loop and 4 machine cycles getting out of the routine, making a total of 771 machine cycles or 0.000771 seconds.
This is a very short delay and to increase the time we need to run this routine about 10,000 times. This is done by adding another file (called the count file) that "calls" this routine and decrements on
each "call."
The simplest way to "call" this routine and decrement the "count" file is to combine the two. This is called a NESTED LOOP or NESTED ROUTINE.

            MOVLW 00
            MOVWF 0C
            MOVWF 0D
           GOTO DelA
           DECFSZ 0D,1
           GOTO DelA

When file 0C is decremented to zero, the program comes out of the inner loop and decrements file 0D. It then goes to the inner loop where file 0C is decremented to zero once again. This is repeated
256 times. The total number of machine cycles is 3+256(768+3)+1+2 = 197,382. This is approx 1/5 second and if a 1/2 second delay is required, the routine must be "called" 3 times. This is done by introducing another file and loading it with 3. This becomes a 3-file nested routine as follows:


              MOVLW 03
              MOVWF 0E
              MOVLW 00
              MOVWF 0C
              MOVWF 0D
DelA     DECFSZ 0C,1
              GOTO DelA
              DECFSZ 0D,1
              GOTO DelA
              DECFSZ 0E,1
              GOTO DelA

The last step is to create "SetUp" and the Main routine.

SetUp      BSF 03,5           ;Select page1
               MOVLW 3E         ;Make GP0 output
               MOVWF 06h       ;Load TRISB file
               BCF 03,5            ;Select page 0
               GOTO Main

Delay      MOVLW 03
               MOVWF 0E
               MOVLW 00
               MOVWF 0C
               MOVWF 0D

DelA        DECFSZ 0C,1
                GOTO DelA
                DECFSZ 0D,1
                GOTO DelA
                DECFSZ 0E,1
                GOTO DelA

Main        MOVLW 01         ;Load W with 1
                MOVWF 06          ;Move W to file 06
                CALL Delay         ;Create ON time
                MOVLW 00
                MOVWF 06          ;Create OFF time
                CALL Delay
                GOTO Main         ;Loop Main routine

The program above appears to be fairly simple, and it is, but it introduces a number of features.
The Delay routine is called a sub-routine and it is called twice from the Main routine. Refer to the simple single-file delay routine above to understand how the file is decremented to zero.
The CALL instruction in the Main routine takes the micro to the sub-routine and the RETURN instruction at the end of the sub-routine sends the micro back to the Main routine.
Because the micro never stops, EVERY program must be ENDLESS. The Program Counter is being constantly incremented. It advances down the program until an instruction is executed that alters the value of the PC to cause a jump to some other part of the program. It may be to a sub-routine or a jump back to the main program. The "jump" instructions are CALL, RETURN and GOTO as well as DECFSZ instructions. This is how a program keeps the micro looping.

By now you will have learnt the in/out port for the '508A is file 06.
It surprised me too. Such an important feature hidden in one of the files!
Not only is the port "hidden" but the register controlling the port lines takes a bit of understanding. The TRIS register controls each of the 6 lines of file 06 and they can be individually made input or output by making the corresponding bit in TRIS a "0" for output or "1" for input.
Each line is called a "General Purpose input output line" and the only thing to remember is GP3 can only be an input line.
This produces one input and 5 output lines.
But the flexibility of the chip and the magic of programming allows you to change any of the output lines to an input line during the running of a program.
In addition, a push-switch on any of the input lines can perform different functions, according to the instructions in the program.
At the beginning of a program it can increment the count on a display, sound a beep in the middle of a program and reset the program and the end of the routine.
The point to remember with the port is the need to set TWO registers (files) to produce an input or output condition.
The TRIS register determines the input or output condition and file 06 determines the HIGH or LOW on an output line.
If the line is an input you do not make the line high or low via the program. It is made high or low via an outside (external) voltage and this is read by the instruction (BTFSS 06,3) and the program branches
according to the condition on the line.
If you want to read all the lines at once, the instruction MOVF 06,0 will move all the lines to W but remember bits 6 and 7 are non-functional. An output line will "read" as 1 if it is HIGH etc.

The next stage in programming involves the use of a TABLE.
A table allows pre-programmed information (called Data, constants, numbers or Literals - different words for the same thing) to be placed in a program. There is nothing complex about implementing a table.
In some microcontrollers data can be picked up from a particular location (such as RAM, ROM or anywhere in the program) and placed in a file with a single instruction. For the '508A, it requires three instructions
to do this. Firstly you need to set-up a table at the commencement of memory and insert the instruction:

Table1 ADDWF 02,1

Within the routine an instruction to MOVe (load) the W register with a "jump" value is needed. This is the value to locate the byte of data in the table and is usually a value moved from a file to the W register. Then the instruction: CALL Table1.
At Table1, the instruction ADDWF 02,1 loads the jump value into the Program Counter to cause the program to jump down the table.
Each byte of data must be combined with the instruction RETLW so that when the micro jumps down the table and picks up the byte of data, it will return to the originating routine with the byte of data in
the W register. Here is a typical layout for the instructions:

StartUp     - - - - -
                  - - - - - 
                    GOTO Main

Table1        ADDWF 02,1
                    RETLW AA
                    RETLW BB
                     - - - - -

Main            - - - - -
                    - - - - -
                    MOVF 0C,0
                    CALL Table1
                     - - - - -
                     - - - - -
                     GOTO Main

Moving file 0C into W (in the Main routine) allows the value in 0C to be changed and thus different bytes in the table can be accessed. If 0C is zero, the first byte in the table is accessed. If 0C is 1,
the second byte is accessed etc.

Instructions containing data (literal values) are classified as Immediate Addressing.

Direct Addressing simply means to operate on (such as SWAPF, INCF, DECF, etc) the file contained in the instruction. For the instruction, INCF 0C,1 the address is 0C.

Relative Addressing involves changing the contents of the Program Counter. Using a Table involves Relative Addressing. See Library of Routines.

The last "trick" in our book is the skill of indirect addressing. This allows you to take any number of bytes of data from a table and load them into consecutive files with the least number of instructions.
Two files are used for the indirect addressing function. They are file 00h, (INDF - INDIRECT File) and file 004h, (FSR - File Select Register).
The INDF file is like a "hole in the wall." You look through the INDF file to the file pointed to by the FSR.
The File Select Register is like an "extension arm." It can reach to all the files (00h to 1F).
Suppose we want to load 08 into file 1A.  To use the Indirect Addressing mode:

1. The FSR is loaded with the address of the first file (Move 1A into FSR).
2. Move 08 into INDF (Move 08 into INDF).

08 gets placed into the file looked at by FSR. Thus 08 gets loaded into file 1A.
If we read INDF, we read the contents of the file looked at by FSR. In other words we read the value in file 1A and the value is 08! This is Indirect Addressing.
FSR is also called the "pointer" file.
The advantage of this programming technique is we can increment FSR and thereby look down a set of files and either read them or write to them, with the least number of instructions.
You can also test a particular bit in any file or see if it is SET or CLEAR.
To do this you SET or CLEAR a bit in INDF and the same bit looked at by FSR will be CLEARed or SET.
To clear 6 files, from 1A to 1F using Indirect Addressing:

             MOVLW 1A     ;Load W with start of RAM
             MOVWF 04     ;Move start to FSR

ClrRAM    CLRF 00,1       ;Clear INDF
                INCF 04,1        ;Increment pointer
                BTFSS 04,4      ;bit 4 will be HIGH when  20h is reached
                GOTO ClrRAM

See the chapter "Things you may want to do" to see how to transfer bytes from a table and place them in a set of files.

This is just about all the tricks you need to know about programming. It's just a matter of using them to do almost anything you want.
All sorts of complex effects and results can be produced by simply connecting devices to the micro and writing the program.
We could continue for 100 more pages but it's best to go to the projects we have already written to see how some of the things are done. You can start with the 10 test programs for the '508A Proto-1 Module.  These are very simple and continue on from this discussion.

Everything you do in electronics should be documented so you can come back at a later stage and carry on as quickly as possible.
This is even more important with programming as much of the thought that goes into producing the code is not evident in the code itself.
You may come back and say "Why did I load a file with 3E?" Or "Why did I set bit7 of file 1F?"
Unless you add notes after each instruction, you may find the reason escapes you. Comments will also help anyone else who has to take over the project or maybe trouble-shoot a bug.

Most programs are written as a Main Routine and a number of sub-routines. This is the standard way of presenting a program and it makes diagnosis easy as the sub-routines are designed to perform a single task and this is how you simplify the operation of a program.
The only point to remember is the stack is 2-high and this means you should only have a Main routine with CALL instructions. You can have a sub-routine with a further CALL but this is the maximum number of "CALLs calling a CALL," for the '508A.
Don't be mis-led. The Main routine can have as many CALL instructions as you need as each CALL will go to a sub-routine and at the end of the sub-routine a RETURN will cause the stack to go to zero. A CALL and RETURN uses the stack once then removes the value on the stack so it is empty for the next CALL and RETURN. See the chapter: "More on the '508A."

All the instructions for the '508A are presented in the "PIC12C508 Instruction Set" chapter. There is only about 33 abbreviated words to remember (called mnemonics) plus a value of "0" if you want the
result to be stored in the W register or "1" if the result is to be stored in the file involved in the instruction.
A full definition of each instruction is also provided in the chapter following the Instruction-Set and this will help you understand what each instruction does.

A few examples are:
ADDLW - ADD Literal and W
DECFSZ - Decrement a file and skip the next instruction if the file is zero.
NOP - No Operation
SWAPF - Swap the nibbles in the file
TRIS - Load the TRIS file
XORWF - Exclusive-OR W with the file.

But the only way to really understand an instruction is to see it in a program such as in the projects at the end of this book.
A suggested way to layout a program is provided in the Library of Routines under "Program Template."
It shows how to layout a program with "Equates" from 0C to 1F. Each time you use a file for counting or temporary storage of information, you simply give the file a name (such as tone1, clock, bluBox, etc) and write the name in the Equates section.
After the equates section is the actual program. The first word the compiler wants to see is "ORG" for origin and a value such as 000. This means the program will start at address 000. The program is now
"tied down" to starting at address 000.
After ORG we place the "SetUp" routine. It firstly sets up the TRIS register and this defines if the lines (bits) of file 06 are to be input or output. The SetUp routine then puts a 1 (HIGH) or 0 (LOW)
on the required lines of file 06h.
Next, any tables used in the program are placed at the beginning of memory so they don't go over address location 0FF (256 bytes down the page).
The sub-routines are next and must include a RETURN statement at the end of each sub-routine.
Finally, the Main routine is written after all the sub-routines. This might appear to be an unusual way to set out a program but most Main routines consist of CALLs to the sub-routines and it simply links
everything together in one giant loop.
An "End" statement tells the compiler to cease compiling. It is not converted to machine code for the micro.

When you are ready to start writing the program, it should be written in an exercise book with labels or tags in an imaginary first column, mnemonics (instructions) in the second column and comments in the third column.
Copy everything onto a template in the NOTEPAD program included in the disk-set: "508A Programming Disks," supplied with this course and you are ready to burn the program into a Pseudo'508A chip using the Gang Burner.
Refer to the separate chapter on burning a '508A using our Windows Program and the chip is ready for fitting into either the '508A Proto-1  Module or '508A Express-6v Module.

So far we have dealt with the program side of a project, but there is an equally complex side called the hardware.
This is the circuit, components and layout and you have to be equally competent in this area to get a project working.
Although we have said the hardware side of a micro project is considerably simpler than designing with discrete components, we could write a book on the technicalities of interfacing components.
Fortunately we have provided a lot of technical information in the 25 books already published by Talking Electronics and if you have been reading them and building the projects you will already understand
a lot about the technical side of connecting devices together.
We have also presented some projects in this issue showing how to connect input devices and convert analogue signals to digital amplitude and how to interface a shift-register and binary counter to expand
the output lines.
The Library of Routines also has information on how to connect one or more switches to an input line.
Use the circuits already presented to help you in this area and keep things simple if you are starting-out.
Do everything one-small-step-at-a-time." When each stage works, you can add a new feature and gradually build-up your design.
When it comes to wiring up the '508A, it's handy to know the pin numbers increment in an anti-clockwise direction, as with all chip numbering, and the in/out lines increment in a clockwise direction.
The positive supply for the chip is connected to pin 1 and the ground (negative) to pin 8. This is the reverse to normal supply rails and is shown at the beginning of this chapter. Some of the pins are also
used for programming and external clock and these are identified in the "508A chapter."

'508A Proto-1 Module
The '508A Proto-1 Module comes with a number of input/output devices on the PC board as well as a small prototyping area of holes and pads so you can construct your own circuit.
While the project is in the development stages, burn the program into the Pseudo'508 using the Gang Burner and plug it into the '508A Proto-1 Module. When you are satisfied with the program, burn a real '508A chip and fit it into the 8-pin socket on the Proto-1 Module for a finished product.

'508A Express-6v Module
If the Proto-1 development area is not large enough, the '508A Express-6v Module has a 22 x 22 hole matrix for prototyping and an 8-pin IC socket for the '508A chip.
This will allow you to layout the circuit exactly how you want it in the final version and it's simply a matter of copying the layout when making the PC board.
The chapter "Converting Ideas to PIC" and "Converting Circuits to PIC" will help with designing a circuit.

 '508A Express-3v Module
If you want a PC board for a really small project, the '508A Express-3v Module is the answer. It fits on top of a two-cell battery holder (with inbuilt switch) but the board has been mainly designed so it
can be cut to size and fitted into a small case with a 3v lithium cell.

The final stage in getting a project operational is combining the software and hardware. This can quite often be the most difficult and frustrating part of the operation as a bug may appear and the project will fail to work.
We have produced a chapter "Debugging '508A Programs" to assist in this area but no amount of assistance will help if you don't know where to start or how to go about investigating the problem.
All I can say is follow my rule.
Take time off to think about the problem. Try to work out if the fault is in the software or hardware, then "home-in" by simplifying the project.
Remove some of the components or prevent some of the program being accessed. Remove some of the CALL or GOTO instructions by placing a delimiter ";" at the front of the instructions thus:

Main       MOVLW 01     ;Load W with 1
              MOVWF 06      ;Move W to file 06
              ;CALL Delay     ;Create ON time
              ;MOVLW 00
              ;MOVWF 06     ;Create OFF time
              ;CALL Delay
              GOTO Main     ;Loop Main routine

and it will not be included in the program when it is assembled.
You can even burn another Pseudo'508 with the reduced program. If the problem still persists, go back to basics and start all over again with a "StartUp" routine and a simple Main routine using say one switch and one LED on the '508A Proto-1 Module.
Get this simple routine working and gradually included more routines until the whole project is reassembled.
The main thing is: Don't give up. We have provided a complete range of tools and accessories to get your program working and there is nothing that succeeds like success.
Don't consider yourself fully versed in programming unless you have read this book from cover to cover as many important points are HIDDEN in its chapters. Like clearing the port file (file 06) before running
a program as any junk in the file will turn on the transistors being driven by the lines. You can find this hint in the Library of Routines, under "SetUp."

For '508A:

SetUp     MOVLW xx
               TRIS 06
               CLRF 06            ;Removes junk

For Pseudo'508A:

SetUp     BSF 03,5
               MOVLW xx
               MOVWF 06h       ;Load TRISB file
               BCF 03,5
               CLRF 06             ;Removes junk

The possibility of a hardware problem (like incorrect wiring or poor layout) can be reduced by using a PC board from one of our projects.
We have a wide range of boards and these will give you a number of choices for input/output devices, from one to fourteen push-buttons and various displays, from LEDs to a 7-segment display.
If a board does not suit exactly, it can be modified by cutting the tracks and connecting the components with fine tinned copper wire.

Don't try and be too clever with programming. Sometimes you can eliminate an instruction by using an existing value in a file to perform another operation.
For instance, the Main program for the Flashing LED can be reduced in length by clearing and incrementing (make 1) the port line GP0:

Main        CLRF 06h         ;Clear file 06
               CALL Delay      ;Create OFF time
               INCF 06,1        ;Make GP0 HIGH
               CALL Delay      ;Create ON time
               GOTO Main      ;Loop Main routine

This only allows a LED on GP0 to be accessed whereas the original program allows the LED to be paced on any line (and the program adjusted accordingly).
The more thought you put into creating clever instructions, the more difficult it will be for someone else to debug anything that doesn't work.
Try to use routines that have been described in the Library of Routines or one of the projects.
Don't create too many sub-routines. A sub-routine with one or two instructions is not worth producing and makes it very difficult when checking through the program.
In addition, if you have a routine such as a beep routine, mark it clearly and don't hide it.
I am looking at a programmers work at the moment and cannot find the beep routine, although it says GOTO Beep. I don't know if it has been left off the hard-copy or cleverly integrated into the sub-routines.
Try to avoid tricks like this. The only person to suffer from "tricky" programming will be yourself, when you come back to the program and have to recall how you structured the program.

Here are 3 clever routines that use the bits in a file to create a special feature:
1. If you are short of files, the flag file (1E or 1F) can be used as a "count" file by loading it with a value of 01 to 0F and decrementing it to zero. By making bit 4 HIGH, bits 5, 6 and 7 can to used as additional flags and are not affected. The file becomes: 0001 1111 with the sub-routine looking for "0" in bit 4. The file can be decremented and after sixteen passes, bit4 becomes zero and the program can branch to another sub-routine.
2. A file emerges from a DECFSZ instruction with zero contents. In the delay sub-routine below, the file enters the routine with an unknown value on the first pass but on the SECOND pass the file will be zero (provided it is not used in any other routine). This means the routine will produce the longest delay. The same applies to nested routines.

DelA           DECFSZ 0C,1
                  GOTO DelA

3. We mentioned not to create a routine, such as a Beep routine, without clearly marking its existence.
But in fact a beep routine can be hidden within a routine that is doing other things such as looking at an input line for the press of a button.
To produce a tone for a piezo, a line needs to be toggled approx every milli-second. This gives a delay of about 1,000 machine cycles between every toggle operation and this interval of time can be used to look at an input. If the piezo is on GP0 and the switch on GP3, a routine can be produced thus:

Button         CALL S_Del         ;Call short delay
                    BTFSS 06,3
                    GOTO Below
                    MOVLW 01          ;Put 01 into W
                    XORWF 06,1        ;Toggle GP0
                    GOTO Button

S_Del          - - - - -


Below          - - - - -

* See Flynn of the Inland - Australia's pioneer radio doctor of the Inland.