Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Understanding &
Programming
the PIC16F84
A beginners' tutorial
by
Jim Brown BSc(Eng), HDipEdAd, GDE (Wits)
To understand how to program a microcontroller, you need input from
many different sources.
This includes ideas and discussions from different instructors. Everyone
provides a different point of view with different terminology to describe a
feature, especially something as complex as programming.
This article by Jim Brown covers many of the features of the PIC16F84
microcontroller and helps you get an overall picture of this amazing
device.
Contents
Introduction
What you need
What you should know
Introducing the PIC16F84
Architecture
Instruction Set
A simple PIC16F84 program
Using MPLAB to debug a program
Pause to reflect
The Instruction Set
Instruction format
The STATUS register
1: Move instructions
MOVF f,d (Move f)
MOVWF f (Move W to f)
MOVLW k (Move literal to W)
2: Clear instructions
CLRF f (Clear f)
CLRW (Clear W)
3: Arithmetic instructions
ADDWF
SUBWF
ADDLW
SUBLW
4: Logical functions
ANDWF f,d (AND W with f)
IORWF f,d (Inclusive OR W with f)
talkingelectronics.com/html/PIC-for-Beginners.html
1/18
3/21/13
7: Program control
GOTO k (Go to address)
CALL k (Call subroutine)
RETURN (Return from subroutine)
RETLW k (Return with literal in W)
RETFIE (Return from Interrupt)
8: Skipping instructions
DECFSZ f,d (Decrement f, skip if 0)
INCFSZ f,d (Increment f, skip if 0)
BTFSC f,b (Bit test f, skip if clear)
BTFSS f,b (Bit test f, skip if set)
11: Miscellaneous
NOP (No operation)
OPTION (Not recommended)
TRIS (Not recommended)
Pause to reflect
Interrupts on the PIC16F84
What's an interrupt?
Types of Interrupt and the INTCON register
Servicing an Interrupt
Timers on the PIC16F84
The basic idea
The TIMER0 module
Using the timer's overflow
Using the EEPROM data memory
Introduction
When I first started looking into programming the PIC16F84, I was daunted by what I saw. It seemed so complex.
The PIC16F84 data sheet from Microchip is quite a technical document and the MPASM manual is a complete
reference. Neither of these documents served as a tutorial, which is what I needed. So this article is a tutorial for
programming the PIC16F84, covering both the instruction set and some MPASM directives. Along the way, it covers
the PIC16F84 itself, in terms of registers, pins and so on.
At the end you will not be a fully-fledged '84 expert. But you will be quite comfortable with the device.
2/18
3/21/13
First, you need to have some of Microchip's documentation. As a minimum, you'll need the PIC16F84 data sheet.
This contains all the real info you will need on the chip itself. You should also have the MPASM User Guide. Both of
these are available from Microchip's website, at http://www.microchip2.com, or from their annual CD 'Microchip
Technical Library'.
You could work through this article with just the above, but you will get a lot more out of it by being able to
experiment. So, load a copy of MPLAB (for Windows) onto your PC.
This is their Interactive Development Environment (IDE), and 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 it's also available as above. Work through
its tutorial before you start this article and it will help you understand the points we will be covering.
The Simulator (Emulator) is fairly good for watching the registers and executing a program in a step-by-step mode but
it will not solve all your problems when a fault occurs.
The single-step mode does not take into account the effect of an input on a program and a delay routine must be
skipped-over to prevent waiting hours for it to execute.
That's all you need, but there's lots more you might like. Not least, is a PIC16F84 chip and a programmer. The Multi
Chip Programmer presented by Talking Electronics is the cheapest kit on the market and comes with some
downloadable software for programming a whole range of chips, of which the PIC16F84 is included.
Of extreme help, perhaps in the longer run, are Microchip's 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 Adobe's .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, closedloop control, and the like.
3/18
3/21/13
6: The use of the I/O pins is the 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 PIC16F84 has 13 pins configured as 2 ports: port A has
5 pins and port B has 8; and we'll be using them later.
Instruction Set
There are 35 instructions in the PIC16F84 instruction set 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: byteoriented, bit-oriented and literal & control. Later on we will use each of these operations.
For now, let's look at one of the instructions. Concentrate more on the format, rather than the function which we'll see
closely later. I've chosen the instruction ADDWF. In this tutorial, I have adopted the Courier font below for all coding
examples. The syntax of this instruction is:
ADDWF f,d
Where ADDWF is the opcode and "f d" are the operands.
The letters ADDWF is called a mnemonic. This is an abbreviation that both the computer and humans can
understand. You will see this same layout in all the 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 W in the name acts on W. The other registers are known as files and we use the letter 'F' in the
commands to indicate a file is being accessed. So, we can understand the command ADDWF adds W to file F. But
what is file F?
Each file (other than W) is given a hexadecimal address. For instance, file 0C is called "0C," file 10 is called "10" and
file 2F is called "2F." The small letter "h" is always added to indicate the file has a hex value, such as file 10h as it
really the sixteenth file in memory.
Some files have names, such as PORTA is 05h, PORTB is 06h and TRISA is 85h. The 'f' in the instruction above is
the actual address of the file. There is no file called "F" or "f" This is a symbol to represent any of the files. So, we
would code the instruction: "add W to file 3C" as:
ADDWF 3Ch,d
Well, not quite - what's the 'd' for?
It is the destination of the result, and you'll see this in many instructions. Depending on the requirement, the result of
the instruction can be put into the working register (W) or file F itself.
If 'd' is 0, the result is in W,
If 'd' is 1, the result is in F.
The instruction can be be either of the following:
ADDWF 3Ch,0 ; adds W to file 3C, result in W
ADDWF 3Ch,1 ; adds W to file 3C, result in 3C
Let's write . . . .
4/18
3/21/13
5/18
3/21/13
Pause to reflect
Where shall we go from here? Well, where are we now? We've looked at the architecture and instruction set briefly;
we've created a simple program and examined the code to get the feel of it; we've edited & assembled this program;
and we've seen some of the simulator's facilities.
I think we should move on to look more fully at the instruction set.
Instruction format
Microchip's grouping does keep instructions of similar format together. The instructions look like this:
byte_command f,d
talkingelectronics.com/html/PIC-for-Beginners.html
6/18
3/21/13
where f is the file register designation and d is the destination; if d=0, the result goes to W. If d=1, the result goes to
register f
bit_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 number 4 in the intcon register. The INTCON
register resides at location 0B
other_command k
where k is an 8-bit constant or literal.
The STATUS register
The '84 has the STATUS register at 03h, which contains the arithmetic status of the arithmetic & logic unit. 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 nibble (bit 3) to the left hand nibble (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)
(f) (dest)
MOVWF f (Move W to f)
(w) (f)
MOVLW k (Move literal to W)
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)
00h (f)
CLRW (Clear W)
00h (W)
Exercise: Expand the above program to clear registers at the end. See clears .asm
3: Arithmetic instructions
Performing arithmetic is pretty important. The '84 can only add and subtract.
Arithmetic occurs either between W and an f register:
ADDWF f,d (Add W & f)
(W)+(f) (dest)
SUBWF f,d (Subtract W from f)
(f)-(W) (dest)
or between W and a literal:
ADDLW k (Add literal & W)
(W)+k (W)
SUBLW k (Subtract W from literal)
k-(W) (W),
Exercise: Use these and previous commands to load a register from 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
talkingelectronics.com/html/PIC-for-Beginners.html
7/18
3/21/13
Technical aside: You may see that subtraction is performed using the 2's complement method. This is the normal
way that subtraction occurs in binary. I'll explain, then show an example.
Firstly, express both numbers in binary. Leave the number from which you are taking away, unchanged. Form the 2's
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. That's the answer. Let's check . .
We want to subtract 20 from 27 - we should get 7. Proceed as follows:
Convert to binary:
27
11011 . . . . x
20
10100 . . . . y
complement:
01011
add 1:
01100 . . . . z
Add x and z:
+ 11011 . . . . x
(1)
00111 = 7
4: Logical functions
At this stage, before we examine the logical functions provided by the '84, we'll discuss logical functions. Consider an
electronic device with 3 wires attached. Let's say that 2 wires are inputs, and output on the 3rd wire depends on the
inputs. Further, we'll say that this is a digital device, so that the 3 wires can only have binary values of 1 & 0.
What relationships can exist between the 2 inputs and the output? The input combinations are easy: 00, 01, 10 &
11. Pin 3 can be 1 if and only if the inputs are both 1 (i.e: 11) or if either or both inputs are 1 (i.e: 01, 10, 11), and
other combinations.
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 a TRUTH TABLE, which is drawn below for the following logical operations: AND, OR,
XOR, NAND, NOR. I'll explain them once you've 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
01
10
11
The function AND means 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 you'll 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
PIC16F84 uses this term.
The PIC16F84 provides a number of logical operations which act on two, 8-bit values; these values are compared bit
for bit. For example - without looking at an '84 instruction - consider the ANDing of the numbers H'5F' (equivalent to
D'95' or B'01011111') and H'A3' (which is D'163' or B'10100011'); resulting in H'03' (which is D'3' or B'00000011').
talkingelectronics.com/html/PIC-for-Beginners.html
8/18
3/21/13
5F:
01011111
A3:
10100011
and:
00000011
Clearly, only in the rightmost 2 positions is the AND satisfied. The result is 1, and 0 elsewhere.
Let's move to the instructions as provided by the 'PIC16F84.
Comparison occurs either between W and an f register:
ANDWF f,d (AND W with f)
(W) AND (f) (dest)
IORWF f,d (Inclusive OR W with f)
(W) OR (f) (dest)
XORWF f,d (Exclusive OR W with f)
(W) XOR (f) (dest)
or between W and a literal:
ANDLW k (AND literal with W)
(W) AND k (W)
IORLW k (Inclusive OR literal with W)
(W) OR k (W)
XORLW k (Exclusive OR literal with W)
(W) XOR k (W)
Lastly, you may have noted that the '84 doesn't 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:
COMF f,d (Complement f)
complement of (f) (dest)
Exercise: I suggest two things here. First, using Windows' calculator, verify the results of the above: this will ensure
you understand the concepts. Then, write an assembler program to verify the '84 instructions, by loading the
appropriate registers, performing the operations and checking the results. See logic .asm.
9/18
3/21/13
We read these two operations as 0 (or 1) becomes the content of bit 'b' in register 'f'.
Exercise: Put 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, may we 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 from the rest of the code; then we call it in as often as we like. The reusable
piece is called a SUB-ROUTINE. The subroutine returns control to the point from which it was called when it's
finished.
Let's look at looping first:
GOTO k (Go to address)
k (PC)
This instruction '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 where you want to go, with a Label. Then you GOTO Label.
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, you'll see from the highlighted line your program is looping. Look at the program counter (PCL) in a
watch window and you'll verify this. See GOTO .asm
Now we shall examine subroutines. We need to understand the concept of the stack. The stack - which has 8 levels
in the PIC16F84 - is the place where the address of the next instruction is placed, when a CALL instruction is met.
As each instruction is executed, it is the job of the Program Counter (PC) to know where the microcontroller is, at
any point in time. The placement of the next address in the Stack tells the microcontroller where to go, after a
subroutine is finished.
We refer to loading the stack as pushing and taking a value off later as popping. The stack is only accessible at
the top: it's like a pile of plates in a hopper. The top of the stack is abbreviated to TOS.
There are 2 instructions associated with any subroutine - one to send the microcontroller to the sub-routine, the other
to bring it back:
CALL k (Call subroutine)
(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 held on the stack
for later retrieval.
RETURN (Return from subroutine)
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 each call is matched by a return.
RETLW k (Return with literal in W)
k (W), TOS (PC)
This returns with k (W) added.
RETFIE (Return from Interrupt)
TOS (PC), 1 GIE
When an interrupt occurs, the PC is pushed to the stack like with a subroutine call, so RETFIE pops it. Also, the
occurrence of an interrupt disables further interrupts: one doesn't want interrupts to be interrupted. What happens is,
talkingelectronics.com/html/PIC-for-Beginners.html
10/18
3/21/13
the interrupt causes 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 that allow you to skip over the next instruction.
DECFSZ f,d (Decrement f, skip if 0)
(f)-1 (dest), skip if result = 0
INCFSZ f,d (Increment f, skip if 0)
(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.' Then use either instruction
to change it, looping through this block of code. Check to see if the instruction following the decfsz or incfsz
(probably a GOTO, to cause the looping) is skipped or not, as appropriate. See Skip .asm.
BTFSC f,b (Bit test f, skip if clear)
skip if (f<b>)=0
BTFSS f,b (Bit test f, skip if set)
skip if (f<b>)=1
Read these instructions as 'bit test f, skip if clear/set".
Exercise: Write a program with a block of code with a loop. Put a BTFSS at the bottom, followed by a GOTO back to
the top. Include some more code. The BTFSS will need to refer to one of the PIC16F84's I/O ports as its f (H'05' or
H'06' for PortA & B respectively), and you can use any pin 0-4 on PortA, 0-7 on PortB. You should have another
GOTO right at the bottom, to make an outer loop back to the top so you can see the program loop to test what
happens when an input pin changes. See Bits .asm
But how do we get the pin to change state? There's an easy way of doing this in MPLAB's simulator. Go Debug >
Simulator stimulus > Asynchronous stimulus; you'll get a table of Stim0 to Stim12 buttons. Right click on any one,
perhaps Stim7, and click Assign pin. Double click on the pin you've elected to use as the sensor, perhaps it was
RA3. 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.
Now we're all set to test. Step through your program. Depending on the initial state of the pin, which 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. (If you
have the port showing in a watch window, you'll 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 we've toggled the pin and so
the BTFSS should get a different answer.
11/18
3/21/13
11: Miscellaneous
NOP (No operation) This instruction does nothing. It is very handy for the creation of short delay intervals
(1uS) to allow things to settle down before another operation is executed.
TRIS 05 This instruction controls the direction of each line of the port called Port A.
It is the Direction Control Register. There are 5 lines in port A, called RA0, RA1, RA2, RA3 and RA4. Each
line can be either input or output. To make a line input, the corresponding bit in the TRIS register is made
"1." To make a line output, the corresponding bit is made "0." Thus the value 01 will make RA0 an input and
all other lines output.
The value 23 (0010 0011) will make RA0 and RA1 input and bit5 will not have any effect as no line corresponds
to this bit!)
TRIS 06 This instruction controls the direction of each line in Port B. There are eight lines in port B. RB0,
RB1, RB2, RB3, RB4, RB5, RB6, and RB7. A "0" in the TRIS register makes the corresponding line in port B
and output. A "1" in the TRIS register makes the line an Input.
This is easy to remember as "0" is similar to 0utput and "1" is similar to 1nput.
You should not use the following instruction, which is included to provide backward compatibility:
OPTION (Not recommended)
Pause to reflect
We have now met each PIC16F84 instruction, with the necessary background if appropriate, and used them in simple
programs. Now, we'll move on to explore two important areas of the PIC16F84: interrupts and timers. These two areas
move the PIC16F84 into the real world.
12/18
3/21/13
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 there's an interrupt,
regardless of the state of the corresponding enable bit.
Servicing an Interrupt
In the PIC16F84, all interrupts are sent to 004h.This point is the interrupt vector and the program is said to vector to
this address. At the vector, we must make sure we provide the necessary code 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
PIC16F84 only saves the PC to the stack (PC+1, actually), and it's up to us to ensure we save and restore anything
else we need!
There are 3 parts to a program which must handle simple interrupts:
an initialize section, where in our case we'll 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.
Initialize: set GIE, INTCON<7>, to enable interrupts set INTE, INTCON<4>, to enable pin 6 interrupt
Handler: save the status of the machine; probably W & STATUS check interrupt flags for source; INTF, RBIF, T0IF
branch to the correct 'sub-handler' for the interrupt type (we've only set INTE, though)
do whatever is required for the interrupt restore the status return
Main: do the payroll calculation, for instance.
Exercise: Start slowly with interrupts. This can get quite complex. 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 routine that merely loops through some 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 it's 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. 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, you'll need to determine the kind of interrupt, and handle it accordingly. See Inter3.asm.
13/18
3/21/13
Let's 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. Open the stopwatch by going Window > Stopwatch. You'll see a simple
window, containing 3 important pieces of information: the number of steps completed in a particular time, and the
frequency. Check that the frequency is set to 4MHz for now, click zero and step your program once. You should see
that you progress to 1 cycle in 1uS. (Unless this was coincidentally a program branch, which is a 2-cycle
instruction.)
So, we have the glimmerings of a wall clock type of timer. We know how much time has passed if we know how
many steps have occurred. Enter Timer0 . . .
14/18
3/21/13
;*********************************** simulator
;watch window: reg1, w, pcl
;*********************************** setup
processor
16F84
reg1 equ
h'10'
;*********************************** program ***
start: movlw h'05' ;load w
movwf reg1
;move (w) to reg1
movlw h'82' ;change w
movf
reg1,0 ;restore w
end
***
***
Program 3: Clears.asm
;clears.asm to show how clrf & clrw work
;based on moves.asm
;*********************************** simulator
;watch window: reg1, w, pcl
;*********************************** setup
processor
16F84
reg1 equ
h'10'
;*********************************** program
start: movlw h'05'
;load w
movwf reg1
;move (w) to reg1
movlw h'82' ;change w
movf
reg1,0 ;restore w
clear: clrf
reg1
;clear reg1
clrw
;clear w
end
Program 4: Arith.asm
;arith.asm to show using ADDWF, SUBWF, ADDLW, SUBLW
;************************************* simulator
;watch window: reg1,reg2,status,w,pcl
;************************************* setup
processor
16F84
reg1 equ
h'10'
reg2 equ
h'12'
;************************************* program
loads: movlw d'20' ;load w
movwf reg1
;load reg1
movlw d'80' ;load w anew
movwf reg2
;load reg2
arith: addlw d'05' ;add d'05' to w
sublw d'100' ;sub w from d'100'
addwf reg1,1 ;add w to reg1, into reg1
subwf reg2,1 ;sub w from reg2, into reg2
end
Program 5: Inter1.asm
;inter1.asm is a simple interrupt handler;
it does not save the state of the machine
;
nor does it determine the kind of interrupt.
talkingelectronics.com/html/PIC-for-Beginners.html
15/18
3/21/13
;*********************************************simulator
;watch window: intcon, pcl
;stack: have this open too - see the return address come & go
;asynch stimulus: have a toggle on rb4
;********************************************* setup
processor 16F84
movlw h'0'
movwf h'0b' ;clear intcon
goto
main
;hop over the isr
;********************************************** isr start
isr: org
h'0004' ;interrupts always vector to here
nop
;here we actually do the stuff
nop
;
of the interrupt
bcf
h'0b',0 ;clear int before going back
retfie
;this re-sets intcon gie
;*********************************************** isr ends
;*********************************************** main start
main org
h'0020' ; leave enough room for the isr!
bsf
h'0b',7 ; set global int enable
bsf
h'0b',3 ; set change on b int enable
payrol nop
; loop here until interrupted,
nop
; doing payroll stuff
goto
payrol
nop
nop
end
Program 6: Inter2.asm
;inter2.asm saves the state of the machine
;
but does not determine the kind of interrupt.
;
;****************************************************simulator
;watch window: intcon, pcl, portb, w, w_saved
;stack: have this open too - see the return address come & go
;asynch stimulus: have a toggle on rb4
;**************************************************** setup
processor 16F84
w_saved
equ
h'10' ;a place to keep w
movlw h'0'
movwf h'0b' ;clear intcon
goto
main
;hop over the isr at the beginning
;**************************************************** isr start
isr
org
h'0004' ;interrupts always vector to here
movwf w_saved
;save w as it was in main
movlw h'65'
;do something to change w
nop
;do more isr stuff
;now, restore w: there is
; no "movfw"- 2 swapf's seems to be
; the way to do this....
swapf w_saved,1
; first, swap w_saved into itself
swapf w_saved,0
; then, swap it into w
bcf
h'0b',0
;clear int on b before going back
retfie
;this re-sets intcon gie
;***************************************************** isr ends
;****************************************************** main start
talkingelectronics.com/html/PIC-for-Beginners.html
16/18
3/21/13
main: org
bsf
bsf
payrol nop
nop
movlw
goto
nop
nop
end
Program 7: Inter3.asm
;inter3.asm saves the state of the machine
;
and determines the kind of interrupt.
;
;**************************************************simulator
;watch window: intcon, pcl, portb, w_saved, w
;stack: have this open too - see the return address come & go
;asynch stimulus: have a toggle on rb4(for rbi) and rb0(int)
;************************************************* setup
processor 16F84
w_saved
equ
h'10'
;a place to keep w
movlw h'0'
movwf h'0b' ;clear intcon
goto
main
;hop over the isr at the beginning
;*************************************************** isr start
isr
org
h'0004'
;interrupts always vector to here
movwf w_saved
;save w as it was in main
;find out what kind of interrupt
btfsc h'0b',0
; is it an rbi?
call
_rbi
; yes- call the rbi 'sub-handler'
btfsc h'0b',1
; is it an int?
call
_int
; yes- call the int 'sub-handler'
;end up here after sub-handler
;now, restore w
swapf w_saved,1
; first, swap w_saved into itself
swapf w_saved,0
; then, swap it into w
bcf
h'0b',0
;clear rbif before going back
bcf
h'0b',1
;clear intf before going back
retfie
; this re-sets intcon gie
_rbi movlw h'65'
;do something to change w
return
_int movlw h'24'
;do something different to w
return
;***************************************************** isr ends
;
;**************************************************** main start
main org
h'0020' ; leave room for the isr!
bsf
h'0b',7 ; set global int enable
bsf
h'0b',3 ; set change on b int enable
bsf
h'0b',4 ; set ext int on pin6 enable
; we've got 2 types of int!
payrol nop
; loop here until interrupted,
nop
; doing payroll
movlw h'0f' ;simulate a calc by loading w
goto
payrol
nop
talkingelectronics.com/html/PIC-for-Beginners.html
17/18
3/21/13
nop
end
Program 8: Time0.asm
;time0.asm to see how timer0 works
;************************************
setup
processor 16F84
STATUS
EQU
H'03'
OPTIO
EQU
H'81'
tmr0
EQU
H'01'
BANK_
EQU
H'05'
T0CS
EQU
H'05'
PSA
EQU
H'03'
clocked
equ
h'10'
INTCON
equ
h'0B'
T0IE
equ
h'05'
GIE
EQU
H'07'
goto
top
;************************************
isr
isr
ORG
h'0004'
incf
clocked ;clocked is the 'wall clock'
BCF
INTCON,2
retfie
;************************************
program
top
org
h'0010'
clrf
tmr0
;clear the tmr0 register
clrf
clocked
mode bsf
STATUS,BANK_
;switch to page 1
bcf
OPTIO,T0CS
;go from counter to timer
bsf
OPTIO,PSA
;no prescaler yet
bsf
INTCON,GIE
bsf
INTCON,T0IE
loop nop
nop
goto
loop
END
talkingelectronics.com/html/PIC-for-Beginners.html
18/18