PIC'n Up The Pace
PIC MICROCONTROLLER
APPLICATIONS GUIDE
FROM
SQUARE [4]
DAVID BENSON
VERSION 1.1NOTICE
‘The material presented in this book is for the education and
amusement of students, hobbyists, technicians and engineers.
Every effort has been made to assure the accuracy of this infor-
mation and its suitability for this purpose. Square 1
Electronics and the author assume no responsibility for the
suitability of this information for any application nor do we
assume any liability resulting from use of this information. No
patent liability is assumed for use of the information contained
herein,
All rights reserved. No part of this manual shall be reproduced
or transmitted by any means (including photo copying) without
written permission from Square 1 Electronics and the author.
Copyright © 1999
TRADEMARKS
PIC is a registered trademark of Microchip Technology Inc. in the U.S.A.
PICmicro is a registered trademark of Microchip Technology, Inc.
PICI6/17 is a registered trademark of Microchip Technology, Inc.
MPLAB is a registered trademark of Microchip Technology, Inc.
MPASM is a registered trademark of Microchip Technology, Inc.
PICSTART Plus is a registered trademark of Microchip Technology, Inc.
ISBN 0-9654162-1-6
PUBLISHER
Square 1 Electronics
P.O. Box 501
Kelseyville,CA 95451 U.S.A.
Voice (707)279-8881
FAX (707) 279-8883
EMAIL
[email protected]
http: //www.sq-1.comINTRODUCTION
“PIC'n Up The Pace” begins where "Easy PIC'n" ends. I am assuming you know all the begin-
ner information included in "Easy PIC'n" either from using the book or from other experience.
There will be very little overlap.
‘The programs included in this book are examples to help you lear. My hope is that you will
study the examples in this book and write your own borrowing from what you see here. ‘That
way, you will know what's in your code because you created it. If you want to borrow from the
code i this book, its curently available for downloading atthe Square 1 website (no charge)
or on disk.
Include files are not used in this book because if you use someone else's include file (this
includes those provided by Microchip), you won't know precisely what's in it and will spend a
lot of time scratching your head because your program isn't working because you didn't pay
attention to what the author of the include file had in mind,
If you write the code, you know what's in it and what it does.
Use of macros and most assembler directives is avoided because they confuse people who are
learning more often than not. If you end up doing a lot of "PIC'n", you may find them useful.
Reluctantly, I have chosen to use file register bank switching rather than use the TRIS and
OPTION instructions for the majority of examples in this book. This will prepare you for situa-
tions where things can't be done otherwise plus it will foster understanding of other's code such
as the examples in Microchip's "Embedded Control Handbook",
think you will particularly enjoy the serial LCD module project. It can be incorporated in your
future projects and can be used as test equipment to troubleshoot your own PICI6 applications
as you develop them. It can provide a “window” into what is happening as a PICI6 program is
executed and a way to display results. It can take the place of the LEDs used in the examples in
this book. When you create your own applications, those pins will be busy controlling your wid-
get instead of LEDs and won't be available for display purposes. With the serial LCD module, 1
pin = 1 wire will allow you to display whatever you choose.
Where programs used previously in the book are combined for use in a more exotic application,
Idid not rewrite the code to achieve double duty (shared) use of file registers. This is particular-
ly true in the LCD chapter.
Finally, MPASM (tm) is the name of the assembler contained in MPLAB (tm), although you
‘won't see it called by name when you use it,HEXADECIMAL NUMBERS vs. MPASM ASSEMBLER
‘The use of hexadecimal numbers with PIC 16s is full of inconsistencies! You will see this when
you look through program listings from other sources. For example port B may be equated to
ihe file address hexadecimal 06 in the following ways:
portb equ 6
06
on
nvo6!
0x06
‘The MOVLW instruction is used to load the W register with hexadecimal literals as follows:
moviw 00
oon
nvoo!
0x00
of
ff pwon't work
ffh iwon't work
nteet
oxee
If 00 and Of work, why doesn't ff work? It looks like the same form to me. The important thing
is to be aware of the inconsistencies and use a format that always works.
‘The first character in the literal expression must be "0" or "h" for the assembler to work.
$0000 ...... to make things manageable we will settle on a standard/uniform way of doing
things for the examples in this book.
Single hex digits by themselves will be used for:
Equates —_bits0->7
Instructions _ bit designator b 0 7
Hex addresses will be in the following form:
File registers = data memory OxXX
Program memory OxXXX‘Hex numbers in literal instructions will be in the following form:
/ ~ 2Hex Digits
OK
f ior A Sp Her
novlw oxoe
‘The programs in this book are written using these conventions.
Alll references to hexadecimal numbers in the text of the book will use the Ox notation.
BINARY AND DECIMAL NUMBERS vs. MPASM ASSEMBLER
Binary and decimal literals may be written as shown:
moviw 100001121" ;binary
moviw d'16? :decimal
Note that the ' is the apostrophe on the same key as" on the keyboard. Some listings I have seen
appear to have the literal bracketed in* '. Only’ ' works with MPASM.
ASCII CHARACTERS vs. MPASM ASSEMBLER
Most ASCII characters may be included in a program by doing the following:
moviw ‘At jascii capital APARTS IS PARTS
As the Microchip microcontroller product line grows, and I am glad that it is, the part numbering
convention/system seems to be getting a bit involved. Also, the microcontroller product line
designation has been changed from PIC16/17 (tm) to PICmicro (tm). Microchip is going to do
‘what it will. You and I, however, need a way to keep things straight between us. The real key to
sanity here is to recognize that there are three fundamental product groups in terms of how they
function and, to some extent, how program code must be written for them. The three product
groups have 12-bit, 14-bit and 16-bit cores. We don't really care how many bits are in an
instruction word. We just need to know which set of rules and features apply when writing code
for a selected chip. Here are some popular examples:
Device Core Size Pins
PIC12¢508 12 8
12¢671 14 8
16C54 12 18
16C554 14 18
16c63 14 28
16c71 14 18
16C74 14 40
16F84 14 18
In days gone by, the 12CXXX parts had 12-bit cores, the PICL6CS whatever parts had 12-bit
cores, etc. But no more. Forget the part numbering scheme and look at the data book or
summary for core size.
"Easy PIC'n" and this book talk only about the 12-bit core base-line and 14-bit core mid-range
parts. We will use PIC16 to designate the 12 and 14-bit core parts for lack of anything better to
do.
‘The PIC16C554 is pin-for-pin compatible with the very popular PIC16CS4 and PICL6CS4A and
currently sells for the same price! The PIC16C554 has a 14-bit core and the features that go
with it such as interrupts and an 8-Level stack, plus 2.5 times the number of file registers. I
would guess that the 14-bit core parts will eventually (long term) replace the 12-bit core parts.
As an aside, notice that the PICI6C556A might be useful as a OTP version of the PICI6F84,
less the EEPROM data memory. Food for thought.
‘The PIC16C84 has been replaced by the PIC16CF84.
Microchip is now publishing a Product Line Card revised quarterly which will tell you what's
new and what's current. I find it to be very useful.PROGRAMMING STYLE
One thing I have learned about myself is that when designing programs for PIC16s, I tend to lay
them out the way I think (do this, then do that). PIC16s don't always work the way I think or
visualize a sequence of functions should flow. There are often better/shorter/faster ways for
PIC16s to do things. For example, let's take a situation where we want to test one bit and then
make the second bit the same (1 or 0) as the one tested.
HUMAN 0 ear
HUMANIPICI6
cae ie
‘GOTO >Picts - Baie
LEAP FRoc ote F
Sample Bt Sot? Cicer Be
No
we BIFSC
Test Sample Bit
rs
Set Bit |
—
‘The most efficient way to code this is to use the default method. The bit to be altered is first
cleared by default. If the bit tested is clear, fine. If not, the bit to be altered is set.Since I am a "visual" person, I find it convenient to keep a "cheat-sheet" handy which has flow
charts for some standard operations. You may find the following useful:
rest rt DECREMENT COUNTER, TEST FOR 0
>=——
No
oTrssc o pee
a
bo Return
GoTo
a Do Whatever
‘COMPARE
y
Byte To Be Compared In
w
t
‘Subtract W From Literal, | Alternative: Use XORWL
SUBLW RosutinW | Exclusive OR W With Literal,
Resutin W
BTFSC ce
We Literal,
Zallag Set
GOTO Elsewhere
‘Atornative: Use BTFSS. ,
Code may be optimized for speed, for minimizing use of program memory space, or so you can
understand it, How these considerations are traded off depends on the learning stage you are in
at the moment and the, demands of the application you are working on.CIRCUIT MODULE FOR EXPERIMENTS
"84. ON A BOARD
A simple circuit module may be assembled for use in all of the experiments in this book. It
includes an 18-pin socket for a PICI6F84 (or PIC16C71) with clock oscillator, reset, power
supply decoupling capacitor, and port pullup resistors. These items are required in or are
common to all of the experiments. ‘The pullup resistors are used in the experiments primarily for
the purpose of preventing unused inputs from floating. There are pullups on port B built into the
PICI6F84, I decided not to use them because they just add confusion to the program examples
and detract from explanation of the applications themselves. So..... if you use the circuit,
module, remember to activate (via DIP switches) pullup resistors on all unused port lines (input
or output). You can save refinements for later.
Trecommend connecting the port lines to a 16-pin DIP socket. A 16-conductor ribbon cable
terminated with 16-pin DIP plugs may then be used to connect the '84 on a board to a solderless
breadboard for many of the experiments. The wiring done on the solderless breadboard is,
‘minimal and chances are you won't want to preserve the specialized part of the circuit after you
have done the experiment anyway (on to better things).
I would definitely use a ZIF socket for the '84 to avoid bending or damaging the pins.
‘The same circuit module may be used for the PIC16C71 A/D experiment by substituting a
PIC16C71 in the microcontroller socket.
‘Two'84 on a board modules are needed for the PIC-to-PIC serial communication experiment.10
+8V
t0KPuip
Gee 6.
Rae a Typeal Fer
i 13 Port Lines
2 RAS Rao 17
3
RA/TOCK! —OSct 16 aa
“WOR osc2 15 | -xNC.
PICi6Fes
5 Vss Vad 14
ont | feed
| Reon L- Clock
RB? 13
T Oscillator
| 7 Ret Res 12 | —
—| srBe Res 11 No. =
—| ope RBA 10 |USING OP-AMPS
‘Op-amps will be used in several applications in this book. A complete dissertation on the care
and feeding of op-amps is beyond the scope of this book and lots of reference material is already
available. I have chosen three op-amps for use in the circuit examples as follows:
Application Op-amp and Power Supply (s)
Offset and scale, 3 op-amps T41c_ +/-9v
Offset _and scale, single op-amp MAX406, +5V
A/D - DIY 1-pin, V in, % transform M358, +9V or MAX406, +5V
D/A ~ R ladder w/buffer LM358, +9V or MAK406, +5V
D/A - PWM filter w/buffer M358, +9V or MAX406, +5V
MAX406BCPA is full part number - see Appendix A for source.
Offset and scale with the 3 op-amp design requires handling both positive and negative voltages.
The 741C operates using both positive and negative power supplies and was chosen because of
it's availability and low price.
Offset and scale can also be accomplished using one single power supply op-amp. The
MAX406 was selected because it operates from a single power supply and it can accept input
voltages ranging from ground potential to the power supply voltage (rail-to-rail).
‘The remaining three applications require processing input (with respect to the op-amp) signals
ranging between 0 and +5 volts with unity gain. An LM358 may be used at the cost of an
additional power supply with higher voltage such as +9 volts (or maybe a charge pump circuit).
‘The LM358 is inexpensive and readily available, My alternate choice is the MAX406BCPA.
which will operate from a single +5V supply and from rail-to-rail. It costs more and is a litde
harder to find. Life is full of trade-offs as usual.
NULL 1 — — 8 NC Nu 1 —| — 8 NC
2 }—- 7 ve 2 IH— 7 Ve
aa vac = & our 3 —| Maxaos [ § our
vv 4— [— 5 NULL ve 4 f— 5 NULL
outa 1 — 8 VE
AD 7 OUTB
1A 3 6 8
GND 4 5 4B
1SERIAL COMMUNICATION
Since PIC16s have few pins, serial communication is, more often than not, the best way for the
microcontroller to communicate with peripheral chips on the same board, or between one PIC16
and another via a short cable. Communication between a PIC16-controlled device and the
‘outside world is typically done serially (via RS-232 for example).
If you have not been exposed to serial communication, it involves taking data which is in a
parallel format, converting it to serial format for transmission down a single (data) wire and
converting the data back to parallel format at the receiving end, Sending 8 bits of data in
parallel requires 8 wires for data. Sending 8 bits serially requires 1 wire for data.
Serial communication involves varying numbers of wires for the various functions. Usually the
count does not include ground. In this book, we will not worry about the number of wires and
‘we won't use anyone's protocol or standard. "We will just concentrate on understanding what's
going on and getting the job done.
‘The next chapter covers shift registers. They come in two flavors--serial-in, parallel-out and
parallel in, serial-out. Getting a PICI6F84 to talk to each type is a good way to get started with
serial communication.
The following chapter involves interfacing a PICI6F84 and 93C46 serial EEPROM. This is
another form of serial communication, the design of which is dictated by the 93C46's pin
complement and internal workings.
Next, we'll get one PIC16F84 talking to another PICI6F84. Several other examples will follow.
By the time you finish, you should fee! comfortable with simple serial communication.
Note that the clock signal in the examples is irregular. Timing diagrams for the serial peripheral
devices used as examples show a nice symmetrical clock signal. This is not required. It also is
not possible in many applications.
12SHIFT REGISTERS
Shift registers are used to convert serial data to parallel or vice versa. “Talking” to shift registers
is a good way to get started learning about serial communication. Shift registers are useful as
parallel output and input ports which may be interfaced with a PIC16 serially.
For our first example, we will use a 74HC164 which is a serial in, parallel out shift register. The
in" vs. “out” designations are with respect to the shift register. The object is to create and send
8 bits of data to the shift register serially and look at its outputs via DVM, LED's or whatever to
see if the byte got there successfully.
‘The PIC16F84 will be used in this example.
‘The data to be sent from the PIC16F84 is initially defined and stored in a file register as 8 bits in
parallel format. In order to convert them to serial format, the 8 bits in the file register are shifted
left (RLF) one at a time. Bit 7 of the file register is sent on its way via a single output port line
after each shift. The most significant bit is sent first because that is what the 74HC164 expects.
Example:
Intal 8 Bits
7 °
Of i]s ]o] [oo] 1] conn oF Fe Rags
Shit Lott (ALF) First Time
From Carry Flag
U=Unknown
1 Sent to por line
ison Geary kee \— From Carry Flag
‘The 8 bits are marched out one at a time in succession.
13SERIAL IN, PARALLEL OUT SHIFT REGISTER - 74HC164
Let's talk about the hardware,
o 1 — |— 14 Vee
svz — es
o 3 —} - 12 6
1 4 —) 7aHo1e4 }—- 11 5
25 — — 10 4
a6 — f- 9 CLR
Vss 7 f- 8 cK
Notice the 74HC164 has three control lines.
+ Serial Input
+ Clear ar Clears outputs to 0's (normally HI)
+ Clock = 4 Shifts data through bit 0 toward bit 7
‘To move data into the shift register, the first data bit is presented to the input. Then it is shifted
in. The second bit is presented and shifted, and so on. Simple!
PIC16F84
14Here is how the complete process of sending one byte of data works:
MAIN
PROGHAal Port A Outputs
¥
Initial Control Word To:
Port A
a
(lear Shit Register
t
Load W With Data To Be
Sent
Call Send Subroutine SUBROUTINE [Save Copy Of Data
Circle Load 8 Counter
tostbit |
| Clear Port A, 0
‘Send Reg Bit 7?
‘Set Port A, 0
‘Shift 164 Ragister | Send
‘Shitt Send Register
¥
Dec Bit Counter
Prop For
Next Pass
GOTO tostbit
tt
Roturn
15‘The shift register outputs are cleared on initialization as part of the power-on reset housekeeping
so that all outputs will be low to start with.
‘The assembly language program for doing all this is a subroutine (ser_out). It is a code module
which may be modified, if necessary, to reflect port pin assignment, etc. and used for your own
future projects.
4HC164. ASM:
list — p=16e84
radix hex
: cpu equates (memory map)
porta equ 0x05
status equ 0x03
sendreg equ Ox0e
count equ Ox0d
trisa equ 0x85
bit equates
mp0 equ
org 0x00
start bsf status, rp0_ ;switch to bank 2
movlw b*00000000" ;outputs
movwE trisa
bef status,rp0 switch back to bank 0
moviw 0x04 1000 0100
mowwf porta feontrol word
bef porta,2 felear shift register
bst porta, 2
moviw 0x80 snumber to be sent
call ser_out sto serial out subroutine
circle goto circle done
ser_out movw£ sendreg —; save copy of number
movlw 0x08 sinit @ counter
movwf count,
testbit bef —porta,0 default
btfsc sendreg,7 ;test number bit 7
bsf porta, 0 rbit is set
shift bsf — portay1 ishift register
bef porta, 1
rotift rif sendreg,f ; shift number left
decfsz count,f — ;decrement bit counter
goto testbit pnext bit
return done
end
pat blast time, select:
; memory unprotected
? watchdog timer disabled (default is enabled)
16; standard crystal (using 4 MHz osc for test) xT
; power-up timer on
PARALLEL IN, SERIAL OUT SHIFT REGISTER - 74HC165
Bringing 8 bits of data into a PICI6 serially is done in a similar way. We will use a 74HC165
parallel in, serial out shift register.
Loan 1 —| }— 16 vec
ck 2 — }— 15 Enab
43 4 fe is
5 4 —] f— 13 2
Oe ee
76 — f- 11 0
Rot 7 — I— 10 oF
Ves 8 — - 9 Hout
Notice the 74HC165 has three control lines.
* Serial output
fe toed a Loads 8 bits into shift register
i Clock Shifts data MS bit first
‘The 8 bits of data presented to the shift register are latched in using the load control line. ‘This
must be done so that if the input lines are changing state with time, only the data latched in at
ne instant in time will be transmitted to the PIC16. The 8 data bits are shifted out most
significant bit first.
Again, one PIC16F84 port pin is used for serial in. It is convenient to use bit 0 for serial input.
The program looks at the port as a whole, rotates bit "0" into the carry flag, and rotates the
contents of the carry flag into the least significant bit of the file register assigned to receive the
incoming data. This process is carried out for each of the 8 bits. Notice that the first bit is
available at the serial output line immediately after the data is latched. Shifting 7 times (not 8) is
required to access the remaining bits.
7PIC16F84
14 ef
24 DI Hout
7AHC165
5 6 out Ves
ToTMAIN
PROGRAM
‘Teach Port A
00000001
a
Teach Por B
=
Inital Word To Port A
(00000100 = 0x04
Display At Port B
ara
Circle
SUBROUTINE
shift
gotbit
DECFSZ
¥
(Clear Receive Register
on eae
Load 8 Counter
¥
Load Byte Into Shitt
Register
Load W With Port A.
Contents
+
‘Store In Temp
¥
Rotate Bit Into Carry
Flag ibe
Rotate Carry Flag into | pe
Receive Register
t
Decrement 8 Counter
No
GOTO shit
——
Return
Shift 165 Register
¥
GOTO getbit
19Again, this is code includes a subroutine which you may use in the future.
/4HCL65 .ASMenemmnnn=.
list — pel6ea4
radix hex
: cpu equates (memory map)
porta equ 0x05
portb equ 0x06
status equ 0x03
revreg equ Ox0e
count equ Ox0d
temp equ Ox0e
trisa equ 0x85
trisb equ 0x86
; bit equates
mp0 equ
org 0x00
start bsf —status,rp0_ ;switch to bank 1
movlw 00000001"
movwf triea
moviw b*00000000' ;outputs
movwf trisb
it 0 = input
bef status, rp0_ switch back to bank 0
moviw 0x04 70000 0200
movwf porta ont rol word
call ser_in sto serial input subroutine
mové —revreg,w
movw£ — portb
circle goto circle
ser_in clrf — revreg felear receive register
movlw 0x08 finit 8 counter
movwf count.
bef porta,2 pload shift register
bs porta,2
getbit movf porta,w read port A
movwf temp istore copy
rf temp, £ rotate bit into carry flag
rif revreg,f rotate carry flag into revreg
decfsz count, # idecrement counter
goto shift.
return done
shift bsf porta, pehift 1 bit
bef porta, 1
goto getbit pagain
end
: the 74HC165 gets shifted 7 times
20at blast time, select:
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal (using 4 MHz osc for test) xT
power-up timer on
‘SERIAL IN, PARALLEL OUT - 74HC595,
‘The 74HC595 is similar to the 74HC164, The 8 outputs of the 74HC164 will change state as
data is shifted in. If the chip is being used as a parallel output port, this will not be a good thing.
‘The 74HC595 has latches which hold the data presented at the output lines. New data may be
shifted in while the outputs remain stable. Then the new data is latched in. This, of course,
requires a 4th control line to latch data.
11 — }— 16 vec
22 — — 50
33 — }- 14 oF
44 }- 13 G
$s | mnosss [13 By
66 - 11 cK
774 }- 10 CLR
vss 8 —| — $s aH
‘The 74HC595 has four control lines.
+ Serial Input
+ Latch J” Shift register contents to latches
+ Clock c= Shifts data Ms bit first
+ Clear “Clears shift register
Data is shifted in most significant bit first.
21AS
Rae |-
Rat
RAO
PIC16F84
Serial Out
For Cascading
(NC Otherwise)
‘The 74HC595 has an output line designed for cascading two or more chips,
cascaded by:
74HC595's may be
+ QH serial output of first chip connected to serial input of second chip
+ Connect shift register clear lines together
* Connect shift clock lines together
+ Connect latch data lines together
Clear ——__——— —
Clock
Latch Data
Serial In
+5 +5
Vee 0 DI G LAT GK GA OH
74HC595
ee See vn
4
|
i
|
22MAIN
ppoaaaal Port A Outputs
{fete
y
Initial Control Word To
Port A
+
Clear Shit Register
+
‘Load W With First Data
Byto To Bo Sent
Call Send Subroutine SUBROUTINE [Save Copy Of Data
Load W With Second [Load 8 Counter
Data Byte To Bs Sent
tostbit
t
Call Send Subroutine
[ease | GearPon Ao
Tah Data |
= a
ici i
SeiPon A 8
Shi 164 Rogier] Send
=
Prop For
Shit = Register | foe poss
Dec Bit Counter
DECFSZ
een
Return
237 4HC595 , ASMane=mnnnnnes
List pel6ee4
radix hex
cpu equates (memory map)
porta equ 0x05
status equ 0x03
sendreg equ Ox0c
count equ —Ox0d
trisa equ 0x85
: bit equates
rp0 equ.
org 0x00
start bsf —status,rp0_ ;switch to bank 1
moviw b*00000000' ;
movwf trisa
mutputs:
bef status, rp0 ;switch back to bank 0
movlw 0x04 0000 0100
moww£ porta ieontrol word
bef ——porta,2 iclear shift register
bsf —porta,2
movlw 0x80 ;first number to be sent
call ser_out ite serial out subroutine
moviw 0x0f isecond number to be sent
call ser_out —to serial out subroutine
bst porta, 3 iregister contents to latches
bef porta, 3
circle goto circle lone.
ser_out movwf sendreg —; save copy of number
movlw 0x08 sinit 8 counter
movwf count
testbit bef porta, 0 lefault
btfsc sendreg,7 test number bit 7
bsf porta, 0 pbit is set
shift bsf porta, ishift register
bef —porta,1
rotlft rif sendreg,f ;shift number left
decfsz count,f ;decrement bit counter
goto testbit pnext bit
return idone
end
pat blast time, select
: memory unprotected
: watchdog timer disabled (default is enabled)
standard crystal (using 4 MHz osc for test) xT
power-up timer on
24SERIAL EEPROMS
Serial EEPROMs come in three main flavors and a variety of sizes. The 93XXX devices are the
easiest to interface to PIC16s (in my humble opinion). We will use the 93C46 (by Microchip
and others) as an example.
‘The 93C46 is a small non-volatile memory peripheral chip. It is organized as 64 registers of 16
bits each. The programming voltage and write timing are developed on-chip. The self-timed
write cycle takes about 10 milliseconds.
All communication with the 93C46 begins with sending 9 instruction bits. The first bit (MSB) is
a logic "1" start bit. The remaining 8 bits may be an op code or an op code and address.
combination. If the operation is a write operation, 16 data bits follow the instruction bits, MSB
first.
‘The 93C46 is available in an 8-pin DIP.
cs 1 — }— 8 veo
cuk 2 —| }— 7 NC
pl 3 —) C48} 6 No
Do 4 }— 5 Vss
‘The control lines
+ Serial data in
+ Serial data out
+ Clock ie
+ Chip select.
Some use rules are:
1) A register must be erased (all 1's) before it can be written to. The chip has a built-in
auto erase cycle which takes place when a write is called for.
2) The chip select pin (CS) must be brought low for a minimum of 1 microsecond
between consecutive instruction cycles to synchronize the internal logic of the device.
3) For read operations, a dummy "0" precedes the 16 data bits. Data is shifted out MSB
first.
254) Completion of an erase cycle or write cycle to an individual memory location takes
about 10 milliseconds. The serial data output (Dg) pin may also be sed as a status pin
during the self-timing phase of these operations t0 indicate the status of the device.
On completion of erase or write, CS is brought low briefly. After that, Dg will be low
until the operation is complete. When Do goes high again, the device is no longer
busy and is accessible for other operations.
‘The instructions are:
+ Read a register
+ Write to a register
+ Erase a register
+ Erase/Write enable (EWEN)
+ Erase/Write disable (EWDS)
+ Erase all registers (ERAL)
+ Write all registers (WRAL) (with same data)
Thaven't figured out why anyone would want to write the same data to all registers, but maybe
you will.
‘There are 6 address bits (to definite 64 register locations) contained in the instruction words that
need them.
More Op Code
Start op or
Operation Bit Code Address
Read 1 1 0 AS Ad a3 az Al AO
Write 1 0 2 AS Ad A3 Az Al AO
Erase 1 1 1 AS Ad a3 a2 al ao
EWEN 1 0 0 2 4 x x x x
EWDS x x
ERAL eee 0 xx
WRAL ee x
X = Don't care
Now we need to digest all this and figure out how to write some code to make the thing work.
One way to write a program to communicate with the 93C46 is to send the start bit as a separate
operation which precedes sending the remaining 8 bits. Then the remaining 8 bits will fit into a
file register. This file register is used as a working register to cook up instruction words:
[— Start Bit - Handled Separately
EE Oncade /— More Oped Or Adress
26The next consideration is what to do with the
Now the instruction table looks like this:
don't cares. Let's make them '0's".
Hex More Op Code
op op or
Operation Code Code Address
Read 1 0 AS Ad AS AZ AL AO
Write Oo 1 AS ad a3 a2 Al AO
Erase aS R43 2) Al AO)
EWEN 0x30 0 0 2 1 0 0 0 0
EWDS x00 0 012 0 0 0 0 0 0)
ERAL e202 0 0 0 0 0 0
WRAL CO 0 0 8 © ) OC t
‘This method of putting "0s" in place of "X's" makes the instruction table look less intimidating.
Further, there are now four hex opcodes we can use for four of the instructions to make life
easier.
Next we need to deal with addresses in individual register operations. Perhaps the easiest thing
to do is to dedicate a file register for holding the address prior to executing our serial routine.
‘The routine can grab the address from there and move it to the working register (labeled "cook").
Don't worry about the upper 2 bits in the address register For the address 00 0000 (binary), use
0x00. The range is 0x00 to Ox3F. In the "cook" register we can modify the upper 2 bits to make
them an erase, read, or write op code. At that point, we have cooked up the complete instruction
for the operation.
This example EEPROM serial communication program will be modular meaning a main
program will call subroutines such as "read one register” or "write one register" which will, in
turn, call other subroutines as needed.
To get started, we will need an erase one register subroutine, a write to one register subroutine,
and a read one register subroutine. We will need to precede erase and write with an erase/write
enable (EWEN) and follow with an erase/write disable (EWDS).
Notice that the start bit is sent as part of the code as needed (requiring 2 instructions) and that 8
bits of op code/address/data are sent at a time directly out of the "cook" register.
You can write an “erase all registers" routine on your own if you find a need for one.
‘These routines may be modified and used in your own programs.
27DEMO CIRCUIT
This circuit will be used to demonstrate interfacing a PIC16 to a 93C46 serial EEPROM:
RAS
Raz
Rat | —
Rao
PIC16F84
pone |=
MAIN PROGRAM - INITIAL TEST
‘The main program will make use of subroutines. It will enable and disable operations, write toa
register, and read back 16 bits of data from a register. If we can make this work, we can do
anything we want with the 93C46.
‘An erase the contents of a register subroutine is also shown.
28Teach Pon A
¥
Teach Por B
t
Initialize Port A
[eset]
LEDs Of
¥
DefineTest Address
¥
Define Data High Byte
¥
Datine Data Low Byte
¥
Call Write Subroutine
¥
Call Read Subroutine
¥
Display Byte AtLEDs | High OrLow Byte
¥
Circle30
owds
Put EWEN Opcode In
‘cook
a
Set Port A, Bit 1
a
Shift Clock - Pulse.
+
Call Send 8 Bits Sub
=aesyaeee
Return
Put EWDS Opeode In
‘cook
¥
Sot Port A, Bit 1
t
‘Shift Clock - Pulse
[_saeree_]
Call Sond 8 Bits Sub
+
Return
Sond Start Bit
‘Send EWEN Opcode
Send Start Bit
‘Sond EWDS Opcodewate CSHigh
Call EWEN Subroutine
¥ ,
Stow
t Pulse
SHigh
a
Put Write Address In
‘cook
=
(cook Bité = 1
Opcode in Y
High 2 Bits
(cok Bit7 = 0
L I Wite
‘Sot Port A, Bit 1
‘Send Start Bit t
Shitt Clock - Pulse
—_—_+
Call Send 8 Bits Sub
4 a
Load Data High Byte In
cook
__+ _
Call Send 8 Bits Sub
v ‘Sond Data
Load Data Low Byte In
‘cook
a
Call Send 8 Bits Sub
¥ 4
Stow
: bute
CSHigh
t
3132
cycled
———>}
Yes, Write Cycle
x
——_ |
-
Call EWDS Subroutine | Disable
¥
Slow
|_s=
Returntoad
Opcode In High 2 Bits
‘Send Start Bit
CSHigh
+
Put Read Address In
‘200k
t
cook Bit 6 = 0
¥
(00k Bit 7=1
¥
‘Set Port A, Bit
¥
Shift Clock - Pulse.
¥
Call Send 8 Bits Sub
¥
Call Sub Shitt 8 bits Out
‘Of EEPROM
¥
Byte In cook To hibyte
¥
all Sub Shit 8 Bits Out
‘Of EEPROM
Y
Low Byte In cook:
ee
(CSLow
Ls __t
——— sk
Return
| Read
Note: Dummy 0 Appears
‘AtOutput
High Byte In hibyte
Low Byte In cookCSHigh
T
——_¥
Call EWEN Subroutine | Erase/Write Enable
¥
Slow
Opcode In High 2 Bits
Sot Port A, Bit 1
T Send Sat Bt
Ti Cock Puke
+
Call Send 8 Bits Sub
L_CatSene 2
v
Slow
¥
SHigh
ecyclet
i Yes, Erase Cycie Completed
Call EWDS Subroutine | Erase/Write Disable
CSLow
T
ey)
34 Returnoe Load 8 Counter
sbit
Call Send Bit 15 Is Sont First,
DECr: =
[coro shit cook tot_]
-
Roturn
| sftcook
Shift cook Lott
¥
GOTO sbit
35sondbit
BTFSC
getprom
36
—
‘Sot Port A, Bit 1
Shift Clock - Pulse
Return
Load 8 Counter
Shift Clock - Pulse.
¥
‘Get Port A Contents
¥
Store Copy
¥
Rotate LS Bit into Carry
Flag
¥
Rotate Carry Flag Into
‘cook
ClearPort A, Bitt | Detauit
Shit Bit Out Of EEPROM -
First Shift Gets Rid Of Dummy Bit
PRE
Data 15 Out First
RLF93046. ASH========="
sannmmnnd /26/97==
map)
List pel6fad
radix hex
? cpu equates (memory
status equ 0x03
porta equ 0x05
porth equ 0x06
cook equ —Ox0e
hibyte equ 0x0d
count equ —Ox0e
address equ 0x0f
datahiequ 0x10
datalo equ 0x11
temp equ 0x12
trisa equ 0x85
trish equ 0x86
i bit equates
xpo equ
org 0x00
start bsf status, rp0
movlw "00000001"
movwf trisa
movlw — '00000000"
moww£ trisb
bef status, rp0
bef portay1
bef porta,2
bef porta, 3
moviw 0x00
movwf — portb
movlw 0x00
movwf address
movlw 0x80
movw£ data_hi
movlw 0x0f,
movwf data_lo
call write
call read
movf cook,
movwf — portb
circle goto circle
sewitch to bank 1
fbit 0 = input
outputs
rawitch back to bank 0
pinitialize
pinitialize
pinitialize
700000000
PLEDs off
idefine test address
idefine test hi byte
idefine test lo byte
weite subroutine
read subroutine
iget 10 byte
idisplay via LEDs
done
ewen — moviw 0x30
mowwE cook
bsf porta, 1
bsf —porta,2
bef —porta,2
call —_sendbits
return
fewen op code
ito cook
isend start bit
pehift
send ewen op code
37ends:
novlw
move
bef
bst
bef
call
return
0x00
cook
porta,1
porta,2
porta,2
sendbits
rewds op code
ito cook
isend start bit
renit
rend ewds op code
write
ecycle2
bst
call,
bet
nop
bst
move
movwt
bef
bsf.
bst
bst
bet
call
movt
movwe
call
movt
ovat
call,
bet
nop
bst
betss
goto
bof
nop
bst
call
bef
nop
return
porta,3
even
porta,3
porta,3
address,
cook
cook, 7
cook, 6
porta,1
porta,2
porta,2
sendbits
data_hi,w
cook
sendbits
data_lo,w
cook
sendbits
pozta,3
porta,3
porta, 0
ecycle2
porta,3
porta,3
ends:
porta,3
res high
yerase/write enable
yes low
#1 microsecond min
pes high
get address
store in cook
‘op code
ims 2 bits
fsend start bit
ishift
isend address
aget data hi
reend data hi
iget data lo
psend data lo
res low
;1 microsecond min
pes high
rwrite cycle complete?
inet yet,
ies low
#1 microsecond min
pes high
iyes, erase/write disable
ies low
#1 microsecond min
read
38
bst
mové
movwe,
bet
bet
bet
bet
bet
eall
call
nov
nowt
call
porta,3
address, ¥
cook
cook, 7
cook, 6
porta,2
porta,2
porta,2
sendbits
getpron
cook, w
hibyte
getprom
yes high
iget address
sop code
ims 2 bits
peend start bit
pshife
isend address
ishift hi 8 bits out of eeprom
hi byte result in hibyte
ishift lo 8 bits out of eeprombef porta, 3 ies low
nop Amicrosecond min
return rexit sub with lo byte in cook
sendbits moviw 0x08
movw£ count
sbit call sendbit_ © ;send 1 bit
dectsz count, £ #done?
goto sftcook = :no
return ryes
sftcook rf cook, f rshift cook left
goto sbit pagain
sendbit bef porta, pdefaurt,
beac cook,7 itest cook bit 7
bst porta, 2 pbit is set
shigt) bsf — porta,2 pshift
bef porta, 2
return
getprom moviw 0x08 #eount
movwf count,
shift2 bsf — porta,2 sshift
bef porta, 2
movf porta,w ;read port A
movw£ temp istore copy
ref temp, £ rotate bit into carry flag
lf cook, jrotate carry flag into cook
dectsz idecrement counter
goto
return done
end
yat blast time, select:
3 memory unprotected
watchdog timer disabled (default is enabled)
standard crystal (using 4 MHz osc for test) xT
power-up timer on
erase bsf porta, 3 cs high
call ewen exase/write enable
bef porta, 3 res low
nop 71 microsecond min
bsf —porta,3 tes high
movf _ address,w ;get address
movw£ cook stoze in cook
sf ——cook,7 ‘op code
psf cook, 6 ims 2 bits
bsf —porta,1 send start bit
bsf —porta,2 shift,
39ecyclel
bef.
call
bef.
nop
bst
betas
goto
bet
nop
bsf
call
bef.
nop
return
porta,2
sendbite
porta,3
porta,3
porta, 0
ecyclel
porta,3
porta,3
exude:
porta,3
isend address
res low
71 microsecond min
zea high
rase cycle complete?
jot yet
yes low
microsecond min
pes high
ryes, erase/write disable
3 low
#1 microsecond min
NOP are used to insure that the 93C46 chip's timing requirements are met.
40PIC-TO-PIC SERIAL COMMUNICATION
In an effort to expand our serial communication capabilities, we will get a couple of PIC16s to
talk to each other. Actually, we'll do part of the job by getting one PICI6 to talk while the other
listens. We'll see if the listener understood what the talker said. We will set this up so you can
continue on your own by sending more than one word and by interchanging the talk/listen roles
(ewo-way communication).
SEND RECEIVE
10K
Close = Send ‘
RAZ
‘Two '84 on a board modules may be used for this experiment.
Both PIC16s are PIC16F84s with 4.0 MHz clock oscillators. For the transmitting chip, port A,
bit 1 is used to transmit. The receiver uses port A, bit 0 to receive. We will choose the bit time
interval as 256 internal clock (1 MHz) cycles. Both transmitter and receiver will use TMRO for
timing.
‘When the transmit data (TD) line is high, the condition is known as "mark". When TD is low,
the condition is known as “space.” The terminology comes from the old teletype days.
‘When one word (8 bits) is sent, the TD line output vs. time will look like this:
_
=,
Un
4‘The TD line sits at mark = logic "1" until the word is sent. It drops to"
bit which tells the receiver PIC16 that an 8-bit word is coming.
first. This is the start
The transmitter transmits bits at some rate (bits per second = baud rate). The receiver must be
set up to receive bits at the same rate. When the receiving PIC16s receive program is running, it
sits in a loop looking for a start bit (high-to-low transition on the receive data (RD) line. When
that transition takes place, the receiver's program waits for a time equal to half the width of the
start bit. It looks at the RD line to see if itis still low. If not, a false start occurred and the
program goes back to looking at the RD line. If the RD line is low, valid data follows and the
program starts TMRO (free-running mode) for a time interval equal to the width of a bit. Then it
looks at the RD line to see if a "0" ora "1" is present. It grabs that bit and shifts it into a file
register (shifting left, MSB received first). The program waits a bit-width (to middle of second
bit, bit 6) and grabs it and stores it. This process is repeated until all 8 data bits have been
received. The 8-bit word received is then displayed at the port B LEDs so you can see if the
correct data was received.
T Slight Offset
Start
Bt | Bt7 Bie
| step
256 | 256 | Etc. Bk
tz Ll se | 206
var een —
Sore oad Ft 8
even
Sta Tiner- Fre Pun
‘The use of TMRO is explained in Eaey PIC'n,
The default method for bit testing is used in the send program. The output bit may be cleared
when it should be set, but it gets cleared right after that. It doesn't matter because the receiver
samples the bit in the center. What goes on at the beginning or end will have no effect.
Flow charts and code for this simple example follow. The technique will be used for the serial
LCD interface in the next chapter.
42SEND
Main, [_Por A, Bitt Output
¥
Port A, Bit HI = Mark
¥
Define Data
[eee
Data To Send Register
No
Twitch Closed 7
Yes
Call Serial Out Sub
a
Circle
RECEIVE | Port, Bits 0 And2
MAIN Inputs
¥
Port B Outputs
=
1
‘Sot Output Bit
tit
US accaaceaeea | seen
times
IF stop Bitradix
pal6ee4
hex
tme0
status
porta
intcon
sendreg
count
optreg
trisa
cpu equates
equ
equ
equ
equ
equ
equ
equ
equ
x02
0x03
0x05
Ox0b
oxde
oxoa,
0x81
0x85
(memory map)
bit equates
eqs
equ
°
5
ewiten
circle
org
bef
movlw
movwt
bef
bsf
movlw
movwt
btfse
goto
call,
goto
ox000
status, rp0
»*00000100"
trisa
status, rp0
porta,1
0x80
sendreg
porta,2
switch
ser_out
circle
iswitch to bank 1
pport A inputs/outputs
witch back to bank 0
poutput mark, bit 1
inunber to be sent
istore
tstart. send?
rot yet,
ito serial out subroutine
idone
ser_out
edmel
nxtbit
time2
bef
bet
clre
clrudt
bsf
movlw
movw£
bef
movlw
movwt
bef
clrf
bet
btfss
goto
bef
rif
bef
btfse
bot
btfss
intcon, 5
intcon,7
emz0
status, rp0
b*11011000"
optreg
status, rp0
0x08
count,
porta,1
tmr0
intcon,2
Anton, 2
eimel
intcon,2
sendreg,£
porta,1
status,e
porta,}
intcon, 2
;disable tmr0 interrupts
disable global interrupts
pelear timer/counter
relear wdt prep prescaler assign
o page 1
et up timer/counter
sback to page 0
pinit shift counter
petart bit
pstart timer/counter
pelear tmr0 overflow flag
ptimer overflow?
tyes, clear overflow flag
protate msb into carry flag
pelear port A, bit 1
ptest carry flag
it is set
itimer overflow?goto timez sno
bef intcon,2-;clear overflow flag
decfsz count,f — ;shifted 8?
goto nxtbit ino
bsf porta, —;yes, output mark
time3 btfss intcon,2 timer overflow?
goto time no
return done
end
¢ blast time, select:
: memory unprotected
watchdog timer disabled (default is enabled)
standard crystal (using 4 MHz osc for test) xT
power-up timer on
46Tao iiorups || SERIAL IN
¥ seri
SetUp THF
Shit Count «8
a
Cc. ——--——- 7?
| If Read Port A
| ¥
| Yes Sore Intomp
| Stan THRO 0700 | Oia v
| 7 RaFtonp 7} ton cary Fag
Gioa Tio Oiow Fag t
RLF rovreg Carry Flag Into revreg
Yes
Ye GOTO time2
i sl Low?|
| >
| = |r _
|e GOTO sbi | fe yt
| Input |
TJ} ect
Stan THRO Free Run | Yes
¥ | Return
Clear TMRO Oriow |
‘Clear TMRO Ofiow Flag
Ld
a7List
radix
2PRCV.ASH=
pal6£e4
hex
tmx
status
porta
portb
intcon
revreg
count
temp
optreg
trisa
trisb
cpu equates (memory map)
equ
equ
equ
equ
equ
equ
equ
equ
equ
equ
equ
x01
0x03
0x05
0x06
Ox0b
Oxde
oxoa,
Oxde
oxe1
0x85
0x86
zp
bit equates
equ
5
start
switch
circle
org
bet
movlw
movwt
movlw
movwt
bof
cle
clr
btfsc
goto.
call,
mové
nowt
goto
0x000
status, rp0
#0000101"
trisa
b*00000000"
trisb
status, xp0
portb
rovreg
porta, 2
switch
revreg,w
portb
circle
pswitch to bank 1
sport A inputs/outputs
iport B outputs
jback to bank 0
soperator ready to receive?
es, to serial in subroutine
jet byte received
idisplay via LED's
ser_in
abit
timer
48
bef
bee.
clrt
clewdt
bet
movlw
movwE
bef
moviw
movwt
befac
goto
movlw
movwt
bet
btfss
goto
intcon, 5
intcon,7
tmr0
status, rpo
111011000"
optreg
status, rp0
0x08
count
porta, 0
abit
oxe0
tmz0
intcon,2
intcon,2
timel
idisable tmr0 interrupts
;disable global interrupts
‘lear timer/counter
iclear wdt prep prescaler assign
ito page 1
iset up timer/counter
sback to page 0
yinit shift counter
flock for start bit
pmark
istart bit received, half bit time
;load and start timer/counter
iclear tmr0 overflow flag
imer overflow?btfsc porta, 0 istart bit still low?
goto sbi ifalse start, go back
elre — tmrd syes, half bit time - start timer/ctr
bef intcon,2;clear tmr0 overflow flag
time2 btfss intcon,2 timer overflow?
goto time2 ine
bef —intcon,2-—zyes, clear tmr0 overflow flag
movf porta,w read port A
movwf temp store
rrf temp, rrotate bit 0 into carry flag
lf revreg,f —;rotate carry into revreg bit 0
decfsz count,f shifted 87
goto time2 ino
time3 btfss intcon,2 timer overflow?
goto time ino
return ryes, byte received
end
at blast time, select:
: memory unprotected
watchdog timer disabled (default is enabled)
standard crystal (using 4 MHz osc for test) XT
power-up timer on
To run the programs:
Run "send" first with switch off (RA2) - establish proper level on TD = mark.
Run receive second with switch off (RA2) - get ready to receive.
Stabilize, then switch on = ready.
Send switch on.
Notice that these routines transmit/receive most significant bit first. To transmit/receive least
significant bit first, change the rotate left file (RLF) instructions to rotate right file (RRF)
instructions.
Multiple bytes may be transmitted from the file registers by using the FSR and indirect
addressing and a counter. Multiple bytes may be transmitted from a table in program memory
by using relative addressing and a counter. Examples of both will be shown in the LCD
Interface chapter.
49LIQUID CRYSTAL DISPLAY INTERFACE
LIQUID CRYSTAL DISPLAY OVERVIEW
Liquid crystal displays (LCD) are now available which are inexpensive, display alphanumeric
characters, require only 14 wires for connection and are simple to use. They come 16 to as
many as 40 characters wide and 1, 2, or 4 lines high. We will use a 1 line x 16 character LCD.
1X16LCD
The | line by 16 character display (Hitachi LM020L, Optrex DMC-16117A, Optrex DMC-
16117AN or equivalent) is controlled by a Hitachi HD44780 LCD controller chip which is sur-
face mounted on the back side of the display module's printed circuit board. The HD44780 dis-
play controller is commonly used in a variety of liquid crystal displays made by manufacturers
such as Hitachi, Optrex, Amperex, Densitron and Epson. The following description will apply
in a general way to similar displays made by these manufacturers,
51Pins And Functions
52
GND
+5V
GND
RS_
R/W - GND for simplicity
BOSR Seer sun
Note: Pin 3 may be used to control brightness. Merely
wiring it to ground is adequate for most applications
and doing so simplifies the circuit.
iat on
LCDPort B
Port A
Pont A
24
Por 8
01234567
0000000000000
LcDThe display module has three control lines. RS makes the selection of instructions vs data and
may be thought of as an address line which selects either the control register or the data register.
‘The R/W line sets up for read vs. write. For our applications, the display will be written to only,
so the R/W line is wired to ground. If used, the read mode would be used to read the contents of
some RAM locations internal to the display module. E enables the display registers for a write
operation when HI (logic 1).
Using the display involves initialization, sending control words and sending data. Two output
ports will be involved in controlling the display, one for display data and display instruction
words and the other for E and RS.
Port Bit (s) Function
B 0-7 Data
A 2 RS
A 1 E
Data vs Instruction
‘There are two ports and some timing involved in controlling the display. The display control
lines are set up before sending either an instruction word or a data word. The RS line is asserted
0 for sending an instruction or 1 for sending data.
RS
Instruction
Data
‘This must be done in advance of pulsing the enable line HI. Also, the data or instruction byte
must be stable at port B prior to pulsing the enable line HI.
54Display Control
Instruction words are sent to the display to tell it what mode to operate in.
Operation Instruction Word Function
Function Set 0x38 8-Bit, 5x7
Used At Initialization only
Display On/Off — 0x0C Display On, No Cursor
OxOF Display On, Cursor Blink At Left
Clear Display 0x01 Clear Display = Blanks
Entry Mode Set 0x06 Increment Mode
‘These instruction words are sent to the display as part of the display initialization routine.
Details follow.
Character Addresses
Each of the 16 display characters has an address. This tells the display controller where to put
the next character data byte.
OOOOOOdo0o000000
0x80 0x87 ‘oxco oxc7
Detailed information about the operation of the display follows.
55LCD OPERATION
PICILCD Circuit
cee
10K<> < 4 RAZ RA 18
one pao 17 | ———+ Serial Input
3 RAATOCK! — Osct 16
o> 8 Vad 14 4MHz
—
eR osce
PIC16Fea
ci
| sod snes
1000, 9 RBS RB4 10
Reset 1
‘Dooooc00000000
LoD
56We will need some code to initialize the display to test the demonstration circuit. This will
consist of a short main program which delays 5 milliseconds to allow the LCD microcontroller
time to get itself organized after power-on reset (essential), an initialization routine for sending
the LCD its operating mode instructions, and a second 5 millisecond delay (not needed here but
useful later). ‘Two time delay subroutines are included along with a subroutine for pulsing the
display module to send each word.
For this example, the LCD module will run in the 8-bit mode meaning 8 parallel lines are used
to transmit instructions and data to the display.
list — p=16£84
radix hex
: cpu equates (memory map)
status equ 0x03
porta equ 0x05,
portb equ 0x06
countl equ —0x0c
count2 equ x0
trisa equ 0x85
trisb equ 0x86
A bit equates
mp0 equ 5
org 0x00
start bsf status, rp0_ switch to bank 1
moviw 100000000" ;outputs.
movwf trisa
mowwf trisb
bef status, rp0 ;switch back to bank 0
moviw b'00000000' ;a1l outputs low
movwf porta
movwf — portb
call del_S jallow lcd time to initialize itself
call initled initialize display
circle goto circle idone
initicd bef —porta,1_— Eline low
bef porta, 2 ;RS line low, set up for control
call de1_125 delay 125 microseconds
moviw 0x38 p8-bit, 5x7
mowwf — portb 70011 1000
call pulse ppulse and delay
moviw 0x0 idisplay on, cursor blinking
movwf portb 0000 1211
call pulse
movlw 0x01 iclear display
movwf — portb 0000 0001
call pulse
call del_s idelay 5 milliseconds after init
return
57Timing And Pulsing
Four subroutines are used for timing and for pulsing or strobing instruction or data words into
the display. The applications for the 5 millisecond time delay subroutine were explained
previously.
The process of sending either an instruction or data word involves:
1) Setting up the RS line (0 or 1)
2) Delay 125 microseconds
3) Sending the control or data word to the output port
4) Raising the E line HI momentarily to enable the display to
receive the byte and then LO again
5) Delay 125 microseconds
5 Millisecond Delay
del_S moviw 0x29 decimal 40
movwf — count2 ito counter
delay call del_125—;delay 125 microseconds
decfsz count2,f do it 40 times = 5 milliseconds
goto delay
return reounter 0, ends delay
125 Microsecond Delay
de1_125 moviw Ox2a
movw£ count
approx 42x3 cycles (decimal)
load counter
repeat decfsz counti,£ — ;decrement. counter
goto repeat. not 0
return icounter 0, ends delay
Pulse Subroutine
pulse bsf —_porta,1 ppulse & line
nop. rdelay
bof porta, 1
call del_125 delay 125 microseconds
returnTesting The Circuit
‘The complete assembly source code for testing the display demo circuit follows. ‘The display
should have a blinking cursor at the left position and all other characters should be blank. This
demonstrates that the circuit and LCD module are operating properly.
a====LCDTST. ASM=: menannes /5/97=:
list p=16e4
radix hex
: cpu equates (memory map)
status equ 0x03
porta equ 0x05
portb equ 0x06
counti equ Ox0c
count2 equ —0c0d
trisa equ 0x85
trisb equ 0x86
3 bit equates
5
org 0x00
start bsf — status, xp0
movlw 00000000"
movwE trisa
movwf trish
switch to bank 1
outputs
bef status, zp0_ ;switch back to bank 0
movlw 100000000" ;a1i outputs low
movwf porta
movw£ — portb
call del_5 sallow led time to initialize itself
call initled —;initdalize display
circle goto circle done
initicd bef porta,1 E line low
bef porta, 2 RS line low, set up for control
call del_125, delay 125 microseconds
movlw 0x38 B-bit, 5x7
movwf — portb 70011 1000
call pulse tpulse and delay
movlw 0x0f display on, cursor blinking
movw£ port 70000 1111
call pulse
moviw 0x01 iclear display
movwE — portb 70000 0001
call pulse
call del_s. sdelay § milliseconds after init
return
del_125 movlw Ox2a fapprox 42x3 cycles (decimal)
movwf count ;load counter
59repeat decfsz countl,f — ;decrement counter
goto repeat. snot 0
return icounter 0, ends delay
del_5 moviw 0x29 sdecimal 40
movwf — count2 ;to counter
delay call del_125 | ;delay 125 microseconds
dectsz count2,£ — ;do it 40 times = 5 milliseconds
goto delay
return feounter 0, ends delay
pulse bsf porta, 1 ppulse E line
nop rdelay
bef porta, 1
call del_125 idelay 125 microseconds
return
end
at blast time, select:
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal (using 4 MHz osc for test) xT
power-up timer on
Display RAM
For the experiments in this book which involve sending characters to an LCD, we will
use 20 file registers as display RAM. ‘The addresses are 0x20 through Ox2F.
0x20 0x27
0x28 oxaF
The display RAM will be filled with the ASCII characters to be displayed including blanks. A
subroutine will be used to send the contents of display RAM to the display one character at a
time in sequence beginning with location 0x20. This involves the use of indirect addressing
(explained in Basy PIC'n). The File Select Register (FSR) will be loaded with the address of
the first character to be sent to the display, 0x20. After the first character has been sent, the FSR
will be incremented to point to the next display RAM location (0x21) in preparation for sending
the second character.
‘The program instruction says to load the W register with the contents of location 0x00. This
location does not exist. What really happens is the contents of the FSR is used as the address.
‘The example code which follows may be examined to see how this works.
60Initialization
The operating mode of the display is determined by the initialization instructions which are sent
to it prior to use. ‘These instructions control data word length (4 or 8 bits - we will use 8 for
now), display on/off, cursor on/off, display clear, character font (5 x 7 or 5 by 10- we will use 5
x7). The details are omitted here.” The useful instructions are:
Operation Control Word Function Delay
Function Set 0x38 B-Bit, 5x7 125 usec
Used At Initialization only
Display on/off 0x0c. Display On, No Cursor 125 psec
ox0F Display On, Cursor Blink At Left
Clear Display 0x01 Clear Display = Blanks 5 msec
Entry Mode Set 0x06 Increment Mode 125 sec
‘These control words are used in the display initialization routines.
‘An example initialization routine follows. The first two instructions select the display's control
register so that control words may be sent. This is followed by a time delay (125 microseconds)
to allow time for the display controller to set up to receive the control words. ‘The next instruc-
tions tell the LCD module that data will be send in 8 bit format and that the character format is
5x7 dots. The next instructions turn the display on and the cursor off. The final instructions
select increment mode with no shift. Details of LCD operation are available in the manufactur-
er’s data book. This is all you need to know for now.
Notice that a time delay subroutine (125 microseconds) is called after each control word is sent.
This is essential and allows the LCD controller time to perform each operation before the next
one is called for.
A longer delay (5 milliseconds) is required between power-on reset and initializing the display
(ist use), after clearing the display (should you choose to use this instruction in one of your own
applications), and after initialization is complete.
ASCII
The LCD displays ASCII characters. A large variety of characters may be displayed including
upper and lower case letters, punctuation marks, special symbols and more. You can even create
your own graphic elements which requires writing to the display's RAM (beyond the scope of
ihis book.)
Most ASCII characters may be defined in MPASM using the MOVLW instruction.
moviw "At idefines capital "A"
61EXAMPLE ROUTINES FOR LCD
The techniques just described may be combined in a program which sets up and controls the
display and which displays the word "HELLO". The characters (including blanks) will be
stored in 16 consecutive file register or RAM. locations. An initialization routine will set up the
display and fill the display RAM with blanks on reset. ‘The subroutines we will need are:
Display RAM
Fill with blanks
Fill with "HELLO"
LCD initialization (reset)
Send 16 characters from display RAM to display
Control
125 microsecond delay
5 millisecond delay
Pulse Subroutine
Main 5
PROGRAM = =
Port B Outputs
Port A Outputs Low
a
Port B Outputs Low
+
FillDispay RAM With
Blanks
¥
‘Message "HELLO™ In
Display RAM
¥
Delay 5 Milliseconds.
t
Initialize LCD
¥
Display RAM Contents
To Display
¥
Circle
62jennemeaLCD8 -ASMO==:
list p=16fe4
radix hex
A cpu equates (memory map)
indf equ 0x00
status equ 0x03
for equ (x04
porta equ 0x05
portb equ 0x06
counti equ 0x0c
count2 equ Ox0d
trisa equ 0x85
trisb equ 0x86
3 bit equates
z ae
rp0 equ 5
org 0x00
start bsf status, rp0_;switch to bank 1
movlw "00000000"
mow trisa
movwf trisb
bef status, rp0._ switch back to bank 0
moviw '00000000' ;all outputs low
movwf porta
movwf — portb
outputs:
call blanks ;£411 display RAM with blanks
call hello ;ereate message in display RAM
call del_5 pallow lcd time to initialize itself
call initicd initialize display
call dispié isend 16 characters to display
circle goto circle pdone
Fill Display With Blanks
Filling the display with blanks can be done using a clear instruction designed for this purpose.
Instead, we will fill the display RAM with blanks and send them to the display. This way, a
character or two in the display ram can be changed while the rest remains as is, including blanks.
Then all 16 characters are sent at once, The whole display message including blanks does not
have to be created each time.
‘The fill the display RAM with ASCII blanks routine works as follows:
63Cai oF
Fra Depa
Aste TOFS
nn ASC Blark=
‘oo
a Bank Day
FA Pocton Pod
Tooyean
ves
oecrsz
%
GTO rater
Insane FSA
_ v
conve
blanks novlw oxi0——_count16
Tovlu 0020" jtiest tsptay RaM address
store owe indf store in display RAM Location
; pointed to by file select segister
dectse counti,£ 169
Notice the use of indirect addressing. The file select register (FSR) is loaded with 0x20, the
address of the first display RAM location. Then the contents of the FSR is incremented 16 times
to step through the 16 display RAM locations.
64Display "HELLO"
Displaying the word "HELLO" may be used to indicate that the microcontroller has been reset
and has control of the display. The five required ASCII characters are stored in the five most
significant character positions in RAM.
hello moviw ‘Ht
movw£ 0x20
moviw 'Et
movw£ 0x21
movlw 'L"
movwf 0x22
movwf 0x23
movlw "0!
movwf 0x24
return
LCD Initialization
‘The initialization subroutine sets up the display for use followed by a long time delay. No cursor
is used.
initled bef porta, 1 1B line low
bef porta, 2 7RS line low, set up for control
call del_125 idelay 125 microseconds
movlw 0x38 p8-bit, 5x7
movw£ — portb 70011 1000
call pulse ypulse and delay
moviw 0x06 pdisplay on, cursor off
movwf — portb 70000 1100
call pulse
moviw 0x06 sincrement mode, no display shift
movwE port 70000 0110
call pulse
eall del_S idelay § milliseconds - required
i before sending data
return
65Character Addresses
Each of the 16 display characters has an address. This tells the display controller where to put
the next character data byte.
OOOO0goo00000000
0x80 0x87 oxco oxc7
‘The display controller thinks of these addresses more as instruction words. Sending 0x80 tells
the controller that display data is about to be sent which is to be placed starting at the most
significant display location (extreme left). Following digits will be placed in sequence moving
to the right.
Note that the 16 display characters are grouped in two blocks of 8 addresses which are not
adjacent in memory (0x80 to 87 and 0xCO to C7). To send all sixteen characters, 0x80 is sent as,
a control word or address prior to sending the first eight characters. OxCO is sent prior to
sending the second group of eight characters.
66Display 16 Characters
For displaying addresses
and data, we will store the
information in display RAM
and then send all 16
characters to the display.
‘Sot Up For Control
¥
Delay Via Subroutine
¥
‘Sond Address Of MS
‘Character 0x80
¥
Pulse And Delay Via
‘Subroutine
¥
‘Sot Up For Data
¥
Delay Via Subroutine
¥
Initialize FSR = 0x20
oven fe 2hat
a ¢
RAM Location Pointed | || ‘Set Up For Control
ToByFSR | | v
v | Delay Via Subroutine
‘Send Data To Display ¥
¥ Sond Addroes Of th
‘Character 0xCO
Pulse & Delay Via
Subroutine =e
Pulse & Delay Viz
Yes Subroutine
8 Digits Sort I
bad ‘Set Up For Data
ira Digs Son? ¥
Increment FSA
es ¥
Increment FSA Delay Via Subroutine
= ,
Return To Main Program
|
67Notice that the first character address must be sent for each block of 8 characters. Moving the
next character address in sequence is automatic except for the jump between the two blocks of 8
characters.
‘The subroutine uses 0x20 to Ox2F as display RAM.
dispi6 bet
bef
call
movlw
mowwE
call,
bst
call,
moviw
novwt
getchar movf
movwt
call,
movlw
subwe
befse
goto
moviw
subwe
btfsc
return
inet
goto
half bef.
call,
movlw
movwE
call
bst.
inct
call
goto
porta,1
porta,2
de1_125
0x80
portb
pulse
porta, 2
del_125
0x20
far
0x00,
portb
pulse
0x27
fsriw
status, z
half
oxze
for,w
status, z
fsr,f
getchar
porta,2
dei_125
0x0
portb
pulse
porta,2
fsr,£
de1_125
getchar
3B line low
7RS line low, set up for control
idelay 125 microseconds
ontrol word = address first half
;pulse and delay
S=1, set up for data
idelay 125 microseconds
pinitialize file select register
get character from display RAM
location pointed to by file select
register
isend data to display
8th character sent?
isubtract w from fer
stest 2 flag
pset up for last 8 characters
;test number
itest z flag
;16 characters sent to led
imove to next character location
;RS=0, set up for control
idelay 125 microseconds
peontrol word = address second half
ipulse and delay
;RS=1, set up for data
sincrement file select register to
select next character
idelay 125 microseconds
Finally, the del_S, del_125 and pulse subroutines as used in the LCD test program are needed.
‘The complete program listing follows
68-LCDB . ASM==
List
radix
pa16fa4
hex
indé
status
fer
porta
portb
count?
count2
triea
trisb
cpu equates (memory map)
equ
equ
equ
equ
equ
equ
equ
equ
equ
0x00
0x03
0x04
0x05
0x06
Ox0c
oxoa
oxes
0x86
bit equates
equ
equ
2
5
circle
org
bef
moviw
movwt
movwt
bet
movlw
movwt
movwé
call,
call
call,
call
call
goto
0x00
status, rp0 ;switch to bank 1
00000000" outputs
trisa
trisb
status, rp0 ;switch back to bank 0
"00000000" ;a11 outputs low
porta
porth
blanks ;£i11 display RAM with blanks
hello iereate message in display RAM
del_s sallow led time to initialize itself
initicd initialize display
dispié send 16 characters to display
circle done
blanks
store
inefer
movlw
movw£
movlw
mowwt
movlw
movwwE
dectsz
goto
return
inet
goto
hello
movlw
movwt
movlw
movwt
movlw
Ox10 jeount=16
count
0x20 ;first display RAM address
fsr jindirect addressing
0x20 jascii blank
indf istore in display RAM location
pointed to by file select register
counti,£ 162
incfsr ino
yes, done
for, f increment file select register
store
a
0x20
ni
0x21
a
69movwe
movwt
movlw
movwE
return
0x22
0x23
10"
oxza
initled
bet
bet
call,
movlw
novwt
call
novlw
movwt
call
movlw
movwe
call
call
return
porta,1
porta,2
del_125
0x38
portb
pulse
Ox0e
portb
pulse
0x06
portb
pulse
del_s
FE line low
RS line low, set up for control
delay 125 microseconds
pB-bit, 5x7
70011 1000
pulse and delay
idisplay on, cursor off
0000 1100
increment mode, no display shift
70000 0110
idelay 5 milliseconds - required
before sending data
disp16
getchar
halg.
70
bef
bet
call,
movlw
move
call
bst
call
moviw
movwt
movt
movwe
call
movlw
subw
btfse
goto
moviw
subwe
befac
return
inet
goto
bef.
call
movlw
movwE
call
bat
inet
porta,1
porta,2
del_125
0x80
portb
pulse
porta,2
del_125
0x20
for
0x00,
portb
pulse
0x27
fsr,w
status, z
half
oxze
for,w
status, z
for, f
getchar
porta,2
de1_125
Oxcd
portb
pulse
porta,2
for, £
7 line low
5RS line low, set up for control
delay 125 microseconds
reontrol word = address first half
rpulse and delay
;RS=1, set up for data
idelay 125 microseconds
sinitialize file select register
iget character from display RAM
location pointed to by file select
register
isend data to display
78th character sent?
psubtract w from fsr
itest z flag
iset up for last 8 characters
itest number
itest 2 flag
716 characters sent to lcd
imove to next character location
;RS=0, set up for control
idelay 125 microseconds
control word = address second half
;pulse and delay
iRS#1, set up for data
sincrement file select register toselect next character
call del_i25 idelay 125 microseconds
goto getchar
del_125 moviw Ox2a papprox 42x3 cycles (decimal)
movwf count pload counter
repeat decfsz countl,f | decrement counter
goto repeat snot 0
return icounter 0, ends delay
del_5 moviw 0x29 pdecimal 40
movwf — count2 ito counter
delay call del_125 idelay 125 microseconds
decfsz count2,£ do it 40 times = 5 milliseconds
goto delay
return poounter 0, ends delay
bsf porta,
nop
bef porta, 1
call del_125 idelay 125 microseconds
return
end
at blast time, select
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal (using 4 MHz osc for test) xT
power-up timer on
DISPLAY HEX BYTE SUBROUTINE
‘The display hex byte subroutine takes the byte passed to it via the W register and prepares it for
display by the LCD along with the corresponding bit pattern. Some blank locations remain at
the right end of the LCD for a future application. ‘The subroutine ends with the display RAM
loaded and ready for the contents to be sent to the LCD.
Main
‘The main program defines the hex byte to be converted for display and calls the display hex byte
subroutine which does the real work.
yweeeem=DISPLHEX .ASM==
list — p=16£84
radix hex
cpu equates (memory map)
indf equ 0x00
pe equ 0x02
nstatus equ 0x03
fer equ (O04
hexbyte equ 0x0c
ms_dig equ 0x0d
sig equ Ox0e
hold equ Ox0f
sa equ 0x10
sb equ = Oxll
sc equ 0x12
aa equ 0x13
counti equ Oxia
bit equates
ce eo 0
note: this works in MPSIM, not in chip
org 0x00
start moviw 0x01 oad w with 0x_, test byte
call disphex call display hex byte sub
3 returns with display RAM filled
circle goto circle ne
aDisplay Hex Byte
‘The user's program ends by loading the W register with the byte to be displayed and calling the
subroutine described below.
rel CI
0x20 (23 26 Ea
Cy Ud
Hox Byte High Nibble Bits
‘Save Copy Hex Byte “Bits To Display RAM
t Ms
Blank Display RAM ¥
z ‘Get Copy Hex Byte
Call Sop Hox Byto t
2 ASCII Digits Mask High Nibble | And With 00001111
4 t isa
MS Digi To Display RAM | 0x20 Result In W eee
LS Digi To Display RAM | 0x21 Call Hex To Bits Sub
‘Got Copy Hox Byte “Bits To Display RAM
t Ls
WSNbbeTOLs | swaoe ¥
Position And Mask | And With 00001111 Return
eS
= = Jump Table
GallHex To Bits Sub
73disphex movwf —hexbyte istore copy of hex byte
call blanks 7111 display RAM with blanks
call —_sephex iseparate hex byte into 2 ASCII digits
movf ms_digw get MS digit
movw£ 0x20 ito display RAM
movf Is_digyw —;get LS digit
movwf 0x21 ito display RAM
swapf hexbyte,w iget copy of hex byte, swap MS/LS
andlw Ox0f ymask AI nibble
call hexbits —call_hex to bits
movf saw iget first bit
movwf 0x23 ito display RAM
movE sbyw jet_ second bit
movwf 0x24 ito display RAM
movf sc,w te.
mow 0x25
movf sdw
movw£ 0x26
movf -hexbyte,w —;get_copy of hex byte
andlw 0x0f pmask HI nibble
call hexbits peall hex to bits
mové sa,w iget first bit
movw£ 0x28 ito display RAM
movf —sb,w iget second bit
movw£ 0x29 ito display RAM
movf sc, rete.
mow 0x2a,
movf sdvw
movw — 0x2b
return
Blanks
‘The blanks subroutine fills the 16 display RAM locations with ASCII blanks (0x20) using
indirect addressing.
blanks movlw 0x10 scount=16
movwf count]
moviw 0x20
movwE far
moviw 0x20
irst display RAM address
sindexed addressing
acid blank
store movef indf ystore in display RAM location
3 pointed to by file select register
decfsz counti,f£ 162
goto incfsr #no
return yes, done
incfsr incf fsr,f pincrement file select register
goto store
74Separate A Hex Byte Into Two ASCII Digits
In programs involving displaying hexadecimal data it will be necessary to separate a hex byte (2
hex digits) into two ASCII digits.
Got Hex Byto
¥
‘Mask High Nibble
Ls Digt
t
(Convert LS Hex Digit To
‘ASCII Via Subroutine
¥
‘Store LS Digit
¥
Got Hex Byte
¥
‘SWAPF And Mask To
‘Obtain MS Hox Digit
¥
‘Convert MS Hex Digit To
‘ASCII Via Subroutine
¥
Store MS Digit
4
Return
sephex movf hexbyte,w get. copy of hex byte
andiw 0x0£ imask hi nibble
call hex2asc = ;hex to ASCII conversion
mowwé 1s dig store
swapf hexbyte,w :get copy of hex byte, swap MS/LS
andiw 0x0f pmask hi nibble
call hex2asc_ = ;hex to ASCII conversion
mowwt ms_dig pstore
return
The routine expects to find the byte to be separated in location hexbyte and stores the
most significant digit at ms_dig and the least significant digit at Is_dig.
75Hex Digit To ASCII Digit Conversion
Notice that hex characters are represented by four bits (nibble) and ASCII characters require
eight bits (byte). To display a hex character, it must first be converted to ASCII using a
conversion routine. The conversion process involves determining whether the hex digit is in the
range 0x0 to 0x9 or OxA to OxF. Conversion is simply a matter of adding 0x30 to the digit if it
falls in the lower range or adding 0x37 if it falls in the upper range.
0x0 - 0x9 Add 0x30
OxA - OxF Add 0x37
hex2ase [Got Hex Digt In W
t
Store Copy In hold
No ‘Add 0x30 To Hex Digt
‘Add 0x37 To Hox Digit
The routine tests for the contents of W 2 Ox0A by subtracting the hex digit to be tested from
one less than OxOA (0x08) followed by testing the carry flag. ‘The details of how comparisons
are done are described in Bagy PIC'n
hex2asc movwf hold istore copy of hex digit
sublw 0x09 peubtract w from 1 less than Ox0a
btfss status,c scarry flag set if w < 0x0a
goto add37
goto add30
add37 movf—hold,w iget hex digit
addlw 0x37
return preturn with ascii in w
add30. movfé hold, iget hex digit
addlw 0x30
return preturn with ascii in w
76Hex To Bits Subroutine
Displaying the bit pattern corresponding to the hex byte is tricky. The work is done one nibble
atthe time, Four RAM locations are used as a scratch pad,
Ueticeed ‘Save W In hold
¥
Fill 4 Locations SA, SB,
SC, SD With ASCII O's
¥
Get hold Contents In W
[sores crerner
Call table Subroutine
(ome J
Call makbits Subroutine | Create Bits
¥
Return
Look Up Create Bits Subroutine
Starting Address.
First, the scratch pad is filled with 0's. Then a jump table is used to direct activity to one-of-
sixteen subroutines, one for each possible hex digit. The hex digit itself is used as the index for
the jump table. If the hex digit is 0x0, the contents of the four scratch pad locations (0000) are
then sent directly to display RAM. If two or three 0's are required, one or two O's are changed to
1's, If the digit is OxF, the scratch pad is filled with I's. If three 1's are required, the scratch pad
is changed to all 1's followed by changing one 1 to a0. Then the contents of the scratch pad is
sent to display RAM.
‘The short subroutines for filling the RAM scratch pad with 1's and O's vary in length. Relative
addressing works only in consecutive one address increments. The easiest method for getting
around this is to:
+ Store the subroutines (variable length) one after the other in the same 256 address segment
‘of memory.
+ Use a jump table to access the routines.
First, all the subroutines are written and laid out in hex digit order in sequential memory
locations. Second, the distance of each subroutine from the beginning of the group of
subroutines (offset) is then put in a table one address apart.table addwe
retlw
retlw
retlw
retlw
retlw
retlw
retlw
retlw
retlw
retlw
retlw
retlw
retlw
retlw
retlw
retlw
port
0x00
ox01
0x04
0x07
0x0b
ox0e
ox12
ox16
oxla
oxid
0x21
0x25
0x29
ox2a
0x32
0x35
tadd offset to program counter
70
2
32
3
74
#5
76
37
‘The subroutine starting offsets are now in a table which may be accessed by adding the value of
the hex digit to be converted to the program counter to go to the proper location in the table.
The return from subroutine takes place with the starting address of the bits routine in the W
register.
hexbits movwe
moviw
movwt
novwt
nowt
movwwt
movt
call
call
return
hold
0x30
sb
sc
sd
hold,w
table
makbits
Create Bits Subroutines:
makbits addwé
return
movlw
movwt
return
moviw
movwé
return
movlw
movwe
movwE
return
novlw
nowwt
return
novlw
78
perf.
0x31
sd
0x31
0x31
sc
ad
0x31
sb
0x31
ysave copy of hex digit
F411 with ascii O's
jet hex digit, use as offset
iget 2nd offset for subroutine table
ito appropriate create bits sub
70x0
70x1.
10x2
1 0%3
0x4
0x5
0000
0001
0010
oor
0100
0102
dd offset to program counter
leave as ismovwt
movwt
return
movlw
movwt
movwt
return
call,
movlw
movwt
return
movlw
novwt
return
moviw
movw£
movwt
return
ovlw
movwt
movwt
return
call
movlw
movw£
return
movlw
movwt
movwt
return
call
movlw
movwt
return
call
movlw
movw£
return
goto
return
sb
od
0x32
sb
fills
0x30
0x32
0x31
ad
0x31
se
fills
0x30
ab
0x31
sa
sb
fillis
0x30
fillis
0x30
sd
fills
Fill With 1's Subroutine
fills
moviw
movwt
movwt
movwt
movwt
return
0x31
sb
se
sd
70x6
20%7
20%8
+09
70x
+ 0xb
0x0
40xa
70xe
5 0xf
o1190
om
1000
1002
1020
101
1100
a101
a110
qua
£411
£411
#511
fill
£41
with 1,2
with 1,8
with 1,8
with Ls
with 1,8
79Program Listing
‘The complete program listing follows. Notice that “table” and “makbits" (also a table) are at the
beginning of the listing so that the assembler will put them in the first 256 locations of program
memory. This can be verified by looking at the file DISPLHEX.LST after the assembler does
it’s thing.
janse===DISPLHEX. ASM==="
list — pwl6£84
radix hex
manne /9/ 97
; cpu equates (memory map)
indf equ 0x00
Pe equ 0x02
status equ 0x03
fsx equ —Ox0d
hexbyte equ 0x0c
msdig equ 0x0d
ls dig equ 0x0e
hold equ Ox0f
sa equ 0x10
sb equ Oxil
sc equ 0x12
sd equ 0x13
counti equ 0x14
: bit equates
°
not in chip
org 0x00
start movlw 0x01 Hload w with Ox_, test byte
call disphex — call display hex byte sub
; returns with display RAM filled
table addwf pe, f jadd offset to program counter
retlw 0x00 70
retlw 0x01 :
retlw 0x04
retlw 0x07
retlw 0x0b
retlw 0x0e
retlw 0x12
retlw 0x16
retlw Oxla
retlw Oxid
retlw 0x21
retlw 0x25
retlw 0x29
retlw 0x2
80makbits
retlw
retlw
addwt
return
movlw
movwE
return
movlw
move
return
movlw
movwt
movwt
return
movlw
movwt
return
movlw
movwé
movwE
return
movlw
owt
movwi
return
call
movlw
movwt
return
movlw
novef
return
moviw
movwt
movwt
return
moviw
movwt
movw£
return
call
movlw
movwé
return
movlw
movw£
movwt
return
call
moviw
movwt
return
call
0x31
0335
perf
0x31
od
0x31
sc
0x32
sd
0x31
sb
x32
sb
od
0x31
sb
fillies
0x30
sa
0x31
0x31
sa
ad
0x31
fills
0x30
sb
0x31
sb
fille
0x30
fills
af
jadd offset to program counter
0x0
70x2
7 0x2
70%3
0x4
70x5
10%6
20%7
20%
0x9
70xa
30x
70xe
70x
70xe
0000
0002
0020
oot
0100
oor
0110
ou
1000
1001
1010
1012
1100
1101
qi10
leave as is
£421 with 1,3
fill with 1,5
£411 with 1,5
£411 with 1,8
81fills
movlw
movwE
return
goto
return
moviw
movwt
movwt
movwt
movwt
return
0x30
od
ills
0x31
sa
sb
sd
Oxf 1111“ f421 with 1,8
disphex
sephex
mowwe
call
call,
move
nowt
movE
movwt
swapt
andilw
call
move
movwe
mové
movw£
move
movwt
movt
novwt
movt
andlw
call,
move
novwt
nov
movwe
move,
movwe
novE
move
return
mové
andlw
call
movwé
swapt
andiw
call
nowt
return
hexbyte
blanks
sephex
ms_dig,w
0x20
1s_digyw
0x21
hexbyte,w
oxof
hexbite
0x23
sb,¥
x24
0x25
sd,w
0x26
hexbyte, w
oxot
nexbits
0x28
sbyw
0x29
Oxza
sd,
0x2
hexbyte,w
ox0f
hex2ase
ls_dig
hexbyte, w
Ox0f,
hex2ase
ms_dig
pstore copy of hex byte
;£111 display RAM with blanks
peeparate hex byte into 2 ASCIT digits
rget MS digit
sto display RAM
iget Ls digit
ito display RAM
iget copy of hex byte, swap MS/LS
ymask HI nibble
all hex to bits
iget first bit
ito display RAM
iget second bit
pete.
get copy of hex byte
ymask HI nibble
peal hex to bits
iget first bit
sto display RAM
iget second bit
ito display RAM
pete.
get copy of hex byte
jmask hi nibble
shex to ASCII conversion
store
iget copy of hex byte, swap MS/LS
ymask hi nibble
hex to ASCII conversion
tore
82hex2asc movwf hold istore copy of hex digit
sublw 0x09 jsubtract w from 1 less than 0x0a
btfss status,c carry flag set if w < Ox0a
goto ada37
goto add30
ada37 movf hold, w iget hex digit
addlw 0x37
return preturn with ascii in w
add30 movf —hold,w iget hex digit
addlw 0x30
return eturn with ascii in w
hexbits movw£ hold isave copy of hex digit
movlw 0x30 P£411 with ascii O's.
movwE sa
movw£ sb
mow sc
mow sd
movf hold, iget hex digit, use as offset
call table jet 2nd offset for subroutine table
call makbits to appropriate create bits sub
return
blanks movlw 0x10 seount=16
movwf count
moviw 0x20 ;first display RAM address
mowwf fsr pindexed addressing
movlw 0x20 pascii blank
store movwf indf istore in display RAM location
: pointed to by file select register
decfsz counti,f 16?
goto incfsr ino
return tyes, done
incfer incf far,f sincrement file select register
goto store
end
at blast time, select:
memory unprotected
standard crystal (using 4 Miz osc for test)
fl watchdog timer disabled (default is enabled)
; power-up timer on
To Use/Test Display Hex Byte:
To put the display hex byte subroutine to work, we need the program which follows. It
(TESTHEX.ASM) includes a new short main program (similar to LCD8.ASM) and
DISPLHEX.ASM. The subroutines "table" and "makbits” are located at the beginning of the
rogram so as to be in the first 256 bytes of program memory.: cpu equates (memory map)
indf equ 0x00
pe equ 0x02
status equ 0x03
fsr equ x04
porta equ 0x05
portb equ 0x06
hexbyte equ Ox0e
ms_dig equ 0x0d
lsdig equ Ox0e
hold equ ——(Ox0f
sa equ 0x10
sb equ Oxil
sc equ 0x12
sd equ 0x13
countl equ Ox14
count2 equ Ox1S
trisa equ 0x85
trisb equ 0x86
bit equates
org 0x00
start goto main sleap over tables
table addwf po, f
retlw 0x00
retlw 0x01
retlw 0x04
retlw 0x07
retlw 0x0b
retlw 0x0e
retlw 0x12
retlw 0x16
retlw Oxia
retlw Oxld
retlw 0x21
retlw 0x25
retlw 0x29
retlw 0x2
retlw 0x31
retlw 0x35
dd offset to program counter
makbits addwf pe, f jadd offset to program counter
return 0x0 -0000-leave as is
84movlw
mowwe
return
movlw
nowt
return
moviw
movwe
movwt
return
movlw
ovat
return
movlw
movwt
movwt
return
moviw
movwé
movwe
return
call
movlw
moet
return
movlw
movw£
return
movlw
movwt
movwi
return
movlw
movwt
movut
return
call
movlw
movwt
return
novlw
movwt
movet
return
call
movlw
movwE
return
call
novlw
movwt
return
goto
return
0x32
sd
0x31
sc
0x31
sa
0x32
sb
0x31
ab
sd
0x32
sb
fillis
0x30
0x31
0x32
od
0x32
se
fillls
0x30
sb
0x31
sa
sb
fills
0x30
se
fillis
0x30
sd
fillis
0x1
70x2
20%3
20x6
20x7
70x8
0x9
70xa
10xe
50xd
70xe
20xE
0002
0010
012
0100
0101
0110
oun
1000
1001
1010
2012
1100
1101
1110
aun
£411,
fill
finn
fill
fi1l
with 1,3
with 1,3
with 1s
with 1,9
with 1,5circle
bet
movlw
movwe
movwE
bet.
movlw
movwt
movwt
call,
call,
movlw
call
call
goto
status, xpd
00000000"
trisa
trisb
status, rp0
b*00000000"
porta
portb
del_5
initled
0x01
disphex
dispié
circle
iswitch to bank 1
poutputs
rswitch back to bank 0
yall outputs low
pallow lcd time to initialize itself
pinitialize display
fload w with 0x_, test byte
jeall display hex byte sub
returns with display RAM filled
ssend 16 characters to display
:done
fillis
movlw
movwe
movwt
novwf
novwt
return
0x31
ab
sd
disphex
86
movwt
call,
call
move
movwt
movE
movwt
ewapt
andlw
call
movE
movwé
mové
nowt
move
movwt
movt
movwt
movt
andlw
call
move
move
mové
movwt
move
movwt
movt
movwé
return
hexbyte
blanks
sephex
ms_dig,w
0x20
1s_digyw
ox21
hexbyte,w
oxot
hexbits
sayw
0x23
sb,w
ox24
sc,
0x25
sd,w
0x26
hexbyte, w
oxoe
hexbits
0x28
sb,w
0x29
scew
Ox2a
sdyw
Ox2b
sstore copy of hex byte
7111 display RAM with blanks
separate hex byte into 2 ASCII digits
get MS digit
to display RAM
get 1S digit
ito display RAM
iget copy of hex byte, swap MS/LS
imask HI nibble
ieall hex to bits
iget first bit
sto display RAM
iget second bit
0 display RAM
tc.
jet copy of hex byte
pmask HI nibble
all hex to bits
iget first bit
sto display RAM
iget second bit
ito display RAM
rete.sephex
mové
andlw
call
movw£
ewapt
andlw
call
movwt
return
hex2ase
ada37
ada30
movwé
sublw
bttss
goto
goto
move
addlw
return
mové
addiw
return
hexbyte,w :get copy of hex byte
oxof mask hi nibble
hex2asc —;hex to ASCII conversion
1s_dig istore
hexbyte,w get copy of hex byte, swap MS/LS
oxor jmask hi nibble
hex2ase hex to ASCII conversion
ms_dig store
hold istore copy of hex digit
0x08 psubtract w from 1 less than Ox0a
status,c ;carry flag set if w < Oxda
ada37
ada30
hold, iget hex digit
0437
freturn with ascii in w
hold,w iget hex digit
0x30
preturn with ascii in w
hexbits
movw£
movlw
movwe
mowwé
movwt
movw£
mové
call
call
return
hold isave copy of hex digit
0x30 ;£i11 with ascii 0's
2b
sc
sd
hold, w sget hex digit, use as offset
table iget 2nd offset for subroutine table
makbite sto appropriate create bits sub
store
incfsr
movlw
movwe
movlw
movwé
novlw
mowwt
dectsz
goto
return
inet
goto
ox10 roount=16
count
0x20 ;first display RAM address
fer sindexed addressing
0x20 pascii blank
indt pstore in display RAM location
pointed to by file select register
counti,£ 162
initiea
bet
bet
call
movlw
novwf
call,
movlw
incfsr ino
tyes, done
for,f jincrement file select register
store
porta,1 line low
porta,2 RS line low, set up for control
del_125 © ;delay 125 microseconds
0x38 bit, 5x7
portb 0011 1000
pulse ppulse and delay
0x00 idisplay on, cursor off
87movw£ — portb #0000 1100
call pulse
movlw 0x06
nerement mode, no display shift
movwf — portb 70000 0110
call pulse
call del_5 idelay 5 milliseconds - required
: before sending data
return
displ6 bef porta, 1 :B line low
bef porta, 2 7RS line low, set up for control
call del_125 idelay 125 microseconds
moviw 0x80 jeontrol word = address first half
movwE — portb
call pulse
bsf porta, 2
call del_125
ielay 125 microseconds
movlw 0x20 sinitialize file select register
mowé fer
getchar movf 0x00, jet character from display RAM
location pointed to by file select
register
movwf port
call pulse end data to display
movlw 0x27 8th character sent?
subwé fsr,w psubtract w from fer
btfsc status,z ;test z flag
goto half ;set up for last 8 characters
movlw 0x2£ itest number
subwf fer,w
btfsc status,z —;test 2 flag
return 16 characters sent to lcd
inct far,f move to next character location
goto getchar
half bef —porta,2 / set up for control
call del_125—;delay 125 microseconds
movlw 0x0 ;eontrol word = address second half
mow porth
call pulse ppulse and delay
bsf —porta,2 ;RS=1, set up for data
inct fer, £ jincrement file select register to
3 select next character
call de1_125 idelay 125 microseconds
goto getchar
de1_125 moviw Ox2a fapprox 42x3 cycles (decimal)
movwf count1 pload counter
repeat decfsz countl,f decrement counter
goto repeat not 0
return icounter 0, ends delay
del_5 movlw 0x29 decimal 40
movwf — count2 ito counter
delay call del_125 delay 125 microseconds
88decfsz count2,£ do it 40 times = 5 milliseconds
goto delay
return yeounter 0, ends delay
pulse bsf —porta,1 rpulse E line
nop idelay
bef —porta,1
call del_125 —;delay 125 microseconds
return
end
fat blast time, select:
: ‘memory unprotected
3 watchdog timer disabled (default is enabled)
7 standard crystal (using 4 MHz osc for test)
7 power-up timer on
894-BIT MODE
‘We started out operating the LCD in the 8-bit mode, meaning instructions and data are
transmitted to the LCD over 8 wires. This is the simplest in terms of understanding their
operation and writing code. PIC16 devices don't have lots of pins, so minimizing the number
devoted to communicating with the LCD may be essential. These displays will also run in the 4-
bit mode using the higher order 4 data lines (D7, 6, 5.4).
Por B
Port A
Port A
aa
Rs
45v00
Kxxx
||! pore
oreassey
LCD
In the 8-bit mode, a byte is presented to the LCD followed by pulsing the E line and then a 125
microsecond delay. In the 4-bit mode, the byte must be cracked into two nibbles by a
subroutine. The MS nibble is presented to the LCD first followed by pulsing the E line. Then
the LS nibble is presented to the LCD followed by pulsing the E line. A 125 microsecond delay
follows pulsing the second nibble.
90MS Nibble To Por Lines
¥
Pulse
t
‘SWAPF
t
LS Nibble To Port Lines.
t
Pul
Ce
125 Microsecond Delay
‘The initialization process is a little confusing. The LCD is first told that the mode will be 8-bit.
‘Then it is told the mode will really be 4-bit. Then it is told to be in the 4-bit mode again followed
by the lower nibble of the function set instruction byte.
192
Bit Mode
|_sarese_]
125 Microsecond Delay
+
4-Bit Modo - MS Nibble
‘Only
¥
125 Microsecond Dolay
(seereee|
4-Bit Function Set -
‘Sond Both Nibbles.
ae ae
Pulse And Delay
¥
Display On, Cursor
Blinking
a
Pulse And Delay
¥
‘Clear Display
V
5 Milisocond Delay
¥
‘Set Up For Control
[score
Control Word
t
‘Set Up For Data
+
Define Character
¥
‘Sond Character
‘Sond 8 (4 Wires)
Sond 4
Sond 444
Sond 4+4
Sond 4+4‘The 4-bit demo
ASCitch
initializes the LCD with the cursor blinking at the MS bit position and
then sends one ASCII character ("A"). The display will show "A" followed by a blinking cursor.
status
porta
portb
count?
count2
bits
trisa
trisb
====LCDTST4 . ASH:
pa16£a4
hex
Jnmnmnnnnmenn5 /26/97==
cpu equates (memory map)
equ
equ
eq
equ
equ
equ
equ
equ
0x03
0x05
0x06
Ox0e
oxod
oxde
0x85
0x86
circle
bit equates
equ
org
bst
movlw
movwt
movwt
bof
movlw
move
movwt
call
call
call
goto
5
0x00
status, xp0
100000000"
trisa
trisb
status, xp0
00000000"
porta
portb
de1_5
initled
display
circle
sewitch to bank 1
youtputs
‘switch back to bank 0
fall outputs low
fallow led time to initialize itself
pinitialize display
isend 'A' character
idone
display
bet
bet
call,
movlw
call,
bst
call,
movlw
call,
return
porta,1
porta,2
del_125
0x80
send
porta,2
del_125
ra
send
iE line low
7RS line low, set up for control
delay 125 microseconds
peontrol word = address first half
;RS=1, set up for data
idelay 125 microseconds
pdefine character
initicd
bef
bef.
call,
moviw
movwe
call
porta?
porta,2
del_125
0x38
bits
flipbit
E line low
RS line low, set up for control
delay 125 microseconds
s8-bit, 5X7 mode
70021 1000
youtput 4 MS bits (LS not used)
93call
call
novlw
movi
call
call
call,
moviw
call
movlw
call
movlw
call,
call,
return
pulse isend bits
del125 © ;delay
0x28 ;4-bit, 5x7 mode
bits #0010 1000
flipbit foutput 4 MS bits (LS not used)
pulse iget into 4-bit mode
del_125
0x28 p4-bit, 5x7 mode
send :send both nibbles
ox0f idisplay on, cursor blinking
send
x01 iclear display
send
dei_s idelay 5 milliseconds
send movwe
call
call
swap
call
call
call
return
bits
f£lipbit
pulse
bits,£ iswap MS and LS nibbles
flipbit foutput what was L$ nibble
pulse
del_125
flipbit bet
btfse
bst.
bef
befse
bet
bef
btfse
bs
bet.
btfse
bsf
return
de1_125 moviw
movwe
repeat decfsz
goto
return
portb, 4 sdefault
bits, 4 stest bit in "bits"
porth,4 pbit in "bite" set
portb, 5
bits,5
port, §
portb, 6
bits, 6
portb, 6
portb,7
bits,7
portb,7
oxza fapprox 42x3 cycles (decimal)
count? pload counter
counti,f — ;decrement counter
repeat inot 0
icounter 0, ends delay
del_S moviw
movw£
delay call
dectsz
goto
return
0x29 idecimal 40
count2 ito counter
del_125 ;delay 125 microseconds
count2,f ;do it 40 times = 5 milliseconds
delay
counter 0, ends delay
pulse bef
94
porta,1 rpulse E linenop rdelay
bef —porta,1
return
end
jat blast time, select:
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal (using 4 MHz osc for test) XT
power-up timer on
LCD MODULE SERIAL INTERFACE
It would be very useful or convenient to use the LCD module as a piece of test equipment or as.
part of a more complex system if it could be connected to another PIC16 via a 1-wire serial
interface. We can do that! We can do it by combining techniques and boards we already have.
The '84 on a board will be the "master" and the LCD/PIC16 unit will be the slave.
1Wie
MASTER SLAVE
RAI RAO
D RD Picco.
+500
"4 ONABOARD ——-
10k ee)
Leb
Push To
Send
My list of functions the slave should perform under direction of the master is:
+ Display "HELLO" at power-on
Display "TEST" on command
Blank display
Place a single ASCII character in any one of 16 display RAM locations
Send the contents of display RAM to the display
Display a hex byte as 2 hex digits and as 8 bits
‘There are lots of ways to do this. My solution follows. You may want to modify mine for your
‘own use or to do it a different way altogether.
95Any time something is sent to the display, an instruction must be included to tell the slave what
todo. Sometimes there will be an ASCII character or hex byte to be sent. Sometimes an
address (RAM location) must be specified. I decided the easiest way to do this is always send 3
bytes at a time even if only 1 or 2 are needed. This makes the software simpler at the flow chart
level.
Packets - 3 bytes (2nd and 3rd may be garbage).
Instruction
‘0x00
0x01
‘oxo
0x03
0x04
0x00
0x01
0x02
0x04
96
‘ASCII Character Display RAM
Or ‘Address
Hox Byte
Blank display RAM
Sond 16 characters to display
Display "TEST:
‘ASCII character and display
RAM address follow - send
charactor to display RAM
Hex byte foliows - convert to
‘ASCII and display
Ox(char) ox(adde)
Ox(hex)Master
‘The main program depends on the task, but always sends the 3 bytes (instr, char, addr).
Initialize
Open Switch Prior |
ToPower-On Open ono
Closed
Define 3 Bytes - instr,
cchar, addr
a
Call Send Stutf
+
Continue
Slave
Initialize
Receive instr And Store
t
ceive char And Store
t
Receive addr And Store
y
Continue
Note: Must Wait For Slave
Program Activity Prior
‘To Sending Next Packet
97y
Initialize
enter
¥
Clear revieg
¥
Receive instr And Store
¥
Receive char And Store
+
98
Receive addr And Store
Get instr
binkram
Call Blank Display RAM
Tocnterm
‘Send 16 Characters
v
Yes Toenterm sndtst
Fill Display RAM With
“TEST”
¥
No Mldross In FSR ‘Sond 16 Characters
Data To RAM Address Ud)
Pointed To By FSR
v
Yos — convhex
Tocnterm
Ye FerbroW Soci Our
Toone 1 1
Call Display Hox Byte ‘Toenterm
|‘The slave program looks at the instruction byte by comparing it with legal instruction bytes until
amatch is found, If the comparison results in setting the Z flag, the bytes (instructions) are
equal (same) and program execution is directed to the appropriate code.
‘Sometimes a delay will be required in the master program to allow the slave time to execute the
instruction (fill display RAM with blanks or send 16 characters to the display for example).
“The program listing LCDMSTR.ASM has three blocks of main program code "hidden" from the
assembler at the end. The actual main code and three blocks should be examined. Each
jnstructs the slave to perform different functions. You can substitute them for the display "test"
portion of the main program if you wish.
‘You have seen much of the code in previous examples.
‘The master board has a "send" switch, This assures that the slave is running and the LCD has
been initialized prior to sending serial information to it.
==LCDMSTR. ASH====="
List pei6ee4
radix hex
anmennnn5 /19/97==
pu equates (memory map)
tmr0 equ (0x01
status equ 0x03
porta equ 0x05,
intcon equ Ox0b
sendreg equ 0x0e
count equ 0x0d
instr equ Ox0de
char equ —Ox0f
addr equ (x10
countl equ Oxi1
optreg equ 0x81
trisa equ 0x85
i bit equates
ce oqo 0)
mp0 equ 5
org 0x00
start bsf —status,rp0_;switch to bank 1
movlw "00000100" ;port A inputs/outputs
mowwf trisa
bef status, rp0 ;switch back to bank 0
bsf —porta,1 poutput mark, bit 1
switch btfsc porta,2 retart send?
goto switch inot yet
;display "TEST"
movlw 0x02 idisplay "test"
movwf instr
99call endstf reall send stuff
;long delay required here if other tasks follow
circle goto circle done
sndstf movf instr,w ;get_ instruction
movwf sendreg —;to be sent
call ser_out to serial out subroutine
mové —char,w iget character or hex byte
movwf sendreg —;to be sent
call ser_out to serial out subroutine
movf addr, w iget address
movwE sendreg —;to be sent
call ser_out. —to serial out subroutine
return
Ser_out bef -—intcon,5 disable tmr0 interrupts
bef intcon,7 -— ;disable global interrupts
clef — tmr0 clear timer/counter
clrwdt yelear wdt prep prescaler assign
bsf status, rp0_ ;to page 1
moviw b'11011000" ;set up timer/counter
movwf —optreg
bef — status, rp0_ ;back to page 0
moviw 0x08 sinit shift counter
movwf count
bef porta,1_— start bit
clef tmr0 start timer/counter
bef —intcon,2 —;clear tmr0 overflow flag
timel btfss intcon,2 —;timer overflow?
goto time ino
bef intcon,2_—;yes, clear overflow flag
nxtbit rlf sendreg,f rotate msb into carry flag
bef porta, ;clear port A, bit 1
btfsc status,c —;test_carry flag
bsf —porta,1 pbit is set
time2 btfss intcon,2 —;timer overflow?
goto time2 :no
bef intcon,2—;clear overflow flag
dectsz count, £ pshifted 8?
goto nxtbit ino
bst —porta,1 ryes, output mark
time3 btfss intcon,2 timer overflow?
goto timed ‘no
return done
de1_125 moviw Ox2a fapprox 42x3 cycles (decimal)
movw£ count load counter
repeat decfsz counti,f£ — ;decrement counter
goto repeat pnot 0
return jcounter 0, ends delay
end
fat blast time, select:
100; memory unprotected
: watchdog timer disabled (default is enabled)
standard crystal (using 4 MHz osc for test) xT
a power-up timer on
isend blanks to display RAM, then to LCD
moviw 0x00 ;blanks to display RAM
movwf instr
call sndsté peall send stuff
call del_125 twait for slave to fill w/blanks
movlw 0x01 isend 16 characters to display
movw£ instr
call sndstf peall send stuff
;display "A" followed by blanks
moviw 0x00 ;blanks to display RAM
movwE instr
call sndsté peall send stuff
call del_125 wait for slave to do it's thing
movlw 0x03, pascii character follows
movwf instr
moviw "A" lefine ascii "AY
movw£ char
movlw 0x20 ;first display RAM address
movwf addr
call sndsté peall send stuff
moviw 0x01 psend 16 characters to display
movw£ instr
call sndsté peall send stuff
idisplay hex byte
moviw 0x04 rhex byte follows
movwf instr
moviw 0x01
movw£ char
call sndsté peall send stuff
jefine hex byte Ox_
101indt
temrd
pe
status
fer
porta
portb
intcon
hexbyte
ms_dig
is_aig
hold
sb
ad
count
count2,
revreg
count
temp
instr
char
addr
optreg
trisa
trisb
102
LCDSLV.AS
List p=16£84
radix hex
cpu equates (memory map)
equ
equ
eq
equ
equ
equ
equ
equ
equ
equ
equ
equ
equ
equ
equ
equ
equ
equ
equ
equ
equ
equ
equ
equ
equ
equ
0x00
0x01
0x02
0x03
0x04
0x08
0x06
0x0b
ox0e
Ox0d
Oxde
Oxof,
x10
Oxil
x12
x13
ould
ox1s
x16
0x17
oxi8
os
Oxia
Ox1b
ox
0x85
0x86
bit equates
equ
equ
equ
org
goto
addwe
retlw
retlw
retlw
retiw
retlw
retiw
retlw
retlw
retlw
retlw
retlw
0x000
pert
0x00
x02
oxo4
0x07
ox0b
Oxde
ox12
Oxi6
Oxla
oxid
ox21
;leap over tables
fadd offset to program counter
5/19/97==makbits
retlw
retlw
retlw
retlw
retlw
addwe
return
novlw
novw£
return
movlw
movwé
return
movlw
movwt
movwt
return
movlw
mowwl
return
movlw
movwE
movwe
return
movlw
movwt
move
return
call
movlw
movwwt
return
movlw
novwf
return
movlw
movwé
movw£
return
movlw
movwt
moet
return
call
movlw
movwt
return
movlw
movwt
movwi
return
call
movlw
0x25
0x29
ox2a
0x32
0x35
port
0x31
sa
0x31
se
0x31
sd
0x31
ab
0x31
sb
od
x31
sb
fills
0x30
0x32
0x31
sd
0x31
fills
030
sb
0x31
eb
fills
0x30
jadd offset to program counter
70x0
20x
2 0x2
30x3
70x
3 0x5
70x6
10x7
10%8
70x
+0xa
30x
30x
10xd
‘9000
0002
0010
oot
0100
0101
0120
oun
1000
1001
1010
1011
1100
aor
leave as is
£411 with 1,8
£411 with 1s
£411 with 1,8
103movet
return
call
movlw
movwt
return
goto
return
fillis Ome 1210 £121 with
030
ed
fills Oxf 1121 £411 with
Ls
Ls
main
enterm
104
bsf
movlw
move
moviw
movwt
bef.
movlw
movwe
bef.
bet.
bet
bet
call
call
call
call
call
elrt
call.
move
movwt
clré
call
move
movwt
clré
call
movE
movi
movt
sublw
btfse
goto
move
sublw
btfsc
goto
move
sublw
btfse
goto
move
sublw
btfsc
goto
status, rp0 ;switch to bank 1
b'00000001' ;port A inputs/outputs
trisa
00000000" sport B outputs
trisb
status, rp0 ;back to bank 0
b*00000000" a1] outputs low
portb
porta,1 fall outputs low
porta,2
porta, 3
porta, 4
blanks ;£i11 display RAM with blanks
hello rereate message in display RAM
del_s fallow led time to initialize itself
initled ;initialize display
dispi6 isend 16 characters to display
revreg ayes
ser_in sto serial in subroutine
rovieg,w get byte received
instr istore instruction
revreg
ser_in ito serial in subroutine
revreg,w get byte received
char tore character or byte
revreg
ser_in 0 serial in subroutine
revreg,w jet byte received
add: tore address
instr,w get copy of instruction
0x00 reompare with 0x00
status,z ;2 flag set if bytes are equal
binkram —;bytes equal
instr, get copy of instruction
0x02 ieompare with 0x01
status,z 7 flag set if bytes are equal
sendi6 rbytes equal
instr,w get. copy of instruction
oxo2 peompare with 0x02
status,z 72 flag set if bytes are equal
sndtst rbytes equal
instr,w get copy of instruction
0x03 seompare with 0x03
status,z ;z flag set if bytes are equal
chr_ram bytes equalmovf instr,w get copy of instruction
gublw 0x04 yeompare with 0x04
btfse status,z 72 flag set if bytes are equal
goto convhex —;bytes equal
goto enterm iwait for next transmission
binkram call blanks ;£411 display ram with blanks
goto enterm back to main
sendl6 call disp1é ysend display RAM contents to CD
goto enterm yback to main
gndtet call test jload display RAM with msg "TEST"
call di sp16 isend display RAM contents to LCD
goto enterm rback to main
chr_ram movf — addr,w iget copy of display RAM address
movwe fs. pstore in file select register
movf char, get copy of character to be display
movwf ind ;to RAM address pointed to by FSR
goto enterm rback to main
convhex movf char, yet. copy of hex byte to be converted
call disphex convert. hex byte for display
call dispi6. pend display RAM contents to LCD
goto enterm yack to main
£illls moviw 0x31
movwf sa
movwf sb
movwf sc
movwf sd.
return
Gisphex movw£ hexbyte — store copy of hex byte
call blanks ;£411 display RAM with blanks
call sephex yseparate hex byte into 2 ASCII digits
movf ms_digw get MS digit
movwf 0x20 ito display RAM
movf 1s_dig,w get 18 digit
movw£ 0x21 ito display RAM
swapf hexbyte,w get copy of hex byte, swap MS/LS
andlw Ox0f pmask HI nibble
call hexbits peall hex to bits
movf 8a, jet first bit
movwf 0x23 ito display RAM
movE sbyw iget second bit
movwf 0x24 pto display RAM
movf sc,w rete.
movwf 0x25
movf — sd,w
movw£ 0x26
movf hexbyte,w get copy of hex byte
andlw 0x0f, pmask HI nibble
105call
move
nowt
move
move
movi
movwe
move,
movwt
return
hexbits call hex to bits
sayw iget first bit
ox28 sto display RAM
sb,w jet second bit
0x29 0 display RAM
sc,w jete.
Oxda
sd,w
0x25
move
andlw
call
movwe
sowapt
andlw
call
move
return
hexbyte,w ;get copy of hex byte
oxo# ask hi nibble
hex2asc — ;hex to ASCII conversion
is_dig istore
hexbyte,w get copy of hex byte, swap MS/LS
oxof smack hi nibble
hex2asc —;hex to ASCII conversion
ms_dig istore
hex2ase
ada37
ada30
movw£
sublw
btfss
goto.
goto.
move
addiw
return
move
addlw
return
hold istore copy of hex digit
0x09 subtract w from 1 less than Ox0a
status,c jcarry flag set if w < 0x0a
ada37
ada30
hold, w sget hex digit
0x37
freturn with ascii in w
hold,w iget hex digit
0x30
freturn with ascii in w
hexbits
movwe
movlw
movwE
movwe
movwt
nowt
move
call
call
return
hold isave copy of hex digit
0x30 ;£i11 with ascii O's.
ab
ed
hold, w get hex digit, use as offset
table get 2nd offset for subroutine table
makbits ito appropriate create bits sub
blanks
store
106
movlw
novwt
movlw
movwt
movlw
movw£
dectsz
goto
return
Oxt0 scount=16
count
ox20 first display RAM address
fsr indexed addressing
0x20 jascii blank
indé ;store in display RAM location
pointed to by file select register
countl,£ 162
incfsr ino
tyes, doneincfsr
inct fsx,f jincrement file select register
hello
goto store
movlw ‘Ht
movwf 0x20
movlw ‘Et
movwf 0x22
moviw ‘Lt
movwf 0x22
movwf 0x23
movlw '0"
movwf 0x24
return
test,
movlw ‘Tt
movwf 0x20
movwf 0x23
moviw "Et
movw£ 0x21
initied
disp1é
getchar
moviw 'S!
movwf 0x22
movlw '!
movwf 0x24
return
bef —sporta,1._-— EB line low
bef porta, 2 #RS line low, set up for control
call del_125 delay 125 microseconds
movlw 0x38 p8-bit, 5x7
movwf — portb 70011 1000
call pulse ppulse and delay
moviw 0x00 display on, cursor off
movwf — portb 70000 1100
call pulse
moviw 0x06 sincrement mode, no display shift
movw£ portb 70000 0110
call pulse
call del_5 idelay § milliseconds - required
before sending data
return
bef —porta,1_—E line low
bef porta, 2 RS line low, set up for control
call del_125—;delay 125 microseconds
moviw 0x80 ieontrol word = address first half
movw£ — portb
call pulse
pulse and delay
bsf —porta,2_-—sRS=1, set up for data
call del_125. ;delay 125 microseconds
movlw 0x20 pinitialize file select register
movwE fsx
mové —0x00,w iget character from display RAM
location pointed to by file select
register
107half
movwf — portb
call pulse ;send data to display
movlw 0x27 #8th character sent?
subw£ fer,w subtract w from fsx
btfsc status, z est z flag
goto half. set up for last 8 characters
movlw 0x2 test number
subwf fer,w
btfsc status,z test z flag
return 16 characters sent to led
inct far, £ move to next character location
goto getchar
bef porta,2 #RS=0, set up for control
call del_125 idelay 125 microseconds
movlw 0xc0 ieontrol word = address second half
movw£ — portb
call pulse
pulse and delay
de1_125
repeat
del_s
delay
bst porta, 2 ;RS*1, set up for data
inct fsr,t sincrement file select register to
select next character
call del_125 idelay 125 microseconds
goto getchar
movlw 0x2a Pprox 42x3 cycles (decimal)
movwf count Pload counter
decfsz counti,f — ;decrement counter
goto repeat pnot 0
return icounter 0, ends delay
movlw 0x29
decimal 40
pulse
sbit
108,
movwf — count2 ;to counter
call del_125 idelay 125 microseconds
decfsz count2,f ;do it 40 times = 5 milliseconds
goto delay
return seounter 0, ends delay
bsf —porta,1 ppulse E line
nop idelay
bef —portay1
call del_125 idelay 125 microseconds
return
bef —intcon,5 —;disable tmr0 interrupts
bef intcon,7?_—;disable global interrupts
clrf — tmr0 pelear timer/counter
clewdt selear wdt prep prescaler assign
bsf status, rp0_ ;to page 1
movlw '11011000' ;set up timer/counter
mowwf optreg
bef status, rp0 ;back to page 0
movlw 0x08 pinit shift counter
movwf count
btfsc porta, 0 look for start bit
goto sbit pmarkmoviw 0x80 sstart bit received, half bit time
movwf tmx jload and start timer/counter
bef —intcon,2-—;clear tmr0 overflow flag
timel btfss intcon,2 —;timer overflow?
goto time ino
btfsc porta,0 petart bit still low?
goto abit ifalse start, go back
clrf — tmr0 ryes, half bit time - start timer/ctr
bef intcon,2 ;elear tmr0 overflow flag
time2 btfss intcon,2 timer overflow?
goto time2 ino
bef intcon,2 yes, clear tmr0 overflow flag
movf porta,w —;read port A
movwf temp restore
xref temp, £ protate bit 0 into carry flag
rlf revreg,f rotate carry into revreg bit 0
decfsz count,f shifted 8?
goto time ino
time3 btfss intcon,2 timer overflow?
goto timed ino
return iyes, byte received
end
at blast time, selec
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal (using 4 Miz osc for test)
power-up timer on
109LCD EXPERIMENTS
‘You may want to experiment with the operation of the display module.
‘Try Your Own Variations:
Function Set
Sit data — 116 duy
(don't worry about
What it means)
0011 1_00
[ O=5e7
=5x10
Display on/off
0» depiay ff
Ve 4 = dlsplay on
(0000) ieee
0 = cursor off, SL O=no blink
1 ecursor on 1 = blink cursor
Entry Mode Set
Ono display shift
/- 1m display shift
110MORE ABOUT ASCII
Many ASCI characters can be defined directly using MPASM as seen previously. For your
reference, a table of ASCII characters follows. You will note that there is quite a variety
available for your use. Just look up the HI and LO nibbles and away you go!
LCD FONT TABLE
UPPER NIBBLE
LOWER NIBBLE 0x2 3 4 5 6 7
0x0 0 Pe P
1 !1aAQaq
2 "2 BRbr
3 #3 cscs
4 s4p0Tat
5 #5 BE uvUeu
6 «6FV EV
7 '7GWgw
8 (8 HX h x
9 )o9TYiy
A "252 52
B +a k k
c N70
F 7200 °
Example: 0x41 = A
Note: 0x20 = Blank
‘The LCD has more fonts available. Refer to the manufacturer's data book for details.
111SCANNING KEYPADS
Keypads are available wired in various ways. If the switches are arranged in a matrix, they can
bbe Scanned by a microcontroller to see if one of the switches is closed (ie, a key is pressed).
For 5 switches/keys or less, itis best to use one port line per switch/key. For 6 keys or more, a
matrix arrangement is most efficient (minimize number of port lines).
‘The keypad shown below has 12 switches arranged in a 4 row by 3 column matrix. Pressing a
key closes a switch which electrically connects one row to one column.
COLUMNS:
Output Port
output port line is 0,
switch closure will assert
Input ine low = 0
Input Port
112‘At the time the input port line is read, its logic level depends, first, on whether the switch is open
‘or closed. If the switch is closed, the logic level at the input port line will be the same as the
‘output port line logic level.
SWITCH CLOSED
SWITCHOPEN __Outputs0_ Output =
INpuT 1 0 1
From the table, we can see that the output line must be low at the time the input line is read to
sec if the switch is closed.
Its easy to scan a keypad matrix by doing the following:
1. Set the first row LO and make the other rows HI.
2. Read the column lines individually looking for a LO.
3. If a LO is detected, the switch connecting the LO
row and the LO column is closed.
The columns are pulled up to 5 volts with 10K resistors and are connected to 3 input port lines.
‘The rows are connected to output port lines. The matrix is scanned under software control.
+5V0C
= 10k
Output Ports
Port B
4+ —_
Input Ponts 5.
6 +
113‘We will use a standard telephone keypad format as our example. ‘The switches are wired in a
matrix. How this is done physically varies. The keypad I pirated from an old telephone has.
most of the "wiring" on a flat very thin flexible sheet of plastic. Visualize it as being a thin
single-sided printed circuit board. The rest of the “wiring” is on the main telephone board. You
can scavenge a phone keypad, make your own matrix using individual SPST push-button
momentary contact switches, or buy a nice commercial unit.
For our example, the 10 decimal digit keys will be used for that purpose. The * and # keys will
be used as function keys.
The 10 decimal keys are used together, so software will scan the 3 x 3 matrix covering the 1
through 9 keys to determine which (if any) number key is pressed. Software will scan the
key separately.
‘The 2 function keys are used one at a time at predictable times, so software will look for specific
function key presses at the appropriate times.
It is apparent that the software must "know" which row is LO when a column LO is detected.
See the software description for more details on how this may be accomplished.
‘The meaning of having a specific key pressed is totally up to the designer who will determine
Wrhat label 1 placed of the key (fo tell the user what that Key's function is) and what the software
does when that key is pressed. Next time you use a microwave oven, run @ copy, or use an
automated teller machine (ATM), think about what each key does, what the software is looking
for when you press each key and what occurs immediately after you press each key.
SOFTWARE DESIGN
Troccurred to me that for programming purposes it would be most convenient to think of the
keypad as a group of decimal number keys and two function keys. The function keys are used at
some times and the number keys at others. ‘The two are not mixed. Going further, it made sense
to me to try to develop a loop or series of loops to scan the number portion of the keypad by
itself and to increment a counter in the process of scanning each key. If a key is pressed, the
counter will contain the same decimal digit as the key position.
‘The function keys are used at semi-predictable times (depends on your application).
Next, I made a flow chart for the program. Then I wrote code.
‘SCAN DECIMAL SUBROUTINE
‘The scan decimal subroutine uses 5 file register (RAM) locations:
Row Ctr Color charcw | [ RowBits | [ ColBis
114‘The scan decimal subroutine scans the 10 decimal key portion of the pad looking for a pressed
key (switch closure). As the subroutine steps through the rows and columns, a counter is
incremented. When a key press is detected, the character counter will contain the decimal digit
corresponding to the key. Itis available for use by the main program which called the scan
decimal subroutine,
The "0" key location is out of sequence (physically), so it is treated as a special case. After that,
the keys are scanned in numerical order.
Starting with "1", the scan sequence is the same as the sequence of the keys.
ROW COL CHARACTER COUNTER
1 1 a
1 2 2 Steps across row 1,
1 3 3 then row 2, etc.
2 1 4
2 2 5
3 3 9
‘Two other counters are used in addition to the character counter. One counter keeps track of the
row number and another counter keeps track of the column number.
The row bit register contains the bit pattern which is output to the keypad rows. The column bit,
register contains the bit pattern which is compared with the pattern read from the column input
port lines when the port B is read.
‘The RLF (rotate one bit left) instruction is used to shift the 1 one position to the left in the bit
pattern obtained from either bit register. The RLF instruction fills in the least significant bit with
the contents of the carry flag. Since the carry flag is in an unknown state (contains garbage)
115prior to the rotate operation, bit 0 is cleared right after the RLF instruction is executed.
0000 0001 Before RLF
0000 001x After RLF
0000 0010 after BCF
CMOS works best if an input is normally held high (+5V) by a pullup resistor and asserted low
when a change is required. To check for a switch closure, the row is asserted low (0) and the
columns are tested for 0 which indicates a switch is closed at the intersection of the two lines.
COLUMN,
45v00
a
Kory
aah 2 ROW
100
4 output por line is 0,
Input Pon | switch closure wil assert
input ine iow = 0
Because of the hardware considerations and because a shift left instruction which fills in behind
with 1's is not available, the row and column bits must be changed to their complements using
the XORLW (exclusive OR) instruction prior to use.
ceononn = p— Row bits
nha ty
000 0010
000 1111 Ox0F
000 1101 Result of XORLW
Pulls row 2 low
To continue:
010 0000 Column bits from register
100 000X Shift one bit left (RLF)
111 0000 OxEF
011 0000 Result of XORLW
=
Pulls column 3 low
116To visualize how all this works (for digits 1 through 9), you may want to mentally follow
through the flow chart and fil in the following table as you go:
TEST COLUMN CHAR ROW cou
TRIP THROUGH COUNT COUNT COUNT
Ast 1 1 1
2nd 2 1 2
3rd 3 1 3
4th 4 2 1
gth 9 3 3
Note that:
1. Character counter must start at 0, look at 0, then increment to 1.
2. Column counter starts at 1. Test for done = 3.
3. Column bits starts at 001 0000.
4, Row counter starts at 1. Test for done = 3.
5. Row bits starts at 000 0001.
17USING KEYPAD AND LCD WITH PIC16
aay elian
a RO
co
Pon B - |
KEYPAD BOARD
|__ Use Pullup Resistors
(On'84 Board
Port B
RAL = serial out to LCD module
Port B
Bits 76543210
K¥3214321
aw aN
col Row
= 400 milliseconds
118DEBOUNCE
The time delay subroutine called "pause" in Bagy PIC'nis used. Two file register (RAM)
locations are used as the M counter and the N counter. Switch contacts tend to bounce and may
be sensed as several key presses unless there is a time delay between samples. 400 milliseconds
‘works well as determined by experiment.
Load “MT Counter
Decrament "6" Counter
Yes
Return
119120
Flow Por Lines High
——
Digit Count = 0
¥
Pow=4
Return "e
Digit Count = 1
¥
Fow Count 1
¥
Inkial Row Bits
Er
Sapa ori
¥
‘Column Count.
¥
Init Column Bits
Rowt
Colt
Digit Avail (1-9)
No ¥
‘Shift Column Bits | ean)
t laste
Ine Column Counter
Yes
4 Row=3?
Inc Digit Counter No
Shit Row Bits
Inc Row Count
Inc Digit CountOn reset, the LCD module will display "HELLO". Press any digit key and the corresponding
umber will be displayed. Press either function key (* or #) and nothing will happen. Why?
J=====SCANPAD - ASM:
List — p=16£84
radix hex
/20/97==
cpu equates (memory map)
tmr0 equ (0x02
status equ 0x03
porta equ 0x05
portb equ 0x06
intcon equ 0x0b
sendreg equ Ox0c
count equ xd.
instr equ 0x0e
char equ Ox0f
addr equ 0x10
countl equ Oxit
digetr equ 0x12
rowctr equ 0x13
colctr equ 0x14
rowbits equ 0x15
colbits equ Ox6
temp equ Ox17
count equ 0x18
meount equ 0x19
optreg equ 0x1
trisa equ 0x85
trish equ 0x86
i bit equates
eu 0
org 0x00
start bef status, rp0_ switch to bank 1
movlw b'00000000" ;port A outputs
movwf trisa
moviw "01110000" ;port B inputs/outputs
movwf trisb
bef —status,rp0 switch back to bank 0
bst porta, 1 poutput mark, bit 1 (serial - LCD)
bst port, 0 prows high
bet — port, 1
bst —portb,2
bsf —portb,3
bef —portb,7 runused line low
ckpad call —scani0
movlw 0x04 shex byte follows
movwE instr
121move
movwe
call
call
goto
digctr,w :get digit
seanld
rowout,
tetcol
laste
laste
bst
bst
bst
bet
crt
bef
befss
return
bsf
movlw
movwt
movwt
move
move,
xorlw
movwi
movlw
mowwt
movlw
movwt
move
andlw
move
move,
xorlw
subwe
btfse
return
nove
sublw
btfsc
goto
rif
bef
inet
inet
goto
move
sublw
befse
goto
rif
bef
inet
ineé
goto
debounce moviw
122
char
sndstt yeall send stuff
debounce time delay - debounce switches
ckpad irepeat
portb, 0 jrows high
portb,1
portb,2
portb,3
digctr idigit counter=0
portb,3 jrow=d
portb/5 —;test_column 2
2"0" key press
portb,3 ;deselect row 4
0x01
digctr idigit counter=1
rowete tow counter=1
rowbits rrow bits = 0000 0001
rowbits,w get row bits
oxof icomplement row bits
portb foutput row bits
0x01
colete #column counter=1
ox10 0001 0000
colbits peol=1
portb,w ;read port B
0x70 jmask off rows and bit 7
temp peolumns
colbits,w get column bits
0x70 icomplement colum bits
temp, ieompare with contents of temp
status, 2
idigit available
coletr,w ;get column count
0x03
status, z 32
lastr
colbits,f shift column bits
colbits,0 ;£ix carry flag garbage
coletr,£
digctr,
tstcol
rowctr,w get. row count
0x03
status, 2 32
seanl0 iscan 10 digit keys again
rowbits,f ;shift row bits
rowbits,0 ;fix carry flag garbage
rowetr,£
digetr,
rowout
oxeemovw£ — mcount ito M counter
loadn moviw Oxfé N
movwf — ncount sto N counter
decn decfsz ncount,£ — ;decrement N
goto decn pagain
decfsz mcount,f decrement M
goto loadn pagain
return done
andstf£ mové — instr,w get instruction
movwf sendreg —;to be sent
call ser_out pto serial out subroutine
mové —char,w tget character or hex byte
movwf sendreg _—;to be sent
call ser_out ito serial out subroutine
movf addr, w iget address
movwf sendreg to. be sent
call ser_out. sto serial out subroutine
return
ser_out bef —intcon,5 disable tmr0 interrupts
bef —intcon,7 —;disable global interrupts
clef — tmr0 felear timer/counter
clewdt iclear wdt prep prescaler assign
bsf —status,xp0 ;to page 1
moviw b'11011000' ;set up timer/counter
movw£ optreg
bef status, rp0 ;back to page 0
moviw 0x08 pinit shift counter
movw£ count
bef = porta,2_— start bit
clrf — tmr0 pstart timer/counter
bef intcon,2-;clear tmr0 overflow flag
timel btfss intcon,2 —;timer overflow?
goto timed. ino
bef intcon,2 yes, clear overflow flag
nxtbit rif sendreg,f rotate msb into carry flag
bef porta,1 ielear port A, bit 1
btfsc status,c —;test carry flag
bsf —_porta,1 bit is set
time2 btfss intcon,2 timer overflow?
goto timez ‘no
bef intcon,2 clear overflow flag
decfsz count, f shifted 8?
goto axtbit ino
bs —porta,1_—yes, output mark
time3 btfss intcon,2 timer overflow?
goto times no
return done
end
fat blast time, select:
7 memory unprotected
123watchdog timer disabled (default is enabled)
standard crystal (using 4 Miz ose for test) XT
power-up timer on
FUNCTION KEYS
‘The function keys * and # are scanned separately. In a typical control application, the program
is looking either for a command or for a number entry (not both at the same time). Individual
subroutines handle each task as needed.
ow Port Lines High
z
Row=4
| No Key
To # Function
‘An “escape” has not been provided here. You can use reset or perhaps add that capability by
using the "O” key and scanning it along with the two function keys. It then acts as a third
function key when the scan function subroutine is running.
? SCANFCT .ASM=======:
List — p=16#84
radix hex
: cpu equates (memory map)
tmr0 equ (Ox01
status equ 0x03
porta equ 0x05
portb equ 0x06
intcon equ — Oxdb
124sendreg equ 0x0c
count equ —Ox0d
instr equ Ox0e
char equ Ox0f
addr equ Ox10
countl equ x11
ncount equ 0x12
meount equ 0x13
funct equ 0x14
optreg equ 0x81
trisa equ 0x85
trisb equ 0x86
2 bit equates
e co 90
P= tr = GJ
org 0x00
start bef —status,rp0_ ;switch to bank 1
movlw "00000000" ;port A outputs
movw£ trisa
moviw '01110000' ;port B inputs/outputs
movwf trisb
bef status, rp0 switch back to bank 0
bsf porta, 1 poutput mark, bit 1 (serial - LCD)
bsf port, 0 frows high
bsf port, 1
bsf —_— port, 2
bsf port, 3
bef —sportb,7 —;unused line low
ckpad call —scanfct
movlw 0x04 shex byte follows
movwf instr
movf funct,w © ;get character
movwf char
call —sndst¢ yeall send stuff
call debounce time delay - debounce switches
goto ckpad irepeat
scanfct bsf — porth,O —; rows high
bsf —portby1
bsf —portb,2
bsf —portb,3
elrf Funct
bef —portb,3 rowed
testk btfss portb, 4 ptest column 1
goto star ne" key pressed
btfss portb, 6 itest column 3
goto pound i# key pressed
goto testk ino key pressed
star moviw Oxaa *
mowwf — funct
return
125pound
movlw
movwt
return
debounce movlw
load
deen
sndsté
ser_out
timel
nxtbit
time2
times
126
movwt
movlw
movwt
dectsz
goto
dectsz
goto
return
move
movwt
call,
mové
movwé
call
mové
movwt
call
return
bef
bet.
clre
clrwdt,
bet
movlw
movwE
bef.
movlw
mowwe
bef
clr
bef
btfas
goto
bet
rif
bef
btEse
bst
btfss
goto
bet
dectsz
goto
bst
btfss
goto
return
0x88
funct
oxee
count
oxee
acount
acount, f
deca
count, £
load
instr,
sendreg
ser_out
chaz,
sendreg
sex_out
addz,w
sendreg
sex_out
intcon, 5
intcon,7
emr0
status, rp0
b*12011000"
optreg
status, rp0
0x08
count
porta,1
tmz0
intcon,2
intcon,2
timel
intcon,2
sendreg, £
porta,1
status,¢
porta,1
intcon, 2
timez
inteon,2
count, £
axtbit
porta,1
intcon,2
times
Ba
ito M counter
ito N counter
idecrement N
pagain
idecrement
pagain
idone
iget instruction
ito be sent
ito serial out subroutine
iget character or hex byte
ito be sent
ito serial out subroutine
iget address
ito be sent
2t0 serial out subroutine
idisable tmr0 interrupts
jdisable global interrupts
jelear timer/counter
ielear wdt prep prescaler assign
ito page 1
iset up timer/counter
jback to page 0
sinit shift counter
petart bit
istart timer/counter
‘lear tmr0 overflow flag
itimer overflow?
syes, clear overflow flag
protate mb into carry flag
relear port A, bit 1
test carry flag
pbit is set
itimer overflow?
jelear overflow flag
ishifted 8?
no
yes, output mark
itimer overflow?
doneend
jat blast time, select
; memory unprotected
watchdog timer disabled (default is enabled)
standard crystal (using 4 MHz osc for test) XT
power-up timer on
On reset, "HELLO" is displayed. Pressing the * key causes "AA" to be displayed. Pressing the
# key results in "88" being displayed. I am certain you will come up with more imaginative
things to do.
127DIGITAL TO ANALOG CONVERSION
DO IT YOURSELF D/A USING A RESISTOR NETWORK
For control purposes, you may wish to output an analog voltage. To do so requires the
conversion of a binary number to an analog voltage level. This may be done using a precision
reference voltage, a resistor network and an op-amp.
Here is a 4-bit version which can be interfaced with four PICI6 port lines. You can easily write
the code to exercise it on your own. Once a binary code is presented to the four output lines, the
voltage at the op-amp output remains fixed. This is in contrast to the pulse width modulation
(PWM) method which follows where, for simple methods of implementing PWM, the PICI6 is
kept busy doing PWM and may have little or no time (depending on the method used) for
anything else.
ssvoc
47K T
ra
ae vou
re tat :
wok 20K Laas OrMaxsos
rr
720K
pot
BOK
Example:
soe ssvoc
20k ook
Vout=
vo
= 2.67 Volts
120K =>
6oK<> “Pr 240K 34.29K
128Bits
3210
0000
0002
0010
0011
0100
0102
0110
0111
1000
1001
1010
1011
1100
1101
1110
aii
8-BIT PARALLEL D/A CONVERTER - AD558
Vout
0.00
0.33
0.67
1.00
1.33
1.67
2.00
2.33
2.67
3.00
3.33
3.67
4.00
4.33
4.67
5.00
‘A single package 8-bit D/A converter is available from Analog Devices as P/N ADS58 which
has the resistor network and summing amplifier built in. It operates directly from the
microprocessor system 5 volt supply. It produces 0 to 2.55 volts out corresponding directly to
the binary numbers written to it.
g
eVousens
16
15
14
13
12
"
10
‘SNS
SEL
GND
GND
Veo
cs
cE
129Output t
10KFor 0-25V +5V
Test
tlk
t | al
Out SNS SEL GND GND Vec CS
on
o 12 5 4 5 8 7?
a
oo
Ret
Rpg |__|
Reg |__|
RBs
Res
SS
i
PIC16F84
The functions of CS and CE are the same. Wire one of them (CE) to ground. CS latches data
with a low-to-high transition, so don't let the fact that CE has a veniculum over it mislead you as
itdid me.
To test the circuit, write a binary number to the converter and measure the output voltage with a
voltmeter or scope.
'=DASSB . ASMom===ann.
list p=l6ea4
radix hex
7 cpu equates (memory map)
status equ 0x03
porta equ 0x05
portb equ 0x06
trisa equ 0x85
trisb equ 0x86
130; bit equates
rpO equ 5
org 0x00
start bsf —status,rp0_ switch to bank 1
movlw '00000000" ;outputs
movwf trisa
movwf trisb
bef status, pO ;switch back to bank 0
movlw b*00000000"
movwf porta pinitialize, cs low
movlw b'10000000' ;volts ~ range 0 to 255 decimal
movw£ portb data to D/A
bsf porta, 0 ;pulse D/A to latch data
bef — porta, 0
circle goto circle
end
pat blast time, select:
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal (using 4 MHz osc for test) XT
power-up timer on
Output Voltage
SFE 2.55
00 0.00
OF 0.15
80 1.27
AD/A converter may be used to generate a variety of analog output voltage waveforms such as
ramp, sawtooth, sine wave, etc. Binary numbers representing narrow segments of the waveform
are sent sequentially to the D/A converter. An 8-bit D/A allows 256 possible voltage levels
which is enough for many applications. 10, 12, 14 and 16-bit converters are available if better
resolution or accuracy is required.
131Code for producing a ramp output voltage waveform follows. The period is about 1.75 millisec-
onds, frequency about 570 Hz. Adding a time delay at the end of each cycle will reduce the
frequency but the output will be "jagged".
+5V
ov
SSERAMP , ASManwwnnm=—n=-
list — pelesaa
radix hex
; cpu equates (memory map)
status equ 0x03
porta equ 0x05
portb equ 0x06
volts equ 0x0c
count! equ —Ox0d.
trisa equ 0x85
trisb equ 0x86
equates
5
org 0x00
start bsf —status,rp0_;switch to bank 1
movlw "00000000" ;outputs
movwf trisa
movwf trish
bef status, rp0 ;ewitch back to bank 0
movlw b'00000000"
movwf porta sinitialize, cs low
clr volte izex0
loop movf_—svolts,w get volts
movw£ portb idata to D/A
bst — porta,O —s;pulse D/A to latch data
bef porta, 0
incf volts, £
goto loop
end
t blast time, select:
memory unprotected
watchdog timer disabled (default is enabled)
a standard crystal (using 4 Miz osc for test) xT
; power-up timer onBinary numbers representing voltage levels can be stored sequentially in a table in program
memory and accessed using relative addressing. A sine wave example follows. This example
only has 19 voltage levels in the table (sine values at 10 degree intervals), so the output is
Jagged. You can add more values to the table. ‘The frequency will be lower as it takes more time
to output the additional values. Also, a time delay is included. You may want to experiment
with changing the delay time and with adding an RC filter to the output (see D/A conversion
apter).
Nel
T = 0,86 milliseconds
£ = 1163 Hz +y|
425V
ov.
s==558SINE. ASM:
list p*
684
radix hex
: cpu equates (memory map)
pe equ 0x02
status equ 0x03
porta equ 0x05
porth equ 0x06
count! equ —0x0c
offctr equ Ox0d
trisa equ 0x85
trisb equ 0x86
; bit equates
© equ 0
org 0x00
start goto do_it jump over table
table addwf pe, f dd offset to program counter
retlw 0x80 -28 volts
retlw 0x95 21.50
retlw Oxad 21.72
retlw 0xcl 71.92
retlw 0x3, 32.10
retiw 0x2 32.26
retlw 0xef, 32.39
retlw 0xE8 32.48
retlw Oxfd 52.54
retlw Oxf 32.55
retlw Oxfd 2.54
133retlw
retiw
retiw
retlw
retlw
retlw
retlw
retlw
retlw
retlw
retlw
retlw
retlw
retlw
retlw
retiw
retiw
retiw
retlw
retlw
retiw
retlw
xetlw
retlw
retlw
ones
Oxef,
Oxe2
Oxd3
Oxel
oxad
0x95
080
Ox6a
ox54
0x40
ox2e
Oxte
ox12
0x08
0x02
0x00
x02
0x08
oxi
oxte
Ox2e
ox40
ox54
Oxéa
52.48
32.39
32.26
32.10
72.92
71.72
71.50
72.28
71.06
70.84
70.64
70.46
0.30
70.17
70.08
0.02
0.00
70.02
70.08
30.17
70.30
70.46
70.64
70.84
71.06
doit bef
movlw
movwe
movwt
bef
movlw
novwt
eyele cir
step mov,
call
mowE
bst
bef.
call
mové
oublw
btfse
goto
inet
goto
delay moviw
movwt
repeat decfsz
goto
return
status, rp0
"00000000"
trisa
trisb
status, -p0
0x00
porta
offctr
offctr,w
table
portb
porta, 0
porta, 0
delay
offctr,w
0x23
status, z
cycle
offctr
step
0x01
count
count, £
repeat
iewitch to bank 1
joutputs
yewitch back to bank 0
700000000
sinitialize, cs low
selear table offset counter
iget offset count
iget volts from table
output data to D/A
pulse D/A to latch data
delay
get offset count
seompare ~ cycle complete?
pinerement offset counter
#3N43 cycles (decimal), N=1 shown
load counter
idecrement counter
not 0
counter 0, ends delay
end
134,tat blast time, select:
: memory unprotected
watchdog timer disabled (default is enabled)
standard crystal (using 4 MHz osc for test) xT
power-up timer on
DO IT YOURSELF D/A USING PULSE WIDTH MODULATION
Digital-to-analog conversion may be done using pulse width modulation (PWM) and a single
PICI6 pin,
PWM Basics
PWM involves outputing a train of pulses aa fixed frequency. The duty cycle Gogic HI ime,
usually expressed as a percentage of the PWM period) is varied to change the average output
voltage.
Poriod Period
rT
LJ Lf
Duty Duty
‘At the end of the duty cycle, the output goes low and at the end of the period, the output goes
high (except for the special cases where the duty cycle is 100 percent or 0 percent).
135As examples:
+sv |-_—______
“sv
ov —
+5V
ov
ov
+5
425
ov
Let's assume we want to generate a 0-SVDC analog voltage level on pin RBO of a PICI6F84
with a 4.0 MHz clock oscillator, We will use a pulse train period of 256 times 3 internal clock
cycles which equates to a frequency of about 1300 Hz. Using 256 makes the binary math easy.
‘The time delay requires 3 instruction cycles so the total PWM period is 768 microseconds.
We will use a software time delay subroutine. To make the duty cycle 50 percent, we will use
the hexadecimal value Ox7F for duty and 0x80 for low time.
PIC16F84
Reo }—+ PWM Output
136MAIN
PROC Initialize
¥
Dating Duty
¥
Define Low Tima
(Output High
t
Get Duy
¥
High Time Via Sub
¥
‘Output Low
5
Gettaw Tine
| ¥
Low Time Via Subroutine
TIMING
SUBROUTINE |_Number In Counter
| een ee
Dec Counter
Number x3 Cycles
1376/4/97 ==
list — p=16£84
radix hex
: cpu equates (memory map)
status equ 0x03
porta equ 0x05
portb equ 0x06
duty equ Ox0e
lowt equ —Ox0d
count equ 0x0e
trisa equ 0x85
trisb equ 0x86
? bit equates
rp0 equ
org 0x00
start bsf —status,rp0_;switch to bank 1
movlw "00000000" ;outputs
movw£ trish
bef status, rp0_ ;switch back to bank 0
movlw 100000000" ;al1 outputs low
movwE portb
moviw Ox7£
movwf duty
jinitial duty cycle $0 percent
moviw 0x80 sinitial low time 50 percent
mowwf low_t
repeat bsf —_portb,0 youtput high, start duty
movf duty, get duty
call time
bef —portb, 0 routput low, start low time
movf low_tyw get low time
call time
goto repeat.
time moww£ count time
loop decfsz_ count, £
goto loop
return
end
pat blast time, select:
3 memory unprotected
watchdog timer disabled (default is enabled)
standard crystal (using 4 MHz osc for test) xT
; power-up timer on
138Connect a DVM to RBO and measure the average voltage with the PWM routine running. The
result should be about 2.5V.
Next, calculate the hex numbers to use in the program to get output voltages of 1.25 and 3.75
volts. Then test them.
LOW-PASS FILTERS
A filter is a frequency-selective circuit which passes a certain range of frequencies and
attenuates others. A simple RC low-pass filter is shown below:
R
TT
Vin © Vout
a
‘This is called a first order (single RC section) low-pass filter. Its frequency response falls off at
higher frequencies. The voltage out is 0.71 times the voltage in at a special point called the 3db
point which is the half-power point. This is also known as the cutoff frequency. For the RC
low-pass filter, the cutoff frequency is:
aoe 1
“ 2mRC 6. 28RC
fe = fae
Where f, is in KHz
Ris in K ohms
Cc is in microfarads
10 4
071= 36 + ora
Slope = 6 db/octave
eu 20 dbidecado
fe Octave 2:1 Frequency changs
Frequency Decade 10:1 Frequency change
139If the input signal is a square wave with period T and frequency f:
Period
1
Frequency = =
Via
‘The filter will be effective if the cutoff frequency f, is 1/10f.
Using our 0.3KHz PWM example, we can easily add a filter to smooth the output and observe
the results.
R
Va re
eee choose C= 0.1. us
R= 53K Use 51K (standard value)
‘Try this with the 50% duty cycle code example (PWMDEMO.ASM).
Period
— Measure Supply Votago
Duy J
Dey sa ve22V
| Perea
XN Measure Times For
Porod and Day
140PWM USING FILTER WITH UNITY GAIN FOLLOWER
Adding an op-amp unity gain follower to the RC low-pass filter prevents loading of the RC
circuit (including loading by a DVM while measuring the output). The result is called an ideal
low pass filter.
+9voc
- OUTA 1 8 vs
stk uae Vout “A 2 7 ouTa
Vin Te ; +A 3 6 38
Or MAKES GND 4 5 4B
0.01 ut
deal Low-Pass Fier
MORE PWM PHILOSOPHY
Notice that 100% and 0% duty cycles are special cases that must be handled separately. Also,
their existence means that a simple program which simply goes HI/lo/HI/lo.won't work. A short
high time will occur for 0% duty cycle and a short low time will occur for 100% duty cycle. So
a simple Up/Down program doesn't solve the problem.
141ANALOG OUTPUT - INCREASE/DECREASE BUTTONS
‘The next example shows how an adjustable analog output on a single PICI6 pin can be created
using PWM. The circuit is controlled by an increase (voltage) button and a decrease bution.
Increase/decrease is proportional to the time the button is pressed (to a maximum of 5 volts at
the output or a minimum of 0 volts). ‘The rate of increase/decrease is ional to the time
between checks of the associated button which is determined by the number of trips through a
program loop between checks. When you test this circuit and program, you can change the
number and observe the results. The number is 0x30 (key response) in the listing
AOUTPWM.ASM.
svc
sox
Ao
Incr «8¥OC
| 10x PIC16F84
Rat RBO | ——+ pwm output
Deer
142OVERVIEW
House Keeping
¥
Initial Duty 50 Percent
repeat E |
‘Set Key Response
repoat2
DoPWM
Delay = pressck Time
Inc Duty Cyclo
Dec Duty Cycle
L
143MAIN
pale on Ports
Initial Duty 50 Percent
repeatt
——
¥
Set Key Response
ropoat2
core
we | i Caco
Keyes
11 Cycle Delay = Time Call pressck Inc Or Dec
ferme tendons
144pwm_per
Get Duty - Store In
‘count
GOTO outiow
(Output High
(GOTO del256-- Delay
FullPeriod
‘
Output Low
¥
‘Cale Low Tima, Store In|
count
Return
Return
145pressck
‘11 Cycles Regardless Of Path
Bay
ate
c
Ein in
l —>
aga
Delay 3 Cycles
ie
i —
ro
nae
Low except when duty cycle = 100 parcant
(exit da1256 with output high)
‘The program handles 0 percent and 100 percent duty cycles. The pressck subroutine takes 11
instruction cycles regardless of the path taken through it. The period of the output is the same
whether or not a check for a button press is made.
Change the button (key) response number to see the effect.
146-AOUTPWM, ASM===—==—
ist — pel6ee4
radix hex
(memory map)
iewitch to bank 1
:inputs/outputs
poutputs
pewiteh back to bank 0
pall outputs low
sinitial duty cycle 50 percent
jinitial key response
jeall PWM period subroutine
idecrement/test button response
delay to make things even
flock for incr/decr button press
i cpu equates
status equ 0x03
porta equ 0x05
portb equ 0x06
duty equ O0x0c
response equ 0x0d
count equ O0x0e
trisa equ 0x85
trisb equ 0x86
i bit equates
z equ = 2
oO | equ o)
org 0x00
start bsf status, rp0
moviw 100000011"
movwf trisa
movlw 100000000"
movwf trisb
bef status, rp0
movlw b*00000000"
movwf — portb
movlw Oxf
movw£ duty
xepeatl moviw 0x30
movwf response
repeat? call pwm_per
decfsz response
goto idle
call pressck
goto repeat]
pressck btfss porta, 1
goto decduty
btfss porta, 0
goto incduty
nop
nop
nop
goto goback
ineduty mov duty,
sublw Oxff
btfss status,z
inet duty
goback return
decduty movf duty,
sublw 0x00
idecrease button pressed?
tyes, decrement duty cycle
pincrease button pressed?
tyes, increment duty cycle
iget duty cycle into w
sduty cycle=0xfe?
sincrement duty cycle
ipress check done
jet duty cycle into W
147btfss status,z
dect duty idecrement duty cycle
goto goback
idle nop
nop.
nop
nop
nop
nop
nop
nop.
nop
goto repeat2
pwmper movf duty, iget duty cycle
movwf count
sublw 0x00 icompare w/0
btfsc status,z
goto outlow
bsf —_portb, 0 youtput high
mové duty, get duty cycle
aublw Ox£f peompare w/Oxff
btfsc status, z
goto de1256
ni decfsz count,f —+high time
goto hi
bef port, 0 youtput low
movf duty, iget duty cycle
sublw Oxf
movw£ — count slow time
lo decfsz count, £
goto 10
return
outlow bef —portb,0 — output low
de1256 moviw Oxff idelay full period
movw£ count
loop decfsz count, f
goto loop
return
end
yat blast time, select:
memory unprotected
watchdog timer disabled (default is enabled)
f standard crystal (using 4 MHz osc for test) xT
power-up timer on
Run the program with an oscilloscope monitoring the output. Press the increase or decrease
button and observe the result.
148PWM USING SOFTWARE, TMRO AND INTERRUPTS - PHILOSOPHY
PWM may not be a full-time job for the microcontroller (depending on the application), but the
PWM functions that are performed must be done when needed on a periodic basis as long as the
‘PWM output is required.
Period
Duty
TH
Do Do something Else
ae
Do Do
If the TH or tl is short (could be 0), there may not be time to do anything else during that time
interval. Code can be written to determine which is longer, TH or tl. ‘The other tasks can then
be performed in the longer of the two time intervals. The PWM routine runs as the main
program and lets the other tasks be performed during TH or tl, whichever is longer. One of the
other tasks is to monitor inputs and determine duty cycle. The updated duty cycle value is stored
in the TH (duty) register.
Duty Cycle = 100%
TH TH
| |
Tu |
a aN
tr |
ad tl
Duty Cycte
=0%
=S Se
Bo Bo
Using this technique requires that the non-PWM task be accomplished in something less than
half the PWM period. If the period = 256 instruction (OSC/4) cycles, then the non-PWM task
would have to be accomplished in 128 cycles less the time required to service the TMRO
interrupts, etc. An example of this concept follows.
149‘We will use a period counter value of 256 and divide the internal clock by 4 using the prescaler.
Period
Duty
Potiod = T= 256 x 4 usec = 1.024 msec
1
Froquoncy f= T= 97 Hz = 1 KH
The test circuit is shown below. The switches on port B are used to input the duty cycle as an 8-
bit number. The switch settings may be changed as the program runs. Again, the output may be
monitored using an oscilloscope.
User options include using the prescaler to slow down TMRO.
+ More time to do useful stuff.
+ Software overhead will cause smaller percentage error.
RAO +svoc
PIC16F84 a
8 Switches And
om Pulup Resistors
PWM Output -——}
+5Vv0C
c
150MAIN
PROGRAM
Initialize
¥
Output High
[see J
‘Set Up TMRO
Cosme |
Duty Cycle = 60 Percent
‘= TH For First Pass.
t
‘Set Useful Flag For First
Pass.
¥
(Clear THI Flag For First
Pass -So Will Do High
‘On First Interrupt
Service
t
Load TMRO With
Complimant Of TH
+
‘Start TMRO
a=
Circle
151ee Cloar Interrupt Flag
SERVICE .
(Includes Do) v cutow
Got Duty Cycle Output Low
‘Start THRO, 266
Kawa ooo
Sat Tt 26
eon Ton Satin
Osos tow Y
ie Se THn Fag
Gea THaFiag z
+ Gatonporbay= ||
Get Duty = Complement oreo
on
Equals Pah Tne
load_t —
i Load8i9, Sto Tine
Uoad=StetTMRO] Least Number Lng Tine
1 Tho Couts Up
Sob0a Tine ober
Fomoce Cary Sat Tina 50%
Gary Siar Tier > 20%
caneare ——
Faun From iowa
Do Useful v
out Read Port 8
Return From Interrupt Port B Contents To duty
Y
Roturn From Interrupt
152List pel6ead
radix hex
cpu equates (memory map)
tmz0 equ (Ox01
status equ 0x03
porta equ 0x05
porth equ 0x06
Antcon equ 0x0b
duty equ Ox0e
flags equ —Ox0d
opt equ (x81
trisa equ 0x85
trisb equ 0x86
; bit equates
ce a0
z equ 2
mp0 equ SS
© equ 0
org 0x00
goto start iskip over location pointed to by
+ interrupt vector
org 0x04
goto isery
start bsf —status,rp0_;switch to bank 1
moviw "00000010" ; inputs/outputs
movwé trisa
moviw b‘11111111' ;inputs
movwf trish
bef —status,rp0 ;switch back to bank 0
bsf —porta,0—;output_high
bef —intcon,2-;clear TMRO interrupt flag
bsf —intcon,7 enable global interrupts
bsf — intcon,5 —;enable TRO interrupts
elrudt, clear WOT prep prescale assign
bsf status, rp0 ;switch to bank 1
movlw b'11010001" ;select THRO, internal
clock source, prescale 4
movwf opt
bef status, rp0 ;return to bank 0
clef — tmr0 istart timer known state
movlw 0x99, sinitial duty cycle 60 percent
movwE duty
movf duty,w iget duty cycle
sublw Oxff complement
movwf — tmr0 petart TMRO
circle goto circle iwait for interrupt
serv bef intcon,2 clear TMRO interrupt flag
153movf — duty,w iget duty cycle
sublw 0x00 feompare w/0x00
btfsc status, 2
goto outlow
movf duty, iget duty cycle
sublw Oxf icompare w/Oxft
btfsc status, 2
goto outhi.
btfss flags,t
goto doth
test TH/tl flag
flag is clear
dotl bef —porta,0 — output low
bef — flags,t =; flag is set, clear it
mov duty, iget duty = comp of tl
nop yequalize time for paths
nop
nop
load_t movwt tmrd jstart THRO
sublw Ox7£ icompaze with 50 percent
btfss status,e
retfie
switch btfsc porta,1 check data ready switch
retfie
mov portb,w ;switch pressed, read data
movwE duty retore in duty cycle register
retfie
doth bsf porta, 0 joutput high
psf — flags, t ;TH/t1 flag is clear, set it
movf duty, w iget duty cycle
sublw Oxff complement
goto load t
outlow bef —porta,0 — output low
clrf — tmr0 yetart TMRO, 256
goto switch
outhi bsf porta, 0 poutput high
clrf — tmr0 pstart TMRO, 256
goto switch
end
fat blast time, select:
memory unprotected
? watchdog timer disabled (default is enabled)
i standard crystal (using 4 MHz ose for test) xT
: power-up timer on
Note that doing other stuff besides PWM includes changing the TH value (tl calculated) to
change the PWM duty cycle.
Changing the output voltage may be done in response to program instructions or to sensing
something in the outside world such as a pushbutton switch closure or a varying analog signal.
154HARDWARE PWM
Another possibility is to use a PIC16 with a capture/compare/PWM (CCP) module such as the
PIC16C63. The CCP module is designed to do PWM unattended, meaning once the CCP
module is programmed to do PWM and the frequency and duty cycle are loaded, PWM occurs
with no further intervention from the PIC16 except to change duty cycle when needed.
‘Much shorter periods (higher frequencies) are possible using hardware PWM.
1558-BIT SERIAL D/A CONVERTER - MAX522
‘The MAX522 from Maxim Integrated Products is a dual 8-bit serial D/A converter in an 8-pin
DIP.
coe) 8 DIN
cK 2 — 7 Veet
Vdd 3 — 6 ours
Ves 4 —| 5 uta
‘The MAXS522 has 3 control lines:
+ Data in
* Clock
+ Chip select (CS)
. Bringing CS low starts the serial communication process. Raising CS high ends the process.
While CS is low, 16 bits are clocked in, The first 8 bits are an instruction word (only 4 of the 8
bits are used). The second 8 bits are the data or may not be used. We will see how this works by
example.
156‘The table shows the commands for the MAX522.
Function Control Data
Load Data To DAC B 001+*+*010 &Bit DAC Data
Load Data To DAC A 001*+*001 8-Bit DAC Data
Load Both DAC Registers 001+**011 8-Bit DAC Data
With Same Data
DAC A And DAC B Active 00100000 00000000
Shut Down DAC B 00110000 00000000
Shut Down DAC A 00101000 00000000
Shut Down DACA And DACB 00111000 00000000
Note: "*" means put in a "0" or "1" according to following rules.
When using a load data command, an active vs. shut down
bit is included for each DAC (SA and SB bits).
SA and SB bits
SA controls DAC A
SB controls DAC B
1 shuts down
0 activates
‘The tables in the MAXIM data book show uncommitted bits and don't care bits (X's). I made
them all "0's". 1 also blew out all the unassigned commands. Much less intimidating!
Notice that the MSB of the control word must be shifted out of the PICI6 to the MAX522 first.
The LA and LB bits in the control word determine which DAC register (A, B or both) the data
goes to. The number "1" loads, "0" does not. The SA and SB bits are used to turn on or shut
down the DAC(s) (A, B or both). A "0" activates the selected DAC, "1" shuts it down.
157‘Turing DACs on or off and loading data may be combined into one control word.
—
a | SB
aT
00110001 XXXXXXXX
Looe, augaweey
J Cer Coumamernnn
were
sete
‘The circuit looks like this:
eras tu..
wt] [Dene
re
-
|
RAO 45V
PIC16F84
‘The reference voltage input (Vref) is tied to SV for this example.
158‘The data codes vs. voltage out goes as follows:
Code Input
Bit 7 0
Volts Out
1211 1111
1000 0000
0000 0001
0000 0000
4.98
2.50
0.02
0.00
approx. 20mV steps
Output A Voltage Level
MAIN
PROGRAM
subt
Load Control Word
¥
Load Volts
¥
Call subt
¥
Circle
¥
Load Control Word
al
Call sor_out
kK
Load Vols
¥
Call sor_out
¥
CSHigh
"
Return
Ref/2
Load Data In DAC A,
DAC AOn,
159160
sor_out [Save Copy Of Data
Load 8 Counter
tostbit "
Clear Port A, 0
°
BIFSC __
Vin max— Vin ain
174‘Assuming a transducer output range of 2.5 to 3.75 volts as in the previous example:
8
3.75 — 2.5
Let R, = 100 K (much larger than sensor)
Let R; = 400 K
Veet(1 + 4) = 3.75(4)
Veer = 3volts
~ FR sealeAdst
otox
100K
woe
i
Sensor Vin »— +} >
00K |axaod Vou
asvpe 7
wet
Citi
3k
Vin max: = OV
Vi, = range Of sensor output
Design for range
Sample 2.5 —= 3.75 volts
Vv, —+v,
R, = 100K
R, = 400K
Vree = 3 volts nominal
To set scaling = spa:
Vin Max applied to Vin (3-75V) Adjust scale so Vay = OV
To set offset = zero
Vin Min applied to Viy (2-.5V) Adjust offset 50 Vaye = 5V
175Scale Adjust
100k
5K
Reference
Voltage
Offset Adjust
Single op-amp offset and scale:
Adjust scale = span first (3 volts at Vee).
Adjust offset = zero second (approx 470K).
Vig (VO1ES) — Vous (volts)
2.5 4.9
2.7 4.2
3.0 3.05 Input range
3.2 2.25 2.5 —» 3. 75V
3.5 1.05
3.75 0.05
40
as
Vin 30
28
+--+ +} +++
o 41 2 3 4 8
176‘Again the result is a straight line relationship between Vjp and Voy. The 1.25 volt input range is
expanded to 0 to 5 volts offset to 0 volts when Vin = 2.5V.
WHY 1 OP-AMP vs 3 OP-AMPS?
The single op-amp design has far fewer components and one power supply which is the 5 volt
logic supply but it is less intuitive (for learning purposes) and has an inverted binary output.
Inverting the output in software is simple--just complement it (0's to 1's, 1's to 0's). This
assumes an 8-bit A/D.
177ANALOG TO DIGITAL CONVERSION
Analog to digital (A/D) conversion is essential to PIC'n because PIC16s can only process digital
information. Analog signals, usually voltages from sensors, must be converted to binary
numbers digestible by the PIC16. As usual, this may be done by one of several methods with
the usual cost/accuracy/resolution/PCB in?/etc. tradeoffs to be made.
PIC16s can measure resistance in a crude way using one digital /O pin. The PIC16C7X series
parts have A/D converters built in. A variety of serial A/D converters are available. We will
look at examples of these three possibilities.
PIC16 PIN AND RC TIME CONSTANT
‘An interesting characteristic of a PIC16 digital /O pin is that there is a threshold voltage below
which an input is recognized as low and above which it is recognized as high. You can measure
it easily using a potentiometer, an LED with series resistor and a DVM. I used 8 LED's here to
avoid rewiring for experiments which appear later in this chapter.
48V00
“Hof _
Gia Read Port Line
a
Initially adjust the voltage at the pin to a littl less than 1 volt. The voltage input will be
interpreted as low. Then slowly increase the voltage until the LED's turn on. I call that voltage
Voip: Vnip Will vary with power supply voltage and slightly from device to device. By my
measurement, Vpip is around 1.23 volts for Vdd = 5 V
178n= VPLIP .ASMee=a= naa
list — pe16£64
radix hex
6/6/97;
: cpu equates (memory map)
status equ 0x03
porta equ 0x05
porth equ 0x06
trisa equ 0x85
trisb equ 0x86
bit equates
ro equ.
org 0x00
start bsf —status,rp0_ ;switch to bank 1
moviw '00000000" outputs
movwf triab
movlw 100000001"
movwf trisa
input /outputs
bef status, rp0 ;switch back to bank 0
clrf — portb nitialize, LED's off
loop btfss__ porta, 0 Hook at input
goto outio idisplay input status
psf —_portb,0 + at port b, bit 0
goto loop.
outlo bef —portb, 0
goto loop.
end
jat blast time, select:
memory unprotected
3 watchdog timer disabled (default is enabled)
standard crystal (using 4 Miz osc for test) XT
: power-up timer on
179Measuring Resistance Via PIC16 Pin And RC Time Constant
Armed with this information, we can now measure resistance using one PIC16 pin! We can do
this by charging a capacitor through a resistor of unknown value and measuring the time it takes
for the voltage across the capacitor to reach Vaip. In advance, we will need to Tun a bunch of
experiments using resistors (or pot) of known Value. We will use TMRO to measure time.
‘The first step in the measurement process is to discharge the capacitor. This is accomplished by
making the pin an output followed by outputting a "0". Then, after a suitable time for
discharging the capacitor has elapsed, the pin is made an input and TMRO is started. The
program watches the pin. When the voltage on the pin reaches Vaip , the timer is read. The time
interval is proportional to resistance.
Following are a program listing and test data for:
PICI6F84
C=0.1 pF
Prescaler = 4
4.00 MHz clock oscillator
+svoc
aX sv
Port Line,
Input vin
vtlip
ove
PIC16F84 Time
list £84
radix hex
c cpu equates (memory map)
tme0 equ (Ox01
status equ 0x03
porta equ 0x05
Porth equ 0x06
Antcon equ 0x0b
opt = equ Ox
trisa equ 0x85
trisb equ 0x86
; bit equates
ep | cau 45)org 0x00
goto start iskip over location pointed to by
interrupt vector
org 0x04
goto serv
start bsf —status,rp0_ ;switch to bank 1
movlw '00000000' outputs
movwf trisa
movwf trisb
bef status, rp0 ;switch back to bank 0
clrf port ;LED's off
bef —intcon,2 -—;clear TMRO interrupt flag
bsf —intcon,7 —;enable global interrupts
bsf — intcon,5 —;enable TWRO interrupts
clrwat pelear WDT prep prescale assign
bef —status,rp0 switch to bank 1
moviw 111010001" ;select 7™RO, internal
i clock source, prescale 4
movw£ opt
bef — status, rp0 return to bank 0
bef porta, 0 discharge cap
clrf — tmr0 pstart timer, known state
dischg btfss tmr0,7 itime for cap discharge
goto dischg
bsf status, rp0_ ;switch to bank 1
bst trisa,O porta, bit 0 input
bef —status,rp0 ;switch back to bank 0
clrf — tmr0 pstart TMRO
flip btfss porta, 0 plook at input
goto flip pinput low
movf — tmr0,w pinput flipped, read timer
movwf — portb idisplay time at port B
bef intcon,5 —;disable TMRO interrupts
circle goto circle done
iserv bef —intcon,5 disable further TMRO interrupts
movlw Oxaa
movwf —portb pdisplay timer overflow condition
idle goto idle
end
pat blast time, select:
a memory unprotected
f watchdog timer disabled (default is enabled)
3 standard crystal (using 4 Miz osc for test) xT
: power-up timer on
181‘The following graph shows resistance vs. counts from TMRO. The “resistance” in an application
could be a potentiometer, thermistor, or photo cell. The counts could be proportional to position,
temperature, or light level.
372.
LJ s7K_ | 144.
256 Counts “ Count
Proscale = 4
‘4.0 MHz Glock Ose.
AID Via PIC16 Digital VO Pin And RC Time Constant
Voltage can be measured in a similar way. R and C are fixed and the time to charge the
capacitor t0 Vpip is proportional to the voltage applied to the resistor.
‘Analog Input —
+9voe
ssvoe 47K
Ly> a
Lmase, YA} Distal v0 -
+ a Input
ont
=~ | Piciers4
High Zn — LL Lowzout
Impedance
Transformation
182+o
x
Lass
pi
Vin -—} I=
LU, vou
Low Output
Impedance
‘The output impedance of the source must be small compared to R. I used a pot to derive the
voltage and an op-amp for impedance transformation.
‘The program is the same as for the resistance measurement example. A plot of counts vs.
voltage is shown. Notice that itis very nonlinear (as you might expect).
‘There is nothing magic about the values I chose for R, C and prescaler division ratio (except that
they work I suppose). This is merely an example to illustrate the concept. There is not much
resolution high on the curve. Measuring voltages in the range of 1.5 to 2.5 V would work well.
Resolution could be improved by reducing the prescaler division ratio or by increasing the clock
oscillator frequency to 5.00 MHZ or both. TMRO could be allowed to roll over with the number
of times being counted.
AD Via PICI6Pin
Voltage At 0.1 ut, 4.7 K, Oscl4
Input Pin 2 LMa58, SK Pot
183SERIAL 8-BIT A/D CONVERTER - ADC0831
‘The ADCO831 from National Semiconductor is an 8-bit serial single channel successive approx-
imation A/D converter in an 8-pin DIP.
<= -——
wei }— 8 Vee
Vine 2 —| 7 CLK
vine 3 —J) A0C0831 | _ § po
vss 4 —| | 5 Veet
Ithas built-in zero and span capability, but we won't use it right away. It has a 0-5V input range
‘operating with a single 5V supply. The A/D may be located right next to the sensor where it will
transmit noise-immune digital data to the PIC16.
‘The ADCO831 has 3 control lines:
+ Data out
+ Clock =
* Chip select CS
Data is shifted out MSB first
Referring to the timing diagram, pulling CS low starts initializing the chip for an A/D
conversion. The chips goes through its setup process which is completed when the clock line
goes high (minimum Tyeqyp 250 ns). When the clock line goes low, the conversion process
starts. A leading "0" appears on the data out (D,) line. The clock line is used to shift out 8 data
bits.
The clock rate or frequency (f.,) must be between 10 KHz and 400 KHz. We will flow chart the
program and get a rough estimate of frequency from that.
Main tit Main
uk
a
A Tootup
Leadingo BA (SB) Bie Bro
L— stant
Conversion
184For our initial experiment, we will use the following circuit:
a wv
Veo GLK 0 Viet
‘pcos
Vine Vin Vee
Ra | i
at
*sv
ee
Piciere4 + sk
GS is for selecting the chip and for starting the conversion. CLK is for shifting data.
185186
MAIN ;
PROGRAM eaielae)
convert
Slow
¥
Pulse Cock Line, Start
Conversion
a
Call ser_in
+
‘Complete Last Clock
Pulse
¥
Grigh
4
Get Data From revreg
a
Display Data At Port B
LEDs
¥
Dolay 200 milliseconds
Adjust Pot
Monitor Vin via DVM
Watch LEDs
Dial in 0x80 (10000000) using pot
Voltage Vj, should be 1/2 Vee
Start Setupser_in Clear revreg,
4
Load 8 Counter
‘Clock Line Low
¥
Read Port A
¥
‘Store Copy
¥
Rotate Bit 0 Into Carry
¥
Rotate Carry Into revreg
GOTO shift
u Clock High
Return T
‘GOTO getbit
The clock frequency is not symmetrical as shown in previous timing diagrams. It is roughly
77 KHz,
T = 134 sec
frequency = = =
1875/27/9T==
list — p=16£84
radix hex
: cpu equates (memory map)
porta equ 0x05
portb equ 0x06
status equ 0x03
revreg equ Ox0e
count equ Ox0d
temp equ Oe
count equ 0x10
meount equ 0x11
trisa equ 0x85
trisb equ 0x86
bit equates
equ 0
2 equ 2
rp0 equ
org 0x00
start bsf status, rp0_ ;switch to bank 1
movlw b'00000001" bit 0 = input
movwE trisa
movlw b'00000000" ;outputs
movwf trisb
bef status, rp0 ;switch back to bank 0
moviw 0x04 70000 0100
movwf porta pinitialize
nop idelay
convert bef —porta,2 iT setup, CS low
nop.
bsf —porta,1 pelock high
nop rdelay
bef porta,1 clock low - start conversion
nop delay
bsf —porta,1 pelock high
call ser_in ;to serial input subroutine
sf —porta,1 Plast clock pulse
nop
bef porta,1 ielock low
nop
bsf —porta,2 #C8 high
movf revreg,w get data
movwf — portb idisplay data via LED'S
call debounce wait a while (200 milliseconds)
goto convert ook at voltage again
ser_in clrf — revreg iclear receive register
movlw 0x08 sinit 8 counter
movw£ count,
188getbit bef —porta,y1_-—clock low
nop idelay 1 instr cycle
movf porta,yw —;read port A
movwf temp istoxe copy
ref temp, irotate bit into carry flag
rlf _revreg,£ rotate carry flag into rcvreg
decfsz count,f | ;decrement counter
goto shift.
return done
shift bsf porta, pelock high
goto getbit zagain
debounce moviw Oxff ™
movw£ — mcount ito M counter
loadn moviw Oxf 2N
movw£ — ncount to N counter
decn decfsz ncount,£ — ;decrement N
goto decn jagain
decfsz mcount, £
goto loadn
idecrement M
again
return done
end
yat blast time, select
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal (using 4 MHz osc for test) XT
power-up timer on
ADC0831 Built-In Offset And Scal
‘The ADCO831 has built-in offset and scale capability. The differential analog voltage input
allows offsetting the analog zero input voltage value. Also, the voltage reference input can be
adjusted to allow encoding any smaller analog voltage span to the full 8 bits of resolution.
+5V 45V
L. :
sk > Sensor>—| Vine Veo
| +5 ‘ap00831 tout
a ee :
“K Vin Veot |= 10k
olet Aj ING Spaneat Aah
COfsets Analog 0
Input Vottage
189‘Try an input range of 2.5 to 3.75 volts as an example.
With the example code running and observing the port B LED's:
2.5 volts at Vint
Adjust offset to just get 00000000 to 00000001
transition
3.75 volts at Vint
Adjust scale to get 11111110 to 11111111 transition
TEMPERATURE MEASUREMENT USING LM335 TEMPERATURE SENSOR
‘Three Op-Amp Offset And Scale
If you wish, you can try out your three op-amp offset and scale circuit in conjunction with the
serial A/D converter.
0 to 50 ‘C thermometer (32 to 122 °F)
122, 323) «803,235
To get LM335 Vax, add °C to 273. Multiply result x10 to
get LM335° Vout,
Example:
54. F = 12.2 °C
273
+422
285.2 —» 2.85 volts —» 1.2 volts at amplifier V,
mp: out.
190ADC0831/LM335 TEMPERATURE MEASUREMENT
‘The LM335 may be interfaced directly with a LM335 temperature sensor making use of the
built-in offest and scale capabilities of the ADCO831.
45V
L358
af
ES
sv ‘apcoest tout
ie
|
5
10k S-—} Vine rot | >= 10k
Min Temp Adj MO mp Adi
Offset Adjust Span/Scale Adjust
Offsets Analog 0 ‘Adjust So Maximum Temperature =
Input Vottago 41111110 To 11111111 Transition
‘The A/D may be located right next to the LM335 sensor which will transmit noise immune
digital data to the microcontroller. See the National Semiconductor "Data Acquisition Linear
Devices” data book for more information.
191PIC16C71 ON-BOARD A/D
‘The PIC16C71 has 4 pins which may (or may not) be used as A/D channels. These are port A,
bits 3,2,1,0. The four analog inputs are multiplexed into one sample and hold circuit. The output
of the sample and hold is the input to a successive approximation converter. The reference
voltage may be the 5 volt supply to the PICI6C71 (range 0-5V) or an external reference (range
3.0 to Vec +0.3 volts) via pin RA3. If an extemal reference is used, only 3 A/D channels are
available.
Important electrical specs are:
Vain Vgg-0-3V tO Vreg
Viet 3:0V to Vaqt0.3V
Maximum source impedance 10K
(0 to 5V Sf Vee = logic supply)
‘We will make a simplifying assumption about timing by assuming it is not critical to get the A/D
conversion done in the shortest time possible. We will use a 4 mlz clock oscillator. ‘The clock
frequency is divided to obtain the clock source for the converter function, The data book talks
about clock period (clock period - Tosc), so it may be better to think of the clock period being
multiplied rather than clock oscillator frequently being divided. We will use the largest clock
period multiplier which is 32. If you develop an application where time is of the essence, you
will need to refer to the data book for timing considerations/options/calculations. Our objective
here is to simplify matters and to get something working.
‘Two registers are used to control the A/D converters and one is used to hold the result of the
conversion.
ADCON1
Controls the port pin functions.
eS
A = analog input
D = digital 1/0
192‘ADCONO
Controls the A/D module.
RW RW.
uo RW RW RW RW RW
nocsi[aocse] im [onsr [orse [eoRone| ane [hoon] 08
7
Bits 7,6
Bit 5
Bits 4,3
Bit 2
Bit 1
Bit 0
Note 1:
°
A= Readable bit
We Writeable bit
U = Unimplemonted bi, read as "0
Power on reset 00000000
ADCS1:ADCSO: A/D conversion clock select bits
Fosc/2
Fosc/8
Fosc/32
11 = Fre (clock derived from RC oscillator)
Unimplemented, read as "0"
CHS2:CHSO: Analog channel select bits
channel 0 (RAQ/ANO)
channel 1 (RA1/AN1)
channel 2 (RA2/AN2)
11 = channel 3 (RA3/AN3)
GO/DONE: A/D conversion status bit
If ADON bit = 1
1 = A/D conversion in progress (setting this
bit starts the A/D conversion)
0 = A/D conversion not in progress (this bit
is automatically cleared by hardware when
the A/D conversion is complete)
ADIF: A/D conversion complete interrupt flag bit
1 = conversion complete (must be cleared in
software)
0 = conversion is not complete
ADON: A/D on bit
1 = A/D converter module is operating
0 = A/D module is shut off and consumes no
operating current
Bit 5 of ADCONO is a general purpose R/W bit for
the PIC16C71 only. For the PIC16C710/711,
this bit is unimplemented and reads as "0".
193ADRES
‘The A/D result register contains the result (data) on completion of the conversion
process. The address is 0x09.
The procedure for performing an A/D conversion is:
+ Configure the port A pins - done once during the setup portion of the main program
+ Select = enable an A/D channel
+ Wait for the A/D to acquire the data (20 sec)
+ Start the conversion - set go/done bit in ADCONO register
+ Use interrupt or polling go/done bit in ADCONO register to detect conversion
completion
+ Read data in A/D result register
+ If you want to do another conversion, wait 16 sec
How will we know when the conversion process is complete? There are two bits in the
ADCON0O register which can be used. The go/done bit (bit 2) may be polled. It is set to start the
conversion process and is cleared when the conversion is complete. The ADIF bit (bit 1) is the
conversion complete interrupt flag. It is set on conversion completion. Note that it must be
cleared in software as part of the interrupt service routine. Of course, the interrupt must be
enabled prior to starting the conversion if this method is used. Bit 6 of the INTCON register is
the A/D interrupt enable (ADIE) flag.
Conversion complete:
+ Result in ADRES register
+ Go/done bit in ADCONO (bit 2) is cleared
+ A/D interrupt flag bit (ADIF) in ADCOND (bit 1) is set
EXAMPLE
This example shows how to use channel 0 on pin RAQ/ANO. We can't use channel 0 as the only
analog input (see table for ADCON1), so we will make port A, pins I and 0 analog inputs with
pin 1 tied to ground and make port A, pins 3 and 2 digital outputs.
PICI6C71
4 MHz clock, Tose = 0.25 yisec
AID clock source = Tyg = Ty5¢x32 = 8 psec
Veep = 5V
194+5V
RA2, 3, 4
RAQVANO
RAVAN
PIC16C71
RB7-0 |
6800
‘All Other Connections SNZ steps
‘Same As For PICI6FS4
Experiments “+
195Initialize
T
——__¥
Configure Pins 00000010"
v Bits 1, 0 Analog
Port B LEDs Off
¥
Disable Interrupts
_
San
seuttetten | yroomant
on Pion
Tube Sr
een
I noes
ta Do arose
| yo
Start Conversion
tost
Test Go/tione Bit
Not Yet
Get AD Result
¥
Display At Por B LEDs
+
Delay 200 Miliseconds
Via Subroutine
196s=AD16C71 . ASH:
list p
radix hex
671
c cpu equates (memory map)
porta equ 0x05
portb equ 0x06
status equ 0x03
adcond equ 0x08
adres equ 0x09
Antcon equ 0x0b
count equ —Ox0d
ncount equ Ox10
meount equ Oxil
trisa equ 0x85
trish equ 0x86
adconl equ 0x88
i bit equates
rpo equ S
org 0x00
start bsf status, rp0_ switch to bank 1
movlw b'00000011" ;inputs/outputs
movw£ trisa
movlw "00000000"
movwf trisb
moviw "00000010" ;port A, bits 1,0 analog input
utputs
movwf —adcont bits 3,2 digital 1/0
bef status, rp0 ;switch back to bank 0
clr portb PLDs off
bef intcon,7 _—;global interrupt disable
meas movlw "10000001" ;configure A/D - select ANO
movw£ — adcon0 + select conv clock, ANO on
call del_20 idelay 20 microseconds
bs adcon0,2—;start_ conversion
test btfsc adcon0,2 —test_go/done bit
goto test.
movf adres, w iconv complete, get A/D result
movwf — portb idisplay data via LEDs
call debounce wait a while (200 milliseconds)
goto meas plook at voltage again
de1_20 moviw 0x07 idelay 20 microseconds
movw£ count,
repeat decfsz count
goto repeat
return
debounce moviw Oxff ™
movwf — meount ito M counter
loadn moviw Oxf f 2
197movwf — ncount to N counter
decn decfsz_ncount,f —;decrement N
goto decn pagain
decfsz mcount,f — ;decrement M
goto loadn again
return done
end
yat blast time, select
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal (using 4 Miz osc for test) XT
power-up timer on
‘Turn the pot and observe the port B LEDs.
198MATH ROUTINES
OK - some math is required for some PIC16 applications. No problem! Itis easier than it
appears at first (for 8-bit or 1-byte arithmetic at least). We will make some simplifying
assumptions. The first is we will limit our scope to handling non-negative numbers in the range
00000 to OXxFFFF.
INSTRUCTIONS REQUIRED
MNEMONIC DESCRIPTION
ADDLW Add literal to W
ADDWE = Add W and £
SUBLW Subtract W from literal (not literal from W as name
suggests!)
SUBWF Subtract W from £
RLF Rotate bits in selected register one position to
left.
Bits rotate through carry flag.
RRF Rotate bits in selected register one position to
right.
Bits rotate through carry flag.
The PIC16 treats all 8-bit numbers as though they are non-negative numbers in the range 0-255.
‘Negative numbers may be dealt with using 2's complement arithmetic, but that is beyond the
scope of this book. Serious two-byte or double precision arithmetic is beyond the scope of this
book as 2's complement arithmetic is required. We will do some simpler math and the result will
be that you will know enough to be able to create some very useful microcontroller systems.
For 8-bit addition (non-negative values in the range 0-255):
Carry flag indicates whether or not the result fits in
8 bits.
Cleared to 0 Result fits in 8 bits
Set to 1 Result is larger than @ bits
200For 8-bit subtraction (non-negative numbers in the range 0-255):
Carry flag indicates whether the result is non-negative
or negative.
set to 1 Non-negative (in the range 0-255)
Cleared to 0 Negative
‘Note that the carry flag isn't really a carry flag.
ARITHMETIC
Addition
‘Two single bytes may be added in two ways, add a literal to the W register contents or add the W
register contents to the contents of a selected register (result in W or f).
addlw 0x01 ;add 0x01 to W
addwi temp,£ add W to temp register
Examples of addition:
0x05 0x01 0x02 0x03 Oxftft
Plus 0x01 Oxfe Oxfe Oxfe x01
Result 0x06 Oxfft 0x00 0x01 0x00
carry flag 0 0 1 1 1
If the sum of the numbers is greater than OxFF, an overflow will occur and the carry flag will be
set to "1", We will see what to do if an overflow occurs later.
Subtraction
‘Two single bytes may be subtracted in two ways, subtract the contents of the W register from a
literal or subtract the W register contents from the contents of a selected register (result in W or
fe
If the subtraction clears the carry flag, the byte in the W register was larger than the byte it was
subtracted from.
sublw Ox-- — subtract W from literal
subwf hold,f ;subtract W from hold register
201Examples of subtraction:
0x05 0x05 Ox05,
Minus 0x06 0x05. 0x04
Result Oxf 0x00 0x01
carry flag 0 1 1
Result negative Result non-negative
Multiplication
Multiplication of a single byte by 2 is accomplished by using the rotate left 1 bit instruction
(RLF). Bit 7 is moved into the carry flag when the instruction is executed. The carry flag
contents is moved into bit 0 at the same time.
é iMMMMAAAA
} CU
Carry
Flag
Since the carry flag will be in an unknown state (garbage) prior to the rotate operation, we must
clear the carry flag first (clear bit 0 in the status register). To see how this works:
status equ 0x03_—«—= status word register
ce eq (0 rbit 0 is carry flag
mult equ Ox0c._—= file register used for multiplication
bef —status,c_ ;clear carry flag
rif mult,f ;rotate bits left, result in mult
The contents of the file register labeled “mult” are, thus, multiplied by 2. Simple!
In binary, we can only multiply by 2 directly. One way to multiply a number by 10 is to
multiply by 2 three times and add the original number multiplied by 2 to the result.
N N = Number
N
202As an example, we will devise a subroutine which will multiply a single byte binary number by
10 (decimal) and store the result. The subroutine must do the following:
Get Number
¥
‘Store Copy Of Number
¥
Multiply Numberx@ | RLF3Times
aa
‘Store Copy OF 8N
¥
Mutily Copy Of
Number x2
__-
‘Add 2N+ BN = 10N.
[Laan |
Return
Note that some of the math program examples are designed to display a result via LEDs at port
B, Some example programs have no means for display (but could be easily modified) as they
were tested using the simulator in MPLAB.
-ICM2 . ASM=====-
multiply by decimal 10 demo
jaseewnnann=3/26/97==
ist — pe16e84
radix hex
, cpu equates (memory map)
status equ 0x03
portb equ 0x06
test_n equ 0x0c
math equ Ox0d.
copy_8xn equ 0x0e
: bit equates
e em 0
org 0x00
start moviw 0x00 Hload w with 0x00
tris port reopy w tristate, port B outputs
203moviw 0x03 stest nunber
call decx10 ito sub
movwf — portb idisplay status via LED's
circle goto circle done
yenter sub with number in w - exit with result in w
decx10 movwf test_n ysave copy of test number
movwf math jworking register
bef — status,c_ clear carry flag
rif math, £ 3x2,
bef status,c—;clear carry flag
rlé math, $32
bef status, lear carry flag
1g math, £ x2
movf math, w iget copy of Bxn
movwf copy_8xn store copy of Bxn
movf test_n,w get copy of a
movwf math
bef status,e —;clear carry flag
rlf math, £ 22
movf math, get copy of 2
addwé — copy_8xn, ;add 2n and 8n
return presult in w
end
jat blast time, select:
: memory unprotected
watchdog timer disabled (default is enabled)
standard crystal (using 4 Miz osc for test)
power-up timer on
DOUBLE PRECISION
What happens if the numbers we need to use are larger than one byte = OxFF = 256 decimal?
We use two or more bytes to represent the number and make use of the carry flag to let the lower
byte overflow into the higher byte,
We will use two bytes in our examples which is enough to represent 0 to 65,535 decimal.
Arithmetic using two bytes is called double precision arithmetic and we will need double
precision addition, subtraction and multiplication techniques for use in our decimal interface.
Double Precision Addition
Double precision addition is accomplished by adding the two least significant bytes followed by
adding the two most significant bytes. If there is a carry resulting from the addition of the least
significant bytes, it will be carried into the most significant byte addition process.
204‘To demonstrate this, we can use the following routine to add the contents of Isb1 and msb1 into
Isb2 and msb;
‘Add LSB's
Ine MSB2
‘Add MSB's
cpu equates (memory map)
status equ 0x03
portb equ 0x06
lsbl equ 0x0
msbi equ Ox0d
1sb2 equ Oxte
msb2 equ (Oxf
; bit equates
ce eq 0
org 0x00
start moviw 0x00 sload w with 0x00
trie portb copy w tristate, port B outputs
moviw Oxff itest number
movw£ 1sbl
movlw 0x00 itest number
movwf msbl
movlw 0x02 stest number
movwf — 1sb2
movlw 0x00 stest number
movwf —msb2
call dbiplus ;to double precision addition
mové —msb2,w get _msb2
movwf — portb idisplay msb2 via LEDs
205circle goto circle
@biplus movf —Isbl,w sfetch 1sb2
addwf — 1sb2,£ yadd low bytes, result in 1sb2
btfsc status,c —;carry set?
inct msb2,f syes, add 1 to msb result
mové —msbl,w ;fetch msb1
addwf — msb2,f yada high bytes, result in meb2
return
end
at blast time, select
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal (using 4 MHz ose for test)
power-up timer on
‘You can run this program in the MPLAB simulator, Open a watch window showing status, Isb1,
msb1,Jsb2, and msb2. Change the test numbers, run the program and check the results.
Double Precision Subtraction
Our (limited) objective for double precision subtraction is to be able to:
+ Subtract a smaller number from a larger one.
+ Subtract a larger number from a smaller one and know that that is
the case, discard the result and take some action.
In our example, we will subtract the bytes labeled "1" (je. Isbl) from the bytes labeled "2",
sem=PICMA , ASHennnennnnennnene:
idouble precision subtraction demo
=6/23/9T==
List — pe16£04
radix hex
3 cpu equates (memory map)
status equ 0x03
portb equ 0x06
isbl equ Ox0e
msbl equ Ox0d.
isb2 equ Oxde
msb2 equ —Ox0f
bit equates
ce equ 0
org 0x00
206start moviw 0x00 pload w with 0x00
tris portb icopy w tristate, port B
: outputs
movlw 0x02. ;test number
mowwf 1sbl
moviw 0x00 jtest number
movwf —msbl
moviw Oxéf jtest number
movwf — 1sb2
moviw Oxff stest number
movw£ —msb2
call dbisub ito double precision subtraction
movf status, jet status to ck carry flag
movwf portb idisplay status via LEDs
circle goto circle done
@blaub movf — 1sbl,w i fetch 1sbi
subwf — 1sb2,f£ ubt low bytes, result in 1sb2
btfss status,c carry clear?
decf — msb2,£ byes, subtract 1 from msb2
movf — msbl,w ;fetch msbl
subwé msb2,f isub high bytes, result in msb2
return
end
yat blast time, select
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal (using 4 Miz osc for test)
power-up timer on
Double Precision Multiplication
Double precision multiplication is carried out by shifting the low byte left RLF) which moves
the most significant bit into the carry flag followed by shifting the high byte left (RLF) which
‘moves the carry flag contents into the least significant bit of the high byte.
Multiply (2-byte)
Clear carry flag
Use RLF (low byte) first
Use RLF (high byte) next
Fao’ | |
Low ay
mur
ra TT
High Byte 207First, the carry flag is cleared. Using RLF multiplies the low byte by 2 and moves the most
significant bit into the carry flag. It also moves the "0" from the carry flag into the low byte
least significant position. Using RLF on the high byte multiplies it by 2 and moves the contents
of the carry flag (which was the most significant bit in the low byte) into the high byte least,
significant bit position.
To test this concept:
-PICMS .ASM
list — p=16f84
radix hex
cpu equates (memory map)
status equ 0x03
portb equ 0x06
lobyte equ —0x0e
nibyte equ —0x0d.
: bit equates
e era 00)
org 0x00
start moviw 0x00 sload w with 0x00
tris portb scopy w tristate, port B outputs
moviw Ox££ jtest number
movw£ lobyte
moviw 0x00 jtest number
movw£ hibyte
call dblmult sto double precision mult
mové hibyte,w jet_hibyte
movw£ port splay hibyte via LED's
circle goto circle done
dblmult bef —status,c clear carry flag
rif lobyte,f — rotate low byte
rif hibyte,f rotate high byte
return
end
jat blast time, selec!
memory unprotected
3 watchdog timer disabled (default is enabled)
standard crystal (using 4 MHz ose for test)
: power-up timer on
208SUBROUTINE WHICH MULTIPLIES A 2-BYTE BINARY NUMBER BY DECIMAL 10
(For Use In Decimal Interface)
‘Store Copy Of Number
¥
Multiply Number x2
+
x2 Again
¥
'Adé Original Number To
Result
¥
New Rasutx2
[eetenet
Return
[(vx2x2) + N]x2 = 10N
This could have been done using:
=x4
2x5
=x10
209J RORSeeePICMG ASM==e=aaenne
imaltiply 2-byte binary by 10 decimal
List
radix
pei6ee4
hex
3/27] 97==
status
porth
lobyte
hibyte
copylo
copyhi
cpu equates (memory map)
circle
decmult
contin
equ 0x03
equ (0x06
equ 0x0
equ Ox0d
equ (Oxde
equ (Ox0f
bit equates
equ = (0
org 0x00
movlw 0x00
tris portb
movlw 0x02
movwf — lobyte
movlw 0x00
movw£ hibyte
call decmult
movf hibyte,w
movw£ — portb
goto circle
movf lobyte,w
movw£ — copylo
mové hibyte,w
movw£ — copyhi
bef status,
lf lobyte,£
rlf —hibyte,£
bef — status,
rif lobyte,£
rig hibyte,£
movf —_copylo,w
addwf — lobyte, £
btfss status,c
goto contin
incf hibyte,£
movf —copyhi,w
addwf —hibyte,f
bef —status,c
rif lobyte,£
rif hibyte,£
return
sload w with 0x00
ieopy w tristate, port B outputs
;test number
;test number
;to 2-byte binary x 10 dec
iget hibyte
idisplay hibyte via LED's
:done
iget low byte
istore copy
iget high byte
istore copy
lear carry flag
irotate low byte
irotate high byte
iclear carry flag
irotate low byte
jrotate high byte
ifetch low byte
jadd low bytes
yearry set?
continue
es, add 1 to hi byte
;fetch high byte
yadd high bytes
pelear carry flag
frotate low byte
protate high byte
210
endjat blast time, select
? memory unprotected
; watchdog timer disabled (default is enabled)
7 standard crystal (using 4 MHz osc for test)
: power-up timer on
8-BIT X 8-BIT MULTIPLY, 2-BYTE RESULT
‘An explanation of how this routine works is alittle beyond the scope of this book, so we'll save
that for another time. ‘The numbers to be multiplied reside in the registers "number" and
“multby".
emannennaa=6/24/9T==
joomsee=PICMS .ASH==:
;8-bit multiplication, 2-byte result demo
list p=16£84
radix hex
i cpu equates (memory map)
status equ 0x03
porth equ 0x06
lobyte equ 0x0c
hibyte equ 0x0d
number equ 0x0e
multby equ 0x0f.
bit equates
ce eq 0
org 0x00
start moviw 0x00 pload w with 0x00
tris portb icopy w tristate, port B outputs
movlw 0x02 itest number
movwf number
movlw 0x05 itest number
movwf multby
call sglmult ito 8x8 multiply
movf hibyte,w get hibyte
movwf — portb idisplay hibyte via LED's
circle goto circle done
sgimult clrf — lobyte
clzf —hibyte
movf number,w ;get number to be multiplied into W
bef —status,c —;clear carry flag
btfse multby,0 — ;bit 0
addwf —hibyte,£
rrf_hibyte,£
xrf__lobyte,f
aitbtfse multby,1 — sbit 1
addwf — nibyte, £
rf hibyte,£
zrf _—_lobyte,£
btfse multby,2 ;bit 2
addwf hibyte,£
ref hibyte,f
rf lobyte,£
btfsc multby,3 ;bit 3
addwf hibyte,f
zrf — hibyte,f
zrf _lobyte,f
btfsc multby,4 —;bit 4
addw£ hibyte,f
rf hibyte,#
rf lobyte,#
btfse multby,5 —sbit 5
addwé hibyte,f
rf hibyte,f
rf lobyte,f
btfsc multby,6 sit 6
addwe hibyte,f
ref hibyte,f
rrf lobyte,f
befse multby,7 —;bit 7
addwf hibyte,£
zré—hibyte,£
zrf —_lobyte,f
return
end
jat blast time, select:
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal (using 4 MHz osc for test)
; Power-up timer on
212DECIMAL INTERFACE
People think in decimal and microcontrollers operate in binary. For control applications,
‘operator inputs (temperature, pressure, flow rate, etc.) are in decimal form, usually entered via a
keypad. Decimal to binary conversion is necessary. Conversely, operating parameters must be
converted from binary to decimal for display. The purpose of this project is to develop the
software to make these conversions.
3-DIGIT DECIMAL TO 8-BIT BINARY
‘The program does some setup and then gets each digit in succession, multiplies by its decimal
‘weight (in binary) and adds it to a register which accumulates the total value of the number. The
first digit entered is the 100's place digit so it is multiplied by 100 and added to the addition
register named "numsum”. The second digit entered is multiplied by 10, and so on, until the
binary equivalent of the number has been assembled in the numsum location.
n
C— x 1008
x10=
Binary Sum =
213Blanks in Display RAM
ae
‘Scan 10 Subroutine
¥
‘Save Copy
.
Blank To Display RAM
0x20
‘Add To numsum
¥
Convert To ASCH
¥
‘ASCII To Display RAM
‘Scan 10 Subroutine
= ea
‘Save Copy
Ye
‘Second Digit = 07
No Yes
MS Digit Flag Set?
Set MS Digit Flag
y* OTo Display RAM 0x21
x10 Blank To Display RAM
7 0x21
‘Add To numsun
‘Convert To ASCII
[gone]
‘ASCII To Display RAM
¢——$_4§—_______
v
Erte
214ECENTRY . ASH=
list p=16£84
radix hex
wenaannnannannn 6/14/97
cpu equates (memory map)
tmr0 equ (Ox01
status equ 0x03
porta equ 0x05
porth equ 0x06
intcon equ 0x0b
sendreg equ Ox0c
count equ —Ox0d
instr equ Ox0e
char equ (Ox0f
addr equ (x10
digetr equ Oxi
rowctr equ Oxi2
colctr equ 0x13
rowbits equ 0x14
colbits equ 0x15
temp equ 0x16
ncount equ 0x17
meount equ 0x18
test_n equ 0x19
math equ Oxia
copy_8xn equ Ox1b
numsum equ Oxlc
und = equ (Ox
ven equ Oxle
hold equ Oxi
flags equ 0x20
optreg equ 0x81
trisa equ 0x85
trisb equ 0x86
bit equates
e equ 0
z equ 2
Bo co Gh
org 0x00
start bsf _—status,rp0_ switch to bank 1
movlw "00000000" ;port A outputs
movwi trisa
movlw '01110000" ;port B inputs/outputs
movwf trisb
bef status, rp0 ;switch back to bank 0
bsf —_porta,1 poutput mark, bit 1 (serial - LCD)
bsf —_—portb, 0 prows high
sf _portb,1
bsf —_—portb,2
bsf —portb,3
bef —portb,7 junused line low
215do100
do10
216
call
call,
moviw
movwt
call
call
novlw
movwt
call
call
clrt
ested
call
move
movwt
sublw
btfsc
goto
bst
mové
call
call
addwe
move
call
movwe
movlw
movwE
movlw
movwt
call,
call,
call.
move
movw£
sublw
btfsc
goto
move
call
add
move,
call
movwt
movlw
movwe
movlw
movwt
call
call
call
move
addwe
call,
novw£
movlw
debounce
debounce
0x00
instr
endstf
debounce
0x01
instr
sndsté
debounce
flags
seanl0
digetr,w
und
0x00
status, 2
hzero
Flags, 0
hund, w
decx10
decx10
numsun, £
hund, w
hex2ase
char
0x20
addr
0x03
instr
andstt
debounce
scant
digctr, w
ten
0x00
status,z
tzero
ten,w
deox10
numsum, £
ten,w
hex2ase
char
ow21
addr
0x03
instr
ondstt
debounce
seani0
digetr,w
nunsum, £
hex2asc
char
0x22
sblanks to display RAM
isend instruction to LCD module
jsend 16 characters to display
jsend instruction to LCD module
selean out
get 100's digit
ssave copy
yeompare ~ digi
syes
ino, this is ms digit
imes 10
ptimes 10, result = x100
fadd 100's to num sum register
jet 100's digit
reonvert binary digit to ascii
idisplay RAM address
jascii char follows, send to display RAM
;send 100's digit to display RAM
ptime delay - debounce switches
iget 10's digit
ysave copy
peompare - digit=0?
tyes
itimes 10
jadd 10's to num sum register
iget 10's digit
iconvert binary digit to ascii
splay RAM address
sascii char follows, send to display RAM.
isend 10's digit to display RAM
itime delay - debounce switches
et Ita digit
padd 1's to num sum register
ieonvert binary digit to ascii
splay RAM addressmovwé addr
movlw 0x03 jascii char follows, send to display RAM
movwf instr
call sndstf isend 1's digit to display RAM
call debounce
send moviw 0x01 pend 16 characters to display
movwf instr
call sndstf ito LCD module
call debounce
;display numsum contents
movf numsum,w get total
movwf char
movlw 0x04 ihex byte follows, convert and display
movwf instr
call sndst£
circle goto circle done
zero movlw 0x20 paseii blank
movw£ char
movlw 0x20 idisplay RAM address
movwf addr
movlw 0x03 jascii character to display RAM
movwf instr
call andsté
call debounce
goto doi0
tzero btfsc flags,0 —;ms digit entered?
goto zerot syes
movlw 0x20 pascii blank
tehar movwf char
moviw 0x21 idisplay RAM address
movwf addr
movlw 0x03 jascii character to display RAM
movwf instr
call sndstf
call debounce
goto dol
zerot moviw 0x30 pascii 0
goto tchar
returns with digit in digctr
scanl0 bsf —_portb,0 jrows high
bs portby1
sf —portb,2
bsf —_portb,3
clrf — digetr idigit counter=0
bef —portb,3__;row=4
btfss portb,5 — test column 2
return 20" key press
bst — portb,3. deselect row 4
movlw 0x01
mowwf — digctr digit counter=1
movwf — rowctr row counter=1
movw£ rowbits frow bits = 0000 0001
217rowout,
tstcol
laste
laste
movt
xorlw
movwé
moviw
movwt
movlw
movwt
move
andlw
movwt
movt
xorlw
subwe,
btfsc
return
move
sublw
btfsc
goto
rig
bet
inct
inef
goto
novf
sublw
btfsc
goto
zit
bet
incf,
ince
goto
rowbits,w
oxot
portb
0x01
coletr
ox10
coibits
portb,¥
0x70
temp
colbite,¥
0x70
temp, w
status, 2
coletr,
0x03,
status, z
laste
colbits,£
colbits, 0
colctr,£
digetr, £
tstcol
rowotr,
0x03
status, z
scani0
rowbits, £
rowbite,0
rowctr,£
digctr, £
rowout,
iget row bits
pcomplement row bits
routput row bits
seolum counter=1
70001 0000
#00!
ixead port B
ymask off rows and bit 7
?eolumns
get column bits
reomplement column bits
icompare with contents of temp
fdigit available
get column count
32
rshift column bits
;fix carry flag garbage
get row count
32
pecan 10 digit keys again
pehift row bits
ix carry flag garbage
debounce moviw
bloop
loadn
deca
movwt
novlw
movwe
movlw
movwE
dectsz
goto
dectsz
goto
decfaz
goto
return
0x02
count
Oxee
meount
Oxee
acount
acount, £
deca
mount, £
load
count,
dbloop
ito counter
™
ito M counter
in
ito N counter
idecrement N
fagain
idecrement M
jagain
ithru loop within a loop twice -
400 milliseconds
done
218
move
movwe
call
nov
movwe
call
mov
instr,w
sendreg
ser_out
char,w
sendreg
ser_out,
addz,w
iget instruction
0 be sent
0 Serial out subroutine
jet character or hex byte
0 be sent
0 serial out subroutine
iget addressmovwf — sendreg to be sent
call ser_out ito serial out subroutine
return
sez_out bef —intcon,5 disable tmr0 interrupts
bef intcon,7? —;disable global interrupts
clrf — tmr0 pelear timer/counter
elrudt pelear wdt prep prescaler assign
bsf —status,rp0_ to page 1
moviw b'11011000' ;set up timer/counter
movw£ — optreg
bef status, rp0 ;back to page 0
movie 0x08 sinit shift counter
movw£ count.
bef porta, 1 start bit
clrf — tmr0 istart timer/counter
bef intcon,2-;clear tmr0 overflow flag
timel btfss intcon,2 timer overflow?
goto timel ino
bef intcon,2—syes, clear overflow flag
axtbit rlf sendreg,f ;rotate msb into carry flag
bef — porta, 1 ielear port A, bit 1
btfsc atatus,c test carry flag
bst porta, 1 pbit is set
time2 btfss intcon,2 — ;timer overflow?
goto time2 ino
bef —intcon,2 clear overflow flag
decfsz count,f shifted 8?
goto axtbit ino
bs£ —porta,1_— yes, output_ mark
time3 btfss intcon,2 timer overflow?
goto timed imo
return #done
yenter sub with number in w - exit with result in w
decx10 movwf test_n ieave copy of test number
movwf math iworking register
bef status,c —;clear carry flag
rif math, 2x2
bef —status,c clear carry flag
rif math, f 2x2,
bef —status,c clear carry flag
rig math, £ px
movf —math,w get copy of 8xn
movw£ copy 8xn store copy of 8xn
movf test_n,w —;get_copy of n
movwf math
bef —status,c clear carry flag
rif math, f 7x2
movf math, iget copy of 2n
addwf copy 8xn,w ;add 2n and 8n
return fresult in w
219yenter with hex digit in w
hex2asc moww£ hold istore copy of hex digit
sublw 0x09 psubtract w from 1 less than 0x0a
btfss status,c —;carry flag set if w < 0x0a
goto add37
goto ada30
add37movf hold, w iget hex digit
addlw 0x37
return ireturn with ascii in w
ada30 mové —hold,w iget hex digit
addlw 0x30
return return with ascii in w
end
at blast time, selec
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal (using 4 MHz ose for test) XT
power-up timer on
USING THE 3-DIGIT DECIMAL TO 8-BIT BINARY DECIMAL ENTRY PROGRAM
"4 ON A BOARD PiciLeD
RA1 +-—B RAO
1D RO
Port B L
7
KEYPAD BOARD
: [fe]
5 |6
8 |9
oje
220+ Power up the PIC84 and PIC/LCD boards
+ Key in 3 digits (including leading zeros)
+ 0- must key in 3 zeros
+ Range of numbers is 0 to 255.
‘The resulting number will be in "numsum" and will be displayed on completion of the time
delay ("debounce").
Examples:
Decimal numsun
000 0x00
015 Ox0F
016 x10
127 Ox7E
128 0x80
255 OxEE
‘The resulting number may be loaded into a counter or used for set point comparison or whatever.
8-BIT BINARY TO 3-DIGIT BCD
‘The magnitude of an unknown 3 digit decimal number can be determined by successive subtrac-
tions. First we test to see how many 100's the number contains. We count the number of times
100 can be subtracted without getting a negative result (subtracting too much). Actually, we will
keep subtracting until we have done it one too many times (as determined by testing the carry
flag) and then add 100 back into the number. The actual number of subtractions equals the 100's
place decimal digit.
Next, we take the remainder and subtract 10 at a time until we have gone too far, add 10 back in
and now we have the 10's place digit.
The 1's place can be displayed directly. As we go along, we will complete the testing for each
decimal place and test 1 see if the remainder is 0. If itis, the remaining digits are O's.
‘The decimal interface program makes use of looping and relative addressing. The index or
offset is used to access a lookup table containing the binary equivalents of 100 and 10. The
same index is used to address another table which is used to store the decimal digits as they are
calculated.
‘The "index" file register is used to develop the offset or index for the two tables. A file register
is used as a counter to count subtractions. The number of subtractions of a given value equals
the corresponding decimal digit. Thus, the file register is the digit counter.
221222
Store Copy Of Number
a
Initialize Registers
aaaeryeeees
Got Chunk" For
‘Subtraction
| fini
GOTO inedig
fin
Ine Digit Countor
Store Digit Count 7
l
(Get Chunk" For
‘Add-Back
‘Add Back
ee Ine Digt Index
‘Store Remainder At one ¥
v Cloar Digit Counterma=-BINZDEC .ASMoensannmennnaanmnnnnnen==6/25/97:
list p=16£84
radix hex
indt
pe
status
fer
number
index
dig ctr
und
ten
one
start
circle
cpu equates (memory map)
equ 0x00
equ 0x02
equ 0x03
equ 0x04
equ (0x0
equ (Ox0d
equ (Ox0e
equ (0x20
equ (0x21
equ 0x22
bit equates
org 0x00
moviw 0x80 idefine test number
call bin2dec — call conversion subroutine
goto circle idone
addwf pe, jadd index to program counter
retlw 0x64 7100 decimar
retlw 0x0a 10 decimal
subtr
movwf number pstore copy of number
clrf hun
clrf ten
clrf one
clrf index
clrf dig _ctr
movf index,w © ;get current index into W
call table tget chunk for subtraction
subwf number,f test
btfsc status,c —;test carry flag
goto incdig
moviw 0x20 pload base address of table
mowwf fs
movf index, w jet index
addwf fer jadd offset
movf dig _ctr,w get digit counter contents
movwf indf istore at digit loc (indexed)
movf index,w ;get_ index
call table iget chunk for addition
addwf number padd back
movf index,w get index
sublw 0x01 pindexe1?
btfsc status,z
223goto finish
incf index sincrement digit index
clrt — dig_ctr
goto subtr
incdig incf dig ctr _—; increment digit counter
goto subtr
finish mové number,w get 1's=remainder
movwE one
return
end
at blast time, select
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal (using 4 MHz ose for test)
power-up timer on
DISPLAY RESULT OF &-BIT BINARY TO 3-DIGIT BCD
* Binary to decimal sub
Results in hund, ten, one registers
+ Leading zeros blanks
+ Uses indexed/indirect addressing
+ Range 0x00 to Oxff 0 to 255 decimal
224No ‘Sond Blank First Dig
tonzero
Ye
‘Second Digit 07
No ‘Send Blank Second
Digit
Do 1/10
[eve
Decimal Point
ye
‘Send 16 Characters To
Display
6/27/9
7 BINLCD .ASM======"
List — p=16£84
radix hex
7 cpu equates (memory map)
indf equ 0x00
tmr0 equ (x02
pe equ 0x02
status equ 0x03
fsx equ 0x04
porta equ 0x05
intcon equ 0x0b
sendreg equ 0x0c
count equ Ox0d
instr equ 0x0e
char equ Oxf
addr equ (x10
number equ 0x12
index equ 0x13
digctr equ Oxl4
ncount equ 0x15
225meount
hold
hund
ten
optreg
zcheck
do100
do10
226
equ Ox16
equ = 0x17
equ 0x20
equ 0x21
equ 0x22
equ 0x81
equ 0x85
bit equates
eq (O
org
bot
moviw
moet
bef
bet
call
call,
movlw
movw£
call
call
movlw
move
call
call,
novlw
call
movi
sublw
btfse
goto.
move
call
movwt
movlw
movwt
movlw
movwt
call,
call
move
call
nowt
movlw
movwé
movlw
novwt
call
call
0x00
status, rp0
"00000000"
trisa
status, rp0
porta,1
debounce
debounce
0x00
instr
sndsté
debounce
0x01
instr
sndst£
debounce
oxor
bin2dec
hund,w
x00
status, 2
hzero
hund, w
hex2ase
char
0x20
addr
0x03
instr
endsté
debounce
ten,
hex2ase
char
x21
addz
0x03
instr
sndstf
debounce
sowitch to bank 1
ort A outputs
iswitch back to bank 0
output mark, bit 1 (serial - LcD)
yblanks to display RAM
isend instruction to LCD module
isend 16 characters to display
yeend instruction te LCD module
idefine test number
feall conversion subroutine
iget 100's digit
peompare - digit=0?
yes
get 100's digit
iconvert binary digit to ascii
idisplay RAM address
jascii char follows, send to display RAM
isend 100's digit to display RAM
itime delay
iget 10's digit
peonvert binary digit to ascii
idisplay RAM address
yascii char follows, send to display RAM
isend 10's digit to display RAM
itime delaydol movf—one,w get 1's digit
call hex2ase convert binary digit to ascii
movwf char
moviw 0x22 jdisplay RAM address
mowwE addr
moviw 0x03 jascii char follows, send to display RAM
movwE instr
call sndstf send 1's digit to display RAM
call debounce time delay
send movlw 0x01 pend 16 characters to display
movwf instr
call sndstf ito LED module
circle goto circle idone
hzero moviw 0x20 pascii blank
movwf char
movlw 0x20
movwE addr
movlw 0x03 jaseii character to display RAM
movw£ instr
call sndstf
isplay RAM address
call — debounce
movf ten,w fget 10's digit
sublw 0x00 icompare - digit=07
btfss status,z
goto dol0
tzero moviw 0x20 pascii blank
movwf char
moviw 0x21
movw£ addr
splay RAM address
moviw 0x03 pascii character to display RAM
movwf instr
call sndsté
call debounce
goto dol
table addwf pc, £ jadd index to program counter
retlw 0x64 #100 decima1
retlw 0x0a #10 decimal
bin2dec movwf number istore copy of number
clrf hun
clrf ten
clrf one
elr£f index
clrf dig ctr
subtr mové index,w get. current index into W
call table pget chunk for subtraction
subwf number,f test
btfsc status,
goto incdig
movlw 0x20 jload base address of table
est carry flag
227iget index
padd offset
iget digit counter contents
istore at digit loc (indexed)
get. index
rget chunk for addition
yadd back
iget. index
ndex=1?
sincrement digit index
sincrement digit counter
mow fer
movf index, w
addwf fer
movf dig_ctz,w
movw£ indf
movf index, w
call table
addvf number
movf index,w
sublw 0x01
btfsc status, 2
goto finish
incf index
clrf dig ctr
goto subtr
incdig incf dig_ctr
goto subtr
finish movf — number,w
movwf one.
return
iget 1's=remainder
ito counter
™
ito M counter
iN
ito N counter
idecrement N
again
idecrement M
pagain
ithru loop within a loop twice -
400 milliseconds
idone
debounce moviw 0x02
movwf count
dbloop movlw Oxff
movwf — mcount
loadn movlw Oxét
movw£ — neount
decn decfsz_ncount,£
goto decn
decfsz mcount, £
goto loadn
dectsz count
goto dbloop
return
andst£ mové — instr,w
movwf — sendreg
call ser_out
movf char, w
movwf — sendreg
call ser_out
mové — addr,w
movwf — sendreg
call ser_out
return
ser_out intcon,$
bef intcon,7
clef — tmr0
elrwde,
bef status, xp0
228
get instruction
sto be sent
;to serial out subroutine
iget character or hex byte
ito be sent
to serial out subroutine
iget address
ito be sent
sto serial out subroutine
disable tmr0 interrupts
idisable global interrupts
selear timer/counter
ielear wdt prep prescaler assign
ito page 1movlw 111011000" ;set up timer/counter
movw£ optreg
bef status, rp0 back to page 0
movlw 0x08 pinit shift counter
movw£ count
bef —porta,i_— start bit
clzf — tmr0 tart timer/counter
bef intcon,2—;clear tmr0 overflow flag
timel btfss intcon,2 timer overflow?
goto time ino
bef intcon,2 yes, clear overflow flag
nxtbit rlé sendreg,£ rotate msb into carry flag
bef porta, 1 iclear port a, bit 1
btfsc status,c est carry flag
bs porta,1 it is set
time2 btfss intcon,2 timer overflow?
goto timez tno
bef intcon,2 lear overflow flag
dectsz count, f ishifted 8?
goto nxtbit ino
bsf —porta,1 ryes, output mark
time3 btfss intcon,2 timer overflow?
goto time}
return
enter with hex digit in w
hex2asc movwf hold istore copy of hex digit
sublw 0x09 yubtract w from 1 less than Ox0a
btfss status,c —;carry flag set if w < 0x0a
goto ada37
goto add30
add37 movf hold, w iget hex digit
addiw 0x37
return preturn with ascii in w
add30 movf hold, w iget hex digit
addiw 0x30
return preturn with ascii in w
end
at blast time, selec
? memory unprotected
: watchdog timer disabled (default is enabled)
: standard crystal (using 4 MHz ose for test) xT
power-up timer on
22916-BIT BINARY TO 5-DIGIT BCD - Range 0x0000 To Ox7FFF
This routine uses the simple but limited capability math described in the math chapter. It will
handle 16-bit non-negative numbers in the range 0x0000 to Ox7FFF.
Short (much) more elegant routines are available to do this including one in Microchip's
"Embedded Control Handbook". I am including this routine so you can see and try one that you
can understand at this point in your learning experience. The neat short routines are based on
some esoteric math which may (or may not) be beyond you. This is also true of the routine in
the next section.
‘Store Copy Of Number
Initialize Registers
¥
Got "Chunks" For
‘Subtraction
=
2-Byte Subtraction Via
‘Subroutine
yy
Ine Digit Counter
Store Digit Count
(Get "Chunks" For
Add-Back
¥
2-Byte Add Via Sub
fini Inc Digit Index
‘Store Remainder At one ¥
t Clear Digit Counter
Return
230faccepts 0x0000 through 7£ff - 0 through 32767
List pe16£84
radix hex
f cpu equates (memory map)
indf equ 0x00
pe equ 0x02
status equ 0x03
for equ (x04
ms equ Ox0c
1s equ = 0x0d
index equ Ox0e
dig ctr equ Ox0f
sbi equ 0x10
msbl equ Oxi
sb2 equ (Oxi2
msb2 equ (0x13
tenk equ 0x20
onek equ Ox21
und equ 0x22
ten equ 0x23
one = equ Ox24
z bit equates
org 0x00
start moviw Ox7£ idefine test nunber MS byte
mow ms
movlw Oxff idefine test number LS byte
mowwf 1s
iprep for calling conversion subroutine
movf ms, iget MS byte
movwf — msb2
mové 1s, yet LS byte
movwE — 1sb2
call dblb2d reall conversion subroutine
circle goto circle
tbllo addwf pe, £ jadd index to program counter
retlw 0x10 0,000 decimal
retlw 0x8 000 decimal
retlw 0x64 7100 decimal
retlw 0x0a 0 decimal
tbl_hi addwe pe, f dd index to program counter
retlw 0x27 0,000 decimal
retlw 0x03 71,000 decimal
231subtr
retlw
clrt
cle
clrt
elre
cize
cle
clr
move
call
movwt
move
call
movwE
call
betss
goto
movlw
nowt
nov
addweé
move
move
move
call
movwé
mové
call,
novwe
call
movt
sublw
btfse
goto
inet
cle
goto
0x00
0x00
tenk
onek
und
ten
index
dig_etr
index,
tbl_lo
sb
index, w
tbl_ni
sbi
dbisub
msb2,7
incdig
0x20
for
index, w
fsr,f
dig_ctr,w
indz
index, w
tbl_lo
sbi
index, w
tb1_pi
msbi
@biplus
index, w
0x03
status, z
finish
index, €
dig_etr
subtr
7100 decimal
0 decimal
iget current index into Ww
iget 1s chunk for subtraction
iget current index into w
get ms chunk for subtraction
ito double precision subtraction
stest bit 7, 1 means neg result
pload base address of table
iget index
jadd offset
iget digit counter contents
tore at digit loc (indexed)
iget index
jet 1s chunk for addition
index
ms chunk for addition
ito double precision addition
iget index
pindex=3?
sincrement digit index
inet
goto
dig_ctr,£
subtr
pincrement digit counter
move
movwe
return
1sb2,¥
get 1's=remainder
done
dblsub
232
movE
subwe
btfss
deck
move
subwe
return
lsbl,w
1sb2,£
status,c
msb2, £
msbl,w
msb2, f
ifetch 1sb1
ysubt low bytes, result in 1sb2
searry clear?
syes, subtract 1 from msb2
pfetch msb1
;sub high bytes, result in msb2dbiplus movf sbi, w
addwf 1sb2,f jadd low bytes, result in 1sb2
btfsc status,c —;carry set?
incf msb2,£ tyes, add 1 to msb result
movf —msbl,w pfetch msb1
addwf —msb2,£ jadd high bytes, result in msb2
return
end
yat blast time, select:
: memory unprotected
watchdog timer disabled (default is enabled)
standard crystal (using 4 MHz osc for test)
3 Power-up timer on
16-BIT BINARY TO 5-DIGIT BCD - Range 0x0000 To OxFFFF
The following routine is like the previous one except for the double add and double subtract.
routines plus a special purpose flag used to determine whether or not a negative result is
generated in the subtraction process. The double subtraction routine uses 2's complement
arithmetic which will not be explained here (advanced topic). You will have to take the fact that
it works on faith and put the routine to work.
‘The routine has the full 16-bit bit range of 0x0000 to OxFFFF.
233Store Copy Of Number
¥
Initialize Registors
¥
(Get “Chunks” For
Subtraction
=
2-Byte Subtraction Via
‘Subroutine
Clear
Wot <—
wet J sot
GOTO incdig
fa
SereDigt Coun [_wepor coun |
¥
Got “Chunks* For
‘Add-Back
ey
2-Byte Add Via Sub
ile ve Inc Digit Index
Store mainder Atone v
Tv (Cloar Digt Courter
| Return ]
234sn) ————
‘
‘Clear Overtiow Flag
¥
‘2% Comp Of
msb1 and Isbt
Tomsb1 and isb1
pus —4
[sb2 ¢ Isbt To Isb2
‘Set Overflow Flag
‘mab2 + msbt To msb2
Return
235DBLB2DY . ASM====:
127/97 ==
jaccepts 0x0000 through ££ff - 0 through 65535
;dblsub uses 2's comp plus flag
list
radix
pri6es4
hex
: cpu equates (memory map)
indf equ 0x00
pe equ 0x02
status equ 0x03
fsr equ 0x04
ms equ 0x0
1s equ Ox0d
index equ 0x0e
dig_ctr equ Oxf
sb] equ Ox10
msbl equ (Oxi
Isb2 equ 0x2.
msb2 equ (x13
flags equ Oxi4
tenk equ 0x20
onek equ Ox21
hund = equ 0x22
ten equ 0x23
one = equ S(Ox24
: bit equates
e eqa2)
ovflw equ = 0
z eae |
rp0 equ 5
org 0x00
start moviw Oxfa sdefine test number MS byte
movwE me
moviw 0x00 idefine test number Ls byte
movwf 1s
rprep for calling conversion subroutine
movf ms, iget MS byte
movwf — msb2
movf 1s, iget LS byte
movw£ — 1sb2
call dblb2d call conversion subroutine
circle goto circle done
tbl_lo addw£ pe, £ add index to program counter
retlw 0x10 10,000 decimal
retlw Oxed 71,000 decimal
retlw 0x64 7200 decimal
retlw 0x0a 710 decimal
236bli addvf pc, £ jadd index to program counter
retlw 0x27 710,000 decimal
retlw 0x03 71,000 decimal
retlw 0x00 7100 decimal
xetlw 0x00 10 decimal
dblb2d clrf — tenk
clrt — onek
elzf und
clzf ten
clrf one
clrf index
clrf dig ctr
bef flags, ovélw
subtr movf index,w get. current index into W
call tbi_lo pget 1s chunk for subtraction
movwf sbi
movf index,w © ;get current index into W
call tbi_hi get ms chunk for subtraction
movwf msbi
call dblsub ro double precision subtraction
btfse status,c test carry flag
goto incdig
movlw 0x20 jload base address of table
movwf for
movf index,w ;get_ index
addwt far, f jadd offset
movf dig _ctr,w get digit counter contents
movwf — indé store at digit loc (indexed)
mové index, w get index
call tbl_lo
movwf sbi
get 1s chunk for addition
movf index,w ;get_ index
call tbl_hit get ms chunk for addition
movwf msbi.
bef — flags, ovf1w
call dbiplus ito double precision addition
movf index,w get index
sublw 0x03 pindex=3?
btfsc status,z
goto finish
incf index,f increment digit index
clrf dig ctr
goto subtr
incdig incf dig ctr,f increment digit counter
goto subtr
finish mové — 1sb2,w iget 1's=remainder
movwf one
return done
dbleub bef ‘flags, ovflw ;clear overflow flag
comf sbi, £ 32's complement stuff
237dbiplus
bli
blx
comt
mové
addlw
movwt
btfse
inet
move
addwe
btfsc
bst
mové
addwe
btfss
goto
btfse
goto
novlw
addwe
goto
inct
return
msbl,£
Asbi,w
0x01
leb1
status,c
msbl, £
1sbi,w
1sb2,£
status,c
flags, ovflw ;indicate overflow occurred
nsbl,w
msb2,£
flags, ovflw
dbix
status, c
abl
0x02
msb2,£
ablx
msb2, £
jadd low bytes
yadd high bytes
end
pat blast time, select
: memory unprotected
? watchdog timer disabled (default is enabled)
? standard crystal (using 4 MHz osc for test)
: power-up timer on
Hex Decimal tenk nek hund ten one
OXFA0O 64,000 06 04 00 00 00
OXFA22 64,034 06 04 00 03 04
OxOOFF 255 00 00 02 05 05
0x0002 2 00 00 00 00 02
So, what can be done with this stuff? A binary result can be displayed in decimal. A decimal
temperature set point can be entered and converted to binary for comparison with a temperature
brought into the microcontroller through an A to D converter. Humans think and communicate
in decimal. Human numbers must be converted to the processor's language and back again.
238DIGITAL THERMOMETER
BUILDING BLOCKS.
‘The building blocks are are now available to build a digital thermometer with a 0°C to 50°C
range.
+ Temperature sensor - LM335
* Signal conditioning
. (several methods)
+ LCD interface
* Math.
+ Decimal interface
Offset and scaling are done by signal conditioning methods which provide a voltage range of 0
to 5 volts to the input of the A/D converter.
BV
AD Input
Voltage
ov
& Temp." 2
The A/D counts up when it does a conversion. It's binary output represents temperature at
0.196 C*/ count.
0x00 =0°C — 30 =o 196 ©
OxFF = 49.98 °C 255counts count
‘We want to multiply the A/D conversion value by 0.196 °C /count. That can't be done but we
can multiply by 196 and worry about the decimal point later. Here is the plan:
239Measure Temperature
¥
Muttipy By 196
+
Convert To Decimal
¥
Round Off To Nearest
1110 Degree
¥
Supress Leading Zeros
[omen]
Display Temperature
‘To multiply the data by 196, we need to find the hex equivalent.
oxca
{La 4
—~12x16 = 192
196
We will multiply the data by 0xC4 using the 8x8 unsigned multiply, 16-bit result routine
described in the chapter on math routines.
We already know how to convert a binary number to decimal. We will talk now about how to
round off and suppress leading zeros. The decimal point is handled simply by displaying it in
the correct position
240ROUNDING OFF
Once the temperature is in decimal form, it should be rounded off as the measurement is,
accurate to within approximately 0.1 C".
Example: 49.980 50.0
‘We will round off the decimal result to the nearest tenth of a centigrade degree.
A litle thought reveals that the rounding process can ripple back all the way to the most
significant digit (see example above).
‘The round off routine rounds off the two least significant digits. It does not clean up trash left in
their places because that information will not be displayed.
244docrnd
242
¥
—
|
ic
wee k—
| stad
c
aed
:
lL zp
oe
:
| / me
a
}-_—
ReturnJECRND . ASM==
jrounds off two least significant digits of a
digit decimal number
126/97:
pase only hund, onek and tenk in subsequent program as
fone and ten are left as trash
List
radix
pri6£84
hex
: cpu equates (memory map)
status equ 0x03
tenk equ 0x20
onek = equ —(Ox21
und equ 0x22
ten equ x23
one equ (x2
: bit equates
e eq 0
z equ 2
org 0x00
start movlw 0x04 idefine 5 test digits
movw£ — tenk
moviw 0x09
movwf onek
movlw 0x09
movwf hund
moviw 0x08
mowwE ten
movlw 0x00
movw£ one.
call decrnd reall round off subroutine
circle goto circle done
decrnd movf — one,w iget one into W
sublw 0x04 ieubtract W from 4, result in W
btfss status,c
call xndi if carry clear, round
movf ten,w get ten into W
sublw 0x04 isubtract W from 4, result in W
btfss status,
call radio :Af carry clear, round
return
rndl incf ten
mové — ten,w scompare
sublw 0x0a presult 10 decimal?
btfss status,z
return prot 10
clrf ten
endl0 inc —hund
movf —hund,w compare
243sublw 0x0a presult 10 decimal?
btfss status,z
return snot 10
clef hund
inc onek
movf —onek,w scompare
sublw 0x0a fresult 10 decimal?
btfss status,z
return snot 10
clrf — onek
incf tenk
return
end
at blast time, select:
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal (using 4 MHz osc for test)
power-up timer on
DISPLAYING TEMPERATURE VIA A LCD
The next routine suppresses high order zeros as was done in the routine for displaying the result
of 8-bit binary to 3-digit BCD conversion. The decimal point is displayed by sending the ASCIT
equivalent to the proper position in display RAM in the PIC16F84 which controls the LCD.
244No ‘Send Blank First Digit
tenzero
‘Second Digit 07
‘Send Blank Second
Doto Digit
Do 1/0
[se
Decimal Point
¥
‘Sond 16 Characters To
Display
‘=TEMPLCD . ASH:
list — p=16£84
radix hex
: cpu equates (memory map)
tmeo equ (Ox01
status equ 0x03
porta equ 0x05
intcon equ 0x0b
sendreg equ 0x0e
count equ 0x0d
instr equ Ox0e
char equ (Ox0E
addr equ —(Ox10
number equ x12
count equ 0x15
meount equ 0x16
hold = equ Ox17
tenk equ 0x20
onek equ Ox?
und = equ (x22
tens equ 0x25
245tenths
optreg
trisa
equ
equ
equ
equ
0x26
0x27
0x81
0x85
bit equates
equ
equ
equ
°
2
5
setup
zcheck
do10
dot
246
org
bsf
movlw
movwt
bef.
bet
call
call
movlw
movwt
call,
call,
novlw
movw£
call
call
movlw
moat
movlw
movwt
movlw
novwt
mové
movwt
nove
movwt
move,
movwt
movE
sublw
befse
goto
movt
call
nowt
novlw
movwt
movlw
movwE
call
call
movi
call,
0x00
status, xp0
»*00000000"
trisa
status, xp0
porta,1
debounce
debounce
x00
instr
sndstf
debounce
0x02
instr
sndsté
debounce
0x00
tenk
0x05
onek
0x00
hund
tenk,w
tens.
onek,w
hund, w
tenths
tens,
0x00
status, 2
tenzero
tens,w
hex2ase
char
0x20
addr
0x03
instr
sndsté
debounce
hex2ase
iswitch to bank 1
iport A outputs
sswitch back to bank 0
foutput mark, bit 1 (serial - LCD)
Pblanks to display RAM
ssend instruction to LCD module
jsend 16 characters to display
jsend instruction to LCD module
jtest digits
;rename for easier comprehension
;from round off to display
iget 10's digit
scompare - digit=02
iyes
jet 10's digit
peonvert binary digit to ascii
idisplay RAM address
jascii char follows, send to display RAM
ysend 10's digit to display RAM
;time delay
iget 1's digit
reonvert binary digit to asciimovwe
movlw
novwt
moviw
movnt
call
call
doldths movE
call
movwt
movlw
novwt
movlw
movwt
call,
call
decpt moviw
movwt
novlw
movwt
movlw
movwt
call
call,
send movlw
movwt
call
circle goto
char
tenzero movlw
movwt
movlw
movwe
moviw
movwE
call
call
move
sublw
btfss
goto
enezero moviw
movwt
movlw
movwé
movlw
movwt
call
call,
goto
debounce movlw
mowwe
ox21 idisplay RAM address
addr
0x03 jascii char follows, send to display RAM
instr
endsté ysend 1's digit to display RAM
debounce time delay
tenths,w ;get 10ths digit
hex2asc -—«s; convert. binary digit to ascii
char
0x23 idisplay RAM address
add
0x03 jascii char follows, send to display RAM
instr
andstf jeend 10ths digit to display RAM
debounce ;time delay
Ox2e jascii "period", decimal point
char
ox22 sdisplay RAM address
adar
0x03 jascii char follows, send to display RAM
instr
sndsté jsend decimal point to display RAM
debounce time delay
0x02 jsend 16 characters to display
instr
endsté ito LCD module
circle done
0x20 jascii blank
char
0x20 display RAM address
addr
0x03 jascii character to display RAM
instr
endstt
debounce
ones, jet 1's digit
ox00 icompare - digit=0?
status, z
dol £ 0, fall thru to onezero
0x20 pascii blank
char
ox2t ;display RAM address
addr
0x03 yascii character to display RAM
instr
sndstt
debounce
dol0ths
0x02 ito counter
count
247dbloop moviw
movwt
loadn — moviw
movwt
decn decfsz
goto
dectsz
goto
dectsz
goto
return
sndstf mové
novwt
call
move
movwé
call
mové
movwt
call
return
ser_out bef
bet
cle
clrade
bsf
movlw
movwt
bef.
movlw
movwe
bef
clr
bof
time. bt fss
goto
bef.
pxtbit rig
bef
btfsc
bsf
time2 bt és
goto
bet
dectsz
goto
bst
time3 bt fss
goto
return
Oxee
meount
Oxee
Acount,
ncount, £
decn
meount, £
loada
count
dbloop
instr,
sendreg
ser_out
chaz,w
sendreg
ser_out
addz,w
sendzeg
ser_out
intcon, 5
intcon,7
tme0
status, rp0
b*11011000"
optreg
status, rp0
0x08
count
porta,1
tmr0
intcon,2
intcon, 2
timel
intcon,2
sendreg, f
porta,1
status,e
porta,1
intcon, 2
time2
intcon, 2
count, £
axtbit
porta,]
intcon, 2
times
™
ito M counter
aN
sto N counter
idecrement N
pagain
decrement M
pagain
ithru loop within a loop twice ~
400 milliseconds
iget instruction
ito be sent
ito serial out subroutine
jet_ character or hex byte
ito be sent
sto serial out subroutine
pget address
ito be sent
ito serial out subroutine
;disable tmr0 interrupts
isable global interrupts
pelear timer/counter
iclear wdt prep prescaler assign
rto page 1
iset up timer/counter
ack to page 0
sinit shift counter
petart bit
pstart timer/counter
;elear tmr0 overflow flag
imer overflow?
°
iyes, clear overflow flag
jrotate msb into carry flag
pelear port A, bit 1
stest carry flag
pbit is set
itimer overflow?
iclear overflow flag
shifted 82
syes, output mark
itimer overflow?
done
248renter with hex digit in w
hex2asc movwf hold ‘store copy of hex digit
sublw 0x09 isubtract w from 1 less than Ox0a
btfss status,c —;carry flag set if w < Ox0a
goto add37
goto add30
add37 movf —hold,w iget hex digit
addlw 0x37
return rreturn with ascii in w
add30 mové hold, w
addlw 0x30
get hex digit
return preturn with ascii in w
end
jat blast time, select
i ‘memory unprotected
? watchdog timer disabled (default is enabled)
standard crystal (using 4 MHz osc for test) xT
power-up timer on
At last you have the modules to create a 0 to 50° digital thermometer good to one tenth C". 1
Ieave it to you to "PIC" your favorite analog signal conditioning method and integrate the
appropriate routines to create a working system.
Hint: Make sure you include all the equates required for each routine.
You can use the techniques you have learned to create other instruments or applications. You
now know enough to display the binary contents of a counter register for example.
Hmmmmmm..
Have fun "PIC'n Up the Pace!"
249PIC16F84 DATA EEPROM MEMORY
‘The PIC16F84 microcontroller has 64 bytes of data EEPROM which may be read or written to
during program execution. This data memory is in a block completely separate from the
program memory and file registers.
‘The data EEPROM memory may be used to store anything you want. Since EEPROM is
nonvolatile, the data stored there will still be there when the power to the PICI6F84 is turned
back on after being off.
‘The EEPROM data memory has an address range of 0x00 to Ox3F. This address space is
accessed by placing the address in a special register (EEADR) and by passing data back and
forth via another special register (EEDATA).
Data is read or written one byte at a time. A single bit cannot be read or written.
Four special function registers are used to read/write the data EEPROM.
Register Address
EEADR 0x09
EEDATA 0x08
EECON1 0x88
EECON2 0x89
‘The write time is about 10 milliseconds and is controlled by an on-chip timer.
‘Some PICI6F8+4 device programmers can program the data EEPROM memory. If the device is
code-protected, only the CPU may access the data EEPROM.
EEADR
‘The EEADR register is capable of addressing a maximum of 256 locations, but only the first 64
are used. Only 6 of the 8 bits in the register are used. Bits 7 and 6 are not decoded. The usable
address range is 0x00 to Ox3F.
EEDATA
EEDATA is an 8-bit register used to pass data into and out of data EEPROM memory.
250EECON1
ECON is the control register and has the functions shown.
R= Roadablebit
W- Wiiteable bit
'§ = Sattable bi, read as "0"
U-= Unimplemanted bi, read as "0"
Power on reset -- -OX000
wrerr | WwrEN| wR | AD | Oxee
Read control bit
41 = Initiates an EEPROM read
Raoad takes one cycle
RD bit can only be sot
(not cleared in software)
(0= Does not init
| L— WA: Write control bit
1 = Initiates a write cyclo
‘The bitis cloared by hardware
‘once write cycle is complete
WRbit can only be set
(not cleared in software)
(0 =Write cycle to the data EEPROM
is complete
|__ WREN: EEPROM write enablo bit
1 = Allows a write cycle
(= Inhibits write to the data EEPROM
| |__ WRERR: EEPROM orror flag bit
1 = Awrte operation is prematurely
torminatad
Termination resus from any
MCLR reset or from a WOT
reset during normal operation
(= The write operation is completed
EEIF: EEPROM write operation interrupt fag bit
11 = The write operation is completed
(must be cleared in softwaro)
(0 = The write operation is not completed or
‘has not beon started
‘— _ Unimplemented: Read as
RD is cleared in hardware
te an EEPROM‘The RD and WR control bits initiate read and write. ‘These bits can only be set (not cleared) in
software to initiate a read or write cycle. They are cleared automatically by completion of a read
or write cycle.
A waite operation is allowed when the WREN bit is set. WREN is cleared on power-up.
The WRERR bit is set when a write cycle is interrupted by a MCLR reset or a WDT time-out
reset. Following a reset, user software can be written to check the WRERR bit and start the
(interrupted) write cycle over again. The address and data will remain unchanged in the EEADR_
and EEDATA registers.
Note that the EEIF interrupt flag is set on completion of a write cycle (after the required 10
milliseconds). It is must be cleared in software.
EECON2
EECON2? is not a physical register, but the address 0x89 is assigned to it. Two control words are
written to it is as part of the write cycle,
READ CYCLE
To read the contents of a data EEPROM memory location, the address is presented to the
EEPROM by writing it to the EEADR register followed by setting the RD control bit in
EECONI (bit 0). In the very next instruction cycle, the data will be available in the EEDATA
register.
EEADR is in Bank 0 and ECON] is in Bank 1, so file register bank switching is required.
‘Address In EEADR
a
Switch To Bank t
Loeorent
‘SetRDBitInEECON | TriggerARead
¥
‘Switch To Bank o
¥
EEDATA Into W
¥
Return
252movlw address. ;define address
movw£ eeadr paddress to register
bsf status, pO ;bank 1
bsf eeconl,rd ;read data EEPROM
bet status, rp0 ;return to bank 0
movf -eedata,w = ;data into W
WRITE CYCLE
‘To write to a data EEPROM memory location, the address is presented to the EEPROM by
writing it to the EEADR register and the data is written to the EEDATA register. So far, $0
good. Next comes a specific sequence of instructions which initiates a WRITE. ‘The timing of
the steps is critical, so the prescribed sequence should be used. Interrupts must be disabled
while this is going on so that the sequence timing won't be disrupted.
‘The WREN bit in EECONI must be set to enable a WRITE. This prevents accidental writing to
the data EEPROM when flawed programs go wild. The WREN bit should be clear at all times
‘except when a WRITE is to take place.
On completion of the WRITE cycle, the WR bit is cleared automatically and the EE write
complete interrupt flag (EEIF) is set. The program can detect completion of the WRITE cycle
by enabling this interrupt, by polling the EEIF flag, or by polling the WR bit. The EEIF and
WREN bits must be cleared by software.
‘Switch To Bank 1
t
‘Set WREN Bit In
ECON) Enable Write
a
Write 0x55 To EECON2
[sees esse]
Wit OxAA To EECON2
4
‘Set WR Bit InEECONt | Trigger Write
¥
(Clear WREN Bit In
ECON
Disable Further Writes
253status
portb
eedata
eoadr
address
byte
trish
eecon)
eecon2
address to EEADR
data to EEDATA
bet
bef
movlw
movwe
movlw
movwt
bst
bef
\=EEPROM. ASM========
List
radix
status, rp0
eeconi, wren
0x55
eecon2
Oxaa,
econ?
eecont, wr
eeconl, wren
prl6ee4
hex
ank 1
senable write
define 0x55
0 register
idefinedxaa
sto register
pset WR bit to trigger write
idisable write
(won't effect
this one)
6/10/97)
map)
wrcompl
circle
254
cpu equates (memory
equ 0x03
equ 0x06
equ 0x08
equ 0x09
equ Ox0c
equ Ox0d
equ (0x86
equ (0x88
equ 0x89
bit equates
eq = 0
eq i
= 2
eq 5
org 0x00
bsf status, xp0
movlw — *00000000'
movw£ trish
bef status, zpo
clrf port
moviw 0x0£
movwf byte
movlw 0x00
movwf address
call write
bsf — status, rp0
btfsc econ, wr
goto wrcompl
bef status, xp0
call read
movwf — portb
goto circle
jewitch to bank 1
outputs
switch back to bank 0
pinitialize, LED's off
ptest data
stest address
jwrite test byte to data EEPROM
to bank 1
test write complete?
iback to bank 0
ixead test byte from data EEPROM
display test byte via LED'sread mové—address,w
yet address
movwf eeadr jaddress to register
bsf status, rp0 ;bank 1
bs£ — eeconl, rd ;read data EEPROM (RD bit will
: be cleared in hardware)
bef —status,rp0 ;return to bank 0
movf eedata,w ;data into W
return preturn with data in W
write movf address,w get address
movwf eeadr jaddress to register
movf byte, w iget data
movwf eedata lata to register
sf status,rp0 to bank 1
sf eeconl, wren enable write
movlw 0x55 idefine 0x55 (per data book)
movwf econ?
movlw Oxaa
movwf — eecon2
0 register
lefine Oxaa (per data book)
o register
psf eeconl,wr set WR bit to trigger write
bef —eeconl, wren disable write (won't effect
a this one)
bef status, rp0 ;back to bank 0
return
end
at blast time, select
memory unprotected
watchdog timer disabled (default is enabled)
i standard crystal (using 4 Miz osc for test) XT
power-up timer on
PROGRAMMING THE DATA EEPROM
Some device programmers are not capable of writing to or programming the PICL6F84's data
EEPROM. If yours is, you are set.
MPLAB controlling the PICSTART Plus (tm) has this capability. The data is included in the
.ASM file as follows:
org 2100
de Oxaa, Oxbb
"de" is an assembler directive - define EEPROM data byte. Data bytes are separated by a
comma followed by a space. The ORG statement places the data at address 0x2100 which
corresponds to 0x00 in data EEPROM.
255-EEP2. ASH:
list — pe16£84
radix hex
i cpu equates (memory map)
status equ 0x03
portb equ 0x06
eedata equ 0x08
eeadr equ 0x09
address equ 0x0e
trisb equ 0x86
eeconl equ 0x88
eecon2 equ 0x89
? bit equates
ra eq 0
we eq 1
wren equ 2
5
org 0x00
start bsf — status,rp0_;awitch to bank 1
moviw '00000000" routputs
mowwf trisb
bef status, rp0 ;switch back to bank 0
clrf —portb initialize, LEDs off
movlw 0x02 stest address
movwf address
call read ixead test byte from data EEPROM
movw£ porth idisplay test byte via LEDs
circle goto circle
read mové —address,w get address
movwf eeadr address to register
bsf status, rp0 bank 1
bsf econ, rd ;read data EEPROM (RD bit will
3 be cleared in hardware)
bef status, rp0 ;return to bank 0
movf eedata,w — ;data into W
return preturn with data in W
org 2100
de Oxaa, Oxbb
end
at blast time, select:
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal (using 4 MHz ose for test) XT
power-up timer on
256‘The sample program EEP2.ASM reads the byte at 0x01, and displays it via the LEDs. The
process of programming the device includes storing the two data bytes to be located at
EEPROM addresses 0x00 and 0x01.
CODE PROTECTION
‘The PIC16F84 code protect bit only protects the code in program memory. Your program can
still access and change the contents of data EEPROM memory with the code protection bit set.
257PROGRAM MEMORY PAGING
PICI6 microcontroller program instructions include the address, or at least most of the address.
‘There is only so much room in the instruction for address information. For parts with "smaller"
program memory, the entire address fits in the instruction word. For parts with "larger" program
memory, this is not be possible. In this situation, the rest of the address (high order bits) comes
from somewhere else. If your base-line part programs require less than 512 memory locations or
if your mid-range part programs require less than 2K memory locations, you will not need to
concem yourself with program memory paging. Program memory paging becomes necessary
‘when those upper limits are exceeded.
Program memory is divided into pages as follows:
12-bit Core 14-bit Core
Base-line Mid-range
Memory Locations 512 2K
Per Page
Program memory page selection will be required if your part has more than one page of program
‘memory and your program will occupy more than page 0. This is done by transferring page
select bits heid temporarily in a register to the program counter when program execution moves
from one page to another. This can occur when CALL and GOTO instructions are executed as
they alter the contents of the program counter to specify another page.
‘The primary considerations for the programmer here are:
*+ What happens when your code crosses a page boundary?
Does MPASM let you know? If so, how does it know?! How do you know?
+ Handling CALL and GOTO instructions.
If you do a GOTO, how do you know what page the destination address is on?
How do you tell the microcontroller to go there?
+ Interrupts - 14-bit core parts only,
What happens to the program counter?
How all this works depends on whether the part is a 12-bit core base-line part or a 14-bit core
mid-range part, so we must treat them separately.
258WHERE TO PUT THE CODE
The only way to control/know memory allocation is to use ORG statements to locate subroutine
starting addresses and code destined for a specific memory page._You can verify this by looking
at the "LOC" numbers = program memory locations in the LST file generated by MPASM as
part of the assembly process. The symbol table and the memory usage map in the .LST file will
also help you figure out where you are and if things are ending up in the right place.
14-BIT CORE MID-RANGE PARTS
‘The specs for some popular mid-range parts are:
Number Of
Program High Bits
Memory To Mess With
Device Pages Size (Live In PCLATH)
PIC16C554 1/4 Eyes 0
cél oor 1K 0
cé2 1/2 1K 0
c7L 1/2 1K 0
Gh 4 aK 1
F84 1/2 1k 0
‘The good news here is that you will have to graduate to using a PICI6C74 (in this group) before
you need to worry about program memory paging.
For all the parts in this family, the program counter is 13 bits wide. The CALL and GOTO
instruction address range is 11 bits, enough to handle 2K of program memory address space.
Our task, then, is to learn what to do with the high order 2 bits when your part has 4K or 8K of
program memory.
Program counter bits 11 and 12 are used to select memory pages in parts having 4K or 8K
program memory.
259The program counter is in two sections, program counter low (PCL) and program counter high
(PCH).
PoH Po.
Ruwes 7 Q
LETT) CLETTTTT)
a 5
Included in OP Code
Page Solect Bits Enough To Define 2k
Program Memory
00 Pageo
01 Paget
10 Page2
11 Pagea
‘The program counter high (PCH) cannot be read or written to directly. It is loaded from a 5-bit
latch called program counter latch high or PCLATH.
PCLATH
43210
a To
=
LL page se is
When a CALL or GOTO instruction is used in a program for a 14-bit core mid-range device
with two program memory pages (4K), the page bit in PCLATH (bit 3) must be programmed to
select the desired destination program memory page prior to executing the CALL or GOTO
instruction. ‘The write to PCLATH bit 3 should immediately proceed the CALL or GOTO
instruction in your program. Bit 4 must be 0.
For 8K parts, two PCLATH bits (3 and 4) are used.
After returning from a subroutine, the page bits should be restored to the current page via
program instructions to prevent confusion.
260110 9 87 °
re | LL TTITTiTt tt)
ai Mi]
eee | (enaemnse lean
ee From CALL OrGOTO
a
pon [| | |
GOTO - 14-bit core (example)
PIC16C74 From code on page 0 to code on page 1
org 0x0000
bs pelath,3_— select page 1
goto job po code on page 1
0x0800
job
Subroutine CALL - 14-bit core (example)
PIC16C74 From code on page 0 to subroutine on page 1 and
return
pelath,3 ;select page 1
do_it ito subroutine on page 1
pelath,3 select page 0 on return
0x0800
do_it
returnInterrupts and Program Memory Paging
In the event of an interrupt, the program counter contents (all 13 bits) is saved on the hardware
stack automatically. Manipulation of PCLATH is not required prior to a return instruction. The
return address is handled automatically including the page (comes from stack).
‘When you are using a device which has more than one page of program memory and your
programn uses interrupts, you will need to save and restore the contents of PCLATH as part of
your interrupt service routine. This is in case PCLATH was written to just prior to the interrupt,
‘You will need its contents after the return from interrupt.
12-BIT CORE BASE-LINE PARTS
The specs for some popular mid-range parts are:
Number Of High
PROGRAM Bits To Mess With -
MEMORY Bits Live In Status
DEVICE Pages Size Register (bits 6 & 7)
PIC16C54 1 512 0
56 2 1K 1
57 4 2K 2
For 12-bit core devices with more than one page of program memory, the status register contains
two bits used for page selection (status register bits 6,5). The two status register page select bits
are loaded into the upper two bits of the program counter (PC 10,9) on execution of a CALL or
GOTO instruction,
GOTO instructions provide the lower 9 bits (bits 0 to 8) of the address to the program counter,
Bits 9 and 10 come from the status register. GOTO's allow jumping to any location in any page.
A CALL loads the lower 8 bits of the program counter. The 9th bit (bit 8) is cleared to "0". This
dictates that the first instruction of a subroutine must be in the first 256 locations of a program
memory page. The upper 2 bits of the program counter are loaded with the page select bits from
the status register if there is more than one page of program memory.
262From Page Select Bits — Sieae |
‘Of Status Register
(PAL PAD) From ALL OrGOTO
Instruction Word
: CALL -Cieared Too
a GOTO - Par Of Instruction Word
Page Select Bits
00 Pageo
ot Paget
10 Page2
11 Pages
GOTO - 12-bit core (example)
PICI6C57 From code on page 0 to code on page 3
0x000
status,5 select page 3
status, 6
task ;to code on page 3
ox600
task
Subroutine CALL - 12-bit core (example)
PICLECS6 From code on page 0 to subroutine on page 1 and
return
status,5 select page 1
do_work ito subroutine on page 1
status,5 select page 0 on return
0x200
do_it
return
Again, the page select bits are made the same as the page the code is on immediately after a
return from subroutine to prevent confusion.
263SUMMARY
CALL Subroutine
12-Bit Base-Line
First instruction of subroutine must be in first 256
locations of any program memory page because 9th bit
(bit 8) of PC is cleared by execution of CALL
instruction. If program memory is larger
than one page (512), you must deal with the upper 2 bits
of the PC.
14-Bit Mid-Range
First instruction of subroutine may be anywhere as long
as PCLATH is programmed first when there is more than
one program memory page.
GoTo
12-Bit Base-Line
Any location on any page. If program memory is larger
than one page (512), you must deal with the upper 2 bits
of the PC.
14-Bit Mid-Range
Any location on any page. If program memory is larger
than one page (2K), you must deal with PCLATH.
264LOCATING TABLES IN PROGRAM MEMORY
Tables are very important because they are the only means by which data can be included in a
program, Their use is introduced in Bay PIC'n. Some more advanced issues are discussed
here.
The only way to control/know memory allocation is to use an ORG statement to locate the
subroutine which contains the table.
‘The rules for locating tables in program memory depend on device core size.
TABLE LOCATION FOR 14-BIT MID-RANGE PARTS
‘As we said in the previous chapter, 14-bit core, mid-range parts may have as much as 8K of
program memory. Each 1K of memory has four 256-location segments. Tables should be
located entirely within a 256 location Segment of program memory. This can be any segment on
any page. When the ADDWF instruction is used to jump into the table, the PCL contains the
computed destination address and itis 8 bits wide. This is the reason for the 256 location limit.
‘Actually, tables can straddle 256 segment boundaries, but that is beyond the scope of this book.
(see Microchip AN5S6).
For the PIC16F84, the 1K of program memory (half page) contains four 256-location segments
which have the following address ranges:
Page 0 0x000 - Ox0FF
Page 1 0x100 - Ox1EF
Page 2 0x200 - 0x2EF
Page 3 0x300 - 0x3EF
265TABLE LOCATION FOR 12-BIT BASE-LINE PARTS
When the ADDWF instruction is used to jump into a table (computed address), the computed 8-
bit result is loaded into the lower 8 bits of the program counter. ‘The 9th bit (bit 8) of the PC is
cleared. The upper 2 bits of the program counter are loaded with the page select bits from the
status register.
109 8 7 o
re [| Tl [|
t | 7
a ‘Computed Result
siaus [_] L Eerie
ADDWF Instruction
Tables are limited to the first 256 locations of any program memory page because the computed
result is 8 bits and execution of the ADDWF instruction clears bit 8 of the PC.
SUMMARY
12-Bit Base-Line
Table must be in first 256 locations of any program
memory page because 9th bit (bit 8) of PC is cleared by
execution of ADDWF instruction.
14-Bit Mid-Range
Table may be in any 256 address program memory segment.
The result of a computed address (ADDWE PC) is
limited to the 8-bit PCL which limits the number of
possible addresses to 256 (unless you want to get really
serious - see Microchip AN556) .
266APPENDIX A
SOURCES
Following is a list of sources for PIC16 parts, information and tools.
Digi-Key Corporation
701 Brooks Ave. South
Thief River Falls, MN 56701-0677 USA
(800) 344-4539
http://www. digikey.com
DonTronics
P.O. Box 595 Tullamarine 3043 Australia
Int+ 613 9338-6266
Int+ 613 9338-2935 FAX
http://www, dont ronics.com
ITU Technologies
3704 Cheviot Ave. Suite 3
Cincinnati, OH 45211
(513) 661-7523
http://www, itutech.com
JDR Microdevices
1850 South 10th Street
San Jose, CA 95112-4108
(800) 538-5000
AMECO
1355 Shoreway Road
Belmont, CA 94002-4100
(800) 831-4242
http://www. jameco.com
Marlin P. Jones
P.O. Box 12685
Lake Park FL 33403-0685
(800) 652-6733
Parts/Programmers
Simmstick ‘t™ protyping
Boards for PIC16
Programmers and Software
Parts/Programmers
Parts/Programmers
Programmers
267Microchip Technology Inc.
2355 West Chandler Blvd.
Chandler, AZ 85224-6199 USA
(602) 786-7200
http://www.microchip. com
microEngineering Labs, Inc.
Box 7532
Colorado Springs, CO 80933 USA
(719) 520-5323
http://www.melabs.com
Maxim Integrated Products, Inc.
120 San Gabriel Drive
Sunnyvale, CA 94086
(408) 737-7600, X6380 Small order
268
desk
Manufacturer of PIC16
Programmers, software
and prototyping PCB's
MAX40 6BCPA
MAX522CPAAPPENDIX B
HEXADECIMAL NUMBERS
Binary numbers which are two bytes long are difficult to recognize, remember and write without
errors, so the hexadecimal numbering system is used instead. ‘Think of hex as a kind of
shorthand notation to make life easier rather than some kind of terrible math.
Hexadecimal Binary Decimal.
0 0000 0
1 0001 1
2 0010 2
3 0011 3
4 0100 4
5 0101 5
G 0110 6
7] 0111 1
8 1000 8
9 1001 9
A 1010 10
B 1011 ql
c 1100 12
D 1101 13
E 1110 14
FE aii 15
Hexadecimal is the language used in this book. It will seem awkward at first, but working with
binary is time consuming and will result in errors which would quickly force you to learn
hexadecimal. Using hexadecimal is not difficult. All you need is a little practice.
One byte requires two hex digits. Note that the bits representing a byte are sometimes shown in
groups of four, Note, also, that the most significant binary digit is on the left.
‘Hex numbers are denoted by "Ox" in this book.
269