Microcontroller Theory
Microcontroller Theory
and
Applications with the PIC18F
M. RAFIQUZZAMAN, Ph.D.
PROFESSOR
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
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
(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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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)
18
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
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
Instructors Manual
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
[FSR2] = 0x0074
6.5
0x0E00
0x6E93
0x0000
0x0EAA
0x6E81
0x0003
6.6
6.7
CLRF
0x20
SETF
0x22
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
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
23
Assume N1 and N2 are already loaded into registers 0x20 and 0x21
respectively.
INCLUDE <P18F4321.INC>
ORG
0x100
SWAPF
0x21, F
MOVF
0x20, W
ADDWF
0x21, W
MOVWF
0x30
SLEEP
END
6.14
INCLUDE <P18F4321.INC>
ORG
0x100
MOVLW
MOVWF
0x20
MOVLW
0x91
MOVWF
0x21
MOVLW
MOVWF
0x22
MOVLW
MOVWF
0x50
MOVLW
0xA2
MOVWF
0x51
Instructors Manual
BACK
24
MOVLW
MOVWF
0x52
LFSR
LFSR
MOVLW
MOVWF
0x30
BCF
MOVF
POSTDEC0, W
; Initialize Counter
ADDWFC POSTINC1, F
DECF
0x30, F
BNZ
BACK
SLEEP
END
6.15
INCLUDE <P18F4321.INC>
ORG
0x100
MOVLW
0x72
MOVWF
0x50
MOVLW
0x64
MOVWF
0x40
MOVLW
0x16
MOVWF
0x25
MOVLW
0x34
Instructors Manual
25
MOVWF
0x20
MOVF
0x25, W
SUBWF
0x50, F
MOVF
0x20, W
SUBWFB
0x40, F
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
26
INCLUDE <P18F4321.INC>
ORG
0x50
MOVLW
MOVWF
0x32
MOVLW
MOVWF
0x33
MOVLW
MULWF
0x32
; 6 x J in PRODH:PRODL
RRNCF
0X33,F
RRNCF
0X33,F
RRNCF
0X33,F
MOVFF
MOVLW
MOVWF
0x50
MOVF
PRODL, W
ADDWF
0x51, F
MOVF
PRODH, W
; Load J
; Load K
ADDWFC 0x50, F
SLEEP
END
6.18
INCLUDE <P18F4321.INC>
ORG
0x50
ANDLW
0x01
Instructors Manual
BNZ
ODD
CLRF
0x40
BRA
FINISH
ODD
SETF
0x40
FINISH
BRA
FINISH
27
; Clear [0x40] to 0s
END
6.19
INCLUDE <P18F4321.INC>
ORG
0x70
MOVWF
0x20
RLCF
0x20, F
BNC
IORLW
BRA
FINISH
POSITIVE
ANDLW
0xFB
FINISH
BRA
FINISH
END
6.20
Assume data is already loaded into 0x70.
INCLUDE <P18F4321.INC>
ORG
0x100
COUNTER
EQU
0x20
PARITY
EQU
0x21
Instructors Manual
28
MOVLW
MOVWF
CLRF
PARITY
RRCF
0x70, F
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
BNC
EVEN
MOVLW
0xDD
MOVWF
0x50
BRA
FINISH
MOVLW
0xEE
MOVWF
0x50
BRA
FINISH
BACK
EVEN
FINISH
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
ORG
0x100
MOVLW
0x01
MOVWF
0x20
MOVLW
0x24
MOVWF
0x21
BCF
RRCF
0x20, F
RRCF
0x21, F
SLEEP
END
29
Instructors Manual
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
SWAPF
0x30, F
MOVLW
0x0F
ANDLW
0x30, F
ANDLW
0x40, W
MULWF
0x30
Instructors Manual
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
BRA
32
POSMUL
<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
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
MULWF
0x40
MOVLW
; Initialize COUNTER
MOVWF
COUNTER
Instructors Manual
BACK
FINISH
BCF
RRCF
PRODH, F
RRCF
PRODL, F
DECF
COUNTER, F
BNZ
BACK
MOVFF
PRODL, 0x50
BRA
FINISH
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
Instructors Manual
SUMSQ
35
ORG
0x200
MOVF
0x60, W
MULWF
0x60
MOVFF
PRODL, 0x70
; Save in 0x70
CALL
MOVF
ADDWF
0x40, F
PRODL
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
36
LOOP
ORG
0x100
CLRF
0x50
; Clear sum to 0
LFSR
0, 0x0020
LFSR
1, 0x0030
MOVLW
D10
MOVWF
0x75
MOVF
MULWF
MOVF
ADDWF
0x50, F
; sum in 0x50
DECF
0x75, F
; Decrement counter by 1
BNZ
LOOP
; Repeat if Z = 0
SLEEP
END
Instructors Manual
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
LFSR
2, 0x50
MOVF
CPFSEQ
BRA
NOTEQUAL
MOVFF
BRA
DOWN
; Initialize counter
NOTEQUAL MOVFF
DOWN
DECF
0x22, F
BNZ
BACK
BRA
FINISH
FINISH
END
7.9
; Decrement counter
Instructors Manual
38
INCLUDE <P18F4321.INC>
BACK
BACK1
ORG
0x100
MOVLW
MOVWF
0x40
BCF
RRCF
0x30, F
RRCF
0x31, F
DECF
0x40, F
BNZ
BACK
MOVLW
MOVWF
0x40
BCF
STATUS, C
RRCF
0x30, F
RRCF
DECF
0x40, F
BNZ
BACK1
SLEEP
END
7.10
INCLUDE <P18F4321.INC>
ORG
0x200
MOVLW
Instructors Manual
39
MOVWF
0x44
; to divide by 16
RRCF
0x31, W
BNC
SETF
BRA
FINISH
POSITIVE RLCF
0x20, F
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
LFSR
0, 0x10
MOVLW
0x0F
Instructors Manual
40
ANDWF
INDF0, F
MOVFF
MOVLW
0x00
SUBWF
INDF0, F
BZ
DOWN
MOVLW
0x05
SUBWF
0x60, F
BZ
DOWN
MOVLW
0x2D
CPFSEQ
0x60
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
41
LFSR
0, 0x23
LFSR
1, 0x33
BCF
STATUS, C
MOVF
; Clear Carry
ADDWFC POSTDEC1, W
DAW
MOVWF
POSTDEC0
DECF
0x50, F
; Decrement counter
BNZ
BACK
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
42
DECF
BNZ
MOVLW
MOVWF
MOVLW
CALL
BRA
ORG
LFSR
0x100
0, 0x50
MOVF
PLUSW0, W
; Subroutine
SQUARE
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
D16
D25
D36
D49
D64
D81
43
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
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
; 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
45
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
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
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
48
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
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
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
51
MOVWF
LOOP
STAY
ADDR
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
Instructors Manual
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
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
0x000200
PORTC, 0x50
0x50
LEDON
PORTC, RC3
HERE
PORTC, RC3
INTCON, INT1IF
54
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
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
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
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
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
58
8.26
The main functions to be performed for interfacing a keyboard are:
y
y
y
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
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
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
60
<P18F4321.INC>
0x70
TRISC, TRISC0
0x08
T0CON
0xF8
TMR0H
0x30
TMR0L
INTCON, TMR0IF
PORTC, RC0
T0CON, TMR0ON
INTCON, TMR0IF
LOOP
T0CON, TMR0ON
BACK
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
Instructors Manual
WAIT
MOVWF
BCF
TMR1L
PIR1, TMR1IF
COMF
PORTD, RD7
BSF
BTFSS
T1CON, TMR1ON
PIR1, TMR1IF
BRA
BCF
BRA
END
WAIT
T1CON, TMR1ON
LOOP
61
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
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
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
64
Instructors Manual
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
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
(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
Counter
=0
Yes
Perform Sum/128 by
shifting sum 7 times to right
67
Instructors Manual
68
Start
[COUNTER1]
[VALUE 0]
16
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
No
NO
Output {VALUE0]
to lower integer
display. Blank
upper integer
display
Output '0'
to fractional
display
Stop
Yes
Output to
displays
Stop
Instructors Manual
69
1
Negate [VALUE 1]
and Store in
VALUE 2
[VALUE 0]
[VALUE0] + 1
[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
70
<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
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
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
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
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
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
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
76
Instructors Manual
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
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
Instructors Manual
;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
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
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
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
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
STKPTR
83
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
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
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
Instructors Manual
BACK
WAIT
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
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
Instructors Manual
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;
Instructors Manual
89
}
void fail(void)
{
while(1)
{
}
}
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
90
TRISC =0x00;
TRISD = 0xFF;
value1 = PORTD & 0x07;
value2 = PORTD & 0x38;
value2 = value2>>3;
sum=value1 + value2;
PORTC=lookup_table[sum];
}
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
{
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
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
330
Instructors Manual
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
//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;
}
95
}
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
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
PIR1bits.TMR1IF=0;
T1CONbits.TMR1ON=1;
97
}
}
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;
Instructors Manual
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)
(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
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
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
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;
}
100
//Clear ADIF to 0
//Start A/D conversion again
Instructors Manual
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
102
convert=ADCresult/51;
sum+ = convert * convert ;
//Conversion factor
//Square the solution;
//Sum up the squares
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:
103
Instructors Manual
(b)
104
}
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
void inc_hour(void);
void main()
{
unsigned char sec, min, hour;
T0CON=0x06;
TMR0H=0xC2;
TMR0L=0xF7;
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
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);
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
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
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
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
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
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
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;
//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
while(1);
112
}
void ADINT_ISR (void)
{
PIR1bits.ADIF = 0;
CCPR1L=ADRESH/3;
PIR1bits.TMR2IF=0;
T2CONbits.TMR2ON=1;
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);
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
Emergency();
break;
113
case 2:
EWCarWaiting(); // Car waiting in E-W direction.
break;
default:
Default();
}
}
}
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;
Instructors Manual
Delay(1);
}
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);
}
114
Instructors Manual
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
115
Instructors Manual
116
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