PROGRAMMING
PIC CHIPS
Part II


Page 14
INDEX

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 to “waste time.”
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. The DECFSZ 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
MOVLW 00
MOVWF 0C

DelA   

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

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

DelA    

 DECFSZ 0C,1
GOTO DelA
DECFSZ 0D,1
GOTO DelA
RETLW 00

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:

1/2-SECOND 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
RETLW 00
The last step is to create "SetUp" and the Main routine.

SetUp

MOVLW 3E ;Make GP0 output
MOVWF 06h ;Load TRISB file
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
RETLW 00

Main

MOVLW 01 ;Turn on LED
MOVWF 06 ;Output a HIGH to file 06
CALL Delay ;Create ON time
MOVLW 00
MOVWF 06 ;Turn off LED
CALL Delay ;Output a LOW
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 RETLW 00 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, RETLW 00 and GOTO as well as DECFSZ instructions. This is how a program keeps the micro looping.

THE IN/OUT PORT  AND THE TRIS REGISTER
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 for the chip.
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 and “0” if it is LOW. It is better to test each line individually e.g: BTFSS 06,0 for GP0.

USING A TABLE
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 ;Add W to the Program Counter

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 is needed.
At Table1, the instruction ADDWF 02,1 adds the jump value to 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.

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

DIRECT 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
Relative Addressing involves changing the contents of the Program Counter. Using a Table involves Relative Addressing. See Library of Routines.

INDIRECT ADDRESSING
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,5 ;bit 5 will be HIGH when 20h is reached
GOTO ClrRAM

GOING FURTHER
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.

DOCUMENT EVERYTHING
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.

CALLS AND RETURNS
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 for a ‘508A 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."
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 RETLW 00 will cause the stack to go to zero. A CALL and RETLW 00 uses the stack once then removes the value on the stack so it is empty for the next CALL and RETLW 00.

ALL THE INSTRUCTIONS
All the instructions for the '508A are presented in the "PIC12C508A Instruction Set." There is only about 33/36 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.
The only way to really understand an instruction is to see it in a program such as in the projects on this site.
A suggested way to layout a program is provided in the Library of Terms and 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 or 0 on the required lines of file 06h to make them HIGH or LOW.
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 RETLW 00 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.

BURNING A CHIP
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) are placed in the second column and comments in the third column.
Copy everything onto a template in NOTEPAD and you are ready to burn the program into an F84 chip using the PIP-02 program and 5x7 Display.
Refer to the 5x7 Display project for more details on burning a chip.
The chip is now ready for fitting into the Pseudo 508A module.

THE CIRCUIT
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 have provided a lot of technical information in the projects in this book.
The Library of Terms 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. Some of the pins are also used for programming and external clock and these are identified on page 21.

'508A 6v Express Module
The 12c508A 6v Express 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.

FINALLY
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.
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 and they will not be included in the program when it is assembled:

Main

MOVLW 01  ;Load W with 1
MOVWF 06
;CALL Delay ;Create ON time

;MOVLW 00

;MOVWF 06
;CALL Delay  ;Create OFF time
GOTO Main  ;Loop Main routine.

You can even burn another chip with the reduced program. If the problem still persists, go back to basics and start over again with a "StartUp" routine and a simple Main routine using say one switch and one LED.
Get this 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 Terms and Routines, under "SetUp."

  For a '508A or F84:

SetUp

MOVLW xx
TRIS 06
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.

TOO CLEVER!
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.

BIT MANIPULATION
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 be 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
RETLW 00

3. We mentioned that you should not 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 like this:

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

 - - - - -
 - - - - -
RETLW 00

Below

 - - - - -
 - - - - -


NEXT