Idiosyncrasies of the instruction set Before you start programming the PIC in assembler, have a thorough read of the datasheet and pay attention to what the instructions do. The instruction mnemonics can be misleading and some instructions don't set flags you'd expect them to. Anyway, here's my 'top ten tips' for the PIC 14-bit instruction set as found on the 12F and 16F PICs
MPASM Pseudo Mnemonics The Microchip MPASM (MPLAB IDE) assembler supports a number of Pseudo Mnemonics. These are just text substitutions for regular PIC instructions but they can make code written using them much more readable and easy to follow. For example the regular instruction BCF STATUS,C will clear the carry flag in the status register. The pseudo mnemonic CLRC does the same thing but it's much easier to 'see' what is being done. A full list of these can be found here: Pseudo Mnemonics List
See also the Microchip MPASM Quick Reference Card
Since subtraction isn't commutative it matters what is being subtracted from what. First thing to remember is that the value in the W Register is always subtracted from whatever is specified in the subtract instruction. The 12/14 bit PIC instruction set has two subtract instructions,
The other thing to understand is how the carry flag is conditioned by the result of the subtract operation. If the value in the W Register is greater than the value it is being subtracted from the carry flag is cleared, otherwise it is set.
There is no subtract-with-carry instruction in the PIC 12/14 bit instructions set. The current state of the carry flag is ignored by the subtract instruction, so you don't have to clear/set it before a subtract instruction executes. However that also means if you are going to do a multi-word subtract operation your code will have to manually test and handle the carry. Below is some code that shows how the subtract instruction works:
movlw 5 Compare and branch The PIC instruction set doesn't have much in the way of compare and branch instructions. The following code will compare a File register with the contents of W and then do a test and branch.
How to Decrement the W Register The PIC doesn't have a decrement W instruction but you can achieve the same thing with this single instruction. This is straight from the Microchip data sheets. The workings of this may not be immediately apparent. The Add and Subtract instructions on the PIC use 2's Complement representation. What this instruction is actually doing is adding the W register to -1 which results in W containing one less than it started with.
Don't forget that the 'addlw' instruction will always affect the zero, carry and digit carry flags, where the 'decf' instruction only affects the zero flag. How to Increment or Decrement a register without affecting any flags The incf and decf instructions set/clear the 'Z'ero flag in the status register. However, the incfsz and decfsz instructions don't affect any flags. So while this will affect the 'Z'ero flag
this will not
Okay, so you have to waste one program memory word with the 'nop' instruction, but if you happen to need to increment or decrement a register without affecting the contents of the status register it can be a quite useful. Test W register for 0 and clear Carry and Digit Carry in one instruction This may seem an obscure thing to want to do but I have used this in a practical application which is how I came across it. When you use a RETLW instruction to load W, the Status register zero flag isn't affected. In my application I was using a lookup table with return data of 0x00 as an end of data delimiter so I needed to test W for a zero value and also needed to clear the carry bit for a shift instruction that followed. Method 1.
Method 2.
This code block exchanges the contents of two file registers using the W register. The smart thing about this code is that it doesn't require the use of a temporary file register to store an intermediate value
I take no credit for this but it's pretty neat in its workings and can be very useful. Copy specific bits from W register into GPR variable This code copies the bits in the W register specified by the bitMask into the bitVar variable while leaving the remaining bits in the bitVar variable unchanged. ; define bit mask
constant to suit application
; enter code block with
First, this is a bad programming example, it's perfectly correct as far as the CPU is concerned but it will make the execution of your code difficult to follow, and more difficult to maintain. With that out of the way, if your code calls a sub-function from within another call, you can save a byte and 2 cycles by using a 'goto' instruction to get to the sub-function and letting the 'return' in the sub-function take you back to the original call. Since the stack on the 12/14 bit PICs is
only 8 levels deep, in some circumstances this trick can 'gain' you a 9th
call, and it will save two instruction cycles.
; 8 x 8 unsigned multiply routine.
; enter with terms to multiply in mult1, mult2
; resHi, ResLo contain 16 bit result on exit
; value in mult2 will is destroyed
_multiply8x8 movfw mult1 ; load mult1 into W reg
clrf resHi ; initialise resHi, ResLo
clrf resLo
bsf resLo,7 ; set bit 7 in resLo to use as loop counter
_mloop rrf mult2,F ; rotate mult2 one bit right
skpnc ; test bit shifted out of mult2
addwf resHi,F ; if it was a 1, add W to ResHi
rrf resHi,F ; shift 16 bit result right one bit
rrf resLo,F ;
skpc ; skip next if carry set as we have shifted 8 times
goto _mloop ; if carry was not set, loop again
return
Binary to packed BCD conversion (If you use this code, please reference http://picprojects.org.uk in your source code, thanks) This code converts a binary number to a packed BCD number using the shift and add +3 algorithm. If you want to know how it works there are plenty of sites that offer explanations. See here. There are two versions of the code; an 8 bit conversion and a 16 bit. If you only need to convert a single byte (8 bit number) the 8 bit version is much faster. The binary number to convert is loaded in
to binH and binL prior to calling the subroutine. The result is
placed in bcdH, bcdM, bcdL. The routine requires two other
working file register variables. The 8-bit conversion requires the
binary value to convert in bin and the results is returned in bcdH, bcdL.
In both versions the contents of binH and binL or bin are destroyed.
binL
;binary number
for conversion - low byte
Waste four instruction cycles with one instruction If you need to waste some cycles in a delay routine you can take advantage of the fact that whenever the PC (program counter) has to be reloaded it takes two instruction cycles. Since you are almost always sure to have a RETURN instruction somewhere in your code, give it a label. Then use a call to go there and back, one instruction, four cycles. If you really have no return anywhere in the code then you need to put one in just for this and it's a two instruction solution. The only thing to watch for is that the stack on the PIC is only 8 levels deep so if you are deep nesting calls make sure this doesn't wipe the top of the stack out.
This routine is based on a hardware parity checker I made about 15 years ago using a couple of 74LS86 quad XOR gate for a memory circuit. Logic function equivalent schematic.
Quick Reference Guide If you use Microchip's MPASM assembler you can use their Pseudo Instruction Mnemonics when writing code which may help to make your code more readable both for others and yourself. I certainly find it to be the case and use them all the time. See table of Pseudo Instructions You can download the 8 page MPASM / MPLINKPICmicro MCU Quick Chart from the Microchip website It's quite a useful document with references for the standard PIC micro instructions, assembler directives and the pseudo instructions. Links to
Microchip Application Notes AN234
Hardware Techniques for PIC Microcontrollers
|
||||||||||||||||||||||||