0% found this document useful (0 votes)
102 views496 pages

Vi điều khiển

The document provides an introduction to the PIC18 microcontroller. It describes the basic components of a computer including the processor, memory, input/output units and common bus. It then discusses the features of the PIC18 microcontroller including its 8-bit CPU, program memory space, data memory and various peripherals. Finally, it covers the organization of memory on the PIC18 including the separation of program and data memory and use of banks in data memory.

Uploaded by

Phuc Thinh
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
102 views496 pages

Vi điều khiển

The document provides an introduction to the PIC18 microcontroller. It describes the basic components of a computer including the processor, memory, input/output units and common bus. It then discusses the features of the PIC18 microcontroller including its 8-bit CPU, program memory space, data memory and various peripherals. Finally, it covers the organization of memory on the PIC18 including the separation of program and data memory and use of banks in data memory.

Uploaded by

Phuc Thinh
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 496

The PIC18 Microcontroller

Chapter 1

Introduction to PIC18

No.1-1
The PIC18 Microcontroller

What is a computer?
Software
Hardware
Computer Hardware Organization
Processor

Common Bus (address, data, & control)

Control Unit

Datapath

Arithmetic
Logic Unit Memory
Output Input
Program Data
Units Units
Registers Storage Storage

Figure 1.1 Computer Organization

No.1-2
The PIC18 Microcontroller

The processor
Registers -- storage locations in the processor
Arithmetic logic unit
Control unit

program counter contains the address of the


next instruction to be executed

status register flags the instruction execution


result

No.1-3
The PIC18 Microcontroller

The microprocessor
A processor implemented on a very large
scale integration (VLSI) chip
Peripheral chips are needed to construct a
product

The Microcontroller
The processor and peripheral functions
implemented on one VLSI chip

No.1-4
The PIC18 Microcontroller

Features of the PIC18 microcontroller


8-bit CPU
2 MB program memory space
256 bytes to 1KB of data EEPROM
Up to 3968 bytes of on-chip SRAM
4 KB to 128KB flash program memory

No.1-5
The PIC18 Microcontroller

Sophisticated timer functions that include: input capture,


output compare, PWM, real-time interrupt, and watchdog
timer
Serial communication interfaces: SCI, SPI, I2C, and CAN
Background debug mode (BDM)
10-bit A/D converter
Memory protection capability
Instruction pipelining
Operates at up to 40 MHz crystal oscillator

No.1-6
The PIC18 Microcontroller

Embedded Systems
A product that uses one or more microcontrollers
as controller (s).
End users are only interested in the functionality
of the product but not on the microcontroller itself.
Cell phones, home security system, automobiles,
and many other products are examples of embedded
products.

No.1-7
The PIC18 Microcontroller

Semiconductor memory

 Random-access memory (RAM): same amount of time is


required to access any location on the same chip
 Read-only memory (ROM): can only be read but not
written to by the processor

Random-access memory

 Dynamic random-access memory (DRAM): need


periodic refresh
 Static random-access memory (SRAM): no periodic
refresh is required

No.1-8
The PIC18 Microcontroller

Read-only memory
Mask-programmed read-only memory (MROM):
programmed when being manufactured
Programmable read-only memory (PROM): can be
programmed by the end user
Erasable programmable ROM (EPROM)
1. Electrically programmable many times
2. Erased by ultraviolet light (through a window)
3. Erasable in bulk (whole chip in one erasure operation)

No.1-9
The PIC18 Microcontroller

Electrically erasable programmable ROM


(EEPROM)
1. Electrically programmable many times
2. Electrically erasable many times
3. Can be erased one location, one row, or whole chip in
one operation

Flash memory
1. Electrically programmable many times
2. Electrically erasable many times
3. Can only be erased in bulk (either a block or the
whole chip)

No.1-10
The PIC18 Microcontroller

Computer software
Computer programs are known as software
A program is a sequence of instructions

Machine instruction (MI)


A sequence of binary digits which can be executed by the
processor
Hard to understand, program, and debug for human being

No.1-11
The PIC18 Microcontroller

Assembly language (AL)


Defined by assembly instructions
An assembly instruction is a mnemonic representation of
a machine instruction
Assembly programs must be translated before it can be
executed -- translated by an assembler
Programmers need to work on the program logic at a very
low level and can’t achieve high productivity.

No.1-12
The PIC18 Microcontroller

High-level language
Syntax of a high-level language is similar to English
A translator is required to translate the program written in a
high-level language -- done by a compiler
Allows the user to work on the program logic at higher level.

Source code
A program written in assembly or high-level language

Object code
The output of an assembler or compiler

No.1-13
The PIC18 Microcontroller

Source code and object code examples

address object code line no. Source code


------------------------------------------------------------------------------------------
00001E 0E06 00010 movlw 0x06
000020 6E11 00011 movwf 0x11,A
000022 0E07 00012 movlw 0x07
000024 6E12 00013 movwf 0x12,A
000026 0E08 00014 movlw 0x08
000028 6E13 00015 movwf 0x13,A
00002A 0E05 00016 movlw 0x05
00002C 5E10 00017 subwf 0x10,F,A
00002E 5E11 00018 subwf x11,F,A

No.1-14
The PIC18 Microcontroller

Radix Specification
Hexadecimal (or hex) number is specified by adding the
prefix 0x or by enclosing the number with single quotes
and preceding it by an H.
0x02, 0x1234, H`2040’ are hex numbers
Decimal numbers are enclosed by single quotes and
preceded by letter D.
D`10’ and D`123’ are decimal numbers
Octal and Binary numbers are similarly specified.
O`234’ is an octal number; B’01011100’ is a binary
number.

No.1-15
The PIC18 Microcontroller

Memory Addressing

Memory consists of a sequence of directly addressable


locations.
A location is referred to as an information unit.
A memory location can be used to store data, instruction,
and the status of peripheral devices.
A memory location has two components: an address and its
contents.

Address Contents

Figure 1.2 The components of a memory location

No.1-16
The PIC18 Microcontroller

The PIC18 Memory Organization

Data Memory and Program Memory are separated

Separation of data memory and program memory makes


possible the simultaneous access of data and instruction.

Data memory are used as general-purpose registers or special


function registers

On-chip Data EEPROM are provided in some PIC18 MCUs

No.1-17
The PIC18 Microcontroller

Separation of Data Memory and Program Memory

Inside the c chip

Program
21-bit progam address 12-bit register address Data
Memory Memory
Space Space
(a portion
PIC18 (Special
of this function
space is on CPU
registers and
the c general
16-bit instruction bus 8-bit data bus
chip) purpose
RAM)

Figure 1.3 The PIC18 memory spaces

No.1-18
The PIC18 Microcontroller

PIC18 Data Memory


Implemented in SRAM and consists of general-purpose
registers and special-function registers. Both are referred
to as data registers.
A PIC18 MCU may have up to 4096 bytes of data
memory.
Data memory is divided into banks. Each bank has 256
bytes.
General-purpose registers are used to hold dynamic data.
Special-function registers are used to control the operation
of peripheral functions.

No.1-19
The PIC18 Microcontroller

Only one bank is active at any time. The active bank is


specified by the BSR register.

Bank switching is an overhead and can be error-prone

PIC18 implements the access bank to reduce the problem


caused by bank switching.

Access bank consists of the lowest 96 bytes and the


highest 160 bytes of the data memory space.

No.1-20
The PIC18 Microcontroller

BSR<3:0>
000h
= 0000 Access RAM 05Fh
Bank 0 060h
GPRs
0FFh
100h
= 0001
Bank 1 GPRs
1FFh
200h
= 0010
Bank 2 GPRs
2FFh
300h
= 0011 Access Bank
Bank 3 GPRs 000h
Access RAM low
3FFh 05Fh
400h Access RAM high 060h
SFRs 0FFh
Bank 4
to GPRs
Bank 13
DFFh
E00h
= 1110
Bank 14 GPRs
EFFh
Unused F00h
= 1111 F5Fh
Bank 15 F60h
SFRs
FFFh
Note. 1. BSR is the 4-bit bank select register.
Figure 1.4 Data memory map for PIC18 devices (redraw with permission of Microchip)

No.1-21
The PIC18 Microcontroller

Program Memory Organization

The program counter (PC) is 21-bit long, which enables


the user program to access up to 2 MB of program
memory.

The PIC18 has a 31-entry return address stack to hold


the return address for subroutine call.

After power-on, the PIC18 starts to execute instructions


from address 0.

No.1-22
The PIC18 Microcontroller

The location at address 0x08 is reserved for high-priority


interrupt service routine.

The location at address 0x18 is reserved for low-priority


interrupt service routine.

Up to 128KB (at present time) of program memory is


inside the MCU chip.

Part of the program memory is located outside of the


MCU chip.

No.1-23
The PIC18 Microcontroller

PC<20:0>
21

stack level 1
.
.
.
stack level 31

000000
Reset Vector
h

High Priority Interrupt Vector 000008h

Low Priority Interrupt Vector 000018h

User Memory Space


On-chip and external
program memory

yxxxxxh

Unimplemented
program memory
Read '0'

1FFFFFh
Note. y can be 0 or 1 whereas x can be 0-F
Figure 1.5 PIC18 Program memory Organization (redraw with permission of
Microchip)

No.1-24
The PIC18 Microcontroller

The PIC18 CPU Register

 The group of registers from 0xFD8 to 0xFFF are dedicated


to the general control of MCU operation.

 These CPU registers are listed in Table 1.2.

 The WREG register is involved in the execution of many


instructions.

 The STATUS register holds the status flags for the


instruction execution and is shown in Figure 1.6.

No.1-25
The PIC18 Microcontroller

26 No.1-26
The PIC18 Microcontroller

27 No.1-27
The PIC18 Microcontroller

No.1-28
The PIC18 Microcontroller

The PIC18 Pipelining (PL)

 The PIC18 Divide most of the instruction execution into


two stages: instruction fetch and instruction execution.

 Up to two instructions are overlapped in their execution.


One instruction is in fetch stage while the second instruction
is in execution stage.

 Because of pipelining, each instruction appears to take one


instruction cycle to complete.

No.1-29
The PIC18 Microcontroller

TCY0 TCY1 TCY2 TCY3 TCY4 TCY5

MOVLW 55h fetch 1 execute 1


MOVWF PORTB fetch 2 execute 2

BRA sub_1 fetch 3 execute 3


BSF PORTA,BIT3 fetch 4 flush
Instruction @address sub_1 fetch sub_1 execute
sub_1
Note: All instructions are single cycle, except for any program branches.

Figure 1.7 An example of instruction pipeline flow

No.1-30
The PIC18 Microcontroller

Sample of data movement instructions

31 No.1-31
The PIC18 Microcontroller

Instruction Format
Format for byte oriented instructions

15 10 9 8 7 0
opcode d a f

d = 0 for result destination to be WREG register.


d = 1 for result destination to be file register (f)
a = 0 to force Access Bank
a = 1 for BSR to select bank
f = 8-bit file register address
Figure 1.8 Byte-oriented file register operations (redraw with permission of
Microchip)

No.1-32
The PIC18 Microcontroller

Byte-to-byte Operations

15 12 11 0
opcode f (source file register)
15 12 11 0
1111 f (destination file register)

f = 12-bit file register address

Figure 1.9 Byte to byte move operations (2 words) (redraw with permission of Microchip)

No.1-33
The PIC18 Microcontroller

Bit-oriented file register operations

15 12 11 9 8 7 0
opcode b a f

b = 3-bit position of bit in the file register (f).


a = 0 to force Access Bank
a = 1 for BSR to select bank
f = 8-bit file register address
Figure 1.10 Bit-oriented file register operations (redraw with permission of
Microchip)

No.1-34
The PIC18 Microcontroller

Literal operations
A literal is a number to be operated on directly by the CPU
15 8 7 0
opcode k

k = 8-bit immediate value


Figure 1.11 Literal operations (redraw with permission of Microchip)

Control operations

These instructions are used to change the program


execution sequence and making subroutine calls.

No.1-35
The PIC18 Microcontroller

15 8 7 0
opcode n<7:0> (literal)
15 8 7 0 GOTO label
1111 n<19:8> (literal)
n = 20-bit immediate value
15 8 7 0
opcode S n<7:0> (literal)
15 8 7 0 CALL funct_name
1111 n<19:8> (literal)
S = fast bit
15 11 10 0
opcode n<10:0> (literal) BRA label
15 8 7 0
opcode n<7:0> (literal) BC label

Figure 1.12 Control operations (redraw with permission of Microchip)

No.1-36
The PIC18 Microcontroller

Access Bank
 In Figures 1.8 to 1.12, PIC18 uses 8 bits to specify a data
register (f field).
 Eight bits can specify only 256 registers.
 This limitation forces the PIC18 to divide data registers (up
to 4096 bytes) into banks.
 Only one bank is active at a time.
When operating on a data register in a different bank, bank
switching is needed.

No.1-37
The PIC18 Microcontroller

Bank switching incurs overhead and may cause program


errors.
Access bank is created to minimize the problems of bank
switching.
Access bank consists of the lowest 96 bytes in general-
purpose registers and the highest 160 bytes of special
function registers.
When operands are in the access bank, no bank switching
is needed.

No.1-38
The PIC18 Microcontroller

Examples of the Use of Access Bank


1. addwf 0x20,F,A ; add the data register at 0x20 in access bank with WREG
; register and store the sum in 0x20.

2. subwf 0x30,F,BANKED ; subtract the value of WREG from the data register
; 0x30 in the bank specified by the current contents
; of the BSR register. The difference is stored in
; data register 0x30.

3. addwf 0x40,W,A ; add the WREG register with data register at 0x40 in
; access bank and leaves the sum in WREG.

No.1-39
The PIC18 Microcontroller

PIC18 Addressing Modes


- Register direct: Use an 8-bit value to specify a data register.
movwf 0x20,A ; the value 0x20 is register direct mode

- Immediate Mode : A value in the instruction to be used as an operand

addlw 0x10 ; add hex value 0x10 to WREG

movlw 0x30 ; load 0x30 into WREG

- Inherent Mode: an implied operand


andlw 0x3C ; the operand WREG is implied

daw ; the operand WREG is implied

No.1-40
The PIC18 Microcontroller

- Indirect Mode: A special function register (FSRx) is used as a pointer


to the actual data register.
Format Example
INDFx x = 0, 1, 2 movwf INDF0
POSTINCx movff POSTINC0,PRODL
POSTDECx movf POSTDEC0,W
PREINCx addwf PREINC1,F
PLUSWx movff PLUSW2,PRODL

No.1-41
The PIC18 Microcontroller

PIC18 Instruction Examples

Data Movement Instruction

lfsr FSR1,0xB00 ; place the value 0xB00 in FSR1

movf PRODL,W ; copy PRODL into WREG

movff 0x100,0x300 ; copy data register 0x100 to data register 0x300

movwf PRODL,A ; copy WREG to PRODL

swapf PRODL,F ; swap the upper and lower 4 bits of PRODL

movb 3 ; load 3 into BSR

movlw 0x10 ; WREG  0x10

No.1-42
The PIC18 Microcontroller

Add Instructions

addwf 0x20,F,A ; add data register and WREG and place sum in WREG

addwfc PRODL,W,A ; add WREG, PRODL, and carry and leave sum
; in WREG

addlw 0x5 ; increment WREG by 5

Subtract Instructions

subfwb PRODL,F ; PRODL  [WREG] – [PRODL] – borrow flag

subwf PRODH,W ; WREG  [PRODH] – [WREG]

subwfb 0x10,F,A ; 0x10  [0x10] – [WREG] – borrow flag

sublw 0x10 ; WREG  0x10 – [WREG]

No.1-43
The PIC18 Microcontroller

RISC CISC
(Reduced Instruction Set Computer) (Complex Instruction Set Computer)

Simple instruction set Complex instruction set

Regular and fixed instruction format Irregular instruction format

Simple address modes Complex address modes

Pipelined instruction execution May also pipeline instruction execution

Separated data and program memory Combined data and program memory

Most operations are register to register Most operations can be register to memory

Take shorter time to design and debug Take longer time to design and debug

Provide large number of CPU registers Provide smaller number of CPU registers

No.1-44
The PIC18 Microcontroller

No.1-45
The PIC18 Microcontroller

Chapter 2

ASSEMBLY LANGUAGE PROGRAMMING

No.2-1
The PIC18 Microcontroller

Components of an Assembly Program

- Assembler directives

- Assembly language instructions

- Comments

No.2-2
The PIC18 Microcontroller

Elements of an Assembly Language Statement

- Label

- Mnemonics

- Operands

- Comment

No.2-3
The PIC18 Microcontroller

Label Field

- Must start from column 1 and followed by a tab, a space, a


colon (:), or the end of a line.

- Must start with an alphabetic character or underscore (_).

- May contain alphanumeric characters, underscores and


question marks (?).

- May contain up to 32 characters and is case-sensitive by


default.

wait btfss sum,7 ; wait is a label


_again decf loop_cnt,F ; _again is a label

No.2-4
The PIC18 Microcontroller

Mnemonic Field
- Can be an assembly instruction mnemonic or
assembly directive
- Must begin in column two or greater
- Must be separated from the label by a colon, one or
more spaces or tabs
addlw 0x10 ; addlw is the mnemonic field
loop incf 0x30,W,A ; incf is a mnemonic
false equ 0 ; equ is the mnemonic field

No.2-5
The PIC18 Microcontroller

The Operand Field


- The operand (s) follows the instruction mnemonic.
- Provides the operands for an instruction or arguments for an
assembler directive.
- Must be separated from the mnemonic field by one or more
spaces or tabs.
- Multiple operands are separated by commas.
movff 0x30,0x400 ; “0x30,0x400” is the operand field
decf loop_cnt,F ; label loop_cnt is the operand
true equ 1 ; „1‟ is the argument for equ

No.2-6
The PIC18 Microcontroller

Comment field
- Is optional

- A comment starts with a semicolon.

- All characters to the right of the semicolon are ignored by


the assembler

- Comments provide documentation to the instruction or


assembler directives

- A comment may explain the function of a single statement


or the function of a group of instructions

No.2-7
The PIC18 Microcontroller

too_high decf mean,F,A ; prepare to search in


the lower half

“too_high” is a label

“decf” is a mnemonic

“mean,F,A” is the operand field

“; prepare to search in the lower half” is a comment

No.2-8
The PIC18 Microcontroller

Assembler Directives

- Control directives

- Data directives

- Listing directives

- Macro directives

- Object file directives

No.2-9
The PIC18 Microcontroller

Control Directives

if <expr> ; directives for conditional assembly


else
endif

Example.

if version == 100
movlw D‟10‟
movwf io_1,A
else
movlw D‟26‟
movwf io_2,A
endif

end ; indicates the end of the program

No.2-10
The PIC18 Microcontroller

[<label>] code [<ROM address>]

- Declares the beginning of a section of program code.

reset code 0x00


goto start

#define <name> [<string>] ; defines a text substitution string

#define loop_cnt 30
#define sum3(x,y,z) (x + y + z)
#define seed 103

#undefine <label> ; deletes a substitution string

No.2-11
The PIC18 Microcontroller

#include “include_file” (or #include <include_file>)

#include “lcd_util.asm” ; include the lcd_util.asm file from current directory

#include <p18F8680.inc> ; include the file p18F8680.inc from the installation


; directory of mplab.

radix <default_radix>
- sets the default radix for data expression
- the default radix values are: hex, dec, or oct

radix dec ; set default radix to decimal

No.2-12
The PIC18 Microcontroller

while <expr>
endw
- The lines between while and endw are assembled as long as <expr> is true.

Data Directives
db <expr>,…,<expr> ; define 1 or multiple byte values
db “text_string” ; define a string
dw <expr>,…,<expr> ; define 1 or multiple word constants
dw “text_string” ; define a string
dt <expr>, …, <expr> ; generates a series of retlw instructions
<label> set <expr> ; assign a value (<expr>) to label
<label> equ <expr> ; defines a constant

No.2-13
The PIC18 Microcontroller

Data Directives Examples

led_pat db 0x30,0x80,0x6D,9x40,0x79,0x20,0x33,0x10,0x5B,0x08

msg1 db “Please enter your choice (1/2):”,0

array dw 0x1234,0x2300,0x40,0x33

msg2 dw “The humidity is “,0

results dt 1,2,3,4,5

sum_hi set 0x01

sum_lo set 0x00

TH equ 200

TL equ 30

No.2-14
The PIC18 Microcontroller

What is a macro?

- A group of instructions that are grouped together and assigned a name


- One or multiple arguments can be input to a macro
- By entering the macro name, the same group of instructions can be
duplicated in any place of the program.
- User program is made more readable by using macros
- User becomes more productive by saving the text entering time

Macro Directives

macro
endm
exitm

No.2-15
The PIC18 Microcontroller

Macro Definition Examples

eeritual macro ; macro name is eeritual


movlw 0x55 ; instruction 1
movwf EECON2 ; instruction 2
movlw 0xAA ; instruction 3
movwf EECON2 ; instruction 4
endm

Macro Call Example

eeritual ; this macro call causes the


; assembler to insert
; instruction 1 … instruction 4

No.2-16
The PIC18 Microcontroller

More Macro Examples


sum_of_3 macro arg1, arg2, arg3 ; WREG  [arg1]+[arg2]+[arg3]
movf arg1,W,A
addwf arg2,W,A
addwf arg3,W,A
endm

sum_of_3 0x01, 0x02, 0x03 ; WREG  [0x01] + [0x02] + [0x03]

No.2-17
The PIC18 Microcontroller

Object File Directives

banksel <label>

- generate the instruction sequence to set active data bank to the one where
<label> is located
- <label> must have been defined before the banksel directive is invoked.

bigq set 0x300




banksel bigq ; this directive will cause the assembler to
; insert the instruction movlb 0x03

No.2-18
The PIC18 Microcontroller

Object File Directives (continues)


[<label>] org <expr>

- sets the program origin for subsequent code at the address defined in <expr>.
- <label> will be assigned the value of <expr>.

reset org 0x00


goto start

start …
led_pat org 0x1000 ; led_pat has the value of 0x1000
db 0x7E,0x30,0x6D,0x79,0x33,0x5B,0x5F,0x70,0x7F,0x7B

No.2-19
The PIC18 Microcontroller

Object File Directives (continued)


processor <processor_type>

- Sets the processor type

processor p18F8680 ; set processor type to PIC18F8680

No.2-20
The PIC18 Microcontroller

Program Development Procedure


- Problem definition
- Algorithm development using pseudo code or flowchart
- Converting algorithm into assembly instruction sequence
- Testing program

Algorithm Representation
Step 1

Step 2

Step 3

No.2-21
The PIC18 Microcontroller

Flowchart Symbols

Terminal A

Process Subroutine

Input or
output B

off-page connector
yes
Decision A
on-page connector
no

Figure 2.1 Flowchart symbols used in this book

No.2-22
The PIC18 Microcontroller

Assembly Program Template

org 0x0000 ; program starting address after power on reset


goto start
org 0x08
… ; high-priority interrupt service routine
org 0x18
… ; low-priority interrupt service routine
start …
… ; your program
end

No.2-23
The PIC18 Microcontroller

Program Template Before Interrupts Have Been Covered

org 0x0000 ; program starting address after power on reset


goto start
org 0x08
retfie ; high-priority interrupt service routine
org 0x18
retfie ; low-priority interrupt service routine
start …
… ; your program
end

No.2-24
The PIC18 Microcontroller

Case Issue
- The PIC18 instructions can be written in either uppercase or lowercase.
- MPASM allows the user to include “p18Fxxxx.inc” file to provide register
definitions for the specific processor.
- All special function registers and bits are defined in uppercase.
- The convention followed in this text is: using lowercase for instructions and
directives, using uppercase for special function registers.

No.2-25
The PIC18 Microcontroller

Byte Order Issue


- This issue concerns how bytes are stored for multi-byte numbers.
- The big-endian method stores the most significant byte at the lowest address
and stores the least significant byte in the highest address.
- The little-endian method stores the most significant byte of the number at the
highest address and stores the least significant byte of the number in the lowest
address.
- The 32-bit number 0x12345678 will stored as follows with two methods:

Big-Endian Method Little-Endian Method

address P P+1 P+2 P+3 P P+1 P+2 P+3

value 12 34 56 78 78 56 34 12 (in hex)

Figure 02_t1 Byte order example

No.2-26
The PIC18 Microcontroller

Programs for Simple Arithmetic Operations

Example 2.4 Write a program that adds the three numbers stored in data
registers at 0x20, 0x30, and 0x40 and places the sum in data register at 0x50.

Solution:

Algorithm:

Step 1
Load the number stored at 0x20 into the WREG register.
Step 2
Add the number stored at 0x30 and the number in the WREG register and
leave the sum in the WREG register.
Step 3
Add the number stored at 0x40 and the number in the WREG register and
leave the sum in the WREG register.
Step 4
Store the contents of the WREG register in the memory location at 0x50.

No.2-27
The PIC18 Microcontroller

The program that implements this algorithm is as follows:


#include <p18F8720.inc> ; can be other processor
org 0x00
goto start
org 0x08
retfie
org 0x18
retfie
start movf 0x20,W,A ; WREG  [0x20]
addwf 0x30,W,A ; WREG  [0x20] + [0x30]
addwf 0x40,W,A ; WREG  [0x20] + [0x30] + [0x40]
movwf 0x50,A ; 0x50  sum (in WREG)
end

No.2-28
The PIC18 Microcontroller

Example 2.5 Write a program to add two 24-bit numbers stored at 0x10~0x12 and
0x13~0x15 and leave the sum at 0x20..0x22.
Solution:
#include <p18F8720.inc>
org 0x00
goto start
org 0x08
retfie
org 0x18
retfie
start movf 0x10,W,A ; WREG  [0x10]
addwf 0x13,W,A ; WREG  [0x13] + [0x10]
movwf 0x20,A ; 0x20  [0x10] + [0x13]
movf 0x11,W,A ; WREG  [0x11]
addwfc 0x14,W,A ; WREG  [0x11] + [0x14] + C flag
movwf 0x21,A ; 0x21  [WREG]
movf 0x12,W,A ; WREG  [0x12]
addwfc 0x15,W,A ; WREG  [0x12] + [0x15] + C flag
movwf 0x22,A ; 0x22  [WREG]
end

No.2-29
The PIC18 Microcontroller

Example 2.6 Write a program to subtract 5 from memory locations 0x10 to


0x13.
Solution:
Algorithm:
Step 1. Place 5 in the WREG register.
Step 2. Subtract WREG from the memory location 0x10 and leave the difference
in the memory location 0x10.
Step 3. Subtract WREG from the memory location 0x11 and leave the difference
in the memory location 0x11.
Step 4. Subtract WREG from the memory location 0x12 and leave the difference
in the memory location 0x12.
Step 5. Subtract WREG from the memory location 0x13 and leave the difference
in the memory location 0x13.

No.2-30
The PIC18 Microcontroller

The Program for Example 2.6

#include <p18F8720.inc>
org 0x00
goto start
org 0x08
retfie
org 0x18
retfie
start movlw 0x05 ; WREG  0x05
subwf 0x10,F,A ; 0x10  [0x10] – 0x05
subwf 0x11,F,A ; 0x11  [0x11] – 0x05
subwf 0x12,F,A ; 0x12  [0x12] – 0x05
subwf 0x13,F,A ; 0x13  [0x13] – 0x05
end

No.2-31
The PIC18 Microcontroller

Example 2.7 Write a program that subtracts the number stored at 0x20..0x23
from the number stored at 0x10..0x13 and leaves the difference at 0x30..0x33.
Solution:
Start

WREG  [0x20]

0x30  [0x10] - [WREG]

WREG  [0x21]
Three-operand
0x31  [0x11] - [WREG] - B
subtraction
WREG  [0x22]
Three-operand
0x32  [0x12] - [WREG] - B subtraction

WREG  [0x23]
Three-operand
0x33  [0x13] - [WREG] - B subtraction

Stop

Figure 2.2 Logic flow of Example 2.7

No.2-32
The PIC18 Microcontroller

The program for Example 2.7


#include <p18F8720.inc>
org 0x00
goto start
org 0x08
retfie
org 0x18
retfie
start movf 0x20, W, A ; 0x30  [0x10] – [0x20]
subwf 0x10, W, A ; “
movwf 0x30, A ; “
movf 0x21, W, A ; 0x31  [0x11] – [0x21]
subwfb 0x11, W, A ; “
movwf 0x31, A ; “
movf 0x22, W, A ; 0x32  [0x12] – [0x22]
subwfb 0x12, W, A ; “
movwf 0x32, A ; “
movf 0x23, W, A ; 0x33  [0x13] – [0x23]
subwfb 0x13, W, A ; “
movwf 0x33, A ; “
end

No.2-33
The PIC18 Microcontroller

Binary Coded Decimal (BCD) Addition


- Decimal digits are encoded using 4 bits
- Two decimal digits are packed into a byte in memory
- After each addition, one needs to use the daw instruction to adjust and correct the
result.
Let data register 0x24 and 0x25 holds BCD numbers, the following instruction sequence
adds these two BCD numbers and saves the sum in 0x30
movf 0x24,W,A
addwf 0x25,W,A
daw
movwf 0x30,A

No.2-34
The PIC18 Microcontroller

Example 2.9 Write an instruction sequence that adds the decimal numbers stored at
0x10...0x13 and 0x14...0x17 and stores the sum in 0x20..0x23.
Solution:
#include <p18F8720.inc>

start movf 0x10,W ; add the least significant byte
addwf 0x14,W ; “
daw ; adjust for valid BCD
movwf 0x20 ; save in the destination
movf 0x11 ; add the second to least significant byte
addwfc 0x15,W ; “
daw ; “
movwf 0x21 ; “
movf 0x12 ; add the second to most significant byte
addwfc 0x16 ; “
daw ; “
movwf 0x22 ; “
movf 0x13 ; add the most significant byte
addwfc 0x17 ; “
daw ; “
movwf 0x23 ; “
end

No.2-35
The PIC18 Microcontroller

Multiplication
- PIC18 has two instructions for 8-bit multiplication: mulwf f and mullw k.
- The products are stored in the PRODH:PRODL register pair.
- The multiplication of numbers larger than 8 bits must be synthesized.
- The following instruction sequence performs 8-bit multiplication operation:

movf 0x10,W,A
mulwf 0x11,A
movff PRODH,0x21 ; upper byte of the product
movff PRODL,0x20 ; lower byte of the product

- To perform multiplication operation on numbers longer than 8 bits, the operand must be
broken down into 8-bit chunks. Multiple 8-bit multiplications are performed and the
resultant partial products are aligned properly and added together.
- Two 16-bit numbers P and Q can be broken down into as follows:

P = PHPL
Q = QHQL

No.2-36
The PIC18 Microcontroller

Adding the Partial Products

8-bit 8-bit 8-bit 8-bit

upper byte lower byte partial product P LQL

upper byte lower byte partial product P HQL

upper byte lower byte partial product P LQH

upper byte lower byte partial product P HQH

Address R+3 R+2 R+1 R Final product P × Q


msb lsb

Note: msb stands for most significant byte and lsb stands for least significant byte

Figure 2.4 16-bit by 16-bit multiplication

No.2-37
The PIC18 Microcontroller

Instruction sequence to multiply two numbers that are stored at N:N+1 and M:M+1:

movf M+1,W,A
mulwf N+1,A ; compute MH  NH
movff PRODL,PR+2
movff PRODH,PR+3
movf M,W,A ; compute ML  NL
mulwf N,A
movff PRODL,PR
movff PRODH,PR+1
movf M,W,A
mulwf N+1,A ; compute ML  NH
movf PRODL,W,A ; add ML  NH to PR
addwf PR+1,F,A ; "
movf PRODH,W,A ; "
addwfc PR+2,F,A ; "
movlw 0 ; "
addwfc PR+3,F,A ; add carry
movf M+1,W,A
mulwf N,A ; compute MH  NL
movf PRODL,W,A ; add MH  NL to PR

No.2-38
The PIC18 Microcontroller

addwf PR+1,F,A ; "


movf PRODH,W,A ; "
addwfc PR+2,F,A ; "
movlw 0 ; "
addwfc PR+3,F,A ; add carry
nop
end

MNxPQS3S2S1S0

No.2-39
The PIC18 Microcontroller

Program Loops

- Enable the microcontroller to perform repetitive operations.


- A loop may be executed a finite number of times or infinite number of
times.

Program Loop Construct

1. Do S forever

Figure 2.5 An infinite loop

No.2-40
The PIC18 Microcontroller

2. for i = n1 to n2 Do S or for i = n2 downto n1 do S

i  i1 i  i2

no no
i  i2 ? i  i1 ?

yes yes

S S

ii+1 i  i- 1

(a) For i = i1 to i2 Do S (b) For i = i2 downto i1 Do S

Figure 2.6 A For-loop looping construct

No.2-41
The PIC18 Microcontroller

3. while C do S

true
C S

false

Figure 2.7 The While ... Do looping construct

4. repeat S until C
initialize C

true
C

fals
e
Figure 2.8 The Repeat ... Until looping construct

No.2-42
The PIC18 Microcontroller

Changing the Program Counter

- Microcontroller executes instruction sequentially in normal condition.

- PIC18 has a 21-bit program counter (PC) which is divided into three

registers: PCL, PCH, and PCU.

- PCL can be accessed directly. However, PCH and PCU are not directly

accessible.

- One can accessed the values of PCH and PCU indirectly by accessing

the PCLATH and PCLATU.

No.2-43
The PIC18 Microcontroller

Changing the Program Counter (Continued)

- Reading the PCL will cause the values of PCH and PCU to be

copied into the PCLATH and PCLATU.

- Writing the PCL will cause the values of PCLATCH and PCLATU

to be written into the PCH and PCU.

- In normal program execution, the PC value is incremented by either

2 or 4.

- To implement a program loop, the processor needs to change the PC

value by a value other than 2 or 4.

No.2-44
The PIC18 Microcontroller

Instructions for Changing Program Counter


BRA n: jump to the instruction with address equals to PC+2+n

BCC n: jump to the instruction with address equals to PC+2+n if the condition code
CC is true.
CC can be any one of the following:
C: C flag is set to 1
NC: C flag is 0
N: N flag is set to 1 which indicates that the previous operation result was negative
NN: N flag is 0 which indicates non-negative condition
NOV: V flag is 0 which indicates there is no overflow condition
NZ: Z flag is 0 which indicates the previous operation result was not zero
OV: V flag is 1 which indicates the previous operation caused an overflow
Z: Z flag is 1 which indicates the previous operation result was zero

goto n:jump to address represented by n

The destination of a branch or goto instruction is normally specified by a label.

No.2-45
The PIC18 Microcontroller

Instructions for Changing Program Counter (continued)


cpfseq f,a ; compare register f with WREG, skip if equal
cpfsgt f,a ; compare register f with WREG, skip if greater than
cpfslt f,a ; compare register f with WREG, skip if less than
decfsz f,d,a ; decrement f, skip if 0
dcfsnz f,d,a ; decrement f, skip if not 0
incfsz f,d,a ; increment f, skip if 0
infsnz f,d,a ; increment f, skip if not 0
tstfsz f,a ; test f, skip if 0
btfsc f,b,a ; test bit b of register f, skip if 0
btfss f,b,a ; test bit b of register f, skip if 1

Instructions for changing register value by 1

incf f,d,a
decf f,d,a

No.2-46
The PIC18 Microcontroller

Examples of Program loops that execute n times

Example 1

i_cnt equ PRODL ; use PRODL as loop count


clrf i_cnt,A
i_loop …
… ; i_cnt is incremented in the loop
movlw n
cpfseq i_cnt,A ; compare i_cnt with WREG and skip if equal
goto i_loop ; executed when i_cnt  loop limit

No.2-47
The PIC18 Microcontroller

Example 2

n equ 20 ; n has the value of 20


lp_cnt set 0x10 ; assign file register 0x10 to lp_cnt

movlw n
movwf lp_cnt ; prepare to repeat the loop for n times
loop … ; program loop
… ; “
decfsz lp_cnt,F,A ; decrement lp_cnt and skip if equal to 0
goto loop ; executed if lp_cnt  0

No.2-48
The PIC18 Microcontroller

Example 2.12 Write a program to compute 1 + 2 + 3 + … + n and save the sum at 0x00
and 0x01.

Solution:
1. Program logic
Start

i1
sum 0

yes
i > n?
no

sum  sum + i

i  i+ 1

Stop

Figure 2.12 Flowchar for computing 1+2+...+n

No.2-49
The PIC18 Microcontroller

Program of Example 2.12 (in for i = n1 to n2 construct)

#include <p18F8720.inc>
radix dec
n equ D'50'
sum_hi set 0x01 ; high byte of sum
sum_lo set 0x00 ; low byte of sum
i set 0x02 ; loop index i
org 0x00 ; reset vector
goto start
org 0x08
retfie
org 0x18
retfie
start clrf sum_hi,A ; initialize sum to 0
clrf sum_lo,A ; "
clrf i,A ; initialize i to 0
incf i,F,A ; i starts from 1
sum_lp movlw n ; place n in WREG
cpfsgt i,A ; compare i with n and skip if i > n
bra add_lp ; perform addition when i  50
bra exit_sum ; it is done when i > 50

No.2-50
The PIC18 Microcontroller

add_lp movf i,W,A ; place i in WREG


addwf sum_lo,F,A ; add i to sum_lo
movlw 0
addwfc sum_hi,F,A ; add carry to sum_hi
incf i,F,A ; increment loop index i by 1
bra sum_lp
exit_sum nop
bra exit_sum
end

No.2-51
The PIC18 Microcontroller

Start
Example 2.13
Write a program
arr_max  arr[0]
to find the i1
largest element
stored in the no
array that is i  n?
yes
stored in data
memory no
arr[i] > arr_max?
locations from
0x10 to 0x5F. yes

arr_max  arr[i]

i  i+ 1

Stop

Figure 2.13 Flowchart for finding the maximum array element

No.2-52
The PIC18 Microcontroller

Program for Example 2.13

arr_max equ 0x00


i equ 0x01
n equ D'80' ; the array count
#include <p18F8720.inc>
org 0x00
goto start
org 0x08
retfie
org 0x18
retfie
start movff 0x10,arr_max ; set arr[0] as the initial array max
lfsr FSR0,0x11 ; place address of arr[1] in FSR0
clrf i,A ; initialize loop count i to 0
again movlw n-1 ; number of comparisons to be made
; the next instruction implements the condition C (i = n)
cpfslt i,A ; skip if i < n-1
bra done ; all comparisons have been done
; the following 7 instructions update the array max
movf POSTINC0,W

No.2-53
The PIC18 Microcontroller

cpfsgt arr_max,A ; is arr_max > arr[i]?


bra replace ; no
bra next_i ; yes
replace movwf arr_max,A ; update the array max
next_i incf i,F,A
goto again
done nop
end

No.2-54
The PIC18 Microcontroller

Reading and Writing Data in Program Memory

- PIC18 provides TBLRD and TBLWT instructions for accessing data in


program memory.
- The operations of reading data from and writing data into program
memory are shown in Figure 2.14 and 2.15.

Program memory
Table pointer
Table latch
TBLPTRU TBLPTRH TBLPTRL
TABLAT

Figure 2.14 Table read operation (Redraw with permission of Microchip)

No.2-55
The PIC18 Microcontroller

Program memory
Table pointer
Table latch
TBLPTRU TBLPTRH TBLPTRL
TABLAT

Figure 2.15 Table write operation (redraw with permission of Microchip)

The table pointer consists of three registers:

• TBLPTRU (6 bits)
• TBLPTRH (8 bits)
• TBLPTRL (8 bits)

No.2-56
The PIC18 Microcontroller

Versions of table read and table write instructions

Table 2.11 PIC18 MCU table read and write instructions


Mnemonic, Status
Description 16-bit instruction word
operator affected
TBLRD* Table read 0000 0000 0000 1000 none
TBLRD*+ Table read with post-increment 0000 0000 0000 1001 none
TBLRD*- Table read with post-decrement 0000 0000 0000 1010 none
TBLRD+* Table read with pre-increment 0000 0000 0000 1011 none
TBLWT* Table write 0000 0000 0000 1100 none
TBLWT*+ Table write with post-increment 0000 0000 0000 1101 none
TBLWT*- Table write with post-decrement 0000 0000 0000 1110 none
TBLWT+* Table write with pre-increment 0000 0000 0000 1111 none

No.2-57
The PIC18 Microcontroller

Reading the program memory location prog_loc involves two steps:

Step 1. Place the address of prog_loc in TBLPTR registers

movlw upper prog_loc


movwf TBLPTRU,A
movlw high prog_loc
movwf TBLPTRH,A
movlw low prog_loc
movwf TBLPTRL,A

Step 2. Perform a TBLRD instruction.

tblrd

The TBLPTR registers can be incremented or decremented before or after the


read or write operations as shown in Table 2.11.

No.2-58
The PIC18 Microcontroller

Logic Instructions

Table 2.12 PIC18 MCU logic instructions


Mnemonic,
operator
Description

andwf f,d,a AND WREG with f


comf f,d,a Complement f
iorwf f,d,a Inclusive OR WREG with f
negf f,a Negate f
xorwf f,d,a Exclusive OR WREG with f
andlw k AND literal with WREG
iolw k Inclusive OR literal with WREG
xorlw k Exclusive OR literal with WREG

Applications of Logic Instructions

1. Set a few bits in a byte


2. Clear certain bits in a byte
3. Toggle certain bits in a byte

No.2-59
The PIC18 Microcontroller

To set bits 7, 6, and 0 of PORTA to 1

movlw B‟11000001‟
iorwf PORTA,F,A

To clear bits 4, 2, and 1 of PORTB to 0

movlw B‟11101001
andwf PORTB,F,A

To toggle bits odd bits of PORTC

movlw B‟10101010‟
xorwf PORTC

No.2-60
The PIC18 Microcontroller

Example 2.16 Write a program to find out the number of elements in an array of 8-bit
elements that are a multiple of 8. The array is in the program memory.
Solution:
Start

1. A number must have the iN


lowest 3 bits equal to 0 to count  0
be a multiple of 8
2. Use the Repeat S until C prod  array[i] AND 0x07
looping construct
no
prod  0?

yes
count  count + 1

ii-1

no
i = 0?

yes
Stop

Figure 2.16 Flowchart for Example 2.16

No.2-61
The PIC18 Microcontroller

#include <p18F8720.inc>
ilimit equ 0x20 ; loop index limit
count set 0x00
ii set 0x01 ; loop index
mask equ 0x07 ; used to masked upper five bits
org 0x00
goto start
… ; interrupt service routines
start clrf count,A
movlw ilimit
movwf ii ; initialize ii to ilimit
movlw upper array
movwf TBLPTRU,A
movlw high array
movwf TBLPTRH,A
movlw low array
movwf TBLPTRL,A
movlw mask
i_loop tblrd*+ ; read an array element into TABLAT
andwf TABLAT,F,A
bnz next ; branch if not a multiple of 8

No.2-62
The PIC18 Microcontroller

incf count,F,A ; is a multiple of 8


next decfsz ii,F,A ; decrement loop count
bra i_loop
nop
array db 0x00,0x01,0x30,0x03,0x04,0x05,0x06,0x07,0x08,0x09
db 0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13
db 0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D
db 0x1E,0x1F
end

No.2-63
The PIC18 Microcontroller

Using Program Loops to Create Time Delays

- The PIC18 uses a crystal oscillator or a RC circuit to generate the clock signal
needed to control its operation.
- The instruction execution time is measured by using the instruction cycle
clock.
- One instruction cycle is equal to four times the crystal oscillator clock period.
- Select an appropriate instruction that will take a multiple of 10 or 20
instruction cycles to execute.
- A desirable time delay is created by repeating the chosen instruction sequence
for certain number of times.

No.2-64
The PIC18 Microcontroller

A Macro to Repeat An Instruction for Certain Number of Times

dup_nop macro kk ; duplicate the nop instruction kk times


variable i
i=0
while i < kk
nop ; takes 1 instruction cycle time
i += 1
endw
endm

To create 0.5 ms time delay with 40 MHz crystal oscillator

radix dec
loop_cnt equ PRODL
movlw 250
movwf loop_cnt,A
again dup_nop 17 ; insert 17 nop instructions
decfsz loop_cnt,F,A ; 1 instruction cycle
bra again ; 2 instruction cycles

No.2-65
The PIC18 Microcontroller

Example 2.18 Write a program to create a time delay of 100 ms for the demo
board that uses a 40 MHz crystal oscillator to operate.
Solution: Repeat the previous instruction sequence for 200 times can create a
100 ms time delay.

radix dec
lp_cnt1 equ 0x21
lp_cnt2 equ 0x22
movlw 200
movwf lp_cnt1,A
loop1 movlw 250
movwf lp_cnt2,A
loop2 dup_nop 17 ; 17 instruction cycles
decfsz lp_cnt2,F,A ; 1 instruction cycle (2 when [lp_cnt1] = 0)
bra loop2 ; 2 instruction cycles
decfsz lp_cnt1,F,A
bra loop1

No.2-66
The PIC18 Microcontroller

Rotate Instructions

rlcf f, d, a ; rotate left f through carry

7 6 5 4 3 2 1 0 C

Figure 2.17 Operation performed by the rlcf f,d,a instruction

rlncf f, d, a ; rotate left f ( not trough carry)

7 6 5 4 3 2 1 0

Figure 2.18 Operation performed by the rlncf f,d,a instruction

No.2-67
The PIC18 Microcontroller

rrcf f, d, a ; rotate right f through carry

C 7 6 5 4 3 2 1 0

Figure 2.19 Operation performed by the rrcf f,d,a instruction

rrncf f, d, a ; rotate right f (not through carry)

7 6 5 4 3 2 1 0

Figure 2.20 Operation performed by the rrncf f,d,a instruction

No.2-68
The PIC18 Microcontroller

Example 2.19 Compute the new values of the data register 0x10 and the C flag after the
execution of the rlcf 0x10,F,A instruction. [0x10] = 0xA9, C = 1
Solution:

The result is
0 1 0 1 0 1 0 0 1
Original value New value
[0x10] = 1010 1001 [0x10] = 01010010
1 0 1 0 1 0 0 1 0 C=0 C=1

Figure 2.21 Operation of the RLCF 0x10,F,A instruction

Example 2.20 Compute the new values of the data register 0x10 and the C flag after the
execution of the rrcf 0x10,F,A instruction. [0x10] = 0xC7, C = 1
Solution:
The result is

1 1 0 0 0 1 1 1 1
Original value New value
[0x10] = 1100 0111 [0x10] = 1110 0011
1 1 1 0 0 0 1 1 1 C=1 C=1

Figure 2.22 Operation of the RRCF 0x10,F,A instruction

No.2-69
The PIC18 Microcontroller

Example 2.21 Compute the new values of the data memory location 0x10 after the
execution of the rrncf 0x10,F,A instruction and the rlncf 0x10,F,A instruction,
respectively. [0x10] = 0x6E
Solution:

The result is
0 1 1 0 1 1 1 0
original value new value
[0x10] = 0110 1110 [0x10] = 0011 0111
0 0 1 1 0 1 1 1

Figure 2.23 Operation performed by the rrncf 0x10, F, A instruction

The result is
0 1 1 0 1 1 1 0
Before After
[0x10] = 0110 1110 [0x10] = 1101 1100
1 1 0 1 1 1 0 0

Figure 2.24 Operation performed by the rlncf 0x10, F, A instruction

No.2-70
The PIC18 Microcontroller

Bit Operation Instructions

bcf f, b, a ; clear bit b of register f


bsf f, b, a ; set bit b of register f
btg f, b, a ; toggle bit b of register f

Examples

1. bcf STATUS,C,A ; clear the C flag of the STATUS register


2. bsf sign,0,A ; set the bit 0 of register sign to 1
3. btg sign,0,A ; toggle bit 0 of register sign (0 to 1 or 1 to 0)

No.2-71
The PIC18 Microcontroller

Perform Multiplication by Shift Left Operations

Multiply the 3-byte number store at 0x00…0x02 by 8

movlw 0x03 ; set loop count to 3


loop bcf STATUS, C, A; clear the C flag
rlcf 0x00, F, A ; shift left one place
rlcf 0x01, F, A ; “
rlcf 0x02, F, A ; “
decfsz WREG,W,A ; have we shifted left three places yet?
goto loop ; not yet, continue

No.2-72
The PIC18 Microcontroller

Perform Division by Shifting to the Right

Divide the 3-byte number stored at 0x10…0x12

movlw 0x04 ; set loop count to 4


loop bcf STATUS, C, A ; shift the number to the right 1 place
rrcf 0x12, F, A ; “
rrcf 0x11, F, A ; “
rrcf 0x10, F, A ; “
decfsz WREG,W,A ; have we shifted right four places yet?
goto loop ; not yet, continue

No.2-73
The PIC18 Microcontroller

Chapter 5

C Language and the Use of PIC18


C Compiler

No.5-1
The PIC18 Microcontroller

Introduction to C Language

- C language is gradually replacing assembly language in many embedded applications.


- C language allows the user to work on the program logic at a higher level than the
assembly language.
- A C program consists of functions and variables.
- A function contains statements that specify the operations to be performed.
- A C statement could be declaration, assignment, function call, control, and null.
- A simple C program is as follows:

#include <stdio.h>
main (void)
{
int a, b, c;
a = 3;
b = 5;
c = a + b;
printf(― a + b = %d \n‖, c);
return 0;
}

No.5-2
The PIC18 Microcontroller

Types, Operators, and Expressions

- Variables and constants are the basic objects in C.


- Variables must be declared before they can be used.
- Both the name and the type of the variable must be included in the declaration.
- A variable name may start with a letter (A through Z or a through z) or underscore
character followed by zero or more letters, digits, or underscore characters.
- The variable name is case-sensitive.

Basic Data Types in C

1. void: used most commonly with functions


2. char: can hold a single byte of data
3. int: integer. The size of type int is 16 bits for PIC18.
4. float: 32-bit, single-precision, floating-point number
5. double: 64-bit double-precision, floating-point number (32-bit for PIC18)

- The PIC18 C compiler also supports the 24-bit short long integer data type.
- Several modifiers can be applied to integer type including short, long, and unsigned.
- Int and char types are signed by default.

No.5-3
The PIC18 Microcontroller

Variable Declarations

A declaration specifies a type and contains a list of one or more variables of that type.

int i, j, k;
char cx, cy;

A variable may also be initialized when it is declared:

int i = 0;
char echo = ‗y‘; /* ASCII of letter y is assigned */

Constants

1. integer
2. character
3. floating-point:
4. character: enclosed by single quotes
5. string: enclosed by double quotes

No.5-4
The PIC18 Microcontroller

Radix of Numbers

1. decimal: default radix


2. octal: add prefix 0. e.g., 04321
3. hexadecimal: add prefix 0x. e.g., 0x3A4B

Arithmetic Operators

+, -, *, /, %, ++, --

Bitwise Operators

& AND PORTD = PORTD & 0x7F;


| OR PORTD = PORTD | 0x80;
^ XOR PORTD = PORTD ^ 0x0F;
~ NOT xyz = ~xyz;
>> right shift abc = abc >> 2;
<< left shift abc = abc << 4;

No.5-5
The PIC18 Microcontroller

Arithmetic and logic operators are often used together with the = operator.

For example,

abc = abc + 3; can be written as abc += 3;


abc = abc >> 4; can be written as abc >>= 4;
xy = xy & 0x7F; can be written as xy &= 0x7F;

Relational and Logical Operators

== equal to (two ‗=‘ characters)


!= not equal to
> greater than
>= greater than or equal to
< less than
<= less than or equal to
&& and
|| or
! not (one‘s complement)

No.5-6
The PIC18 Microcontroller

In C language,

- A statement is terminated by a semicolon.


- A compound statement is a group of statements enclosed by braces { and }.
- A compound statement is not terminated by a semicolon.
- A control-statement specify the order in which computations are performed.

Control Flow Statements

If statement
if (expression) if (a > b)
statement; PORTA |= 0x48;

If-else Statement
if (expression) if (ax == 0)
statement1; abc = 3;
else else
statement2; abc = 5;

if-else statement can be replaced by abc = (ax == 0)? 3:5;


the ?: operator.

No.5-7
The PIC18 Microcontroller

Multiway Conditional Statement


if (expression1) if (k == 1)
statement1; return 2;
else if (expression2) else if (k == 4)
statement2; return 5;
else if (expression3) else
statement3; return 0;

else
statementn;

Switch Statement
switch (expression) { switch (i) {
case const_expr1: case 1: set_temp (50);
statement1; break;
break; case 2: set_pressure (30);
case const_expr2: break;
statement2; …
break; default:
… set_temp (20);
default: set_pressure(28);
statementn; break;
} }

No.5-8
The PIC18 Microcontroller

for-loop Statement

for (expr1; expr2; expr3)


statement;
where,
expr1 & expr3 are assignments or function calls
expr2 is a relational statement

Examples
count1 = 0;
for (i = 0; i < 30; i++)
if (arr[i] & 0x03) /* is arr[i] dividable by 4? */
count1 ++;

count2 = 0;
for (j = 30; j > 0; j--)
if ((arr[i] > 5) && (arr[j] < 20))
count2++;

No.5-9
The PIC18 Microcontroller

while statement
while (!(ADCON1 & 0x80)); /* null statement */
while (expression)
statement; while (1) { /* infinite loop */

}

do-while statement
i = sum = 0;
do do
statementx sum = sum + i;
while (expressiony) i++;
while (i < 50);
goto statement
if (temperature > 100)
goto label;
goto alarm;

The use of goto statement
is not considered a good
alarm:
programming style.
set_alarm(); /* call a function to
turn on alarm; */

No.5-10
The PIC18 Microcontroller

Input and Output

- Not part of C language.


- ANSI standard defines a set of library functions for input and output that must be
supported by the C compiler. Among them

The getchar ( ) function returns a character when it is called. The character is received
from the serial communication port.

The putchar (int) outputs a character on the standard output device.

The puts (const char *s) function outputs the string pointed to by s to the standard
output device.

The printf (formatting string, arg1, arg2, …, argn) function outputs the arguments to
the standard output device using the supplied formatting string).

The Microchip PIC18 C compiler does not support the printf() function.

No.5-11
The PIC18 Microcontroller

Functions and Program Structure

- Every C program consists of one or more functions.


- The definition of a function cannot be embedded within another function.
- Values can be passed to a function through arguments.
- A function may return a value to the caller using the return statement.
- The syntax of a function definition is as follows:

return_type function_name (declarations of arguments)


{
declarations and statements
}

The following function converts a lowercase letter to uppercase:

char lower2upper (char cx)


{
if (cx >= ‗a‘ && cx <= ‗z‘) return (cx – (‗a‘ – ‗A‘));
}

No.5-12
The PIC18 Microcontroller

- A function cannot be called before it has been defined.


- This dilemma is solved by using function prototype statement.
- The syntax for a function prototype statement is

return_type function_name (declarations of arguments);

Example 5.1 Write a C function to compute the average of an array of integers. Both the
starting address of the array and the array count are passed to this function.
Solution:

int array_ave (int arr[ ], int ar_cnt)


{
short long int sum;
int i;
sum = 0;
for (i = 0; i < ar_cnt; i++)
sum += arr[i];
return (sum / ar_cnt);
}

No.5-13
The PIC18 Microcontroller

Example 5.2 Write a function to compute the square root of a 32-bit number using the
successive approximation method.
Solution:
unsigned sq_root (unsigned long int xz)
{
unsigned int sar, guess_mask, rest_mask;
unsigned int i;
sar = 0; /* successive approximation register is initialized to 0 */
guess_mask = 0x8000; /* this mask is used to guess the ith bit to be 1 */
i = 16;
do {
rest_mask = ~guess_mask; /* rest_mask is used to cancel the incorrect guess */
sar |= guess_mask; /* guess the ith bit to be 1 */
if (sar * sar > xz)
sar &= rest_mask; // change the bit to 0
guess_mask >> 1;
i--;
} while (i > 0);
if ((xy - sar * sar) < ((sar + 1)*(sar + 1) – xy))
return sar;
else return (sar + 1);
}

No.5-14
The PIC18 Microcontroller

Example 5.3 Write a function to test whether an integer is a prime number.


Solution:

unsigned sq_root (unsigned long int xz);

/* this function returns a 1 if ka is prime. Otherwise, it returns a 0. */


char test_prime (unsigned long int ka)
{
unsigned int i, limit;
if (ka == 1) return 0;
else if (k2 == 2) return 1;
limit = sq_root (ka); /* find the square root of ka */
for (i = 2; i <= limit; i++)
if ((a % i) == 0) return 0;
return 1;
}

No.5-15
The PIC18 Microcontroller

Example 5.4 Write a program to find out the number of prime numbers between 1000 and
10000.
Solution:

#include <stdio.h>
char test_prime (unsigned int a); /* prototype declaration of test_prime () */
unsigned sq_root (unsigned long int xz); /* prototype of sq_root () */

main ( )
{
unsigned int i, prime_count;
prime_count = 0;
for (i = 1000; i <= 10000; i++) {
if (test_prime(i))
prime_count ++;
}
printf(―\n The total prime numbers between 1000 and 10000 is %d\n‖, prime_count);
}
/* include the functions sq_root () and test_prime () here */

No.5-16
The PIC18 Microcontroller

Pointers and Addresses

- A pointer is a variable that holds the address of a variable.


- Pointers can be used to pass information back and forth between a function and its
calling point.
- Pointers provide a way to return multiple data items from a function via its arguments.
- The syntax for declaring a pointer type:

type_name *pointer_name;

- One can use the & operator to assign the address of a variable to a pointer variable.
- One can use the * operator to access the value pointed to by a pointer variable.

For example,
int *ax;
char *cp;
int x, y;

ax = &x; /* assign the address of x to ax */


y = *ax; /* y gets the value of x */

No.5-17
The PIC18 Microcontroller

Example 5.5 Write the bubble sort function to sort an array of integers.
Solution: A swap function is needed by the bubble sort.

void swap (int *, int *);


void bubble (int a[], int n) /* n is the array count */
{
int i, j;
for (i = 0; i < n – 1; i++)
for (j = 0; j < n – (i+1); j++)
if (a[j ] > a[j+1])
swap (&a[j], &a[j+1]);
}
void swap (int *px, int *py)
{
int temp;
temp = *px;
*px = *py;
*py = temp;
}

No.5-18
The PIC18 Microcontroller

Arrays
- An array holds one or multiple data items of common characteristics.
- Each array element is referred to by specifying the array name followed by one or
more subscripts, with each subscript enclosed in brackets.
- Each subscript must be a nonnegative number.
- The number of subscripts determines the dimensionality of the array.
- High dimensional arrays are not used very often in 8- and 16-bit microcontroller
applications.
- A one-dimensional array can be expressed as
data_type array_name [expression];

- A two-dimensional array is defined as


data_type array_name [expr1][expr2];

- An array can be initialized when it is defined:

unsigned char led_pattern [10] =


{0x7E, 0x30, 0x6D, 0x79, 0x33, 0x5B, 0x5F, 0x70, 0x7F, 0x7B};

char prompt [24] = ―Please enter an integer:‖;

No.5-19
The PIC18 Microcontroller

Passing Arrays to a Function


- An array name can be used as an argument to a function.
- To pass an array to a function, the array name must appear by itself, without brackets
or subscripts, as an actual argument within a function call.
- An example is as follows:

int average (int n, int arr[]);


void main ( )
{
int n, avg; /* variable declaration */
int arr[50]; /* array definition */

avg = average(n, arr); /* function call */

}
int average (int k, int brr[]) /* function definition */
{

}

No.5-20
The PIC18 Microcontroller

Structures
- A structure is a group of related variables that can be accessed through a common name.
- Each item within a structure has its own data type.
- The syntax of a structure declaration:
struct struct_name { /* struct_name is optional */
type1 member1;
type2 member2;

}
- The struct_name is optional, if it exists, defines a structure tag.
- A struct declaration defines a type.
- The right brace terminates the list of members and may be followed by a list of variables.
- A structure definition not followed by a list of variables does not reserve any space.
- An example,

struct catalog_tag {
char author [40];
char title [40];
char pub [40];
unsigned int date;
unsigned char rev;
} card;

No.5-21
The PIC18 Microcontroller

Union
- May hold objects of different types and sizes with the compiler keeping track of size
and alignment requirements.
- Allow one to manipulate different kinds of data in a single area of storage without
embedding any machine dependent information in the program.
- Syntax of the union is

union union_name {
type-name1 element1;
type-name2 element2;

type-namen elementn;
};

- The union_name field is optional, when exists, is called a union tag.


- Union variables can be declared at the same time when a union type is declared.

No.5-23
The PIC18 Microcontroller

An example of union

union u_tag {
int i;
char c[4];
} temp;

The access of union members is similar to structure type:

1. union-name.member
2. union-pointermember

No.5-24
The PIC18 Microcontroller

Automatic/External/Static/Volatile

- A variable defined inside a function is an internal variable.


- Internal variables are automatic. They come into existence when a function is entered
and disappear when it is left.
- External variables are defined outside of any function and may be accessible by many
functions.
- An internal variable can be made into static by adding the keyword static when it is
declared.
- A static variable will maintain its value over function calls.
- When a variable is declared static outside all the functions in a file, its scope is limited
to the file in which it is declared.
- A volatile variable has a value that can be changed by something other than the user
code.
- I/O ports and timer registers are examples of volatile variables.
- Compiler makes no assumption on the value of a volatile variable and won‘t perform
any optimization on the volatile variable.

No.5-25
The PIC18 Microcontroller

Project Build Process of the Microchip PIC18 C Compiler

1. Source code entering and editing


2. Object code generation
3. Library files creation and maintenance (optional). The user can optionally put
related reusable function modules in a single library file.
4. Program linking and executable code generation
5. The whole process is shown in Figure 5.2.
6. The file output.hex can be downloaded into the target hardware for execution.
7. The fle output.cod provides information needed in debugging process.
8. The file output.lst contains the source code side by side with final binary code and
line numbers.
9. The file output.out is an intermediate file used by the linker to generate cod file,
hex file, and listing file.
10. The file output.map shows the memory layout after linking.

No.5-26
The PIC18 Microcontroller

source legend
input.asm input1.c input2.c file
files

program
mpasm.exe mcc18.exe mcc18.exe
cpp18.exe cpp18.exe

object input.o input1.o input3.o input2.o


files

mplib.exe

library lib1.lib script.lkr


linker script
files

mplink.exe
_mplink.exe mp2cod.exe mp2hex.exe

output
output.map output.out output.hex
files

output.lst output.cod

Figure 5.2 Project build process (reprint with permission of Microchip)

No.5-27
The PIC18 Microcontroller

The MPLINK Linker Functions

1. Locating code and data


2. Resolving addresses
3. Generating an executable
4. Configuring stack size and location
5. Identifying address conflicts
6. Providing symbolic debug information

A linker file (with a suffix .lkr to the file name) must be added to the project to provide
the above function.

The linker file without debug support for the PIC18F8720 is shown in Figure 5.3a. The
linker file with debug support for the PIC18F8720 is shown in Figure 5.3b.

No.5-28
The PIC18 Microcontroller
// Sample linker command file for 18F8720
// $Id: 18f8720.lkr,v 1.4 2002/08/22 20:53:50 sealep Exp $
LIBPATH .
FILES c018i.o
FILES clib.lib
FILES p18f8720.lib

CODEPAGE NAME=vectors START=0x0 END=0x29 PROTECTED


CODEPAGE NAME=page START=0x2A END=0x1FFFFF
CODEPAGE NAME=idlocs START=0x200000 END=0x200007 PROTECTED
CODEPAGE NAME=config START=0x300000 END=0x30000D PROTECTED
CODEPAGE NAME=devid START=0x3FFFFE END=0x3FFFFF PROTECTED
CODEPAGE NAME=eedata START=0xF00000 END=0xF000FF PROTECTED
ACCESSBANK NAME=accessram START=0x0 END=0x5F
DATABANK NAME=gpr0 START=0x60 END=0xFF
DATABANK NAME=gpr1 START=0x100 END=0x1FF
DATABANK NAME=gpr2 START=0x200 END=0x2FF
DATABANK NAME=gpr3 START=0x300 END=0x3FF
DATABANK NAME=gpr4 START=0x400 END=0x4FF
DATABANK NAME=gpr5 START=0x500 END=0x5FF
DATABANK NAME=gpr6 START=0x600 END=0x6FF
DATABANK NAME=gpr7 START=0x700 END=0x7FF
DATABANK NAME=gpr8 START=0x800 END=0x8FF
DATABANK NAME=gpr9 START=0x900 END=0x9FF
DATABANK NAME=gpr10 START=0xA00 END=0xAFF
DATABANK NAME=gpr11 START=0xB00 END=0xBFF
DATABANK NAME=gpr12 START=0xC00 END=0xCFF
DATABANK NAME=gpr13 START=0xD00 END=0xDFF
DATABANK NAME=gpr14 START=0xE00 END=0xEFF
ACCESSBANK NAME=accesssfr START=0xF60 END=0xFFF PROTECTED
SECTION NAME=CONFIG ROM=config
STACK RAM=gpr14
SIZE=0x100
Figure 5.3a P18F8720 linker file without debugging support (reprint with permission
of Microchip)

No.5-29
The PIC18 Microcontroller
// Sample linker command file for 18F8720i for MPLAB ICD2
// $Id: 18f8720i.lkr,v 1.3 2002/11/07 23:23:51 sealep Exp $
LIBPATH .
FILES c018i.o
FILES clib.lib
FILES p18f8720.lib
CODEPAGE NAME=vectors START=0x0 END=0x29 PROTECTED
CODEPAGE NAME=page START=0x2A END=0x1FDBF
CODEPAGE NAME=debug START=0x1FDC0 END=0x1FFFF PROTECTED
CODEPAGE NAME=idlocs START=0x200000 END=0x200007 PROTECTED
CODEPAGE NAME=config START=0x300000 END=0x30000D PROTECTED
CODEPAGE NAME=devid START=0x3FFFFE END=0x3FFFFF PROTECTED
CODEPAGE NAME=eedata START=0xF00000 END=0xF000FF PROTECTED
ACCESSBANK NAME=accessram START=0x0 END=0x5F
DATABANK NAME=gpr0 START=0x60 END=0xFF
DATABANK NAME=gpr1 START=0x100 END=0x1FF
DATABANK NAME=gpr2 START=0x200 END=0x2FF
DATABANK NAME=gpr3 START=0x300 END=0x3FF
DATABANK NAME=gpr4 START=0x400 END=0x4FF
DATABANK NAME=gpr5 START=0x500 END=0x5FF
DATABANK NAME=gpr6 START=0x600 END=0x6FF
DATABANK NAME=gpr7 START=0x700 END=0x7FF
DATABANK NAME=gpr8 START=0x800 END=0x8FF
DATABANK NAME=gpr9 START=0x900 END=0x9FF
DATABANK NAME=gpr10 START=0xA00 END=0xAFF
DATABANK NAME=gpr11 START=0xB00 END=0xBFF
DATABANK NAME=gpr12 START=0xC00 END=0xCFF
DATABANK NAME=gpr13 START=0xD00 END=0xDFF
DATABANK NAME=gpr14 START=0xE00 END=0xEF3
DATABANK NAME=dbgspr START=0xEF4 END=0xEFF PROTECTED
ACCESSBANK NAME=accesssfr START=0xF60 END=0xFFF PROTECTED
SECTION NAME=CONFIG ROM=config
STACK RAM=gpr13
SIZE=0x100
Figure 5.3b P18F8720 linker file with debugging support (reprint with permission
of Microchip)

No.5-30
The PIC18 Microcontroller

Inline Assembly
- The MPLAB C compiler provides an internal assembler that allows the user to enter
a block of assembly instructions into the C program.
- The block of instructions must begin with _asm and end with _endasm.
- Some restrictions to inline assembly apply:
1. No directive support
2. Comments must be C or C++ notation
3. Full text mnemonics must be used for table reads/writes, that is

- TBLRD (not TBLRD*)


- TBLRDPOSTDEC (not TBLRD*-)
- TBLRDPOSTINC (not TBLRD*+)
- TBLRDPREINC (not TBLRD+*)
- TBLWT (not TBLWT*)
- TBLWTPOSTDEC (not TBLWT*-)
- TBLWTPOSTINC (not TBLWT*+)
- TBLWTPREINC (not TBLWT+*)
4. No defaults for instruction operands—all operands must be specified.
5. Default radix is decimal.
6. Label must include colon.

No.5-31
The PIC18 Microcontroller

Example of in-line assembly

_asm
clrf count,0
loop:
movlw 0x20 // check loop count
cpfseq count,0 // ―
goto doit
goto done
doit:
movf sum_lo,0,0 // move sum_lo to WREG
addwf count,0,0 // add count to sum_lo
movwf sum_lo,0 // update sum_lo
movlw 0 // add carry to high byte of sum
addwf sum_hi,1,0 // ―
incf count,1,0
goto loop
done:
nop
_endasm

No.5-32
The PIC18 Microcontroller

Bit Field Manipulation

The processor-specific header file includes a structure definition that allows the user to
access individual bits of a register by
1. appending bits to the register name
2. appending a period to the symbol resulted in step 1
3. specifying the bit name after the period

For example,

PORTBbits.RB0 = 1; /* pull PORTB bit 0 to high */


PORTBbits.RB1 = 0; /* pull PORTB bit 1 to low */
STATUSbits.C = 0; /* clear the C flag to 0 */

No.5-33
The PIC18 Microcontroller

PIC18 Instructions Provided as Macros

Table 5.7 PIC18 instructions provided as C macros (reprint with permission of Microchip)
Instruction macro Action
Nop () Executes a no operation (NOP)
ClrWdt () Clears the watchdog timer (CLRWDT)
Sleep () Executes a SLEEP instruction
Reset () Executes a RESET instruction
Rlcf (var, dest, access) Rotate var to the left through the carry bit
Rlncf (var, dest, access) Rotate var to the left without going through the carry bit
Rrcf (var, dest, access) Rotate var to the right through the carry bit
Rrncf (var, dest, access) Rotate var to the right without going through the carry bit
Swap (var, dest, access) Swaps the upper and lower nibbles of var

Note. 1. var must be an 8-bit quantity (i.e., char) and not located on the stack.
2. If dest is 0, the result is stored in WREG, and if dest is 1, the result is located in
var. If access is 0, the access bank will be selected, overriding the BSR value. If
access is 1, then the bank will be selected as per the BSR value.
3. Each of the macros affects MPLAB C18's ability to perform optimization on the
functions using these macros.

No.5-34
The PIC18 Microcontroller

The #pragma Statement

A compiler writer can add implementation-dependent options to the language by using


the #pragma statement including

1. declare data or code sections


2. declare section attributes
3. locate code or data
4. declare interrupt vectors
5. declare interrupt service routines (to be discussed in Chapter 6)
6. other implementation-dependent features

No.5-35
The PIC18 Microcontroller

MPLAB C18 Library Functions

- A library is a collection of functions grouped for reference and ease of linking.


- C18 libraries are included in the lib subdirectory of the installation.
- C libraries are divided into two groups: processor-independent libraries and
processor-specific libraries.

Processor-Specific Libraries
- Files contain definitions that may vary across different members of the PIC18
family.
- These libraries include all the peripheral routines and the special-function
definitions.
- The processor-specific libraries are named pprocessor.lib. For example, the library
for the PIC18F8720 is named p18F8720.lib.

Processor-Independent Libraries
- General functions and math functions are in this category.
- These functions are contained in clib.lib.

No.5-36
The PIC18 Microcontroller

MPLAB C18 general library supports the following categories of routines:

• Character classification functions


• Data conversion functions
• Delay functions
• Memory and string manipulations

These library functions are listed in Table 5.10a, 5.10b, 5.11a, 5.11b, 5.12a, and 5.12b.
The prototype definitions of delay functions are listed in Table 5.12b.

Table 5.12b Names and prototype declarations of C delay routines in MPLAB


C18 compiler (reprint with permission of Microchip)
name Description
Delay1TCY void Delay1TCY (void);
Delay10TCYx void Delay10TCYx (unsigned char unit);
Delay100TCYx void Delay100TCYx (unsigned char unit);
Delay1KTCYx void Delay1KTCYx (unsigned char unit);
Delay10KTCYx void Delay10KTCYx (unsigned char unit);

No.5-37
The PIC18 Microcontroller

Creating time delay can easily be done by calling the appropriate delay functions. For
example, with fOSC = 32 MHz, instruction cycle time = 1/8 ms,

The following two statements can create 100 ms and 1 ms delays, respectively:

Delay100TCYx(8);

Delay1KTCYx(8);

No.5-38
The PIC18 Microcontroller

Chapter 6

Interrupts, Resets, and Configuration

No.6-1
The PIC18 Microcontroller

Interrupts
- Without interrupts, the processor will execute programs by following
the program logic flow.

- Interrupt is an event that will cause the CPU to stop the normal
program execution and provide some service to the event.

- An interrupt can be generated inside and outside the microcontroller


chip.

- An external interrupt is generated when the external hardware asserts


an interrupt signal to the CPU.

No.6-2
The PIC18 Microcontroller

Interrupts (cont’)
- An internal interrupt can be generated by the hardware circuitry
inside the chip and caused by software errors.

- Abnormal situations that occur during program execution, such as


illegal opcodes, overflows, divide-by-zero, and underflow, are referred
to as software interrupts.

- Software interrupts are also called traps and exceptions.

- A good analogy for interrupt is how one will act when there is a
incoming phone call.

No.6-3
The PIC18 Microcontroller

Applications of Interrupts

- Coordinate I/O activities and prevent CPU from being tied up during
the data transfer process.

- Perform time-critical operation—one example is process control.

- Provide a graceful way to exit from the application when a software


error occurred.

- Remind the CPU to perform routine tasks:


1. Keep track of time of day
2. Periodic data acquisition
3. Task switching in a multi-tasking operating system
4. Others

No.6-4
The PIC18 Microcontroller

Interrupt Maskability

- Some interrupts are not desirable under some situations and should be
ignored by the CPU. These interrupts are called maskable interrupt.

- Other interrupts represent events that the CPU shouldn’t ignore and
must take immediate action. These interrupts are called nonmaskable
interrupts.

- A program can disable (mask) an interrupt by setting or clearing a bit


for most processors.

- An interrupt is pending when it is active but not serviced by the CPU

No.6-5
The PIC18 Microcontroller

Interrupt Priority

- A microcontroller or microprocessor normally have multiple interrupt


sources.

- More than one interrupt source can be pending at the same time.

- The CPU needs to decide which one of the pending interrupts to service.

- The solution for handling multiple pending interrupts is to prioritize all


interrupts.

- The interrupt at the higher priority will be attended before the interrupt at
the lower priority.

- Interrupt priority can be implemented by the hardware or software.

- The PIC18 supports two-level interrupt priority only and let the software
to decide which pending interrupt to service.
No.6-6
The PIC18 Microcontroller

Interrupt service

- The CPU provides service to an interrupt by executing an interrupt


service routine.
- After providing service to the pending interrupt, the CPU must
resume normal program execution.
- The complete interrupt service cycle involves the following:

1. Saving the program counter in the stack


2. Saving the CPU status in the stack (optional for some processor)
3. Identifying the interrupt source
4. Resolving the starting address of the corresponding interrupt
service routine
5. Executing the interrupt service routine
6. Restoring the CPU status from the stack
7. Restoring the program counter from the stack
8. Resuming the interrupted program

No.6-7
The PIC18 Microcontroller

- For maskable interrupts, the CPU starts to provide service to the


interrupt after it completes the execution of the current instruction.

- For some maskable interrupts, the CPU may provide service to the
interrupt without completing the current instruction.

No.6-8
The PIC18 Microcontroller

Interrupt Vector

- The starting address of the interrupt service routine is called


interrupt vector.

- There are three methods for determining the interrupt vector:

1. Predefined.
2. Stored in a predefined memory location
3. Execute an interrupt vector acknowledge cycle to fetch a vector
number to locate the interrupt vector.

- The PIC18 uses the first method to identify the interrupt vector.

No.6-9
The PIC18 Microcontroller

Interrupt Programming
Step 1. Write the service routine

org ox08
… ; interrupt service for high priority interrupts

retfie
org 0x18
… ; interrupt service for low priority interrupts
retfie

Step 2. Initialize the interrupt vector table


(not needed for PIC18)

Step 3. Enable interrupts to be serviced

No.6-10
The PIC18 Microcontroller

The PIC18 Interrupt Sources

- Four edge-triggered INT pin (INT0…INT3) interrupts


- Port B pins change (any one of the upper four Port B pins)
- On-chip peripheral function interrupts. Not all the PIC18 members have the same
number of peripheral function interrupts.

Registers Related to Interrupts


These registers enable/disable the interrupts, set the priority of the interrupts, and
record the status of each interrupt source.
- RCON
- INTCON
- INTCON2
- INTCON3
- PIR1, PIR2, and PIR3
- PIE1, PIE2, and PIE3
- IPR1, IPR2, and IPR3

Each interrupt source has three bits to control its operation:


- A flag bit
- An enable bit
- A priority bit

No.6-11
The PIC18 Microcontroller

RCON register
7 6 5 4 3 2 1 0
IPEN - - RI TO PD POR BOR
IPEN: Interrupt priority enable bit
0: Disable priority levels on interrupts
1: Enable priority levels on interrupts
RI: RESET instruction flag bit
0: The reset instruction was executed causing a device reset
1: The reset instructionwas not executed
TO: Watchdog timeout flag bit
0: A watchdog timeout occurred
1: After power-up, CLRWDT instruction, or SLEEP instruction
PD: Power-down detection flag bit
0: By execution of the SLEEP instruction
1: After power up or by the CLRWDT instruction
POR: Power-on reset status bit
0: A power-on reset has occurred
1: A power-on reset has not occurred
BOR: Brown-out reset status bit (PIC18CX01 does not have this bit)
0: A brown-out reset has occurred
1: A brown-out reset has not occurred

Figure 6.1 The RCON Register (reprint with permission of Microchip)

No.6-12
The PIC18 Microcontroller
7 6 5 4 3 2 1 0
GIE/GIEH PEIE/GIEL TMR0IE INT0IE RBIE TMR0IF INT0IF RBIF

GIE/GIEH: Global interrupt enable bit


when IPEN (RCON<7>)= 0
0: disables all interrupts
1: enables all interrupts
when IPEN = 1
0: disables all interrupts
1: enables all high priority interrupts
PEIE/GEIEL: Peripheral interrupt enable bit
when IPEN = 0:
0: disables all peripheral interrupts
1: enables all peripheral interrupts
when IPEN = 1
0: disables all low priority interrupts
1: enables all low priority interrupts
TMR0IE: TMR0 overflow interrupt enable bit
0: disables TMR0 overflow interrupt
1: enables TMR0 overflow interrupt
INT0IE: INT0 pin interrupt enable
0: disables INT0 pin interrupt
1: enables INT0 pin interrupt
RBIE: PORTB port change interrupt enable bit
0: disables PORTB port change interrupt
1: enables PORTB port change interrupt
TMR0IF: TMR0 overflow interrupt flag bit
0: TMR0 has not overflowed
1: TMR0 has overflowed
INT0IF: INT0 pin interrupt flag bit
0: the INT0 pin interrupt did not occur
1: the INT0 pin interrupt has occurred
PORTB port change interrupt flag bit
0: none of the RB7:RB4 pins have changed state
1: at least one of the RB7:RB4 pins change state

Figure 6.2a The INTCON register (reprint with permission of Microchip)

No.6-13
The PIC18 Microcontroller

7 6 5 4 3 2 1 0
RBPU INTEDG0 INTEDG1 INTEDG2 INTEDG3 TMR0IP INT3IP RBIP

RBPU: PORTB pull-up enable bit


0: all PORTB pull-ups are enabled
1: all PORTB pull-ups are disabled
INTEDG0..INTEDG3: INT0..INT3 interrupt pins edge select
0: interrupt on falling edge
1: interrupt on rising edge
TMR0IP: TMR0 overflow interrupt priority bit
0: low priority
1: high priority
INT3IP: INT3 interrupt priority bit (not available in P18FXX8 & P18CX01)
0: low priority
1: high priority
RBIP: PORTB change interrupt priority bit
0: low priority
1: high priority
Note. 1. PIC18FXX8 does not have INTEDG2 & INTEDG3)
2. PIC18C601/801 does not have INTEDG3
Figure 6.2b The INTCON2 register (reprint with permission of Microchip)

No.6-14
The PIC18 Microcontroller

7 6 5 4 3 2 1 0
INT2IP INT1IP INT3IE INT2IE INT1IE INT3IF INT2IF INT1IF

INT2IP..INT1IP: INT2..INT1 interrupt priority bit


0: low priority
1: high priority
INT3IE..INT1IE: INT3..INT1 interrupt enable bit
0: disable interrupt
1: enable interrupt
INT3IF..INT1IF: INT3..INT1 interrupt flag bit
0: interrupt did not occur
1: interrupt occurred
Note. 1. PIC18FXX2 , PIC18CXX2, PIC18CXX8, and PIC18FXX8 do not
have INT2 and INT3 enable and flag bits
2. PIC18C601/801 does not have INT3 enable and flag bits

Figure 6.2c The INTCON3 register (reprint with permission of Microchip)

No.6-15
The PIC18 Microcontroller
7 6 5 4 3 2 1 0
PSPIF(1) ADIF RC1IF TX1IF SSPIF CCP1IF TMR2IF TMR1IF
PSPIF: Parallel slave port Read/Write interrupt flag bit (1)
0: no read or write has occurred
1: a read or write operation has taken place (must be cleared in software)
ADIF: A/D converter interrupt flag bit
0: the A/D conversion is not completed
1: an A/D conversion completed (must be cleared in software)
RCIF: USART receive interrupt flag bit
0 = the USART receive buffer is empty
1 = the USART receive buffer is full (cleared by reading RCREG)
TXIF: USART transmit tnterrupt flag bit
0 = the USART transmit buffer is full
1 = the USART transmit buffer is empty
SSPIF: Synchronous serial port interrupt flag bit
0 = waiting to transmit/receive
1 = the transmission/reception is complete (must be cleared in software)
CCP1IF: CCP1 interrupt flag bit
Capture mode
1 = a TMR1 register capture occurred (must be cleared in software)
0 = no TMR1 register capture occurred
Compare mode
0 = no TMR1 register compare match occurred
1 = a TMR1 register compare match occurred (must be cleared in software)
PWM mode
Unused in this mode
TMR2IF: TMR2 to PR2 match interrupt flag bit
0 = No TMR2 to PR2 match occurred
1 = TMR2 to PR2 match occurred (must be cleared in software)
TMR1IF: TMR1 overflow interrupt flag bit
0 = TMR1 register did not overflow
1 = TMR1 register overflowed (must be cleared in software)
Note 1. Enabled only in Microcontroller mode for the PIC18F8X20 devices
2. PIC18CX01 device does not have PSPIF flag bit
Figure 6.3a The PIC18 PIR1 register (reprint with permission of Microchip)

No.6-16
The PIC18 Microcontroller

7 6 5 4 3 2 1 0
- CMIF - EEIF BCLI LVDIF TMR3IF CCP2IF
F
CMIF: Comparator interrupt flag bit
0: the comparator input has not changed
1: the comparator input has changed (must clear in software)
EEIF: Data EEPROM/FLASH write operation interrupt flag bit
0: the write operation is not complete
1: the write operation is complete (must cleared in software)
BCLIF: Bus collision interrupt flag bit
0: no bus collision
1: a bus collision occurred while SSP module was transmission (I2C mode)
(must be cleared in software)
LVDIF: low voltage detect interrupt flag bit
0: the device voltage is above the low voltage detect trip point
1: a low voltage condition occurred (must be cleared in software)
TMR3IF: TMR3 overflow interrupt flag bit
0: TMR3 register did not overflow
1: TMR3 register overflowed
CCP2IF: CCP2 interrupt flag bit
Capture mode
0: no TMR1 or TMR3 register capture occurred
1: a TMR1 or TMR3 register capture occurred (must be cleared in software)
Compare mode
0: no TMR1 or TMR3 register compare match occurred
1: TMR1 or TMR3 register compare match occurred (must be cleared in software)
PWM mode:
unused in this mode
Figure 6.3b The PIC18 PIR2 register (reprint with permission of Microchip)

No.6-17
The PIC18 Microcontroller

7 6 5 4 3 2 1 0
- - RC2IF TX2IF TMR4IF CCP5IF CCP4IF CCP3IF
RC2IF: USART2 receive interrupt flag bit
0 = the USART receive buffer is empty
1 = the USART receive buffer is full (cleared when RCREG is read)
TX2IF: USART2 transmit interrupt flag bit
0 = the write operation is not complete
1 = the USART transmit buffer is empty (cleared when TXREG is written)
TMR4IF: TMR4 overflow interrupt flag bit
0 = TMR4 did not overflow
1 = TMR4 register overflowed (must be cleared in software)
CCPxIF: CCPx interrupt flag bit (x = 3, 4, 5)
Capture mode:
0 = No TMR1 or TMR3 register capture occurred
1 = A TMR1 or TMR3 register capture occured (must be cleared in software)
Compare mode:
0 = No TMR1 or TMR3 register compare match occurred
1 = A TMR1 or TMR3 register compare match occurred (must cleared in software)
PWM mode: (not used)

Figure 6.3c The PIR3 register (PIC18FXX20) (reprint with permission of Microchip)

No.6-18
The PIC18 Microcontroller
7 6 5 4 3 2 1 0
TXB2IF/ RXB1IF/
IRXIF WAKIF ERRIF TXBnIF TXB1IF TXB0IF RXBnIF RXB0IF
IRXIF: Invalid message received interrupt flag bit
0: an invalid message has not occurred on the CAN bus
1: an invalid message has occurred on the CAN bus
WAKIF: Bus activity wakeup interrupt flag bit
0: activity on the CAN bus has not occurred
1: activity on the CAN bus has occurred
ERRIF: CAN bus error interrupt flag big
0: an error has not occurred in the CAN module
1: an error has occurred in the CAN module (multiple sources)
When CAN is in mode 0
TXB2IF..TXB0IF: Transmit buffer 2..0 interrupt flag bit
0: transmit buffer 2..0 has not completed transmission of a message
1: transmit buffer 2..0 has completed transmission of a message and may be reloaded
When CAN is in mode 1 or mode 2
TXBnIF: Any transmit buffer interrupt flag bit
0: No message was transmitted
1: One or more transmit buffer has completed transmission of a message and may
reloaded
TXB1IF and TXB0IF are forced to 0 in mode 1 and mode 2
When CAN is in mode 0
RXB1IF..RXB0IF: Receive buffer 1..0 interrupt flag bit
0: receive buffer 1 (or 0) has not received a new message
1: receive buffer 1 (or 0) has received a new message
When CAN is in mode 1 or mdoe 2
RXBnIF: CAN receive buffer interupt flag big
0: No receive buffer has received a new message
1: One or more receive buffer has received a new message
RXB0IF is forced to 0 when in mode 1 or mode 2
Figure 6.3d The PIC18 PIR3 register (PIC18FXX8 or other devices with CAN)
(reprint with permission of Microchip)

No.6-19
The PIC18 Microcontroller

7 6 5 4 3 2 1 0
PSPIE(1 ADIE RC1IE TX1IE SSPIE CCP1IE TMR2IE TMR1IE
)
PSPIE: Parallel slave port Read/Write interrupt enable bit (1)
0: disables the PSP read/write interrupt
1: eables the PSP read/write interrupt
ADIE: A/D converter interrupt enable bit
0: disables the A/D interrupt
1: enables the A/D interrupt
RC1IE: USART1 receive interrupt enable bit
0 = disable the USART1 receive interrupt
1 = enable the USART1 receive interrupt
TX1IE: USART1 transmit interrupt enable bit
0 = disable the USART1 transmit interrupt
1 = enable the USART1 transmit interrupt
SSPIE: Synchronous serial port interrupt enable bit
0 = disables the MSSP interrupt
1 = enables the MSSP interrupt
CCP1IE: CCP1 interrupt enable bit
0 = disables the CCP1 interrupt
1 = enables the CCP1 interrupt
TMR2IE: TMR2 to PR2 match interrupt enable bit
0 = disables the TMR2 to PR2 match interrupt
1 = enables the TMR2 to PR2 match interrupt
TMR1IE: TMR1 overflow interrupt enable bit
0 = disables TMR1 register overflow interrupt
1 = enables TMR1 register overflow interrupt

Note 1. Enabled only in Microcontroller mode for the PIC18F8X20 devices


2. The PIC18C601/801 does not have PSPIE flag bit
Figure 6.4a The PIE1 register (reprint with permission of Microchip)

No.6-20
The PIC18 Microcontroller

7 6 5 4 3 2 1 0
- CMIE - EEIE BCLIE LVDIE TMR3IE CCP2IE
CMIE: Comparator interrupt enable bit
0: disables the comparator interrupt
1: enables the comparator interrupt
EEIE: Data EEPROM/FLASH write operation interrupt enable bit
0: disables the write operation interrupt
1: enables the write operation interrupt
BCLIE: Bus collision interrupt enable bit
0: disables the bus collision interrupt
1: enables the bus collision interrupt
LVDIE: low voltage detect interrupt enable bit
0: disables the device voltage detect interrupt
1: enables the device voltage detect interrupt
TMR3IE: TMR3 overflow interrupt enable bit
0: disables the TMR3 overflow interrupt
1: enables the TMR3 overflow interrupt
CCP2IE: CCP2 interrupt enable bit
0: disables the CCP2 interrupt
1: enables the CCP2 interrupt
Note 1. The PIC18C601/801 has only the lower four bits of this register.
2. The PIC18FXX2 does not have the CMIF bit

Figure 6.4b The PIE2 register (reprint with permission of Microchip)

No.6-21
The PIC18 Microcontroller

7 6 5 4 3 2 1 0
- - RC2IE TX2IE TMR4IECCP5IE CCP4IE CCP3IE
RC2IE: USART2 receive interrupt enable bit
0: the comparator input has not changed
1: the comparator input has changed (must clear in software)
TX2IE: USART2 transmit interrupt enable bit
0: disables the USART2 transmit enable bit
1: enables the USART2 transmit enable bit
CCPxIE: CCPx interrupt enable bit (x = 3, 4, or 5)
0: disables the CCPx interrupt
1: enables the CCPx interrupt

Figure 6.4c The PIE3 register (PIC18FXX20) (reprint with


permission of Microchip)

No.6-22
The PIC18 Microcontroller

7 6 5 4 3 2 1 0
TXB2IE/ RXB1IE/
IRXIE WAKIE ERRIE TXBnIE TXB1IE TXB0IE RXBnIE RXB0IE
IRXIE: Invalid message received interrupt enable bit
0: disables the invalid CAN message received interrupt
1: enables the invalid CAN message received interrupt
WAKIE: Bus activity wakeup interrupt enable bit
0: disables the bus activity wakeup interrupt
1: enables the bus activity wakeup interrupt
ERRIE: CAN bus error interrupt enable big
0: disables the CAN bus error interrupt
1: enables the CAN bus error interrupt
When CAN is in mode 0:
TXB2IE..TXB0IE: Transmit buffer 2..0 interrupt enable bit
0: disables transmit buffer 2..0 interrupt
1: enables transmit buffer 2..0 interrupt
When CAN is in mode 1 or mode 2:
TXBnIE: CAN transmit buffer interrupt enable bit
0: disable all transmit buffer interrupts
1: enable transmit buffer interrupt; individual interrupt is enabled by TXBIE abd BIE0
When CAN is in mode 0:
TXB1IE and TXB0IE are forced to 0 in mode 1 and mode 2.
RXB1IE..RXB0IE: Receive buffer 1..0 interrupt enable bit
0: disables receive buffer 1 (or 0) interrupt
1: enables receive buffer 1 (or 0) interrupt
When CAN is in mode 1 or mdoe 2:
RXBnIE: CAN receive buffer interrupt enable bit
0: disable all receive buffer interrupts
1: enable receive buffer interrupts; individual interrupts is enabled by BIE0
RXB0IE is forced to 0 when in mode 1 and mode 2.
Figure 6.4d Contents of the PIC18 PIE3 register (PIC18FXX8 and other devices with CAN)
(reprint with permission of Microchip)

No.6-23
The PIC18 Microcontroller

7 6 5 4 3 2 1 0
- CMIP - EEIP BCLIP LVDIP TMR3IP CCP2IP
CMIP: Comparator interrupt priority bit
0: low priority
1: high priority
EEIP: Data EEPROM/FLASH write operation interrupt priority bit
0: low priority
1: high priority
BCLIP: Bus collision interrupt priority bit
0: low priority
1: high priority
LVDIP: low voltage detect interrupt priority bit
0: low priority
1: high priority
TMR3IP: TMR3 overflow interrupt priority bit
0: low priority
1: high priority
CCP2IP: CCP2 interrupt priority bit
0: low priority
1: high priority
Note 1. The PIC18C601/801 has only the lower four bits of this register.
2. The PIC18FXX2 does not have the CMIP bit

Figure 6.5b The IPR2 register (reprint with permission of Microchip)

No.6-25
The PIC18 Microcontroller

7 6 5 4 3 2 1 0
- - RC2IP TX2IP TMR4IP CCP5IP CCP4IP CCP3IP
RC2IP: USART2 receive interrupt priority bit
0: low priority
1: high priority
TX2IP: USART2 transmit interrupt priority bit
0: low priority
1: high priority
CCPxIP: CCPx interrupt priority bit (CCP modules 3, 4, and 5)
0: low priority
1: high priority
Figure 6.5c The IPR3 register (PIC18FXX20) (reprint with permission
of Microchip)

No.6-26
The PIC18 Microcontroller

7 6 5 4 3 2 1 0
TXB2IP/ RXB1IP/
IRXIP WAKI ERRIP TXBnIP TXB1IP TXB0IP RXBnIP RXB0IP
P
IRXIP: Invalid message received interrupt priority bit
0: low priority
1: high priority
WAKIP: Bus activity wakeup interrupt enable bit
0: low priority
1: high priority
ERRIP: CAN bus error interrupt enable big
0: low priority
1: high priority
TXB2IP..TXB0IP: Transmit buffer 2..0 interrupt enable bit
In mode 0
0: low priority
1: high priority
In mode 1 and mode 2
TXBnIP is used as the priority bit for all CAN transmit buffers
0: low priority
1: high priority
Bit 3 and 2 are forced to 0 in CAN mode 1 and mode 2.
RXB1IP..RXB0IP: Receive buffer 1..0 interrupt enable bit
In mode 0
0: low priority
1: high priority
In mode 1 and 2
RXBnIP is used to enable the priority of all receive buffer
0: low priority
1: high priority
Bit 0 is forced to 0 in CAN mode 1 and mode 2.

Figure 6.5d The IPR3 register (Devices with CAN) (reprint with
permission of Microchip)

No.6-27
The PIC18 Microcontroller

No.6-28
The PIC18 Microcontroller

PIC18 Interrupt Operation

- The interrupt priority scheme can be enabled or disabled.

- All interrupts are divided into core group and peripheral group.

- The priority bits of the interrupts sources in the core group are contained in
one of the interrupt control registers.

- When the priority scheme is enabled, all high-priority interrupts are under
the control of a two-level interrupt enabling mechanism.

- All low-priority interrupts are under the control of a three-level interrupt


enabling scheme.

No.6-29
The PIC18 Microcontroller

PIC18 Interrupt Operation (cont’)

- When the priority scheme is disabled, all interrupts in the core group are under
the control of a two-level interrupt enabling scheme.

- All interrupts in the peripheral group are under the control of a three-level
enabling scheme.

- The following interrupts are in the core group:


1. INT0…INT3 pin interrupts
2. TMR0 overflow interrupt
3. PORTB input pin (RB7…RB4) change interrupts

- When an interrupt is responded to, the GIE bit is cleared to disable further
interrupt the return address is pushed onto return address stack and the PC is
loaded with the interrupt vector.

No.6-30
The PIC18 Microcontroller

PIC18 Interrupts without Setting Priority

- The priority scheme is disabled by clearing the bit 7 of the RCON register.

- All interrupt sources share the common interrupt vector at 0x08.

- In order to identify the cause of interrupt, one need to check each individual
interrupt flag bit.

- The interrupt sources in the core group can be enabled by setting the GIE bit
and the corresponding enable bit of the interrupt source.

- To enable TMR0 interrupt, for example, one must set both the GIE and the
TMR0IE bits to 1.

- The interrupts in the peripheral group can be enabled by setting the GIE, PEIE,
and the associated interrupt enable bits.

- To enable A/D interrupt, one needs to set the GIE, PEIE, and the ADIE bits

No.6-31
The PIC18 Microcontroller

PIC18 Interrupts with Priority Enabled

- Should be used when certain interrupts need to be serviced promptly.

- The PEIE bit of the INTCON register is used as the low-priority interrupt
enable bit.

- A high-priority interrupt is enabled when the GIEH bit and its interrupt enable
bit are set to 1.

- A low-priority interrupt is enabled when the GIEH, GIEL, and its associated
interrupt enable bits are all set to 1.

- By default, all interrupts are placed in high priority.

- The pending interrupts in the high-priority group will always be served before
the interrupts in the low-priority group.

- Interrupt flags must be cleared in the interrupt service routine to avoid


recursive interrupts.
No.6-32
The PIC18 Microcontroller

INT0…INT3 Pin Interrupts

- All INT pins interrupt are edge-triggered.


- The edge-select bits are contained in the INTCON2 register.
- When an edge-select bit is set to 1, the corresponding INT pin interrupt on the rising
edge.

Port B Pins Input Change Interrupt


- An input change on pins RB7…RB4 sets the flag bit RBIF (INTCON<0>).
- If the RBIE bit is set, then the setting of the RBIF bit causes an interrupt.
- In order to use this interrupt, the RB7…RB4 pins must be configured for input.

TMR0 Overflow Interrupt


- The Timer0 module contains a 16-bit timer TMR0.
- Timer0 can operate in either 8-bit or 16-bit mode.
- When TMR0 rolls over from 0xFF to 0x00 or from 0xFFFF to 0x0000, it may trigger
an interrupt.

No.6-33
The PIC18 Microcontroller

PIC18 Interrupt Programming

Two steps are needed:


Step 1
Write the interrupt service routine and place it in the predefined program memory.
Step 2
Set the appropriate interrupt enable bits to enable the desired interrupt.

A circuit for illustrating interrupt programming is shown in Figure 6.6b.

- The circuit is available in SSE452, SSE8680, and SSE8720 demo boards.


- Connect the 1 Hz output from the function generator to the INT0 pin.
- By enabling the INT0 interrupt, the INT0 pin will generate an interrupt to the CPU
once every second.
- The interrupt service routine simply increments a memory counter, outputs it to the
Port D pins, and returns.
- An LED is turned on when its driving Port D pin outputs a low.

Example 6.1 Write an assembly program to handle the INT0 interrupt for the circuit
shown in Figure 6.6b.

No.6-34
The PIC18 Microcontroller

5V

PIC18F8680
470 470

RD7
1 Hz RD6
RD5
INT0
RD4
RD3
RD2
RD1
RD0

Figure 6.6b INT0 interrupt circuit and LEDs

No.6-35
The PIC18 Microcontroller

#include <p18F8680.inc>
count equ 0x00
org 0x00
goto start
org 0x08
goto ISR_hi
org 0x18
retfie
start setf count ; count down from 255
clrf TRISD ; configure port D for output
movff count,PORTD ; output count to LEDs
bsf RCON,IPEN ; enable priority interrupt
movlw 0x90 ; enable INT0 interrupt
movwf INTCON ; and clear INT0IF flag
forever nop
bra nop

ISR_hi btfss INTCON,INT0IF ; check interrupt source


retfie ; not caused by INT0, return
decf count,F
movff count,PORTD ; output count to LEDs
retfie

No.6-36
The PIC18 Microcontroller

Interrupt Programming Template in C


#include <p18Fxxx.h>
void low_ISR(void);
void high_ISR(void);
#pragma code high_vector = 0x08 // force the following statement to start at
void high_interrupt (void) // 0x08
{
_asm
goto high_ISR;
_endasm
}

#pragma code //return to the default code section


#pragma interrupt high_ISR
void high_ISR (void)
{
… //handle high-priority interrupts
}

No.6-37
The PIC18 Microcontroller

#pragma code low_vector = 0x18 //force the following statements to start at


void low_interrupt (void) //0x18
{
_asm
goto low_ISR;
_endasm
}

#pragma code //return to the default code section


#pragma interruptlow low_ISR
void low_ISR (void)
{
… //handle low-priority interrupts
}

void main (void)


{

}

No.6-38
The PIC18 Microcontroller

Example 6.2 Write a C language version of the program for example 6.1.
#include <p18Fxxx.h>
void low_ISR(void);
void high_ISR(void);
unsigned char count;
#pragma code high_vector = 0x08 // force the following statement to start at
void high_interrupt (void) // 0x08
{
_asm
goto high_ISR;
_endasm
}
#pragma code //return to the default code section
#pragma interrupt high_ISR
void high_ISR (void)
{
if (INTCONbits.INT0IF){ //handle high-priority interrupts
count++;
PORTD = count;
}
}

No.6-39
The PIC18 Microcontroller

#pragma code low_vector = 0x18//force the following statements to start at


void low_interrupt (void) //0x18
{
_asm
goto low_ISR;
_endasm
}
#pragma code //return to the default code section
#pragma interruptlow low_ISR
void low_ISR (void)
{
_asm // handle low-priority interrupts
retfie // simply return
_endasm
}

No.6-40
The PIC18 Microcontroller

void main (void)


{
TRISD = 0x00; // Configure PORTD for output
count = 0xFF; // turn off all LEDs initially
PORTD = count; // “
RCONbits.IPEN = 1; // enable priority interrupt
INTCON = 0x90; // enable INT0 interrupt
while (1); // stay in an infinite loop
}

No.6-41
The PIC18 Microcontroller

Context Saving During Interrupts

- When an interrupt occurs, the PIC18 MCU saves WREG, BSR, and STATUS in the
fast register stack.
- The user can use the retfie fast instruction to retrieve these registers before
returning from the interrupt service routine.
- One can save additional registers in the stack if the interrupt service needs to modify
these registers. These registers must be restored before returning from the service
routine.
- In C language, one can add a save clause to the #pragma statement to inform the C
compiler to generate appropriate instructions for saving additional registers.

#pragma interrupt high_ISR save = reg1,…,regn


#pragma interrupt low_ISR save = reg1,…,regn

- A whole section of data can be saved by the following statements:

#pragma interrupt high_ISR save = section(“section name”)


#pragma interrupt low_ISR save = section(“section name”)

No.6-42
The PIC18 Microcontroller

Resets

- Resets can establish the initial values for the CPU registers, flip-flops, and control
registers of the interface chips so that the computer can function properly.
- The reset service routine will be executed after the CPU leaves the reset state.
- The reset service routine has a fixed starting address and is stored in the read only
memory.
- The PIC18 can differentiate the following types of reset:
1. Power-on reset (POR)
2. MCLR pin reset during normal operation
3. MCLR pin reset during sleep mode
4. Watchdog timer (WDT) reset (during normal operation)
5. Programmable brown-out reset (BOR)
6. RESET instruction
7. Stack full reset
8. Stack underflow reset

No.6-43
The PIC18 Microcontroller

No.6-44
The PIC18 Microcontroller

Chapter 6

Parallel Ports

No.6-1
The PIC18 Microcontroller

Introduction

- Embedded products are designed to allow the user to provide input and receive

results.
- The speed and characteristics of I/O devices are quite different from the CPU.
- Peripheral chips are used to resolve the difference between the I/O devices and
the CPU.
- The major function of the interface chip is to synchronize the data transfer
between the CPU and I/O devices.
- Resistors may be needed to limit the current flow, whereas buffer chips may be
needed to increase the current flow required by the I/O devices.
- An interface chip consists of control registers, data registers, status registers,
data direction register, and control circuitry.

No.6-2
The PIC18 Microcontroller

- Control registers allow the user to set up operation parameters.


- Data registers holds the data to be output or received.
- Status register records the status of the I/O operation.
- Data direction register allows the user to set the direction of data
transfer.
- To input, the processor reads data from the data register.
- To output, the processor writes data into the data register.
- The interconnection between the microprocessor, interface chips, and
I/O devices are shown in Figure 7.1.

No.6-3
The PIC18 Microcontroller

Address from to
Decoder input output
device I/O pins device

CE CE
Interface Interface
chip 1 chip 1

Microprocessor

Data Bus

Figure 7.1 Interface chip, I/O devices, and microprocessor

- The address decoder in Figure 7.1 allows one and only one interface chip to exchange
data with the microprocessor at a time.
- Data transfer can be proceeded in parallel or bit by bit (serial method).
- Serial method is meant to be used with slower I/O devices
- Parallel method is meant to be used with high-speed devices.
- This chapter focuses on parallel I/O.

No.6-4
The PIC18 Microcontroller

I/O Addressing

- The processor needs to access the registers of the interface chip to perform

the I/O operation.


- An address is needed to select the register inside the interface chip and
instructions need to be executed to carry out the appropriate operations.
- Two issues arise here:

1. Address space sharing

2. Instruction set and addressing modes sharing

No.6-5
The PIC18 Microcontroller

I/O Synchronization
- The role of the interface chip is shown in Figure 7.2.
- For input, the CPU needs to make sure it reads when the data is valid and reads only
once.
- For output, the CPU needs to make sure that the output device is ready to accept new
data.
- There are two aspects in the I/O synchronization: the synchronization between the
CPU and interface chip and the synchronization between the interface chip and the I/O
device.

handshake or
Control signals strobe signal I/O device
Microprocessor Interface chip electronics
(such as R/W or
interrupt)
Data Bus

Data Bus Data Bus

Figure 7.2 The role of an interface chip

No.6-6
The PIC18 Microcontroller

Synchronization between the CPU and the Interface Chip


1. Polling method. Use a flag bit to indicate the readiness of I/O operation.

2. Interrupt-driven method. Use the interrupt signal to inform the CPU that new data
is available or output device is ready for more data.

None of the PIC18 I/O ports support either method directly.

No.6-7
The PIC18 Microcontroller

Synchronizing the Interface Chip with I/O Devices

1. No method
- Input: The interface returns the current value of the input pins.
- Output: The interface drives the data written by the CPU directly on output pins.

2. Strobe method
- A strobe signal is used to synchronize data transfer.
- Input: The input device places data on input pins, wait until data is stable, and then
asserts the strobe signal to inform the interface chip to latch the data.
- Output: The interface chip drives data to be output on the output pins, wait until
data is stable, and then asserts the strobe signal to inform the output device
to latch the data.
- PIC18 does not support this method.

No.6-8
The PIC18 Microcontroller

3. Handshake method
- Two handshake signals are used to synchronize the data transfer between the
interface chip and I/O device. H1 is driven by interface chip and H2 is driven
by I/O device.
- There are two versions of handshaking: pulse mode and interlock mode.
- Handshaking signals transactions for input and output are shown in Figure 7.3
and 7.4, respectively.

No.6-9
The PIC18 Microcontroller

H1

Data Valid Data

H2

(a) Interlocked

H1

Data Valid Data

H2

(b) Pulse mode

Figure 7.3 Input Handshakes

No.6-10
The PIC18 Microcontroller

H1

Data Valid Data

H2
(a) Interlocked

H1

Data Valid Data

H2
(b) Pulse Mode
Figure 7.4 Output Handshaking

No.6-11
The PIC18 Microcontroller

Overview of the PIC18 Parallel I/O Ports

- I/O pins are often grouped into ports.

- A port consists of up to 8 pins, a data direction register (TRISx), a latch

register (LATx) , and a data register (PORTx); where, x = A…H, J, K.

- Data to be output is written into the latch, which in turn drives the output

pins.

- A PIC18 may have as many as 10 I/O ports.

- An I/O port is often multiplexed with one or more peripheral functions.

- When a peripheral function is enabled, the I/O pins cannot be used for

general-purpose I/O.

No.6-12
The PIC18 Microcontroller

- Devices with 18 pins and 20 pins have two I/O ports: A and B.

- Devices with 28 pins have three I/O ports: A, B, and C.

- Devices with 40 pins (DIP package) and 44 pins (PLCC package) have five

parallel ports: A, B, C, D, and E.

- Devices with 64 pins (TQFP package) and 68 pins (PLCC package) have seven

ports: A, B, C, D, E, F, and G.

- Most 80-pin (TQFP package) and 84-pin devices (PLCC package) have nine

ports but some 84-pin devices (e.g., PIC18F858 in PLCC package) have 10 ports.

- The number of pins available in each port is shown in Table 7.1.

No.6-13
The PIC18 Microcontroller

Table 7.1 Number of pins available in each paralle port


Port Name No. of Pins Pin Name
A 7 RA6..RA0
B 8 RB7..RB0
C 8 RC7..RC0
D 8 RD7..RD0
E 8 RE7..RE0
F 8 RF7..RF0
G 5 RG4..RG0
H 8 RH7..RH0
J* 8 RJ7..RJ0
K 4 RK3..RK0
Note. The Port J of the PIC18C858 has only four pins
Port K is available in PIC18F858 only.

No.6-14
The PIC18 Microcontroller

Reading and Writing the I/O Ports

- Data direction needs to be set before the I/O operation.


- To configure an I/O pin for input, set the associated bit in the TRIS register to 1.
- To configure an I/O pin for output, set the associated bit in the TRIS register to 0.

Example 7.1 Write an instruction sequence to output the hex value 0x33 to port D.
Solution:
The port D should be configured for output before data is written to it.

clrf TRISD,A ; configure port D for output


movlw 0x33
movwf PORTD,A

Example 7.2 Write an instruction sequence to read the current value of port D into
WREG.
Solution:
setf TRISD,A ; configure port D for input
movf PORTD,W,A ; read port D pin value into WREG

No.6-15
The PIC18 Microcontroller

- Part of an I/O port pins can be configured for input whereas others are configured for
output.

Example 7.3 Configure the upper four pins of port D for input and the lower four pins
for output.
Solution:

movlw 0xF0
movwf TRISD,A

No.6-16
The PIC18 Microcontroller

Interfacing with LEDs 5V

- Several interfacing methods are 300~500 

Output Pin
possible.
- Method (a, b) is used to drive (a) low voltage on output pin lights LED

Output Pin
LED directly.
300~500 

- Method (c) provides


some protection to the
microcontroller. (b) high voltage on output pin lights LED

5V

Output Pin
300~500 

(c) high voltage on output pin lights LED

Figure 7.15 PIC18 output port pin driving an LED

No.6-17
The PIC18 Microcontroller

Interfacing with Seven-Segment Displays


- Used to display a few decimal digits.
- A buffer chip is often used to provide enough current to drive the displays.
- A one-display circuit is shown in Figure 7.16.
- Multiple-digit displays can be achieved by using time-multiplexing technique shown
in Figure 7.17.
- To display a decimal digit, appropriate pattern must be output to port D in Figure
7.16 and 7.17. These patterns are shown in Table 7.2.
PIC18
300  each
a
RD6 a
RD5 b f
c b
RD4
74HC244

g
RD3 d
RD2 e e c
RD1 f
RD0 g
d
common cathode

Figure 7.16 Driving a single seven-segment display

No.6-18
The PIC18 Microcontroller

#5 #4 #0
300  a a . . . a
. b . b . . . b
. .
300  . .
g g
74HC244 . . . g
RD6 RD5 RD0 common common common
cathode cathode cathode
R
RB5 2N2222

IMAX = 70 mA
R 2N2222
RB4 .
PIC18 MCU .
. R
RB0 2N2222

Figure 7.17 Port B and Port D together drive six seven-segment displays

No.6-19
The PIC18 Microcontroller

Table 7.2 Decimal to seven-segment decoder

Decimal Segments Corresponding


digit a b c d e f g Hex Number
0 1 1 1 1 1 1 0 0x7E
1 0 1 1 0 0 0 0 0x30
2 1 1 0 1 1 0 1 0x6D
3 1 1 1 1 0 0 1 0x79
4 0 1 1 0 0 1 1 0x33
5 1 0 1 1 0 1 1 0x5B
6 1 0 1 1 1 1 1 0x5F
7 1 1 1 0 0 0 0 0x70
8 1 1 1 1 1 1 1 0x7F
9 1 1 1 1 0 1 1 0x7B

The display a decimal digit on display i, perform the following operations:

1. Configure both port B and port D for output


2. Drive RBi pin to high
3. Drive other port B pins to low
4. Output the hex value corresponding to the specified decimal digit to port D

No.6-20
The PIC18 Microcontroller

Example 7.4 Write an instruction sequence to display 5 on the seven-segment display #4


in Figure 7.17.
Solution:
In assembly,
clrf TRISB,A ; configure port B for output
clrf TRISD,A ; configure port D for output
movlw 0x5B ; output the segment pattern of 5
movwf PORTD ; “
movlw 0x10 ; enable display #4 to light
movwf PORTB ; “

In C language,

TRISB = 0x00;
TRISD = 0x00;
PORTD = 0x5B;
PORTB = 0x10;

No.6-21
The PIC18 Microcontroller

How to display multiple digit in Figure 7.17?

- Light each digit in turn briefly (say, 1 ms a time) and then turned off.
- When one display is lighted, all other displays are turned off.
- Because of the persistence of vision, all displays will appear lighted simultaneously.

Example 7.5 Write a program to display 654321 on the six seven-segment displays in
Figure 7.17 assuming that the PIC18 is running with a 32-MHz crystal oscillator.
Solution: The values to be output to port B and port D are listed in Table 7.5.

Table 7.3 Table of display patterns for Example 7.5


Seven-segment Displayed
Port D Port B
display BCD digit
#5 6 0x5F 0x20
#4 5 0x5B 0x10
#3 4 0x33 0x08
#2 3 0x79 0x04
#1 2 0x6D 0x02
#0 1 0x30 0x01

No.6-22
The PIC18 Microcontroller

#include <p18F8680.inc>
radix dec
dup_nop macro kk ; this macro will duplicate the “nop” instruction
variable i ; kk times
i=0 ; need to be at a separate line
while i < kk
nop
i += 1 ; need to be at separate line
endw
endm
lp_cnt set 0x00 ; use data memory 0 as loop count
lp_cnt1 set 0x01 ; another loop count
org 0x00
goto start
org 0x08
retfie
org 0x18
retfie
start clrf TRISB,A ; configure Port B for output
clrf TRISD,A ; configure Port D for output
forever movlw 0x06 ; there are six digits to be displayed
movwf lp_cnt ; "

No.6-23
The PIC18 Microcontroller

movlw upper disp_tab


movwf TBLPTRU,A ; "
movlw high disp_tab ; "
movwf TBLPTRH,A ; "
movlw low disp_tab ; "
movwf TBLPTRL,A ; "
loop tblrd*+
movff TABLAT,PORTD ; output the seven-segment pattern
tblrd*+
movff TABLAT,PORTB ; turn on one display
call wait_ms ; wait for half a millisecond
decfsz lp_cnt,F,A ; decrement the loop count
goto loop ; read the next pattern
goto forever ; go to the start of the pattern table
end

No.6-24
The PIC18 Microcontroller

#include <delays.h>
#include <p18F8680.h>
char display[6][2] = {{0x5F,0x20},{0x5BD,0x10},{0x33,0x08},{0x79,0x04},
{0x6D,0x02}, {0x30,0x01}};
void main ()
{
int i;
TRISB = 0x00; /* configure Port B for output */
TRISD = 0x00; /* configure Port D for output */
while (1) {
for (i = 0; i < 6; i++) {
PORTD = display[i][0]; /* output display pattern */
PORTB = display[i][1]; /* turn on one display */
Delay1KTCYx(8); /* wait for 1 ms */
}
}
}

No.6-26
The PIC18 Microcontroller

Using the LCD kits with the HD44780 LCD Controller

- Can control the display of up to 80 characters in an LCD kit.


- Block diagram of the HD44780 is shown in Figure 7.20.
- A standard connector for the HD44780-based connection method is shown in Table
7.5.

DB7 COM 16
LCDP (FRD7069)
DB0

E CONTROLLER SEG 40
LSI SEG 160
R/W
HD44780
RS
VEE
VCC 4
SEGMENT DRIVER x 4
VSS

Figure 7.20 Block diagram of the DMC-20434 LCD kit

No.6-27
The PIC18 Microcontroller

Table 7.4 Pin assignment for displays with less than 80 characters
Pin No. symbol I/O Function
1 VSS - Power supply (GND)
2 VCC - Power supply (+5V)
3 VEE - Contrast adjust
4 RS I 0 = instruction input, 1 = data input
5 R/W I 0 = write to LCD, 1 = read from LCD
6 E I enable signal
7 DB0 I/O data bus line 0
8 DB1 I/O data bus line 1
9 DB2 I/O data bus line 2
10 DB3 I/O data bus line 3
11 DB4 I/O data bus line 4
12 DB5 I/O data bus line 5
13 DB6 I/O data bus line 6
14 DB7 I/O data bus line 7

- The DB7..DB0 pins are used to exchange data with the microcontroller.
- The R/W pin determines the data transfer direction.
- The E pin enables the data exchange with the LCD kit.
- The HD44780 has an instruction register and a data register.
- The RS signal selects the instruction register when it is low and selects the data
register when it is 1.
- The VEE signal is used to adjust the brightness of the LCD and is often connected to
a potentiometer.

No.6-28
The PIC18 Microcontroller

The HD44780 Controller

- The HD44780 can be configured to control 1-line, 2-line, and 4-line displays.
- The HD44780 controller has character generator ROM that can generate 208 5  8 dot
characters and 32 5  10 dot characters.
- Character generator RAM is available for defining 8 5  8 character patterns and 4
5  10 character patterns.
- A set of instructions (Table 7.6) is available for users to configure the LCD operations.
- The HD44780 controller has display data memory (DDRAM) to store the display
data.
- The address of a display data memory location determines where the next character
will appear on the LCD screen.
- The mapping from display data memory to the LCD screen position is not sequential
and is shown in Table 7.8a, 7.8b, and 7.8c.
Table 7.8a DDRAM address usage for a 1-line LCD
Visible
Display size character positions DDRAM addresses
1*8 00..07 0x00..0x07
1 * 16 00..15 0x00..0x0F
1 * 20 00..19 0x00..0x13
1 * 24 00..23 0x00..0x17
1 * 32 00..31 0x00..0x1F
1 * 40 00..39 0x00..0x27

No.6-29
The PIC18 Microcontroller

Table 7.8b DDRAM address usage for a 2-line LCD


Visible
Display size character positions DDRAM addresses
2 * 16 00..15 0x00..0x0F + 0x40..0x4F
2 * 20 00..19 0x00..0x13 + 0x40..0x53
2 * 24 00..23 0x00..0x17 + 0x40..0x57
2 * 32 00..31 0x00..0x1F + 0x40..0x5F
2 * 40 00..39 0x00..0x27 + 0x40..0x67

Table 7.8c DDRAM address usage for a 4-line LCD


Visible
Display size character positions DDRAM addresses
4 * 16 00..15 0x00..0x0F + 0x40..0x4F + 0x14..0x23 + 0x54..0x63
4 * 20 00..19 0x00..0x13 + 0x40..0x53 + 0x14..0x27 + 0x54..0x67
4 * 40 00..39 on 1st controller 0x00..0x27 + 0x40..0x67 on 1st controller and
and 00..39 on 2nd 0x00..0x27 + 0x40..0x67 on 2nd controller
controller

No.6-30
The PIC18 Microcontroller

Table 7.6 HD44780 instruction set


Code Execution
Instruction Description
RS R/W B7 B6 B5 B4 B3 B2 B1 B0 time
Clear display 0 0 0 0 0 0 0 0 0 1 Clears display and returns cursor to the 1.64 ms
home position (address 0).
Cursor home 0 0 0 0 0 0 0 0 1 * Returns cursor to home position (address 0). 1.64 ms
Also returns display being shifted to the
original position. DDRAM contents remain
unchanged.
Entry mode set 0 0 0 0 0 0 0 1 I/D S Set cursor move direction (I/D), specifies to 40 s
shift the display (S). These operations are
performed during data read/write.
Display on/off 0 0 0 0 0 0 1 D C B Sets on/off of all display (D), cursor on/off 40 s
control (C) and blink of cursor position character
(B).
Cursor /display 0 0 0 0 0 1 S/C R/L * * Sets cursor-move or display-(S/C), shift 40 s
shift direction (R/L). DDRAM contents remains
unchanged.
Function set 0 0 0 0 1 DL N F * * Sets interface data length (DL), number of 40 s
display line (N) and character font (F).
Set CGRAM 0 0 0 1 CGRAM address Sets the CGRAM address. CGRAM data is 40 s
address sent and received after this setting.
Set DDRAM 0 0 1 DDRAM address Sets the DDRAM address. DDRAM data is 40 s
address sent and received after this setting.
Read busy flag 0 1 BF CGRAM/DDRAM Reads busy flag (BF) indicating internal 0 s
and address operation is being performed and reads
address
counter CGRAM or DDRAM address counter
contents (depending on previous
instruction).
Write to CGRAM 1 0 write data Writes data to CGRAM or DDRAM. 40 s
or DDRAM
Read from 1 1 read data Reads data from CGRAM or DDRAM. 40 s
CGRAM or
DDRAM

No.6-31
The PIC18 Microcontroller

Table 7.7 LCD instruction bit names


Bit name Settings
I/D 0 = decrement cursor position. 1 = increment cursor position
S 0 = no display shift. 1 = display shift
D 0 = display off 1 = display on
C 0 = cursor off 1 = cursor on
B 0 = cursor blink off 1 = cursor blink on
S/C 0 = move cursor 1 = shift display
R/L 0 = shift left 1 = shift right
DL 0 = 4-bit interface 1 = 8-bit interface
N 0 = 1/8 or 1/11 duty (1 line) 1 = 1/16 duty (2 lines)
F 0 = 5x7 dots 1 = 5 x 10 dots
BF 0 = can accept instruction 1 = internal operation in progress

The IR Register
- The microcontroller writes command (or instruction) into this register to configure
the LCD operation parameters.
- The LCD instruction set is listed in Table 7.6.

No.6-32
The PIC18 Microcontroller

The DR Register
- The data to be written into the DDRAM or CGRAM is written into this register.
- To read data from DDRAM or CGRAM, the microcontroller reads from this register.

Address Counter (AC)


- This 7-bit address counter keeps track of the address of the next DDRAM or CGRAM
location to be accessed.
- The selection of DDRAM or CGRAM is determined by the instruction.
- The content of this register is incremented after the access to DDRAM or CGRAM.
- The register selection is shown in Table 7.9.

Table 7.9 Register selection


RS R/W Operation

0 0 IR write as an internal operation (display clear, etc)


0 1 Read busy flag (DB7) and address counter (DB0 to DB6)
1 0 DR write as an internal operation (DR to DDRAM or CGRAM)
1 1 DR read as an internal operation (DDRAM or CGRAM to DR)

No.6-33
The PIC18 Microcontroller

HD44780 Commands

1. Clear display (0x01). This command clears the LCD screen, sets the address
counter to 0, sets the cursor to the upper left corner of the LCD screen, and also sets
the I/D bit to 1 in entry mode.

2. Return Home (0x02). Sets DDRAM address 0 into address counter, move cursor to
the upper left corner of the display but does not change the contents of the DDRAM.

3. Entry Mode Set. The I/D bit of this command controls the incrementing or
decrementing of the DDRAM address. The display will shift if the S bit is 1 when the
DDRAM is being written into.

4. Display On/Off Control. This command can turn on the display (D = 1), turn on the
cursor (C = 1), and turn on the cursor blinking (B = 1).

5. Cursor or Display Shift. This command determines to shift the cursor (S/C = 0 bit)
or display (S/C bit = 1) to the right (R/L bit = 1) or to the left (R/L bit = 0).

No.6-34
The PIC18 Microcontroller

6. Function Set. This command allows the user to set the interface data length, select
the number of lines, and the font size:
DL bit. When set to 1, data is exchanged in 8-bit length. Otherwise, data is exchanged
in 4-bit length.
N bit. When set to 1, two-line display is selected. Otherwise, 1-line display is
selected.
F bit. When set to 0, the 5  7 font is selected. Otherwise, 5  10 font is selected.

7. Set CGRAM Address. This command contains the CGRAM address to be set into
the address counter.

8. Set DDRAM Address. This command allows to set the DDRAM address into the
address counter.

9. Read Busy Flag and Address. This instruction reads the busy flag (BF) and the
address counter. The BF flag indicates whether the LCD controller is still executing
the previously received command.

No.6-35
The PIC18 Microcontroller

Interfacing the HD44780 with the PIC18

- There are two methods to interface the LCD kit to the PIC18.
- The first method is treating the LCD kit as an I/O device. One of the available
I/O port is used to connect to the DB7…DB0 pins. Other port pins are used to connect
to the R/W, E, and S inputs of the LCD kit and generate the required timing sequence
on these three pins.
- The second method is to treat the LCD kit as a memory device and use the address
decoder to generate a select signal to select the LCD kit. This method allows the user
to use the table read and table write instructions to access the LCD kit.
- The second method cannot be used by those PIC18 members that do not support the
external memory.
- Only the first method will be used to interface the LCD kit with the PIC18 in this text.
- The circuit for the first approach is shown in Figure 7.21.

No.6-36
The PIC18 Microcontroller

HD44780-based LCD
PIC18 MCU Module

5V
RH7 E
RH6 R/W VCC
RH5 RS 5V

VEE
RE7...RE0 DB7..DB0

GND

Figure 7.21a LCD interface example (8-bit bus)

No.6-37
The PIC18 Microcontroller

HD44780-based LCD
PIC18 MCU Module

5V
RH7 RS
RH6 R/W VCC
RH5 E 5V

VEE
RE7...RE4 DB7..DB4

GND

Figure 7.21b LCD interface example (4-bit bus)

No.6-38
The PIC18 Microcontroller

Timing Consideration for the LCD

- Certain timing parameters must be satisfied in order to successfully access the LCD.
- The read and write timing diagrams are shown in Figure 7.22 and 7.23.
- The HD44780 can operate at either 1 MHz or 2 MHz. The values of timing parameters
for 2-MHz operation are shown in Table 7.12.

RS

tAS tAH

R/W
PWEH tEf

E
tEr tDDR tDHR
DB0-DB7 Valid data
tCYCLE

Figure 7.22 HD44780 LCD controller read timing diagram

No.6-39
The PIC18 Microcontroller

RS

tAS tAH

R/W
PWEH tEf

E
tEr tDSW
tH
DB0-DB7 Valid data
tCYCLE

Figure 7.23 HD44780 LCD controller write timing diagram

Table 7.12 HD44780 bus timing parameters (2 MHz operation)


Symbol Meaning Min Typ Max. Unit
tCYCLE Enable cycle time 500 - - ns
PWEH Enable pulse width (high level) 230 - - ns
tEr, tEf Enable rise and decay time - - 20 ns
tAS Address setup time, RS, R/W, E 40 - - ns
tDDR Data delay time - - 160 ns
tDSW Data setup time 80 - - ns
tH Data hold time (write) 10 - - ns
tDHR Data hold time (read) 5 - - ns
tAH Address hold time 10 - - ns

No.6-40
The PIC18 Microcontroller

LCD Programming

To display messages on the LCD, the following subroutines are needed:

1. LCD_rdy: make sure the LCD is not busy with internal operation

2. init_lcd: configure the LCD operation parameters

3. LCD_cmd: send a command to the LCD

4. send2LCD: generate a timing sequence to output the contents of WREG to the LCD

5. LCD_putc: output the character in WREG to the LCD

6. LCD_putstr: output the string in program memory pointed to by TBLPTR to the LCD

7. LCD_putsr: output the string in data memory pointed to by FSR0 to the LCD

8. get_DDRAM_addr: reads the current DDRAM address and returns it in PRODL.

No.6-41
The PIC18 Microcontroller

The following signals are defined to simplify the access of signals for the SSE8680 and
SSE8720 demo boards:

LCD_DATA equ PORTE ; LCD data bus


#define LCD_D_DIR TRISE,A ; LCD data port direction
#define LCD_E PORTH,7,A ; LCD E clock
#define LCD_E_DIR TRISH,7,A ; LCD E clock direction
#define LCD_RW PORTH,6,A ; LCD read/write line
#define LCD_RW_DIR TRISH,6,A ; LCD R/W pin direction
#define LCD_RS PORTH,5,A ; LCD register select line
#define LCD_RS_DIR TRISH,5,A ; LCD RS signal direction
#define lcd_cport PORTH,A

No.6-42
The PIC18 Microcontroller

Procedure for Writing a Byte into the IR register

Step 1
Pull the RS and the E signals to low.

Step 2
Pull the R/W signal to low.

Step 3
Pull the E signal to high.

Step 4
Output data to the output port attached to the LCD data bus. (Need to configure port E
for output).

Step 5
Pull the E signal to low.

No.6-43
The PIC18 Microcontroller

Procedure for Reading a Byte from the IR register

Step 1
Pull the RS and the E signals to low.

Step 2
Pull the R/W signal to high.

Step 3
Pull the E signal to high.

Step 4
Read the value of the LCD data bus. (need to configure port E for input)

Step 5
Pull the E signal to low.

No.6-44
The PIC18 Microcontroller

Procedure for Writing a Byte into the LCD data register

Step 1
Pull the RS signal to high and pull the E signals to low.

Step 2
Pull the R/W signal to low.

Step 3
Pull the E signal to high.

Step 4
Output data to the I/O port attached to the LCD data bus.

Step 5
Pull the E signal to low.

No.6-45
The PIC18 Microcontroller

; The following subroutines are written to work for fOSC up to 32 MHz.

LCD_rdy setf LCD_D_DIR ; configure LCD data port for input


bcf LCD_RS ; select IR register
bsf LCD_RW ; setup to read busy flag
bsf LCD_E ; pull LCD E-line to high
nop ; small delay
movf LCD_DATA,W,A ; read busy flag and DDRAM address
nop ; small delay to lengthen E pulse
bcf LCD_E ; pull LCD E-line to low
btfsc WREG,7,A ; is busy flag (BF) cleared
goto LCD_rdy
clrf LCD_D_DIR ; configure data pins for output
return

No.6-46
The PIC18 Microcontroller

LCD_cmd pushr WREG ; save WREG in the stack


call LCD_rdy ; wait until LCD is ready
bcf LCD_RS ; select IR register
bcf LCD_RW ; Set write mode
bsf LCD_E ; Setup to clock data
popr WREG ; restore WREG
movwf LCD_DATA,A ; send out the command in WREG
nop ; small delay to lengthen E pulse
bcf LCD_E
return

A common LCD configuration for a 2x20 LCD is as follows:

• Set the LCD to 2-line display


• Turn on display, cursor, and blinking
• Shift cursor right
• Clear the display and return the cursor to home position

No.6-47
The PIC18 Microcontroller

LCD_init clrf LCD_ctl_port ; make sure the LCD control port is low
bcf LCD_E_DIR ; configure control lines
bcf LCD_RW_DIR ; directions to output
bcf LCD_RS_DIR ; "
movlw 0x3C ; configure display to 2 x 20
call LCD_cmd ; send command to LCD
movlw 0x0F ; turn on display and cursor
call LCD_cmd ; "
movlw 0x14 ; shift cursor right
call LCD_cmd ; "
movlw 0x01 ; clear cursor and return to home position
call LCD_cmd ; "
return

No.6-48
The PIC18 Microcontroller

get_DDRAM_addr
setf LCD_D_DIR ; configure LCD data port for input
bcf LCD_RS ; select IR register
bsf LCD_RW ; setup to read busy flag
bsf LCD_E ; pull LCD E-line to high
nop ; add a small delay
movf LCD_DATA,W ; read busy flag and DDRAM address
nop ; small delay to length E pulse
bcf LCD_E ; pull LCD E-line to low
movwf PRODL,A
return

send2LCD ; this subroutine writes WREG to LCD


bsf LCD_RS ; select DR register
bcf LCD_RW ; Set write mode
bsf LCD_E ; Setup to clock data
nop
movwf LCD_DATA,A ; write into LCD DR
nop ; a short delay
bcf LCD_E
return

No.6-49
The PIC18 Microcontroller

Output a Character to a 2x20 or a 4x20 LCD


- One needs to check if the address counter points to the end of a row.
- To find out if the address counter is at the end of a row, one needs to read the
DDRAM address.
- The character that is output to the end of a row cannot be displayed and must be
resent to the beginning of the next row.

LCD_putc pushr WREG ; save WREG


call LCD_rdy ; wait until LCD is not busy
popr WREG ; restore data in WREG
call send2LCD ; write WREG content to LCD
pushr WREG ; save WREG data
call get_DDRAM_addr ; get the DDRAM address in PRODL
movlw 0x13
cpfseq PRODL,A
goto chk_0x53
; reach the end of first line
movlw 0xC0
call LCD_cmd ; set DDRAM address to 0x40
call LCD_rdy
popr WREG
call send2LCD ; re-output the same character
return
No.6-50
The PIC18 Microcontroller

chk_0x53 movlw 0x53


cpfseq PRODL,A
goto chk_0x27
; reach the end of the second line
movlw 0x94 ; set DDRAM address to 0x14 (start of
call LCD_cmd ; 3rd row)
call LCD_rdy
popr WREG
call send2LCD
return
; reach the end of the third line
chk_0x27 movlw 0x27
cpfseq PRODL,A
return
movlw 0xD4 ; set DDRAM address to 0x54 (start of
call LCD_cmd ; 4th row)
call LCD_rdy
popr WREG
call send2LCD
return

No.6-51
The PIC18 Microcontroller

; output a string (pointed to by TBLPTR) in program memory to the LCD


LCD_putstr tblrd*+ ; read a character into TABLAT
movf TABLAT,W,A ; copy to WREG
tstfsz WREG,A ; test WREG and skip if zero
goto send_it
return
send_it call LCD_putc
goto LCD_putstr

; output a string (pointed to by FSR0) in data memory to the LCD


LCD_putsr movf POSTINC0,W ; read a byte to WREG
tstfsz WREG,A ; test WREG and skip if zero
goto send_it
return
send_it call LCD_putc
goto LCD_putsr

No.6-52
The PIC18 Microcontroller

In C language,

#define LCD_DATA PORTE


#define LCD_D_DIR TRISE
#define LCD_RS PORTHbits.RH5
#define LCD_RS_DIR TRISHbits.TRISH5
#define LCD_RW PORTHbits.RH6
#define LCD_RW_DIR TRISHbits.TRISH6
#define LCD_E PORTHbits.RH7
#define LCD_E_DIR TRISHbits.TRISH7
/* These are function prototype definitions */
void LCD_rdy(void);
void LCD_cmd(char cx);
void LCD_init(void);
char get_DDRAM_addr(void);
void LCD_putc (char dx);
void LCD_putstr(rom char *ptr);
void LCD_putsr(char *ptr);
void send2LCD(char xy);

No.6-53
The PIC18 Microcontroller

/******************************************************************/
/* the following function waits until the LCD is not busy. */
/******************************************************************/
void LCD_rdy(void)
{
char test;
LCD_D_DIR = 0xFF; /* configure LCD data bus for input */
test = 0x80;
while (test) {
LCD_RS = 0; /* select IR register */
LCD_RW = 1; /* Set read mode */
LCD_E = 1; /* Setup to clock data */
test = LCD_DATA;
Nop();
LCD_E = 0; /* complete a read cycle */
test &= 0x80; /* check bit 7 */
}
LCD_D_DIR = 0x00; /* configure LCD data bus for output */
}

No.6-54
The PIC18 Microcontroller

/******************************************************************/
/* The following function sends a command to the LCD. */
/******************************************************************/
void LCD_cmd(char cx)
{
LCD_rdy(); /* wait until LCD is ready */
LCD_RS = 0; /* select IR register */
LCD_RW = 0; /* Set write mode */
LCD_E = 1; /* Setup to clock data */
Nop();
LCD_DATA = cx; /* send out the command */
Nop(); /* small delay to lengthen E pulse */
LCD_E = 0; /* complete an external write cycle */
}

No.6-55
The PIC18 Microcontroller

/*******************************************************************/
/* The following function initializes the LCD kit properly. */
/*******************************************************************/
void LCD_init(void)
{
PORTH = 0; /* make sure LCD control port is low */
LCD_E_DIR = 0; /* configure LCD control port for output */
LCD_RS_DIR = 0; /* “ */
LCD_RW_DIR = 0; /* “ */
LCD_cmd(0x3C); /* configure display to 2 rows */
LCD_cmd(0x0F); /* turn on display, cursor, and blinking */
LCD_cmd(0x14); /* shift cursor right */
LCD_cmd(0x01); /* clear display and move cursor to home */
}

No.6-56
The PIC18 Microcontroller

/*******************************************************************/
/* The following function obtains the LCD cursor address. */
/*******************************************************************/
char get_DDRAM_addr (void)
{
char temp;
LCD_D_DIR = 0xFF; /* configure LCD data port for input */
LCD_RS = 0; /* select IR register */
LCD_RW = 1; /* setup to read busy flag */
LCD_E = 1; /* pull LCD E-line to high */
Nop(); /* small delay */
temp = LCD_DATA & 0x7F; /* read DDRAM address */
Nop(); /* small delay to length E pulse */
LCD_E = 0; /* pull LCD E-line to low */
return temp;
}

No.6-57
The PIC18 Microcontroller

/*********************************************************************/
/* The following function sends a character to the LCD kit. */
/*********************************************************************/
void LCD_putc (char dx)
{
char addr;
LCD_rdy(); /* wait until LCD internal operation is complete */
send2LCD(dx);
LCD_rdy(); /* wait until LCD internal operation is complete */
addr = get_DDRAM_addr();
if (addr == 0x13) {
LCD_cmd(0xC0); /* set address to 0x40 (1st column of the 2nd row) */
LCD_rdy();
send2LCD(dx);
}
else if(addr == 0x53) {
LCD_cmd(0x94); /* set address to 0x14 (1st column of the 3rd row) */
LCD_rdy();
send2LCD(dx);
}

No.6-58
The PIC18 Microcontroller

else if(addr == 0x27){


LCD_cmd(0xD4); /* set address to 0x54 (1st column of the 4th row) */
LCD_rdy();
send2LCD(dx);
}
}

/**************************************************************/
/* The following function outputs a string to the LCD. */
/**************************************************************/
void LCD_putstr(rom char *ptr)
{
while (*ptr) {
LCD_putc (*ptr);
ptr++;
}
}

No.6-59
The PIC18 Microcontroller

/**************************************************************/
/* The following function outputs a string to the LCD. */
/**************************************************************/
void LCD_putsr(char *ptr)
{
while (*ptr) {
LCD_putc (*ptr);
ptr++;
}
}
/****************************************************************/
/* The following function writes a character to the LCD. */
/****************************************************************/
void send2LCD(char xy)
{
LCD_RS = 1;
LCD_RW = 0;
LCD_E = 1;
LCD_DATA = xy;
Nop();
Nop();
LCD_E = 0;
}
No.6-60
The PIC18 Microcontroller

Interfacing with DIP Switches


5V

SW DIP-8 PIC18F8680
RF0
RF1
RF2
RF3
RF4
RF5
RF6
RF7

Figure 7.24b Connecting a set of eight DIP switches to port F of the PIC18F8680

Reading a byte from the DIP switches to WREG

movlw 0xFF ; configure port F for input


movwf TRISF ; “
movf PORTF,W ; read portF

No.6-61
The PIC18 Microcontroller

Interfacing with Keypad

Types of Key Switches

1. Membrane: A plastic or rubber membrane presses one conductor onto another.

This type of switches can be made very small.

2. Capacitive: Two parallel plates. Pressing the plates changes the distance between

the plates and changes the capacitance.

No.6-62
The PIC18 Microcontroller

3. Hall effect: The motion of the magnetic flux lines of a permanent magnet perpendicular

to a crystal is detected as voltage appearing between the two faces of the crystal

4. Mechanical: Two metal contacts are brought together to complete an electrical circuit

No.6-63
The PIC18 Microcontroller

Mechanical Keypads and Keyboard

- Low cost and strength of construction

- Most popular

- Pressing the key switch generates a series of pulses instead of a single clean

output

- Human being cannot press and release the key switch 20 ms

- A debouncing process is required for correct operation

No.6-64
The PIC18 Microcontroller

Keypad Input Program Consists of Three Parts

1. Keypad scanning
2. Key switch debouncing
3. Table lookup

Keypad Scanning

- Performed to detect which key is being pressed


- Performed row by row and column by column
- The rows and columns of a keypad are simply conductors
- A simple keypad is shown in Figure 7.26b.
- The row to be scanned is pulled to low. Other rows are pulled high.
- When a key is pressed, the corresponding row and column are shorted together and is
detected low.
- The diodes in Figure 7.26b provides protection of accidental simultaneous press of
multiple keys.

No.6-65
The PIC18 Microcontroller

PIC18 MCU

RJ7
RJ6
RJ5
RJ4
RJ3 3 7 B F
RJ2 2 6 A E
RJ1 1 5 9 D
RJ0 0 4 8 C
4.7K 5V

Figure 7.26b Sixteen-key keypad connected to PIC18 (used


in all SSE demo boards)

No.6-66
The PIC18 Microcontroller

Keypad Debouncing

- When a key is pressed, the voltage of the key switch falls and rises a few times within
a period of about 5 ms as a contact bounces.
- A debouncer will recognize that the switch is closed after the voltage is low for about
10 ms and will recognize that the switch is open after the voltage is high for about 10
ms.
- Both hardware and software debouncing solutions are available.
- The simplest and most popular software solution is wait-and-see. The program
simply waits for 10 ms after detecting a key switch is closed and re-examines the
same key.
- Three hardware debouncing techniques are shown in Figure 7.27.

ASCII Code Lookup

- The keypad input subroutine returns the ASCII code to the caller.
- This step can be embedded in the debouncing procedure.

No.6-67
The PIC18 Microcontroller

VDD
Set
R Q Q

Reset Rese Set


R t
(a) Set-reset latch

VDD
R

4050 Vout

(b) CMOS gate debouncer

VDD

R
H
Vout
Threshold level
C
L
Switch closed
(c) Integrating RC circuit debouncer

Figure 7.27 Hardware debouncing techniques

No.6-68
The PIC18 Microcontroller

Example 7.10 Write a program to perform keypad scanning, debouncing, and returns
the ASCII code of the pressed key to the caller.
Solution:
The instruction sequence for the first row is as follows:
keypad_dir equ TRISJ ; keypad direction control register
keypad equ PORTJ ; keypad port

get_key movlw 0x0F ; configure the upper four pins of keypad


movwf keypad_dir,A ; port for output, others for input
movlw 0xF0 ; set all keypad rows to high
iorwf keypad,F ; “
scan_r0 movlw 0xEF
andwf keypad,F,A ; prepare to scan row 0 (driven by RB4)
scan_k0 btfss keypad,0,A ; check key 0
goto db_key0
scan_k1 btfss keypad,1,A ; check key 1
goto db_key1
scan_k2 btfss keypad,2,A ; check key 2
goto db_key2
scan_k3 btfss keypad,3,A ; check key 3
goto db_key3

No.6-69
The PIC18 Microcontroller

db_key0 call wait10ms ; wait for 10 ms


btfsc keypad,0,A ; is key 0 still closed?
goto scan_k1 ; key 0 not pressed, check key 1
movlw 0x30
return
db_key1 call wait10ms
btfsc keypad,1,A ; is key 1 still closed?
goto scan_k2
movlw 0x31
return
db_key2 call wait10ms
btfsc keypad,2,A ; is key 2 still closed?
goto scan_k3
movlw 0x32
return
db_key3 call wait10ms
btfsc keypad,3,A
goto scan_r1
movlw 0x33
return

No.6-70
The PIC18 Microcontroller

; *******************************************************************
; This subroutine creates a 10 ms delay using timer 0 with fOSC = 32 MHz.
; *******************************************************************
wait10ms bcf INTCON,INT0IE,A ; disable TMR0 interrupt
bcf INTCON,INT0IF,A ; clear TMR0IF flag
movlw 0x03 ; configure TMR0 with 1:16 prescaler
movwf T0CON,A ; configure TMR0
movlw 0x3C
movwf TMR0H,A
movlw 0xBB
movwf TMR0L,A ; load (50000 - 12) into TMR0
bsf T0CON,TMR0ON,A ; enable TMR0
dlyloop btfss INTCON,INT0IF,A ; is 10 ms over yet?
goto dlyloop
return
end

The C language version is in the following slides:

No.6-71
The PIC18 Microcontroller

#include <p18F8680.h>
#define keypad_dir TRISJ
#define keypad PORTJ
void wait_10ms(void);

unsigned char get_key (void)
{
keypad_dir = 0x0F; /* configure RJ7..RJ4 for output */
keypad |= 0xF0; /* RJ3..RJ0 for input */
while (1) {
keypad &= 0xEF; /* set RJ4 to low to scan the first row */
if (!(keypadbits.RB0)) {
wait_10ms( );
if (!(keypadbits.RB0))
return 0x30; /* return the ASCII code of 0 */
}
if (!(keypadbits.RB1)) {
wait_10ms( );
if (!(keypadbits.RB1))
return 0x31; /* return the ASCII code of 1 */

}

No.6-72
The PIC18 Microcontroller

The MAX5102 DAC

- Dual-channel, 8-bit DAC made by Maxim


- Block diagram and pin assignment are shown in Figure 7.28 and 7.29.

VDD 1 16 OUTA
input -
REF 2 15 OUTB D7 DAC A OUTA
latch A +
.
SHDN 3 14 GND
.
input -
WR 4 MAXIM 13 A0 D0 OUTB
DAC B +
MAX5102 latch B
D7 5 12 D0
D6 6 11 D1
Control
D5 7 10 D2 A0
logic
D4 8 9 D3 MAX5102

WR REF SHDN
Figure 7.28 MAX5102 Pin configuration Figure 7.29 MAX5102 Pin configuration

No.6-73
The PIC18 Microcontroller

Pin Functions

• OUTA, OUTB: analog voltage output.


• D7..D0: data inputs. Digital code to be converted is sent to MX5102 over these eight pins.
• REF: Reference voltage input. This signal controls the magnitude of OUTA and OUTB.
• WR: Write. When this signal is low, new digital code can be written into the MAX5102.
• A0: DAC address select bit. DAC address select bit. Channel A is selected when A0 = 0.
• VDD: Positive supply voltage. The range of VDD is from 5V to 15V.
• GND: Ground.
• SHDN: Shutdown. When set to high, this signal shuts down the chip to save power.

Voltage Output

VOUT = (NB  VREF)  256

where, NB is the digital input to be converted


VREF is the reference voltage

No.6-74
The PIC18 Microcontroller

Functioning of the MAX5102 DAC

- To write new data to be converted, the WR input must be low.


- Data input is latched on the rising edge of the WR signal.
- After WR goes high, the data input can change without affecting VOUT.
- Circuit connection with the PIC18 is shown in Figure 7.31.

5V
PIC18 MAX5102
VDD 0.1F
RD7..RD0 D7..D0 REF

OUTA
RB1 WR
OUTB

RB0 A0 SHDN
GND

Figure 7.30 Circuit connection between the MAX5102 and PIC18

No.6-75
The PIC18 Microcontroller

Example 7.11 Write a program to generate a 1KHz square wave from OUTA pin
assuming the instruction cycle time is 200 ns (correspond to 20 MHz crystal oscillator).
Solution: The procedure is as follows:
Step 1
Configure the pins RD7..RD0, RB1..RB0 for output.
Step 2
Clear the RB0 pin to low to select OUTA channel.
Step 3
Pull the RB1 pin to low.
Step 4
Output 255 to Port D.
Step 5
Pull the RB1 pin to high.
Step 6
Wait for 0.5 ms.
Step 7
Pull the RB1 pin to low.
Step 8
Output 0 to Port D.
Step 9
Pull the RB1 pin to high.

No.6-76
The PIC18 Microcontroller

Step 10
Wait for 0.5 ms.
Step 11
Go to Step 3.

The C program to generate the waveform is as follows:


#define DAC_data PORTD /* DAC data port */
#define DAC_dat_dir TRISD /* DAC data bus direction register */
#define DAC_ctl_dir TRISB /* DAC control pins direction */
#define DAC_WR PORTBbits.RB1 /* DAC write control pin */
#define DAC_A0 PORTBbits.RB0 /* DAC A0 pin */
#define output 0x00
#define high 1
#define low 0
void main (void)
{
DAC_dat_dir = output; /* configure DAC data bus direction to output */
DAC_ctl_dir &= 0xFC; /* configure WR & A0 pins for output */
DAC_A0 = 0; /* select OUTA channel */

No.6-77
The PIC18 Microcontroller

while (1) {
DAC_WR = low;
DAC_data = 255; /* output a high voltage */
DAC_WR = high;
Delay100TCYx(25); /* wait for 0.5 ms */
DAC_WR = low;
DAC_data = 0; /* output a low voltage */
DAC_WR = high;
Delay100TCYx(25); /* wait for 0.5 ms */
}
}

No.6-78
The PIC18 Microcontroller

Chapter 8

Timers and CCP Modules

No.8-1
The PIC18 Microcontroller

Introduction

- Time is represented by the count in a timer.

- There are many applications that cannot be implemented without a timer:


1. Event arrival time recording and comparison
2. Periodic interrupt generation
3. Pulse width and period measurement
4. Frequency and duty cycle measurement
5. Generation of waveforms with certain frequency and duty cycle
6. Time references
7. Event counting
8. Others

No.8-2
The PIC18 Microcontroller

The PIC18 Timer System


- A PIC18 microcontroller may have up to 5 timers: Timer0…Timer 4.
- Timer0, Timer1, and Timer3 are 16-bit timers whereas Timer2 and Timer4 are 8-bit.
- When a timer rolls over, an interrupt may be generated if it is enabled.
- Both Timer2 and Timer4 use instruction cycle clock as the clock source whereas the
other three timers may also use external clock input as the clock source.
- A PIC18 device may have one, two, or five CCP modules.
- CCP stands for Capture, Compare, and Pulse Width Modulation.
- Each CCP module can be configured to perform capture, compare, or PWM function.
- In capture operation, the CCP module copy the contents of a timer into a capture
register on an signal edge.
- In compare operation, the CCP module compares the contents of a CCPR register
with that of Timer1 (or Timer3) in every clock cycle. When these two registers are
equal, the associated pin may be pulled to high, or low, or toggled.
- In PWM mode, the CCP module can be configured to generate a waveform with
certain frequency and duty cycle.

No.8-3
The PIC18 Microcontroller

Timer0
- Can be configured as an 8-bit or 16-bit timer or counter.
- Can select the internal instruction cycle clock or the T0CKI signal as the clock signal.
- The user can choose to divide the clock signal by a prescaler before connecting it to
the clock input to Timer0.
- The T0CON register controls the operation of Timer0.

Set interrupt
flag bit TMR0IF
on overflow
FOSC/4 0
1 Sync with TMR0
1 internal TMR0L
Programmable high byte
T0CKI pin 0 clocks
Prescaler 8
T0CS (2 Tcy delay) Read TMR0L
T0SE 3
PSA 8 8
Write TMR0L
T0PS2,T0PS1,T0PS0

TMR0H

8
Data bus <7:0>
Figure 8.1b Timer0 block diagram in 16-bit mode (redraw with permission of Microchip)

No.8-4
The PIC18 Microcontroller

7 6 5 4 3 2 1 0

value after TMR0ON T08BIT T0CS T0SE PSA T0PS2 T0PS1 T0PS0
reset 1 1 1 1 1 1 1 1
TMR0ON: Timer0 on/off control bit
0 = stops Timer0
1 = Enables Timer0
T08BIT: Timer0 8-bit/16-bit control bit
0 = Timer0 is configured as a 16-bit timer
1 = Timer0 is configured as an 8-bit timer
T0CS: Timer0 clock source select
0 = Instruction cycle clock
1 = Transition on T0CKI pin
T0SE: Timer0 source edge select bit
0 = Increment on falling edge transition on T0CKI pin
1 = Increment on rising edge transition on T0CKI pin
PSA: Timer0 prescaler assignment bit
0 = Timer0 prescaler is assigned . Timer0 clock input comes from prescaler output.
1 = Timer0 prescaler is not assigned. Timer0 clock input bypasses prescaler.
T0PS2:T0PS0: Timer0 prescaler select bits
000 = 1:2 prescaler value
001 = 1:4 prescaler value
010 = 1:8 prescaler value
011 = 1:16 prescaler value
100 = 1:32 prescaler value
101 = 1:64 prescaler value
110 = 1:128 prescaler value
111 = 1:256 prescaler value

Figure 8.2 T0CON register (reprint with permission of Microchip)

No.8-5
The PIC18 Microcontroller

- Timer0 can operate as a timer or as a counter.


- When the clock source is the instruction cycle clock, it operates as a timer.
- When the clock source is the T0CKI pin, it operates as a counter.
- As shown in Figure 8.1b, when PIC18 reads the TMR0L register, the upper half of
Timer0 is latched into the TMR0H register. This makes sure that the PIC18 always
reads a 16-bit value that its upper byte and lower byte belong to the same time.

Example 8.2 Write a subroutine to create a time delay that is equal to 100 ms times the
contents of the PRODL register assuming that the crystal oscillator is running at 32
MHz.
Solution: The 100 ms delay can be created as follows:
1. Place the value 15535 into the TMR0 high byte and the TMR0L register so that
Timer0 will overflow in 50000 clock cycles.
2. Choose instruction cycle clock as the clock source and set the prescaler to 16
so that Timer0 will roll over in 100 ms.
3. Enable Timer0.
4. Wait until Timer0 to overflow.

No.8-6
The PIC18 Microcontroller

delay movlw 0x83 ; enable TMR0, select internal clock,


movwf T0CON,A ; set prescaler to 16
loopd movlw 0x3C ; load 15535 into TMR0 so that it will
movwf TMR0H,A ; roll over in 50000 clock cycles
movlw 0xAF ; "
movwf TMR0L,A ; "
bcf INTCON,TMR0IF,A ; clear the TMR0IF flag
wait btfss INTCON,TMR0IF,A ;
bra wait ; wait until 100 ms is over
decfsz PRODL,F,A
bra loopd
return

No.8-7
The PIC18 Microcontroller

In C language,

void delay (char cx)


{
int i;
T0CON = 0x83; /* enable TMR0, select instruction clock, prescaler set to 16 */
for (i = 0; i < cx; i++) {
TMR0 = 15535; /* load 15535 into TMR0 so that it rolls */
/* over in 50000 clock cycles */
INTCONbits.TMR0IF = 0;
while(!(INTCONbits.TMR0IF)); /* wait until TMR0 rolls over */
}
return;
}

No.8-8
The PIC18 Microcontroller

Timer1

- Is a 16-bit timer/counter depending upon the clock source.

- An interrupt may be requested when Timer1 rolls over from 0xFFFF to


0x0000.
- Timer1 can be reset when the CCP module is configured to compare mode
to generate a special event trigger.
- Timer1 operation is controlled by the T1CON register.
- Timer1 can be configured to use the oscillator connected to the T1OSO and
T1OSI pins.
- The Timer1 oscillator is primarily intended for a 32 KHz crystal.
- Timer1 can be used to create time delays and measure the frequency of an
unknown signal.

No.8-9
The PIC18 Microcontroller

Data bus
<7:0>
8

TMR1H CCP Special


event trigger
Write TMR1L
8 8
Read TMR1L
8 Synchronized
0 clock input
TMR1
TMR1L
high byte 1

TMR1ON T1SYNC
on/off
T1OSC
T13CKI/T1OSC 1 Synchronize
Prescaler
T1OSCEN de
FOSC/4 1, 2, 4, 8
Enable 0
internal t
T1OSI Oscillator
clock
2 SLEEP input
TMR1CS
T1CKPS1:T1CKPS0

Figure 8.3 Timer1 block diagram: 16-bit mode (redraw with permission of Microchip)

No.8-10
The PIC18 Microcontroller

7 6 5 4 3 2 1 0

value after RD16 -- T1CKPS1 T1CKPS0 T1OSCEN T1SYNC TMR1CS TMR1ON


reset 0 0 0 0 0 0 0 0
RD16: 16-bit read/write mode enable bit
0 = Enables read/write of Timer1 in two 8-bit operations
1 = Enable read/write of Timer1 in 16-bit operation
T1CKPS1:T1CKPS0: Timer1 input clock prescale select bits
00 = 1:1 prescale value
01 = 1:2 prescale value
10 = 1:4 prescale value
11 = 1:8 prescale value
T1OSCEN: Timer1 oscillator enable bit
0 = Timer1 oscillator is shut off
1 = Timer1 oscillator is enabled
T1SYNC: Timer1 external clock input synchronization select bit
When TMR1CS = 1
0 = Synchronize external clock input
1 = Do not synchronize external clock input
When TMR1CS = 0
This bit is ignored.
TMR1CS: Timer1 clock source select bit
0 = Instruction cycle clock (FOSC/4)
1 = External clock from pin RC0/T1OSO/T13CKI
TMR1ON: Timer1 on bit
0 = Stop Timer1
1 = Enables Timer1
Figure 8.4. T1CON contents (redraw with permission of Microchip)

No.8-11
The PIC18 Microcontroller

Example 8.3 Use Timer0 as a timer to create a one-second delay and use Timer1 as a
counter to count the rising (or falling) edges of an unknown signal (at the T1CKI pin)
arrived in one second which would measure the frequency of the unknown signal. Write
a program to implement this idea assuming that the PIC18 MCU is running with a 32
MHz crystal oscillator.
Solution:
A one-second delay can be created by placing 10 in PRODL and calling the delay
function in Example 8.2.

Timer1 should be configured as follows:

• 16-bit mode
• prescaler value set to 1
• disable oscillator
• do not synchronize external clock input
• select external T1CKI pin signal as the clock source

No.8-12
The PIC18 Microcontroller

- Timer1 may overflow many times in one second.


- The user must enable the Timer1 overflow interrupt and keep track of the number
of times that it interrupts.

The setting of Timer1 interrupt is as follows:

- Enable priority interrupt


- Place Timer1 interrupt at high priority
- Enable only Timer1 roll-over interrupt

No.8-13
The PIC18 Microcontroller

#include <p18F8680.inc>
t1ov_cnt set 0x00 ; Timer1 rollover interrupt count
freq set 0x01 ; to save the contents of Timer1 at the end
org 0x00
goto start
; high priority interrupt service routine
org 0x08
btfss PIR1,TMR1IF,A ; skip if Timer1 roll-over interrupt
retfie ; return if not Timer1 interrupt
bcf PIR1,TMR1IF,A ; clear the interrupt flag
incf t1ov_cnt,F,A ; increment Timer1 roll-over count
retfie
; dummy low priority interrupt service routine
org 0x18
retfie
start clrf t1ov_cnt,A ; initialize Timer1 overflow cnt to 0
clrf freq,A ; initialize frequency to 0
clrf freq+1,A ; "
clrf TMR1H ; initialize Timer1 to 0
clrf TMR1L ; "
clrf PIR1 ; clear all interrupt flags
bsf RCON,IPEN,A ; enable priority interrupt

No.8-14
The PIC18 Microcontroller

movlw 0x01 ; set TMR1 interrupt to high priority


movwf IPR1,A ; "
movwf PIE1,A ; enable Timer1 roll-over interrupt
movlw 0x87 ; enable Timer1, select external clock, set
movwf T1CON,A ; prescaler to 1, disable crystal oscillator
movlw 0xC0 ; enable global and peripheral interrupt
movwf INTCON,A ; "
movlw 0x0A
movwf PRODL,A ; prepare to call delay to wait for 1 second
call delay ; Timer1 overflow interrupt occur in this second
movff TMR1L,freq ; save frequency low byte
movff TMR1H,freq+1 ; save frequency high byte
bcf INTCON,GIE,A ; disable global interrupt
forever nop
bra forever
end

The C language version of the program is in the following slides.

No.8-15
The PIC18 Microcontroller

#include <p18F8680.h>
unsigned int t1ov_cnt;
unsigned short long freq;
void high_ISR(void);
void low_ISR(void);
#pragma code high_vector = 0x08 // force the following statement to
void high_interrupt (void) // start at 0x08
{
_asm
goto high_ISR
_endasm
}
#pragma code //return to the default code section
#pragma interrupt high_ISR
void high_ISR (void)
{
if(PIR1bits.TMR1IF){
PIR1bits.TMR1IF = 0;
t1ov_cnt ++;
}
}

No.8-16
The PIC18 Microcontroller

void delay (char cx); /* prototype declaration */


void main (void)
{
char t0_cnt;
char temp;
t1ov_cnt = 0;
freq = 0;
TMR1H = 0; /* force Timer1 to count from 0 */
TMR1L = 0; /* " */
PIR1 = 0; /* clear Timer1 interrupt flag */
RCONbits.IPEN = 1; /* enable priority interrupt */
IPR1 = 0x01; /* set Timer1 interrupt to high priority */
PIE1 = 0x01; /* enable Timer1 roll-over interrupt */
T1CON = 0x83; /* enable Timer1 with external clock, prescaler 1 */
INTCON = 0xC0; /* enable global and peripheral interrupts */
delay (10); /* create one-second delay and wait for interrupt */
INTCONbits.GIE = 0;/* disable global interrupt */
temp = TMR1L;
freq = t1ov_cnt * 65536 + TMR1H * 256 + temp;
}

No.8-17
The PIC18 Microcontroller

Timer2
- 8-bit timer TMR2 and 8-bit period register PR2.

TMR2 sets flag bit


output TMR2IF

Prescaler Reset
FOSC/4 TMR2
1:1, 1:4, 1:16

2 Postcaler
Comparator
T2CKPS1:T2CKPS0 EQ 1:1 to 1:16

4
PR2
T2OUTPS3:T2OUTPS0

Figure 8.5 Timer2 block diagram (redraw with permission of Microchip)

- TMR2 is counting up and comparing with PR2 in every clock cycle.


- When TMR2 equals PR2, the EQ signal will reset TMR2.
- A postscaler is applied to the EQ signal to generate the TMR2 interrupt.
- The TMR2 output is fed to the synchronous serial port module.
- The operation of Timer2 is controlled by T2CON register.

No.8-18
The PIC18 Microcontroller

7 6 5 4 3 2 1 0

value after -- TOUTPS3 TOUTPS2 TOUTPS1 TOUTPS0 TMR2ON T2CKPS1 T2CKPS0


reset 0 0 0 0 0 0 0 0
TOUTPS3:TOUTPS0: Timer2 output postscale select bits
0000 = 1:1 postscale
0001 = 1:2 postscale
.
.
.
1111 = 1:16 postscale
TMR2ON: Timer2 on bit
0 = Timer2 is off
1 = Timer2 is on
T2CKPS1: T2CKPS0: Timer2 clock prescale select bits
00 = prescaler is 1
01 = prescaler is 4
1x = prescaler is 16

Figure 8.6. T2CON control register (redraw with permission of Microchip)

No.8-19
The PIC18 Microcontroller

Example 8.4 Assume that the PIC18F8680 is running with a 32 MHz crystal oscillator.
Write an instruction sequence to generate periodic interrupts every 8 ms with high
priority using Timer2.
Solution: By setting the prescaler and postscaler to 16 and loading 249 into the PR2
register, Timer2 will generate periodic interrupt every 8 ms:

movlw D’249’ ; load 249 into PR2 so that TMR2 counts up


movwf PR2,A ; to 249 and reset
bsf RCON,IPEN,A ; enable priority interrupt
bsf IPR1,TMR2IP,A ; place TMR2 interrupt at high priority
bcf PIR1,TMR2IF,A ;
movlw 0xC0
movwf INTCON,A ; enable global interrupt
movlw 0x7E ; enable TMR2, set prescaler to 16, set
movwf T2CON,A ; postscaler to 16
bsf PIE1,TMR2IE,A ; enable TMR2 overflow interrupt

No.8-20
The PIC18 Microcontroller

Timer3
- Timer3 consists of two 8-bit registers TMR3H and TMR3L.

- Timer3 can choose to use either the internal (instruction cycle clock) or
external signal as the clock source.
- The block diagram of Timer3 is quite similar to that of Timer1.
- Reading TMR3L will load the high byte of Timer3 into the TMR3H
register.
- Timer3 operation is controlled by the T3CON register.

No.8-21
The PIC18 Microcontroller

7 6 5 4 3 2 1 0

value after RD16 T3CCP2 T3CKPS1 T3CKPS0 T3CCP1 T3SYNC TMR3CS TMR3ON
reset 0 0 0 0 0 0 0 0
RD16: 16-bit read/write mode enable bit
0 = Enables read/write of Timer3 in two 8-bit operations
1 = Enables read/write of Timer3 in 16-bit operation
T3CCP2:T3CCP1: Timer3 and Timer1 to CCPx enable bits
00 = Timer1 and Timer2 are the clock sources for CCP1 through CCP5
01 = Timer3 and Timer4 are the clock sources for CCP2 through CCP5;
Timer1 and Timer2 are the clock sources for CCP1
10 = Timer3 and Timer4 are the clock sources for CCP3 through CCP5;
Timer1 and Timer2 are the clock sources for CCP1 and CCP2
11 = Timer3 and Timer4 are the clock sources for CCP1 through CCP5
T3CKPS1:T3CKPS0: Timer3 input clock prescale select bits
00 = 1:1 prescale value
01 = 1:2 prescale value
10 = 1:4 prescale value
11 = 1:8 prescale value
T3SYNC: Timer3 external clock input synchronization select bit
When TMR3CS = 1
0 = Synchronizes external clock input
1 = Do not synchronize external clock input
When TMR3CS = 0
This bit is ignored.
TMR3CS: Timer3 clock source select bit
0 = Instruction cycle clock (FOSC/4)
1 = External clock from pin RC0/T1OSO/T13CKI
TMR3ON: Timer3 on bit
0 = Stops Timer3
1 = Enables Timer3
Figure 8.8. T3CON contents (redraw with permission of Microchip)

No.8-23
The PIC18 Microcontroller

Timer4
- Only available to the PIC18F8X2X and PIC18F6X2X devices.
- The block diagram of Timer4 is shown in Figure 8.9.
- The value of TMR4 is compared to PR4 in each clock cycle.
- When the value of TMR4 equals that of PR4, TMR4 is reset to 0.
- The contents of T4CON are identical to those of T2CON.

TMR4 sets flag bit


output TMR4IF

Prescaler Reset
FOSC/4 TMR4
1:1, 1:4, 1:16

2 Postcaler
Comparator
T4CKPS1:T4CKPS0 EQ 1:1 to 1:16

4
PR4
T4OUTPS3:T4OUTPS0

Figure 8.9 Timer4 block diagram (redraw with permission of Microchip)

No.8-24
The PIC18 Microcontroller

C Library Functions for Timers

Functions for disabling timers

void CloseTimer0 (void);


void CloseTimer1 (void);
void CloseTimer2 (void);
void CloseTimer3 (void);
void CloseTimer4 (void);

Functions for configuring timers

void OpenTimer0 (unsigned char config);


void OpenTimer1 (unsigned char config);
void OpenTimer2 (unsigned char config);
void OpenTimer3 (unsigned char config);
void OpenTimer4 (unsigned char config);

The arguments to these functions are a bit mask that is created by ANDing the values
from each category.

Include the timers.h file in order to use these library functions.

No.8-25
The PIC18 Microcontroller

Enable Timer0 Interrupt


TIMER_INT_ON enable interrupt
TIMER_INT_OFF disable interrupt
Timer Width
T0_8BIT 8-bit mode
T0_16BIT 16-bit mode
Clock Source
T0_SOURCE_EXT external clock source
T0_SOURCE_INT internal clock source
External Clock Trigger
T0_EDGE_FALL External clock on falling edge
T0_EDGE_RISE External clock on rising edge
Prescale Value
T0_PS_1_n 1: n prescale (n = 1, 2, 4, 8, 16, 32, 64, 128, or 256)

Example

OpenTimer0 (TIMER_INT_ON & T0_8BIT & T0_SOURCE_INT &


T0_PS_1_32);

No.8-26
The PIC18 Microcontroller

Functions for Reading Timer Values

unsigned int ReadTimer0 (void);


unsigned int ReadTimer1 (void);
unsigned char ReadTimer2 (void);
unsigned int ReadTimer3 (void);
unsigned char ReadTimer4 (void);

unsigned int cur_time;


cur_time = ReadTimer1();

Functions for writing values into timers

void WriteTimer0 (unsigned int timer);


void WriteTimer1 (unsigned int timer);
void WriteTimer2 (unsigned char timer);
void WriteTimer3 (unsigned int timer);
void WriteTimer4 (unsigned char timer);

writeTimer0 (15535);

No.8-27
The PIC18 Microcontroller

Capture/Compare/PWM (CCP) Modules

- Each CCP module requires the use of timer resource.

- In capture or compare mode, the CCP module may use either Timer1 or Timer3 to

operate.

- In PWM mode, either Timer2 or Timer4 may be used.

- The operations of all CCP modules are identical, with the exception of the special

event trigger mode present on CCP1 and CCP2.

- The operation of a CCP module is controlled by the CCPxCON register.

No.8-28
The PIC18 Microcontroller
7 6 5 4 3 2 1 0
-- -- DCxB1 DCxB0 CCPxM3 CCPxM2 CCPxM1 CCPxM0
value after
reset 0 0 0 0 0 0 0 0

DCxB1:DCxB0: PWM duty cycle bit 1 and bit 0 for CCP module x
capture mode:
unused
compare mode:
unused
PWM mode:
These two bits are the lsbs (bit 1 and bit 0) of the 10-bit PWM duty cycle.
CCPxM3:CCPxM0: CCP module x mode select bits
0000 = capture/compare/PWM disabled (resets CCPx module)
0001 = reserved
0010 = compare mode, toggle output on match (CCPxIF bit is set)
0100 = capture mode, every falling edge
0101 = capture mode, every rising edge
0110 = capture mode, every 4th rising edge
0111 = capture mode, every 16th rising edge
1000 = compare mode, initialize CCP pin low, on compare match force CCP pin high
(CCPxIF bit is set)
1001 = compare mode, initialize CCP pin high, on compare match force CCP pin low
(CCPxIF bit is set)
1010 = compare mode, generate software interrupt on compare match (CCP pin
unaffected, CCPxIF bit is set).
1011 = compare mode, trigger special event (CCPxIF bit is set)
For CCP1 and CCP2: Timer1 or Timer3 is reset on event
For all other modules: CCPx pin is unaffected and is configured as an I/O port.
11xx = PWM mode
Figure 8.10 CCPxCON register (x = 1,..,5) (redraw with permission of Microchip)

No.8-29
The PIC18 Microcontroller

CCP Module Configuration

- Each module is associated with a control register (CCPxCON) and a data register

(CCPRx).

- The data register in turn consists of two 8-bit register: CCPRxL and CCPRxH.

- The CCP modules utilize Timers 1, 2, 3, or 4, depending on the module selected.

- Timer1 and Timer3 are available to modules in capture or compare mode.

- Timer2 and Timer4 are available to modules in PWM mode.

- The assignment of a particular timer to a module is determined by the bit 6 and bit 3

of the T3CON register as shown in Figure 8.11.

No.8-30
The PIC18 Microcontroller

T3CON<6,3>=00 T3CON<6,3>=01 T3CON<6,3>=10 T3CON<6,3>=11


TMR1 TMR3 TMR1 TMR3 TMR1 TMR3 TMR1 TMR3

CCP1 CCP1 CCP1 CCP1

CCP2 CCP2 CCP2 CCP2

CCP3 CCP3 CCP3 CCP3

CCP4 CCP4 CCP4 CCP4

CCP5 CCP5 CCP5 CCP5

TMR2 TMR4 TMR2 TMR4 TMR2 TMR4 TMR2 TMR4

Figure 8.11 CCP and Timer interconnect configurations (redraw with permission of Microchip)

No.8-31
The PIC18 Microcontroller

CCP in Capture Mode


- Main use of CCP is to capture event arrival time
- An event is represented by a signal edge.
- The PIC18 event can be one of the following:
1. every falling edge
2. every rising edge
3. every 4th rising edge
4. every 16th rising edge
set flag bit
CCPxIF TMR3H TMR3L

Prescaler T3CCP2 TMR3


1, 4, 16 enable
CCPx
pin
CCPRxH CCPRxL

and TMR1
edge detect T3CCP2 enable

TMR1H TMR1L
Q's CCPxCON<3:0>

Figure 8.13 Capture mode operation block diagram (redraw with permission of Microchip)

No.8-32
The PIC18 Microcontroller

Capture Operation

- When a capture is made, the interrupt flag bit, CCPxIF is set.


- The CCPxIF flag must be cleared by software.
- In capture mode, the CCPx pin must be configured for input.
- The timer to be used with the capture mode must be running in timer mode or
synchronous counter mode.
- To prevent false interrupt, the user must disable the CCP module when switching
prescaler.

Microchip C Library Functions for CCP in Capture Mode

- Need to include the file capture.h in order to use these functions

Table 8.1 MCC18 C library functions for CCP peripheral


Function Description
CloseCapturex Disable capture channel x
OpenCapturex Configure capture channel x
ReadCapturex Read a value from CCP channel x

No.8-33
The PIC18 Microcontroller

void OpenCapture1 (unsigned char config);


void OpenCapture2 (unsigned char config);
void OpenCapture3 (unsigned char config);
void OpenCapture4 (unsigned char config);
void OpenCapture5 (unsigned char config);

There are two values for the parameter config: interrupt enabling and the edge to
capture.

Interrupt enabling

CAPTURE_INT_ON : interrupt enabled


CAPTURE_INT_OFF : interrupt disabled

Edge to capture

Cx_EVERY_FALL_EDGE : capture on every falling edge


Cx_EVERY_RISE_EDGE : capture on every rising edge
Cx_EVERY_4_RISE_EDGE : capture on every 4th rising edge
Cx_EVERY_16_RISE_EDGE : capture on every 16th rising edge

No.8-34
The PIC18 Microcontroller

Applications of Capture Mode

• Event arrival time recording


• Period measurement
• Pulse width measurement
• Interrupt generation
• Event counting
• Time reference
• Duty cycle measurement

No.8-35
The PIC18 Microcontroller

Example 8.5 Period measurement. Use the CCP channel 1 in capture mode to
measure the period of an unknown signal assuming that the PIC18 MCU is running
with a 16 MHz crystal oscillator. Use the number of clock cycles as the unit of period.
The period of the unknown signal is shorter than 65536 clock cycles.

Solution:
Either two consecutive rising edges or two falling edges must be captured.
The difference of these two edges becomes the period of the signal.
The required timers settings are

- CCP1 (RC2): input


- Timer1: 16-bit mode, use instruction clock as clock source, 1:1 prescaler
- Timer3: select Timer1 as base timer for the CCP1 capture mode
- CCP1: capture on every rising edge
- Disable CCP1 interrupt

No.8-36
The PIC18 Microcontroller

#include <p18F8720.inc>
org 0x00
goto start
org 0x08
retfie
org 0x18
retfie
start bsf TRISC,CCP1,A ; configure CCP1 pin for input
movlw 0x81 ; use Timer1 as the time base
movwf T3CON,A ; of CCP1 capture
bcf PIE1,CCP1IE,A ; disable CCP1 capture interrupt
movlw 0x81 ; enable Timer1, prescaler set to 1,
movwf T1CON,A ; 16-bit, use instruction cycle clock
movlw 0x05 ; set CCP1 to capture on every rising edge
movwf CCP1CON,A ; "
bcf PIR1,CCP1IF,A ; clear the CCP1IF flag
edge1 btfss PIR1,CCP1IF,A ; wait for the first edge to arrive
bra edge1 ; "
movff CCPR1H,PRODH ; save the first edge
movff CCPR1L,PRODL ; "

No.8-37
The PIC18 Microcontroller

bcf PIR1,CCP1IF,A ; clear the CCP1IF flag


edge2 btfss PIR1,CCP1IF,A ; wait for the second edge to arrive
bra edge2 ; "
clrf CCP1CON ; disable CCP1 capture
movf PRODL,W,A
subwf CCPR1L,W,A ; subtract first edge from 2nd edge
movwf PRODL,A ; and leave the period in PRODH:PRODL
movf PRODH,W,A ; "
subwfb CCPR1H,W,A ; "
movwf PRODH,A ; "
forever goto forever ;
end

The C language version of the program is in the next slide.

No.8-38
The PIC18 Microcontroller

#include <p18F8720.h>
void main (void)
{
unsigned int period;

TRISCbits.TRISC2 = 1; /* configure CCP1 pin for input */


T3CON = 0x81; /* use Timer1 as the time base for CCP1 capture */
PIE1bits.CCP1IE = 0; /* disable CCP1 capture interrupt */
PIR1bits.CCP1IF = 0; /* clear the CCP1IF flag */
T1CON = 0x81; /* enable 16-bit Timer1, prescaler set to 1 */
CCP1CON = 0x05; /* capture on every rising edge */
while (!(PIR1bits.CCP1IF)); /* wait for 1st rising edge */
PIR1bits.CCP1IF = 0;
period = CCPR1; /* save the first edge (CCPR1 is accessed as a 16-bit value) */
while (!(PIR1bits.CCP1IF)); /* wait for the 2nd rising edge */
CCP1CON = 0x00; /* disable CCP1 capture */
period = CCPR1 - period;
}

No.8-39
The PIC18 Microcontroller

- The clock period of an unknown signal could be much longer than 2 16 clock cycles.
- One will need to keep track of the number of times that the timer overflows.
- Each timer overflow adds 216 clock cycles to the period.

Let
ovcnt = timer overflow count
diff = the difference of two edges
edge1 = the captured time of the first edge
edge2 = the captured time of the second edge

Case 1: edge2  edge1


period = ovcnt  216 + diff

Case 2: edge1 > edge2


period = (ovcnt – 1)  216 + diff

- The Timer1 overflow interrupt should be enabled after the first signal edge is
captured.
- Timer1 interrupt service routine simply increments ovcnt by 1 and returns.

No.8-40
The PIC18 Microcontroller

Example 8.6 Write a program to measure the period of a signal connected to the
CCP1 pin assuming that the instruction clock is running at 5 MHz. Make the program
more general so that it can also measure the period of a signal with very low frequency.
Solution:

#include <p18F8720.inc>
ov_cnt set 0x00 ; timer overflow count
per_hi set 0x01 ; high byte of edge difference
per_lo set 0x02 ; low byte of edge difference
org 0x00
goto start
org 0x08
goto hi_pri_ISR ; go to the high-priority service routine
org 0x18
retfie

No.8-41
The PIC18 Microcontroller

start clrf ov_cnt,A ; initialize overflow count by 1


bcf INTCON,GIE,A ; disable all interrupts
bsf RCON,IPEN,A ; enable priority interrupt
bcf PIR1,TMR1IF,A ; clear the TMR1IF flag
bsf IPR1,TMR1IP,A ; set Timer1 interrupt to high priority
bsf TRISC,CCP1,A ; configure CCP1 pin for input
movlw 0x81 ; use Timer1 as the time base
movwf T3CON,A ; of CCP1 capture
bcf PIE1,CCP1IE,A ; disable CCP1 capture interrupt
movlw 0x81 ; enable Timer1, prescaler set to 1,
movwf T1CON,A ; 16-bit mode, use instruction cycle clock
movlw 0x05 ; set CCP1 to capture on every rising edge
movwf CCP1CON,A ; "
bcf PIR1,CCP1IF,A ; clear the CCP1IF flag
edge1 btfss PIR1,CCP1IF,A ; wait for the first edge to arrive
goto edge1 ; "
movff CCPR1H,per_hi ; save the high byte of captured edge
movff CCPR1L,per_lo ; save the low byte of captured edge
bcf PIR1,TMR1IF,A
movlw 0xC0
iorwf INTCON,F,A ; enable global interrupts
bsf PIE1,TMR1IE ; enable Timer1 overflow interrupt

No.8-42
The PIC18 Microcontroller

edge2 btfss PIR1,CCP1IF,A ; wait for the 2nd edge to arrive


goto edge2
movf per_lo,W,A
subwf CCPR1L,W,A
movwf per_lo,A ; save the low byte of edge difference
movf per_hi,W,A
subwfb CCPR1H,W,A
movwf per_hi,A ; save the high byte of edge difference
btfsc STATUS,C,A
goto forever
decf ov_cnt,A ; 1st edge is larger, so decrement overflow count
negf per_lo,F ; compute its magnitude
comf per_hi,F ; “
movlw 0x00 ; “
addwfc per_hi,F ; “
forever nop
goto forever
hi_pri_ISR btfss PIR1,TMR1IF,A ; high priority interrupt service routine
retfie ; not Timer1 interrupt, so return
incf ov_cnt
bcf PIR1,TMR1IF,A ; clear Timer1 overflow interrupt flag
retfie
end
No.8-43
The PIC18 Microcontroller

#include <p18F8720.h>
#include <timers.h>
#include <capture.h>
unsigned int ov_cnt, temp;
unsigned short long period; /* 24-bit period value */
void high_ISR(void);
void low_ISR(void);
#pragma code high_vector = 0x08 // force the following statement to
void high_interrupt (void) // start at 0x08
{
_asm
goto high_ISR
_endasm
}
#pragma interrupt high_ISR
void high_ISR (void)
{
if (PIR1bits.TMR1IF) {
PIRbits.TMR1IF = 0;
ov_cnt ++;
}

No.8-44
The PIC18 Microcontroller

void main (void)


{
unsigned int temp1;
ov_cnt = 0;
INTCONbits.GIE = 0; /* disable global interrupts */
RCONbits.IPEN = 1; /* enable priority interrupts */
PIR1bits.TMR1IF = 0;
IPR1bits.TMR1IP = 1; /* promote Timer1 rollover interrupt to high priority */
TRISCbits.TRISC2 = 1; /* configure CCP1 pin for input */
OpenTimer1 (TIMER_INT_ON & T1_16BIT_RW & T1_PS_1_1 &
T1_OSC1EN_OFF & T1_SYNC_EXT_OFF &
T1_SOURCE_INT);
OpenTimer3 (TIMER_INT_OFF & T3_16BIT_RW & T3_PS_1_1 &
T3_SOURCE_INT & T3_PS_1_1 & T3_SYNC_EXT_ON &
T1_SOURCE_CCP);
/* turn on Timer3 and appropriate parameters */
OpenCapture1 (CAPTURE_INT_OFF & C1_EVERY_RISE_EDGE);
PIE1bits.CCP1IE = 0; /* disable CCP1 capture interrupt */
PIR1bits.CCP1IF = 0;
while(!(PIR1bits.CCP1IF));

No.8-45
The PIC18 Microcontroller

temp = ReadCapture1( ); /* save the first captured edge */


PIR1bits.CCP1IF = 0;
PIR1bits.TMR1IF = 0;
INTCON |= 0xC0; /* enable global interrupts */
PIE1bits.TMR1IE = 1; /* enable Timer1 rollover interrupt */
while(!(PIR1bits.CCP1IF));
CloseCapture1(); /* disable CCP1 capture */
temp1 = ReadCapture1( );
if (temp1 < temp)
ov_cnt--;
period = ov_cnt * 65536 + temp1 - temp;
}

No.8-46
The PIC18 Microcontroller

CCP in Compare Mode

- The 16-bit CCPRx register is compared against the TMR1 (or TMR3).
- When they match, one of the following actions may occur on the associated CCPx pin:

1. driven high
2. driven low
3. toggle output
4. remains unchanged

How to Use the Compare Mode?

1. Makes a copy of the 16-bit timer value (Timer1 or Timer3)


2. Adds to this copy a delay count
3. Stores the sum in the CCPRxH:CCPRxL register pair

Special Event Trigger

- The CCP1 and CCP2 modules can also generate this event to reset TMR1 or TMR3
depending on which timer is the base timer.

No.8-47
The PIC18 Microcontroller

special event
trigger
CCPRxH CCPRxL
set flag bit
CCPxIF
Q S Output
Logic comparator
CCPx pin R match
output
enable

CCPxCON<3:0> T3CCP2 0 1
mode select

TMR1L TMR1H TMR3H TMR3L

Figure 8.19 Circuit for CCP in compare mode (redraw with permission of Microchip)

- The CCP compare mode can be used to generate waveforms and create delays.

No.8-48
The PIC18 Microcontroller

Example 8.7 Use CCP1 to generate a periodic waveform with 40% duty cycle and 1
KHz frequency assuming that the instruction cycle clock frequency is 4 MHz.
Solution: The waveform of 1 KHz waveform is shown in Figure 8.20.

400 s

600 s

Figure 8.20 1KHz 40% duty cycle waveform

The algorithm is shown in Figure 8.21.

No.8-49
The PIC18 Microcontroller
Start

set CCP1 pin high initially and then


pull low on match

Clear CCP1IF flag

Start a CCP1 compare operation with


a delay of 400 s

no
CCP1IF = 1?
yes
set CCP1 pin low initially and then
pull high on match

Clear CCP1IF flag

Start a CCP1 compare operation with


a delay of 600 s

no
CCP1IF = 1?
yes
set CCP1 pin high initially and then
pull low on match

Clear CCP1IF flag

Figure 8.21b Logic flow for generating a 1-KHz waveform with 40% duty cycle

No.8-50
The PIC18 Microcontroller

#include <p18F8720.inc>
hi_hi equ 0x06 ; number (1600) of clock cycles that signal
hi_lo equ 0x40 ; is high
lo_hi equ 0x09 ; number (2400) of clock cycles that signal
lo_lo equ 0x60 ; is low
org 0x00
goto start

start bcf TRISC,CCP1 ; configure CCP1 pin for output
movlw 0xC9 ; enable 16-bit Timer3, prescaler 1:1
movwf T3CON ; “
bcf PIR1,CCP1IF
movlw 0x09 ; CCP1 pin set high initially and
movwf CCP1CON ; pull low on match
; CCPR1 TMR3 + 1600 ; start a new compare operation
movlw hi_lo ; “
addwf TMR3L,W ; “
movwf CCPR1L ; “
movlw hi_hi ; “
addwfc TMR3H,W ; “
addwfc TMR3H,W ; “

No.8-51
The PIC18 Microcontroller

bcf PIR1,CCP1IF
hi_time btfss PIR1,CCP1IF ; wait until CCPR1 matches TMR3
bra hi_time ; “
bcf PIR1,CCP1IF
movlw 0x08 ; CCP1 pin set low initially and
movwf CCP1CON ; pull high on match
; CCPR1  CCPR1 + 2400 ; start another compare operation
movlw lo_lo ; “
addwf CCPR1L,F ; “
movlw lo_hi ; “
addwfc CCPR1H,F ; “
lo_time btfss PIR1,CCP1IF ; wait until CCPR1 matches TMR3
bra lo_time ; “
bcf PIR1,CCP1IF
movlw 0x09 ; CCP1 pin set high initially and
movwf CCP1CON ; pull low on match
movlw hi_lo ; start another new compare operation
addwf CCPR1L,F ; “
movlw hi_hi ; “
addwfc CCPR1H,F ; “
bra hi_time
end

No.8-52
The PIC18 Microcontroller

#include <p18F8720.h>
void main (void)
{
TRISCbits.TRISC2 = 0; /* configure CCP1 pin for output */
T3CON = 0xC9; /* turn on TMR3 in 16-bit mode, TMR3 & TMR4 as
base timer for all CCP modules */
CCP1CON = 0x09; /* configure CCP1 pin set high initially and pull low
on match */
CCPR1 = TMR3 + 1600; /* start CCP1 compare operation with 1600 cycles
delay */
PIR1bits.CCP1IF = 0;
while (1) {
while (!(PIR1bits.CCP1IF));
PIR1bits.CCP1IF = 0;
CCP1CON = 0x08; /* set CCP1 pin low initially, pull high on match */
CCPR1 += 2400; /* start CCP1 compare with 2400 as delay */
while (!(PIR1bits.CCP1IF));
PIR1bits.CCP1IF = 0;
CCP1CON = 0x09; /* change CCP1 setting */
CCPR1 += 1600;
}
}

No.8-53
The PIC18 Microcontroller

Example 8.8 Use interrupt-driven approach to generate the waveform specified in


Example 8.7.
Solution: This program uses a flag to select either 1600 (=0) or 2400 (=1) as the delay
count for the compare operation.

#include <p18F8720.inc>
hi_hi equ 0x06 ; number (1600) of clock cycles that signal
hi_lo equ 0x40 ; is high
lo_hi equ 0x09 ; number (2400) of clock cycles that signal
lo_lo equ 0x60 ; is low
flag equ 0x00 ; select 1600 (=0) or 2400 (=1) as delay
org 0x00
goto start
org 0x08
goto hi_ISR
org 0x18
retfie
start bcf TRISC,CCP1 ; configure CCP1 pin for output
movlw 0xC9 ; choose TMR3 as the base timer for
movwf T3CON ; CCP1
movlw 0x09 ; configure CCP1 pin to set high initially

No.8-54
The PIC18 Microcontroller

movwf CCP1CON ; and pull low on match


; start a compare operation so that CCP1 pin stay high for 400 s
movlw hi_lo
addwf TMR3L,W
movwf CCPR1L
movlw hi_hi
addwfc TMR3H,W
movwf CCPR1H
bcf PIR1,CCP1IF
hi_lst btfss PIR1,CPP1IF
bra hi_lst
bcf PIR1,CCP1IF
movlw 0x02 ; CCP1 pin toggle on match
movlw CCP1CON ; “
movlw lo_lo ; start next compare operation
addwf CCPR1L,F ; “
movlw lo_hi ; “
addwfc CCPR1H,F ; “
bsf IPR1,CCPR1IP ; set CCP1 interrupt to high priority
clrf flag ; next delay count set to 1600
movlw 0xC0
iorwf INTCON,F ; enable interrupt

No.8-55
The PIC18 Microcontroller

bsf PIE1,CCP1IE ; “
forever nop ; wait for interrupt to occur
bra forever

hi_ISR btfss PIR1,CCP1IF ; is the interrupt caused by CCP1?


retfie
bcf PIR1,CCP1IF
btfsc flag,0 ; prepare to add 1600 if flag is 0
goto add_2400
movlw hi_lo ; start a new compare operation
addwf CCPR1L,F ; that will keep CCP1 pin high for 1600
movlw hi_hi ; clock cycles
addwfc CCPR1H,F ; “
btg flag,0 ; “
retfie
add_2400 movlw lo_lo ; start a new compare operation that will
addwf CCPR1L,F ; keep CCP1 pin low for 2400 clock cycles
movlw lo_hi ; “
addwfc CCPR1H,F ; “
btg flag,0 ; toggle the flag
retfie
end

No.8-56
The PIC18 Microcontroller

Example 8.9 Assume that there is a PIC18 demo board (e.g., SSE8720) running with a
16-MHz crystal oscillator. Write a function that uses CCP1 in compare mode to create
a time delay that is equal to 10 ms multiplied by the contents of PRODL.
Solution:
- Set the Timer3 prescaler to 1
- Use 40000 as the delay count of the compare operation

dly_by10ms movlw 0x81 ; enable Timer3 in 16-bit mode, 1:1 prescaler


movwf T3CON,A ; use Timer1 as base times for CCP1
movlw 0x81 ; enable Timer1 in 16-bit mode with 1:1
movwf T1CON,A ; prescaler
movlw 0x0A ; configure CCP1 to generate software
movwf CCP1CON,A ; interrupt on compare match
movf TMR1L,W,A ; to perform a CCP1 compare with
addlw 0x40 ; 40000 cycles of delay
movwf CCPR1L,A ; "
movlw 0x9C ; "
addwfc TMR1H,W,A ; "
movwf CCPR1H,A ; "
bcf PIR1,CCP1IF,A

No.8-57
The PIC18 Microcontroller

loop btfss PIR1,CCP1IF,A ; wait until 40000 cycles are over


goto loop
dcfsnz PRODL,F,A ; is loop count decremented to zero yet?
return 0 ; delay is over, return
bcf PIR1,CCP1IF,A ; clear the CCP1IF flag
movlw 0x40 ; start the next compare operation
addwf CCPR1L,F,A ; with 40000 cycles delay
movlw 0x9C ; "
addwfc CCPR1H,F,A ; "
goto loop
In C,
void dly_by10ms (unsigned char kk)
CCP1CON = 0x0A; /* configure CCP1 to generate software interrupt */
T3CON = 0x81; /* enables Timer3 to select Timer1 as base timer */
T1CON = 0x81; /* enables Timer1 in 16-bit mode with 1:1 as prescaler */
PIR1bits.CCP1IF = 0;
while (kk) {
while (!PIR1bits.CCP1IF);
PIR1bits.CCP1IF;
kk--;
CCPR1 += 40000; }
return;
}
No.8-58
The PIC18 Microcontroller

Use CCP Compare to Generate Sound

- A speaker is needed to generate the sound.


- The CCP1 compare mode can be used to generate the sound.

5V
10 

8

PIC18F452
74HC04
1K
CCP1 2N2222

Figure 8.22 Circuit connection for siren generation

No.8-59
The PIC18 Microcontroller

Example 8.10 Use the circuit in Figure 8.22 to generate a siren that oscillates between
440 Hz and 880 Hz assuming the PIC18 is running with a 4 MHz crystal oscillator.
Solution: The procedure is as follows:

Step 1. Configure the CCP channel to operate in the compare mode and toggle output on
match.
Step 2. Start a compare operation and enable its interrupt with a delay equals to half of
the period of the sound of the siren.
Step 3. Wait for certain amount of time (say half of a second). During the waiting period,
interrupts will be requested by the CCP compare match many times. The interrupt
service routine simply clears the CCP flag and starts the next compare operation and
then return.
Step 4. At the end of the delay choose different delay time for the compare operation so
the siren sound with different frequency can be generated.
Step 5. Wait for the same amount of time as in Step 3. Again, interrupt caused by CCP
compare match will be requested many times.
Step 6. Go to Step 2.

No.8-60
The PIC18 Microcontroller

#include <p18F452.inc>
hi_hi equ 0x02 ; delay count to create 880 Hz sound
hi_lo equ 0x38 ; "
lo_hi equ 0x04 ; delay count to create 440 Hz sound
lo_lo equ 0x70 ; "
org 0x00
goto start
org 0x08
goto hi_ISR
org 0x18
retfie
start bcf TRISC,CCP1,A ; configure CCP1 pin for output
movlw 0x81 ; Enable Timer3 for 16-bit mode, use
movwf T3CON,A ; Timer1 as the base timer of CCP1
movwf T1CON,A ; enables Timer1 for 16-bit, prescaler set to 1:1
movlw 0x02 ; CCP1 pin toggle on match
movwf CCP1CON,A ; "
bsf RCON,IPEN ; enable priority interrupt
bsf IPR1,CCP1IP ; configure CCP1 interrupt to high priority
movlw hi_hi ; load delay count for compare operation

No.8-61
The PIC18 Microcontroller

movwf PRODH ; into PRODH:PRODL register pair


movlw hi_lo ; “
movwf PRODL ; “
movlw 0xC0
iorwf INTCON,F,A ; set GIE & PIE bits
movf PRODL,W,A ; start a new compare operation with
addwf TMR1L,W,A ; delay stored in PRODH:PRODL
movwf CCPR1L,A ; "
movf PRODH,W,A ; "
addwfc TMR1H,W,A ; "
movwf CCPR1H,A ; "
bcf PIR1,CCP1IF,A ; clear CCP1IF flag
bsf PIE1,CCP1IE ; enable CCP1 interrupt
forever call delay_hsec ; stay for half second in one frequency
movlw lo_hi ; switch to different frequency
movwf PRODH,A ; "
movlw lo_lo ; "
movwf PRODL,A ; "
call delay_hsec ; stay for half second in another frequency
movlw hi_hi ; switch to different frequency
movwf PRODH,A ; "
movlw hi_lo ; "

No.8-62
The PIC18 Microcontroller

movwf PRODL,A ; "


goto forever

hi_ISR bcf PIR1,CCP1IF,A ; clear the CCP1IF flag


movf PRODL,W,A ; start the next compare operation
addwf CCPR1L,F,A ; using the delay stored in PRODH:PRODL
movf PRODH,W,A ; "
addwfc CCPR1H,F,A ; "
retfie
delay_hsec movlw 0x85
movwf TMR0H,A
movlw 0xED
movwf TMR0L,A
movlw 0x83 ; enable TMR0, select instruction clock,
movwf T0CON,A ; prescaler set to 16
bcf INTCON,TMR0IF,A
loopw btfss INTCON,TMR0IF,A
goto loopw ; wait for a half second
return
end

No.8-63
The PIC18 Microcontroller

Example 8.11 For the circuit in Figure 8.22, write a program to generate a simple song
assuming that fOSC = 4MHz.
Solution:
- The example song to be played is a German folk song. Two tables are used by the
program:
1. Table of numbers to be added to CCPR1 register to generate the waveform with the
desired frequency.
2. Table of numbers that select the duration of each note.

#include <p18F452.h>
#define base 3125 /* counter count to create 0.1 s delay */
#define NOTES 38 /* total notes in the song to be played */
#define C4 0x777
#define F4 0x598
#define G4 0x4FC
#define A4 0x470
#define B4 0x3F4
#define C5 0x3BC
#define D5 0x353
#define F5 0x2CC

No.8-64
The PIC18 Microcontroller

unsigned rom int per_arr[38] = { C4,A4,G4,A4,F4,C4,C4,C5,


B4,C5,A4,A4,F4,D5,D5,D5,
C5,A4,C5,C5,B4,A4,B4,C5,
A4,F4,D5,F5,D5,C5,A4,C5,
C5,B4,A4,B4,C5,A4};
unsigned rom char wait[38] = ( 3,5,3,3,5,3,3,5,
3,3,5,3,3,5,3,3,
5,3,3,3,2,2,3,3,
6,3,5,3,3,5,3,3,
3,2,2,3,3,6}
void delay (unsigned char xc);
void high_ISR(void);
void low_ISR(void);
#pragma code high_vector = 0x08;
void high_interrupt(void)
{
_asm
goto high_ISR
_endasm
}

No.8-65
The PIC18 Microcontroller

#pragma code low_vector = 0x18


void low_interrupt (void)
{
_asm
goto low_ISR
_endasm
}
#pragma interrupt high_ISR
void high_ISR(void)
{
if (PIR1bits.CCP1IF) {
PIR1bits.CCP1IF = 0;
CCPR1 += half_cycle;
}
}
# pragma interrupt low_ISR
void low_ISR (void)
{
_asm
retfie 0
_endasm
}

No.8-66
The PIC18 Microcontroller

void main (void)


{
int i, j;

TRISCbits.TRISC2 = 0; /* configure CCP1 pin for output */


T3CON = 0x81; /* enables Timer3 in 16-bit mode, Timer1
for CCP1 time base */
T1CON = 0x81; /* enable Timer1 in 16-bit mode */
CCP1CON = 0x02; /* CCP1 compare mode, pin toggle on match */
IPR1bits.CCP1IP = 1; /* set CCP1 interrupt to high priority */
PIR1bits.CCP1IF = 0; /* clear CCP1IF flag */
PIE1bits.CCP1IE = 1; /* enable CCP1 interrupt */
INTCON |= 0xC0; /* enable high priority interrupt */
for (j = 0; j < 3; j++) {
i = 0;
half_cyc = per_arr[0];
CCPR1 = TMR1 + half_cyc;
while (i < NOTES) {
half_cyc = per_arr[i]; /* get the cycle count for half period of the note */
delay (wait[i]); /* stay for the duration of the note */
i++;
}

No.8-67
The PIC18 Microcontroller

INTCON &= 0x3F; /* disable interrupt */


delay (5);
delay (6);
INTCON |= 0xC0; /* re-enable interrupt */
}

}
/* ---------------------------------------------------------------------------------------------------- */
/* The following function runs on a PIC18 demo board running with a 4 MHz crystal */
/* oscillator. The parameter xc specifies the amount of delay to be created */
/* ---------------------------------------------------------------------------------------------------- */
void delay (unsigned char xc)
{
switch (xc){
case 1: /* create 0.1 second delay (sixteenth note) */
T0CON = 0x84; /* enable TMR0 with prescaler set to 32 */
TMR0 = 0xFFFF - base; /* set TMR0 to this value so it overflows in
0.1 second */
INTCONbits.TMR0IF = 0;
while (!INTCONbits.TMR0IF);
break;

No.8-68
The PIC18 Microcontroller

case 2: /* create 0.2 second delay (eighth note) */


T0CON = 0x84; /* set prescaler to Timer0 to 32 */
TMR0 = 0xFFFF - 2*base; /* set TMR0 to this value so it overflows in
0.2 second */
INTCONbits.TMR0IF = 0;
while (!INTCONbits.TMR0IF);
break;
case 3: /* create 0.4 seconds delay (quarter note) */
T0CON = 0x84; /* set prescaler to Timer0 to 32 */
TMR0 = 0xFFFF - 4*base; /* set TMR0 to this value so it overflows in
0.4 second */
INTCONbits.TMR0IF = 0;
while (!INTCONbits.TMR0IF);
break;
case 4: /* create 0.6 s delay (3 eighths note) */
T0CON = 0x84; /* set prescaler to Timer0 to 32 */
TMR0 = 0xFFFF - 6*base; /* set TMR0 to this value so it overflows in
0.6 second */
INTCONbits.TMR0IF = 0;
while (!INTCONbits.TMR0IF);
break;

No.8-69
The PIC18 Microcontroller

INTCONbits.TMR0IF = 0;
while (!INTCONbits.TMR0IF);
break;
case 6: /* create 1.2 second delay (3 quarter note) */
T0CON = 0x84; /* set prescaler to Timer0 to 32 */
TMR0 = 0xFFFF - 12*base; /* set TMR0 to this value so it overflows
in 1.2 second */
INTCONbits.TMR0IF = 0;
while (!INTCONbits.TMR0IF);
break;
case 7: /* create 1.6 second delay (full note) */
T0CON = 0x84; /* set prescaler to Timer0 to 32 */
TMR0 = 0xFFFF - 16*base; /* set TMR0 to this value so it overflows
in 1.6 second */
INTCONbits.TMR0IF = 0;
while (!INTCONbits.TMR0IF);
break;

default:
break;
}
}

No.8-70
The PIC18 Microcontroller

CCP in PWM Mode


CCPxCON<5:4>
Duty cycle registers (x = 1, .., 5)
CCPRxL

CCPRxH (slave)

Comparator R Q

CCPx
TRISz<k>
TMRy (y = 2 or 4) z = C or B or G
S

Comparator
Clear timer,
CCPx pin and
latch D.C
PRy (y=2 or 4)

Figure 8.24 Simplified PWM block diagram (redraw with permission of Microchip)

No.8-71
The PIC18 Microcontroller

PWM period = [(PRy) + 1]  4  TOSC  (TMRy prescale factor)

PWM duty cycle = (CCPRxL:CCPxCON<5:4>)  TOSC  (TMRy prescale factor)

Procedure for using the PWM module:

Step 1
Set the PWM period by writing to the PRy (y = 2 or 4) register.
Step 2
Set the PWM duty cycle by writing to the CCPRxL register and CCPxCON<5:4> bits.
Step 3
Configure the CCPx pin for output
Step 4
Set the TMRy prescale value and enable Timery by writing to TyCON register
Step 5
Configure CCPx module for PWM operation

No.8-72
The PIC18 Microcontroller

Example 8.12 Configure CCP1 in PWM mode to generate a digital waveform with
40% duty cycle and 10 KHz frequency assuming that the PIC18 MCU is running with
a 32 MHz crystal oscillator.

Solution:
Timer setting

1. Use Timer2 as the base timer of CCP1 through CCP5 for PWM mode
2. Enable Timer3 in 16-bit mode with 1:1 prescaler
3. Set Prescaler to Timer2 to 1:4

Period register value is

PR2 = 32  106  4  4  104 – 1 = 199

Duty Cycle value

CCPR1L = 200  40% = 80

No.8-73
The PIC18 Microcontroller

Instruction sequence to achieve the previous setting:

movlw 0xC7 ; set period value to 199


movwf PR2,A ; “
movlw 0x50 ; set duty cycle value to 80
movwf CCPR1L,A ; “
movwf CCPR1H,A ; “
bcf TRISC,CCP1,A ; configure CCP1 pin for output
movlw 0x81 ; enable Timer3 in 16-bit mode and use
movwf T3CON,A ; Timer2 as time base for PWM1 thru PWM5
clrf TMR2,A ; force TMR2 to count from 0
movlw 0x05 ; enable Timer2 and set its prescaler to 4
movwf T2CON,A ; “
movlw 0x0C ; enable CCP1 PWM mode
movwf CCP1CON,A ; “

No.8-74
The PIC18 Microcontroller

PIC18 Pulse Width Modulation C Library Functions

void ClosePWM1 (void);


void ClosePWM2 (void);
void ClosePWM3 (void);
void ClosePWM4 (void);
void ClosePWM5 (void);
void OpenPWM1 (char period);
void OpenPWM2 (char period);
void OpenPWM3 (char period);
void OpenPWM4 (char period);
void OpenPWM5 (char period);

void SetDCPWM1 (unsigned int dutycycle);


void SetDCPWM2 (unsigned int dutycycle);
void SetDCPWM3 (unsigned int dutycycle);
void SetDCPWM4 (unsigned int dutycycle);
void SetDCPWM5 (unsigned int dutycycle);

No.8-75
The PIC18 Microcontroller

Example 8.13 Write a set of C statements to configure CCP4 to generate a digital


waveform with 5 KHz frequency and 70% duty cycle assuming that the PIC18F8720
is running with a 16 MHz crystal oscillator. Use Timer4 as the base timer.
Solution:
- Set timer prescaler to 4 and set the period value to be 200
- Duty cycle value to be written is 200  70%  4 = 560
- The following C statements will configure CCP1 to generate 5 KHz, 70% duty
cycle waveform:

TRISGbits.TRISG3 = 0; /* configure CCP4 pin for output */


OpenTimer3(TIMER_INT_OFF & T3_16BIT_RW & T3_SOURCE_INT &
T3_PS_1_1 & T3_SOURCE_CCP & T3_OSC1EN_OFF);
OpenTimer4(TIMER_INT_OFF & T4_PS_1_1 & T4_POST_1_1);
SetDCPWM4 (560);
OpenPWM4(199);

No.8-76
The PIC18 Microcontroller

PWM Application 1 – Light Dimming

5V, 0.5A lamp 5V, 0.5A lamp

PWM 1K PWM 1K


PNP NPN

Figure 8.25 Using PWM to control the brightness of a light bulb

No.8-77
The PIC18 Microcontroller

Example 8.14 Write a program to dim the lamp in Figure 8.25 to 10% of its brightness
in 5 seconds assuming that the PIC18 is running with a 32 MHz crystal oscillator.
Solution:
- Set duty cycle to 100% initially. Load 99 and 400 as the initial period and duty
cycle register values.
- Dim the lamp by 10% in the first second by reducing the brightness in 10 steps.
- Dim the lamp down to 10% brightness in the next 4 seconds in 40 steps.
#include <p18F452.inc>
org 0x00
goto start
org 0x08
retfie
org 0x18
retfie
start bcf TRISC,CCP1,A ; configure CCP1 pin for output
movlw 0x81 ; Use Timer2 as the base timer for PWM1
movwf T3CON ; and enable Timer3 in 16-bit mode
movlw 0x63 ; set 100 as the period of the digital
movwf PR2,A ; waveform

No.8-78
The PIC18 Microcontroller

movlw 0x64 ; set 100 as the duty cycle


movwf CCPR1L,A ; "
movwf CCPR1H,A ; "
movlw 0x05 ; enable Timer2 and set its prescaler to 4
movwf T2CON,A ; "
movlw 0x0C ; enable PWM1 operation and set the lowest
movwf CCP1CON,A ; two bits of duty cycle to 0
movlw 0x0A ; use PRODL as the loop count
movwf PRODL,A ; "
loop_1s call delay ; call "delay" to delay for 100 ms
decf CCPR1L,F,A ; decrement the duty cycle value by 1
decfsz PRODL,F,A ; check to see if loop index expired
goto loop_1s
movlw 0x28 ; repeat the next loop 40 times
movwf PRODL,A ; "
loop_4s call delay ; call "delay" to delay for 100 ms
decf CCPR1L,F,A ; decrement duty cycle value by 2
decf CCPR1L,F,A ; "
decfsz PRODL,F,A ; is loop index expired?
goto loop_4s
forever nop
bra forever

No.8-79
The PIC18 Microcontroller

Lamp Dimming C Program

#include <p18F452.h>
#include <pwm.h>
#include <timers.h>
void delay (void);
void main (void)
{
int i;
TRISCbits.TRISC2 = 0; /* configure CCP1 pin for output */
T3CON = 0x81; /* use Timer2 as base timer for CCP1 */
OpenTimer2 (TIMER_INT_OFF & T2_PS_1_4 & T2_POST_1_1);
SetDCPWM1 (400); /* set duty cycle to 100% */
OpenPWM1 (99); /* enable PWM1 with period equals 100 */
for(i = 0; i < 10; i++) {
delay();
CCPR1L --; /* decrement duty cycle value by 1 */
}
for(i = 0; i < 40; i++) {
delay();
CCPR1L -= 2; /* decrement duty cycle value by 2 */
}
}

No.8-80
The PIC18 Microcontroller

DC Motor Control
- DC motor speed is regulated by controlling its average driving voltage. The higher
the voltage, the faster the motor rotates.
- Changing motor direction can be achieved by reversing the driving voltage.
- Motor braking can be performed by reversing the driving voltage for certain length
of time.
- Most PIC18 devices have PWM functions that can be used to drive DC motors.
- Many DC motors operate with 5 V supply.
- DC motors require large amount of current to operate. Special driver circuits are
needed for this purpose.
- A simplified DC motor control circuit is shown in Figure 8.26.

PIC18 MCU

direction
RB4

speed
CCP1 on/off Driver DC motor

feedback
CCP2

Figure 8.26A simplified circuit for DC motor control

No.8-81
The PIC18 Microcontroller

DC Motor Driver L293


VSS
1 1 L293
0 16
CE1 1 L293 16 VSS 2 1
1 15
0 0 M
IN1 2 15 IN4
3 1 3
OUT1 3 14 OUT4 14
13
GND 4 13 GND 4
M 12
5
GND 5 12 GND
11
OUT2 6 11 OUT3
6 4
IN2 7 10 IN3 1 2 10 1
7 0 M
VS 8 9 CE2 0 9
8 1
0

(a) Pin Assignment VS (b) Motor connection

Figure 8.27 Motor driver L293 pin assignment and motor connection

No.8-82
The PIC18 Microcontroller

L293 Motor Driver


- The L293 has four channels and can deliver up to 1 A of current per channel.
- The L293 has separate logic supply and takes a logic input to enable or disable each
channel.
- Clamping diodes are provided to drain the kickback current generated from the
inductive load during the motor reversal.

FeedBack
- DC motor needs the speed information to adjust the voltage output to the motor
driver circuit.
- A sensing device such as Hall-effect transistor can be used to measure the motor
speed.
- The Hall-effect transistor can be mounted on the shaft (rotor) of a DC motor and
magnets are mounted on the armature (stator).
- The attachment of the Hall-effect transistors is shown in Figure 8.28.
- Each time the magnet passes by the Hall-effect transistor, a pulse is generated.
- CCP capture mode can be used to measure the motor speed.
- The schematic of a motor-control system is illustrated in Figure 8.29.

No.8-83
The PIC18 Microcontroller

Magnets

Hall-effect
transistor

T/2
T is the time for one revolution
Figure 8.28 The output waveform of the Hall-effect transistor

No.8-84
The PIC18 Microcontroller

VCC VCC
PIC18F452
1 16
8 3
15
CCP1 2 6.8F
13
RB4 7
12
0.33 F
4 L293
5
9 M
10 6
NC
11 14 VCC
VCC 6.8F
CCP2 1
30137
10K 3 2

All diodes are the same and could be any one of the 1N4000 series Hall-effect
switch
Figure 8.29 Schematic of a PIC18-based motor-control system

No.8-85
The PIC18 Microcontroller

- Pin 2 and pin 7 drives the two terminals of the DC motor.


- Depending on the voltages applied to pin 2 and pin 7, the motor can be rotating in
clockwise or counterclockwise direction as shown in Figure 8.30.

L293
PWM (CCP1)
A When A = B, torque
applied to motor = 0
A

Motor When A B, motor runs


B
off off
Port Pin (RB4) B
clockwise counterclockwise

Figure 8.30 The L293 motor driver

No.8-86
The PIC18 Microcontroller

Electrical Braking
- Once a DC motor is running, it picks up speed.

- Turning off the voltage to the motor does not stop the motor immediately.

- The momentum of the DC motor will keep the motor running after the voltage it

turned off.

- An abrupt stop may be achieved by reversing the voltage applied to the motor .

- The duration of braking needs to be precisely measured.

No.8-87
The PIC18 Microcontroller

Example 8.15 For the circuit shown in Figure 8.29, write a function in C language to
measure the motor speed (in RPM) assuming that the PIC18 MCU is running with a 20
MHz crystal oscillator.
Solution:
- Motor speed can be measured by capturing two consecutive rising or falling edges.
- Let diff and f are the difference of two captured edges and the Timer1 frequency.

Speed = 60  f  ( 2  diff)

No.8-88
The PIC18 Microcontroller

unsigned int motor_speed(void)


{
unsigned int edge1, diff, rpm;
long unsigned temp;

T3CON = 0x81; /* enables Timer3 in 16-bit mode and use Timer1 and Timer2 for
CCP1 thru CCP2 operations */
OpenTimer1(TIMER_INT_OFF & T1_16BIT_RW & T1_SOURCE_INT &
T1_PS_1_4); /* set Timer1 prescaler to 1:4 */
PIR2bits.CCP2IF = 0;
OpenCapture2(CAPTURE_INT_OFF & C2_EVERY_RISE_EDGE);
while (!PIR2bits.CCP2IF);
edge1 = CCPR2; /* save the first rising edge */
PIR2bits.CCP2IF = 0;
while (!PIR2bits.CCP2IF);
CloseCapture2();
diff = CCPR2 - edge1; /* compute the difference of two rising consecutive edges */
temp = 1250000ul/(2 * diff);
rpm = temp * 60;
return rpm;
}

No.8-89
The PIC18 Microcontroller

Example 8.16 Write a subroutine to perform the electrical braking.


Solution: Electrical braking is implemented by setting the duty cycle to 0% and
setting the voltage on the RB4 pin to high for certain amount of time. The braking
program is as follows:

brake bsf PORTB,RB4,A ; reverse the applied voltage to motor


movlw 0x00 ; “
movwf CCPR1L,A ; set PWM1 duty cycle to 0
call brake_time ; wait for certain amount of time
bcf PORTB,RB4,A ; stop braking
return

No.8-90
The PIC18 Microcontroller

Chapter 9

Universal Synchronous Asynchronous


Receiver Transceiver

No.9-1
The PIC18 Microcontroller

Why Serial Communication?

- Parallel I/O uses many signal pins.


- Synchronization problem over longer distance
- Cost of cable
- Many applications do not need high data rate

Types of Serial I/O

1. USART (universal synchronous asynchronous receiver and transceiver)


2. SPI (synchronous peripheral interface)
3. I2C (inter-integrated circuit)
4. CAN bus (controller area network bus)
5. LIN (local interconnect network) – won‘t be covered

No.9-2
The PIC18 Microcontroller

The EIA232 Standard

- Developed in 1960 by electronic industry association.


- The latest revision is EIA232E.
- EIA232 is also referred to as RS232 for historical reason.
- Both computers and terminals are called data terminal equipment (DTE).
- Modems, bridges, and routers are called data communication equipment (DCE).
- There are four aspects to the EIA232:

1. Electrical specifications
2. Functional aspects—the function of each signal
3. Mechanical specifications
4. Procedural specifications

No.9-3
The PIC18 Microcontroller

Electrical Specifications

- Data rates: EIA232 is applicable to data rate no more than 20 Kbps. The most
commonly used data rates are 300, 1200, 2400, 9600, and 19200 baud

- Signal state voltage assignments:


1. voltages between -3 V to -25 V are considered as logic 1
2. voltages between +3 V to 25 V are considered as logic 0
- Signal transfer distance: Signal should be able to transferred correctly up to 15 meters.

No.9-4
The PIC18 Microcontroller

Functional Specifications

- Twenty-two signals are defined.


- Signals are divided into six groups:

1. Signal ground and shield


2. Primary communication channel
3. Secondary communication channel
4. Modem status and control signals
5. Transmitter and receiver timing signals
6. Channel test signals

- Secondary communication channel consists of the same signals as in the primary


channel but rarely used.
- Timing signals are not used in asynchronous mode
- Channel test signals are not used in normal communications

No.9-5
The PIC18 Microcontroller

Primary Communication Channel Signals

- Pin 2: transmit data


- Pin 3: receive data
- Pin 4: request to send signal (RTS)—asserted when in logic 0
- Pin 5: clear to send signal (CTS)—asserted when in logic 0

Modem Status and Control Signals

- Pin 6: data set ready (DSR)—asserted when in logic 0


- Pin 20: DTE ready (DTR)—asserted when in logic 0
- Pin 8: received line signal detector (CD)—also called carrier detect, asserted in logic 0
- Pin 22: ring indicator (RI)—asserted when in logic 0
- Pin 23: data signal rate selector—asserted when in logic 0

No.9-6
The PIC18 Microcontroller

Mechanical Specification
- Specifies a 25-pin connector
- A 9-pin connector is used most often in PC but not specified in the standard

No.9-7
The PIC18 Microcontroller
Signal Signal
Direction Signal Name Signal Name Direction

to DCE Secondary transmitted data 1 Protective ground Both


14
to DTE Transmit clock 2 Transmitted data to DCE
15
to DTE Secondary received data 3 Received data to DTE
16
to DTE Receiver clock 4 Request to send to DCE
17
5 Clear to send to DTE
Unassigned 18
to DCE Secondary request to send 6 Data set ready to DTE
19
7 Signal ground Both
to DCE Data terminal ready 20
8 Carrier detect to DTE
to DTE Signal quality detect 21
Ring indicator 9 Reserved
to DTE 22
Both Data rate select 10 Reserved
23
11 Unassigned
to DCE Transmit clock 24
12 Secondary carrier detect to DTE
Unassigned 25
13 Secondary clear to send to DTE

Figure 9.1a EIA232E DB25 connector and pin assignment

5 Ground
Ring Indicator 9
4 DTE Ready
Clear to Send 8
3 Transmitted Data
Request to send 7
2 Received Data
DCE Ready 6
1 Received Line Signal Detect

Figure 9.1b EIA232E DB9 connector and signal assignment

No.9-8
The PIC18 Microcontroller

EIA232 Procedural Specification

Case 1: Point-to-point asynchronous connection

Computer Modem Modem Computer


(DTE) (DCE) (DCE) (DTE)
Tx Tx Tx Tx
Rx Rx Rx Rx
CD CD Direct link CD CD
CTS CTS CTS CTS
RTS RTS RTS RTS
DSR DSR DSR DSR
GND GND GND GND

Tx: transmit data CTS: clear to send


Rx: receive data RTS: request to send
CD: data carrier detect DSR: data set ready

Figure 9.2 Point-to-point asynchronous connection

No.9-9
The PIC18 Microcontroller

Sequence of events occurred during data transmission over dedicated link

Time
Local Remote
1. DCE asserts DSR

2. DTE asserts RTS


3. DCE asserts CTS

4. DTE starts to send


data (to local DCE)

5. DCE sends out a


carrier and then the
modulated data 6. DCE asserts DCD

7. DTE waits for


arrival of data

8. DCE sends out


demodulated
received data
9. DEC receives
demodulated data

No.9-10
The PIC18 Microcontroller

Case 2: two DTEs exchange data over public phone lines

- Two additional signals are needed: DTR and RI


- There are three phases in the data transmission:
1. Establishing the connection
2. Data transmission
3. Disconnection

Computer Modem Modem Computer


(DTE) (DCE) (DCE) (DTE)

Tx Tx Tx Tx
Rx Rx Rx Rx
RING RING RING RING
Phone line
DCD DCD DCD DCD
CTS CTS CTS CTS
RTS RTS RTS RTS
DSR DSR DSR DSR
DTR DTR DTR DTR
GND GND GND GND

Figure 9.3 Asynchronous connection over public phone line

No.9-11
The PIC18 Microcontroller

time
Local (transmission side) Remote (receiving side)
Connection
establishment
phase
1. DTE asserts DTR

2. DCE dials the


phone number 3. DCE detects the ring
and asserts RING
4. DTE asserts DTR
to accept the call

5. DCE sends out a


carrier and asserts
6. DCE asserts DSR DSR
and DCD and also
sends out a carrier
for full duplex
operation
7. DCE asserts DCD
(full duplex operation)

No.9-12
The PIC18 Microcontroller

Sequence of events occur during data transmission (continued)

time
Local (transmission side) Remote (receiving side)
Data
transmission
phase
1. DTE asserts RTS

2. DCE asserts CTS

3. DTE sends out


data to DCE
4. DCE modulates data
and sends it out 5. DCE demodulates
data and forwards
the data to DTE 6. DTE receives
data
Disconnection
phase

1. DTE drops RTS


2. DCE drops CTS
and drops the carrier
3. DCE deasserts
DCD & DSR
4. DTE deasserts
DTR

No.9-13
The PIC18 Microcontroller

Data Format

- Data is transmitted character by character


- Each character is preceded by a start bit, followed by seven to nine data bits, and
terminated by one to two stop bits.
- The receiver uses a clock signal with a frequency that is a multiple (usually 16) of the
data rate to sample the incoming data in order to detect the arrival of start bit and
determine the bit values.
- A majority circuit takes three samples (bit 7, 8, and 9) in each bit time to detect the
arrival of the start bit and determine the logic value of each data bit.
- In older designs, a character can be terminated by one, one and a half, two stop bits.
- In new designs, only one stop bit is used.

Start Stop Stop


0 1 2 3 4 5 6 7
bit bit 1 bit 2

Figure 9.4 The format of a character

No.9-14
The PIC18 Microcontroller

Example 9.1 Sketch the output of the letter K when it is transmitted using the format of
one start bit, eight data bits, and one stop bit.
Solution: Letters are represented in ASCII code. The ASCII code of letter K is $4B (=
01001011). The format of the output of letter K is shown in Figure 9.6.

Start bit Stop bit

0 1 1 0 1 0 0 1 0 1

(a) output waveform at microcontroller interface

0 1 1 0 1 0 0 1 0 1
(b) output waveform at EIA232E interface
Figure 9.6 Data format for letter k

No.9-15
The PIC18 Microcontroller

Data Transmission Errors

1. Framing error
- May occur due to clock synchronization problem
- Can be detected by the missing stop bit
2. Receiver overrun
- May occur when the CPU did not read the received data for a while
3. Parity errors
- Occur due to odd number of bits change values

No.9-16
The PIC18 Microcontroller

Null Modem Connection


- Used when two DTEs are located side by side and use the EIA232 interface to
exchange data.
- Null modem connection connects signals in such a way to full two DTEs to think
that they connected through a modem.
- In Figure 9.7, the signals on the same row of DTE1 and DTE2 are connected
together.
- The cost of two modems are saved with Null modem connection.

DTE 1 DTE 2
Signal Name Signal Name
DB25 pin DB9 pin DB9 pin DB25 pin
FG (frame ground) 1 - - 1 FG
TD (transmit data) 2 3 2 3 RD
RD (receive data) 3 2 3 2 TD
RTS (request to send) 4 7 8 5 CTS
CTS (clear to send) 5 8 7 4 RTS
SG (signal ground) 7 5 5 7 SG
DSR (data set ready) 6 6 4 20 DTR
CD (carrier detect) 8 1 4 20 DTR
DTR (data terminal ready ) 20 4 1 8 CD
DTR (data terminal ready ) 20 4 6 6 DSR

Figure 9.7 Null Modem connection

No.9-17
The PIC18 Microcontroller

The PIC18 Serial Communication Interface

- A serial communication interface can be called a USART or UART.


- A USART supports both synchronous and asynchronous modes of operation.
- A PIC18 device supports either one or two identical USARTs.
- The USART port can be used to communicate with a CRT terminal, a personal
computer, A/D converter, D/A converter, and serial EEPROMs.
- The USART can operate in three modes:

1. Asynchronous mode (full duplex)


2. Synchronous—master (half duplex)
3. Synchronous—slave (half duplex)

USART-Related Pins

- RC6/TX1/CK1 and RC7/RX1/DT1 (USART1)


- RG1/TX2/CK2 and RG2/TX2/DT2 (USART2)

USART-Related Registers
- Transmit status register (TXSTA) - Transmit register (TXREG)
- Receive status register (RCSTA) - Receive register (RCREG)
- Baud rate generate register (SPBRG)

No.9-18
The PIC18 Microcontroller

7 6 5 4 3 2 1 0

Value after CSRC TX9 TXEN SYNC -- BRGH TRMT TX9D


reset 0 0 0 0 0 0 1 0

CSRC: Clock Source Select bit


Asynchronous mode: (don't care)
Synchronous mode:
0 = Slave mode (clock from external source)
1 = Master mode (clock generated internally from BRG)
TX9: 9-bit Transmit Enable bit
0 = selects 8-bit transmission
1 = selects 9-bit transmission
TXEN: Transmit Enable Bit
0 = Transmit disabled
1 = Transmit enabled
SYNC: USART Mode Select Bit
0 = Asynchronous mode
1 = Synchronous mode
BRGH: High Baud Rate Select Bit
Asynchronous mode:
0 = low speed
1 = high speed
Synchronous mode (unused)
TRMT: Transmit Shift Register Status Bit
0 = TSR full
1 = TSR empty
TX9D: 9th bit of transmit data
Can be Address/Data bit or a parity bit

Figure 9.8 The TXSTA Register (redraw with permission of Microchip)

No.9-19
The PIC18 Microcontroller
7 6 5 4 3 2 1 0

Value after SPEN RX9 SREN CREN ADDEN FERR OERR RX9D
reset 0 0 0 0 0 0 1 0
SPEN: Serial Port Enable bit
0 = Serial port disabled
1 = Serial port enabled
RX9: 9-bit Receive Enable bit
0 = Selects 8-bit reception
1 = Selects 9-bit reception
SREN: Single Receive Enable bit
Asynchronous mode (don't care)
Synchronous mode - Master (This bit is cleared after reception is complete):
0 = Disables single receive
1 = Enables single receive
Synchronous mode - Slave: (don't care)
CREN: Continuous Receive Enable bit
Asynchronous mode:
0 = Disables receiver
1 = Enables receiver
Synchronous mode:
0 = Disables continuous receive
1 = Enables continuous receive (CREN overrides SREN)
ADDEN: Address Detect Enable bit
Asynchronous mode 9-bit (RX9 = 1):
0 = Disables address detection, all bytes are received, and 9th bit can be used
as parity bit.
1 = Enables address detection, enable interrupt and load of the receive buffer
when RSR<8> is set
FERR: Framing Error bit
0 = no framing error
1 = Framing error
OERR: Overrun Error bit
0 = No overrun error
1 = Overrun error (can be cleared by clearing bit CREN)
RX9D: 9th bit of Received Data
This can be Address/Data bit or a parity bit, and must be calculated by firmware.
Figure 9.9 The RXSTA Register (redraw with permission of Microchip)

No.9-20
The PIC18 Microcontroller

- The shift clock for the USART is generated by the baud rate generator (SPBRG).
- In asynchronous mode, the BRGH bit of the TXSTA register also involves in the baud
rate computation.
- The baud rate is computed using the formula shown in Table 9.2.

Table 9.2 Formula for baud rate


SYNC bit BRGH = 0 (low speed) BRGH = 1 (high speed)
0 (Asynchronous) Baud rate = FOSC/(64 (X+1)) Baud Rate = FOSC/(16(X+1))
1 (Synchronous) Baud Rate = FOSC/(4(X+1)) N/A

Note. X is the content of the SPBRG register

In asynchronous mode:
When BRGH = 1, SPBRG = (FOSC/(16 x baud rate)) - 1
When BRGH = 0, SPBRG = (FOSC/(64 x baud rate)) - 1
In synchronous mode:
SPBRG = (FOSC/(4 x baud rate)) - 1

No.9-21
The PIC18 Microcontroller

Example 9.2 Compute the value to be written into the SPBRG register to generate 9600
baud for asynchronous mode high-speed transmission assuming the frequency of the crystal
oscillator is 20 MHz.
Solution: The value (for BRGH = 1) to be written into the SPBRG register is

SPBRG = 20  106  (16  9600) – 1 = 130 – 1 = 129

The actual baud rate is

20,000,000  (16  130) = 9615.4

The resultant error rate is (9615.4 – 9600)  9600  100% = 0.16%.

The same baud rate can also be achieved by using low speed (BRGH = 0) approach in which

SPBRG = 20,000,000  (64  9600) – 1 = 31

The actual baud rate is

20000000  (64  32) = 9765.6

The resultant error rate is (9765.6 – 9600)  9600  100% = 1.7%.

No.9-22
The PIC18 Microcontroller

Example 9.3 Write a subroutine to configure the USART1 transmitter to transmit data
in asynchronous mode using 8-bit data format, disable interrupt, set baud rate to 9600.
Assume the frequency of the crystal oscillator is 16 MHz.
Solution:
- Write the value of 0x24 into the TXSTA1 register
- Configure TX1 pin for output, RX1 pin for input:

usart1_open movlw 0x24


movwf TXSTA1
movlw D‘103‘ ; set baud rate to 9600
movwf SPBRG1 ; ―
bsf TRISC,RC7 ; configure RX1 pin for input
bcf TRISC,RC6 ; configure TX1 pin for output
bcf PIE1,TXIE ; disable transmit interrupt
bsf RCSTA1,SPEN ; enable USART1
return

No.9-24
The PIC18 Microcontroller

In C language,

void usart1_open(void)
{
TXSTA1 = 0x24;
SPBRG1 = 103;
TRISCbits.RC7 = 1; /* configure RX1 pin for input */
TRISCbits.RC6 = 0; /* configure TX1 pin for output */
PIE1bits.TXIE = 0; /* disable transmit interrupt */
RCSTA1bits.SPEN = 1; /* enable USART port */
}

No.9-25
The PIC18 Microcontroller

Example 9.4 Write a subroutine to output the character in WREG to USART1 using
the polling method.
Solution:
- Data can be sent to the transmitter only when the transmit register is empty.

putc_usart1 btfss PIR1,TXIF,A ; wait until TXIF flag is set before output
bra putc_usart1
movwf TXREG1
return

In C language,

void putc_usart1 (char xc);


{
while (!PIR1bits.TX1IF);
TXREG1 = xc;
}

No.9-26
The PIC18 Microcontroller

Example 9.5 Write a subroutine to output a string (in program memory) pointed to by
TBLPTR and terminated by a NULL character from USART1.
Solution:
; *******************************************************************
; The following subroutine outputs the string pointed to by TBLPTR. It is called
; with fast save enabled.
; *******************************************************************
puts_usart1 TBLRD*+ ; read one character into TABLAT
movf TABLAT,W,A ; place the character in WREG
bz done ; is it a NULL character?
call putc_usart1 ; not NULL, output
bra puts_usart1 ; continue
done return fast

In C language,

void puts_usart1 (unsigned rom char *cptr)


{
while(*cptr)
putc_usart1 (*cptr++);
}

No.9-27
The PIC18 Microcontroller

CREN OERR FERR

x64 Baud rate CLK


 msb RSR register lsb
SPBRG or
 STOP (8) 7 ... 0 START
Baud rate generator

RX pin
RX9
Pin Buffer Data
and Control Recovery
FIFO
RX9D RCREG Register
SPEN
interrupt
RCIF
RCIE 8

Data Bus
Figure 9.11 USART receive block diagram (redraw with permission of Microchip)

No.9-28
The PIC18 Microcontroller

Example 9.6 Write an instruction sequence to configure the USART1 to receive data in
asynchronous mode using 8-bit data format, disable interrupt, set baud rate to 9600.
Assume that the frequency of the crystal oscillator is 16 MHz.
Solution:

movlw 0x90 ; enable USART1 and receiver


movwf RCSTA1,A
movlw D‘103‘
movwf SPBRG1,A ; set up baud rate to 9600
bsf TRISC,RX1,A ; configure RX1 pin for input
bcf TRISC,TX1,A ; configure TX1 pin for input

In C language,

RCSTA1 = 0x90;
SPBRG = 103;
TRISC |= 0x80; /* configure RC7/RX1 pin for input */
TRISC &= 0xBF /* configure RC6/TX1 pin for output */

No.9-29
The PIC18 Microcontroller

Example 9.7 Write a subroutine to read a character from USART1 and return the
character in WREG using the polling method. Ignore any errors.
Solution: A new character is received if the RCIF flag of the PIR1 register is set to 1.
getc_usart1 btfss PIR1,RCIF ; make sure a new character has been received
bra getc_usart1
movf RCREG1,W ; read the character
return FAST

In C language,

unsigned char getc_usart1 (void)


{
while (!PIR1bits.RCIF);
return RCREG1;
}

No.9-30
The PIC18 Microcontroller

Example 9.8 Write a subroutine to read a string from the USART1 and store the string
in a buffer pointed to by FSR0.
Solution:
The string from the USART port is terminated by a carriage return character.

CR equ 0x0D
gets_usart1 call getc_usart1
movwf INDF0 ; save the character in buffer
sublw CR
bz done
clrf PREINC0,F ; move the pointer
goto gets_usart1
done clrf INDF0 ; terminate the string with a NULL character
return

No.9-31
The PIC18 Microcontroller

In C language,

#define CR 0x0D
void gets_usart1 (char *ptr)
{
char xx;
while (1)
{
xx = getc_usart1( ); /* read a character */
if (xx == CR) { /* is it a carriage return? */
*ptr = ‗\0‘; /* terminate the string with a NULL */
return;
}
ptr++ = xx; /* store the received character in the buffer */
}
}

No.9-32
The PIC18 Microcontroller

Flow Control of USART in Asynchronous Mode

- In some circumstances, the software cannot read the received data and needs to inform
the transmitter to stop.
- In some other situation, the transmitter may need to be told to suspend transmission
because the receiver is too busy to read data.
- Both situations are handled by flow control.
- There are two flow control methods: hardware and XON/XOFF.
- XON and XOFF are two standard ASCII characters.
- The ASCII code for XON and XOFF are 0x11 and 0x13, respectively.
- Whenever a microcontroller cannot handle the incoming data, it sends the XOFF to
the transmitter.
- When the microcontroller can handle incoming characters, it sends out XON
character.

No.9-33
The PIC18 Microcontroller

C Library Functions for USART


Table 9.3a Library functions for devices with only one USART
Function Description
BusyUSART Is the USART transmitting?
CloseUSART Disable the USART
DataRdyUSART Is data available in the USART read buffer?
getcUSART Read a byte from USART
getsUSART Read a string from USART
OpenUSART Configure the USART
putcUSART Write a byte to the USART
putsUSART Write a string from data memory to the USART
putrsUSART Write a string from program memory to the USART
ReadUSART Read a byte from the USART
WriteUSART Write a byte to the USART

Table 9.3b Library functions for devices with multiple USARTs


Function Description
BusyxUSART Is the USART x transmitting?
ClosexUSART Disable the USART x
DataRdyxUSART Is data available in the USART x read buffer?
getcxUSART Read a byte from USART x
getsxUSART Read a string from USART x
OpenxUSART Configure the USART x
putcxUSART Write a byte to the USART x
putsxUSART Write a string from data memory to the USART x
putrsxUSART Write a string from program memory to the USART x
ReadxUSART Read a byte from the USART x
WritexUSART Write a byte to the USART x
Note. x = 1 or 2

No.9-34
The PIC18 Microcontroller

The following functions return a ―1‖ if the transmitted is busy:

char BusyUSART (void); -- used on devices with single USART


char Busy1USART (void); -- used on devices with two USARTs
char Busy2USART (void); -- used on devices with two USARTs

The following functions disable the transmitter and receiver:

void CloseUSART (void); -- used on devices with single USART


void Close1USART (void); -- used on devices with two USARTs
void Close2USART (void); -- used on devices with two USARTs

The following functions return a ―1‖ if the RCIF flag is set:

char DataRdyUSART (void); -- used on devices with single USART


char DataRdy1USART (void); -- used on devices with two USARTs
char DataRdy2USART (void); -- used on devices with two USARTs

No.9-35
The PIC18 Microcontroller

Any one of the following functions read a byte from the receive buffer including the 9 th
bit:

char getcUSART (void); -- used on devices with single USART


char getc1USART (void); -- used on devices with two USARTs
char getc2USART (void); -- used on devices with two USARTs
char ReadUSART (void); -- used on devices with single USART
char Read1USART (void); -- used on devices with two USARTs
char Read2USART (void); -- used on devices with two USARTs

The following functions read the specified number of byes from the USART module and
save the string in a buffer:

void getsUSART (char *buffer, unsigned len); -- for devices with single USART
char gets1USART (char *buffer, unsigned len); -- for devices with two USART
char gets2USART (char *buffer, unsigned len); -- for devices with two USART

No.9-36
The PIC18 Microcontroller

The status bit and the 9th data bit are saved in a union with the following declaration:

union USART
{
unsigned char val;
struct
{
unsigned RX_NINE: 1;
unsigned TX_NINE: 1;
unsigned FRAME_ERROR: 1;
unsigned OVERRUN_ERROR: 1;
unsigned fill: 4;
};
};

No.9-37
The PIC18 Microcontroller

The following functions write one character to the transmit buffer:

char putcUSART (char data); -- used on devices with single USART


char putc1USART (char data); -- used on devices with two USARTs
char putc2USART (char data); -- used on devices with two USARTs
char WriteUSART (char data); -- used on devices with single USART
char Write1USART (char data); -- used on devices with two USARTs
char Write2USART (char data); -- used on devices with two USARTs

The following functions output a string in program memory to the USART module:

void putrsUSART (const rom char *data); -- used on devices with single USART
void putrs1USART (const rom char *data); -- used on devices with two USARTs
void putrs2USART (const rom char *data); -- used on devices with two USARTs

The following functions output a string in data memory to the USART module:

void putsUSART (char *data); -- used on devices with single USART


void puts1USART (char *data); -- used on devices with two USARTs
void puts2USART (char *data); -- used on devices with two USARTs

No.9-38
The PIC18 Microcontroller

The following functions configured the specified USART module:

void OpenUSART (unsigned char config,


char spbrg); -- used on devices with single USART
void Open1USART (unsigned char config,
char spbrg); -- used on devices with two USARTs
void Open2USART (unsigned char config,
char spbrg); -- used on devices with two USARTs

The config parameter is defined by ANDing the following parameters:

Interrupt on Transmission:
USART_TX_INT_ON Transmit interrupt ON
USART_TX_INT_OFF Transmit interrupt OFF
Interrupt on Reception:
USART_RX_INT_ON Receive interrupt ON
USART_RX_INT_OFF Receive interrupt OFF
USART Mode:
USART_ASYNCH_MODE Asynchronous mode
USART_SYNCH_MODE Synchronous mode

No.9-39
The PIC18 Microcontroller

Transmission Width:
USART_EIGHT_BIT 8-bit transmit/receive
USART_NINE_BIT 9-bit transmit/receive
Slave/Master Select:
USART_SYNC_SLAVE Synchronous slave mode
USART_SYNC_MASTER Synchronous master mode
Reception mode:
USART_SINGLE_RX Single reception
USART_CONT_RX Continuous reception
Baud rate: (applied to asynchronous mode only)
USART_BRGH_HIGH High baud rate
USART_BRGH_LOW Low baud rate

The spbrg is the value to be written into the SPBRG register to set the baud rate.

An example,
Open1USART (USART_TX_INT_OFF & USART_RX_INT_OFF &
USART_ASYNCH_MODE & USART_EIGHT_BIT &
USART_BRGH_HIGH, 103);

No.9-40
The PIC18 Microcontroller

Interface Asynchronous Mode USART with EIA232

- The USART in asynchronous mode is mainly used with the EIA232 interface.
- The USART module uses 0 and 5V to represent logic 0 and 1 and hence cannot be
connected to the EIA232 circuit directly.
- A circuit called EIA232 transceiver is needed to translate the voltage levels of the
USART to and from the voltage levels of the EIA232 interface.
- EIA232 transceivers are available from many vendors.
- LT1080/1081 from Linear Technology, ST232 from SGS Thompson, the ICL232
from Intersil, the MAX232 from MAXIM, and the DS14C232 from National
Semiconductor are examples of the EIA232 transceiver. These EIA232 transceivers
operate with a 5-V power supply.
- The pin assignment of the MAX232 is shown in Figure 9.12.
- The circuit connection of the MAX232 with the PIC18 is shown in Figure 9.13.

No.9-41
The PIC18 Microcontroller
+5 V
6.3V
0.1F - +
16 0.1F C4

1 VCC
C1+
2
C1 0.1F V+
3
C1-
4 6
C2+ V-
C3 0.1F
C2 0.1F DC-to-DC Converter
5
C2-
+5 V

TTL/CMOS 11 T1IN D1
T1OUT 14

inputs +5 V
EIA-232-E
outputs
10 T2IN T2OUT 7
TTL/CMOS D2
inputs

TTL/CMOS 12 R1OUT R1IN 13


outputs R1
5K EIA-232-E
inputs
TTL/CMOS 9 R2OUT R2IN 8
outputs R2
5K

GND
15

Figure 9.12 Pin assignments and connections of the MAX232A

No.9-42
The PIC18 Microcontroller

MAX232 1
DCD
6 DSR

11 14 2
RC6/TX T1IN T1OUT RxD

10 8 7 RTS
CTS* T2IN R2IN
12 13 3
RC7/RX R1OUT R1IN TxD
9 7 8 CTS
RTS* R2OUT T2OUT
4
DTR
Note: Both CTS and RTS are
jumpered to an I/O pin in case 9 RI
hardware handshake is needed
5
GND

DB9 connector

Figure 9.13 Diagram of USART and EIA232 DB9 connector wiring in SSE452,
SSE8680, and SSE8720 demo boards

No.9-43
The PIC18 Microcontroller

USART Synchronous Master Mode

- This mode is entered by setting bits SYNC, SPEN and CSRC.


- Data is transmitted in half-duplex mode.
- The clock signal is driven out from the CK pin.

Synchronous Master Transmission


- Setting the TXEN bit enables the USART module, which will start the SPBRG
circuit to generate the shift clock.
- The actual data transmission does not start until a byte is written into the TXREG
register.
- The data bits are shifted out on the rising edge of CK and becomes stable on the
falling edge of the same clock period.

Synchronous Master Reception


- Reception is enabled by setting the SREN or CREN bit.
- Data is sampled on the falling edge of the CK clock.
- If only the SREN bit is set, only one character will be received.
- If the CREN bit is set, the reception will continue until the CREN bit is cleared.

No.9-44
The PIC18 Microcontroller

QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ QQQQ
1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4

RC/RX/DT bit 0 bit 1 bit 2 bit 3 bit 4 bit 5 bit 6 bit 7

RC6/TX/CK

Write to
TXREG

TXIF bit

TRMT bit

TXEN bit

Figure 9.14 USART transmission in synchronous master mode (redraw with permission of
Microchip)

No.9-45
The PIC18 Microcontroller

QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ QQQQ
1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4

RC/RX/DT bit 0 bit 1 bit 2 bit 3 bit 4 bit 5 bit 6 bit 7

RC6/TX/CK

Write to
SREN

SREN bit

CREN bit '0'

RCIF bit
(interrupt)

Figure 9.15 USART reception in synchronous master mode (SREN=1)


(redraw with permission of Microchip)

No.9-46
The PIC18 Microcontroller

USART Synchronous Slave Mode

- Shift clock is provided by external device and is input to the CK pin.


- Slave mode is entered by setting both the SYNC and SPEN bits and clearing the
CSRC bit.

Synchronous Slave Transmission


- The shift clock signal is an input from the CK pin.
- CREN bit must be cleared.
- Transmission is enabled by setting the TXEN bit.
- Transmission is started by loading data into the TXREG register.

Synchronous Slave Reception


- Clock source is an input from the CK pin.
- When the RCIF flag is set, read the RCREG register to get the lower 8 bits.
- If 9-bit reception is enabled, then read the 9th bit from the RCSTA register.
- If there is any error, then clear the error by clearing the CREN bit.

No.9-47
The PIC18 Microcontroller

Applications of USART Synchronous Mode

- Interfacing with shift registers to expand the number of I/O ports.


- Exchange data with other PIC18 microcontrollers

The 74LS165 Shift Register


- Has parallel inputs P7…P0 to be loaded into 74LS165 when PL is low.
- Data is shifted in from the DS pin when the PL input is high, one clock input is
high, and the second clock input has a rising edge.
- Data is shifted out from Q7, which allows multiple 74LS165 to be concatenated.

VCC CP2 P3 P2 P1 P0 DS Q7
16 15 14 13 12 11 10 9

74LS165

1 2 3 4 5 6 7 8

PL CP1 P4 P5 P6 P7 GND
Q7

Figure 9.16 74LS165 pin assigment

No.9-48
The PIC18 Microcontroller

Table 9.4 Truth table of 74LS165


CP Contents
PL Response
1 2 Q0 Q1 Q2 Q3 Q4 Q5 Q6 Q7
L X X P0 P1 P2 P3 P4 P5 P6 P7 Parallel load
H L  DS Q0 Q1 Q2 Q3 Q4 Q5 Q6 right shift
H H  Q0 Q1 Q2 Q3 Q4 Q5 Q6 Q7 no change
H  L DS Q0 Q1 Q2 Q3 Q4 Q5 Q6 right shift
H  H Q0 Q1 Q2 Q3 Q4 Q5 Q6 Q7 no change

Example 9.9 Show the circuit connection for using one 74LS165 to add an input port
to the PIC18F8720 using the USART2 in synchronous master mode. Write a
subroutine to configure the USART2 properly and a subroutine to shift one byte of
data assuming that the PIC18F8720 is running with a 16-MHz crystal oscillator.
Assume that the user uses eight switches to set the value to be input and uses INT1
interrupt to inform the arrival of data.
Solution:
1. Use the synchronous master mode to interface with the 74LS165.
2. Configure RG2/DT2 and RG1/CK2 for input and output, respectively.
3. Set baud rate to 1 Mbps
4. Enable INT1 interrupt
5. Circuit connection is shown in Figure 9.17.

No.9-49
The PIC18 Microcontroller

PIC18F8720 74LS165 5V

VCC
RG1/CK CP2 P0 D7
P1 D6
RG2/DT2 Q7 P2 D5
P3 D4 connected
to DIP
INT1 DS P4 D3 switches
debounced
CP1 P5 D2
switch
P6 D1
RB4 PL P7 D0
GND

Figure 9.17 Circuit connection between the PIC18F8720 and 74LS165

No.9-50
The PIC18 Microcontroller

Procedure for inputting data from 74LS165

1. Set up a new value to P0 to P7 using the DIP switches.


2. Press the debounced switch to request an interrupt using the INT1 pin.
3. The INT1 interrupt service routine reads in the data from the RCREG2.

#include <p18F8720.inc>
rcv_buf set 0 ; buffer to hold the received byte
org 0x00
goto start
org 0x08
goto hi_ISR
org 0x18
retfie
start bcf TRISG,RG1,A ; configure CK2 pin for output
bsf TRISG,RG2,A ; configure DT2 pin for input
call open_usart2
call open_INT1
forever nop
bra forever

No.9-51
The PIC18 Microcontroller

; *****************************************************************
; The following function configures USART2 to operate in
; synchronous master mode with baud rate set to 10**6.
; *****************************************************************
open_usart2 movlw 0x03
movwf SPBRG2,A ; set the shift rate to 1MHz
movlw 0x90 ; set synchronous master mode
movwf TXSTA2,A ; "
movlw 0x80 ; enable USART2 and disable
movwf RCSTA2,A ; reception
return
; ************************************************************************
; The following subroutine configures INT1 to high priority and
; then enable its interrupt.
; ************************************************************************
open_INT1 bsf RCON,IPEN,A ; enable priority interrupt
movlw 0x48 ; set INT1 interrupt to high priority,
movwf INTCON3,A ; and then enable INT1 interrupt
movlw 0xC0 ; enable global interrupt
movwf INTCON ; "
return

No.9-52
The PIC18 Microcontroller

; *************************************************************************
; The high priority interrupt service routine makes sure
; that the interrupt is caused by usart2 INT1IF and then enable
; reception by setting SPEN bit. Wait until a byte is received.
; *************************************************************************
hi_ISR btfss INTCON3,INT1IF,A ; is interrupt caused by INT1?
retfie ; interrupt is not caused by INT1
bcf INTCON3,INT1IF,A ; clear INT1IF
bcf PORTB,RB4,A ; load data into 74LS165
nop ; "
bsf PORTB,RB4,A ; disable new data into 74LS165
bcf PIR3,RC2IF,A ;
bsf RCSTA2,SREN,A ; enable single reception from USART2
wait btfss PIR3,RC2IF,A ; wait for the arrival of a byte
bra wait
movff RCREG2,rcv_buf
retfie
end

No.9-53
The PIC18 Microcontroller

The 74LS164 Shift Register


- Has parallel outputs and two serial inputs
- Pin assignment and truth table are shown in Figure 9.18 and Table 9.5, respectively.
Q
VCC Q6 Q5 Q4 MR CP
7
14 13 12 11 10 9 8

74LS164

1 2 3 4 5 6 7
A B Q0 Q1 Q2 Q3 GND

Figure 9.18 74LS164 pin assigment

Table 9.5 Truth table of 74LS164

Operating Inputs Outputs


Mode A B Q0 Q1 - Q7
MR
Reset (clear) L X X L L-L
H L L L Q0 - Q6
H L H L Q0 - Q6
Shift
H H L L Q0 - Q6
H H H H Q0 - Q6

No.9-54
The PIC18 Microcontroller

Example 9.10 Show the circuit connection if you are to use one 74LS164 to add an
output port to the PIC18F8720 using the USART2 module in synchronous master
mode. Write a subroutine to shift out one byte of data assuming that the PIC18F8720 is
running with a 16-MHz crystal oscillator. The user may uses Q7..Q0 to drive LEDs.
Solution: The circuit connection is shown in Figure 9.19. Q7…Q0 should be used as
the least significant bit to the most significant bit.

PIC18F8720 74LS164 5V

VCC
RG1/CK CP Q7
Q6
RG2/DT2 A
Q5 used to
5V drive
Q4 output
B Q3 devces
such as
Q2 LEDs
MR
Q1
GND Q0

Figure 9.19 Circuit connection between the PIC18F8720 and 74LS164

No.9-55
The PIC18 Microcontroller

The following subroutine outputs the character in WREG to the USART2:

outc_usart2 bsf RCSTA2,SPEN ; enable USART2 port pins


poll2 btfss PIR3,TX2IF,A ; is TX2IF flag set?
bra poll2
movwf TXREG2,A
return

Using the USART Synchronous Mode to Exchange Data with other PIC18 MCUs

PIC18 MCU PIC18 MCU

RC7/TX1/CK1 RC7/TX1/CK1

RC7/RX1/DT1 RC7/RX1/DT1

(master mode) (slave mode)

Figure 9.20 Two PIC18s exchange data using USART synchronous mode

No.9-56
The PIC18 Microcontroller

Enhanced USART

- Newer PIC18 devices add some enhancements to the USART port:

1. Automatic baud rate detection and calibration


2. Sync break reception
3. 12-bit break character transmit
4. A baud rate control register (BAUDCONx, x = 1, or 2) is added for additional
baud control

- These additional features can be used to support the LIN protocol

No.9-57
The PIC18 Microcontroller

Chapter 9

Analog-to-Digital Converter

No.9-1
The PIC18 Microcontroller

Basics of A/D Conversion

- Can convert only electrical voltages to digital values


- A transducer is needed to convert a non-electric quantity into an electrical voltage
- Different names of transducers are used for different physical quantities
- A data acquisition system is used to referred to those systems that perform A/D
conversions.

temperature
pressure Digital
signal
voltage voltage A/D value
light Transducer conditioning Computer
weight circuit converter
airflow
Such as a (optional)
humidity sensor,
. load cell,
. photocall, or
. thermocouple
. Figure 12.1 The A/D conversion process
.

No.9-2
The PIC18 Microcontroller

Analog Voltage and Digital Code Characteristic

1. Characteristic of an Ideal A/D Converter

- Needs infinite number of bits to encode the A/D conversion result


- Unachievable and impractical
Digital Code

Voltage
Figure 12.2 An ideal A/D converter output characteristic

No.9-3
The PIC18 Microcontroller

Characteristic of an Ideal n-bit A/D Converter

- The area between dotted line and staircase is called the quantization error.
- The resolution of this A/D converter is VDD/2n.
- Average conversion error is VDD/2n+1.
- A real A/D converter has nonlinearity.

2 n-
1
output code

1
0 Voltage
VDD
n
VDD /2
Figure 12.3 Output characteristic of an ideal n-bit A/D
converter

No.9-4
The PIC18 Microcontroller

A/D Conversion Algorithms

1. Parallel (Flash) A/D converter


2. Slope and double-slope A/D converter
3. Sigma-Delta A/D converter
4. Successive Approximation A/D converter

Successive Approximation A/D Conversion Method


- Most commonly used A/D conversion method for 8-bit and 16-bit microcontrollers.

analog
comparator
+ Vin (analog input)
-

Successive VRH
Control Digital-to-analog
Clock Logic approximation
converter VRL
register (SAR)

Output Digital
Latch code

Figure 12.4 Block diagram of a successive approximation A/D converter

No.9-5
The PIC18 Microcontroller

Successive Approximation Method

Start

SAR[n-1, ..., 0]  0
in-1

SAR[i]  1

Convert the value in


SAR to a voltage
ii-1

Is the
Converted voltage yes
SAR[i]  0
greater than
the input?

no

no
i = 0?
yes
Sop

Figure 12.5 Successive approximation A/D conversion method

No.9-6
The PIC18 Microcontroller

Optimal Voltage Range for A/D Conversion

- A/D converter requires a low reference voltage (VREF-) and a high reference
voltage (VREF+) to perform conversion.
- Most A/D converters are ratiomertic:

1. An analog input of VREF- is converted to digital code 0.


2. An analog input of VREF+ is converted to digital code 2n – 1.
3. An analog input of k V is converted to digital code

(2n – 1)  (k - VREF-)  (VREF+ - VREF-)

- The A/D conversion result k corresponds to the following analog input:

VK = VREF- + (VREF+ - VREF-)  k  (2n – 1)

- Most systems use VDD and 0V as VREF+ and VREF-, respectively.


- The output of a transducer should be scaled and shifted to the range of 0V ~ V DD in
order to achieve the best accuracy

No.9-7
The PIC18 Microcontroller

Example 12.1 Suppose that there is a 10-bit A/D converter with VREF- = 1 V and VREF+
= 4V. Find the corresponding voltage values for the A/D conversion results of 25, 80,
240, 500, 720, 800, and 900.
Solution:
The corresponding voltages are as follows:

1V + (3  25)  (2^10 – 1) = 1.07 V


1V + (3  80)  (2^10 – 1) = 1.23 V
1V + (3  240)  (2^10 – 1) = 1.70 V
1V + (3  500)  (2^10 – 1) = 2.47 V
1V + (3  720)  (2^10 – 1) = 3.11 V
1V + (3  800)  (2^10 – 1) = 3.35 V
1V + (3  900)  (2^10 – 1) = 3.64 V

No.9-8
The PIC18 Microcontroller

Scaling Circuit

- Used to amplify the transducer output from a range of 0V ~ VZ to 0 ~ VDD.


- Usually VZ is smaller than VDD.
- Voltage gain of the circuit in Figure 12.6 is

AV = VOUT  VIN = (R1 + R2)  R1 = 1 + R2/R1 (12.2)

- Both R1 and R2 must be commercially available resistors.

VIN +
OP AMP VOUT

R1 R2

Figure 12.6 A voltage scaler

No.9-9
The PIC18 Microcontroller

Scaling Circuit VIN +


OP AMP VOUT
AV = VOUT  VIN = (R1 + R2)  R1 = 1 + R2/R1
R1 R2

Figure 12.6 A voltage scaler

Example 12.2 Suppose the transducer output voltage ranges from 0V to 200 mV.
Choose the appropriate values for R1 and R2 to scale this range to 0~5V.
Solution:

R2/R1 = (VOUT /VIN) – 1 = 24

Choose 240 KW for R2 and 10 KW for R1.

No.9-10
The PIC18 Microcontroller

Summing circuit (Fig 12.7-a of the textbook)


R0
Rf

+12 V
- R1 +12 V
741 VIN -
+ VM 741 VOUT
+
- 12 V R2
- 12 V
VM = - VIN V1 Rf
VOUT = VIN - Rf V1 (12-5)
R1 R2

Figure 12T.7 Level shifting and scaling circuit

No.9-11
The PIC18 Microcontroller

Inverting voltage follower circuit (Fig 12.7-b of the textbook)

R0
Rf

R0 +12 V
VIN - R1 +12 V
741 -
+ VM 741 V
+
- 12 V R2
- 12 V
VM = - VIN V1 Rf
VOUT = VIN - R
R1 R

Figure 12T.7 Level shifting and scaling circuit

No.9-12
The PIC18 Microcontroller

Voltage Translation Circuit


- Needed to shift and scale the transducer output in a range of –VX ~ VZ to 0V ~ VDD.

R0
Rf

R0 +12 V
VIN - R1 +12 V
741 -
+ VM 741 VOUT
+
- 12 V R2
- 12 V
VM = - VIN V1 Rf
VOUT = VIN - Rf V1
R1 R2

Figure 12T.7 Level shifting and scaling circuit

No.9-13
The PIC18 Microcontroller

R0 Example 12.3 Choose appropriate resistor values R and the adjusting voltage so that the
f the range of –1.2V ~ 3.0V to
circuit shown in Figure 12.7c can shift the voltage from
the range of 0V ~ 5V.
+12 Solution:
V Applying Equation 12.5:
R1 +12 V
41 0 = -1.2  (Rf/R1) – (Rf/R2)  V1 -
5 = 3.0V (Rf/R1) – (Rf/R2)  V1 741
M VOUT
+ R2 = 50 KW, and Rf = 12KW
Choose R0 = R1 = 10 KW and V1 = -5V, solve
12 V R2
- 12 V
= - VIN V1 Rf
VIN - Rf V1
M
VOUT =
R0
Rf
R1 R2
R0 +12 V
VIN -R +12 V
ure 12T.7 Level
741 shifting and scaling
V
- circuit 1

+ M 741 VOUT
+
- 12 V R2
- 12 V
VM = - VIN V1 Rf
VOUT = VIN - Rf V1 (12-5)
R1 R2

Figure 12T.7 Level shifting and scaling circuit


No.9-14
The PIC18 Microcontroller

The PIC18 A/D Converter

- The PIC18 has a 10-bit A/D converter.


- The number of analog inputs varies among difference PIC18 devices.
- The A/D converter has the following registers:

• A/D Result High Register (ADRESH)


• A/D Result Low Register (ADRESL)
• A/D Control Register 0 (ADCON0)
• A/D Control Register 1 (ADCON1)
• A/D Control Register 2 (ADCON2)

- The contents of these registers vary with the PIC18 members.


- Early PIC18 (PIC18FXX2) members have only ADCON0 and ADCON1 registers.

No.9-15
The PIC18 Microcontroller

ADCON0 Register
7 6 5 4 3 2 1 0
ADCS1 ADCS0 CHS2 CHS1 CHS0 GO/DONE -- ADON
value after
reset 0 0 0 0 0 0 0 0

ADCS1:ADCS0: A/D conversion clock select bits


(used along with ADCS2 of the ADCON1 register (shown in Table 12.1)
CHS2:CHS0: Analog channel select bits
000 = channel 0, (AN0)
001 = channel 1, (AN1)
010 = channel 2, (AN2)
011 = channel 3, (AN3)
100 = channel 4, (AN4)
101 = channel 5, (AN5)
110 = channel 6, (AN6)
111 = channel 7, (AN7)
GO/DONE: A/D conversion status bit
when ADON = 1
0 = A/D conversion not in progress
1 = A/D conversion in progress (setting this bit starts the A/D conversion.
This bit will be cleared by hardware when A/D conversion is done)
ADON: A/D on bit
0 = A/D converter module is shut-off
1 = A/D converter module is powered up
Figure 12.8a ADCON0 register (PIC18FXX2 and PIC18FXX8)
(redraw with permission of Microchip)

No.9-16
The PIC18 Microcontroller

Table 12.1 A/D conversion clock source select bits


ADCS2: ADCS0 Clock conversion
000 FOSC/2
001 FOSC/8
010 FOSC/32
011 FRC (clock derived from RC oscillator)
100 FOSC/4
101 FOSC/16
110 FOSC/64
111 FRC(clock derived from RC oscillator)

No.9-17
The PIC18 Microcontroller

7 6 5 4 3 2 1 0
-- -- CHS3 CHS2 CHS1 CHS0 GO/DONE ADON
value after
reset 0 0 0 0 0 0 0 0

CHS3:CHS0: Analog channel select bits


0000 = channel 0, (AN0)
0001 = channel 1, (AN1)
0010 = channel 2, (AN2)
0011 = channel 3, (AN3)
0100 = channel 4, (AN4)
0101 = channel 5, (AN5)
0110 = channel 6, (AN6)
0111 = channel 7, (AN7)
1000 = channel 8, (AN8)
1001 = channel 9, (AN9)
1010 = channel 10, (AN10)
1011 = channel 11, (AN11)
1100 = channel 12, (AN12)
1101 = channel 13, (AN13)
1110 = channel 14, (AN14)
1111 = channel 15, (AN15)
GO/DONE: A/D conversion status bit
when ADON = 1
0 = A/D conversion not in progress
1 = A/D conversion in progress (setting this bit starts the A/D conversion.
This bit will be cleared by hardware when A/D conversion is done)
ADON: A/D on bit
0 = A/D converter module is shut-off
1 = A/D converter module is powered up
Figure 12.8b ADCON0 register (PIC18FXX20/PIC18FXX80/PIC18FXX85)
(redraw with permission of Microchip)

No.9-18
The PIC18 Microcontroller

7 6 5 4 3 2 1 0
VCFG1 VCFG0 -- CHS2 CHS1 CHS0 GO/DONE ADON
value after
reset 0 0 0 0 0 0 0 0
VCFG1:VCFG0: Voltage reference configuration bits
(See Table 12.2)
CHS2:CHS0: Analog channel select bits
000 = channel 0, (AN0)
001 = channel 1, (AN1) Table 12.2 Voltage reference configuration bits
010 = channel 2, (AN2)
011 = channel 3, (AN3) VCFG1:VCFG0 A/D VREF+ A/D VREF-
100 = channel 4, (AN4) 00 AVDD AVSS
101 = channel 5, (AN5) 01 External VREF+ AVSS
110 = channel 6, (AN6) 10 AVDD External VREF-
111 = channel 7, (AN7) 11 External VREF+ External VREF-
GO/DONE: A/D conversion status bit
when ADON = 1
0 = A/D conversion not in progress
1 = A/D conversion in progress (setting this bit starts the A/D conversion.
This bit will be cleared by hardware when A/D conversion is done)
ADON: A/D on bit
0 = A/D converter module is shut-off
1 = A/D converter module is powered up

Figure 12.8c ADCON0 register (PIC18F1220/1320)


(redraw with permission of Microchip)

No.9-19
The PIC18 Microcontroller

ADCON1 Register
- Configure an input pin as analog or digit.
- An input to be converted must be an analog input.

7 6 5 4 3 2 1 0
ADFM ADCS2 -- -- PCFG3 PCFG2 PCFG1 PCFG0
value after
reset 0 0 0 0 0 0 0 0

ADFM: A/D result format select bit


0 = left justified. Six least significant bits of ADRESL are 0s.
1 = right justified. Most significant bits of ADRESH are 0s.
ADCS2: A/D conversion clock select.
This bit along with the ADCS1:ADCS0 bits of ADCON0 are used to select
clock source for A/D conversion.
PCFG3:PCFG0: A/D port configuration control bits.
(see Table 12.3)

Figure 12.9a ADCON1 register (PIC18FXX2 and PIC18FXX8)


(redraw with permission of Microchip)

No.9-20
The PIC18 Microcontroller

Table 12.3 A/D port configuration control bits


PCFG
<3:0>
AN7 AN6 AN5 AN4 AN3 AN2 AN1 AN0 VREF+ VREF- C/R

0000 A A A A A A A A VDD VSS 8/0


0001 A A A A VREF+ A A A AN3 VSS 7/1
0010 D D D A A A A A VDD VSS 5/0
0011 D D D A VREF+ A A A AN3 VSS 4/1
0100 D D D D A D A A VDD VSS 3/0
0101 D D D D VREF+ D A A AN3 VSS 2/1
011x D D D D D D D D -- -- 0/0
1000 A A A A VREF+ VREF- A A AN3 AN2 6/2
1001 D D A A A A A A VDD VSS 6/0
1010 D D A A VREF+ A A A AN3 VSS 5/1
1011 D D A A VREF+ VREF- A A AN3 AN2 4/2
1100 D D D A VREF+ VREF- A A AN3 AN2 3/2
1101 D D D D VREF+ VREF- A A AN3 AN2 2/2
1110 D D D D D D D A VDD VSS 1/0
1111 D D D D VREF+ VREF- D A AN3 AN2 1/0

A = analog input D = digital input


C/R = # of analog input channels/# of A/D voltage references

No.9-21
The PIC18 Microcontroller

7 6 5 4 3 2 1 0
-- -- VCFG1 VCFG0 PCFG3 PCFG2 PCFG1 PCFG0
value after
reset 0 0 0 0 0 0 0 0

VCFG1:VCFG0: Voltage reference configuration bits


(see Table 12.2)
PCFG3:PCFG0: A/D port configuration control bits
AN15 AN14 AN13 AN12 AN11 AN10 AN9 AN8 AN7 AN6 AN5 AN4 AN3 AN2 AN1 AN0

0000 A A A A A A A A A A A A A A A A
0001 D D A A A A A A A A A A A A A A
0010 D D D A A A A A A A A A A A A A
0011 D D D D A A A A A A A A A A A A
0100 D D D D D A A A A A A A A A A A
0101 D D D D D D A A A A A A A A A A
0110 D D D D D D D A A A A A A A A A
0111 D D D D D D D D A A A A A A A A
1000 D D D D D D D D D A A A A A A A
1001 D D D D D D D D D D A A A A A A
1010 D D D D D D D D D D D A A A A A
1011 D D D D D D D D D D D D A A A A
1100 D D D D D D D D D D D D D A A A
1101 D D D D D D D D D D D D D D A A
1110 D D D D D D D D D D D D D D D A
1111 D D D D D D D D D D D D D D D D

1. AN15:AN12 are available only in PIC18F8X8X devices


2. AN12 is also available in PIC18F2X20/PIC18F4X20 devices
3. AN5 through AN7 are not available in PIC18F2X20 devices
Figure 12.9b ADCON1 register (PIC18FXX20/PIC18FXX80/PIC18FXX85)
(excluding PIC18F1320/1220) (redraw with permission of
Microchip)

No.9-22
The PIC18 Microcontroller

7 6 5 4 3 2 1 0
-- PCFG6 PCFG5 PCFG4 PCFG3 PCFG2 PCFG1 PCFG0
value after
reset 0 0 0 0 0 0 0 0
PCFG6..PFCG0: AN6..AN0 A/D port configuration bit
0 = Pin configured as an analog channel -- digital input disabled and read as 0
1 = Pin configured as a digital input
Figure 12.9c ADCON1 register (PIC18F1220/1320)
(redraw with permission of Microchip)

No.9-23
The PIC18 Microcontroller

ADCON2 Register
7 6 5 4 3 2 1 0
ADFM -- ACQT2 ACQT1 ACQT0 ADCS2 ADCS1 ADCS0
value after
reset 0 0 0 0 0 0 0 0
ADFM: A/D result format select bit
0 = left justified
1 = right justified
ACQT2:ACQT0: A/D acquisition time select bits
000 = 0 TAD(1)
001 = 2 TAD
010 = 4 TAD
011 = 6 TAD
100 = 8 TAD
101 = 12 TAD
110 = 16 TAD
111 = 20 TAD
ADCS2:ADCS0: A/D conversion clock select bits
000 = FOSC/2
001 = FOSC/8
010 = FOSC/32
011 = FRC (clock derived from A/D RC oscillator)
100 = FOSC/4
101 = FOSC/16
110 = FOSC/64
111 = FRC (clock derived from A/D RC oscillator)
Note 1: If the A/D FRC clock source is selected, a delay of one TCY (instruction
cycle) is added before the A/D clock starts. This allows the SLEEP
instruction to be executed before starting a conversion.

Figure 12.10a ADCON2 register (PIC18F8X8X/8X2X/6X2X/2X20/4x20/1220/1320)


(redraw with permission of Microchip)

No.9-24
The PIC18 Microcontroller

7 6 5 4 3 2 1 0
ADFM -- -- -- -- ADCS2 ADCS1 ADCS0
value after
reset 0 0 0 0 0 0 0 0
ADFM: A/D result format select bit
0 = left justified
1 = right justified
ADCS2:ADCS0: A/D conversion clock select bits
000 = FOSC/2
001 = FOSC/8
010 = FOSC/32
011 = FRC (clock derived from an RC oscillator = 1 MHz max)
100 = FOSC/4
101 = FOSC/16
110 = FOSC/64
111 = FRC (clock derived from an RC oscillator = 1 MHz)

Figure 12.10b ADCON2 register (PIC18F8720/8620/8520/6720/6620/6520)


(redraw with permission of Microchip)

No.9-25
The PIC18 Microcontroller

A/D Acquisition Requirements


- The A/D converter has a sample-and-hold circuit for analog input.
- The sample-and-hold circuit keeps the voltage stable when it is converted.
- The sample-and-hold circuit is shown in Figure 12.11.
VDD sampling
switch
ANX VT = 0.6V SS
RS RIC  1K RSS

CPIN VT = 0.6V Ileakage CHOLD = 120


VAIN
5pF pF
± 500 nA
VSS
CPIN = Input capacitance
VT = threshold voltage VDD
Ileakage = leakage current at the pin due to various junctions.
RIC = interconnect resistance 6V
5V
SS = sampling switch
4V
CHOLD = sample/hold capacitance (from DAC). This 3V
capacitor has a range from 25 pF to 120 pF. 2V
RSS = sampling switch resistance
5 6 7 8 9 10 11
Figure 12.11 Analog input circuit model Sampling switch R SS (KW)
(redraw with permission of Microchip)

No.9-26
The PIC18 Microcontroller

Automatic Acquisition Time

- For earlier PIC18 members, when the GO/DONE bit is set, sampling is stopped and
conversion begins.
- The user is responsible for making sure enough acquisition time is provided.
- For newer PIC18 members, the A/D module will continue to sample after the
GO/DONE bit is set for the selected acquisition time.
- The automatic acquisition time makes A/D programming a little easier.

Selecting the A/D Conversion Clock

- The per bit A/D conversion time is defined as TAD.


- Each 10-bit A/D conversion takes 12 TAD to complete.
- For some devices, the options for TAD are defined in ADCON0. For others, the
options for TAD are defined in ADCON2.
- The length of TAD must be at least 1.6 ms.
- The options for TAD versus crystal oscillator frequency are listed in Table 12.4

No.9-28
The PIC18 Microcontroller

Table 12.4 T AD vs. device operating frequencies


AD clock source (T AD ) maximum device frequency
Operation ADCS2:ADCS0 normal MCU Low power MCU

2 TOSC 000 1.25 MHz 666 KHz


4 TOSC 100 2.50 MHz 1.33 MHz
8 TOSC 001 5.00 MHz 2.66 MHz
16 TOSC 101 10.0 MHz 5.33 MHz
32 TOSC 010 20.0 MHz 10.65 MHz
64 TOSC 110 40.0 MHz 21.33 MHz
RC x11 1.00 MHz 1.00 MHz

Note. Lower power device has a letter L in its name. For example,
PIC18LF8720

A/D Conversion Operation

- For PIC18 members without the feature of automatic acquisition, A/D conversion
will start immediately after setting the GO/DONE bit.
- For devices with automatic acquisition, the device will continue to perform data
acquisition until the preprogrammed time is up and then start the A/D conversion.

No.9-29
The PIC18 Microcontroller

Example 12.4 Write an instruction sequence to configure the A/D converter of the
PIC18F8680 to operate with the following parameters:
• Conversion result right justified
• fOSC = 32 MHz
• The highest ambient temperature may reach 60oC
• Use VDD and VSS as the high and low reference voltages
• Convert channel AN0
• Enable A/D module

Solution:
- TCOFF = (60 -25)  0.05 = 1.75 ms
- The required acquisition time = (9.61 + 2 + 1.75) = 13.36 ms.
- fOSC = 32 MHz, the A/D clock source must be set to 64 fOSC, which makes TAD =
2ms.
- PIC18F8680 supports automatic acquisition time, it must be set to at least 8 TAD to
make it greater than 13.36 ms

No.9-30
The PIC18 Microcontroller

Assembly instruction sequence that achieve the desired setting:

movlw 0x01 ; select channel AN0 and enable A/D


movwf ADCON0,A ; ―
movlw 0x0E ; configure only channel AN0 as analog port,
movwf ADCON1,A ; select VDD and VSS as reference voltage
movlw 0xA6 ; set A/D result right justified, set acquisition
movwf ADCON2,A ; time to 8 TAD, clock source FOSC/64

In C language,

ADCON0 = 0x01;
ADCON1 = 0x0E;
ADCON2 = 0xA6;

No.9-31
The PIC18 Microcontroller

Example 12.5 Write an instruction sequence to configure the A/D converter of the
PIC18F452 to operate with the following parameters:

• Conversion result right justified


• fOSC = 32 MHz
• The highest ambient temperature may reach 60oC
• Use VDD and VSS as the high and low reference voltages
• Convert channel AN0
• Enable A/D module

Solution:
movlw 0x81 ; select fOSC/64 as the conversion clock
movwf ADCON0,A ; ―
movlw 0xCE ; A/D conversion result right justified
movwf ADCON1,A ; configure only AN0 pin as analog,

No.9-32
The PIC18 Microcontroller

Procedure for Performing A/D Conversion

- Configure the A/D module


1. Configure analog pins, reference voltages
2. Select A/D input channel
3. Select A/D acquisition time (if available)
4. Select A/D conversion clock
5. Enable A/D module
- Configure A/D interrupt
1. Clear ADIF flag
2. Set ADIE bit (if desired)
3. Set GIE bit (if desired)
- Wait for the desired acquisition time (if required)
- Start conversion by setting the GO/DONE bit
- Wait for A/D conversion to complete
- Read the A/D result registers; clear the ADIF flag
- For next conversion, go to step 1 or step 2.

No.9-33
The PIC18 Microcontroller

Example 12.6 Assume that the AN0 pin of a PIC18F8680 running with a 32 MHz
crystal oscillator is connected to a potentiometer. The voltage range of the
potentiometer is from 0V to 5V. Write a program to measure the voltage applied to the
AN0 pin, convert it, and retrieved the conversion result and place it in
PRODH:PRODL.
Solution:

No.9-34
The PIC18 Microcontroller

#include <p18F8680.inc>
org 0x00
goto start
org 0x08
retfie
org 0x18
retfie
start movlw 0x01 ; select channel AN0 and enable A/D
movwf ADCON0,A ; "
movlw 0x0E ; use VDD & VSS as reference voltages &
movwf ADCON1,A ; configure channel AN0 as analog input
movlw 0xA6 ; select FOSC/64 as conversion clock,
movwf ADCON2,A ; 8 TAD for acquisition time, right-justified
bsf ADCON0,GO,A ; start A/D conversion
wait_con btfsc ADCON0,DONE,A ; wait until conversion is done
bra wait_con
movff ADRESH,PRODH ; save conversion result
movff ADRESL,PRODL ; "
end

No.9-35
The PIC18 Microcontroller

A/D Converter C Library Functions

char BusyADC (void);


- Returns a 1 if the A/D module is busy. Returns a 0 if not.
void CloseADC (void);
- Disable the A/D module.
void ConvertADC (void);
- Start an A/D conversion
int ReadADC (void);
- Reads the A/D conversion result
void SetChanADC (unsigned char channel);
- Selects the pin used as input to the A/D converter. The channel value can be from
ADC_CH0 through ADC_CH15.
void OpenADC (unsigned char config, unsigned char config2);
- The setting of config and config2 depends on the device.
- The PIC18F1X20/2X20/3X20/4X20 have a third argument: portconfig.
- The values of these arguments are in the following slides

No.9-36
The PIC18 Microcontroller

PIC18FXX2, PIC18FXX2, and PIC18FXX8


The first argument config may have the following values:
A/D clock source
ADC_FOSC_2 FOSC/2
ADC_FOSC_4 FOSC/4
ADC_FOSC_8 FOSC/8
ADC_FOSC_16 FOSC/16
ADC_FOSC_32 FOSC/32
ADC_FOSC_64 FOSC/64
ADC_FOSC_RC Internal RC Oscillator
A/D result justification
ADC_RIGHT_JUST Result in least significant bits
ADC_LEFT_JUST Result in most significant bits

No.9-37
The PIC18 Microcontroller

A/D voltage reference source


ADC_8ANA_0REF VREF+ = VDD, VREF- = VSS, all analog channels
ADC_7ANA_1REF AN3 = VREF+, all analog channels except AN3
ADC_6ANA_2REF AN3 = VREF+, AN2 = VREF-
ADC_6ANA_0REF VREF+ = VDD, VREF- = VSS
ADC_5ANA_1REF AN3 = VREF+, VREF- = VSS
ADC_5ANA_0REF VREF+ = VDD, VREF- = VSS
ADC_4ANA_2REF AN3 = VREF+, AN2 = VREF-
ADC_4ANA_1REF AN3 = VREF+
ADC_3ANA_2REF AN3 = VREF+, AN2 = VREF-
ADC_3ANA_0REF VREF+ = VDD, VREF- = VSS
ADC_2ANA_2REF AN3 = VREF+, AN2 = VREF-
ADC_2ANA_1REF AN3 = VREF+
ADC_1ANA_2REF AN3 = VREF+, AN2 = VREF-, AN0 = A
ADC_1ANA_0REF AN0 is analog input
ADC_0ANA_0REF All digital I/O

No.9-38
The PIC18 Microcontroller

The second argument config2 may have the following values:


Channel
ADC_CH0 Channel 0
ADC_CH1 Channel 1
ADC_CH2 Channel 2
ADC_CH3 Channel 3
ADC_CH4 Channel 4
ADC_CH5 Channel 5
ADC_CH6 Channel 6
ADC_CH7 Channel 7
A/D Interrupts
ADC_INT_ON Interrupts enabled
ADC_INT_OFF Interrupts disabled

No.9-39
The PIC18 Microcontroller

PIC18C658/858, PIC18C601/801, PIC18F6X20, PIC18F8X20


The first argument config may have the following values:
A/D clock source
ADC_FOSC_2 FOSC/2
ADC_FOSC_4 FOSC/4
ADC_FOSC_8 FOSC/8
ADC_FOSC_16 FOSC/16
ADC_FOSC_32 FOSC/32
ADC_FOSC_64 FOSC/64
ADC_FOSC_RC Internal RC oscillator
A/D result justification
ADC_RIGHT_JUST Result in least significant bits
ADC_LEFT_JUST Result in most significant bits

No.9-40
The PIC18 Microcontroller

A/D port configuration


ADC_0ANA All digital
ADC_1ANA analog AN0 digital: AN1—AN15
ADC_2ANA analog AN0-AN1 digital: AN2—AN15
ADC_3ANA analog AN0-AN2 digital: AN3—AN15
ADC_4ANA analog AN0-AN3 digital: AN4—AN15
ADC_5ANA analog AN0-AN4 digital: AN5—AN15
ADC_6ANA analog AN0-AN5 digital: AN6—AN15
ADC_7ANA analog AN0-AN6 digital: AN7—AN15
ADC_8ANA analog AN0-AN7 digital: AN8—AN15
ADC_9ANA analog AN0-AN8 digital: AN9—AN15
ADC_10ANA analog AN0-AN9 digital: AN10—AN15
ADC_11ANA analog AN0-AN10 digital: AN11—AN15
ADC_12ANA analog AN0-AN11 digital: AN12—AN15
ADC_13ANA analog AN0-AN12 digital: AN13—AN15
ADC_14ANA analog AN0-AN13 digital: AN14—AN15
ADC_15ANA all analog

No.9-41
The PIC18 Microcontroller

The second argument config2 has the following values:


Channel
ADC_CH0 Channel 0
ADC_CH1 Channel 1
ADC_CH2 Channel 2
ADC_CH3 Channel 3
ADC_CH4 Channel 4
ADC_CH5 Channel 5
ADC_CH6 Channel 6
ADC_CH7 Channel 7
ADC_CH8 Channel 8
ADC_CH9 Channel 9
ADC_CH10 Channel 10
ADC_CH11 Channel 11
ADC_CH12 Channel 12
ADC_CH13 Channel 13
ADC_CH14 Channel 14
ADC_CH15 Channel 15
A/D Interrupts
ADC_INT_ON Interrupts enabled
ADC_INT_OFF Interrupts disabled

No.9-42
The PIC18 Microcontroller

A/D voltage configuration


ADC_VREFPLUS_VDD VREF+ = AVDD
ADC_VREFPLUS_EXT VREF+ = external
ADC_VREFMINUS_VSS VREF- = AVSS
ADC_VREFMINUS_EXT VREF- = external

PIC18F6X8X, PIC18F8X8X, PIC18F1X20, PIC18F2X20, PIC18F4X20


The first argument config may have the following values:
A/D clock source
ADC_FOSC_2 FOSC/2
ADC_FOSC_4 FOSC/4
ADC_FOSC_8 FOSC/8
ADC_FOSC_16 FOSC/16
ADC_FOSC_32 FOSC/32
ADC_FOSC_64 FOSC/64
ADC_FOSC_RC Internal RC oscillator
A/D result justification
ADC_RIGHT_JUST Result in least significant bits
ADC_LEFT_JUST Result in most significant bits

No.9-43
The PIC18 Microcontroller

A/D acquisition time select


ADC_0_TAD 0 Tad
ADC_2_TAD 2 Tad
ADC_4_TAD 4 Tad
ADC_6_TAD 6 Tad
ADC_8_TAD 8 Tad
ADC_12_TAD 12 Tad
ADC_16_TAD 16 Tad
ADC_20_TAD 20 Tad
The second argument config2 may have the following values:
Channel
ADC_CH0 Channel 0
ADC_CH1 Channel 1
ADC_CH2 Channel 2
ADC_CH3 Channel 3
ADC_CH4 Channel 4
ADC_CH5 Channel 5
ADC_CH6 Channel 6
ADC_CH7 Channel 7
ADC_CH8 Channel 8
ADC_CH9 Channel 9
ADC_CH10 Channel 10

No.9-44
The PIC18 Microcontroller

ADC_CH11 Channel 11
ADC_CH12 Channel 12
ADC_CH13 Channel 13
ADC_CH14 Channel 14
ADC_CH15 Channel 15
A/D Interrupts
ADC_INT_ON Interrupts enabled
ADC_INT_OFF Interrupts disabled
A/D voltage configuration
ADC_VREFPLUS_VDD VREF+ = AVDD
ADC_VREFPLUS_EXT VREF+ = external
ADC_VREFMINUS_VSS VREF- = AVSS
ADC_VREFMINUS_EXT VREF- = external

- The third argument portconfig is any value from 0 to 127 for the
PIC18F1220/1320.
- The argument portconfig is any value from 0 to 15 for the PIC2220/2320/4220
and PIC18F4320/6X8X/8X8X.

No.9-45
The PIC18 Microcontroller

Example 12.7 Write a C program to configure the A/D module of the PIC18F452 with
the following characteristics and take one sample, convert it, and store the result in a
memory location:
• Clock source set to FOSC/64
• Result right justified
• Set AN0 pin of port A for analog input, others for digital
• Use VDD and VSS as high and low reference voltages
• Select AN0 to convert
• Disable interrupt
Solution:

No.9-46
The PIC18 Microcontroller

#include <p18F452.h>
#include <adc.h>
#include <stdlib.h>
#include <delays.h>
int result;
void main (void)
{
OpenADC(ADC_FOSC_64 & ADC_RIGHT_JUST & ADC_1ANA_0REF,
ADC_CH0 & ADC_INT_OFF);
Delay10TCYx(20); // provides 200 instruction cycles of acquisition time
ConvertADC( ); // start A/D conversion
while(BusyADC( )); // wait for completion
result = ReadADC( ); // read result
CloseADC( );
}

No.9-47
The PIC18 Microcontroller

Using the Temperature Sensor TC1047A


- Can measure temperature from -40oC to 125oC
- The voltage output of this sensor is 0.1V at -40oC, 1.75V at 125oC.

VOUT

1.75

VSS
1.4
3
0.9
TC1047A

0.5
1 2
0.1
VDD VOUT
-40 0 40 90 125
Temperature
Figure 12.14 TC1047A V OUT vs. temperature characteristic

No.9-48
The PIC18 Microcontroller

Example 12.8 Describe a circuit connection and the required program to build a digital
thermometer. Display the temperature in three integral and one fractional digits using
the LCD. Measure and display the temperature over the whole range of TC1047A; that
is, -40oC to +125oC. Update the display data ten times per second and assume that the
PIC18F8680 operates with a 32 MHz crystal oscillator.
Solution:
- A signal conditioning circuit is needed to shift and scale the output of the TC1047A
to 0 ~ 5V.
- To convert the A/D conversion result back to the corresponding temperature,
perform the following operations:

1. Divide the conversion result by 6.2


2. Subtract the quotient by 40

- The operation of ―divide by 6.2‖ can be implemented by


1. Multiplying the conversion result by 10
2. Dividing the product by 62

- The digital thermometer circuit is shown in Figure 12.15.

No.9-49
The PIC18 Microcontroller

5V 9K
10K Rf PIC18F8680
TC1047A
10K +12 V
VOUT - +12 V
3K -
741
+ VM R1 741 AN0
+
- 12 V 150K R2
- 12 V
- 5V

Figure 12.15 Circuit connection between the TC1047A and the PIC18

The Procedure

Step 1
Configure A/D converter and Timer0 properly. Timer0 is configured to overflow every
200 ms.
Step 2
Start an A/D conversion.
Step 3
Wait until the A/D conversion is complete.
Step 4
Multiply the conversion result by 10.

No.9-50
The PIC18 Microcontroller

Step 5
Divide the product resulted in step 4 by 62 to obtain temperature reading. Use variables
quo and rem to hold the quotient and remainder.
Step 6
Subtract 40 from the variable quo to obtain the actual temperature.
Step 7
If (quo > 0), go to step 9; else replace quo with its two’s complement.
Step 8
If rem  0, then
decrement quo by 1
rem  62 – rem.
Step 9
Compute the fractional digit by multiplying rem by 10 and then dividing the resulted
product by 62.
Step 10
Compute the integral digits by performing repeated division by 10 to quo.
Step 11
Wait until Timer0 overflows and then go to Step 2.

No.9-51
The PIC18 Microcontroller

#include <p18F8680.inc>
; -----
; include macro definitions for pushr, push_dat, popr, alloc_stk, dealloc_stk here.
; -----
; ********************************************************************
; The following definitions are used by the 16-bit multiplication routine
; ********************************************************************
loc_varm equ 4 ; number of bytes used for local variable
pd0 equ 7 ; offset of PD3 from frame pointer
pd1 equ 6 ; offset of PD2 from frame pointer
pd2 equ 5 ; offset of PD1 from frame pointer
pd3 equ 4 ; offset of PD0 from frame pointer
MD_lo equ -8 ; offset of MD_lo from frame pointer
MD_hi equ -7 ; offset of MD_hi from frame pointer
ND_lo equ -6 ; offset of ND_lo from frame pointer
ND_hi equ -5 ; offset of ND_hi from frame pointer
buf_lo equ -4
buf_hi equ -3
ptr_hi equ 0x01 ; address of buffer to hold product
ptr_lo equ 0x00 ; "

No.9-52
The PIC18 Microcontroller

; ********************************************************************
; The following definitions are used by the 16-bit unsigned divide routine
; ********************************************************************
loc_var equ 2 ; local variable size
lp_cnt equ 1 ; loop count
temp equ 2 ; temporary storage
quo_hi equ -7 ; offset for quotient and dividend from frame
quo_lo equ -8 ; pointer
rem_hi equ -5 ; offset for remainder from frame pointer
rem_lo equ -6 ; "
dsr_hi equ -3 ; offset for divisor from frame pointer
dsr_lo equ -4 ; "
quo set 0x02 ; memory space to hold the quotient
rem set 0x04 ; memory space to hold the remainder
; ************************************************************************
; variables for holding temperature conversion result and string
; ************************************************************************
int_pt set 0x06 ; space to hold integer part of the temperature
temp_buf set 0x08 ; reserve 6 bytes to hold the temperature
; digits, sign, period, and NULL

No.9-53
The PIC18 Microcontroller

org 0x00 ; reset vector


goto start
org 0x08
retfie
org 0x18
retfie
start lfsr FSR1,0xC00 ; set up stack pointer
; initialize the temperature string to ^^0.0
call a2d_init ; configure and turn on A/D module
forever movlw 0x20 ; store space character
movwf temp_buf ; "
movwf temp_buf+1 ; "
movlw 0x30 ; store a 0 digit
movwf temp_buf+2 ; "
movwf temp_buf+4 ; "
movlw 0x2E ; store a period
movwf temp_buf+3 ; "
clrf temp_buf+5 ; terminate the string with a NULL character

call OpenTmr0 ; initialize and enable Timer0


bsf ADCON0,GO,A ; start A/D conversion

No.9-54
The PIC18 Microcontroller

wait_a2d btfsc ADCON0,DONE,A ; wait until A/D conversion is complete


bra wait_a2d ; "
pushr ADRESL ; push the A/D conversion result in
pushr ADRESH ; stack
push_dat 0x0A ; push 10 in the stack for multiplier
push_dat 0x00 ; "
push_dat ptr_lo ; pass buffer pointer to the subroutine
push_dat ptr_hi ; "
call mul_16U,FAST ; multiply A/D conversion result by 10
dealloc_stk 6 ; deallocate space used in the stack
movlw ptr_lo ; place the address of product in FSR0
movwf FSR0L,A ; "
movlw ptr_hi ; "
movwf FSR0H,A ; "
movf POSTINC0,W,A ; push (A/D result x 10)
pushr WREG ; "
movf INDF0,W,A ; "
pushr WREG ; "
alloc_stk 2
push_dat 0x3E ; push 62 into the stack as the divisor
push_dat 0 ; "
call div16u,FAST ;

No.9-55
The PIC18 Microcontroller

dealloc_stk 2
popr rem+1 ; retrieve remainder high byte (should be 0)
popr rem ; retrieve remainder low byte
popr int_pt+1 ; retrieve integer part of the (should be 0)
popr int_pt ; temperature
; subtract 40 from integer part to obtain the actual temperature
movlw 0x28 ; calculate the actual temperature
subwf int_pt,F,A ;"
bnn non_minus ; if non-minus, no need for further check
negf int_pt,A ; find the magnitude of temperature
movlw 0x2D
movlw temp_buf ; store the minus sign
movf rem,W,A ; check the fractional part before divide
bz separate_dd ; branch to separate integer digits if rem = 0
decf int_pt,F,A ; fractional digit  0, decrement integer part
movlw 0x3E ; need to find the complement of the fractional
subwf rem,F,A ; digit
negf rem,A ;"
; calculate the fractional digit
non_minus
movlw 0x0A
mulwf rem

No.9-56
The PIC18 Microcontroller

pushr PRODL ; push (remainder x 10)


pushr PRODH ; "
alloc_stk 2
push_dat 0x3E ; push 62 into the stack as the divisor
push_dat 0 ; "
call div16u,FAST ;
dealloc_stk 2
popr rem+1 ; retrieve remainder high byte (= 0)
popr rem ; retrieve remainder low byte
popr quo+1 ; retrieve quotient high byte (= 0)
popr quo ; retrieve quotient low byte
; round the fractional digit
movlw 0x1F ; is remainder >= 31?
cpfslt rem,A ; smaller, then skip
incf quo,A
movlw 0x0A ; is quo equal to 10?
cpfseq quo,F,A
goto no_round
clrf quo,A
incf int_pt,A
no_round movlw 0x30 ; convert to ASCII of BCD digit
addwf quo,F,A

No.9-57
The PIC18 Microcontroller

movwf temp_buf+4 ; save the ASCII of the fractional digit


; separate the integral digits using repeated division by 10
separate_dd
pushr int_pt ; push integer part
push_dat 0 ; "
alloc_stk 2
push_dat 0x0A ; push 10 as the divisor
push_dat 0 ; "
call div16u,FAST
dealloc_stk 2
popr rem+1
popr rem
popr quo+1
popr quo
movlw 0x30
addwf rem,W,A
movwf temp_buf+2 ; save the one's digit
movf quo,W,A ; check the quotient
bz next_time ; wait to perform next conversion
; prepare to separate ten's digit
movlw 0x0A ; is the quotient >= 10?
cpfslt quo,A ; "

No.9-58
The PIC18 Microcontroller

goto yes_ge
movlw 0x30
addwf quo,W,A
movwf temp_buf+1 ; save the ten's digit
goto next_time ; "
yes_ge movlw 0x31 ; save "1" as the hundred's digit
movwf temp_buf,A ; "
movlw 0x0A ; separate the ten's digit and place it
subwf quo,W,A ; in WREG
addlw 0x30 ; convert ten's digit to ASCII and
movwf temp_buf+1,A ; save ten's digit
next_time btfss INTCON,TMR0IF,A ; wait until 200 ms is over
goto next_time
; -----
; add instructions to update display here
; -----
goto forever ; prepare to perform next A/D conversion

No.9-59
The PIC18 Microcontroller

; *********************************************************************
; This routine will place 15535 in TMR0 so that it overflows in 50000 count.
; When prescaler is set to 32 with fOSC = 32MHz, it will overflow in 200 ms.
; *******************************************************************
OpenTmr0 movlw 0x3C ; place 15535 in TMR0
movwf TMR0H ; so that it overflows in
movlw 0xAF ; 200 ms
movwf TMR0L ; "
movlw 0x84 ; enable TMR0, select internal clock,
movwf T0CON ; set prescaler to 32
bcf INTCON,TMR0IF ; clear TMR0IF flag
return
; ************************************************************
; This routine initialize the A/D converter to select channel AN0 as
; analog input other pins for digital pin. Select VDD and VSS as A/D
; conversion reference voltages, result right justified, FOSC/64 as
; A/D clock source, 8 TAD for acquisition time.
; *************************************************************
a2d_init movlw 0x01 ; select channel AN0
movwf ADCON0 ; and enable A/D module
movlw 0x0E ; use VDD & VSS as A/D reference voltage
movwf ADCON1 ; & configure AN0 as analog input

No.9-60
The PIC18 Microcontroller

movlw 0xA6 ; result right justified, FOSC/64 as A/D clock


movwf ADCON2 ; source and set acquisition time to 8 TAD
return
; -----
; include subroutines div16u and mul_16U here.
; -----
end

No.9-61
The PIC18 Microcontroller

#include <p18F8680.h>
#include <timers.h>
#include <adc.h>
unsigned char temp_buf[6];
void main (void)
{
int a2d_val;
unsigned int quo, rem;
char fd1, fdr;
ADCON0 = 0x01; //select channel AN0, enable A/D module
ADCON1 = 0x0E; //use VDD, VSS as reference and configure AN0 for analog
ADCON2 = 0xA6; //result right justified, 8TAD acquisition time, FOSC/64
OpenTimer0(TIMER_INT_OFF & T0_16BIT & T0_SOURCE_INT &
T0_PS_1_32); //start Timer0 and make it overflow in 200 ms
while (1) {
temp_buf[5] = '\0';
temp_buf[0] = 0x20; //set to space
temp_buf[1] = 0x20; //set to space
temp_buf[2] = 0x30; //set to digit 0
temp_buf[3] = 0x2E; //store the decimal point
temp_buf[4] = 0x30; //set to digit 0
ConvertADC( ); //start an A/D conversion

No.9-62
The PIC18 Microcontroller

while(BusyADC()); //wait until A/D conversion is done


a2d_val = 10 * ReadADC();
quo = a2d_val / 62; //convert to temperature
rem = a2d_val % 62;
if (quo < 40) //is temperature minus?
{
quo = 40 - quo;
temp_buf[0] = 0x2D;//set sign to minus
if (rem != 0)
{
quo --;
rem = 62 - rem;
}
}
fd1 = (rem * 10) / 62; //fd1 will be between 0 and 9
fdr = (rem * 10) % 62;
if (fdr >= 31)
fd1 ++;
if (fd1 == 10) { //fractional digit can only be between 0 and 9
quo++;
fd1 = 0;
}

No.9-63
The PIC18 Microcontroller

temp_buf[4] = 0x30 + fd1; //store the ASCII code of fractional digit


temp_buf[2] = quo % 10 + 0x30; //store ASCII code of one’s digit
quo = quo / 10;
if (quo != 0)
{
temp_buf[1] = (quo - 10) + 0x30; //ten’s digit of temperature
quo -= 10;
}
if (quo == 1)
temp_buf[0] = 0x31; //hundred’s digit of temperature
while(!INTCONbits.TMR0IF); //wait until Timer0 overflows
INTCONbits.TMR0IF = 0; //clear the TMR0IF flag
}
}

No.9-64
The PIC18 Microcontroller

Using the IH-3606 Humidity Sensor


- Voltage output is 0.8V to 3.9V for the relative humidity from 0 to 100%
- Can resist contaminant vapors such as organic solvent, chlorine, and ammonia.
- A 3-pin device
- Light sensitive and should be shielded from bright light
- Pin assignment is shown in Figure 12.16.
- Characteristics are listed in Table 12.5.

IH-3605

GND VOUT VS
Figure 12.16 Honeywell IH-3605 humidity sensor

No.9-65
The PIC18 Microcontroller

Table 12.5 Specifications of IH-3605


Specification Description
total accuracy ± 2% RH, 0-100% TH @25 oC
Interchangeability ± 5% RH up to 60% RH, ±8% RH at 90% RH
Operating temperature -40 to 85 o C (-40 to 185oF)
Storage temperature -51 to 110 oC (-60 to 223o F)
Linearity ±0.5% RH typical
Repeatability ±0.5% RH
Humidity Stability ±1% RH typical at 50% RH in 5 years
Temp. effect on 0% RH voltage ±0.007% RH/o C (negligible)
Temp. effect on 100% RH voltage -0.22% RH/ oC
Output voltage VOUT = (VS)(0.16 to 0.78) nominal relative to
supply voltage for 0-100% RH; i.e., 1-4.9V
for 6.3V supply; 0.8 - 3.9V for 5V supply;
Sink capability 50 microamp; drive capability
5 microamps typical; low pass 1KHz filter
required. Turn on time < 0.1 sec to full output.
VS Supply requirement 4 to 9V, regulated or use output/supply ratio;
calibrated at 5V
Current requirement 200 microamps typical @5V, increased to
2mA at 9V

No.9-66
The PIC18 Microcontroller

Example 12.9 Construct a humidity measurement system that consists of the


PIC18F8680, an IH-3605 humidity sensor, and an LCD. The PIC18F8680 is running
with a 32 MHz crystal oscillator.
Solution:
- It is beneficial to scale and shift the humidity sensor output to the range of 0~5V.
- A 1-KHz low pass filter is needed at the output of the humidity sensor.
- To convert to the relative humidity, divide the A/D conversion result by 10.23.
- The humidity data will be represented using an LCD or four seven-segment displays.

VS (= 5V)
R0
Rf

1KW R0 +12 V
VOUT - R1 +12 V
0.16mF 741 -
IH-3605 + 741 VOUT
GND +
- 12 V R2
- 12 V
V1
R0 = R1 = 10KW
R  W PIC18F8680
Rf  W
V1 = 5V AN0

Figure 12.17 Relative humidity measurement circuit

No.9-67
The PIC18 Microcontroller

#include <p18F8680.h>
#include <timers.h>
#include <adc.h>
unsigned char hum_buf[6]; //buffer to hold relative humidity
void main (void)
{
unsigned short long a2d_val;
unsigned short long quo, rem, temp1;
char fd1, i;
ADCON0 = 0x01; //select channel AN0, enable A/D module
ADCON1 = 0x0E; //use VDD, VSS as reference and configure AN0 for analog
ADCON2 = 0xA6; //result right justified, acquisition time = 8 TAD, FOSC/64
OpenTimer0(TIMER_INT_OFF & T0_16BIT & T0_SOURCE_INT &
T0_PS_1_32); //start Timer0 and make it overflow in 200 ms
while (1) {
hum_buf[0] = 0x20; //set to space
hum_buf[1] = 0x20; //set to space
hum_buf[2] = 0x30; //set to digit 0
hum_buf[3] = 0x2E; //store the decimal point
hum_buf[4] = 0x30; //set to digit 0
hum_buf[5] = '\0'; //terminate with a NULL character
ConvertADC( ); //start an A/D conversion
while (BusyADC( )); //wait until A/D conversion is done
No.9-68
The PIC18 Microcontroller

a2d_val = 100 * ReadADC();


quo = a2d_val / 1023; //convert to relative humidity
rem = a2d_val % 1023; // "

fd1 = (rem * 10) / 1023; //compute the fractional digit


temp1 = (rem * 10) % 1023;
if (temp1 > 511) //should round up the fractional digit
fd1 ++;
if (fd1 == 10) { //if fractional digit becomes 10, zero it
fd1 = 0; // and add 1 to integer part
quo++;
}
hum_buf[4] = 0x30 + fd1; //ASCII code of fractional digit
hum_buf[2] = quo % 10 + 0x30; //ASCII code of one's digit
quo = quo / 10;
if (quo != 0)
{
hum_buf[1] = (quo % 10) + 0x30;
quo /= 10;
}

No.9-69
The PIC18 Microcontroller

if (quo == 1)
hum_buf[0] = 0x31;
while(!INTCONbits.TMR0IF); //wait until Timer0 overflows
for (i = 0; i < 4; i++) { //wait for Timer0 to overflow four more times
INTCONbits.TMR0IF = 0; //clear the TMR0IF flag
while(!INTCONbits.TMR0IF); //wait for Timer0 to overflow
}
INTCONbits.TMR0IF = 0
}
}

No.9-70
The PIC18 Microcontroller

Measuring Barometric Pressure

- Barometric pressure is the pressure existing at any point in the earth atmosphere.
- The barometric pressure can be measured as an absolute pressure or can be
referenced to some other value or scale.
- The meteorology and avionics industries measure the absolute pressure.
- The units used to represent the barometric pressure include in-Hg, kPa, mbar, and
psi.
- A comparison of barometric pressures in different units is shown in Table 12.6.

Table 12.6 Altitude versus pressure data


Altitude (ft) Pressure (in-Hg) Pressure (mbar) Pressure (kPa) Pressure (psi)
0 29.92 1013.4 101.4 14.70
500 29.38 995.1 99.5 14.43
1000 28.85 977.2 97.7 14.17
6000 23.97 811.9 81.2 11.78
10000 20.57 696.7 69.7 10.11
15000 16.86 571.1 57.1 8.28

No.9-71
The PIC18 Microcontroller

The SenSym ASCX30AN Pressure Sensor


- Can measure barometric pressure from 0 to 30 psia
- The range of barometric pressure is between 28 to 32 in-Hg or 948 to 1083.8 mbar.
- The ASCX30AN output voltage would range from 2.06 V to 2.36 V.

Pin 1: External offset adjust


Pin 2: VS
Pin 3: VOUT
ASCX30AN Pin 4: GND
Pin 5: N/C
Pin 6: N/C

1 2 3 4 5 6

Figure 12.18 ASCX30AN pin assignment

No.9-72
The PIC18 Microcontroller

(1)
Table 12.7 ASCX30AN performance characteristics
Characteristic min typ max
Pressure range 0 psia -- 30 psia
Zero pressure offset 0.205 0.250 0.295
Full-scale span (2) 4.455 4.500 4.545
Output at FS pressure 4.660 4.750 4.840
Combined pressure non-linearity and -- ±0.1 ±0.5
pressure hysteresis (3)
Temperature effect on span (4) -- ±0.2 ±1.0
Temperature effect on offset (4) -- ±0.2 ±1.0
Response time (10% - 90%) (5) -- 0.1 --
Repeatability -- ±0.05 --
Note 1. Reference conditions: TA = 25 oC, supply voltage VS = 5 V
2. Full scale span is the algebraic difference between the output
voltage at full-scale pressure and the output at zero pressure.
Full-scale span is ratiometric to the supply voltage.
3. Pressure non-linearity is based on the best-fit straight line.
Pressure hysteresis is the maximum output difference at any
point within the operating pressure range for increasing and
decreasing pressure.
4. Maximum error band of the offset voltage or span over the
compensated temperature range, relative to the 25 oC reading.
5. Response time for 0 psi to full-scale pressure step response.
6. If maximum pressure is exceeded, even momentarily, the
package may leak or burst, or the pressure-sensing die may
burst.

No.9-73
The PIC18 Microcontroller

Example 12.10 Describe the circuit connection of the ASCX30AN, the voltage level
shifting and scaling circuit, and write a program to measure and display the barometric
pressure in units of mbar.
Solution:
- A shift and scale circuit is needed to convert the voltage to the range from 0 to 5V.
- The typical offset adjust is 0.25V and can be achieved by using a potentiometer.

5V
27K PIC18F8680
10K Rf
ASCX30AN
10K +12 V 1.6K
VOUT - R1 +12 V
5V 74 -
+1 VM 74 AN0
+1
offset adjust 3.9 R2
- 12 V
- 12 V
5V

Figure 12.19 Barometric pressure sensor output scaling and shifting circuit.

No.9-74
The PIC18 Microcontroller

- The barometric pressure (in mbar) can be derived by dividing the A/D conversion
result by 7.53 and then add 948 to the quotient.

Barometric pressure = 948 + A/D result / 7.53


= 948 + (A/D result * 100)/753

#include <p18F8680.h>
#include <timers.h>
#include <adc.h>
unsigned char bp_buf[7];
void main (void)
{
unsigned short long a2d_val;
unsigned short long quo, rem, temp1;
char fd1, i;

ADCON0 = 0x01; //select channel AN0, enable A/D module


ADCON1 = 0x0E; //use VDD, VSS as reference and configure AN0 for analog
ADCON2 = 0xA6; //result right justified, acquisition time = 8 TAD, FOSC/64
OpenTimer0(TIMER_INT_OFF & T0_16BIT & T0_SOURCE_INT &
T0_PS_1_32); //start Timer0 and make it overflow in 200 ms

No.9-75
The PIC18 Microcontroller

while (1) {
bp_buf[0] = 0x20; //set to space
bp_buf[1] = 0x20; //set to space
bp_buf[2] = 0x20; //set to space
bp_buf[3] = 0x30; //set to digit 0
bp_buf[4] = 0x2E; //store the decimal point
bp_buf[5] = 0x30; //set to digit 0
bp_buf[6] = '\0'; //terminate the string with a NULL character
ConvertADC( ); //start an A/D conversion
while(BusyADC()); //wait until A/D conversion is done
a2d_val = 100 * ReadADC();
quo = a2d_val/753; //convert to barometric pressure
rem = a2d_val%753; // "
quo += 948; //add the barometric pressure at A/D
//conversion result 0 to obtain the
//actual barometric pressure

fd1 = (rem * 10)/753; //compute the fractional digit


temp1 = (rem * 10)%753;
if (temp1 > 376) //should we round up the fractional digit?
fd1 ++;

No.9-76
The PIC18 Microcontroller

if (fd1 == 10) { //if fractional digit becomes 10, zero it


fd1 = 0; //and add 1 to integer part
quo++;
}
bp_buf[5] = 0x30 + fd1; //ASCII code of fractional digit
bp_buf[3] = quo % 10 + 0x30; //ASCII code of one's digit
quo = quo / 10;
bp_buf[2] = quo % 10 + 0x30; //ten's digit
quo /= 10;
bp_buf[1] = quo % 10 + 0x30; //hundred's digit
quo /= 10;
bp_buf[0] = quo + 0x30; //thousand's digit
while(!INTCONbits.TMR0IF); //wait until Timer0 overflows
for (i = 0; i < 4; i++) { //wait for Timer0 to overflow four more times
INTCONbits.TMR0IF = 0; //clear the TMR0IF flag
while(!INTCONbits.TMR0IF); //wait for Timer0 to overflow
}
INTCONbits.TMR0IF = 0;
}
}

No.9-77

You might also like