Library of Routines for PIC12F629
Colin Mitchell
Colin Mitchell
Make sure to subscribe to our newsletter and be the first to know the news.

Table Of Contents

Add a value to a File
Add "bits" to a port - turn on bits or "lines."
Address a File
Addressing a Set of Files
AND - see also Mask
Beep see Tone
Binary to HEX: see Decimal to Binary to HEX
Binary Hex and Decimal numbers
Block Transfer
Button see Switch
CALL see also Stack
CALL Table see also Table and Output a Table Value
Carry - see also ROTATE for one of the operations involving CARRY.
CBLOCK - (define a Block of Constants)
Change Direction
Clear a list of files (registers)
Config - configuration
Copy bits from one file to another
Data Table - see DT below
Debounce a Button (Switch)
Decimal, Hex and Binary numbers
Detect a value
DS or ds (means: Define Space)
DT - Data Table

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

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

Add MOVLW 0CCh      ;Put CCh into W
    ADDWF 2Eh,1     ;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
MOVLW 10h       ;Put 10h into W - this is bit 5
IORWF GPIO,1    ;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:

MOVWF 2A,0      ;Copy file 2A into W
DECFSZ 2A,1     ;Decrement file 2A
INCF 2A,1       ;Increment file 2A
INCF 2A,0       ;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
carry03,0Test the carry bit:
btfss 03,0 ;skip if a carry-out of the most significant bit has occurred.
prescaler assigned to WDTbsf Option_reg,3
bsf 81h,3
see: Watchdog timer
Option register is in bank 1
prescaler assigned to Timer0bcf Option_reg,3
bcf 81h,3
Timer0 is in bank 0
GPIOfile 05hsee input/output port. “Setting the port bits HIGH or LOW”
TRISIOfile 85hsee “Setting the ports bits input or output”
Statusfile 03Contains the carry, bank select and zero flags.
zero flag
zero bit
03,2zero 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 Countergoto $ + 3
(Left parenthesis1 + ( d * 4)
)Right parenthesis(length + 1) * 256
!NOT (logical complement)if ! (a == b)
Negation (2’s complement)– 1 * length
~Complementflags = ~ flags
*Multiplya = b * c
/Dividea = b / c
%Modulusentry_len = tot_len % 16
+Addtot_len = entry_len * 8 + 1
Subtractentry_len = (tot – 1) / 8
<<Left Shiftflags = flags << 1
>>Right Shiftflags = flags >> 1
>=Greater or equalif entry_idx >= num_entries
>Greater thanif entry_idx > num_entries
<Less thanif entry_idx < num_entries
<=Less or equalif entry_idx <= num_entries
\==Equal toif entry_idx == num_entries
! =Not equal toif entry_idx ! = num_entries
&Bitwise ANDflags = flags & ERROR_BIT
^Bitwise EXclusive ORflags = flags ^ ERROR_BIT
Bitwise Inclusive ORflags = flagsERROR_BIT
&&Logical ANDif (len == 512) && (b == c)
Logical ORif (len == 512)(b == c)
\=Set equal toentry index = 0
+=Add to, set equalentry index += 1
– \=Subtract, set equalentry index – \= 1
*=Multiply, set equalentry index *= entry_length
/=Divide, set equalentry total /= entry_length
%=Modulus, set equalentry index %= 8
<<=Left shift, set equalflags <<= 3
>>=Right shift, set equalflags >>= 3
&=AND, set equalflags &= ERROR_FLAG
=Inclusive OR, set equalflags= ERROR_FLAG
^ =EXclusive OR, set equalflags ^= ERROR_FLAG
++Incrementi ++
– –Decrementi – –


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

NewSw  movf Sw,0        ;Move file "Sw" to W
       bz   timeout     ;If Sw file is zero, the result of moving it to w (or to itself) will
       xxxxxxx          ;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
        - - - - - - - -
        - - - - - - - -
        - - - - - - - -

Delay   MOVLW 80h           ;Put 80h into W
        MOVWF 2A            ;Copy 80h into file 21A
DelA    DECFSZ 2A,1         ;Decrement file 21A
        GOTO DelA           ;Loop until file 2A is zero
        RETLW 00

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       ;File 2A contains 05. Move it to W
        CALL Table      ;W will return with 6D
        MOVWF 2C        ;Move 6D to file 2C
Table   ADDWF 02h,1     ;Add W to the Program Counter to create a jump.
        RETLW 3Fh
        RETLW 06h
        RETLW 5Bh
        RETLW 4Fh
        RETLW 66h
        RETLW 6Dh
        RETLW 7Dh
        RETLW 07h
        RETLW 7Fh
        RETLW 6Fh

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        ;Go to Bank 1
BSF TRISIO,1    ;Make GP1 input
BCF 03,5        ;Go to Bank 0 - the program memory area.
BSF 03,5        ;Go to Bank 1
BCF TRISIO,1    ;Make GP1 output
BCF 03,5        ;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    ;FSR is loaded with the value of the first file to be cleared
        movwf  FSR          ;
ClrLoop clrf   INDF         ;INDF is file 00 and this command actually clears the file looked-at by FSR

        incf   FSR,f        ;advance to next file
        movlw  EndFile      ;Load FSR with value of End File
        subwf  FSR,w        ;perform a subtraction
        btfss  status,z     ;zero bit will be set when result is zero - end file reached
        goto   ClrLoop
 ;clear EEPROM

clear movlw  .22          ;the number to be cleared
      movwf  loops
      bsf    status,rp0   ;select bank1
      clrf   eeadr
      decf   eeadr        ;to start at first address
      bsf    status,rp0   ;select bank1
      incf   eeadr,1
      clrf   eedata       ;put a blank at each address
      bcf    status,rp0   ;select bank0
      call   write
      decfsz loops,1
      goto   $-6
      retlw  00


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 GP5100  = 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     ;clear target bit7:bit6
swapf  source,w     ;the lower nibble of source will be swapped with
                    ;high nibble and the result will be placed in w
andlw  b'11000000'  ;only the two top bits of source will remain
iorwf  target,f     ;the two top bits of source will be added to "target"

To copy bit3:bit2 from “source” to bit3:bit2 “target”

movf   source,w     ;move source into w
andlw  b'00000011'  ;only the two lower bits of source will remain
iorwf  target,f     ;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 000010h320010 000020h
10000 00011170001 000111h330010 000121h
20000 00102180001 001012h340010 001022h
30000 00113190001 001113h350010 001123h
40000 01004200001 010014h360010 010024h
50000 01005210001 010115h370010 010125h
60000 01106220001 011016h380010 011026h
70000 01117230001 011117h390010 011127h
80000 10008240001 100018h400010 100028h
90000 10019250001 100119h410010 100129h
100000 1010A260001 10101Ah420010 00102Ah
110000 1011B270001 10111Bh430010 10112Bh
120000 1100C280001 11001Ch440010 11002Ch
130000 1101D290001 11011Dh450010 11012Dh
140000 1110E300001 11101Eh460010 11102Eh
150000 1111F310001 11111Fh470010 11112Fh
480011 000030h640100 000040h800101 000050h
490011 000131h650100 000141h810101 000151h
500011 001032h660100 001042h820101 001052h
510011 001133h670100 001143h830101 001153h
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 10115Bh
600011 11003Ch760100 11004Ch920101 11005Ch
610011 11013Dh770100 11014Dh930101 11015Dh
620011 11103Eh780100 11104Eh940101 11105Eh
630011 11113Fh790100 11114Fh950101 11115Fh
960110 000060h1120111 000070h1281000 000080h
970110 000161h1130111 000171h1291000 000181h
980110 001062h1140111 001072h1301000 001082h
990110 001163h1150111 001173h1311000 001183h
1000110 010064h1160111 010074h1321000 010084h
1010110 010065h1170111 010175h1331000 010185h
1020110 011066h1180111 011076h1341000 011086h
1030110 011167h1190111 011177h1351000 011187h
1040110 100068h1200111 100078h1361000 100088h
1050110 100169h1210111 100179h1371000 100189h
1060110 10106Ah1220111 10107Ah1381000 00108Ah
1070110 10116Bh1230111 10117Bh1391000 10118Bh
1080110 11006Ch1240111 11007Ch1401000 11008Ch
1090110 11016Dh1250111 11017Dh1411000 11018Dh
1100110 11106Eh1260111 11107Eh1421000 11102Eh
1110110 11116Fh1270111 11111Fh1431000 11118Fh
1441001 000090h1601010 0000A0h1761011 0000B0h
1451001 000191h1611010 0001A1h1771011 0001B1h
1461001 001092h1621010 0010A2h1781011 0010B2h
1471001 001193h1631010 0011A3h1791011 0011B3h
1481001 010094h1641010 0100A4h1801011 0100B4h
1491001 010095h1651010 0101A5h1811101 1011B5h
1501001 011096h1661010 0110A6h1821011 0110B6h
1511001 011197h1671010 0111A7h1831011 0111B7h
1521001 100098h1681010 1000A8h1841011 1000B8h
1531001 100199h1691010 1001A9h1851011 1001B9h
1541001 10109Ah1701010 1010AAh1861011 0010BAh
1551001 10119Bh1711010 1011ABh1871011 1011BBh
1561001 11009Ch1721010 11007Ch1881011 1100BCh
1571001 11019Dh1731010 1101ADh1891011 11018Dh
1581001 11109Eh1741010 1110AEh1901011 1110BEh
1591001 11119Fh1751010 1111AFh1911011 1111BFh
1921100 0000C0h2081101 0000D0h2241110 0000E0h
1931100 0001C1h2091101 0001D1h2251110 0001E1h
1941100 0010C2h2101101 0010D2h2261110 0010E2h
1951100 0011C3h2111101 0011D3h2271110 0011E3h
1961100 010064h2121101 0100D4h2281110 0100E4h
1971100 0100C5h2131101 0101D5h2291110 0101E5h
1981100 0110C6h2141101 0110D6h2301110 0110E6h
1991100 0111C7h2151101 0111D7h2311110 0111E7h
2001100 1000C8h2161101 1000D8h2321110 1000E8h
2011100 100169h2171101 1001D9h2331110 1001E9h
2021100 10106Ah2181101 1010DAh2341110 1010EAh
2031100 10116Bh2191101 1011DBh2351110 1011EBh
2041100 1100CCh2201101 1100DCh2361110 1100ECh
2051100 1101CDh2211101 11017Dh2371110 1101EDh
2061100 1110CEh2221101 1110DEh2381110 11102Eh
2071100 1111CFh2231101 1111DFh2391110 1111EFh
2401111 0000F0h
2411111 0001F1h
2421111 0010F2h
2431111 0011F3h
2441111 0100F4h
2451111 0101F5h
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:
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:

nop         ;1 microsecond
goto $+1    ;2 microseconds
call $+2    ;3 instructions produce 2 + 2 + 2 +2 microseconds
goto $+1    ;the micro will return to wherever the sub-routine was
retlw 00    ;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

Del     MOVLW 80h       ;Put 80h into W
        MOVWF 3A        ;Copy 80h into file 1A
DelA    DECFSZ 3A,1     ;Decrement file 3A
        GOTO DelA       ;Loop until file 3A is zero
        RETLW 00

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.

    DECFSZ 3A,1     ;Decrement file 3A
    GOTO Del        ;Loop until file 3A is zero
    RETLW 00

1mS delay

The same length of delay can be produced by using the “w” register:.

Del     movlw  .255
Del1    addlw  -.1      ;(no decrement instruction) so subtract 1 from "w"
        btfss  3,2      ;test the zero bit in status file and skip if zero bit is set.
        goto   Del1     ;this will produce 255 loops of 4uS - about 1mS
        retlw  00


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

    DECFSZ 3A,1     ;Decrement file 3A
    GOTO Del        ;Loop until file 3A is zero
    DECFSZ 3B,1     ;Decrement file 3B
    GOTO Del        ;Loop until file 3B is zero
    RETLW 00

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:

Del  MOVLW 7Dh      ;Load W with 125 for 125mS delay
     MOVLW 3B
Del1 NOP
     DECFSZ 3A,1    ;Decrement file 3A
     GOTO Del1      ;Loop until file 3A is zero
     DECFSZ 3B,1    ;Decrement file 3B
     GOTO Del1      ;Loop until file 3B is zero
     RETLW 00

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

Delay1  movlw  0x0B0h   ;499994 cycles
        movwf  d1
        movlw  17h
        movwf  d2
        movlw  0x02
        movwf  d3
Delay2  decfsz d1, f
        goto   $+2
        decfsz d2, f
        goto   $+2      ;this sends the micro to: goto Delay2
        decfsz d3, f
        goto   Delay2
        goto   $+1      ;2 cycle instruction that advances the
        goto   $+1      ; micro to the next instruction
        goto   $+1      ; 2 more cycles
        retlw  00               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

Delay1  movlw  0x11     ;1,999,996 cycles
        movwf  d1
        movlw  0x5D
        movwf  d2
        movlw  0x05
        movwf  d3
Delay2  decfsz d1, f
        goto   $+2
        decfsz d2, f
        goto   $+2      ;this sends the micro to: goto Delay2
        decfsz d3, f
        goto   Delay2
        goto   $+1      ;2 cycle instruction that advances the
        goto   $+1      ; micro to the next instruction
        retlw  00

Code generated by http://www.golovchenko.org/cgi-bin/delay

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

   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   ;Starting point of EEPROM
DE 43h      ;First EEPROM location holds the value 43h

The locations in EEPROM:

ORG 2100h                                       ;Starting point
DE 84h, 16h, 23h, 80h, 0CAh, 32h, 7Bh, 0A2h     ;
DE 34h, 53h, 25h, 02h, 0FFh, 20h, 03h, 04h      ;
                                                ;for up to eight lines


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

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


The sub-routine to write to EEPROM is shown below.

EEWrite  bsf   status,rp0       ;bank1
        bsf    EECN1,WREN       ;enable write
        bcf    INTCON,GIE       ;disable interrupts
        molw   55h              ;unlock write
        movwf  EECON2           ;
        movlw  AAh              ;
        movwf  EECON2           ;
        bsf    EECON,WR         :start the write
        bsf    INTCON,GIE       ;enable interrupts
        bcf    Status,rp0       ;bank 0
        retlw  00               ;Return

Colin Mitchell

Colin Mitchell



Social Media


Related Posts

Transistor Test
© 2021, All Rights Reserved.

Quick Links

Advertise with usAbout UsContact Us

Social Media