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