FLASHING A LED
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
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 - - - - -
- - - - -
Delay - - - - -
- - - - -
Turn on LED (The
instructions to turn on a LED)
Turn off LED (The instructions to turn off a LED)
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:
DelA DECFSZ 0C,1 ;1 machine
;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
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
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
The last step is to create "SetUp" and the Main routine.
03,5 ;Select page1
MOVLW 3E ;Make GP0 output
MOVWF 06h ;Load TRISB file
Delay MOVLW 03
DelA DECFSZ 0C,1
01 ;Load W with 1
MOVWF 06 ;Move W to file
CALL Delay ;Create ON time
MOVWF 06 ;Create OFF time
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.
THE IN/OUT PORT
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
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.
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
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 - - - - -
- - - - -
Table1 ADDWF 02,1
- - - - -
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
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
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
04,1 ;Increment pointer
BTFSS 04,4 ;bit 4 will be HIGH when 20h is
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.
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 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
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.
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) in the second column and comments in the
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
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.
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
06 ;Move W to file 06
Delay ;Create ON time
06 ;Create OFF time
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,
SetUp MOVLW xx
SetUp BSF 03,5
MOVWF 06h ;Load TRISB file
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:
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
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
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
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:
S_Del ;Call short delay
MOVLW 01 ;Put 01 into W
XORWF 06,1 ;Toggle GP0
S_Del - - - - -
Below - - - - -
* See Flynn of the Inland - Australia's pioneer radio doctor of the Inland.