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