Nearly all these instructions also work with PIC16F628. Just check on Port value(s) and first available file.
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!!
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."
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.
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!!
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 occurred. |
prescaler assigned to WDT | bsf Option_reg,3 or: bsf 81h,3 | see: Watchdog timer Option register is in bank 1 |
prescaler assigned to Timer0 | bcf Option_reg,3 or: 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 |
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
OPERATOR | Example | |||||
---|---|---|---|---|---|---|
$ | 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 endc 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.
A Beep is a tone of short duration.
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.
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
Transfer 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
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." yyyyyyyyy timeout
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 xxxxxxxxx - - - - - - - - - - - - - - - - - - - - - - - - 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
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
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
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 endc
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 d1 d2 d3 endc
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. endc
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).
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!
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:
E.g:
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
OR
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.
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:
_CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_ON & _LVP_OFF
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)
_CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_ON & _LVP_OFF
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' Oscillator: 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
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.
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.
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:
0 | 0000 0000 | 0 | 16 | 0001 0000 | 10h | 32 | 0010 0000 | 20h |
1 | 0000 0001 | 1 | 17 | 0001 0001 | 11h | 33 | 0010 0001 | 21h |
2 | 0000 0010 | 2 | 18 | 0001 0010 | 12h | 34 | 0010 0010 | 22h |
3 | 0000 0011 | 3 | 19 | 0001 0011 | 13h | 35 | 0010 0011 | 23h |
4 | 0000 0100 | 4 | 20 | 0001 0100 | 14h | 36 | 0010 0100 | 24h |
5 | 0000 0100 | 5 | 21 | 0001 0101 | 15h | 37 | 0010 0101 | 25h |
6 | 0000 0110 | 6 | 22 | 0001 0110 | 16h | 38 | 0010 0110 | 26h |
7 | 0000 0111 | 7 | 23 | 0001 0111 | 17h | 39 | 0010 0111 | 27h |
8 | 0000 1000 | 8 | 24 | 0001 1000 | 18h | 40 | 0010 1000 | 28h |
9 | 0000 1001 | 9 | 25 | 0001 1001 | 19h | 41 | 0010 1001 | 29h |
10 | 0000 1010 | A | 26 | 0001 1010 | 1Ah | 42 | 0010 0010 | 2Ah |
11 | 0000 1011 | B | 27 | 0001 1011 | 1Bh | 43 | 0010 1011 | 2Bh |
12 | 0000 1100 | C | 28 | 0001 1100 | 1Ch | 44 | 0010 1100 | 2Ch |
13 | 0000 1101 | D | 29 | 0001 1101 | 1Dh | 45 | 0010 1101 | 2Dh |
14 | 0000 1110 | E | 30 | 0001 1110 | 1Eh | 46 | 0010 1110 | 2Eh |
15 | 0000 1111 | F | 31 | 0001 1111 | 1Fh | 47 | 0010 1111 | 2Fh |
48 | 0011 0000 | 30h | 64 | 0100 0000 | 40h | 80 | 0101 0000 | 50h |
49 | 0011 0001 | 31h | 65 | 0100 0001 | 41h | 81 | 0101 0001 | 51h |
50 | 0011 0010 | 32h | 66 | 0100 0010 | 42h | 82 | 0101 0010 | 52h |
51 | 0011 0011 | 33h | 67 | 0100 0011 | 43h | 83 | 0101 0011 | 53h |
52 | 0011 0100 | 34h | 68 | 0100 0100 | 44h | 84 | 0101 0100 | 54h |
53 | 0011 0100 | 35h | 69 | 0100 0101 | 45h | 85 | 0101 0101 | 55h |
54 | 0011 0110 | 36h | 70 | 0100 0110 | 46h | 86 | 0101 0110 | 56h |
55 | 0011 0111 | 37h | 71 | 0100 0111 | 47h | 87 | 0101 0111 | 57h |
56 | 0011 1000 | 38h | 72 | 0100 1000 | 48h | 88 | 0101 1000 | 58h |
57 | 0011 1001 | 39h | 73 | 0100 1001 | 49h | 89 | 0101 1001 | 59h |
58 | 0011 1010 | 3Ah | 74 | 0100 1010 | 4Ah | 90 | 0101 0010 | 5Ah |
59 | 0011 1011 | 3Bh | 75 | 0100 1011 | 4Bh | 91 | 0101 1011 | 5Bh |
60 | 0011 1100 | 3Ch | 76 | 0100 1100 | 4Ch | 92 | 0101 1100 | 5Ch |
61 | 0011 1101 | 3Dh | 77 | 0100 1101 | 4Dh | 93 | 0101 1101 | 5Dh |
62 | 0011 1110 | 3Eh | 78 | 0100 1110 | 4Eh | 94 | 0101 1110 | 5Eh |
63 | 0011 1111 | 3Fh | 79 | 0100 1111 | 4Fh | 95 | 0101 1111 | 5Fh |
96 | 0110 0000 | 60h | 112 | 0111 0000 | 70h | 128 | 1000 0000 | 80h |
97 | 0110 0001 | 61h | 113 | 0111 0001 | 71h | 129 | 1000 0001 | 81h |
98 | 0110 0010 | 62h | 114 | 0111 0010 | 72h | 130 | 1000 0010 | 82h |
99 | 0110 0011 | 63h | 115 | 0111 0011 | 73h | 131 | 1000 0011 | 83h |
100 | 0110 0100 | 64h | 116 | 0111 0100 | 74h | 132 | 1000 0100 | 84h |
101 | 0110 0100 | 65h | 117 | 0111 0101 | 75h | 133 | 1000 0101 | 85h |
102 | 0110 0110 | 66h | 118 | 0111 0110 | 76h | 134 | 1000 0110 | 86h |
103 | 0110 0111 | 67h | 119 | 0111 0111 | 77h | 135 | 1000 0111 | 87h |
104 | 0110 1000 | 68h | 120 | 0111 1000 | 78h | 136 | 1000 1000 | 88h |
105 | 0110 1001 | 69h | 121 | 0111 1001 | 79h | 137 | 1000 1001 | 89h |
106 | 0110 1010 | 6Ah | 122 | 0111 1010 | 7Ah | 138 | 1000 0010 | 8Ah |
107 | 0110 1011 | 6Bh | 123 | 0111 1011 | 7Bh | 139 | 1000 1011 | 8Bh |
108 | 0110 1100 | 6Ch | 124 | 0111 1100 | 7Ch | 140 | 1000 1100 | 8Ch |
109 | 0110 1101 | 6Dh | 125 | 0111 1101 | 7Dh | 141 | 1000 1101 | 8Dh |
110 | 0110 1110 | 6Eh | 126 | 0111 1110 | 7Eh | 142 | 1000 1110 | 2Eh |
111 | 0110 1111 | 6Fh | 127 | 0111 1111 | 1Fh | 143 | 1000 1111 | 8Fh |
144 | 1001 0000 | 90h | 160 | 1010 0000 | A0h | 176 | 1011 0000 | B0h |
145 | 1001 0001 | 91h | 161 | 1010 0001 | A1h | 177 | 1011 0001 | B1h |
146 | 1001 0010 | 92h | 162 | 1010 0010 | A2h | 178 | 1011 0010 | B2h |
147 | 1001 0011 | 93h | 163 | 1010 0011 | A3h | 179 | 1011 0011 | B3h |
148 | 1001 0100 | 94h | 164 | 1010 0100 | A4h | 180 | 1011 0100 | B4h |
149 | 1001 0100 | 95h | 165 | 1010 0101 | A5h | 181 | 1101 1011 | B5h |
150 | 1001 0110 | 96h | 166 | 1010 0110 | A6h | 182 | 1011 0110 | B6h |
151 | 1001 0111 | 97h | 167 | 1010 0111 | A7h | 183 | 1011 0111 | B7h |
152 | 1001 1000 | 98h | 168 | 1010 1000 | A8h | 184 | 1011 1000 | B8h |
153 | 1001 1001 | 99h | 169 | 1010 1001 | A9h | 185 | 1011 1001 | B9h |
154 | 1001 1010 | 9Ah | 170 | 1010 1010 | AAh | 186 | 1011 0010 | BAh |
155 | 1001 1011 | 9Bh | 171 | 1010 1011 | ABh | 187 | 1011 1011 | BBh |
156 | 1001 1100 | 9Ch | 172 | 1010 1100 | 7Ch | 188 | 1011 1100 | BCh |
157 | 1001 1101 | 9Dh | 173 | 1010 1101 | ADh | 189 | 1011 1101 | 8Dh |
158 | 1001 1110 | 9Eh | 174 | 1010 1110 | AEh | 190 | 1011 1110 | BEh |
159 | 1001 1111 | 9Fh | 175 | 1010 1111 | AFh | 191 | 1011 1111 | BFh |
192 | 1100 0000 | C0h | 208 | 1101 0000 | D0h | 224 | 1110 0000 | E0h |
193 | 1100 0001 | C1h | 209 | 1101 0001 | D1h | 225 | 1110 0001 | E1h |
194 | 1100 0010 | C2h | 210 | 1101 0010 | D2h | 226 | 1110 0010 | E2h |
195 | 1100 0011 | C3h | 211 | 1101 0011 | D3h | 227 | 1110 0011 | E3h |
196 | 1100 0100 | 64h | 212 | 1101 0100 | D4h | 228 | 1110 0100 | E4h |
197 | 1100 0100 | C5h | 213 | 1101 0101 | D5h | 229 | 1110 0101 | E5h |
198 | 1100 0110 | C6h | 214 | 1101 0110 | D6h | 230 | 1110 0110 | E6h |
199 | 1100 0111 | C7h | 215 | 1101 0111 | D7h | 231 | 1110 0111 | E7h |
200 | 1100 1000 | C8h | 216 | 1101 1000 | D8h | 232 | 1110 1000 | E8h |
201 | 1100 1001 | 69h | 217 | 1101 1001 | D9h | 233 | 1110 1001 | E9h |
202 | 1100 1010 | 6Ah | 218 | 1101 1010 | DAh | 234 | 1110 1010 | EAh |
203 | 1100 1011 | 6Bh | 219 | 1101 1011 | DBh | 235 | 1110 1011 | EBh |
204 | 1100 1100 | CCh | 220 | 1101 1100 | DCh | 236 | 1110 1100 | ECh |
205 | 1100 1101 | CDh | 221 | 1101 1101 | 7Dh | 237 | 1110 1101 | EDh |
206 | 1100 1110 | CEh | 222 | 1101 1110 | DEh | 238 | 1110 1110 | 2Eh |
207 | 1100 1111 | CFh | 223 | 1101 1111 | DFh | 239 | 1110 1111 | EFh |
240 | 1111 0000 | F0h |
241 | 1111 0001 | F1h |
242 | 1111 0010 | F2h |
243 | 1111 0011 | F3h |
244 | 1111 0100 | F4h |
245 | 1111 0101 | F5h |
246 | 1111 0110 | F6h |
247 | 1111 0111 | F7h |
238 | 1111 1000 | F8h |
249 | 1111 1001 | F9h |
250 | 1111 1010 | FAh |
251 | 1111 1011 | FBh |
242 | 1111 1100 | FCh |
243 | 1111 1101 | FDh |
254 | 1111 1110 | FEh |
255 | 1111 1111 | FFh |
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:
DECF 3A,1
DECF 3A,1
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:
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.
Del NOP 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):
Del NOP 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 d1 d2 d3 endc 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 d1 d2 d3 endc 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
Example:
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 ;...... minute second deci milli micro ;...... endc ;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% _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 NOP 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 dec4 decfsz minute,F goto $-0x0D - micro will go to "NOP" above return ;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% _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 NOP goto $+1 goto $+1 goto $+1 movlw 0x09 call _WAIT_100m movlw 0x63 call _WAIT_1m movlw 0x63 call _WAIT_10us dec3 decfsz second,F goto $-0x0B return ;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% _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 NOP goto $+1 goto $+1 goto $+1 movlw 0x63 call _WAIT_1m movlw 0x63 call _WAIT_10us dec2 decfsz deci,F goto $-9 - micro will go to "NOP" above return ;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% _WAIT_1m ; W * 1000 cycles movwf milli movlw 0x63 ; 99 * 10?s = .99ms call _WAIT_10us goto dec NOP goto $+1 goto $+1 goto $+1 movlw 0x63 call _WAIT_10us dec decfsz milli,F goto $-7 - micro will go to "NOP" above return ;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% _WAIT_10us ; W * 10cycles movwf micro goto dec5 NOP goto $+1 goto $+1 goto $+1 dec5 decfsz micro,F goto $-5 return
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 _1Sec movlw 05h movwf delC nop decfsz tmr1L,1 goto $-2 decfsz tmr1H,1 goto $-4 decfsz delC,1 goto $-6 retlw 00
+1
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.
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.
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
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 ;Starting point of EEPROM DE 43h ;First EEPROM location holds the value 43h END
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 END
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
Quick Links
Legal Stuff
Social Media