|
|
RE-CAPPING
Page 17
INDEX
This section goes over some of the PIC Programming theory we
covered in the previous chapters.
INTRO
The PIC12c508A and PIC16F84 have a lot in common. Almost all the instructions
are the same and you only have to remember about 35.
The full list can be viewed by clicking:
PIC12C508A
and
PIC16F84. They can also
be printed-out.
This part of the course covers the PIC12C508A and is suitable for projects
requiring up
to 5 outputs. For larger projects, the
PIC16F84 will be suitable.
We have already explained the difficulty in experimenting with the PIC12c508A.
It is a one-time programmable chip and if a project takes 50
"changes" to get it operational, you will need 50 or more chips. But
the answer is to take our approach.
Our method is to use a re-programmable PIC16F84 to hold the PIC12c508A code and
when the program is running correctly, a single PIC12C508A can be
"burnt."
This saves lot of cost and frustration.
When you read through the previous chapters of this course you will find how to
combine two or three items (such as LEDs, microphones, speakers etc) on a single line and you will get some idea of the
size of a project you can design with a PIC12C508A.
You will be amazed what can be done with a microcontroller and if you are thinking
of commercialising your idea, nothing could be better than using one of our
selection: PIC12C508A or PIC16F84.
With this in mind, here is how to go about creating the program:
Remember, the PIC12C508A is the target chip (this is where the program will be
placed when it is running perfectly), and the PIC16F84 is the chip we use to
hold the program during the designing stages.
START FROM THE
BEGINNING . . .
This chapter has been prepared for readers like Mr Nat. Joseph of Enja Manufacturing.
He needs to design an intelligent battery charger. He has been designing and
producing 12/24v 500VA and 1kVA battery chargers for the past 45 years. But he
needs something that is "fool-proof". Something that will detect
"reverse connection" and "flat-battery" charging.
In Nat's case, he needs an A-to-D converter and this will be covered later. The
rest of the programming will be covered in this section.
This is
only one of a thousand requests for a PIC design and we have kept the
discussion simple to get everyone started.
You may have seen lots of sites and companies offering PIC Programming
courses. When you look into them, they all cost a fortune and require special modules to hold the
program. Nearly all the courses don't have anything to do with PIC
programming. They merely use a PIC chip as the transport medium. Their
"programming" or "designing" techniques don't involve
machine language at all and you are not learning anything about PIC
programming. There is no comparison between them and us.
It may be easier to program in BASIC but it's a bit like getting you to build a
radio with plug-in modules with "Part A," "Part B" on
them. We teach you the electronics side of things.
Believe me, programming in machine language is no more difficult than in an
interpreter language such as BASIC. Any form of programming requires an
understanding of the rules and remembering terms. The advantage of machine code
is flexibility. With Machine Code you can do anything the micro is designed to carry out and the
cost is the lowest. To produce a project for commercialisation, you have to
keep the cost to a minimum. You have to do it via machine code. That's what this
course is all about.
With this, let's start:
THE PROGRAM
A program is written one-line-at-a-time. Each line is called an INSTRUCTION
and consists of letters and
numbers. The line reads like a miniature sentence. Go to the instruction sets: PIC12C508A
and
PIC16F84 to see how
to read each line. When letters represent words, it is called a mnemonic. A mnemonic
is designed to be easily read and all the instructions are easy to read.
A program is laid out in three columns. The first column contains the LABELS.
These are 3 or 4 letter words and are placed at the beginning of each
sub-routine so the micro can go to a sub-routine and carry out the
instructions.
The second column contains the INSTRUCTIONS. These are the mnemonic instructions
mentioned above.
The third column contains the COMMENTS. These are the notes you provide
when writing each instruction to remind you what each instruction is doing.
Before each instruction is a semi-colon ";" When the program is being
ASSEMBLED (the mnemonics converted to machine code values) the comments are
ignored.
You can write a program on a blank page in a program such as TextPad or NotePad and create your own columns but hidden characters such as "blank
space" and "line return" sometimes corrupt the operation of
ASSEMBLY and it's better to use one of our TEMPLATES (Click
HERE for the
Blank84.zip file).
THE FILES
The first thing you will want to know is the files you can use.
The twenty files that are common to both chips are: 0C, 0D, 0E, 0F, 10h, 11h,
12h, 13h, 14h, 15h, 16h, 17h, 18h, 19h, 1A, 1B, 1C, 1D, 1E, 1F.
For the PIC12c508A, the first seven files are Special Function
files: Special Function Registers (SFR's)
File: 00 is INDF (Indirect File)
File: 01 is TMR0 (Timer 0)
File: 02 is PCL (Program Counter LOW bits)
File: 03 is STATUS
File: 04 is FSR (File Select Register)
File: 05 is OSCCAL (Oscillator Calibration)
File: 06 is GPIO (General Purpose In/out lines) GP0, GP1, GP2, GP4, GP5. (GP3 is in-only.)
THE INPUT/OUTPUT PORT
The input/output port common to both chips is file 06. The PIC16F84 has
another port (file 05) but this is not common to the PIC12C508A. Only the
lowest 6 bits of file 06 are common. For the PIC12C508A, these lowest bits
are called GP lines. They are called: GP0, GP1, GP2, GP3, GP4, and GP5.
Note: GP3 is an input-only line. For the PIC16F84, the lowest bits
are called: RB0, RB1, RB2, RB3, RB4 and RB5. (lines RB6 and RB7 on the PIC16F84
are not on the PIC12C508A and thus we cannot use them if you want your program to be available for the
PIC12C508A). When programming, the lines are addressed as:
06,0 06,1 06,2 06,2
06,4 and 06,5
There are 4 things you can do with each
line:
1. Test and skip if it is LOW:
The instructions are: BTFSC 06,0 BTFSC
06,1 BTFSC 06,2 BTFSC
06,3 BTFSC 06,4
BTFSC 06,5
2. Test and skip if it is HIGH:
The instructions are: BTFSS 06,0 BTFSS
06,1 BTFSS 06,2 BTFSS
06,3 BTFSS 06,4
BTFSS 06,5
3. Make it HIGH:
The instructions are: BSF 06,0 BSF 06,1 BSF
06,2 (bit 3 is input-only for the
PIC12C508A)
BSF 06,4 BSF 06,5
4. Make it LOW:
The instructions are: BCF 06,0 BCF 06,1 BCF
06,2 (bit 3 is input-only for the
PIC12C508A)
BCF 06,4 BCF 06,5
This is called bit manipulating. In other words the bits of the
file are made HIGH, LOW or tested. The whole file can
also be cleared, moved, rotated, and the logic operations such as AND, OR,
XOR can be performed on the file, as well as ADD, COMplement, INCrement,
DECrement, SUBtract and SWAP nibbles.
The easiest way to operate on the input/output file is with bit
manipulation. The file is cleared at the beginning of the program and
then each bit can be made HIGH, LOW or tested etc.
Before you can set, clear or test a bit on the
input/output file 06, it must be configured so that the bits
are either input or output. This is done via the TRIS file. You can have any arrangement at all for
the 6 bits, as any bit can be either input or output and the bit can be
changed at any time during the running of a program. The only thing you
have to remember is bit 3 for the PIC12C508A can only be an input and
thus it must be programmed as "1".
Setting the bits to input or output is done via the
TRIS file. Making the lowest bit of the TRIS file "0", will make line GP0
(RB0) an output. Making the lowest bit of the TRIS file "1", will make line
GP0 (RB0) an input. You can have any combination for the 6 lines, but make
sure bit 3 of TRIS is "1" so that GP3/RB3 is input. Bit 3
of TRIS is: 0000 1000
To make GP0/RB0 HIGH, two operations
must be carried out.
1. The lowest bit in the TRIS file must be made "0" so that the line
is an output.
2. The lowest bit in file 06 must be SET (to make the output line HIGH)
Here are the 3 instructions:
|
MOVLW 00
|
;(the lowest bit must be 0 -
other bits can be 0 or 1, for the other in/out lines)
|
TRIS
06
|
;(TRIS is loaded with 00)
|
BSF
06,0
|
;(the lowest
bit must be "1" to make GP0 HIGH)
|
To read GP3/RB3, two operations must be
carried out.
1. Bit 3 in the TRIS file must be made "1" so that the line is an
input.
2. Read bit 3 of file 06. The "read" operation does not have a direct
instruction. The closest instruction is "test". The input line can be
tested and if it is HIGH (SET), the micro will skip the next
instruction.
Here are the instructions:
|
MOVLW 08
|
;(bit 3 must be 1 - the
other bits can be 0 or 1, for the other in/out lines)
|
TRIS
06
|
;(TRIS is loaded with 08)
|
BTFSS 06,3
|
;(bit 3 of the input/output
port is tested to see if it is HIGH)
|
GOTO Below
|
;(the micro will go here if the
input line is LOW)
|
xxxxxxxx
|
;(the
micro will go here if the input line is HIGH)
|
A switch is connected to input line GP3/RB3 as shown in the diagram
below:
To check when the switch is pressed, a sub-routine is created and this
routine is "CALLED" on a regular basis. This is called "polling
the switch". When the switch is detected, the sub-routine puts a
"flag" in a register and returns to the Main routine. The Main routine
then checks the "flag" and carries out further operations.
We suggest using file 1F to store the flags. File 1F must be cleared
at the beginning of the program so that each bit can be set or cleared. File 06
(the input/output port) must be set up so that GP3/RB3 is an input line. This
has been coved above via the TRIS file.
|
Here is the sub-routine to check the switch:
|
Sw1 |
BTFSS 06,3 |
;Check input line to see if it is HIGH |
|
GOTO Sw1A |
;Input line is LOW |
|
BSF 1F,0 |
;Set the flag bit |
|
RETLW 00 |
;Return to Main routine |
Sw1A |
BCF 1F,0 |
;Clear the flag bit |
|
RETLW 00 |
;Return to Main routine |
|
The sub-routine must be "transparent". In other words it must be
able to be CALLED from any routine, carry out an operation and return to
the routine. The switch sub-routine (Sw1) should not go to a particular part of the
program if the switch is pressed as this will cause a lot of problems with the
"stack" and it will be difficult to keep track of the execution of
the program. It should return to the same routine that called it. This
satisfies the stack requirement. Two other things must be processed to detect the
switch closure (these are called switch bounce and switch detection -
a flag that detects the switch is pressed for the FIRST time) and these will be covered later.
LOADING A FILE WITH A VALUE
It takes two instructions to load a file with a value. You cannot place a number directly into
a file.
To load a file with a value, the number (called a literal) is placed into the
working register called "W".
The number is then moved from W to the file.
The instruction to put a number into W is: MOVLW.
This means: MOVe a Literal into W. The literal can be 00 to
FF. The numbers 00 to FF are called hex (for hexadecimal - meaning base
16).
The instruction to do this is: MOVLW 00 to MOVLW FF
The number is then moved from W to the file.
The instructions is: MOVWF 0C to MOVWF
1F (where 0C to 1F are the files we use to store our program).
To put 6A into file 1C, the instructions are:
MOVLW 6A
MOVWF 1C
A file can be incremented or decremented via the following instructions:
INCF, DECF.
e.g: INCF 1C,0 (the result is placed in W)
INCF 1C,1 (the result is placed in
the file)
DECF 1D,0 (the result is placed in W)
DECF 1D,1 (the result is placed in
file 1D)
A file can be altered (incremented or
decremented) by setting or clearing a bit. This requires an understanding
of hex and only one bit can be set or cleared per instruction.
A file can be doubled via the RLF instruction
A file can be halved via the RRF instruction
THE DELAY
- THE TIME-DELAY
Nearly every program will require a delay routine.
Some programs will require both a short delay and a long delay. To
to increase the
length of a delay, it can be called a number of times. The Library of Terms and
Routines contains all you need to know on delays but here is a simplified
summary.
A delay is a "do-nothing" routine and requires at least one
file. The shortest delay is a NOP instruction in a program
but this takes only 1 microsecond to execute. This may be sufficient for some situations
but most require a longer delay.
The simplest delay is:
|
Del |
DECFSZ 1A,1 |
;Decrement
file 1A |
|
|
GOTO Del |
|
|
|
RETLW 00 |
;Return when
file 1A is zero |
|
The simplest delay |
It uses the DECFSZ instruction. The micro decrements the file and tests it for
zero. If it is not zero, the micro executes a loop in the delay
sub-routine and this takes a short time to perform. The micro comes out of
the delay sub-routine when the file is zero.
If the file is not be pre-loaded, the length of the delay is unknown on the first
execution. This generally occurs at the beginning of a program and will not be
noticed. The file leaves the sub-routine with "00" and when the sub-routine is
called the second time, it produces 256 loops. Each loop takes 3
microseconds and this produces a total length of time of 255x3 + 4 = 769
microseconds. This time is very short in human terms.
1 MILLISECOND DELAY
Here is a 1millisecond delay that doesn't use a file. It uses only the W
register (The Working register or Accumulator as referred to when using other
microprocessors). It is much more complicated to understand than the DECFSZ
instruction used above.
|
Del
|
MOVLW 0F9h
|
;Load W with 249
|
|
|
NOP |
|
|
|
NOP |
|
|
Del1 |
ADDLW 0FFh
|
;Subtract 1 from W
|
|
|
BTFSS 03,2 |
;Test Z bit in Status file.
Skip when zero |
|
|
GOTO Del1 |
;Loop |
|
|
RETURN |
|
|
A simple 0-file Delay = 1 millisec (uses only W)
|
The routine consists of 248 x 4 microseconds + 1 x 3 microseconds + 3
microseconds entry + 2
microseconds for Return.
The instruction SUBLW 1 subtracts W from one, not the reverse. To subtract
one from W you add the two's compliment of 1 which is 0FFh, and the instructions
is: ADDLW 0FFh. The routine is testing the zero bit, (Z) in the STATUS register which will be set
when the subtraction results in zero. The bit test takes 1 microsecond unless the skip is taken, in which case
it takes 2 microseconds.
A LONGER DELAY
If you need a delay to view a display or flash a LED, the total number of
microseconds will be about 250,000 or more.
This requires two files.
The two files are placed so that one file is inside the other file. This is
called a Nested Loop. File 1A is the inside file and file 1B surrounds it.
Files 1A and 1B will be zero on the second execution of the particular file and
file 1A is firstly decremented to zero. The micro advances to file 1B and it is
decremented by a count of one. File 1A is decremented again 256 times and the outer
file is decremented again. This continues until file 1B reaches zero. The
delay below produces a delay of about 196,000 microseconds (0.196 sec).
|
Del
|
DECFSZ 1A,1
|
;Decrement
file 1A
|
|
|
GOTO Del |
|
|
|
DECFSZ 1B,1
|
;Decrement file 1B
|
|
|
GOTO Del |
|
|
|
RETLW 00 |
;Return when
file 1B is zero |
|
A simple 2-file Delay = 0.196sec
|
A delay can be increased by adding a NOP instruction to the inner loop. The
inner loop above takes 3 microseconds and each NOP adds 1 microsecond.
The routine below produces a delay of 260,614 uS, by simply adding a single NOP.
Note the placement of the NOP instruction. It must be placed before the DECFSZ
instruction. It cannot be placed after the DECFSZ instruction as this will
prevent DECFSZ working correctly. DECFSZ must
have two different "GOTO" instructions after it so that two
decisions can be carried out.
|
Del
|
NOP
|
|
|
|
DECFSZ 1A,1
|
;Decrement
file 1A
|
|
|
GOTO Del |
|
|
|
DECFSZ 1B,1 |
;Decrement file 1B |
|
|
GOTO Del |
|
|
|
RETLW 00 |
;Return when
file 1B is zero |
|
A 2-file Delay with extra NOP
|
To show the effect of adding more NOP instructions, the routine below has
5 NOP's. The total time delay is 521,989uS. This is approx 1/2sec.
|
Del
|
NOP
|
|
|
|
NOP
|
|
|
|
NOP
|
|
|
|
NOP
|
|
|
|
NOP
|
|
|
|
DECFSZ 1A,1
|
;Decrement
file 1A
|
|
|
GOTO Del |
|
|
|
DECFSZ 1B,1 |
;Decrement file 1B |
|
|
GOTO Del |
|
|
|
RETLW 00 |
;Return when
file 1B is zero |
|
A 2-file Delay with 5 extra NOPs
|
For a longer delay, a 3-file routine is needed. It has the same format
as the previous routines:
A simple 3-file delay will produce a delay of 49,974,689uS. This is nearly 50
seconds!
|
Del
|
DECFSZ 1A,1
|
;File 1A = inner
|
|
|
GOTO Del |
|
|
|
DECFSZ 1B,1 |
;File 1B
= middle |
|
|
GOTO Del |
|
|
|
DECFSZ 1C,1
|
;File
1C = outer |
|
|
GOTO Del |
|
|
|
RETLW 00 |
;Return when
file 1C is zero |
|
A simple 3 file Delay = 50sec
|
See Library of Terms and Routines for more details on accurate
time-delays and creating a time-delay to suit a particular application.
The outer file (file 1C) is decremented once. This file has
the greatest effect on altering the time-delay.
A 2-file Delay = 0.196 sec. A 3-file delay is 256 times larger than a 2-file
Delay.
0.196 x 256 = 50 secs.
Any delay between 0.196 and 50 seconds can be produced by pre-loading file
1C with a value from 01 to FF. Each increment will add 0.195 sec to the
delay (Pre-loading with 00 will create the LONGEST delay).
The delay below produces 4 loops of the 2-file delay made of up files 1A and
1B. The delay value is approx 4 x 0.196 = 0.784 sec. Don't
forget, an instruction such as MOVLW 10 is a hex value and must be written as MOVLW 10h.
This will produce 16 loops.
|
Del
|
MOVLW 04
|
|
|
|
MOVWF 1C
|
|
|
DelA
|
DECFSZ 1A,1
|
;File 1A = inner
|
|
|
GOTO DelA |
|
|
|
DECFSZ 1B,1 |
;File 1B
= middle |
|
|
GOTO DelA |
|
|
|
DECFSZ 1C,1
|
;File
1C = outer |
|
|
GOTO DelA |
|
|
|
RETLW 00 |
;Return when
file 1C is zero |
|
A 3 file Delay with pre-load for file 1C
|
CREATING A PROGRAM
We can now combine the above to produce a very simple program. We will be using
a PIC16F84 chip to hold our program as
it is re-programmable. The instructions we use are readable and executable by
both the PIC12c508A and PIC16F84. The in/out port we use is the same for both
chips and the files used are available in both chips.
In fact we have scaled down the instruction-set slightly to the level of a
PIC12C508A and this gives us the possibility of a 511 line program, 5 in/out
lines and one input-only line. The 5 in/out lines can be changed during the
running of the program and sometimes more than one output device can be placed
on a line without interference.
In any case, your first program will not take anything like the full capability
of the chip.
Programs start at the first address in memory (000) and the first thing to do is
set up the in/out control file (TRIS file) so that the 6 lines are either input
or output. This requires only two instructions. The TRIS file is called TRIS 06.
Only the lowest 6 bits of the file are used. The lowest bit (bit 0) corresponds
to GP0, through to bit 5 corresponding to GP5. When a bit is zero (0) it
corresponds to output and a "1" corresponds to input. Don't forget,
bit 3 must be "1" as GP3 can only be input.
For TRIS
file:
0 =
output 1 = input
|
For example: xx00 1000 makes all lines output and GP3 input. The top two
bits are not used.
0011 1000 makes GP0 = output, GP1 = output, GP2 = output, GP3
= input,
GP4 = input, GP5 = input. The two top bits
are not used. The first 4 bits are converted to produce the first hex value in
the instruction and the second four bits produce the second hex
value.
For example: 0011 1000 = 38
0001 1001 = 19
0010 1100 = 2C
0011 1110 = 3E
0000 1000 = 08
The SetUp routine is:
SetUp
|
MOVLW 08 |
;GP0 output, GP3 input |
|
TRIS 06 |
;Load TRIS file |
The next routine to work on is Main. This
goes at the end of all the other routines. Main routine is a loop. Main
calls all the other routines, (called sub-routines) carries out a particular
operation and returns to Main. Many of the sub-routines will require a
delay routine and this is called a "call calling a call".
The sub-routine will call the delay routine and return to the sub-routine. The
micro will end the sub-routine and return to Main. At the end of SetUp,
an instruction is required to take the micro to Main:
SetUp
|
MOVLW 08 |
;GP0 output, GP3 input |
|
TRIS 06 |
;Load TRIS file |
|
GOTO Main |
|
Main consists of instructions that call
sub-routines. Here is a typical Main routine. It carries out small
operations such as loading a file with a value for decrementing, then CALLs a
sub-routine and returns. The microcontroller constantly loops Main.
Main
|
BSF 06,2 |
;Set the Pulser output HIGH |
|
CALL Delay |
|
|
BCF 06,2
|
;Set the Pulser output LOW
|
|
CALL Delay
|
|
|
MOVLW 05
|
;5 loops for file 0E
|
|
MOVWF 0E
|
|
Main1 |
MOVLW 0B0h
|
;B0 loops for file 0D
|
|
MOVWF 0D
|
|
Main2 |
MOVLW 04h
|
;toggle the Logic Pulser output RB2
|
|
XORWF 06,1
|
|
|
CALL Input
|
|
|
CALL TstA
|
|
|
DECFSZ 0Dh,1
|
;B0 loops |
|
GOTO Main2 |
|
|
DECFSZ 0Eh,1 |
;5 lots of B0 loops |
|
GOTO Main1 |
|
|
BCF 06,2 |
;Set the Pulser output LOW |
|
CALL Delay |
|
|
INCF 11h,1 |
;Increment the 1 minute alarm file |
|
MOVLW 40h |
;40h = 64 loops of 1 second = 1 minute |
|
XORWF 11h,0 |
;Is alarm file
= zero |
|
BTFSC 03,2 |
;Test the zero flag |
|
CALL Alarm |
;"turn off Logic Probe" beep |
|
BCF 06,5 |
;Turn off piezo bit |
|
GOTO Main |
|
CONCLUSION
This concludes our re-capping of the chapters to date. Some of the instructions
in Main will not be understood at this stage but the point to note is the
layout of a program.
A program consists of 4 sections:
1. The SetUp routine.
2. Tables.
3. Sub-routines.
4. Main
Keeping to this format will enable you to follow other programmer's work as well
as allow you to come back to your own code at a later date and modify it without
frustration.
Place the sub-routines alphabetically in the program so they can be located
easily and keep the number of sub-routines to a minimum.
It is very disjointing, jumping up and down a program and diving into lots of
small sub-routines. The microcontroller has no problem moving up and down a
program at lightening speed but the human brain is easily distracted. If a
sub-routine is designed to make a decision, the result of a decision is placed
in a file called a "flag" file and returns to Main. An
instruction in Main looks at the flag bit and CALLs the appropriate
sub-routine.
Here is the layout to follow: (this program is only a demo set of
instructions to show you the placement of the labels - Table1 etc)
SetUp
|
MOVLW 08 |
;GP0 output, GP3 input |
|
TRIS 06 |
;Load TRIS file |
|
GOTO Main |
|
|
|
|
Table1 |
ADDWF 02,1 |
;Add W to Program Counter |
|
RETLW 0F5h |
;0F5h
for
500 Hz tone |
|
|
|
DelA |
DECFSZ 1A,1 |
;Decrement
file 1A |
|
GOTO DelA |
|
|
RETLW 00 |
;Return when
file 1A is zero |
|
|
|
TstA |
MOVLW 00h |
;Eliminate file 1E if it is zero |
|
XORWF 1E,0 |
;XOR file 1E with W |
|
BTFSC 03,2 |
;Test zero flag to see if file 1E is zero |
|
GOTO TstA |
;File 1E is zero |
|
RETLW 00 |
|
|
|
|
Main |
BSF 06,2 |
;Set the Pulser output HIGH |
|
CALL DelA |
|
|
BCF 06,2
|
;Set the Pulser output LOW
|
|
CALL TstA
|
|
|
CALL Table1 |
|
|
GOTO Main |
|
Main routine
is a loop. The micro is constantly looping this routine. During the execution of
this routine, the micro goes to the sub-routines and returns back to Main. Each sub-routine
must have a RETLW 00 instruction so that the
micro returns to Main. Main
must have a "GOTO Main" instruction so that the loop is
complete.
This is the basis of all programming.
Any decisions or data that is generated in a sub-routine is stored in flag
register. In other words, a sub-routine should not have branches that send the
micro in other directions as it may be very difficult to get back to
Main. (you may cause stack overflow)
RETurn to Main as soon as possible and have an instruction in Main look at
the flag file and CALL a sub-routine if a condition is present.
The next page contains a test on the
topics we have covered to date . . .
NEXT
|