Sunteți pe pagina 1din 119

Microcontroller Theory

and
Applications with the PIC18F
M. RAFIQUZZAMAN, Ph.D.
PROFESSOR

ELECTRICAL AND COMPUTER ENGINEERING


California State Polytechnic University
Pomona, California USA

MICROCONTROLLER
THEORY AND APPLICATIONS
WITH THE PIC18F

TABLE OF CONTENTS
Page

Chapter 2

....................................................................

Chapter 3

....................................................................

Chapter 4

....................................................................

10

Chapter 5

....................................................................

17

Chapter 6

....................................................................

20

Chapter 7

....................................................................

30

Chapter 8

....................................................................

47

Chapter 9

....................................................................

59

Chapter 10

....................................................................

88

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

CHAPTER 2
2.1
Single- chip Microcomputer : CPU, memory, and I/O in a single chip.
Microcontrollers evolved from single-chip microcomputers. The
microcontrollers are typically used for dedicated applications such as automotive
systems, home appliances, and home entertainment systems. Typical
microcontrollers, therefore, include on-chip timers and A/D (analog to digital) and
D/A (digital to analog) converters.
2.2
The ALU is 8-bit.
PIC18F4321.
2.3
(a) The PC stores address of the instruction. The MAR stores address of data.
(b) The result is stored in the accumulator after most ALU operations.
The Instruction register stores instructions.
(c) Depending on the register section, the microcontroller can be classified either
as an accumulator-based or a general-purpose register-based machine. In an
accumulator-based microcontroller such as the PIC18F, the data is assumed to be
held in a register called the accumulator. All arithmetic and logic operations are
performed using this register as one of the data sources. The result after the
operation is stored in the accumulator.
In general-purpose register-based microcontroller such as the Texas
Instruments MSP430, the microcontroller contains several general-purpose
registers. These registers can hold data, memory addresses, or the results of
arithmetic or logic operations.
2.4
(a)
0916 =
+1716 =
2016 =

0011
0000
0001
(0) 0010

111
1001
0111
0000

flags
sign = 0
carry = 0

overflow = 0
zero = 0

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

(b)
A516 =
-A516 =
0016 =

1111
1010
0101
(1) 0000

111
0101
1011
0000

7116 =
-A916 =
C816 =

1110
0111
0101
(0) 1100

111
0001 flags
0111 sign = 1, zero = 0
1000 carry = 1s complement of 0 = 1,
overflow = 0

(c)

(d)

1111
6E16 =
0110
+ 3A16 = 0011
A916 ?(0) 1010

(e)
7E16 =
+7E16 =
FC16 ?

flags
sign = 0, zero = 1
carry = 1s complement of 1 =0,
overflow = 0

110
flags
1110 sign = 1, carry = 0
1010 zero = 0, overflow = 1, Wrong result
1000

1111
0111
0111
(0) 1111

110
1110
flags
1110 sign = 1, carry = 0
1100 zero = 0, overflow = 1, Wrong result

2.5
The PUSH OPERATION: is writing to the top or bottom of the stack.
The POP OPERATION: is reading from the top or bottom of the stack.
2.6
(a) SP = 20BE
(b) (20BE) = 05, (20BF) = 02, assuming low byte is stored in low address, and
high byte is stored in high address.
2.7
To load the program counter with the address of the first instruction to be executed.

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

2.8
22 bits.
0x3FFFFF
2.9
2kB
2.10
In von Neumann architecture, a single memory system with the same address and
data buses is used for accessing both programs and data. This means that programs
and data cannot be accessed simultaneously. This may slow down the overall
speed. Texas Instruments MSP 430 uses von Neumann architecture.
Harvard architecture is a type of computer architecture which uses separate
Program and data memory units along with separate buses for instructions and
data. This means that these processors can execute instructions and access data
simultaneously. Microchip PIC18F uses Harvard architecture.
2.11
In order to execute a program, conventional CPUs repeat the following three
steps for completing each instruction:
Step 1:
Fetch : The CPU fetches (Instruction Read) the instruction from the
main memory (external to the CPU) into the Instruction Register.
Step 2:
Decode: The CPU decodes or translates the instruction using the
Control Unit. The Control Unit inputs the contents of the Instruction Register, and
then decodes (translates) the instruction to determine the instruction type.
Step 3:
Execute: The CPU executes the instruction using the Control Unit. In
order to accomplish the task, the Control Unit generates a number of enable signals
required by the instruction.
The PIC18F CPU uses pipelining in which instruction fetch and execute
cycles are overlapped in order to speed up instruction execution.
2.12
CISC CPUs contain a large number of instructions and many addressing modes
while RISC CPUs include a simple instruction set with a few addressing modes.
Almost all computations can be obtained from a few simple operations. RISC

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

basically supports a small set of commonly used instructions which are executed at
a fast clock rate compared to CISC which contains a large instruction set (some of
which are rarely used) executed at a slower clock rate. In order to implement fetch
/execute cycle for supporting a large instruction set for CISC, the clock is typically
slower.
In CISC, most instructions can access memory while RISC contains mostly
load/store instructions. The complex instruction set of CISC requires a complex
control unit, thus requiring microprogrammed implementation. RISC utilizes
hardwired control which is faster. CISC is more difficult to pipeline while RISC
provides more efficient pipelining. An advantage of CISC over RISC is that
complex programs require fewer instructions in CISC with a fewer fetch cycles
while the RISC requires a large number of instructions to accomplish the same task
with several fetch cycles. However, RISC can significantly improve its
performance with a faster clock, more efficient pipelining and compiler
optimization.
2.13
The PIC18F can convert an analog signal into a 10-bit value using its on-chip A/D
(Analog to Digital) converter.
The PIC18F can perform functions such as capture, compare, and pulse
width modulation (PWM) using the timers and CCP (Capture / Compare / PWM)
modules. The PIC18F can compute the period of an incoming signal using the
capture module. The PIC18F can produce a periodic waveform or time delays
using the compare module. The PIC18Fs on-chip PWM can be used to obtain
pulse waveforms with a particular period and duty cycle which are ideal for
applications such as motor control.
Serial I/O is typically fabricated as an on-chip module with the PIC18F.
This will facilitate interfacing the PIC18F with peripheral devices utilizing serial
data transmission synchronized with the clock.
2.14
Pipelining is a technique that overlaps instruction fetch (instruction read) with
execution. This allows a microcontrollers processing operation to be broken
down into several steps (dictated by the number of pipeline levels or stages) so that
the individual step outputs can be handled by the microcontroller in parallel.
Pipelining is often used to fetch the microcontrollers next instruction while
executing the current instruction, which considerably speeds up the overall
operation of the microcontroller.

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

2.15
The PIC18F implements a two-stage pipeline. The PIC18F CPU fetches the
instruction during the first stage. However, during the second stage, the PIC18F
CPU while executing the instruction, fetches the next instruction. This is called
two-stage instruction pipelining, and is used by the PIC18F to increase the speed
of instruction execution. When the PIC18F fetches a branch instruction, it clears
or flushes the pipeline and executes a new sequence of instructions starting at the
new branch address.

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

CHAPTER 3
3.1
Microcontrollers can be programmed using semi-English-language statements
(assembly language). In addition to assembly language, microcontrollers use a
more understandable human-oriented language called the high-level language.
High-level language such as C is portable while Assembly language is not.
Compilers normally provide inefficient machine codes because of the general
guidelines that must be followed for designing them. C is a high-level language
that includes Input/Output instructions. However, the compiled codes generate
many more lines of machine code than an equivalent assembly language program.
Therefore, the assembled program will take up less memory space and will execute
much faster compared to the compiled C .
Although C/C++ language includes I/O instructions, applications involving
I/O are normally written in assembly language. One of the main uses of assembly
language is in writing programs for real-time applications. Real-time means that
the task required by the application must be completed before any other input to
the program can occur which will change its operation. Typical programs involving
non-real-time applications and extensive mathematical computations may be
written in C .
3.2
Yes
3.3
No
3.4
(a) The 8-bit contents of address 0x23 are 00H.
(b) The 8-bit contents of address 0x23 are 12H.
3.5
(a) Cross assembler is a program resident in a processor and assembles programs
written in assembly language of another processor.
Resident assembler is a program that assembles programs written in assembly
language for the same processor.
(b) Two-Pass assembler is a program that goes through the program twice. In the
first pass, it assigns addresses to labels. In the second pass, it assembles the

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

program and thus takes care of forward branching. Meta-assembler assembles


programs for several microcontrollers.
3.6
z = a +(b c) + (d e) - (f / g) - (h i);
(a)
mul
add
mul
add
div
sub
mul
sub
(b)
mov
mul
add
mov
mul
add
mov
div
sub
mov
mul
sub
mov

b,
a,
d,
r1,
g,
r1,
h,
r1,

Three Address
c,
r0
r0,
r0
e,
r1,
r0,
r0
f,
R1
r0,
r0
i,
r1
r0,
z

Two Address
b,
r0
c,
r0
a,
r0
d,
r1
e,
r1
r1,
r0
f,
r1
g,
r1
r1,
r0
h,
r1
i,
r1
r1,
r0
r0,
z

;
;
;
;
;
;
;
;
;
;
;
;
;

;
;
;
;
;
;
;
;

r0
r0
r1
r0
r1
r0
r1
z
r0
r0
r0
r1
r1
r0
r1
r1
r0
r1
r1
r0
z

b
a
d
r0
f/g
r0
h
r0
b
r0
a
d
e
r0
f
r1/g
r0
h
r1
r0
r0

c
r0
e
r1

r1
i
r1

c
r0

r1
r1

r1

i
r1

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

3.7

We know that :
a / a = 0 and a / 0 = a
(a / b) / a = a / b / a = a / a / b
= (a / a) / b
= 0/ b = b

The following sequence uses the above result in order to achieve the desired result:
/
XOR
R1,
R2
;
R2
R1
R2

/
XOR
R2,
R1
;
R1
R1
R2

/
XOR
R1,
R2
;
R2
R1
R2

3.8
M = 1111 11112, Q = 1111 11002
Since M and Q are both negative numbers.
2s complement of M = 0000 00012
2s complement of Q = 0000 01002
Multiplying the 2s complement of M and Q using unsigned multiplication
method,
product = 0000 0000 0000 0100 2 = + 410.
The sign of the product,
S n = M n /Q n = 1 / 1 = 0
Hence, the result is + 410

3.9
Quotient = -8, Remainder = -1. The sign of the remainder is the same as the sign of
the dividend unless remainder is zero.
3.10
Logically AND with 8-bit hex data ED 16
3.11
Logically OR with 8-bit hex data 81 16 .

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

3.12
After arithmetically shifting B6 16 three times to left, the result will be B0 16 . Since
the most significant bit changes from 1 to 0 during shifting, the overflow bit is set
to one.
3.13
(a) To load constants into CPU registers.
(b) To access data items stored in the memory.
(c) To access data stored in memory location addressed by the contents of a
register.
(d) To design short branch or subroutine call instructions; to develop
position independent program.
(e) No operand instructions such as NOP.
3.14
Subroutines allow one to write one program for a specific function whose results
are required many times in the main program.
3.15
When a subroutine call is made, the system usually stores the return address in the
stack. This process is a natural solution for implementing subroutine calls so that
program execution starts at the right address in the main program after execution of
the RETURN instruction placed at the end of the subroutine.

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

10

CHAPTER 4
4.1
The CPU can directly execute programs in main or primary memory. The size of
the main memory is defined by the number of address pins on the CPU.
Programs in the secondary or auxiliary memory can not directly be executed
by the CPU. Operating system is required to load the programs from the
secondary to primary memory for execution. Hard disk is an example of secondary
memory.
4.2
2 24 = 16 Megabytes.
4.3
(a) EPROMs (Erasable PROMs) can be reprogrammed and erased. The chip must
be removed from the board for programming. This memory is erased by exposing
the chip via a lid or window on the chip to ultraviolet light. Typical erase times
vary between 10 and 20 min. The EPROM can be programmed by inserting the
chip into a socket of the EPROM programmer and providing proper addresses and
voltage pulses at the appropriate pins of the chip.
EEROMs (Electrically Erasable PROMs) can be programmed without
removing the memory from the ROMs sockets. These memories are also called
read mostly memories (RMMs), because they have much slower write times than
read times. Therefore, these memories are usually suited for operations when
mostly reading rather that writing will be performed.
(b) Both SRAM and DRAM are read/write volatile memories. SRAM (Static
RAM) stores data in flip-flops. Therefore, this memory does not need to be
refreshed.
DRAM (Dynamic RAM) stores data in capacitors. That is, it can hold data
for a few milliseconds. Hence, DRAMs are refreshed typically by using external
refresh circuitry. Dynamic RAMs (DRAMs) are used in applications requiring
large memory. DRAMs have higher densities than SRAMs.
4.4
Flash memory is designed using a combination of EPROM and EEPROMs, and is
nonvolatile.
4.5
(a) 214 = 16,384

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

(b) 1K x 1 bit = 1024 bits


Total number of chips =

16,384x 8
1024

11

= 128 chips

(c) Eight 1k x 1 chips will provide storage of 1k x8. Hence, four bits can be used
for chip selects with a 4 x 16 decoder. Each decoder output will select a group of
eight 1k x 1 chips.
4.6

13

12

A A
0

11

2732
4K x 8

OE
CE

O0 O 7

A A12

2764
8K x 8

O0 O7

OE

12

2 =4 K

CE

13

2 =8 K

4.7
(a)

20

(b)

6 x 64 decoder

4.8
14 unused address pins Available; maximum Directly Addressable Memory = 16
Megabytes.
4.9
Two memory decoding techniques are typically used. These are: Linear decoding,
and full decoding .
Linear decoding is obtained by using unused address pins of the microprocessor as
memory chip selects. This method is suitable for small memory design. Memory
foldback due to unused dont care conditions for address pins occur in memory
decoding. This results into address duplication and thus wastage of memory. Bus
conflict may occur if the designer is not careful.
Full decoding uses a decoder to decode unused address pins of the
microprocessor for enabling memory chips. This method can be used for large
memory design. Full decoding avoids bus conflict.

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

12

4.10

A12
A11
A10
A9
R/W
A -A
15

13
(Unused)

A 0 A8

WE CS1 CS2
A 0 A8

CPU

512x8

Memory chip#1

D0 D7

D0 D7

WE CS1 CS2
A0 A 8
512x8

Memory chip#2

D0 D7

64K means that the microprocessor has 16 address pins.


A15-A13 are dont cares. Assume 1s.
Memory chip #1: A15 A14 A13 A12 A11 A10 A9 A 8 ......A 0
1 1 1 0 1
EC00H - EDFFH

0 all 0s to 1s

Memory chip #2: A15 A14 A13 A12 A11 A10 A9A 8 ......A 0
1 1 1 1 0
F200H - F3FFH

1 all 0s to 1s

4.11
(a)

ROM map:
A15 A14 A13 A12 A11 A 10 ................A 0
all 0s to 1s

0000H - 07FFH
RAM map:
A15 A14 A13 A12 A11 A10 A9 A8 A 7 ................A 0 (A10 A9 A8 are dont cares; assume 0s)
0 0 1 0 0 0 0 0
2000H - 20FFH

all 0s to 1s

(b) No bus conflict occurs since the selected decoder output ensures enabling of
one memory chip at a time. The unused outputs of the decoder can be used for
memory expansion.

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

4.12
A 14
A 13
A 12
A 15

C
B
A
G1

A 11
A 10

G 2A
G 2B 4

A 0 A9

74138
1 0

CE
A -A
0

1K x 8
EPROM

OE

D0 D7
CE
A - A
0

R/W

CPU

WE

CE
A -A
0

WE

1K x 8
RAM 0

8
9

1K x 8
RAM 1

13

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

4.13

A
A
A
A
A
A

15
14

13
12

11
10

A 0 A9

C
B
A
G1
G 2A
G 2B

74138
7 6 3
CE
A0- A

OE

1K x 8
EPROM

D0 D7
CE
A0 - A
9

R/W

CPU

OE

1K x 8
RAM 0

CE
A0 - A
OE

1K x 8
RAM 1

14

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

15

4.14
Foldback means duplication of addresses in linear decoding.
4.15
There are two ways of transferring data between the microcontroller and I/O
devices:
y
Programmed I/O
y
Interrupt I/O
Using programmed I/O, the CPU executes a program to perform all data
transfers between the microcontroller and the external device. The main
characteristic of this type of I/O technique is that the external device carries out
the functions as dictated by the program inside the microcontroller memory. In
other words, the CPU completely controls all transfers. Programmed I/O is CPU initiated I/O transfer.
In interrupt I/O, an external device can force the CPU to stop executing the
current program temporarily so that it can execute another program known as the
interrupt service routine. This routine satisfies the needs of the external device.
After having completed this program, a return from interrupt instruction can be
executed at the end of the service routine to return control at the right place in the
main program. Interrupt I/O is device - initiated I/O transfer.
4.16
The microcontroller uses IN or OUT instruction to transfer data
via I/O Ports.
Memory-mapped I/O: I/O ports are mapped as memory locations. Memory
oriented instructions are used for input and output.
The PIC18F uses memory-mapped I/O.
Standard I/O:

4.17
Memory mapping means all physical addresses available in the main memory
where programs can be written by a user for execution. Memory mapped I/O is a
technique of mapping an I/O port as a memory address.
4.18
Polled I/O and Interrupt I/O: Polled I/O is conditional I/O transfer. The CPU
wastes time by waiting in loop and checking a condition before the I/O transfer. In

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

16

Interrupt I/O, data transfer occurs upon activation of the CPUs interrupt pin by an
external device.
4.19
Subroutine is called by an instruction while interrupt is initiated by activating the
microcontrollers interrupt pin by an external device. The subroutine call
instructions with microcontrollers save only the contents of the program counter
onto stack before executing the subroutine whereas the microcontrollers typically
save program counter, status registers and some other registers before executing
the interrupt service routine.
4.20
Interrupt address vector is the starting address of the service routine.

4.21
Maskable interrupts can be enabled or disabled by microcontroller instructions
while the nonmaskable interrupt can not be enabled or disabled by instructions.
Nonmaskable interrupt has higher priority. Power failure interrupt is handled
using nonmaskable interrupt.
4.22
Internal interrupts are typically caused due to occurrence of conditions such as
timer interrupt or completion of A/D conversion. The external interrupts, on the
other hand, are initiated by an external device via interrupt pins.

Instructors Manual

Microcontrollerr Theory & Applications with the PIC18F

17

CHAPTER 5
5.1
The PC is 21-bit wide. Hence, the maximum size of the PIC18Fs addressable
program memory is 2 MB ( 2 21 ).
5.2
Flash memory
5.3
The PIC18F can have a data memory of up to 4096 bytes.
12 bits are used to address data memory. This means that the maximum size of the
data memory is
2 12 = 4096 bytes.
5.4
SRAM
5.5
The PIC18F4321 contains a maximum of 8 K bytes of on-chip program memory.
The PIC18F4321, on the other hand, contains a maximum of 512 bytes of data
memory.
Critical data can be stored in the PIC18F4321 EEPROM and can be protected from
reading or writing by other users.
5.6
40 MHz
5.7
The PIC18F CCP module can perform functions such as capture, compare, and
pulse width modulation (PWM) using the timers and CCP (Capture / Compare /
PWM) modules. The PIC18F can compute the period of an incoming signal using
the capture module. The PIC18F can produce a periodic waveform or time delays
using the compare module. The PIC18Fs on-chip PWM can be used to obtain
pulse waveforms with a particular period and duty cycle which are ideal for
applications such as motor control.
5.8
The PIC18F uses a two-stage pipeline. This means that execution of the previous
instruction is overlapped with fetching of the current instruction. This speeds up
the program execution by the CPU.
5.9
(a) PC contains addresses of instructions in program memory whereas the FSRs
point indirectly to data memory.

Instructors Manual

(b)

Microcontrollerr Theory & Applications with the PIC18F

18

WREG is the accumulator, and is typically used for performing ALU


operations. IR stores instructions.

5.10
4002H
5.11
MOVLB 0x0F
5.12
Address of the PIC18F Status register is 0xFD8
Address of the PIC18F STKPTR is 0xFFC
5.13
No.
The PIC18F hardware stack is a group of 31 21-bit registers to hold memory
addresses. The low five bits of the STKPTR are used to address the stack. The
31 stack registers are neither part of program memory nor data memory.
5.14
N = 0, OV = 0, Z = 1, DC = 1, C = 0
5.15
Large areas of data memory require an efficient addressing scheme to make rapid
access to any address possible. Ideally, this means that an entire address does not
need to be provided for each read or write operation. For PIC18F, this is
accomplished with a RAM banking scheme. This divides the memory space into 16
contiguous banks of 256 bytes. Depending on the instruction, each location can be
addressed directly by its full 12-bit address, or an 8-bit low-order address and a
4-bit Bank Pointer.
Most instructions in the PIC18F instruction set make use of the Bank
Pointer, known as the Bank Select Register (BSR). The BSR holds the four Most
Significant bits of a locations address;
the PIC18F instruction contains the 8 Least Significant bits. Only the four lower
bits of the BSR are implemented (BSR3:BSR0). The value of the BSR indicates
the bank in data memory; the 8 bits in the instruction show the location in the bank
and can be thought of as an offset from the banks lower boundary.
In order to access a memory location from one bank to a memory location in
a different bank, bank switching is required. However the need for bank switching,
sometimes, creates a major problem for the programmer. Obviously, programs
will not work if the programmer forgets about bank switching. To facilitate access

Instructors Manual

Microcontrollerr Theory & Applications with the PIC18F

19

for the most commonly used data memory locations, the data memory is
configured with an Access Bank, which allows users to access a mapped block
of memory without bank switching.
5.16
Most instructions contain one or more operands. Some instructions have no
operands. The manner in which a microcontroller specifies location(s) of
operand(s) and destination addresses is called the addressing mode.
5.17
(a)
Implied mode
(b)
Literal mode
(c)
Indirect with preincrement mode
5.18
The PIC18F assembly language instruction sequence is provided below:

REPEAT

MOVLW
MOVWF
LFSR

D50
0x80
0,0x0010

CLRF

PREINC0

DECF
BNZ

0x80,F
REPEAT

; Move 50 decimal into WREG


; Initialize Counter 0x80 with 50 decimal
; Initialize pointer FSR0 with starting
;address 0x010
; Clear a location to 0 and increment FSR0
;by 1
; Decrement Counter by 1
; Branch to REPEAT if Zero flag = 0, else
; go to the next instruction

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

20

CHAPTER 6
6.1

MOVF

0x30, W

ADDWF 0x40, W
MOVWF 0x50
6.2
Assume data are already loaded into 0x30, 0x40, 0x50, and 0x60. Also,
assume that no carry is generated due to subsequent addition of two numbers.
INCLUDE <P18F4321.INC>
A

EQU

0x30

EQU

0x40

EQU

0x50

EQU

0x60

EQU

0x70

MOVF

A, W

ADDWF

B, W

ADDWF

C, W

MOVWF

MOVF

D, W

SUBWF

E, F

SLEEP
END

6.3

6.4

(a)

[0x20] = FFH

(b)

[0x0060] = 0x2A

(a)

[0x0075] = 0xFE

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

[FSR2] = 0x0074

6.5

0x0E00
0x6E93
0x0000
0x0EAA
0x6E81
0x0003

6.6

6.7

CLRF

0x20

SETF

0x22

To write an instruction sequence for P = P - Q;


The PIC18F instruction sequence is provided below:
MOVF

Q, W ; Q d W

SUBWF

P, F ; P - Wd P

6.8
The C code is equivalent to:
if (P>Q)
P = 10;
else
P+ = 5;
The PIC18F assembly language instruction sequence is provided below:
MOVF

Q, W

21

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

CPFSGT

BRA

EPART

MOVLW

D10

MOVWF

BRA

NEXT

EPART MOVLW 5
ADDWF

NEXT ----

6.9
[WREG] = 0x110
6.10

(a)

MOVLW 0 or ANDLW 0

(b) CLRF
ANDWF

0x40
0x40, W

6.11
BCF STATUS, C
6.12
Machine code : 11010 + 11-bit offset
Target branch address = (PC+2) + 2 x offset
200 = 202 + 2 x offset
Hence, offset = -1 (decimal) = 111 1111 1111 (binary)
Therefore, the machine code is : 1101 0111 1111 1111 = 0xD7FF

6.13

22

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

23

Assume N1 and N2 are already loaded into registers 0x20 and 0x21
respectively.
INCLUDE <P18F4321.INC>
ORG

0x100

SWAPF

0x21, F

; Swap nibbles of N2 in 0x21

MOVF

0x20, W

; Move [0x20] into WREG

ADDWF

0x21, W

; Add [WREG] with [0x21],


;store result in WREG

MOVWF

0x30

; Store result in 0x30

SLEEP
END

6.14
INCLUDE <P18F4321.INC>
ORG

0x100

MOVLW

0xF1 ; Load highest byte of the first 24-bit data

MOVWF

0x20

MOVLW

0x91

MOVWF

0x21

MOVLW

0xB5 ; Load lowest byte of the first 24-bit data

MOVWF

0x22

MOVLW

0x04 ; Load highest byte of the second 24-bit data

MOVWF

0x50

MOVLW

0xA2

MOVWF

0x51

Instructors Manual

BACK

Microcontroller Theory & Applications with the PIC18F

24

MOVLW

0x07 ; Load lowest byte of the second 24-bit data

MOVWF

0x52

LFSR

0, 0x22 ; Initialize pointer

LFSR

1, 0x50 ; Initialize pointer

MOVLW

MOVWF

0x30

BCF

STATUS, C ; Clear Carry flag

MOVF

POSTDEC0, W

; Initialize Counter

ADDWFC POSTINC1, F
DECF

0x30, F

BNZ

BACK

; Load a byte of first data into WREG


; Add with a byte of second data, and
;store result

SLEEP
END

6.15
INCLUDE <P18F4321.INC>
ORG

0x100

; Starting address of program

MOVLW

0x72

; load low byte of first data

MOVWF

0x50

MOVLW

0x64

MOVWF

0x40

MOVLW

0x16

MOVWF

0x25

MOVLW

0x34

; load high byte of first data

; load low byte of second data

; load high byte of second data

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

25

MOVWF

0x20

MOVF

0x25, W

; Load low byte of second data into WREG

SUBWF

0x50, F

; Subtract low bytes, store result in 0x50

MOVF

0x20, W

; Load high byte of second data into WREG

SUBWFB

0x40, F

; Subtract low bytes with borrow , store


;result in 0x40

SLEEP
END
6.16
Assume data are already loaded into data registers.
INCLUDE
ORG
COUNTER EQU
MOVLW
MOVWF
MOVLW
MOVWF
MOVWF
LFSR
LFSR
BACK
MOVF
MULWF

<P18F4321.INC>
0x100
; Starting address of program
0x20
D10
; Initialize COUNTER with 10
COUNTER ; Move [WREG] into COUNTER
0
; Clear 16-bit SUM to 0
0x40
0x41
0, 0x50
; Initialize pointer for Xi
1, 0x70
; Initialize pointer for Yi
POSTINC0, W; Move Xis into WREG
POSTINC1 ; Unsigned multiply by Yis
; Result in PRODH:PRODL
MOVF
PRODL, W ; SUM in 0x41:0x40
ADDWF 0x40, F
MOVF
PRODH, W
ADDWFC 0x41, F
DECF
COUNTER
BNZ
BACK
SLEEP
END

6.17

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

26

INCLUDE <P18F4321.INC>
ORG

0x50

MOVLW

MOVWF

0x32

MOVLW

MOVWF

0x33

MOVLW

MULWF

0x32

; 6 x J in PRODH:PRODL

RRNCF

0X33,F

; Compute K/2 in 0x33

RRNCF

0X33,F

; Compute K/2 in 0x33

RRNCF

0X33,F

; Compute K/4 in 0x33

MOVFF

0x33, 0x51 ; K/8 in 0x51

MOVLW

MOVWF

0x50

MOVF

PRODL, W

ADDWF

0x51, F

MOVF

PRODH, W

; Load J

; Load K

; Zero extend (K/8) to 16 bits

ADDWFC 0x50, F
SLEEP
END
6.18
INCLUDE <P18F4321.INC>
ORG

0x50

ANDLW

0x01

; Check if [WREG] odd or even

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

BNZ

ODD

CLRF

0x40

BRA

FINISH

ODD

SETF

0x40

FINISH

BRA

FINISH

27

; Clear [0x40] to 0s

; Set [0x40] to all 1s

END
6.19
INCLUDE <P18F4321.INC>
ORG

0x70

MOVWF

0x20

; Save [WREG] in 0x20

RLCF

0x20, F

; Check whether the number is


;positive or negative

BNC

POSITIVE ; If no carry, branch to positive

IORLW

BRA

FINISH

POSITIVE

ANDLW

0xFB

FINISH

BRA

FINISH

; else negative, insert 1 at bit 2 of


;WREG

; Clear bit 2 of WREG

END
6.20
Assume data is already loaded into 0x70.
INCLUDE <P18F4321.INC>
ORG

0x100

COUNTER

EQU

0x20

PARITY

EQU

0x21

; Register 0x21to hold number of 1s

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

28

MOVLW

MOVWF

COUNTER ; Initialize COUNTER

CLRF

PARITY

; Clear register 0x21 to 0

RRCF

0x70, F

; Check a bit to carry

BC

DOWN

; If carry is 1, increment
;register 0x21

BRA

DOWN1
; else, dont increment, but decrement
; COUNTER

DOWN

INCF

PARITY, F

DOWN1

DECF

COUNTER, F

BNZ

BACK

RRCF

PARITY, F ; Check if # of 1s in 0x21 is odd or


;even

BNC

EVEN

; If no carry, even parity

MOVLW

0xDD

; else, odd parity

MOVWF

0x50

; Store 0xDD in 0x50

BRA

FINISH

MOVLW

0xEE

MOVWF

0x50

BRA

FINISH

BACK

EVEN

FINISH

; If Z = 1, 0x21 has number of 1s

; Store 0xEE in 0x50

END
6.21
Assume that the unsigned 16-bit number is 0x0124 (arbitrarily chosen). Since the
remainder can be discarded, unsigned division can be accomplished by logically
shifting the 16-bit unsigned number, 0x0124 once to the right.
INCLUDE <P18F4321.INC>

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

ORG

0x100

MOVLW

0x01

MOVWF

0x20

MOVLW

0x24

MOVWF

0x21

BCF

STATUS, C ; Clear Carry flag to 0

RRCF

0x20, F

RRCF

0x21, F

SLEEP
END

; Load high byte into 0x20

; Load low byte into 0x21

; Right shift [0x20][0x21] once

29

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

30

CHAPTER 7
7.1
Assume data are already loaded into registers.

ODD

FINISH

INCLUDE
ORG
RRCF
BC
CLRF
CLRF
BRA
MOVF
SUBWF
MOVWF
MOVF
SUBFWB
MOVWF
BRA
END

<P18F4321.INC>
0x150
0x50, F
; Check whether [0x50] is odd or even
ODD
; If Carry = 1, result odd, stop
0x40
; else, store 0s in 0x40 and 0x41
0x41
FINISH
; Branch to Stop
0x30, W
; Subtract low bytes
0x20, W
0x41
; Store low byte subtraction result in 0x41
0x21, W
; Subtract high bytes
0x31, W
0x40
; Store high byte subtraction result in 0x40
FINISH
; Stop

7.2
Assume data is already loaded into 0x30.
INCLUDE <P18F4321.INC>
ORG

0x200

MOVFF

0x30, 0x40 ; Copy data in 0x40

SWAPF

0x30, F

; Move data into low 4 bits

MOVLW

0x0F

; Move mask data into WREG

ANDLW

0x30, F

; One unsigned 8-bit data in 0x30

ANDLW

0x40, W

; Another unsigned data in WREG

MULWF

0x30

; unsigned multiply data


; Since result will be 8-bit maximum,
; PRODL will contain result

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

MOVWF
SLEEP

PRODL, 0x31

31

; Result in 0x31
; HALT

END
7.3
Assume data are already loaded into data register 0x30. Perform signed
multiplication.
INCLUDE
ORG
EQU
EQU
EQU
EQU
MOVFF
MOVLW
ANDWF
BNZ
MOVLW
ANDWF
MOVLW
IORWF
SWAPF
MOVLW
ANDWF
MOVLW
MOVWF
CALL

<P18F4321.INC>
0x100
MULT1
0x30
MULT2
0x40
SIGN1
0X50
SIGN2
0X51
MULT1, MULT2; Save data in 0x40
8
; Mask bit 3 (sign bit) of 1st data
MULT1, W
SIGN
; If Z = 1, branch to sign extend
0x0F
; else, zero extend 1st data
MULT1, F
SIGN
0xF0
MULT1, F
MULT2, F
0x0F
; zero extend 2nd data
MULT2, F
5
; Initialize STKPTR since
STKPTR ; since subroutine is used
SMULT
; Call subroutine for signed
;multiplication
SLEEP
; Halt. 8-bit result in PRODL
ORG
0x200
; Subroutine for signed multiplication
SMULT
CLRF
SIGN1
; Clear [SIGN1] to 0
CLRF
SIGN2
; Clear [SIGN2] to 0
; STEPS 1 AND 2 OF THE ALGORITHM OF SECTION 7.7.1
BTFSS
MULT1, 7 ; Check sign bit 7 for 1 for 1st #
BRA
NEG
; If sign = 0, branch to check sign of
; 2nd#
INCF
SIGN1 ; Increment [SIGN1] if sign of 1st# = 1
NEGF
MULT1 ; and take 2's complement of [MULT1]
NEG
BTFSS
MULT2, 7 ; Check sign bit 7 for 1 for 2nd #

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

BRA

32

POSMUL

;If both sign= 0, branch for unsigned


;mul
INCF
SIGN2
; Increment [SIGN2] if sign of 2nd#
;= 1
NEGF
MULT2
; and take 2's complement of
;[MULT2]
; STEP 3 OF THE ALGORITHM OF SECTION 7.7.1
POSMUL MOVF
MULT1, W ; Move [MULT1] to WREG
MULWF MULT2
; Unsigned product in
;PRODH:PRODL
MOVF
SIGN1, W ; Move [SIGN1] to WREG
XORWF
SIGN2
; Compute sign of the result
BTFSS
SIGN2, 0 ; If sign of result is 0, result in
BRA
FINISH
; PRODH:PRODL and Stop
COMF
PRODL
; For negative result, take comp of
;PROD
; STEPS 4 AND 5 OF THE ALGORITHM OF SECTION 7.7.1
COMF
PRODH
; Take 2s complement of PRODL
MOVLW 1
ADDWF PRODL
MOVLW 0
ADDWFC PRODH, F ; Result in PRODH:PRODL in 2s
;comp
FINISH
RETURN
END
7.4
INCLUDE
ORG
DIVIDEND EQU
DIVISOR EQU
COUNTER EQU
MOVLW
MOVWF
MOVLW
MOVWF
MOVLW
SUBLW
MULLW
MOVFF
MOVLW
MOVWF

<P18F4321.INC>
0x150
0x20
0x40
0x21
4
; Initialize STKPTR since subroutine is used
STKPTR
D50
; Load 50 deg F to be converted to deg C
DIVIDEND
D32
DIVIDEND ; (F-32) in WREG
5
; 8-bit result of (F-32) x 5 in PRODL.
PRODL, DIVIDEND
; Save in DIVIDEND
9
DIVISOR

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

33

CALL
UDIV
FINISH
BRA
FINISH
; Halt. 8-bit result in 0x21
ORG
0x100
UDIV
CLRF
COUNTER
; Clear Counter to 0
; STEPS 1 AND 2 OF THE ALGORITHM OF SECTION 7.7.2
BACK
CPFSEQ
DIVIDEND
; If dividend equals divisor, skip next
;instr.
BRA
RESULT
; If not equal, branch to RESULT
INCF
COUNTER, F ; Increment [0x21] by 1
SUBWF
DIVIDEND, F ; Subtract divisor from dividend, result
;in 0x20
BRA
MAIN ; Go to Halt
; STEPS 3 , 4 AND 5 OF THE ALGORITHM OF SECTION 7.7.2
RESULT CPFSGT
DIVIDEND ; If dividend greater than divisor, skip
;next inst.
BRA
MAIN
; Quotient in 0x21, Remainder in 0x20
;is assumed
; to be 0 in this case, return
INCF
COUNTER, F ; Increment [0x21] by 1
SUBWF
DIVIDEND, F ; Subtract divisor from dividend,
;result in 0x20
BRA
BACK
; Repeat
MAIN
RETURN
; Return
END
7.5
Assume data is already loaded into 0x40.
INCLUDE <P18F4321.INC>

COUNTER

ORG

0x100

EQU

0x50

MOVF

0x40, W

; Move X into WREG

MULWF

0x40

; Compute (X ** 2). Result in


;PRODH:PRODL

MOVLW

; Initialize COUNTER

MOVWF

COUNTER

Instructors Manual

BACK

FINISH

Microcontroller Theory & Applications with the PIC18F

BCF

STATUS, C ; Clear Carry and compute


;(X**2)/128

RRCF

PRODH, F

RRCF

PRODL, F

DECF

COUNTER, F

BNZ

BACK

MOVFF

PRODL, 0x50

BRA

FINISH

; Store 8-bit result in 0x50

END
7.6
INCLUDE <P18F4321.INC>

HERE

ORG

0x100

LFSR

0, 0x0070

MOVLW

0xFF

MOVWF

0x30

MOVLW

MOVWF

0x60

MOVLW

0x10

MOVWF

STKPTR

CALL

SUMSQ

MOVFF

0x40, PREINC0

BRA

HERE

34

; Load X

; Load Y

; Push 8-bit result onto


;software stack

Instructors Manual

SUMSQ

Microcontroller Theory & Applications with the PIC18F

35

ORG

0x200

MOVF

0x60, W

MULWF

0x60

; 8-bit (Y**2) in PRODL

MOVFF

PRODL, 0x70

; Save in 0x70

CALL
MOVF

SMUT ; Compute 8-bit (X**2) in


PRODL, W

ADDWF

0x40, F

PRODL

; (X**2 + Y**2) in 0x40

RETURN
ORG
MULT1
MULT2
SIGN1
SIGN2
SMUT

0x150

EQU
0x30
EQU
0x30
EQU
0X50
EQU
0X51
CLRF
SIGN1
; Clear [SIGN1] to 0
CLRF
SIGN2
; Clear [SIGN2] to 0
; STEPS 1 AND 2 OF THE ALGORITHM OF SECTION 7.7.1
BTFSS
MULT1, 7 ; Check sign bit 7 for 1 for 1st #
BRA
NEG
; If sign = 0, branch to check sign of
; 2nd#
INCF
SIGN1 ; Increment [SIGN1] if sign of 1st# = 1
NEGF
MULT1 ; and take 2's complement of [MULT1]
NEG
BTFSS
MULT2, 7 ; Check sign bit 7 for 1 for 2nd #
BRA
POSMUL ;If both sign= 0, branch for unsigned
;mul
INCF
SIGN2 ; Increment [SIGN2] if sign of 2nd# = 1
NEGF
MULT2 ; and take 2's complement of [MULT2]
; STEP 3 OF THE ALGORITHM OF SECTION 7.7.1
POSMUL
MOVF
MULT1, W ; Move [MULT1] to WREG
MULWF MULT2 ; Unsigned product in PRODH:PRODL
MOVF
SIGN1, W ; Move [SIGN1] to WREG
XORWF
SIGN2
; Compute sign of the result
BTFSS
SIGN2, 0 ; If sign of result is 0, result in
BRA
FINISH
; PRODH:PRODL and Stop
COMF
PRODL
; For negative result, take comp of
;PRODL

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

36

; STEPS 4 AND 5 OF THE ALGORITHM OF SECTION 7.7.1


COMF
PRODH
; Take 2s complement of PRODL
MOVLW 1
ADDWF PRODL
MOVLW 0
ADDWFC PRODH, F ; Result in PRODH:PRODL in 2s
;comp
FINISH
RETURN
END
7.7
Assume arrays x[i] and y[i] are already loaded into 0x20 and 0x30 respectively.
Use MULWF for unsigned multiplication.
INCLUDE <P18F4321.INC>

LOOP

ORG

0x100

CLRF

0x50

; Clear sum to 0

LFSR

0, 0x0020

; Load 0x0020 into FSR0

LFSR

1, 0x0030

; Load 0x0030 into FSR1

MOVLW

D10

; Move 10 (decimal) into counter 0x75

MOVWF

0x75

MOVF
MULWF

POSTINC0, W; Move x[i] into WREG, increment ptr


POSTINC1 ; unsigned multiply in x[i] * y[i]

MOVF

PRODL, W ; Move 8-bit product to WREG

ADDWF

0x50, F

; sum in 0x50

DECF

0x75, F

; Decrement counter by 1

BNZ

LOOP

; Repeat if Z = 0

SLEEP
END

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

37

7.8
INCLUDE <P18F4321.INC>

BACK

ORG

0x150

MOVLW

0xEE

MOVWF

0x20

CLRF

0x21

MOVLW

D10

MOVWF

0x22

LFSR

0, 0x60

; Initialize software SP

LFSR

1, 0x30

; Initialize pointer for string 1

LFSR

2, 0x50

; Initialize pointer for string 2

MOVF

POSTINC1 ; Move a byte from string 1 to WREG

CPFSEQ

POSTINC2 ; Compare with string2 for equality

BRA

NOTEQUAL

MOVFF

0x20, PREINC0 ; Push EE to software stack

BRA

DOWN

; Initialize counter

NOTEQUAL MOVFF

0x21, PREINC0 ; Push 0 onto software stack

DOWN

DECF

0x22, F

BNZ

BACK

BRA

FINISH

FINISH

END
7.9

; Decrement counter

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

38

INCLUDE <P18F4321.INC>

BACK

BACK1

ORG

0x100

MOVLW

MOVWF

0x40

BCF

STATUS, C ; Clear Carry

RRCF

0x30, F

; Shift [0x30][0x31] seven times

RRCF

0x31, F

; to right to move 9-bit data

DECF

0x40, F

; in low 9 bits of the registers

BNZ

BACK

MOVLW

MOVWF

0x40

BCF

STATUS, C

RRCF

0x30, F

RRCF

0x31, F ; to right to divide by 8 by discarding remainder

DECF

0x40, F

BNZ

BACK1

; Shift [0x30][0x31] three times

SLEEP
END
7.10
INCLUDE <P18F4321.INC>
ORG

0x200

MOVLW

; Load shift count in 0x44

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

39

MOVWF

0x44

; to divide by 16

RRCF

0x31, W

; Check sign bit

BNC

POSITIVE ; If Carry = 0, the number is positive

SETF

0x40 ; else, the number is negative, set [0x40] to 1s

BRA

FINISH

POSITIVE RLCF

0x20, F

; Shift [0x21][0x20] four times to left

RLCF

0x21, F

; to multiply by 8

DECF

0x44, F

BNZ

POSITIVE

BRA

FINISH

FINISH

END
7.11
Assume data are already loaded into data memory from 0x10 through 0x2D. Also,
note that a number P is divisible by 5 if its least significant digit is either 0 or
5.
INCLUDE <P18F4321.INC>

BACK

ORG

0x100

MOVLW

0x2D

MOVWF

0x60

CLRF

0x40

; Clear counter 0x40 to 0

LFSR

0, 0x10

; Load starting address into FSR0

MOVLW

0x0F

; Load mask data into WREG

; Move last address to 0x60

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

40

ANDWF

INDF0, F

; Retain low 4 bits of data in data memory


;address

MOVFF

INDF0, 0x60; Save masked data in 0x60

MOVLW

0x00

; Load 0 into WREG

SUBWF

INDF0, F

; Subtract 0 from data

BZ

DOWN

; If Z = 1, divisible by 5, increment [0x40]

MOVLW

0x05

; Else, load 5 into WREG

SUBWF

0x60, F

; Subtract 5 from data byte

BZ

DOWN

; If Z = 1, divisible by 5, increment [0x40]

MOVLW

0x2D

; Load last address into WREG

CPFSEQ

0x60

; If [FSR0] = 0x2D, skip

BRA

DOWN1

FINISH

BRA

FINISH

DOWN

INCF

0x40, F

; Increment [0x40] by 1

DOWN1

INCF

FSR0, F

; Increment [FSR0] by 1

BRA

BACK

END
7.12
Assume data are already loaded into data registers.
INCLUDE <P18F4321.INC>
ORG

0x100

MOVLW

MOVWF

0x50

; Initialize counter

Instructors Manual

BACK

Microcontroller Theory & Applications with the PIC18F

41

LFSR

0, 0x23

LFSR

1, 0x33

BCF

STATUS, C

MOVF

INDF0, W ; Load a data byte into WREG for 1st #

; Clear Carry

ADDWFC POSTDEC1, W

; Add with carry, result in WREG

DAW

; Convert to valid BCD

MOVWF

POSTDEC0

; Store in data memory

DECF

0x50, F

; Decrement counter

BNZ

BACK

; Branch to BACK if Z not 0

SLEEP
END
7.13
; Main program
INCLUDE <P18F4321.INC>
ORG
0x200
COUNTER EQU
0x20
MOVLW UPPER ADDR ; Move upper 5 bits (00H) of address
MOVWF TBLPTRU ; to TBLPTRU
MOVLW HIGH ADDR
; Move bits 15-8 (03H) of address
MOVWF TBLPTRH ; to TBLPTRH
MOVLW LOW ADDR ; Move bits 7-0 (00H) of address
MOVWF TBLPTRL ; to TBLPTRL
LFSR
0, 0x50
; Initialize FSR0 to 0x50 to be used as
; destination pointer in data memory
MOVLW D10
; Initialize COUNTER with 10
MOVWF COUNTER ; Move [WREG] into COUNTER
LOOP
TBLRD*+
; Read data from program memory
; into TABLAT, increment TBLPTR by 1
MOVF
TABLAT, W ; Move [TABLAT] into WREG

Instructors Manual

MOVWF

FINISH

Microcontroller Theory & Applications with the PIC18F

42

DECF
BNZ
MOVLW
MOVWF
MOVLW
CALL
BRA

POSTINC0 ; Move W into data memory pointed


; to by FSR0, and then increment FSR0
; by 1
COUNTER, F ; Decrement COUNTER BY 1
LOOP
; Branch if Z = 0, else Stop
0x10
STKPTR
5
; BCD digit arbitrarily chosen
SQUARE
FINISH

ORG
LFSR

0x100
0, 0x50

MOVF

PLUSW0, W

; Subroutine
SQUARE

; Starting address of the pointer


;where squares are stored
; Move the square of the BCD digit
;into WREG

RETURN
ORG
0x300
; Square of BCD digits
ADDR DB D0, D1, D4, , D9, D16, D25, D36, D49, D64, D81
END
7.14
; Main program
INCLUDE <P18F4321.INC>
ORG
0x200
MOVLW 0x10
MOVWF STKPTR
MOVLW 5
; BCD digit arbitrarily chosen
CALL
SQUARE
FINISH
BRA
FINISH
; SUBROUTINE
ORG
0x100
SQUARE MULLW 2
;Double the WREG value
MOVF
PRODL,W ;Place the answer back into WREG
ADDWF
PCL
;Use PCL to find the location on the table
; PCL CONTAINS THE STARTING ADDRESS OF THE TABLE
RETLW
D0
;Value for square of 0
RETLW
D1
;Value for square of 1
RETLW
D4
;Value for square of 2
RETLW
D9
;Value for square of 3

Instructors Manual

RETLW
RETLW
RETLW
RETLW
RETLW
RETLW
END

Microcontroller Theory & Applications with the PIC18F

D16
D25
D36
D49
D64
D81

43

;Value for square of 4


;Value for square of 5
;Value for square of 6
;Value for square of 7
;Value for square of 8
;Value for square of 9

7.15
Assume BCD digit is low nibble of each byte; high nibble is 0.
N = (N2 x 10 1 + N1) x 10 + N0
The PIC18F assembly language program is provided below:
INCLUDE
ORG
BCD2BIN MOVLW
MOVWF
MOVLW
MOVWF
LFSR
MOVF
MULWF
MOVF
ADDWF
MOVF
ADDWF
MOVF
MULWF
MOVF
ADDWF
RETURN
END

<P18F4321.INC>
0x150
0
; Clear 8-bit sum in 0x50 to 0
0x50
D10
0x40
0, 0x30
; Initialize pointer
POSTINC0, W
; Move N2 into WREG
0x40
; 10 x N2 dPRODL
PRODL, W
0x50, F
POSTINC0, W
; Move N1 into WREG
0x50, F
; (N2 x10 + N1) in 0x50
0x40, W
0x50
; (N2 x10 + N1) x 10 in PRODL
POSTINC0, W
; Move N0 into WREG
0x50, F
; Result in 0x50

7.16
; Main program
INCLUDE <P18F4321.INC>
ORG
0x150
LFSR
1, 0x30

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

MOVLW
MOVWF
CALL
RRNCF
RRNCF
RRNCF
SLEEP

D20
STKPTR
SUM
0X50,F
0X50,F
0X50,F

ORG
CLRF
MOVLW
MOVWF
MOVF
ADDWF
DECF
BNZ
RETURN
END

0x100
0x50
; Clear sum to 0
8
0x60
; Move 8 to 0x60
POSTINC1, W
; Move Xi to WREG
0x50, F
; Add Xis, result in 0x50
0x60, F
BACK

44

; Unsigned divide by 8 by shifting


;three times to right

; Subroutine
SUM
BACK

7.17
INCLUDE
VALUE
EQU
CONST
EQU
COUNTER EQU
ORG
CLRF
MOVLW
SUBWF
BN
BACK

INCF
MOVLW
ADDWF
MOVF
SUBWF
BN
BRA
FINISHED JMP
END
7.18

<P18F4321.INC>
0x20
;0x20 contains the number
0x21
0x22
0x100
COUNTER
;Clear [COUNTER] to 0
1
VALUE, F
;Subtract 1 from number.
FINISHED ;If the number is 0, result will be negative,
;branch to end
COUNTER, F
;else, increment [COUNTER] by 1
2
CONST, F ;Increment [CONST] by 2 to obtain 3, 5 etc
CONST, W
;Move [CONST] to WREG
VALUE, F
;Subtract [WREG] from [VALUE]
FINISHED
;If result negative, go to end
BACK
; else, repeat
FINISHED ;COUNTER contains sq root of the number

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

45

Since Fosc = 1 MHz, each instruction cycle = 4 sec


Total Delay (D) for the DELAY loop = (145, 940 msec)/(4 sec) = 34, 685
Delay (I2) in LOOP2 = 99 (3) + 2 = 299
Delay (I1) between the label LOOP1 and the BNZ LOOP1
instruction = (Q-1)x ( 2 + I2 + 3) + (2 + I2 + 4)
= (Q-1)x (I2 + 5) + ( I2 + 6)
= Q (I2 + 5) + 1
= 304 Q + 1
Total Delay in the DELAY loop including MOVLW, MOVWF, and RETURN =
2 + I1 +2 = I1 + 4 = 304 Q + 5
Hence, 304 Q + 5 = 34, 685
304Q = 34, 680
Therefore, Q = 120

7.19
The timing calculation for Method I is : 1 + 1 + 79 x (1 + 2) + 1 + 1 = 241
instruction cycles.
The timing calculation for Method II is : 1 + 1 + 79 x (1 + 1 ) + 1 + 2 = 163
instruction cycles.
If we assume a default clock of 1 MHz, then one instruction cycle = 4 x 1 sec = 4
sec.
Therefore, the first delay loop (Method I) will take 0.964 msec while the second
loop (Method II) will take 0.653 msec. Hence, Method II is better choice in terms
of execution time.

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

47

Chapter 8
8.1
Pin numbers 11 and 32 are for power, and pin numbers 12 and 31 are for ground.
The purpose is to distribute power in order to reduce noise.
8.2
1 MHz
8.3
Upon activating the

MCLR

pin, the PC is loaded with address 0.

8.4
A Power-on reset is generated upon power-up whenever VDD rises above a
certain threshold.
This allows the device to start in the initialized state when VDD is adequate for
operation.
A manual reset, on the other hand, is activated a push button connecting to the
PIC18F4321s MCLR pin via a reset circuit. The reset circuit provides the
minimum timing requirements for the manual reset. During normal operation, a
program can be executed by activating the push button.
8.5
The PIC18F4321 chip contains four 8-bit ports namely, Ports A through D, a 4-bit
port called Port E.
8.6
(a) SETF

TRISC

(c) MOVLW
MOVWF

0x0F
ADCON1

(b) CLRF

TRISD

(d) CLRF

TRISA

8.7
INCLUDE
SETF
BCF
BCF

<P8F4321.INC>
PORTC
; Configure PORTC as an input port
TRISD, 6 ; Configure bit 6 of PORTD as output
PORTD, 6 ; Turn LED OFF

Instructors Manual

MOVF
MOVLW
ANDWF
MOVLW

FINISH
LED

SUBWF
BZ
MOVLW
SUBWF
BZ
MOVLW
SUBWF
BZ
MOVLW
SUBWF
BZ
SLEEP
BSF
BRA
END

Microcontroller Theory & Applications with the PIC18F

48

PORTC, F ; Input PORTC


0x07
PORTC, F ; Retain low three bits
0x00
; Check for no high switches, 0 is an even
;number
PORTC, W
LED
; If no high switches, turn LED ON
0x03
; Check for two high switches
PORTC, W
LED
; If two high switches, turn LED ON
0x05
; Check for two high switches
PORTC, W
LED
; If two high switches, turn LED ON
0x06
; Check for two high switches
PORTC, W
LED
; If two high switches, turn LED ON
; Halt
PORTD, 6; Turn LED ON
FINISH

8.8
INCLUDE
MOVLW

FINISH

MOVWF
MOVF
MOVWF
MOVF
MOVWF
RRNCF
RRNCF
BCF
BCF
MOVFF
MOVFF
BRA
END

<P18F4321.INC>
0x0F
;Configure PORTA and PORTB as
;inputs
ADCON1
PORTA, W
;Input PORTA into WREG
0x20
;Save in 0x20
PORTB, W
;Input PORTB into WREG
0x21
;Save in 0x21
0x20, F
;Align data in PORTA
0x21, F
;Align data in PORTB
TRISA, RA0 ;Configure RA0 as output
TRISB, RB0 ;Configure RB0 as output
0x20, PORTA ;Output to PORTA LED
0x21, PORTB ;Output to PORTB LED
FINISH

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

49

8.9
INCLUDE
ORG
MOVLW
MOVWF
MOVLW

LED
FINISH

MOVF
ANDLW
BNZ
MOVLW
MOVF
ANDLW
BZ
MOVLW
MOVF
ANDLW
BZ
MOVLW
MOVF
ANDLW
BZ
MOVLW
MOVWF
BRA
MOVLW
MOVWF
BRA
END

<P18F4321.INC>
0x100
0x04
TRISD
;Configure PORTD as output, turn LEDs
;OFF
0x1B
;Output 11 to NAND inputs keeping LEDs
;OFF
PORTD, W ;Input PORTD into WREG
4
;Mask NAND output (bit 2)
LED
;If NAND output is 1, turn ON faulty LED
0x19
;Output 01 to NAND inputs
PORTD, W ;Input PORTD into WREG
4
;Mask NAND output (bit 2)
LED
;If NAND output is 0, turn ON faulty LED
0x1A
;Output 10 to NAND inputs
PORTD, W ;Input PORTD into WREG
4
;Mask NAND output (bit 2)
LED
;If NAND output is 0, turn ON faulty LED
0x18
;Output 00 to NAND inputs
PORTD, W ;Input PORTD into WREG
4
;Mask NAND output (bit 2)
LED
;If NAND output is 0, turn ON faulty LED
0x10
;Turn ON LED indicating good chip
PORTD
FINISH
8
;Turn ON LED indicating faulty chip
PORTD
FINISH

8.10
INCLUDE <P18F4321.INC>
; MAIN PROGRAM
ORG
0x40
SETF
TRISC
;Configure PORTC is input
CLRF
TRISD
;Configure PORTD is output
MOVLW 0x10
MOVWF STKPTR ;Initialize STKPTR to 0x10
LOOP
MOVF
0x20, W
;Move [0x20] to WREG

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

50

ANDLW 7
;Mask the lower 3 bits
MOVWF 0x20
MOVF
0x21, W
;Move [0x20] to WREG
ANDLW 7
;Mask the lower 3 bits
ADDWF 0x20, W
;Addition result in WREG
CALL
LOOKUP ;Call the subroutine LOOKUP
MOVWF PORTD
;Move WREG to PORTD
BRA
LOOP
;Loop
; SUBROUTINE
ORG
0x70
LOOKUP MULLW 2
;Double the WREG value
MOVF
PRODL,W ;Place the answer back into WREG
ADDWF
PCL
;Use PCL to find the location on the table
; PCL CONTAINS THE STARTING ADDRESS OF THE TABLE
RETLW
0x3F
;Value for 0 display
RETLW
0x06
;Value for 1 display
RETLW
0x5B
;Value for 2 display
RETLW
0x4F
;Value for 3 display
RETLW
0x66
;Value for 4 display
RETLW
0x6D
;Value for 5 display
RETLW
0x7D
;Value for 6 display
RETLW
0x07
;Value for 7 display
RETLW
0x7F
;Value for 8 display
RETLW
0x67
;Value for 9 display
END

8.11
INCLUDE
ORG
COUNTER EQU
MOVLW

<P18F4321.INC>
0x100
0x20
UPPER ADDR ; Move upper 5 bits (00H) of address

MOVWF TBLPTRU ;
MOVLW HIGH ADDR
MOVWF TBLPTRH ;
MOVLW LOW ADDR
MOVWF TBLPTRL ;
LFSR
0, 0x30
;
; destination pointer in data memory
MOVLW D10
;

to TBLPTRU
; Move bits 15-8 (03H) of address
to TBLPTRH
; Move bits 7-0 (00H) of address
to TBLPTRL
Initialize FSR0 to 0x30 to be used as
Initialize COUNTER with 10

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

51

MOVWF
LOOP

STAY
ADDR

COUNTER ; Move [WREG] into COUNTER


TBLRD*+ ; Read data from program memory
; into TABLAT, increment TBLPTR by 1
MOVF
TABLAT, W
; Move [TABLAT] into WREG
MOVWF POSTINC0 ; Move W into data memory pointed
; to by FSR0, and then increment FSR0
; by 1
DECF
COUNTER, F ; Decrement COUNTER BY 1
BNZ
LOOP
; Branch if Z = 0, else Stop
SETF
TRISC
; Configure PORTC as input
CLRF
TRISD
; Configure PORTD as output
LFSR
0, 0x00
; Load FSR0 to be used as a pointer
MOVF
PORTC, W ; Input an ASCII code in WREG
MOVFF
PLUSW0, PORTD ; using indexed addressing
BRA
STAY
ORG
0x300 ; EBCDIC codes for BCD digits
DB 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9
END

8.12
INCLUDE <P18F4321.INC>
ORG
0x200
START
MOVLW 0x0F
MOVWF ADCON1
BCF
TRISC, 1
BCF
PORTC, RC1
BACK
MOVF
PORTB, 0x20
RRCF
0x20, W
BNC
BACK
BSF
PORTC, RC1
BRA
START
END

;Configure PORTB as input


; Configure bit 1 of PORTC as an output
;Turn LED OFF
; Input PORTB into 0x20
; Rotate right once to align output data
;Wait for the COMP.output to be HIGH
;Turn LED ON

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

52

8.13
The PIC18F assembly language program is provided in the following:
INCLUDE <P18F4321.INC>
ORG
0
GOTO
MAIN_PROG
; MAIN PROGRAM
ORG
0x00080
MAIN_PROG
MOVLW 5
MOVWF STKPTR
BCF
TRISC,1

; RESET
; MAIN PROGRAM
; Initialize STKPTR with 5
; Configure bit 1 OF PORTC as
; output
; Configure INT1 as input

MOVLW 0x0F
MOVWF ADCON1
BCF
INTCON, INT1IF ; Clear interupt flag
BSF
INTCON3, INT1IE; Enable the external interrupt
BSF
INTCON, GIE
; Enable global interrupts
BCF
PORTC, RC1
; Turn LED OFF
OVER
BRA
OVER
; Wait for interrupt
GOTO
MAIN_PROG
; Repeat
; INTERRUPT SERVICE ROUTINE
ORG
0X000008
BRA
ISR
ORG
0x000150
; Interrupt Address Vector
ISR
BSF
PORTC, RC1
; Turn LED ON
BCF
INTCON, INT1IF ; Clear the external interrupt
; flag to avoid double interrupt
RETFIE
; Enable interrupt and return
END

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

8.14 (a)

From INT0
output
of OR
PORTC
gate in
Figure
P8.14
PIC18F4321

3
.
.

To
LED

X
From output
of top
comparator
of Figure
P8.14

(b)
The PIC18F assembly language program is provided in the following:
INCLUDE <P18F4321.INC>
ORG
0
GOTO
MAIN_PROG
; MAIN PROGRAM
ORG
0x000150
MAIN_PROG MOVLW 0x10
MOVWF STKPTR
MOVLW 1
MOVWF TRISC
MOVLW 0x0F
MOVWF ADCON1
BCF
INTCON, INT0IF
BSF
INTCON, INT0IE
BSF
INTCON, GIE
BCF
PORTC, RC3
OVER
BRA
OVER
GOTO
MAIN_PROG
; INTERRUPT SERVICE ROUTINE
ORG
0X000008
BRA
ISR

; RESET
; MAIN PROGRAM
; Initialize STKPTR to 0x10
; Configure PORTC
; Configure INT0 as input
; and bit 1 as input
; Clear interrupt flag
; Enable the external interrupt
; Enable global interrupts
; Turn LED OFF
; Wait for interrupt
; Repeat

53

Instructors Manual

ISR

LEDON
HERE

ORG
MOVFF
RRCF
BC
BCF
BRA
BSF
BCF

Microcontroller Theory & Applications with the PIC18F

0x000200
PORTC, 0x50
0x50
LEDON
PORTC, RC3
HERE
PORTC, RC3
INTCON, INT1IF

54

; Interrupt Address Vector


; Move PORTC into 0x50
; Turn LED OFF
; Turn LED ON
;Clear the external interrupt flag to
;avoid double interrupt

RETFIE
END

8.15
0x000008
8.16
The PIC18F4321 does not have any nonmaskable external interrupts. All external
interrupts (INT0, INT1, INT2) are maskable.
8.17
High priority interrupt address vector is 0x000008.
Low priority interrupt address vector is 0x000018.
8.18
Upon power-on reset, all interrupts in the PIC18F4321 have high priorities; no
interrupt priorities are available.
8.19
RETFIE instruction pops the contents of the program counter previously pushed
before going to the service routine, enables the global interrupt enable bit, and
returns control to the appropriate place in the main program. The RETFIE 1
instruction, on the other hand, pops the contents of WREG, BSR, and STATUS
registers (previously PUSHed) from shadow registers WS, STATUSS, and BSRS
before going to the main program,, enables the global interrupt enable bit, and
returns control to the appropriate place in the main program.

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

55

8.20
In order to program INT1 as a high priority interrupt and INT2 as a low priority
interrupt, the following instruction sequence can be used:
BSF RCON, IPEN
BSF
BSF
BSF
BCF

; Set IPEN to 1, enable


; interrupt level
INTCON, GIEL ; Set low priority levels
INTCON, GIEH ; Set high priority levels
INTCON3, INTIP ; INT1 has high level
INTCON3, INT2P ; INT2 has low level

8.21
INT0 has high priority level.
8.22
Upon power-on reset, each of the external interrupts (INT0, INT1, INT2) are
activated by a rising edge pulse (LOW to HIGH).
The following PIC18F instruction sequence will activate the triggering level of
INT0 by rising edge, and INT1 and INT2 by falling edge:
BSF INTCON2, INTEDG0
BCF INTCON2, INTEDG1
BCF INTCON2, INTEDG2
8.23
The PIC18F4321 provides four interrupt-on-change pins (KB10 through KB13).
These pins are multiplexed among others with bits 4 through 7 of PORT B.
An input change (HIGH to LOW or LOW to HIGH) on one or more of these
interrupts sets the flag bit, RBIF (bit 0 of INTCON register). Note that a single bit
is assigned to all four interrupts.
8.24
The three control pins, EN, R/W, and RS allow the user to let the display know
what kind of data is sent. The EN pin latches the data from the D0-D7 pins into
the LCD display. Data on D0-D7 pins will be latched on the trailing edge
(high-to-low) of the EN pulse. The EN pulse must be at least 450 ns wide. The
R/W (read/write) pin, allows the user to either write to the LCD or read data from
the LCD.

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

56

8.25

MAIN

AGAIN

INCLUDE <P18F4321.INC>
ORG
0x100
; Start of the MAIN program
MOVLW 5
; Initialize STKPTR with arbitrary value
; of 5
MOVWF STKPTR
CLRF
TRISD
;PORTD is output
CLRF
TRISB
;PORTB is output
SETF
TRISC
;PORTC is input
MOVF
PORTC, W ;Move switch values to WREG
MOVWF 0x50
;Save in 0x50
MOVLW 0x0F
ANDWF 0x50, F
;Mask low 4 bits, and save in 0x50
CPFSEQ 0x50
;Compare switch values with 0x0F
BRA
AGAIN
CLRF
PORTB
;rs=0 rw=0 en=0
MOVLW D10
;20 msec delay
CALL
DELAY
MOVLW 0x0C
;Display on, Cursor off
CALL
CMD
MOVLW D10
;20 msec delay
CALL
DELAY
MOVLW 0x01
CALL
CMD
;Clear Display
MOVLW D10
;20 msec delay
CALL
DELAY
MOVLW 0x06
;Shift Cursor to the right
MOVLW D10
;20 msec delay
CALL
DELAY
MOVLW 0x80
;Move cursor to the start of the first line
CALL
CMD
MOVLW D10
;20 msec delay
CALL
DELAY
MOVLW A'P'
;Send ASCII P
CALL
LCDDATA
MOVLW A'I'
;Send ASCII I
CALL
LCDDATA
MOVLW A'C'
;Send ASCII C
CALL
LCDDATA
MOVLW A'1'
;Send ASCII 1
CALL
LCDDATA
MOVLW A'8'
;Send ASCII 8

Instructors Manual

CALL
MOVLW
CALL
FINISH
BRA
CMD
MOVWF
MOVLW
MOVWF
MOVLW
CALL
CLRF
RETURN
LCDDATA MOVWF
MOVLW
MOVWF
MOVLW
CALL
MOVLW
MOVWF
RETURN
DELAY
MOVWF
LOOP1
MOVLW
LOOP2

MOVWF
DECFSZ
GOTO
DECFSZ
GOTO
RETURN
END

Microcontroller Theory & Applications with the PIC18F

LCDDATA
A'F'
LCDDATA
FINISH
PORTD
0x04
PORTB
D10
DELAY
PORTB
PORTD
0x05
PORTB
D10
DELAY
0x01
PORTB
0x20
D255

57

;Send ASCII F
;Command is sent to PORTD
;rs=0 rw=0 en=1
;20 msec delay
;rs=0 rw=0 en=0
;Data sent to PORTD
;rs=1 rw=0 en=1
;20 msec delay
;rs=1 rw=0 en=0
;LOOP2 provides 2 msec delay with a
;count of 255

0x21
0X21
LOOP2
0x20
LOOP1

In the above, the following loop for the 2 msec delay is used:
LOOP1
MOVLW D255
;LOOP2 provides 2 msec delay with a count
;of 255
MOVWF
0x21
LOOP2
DECFSZ 0X21
GOTO
LOOP2

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

58

8.26
The main functions to be performed for interfacing a keyboard are:
y
y
y

Sense a key actuation.


Debounce the key.
Decode the key.

8.27
The two-key lockout ensures that only one key is pressed. An additional key
pressed and released does not generate any codes. The system is simple to
implement and most often used. However, it might slow down the typing because
each key must be released fully before the next one is pressed down. On the other
hand, the N-key rollover will ignore all keys pressed until only one remains down.

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

59

CHAPTER 9

9.1
Bit 7: Set to 0 so that TMR0 is off
Bit 6: Set to 1 in order to enable the 8-bit mode of TMR0
Bit 5: Set to 1 so that an external crystal oscillator can be used
Bit 4: Set to 1 so the timer will increment when the clock is going from high to
low, the negative edge
Bit 3: Set to 0 in order to enable the prescaler function
Bit 2-0: Set to 011 to enable a 1:16 prescaler
Final solution:
T0CON=0x73
9.2
Counter value = 100 = Initial counter value.
The timer counts up from the initial value of 100 to 255, and then rolls over
(increments) to 0. The number of counts for rollover is (255 - 100) = 155.
Note that an extra cycle is needed for the roll over from 0xFF (255 10 ) to
0x00, and the TMR0IF flag is then set to 1. Because of this extra cycle, the total
number of counts for rollover = 155 + 1 = 156 10 = 9CH. Hence, TMR0L should be
loaded with 9CH.
INCLUDE
ORG
MOVLW
MOVWF
MOVLW
MOVWF
BCF
BSF
LOOP BTFSS
BRA
FINISH BRA
END

<P18F4321.INC>
0x70
0x43
T0CON
0x9C
TMR0L
INTCON, TMR0IF
T0CON, TMR0ON
INTCON, TMR0IF
LOOP
FINISH

;TMR0 8-bit 1:16 prescaler


;Count of 100
;Clear TMR0 rollover interrupt flag
;Turn on TMR0
;Wait for rollover

9.3
Each half cycle of the square wave with 50% duty cycle is 2 msec.
Clock Period = 1/(4 MHz) = 0.25 sec, Instruction cycle clock period = 4 x 0.25 
sec= 1 sec.

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

60

No prescalar value is assigned.


Time delay = Instruction cycle x Prescale value x Count
Hence, Count = (2 ms) / (1 sec ) = 2000 10 (0x07D0). The timer counts up from an
initialized value to 0xFFFF, and then rolls over (increments) to 0000H. The
number of counts for rollover is (0xFFFF - 0x07D0) = 0xF82F.
Note that an extra cycle is needed for the roll over from 0xFFFF to 0x0000,
and the TMR0IF flag is then set to 1. Because of this extra cycle, the total number
of counts for roll over = 0xF82F + 1 = 0xF830.
The PIC18F assembly language program is provided below:
INCLUDE
ORG
BCF
MOVLW
MOVWF
BACK MOVLW
MOVWF
MOVLW
MOVWF
BCF
COMF
BSF
LOOP BTFSS
BRA
BCF
BRA
END

<P18F4321.INC>
0x70
TRISC, TRISC0
0x08
T0CON
0xF8
TMR0H
0x30
TMR0L
INTCON, TMR0IF
PORTC, RC0
T0CON, TMR0ON
INTCON, TMR0IF
LOOP
T0CON, TMR0ON
BACK

;Bit 0 of PortC is output


;TMR0 16-bit no prescaler
;TMR0H value
;TMR0L value
;Clear TMR0 interrupt flag
;1's compliment of bit 0 PORTC
;Turn on TMR0
;Wait for interrupt
;Turn off TMR0
;Go again

9.4
From Problem 9.3, the TIMR1H:TMR1L should be loaded with 0xF830. The
PIC18F assembly language program is provided below:
INCLUDE <P18F4321.INC>
ORG
0x70
BCF
TRISD, RD7
MOVLW
0xC8
MOVWF T1CON
LOOP

MOVLW
MOVWF
MOVLW

0xF8
TMR1H
0x30

;Bit 7 of PORTD is output


;Setup Timer1 as 16-bit, no
;prescaler
;Value placed in TMR1H

Instructors Manual

WAIT

Microcontroller Theory & Applications with the PIC18F

MOVWF
BCF

TMR1L
PIR1, TMR1IF

COMF

PORTD, RD7

BSF
BTFSS

T1CON, TMR1ON
PIR1, TMR1IF

BRA
BCF
BRA
END

WAIT
T1CON, TMR1ON
LOOP

61

;Value place in TMR1L


;Clear Timer1rollover interrupt
;flag
;1's complement of bit 7 of
;PORTD
;Turn on Timer1
;Wait until Timer1 interrupt
;occurs
;Turn Timer1 off

9.5

LOOP
FINISH

INCLUDE <P18F4321.INC>
ORG
0x70
BCF
TRISC, TRISC0 ; Configure bit 0 of PORT C as
;output
BCF
PORTC, RC0
; Turn LED OFF
CLRF
T2CON
;8-bit, no prescaler and no postscaler
CLRF
TMR2
; Clear TMR2 to 0
MOVLW D200
MOVWF PR2
;count 200 times
BCF
PIR1, TMR2IF
;Clear TMR2 interrupt flag
BSF
T2CON, TMR2ON;Turn on TMR2
BTFSS
PIR1, TMR2IF
;Wait for TMR2 to count to 200
BRA
LOOP
BSF
PORTC, RC0
;Turn LED on
BRA
FINISH
END

9.6
Each half cycle of the square wave with 50% duty cycle is 2 msec.
Clock Period = 1/(4 MHz) = 0.25sec, Instruction cycle clock period = 4 x 0.25
sec= 1sec.
Time delay = Instruction cycle x Prescale value x Count
Hence, Count = (2 ms) / (1 sec x 8) = 250 10 (0x00FA). The timer counts up from
an initialized value to 0xFFFF, and then rolls over (increments) to 0000H. The
number of counts for rollover is (0xFFFF - 0x00FA) = 0xFF05.
Note that an extra cycle is needed for the roll over from 0xFFFF to 0x0000,
and the TMR0IF flag is then set to 1. Because of this extra cycle, the total number
of counts for roll over = 0xFF05 + 1 = 0xFF06.

Instructors Manual

BACK

LOOP

Microcontroller Theory & Applications with the PIC18F

62

INCLUDE <P18F4321.inc>
ORG
0x70
BCF
TRISC, TRISC3 ;PORTC pin 3 is output
MOVLW
0xBC
MOVWF T3CON
;TMR3 16-bit with 1:8
;prescaler
BCF
PIR2, TMR3IF
;Clear TMR3IF
MOVLW 0xFF
;Initialize TMR3H:TMR3L
MOVWF TMR3H
MOVLW 0x06
MOVWF TMR3L
BTG
PORTC, RC3
;Toggle bit 3 of PORTC
BSF
T3CON, TMR3ON;Start TMR3
BTFSS
PIR2, TMR3IF ;Wait for TMR3IF to be one
BRA
LOOP
BCF
T3CON, TMR3ON;Stop TMR3
BRA
BACK
END

9.7
INCLUDE <P18F4321.inc>
D0
EQU
0x30
;Set variables equal to a register
D1
EQU
0x31
ADCONRESULT EQU
0x34
ORG
0x000
;Reset
GOTO
MAIN_PROG
; Main Program
ORG
0x100
MAIN_PROG MOVLW0x10
;Initialize STKPTR since interrupt
;and subroutines are used
MOVWF STKPTR ;Value arbitrarily chosen
CLRF
TRISC
;Set PortC and PortD as output
CLRF
TRISD
MOVLW 0x01
;Select AN0 for input and enable
;ADC
MOVWF ADCON0
MOVLW
0x0D
MOVWF ADCON1 ; Set VDD and VSS as reference
; input voltages and AN0 as analog
MOVLW
0x29
MOVWF
ADCON2 ;Left justified 12TAD and Fosc/8
BSF
PIE1,ADIE ;Enable the ADC interrupt flag

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

63

BCF
PIR1, ADIF ;Clear the ADC interrupt flag
BSF
INTCON, PEIE
;Enable peripheral interrupts
BSF
INTCON, GIE
;Enable global interrupts
BSF
ADCON0,GO
;Start A/D conversion
WAIT
BRA
WAIT
;Wait for interrupt
GOTO
MAIN_PROG
;INTERRUPT SERVICE ROUTINE
ORG
0x0008
;Interrupt Address Vector
BCF
PIR1, ADIF
;Clear ADIF
MOVFF
ADRESH,ADCONRESULT ;Move 8-bits of result into
; ADCONRESULT register
CALL
DIVIDE
; Call the divide subroutine
CALL
DISPLAY
;Call display subroutine
RETFIE
DIVIDE
CLRF
D0
;Clears D0
CLRF
D1
;Clears D1
MOVLW
D51
;Load 51 into WREG
EVEN
CPFSEQ ADCONRESULT
BRA
QUOTIENT
INCF
D1, F
SUBWF
ADCONRESULT, F
QUOTIENTCPFSGT ADCONRESULT ;Checks if ADCONRESULT
;still greater than 51
BRA
DECIMAL
INCF
D1, F
; increment D1 for each time
; ADCONRESULT is greater
; than 51
SUBWF
ADCONRESULT, F; Subtract 51 from
;ADCONRESULT
BRA
EVEN
DECIMAL MOVLW 0x05
REMAINDER CPFSGT ADCONRESULT ; Checks if ADCONRESULT
; greater than 5
BRA
DIVDONE
INCF
D0, F
; Increment D0 each
SUBWF
ADCONRESULT, F ; Subtract 5
;from ADCONRESULT
BRA
REMAINDER
DIVDONE RETURN
DISPLAY MOVFF
D1, PORTC
; Output D1 on integer 7-seg
MOVFF
D0, PORTD
; Output D0 on fractional 7-seg
RETURN
END

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

64

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

65

9.8
The hardware block diagram is provided below:

Analog Signal
5v peak-to-peak

Absolute
Value
Circuit

AN0

a-g
7

a-g
7

Common Anode
7-Segment Displays
a-g

7447

B
C
D

PORT A

2
3

7447 A

B
C
D

B
7447 C
D

1
2

6
7

PORT C

PORT D
PIC18F4321

Square
root algorithm
The square root of xi 2 /N will be calculated up to one decimal point. Assume xi 2
to be an 8-bit number. Hence, the maximum value is 255. Since the square root of
256 is 16, assume the initial value of the square root is 16. The square root
algorithm is as follows:
Suppose, xi 2 /N is 225. Guess 16 as the square root. The difference is (16 2 225) = 31. Since the difference is positive, decrement the guess value of 16 by 1 to
obtain 15. Calculate the difference, (15 2 - 225) = 0. Since the difference is 0, the
square root of 225 will be 15. Note that there would be no fractional part.
Suppose xi 2 /N is 255. Guess 16 as the square root. The difference is (16 2 - 255) =
-1. Since the difference is negative, decrement the guess value of 16 by 1 to obtain
15. The integer part of the square root will be 15. Next, in order to calculate the
fractional part in this case, calculate the difference, (255- 15 2 ) = 30 and then
increment the integer part by 1 to obtain 16, and then calculate the difference, (16 2 15 2 ) = 31. Hence, Fractional part = Quotient of (30 x 10/31) = 9. Therefore, the
approximate value of the square root of 255 will be 15.9.
Next, suppose, xi 2 /N is 180. To find the square root of 180, first guess that
the square root of 180 as 16. Calculate the difference, (16 2 - 180) = 76. Since 76 is
positive, decrement 1 from 16 to obtain 15, and guess the next square root as 15.
The difference, (15 2 - 180) = 45. Since 45 is positive, decrement 1 from 15 to

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

66

obtain 14, and guess the next square root as 14. Calculate the difference (14 2 - 180)
= 16. Since 16 is positive, decrement 1 from 1 to obtain 13, and guess the next
square root as 13. Calculate the difference (13 2 - 180) = -11.Since the result is
negative, stop.
Integer part is 13. Next, calculate the fractional part for this case. For fractional
part, negate the differences -11 to obtain +11. Next, increment the integer part by 1
to obtain 14, and then calculate the difference, (14 2 -180) = 16. Hence, the
fractional part = Quotient of (11 x 10/16) = 6. Therefore, the approximate value of
the square root of 180 will be 13.6.
Since the integer part will be displayed in BCD, the integer part should be
converted from binary to BCD. If the integer part is greater than 15, ten will be
subtracted from 15, and a counter will be incremented by one. The counter value
will be the upper most decimal digit of the two-digit integer displays. The
subraction result will be the lower digit of the integer display.

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

(a) FLOWCHART FOR xi 2 /N:

Flowchart for calculating SQRT [

(X i 2) / N ]

n=1

Start
Configure PortC and PortD
Sum <--- 0
Counter <--- 128
Initialize ADCON0, ADCON1 and ADCON2
START A/D CONVERSION

Is
conversion
complete
?

No

Yes
ADRESL <--Xi

Perform X 2 in PRODL
i

Sum <-- Sum + PRODL


Counter <-- Counter - 1
No

Counter
=0
Yes
Perform Sum/128 by
shifting sum 7 times to right

Find sq root of sum and display


Stop

67

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

68

FLOWCHART FOR COMPUTING THE INTEGER PART OF THE


SQUARE ROOT:

Start
[COUNTER1]

[VALUE 0]

16

Square [VALUE 0] in PRODL

[VALUE 1] <-- [PRODL] - [Sum]

Yes

Is
[VALUE1]
=

[VALUE 0]
>9

0
?

No
Output [VAUE 0]
to Lower interger
display. Blank
upper integer
display

Is
[Value1]
negative
?

No

Decrement
[VALUE 0]
by one

Yes
Yes

[VALUE 0]
>9

[VALUE 3] <-- [VALUE 0] - 10


[COUNTER 1] <-- [COUNTER 1] +1
Output [Counter 1] to
upper integer display
and [VALUE 3] to Lower
integer display.

No

NO

Output {VALUE0]
to lower integer
display. Blank
upper integer
display

Output '0'
to fractional
display

Stop

Yes

[VALUE 3] <-- [VALUE 0] - 10


1

[COUNTER 1] <-- [COUNTER 1] +1

Output to
displays

Stop

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

69

FLOWCHART FOR COMPUTING THE FRACTIONAL PART OF THE


SQUARE ROOT:

1
Negate [VALUE 1]
and Store in
VALUE 2
[VALUE 0]

[VALUE0] + 1

Square [VALUE 0] in PRODL


[VALUE 4]

[PRODL]- [Sum]

Multiply [VALUE 2] by 1 0
and save [PRODL] in VALUE6
Unsigned divide
[VALUE5] by [VALUE 4]
[COUNTER2] <-- Quotient (Rractional Part)
Output [COUNTER2] to Port D
Stop

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

70

(b) The PIC18F assembly language program is provided below:


INCLUDE
VALUE0 EQU
VALUE1 EQU
VALUE2 EQU
VALUE3 EQU
VALUE4 EQU
VALUE5 EQU
ADCONRESULT EQU
SUM
EQU
COUNTER EQU
COUNTER1 EQU
COUNTER2 EQU
ORG
CLRF
CLRF
MOVLW
MOVWF
MOVLW
MOVWF
MOVLW
MOVWF

<P18F4321.inc>
0x30
0x31
0x32
0x33
0x34
0x35
0x36
0x37
0x38
0x39
0x3A
0x200
TRISC
;Set PortC and PortD as output
TRISD
D128
COUNTER
0x01
;Select AN0 for input and enable ADC
ADCON0
0x01
ADCON1 ; Set VDD and VSS as reference voltages
;and AN0 as analog input
MOVLW
0x29
MOVWF
ADCON2 ;Right justified 12TAD and Fosc/8
CLRF
SUM
;Clear SUM to 0
START
BSF
ADCON0,GO ;Start AD conversion
INCONV BTFSC
ADCON0, DONE ;Wait until A/D conversion is done
BRA
INCONV
MOVF
ADRESH, W ;Move highest 8-bits of Xi into WREG
MULWF ADRESH ;Compute Xi**2 in PRODL
MOVF
PRODL, W ;Move Xi**2 into WREG
ADDWF SUM, F
;Add (Xi**2) to SUM
DECF
COUNTER, F;Decrement COUNTER
BNZ
START
;Go back for the next sample
;Sum of Xi**2 in SUM. Next, compute SUM/128 by shifting SUM, seven times
;to right
BCF
STATUS, C ;Clear Carry to 0
DIVIDE
MOVLW 7
; Move 7 for dividing (Xi**2) by 128 via
;shifting
MOVWF COUNTER
RRCF
SUM, F

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

71

DECF
COUNTER, F
BNZ
DIVIDE
;SUM contains 8-bit value of ( Sum of Xi**2)/128.
CLRF
COUNTER1
;Clear COUNTER1 to 0
MOVLW
D16
MOVWF
VALUE0
START1 MOVF
VALUE0, W
;Move [VALUE0] to WREG
MULWF
VALUE0
;Square [VALUE0] in PRODL
MOVFF
PRODL, VALUE1
MOVF
SUM, W
;Move [SUM] to WREG
SUBWF
VALUE1, F
BNZ
NEGATIVE
MOVLW
D9
CPFSGT
VALUE0
;Check whether integer value
; greater than 9
BRA
DISPLAY1
;If it is, the integer is
;between 10 and 15
MOVLW
0xF0
;Data for blanking upper
;integer display and retaining lower integer
IORWF
VALUE0
MOVFF
VALUE0, PORTC ;Display integer on lower 7-seg
;display and blank upper seven seg
MOVLW
0
;Display 0 on fractional display
MOVWF
PORTD
HERE
BRA
HERE
DISPLAY1 MOVFF
VALUE0, VALUE3
MOVLW
D10
SUBWF
VALUE3, F
INCF
COUNTER1, F
MOVF
COUNTER1, W
SWAPF
VALUE3, F ;Move lower integer to higher nibble
;of Port C
IORWF
VALUE3, F
MOVFF
VALUE3, PORTC ;Output both integers to Port C
FINISH1 BRA
FINISH1
NEGATIVEBN
DISPLAY2
DECF
VALUE0, F
BRA
START1
DISPLAY2 MOVLW
D9
CPFSGT
VALUE0
;Check whether integer value
;greater than 9
BRA
DISPLAY3 ;If it is, integer is between 10 and 15

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

72

MOVLW

0xF0

IORWF
MOVFF

VALUE0
VALUE0, PORTC ;Display integer on lower 7-seg
;display and blank upper seven seg
0
;Display 0 on fractional display
PORTD
FRACTION
VALUE0, VALUE3
D10
VALUE3, F
COUNTER1, F
COUNTER1, W
VALUE3, F
;Move lower integer to higher
;nibble of Port C
VALUE3, F
VALUE3, PORTC ;Output both integers to Port C

MOVLW
MOVWF
BRA
DISPLAY3 MOVFF
MOVLW
SUBWF
INCF
MOVF
SWAPF

;Data for blanking upper integer


;display and retaining lower integer

IORWF
MOVFF
; Compute fractional part
FRACTION MOVFF
VALUE1, VALUE2
NEGF
VALUE2
INCF
VALUE0, F
MOVF
VALUE0, W
MULWF
VALUE0
MOVFF
PRODL, VALUE4
MOVF
SUM, W
SUBWF
VALUE4, F
MOVF
VALUE2, W
MULLW
D10
MOVFF
PRODL, VALUE5
; Unsigned divide [VALUE5] by [VALUE4], Quotient in COUNTER2
MOVF
VALUE4, W
; Divisor in WREG
CLRF
COUNTER2
; Clear COUNTER2 to 0
BACK
CPFSEQ
VALUE5
; If dividend equals
;divisor, skip next instr.
BRA
RESULT
; If not equal, branch to
;RESULT
INCF
COUNTER2, F ; Increment COUNTER2
SUBWF
VALUE5, F
; Subtract divisor from
;dividend, result in VALUE5
BRA
DISPLAY4
; Go to DISPLAY4
RESULT CPFSGT
VALUE5
; If dividend greater than divisor,
;skip next inst.

Instructors Manual

BRA
INCF
SUBWF
BRA
DISPLAY4 MOVFF
FOREVER GOTO
END

Microcontroller Theory & Applications with the PIC18F

DISPLAY4

73

; Quotient in COUNTER2,
;Remainder in VALUE5, halt
COUNTER2, F ; Increment [COUNTER2] by 1
VALUE5, F
; Subtract divisor from
;dividend, result in COUNTER2
BACK
; Repeat
COUNTER2, PORTD; Display fractional part on Port C
FOREVER
; Halt

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

74

9.9
(a)
Discharge voltage, Vc (t) = k e t/RC . For one time constant, t = RC. Hence, Vc (t) =
(k/e). Hence, Vc(t) = 0.368 k. If k = 5.5V is arbitrarily used in this example, then
Vc(t) = 2.02V for one time constant.

Figure above shows the hardware schematic of the capacitance meter. The
capacitor is charged by outputting a 1 (5 V) via bit 0 of Port C. Three 741 op
amps are used. With a gain of 3, a 15V output is obtained from the 741 connected
to bit 0 (RC0) of Port C. Since discharge time is used rather than charging time, as
soon as the capacitance is charged to 5.5 volts (arbitrarily chosen) as detected by
another 741 connected to bit 1 (RC1) of Port C, the PIC18F 4321 is programmed
to output 0 from RC0 so that the capacitor starts discharging. A counter is
incremented using a one-second software delay loop. When the voltage drops to
2.02V after one time constant detected by another 741 via bit 2 (RC2) of Port C,
the counter is stopped. The content of the counter will provide the value of the
capacitor in microfarad. This is because one Megaohm resistor is used to charge
the capacitor. Capacitors of different ranges of values (picofarad, nanofarad) can
be obtained by selecting different resistor values. The counter value is output to
two seven-segment displays via two 7447s. The capacitor value in the range of 1
F to 15 F is used; the fractional part is discarded.

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

75

(b)
#INCLUDE <P18F4321.INC>
ORG
0
BRA
MAIN
MAIN
ORG
0x200
DELAY
EQU
0x14
DELAY1 EQU
0x15
COUNTER EQU
0x30
BCF
TRISC,TRISC0 ;Configure bit 0 of Port C as output
BSF
TRISC, TRIS1
;Configure bit 1 of Port C as input
BSF
TRISC,TRIS2
;Configure bit 2 of Port C as input
CLRF
TRISD
;Configure Port D as output
CLRF
PORTD
CLRF
COUNTER
;Clear COUNTER to 0
BSF
PORTC, RC0
;Start charging the capacitor
WAIT
BTFSS
PORTC, RC1
;Check RC1 for HIGH to discharge
BRA
WAIT
;else, wait
BCF
PORTC, RC0
WAIT1
MOVLW D249
;Time delay for 500 cycles
MOVWF DELAY
LOOP1
MOVLW D249
;Time delay for 500x500 cycles, 1-sec delay
MOVWF DELAY1
LOOP
DECF
DELAY1, F
BNZ
LOOP
DECF
DELAY
BNZ
LOOP1
INCF
COUNTER, F
;Start incrementing COUNTER
BTFSC
PORTC, RC2
;Check RC2 to be LOW for done
BRA
WAIT1
;Capacitor will be [COUNTER]
MOVLW 0
ADDWF COUNTER, W
DAW
;Convert into correct packed BCD
MOVWF PORTD
;Output WREG to Port D
SLEEP
END
9.10
Assume 8 MHz internal clock. Each instruction cycle is 0.5 s.
Time delay = Instruction cycle x Prescale value x Counter value
For 1 sec delay with prescale value of 1:128,
Counter value = (1 sec)/ ( 0.5 s x 128) = 15625 = 3D09H. The counter counts up
from an initial value of FFFFH, and then rolls over to 0000H. The number of
counts for rollover = FFFFH - 3D09H = C2F6H. An extra cycle is needed for
rollover. Hence, total number of counts = C2F7H.

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

76

The PIC18F assembly language program is provided below:


INCLUDE <P18F4321.INC>
SEC
EQU
0x20
MIN
EQU
0x21
HOUR
EQU
0x22
ORG
0X70
MOVLW 5
MOVWF STKPTR
MOVLW
0x06
MOVWF T0CON
;1:128 prescale, internal oscillator
; For 1 sec time delay, initialize TMR0H with 0xC2, and TMRL with 0xF7
MOVLW
0xC2
MOVWF
TMR0H
;Value placed in TMR0H
MOVLW
0xF7
MOVWF
TMR0L
;Value placed in TMR0L
BCF
INTCON, TMR0IF;Clear Timer0 interrupt flag
BSF
INTCON, TMR0IE;Enable Timer1 interrupt
CLRF
SEC
;Clear SEC register
CLRF
MIN
;Clear MIN register
CLRF
HOUR
;Clear hour register
BSF
T0CON, TMR0ON;Turn on Timer0
LOOP
BTFSS
INTCON, TMR0IF
GOTO
LOOP
INCF
SEC
MOVLW D'60' ;Move 60 into WREG
CPFSLT
SEC ;Compare value in SEC to 60 and skip if less than
CALL
INC_MIN ;else, call the INC_MIN subroutine
BSF
T0CON,TMR0ON
BRA
LOOP
ORG
0x100
INC_MIN CLRF
SEC
;Clear SEC register
INCF
MIN
;Increment the MIN register
MOVLW D'60'
;Move 60 into WREG
CPFSLT
MIN ;Compare value in MIN to 60 and skip if less than
CALL
INC_HOUR;else, call the INC_HOUR subroutine
RETURN
ORG
0x200
INC_HOUR CLRF
MIN
;Clear MIN register
INCF
HOUR
;Increment the HOUR register
MOVLW
D'25'
;Move 25 into WREG
CPFSLT
HOUR;Compare value in HOUR to 25 skip if less than
CLRF
HOUR
;Clear HOUR register

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

77

SLEEP
END
9.11
INCLUDE
ADCONRESULT EQU
VALUE
EQU
ORG
CLRF
CLRF
MOVLW
MOVWF
MOVLW
MOVWF
MOVLW
MOVWF

INCONV

MOVLW
MOVWF
BSF
BTFSC
BRA
MOVF
MULWF
MOVF
CLRF
RRCF
END

<P18F4321.inc>
0x36
0x37
0x200
TRISC
;Set PortC and PortD as output
TRISD
D128
COUNTER
0x01
;Select AN0 for input and enable ADC
ADCON0
0x01
ADCON1 ; Set VDD and VSS as reference voltages
;and AN0 as analog input
0x29
ADCON2 ;Left justified 12TAD and Fosc/8
ADCON0,GO
;Start AD conversion
ADCON0, DONE ;Wait until A/D conversion is done
INCONV
ADRESH, W
;Move 8-bits of Xi into WREG
ADRESH ;Compute Xi**2 in PRODL
PRODL, VALUE ;Move Xi**2 into VALUE
STATUS, C ;Clear the carry flag
VALUE
;Divide (VALUE **2) part by 2
;VALUE will contain power in mW

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

78

9.12
The block diagram is provided below:

PORTB

a-g

7447 B

C
D

Common Anode
7-Segment Displays

a-g
7

B
7447 C
D

RB1
INT0

Decrement
Button
Increment
Button

3
4

PORT C

5
6
7

PIC18F4321

The PIC18F assembly language program is provided below:


INCLUDE <P18F4321.INC>
;RESET vector
ORG
0x000
GOTO
MAIN
;Interrupt address vector
ORG
0x0008 ;System will go to CHECK_INT at interrupt
GOTO
CHECK_INT
;Interrupt service routine
ORG
0x0040
CHECK_INT BTFSS
PORTB, RB1
;If RB1 = 1, Decrement
BRA
INC_ISR
BCF
INTCON, INT0IF ;Clear INT0 interrupt flag
MOVLW
0x00
CPFSEQ PORTC
;If PORTC equals 0 do not decrement
DECF
PORTC
;If greater than 0 decrement
BRA
BACK
INC_ISR BCF
INTCON, INT0IF ;Clear INT0 interrupt flag
MOVLW
0x09
CPFSEQ
PORTD
;If PORTC equals 9 do not increment
BRA
BACK
INCF
PORTD
;If less than 9 increment
BACK
RETFIE

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

;Main Program
MAIN
CLRF
MOVLW
MOVWF
BCF
BCF
BSF
MOVLW
MOVWF
CLRF
WAIT
BRA
SLEEP
END

79

TRISC
;PORTC is output
0x0F
ADCON1 ;RB0as INT0 and RB1 as digital input
INTCON, INT0IF ;Clear INT0 interrupt flag
INTCON3, INT1IF
;Clear INT1 interrupt flag
INTCON, GIE
;Enable global interrupts
D20
;Initialize STKPTR since interrupt is used
STKPTR
PORTC
;Clear PORTC
WAIT
;Wait for a button to be pushed

9.13

Latch

TIL311

Hex Display
with
on-chip
decoder

Port C

4
4

Display with on-chip decoder

PB3
PB2
PB1
PB0

connected to D
connected to C
connected to B
connected to A

PB 3
PB 0

Port D
PIC18F4321

0
1
2
3

.
.

8
4
0

z
z

zF
z

z
z
z

10K

10K

PB6
PB5
PB4

10K

10K

+ 5V

z
z
z

10K

10K

10K

10K

z
z

0
1
2
3
4
5
6
7

Assume that decimal numbers 0 through 9 will be pushed on the hex keyboard.
The PIC18F assembly language program is provided below:

OPEN

INCLUDE <P18F4321.INC>
ORG
0x100
;Starting address of the
;program
EQU
0xF0
;Row/column codes if all
;keys
;are open

Instructors Manual

COUNTER EQU
COUNTER1 EQU
MOVLW
MOVWF
MOVLW
MOVWF
MOVLW
MOVWF
LFSR

Microcontroller Theory & Applications with the PIC18F

80

0x80
0x81
0x00
; Move upper 5 bits (00H) of address
TBLPTRU ; to TBLPTRU
0x02
; Move bits 15-8 (02H) of address
TBLPTRH ; to TBLPTRH
0x00
; Move bits 7-0 (00H) of address
TBLPTRL ; to TBLPTRL
1, 0x50
; Initialize FSR1 to 0x50 to be used as
; destination pointer in data memory
MOVLW D10
; Initialize COUNTER with 10
MOVWF COUNTER ; Move [WREG] into COUNTER
LOOP
TBLRD*+
; Read data from program memory into
; TABLAT, increment TBLPTR by 1
MOVF
TABLAT, W
; Move [TABLAT] into WREG
MOVWF POSTINC1; Move [WREG] into data memory pointed to
; by FSR1, and then increment FSR1 by 1
DECF
COUNTER, F
; Decrement COUNTER BY 1
BNZ
LOOP
; Branch if Z = 0, else Stop
CLRF
TRISB
; Configure port B as an output port
CLRF
TRISC
; Configure port C as an output port
SETF
TRISD ; Configure port D as an input port
MOVLW 4
; STKPTR is initialized with arbitrary value
MOVWF STKPTR
; since subroutine DELAY is used later
MOVLW 0
; Send 0 to enable display and then
MOVWF PORTB
; Initialize displays with 0s
NEXT2 MOVLW 3
MOVWF COUNTER1; Initialize COUNTER1 with 3 since there
; are three displays
SCAN_KEY MOVWF PORTC
; Output 0s to rows of the keyboard
MOVLW OPEN
; Move 0xF0 to 0x30
MOVWF 0x30
KEY_OPEN MOVF PORTD,W ; Read PORTD into WREG
SUBWF
0x30, W
; Are all keys opened?
BNZ
KEY_OPEN
; Repeat if closed
CALL
DELAY
; Debounce for 20 ms
KEY_CLOSE MOVF PORTD, W
; Read PORTD into WREG
SUBWF
0x30, W
; Are all keys closed?
BZ
KEY_CLOSE ; Repeat if opened
CALL
DELAY
; Debounce again for 20 ms

Instructors Manual

SETF
BCF
NEXT_ROW RLCF
MOVFF
MOVFF
MOVF
MOVWF
MOVLW
ANDWF
CPFSEQ
BRA
MOVFF
BSF
GOTO
DECODE MOVLW
MOVWF
MOVWF
DECF
LFSR
MOVF
SEARCH CPFSEQ
BRA
MOVLW
CPFSEQ
BRA
MOVLW
IORWF
BACK
MOVFF

TWO

ONE

DECF
BZ
BRA
MOVLW
CPFSEQ
BRA
MOVLW
IORWF
BRA
MOVLW
CPFSEQ
BRA

Microcontroller Theory & Applications with the PIC18F

81

0x35
; Set 0x35 contents to all 1s
STATUS, C ; Clear Carry Flag
0x35, F
; Set up row mask
0x35, 0x36
; Save row mask in 0x36
0x35, PORTC ; Output 0 to a row
PORTD, W
; Read PORTD into WREG
0x31
; Save row/column codes in 0x31
0xF0
0x31, W
; Mask row code
0x30
; Is column code affected?
DECODE
; If yes, decode column code
0x36, 0x35
; Restore row mask in 0x35
STATUS, C ; Clear Carry flag to 0
NEXT_ROW ; Check next row
D10 ; Initialize 0x32 with 10 decimal since there
0x32
; are 10 decimal numbers
0x33
; Move 10 to 0x33
0x33, F
; Decrement 0x33 by 1 to contain hex
; digits 9 to 0
0, 0x50
; Initialize FSR0 with 0x50
0x31, W
; Move row code to WREG
POSTINC0
; Compare and skip if equal
SEARCH1
; Loop if not found
3
; Move 3 to WREG
COUNTER1
TWO
0x60
; Data for enabling right-most display,
0x33, F
; disabling others
0x33, PORTB ; Digital the hex digit to the right-most
; display
COUNTER1, F
NEXT2
NEXT1
; Branch to NEXT1
2
COUNTER1
ONE
0x50
; Data for enabling middle display,
0x33, F ; disabling others
BACK
1
COUNTER1
NEXT2

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

82

MOVLW
0x30
; Data for enabling left-most display,
IORWF
0x33, F
; disabling others
BRA
BACK
SEARCH1 MOVF
0x31, W
DECF
0x33, F
; Decrement 0x32
DECF
0x32, F
; Decrement 0x33
BNZ
SEARCH
; Branch to SEARCH if not 0
NEXT1 GOTO
SCAN_KEY ; Return to scan another key
DELAY MOVLW
D10
; 20 msec delay routine
MOVWF
0x20
LOOP1
MOVLW
D255
; LOOP2 provides 2 msec delay
MOVWF
0x21
LOOP2 DECFSZ
0x21
GOTO
LOOP2
DECFSZ
0x20
GOTO
LOOP1
RETURN
ORG
0x200
;#48 Keyboard decode table
TABLE DB
0xDB
;
Code for 9
DB
0xEB
;
Code for 8
DB
0x7D
;
Code for 7
DB
0xBD
;
Code for 6
DB
0xDD
;
Code for 5
DB
0xED
;
Code for 4
DB
0x7E
;
Code for 3
DB
0xBE
;
Code for 2
DB
0xDE
;
Code for 1
DB
0xEE
;
Code for 0
END
9.14
For the master microcontroller:
INCLUDE <P18F4321.INC>
ORG
0x00
GOTO
MAIN
ORG
0x70
MAIN
BCF
TRISC, RC5
BCF
TRISC, RC3
SETF
TRISD
MOVLW 7

;Reset
;Configure RC5/SD0 as output
;Configure RC3/SCK as output
;Configure PORTD as input
; Initialize STKPTR to 7 since
;subroutine

Instructors Manual

MOVWF

Microcontroller Theory & Applications with the PIC18F

STKPTR

83

;called SERIAL_WRITE is used in the


;program

MOVLW
MOVWF
MOVLW
MOVWF

0x40
SSPSTAT ;Set data transmission on high to low clock
0x20
SSPCON1
;Enable serial functions and set to
;master device,and Fosc/4
GET_DATA MOVF
PORTD,W
;Move switch value to WREG
CALL
SERIAL_WRITE;Call SERIAL_WRITE function
BRA
GET_DATA
SERIAL_WRITE MOVWF
SSPBUF ;Move switch value to serial buffer
WAIT BTFSS
SSPSTAT, BF
;Wait until transmission is complete
BRA
WAIT
RETURN
END
For slave microcontroller:

MAIN

WAIT

INCLUDE
ORG
GOTO
ORG
BSF
BSF
CLRF
BCF
MOVLW
MOVWF
MOVLW
MOVWF
BTFSS
BRA
MOVFF
BTFSS

BRA
FINISH

FINISH
BSF
BRA
END

<P18F4321.INC>
0x00
;Reset
MAIN
0x100
TRISC, RC4
;Configure RC4/SDI as input
TRISC, RC3
;Configure RC3/SCK as input
TRISB
;Configure PORTB as output
PORTD, RB5
;Turn off LED
0x40
SSPSTAT ;Set data transmission on high to low clock
0x25
SSPCON1 ;Enable serial functions and set to the slave
SSPSTAT, BF
;Wait until transmission
;is complete (BF=1)
WAIT
;If BF=0, wait
SSPBUF, 0x20
;Output serial buffer data to
;register 0x20
0x20, 0
;Test switch data bit 0, if closed
;LED is already off,
;goto end
PORTB, RB5
;Turn on LED, if switch if open
FINISH

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

84

9.15
The PIC18F assembly language program is provided below:
INCLUDE <P18F4321.INC>
ORG
0x200
BSF
TRISC, TRISC2 ;CCP1 input
MOVLW
0x05
MOVWF CCP1CON ;Capture mode, event on rising edge
MOVLW
0xC8
MOVWF
T1CON
;Internal clock, no prescale
MOVLW 0X00
MOVWF CCPR1H ;Clear CCPR1H to 0
MOVWF CCPR1L ;Clear CCPR1L to 0
CLRF
PIR1, CCP1IF
;Clear CCP1IF
WAIT
BTFSS
PIR1, CCP1IF
;Wait for the first rising edge
GOTO
WAIT
BSF
T1CON, TMR1ON;Turn Timer1 ON
MOVFF
CCPR1L, 0x20
;Save CCPR1L in 0x20 at 1st
;rising edge
MOVFF
CCPR1H, 0x21 ;Save CCPR1H in 0x21 at 1st
;rising edge
CLRF
PIR1, CCP1IF
;Clear CCP1IF
WAIT1
BTFSS
PIR1, CCP1IF
;Wait for next rising edge
GOTO
WAIT1
BCF
T1CON, TMR1ON;Turn OFF Timer1
CLRF
CCP1CON ;Disable capture
MOVF
0x20, W
;Move 1st Low byte to WREG
SUBWF
CCPR1L, F ;Subtract WREG from 2nd low byte
;Result in 0x20
MOVF
0x21, W
;Move 1st HIGH byte to WREG
SUBWFB CCPR1H, F ;Subtract WREG with borrow
;from 2nd high byte, result in 0x21
HERE
BRA
HERE
;Halt
END
9.16
With 4-MHz Crystal, Timer clock period = 1sec. With 50% duty cycle, the
pulse width is 10 ms. Hence, Counter value = (10ms)/(1sec) = 10,000 = 0x2710.
Therefore, CCPR1H is loaded with 0x27, and CCPR1L is initialized with 0x10.
The PIC18F assembly language program is provided below:
INCLUDE

<P18F4321.INC>

Instructors Manual

AGAIN

MAIN

Microcontroller Theory & Applications with the PIC18F

ORG
BCF
MOVLW
MOVWF
CLRF
CLRF
MOVLW
MOVWF
MOVLW
MOVWF
MOVLW
MOVWF
CLRF
CLRF
BCF
BSF
BTFSS
BRA
BCF
BRA
END

85

0x200
TRISC, CCP1
;CCP1 output
0xDC
T1CON
;16-bit, 1:2 prescale
TMR1L
TMR1H
;Clear TMR1L and TMR1H
0x02
CCP1CON ;Compare mode, toggle CCP1 on match
0x10
CCPR1L
0x27
CCPR1H
;Values needed for 20ms square wave
TMR1L
;Clear TMR1L and TMR1H
TMR1H
PIR1, CCP1IF
;Clear CCP1 interrupt flag
T1CON, TMR1ON;Start TMR1
PIR1, CCP1IF
;Wait for compare
MAIN
T1CON, TMR1ON ;Stop TMR1,CCP1 toggles upon
;match
AGAIN

9.17
PR2 = [(Fosc)/(4 x Fpwm x TMR2 Prescale Value)] - 1
PR2 = [(10 MHz)/(4 x 16 KHz x 1)] - 1 assuming Prescale value of 1
PR2 = 155. With 75% duty cycle = 0.75 x 155 = 116.25. Hence, the CCPR1L
register will be loaded with 116, and bits DC1B1:DC0B0 (CCP1CON register)
with 01 (binary).
The PIC18F assembly language program is provided below:
INCLUDE
ORG
MOVLW
MOVWF
MOVLW
MOVWF
MOVLW
MOVWF

<P18F4321.INC>
0x100
D155
PR2
D116
CCPR1L
0x10
CCP1CON

;Initialize PR2 register


;Initialize CCPR1L
;CCP1 OFF,
;DC1B1:DC0B0=01

Instructors Manual

BACK
WAIT

Microcontroller Theory & Applications with the PIC18F

BCF
CLRF
MOVLW
MOVWF
CLRF
BCF
BSF
BTFSS
GOTO
BRA
END

86

TRISC, CCP1
;Configure CCP1 pin as output
T2CON
;1:1 prescale, Timer2 OFF
0x1C
;PWM mode
CCP1CON
TMR2
;Clear Timer2 to 0
PIR1, TMR2IF
;Clear TMR2IF to 0
T2CON, TMR2ON;Turn Timer2 ON
PIR1, TMR2IF
;Wait until TMR2IF is HIGH
WAIT
BACK

9.18
PR2 = [(Fosc)/(4 x Fpwm x TMR2 Prescale Value)] - 1
= [(4 MHz)/(4 x 800x 16)] - 1
= 77.125
Hence, PR2 will be 77 approximately.
After converting the potentiometer voltage into 8-bit binary, the ADRESH
will contain the converted data. Note that the 8-bit ADRESH register can
accommodate a maximum value of 255. The contents of ADRESH can be moved
to CCPR1L to represent the decimal portion of the duty cycle. In order for the duty
cycle to be in the range of 0 to 77, the contents of ADRESH must be divided by
which is 3 (255/77 = 3 approximately). This will ensure that the decimal portion of
the duty cycle is between 0 and 77. The higher the voltage accross the
potentiometer, the higher will be the value of ADRESH/3. This means that the
higher will be the integer portion of the duty cycle in the CCPR1L register. This
will generate a PWM waveform with a higher duty cycle, and thus the motor will
run faster.
INCLUDE <P18F4321.INC>
ORG
0x000
GOTO
MAIN
ORG
0x0008 ;System will go to CHECK_INT at interrupt
GOTO
CHECK_INT
ORG
0x0040
CHECK_INT BRA
ADIF_ISR
;Goto ISR
RETFIE
ORG
0x70
MAIN
MOVLW 0xEC
MOVLW 7
;Initialize STKPTR since interrupt
;is used
MOVWF STKPTR
MOVWF OSCCON
;Setting the internal clock to 4Mhz

Instructors Manual

MOVLW
MOVWF
MOVLW
MOVWF
CLRF
BCF
MOVLW
MOVWF
MOVLW
MOVWF
MOVLW
MOVWF
MOVLW
MOVWF
MOVLW
MOVWF
START
BSF
WAIT
BRA
ADIF_ISR MOVFF
MOVLW
CLRF
DIVIDE
CPFSGT
BRA
INCF
SUBWF
BRA
FINISHED MOVFF
BCF
BSF
AGAIN
BTFSS
BRA
BRA
END

Microcontroller Theory & Applications with the PIC18F

0x00
TRISC
0x02
T2CON
TMR2
PIR1, TMR2IF
0x31
ADCON0
0x00
ADCON1
0x28
ADCON2
0x0C
CCP1CON
D'77'
PR2
ADCON0,GO
WAIT
ADRESH, 0x20
0x03
0x21
0x20

87

;Make PORTC output


;Configure Timer 2 with prescale 16
;and no postscale
;Clears Timer 2 interrupt flag
;Use AN12, or B0 as ADC
;Enable pins for analog input
;12 TAD and Fosc/8 conversion clock
;Use as PWM generator
;Set period of PWM signal

;Start the ADC


;Wait for ADC to interrupt
;Move value in ADRESH to 0x20
;Move 3 into the WREG
;Clear value in 0x21
;Compare the value to 3 skip if
;greater than
FINISHED
;Division is done
0x21, F
;Increment 0x21
0x20
;Subtract 3 from 0x20
DIVIDE
;subtract again
0x21, CCPR1L
;Move final value into CCPR1L
PIR1, TMR2IF
;Clear Timer 2 interrupt flag
T2CON, TMR2ON;Turn on Timer 2
PIR1, TMR2IF
;Wait until cycle is over
AGAIN
START
;Start again

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

88

CHAPTER 10

10.1
(a) TRISC=0xFF;
(b) TRISD=0x00;
(c) Bits 0-4 of PORTB as digital inputs:
ADCON1 = 0x0F;
(d) TRISA=0x00;
10.2
#include <P18F4321.h>
void main (void)
{
TRISCbits.TRISC1=1;
//Configure PORTC bit 1 as input
TRISDbits.TRISD1=1;
//Configure PORTD bit 1 as input
TRISCbits.TRISC0= 0;
//Configure PORTC bit 0 as output
TRISDbits.TRISD0= 0;
//Configure PORTD bit 0 as output
PORTCbits.RC0= PORTCbits.RC1>>1;//Align and output data to PORTC bit 0
PORTDbits.RD0= PORTDbits.RD1>>1;//Align and output data to PORTD bit 0
while(1);
//Finished
}

10.3
#include <P18F4321.h>
void fail (void);
void main ()
{
TRISDbits.TRISD0=0;
TRISDbits.TRISD1=0;
TRISDbits.TRISD2=1;
TRISDbits.TRISD3=0;
TRISDbits.TRISD4=0;
PORTDbits.RD0=0;
PORTDbits.RD1=0;

//Bit0 of PORTD output


//Bit1 of PORTD output
//Bit2 of PORTD input
//Bit3 of PORTD output
//Bit4 of PORTD output
//Test case 00

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

89

if(PORTDbits.RD2==0) //If output is 0 fail


fail();
PORTDbits.RD0=1;
//Test case 01
PORTDbits.RD1=0;
if(PORTDbits.RD2==0) //If output is 0 fail
fail();
PORTDbits.RD0=0;
//Test case 10
PORTDbits.RD1=1;
if(PORTDbits.RD2==0) //If output is 0 fail
fail();
PORTDbits.RD0=1;
//Test case 11s
PORTDbits.RD1=1;
if(PORTDbits.RD2==1) //If output is 1 fail
fail();
while(1)
{
PORTDbits.RD3=1;
PORTDbits.RD4=0;
}

//NAND chip has passed test


//Turn off LED on bit 3
//Turn on LED on bit 4

}
void fail(void)
{
while(1)
{

//NAND chip has failed test


PORTDbits.RD3=0;
PORTDbits.RD4=1;

//Turn on LED on bit 3


//Turn off LED on bit 4

}
}
10.4
#include <P18F4321.h>
unsigned char sum, value1, value2; //Declare variables sum, value1 and value2
//Declare lookup_table for Seven-Segment values
unsigned char
lookup_table[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x67};
void main()
{

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

90

TRISC =0x00;
TRISD = 0xFF;
value1 = PORTD & 0x07;
value2 = PORTD & 0x38;
value2 = value2>>3;
sum=value1 + value2;

//Configure PortC as output


//Configure PortD as input
//Mask off lower 3 bits of PORTD
//Mask off bits 3-5 of PORTD
//Shift value2 three times to right
//Sum of the lower bits of the two values

PORTC=lookup_table[sum];

//Output the thecode for the required BCD


//digit to display

}
10.5
#include <P18F4321.h>
//Declare lookup_table for EBCDIC printer
unsigned char
lookup_table[10]={0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9};
void main()
{
unsigned char ASCII_value, temp;
TRISC=0xFF;
TRISD=0x00;
ASCII_value=PORTC;

//Declare variables
//PortC is input
//PortD is output
//Move ASCII value from PORTC to
//variable ASCII_value
temp=ASCII_value & 0x0F;
//Mask lower 4 bits
PORTD=lookup_table[temp]; //Output based on lower 4 bits of the ASCII input
}
10.6
#include <P18F4321.h>
void main (void)
{
TRISCbits.TRISC0 = 1; //Configure bit 0 of PORTC as input
TRISDBITS.TRISD1 = 0; //Configure bit 1 of PORTD 1s output
PORTDbits.RD1 = 0; //Turn LED OFF
while(1)
{
PORTD = 0; //Turn LED OFF
while(PORTCbits.RC0==1) //While Vx > Vy

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

{
PORTDbits.RD1=1; //Turn LED ON
}
}
}
10.7
#include <P18F4321.h>
void ISR (void);
#pragma interrupt check_int
void check_int(void)
{
if (INTCON3bits.INT1IF==1)
ISR();
}
#pragma code check_Int=0x08 //At interrupt code jumps here
void check_Int(void)
{
_asm //Using assembly language
GOTO check_int
_endasm
}
#pragma code
void main()
{
TRISDbits.TRISD0=0; //PORTD bit 0 is output
ADCON1=0x0F; //Configure PORTB to be digital input
INTCON3bits.INT1IE=1; //Enable external interrupt
INTCON3bits.INT1IF=0; //Clear the external interrupt flag
INTCONbits.GIE=1; //Enable global interrupts
PORTDbits.RD1=0; //Turn off LED;
while(1){
PORTDbits.RD1=0; //LED is off
}

91

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

92

}
void ISR(void){ //Interrupt service routine
INTCON3bits.INT1IF=0; //Clear external interrupt flag
PORTDbits.RD1=1; //Turn LED on
}
}
10.8 (a)
PIC18F4321
PORTA

12V

LED

B2
INT0
B1

Voltage
VM
measurement

PORTB

11V

(b) The C-program is provided below:


#include <P18F4321.h>
void ISR (void);
#pragma interrupt check_int
void check_int(void)
{
if (INTCONbits.INT0IF==1)
ISR();
}
#pragma code check_Int=0x08
void check_Int(void)
{
_asm //Using assembly language
GOTO check_int

//At interrupt code jumps here

330

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

93

_endasm
}
#pragma code
void main()
{
ADCON1=0x0F;
//Configure PORTB to be digital input
TRISA=0x00;
//PORTA is output
INTCONbits.INT0IE=1;
//Enable external interrupt
INTCON0bits.INT0IF=0;
//Clear the external interrupt flag
INTCONbits.GIE=1;
//Enable global interrupts
PORTAbits.RA3=0;
//LED is off
While(1);
//Wait for interrupt
}
void ISR(void){
//Interrupt service routine
PORTAbits.RA3=1;
//Turn LED on
while(1);
//wait forever
}
10.9
INTCON3bits.INT1IE=1;
//Enable external interrupt INT1
INTCON3bits.INT1IF=0;
//Clear INT1IF
INTCON3bits.INT2IE=1;
//Enable external interrupt INT2
INTCON3bits.INT2IF=0;
//Clear INT2 external interrupt flag
INTCON3bits.INT1IP=1;
//Set INT1 to high priority interrupt
INTCON3bits.INT2IP=0;
//Set INT2 to low priority interrupt
RCONbits.IPEN=1;
//Enable priority interrupts
INTCONbits.GIEH=1; //Enable global high priority interrupts
INTCONbits.GIEL=1; //Enable global low priority interrupts

10.10
#include <P18F4321.h>
void cmd(unsigned char);
void data(unsigned char);
void delay(unsigned int);
void main(void)
{
unsigned char in, out, i ;

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

unsigned char disp[6] = {P,I,C,1,8,F};


TRISB=0;
TRISC=0xFF;
TRISD=0;
PORTB=0x00;
delay(10);
cmd(0x0C);
delay(10);
cmd(0x01);
delay(10);
cmd(0x06);
delay(10);
cmd(0x80);
delay(10);

//message

//PORTB is output
//PORTC is input
//PORTD is output
//rs=0 rw=0 en=0
//20 msec delay
//Display On, Cursor Off
//20 msec delay
//Clear Display
//20 msec delay
//Shift curser to the right
//20 msec delay
//Start at line 1 poistion 0
//20 msec delay

while(1)
{
cmd(0x01); //Clear Display
delay(10);
switch_value=PORTC & 0x0F; //Mask lower 4 bits
if(switch_value == 0x0F)//If all 4 switches are HIGH
{
for (i = 0; i <6 ; i++)
data (disp [i] );
}
}
}
void cmd(unsigned char value)
{
PORTD=value; //Command is sent to PORTD
PORTB=0x04;
//rs=0 rw=0 en=1
delay(10);
PORTB=0x00;
//rs=0 rw=0 en=0
}
void data(unsigned char value)
{
PORTD=value;
//Data sent to PORTD
PORTB=0x05;
//rs=1 rw=0 en=1
delay(10);

94

Instructors Manual

PORTB=0x01;
}

Microcontroller Theory & Applications with the PIC18F

95

//rs=1 rw=0 en=0

void delay(unsigned int itime)


{
unsigned int i,j;
for(i=0; i<itime; i++)
for(j=0; j<255;j++);
}
10.11
Count = 255-100 = 155 = 0x9B
#include <P18F4321.h>
void main()
{
T0CON=0x43;
//TMR0 8-bit 1:16 precaler
TMR0L=0x9B; //Count of 100
INTCONbits.TMR0IF=0;
//Clear TMR) interrupt flag
INTCONbits.TMR0IE=0;
//Enable TMR0 interrupt
T0CONbits.TMR0ON=1;
//Turn on TMR0
while (INTCONbits.TMR0IF==0);

//Wait for interrupt

}
10.12
Each half cycle of the square wave with 50% duty cycle is 2 msec.
Clock Period = 1/(4 MHz) = 0.25 sec, Instruction cycle clock period = 4 x 0.25 
sec= 1 sec.
No prescalar value is assigned.
Time delay = Instruction cycle x Prescale value x Count
Hence, Count = (2 ms) / (1 sec ) = 2000 10 (0x07D0). The timer counts up from an
initialized value to 0xFFFF, and then rolls over (increments) to 0000H. The
number of counts for rollover is (0xFFFF - 0x07D0) = 0xF82F.
Note that an extra cycle is needed for the roll over from 0xFFFF to 0x0000,
and the TMR0IF flag is then set to 1. Because of this extra cycle, the total number
of counts for roll over = 0xF82F + 1 = 0xF830.
The PIC18F assembly language program is provided below:

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

96

#include <p18f4321.h>
void main(void)
{
TRISCbits.TRISC0=0;
//Configure bit 0 of PortC as output
T0CON=0x08;
//Timer0 is 16-bit no prescaler
TMR0H=0xF8;
//Value placed TMR0H
TMR0L=0x30;
//Value placed in TMR0L
INTCONbits.TMR0IF=0;//Clear TMR0 interrupt flag
T0CONbits.TMR0ON=1;
//Turn on TMR0
while(1)
{
while(INTCONbits.TMR0IF==0);
T0CONbits.TMR0ON=0;
//Turn off TMR0
PORTCbits.RC0=~PORTCbits.RC0; //Change output of square wave
TMR0H=0xF8;
//Value placed in TMR0H
TMR0L=0x30;
//Value placed in TMR0L
INTCONbits.TMR0IF=0;//Clear TMR0 interrupt flag
T0CONbits.TMR0ON=1;
//Turn on TMR0
}
}
10.13
From Problem 10.12, Count = 0xF830
#include <p18f4321.h>
void main(void)
{
TRISDbits.TRISD7=0;
//PortD bit 7 is output
T1CON=0xC8;
//Timer1 is 16-bit no prescaler
TMR1H=0xF8;
//Value placed in TMR0H
TMR1H=0x30;
//Value placed in TMR0L
PIR1bits.TMR1IF=0;
//Clear TMR1 interrupt flag
T1CONbits.TMR1ON=1;
//Turn on TMR1
while(1)
{
while(PIR1bits.TMR1IF==0);
T1CONbits.TMR1ON=0;
//Turn off TMR0
PORTDbits.RD7=~PORTDbits.RD7;//Chage output of square wave
TMR1H=0xF8;
//Value placed in TMR1H
TMR1L=0x30;
//Value placed in TMR1L

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

PIR1bits.TMR1IF=0;
T1CONbits.TMR1ON=1;

97

//Clear TMR1 interrupt flag


//Turn on TMR1

}
}
10.14
#include <P18F4321.h>
void main()
{
TRISCbits.TRISC0=0; //Bit 0 of PORTC is output
T2CON=0;
// no prescaler and no postscaler
TMR2=0;
//Clear TMR2 to 0
PR2 = 200;
PIR1bits.TMR2IF=0;
//Clear rollover interrupt flag
PORTCbits.RC0=0;
//Turn LED off
T2CONbits.TMR2ON=1;//Turn on TMR2
while(PIR1bits.TMR2IF==0); //Wait for TMR2 to count to 200
PORTCbits.RC0=1;
//Turn on LED
}
10.15
Each half cycle of the square wave with 50% duty cycle is 2 msec.
Clock Period = 1/(4 MHz) = 0.25sec, Instruction cycle clock period = 4 x 0.25
sec= 1sec.
Time delay = Instruction cycle x Prescale value x Count
Hence, Count = (2 ms) / (1 sec x 8) = 250 10 (0x00FA). The timer counts up from
an initialized value to 0xFFFF, and then rolls over (increments) to 0000H. The
number of counts for rollover is (0xFFFF - 0x00FA) = 0xFF05.
Note that an extra cycle is needed for the roll over from 0xFFFF to 0x0000,
and the TMR0IF flag is then set to 1. Because of this extra cycle, the total number
of counts for roll over = 0xFF05 + 1 = 0xFF06.
#include <P18F4321.h>
#define PWM PORTCbits.RC3
void main()
{
TRISCbits.TRISC3=0;

//PORTC pin 3 is output

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

98

T3CON=0xC8;
//Timer3 is 16-bit no prescaler
TMR3H=0xFF;
//Value placed in TMR3H
TMR3L=0x06;
//Value placed in TMR3L
PIR2bits.TMR13F=0;
//Clear TMR3 rollover interrupt flag
T3CONbits.TMR3ON=1;
//Turn on TMR3
while(1)
{
while(PIR2bits.TMR3IF==0);
T3CONbits.TMR3ON=0;
//Turn off TMR3
PORTDbits.RD7=~PORTDbits.RD7;//Chage output of square wave
TMR3H=0xFF;
//Value placed in TMR3H
TMR1L=0x06;
//Value placed in TMR3L
PIR2bits.TMR3IF=0;
//Clear TMR3 rollover interrupt flag
T3CONbits.TMR3ON=1;
//Turn on TMR3
}
}
10.16
(a)

A square wave with 50% duty cycle or a symmetrical square wave.

(b) Note that T0CON = 0x01. Hence, Timer0 is configured in the 16-bit mode
with 1:4 prescale value. One counter clock = 4 x 4 sec = 16 sec. The timer is
loaded with 0xC2F7 = 49, 911 (decimal). Therefore, (65,536 - 49,911) x 32 sec =
250, 000 sec = 0.25 sec. This is actually half the period. So, the full period of the
signal = 2x 0.25 sec = 0.5 sec. Thus the frequency of the signal = 1/0.5sec = 2 Hz.
(c) In this case, the timer is configured as an 8-bit timer with a prescale factor of
8. Therefore, one clock period = 4 sec x 8 = 32 sec. The TMR0L is loaded with
0xF7(247 decimal). Hence, period of the signal = (256 - 247) x (32 sec) x 2 = 288
sec . Therefore, Frequency = (1/0.288msec) = 1.736 KHz.

10.17
In order to design the voltmeter, the PIC18F4321 on-chip A/D converter available
will be used. Three registers ADCON0-ADCON2 need to be configured. In
ADCON0, bit 0 of PORT A
( RA0/AN0) is designated as the analog signal to be converted. Hence,
CHS3-CHS0 bits (bits 5-2) are programmed as 0000 to select channel 0 (AN0).

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

99

The ADCON0 register is also used to enable the A/D, starting the A/D, and then
check the End of conversion bit.
The reference voltages are chosen by programming the ADCON1 register.
In this example, VDD (by clearing bit 4 of ADCON1 to 0) ,and VSS (by clearing
bit 5 of ADCON1 to 0) will be used. The ADCON1 register is also used to
configure AN0 (bit 0 of PORT A) as an analog input by writing 1101 at
PCFG3-PCFG0 (bits 3-0 of ADCON1). Note that there are several choices to
configure AN0 as an analog input.
The ADCON2 is used to set up the acquisition time, conversion clock, and
also, if the result is to be left or right justified. In this example, 8-bit result is
assumed. The A/D result is configured as left justified, and therefore, the 8-bit
register ADRESH will contain the result. The contents of ADRESL are ignored.
Because the maximum decimal value that can be accommodated in 8 bits of
ADRESH is 25510 (FF16), the maximum voltage of 5 V will be equivalent to 25510.
This means the display in decimal is given by
D = 5 (input/255)
= input/51
= quotient +remainder
Int eger part

This gives the integer part. The fractional part in decimal is


F = (remainder/51)10
j (remainder)/5

For example, suppose that the decimal equivalent of the 8-bit output of A/D
is 200.
D = 200/51 e quotient = 3, remainder = 47
integer part = 3
fractional part, F = 47/5 = 9

Therefore, the display will show 3.9 V.


From these equations, the final result will be in BCD which can then be sent
to the 7447 decoders. Finally, the result is displayed on two 7-segment displays.
The C language program for the voltmeter is provided below:
#include <p18f4321.h>
unsigned int result;
void convert (void);
void divide (void);
#pragma code ADCINT=0x08
void ADCINT (void)

//At interrupt, code jumps here

Instructors Manual

{ _asm
GOTO check_int
_endasm
}
void main()
{
TRISC = 0;
TRISD = 0;
PIE1bits.ADIE = 1;
PIR1bits.ADIF = 0;
INTCONbits.PEIE = 1;
INTCONbits.GIE = 1;
ADCON0=0x01;
ADCON1=0x00;
ADCON2=0x29;
ADCON0bits.GO = 1;
while(1);
}
#pragma interrupt convert
void convert (convert)
{
PIR1bits.ADIF = 0;
result = ADRESH;
divide();
ADCON0bits.GO = 1;
}
void divide (void)
{
PORTC = result/51;
PORTD = result%51;
}

Microcontroller Theory & Applications with the PIC18F

100

//Configure Port C as output


//Configure Port D as output
//enable ADC interrupt
//clear ADC interrupt flag
//enable peripheral interrupt
// enable global interrupt
//Select AN0
//Enable AN0 and select reference voltages
//Left justified, 12 TAD, Fosc/8
//Start A/D conversion
//Wait for interrupt

//Clear ADIF to 0
//Start A/D conversion again

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

101

10.18
(a)

Analog Signal

5v peak-to-peak

Common Anode
7-Segment Displays

a-g

a-g
7

Absolute
Value
Circuit

7447 B

C
D

0
1

B
7447 C
D

PORT A

PORT C

2
3

PORT D

PIC18F4321

(b)
The C language program is provided below:
#include <P18F4321.h>
#include <math.h>
//Allows the sqrt() function
void main()
{
unsigned int i, j, ADCresult;
unsigned char D0, D1;
unsigned double sum, convert, square, final; //Allows decimal answers
TRISC=0x00;
TRISD=0x00;
ADCON0 = 0x00;
//Configure the ADC registers
ADCON1 = 0x0E;
ADCON2 = 0xAC;
sum=0;
for (i=0; i<128; i++)
{
for (j=0; j<2000; j++);
//Delay of 2ms between samples
ADCON0bits.GO=1;
//Start ADC
while(ADCON0bits.DONE == 1);//Wait for ADC to finish
ADCresult = ADRESH;
//Move the ADC result into ADCresult

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

102

convert=ADCresult/51;
sum+ = convert * convert ;

//Conversion factor
//Square the solution;
//Sum up the squares

final=10*sqrt(sum >> 7);

//Divide by 128, Take the square of the


//sums, multiply by
//10 in order to be able to separate the whole

//and fractional numbers


D1 = final/10;
D0 = final% 10;
PORTC=D1;
PORTD=D0;

//Display whole number on PORTC


//Display fractional number on PORTD

10.19
(a) Discharge voltage, Vc (t) = k e t/RC . For one time constant, t = RC. Hence, Vc
(t) = (k/e). Hence, Vc(t) = 0.368 k. If k = 5.5V is arbitrarily used in this example,
then Vc(t) = 2.02V for one time constant.
In the hardware schematic shown below, the capacitor is charged by
outputting a 1 (5 V) via bit 0 of Port C. Three 741 op amps are used. With a gain
of 3, a 15V output is obtained from the 741 connected to bit 0 (RC0) of Port C.
Since discharge time is used rather than charging time, as soon as the capacitance
is charged to 5.5 volts (arbitrarily chosen) as detected by another 741 connected to
bit 1 (RC1) of Port C, the PIC18F 4321 is programmed to output 0 from RC0 so
that the capacitor starts discharging. A counter is incremented using a one-second
software delay loop. When the voltage drops to 2.02V after one time constant
detected by another 741 via bit 2 (RC2) of Port C, the counter is stopped. The
content of the counter will provide the value of the capacitor in microfarad. This is
because one Megaohm resistor is used to charge the capacitor. Capacitors of
different ranges of values (picofarad, nanofarad) can be obtained by selecting
different resistor values. The counter value is output to two seven-segment
displays via two 7447s. The capacitor value in the range of 1 F to 15 F is used;
the fractional part is discarded.

Instructors Manual

Hardware Schematic:

Microcontroller Theory & Applications with the PIC18F

103

Instructors Manual

(b)

Microcontroller Theory & Applications with the PIC18F

104

The C-program for the capacitance meter is provided below:

#include <p18f4321.h> //<p18f2480.h>


void main(void)
{
int DELAY;
int DELAY1;
int COUNTER;
int i,k;
TRISCbits.TRISC0=0;
//Output to charge Capacitor
TRISCbits.TRISC1=1;
//Bit 1 of PORTC input
TRISCbits.TRISC2=1;
//Bit 2 of PORTC input
TRISD=0x00;
//Set PORTD output
PORTD=0x00;
COUNTER=0;
//Clear counter to 0
PORTCbits.RC0=1;
//Start charging the capacitor
while(PORTCbits.RC1=0);
//Wait until RC1 high, then discharge
PORTCbits.RC0=0;
while(PORTCbits.RC2=1)
{
for(i=0; i<249; i++)
for(k=0; k<249; k++); //time delay
COUNTER++;
//Start incrementing counter
}
PORTD=COUNTER;

//Output counter value on PORTD

}
10.20
Assume 8 MHz internal clock. Each instruction cycle is 0.5 s.
Time delay = Instruction cycle x Prescale value x Counter value
For 1 sec delay with prescale value of 1:128,
Counter value = (1 sec)/ ( 0.5 s x 128) = 15625 = 3D09H. The counter counts up
from an initial value of FFFFH, and then rolls over to 0000H. The number of
counts for rollover = FFFFH - 3D09H = C2F6H. An extra cycle is needed for
rollover. Hence, total number of counts = C2F7H.
#include <P18F4321.h>
unsigned char sec, min, hour;
void inc_min(void);

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

void inc_hour(void);
void main()
{
unsigned char sec, min, hour;
T0CON=0x06;
TMR0H=0xC2;
TMR0L=0xF7;

//1:128 prescale internal oscillator


//Value for 1 second

INTCONbits.TMR0IF=0;
//Clear TMR0 interrupt flag
INTCONbits.TMR0IE=1;
//Enable TMR0 interrupts
sec=0;
min=0;
hour=0;
//Clear the sec, min, and hour
T0CONbits.TMR0ON=1;
//Start TMR0
while(1)
{
while(INTCONbits.TMR0IF==0);
//Wait for 1 second
TMR0L=0xDC;
TMR0H=0x0B;
//Value for 1 second
sec++;
if(sec==60)
inc_min(); //If seconds is 60 go to inc_min
}
}
void inc_min(void)
{
sec=0;
//Clear seconds
min++;
//Increment mininute
if(min==60)
inc_hour(); //If minutes equal 60 go to inc_hour
}
void inc_hour(void)
{
min=0;
hour++;
if(hour==25)
hour=0;
}

//Clear minutes
//Increment hours
//If hour equals 25 clear value

105

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

106

10.21
#include <P18F4321.h>
unsigned int FINAL,ADCONRESULT, ANSWER; //Initialize variables
unsigned char D1,D0;
void POWER_CALC(void);
void main()
{
unsigned int i;
ADCON0 = 0x01; //Select AN0 for input and enable ADC
ADCON1 = 0x01; //Set VDD and VSS as reference voltages
//and AN0 as analog input
ADCON2 = 0x29; //Left justified 12TAD and Fosc/8
while(1)
{
ADCON0bits.GO = 1;
while(ADCON0bits.DONE == 1);

//Start the ADC


//Wait until conversion is complete

ADCONRESULT = ADRESH;
//Move the ADC result into
ADCONRESULT
FINAL=(ADCONRESULT*10)/51; //Conversion factor
POWER_CALC();
}
}
void POWER_CALC()
{
ANSWER=(FINAL*FINAL); //Square the voltage
ANSWER=>>1;
//Divide by 2 for power in mW
}
10.22
The block diagram is provided below:

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

PORTB

a-g

7447 B

C
D

2
4

INT0

Increment
Button

PORT C

B
7447 C

a-g

Decrement
Button

RB1

Common Anode
7-Segment Displays

107

6
7

PIC18F4321

The C-language program can be written following the PIC18F assembly language
program of Problem 9.12.
10.23
The block diagram is provided below:

Latch

TIL311

BCD Display
with
on-chip
decoder

4
4

Display with on-chip decoder

PB3
PB2
PB1
PB0

Port C

connected to D
connected to C
connected to B
connected to A

PB 3
PB 0

Port D
PIC18F4321

0
1
2
3

.
.

8
4
0

z
z

zF
z

z
z
z

10K

10K

PB6
PB5
PB4

10K

10K

+ 5V

z
z
z

10K

10K

10K

10K

z
z
z
z

0
1
2
3
4
5
6
7

The C-language program can be written following the PIC18F assembly language
program of Problem 9.13.

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

108

10.24
The following code is used to program the master PIC18F4321 device:
#include <p18f4321.h>
void SPI_out(unsigned char);
void main (void)
{
unsigned char output;
TRISCbits.TRISC5 = 0; //Configure SPI data as output
TRISCbits.TRISC3 =0; //Configure SCK as output
TRISD=0xFF;
//PORTD is input
SSPSTAT= 0x40; //Transmission occurs on high to low clock
SSPCON1 = 0x20; //Enable serial functions and set as master device
while(1){
if(PORTDbits.RD0==0)
output=0x00;
if(PORTDbits.RD0==1)
output=0x01;
SPI_out(output); //Send variable 'output' to SPI_out
}
}
void SPI_out(unsigned char SPI_data)
{
SSPBUF = SPI_data;
//Place switch value into the serial buffer
while (SSPSTATbits.BF == 0); //Wait for transmission to finish
}
The following code is used to program the slave PIC18F4321 device:
#include <p18f4321.h>
unsigned char value;
void main (void)
{
TRISCbits.TRISC4 = 1; //Configure SPI data as input
TRISCbits.TRISC3 =1; //Configure SCK as input
TRISB=0x00;
//PORTB is output
SSPSTAT= 0x40; //Transmission occurs on high to low clock
SSPCON1 = 0x25; //Enable serial functions and disable the slave device
while(1){
while (SSPSTATbits.BF == 0); // Wait for transmission to finish

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

109

value=SSPBUF;
//Move serial buffer to variable value
if(value==0x01)
PORTBbits.RB5=1;
//Turn on LED
if(value==0x00)
PORTBbits.RB5=0;
//Turn off LED
}
}
10.25
#include <P18F4321.h>
void main()
{
TRISC=1;
//PORTC is input
CCP1CON=0x05; //Capture mode, event on rising edge
T1CON=0xC8; //Internal clock, no prescale
TMR1L=0;
//Clear TMR1L register
TMR1H=0;
//Clear TMR1H register
PIR1bits.CCP1IF=0;//Clear CCP1 interrupt flag
while(PIR1bits.CCP1IF==0); //Wait for first rising edge
T1CONbits.TMR1ON=1;
//Turn on TMR1
PIR1bits.CCP1IF=0;
//Clear CCP1 interrupt flag
while(PIR1bits.CCP1IF==0); //Wait for second rising edge
T1CONbits.TMR1ON=0;
//Turn off TMR1
while(1);
//Period is found in registers CCPR1L and CCPR1H
}
10.26
#include <P18F4321.h>
void main()
{
TRISCbits.TRISC2=0;
T1CON=0xDC;
TMR1L=0x00;
TMR1H=0x00;
CCP1CON=0x02;
CCPR1L=0x10;
CCPR1H=0x27;
PIR1bits.CCP1IF=0;

//CCP1 as output
//16-bit 1:2 prescale
//Clear TMR1L and TMR1H
//Compare mode, toggle output on match
//Value for 20ms square wave
//Clear CCP1 interrupt flag

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

110

PIE1bits.CCP1IE=1;
//Enable CCP1 interrupt
while(1) {
T1CONbits.TMR1ON=1;
//Start TMR1
while(PIR1bits.CCP1IF==0); //Wait for compare
T1CONbits.TMR1ON=0;
//Stop TMR1
TMR1L=0x00;
TMR1H=0x00;
//Clear TMR1L and TMR1H
}
}
10.27
#include <p18f4321.h>
void main (void)
{
TRISC=0x00;
//PORTC is output
T2CON=0x00;
//Configure TMR2 with no precscale and no postscale
TMR2=0x00;
PIR1bits.TMR2IF=0;//Clear TMR2 interrupt flag
CCP1CON=0x0C; //Use PWM generator
PR2=156;
//Set period of PWM
while(1)
{
CCPR1L=117;
//Value for 75% duty cycle
PIR1bits.TMR2IF=0;
//Clear TMR2 interrupt flag
T2CONbits.TMR2ON=1;
//Turn on TMR2
while(PIR1bits.TMR2IF==0); //Wait until cycle is over
}
}
10.28
PR2 = [(Fosc)/(4 x Fpwm x TMR2 Prescale Value)] - 1
= [(4 MHz)/(4 x 800x 16)] - 1
= 77.125
Hence, PR2 will be 77 approximately.

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

111

After converting the potentiometer voltage into 8-bit binary, the ADRESH
will contain the converted data. Note that the 8-bit ADRESH register can
accommodate a maximum value of 255. The contents of ADRESH can be moved
to CCPR1L to represent the decimal portion of the duty cycle. In order for the duty
cycle to be in the range of 0 to 77, the contents of ADRESH must be divided by
which is 3 (255/77 = 3 approximately). This will ensure that the decimal portion of
the duty cycle is between 0 and 77. The higher the voltage accross the
potentiometer, the higher will be the value of ADRESH/3. This means that the
higher will be the integer portion of the duty cycle in the CCPR1L register. This
will generate a PWM waveform with a higher duty cycle, and thus the motor will
run faster.
The C-program is provided below:
#include <p18f4321.h>
void ADINT_ISR(void);
#pragma interrupt check_int
void check_int(void)
{ ADINT_ISR();
}
#pragma code ADC_INT=0x08
void ADC_Int (void)
{ _asm
GOTO check_int
_endasm
}
void main()
{ OSCCON=0xEC;
PIE1bits.ADIE = 1;
PIR1bits.ADIF = 0;
INTCONbits.PEIE = 1;
INTCONbits.GIE = 1;
TRISC=0;
T2CON=0x02;
PIR1bits.TMR2IF=0;
ADCON0=0x31;
ADCON1=0x00;
ADCON2=0x29;
CCP1CON=0x0C;
PR2= 77;
TMR2 = 0;
ADCON0bits.GO = 1;

//At interrupt, code jumps here

//4 Mhz
//enable ADC interrupt
//clear ADC interrupt flag
//enable peripheral interrupt
// enable global interrupt
//CCP1 output
//Configure Timer2 with prescale 16
//Clear Timer2 interrupt
//AN12
//Enable analog pins
//Fosc/8
//PWM enable

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

while(1);

112

//Wait for interrupt

}
void ADINT_ISR (void)
{
PIR1bits.ADIF = 0;
CCPR1L=ADRESH/3;
PIR1bits.TMR2IF=0;
T2CONbits.TMR2ON=1;

//Clear Timer 2 interrupt

while(PIR1bits.TMR2IF==0);
ADCON0bits.GO = 1;
}

10.29
//This C program controls the functioning of two-direction traffic lights.
#include <p18f4321.h>
#define SecInd PORTAbits.RA7
void Default(void);
void Emergency(void);
void Delay(unsigned char);
void EWCarWaiting(void);

//Define PORT A bit 7 as Seconds Indicator

void main(void)
{
TRISB = 0;
// North-South Light
TRISD = 0;
// East-West Light
TRISC = 0xFF; // E-W Car Waiting and Emergency switches inputs
TRISAbits.TRISA7 = 0;
// Timer ON indicator
T0CON = 0;
while(1)
{
switch(PORTC) {
case 0:
Emergency(); // If car waiting in E-W direction
//and
break;
// emergency switch is ON.
case 1:

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

Emergency();
break;

113

// Emergency switch is ON.

case 2:
EWCarWaiting(); // Car waiting in E-W direction.
break;
default:
Default();
}

// Give Green light to N-S direction.

}
}
void Delay(unsigned char Dly)
{
unsigned char i;
for(i = 1; i <= Dly; i++){
// One loop = 500 mSec delay
TMR0H = 0x0B;
// Loading Timer 0 High
TMR0L = 0xDC;
// Loading Timer 0 Low
INTCONbits.TMR0IF = 0;
// Clearing Timer 0 Flag
T0CONbits.TMR0ON = 1;
// Starting Timer 0
while(INTCONbits.TMR0IF == 0) // Testing Flag
;
// Waiting for flag to turn to 1
SecInd=~SecInd;
// Toggle seconds indicator
T0CONbits.TMR0ON = 0;
// Stopping the timer
INTCONbits.TMR0IF = 0;
// Clearing the Flag
}
}
void Default()
{
PORTB = 4;
PORTD = 1;
}
void Emergency(void)
{
PORTB = 1;
PORTD = 1;
Delay(1);
PORTB = 0;
PORTD = 0;

// Green on North-South Direction


// Red on East-West direction

// Turn both red lights ON


// Wait 1/2 Sec
// Turn both red lights OFF

Instructors Manual

Delay(1);

Microcontroller Theory & Applications with the PIC18F

// Wait 1/2 sec

}
void EWCarWaiting(void)
{
PORTB = 2;
PORTD = 1;
Delay(4);
PORTB = 1;
PORTD = 4;
Delay(10);
PORTB = 1;
PORTD = 2;
Delay(4);
PORTB = 4;
PORTD = 1;
Delay(20);
}

// Turn North-South Light yellow


// Keep East-West Light red
// 2 Seconds delay
// Turn North-South Light Red
// Turn East-West Light Green
// 5 Seconds delay
// Keep North-South Light Red
// Turn East-West Light Yellow
// 2 Seconds delay
// Turn North-South Light Green
// Turn East-West Light Red
// 10 Seconds Delay

The ASM chart is provided below:

114

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

Start

No

Is
Emergency
Switch
ON?

Turn North-South
Green Light ON.
Turn East-West Red
light on.

Yes

Flash North-South
and East-West Red
Lights.

Is
there a
vehicle waiting
in the east-west
Direction

Turn North-South
Yellow Light ON for 2
secs. keep East-West
Red light ON

Turn North-South
Red Light ON, and the
East-West Green Light
ON for 5 seconds

Keep North-South Red


Light ON, and turn the
East-West Yellow light
ON for 2 seconds

115

Instructors Manual

Microcontroller Theory & Applications with the PIC18F

116

The hardware schematic is provided below:

330
330
+5VDC

10K

330

PIC18F4321

10K

Emergency
Switch

Car-Waiting in
East-West Direction

330

Sec. Ind.

North-South
RA7
RC0
RC1

RB2
RB1
RB0

330
330
330

RD0
RD1

RD2

R
East-West

S-ar putea să vă placă și