Library of Routines
for PIC12F629
Nearly all these instructions also work with
PIC16F628. Just check on Port value(s) and
first available file.

see: Talking Electronics website
A-E   E-P    P-Z

See the article Start Here with PIC12F629 for helpful programming notes and a map of the files.
The following is a list of sub-routines, ideas, and help for the PIC12F629.  They apply to any project using the PIC12F629.
They can be put into your program and modified in any way -  to suit the input/output lines. 
The "Copy and Paste" version of these sub-routines can be found HERE.
Your program should be created on a template in a text editor such as NotePad, using blank12F629.asm  as a starting layout.  It provides the correct layout and spacing. 
An unusual problem you may get is a failure to compile your program due to hidden formatting/characters. 
MPASM will not produce the needed .hex file if any problem exists in a program but it will produce a .lst file containing the faults. If you open .lst and see unusual mistakes, they will be due to hidden formatting characters. Simply retype all the wording around the mistake (in the .asm file) and the program will compile.  Do not use EditPad as it produces hidden characters.
To use the Library of Routines below, go to the NotePad set of "Copy and Paste" Routines  and "Copy and Paste" them into your program in another NotePad, as needed. 
Additional sub-routines can be found in the PIC Programming Course. This is on the subscription section of the website.

Make sure each sub-routine uses a file (a register) with a name (a hex number) that doesn't clash with any other sub-routine you have created.
Make sure CALLs go to a sub-routine that has a RETURN (use retlw  00) to bring the micro back to the correct pace in the program and create Labels that let you know what the sub-routine is doing.
The following library is presented in alphabetical order. Using these sub-routines will get you started very quickly and will assist you with 70% - 90% of a new project.  
Read through the entire library so you know what is possible.  
Simply think of a word or requirement, go to the word and read about it. Many of the sub-routines are also available in the "Copy and Paste" section.
Paste them into your program and modify them to suit. The micro will take each instruction and carry it out. Make sure you have a RETLW 00 that brings the micro back to Main.
Get each sub-section working correctly before adding more instructions. Gradually build up your program and save it as a NEW NAME so it can be recalled if a major problem develops. Do not save it as the previous name as MPASM will sometimes not assemble it (it will think it has already been assembled and  - do nothing!!) and you will wonder why the improvements do not work!!

Add a value to a File
The PIC12F629 does not have a single instruction to add a number to a file. Two instructions are needed to carry out this operation.

;Put CCh into W
CC will be added to the contents of file "2E."

Add "bits" to a port - turn on bits or "lines."
This is handy when more than one output line needs to be turned on.

;suppose GPIO has bits 0, 1 and 2 HIGH and we need
;   to turn on bit 5
;Put 10h into W - this is bit 5
10h will be added to the contents of file "05."

alternately, bit 5 can be SET

   bsf  GPIO,5

If more than one line needs to be made "HIGH" or "LOW," at the same time, you need to use:

   movlw   xxh
   iorwf     GPIO,1

This is necessary as the PIC12F629 will fail to set two or more lines via the following instructions:

   bsf   GPIO, 0
   bsf   GPIO, 2

The author has found the PIC12F629 will fail to set the second line.

Address a File
This means "to act on" or "work with" a file. It can be to "move a value into a file," "increment a file," "decrement a file" or other similar operation.  Only files can be addressed (the instructions in the program cannot be address or altered). The files we are talking about are the "empty" files from 20h to 5F.  None of the program or the values in the tables can be altered. The values in a table can be accessed and copied by a set of instructions covered in CALL Table.
Typical addressing instructions are:

;Copy file 2A into W
;Decrement file 2A
;Increment file 2A
;will put the increment of file 2A into W but file 2A will not alter!!

Addressing a Set of Files
A number of files can be used to store temporary data, such as the digits or letters of a score-board. 
This is sometimes called a "scratchpad" or "scratchpad area."  The files should be sequential to make programming easy. 
Suppose we have 8 files and need to address them with a simple sub-routine to output the data to a display. The sub-routine is called INDIRECT ADDRESSING. See Indirect Addressing.

Here are some of the common flags and bits.
For the other flags, see
PIC12F629 Data Sheet (.pdf  4,926KB)

bank select:
bsf 03,5
bcf 03,5
selects bank 1 - this is where the OPTION register is accessed.
selects bank 0 - this is the normal programming area
carry 03,0 Test the carry bit:
btfss  03,0  ;skip if a carry-out of the most significant bit has  
assigned to
bsf  Option_reg,3
bsf  81h,3
see: Watchdog timer
Option register is in bank 1
assigned to
bcf  Option_reg,3
bcf  81h,3
Timer0 is in bank 0
GPIO file 05h see input/output port. "Setting the port bits HIGH or LOW"
TRISIO file 85h see "Setting the ports bits input or output"
Status file 03 Contains the carry, bank select and zero flags.
zero flag
zero bit
03,2 zero flag is bit 2 of file 03 (the STATUS file)
1 = The result of an arithmetic or logic operation is zero
0 =
The result of an arithmetic or logic operation is not zero
You can look at bit 2:
btfss 03,2    ; skip if the zero bit is SET

AND - see also Mask
The AND operation will mask any or all the bits in a file. In this way you can "remove" any bit or the upper or lower nibble etc.
The quickest way to perform the operation is as follows:
To mask (remove) the lower nibble, it is ANDed with F0h (written as 0F0h)
To mask (remove) the upper nibble, it is ANDed with 0Fh (can be written 00Fh)

Place the value (say countA) to be operated on, into w:
     movf      countA,w

     andlw    0F0h           ;only the upper 4 bits will be in w.

     - see also Pseudo Instructions

$ Current/Return Program Counter goto $ + 3
( Left parenthesis 1 + ( d * 4)
) Right parenthesis (length + 1) * 256
! NOT (logical complement) if !  (a == b)
Negation (2's complement) 1 * length
~ Complement flags = ~ flags
* Multiply a = b * c
/ Divide a = b / c
% Modulus entry_len = tot_len % 16
+ Add tot_len  = entry_len * 8 + 1
Subtract entry_len = (tot 1) / 8
<< Left Shift flags = flags << 1
>> Right Shift flags = flags >> 1
>= Greater or equal if entry_idx >= num_entries
> Greater than if entry_idx > num_entries
< Less than if entry_idx < num_entries
<= Less or equal if entry_idx <= num_entries
== Equal to if entry_idx == num_entries
! = Not equal to if entry_idx ! = num_entries
& Bitwise AND flags = flags & ERROR_BIT
^ Bitwise EXclusive OR flags = flags ^ ERROR_BIT
| Bitwise Inclusive OR flags = flags | ERROR_BIT
&& Logical AND if (len == 512) && (b == c)
| | Logical OR if (len == 512) | | (b == c)
= Set equal to entry index = 0
+= Add to, set equal entry index += 1
= Subtract, set equal entry index = 1
*= Multiply, set equal entry index *= entry_length
/= Divide, set equal entry total  /= entry_length
%= Modulus, set equal entry index %= 8
<<= Left shift, set equal flags <<= 3
>>= Right shift, set equal flags >>= 3
&= AND, set equal flags &= ERROR_FLAG
| = Inclusive OR, set equal flags | = ERROR_FLAG
^ = EXclusive OR, set equal flags ^= ERROR_FLAG
++ Increment i ++
Decrement i  

The following routine will produce the average of 4 values. Result in: Average and Average+1.

cblock h'20' 	;start of general purpose registers
Buffer:8 		;Buffer has 8 files
Average:2 		;Average,      Average+1 will contain overflow

	movlw Buffer 	;get Buffer address
	movwf FSR 	;point FSR at Buffer
Av 	call GetADC 	;read the ADC
	bsf STATUS,RP0 	;bank 1
	movwf ADRESL 	;get the low byte
	bcf STATUS,RP0 	;back to bank 0
	movwf INDF 	;store in buffer
	incf FSR,F 	;and point to next location
	movwf ADRESH 	;get high byte
	movwf INDF 	;and store it
	incf FSR,F 	;point to next location
	movfw FSR 	;see if FSR has reached
	xorlw Buffer+8 	;the end of the buffer
	movlw Buffer 	;prepare to reset FSR
	btfsc STATUS,Z 	;if it's at the end
	movwf FSR 	;reset it

	movfw Buffer 	;move first value to average
	movwf Average
	movfw Buffer+1 	;and high byte
	movwf Average+1

	movfw Buffer+2 	;add second value
	addwf Average,f 	;first low byte
	btfsc STATUS,C 	;if there was an overflow
	incf Average+1,f 	;increment high byte
	movfw Buffer+3 	;and add in high byte
	addwf Average+1,f

	movfw Buffer+4 	;add third value
	addwf Average,f
	btfsc STATUS,C
	incf Average+1,f
	movfw Buffer+5
	addwf Average+1,f

	movfw Buffer+6 	;add fourth value
	addwf Average,f
	btfsc STATUS,C
	incf Average+1,f
	movfw Buffer+7
	addwf Average+1,f

	bcf STATUS,C 	;divide by 2
	rrf Average+1,f 	;by shifting high byte
	rrf Average,f 	;and then low byte
	bcf STATUS,C 	;divide by 4
	rrf Average+1,f
	rrf Average,f

When writing a program, all your instructions are written in an area called bank0. However some of the registers are in other banks and you need to go to these banks to load data into the selected file (register) or read from the file.
The simplest way to go from bank0 to bank1 is to set rp0 in the status file: 
bsf      status, rp0    
To go from bank1 to bank0 the rp0 bit is cleared: 
bcf      status, rp0  
However you can use a directive that is recognised by the assembler called: banksel
You can use the name of any register in the bank you wish to select with the banksel directive, such as:
banksel       trisA
banksel       trisio

to go to bank0:
banksel      0x00   or 00h

Here is the list of files for a PIC12F629 in bank0 and bank1:

After accessing a file in Bank1, you must go to bank0, by adding the instruction: bcf      status, rp0    or banksel      0x00    to continue with your program.

Beep see Tone
A Beep is a tone of short duration. 

Binary to HEX: see Decimal to Binary to HEX

Binary Hex and Decimal numbers
Any mixture of binary, Hex and decimal numbers can be shown in a program.
Binary numbers are presented as: 0b00000000'  or b'00000000'  or B'00000000' or 00000000b or b'0100' indicates the lowest 4.
Hex numbers are shown as:   0x2    or 0x0F (= fifteen)  or 0x3C or h'  or $ 
or <digits>h (must begin with 0 ....9)
Decimal numbers are shown as:  d'250' 
or decimal numbers without a prefix.

Block Transfer
A block of data can be transferred to another location via the following sub-routine:
12 bytes at address 30h - 3Bh  to transfer to 50h - 5Bh

	movlw	0Ch
	movwf	temp1	;no of loops
	movlw	30h	;start of 1st block
	movwf	04h	;load FSR
	movf	00h,0	;move value looked at by FSR into W
	bcf	04h,5
	bsf	04h,6	;turns FSR 30h to 50h
	movwf	00h
	bsf	04h,5
	bvf	04h,6	;turns FSR 50h to 30h
	incf	04h,1
	decfsz	temp1,1
	goto	$-8
	retlw	00

Button see Switch

bz    - branch on zero flag being set to "1"   See more instructions in "MACRO."

movf   Sw,0
bz      timeout
;Move file "Sw" to W
;If Sw file is zero, the result of moving it to w (or to itself) will
;set the zero flag to "1" and the micro will goto "timeout."

CALL see also Stack
CALL means to branch to, and return from a subroutine. It does NOT mean GOTO. GOTO means to branch unconditionally and maybe not return to the present routine. CALL means to branch to another sub-routine and RETURN to the next address. Every CALL must have its own RETURN or RETLW 00 to 0FFh statement.
Use only RETLW 00.   Do not use RETURN.
When a CALL instruction is executed, the next address-value is placed on the stack and the micro goes to the location identified in the instruction.
Do not "GOTO" a sub-routine that has a RETURN at the end of it. The micro will not know where to return as the GOTO instruction does not put a return address into memory (the stack).
The CALL instruction works to the full 1024 locations in a PIC12F629 chip.

The micro will come to CALL Delay in the sub-routine below. It will then advance down the program to Delay and carry out instructions until it reaches RETURN. The micro will then move up the program to the xxxxxxxxx line. 


CALL Delay
- - - - - - - -
- - - - - - - -
- - - - - - - -


;Put 80h into W
;Copy 80h into file 21A
;Decrement file 21A
;Loop until file 2A is zero

CALL Table   see also Table and Output a Table Value 
The instructions CALL Table uses the value in W and adds it to the Program Counter (PC - location 02 (file 02) - the ,1 indicates the value in W will be placed in the Program Counter file) to create a JUMP VALUE to jump down a Table and pick up a value. The instruction beside each value in a table places the value in W and makes the micro return to the instruction after CALL Table. The next instruction should be to move the value from W to a file.
Call MOVF 2A,0
CALL Table
;File 2A contains 05. Move it to W
;W will return with 6D
;Move 6D to file 2C


ADDWF 02h,1
;Add W to the Program Counter to create a jump. 

Carry  - see also ROTATE for one of the operations involving CARRY.
The carry bit is located in the STATUS register (file 03) and is bit 0. 
The carry bit is SET when the result of an operation is larger than 0ffh.
The carry bit is SET when the result of an operation is less than zero.
It is cleared by the instruction: 
BCF 03,0 - clear bit0 in file 03
Carry is SET by the instruction:
BSF 03,0   

To test the carry:
BTFSS 03,0
GOTO AAA     ;The micro will go HERE if the carry is NOT set.
GOTO BBB     ;The micro will go HERE if the carry is SET.

The carry is also used when a file is rotated left or right.
When a file is rotated left, the MSB (most significant bit (bit 7) is passed into the carry and the carry-bit is passed into the file as bit 0. If you don't want the "carry bit" to affect the outcome of the operation it must be cleared before-hand, thus:
       bcf      03,0

CBLOCK - (define a Block of Constants)
This is a directive used for defining files that will be reserved for an application. The format of  CBLOCK is:

cblock 0x20	;define the start of the files. The first "file" or "register" for a 12F629 is 20h
Lowbyte		;this will be file 20h
Medbyte		;this will be file 21h
Hibyte		;this will be file 22h etc  etc  etc

This method of declaring variables is quite good, but  macros cannot take advantage of it.

The alternative to cblock is:
Lowbyte    equ   20h
Medbyte	equ   21h
Hibyte       equ   22h	

cblock can use other files, starting at say 4Ch:  The 3 files d1, d2 and d3 are files for a
delay routine and are files 4Ch, 4Dh and 4Eh.

cblock 0x4C

Another method of defining files is:

org   20h

save     ds   1
flag       ds   2
count    ds   1
csave   ds    1
temp    ds    2
ontime  ds   1
oftime   ds   1
timer    ds    3
freq       ds    2
mode    ds   1
rate      ds   1
hi         ds   1
low       ds   1
delay    ds   3
The compiler will allow one file (20h) for "save" and two files for "flag."    timer will be given 3 files.

When writing the program, you write the instruction such as     incf    flag,1  for the first flag file and
btfss   flag+1   for the second flag file.

Another way to define fines in cblock:

cblock 0x20	   ;define the start of the files. The first "file" or "register" for a 12F629 is 20h
delay		   ;this will be file 20h
delay2		   ;this will be file 21h
timing,timing3,timing6	   ;file 22h,23h,24h
detect:4                                             ;file 25h,26h,27h,28h    Note ":4"indicates 4 files are needed.


Change Direction 
The direction of an input/output line (or a whole port) can be changed at any time during the running of a program.  The file we are loading or setting or clearing is file 85. It is in Bank 1. This file is called TRISIO.

BSF 03,5
BCF 03,5
;Go to Bank 1
;Make GP1 input
;Go to Bank 0 - the program memory area.

BSF 03,5
BCF 03,5
;Go to Bank 1
;Make GP1 output
;Go to Bank 0 - the program memory area.

See also: SetUp for setting up the Input/Output lines. See Input for the instruction(s) to make a line Input. See Output to make a line Output. Lines are changed by setting or clearing bits of the TRISIO register. This is called BIT MANIPULATION. This prevents touching (and upsetting) other lines.

See Toggle to change the STATE of a line (from HIGH to LOW or LOW to HIGH). 

Clear a list of files (registers)

movlw    StartFile
movwf    FSR
clrf         INDF

incf       FSR,f
movlw   EndFile
subwf   FSR,w
btfss    status,z
goto     ClrLoop
;FSR is loaded with the value of the first file to be cleared
;INDF is file 00 and this command actually clears the file
looked-at by FSR
;advance to next file
;Load FSR with value of End File
;perform a subtraction
;zero bit will be set when result is zero - end file reached

To compare two values, you can use XOR.

To compare two numbers, they are XORed together and if they are the same, the Z flag will be set. Take two numbers: 

number  =  7A    =    0111 1010 
W         =  7A    =     0111 1010 

Starting at the right hand end, ask yourself the question, "Is one OR the other a 1?" The answer is no. The next column. "Is one number OR the other a 1?" No BOTH the numbers are 1! so that's why the answer is NO. In this way every column has the answer NO, when both numbers match. 
When all the answers are Zero, the flag rises! to say the result is ZERO. In other words it is SET. 
To find the zero flag look in the STATUS register, bit 2, i.e. File 03,2. 

e.g: To compare two files: 

                MOVF 2A,0           ;Move one file into W 
                XORWF 2B,0         ;XOR W and 2B 
                BTFSS 03,2           ;Test Z flag  If Z flag is SET (ie 1) the two files are the SAME! 

The same thing can be done by using the subtract operation:

                MOVF 2A,0           ;Move one file into W 
                SUBWF 2B,0         ;Subtract W from 1B 
                BTFSS 03,2           ;Test Z flag  If Z flag is SET (ie 1) the two files are the SAME! 

Z flag is SET (ie 1) when the two files are the SAME!

The contents of a file can be compared with the contents of the working register (W) to determine their relative magnitudes. This is done by subtracting the contents of W from the selected file. By testing the Carry and Zero flags, 4 results can be obtained: 

                MOVLW 22h          ;Put 22h in W 
                MOVWF 3C           ;Move 22h to file 3C 
                MOVLW 15h          ;Put 15h in W 
                SUBWF 3C,1         ;Subtract 15h from 22h 
                BTFSS 03,2           ;Test Zero flag 


                BTFSS 03,0           ;Test Carry flag 

Zero flag is SET if W = File value = Match 
Zero flag is CLEAR if no Match 
Carry flag is SET if a borrow did not occur (W is less than or equal to file value) 
Carry flag is CLEAR if a borrow occurred (W is greater than file value) 

(Put a value into W and perform SUBWF). Test Carry:

More than: Carry flag is CLEAR if W is greater than file value.

Less than: Carry flag is SET if W is less than or equal to file value.

Suppose a file (file 3E) is incremented to 8 such as in the Logic Probe with Pulser. We need to know if the file is 1, 2 or 3. The first thing to do is eliminate the possibility of zero. 

TestA    MOVLW 00h          ;Eliminate file 3E if it is zero, 
             XORWF 3E,0         ;XOR file 3E with W
             BTFSC 03,2          ;Test the zero flag to see if file 3E is zero
             GOTO TestA1       ;File 3E is zero

The SUBWF operation below subtracts the W register (via a process called the 2's complement method) from file 3E and the carry flag in the Option register (file 03) will be SET if 3E is equal to W or more than W (i.e: 4 or more). 

             MOVLW 04            ;Put 04 into W for subtract operation
             SUBWF 3E,0          ;Carry will be set if 3E is = or more than 4
             BTFSS 03,0            ;Test the carry flag 
             GOTO Hi                ;Go to another sub-routine such as "Hi"

Here is the outcome for all the possibilities for file3E:
     If 3E = 0   C = 0  (we have eliminated the possibility of zero via the first 4 lines above)
     If 3E = 1   C = 0  (carry is zero - this is not the CARRY BIT it is the SET (1) or clear (0) indicator)
     If 3E = 2   C = 0
     If 3E = 3   C = 0 (carry is clear)
     If 3E = 4   C = 1 (carry is set)
     If 3E = 5   C = 1
     If 3E = 6   C = 1
     If 3E = 7   C = 1
     If 3E = 8   C = 1

The carry bit in the Option file is bit 0.  Therefore we test bit 0 of file 03:
       BTFSS 03,0
The result in 3E can only be 1, 2, or 3. 

 Config  - configuration
The configuration word is located at address 2007h and is only accessed during programming.
'__CONFIG' directive is used to embed configuration data within .asm file.
Note the double underbar at the front of "config."
Some of the configuration settings:
Each setting has a single underbar and a "&" sign, with a single space between "&" sign.

All configuration settings (sometimes called "fuses") are "set" or "active" when =1.
BUT three are "active" when set =0.  This is called "active LOW" 
They are: CP - Code Protect  = active when = 0
              CPD - Code Protect Data = active  when = 0
              PWRTE - Power-up Timer = active when = 0. 

 Use the following to set the "fuses:"   (easy to read and understand)


By default, all config bits are initialized to "1"

Here is an example of how the configuration word is created:

; ----- Configuration Word -----------
; Bandgap                 11                 Highest voltage (00 lowest voltage) for BOD and POR
; Unimplemented           000              Read as '0'
; Data code protection        1             CPD disabled (0=enabled)
; Code protection                 1            CP disabled (0 = program memory code protection enabled)
; Brown-out detect                 1           BOD enabled (0=BOD disabled)
; GP3/MCLRE                         0          digital I/O, MCLR internally tied to Vdd
; Power-up timer                        1         PWRT disabled (0=PWRT enabled)
; Watchdog timer                        0        WDT disabled (0=WDT disabled)
; Oscillator                                   100     INTOSC I/O on GP4 & GP5
 __config                b'11000111010100'

000  = LP oscillator Low power crystal on GP4 and GP5
001  = XT oscillator  Crystal/resonator on GP4 and GP5
010  = HS oscillator  High Speed
crystal/resonator on GP4 and GP5
011  = EC: I/O function on GP4  ClkIn on GP5

100  = INTOSC oscillator
I/O on GP4 & GP5
101  = INTOSC ClkOut on GP4  I/O on GP5
110  = RC oscillator I/O function on GP4  RC on GP5
111  = RC oscillator ClkOut on GP4  RC on GP5

Copy bits from one file to another
To copy bit3:bit2 from "source" to bit7:bit6 "target"

movlw    b'00111111'
andwf    target,f
swapf    source,w

andlw    b'11000000'
iorwf     target,f
;clear target bit7:bit6
;the lower nibble of source will be swapped with
;high nibble and the result will be placed in w
;only the two top bits of source will remain
;the two top bits of source will be added to "target"

To copy bit3:bit2 from "source" to bit3:bit2 "target"

movf     source,w
andlw    b'00000011'
iorwf     target,f
;move source into w
;only the two lower bits of source will remain
;the two lower bits of source will be added to "target"

If you want to count the number of pulses from a push-button or switch, the easiest way is to increment a file. A file will hold up to 255. The result is stored as a hexadecimal number from 01 to FF.
If you want to count to three, pre-load a file with 3 and decrement it and detect zero.

Data Table - see DT below


Debounce a Button (Switch)
See Switch and Poll

This is not a term used in creating a program in PIC language, however we have two suggestions for finding a "bug" or problem in a program. 
1. Go back to your previously saved version and note the differences in the programs. Try to visually detect the fault. 
2. "Home-in" on the faulty section and see how far the micro is getting through by inserting a Wait instruction. (See Wait)   A LED on an output line will illuminate to indicate the micro has reached the instruction.  

Decimal, Hex and Binary numbers
Any mixture of binary, Hex and decimal numbers can be shown in a program.
Binary numbers are presented as: 0b00000000'  or b'00000000'  or B'00000000' or 00000000b or b'0100' indicates the lowest 4.
Hex numbers are shown as:   0x2    or 0x0F (= fifteen)  or 0x3C or h'  or $ 
or <digits>h (must begin with 0 ....9)
Decimal numbers are shown as:  d'250' 
or decimal numbers without a prefix.


Decimal to Binary to HEX:
00000 00000160001 000010h32 0010 000020h
10000 00011170001 000111h33 0010 000121h
20000 00102180001 001012h34 0010 001022h
30000 0011319 0001 001113h35 0010 0011023h
40000 0100420 0001 010014h36 0010 010024h
50000 0100521 0001 010115h37 0010 010125h
60000 0110622 0001 011016h38 0010 011026h
70000 0111723 0001 011117h39 0010 011127h
80000 1000824 0001 100018h40 0010 100028h
90000 1001925 0001 100119h41 0010 100129h
100000 1010A26 0001 10101Ah42 0010 00102Ah
110000 1011B27 0001 10111Bh43 0010 101102Bh
120000 1100C28 0001 11001Ch44 0010 11002Ch
130000 1101D29 0001 11011Dh45 0010 11012Dh
140000 1110E300001 11101Eh460010 11102Eh
150000 1111F310001 11111Fh47 0010 11112Fh

48 0011 000030h640100 000040h800101 000050h
490011 000131h650100 000141h810101 000151h
500011 001032h660100 001042h820101 001052h
510011 001133h670100 001143h830101 0011053h
520011 010034h680100 010044h840101 010054h
530011 010035h690100 010145h850101 010155h
540011 011036h700100 011046h860101 011056h
550011 011137h710100 011147h870101 011157h
560011 100038h720100 100048h880101 100058h
570011 100139h730100 100149h890101 100159h
580011 10103Ah740100 10104Ah900101 00105Ah
590011 10113Bh750100 10114Bh910101 101105Bh
600011 11003Ch760100 11004Ch920101 11005Ch
610011 11013Dh770100 11014Dh930101 11015Dh
620011 11103Eh780100 11104Eh940101 11105Eh
630011 11113Fh790100 11114Fh950101 11115Fh

960101 000060h1120111 000070h128 1000 000080h
970101 000161h1130111 000171h1291000 000181h
980101 001062h1140111 001072h1301000 001082h
990101 001163h1150111 001173h1311000 0011083h
1000101 010064h1160111 010074h1321000 010084h
1010101 010065h1170111 010175h13310000 010185h
1020101 011066h1180111 011076h1341000 011086h
1030101 011167h1190111 011177h1351000 011187h
1040101 100068h1200111 100078h1361000 100088h
1050101 100169h1210111 100179h1371000 100189h
1060101 10106Ah1220111 10107Ah1381000 00108Ah
1070101 10116Bh1230111 10117Bh1391000 101108Bh
1080101 11006Ch1240111 11007Ch1401000 11008Ch
1090101 11016Dh1250111 11017Dh1411000 11018Dh
1100101 11106Eh1260111 11107Eh1421000 11102Eh
1110101 11116Fh1270111 11111Fh1431000 11118Fh

1441001 000090h1601010 0000A0h176 1011 0000B0h
1451001 000191h1611010 0001A1h1771011 0001B1h
1461001 001092h1621010 0010A2h1781011 0010B2h
1471001 001193h16310100011A3h1791011 00110B3h
1481001 010094h1641010 0100A4h1801011 0100B4h
1491001 010095h1651010 0101A5h18111011 0101B5h
1501001 011096h1661010 0110A6h1821011 0110B6h
1511001 011197h1671010 0111A7h1831011 0111B7h
1521001 100098h1681010 1000A8h1841011 1000B8h
1531001 100199h1691010 1001A9h1851011 1001B9h
1541001 10109Ah1701010 1010AAh1861011 0010BAh
1551001 10119Bh1711010 1011ABh1871011 10110BBh
1561001 11009Ch1721010 11007Ch1881011 1100BCh
1571001 11019Dh1731010 1101ADh1891011 11018Dh
1581001 11109Eh1741010 1110AEh1901011 1110BEh
1591001 11119Fh1751010 1111AFh1911011 1111BFh

1921100 0000C0h2081101 0000D0h224 1110 0000E0h
1931100 0001C1h2091101 0001D1h2251110 0001E1h
1941100 0010C2h2101101 0010D2h2261110 0010E2h
1951100 0011C3h2111101 0011D3h2271110 00110E3h
1961100 010064h2121101 0100D4h2281110 0100E4h
1971100 0100C5h2131101 0101D5h22911100 0101E5h
1981100 0110C6h2141101 0110D6h2301110 0110E6h
1991100 0111C7h2151101 0111D7h2311110 0111E7h
2001100 1000C8h2161101 1000D8h2321110 1000E8h
2011100 100169h2171101 1001D9h2331110 1001E9h
2021100 10106Ah2181101 1010DAh2341110 0010EAh
2031100 10116Bh2191101 1011DBh2351110 10110EBh
2041100 1100CCh2201101 1100DCh2361110 1100ECh
2051100 1101CDh2211101 11017Dh23711100 1101EDh
2061100 1110CEh2221101 1110DEh2381110 11102Eh
2071100 1111CFh2231101 1111DFh2391110 1111EFh


2401111 0000F0h
2411111 0001F1h
2421111 0010F2h
243 1111 0011F3h
2441111 0100F4h
2451111 0100F5h
2461111 0110F6h
2471111 0111F7h
2381111 1000F8h
2491111 1001F9h
2501111 1010FAh
2511111 1011FBh
2421111 1100FCh
2431111 1101FDh
2541111 1110FEh
2551111 1111FFh


To decrement a file, use the instruction: DECF 3A,1. This puts the new value back into the file. Do not use DECF 3A,0 as the new value goes into W!
To decrement a file twice, use:
To halve the value of a file, the contents is shifted right:
RRF 3A,1- the file must not have a bit in bit0. 
A file can be decremented until it is zero:   
DECFSZ, 3A,1   
To decrement W we can use the instruction: addlw  -1  
We can also decrement a file by adding a value to it.
For example we can decrement a file by an amount of .10 by adding .246 to it.  (0ffh = .256)
suppose file 3Ah has a value of .60
   movlw   .246 (ten less than a full file)
   addwf    3Ah
  file 3A will now contain .50

A delay sub-routine is needed for almost every program. One of the main purposes is to slow down the execution of a program to allow displays to be viewed and tones to be produced. 
The shortest delay is NOP. This is a "do nothing" instruction that takes 1 micro-second. 
You will need one million "NOP's" to produce a 1 second delay. 

Here are some instructions to produce a very short delay:

goto $+1

call $+2
goto $+1
retlw 00
;1 microsecond
;2 microseconds
;3 instructions produce 2 + 2 + 2 +2 microseconds

;the micro will return to wherever the sub-routine was ;called from

It is impractical to use instructions with just a microsecond delay as the program space will only allow about 1,000 instructions or 2,000 microseconds! 
The answer is to create a loop. If a file is loaded with a value and decremented, it will create a short delay. The two instructions: DECFSZ 3A,1 and GOTO DelA will take 3uS.    80h loops = 127 loops x 3 + 1 loop x 2uS  +  2uS on entry + 1uS on exit = 386uS      

;Put 80h into W
;Copy 80h into file 1A
;Decrement file 3A
;Loop until file 3A is zero

A simpler delay routine below decrements a file with 256 loops. Each loop is 4uS and the result is slightly more than 1,000uS = 1mS. The routine exits with 00h in the file. On the second execution, the routine performs 256 loops - the file does not have to be pre-loaded. 
The longest delay (such as the one below) using a single file is approx 1mS.      


;Decrement file 3A
;Loop until file 3A is zero

1mS delay

The same length of delay can be produced by using the "w" register:.      
movlw    .255
addlw     -.1
btfss      3,2
goto      Del1
retlw     00

;(no decrement instruction) so subtract 1 from "w"
;test the zero bit in status file and skip if zero bit is set.
;this will produce 255 loops of 4uS - about 1mS


To produce delays longer than 1mS, two or more files are needed. Each file is placed around the previous to get a multiplying effect. The inner delay produces 256 loops, the output file produces 256 loops of the inner file. This results in 256 x 256 loops = 256mS.
The simplest delay decrements a file to zero. At the end of an execution, a delay contains 00 and this produces the longest delay, the next time it is used. 
This means a file does not have to be pre-loaded. 
The following is a two-file nested delay. The delay time is approx 260mS (say 1/4Sec):


;Decrement file 3A
;Loop until file 3A is zero
;Decrement file 3B
;Loop until file 3B is zero

260mS Delay

If you want a delay between 1mS and 256mS, you will need to pre-load file 3B. For each value loaded into file 3B, a delay of 1mS will be produced. A 125mS delay is shown below:     

;Load W with 125 for 125mS delay

;Decrement file 3A
;Loop until file 3A is zero
;Decrement file 3B
;Loop until file 3B is zero

125mS Delay 

A 0.5 second delay:
     ; Delay = 0.5 seconds = 500,000 cycles
     ; Clock frequency = 4 MHz

cblock 0x20    ;delay files d1, d2 and d3 are at 20h, 21h and 22h

movlw     0x0B0h
movwf     d1
movlw     17h
movwf     d2
movlw     0x02
movwf     d3
decfsz    d1, f
goto       $+2
decfsz    d2, f
goto       $+2
decfsz    d3, f
goto       Delay2
goto       $+1
goto       $+1
goto       $+1
retlw      00
;499994 cycles

;this sends the micro to: goto Delay2

;2 cycle instruction that advances the
; micro to the next instruction
; 2 more cycles
                     checked 3-2-08

The goto $+2 instruction is a 2-cycle instruction that sends the micro 2-instructions down the program. This instruction has two advantages. It provides a delay of 2 microseconds @4MHz and saves creating a label.
In the decrementing section of the sub-routine (Delay2), the instruction: goto $+2  makes the micro go to 2 instructions down the program. This is simply a new and novel way to produce a delay routine.
The second goto $+2 sends the micro to: goto Delay2. The first instruction could have been goto $+4 but this routine is designed to "waste" time and every instruction adds to the delay.

A 2 second delay:
     ; Delay = 2 seconds = 2,000,000 cycles
     ; Clock frequency = 4 MHz

cblock 0x20    ;delay files d1, d2 and d3 are at 20h, 21h and 22h

movlw     0x11
movwf     d1
movlw     0x5D
movwf     d2
movlw     0x05
movwf     d3
decfsz    d1, f
goto       $+2
decfsz    d2, f
goto       $+2
decfsz    d3, f
goto       Delay2
goto       $+1
goto       $+1
retlw      00
;1,999,996 cycles

;this sends the micro to: goto Delay2

;2 cycle instruction that advances the
; micro to the next instruction

Code generated by

The following sub-routine will produce a delay of "X" minutes and "Y" seconds.
The following example make the micro wait EXACTLY 930,000,000 instruction cycles.
i.e: 15 minutes 30 seconds
movlw   0x0F                 ;This will produce 15 minutes. This the "X" value
call       _WAIT_1Min
movlw   0x30                 ;This will produce 30 seconds.  This is the "Y" value
call       _WAIT_1s

;   The following delays are calibrated for operation at 4MHz
;  OPERATION: Create a literal in W. This literal represents the multiplier
; of the delay. Immediately call the function.
; Example:
;	movlw	0x0F
;	call	_WAIT_1Min
;	movlw	0x30
;	call	_WAIT_1s

cblock	0x20 - the names of the files below will start at file 20h
_WAIT_1Min				; W * 60,000,000
	movwf	minute
	movlw	0x3B		; 59 * 1,000,000
	call	_WAIT_1s
	movlw	0x09		; 9 * 100,000
	call	_WAIT_100m
	movlw	0x63		; 99 * 1000
	call	_WAIT_1m
	movlw	0x63		; 99 * 10
	call	_WAIT_10us
	goto	dec4		; <= 59,999,996 cycles
	goto	$+1
	goto	$+1
	goto	$+1
	movlw	0x3B
	call	_WAIT_1s
	movlw	0x09
	call	_WAIT_100m
	movlw	0x63
	call	_WAIT_1m
	movlw	0x63
	call	_WAIT_10us
	decfsz	minute,F
	goto	$-0x0D - micro will go to "NOP" above
_WAIT_1s				; W * 1,000,000
	movwf	second
	movlw	0x09		; 9 * 100,000
	call	_WAIT_100m
	movlw	0x63		; 99 * 1000
	call	_WAIT_1m
	movlw	0x63		; 99 * 10
	call	_WAIT_10us
	goto	dec3		; <= 999,996 cycles
	goto	$+1
	goto	$+1
	goto	$+1
	movlw	0x09
	call	_WAIT_100m
	movlw	0x63
	call	_WAIT_1m
	movlw	0x63
	call	_WAIT_10us
	decfsz	second,F
	 goto	$-0x0B
_WAIT_100m				; W * 100,000
	movwf	deci
	movlw	0x63		; 99 * 1000
	call	_WAIT_1m
	movlw	0x63		; 99 * 10
	call	_WAIT_10us
	goto	dec2		; <= 99,996 cycles

	goto	$+1
	goto	$+1
	goto	$+1
	movlw	0x63
	call	_WAIT_1m
	movlw	0x63
	call	_WAIT_10us

	decfsz	deci,F
	 goto	$-9   - micro will go to "NOP" above
_WAIT_1m			; W * 1000 cycles
	movwf	milli
	movlw	0x63	; 99 * 10?s = .99ms
	call	_WAIT_10us
	goto	dec

	goto	$+1
	goto	$+1
	goto	$+1
	movlw	0x63	
	call	_WAIT_10us
	decfsz	milli,F
	goto	$-7   - micro will go to "NOP" above
_WAIT_10us			; W * 10cycles
	movwf	micro
	goto	dec5
	goto	$+1
	goto	$+1
	goto	$+1
	decfsz	micro,F
	goto	$-5

A delay can be created using the timers in the PIC12F629. Timer0 is 8-bit and is identified as:
tmr0       equ           H'0001'

Timer1 is 16 bit and can be used a two 8-bit timers:
tmr1L      equ           H'000E'
tmr1H      equ           H'000F'

(this is equal to three 8-bit timers)

No pre-setting-up is required. You can use them in place of a file.

           ;1 second delay using timer1L and timer1H

        movlw 05h
        movwf delC
        decfsz tmr1L,1
        goto                 $-2
       decfsz tmr1H,1
       goto                 $-4
       decfsz delC,1
       goto                $-6
       retlw                00


Here's a clever instruction:  +1

You can goto or call any sub-routine by using the name of the sub-routine and you will enter it via the first instruction - this is normal.
But if the sub-routine loads a value at the beginning, you can load a different value and call the sub-routine to get a different result.
All you have to do is enter the sub-routine at a position, one or two instructions, down the routine:

call  timer+1       or:   goto  delay+2   

The sub-routine will use your new value and exit with a different result, or delay.

Detect a value
If a file has been incremented in a sub-routine you may want to know the value it contains. 
You may want to know its exact value or if it is higher or lower than a certain value. 
To see if it is an exact value, it is XORed with a known value. See XOR.
To detect a particular value, they are XORed together. See XOR. 
You can also detect a particular value by BIT TESTING. You must make sure that all the numbers being tested can be distinguished by testing a single bit. For example: 1, 2, 4, 8, 10h can be tested via bits 0, 1, 2, 3, 4. But if 3 is included in your requirement, you cannot test a single bit.  

To find out if two numbers are different, they are XORed together. See XOR

Simple division such as divide by 2 can be performed by the RRF instruction. Successive RRF's will divide by 4, 8, sixteen etc. Other divisions are beyond the scope of this course. The number cannot have a bit in bit0, if an accurate division is required.

DS   or ds   (means: Define Space)
This term can be seen in some programs, as:

count     ds    2
sum      ds     1
dve        ds    3

It is the code for: "advances the load pointer by the specified value." 
Reserve the number of file locations. ORG must be set for this to work.
It simply allocates two locations for count, one for sum and three for dve    This allows the programmer to produce files for:  count, count+1, sum, dve, dve+1, dve+2 

DT - Data Table
The DT directive (command) allows you to create a table without having to write:
      retlw  40h
      retlw  79h
      retlw  3Ah
      retlw  4Ch

For example:

SegTable  ANDLW 0Fh       ; convert a number in W to segment form
               ADDWF PCL,F

               DT     40h,79h,24h,30h,19h,12h,02h,78h,00h,10h
               DT     7Fh,7Fh,7Fh,7Fh,7Fh,7Fh

Will compile to:

SegTable  ANDLW 0Fh       ; convert a number in W to 7-segment form
               ADDWF PCL,F
retlw  40h
               retlw  79h
               retlw  24h   etc

To double the value of the contents of a file, it is shifted LEFT (RLF 3A,1).    The number must be less than 80h. (it must not have a bit in location bit7).


The PIC12F629 has 128 bytes of EEPROM, from 00h to 7F to permanently store data. 
If you need to store only a few bytes of data for a short period of time, use files that are not required for the running of the program. This information will be lost when power is removed. 
The 128 bytes of EEPROM requires a special set of instructions to place data into EEPROM. The actual writing time for this data is very long (in computer terms) and can be done in the background, while the main program is executing. A flag will SET when the data has been written and this will allow another byte of data to be entered. 
Each EEPROM cell can be written about 1 million times. 

Before reading a value in a location in the EEPROM, it must be loaded with a value during "burning." To load the first location in EEPROM with a value, the following instructions are placed in a program. The EEPROM starts at location 2100h and the term DE means: "define EEPROM." There are 128 EEPROM locations and by following the layout in the second table, any location can be addressed during burning.      


ORG 2100h  
DE 43h  
;Starting point of EEPROM
;First EEPROM location holds the value 43h
 The locations in EEPROM:

ORG 2100h  
DE 84h, 16h, 23h, 80h, 0CAh, 32h, 7Bh, 0A2h 
DE 34h, 53h, 25h, 02h, 0FFh, 20h, 03h, 04h 

;Starting point 
;for up to eight lines


The sub-routine to read a value in the EEPROM is shown below.         

bsf      Status, rp0 
movlw  Config_addr 
movwf  EEADR
bsf      EECON1, rd
movf    EEDATA,0
bcf      Status, rp0
retlw   00
;go to Bank 1
;address to read
;EE read
;move data to W
;back to bank 0

The sub-routine to write to EEPROM is shown below. 
bsf        status,rp0
bsf        EECN1,WREN
bcf        INTCON,GIE
molw     55h
movwf    EECON2
movlw    AAh
movwf    EECON2
bsf        EECON,WR
bsf        INTCON,GIE
bcf        Status,rp0
retlw     00
;enable write
;disable interrupts
;unlock write
:start the write
;enable interrupts
;bank 0


To Top