Understanding & Programming The PIC16C84: A Beginners' Tutorial Jim Brown

Download as pdf or txt
Download as pdf or txt
You are on page 1of 35

Understanding & Programming the

PIC16C84
A beginners tutorial
Jim Brown BSc(Eng), HDipEdAd, GDE (Wits)
RTF -->HTML Translation by: Dan Creagan

Contents at a Glance
Contents at a Glance
Contents
List of Programs
Introduction
Introducing the PIC84
The Instruction Set
Interrupts on the 84
Timers on the 84
Using the EEPROM data memory
Appendix: Program listings

Contents
Contents at a Glance
Contents
List of Programs
Introduction
Background
What you need
What you should know
Introducing the PIC84
Architecture
Instruction Set
A simple PIC84 program
Using MPLAB to debug the program
Pause to reflect
The Instruction Set
Instruction format
The STATUS register
1: Move instructions
o MOVF f,d (Move f, PIC p58)
MOVWF f (Move W to f, PIC p58)
MOVLW k (Move literal to W, PIC p58)
2: Clear instructions
o CLRF f (Clear f, PIC p55)
CLRW (Clear W, PIC p55)
3: Arithmetic instructions
o ADDWF f,d (Add W & f, PIC p53)
SUBWF f,d (Subtract W from f, PIC p61)
ADDLW k (Add literal & W, PIC p53)
SUBLW k (Subtract W from literal, PIC p61)
4: Logical functions
o ANDWF f,d (AND W with f, PIC p53)
IORWF f,d (Inclusive OR W with f, PIC p58)
XORWF f,d (Exclusive OR W with f, PIC p62)
ANDLW k (AND literal with W, PIC p53)
IORLW k (Inclusive OR literal with W, PIC p57)
XORLW k (Exclusive OR literal with W, PIC p62)
COMF f,d (Complement f, PIC p56)
5: Decrementing & Incrementing
o DEC f,d (Decrement f, PIC p56)
INC f,d (Increment f, PIC 57)
6: Bit setting & clearing
o BCF f,b (Bit clear f, PIC p54)
BSF f,b (Bit set f, PIC p54)
7: Program control
o GOTO k (Go to address, PIC p57)
CALL k (Call subroutine, PIC p55)
RETURN (Return from subroutine, PIC p60)
RETLW k (Return with literal in W, PIC p59)
RETFIE (Return from Interrupt, PIC p59)
8: Skipping instructions
o DECFSZ f,d (Decrement f, skip if 0, PIC p56)
INCFSZ f,d (Increment f, skip if 0, PIC p57)
BTFSC f,b (Bit test f, skip if clear, PIC p54)
BTFSS f,b (Bit test f, skip if set, PIC p55)
9: Rotations & Swap
o RRF f,d (Rotate right f thru carry, PIC p60)
RLF f,d (Rotate left f thru carry, PIC p60)
SWAPF f,d (Swap nybbles in f, PIC p62)
10: Sleep & Watchdog Timer
o SLEEP (Sleep, PIC p60)
CLRWDT (Clear watchdog timer, PIC p56)
11: Miscellaneous
o NOP (No operation, PIC p59)
OPTION (Not recommended)
TRIS (Not recommended)
Pause to reflect
Interrupts on the 84
Whats an interrupt?
Types of Interrupt and the INTCON register
Servicing an Interrupt
Timers on the 84
The basic idea
The TIMER0 module
Using the timers overflow
Using the EEPROM data memory
Appendix: Program listings
List of Programs
Program 1: simple . asm

o Program 2: moves . asm
Program 3: clears . asm
Program 4: arith . asm
Program 5: inter1.asm
Program 6: inter2.asm
Program 7: inter3.asm
Program 8: time0.asm
Introduction
Background
When I first started looking into programming the PIC84, I was daunted by what I saw as the complexity of the
thing. After all, I was only getting into this for a hobby- not as a control engineer. I had had some experience years
before with Zilogs Z80, so I knew what registers, op-codes and so on were, but was still a little perplexed. The
PIC84 data sheet from Microchip is quite a technical document, and the MPASM manual is a reference. Neither of
these documents served me as a tutorial, which is what I needed. So this manual is quite simply my idea of a tutorial
for programming the PIC84, covering both the 84s instruction set and some MPASM directives. Along the way,
it covers the 84 itself, in terms of registers, pins and so on.
By the end of working through this material you will not be a fully-fledged 84 expert. But you will be quite
comfortable with the device, even though you wont necessarily have touched one!
What you need
First, you need a copy of this guide. Preferably your own copy, so you can scribble in it to your
hearts content. Feel free to make as many copies of this as you wish- its freeware.
Second, you need to have some of Microchips documentation. As a minimum, youll need the
PIC84 data sheet. This contains all the real info you will need on the chip itself. I refer to this
from time to time: theres no point my trying to duplicate the detail of the info, or the diagrams.
You should also have the MPASM User Guide. Both of these are available from Microchips
website, at http://www.microchip2.com, or from their annual CD Microchip Technical Library.
I refer to these thus: [PIC] or [MPASM] with a page, figure or table number; for instance
[PIC figure 3.4.1] or [MPASM table 6]. [ed: The page, figure, and table numbers reffered to
here come from an older version of the '84 datasheet which is available at
http://www.piclist.com/images/piclist/30445B.PDF]
You could work through the material with just the above, but you will get a lot more out of it by
being able to experiment. So, thirdly, load a copy of MPLAB (for Windows) onto your PC. This
is their Interactive Development Environment (IDE), and it contains an editor, assembler and a
simulator. Here, you can create your source code (editor), produce the executable code
(assembler) and then run it on your PC (simulator). In the simulator, you can watch the program
running, keeping an eye on the registers and even simulate events like externally caused changes
to the I/O pins. You really should get this, and its also available as above. Work through its
tutorial before you start this book, at least so you can find your way around it.
Thats all you need, but theres lots more you might like. Not least, is a PIC84 chip and some
kind of PC based programmer. I havent covered the physical use of it in here, but might in a
future volume. But there are many sources of info for that. I also found it handy to have a
calculator that works in decimal, hex and binary for conversions: theres one in Windows which
you just need to switch to scientific mode.
Of extreme help- perhaps in the longer run- are Microchips Application Notes (ANs). These are
available from them, and a handy source is the CD-ROM mentioned above. These notes cover
all sorts of uses of the PICs, with many helpful insights into real-world use. The ANs are in
Adobes .pdf format: using Adobe Acrobat you can search through the ANs looking for terms
like motor or serial and read the ANs appropriate to your needs.
One of the notes, AN585 on real-time operating systems for the PIC, refers to Real time
programming- Neglected topics. I urge you to get your hands on a copy- it is a fascinating
tutorial on the whole subject of interrupts, closed-loop control, and the like.
What you should know
Its not really for me to say what you should know: I dont know who you are or what you do.
But, I guess youll find it easier going if you do understand (or can find out about) basic
computer terminology like bits, bytes & EEPROM and concepts like binary and hex. Of course,
if youre using the simulator on your PC, you must feel comfortable with your PC and
Windows, and have played with the IDE tutorial.
I certainly dont expect that you have any PIC84 knowledge- this tutorial is aimed at the
absolute neophyte.
Introducing the PIC84
Architecture
A microcontroller such as the 84 is- by its nature- a complete computer on a chip. It has 1: a
processor and 2: registers, as well as 3: program and 4: data memory. This makes it different
from mere CPUs which have only the processor and registers.
1: The PIC84 has an 8-bit processor, and thats all we need to know about it!
2: The 58 registers are the processors internal working storage. Referring to [PIC figure
4-2], youll see that some of these have names (STATUS, PORTB etc): these have
special functions and well examine them later. PORTA, for instance, contains the
contents of one of the I/O ports, namely port A. There are 36 general purpose registers,
and we can consider these as ours (as opposed to the processors special ones) and use
them as our scratch pad.
3: The 84 has 1K x 14 program memory: that means there are 1024 program locations,
and each is 14 bits wide. Youll see from [PIC fig 3.4.1] that the memory goes from
0000h to 03FFh: 03FFhex is 1023 in decimal so there are 1024 locations including 0000.
The 14 bits wide part comes from the length of each instruction: look at any one in
[PIC section 4.2] and youll see that each is 14 bits long. For instance, ADDLW is 11
111X kkkk kkkk : dont worry about what this means, just count it! Well be using this
memory extensively later on.
4: It has 64 bytes data memory, which is used for storage of, for instance, calibration
values. Well look at the use of this EEPROM memory last in this booklet.
In addition, the device includes 5: four types of interrupt and 6: 13 I/O pins.
5: Interrupts are means of something preempting the program. A button press by an operator, could
interrupt the programs normal flow and cause some special treatment. Well examine the 84s interrupt
techniques later.
6: The use of the I/O pins is key to the use of a device like the 84, since any process consists of 3 parts-
the input to the process, the process itself, and the output. The 84 has 13 pins configured as 2 ports: port A
comprises 5 pins and port B has 8; and well be using them later.
Instruction Set
There are 35 instructions in the PIC84 instruction set; all are 14 bits long, and consist of an opcode and operand/s.
Basically, the opcode specifies what to do and the operand/s specify how or where. These instructions are split into
3 groups: byte-oriented, bit-oriented and literal & control. Later on we will use each and every one of these
operations, firstly individually (usually trivially) and secondly with others in more meaningful scenarios.
For now, lets look at one of the instructions. Concentrate more on the format thereof, rather than the function
which well see closely later. Ive chosen the instruction ADDWF- see [PIC table 4.2]. In this tutorial, I have
adopted the Courier font below for all coding examples. The syntax of this instruction is:
ADDWF f , d
and youll see this sort of look in many other instructions.
This is an appropriate time to introduce the working register: this is a special register (over and above those already
mentioned) known as the W register, and it is where the arithmetic and logic unit (ALU) does the maths. Any
instruction with the W in the name acts on the working register. Generally, some other register is known as F in
these commands. So- almost intuitively- we can understand that the command ADDWF adds the working register to
register F. But where is register F?
Have a look at [PIC fig 4-2]: each register (other than W, that is, which isnt in the figure since it is a special one) is
given a hexadecimal address. For instance, PORTA is 05h, TRISA is 85h and we could use one of the 36 GP
registers between 0Ch and 2Fh like 3Ch. The f in the command is a place holder for the actual address of the
register F; remember there is no register F as such- it is a generic name for some register or other. So, we would
code the instruction as:
ADDWF 3Ch, d
Well, not quite- whats the d for? It is the destination of the result, and youll see this in many operations.
Depending on our needs at the time, we need to choose to put the result either back into the working register or
register F itself. [PIC page 51] explains that d may be 1 or 0: a 0 causes the result to go to W, and a 1 puts it in F.
Finally, therefore, this command could be either of the following, depending on our needs:
ADDWF 3Ch, 0 ; adds Wt o r eg 3C, r esul t t o W
ADDWF 3Ch, 1 ; adds Wt o r eg 3C, r esul t t o 3C
Lets get on with actually writing a simple program . . . .
A simple PIC84 program
This sample program serves a number of purposes. Apart from showing how to use a few instructions, it also
introduces a couple of the assembler concepts and will also show some simple simulator techniques. The program,
simple.asm is presented below; Ill walk you through it line by line.
Program 1: simple . asm
; si mpl e. asm
; t o demonst r at e t he l ook & f eel of a pr ogr am
; and i nt r oduce some i nst r uct i ons & di r ect i ves
; ***************** set up *******************************
pr ocessor 16C84 ; pr ocessor t ype
or g 0010h ; or i gi n of pr ogr ami n memor y
w equ 0 ; i n byt e i nst r uct i ons, use w & f
f equ 1 ; i nst ead of 0 & 1, i t s much cl ear er
my_r eg_1 equ H 10 ; posi t i on my 2 r egi st er s i n f i l e
my_r eg_2 equ H 15 ; map at h 10 & H 15
; ***************** pr ogr am******************************
; al l we' r e goi ng t o do, i s l oad t he accum( r eg w) wi t h
; some val ues and pl ay ar ound wi t h some ar i t hmet i c i n w
; and my_r eg_1&2
movl w H 08 ; put val ue H 08 i nt o w r egi st er
movwf my_r eg_1 ; move cont ent s of w t o my_r eg_1
; not e- same as movwf 10h, si nce
; my_r eg_1 and 10h ar e same t hi ng
movl w 32h ; put 32h i nt o w r eg
addwf my_r eg_1, f ; add cont ent s of w t o t hat of my_r eg_1
; answer goes i nt o my_r eg_1, due t o f
movl w 92h ; put val ue 92h i nt o w r egi st er
movwf my_r eg_2 ; move cont ent s of w t o my_r eg_2
; not e- same as movwf 15h, si nce
; my_r eg_2 and 15h ar e same t hi ng
movl w 26h ; put 26h i nt o w r eg
subwf my_r eg_2, w ; subt r w f r ommy_r eg_2
; answer goes i nt o w
end
Lets examine this sample program. You should verify the following by finding each directive or instruction in the
appropriate Microchip book:
Anything after a ; is a comment. Every programming book in the world recommends comments to
explain whats going on (at least to others, if not to yourself!).
In the part called setup, we meet three assembler directives:
o pr ocessor tells the assembler which model of Microchip the program is for. If this is incorrect,
then you might use an instruction in the code, for a processor which doesnt support that
instruction and an assembly error will result.
o or g tells the assembler where to start putting the code in program memory. From the memory
map [PIC figure 4.1], you can see that you should at least put your program beyond 0004h.
o equ is an equivalence. It simply means that the items on either side of equ mean the same thing.
For instance, the ADDWF instruction expects a 0 or 1 in the d place: by equating a w with a
0, it means we can use the w in the instruction rather than 0. This is easier to remember
during coding, and to read later. Similarly, by equating my_r eg_1 with 10h, every time I want to
refer to register 10h, I can more easily refer to it by its meaningful, more easily remembered,
name.
In the part called program, we meet a number of 84 instructions. Check the full descriptions in [PIC] if you like;
well be looking at them later, anyway.

o MOVLWk [PIC page 58] causes the value k (eg 08h) to be put into the working register.
o MOVWF f [PIC page 58] copies the contents of W into register f. Note that movwf is strictly a
misnomer, since this is really a copy (W is not cleared), not a move (in which W would be
emptied). Note too, Microchips convention in [PIC] by comparing movl wand movwf : in
describing the operation, the parentheses () mean the contents of. Thus k (W) means the
value k becomes the contents of W; (W) (f) means that the contents of W become the contents
of f. Lastly, be sure you understand the use of the equ concept with respect to registers. The f in
MOVWF f refers to a register; [PIC figure 4-2] shows that registers have hex addresses and we
would expect the instruction to read MOVWF 10h for instance. Equating my_reg_1 with 10h,
means I can write MOVWF my_r eg_1 with the same result.
o ADDWF f , d and SUBWF f , d [PIC pages 53 & 61] respectively perform the arithmetic
addition & subtraction on the contents of W and f. Note the use of the equivalencies here too; we
can refer to my_reg_1 as before, and also replace the allowed values of d (ie, 0 &1) with w & f
respectively. Hence we can write ADDWF my_r eg_1, f in place of ADDWF 10h, 1.
Lets assemble and run this program . . .


Using MPLAB to debug the program
This is a three step process: edit the source code, assemble it, and then run the simulator to see what happens. If you
worked through the MPLAB tutorial, you will already know about the editing and assembling. Ill assume you have
and do, and so we can move to the simulation.
With sample .asm successfully assembled, and the editor being the only window open in MPLAB, single-step
through the program (the footstep icon). Not too helpful- you see each line of the program being highlighted as it is
activated, but thats it.
So, lets start to use a few of the simulators other facilities. I suggest you open the following other windows in
MPLAB. They all serve similar purposes- namely to see whats happening in the registers- but all implement
differently. I found it useful to have them all open at once, to compare the implementations:
Window >File Register
This window lists the contents of all file registers from 00 to 2F- ie, it does not show those in the region 80
to 8B. As you step through the program, you will be able to see the hex contents of registers 10h and 15h
change. Note that any register whose contents have just changed is shown in red- this goes back to blue on
the next step (unless theres another change of course).
Window >Special Function Registers
Here you can see the SFRs by name, rather than location which is what the previous window shows. The
contents are shown in decimal, hex and binary.
Window >New Watch Window
This is your custom window into the registers, and it allows you to select which registers you want to
monitor. All registers are available to choose, both SFRs and GPRs. When you choose New Watch
Window, you are prompted with an input box and a down arrow. Click the arrow, and a list of all available
registers appears: choose the one you want (eg, my_reg_1) and then OK. Youll see the contents of the
register displayed in the window. To add other registers you can either click in the watch windows top-
left-corner icon, and then choose Add Watch; or just press the Insert key (while the watch window is
selected). You can save oft used combinations as .wat files, and then load them back later with Window >
Load Watch Window.
A word of warning . . . Where did the list of register names to select from, come from? The SFRs are
obvious: the MPLAB knows about them anyway. The others, like my_reg_1&2, come from the equ
directives in your code, which is great. However, in our example, we have also used w equ 0 and f
equ 1 although these are not intended as register names. However, they still appear in the list of
possibilities. So whats the problem- just dont choose them you say. But dont forget that w is a register:
so now there are 2 w entries in the list, one was there all along (the working register), and we caused the
other with the equ. Using either of them, causes a symbol not found error in your watch table, meaning
that you cannot monitor the working register if you have declared a w equ in your code. Try it yourself,
then comment the offending line out with a ;, re-assemble and try again. Now you can use the working
register in the watch.
With these three windows, step through your program: youve now got some insight into whats going on. Satisfy
yourself that all is working to plan.
Pause to reflect
Where shall we go from here? Well, where are we now? Weve looked at the architecture and instruction set
briefly; weve created a simple program and examined the code to get the feel of it; weve edited & assembled this
program; and weve seen some of the simulators facilities.
I think we should move on to look more fully at the instruction set. I know that [PIC] covers all the registers, flags,
interrupts, timers and stuff before going on to the instructions, but I found this the better way.
The Instruction Set
Microchip present full details of the instruction set in [PIC, section 9, page 51 on]. They group these into 3
categories which I dont find particularly useful. These are Byte- and Bit-oriented and Literal / Control operations. I
have taken the view of grouping them into what we use each command for, such as performing arithmetic. Page 52
in [PIC] gives a one-page summary of the commands; I made a copy of this page loose from the data sheet, for easy
reference. A windows help file is available on the Internet from Trisys Inc: I found this very useful. It contains
details- similar to those in [PIC]- on the instruction set and the special function registers. Its a normal windows
help file, with the expected hypertext links & searches.
For each instruction, I have explained the operation as described in [PIC], and have expanded on [PIC]s
explanations where appropriate. (For instance, I have explained what an inclusive or actually is in IORWF.) Perhaps
more importantly, I have suggested exercises to use the instructions as presented, with a possible solution given in
the Appendix. The exercises suggested are quite trivial, but will afford you the opportunity to use each instruction,
and also practice using the simulator. Remember to use things like the watch window to see whats going on as you
step your program: keep an eye on registers you decide to use, as well as W and STATUS.
Instruction format
Microchips grouping does keep instructions of similar format together. The instructions look like this:
byt e_command f , d
where f is the file register designation and d is the destination; if d=0, the result goes to the working
register, w; if d=1, the result goes to register f
bi t _command f , b
where f is the file register, and b is the bit therein; bits are numbered from 0 on the right, to 7 on the left. In
the text, a bit is written as FILE_REG<n>, for instance INTCON<4>means bit no 4 in the intcon register
at 0B
ot her _command k
where k is an 8-bit constant or literal.
The STATUS register
The 84 implements a STATUS register at 03h, which contains the arithmetic status of the arithmetic & logic unit;
see [PIC fig 4-3]. Have a glance down the Status Affected column of [PIC table 9-2], and you will see that many
84 instructions affect certain parts of STATUS. Many instructions affect STATUS<2>, Z- the Zero flag, which
gets set if the result of an operation was zero. Certain operations affect the carry bits: STATUS<0>, C- the Carry
bit, is set if a carry out occurs from the left-most bit in the result; STATUS<1>, DC- the Digit Carry bit, is set if
there is a carry between the hex digits (ie, from the right hand nybble (bit 3) to the left hand nybble (bit 4). Two
commands affect STATUS<3>, the Power Down bit PD, and STATUS<4>, the Time Out bit TO.


1: Move instructions
We have met some of these instructions, which do nothing other than put things in registers.
MOVF f,d (Move f, PIC p58)
(f) (dest)
MOVWF f (Move W to f, PIC p58)
(w) (f
MOVLW k (Move literal to W, PIC p58)
k (W)
Exercise: Write a program to use these commands to (for instance) put something into W, move it from there to
another register, put something else into W, and then move the original thing back to W. See moves .asm.
2: Clear instructions
These 2 commands clear a register.
CLRF f (Clear f, PIC p55)
00h (f)
CLRW (Clear W, PIC p55)
00h (W)
Exercise: Expand the above program to clear registers at the end. See clears .asm .
3: Arithmetic instructions
Performing arithmetic is pretty important: thats why computers are called computers after all. The 84 can only add
and subtract though.
Arithmetic occurs either between W and an f register:
ADDWF f,d (Add W & f, PIC p53)
(W)+(f) (dest)
SUBWF f,d (Subtract W from f, PIC p61)
(f)-(W) (dest)
or between W and a literal:
ADDLW k (Add literal & W, PIC p53)
(W)+k (W)
SUBLW k (Subtract W from literal, PIC p61)
k-(W) (W), [PIC p61]
Exercise: Use these and previous commands to load some registers and W, and do some adding and subtracting.
Keep a close eye on the carry bit and on the zero bit in the status register. See arith .asm.
Technical aside: You may see in [PIC] that subtraction is performed using the 2s complement method. Que? I
hear you ask. This is the normal way that subtraction occurs in binary. Ill explain, then look at an example. Express
both numbers in binary. Leave the number from which you are taking away, unchanged. Form the 2s complement
of the one which is being taken away thus: change all 0s to 1s and all 1s to 0s (this is the complement), add 1 to the
right hand digit, carrying to the left as necessary. Now add the result to the unchanged other number. Discard the
carry at the left, if there is one. Thats the answer. Lets check . .
We want to subtract 20 from 27- we should get 7. Proceed as follows:
Convert to binary: 27 11011 . . . . x
20 10100 . . . . y
Make 2s complement of y: complement: 01011
add 1: 01100 . . . . z
Add x and z: +11011 . . . . x
1.
1.






1. 00111 =7 QED.
The 1 in brackets is the carry, which gets discarded.
4: Logical functions
At this stage, before we examine the logical functions provided by the 84, well discuss what logical functions are.
Consider for the time being an electronic device of some description, with 3 wires attached. Lets say that 2 wires
are inputs, and that what gets output on the 3
rd
wire depends on the inputs. Further, well say that this is a digital
device, so that the 3 wires can only have binary values of 1 & 0.
What relationships can exist, then, between the 2 inputs and the output? The input combinations are easy: if
wire/pin 1 can be 0 or 1, and so can pin 2, then the combinations are 00, 01, 10 & 11. What about pin 3: perhaps it
must be a 1 if and only if the inputs are both 1 (ie 11); or perhaps a 1 if either or both inputs is 1 (ie 01, 10, 11). Or
whatever!
The basic relationships are known as and and or; and means both inputs while or means either or both. Most
explanations of this resort to the so called truth table, which I have drawn below for the following logical
operations: and, or, xor, nand, nor. Ill explain them once youve had a look at the table.

Inputs A B A AND B A OR B A XOR B A NAND B A NOR B

both either, both either, not both not both neither, not both
00 0 0 0 1 1
01 0 1 1 1 0
10 0 1 1 1 0
11 1 1 0 0 0
The function and means that the result is 1 only when both inputs are 1. The or means that either input may be a 1
for output to be 1, but so may both. The function xor means exclusive or, and means that either input as 1 will cause
a 1 to be output, and specifically excludes the situation where both inputs are 1. Lastly, the nand and nor are the
negations of and and or respectively: compare the columns and youll see what this means.
By the way, the or function (as opposed to the xor function) is sometimes known as the inclusive or (ior). The 84
in fact uses this term.
The 84 provides a number of logical operations which act on 2, 8-bit values; these values are compared bit for bit.
For example- without yet looking at an 84 instruction- consider the anding (is there such a word?) of the numbers
H5F (equivalent to D95 and B01011111) and HA3 (which is D163 and B10100011); resulting in H03
(which is D3 or B00000011).
5F: 01011111
A3: 10100011
and: 00000011
Clearly, only in the rightmost 2 positions is the and satisfied, resulting is 1s there and 0s elsewhere. You should
check this on the calculator in Windows, which has logical functions built in.
So, lets move to the instructions as provided by the 84.
Comparison occurs either between W and an f register:
ANDWF f,d (AND W with f, PIC p53)
W. .and. (f) (dest)
IORWF f,d (Inclusive OR W with f, PIC p58)
W. .or. (f) (dest)
XORWF f,d (Exclusive OR W with f, PIC p62)
W. .xor. (f) (dest)
or between W and a literal:
ANDLW k (AND literal with W, PIC p53)
W. .and. k (W)
IORLW k (Inclusive OR literal with W, PIC p57)
W. .or. k (W)
XORLW k (Exclusive OR literal with W, PIC p62)
W. .xor. k (W)
Lastly, you may have noted that the 84 doesnt provide nand or nor functions. Rather, it provides the means of
complementing (negating) a register; this means to nand you must first and and then com:
COMF f,d (Complement f, PIC p56)
complement of (f) (dest)
Exercise: I suggest 2 things here. First, using Windows calculator, verify the results of the examples in [PIC] with
each of the above: this will ensure that you understand the concepts. Then, write an assembler program to verify the
84 instructions, by loading the appropriate registers, performing the actions, then checking the results. See logic
.asm.
5: Decrementing & Incrementing
Two simple instructions can decrement or increment the contents of a register, thus:
DEC f,d (Decrement f, PIC p56)
(f)-1 (dest)
INC f,d (Increment f, PIC 57)
(f)+1 (dest)
Exercise: In a program, perhaps by adding to one of the previous ones in which you do some arithmetic or some
logic, check out that these commands do work. Keep an eye on the Zero flag, which is set if either command causes
the register in question to go to zero: well rely on this fact in 2 more commands later. See dec_int .asm
6: Bit setting & clearing
Using the following 2 commands, you can set or clear any bit b in register f. But why would we want to? Two
reasons come to mind:
First, as an example, the register in question might be a port controlling some external equipment. Each bit
could be switching a different device: a motor, a light or whatever. Setting and clearing each bit switches
each device on or off.
Second, as well see in 8. below, we can use the fact that a bit is set or clear to skip instructions in our
program. Being able to set or clear any bit gives us the ability to control this process.
BCF f,b (Bit clear f, PIC p54)
0 (f<b>)
BSF f,b (Bit set f, PIC p54)
1 (f<b>)
We read these two operations as "0 (or 1) becomes the content of bit b in register f".
Exercise: Sprinkle these commands into any of the programs above, and watch the changes to individual bits in
your watch window. See bits .asm
7: Program control
For many reasons, we need to control the flow through our program. Normally, flow proceeds linearly from the top;
often this is not suitable.
Firstly, we often need to loop through certain instructions: we might have a system in which one process is a
continuous one. This might be the control of a bucket conveyor which continuously adds ingredients to a vat. Here,
when a bucketful is added, we take it from the top and go through the same steps again, adding more on each pass.
Second, there may be part of our program which is useful in many other parts. Rather than repeating this code in
many places, we separate the piece we like from the rest of the code; then we merely call it in as often as we like,
from wherever. The reusable piece is called a subroutine. The subroutine returns control to the point from which it
was called when its finished.
Lets look at looping first:
GOTO k (Go to address, PIC p57)
k (PC)
This instruction literally goes to k, which it does this by loading the address of k into the program counter, PC. In
order to use goto you should start the line to which you want to go, with a label. Then you goto label. See [MPASM
p15] for rules on labels.
Exercise: Modify one of the programs you have already written. You could put a label near the top, and a goto later
on. As you step, youll see from the highlighted line that your program loops through the same part again and again.
Look at the program counter (pcl) in a watch window and youll verify this. See goto .asm
Now we shall examine subroutines. We need to understand the concept of the stack first. Look at [PIC figure 4-1]
and youll see a connection between the program counter and the stack. The stack- which has 8 levels in the 84- is
the repository of where the PC was before the subroutine was invoked. This is so that the program can go back to
take up where it left off when the subroutine is finished. Strictly speaking, the stack is loaded with the address of the
instruction immediately after the one doing the sending; otherwise it would keep on going back and performing the
instruction it had done earlier- we really want the next one. We refer to loading the stack as pushing and taking a
value off later as popping. The stack is only accessible at the top: its like a pile of plates in one of those hoppers in
a restaurant. The top of the stack is abbreviated as TOS.
There are 2 instructions associated with any subroutine- one to send the program off to it, the other to bring it back:
CALL k (Call subroutine, PIC p55)
(PC)+1 TOS, k (PC)
The call to a subroutine pushes the current PC+1 onto the stack, then changes the PC to the address k. This results
in program flow jumping to the subroutine, but the address to come back to later is safely ensconced on the stack
for later retrieval.
RETURN (Return from subroutine, PIC p60)
TOS (PC)
Return is the last instruction in the subroutine itself. The return instruction pops the stack, and so the program
resumes in the right place. Think about the depth of the stack: it means that calls can be nested, and flow will be
correct as long as the calls are matched by returns. Consider the following, which is OK:
CALL . . . . . push 1
st
addr ess
CALL. . . . push 2
nd
addr ess
RETURN. . . pop 2
nd
addr ess
RETURN. . . . . pop 1
st
addr ess.
But we dont want this, which is not OK:
CALL . . . . push 1
st
addr ess
CALL . . . push 2
nd
addr ess
RETURN . . . . pop 1
st
addr ess
RETURN . . . pop 2
nd
addr ess.
As an alternative to the vanilla-flavoured return, you can bring a value back with you, thus:
RETLW k (Return with literal in W, PIC p59)
k (W), TOS (PC)
This is the normal return, with the k (W) added.
Exercise: Write a program to execute some code- anything you like- and then branch to a subroutine to do
something else. Check that you return correctly. Use both types of return.
Problems? You probably had a little difficulty wondering where to put the subroutine in the source. How do you
stop the subroutine being run by mistake? Because wherever you put it- either above or below the main part of the
program, the programs natural flow will go through the subroutine, which is called subby here. If the stack is
empty , this causes a stack underflow error, as when the subroutines return is encountered before a call has been
made. If the stack has indeed been pushed by some other event- like an interrupt- then the return would be honoured
but incorrectly.
; exampl e 1 ; exampl e 2
. .
. .
l abel subby cal l subby
. subby code her e .
. and her e .
r et ur n l abel subby
. . subby code her e
. . and her e
cal l subby r et ur n
. .
. .
The way around this seems to be to proceed more or less as example 1, with the subroutines at the top. But, down
below where the main part of the program is, have a label like start; above the subroutines, have a goto start to hop
over them in the normal course of things. When a subroutine is called, the program shoots to the top: one subroutine
will not flow into another, because the return will take care of this. Thus:
got o st ar t
l abel subby1
.
r et ur n
l abel subby2
.
r et ur n
st ar t
.
.
cal l subby2
.
cal l subby1
.
. et c
See subby .asm
Associated with these last 2 commands is another type of return, which is to do with
interrupts. We will look at interrupts later, but for completeness Ive put the return from
interrupt here:
RETFIE (Return from Interrupt, PIC p59)
TOS (PC), 1 GIE
When an interrupt occurs, the PC is pushed to the stack like with a subroutine call, so retfie pops it back out. Also,
though, the occurrence of an interrupt disable further interrupts: one doesnt want interrupts interrupted after all.
What happened was, that the interrupt caused the global interrupt enable flag, GIE (INTCON<7>) to be set to 0.
Returning from an interrupt means that further interrupts should be allowed, hence retfie sets GIE back to 1.
8: Skipping instructions
There are 4 instructions which allow you to skip over the next instruction. Ill explain this before we look at the
commands themselves.
In the conveyor example above, we dont want the vat to overflow, so lets have a level sensor in the vat (just like
the ball-valve in the loo) which switches on when the vat is full. The conveyor is running, adding bucketsful; the
program needs to monitor the switch, and when the vat is full (the switch closes) the program switches off the
conveyor and starts some other part of the process, perhaps the mixer. This process is shown below: the dots show
some or other process happening before and after the part of interest. Ive used line numbers for ease of reference.
This is not in 84 assembler!
.
l i ne # 40: st ar t conveyor
.
.
l i ne # 63: i s t he l evel sensor swi t ch set ?
l i ne # 64: no- go back t o l i ne # 63 and l ook agai n
l i ne # 65: yes- st op t he conveyor
l i ne # 66: st ar t t he mi xer and car r y on
.
.


In this example, we need to skip line 64 when the vat is full. When the vat still has room, this code will cause more
ingredient to be added; the conveyor will stop and the mixer will start when the vat full sensor has switched on.
Now we can look at the commands which do this skipping in the 84:
DECFSZ f,d (Decrement f, skip if 0, PIC p56)
(f)-1 (dest), skip if result =0
INCFSZ f,d (Increment f, skip if 0, PIC p57)
(f)+1 (dest), skip if result =0
The above commands are based on the decf and incf commands seen earlier: the sz part means skip if zero.
Exercise: Verify these 2 instructions by loading a start value into a register called count or something. Then use
either instruction to change it, looping through this block of code. Check that the instruction following the decfsz or
incfsz (probably a goto, to cause the looping) is skipped or not, as appropriate. (This approach would work if the
conveyor had to add say 10 bucketsful, rather than wait for a sensor.) See skip .asm.
BTFSC f,b (Bit test f, skip if clear, PIC p54)
skip if (f<b>)=0
BTFSS f,b (Bit test f, skip if set, PIC p55)
skip if (f<b>)=1
Read these instructions as bit test f, skip if clear/set".
These commands could be used to check the vat full sensor mentioned above. The bit to be tested would be the bit
of a port on the 84: it would be set or cleared by the sensor from time to time.
Exercise: Write a program with a block of code to loop through. These can be just about any instructions, and will
simulate the conveyor as nonsense. Have a btfss at the bottom, followed by a goto back to the top. Have some more
code then, which simulates the mixer coming on. The btfss will need to refer to one of the 84s I/O ports as its f
(H05 or H06 for porta & b respectively), and you can use any pin 0-4 on porta, 0-7 on portb you wish. You
should have another goto right at the bottom, to make a sort of outer loop back to the top- this might not be too real-
life, but youll want the whole program to loop to test what happens when the pin changes. See bits .asm
But how do we get the pin to change its state, simulating the vat full sensor? Theres an easy way of doing this in
MPLABs simulator. Go Debug >Simulator stimulus >Asynchronous stimulus; youll get a table of Stim0 to
Stim12 buttons. Right click on any one, perhaps Stim7, and click Assign pin. Double click on the pin youve elected
to use as the sensor, perhaps it was RA3, say. Stim7 then changes to RA3 . Now right click on the button again: you
can choose to pulse, make low, make high or toggle the pin. Here, we would want to toggle the pin, since the vat
sensor will be changing from time to time probably, as it empties and fills.
Now were all set to test. Step through your program. Depending on the initial state of the pin, which [PIC table 4-
1] says is unknown at power up, the program will loop or not. (At the inner loop, that is; it will always go back to
the top from the very bottom, for testing purposes.) Any time you like, left click on your chosen Stim button, now
known as RA3 or whatever. (If you have the port showing in a watch window, youll see the pin change state at the
next instruction boundary.) In any case, next time the program gets to the btfss step, it should behave differently,
since weve toggled the pin and so the btfss should get a different answer.


9: Rotations & Swap
Three instructions allow you to manipulate the bits within a register. Of these, two slide the bits to the right or left
(through the carry bit), the third switches the registers two nybbles over.
RRF f,d (Rotate right f thru carry, PIC p60)
Each bit in the f register is moved 1 to the right; the one that falls off the right is circled round to the carry,
and the carry moves in from the left.
RLF f,d (Rotate left f thru carry, PIC p60)
Each bit in the f register is moved 1 to the left; the one that falls off the left moved into the carry, and the
carry is circled round to the right.
SWAPF f,d (Swap nybbles in f, PIC p62)
(f<3:0) (dest<7:4>), (f<7:4>) (dest<3:0>)
Exercise: Observe the effect of these commands on the contents of some registers. See rot_swap.asm.
10: Sleep & Watchdog Timer
These 2 commands are related, in that the WDT is one of the ways of waking up from sleep. I cover the whole
notion of timers later, so for now accept these instructions for what they are.
SLEEP (Sleep, PIC p60)
0 WDT, 0 WDT prescaler, 1 TObar, 0 PDbar
CLRWDT (Clear watchdog timer, PIC p56)
0 WDT, 0 WDT prescaler, 1 TObar, 1 PDbar
11: Miscellaneous
NOP (No operation, PIC p59)
This instruction literally does nothing
You should not use the following 2 instructions, which are included to provide backward compatibility:
OPTION (Not recommended)
TRIS (Not recommended)
Pause to reflect
We have now met each 84 instruction, with the necessary background if appropriate, and used them in simple
programs. Now, well move on to explore two important areas of the PIC84: interrupts and timers. It is these two
areas which move the 84 into the real world.

Interrupts on the 84
Whats an interrupt?
Put simply, its exactly what it says: a means of getting the computers attention. Refer to the conveyor/mixer
scenario mentioned earlier (p17), where we saw the following snippet of pseudocode:
.
l i ne # 40: st ar t conveyor
.
.
l i ne # 63: i s t he l evel sensor swi t ch set yet ?
l i ne # 64: no- go back t o l i ne # 63 and l ook agai n
l i ne # 65: yes- st op t he conveyor , t hen
l i ne # 66: st ar t t he mi xer and car r y on
.
.
Here, the program will loop around line 63 and 64 for ever if necessary, waiting for the vat to fill up. Thats OK, the
programs job is to run the process! Well, true, but its wasteful. It might take a few seconds, minutes or hours to fill
the vat; we could have the program doing something useful while its waiting. But if the programs off somewhere
else- doing the payroll?- and the switch closes, how will the program know? Its not looking.
Same way as you get someones attention when you come to visit. Theyre not standing looking out the front door
all day, theyre going about their daily business; your knock on the door interrupts this, and they come to the door.
Our program would look something like this:
.
l i ne # 40: swi t ch on t he conveyor
.
l i ne # 50: do some payr ol l wor k
l i ne # 51: and some mor e, and st ay up her e unt i l i nt er r upt ed
.
.
.
l i ne # 60: onl y come her e when i nt er r upt ed
l i ne # 61: st op t he conveyor
l i ne # 62: swi t ch on t he mi xer
l i ne # 63: go back t o wher e you wer e when you got sent her e
Now, the program spends most of its time in the payroll section, not looking at the switch in the vat. When the
switch closes, the hardware takes care of things: the switch is connected to the computer by the interrupt request
line (IRQ), and program control is passed to a predetermined point. That point is line #60 in the example above,
and what happens at line 60 is up to the program/mer.
Notice something crucial here: once the interrupt has been taken care of, control must go back to where it was
earlier. Not only that, but the state of the system must be put back: if any registers were changed while handling the
interrupt, they must be restored. Well look into this later.
Now we know what an interrupt is in concept, we can look at how the 84 allows for this notion.


Types of Interrupt and the INTCON register
The 84 has 4 different types of interrupt [PIC p44]:
an external interrupt on pin 6, aka RB0
a change on any of pins 10-13, aka RB4-7
a timer overflow
an EEPROM write complete.
(Of these 4 types, the first one is the kind wed use in the above conveyor/payroll program.)
In order to allow interrupts, and to determine the source thereof, the processor uses the INTCON register (0Bh)
whose contents are detailed in [PIC table 4-5], and which Ill explain here. Each bit serves a specific purpose, and
interrupts work according to the value (set or clear) of the various bits.
Firstly, interrupts as a whole may be enabled or disabled by INTCON<7>, the GIE (Global Interrupt Enable) bit. If
this bit is clear, then no interrupts may occur: this is the power-up value by the way. Also, if an interrupt occurs,
then GIE is cleared to prevent the interrupt being interrupted; returning from the interrupt with the retfie instruction
re-enables interrupts.
Second, each of the interrupt types must be enabled with its own bit in INTCON, before it can be used:
external interrupt on pin 6: INTCON<4>, the INTE bit
change on any of pins 10-13: INTCON<3>, the RBIE bit
timer overflow: INTCON<5>, the T0IE bit
EEPROM write complete: INTCON<6>, the EEIE bit.
Third, when interrupts occur, certain bits (known as interrupt flags)are set so that we may determine the source of
the interrupt:
external interrupt on pin 6: INTCON<1>, the INTF bit
change on any of pins 10-13: INTCON<0>, the RBIF bit
timer overflow: INTCON<2>, the T0IF bit.
Why do we need to know the source? Well, depending on the type of interrupt, we will take different action:
checking the appropriate bit tells us which interrupt it is. Note that the interrupt flags always get set when theres an
interrupt, regardless of the state of the corresponding enable bit.


Servicing an Interrupt
In the conveyor/payroll example above, there must be a means of sending the program to the right place to sort out
the interrupt; line 60 in the example. How does the processor know where to go? In the PIC84, all interrupts are
sent to 0004h: in the parlance of microprocessors, this point is the interrupt vector, and the program is said to
vector there. At the vector, we must make sure that we provide whatever code is necessary to take care of the
problem.
A crucial point is that we might need to save the status of the machine as it was before interruption, before we
service the interrupt. Clearly, the activities undertaken during servicing could change such things as the W &
STATUS registers; we would need these restored after handling the interrupt, in order that our other work may
resume. The 84 only saves the PC to the stack (PC+1, actually), and its up to us to ensure we save and restore
anything else we need!
Lets walk through a scenario in pseudocode, without yet looking at the 84 code. Foster suggests 3 parts to a
program which must handle simple interrupts: an initialize section, where in our case well enable the interrupts; a
main section, where the bulk of the time is spent (doing the payroll, or whatever) and the handler part where the
interrupt is taken care of.
I ni t i al i ze: set GI E, I NTCON<7>, t o enabl e i nt er r upt s
set I NTE, I NTCON<4>, t o enabl e pi n 6 i nt er r upt
Handl er : save t he st at us of t he machi ne; pr obabl y W& STATUS
o

check i nt er r upt f l ags f or sour ce; I NTF, RBI F, T0I F
br anch t o t he cor r ect sub- handl er f or t he
i nt er r upt t ype
o

( we ve onl y set I NTE, t hough)
do what ever i s r equi r ed f or t he i nt er r upt
r est or e t he st at us
r et ur n
Mai n: do t he payr ol l cal cul at i ons
Exercise: Start slowly with interrupts- this can get quite hairy. Write a program to provide
the absolute minimum interrupt ability: enable them, have an interrupt service routine
that does little if anything other than re-enable interrupt and then return, and a main part
that merely loops through some meaningless code waiting for an interrupt. You need not
save the status of the machine, nor check for the type of interrupt at this stage. In order to
see this program working properly in the simulator, I suggest using the interrupt on
change in port b, using the asynchronous stimulus technique discussed before. Use a toggle
on the pin to effect the change: while the program is looping in the main section, toggle the
pin and check that the interrupt occurs when you next step the program. While the
program is then in the isr, toggle the pin again: if its all working, the pin change will not
cause an interrupt, because GIE will have been cleared. See inter1 . asm.
Exercise: Now add to the program, to save the state of the machine at the interrupt. To test
this, make sure you load W (say) in the main part, then change it in the ISR, and check
that it gets restored properly. Hint: see [PIC p46, example 8-1]. See inter2.asm
Exercise: Finally, allow for more than 1 kind of interrupt- change on one of portb pin 4:7
as well as an interrupt on the rb0/int pin. Now, youll need to determine the kind of
interrupt, and handle it accordingly. See inter3.asm.

Timers on the 84
The basic idea
The basic idea, is that we will want to use our 84 to time something. Time, that is, in the way we would use a wall
clock: we might switch on our fish-tank lights for instance, or close the curtains at 18h00 each night. But theres no
clock in the 84: no clock in the wall clock sense anyway.
What there is though, is a simple relationship between the carrying out of instructions and the speed with which the
processor ticks away. The book tells us [PIC p1] that an instruction completes in 1 cycle, namely 400ns when the
processor is being clocked at 10MHz.
Lets verify this, and introduce a handy feature of MPLAB at the same time: the Stopwatch. In MPLAB prepare to
run any of the programs you have written up to now. Open the stopwatch by going Window >Stopwatch. Youll
see a simple window, containing 3 important pieces of information: the number of steps completed in what time,
and at what frequency. Check that the frequency is set to 10MHz for now, click zero and step your program once.
You should see that you progress to 1 cycle in 400ns. (Unless this was coincidentally a program branch, which is a
2-cycle instruction.) Experiment with various frequencies; for instance 400ns becomes 40ns at 100MHz, or 800ns at
5MHz.
So, we have the glimmerings of a wall clock type of timer here- we know how much time has passed if we know
how many steps have occurred. Enter Timer0 . . .
The TIMER0 module
The PIC84 timer, TIMER0, works on the basis that each time an instruction cycle occurs, a certain interval of time
has elapsed. When TIMER0 is running, its register (TMR0) is incremented each cycle; each 400ns if the clock is a
10MHz one. Therefore, the value of TMR0 represents the time in 400ns steps. But TMR0, like all registers, is an
8-bit one and can thus only count as high as FF: that means time only goes as far as 255 x 400ns =102000ns or
about 100 s which is not too long. Cast your mind back to the discussion of interrupts earlier, where we said that
one of the interrupt types was a timer overflow interrupt: that means that the TMR0 register has gone over the top at
FF and back to 00. That means the interrupt occurs every 100 s of real time. Its up to us to do something with this
interrupt, which probably means incrementing a register of our own, clocked say: every time clocked gets to a
certain value, that means 1 second of real time, and wed probably then go off and increment another register,
perhaps seconds
Lets walk through the process, then, of simply getting TIMER0 going, using the initialize, handler, main interrupt
technique used earlier.
I ni t i al i ze: set GI E, I NTCON<7>, t o enabl e i nt er r upt s
set T0I E, I NTCON<5>, t o enabl e t i mer i nt er r upt
cl ear T0CS, OPTI ON<5>, t o enabl e t i mer - see
set PSA, OPTI OPN<3>, t o keep pr escal er out of t hi s
Handl er : i ncr ement cl ocked , our over f l ow count er
Mai n: have some t r i vi al l oop t o keep t he pr ogr amgoi ng
Exercise: Write a program to implement the above simple timer, bearing in mind we wont
be doing anything with the timer overflows other than clicking them in clocked. Check the
program in the simulator, having visible any registers you think you should monitor, also
the stopwatch. Before you start, youll need to figure out how to access the option register,
which is not quite as simple as accessing say status. Ive explained it below. See time1.asm.
Accessing registers in Bank1: Youll have noticed in [PIC fig 4-2, p12] that some registers
like option are in what they refer to as Bank1, as opposed to Bank 0. Others, like status are
in both Banks. What this means in practical terms, is that these Bank 1 registers are not
normally available, because our default sphere of operations is Bank 0. We use the status
register to effect a switch between banks, with RP0 & RP1 (STATUS<5> & <6>) doing the
trick. This simply means that we must set RP1 to go to Bank1 and clear it to return. For
those registers which are in both banks, you can of course access them no matter where
you are, but remember the register has 2 different addresses: status is known as h03 and
h83.
Using the timers overflow
Now we can probably see the wood through the trees: we have a register clocked which is updating whenever the
timer overflows. Thats roughly every 100 s. Being an 8-bit register itself, clocked can of course only count to
255, and so it will overflow at 255 x 100 s which is 2.55 x 10
-2
seconds. Well need to count these overflows too,
into say clocked2. Now, were getting closer to the actual second, which is what were heading for: how high do we
need to count in clocked2 to reach 1 second? Incrementing every .0255 seconds there are roughly 39 increments in
a second , so this means, finally, we can count real-time seconds by incrementing another register, perhaps
SECONDS, every 39 steps. To get to minutes and hours, we can simply overflow SECONDS into MINUTES at 60
seconds and MINUTES into HOURS every 60 minutes.
Exercise: Create a program to implement the above, at least as far as the SECONDS register.

Using the EEPROM data memory
Appendix: Program listings
The following programs are intended as illustrative of the use of the commands discussed. They are certainly trivial,
and probably not paragons of programming technique! In each, I have added a section called si mul at or : this
section is a suggestion for things you might like to do during the simulation of your program. For instance, you
might need to have a watch window open showing the W register and portb, as well as having the stack open too. Of
course, its up to you how you design and code these programs, and how you experiment with them in the
simulator.
Program 2: moves . asm
; moves. asmt o show how MOVF, MOVWF & MOVLWwor k
; *********************************** si mul at or ***
; wat ch wi ndow: r eg1, w, pcl
; *********************************** set up ***
pr ocessor 16c84
r eg1 equ h' 10'
; *********************************** pr ogr am***
st ar t : movl w h' 05' ; l oad w
movwf r eg1 ; move ( w) t o r eg1
movl w h' 82' ; change w
movf r eg1, 0 ; r est or e w
end


Program 3: clears . asm
; cl ear s. asmt o show how cl r f & cl r w wor k
; based on moves. asm
; *********************************** si mul at or
; wat ch wi ndow: r eg1, w, pcl
; *********************************** set up
pr ocessor 16c84
r eg1 equ h' 10'
; *********************************** pr ogr am
st ar t : movl w h' 05' ; l oad w
movwf r eg1 ; move ( w) t o r eg1
movl w h' 82' ; change w
movf r eg1, 0 ; r est or e w
cl ear : cl r f r eg1 ; cl ear r eg1
cl r w ; cl ear w
end


Program 4: arith . asm
; ar i t h. asmt o show usi ng ADDWF, SUBWF, ADDLW, SUBLW
; ************************************* si mul at or
; wat ch wi ndow: r eg1, r eg2, st at us, w, pcl
; ************************************* set up
pr ocessor 16c84
r eg1 equ h' 10'
r eg2 equ h' 12'
; ************************************* pr ogr am
l oads: movl w d' 20' ; l oad w
movwf r eg1 ; l oad r eg1
movl w d' 80' ; l oad w anew
movwf r eg2 ; l oad r eg2
ar i t h: addl w d' 05' ; add d' 05' t o w
subl w d' 100' ; sub w f r omd' 100'
addwf r eg1, 1 ; add w t o r eg1, i nt o r eg1
subwf r eg2, 1 ; sub w f r omr eg2, i nt o r eg2
end




Program 5: inter1.asm
; i nt er 1. asmi s a si mpl e i nt er r upt handl er -
; i t does not save t he st at e of t he machi ne
; nor does i t det er mi ne t he ki nd of i nt er r upt .
;
; *********************************************si mul at or
; wat ch wi ndow: i nt con, pcl
; st ack: have t hi s open t oo- see t he r et ur n addr ess come & go
; asynch st i mul us: have a t oggl e on r b4
; ********************************************* set up
pr ocessor 16c84
movl w h' 0'
movwf h' 0b' ; cl ear i nt con
got o mai n ; hop over t he i sr
; ********************************************** i sr st ar t
i sr : or g h' 0004' ; i nt er r upt s al ways vect or t o her e
nop ; her e we act ual l y do t he st uf f
nop ; of t he i nt er r upt
bcf h' 0b' , 0 ; cl ear i nt bef or e goi ng back
r et f i e ; t hi s r e- set s i nt con gi e
; *********************************************** i sr ends
;
; *********************************************** mai n st ar t
mai n: or g h' 0020' ; l eave enough r oomf or t he i sr !
bsf h' 0b' , 7 ; set gl obal i nt enabl e
bsf h' 0b' , 3 ; set change on b i nt enabl e
payr ol : nop ; l oop her e unt i l i nt er r upt ed,
nop ; doi ng payr ol l st uf f
got o payr ol ;
nop
nop
end




Program 6: inter2.asm
; i nt er 2. asmdoes save t he st at e of t he machi ne
; but does not det er mi ne t he ki nd of i nt er r upt .
;
; ****************************************************si mul at or
; wat ch wi ndow: i nt con, pcl , por t b, w, w_saved
; st ack: have t hi s open t oo- see t he r et ur n addr ess come & go
; asynch st i mul us: have a t oggl e on r b4
; **************************************************** set up
pr ocessor 16c84
w_saved equ h' 10' ; a pl ace t o keep w
movl w h' 0'
movwf h' 0b' ; cl ear i nt con
got o mai n ; hop over t he i sr at t he begi nni ng
; **************************************************** i sr st ar t
i sr : or g h' 0004' ; i nt er r upt s al ways vect or t o her e
movwf w_saved ; save w as i t was i n mai n
movl w h' 65' ; do somet hi ng t o change w
nop ; do mor e i sr st uf f
; now, r est or e w: t her e i s
; no " movf w" - 2 swapf ' s seems t o be
; t he way t o do t hi s. . . .
swapf w_saved, 1 ; f i r st , swap w_saved i nt o i t sel f
swapf w_saved, 0 ; t hen, swap i t i nt o w
bcf h' 0b' , 0 ; cl ear i nt on b bef or e goi ng back
r et f i e t hi s r e- set s i nt con gi e
; ***************************************************** i sr ends
;
; ****************************************************** mai n st ar t
mai n: or g h' 0020' ; l eave r oomf or t he i sr !
bsf h' 0b' , 7 ; set gl obal i nt enabl e
bsf h' 0b' , 3 ; set change on b i nt enabl e
payr ol : nop ; l oop her e unt i l i nt er r upt ed,
nop ; doi ng payr ol l st uf f
movl w h' 0f ' ; si mul at e a cal c by l oadi ng w
got o payr ol ;
nop
nop


end
Program 7: inter3.asm
; i nt er 3. asmsaves t he st at e of t he machi ne
; and det er mi nes t he ki nd of i nt er r upt .
;
; **************************************************si mul at or
; wat ch wi ndow: i nt con, pcl , por t b, w_saved, w
; st ack: have t hi s open t oo- see t he r et ur n addr ess come & go
; asynch st i mul us: have a t oggl e on r b4( f or r bi ) and r b0( i nt )
; ************************************************* set up
pr ocessor 16c84
w_saved equ h' 10' ; a pl ace t o keep w
movl w h' 0'
movwf h' 0b' ; cl ear i nt con
got o mai n ; hop over t he i sr at t he begi nni ng
; *************************************************** i sr st ar t
i sr : or g h' 0004' ; i nt er r upt s al ways vect or t o her e
movwf w_saved ; save w as i t was i n mai n
; f i nd out what ki nd of i nt er r upt
bt f sc h' 0b' , 0 ; i s i t an r bi ?
cal l _r bi ; yes- cal l t he r bi ' sub- handl er '
bt f sc h' 0b' , 1 ; i s i t an i nt ?
cal l _i nt ; yes- cal l t he i nt ' sub- handl er '
; end up her e af t er sub- handl er
; now, r est or e w
swapf w_saved, 1 ; f i r st , swap w_saved i nt o i t sel f
swapf w_saved, 0 ; t hen, swap i t i nt o w
bcf h' 0b' , 0 ; cl ear r bi f bef or e goi ng back
bcf h' 0b' , 1 ; cl ear i nt f bef or e goi ng back
r et f i e ; t hi s r e- set s i nt con gi e
_r bi : movl w h' 65' ; do somet hi ng t o change w
r et ur n
_i nt : movl w h' 24' ; do somet hi ng di f f er ent t o w
r et ur n
; ***************************************************** i sr ends
;
; **************************************************** mai n st ar t
mai n: or g h' 0020' ; l eave r oomf or t he i sr !
bsf h' 0b' , 7 ; set gl obal i nt enabl e
bsf h' 0b' , 3 ; set change on b i nt enabl e
bsf h' 0b' , 4 ; set ext i nt on pi n6 enabl e
; we' ve got 2 t ypes of i nt !
payr ol : nop ; l oop her e unt i l i nt er r upt ed,
nop ; doi ng payr ol l st uf f
movl w h' 0f ' ; si mul at e a cal c by l oadi ng w
got o payr ol ;
nop
nop
end


Program 8: time0.asm
; t i me0. asmt o see how t i mer 0 wor ks
;
; ************************************ set up
pr ocessor 16c84
STATUS EQU H' 03'
OPTI O EQU H' 81'
t mr 0 EQU H' 01'
BANK_ EQU H' 05'
T0CS EQU H' 05'
PSA EQU H' 03'
cl ocked equ h' 10'
I NTCON equ h' 0B'
T0I E equ h' 05'
GI E EQU H' 07'
got o t op
; ************************************ i sr
i sr : ORG h' 0004'
i ncf cl ocked ; cl ocked i s t he ' wal l cl ock'
BCF I NTCON, 2
r et f i e
; ************************************ pr ogr am
t op: or g h' 0010'
cl r f t mr 0 ; cl ear t he t mr 0 r egi st er
cl r f cl ocked
mode: bsf STATUS, BANK_ ; swi t ch t o page 1
bcf OPTI O, T0CS ; go f r omcount er t o t i mer
bsf OPTI O, PSA ; no pr escal er yet
bsf I NTCON, GI E
bsf I NTCON, T0I E
l oop: nop
nop
got o l oop
END
Questions:
sujith_pic@rediffmail.com asks:
I am new to PIC programming. Is there any good links from which i can learn the basics
of PIC programming in C. I have downloaded MPLAB from microchip. Can you plese
guide me where to start from.
Paul Brian Penrose Ransley of Solent Semiconductor Services asks:
Thanx for the tutorial but I found that it referred to some programms that I was unable to
find. ie goto.asm, skip.asm time1.asm are a few. Where can I get hold of these? Thanx
very much Regards Paul
J ames Newton answers: "I believe these are sample programs that come with MPLAB or
MPASM"
Interested:

See:
/techref/microchip/begin.htm
See also:

Comments:
In the beginning, MPLAB is recommended. For those of us without a Windows
computer, there are gpsim and gputils.
gputils: http://gputils.sourceforge.net/
gpsim: http://www.dattalo.com/gnupic/gpsim.html
gnupic (a general resource): http://www.gnupic.org/
in 1985 i got my first computer (a commodore 64) at the age of 14. at that age you learn
fast and by the time i was 15 i could program in basic and assembly using a machine
code monitor. when i reached 16 i realised i was somewhat of a nerd,sold the
commodore 64 and took up drinking,smoking ,women and started my apprenticeship as
an electrician. by the time i was 23 a ressesion had hit the uk and unemployment was
high and lots of people were claiming state benefit including me. during my boredom i
realised that i should have carried on with the computing when i was 16 and made a
career out of it. pc's were at this point were just begginng to take over from the miriad of
different computer companies (whose software only worked on their platform(not
suprising they all went bust really apart from mac whole survived somehow))vaguely
remembering the basics of of my teenage programming years i searched the second hand
pages for a by then outdated commodore 64 which i found and purchased for next to
nothing i got a few old books from the library and remastered programming the c64 in no
time. i wrote a program in assembly which made a tank sprite (younger people will be be
wondering what a sprite is :-) )move around the screen controlled via a joystick. at the
time i thought how easy it would be to write a game for the commodore but its an
outdated computer and it would not sell so not being able to afford a pc(which then
would have been something pathetic like a 386/486 sx 50mhz which is only good for the
bin these days)i gave it up. by the time i was 26 i could afford a pc and bought a 120mhz
pentium and was completely puzzled by the whole windows operating system which
seemed to mask any way of programming the damded thing,the windows learning curve
started there. in 2001 at the age of 30 i realised that i had been working as an electrician
for 14 years and was still no better off moneywise than i was when i left school at 16 so i
started back at college on a 2 year hnc course in electronic engineering (1/3 of a
degree)now in 2002 i am very conversant with windows, and also due to my first year
hnc,logic/boolean algebra/c programming(borland turbo c 3.0) i have given you possibly
too much history before cutting to the chase but its fairly relevent. i recently purchased a
16f84a kit and soldered it together the software that came with the kit was terrible
(lights.pic) which came as a .pic file (whatever one of those is)which then had to be
converted into a .hex file through some terrible dos program and uploaded to the pic chip
via a prog called picall.exe i was completely suprised that it worked at all but it did
work...it made 5 led's flash in a binary count.....woopy doo , no programming tutorial or
nothing . so i scoured the net for info but everything i came across seemed to be aimed
towards intermediate/expert thank the lord i found this site i was on the verge of giving it
up and binning the 16f84a great site,one thing i found was when i wrote your first
example program sample.asm and tried to build it i got a cannot find .hex message when
i looked closer 3 lines needed altering H'10' H'15' and H'08' needed changing to 0010h
0015h and 0008h then it worked perfectly. one thing i have noticed whilst trying to find
info on how to program the damnded pic is that programming instructions have
altered,the c programming instructions which i have recently learnt seem different to the
ones listed in examples which seem foriegn to me. and ok i can accept this one since i
learnt to program assembly on a system developed 20 years ago, but why replace an easy
to understand instruction (opcode) such as lda #ff (load accumulator with hex ff) with
movlw 00ffh i originally remeber the x and y registers . did someone suddenly decide to
call the accumulator the w register? and sta #$0400 (store accumulator at hex address
0400) seems much easier to me than movwf 0400h,f and why has the command jmp
been replaced by the BASIC command goto? well you can look at my comments in a
light hearted way and laugh thats why i basically put this message up but any help would
be greatly appreciated. i really wish i had carried on at 16 because i would have been on
top of things now and been something of an expert but things have developed rapidly and
i find that as hard as i try to get a full understanding of things technology seems to be
increasing at a faster rate than my learning capabilities can cope with. sound familier to
anyone? :-)

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy