Note 1: Interfacing A Matrix Keypad
Note 1: Interfacing A Matrix Keypad
Note 1: Interfacing A Matrix Keypad
How it works. Code at the beginning of the program sets the lower four
bits of port RB (connected to the columns of the keypad) to output, and
the upper four bits (rows) to input. It also sets port RA, which will drive
LEDs indicating the binary number of the key pressed, to output.
The routine scankeys does the actual work of reading the keypad. It
performs the following basic steps:
If the first key, key 0, is pressed, the routine exits with a 0 in the variable
key, because it ends before the first increment instruction. If no key is
pressed, the variable key is incremented 16 (010h) times. Therefore, this
470 LED
470 LED
1 18 470 LED
RA2 RA1
2 17
RA3 RA0 220 pF
You may want to add 1k series resistors in Vcc 3 16
; PROGRAM: KEYPAD
; This program demonstrates a simple method for scanning a matrix-encoded
; keypad. The 4 columns of the pad are connected to RB.0 through RB.3; 4 rows to
; RB .4 through RB .7. The scanning subroutine returns the code of key pressed
; (0h—0Fh) in the variable key. If no switch is pressed, the out-of-range value 10h is
; returned in key (this avoids the use of a separate flag variable).
keypad = rb
row1 = rb.4
row2 = rb.5
row3 = rb.6
row4 = rb.7
; Subroutine to scan the keypad. Assumes that the calling routine will delay long
; enough for debounce.
scankeys clr key
; On the first time through the following loop, the carry bit (1) is pulled into keypad.
; On subsequent loops, the lone 1 moves across the column outputs.
:scan rl keypad
clrb c ; follow the 1 with zeros
jb row1, press
; If a 1 is detected, quit the routine with the current value of key. If row1, column1 is
; pressed, the value of key is 0 (on the first loop). If not, increment key and try the
; next row.
inc key
jb row2, press
inc key
jb row3, press
inc key
jb row4, press
inc key
djnz cols, :scan ; Try all 4 columns.
press ret ; Return with value in key.
; If no key is pressed, the value will be 10h due to execution of the final increment
; instruction. The program should interpret this out-of-range value as ‘no press.’
START BIT BIT BIT BIT BIT BIT BIT BIT STOP
BIT 0 1 2 3 4 5 6 7 BIT
Figure 1. A byte of serial data. The byte depicted is 01011010, the ASCII code for Z.
The example presented here does not use any of the RS-232 handshak-
ing lines. These lines help when a fast computer must communicate
with (for instance) a slow printer. When the receiving device does not
use the handshaking lines, it is necessary to loop them back as shown
in figure 2. That way, when the computer asks for permission to send,
the signal appears at its own clear-to-send pin. In effect, it answers its
own question.
DB-25 DB-9
PIN PIN
2 3 DATA to SERIAL IN
4 7 RTS
5 8 CTS
6 6 DSR
8 1 DCD
20 4 DTR
to PIC circuit
7 3 GND GND
Listing 1 begins by setting up the input and output bits. It then enters
a loop waiting to detect the start bit. Once the start bit is detected, the
program waits one-half bit time and checks to see whether the start bit
is still present. This helps ensure that the program isn’t fooled by a noise
burst into trying to receive a nonexistent transmission. It also makes
sure that subsequent bits are read during the middle of their time slots;
another precaution against noise.
Once it detects and verifies the start bit, the program enters another loop
that does the actual job of receiving the data. It works like this:
If you are unfamiliar with the rotate right (rr) instruction, you may not
see how the input bit gets from the carry bit into the receive byte.
Performing an rr on a byte moves its bits one space to the right. Bit 7 goes
to bit 6, bit 6 to bit 5, and so on. Bit 0 is moved into the carry bit. The carry
bit moves into bit 7.
Once the byte is received, the program waits a final bit delay (until the
middle of the stop bit), copies the received byte to the output port to
which the LEDs are connected, and goes back to the beginning to await
another start bit.
The program can be set up for most standard data rates. The table lists
PIC clock speeds and values of the bit time constant bit_K (declared at
the beginning of listing 1) for a wide range of common rates. For other
combinations of clock speed and data rate, just replace the delay
routines with ones that provide the appropriate timing. The footnote to
the table gives general guidance.
1/4 MC1489A:
pins 1, 4, 7, 10 to gnd; pin 14 to
RS-232 +5 Vdc; rest not connected.
serial in 1 18
13 11
RA2 RA1
2 17 ceramic resonator
12
RA3 RA0 w/integral capacitors
+5 3 16
RTCC OSC1
47pF
4 15
MCLR OSC2 +5
5 PIC 14
RS-232
Vss 16C54 Vdd
1 6 13 470 LED
serial in
RA2 RB0 RB7
22k 7 12 470 LED
RB1 RB6
8 11 470 LED
RB2 RB5
9 10 470 LED
A 22k resistor may be used
instead of the 1489. Change RB3 RB4
the program as marked in
listing 1. 470 LED
470 LED
Figure 3.
470 LED
Schematic to
accompany 470 LED
RCV232.SRC.
; PROGRAM: RCV232
; This program receives a byte of serial data and displays it on eight LEDs
; connected to port RB . The receiving baud rate is determined by the value of the
; constant bit_K and the clock speed of the PIC. See the table in the application note
; (above) for values of bit_K. For example, with the clock running at 4 MHz and a
; desired receiving rate of 4800 baud, make bit_K 50.
device pic16c54,xt_osc,wdt_off,protect_off
reset begin
; This delay loop takes four instruction cycles per loop, plus eight instruction cycles
; for other operations (call, mov, the final djnz, and ret). These extra cycles become
; significant at higher baud rates. The values for bit_K in the table take the time
; required for additional instructions into account.
; This delay loop is identical to bit_delay above, but provides half the delay time.
A byte of serial data is commonly sent as 10 bits: a start bit, eight data
bits, and a stop bit. The duration of these bits is calculated by dividing
+5
10 µF
10 µF
1 16
C1+ Vcc
2 15
MAX
10 µF +10 GND
3 232 14
C1- X1 out
4 13
C2+ R1 in
10 µF 5 12
C2- R1 out
10 µF 6 11
-10 X1 in
7 10 1 18
RS-232
serial out X2 out X2 in RA2 RA1
8 9 2 17
+5 ceramic resonator
R2 in R2 out RA3 RA0 w/integral capacitors
3 16
1k RTCC OSC1
4 15
MCLR OSC2
5 PIC 14
1 Reset Vss 16C54 Vdd +5
RS-232
serial out RA2 6 13
RB0 RB7
7 12
RB1 RB6
8 11
The PIC's output may be connected RB2 RB5
directly to the serial input of the 9 10
terminal or PC. Change the program RB3 RB4
as marked in listing 1.
How it works. The PIC program in listing 1 sends a short text string as
a serial data stream whenever the PIC is reset. To reset the PIC, push and
release the reset button shown in the schematic (if you are using the
Parallax Downloader, omit S1 and use the built-in reset switch). If you
lack appropriate terminal software for your computer, listing 2 is a
BASIC program that will help get you started. If you use other terminal
software and get “device timeout” errors, try cross-connecting the
handshaking lines as shown in figure 2 below. This has the effect of
disabling handshaking. The program in listing 2 does this in software.
The PIC program starts by setting port RA to output. Serial data will be
transmitted through pin RA.2. The program consists of two major loops,
defined by the labels :again and :xmit. The first loop, :again, initializes the
Page 100 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 3: Sending RS-232 Serial Data
bit counter, and then gets a byte from the subroutine/table called string.
Once string returns a byte in the w register, the program puts this byte
into xmt_byte. After a start bit is sent by clearing the serial-out pin, :xmit
takes over. It performs the following steps:
With the :xmit loop finished, the program sets the serial-out pin to send
a stop bit, and checks to see whether it has reached the end of the string.
If not, it goes back to :again to retrieve another byte. If it is done with the
string, the program enters an endless loop.
DB-25 DB-9
PIN PIN
4 7 RTS
5 8 CTS
6 6 DSR
8 1 DCD
20 4 DTR
to PIC circuit
7 3 GND GND
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 101
Note 3: Sending RS-232 Serial Data
tional features, such as additional I/O channels, higher signaling rates,
lower power consumption, and the ability to work without external
capacitors.
Modifications. The MAX232 draws more current and costs more (in
single-part quantities) than the PIC it supports. Most of the time, this is
still a bargain compared to adding a bipolarity power supply to a device
just to support RS-232 signaling. In fact, the MAX232 has excess current
capacity that can be used to power other small bipolarity devices, such
as low-power op-amps. Depending on the application, additional
voltage regulation may be required.
If you plan to use the serial port infrequently, consider powering the
MAX chip through one of the PIC’s I/O pins. Your program could turn
the MAX on shortly before it needed to send a serial message, and turn
it back off afterward. This option is especially attractive for uses that
require wringing the most life out of a set of batteries.
In some cases, you may be able to dispense with the serial line driver
altogether. Make the changes marked in listing 1 “for direct connec-
tion” and wire RA.2 directly to the serial receive connection of your
terminal or PC. The changes in the program invert the logic of the serial
bits, so that a 1 is represented by an output of 0 volts and a 0 is a 5-volt
output. According to RS-232, the receiving device should expect volt-
ages of at least -3 volts for a 1 and +3 volts for a 0. Voltages lying between
+3 and -3 are undefined, meaning they could go either way and still
comply with the standard.
Page 102 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 3: Sending RS-232 Serial Data
That’s why this cheap trick works. Don’t count on it to provide full RS-
232 performance, especially when it comes to sending data rapidly over
long cables. Keep cables short and you shouldn’t have any problems
(19,200 baud seems to work error-free through 6 feet of twisted pair).
If your application will have access to the handshaking pins, you may
be able to steal enough power from them to eliminate batteries entirely.
According to the RS-232 specifications, all signals must be capable of
operating into a 3000-ohm load. Since many computers use ±12 volts for
their RS-232 signals, each line should be capable of delivering 4 mA. In
practice, most can provide more, up to perhaps 15 mA. The only
problem with exploiting this free power is that the software running on
the PC or terminal must be written or modified to keep the handshaking
lines in the required state.
One final hardware note: Although timing isn’t overly critical for
transmitting serial data, resistor/capacitor timing circuits are inad-
equate. The PIC’s RC clock is specified to fairly loose tolerances (up to
±28 percent) from one unit to another. The values of common resistors
and capacitors can vary substantially from their marked values, and
can change with temperature and humidity. Always use a ceramic
resonator or crystal in applications involving serial communication.
Values of Timing Constant Bit_K for Various Clock Speeds and Bit Rates
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 103
Note 3: Sending RS-232 Serial Data
; PROGRAM: XMIT232
; This program transmits a string of serial data. The baud rate is determined by the
; value of the constant bit_K and the clock speed of the PIC. See the table in the
; application note (above) for values of bit_K. For example, with the clock running at
; 4 MHz and a desired transmitting rate of 4800 baud, make bit_K 50.
Page 104 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 3: Sending RS-232 Serial Data
; To change the baud rate, substitute a new value for bit_K at the beginning of this
; program.
10 CLS
15 REM Substitute desired baud rate for 19200 in the line below.
20 OPEN “com1:19200,N,8,1,CD0,CS0,DS0,OP0” FOR INPUT AS #1
30 IF NOT EOF(1) THEN GOSUB 200
40 GOTO 30
200 Serial$ = INPUT$(LOC(1), #1)
210 PRINT Serial$;
220 RETURN
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 105
BLANK PAGE
Page 106 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 4: Reading Rotary Encoders
Introduction. This application note covers the use of incremental
rotary encoders with PIC microcontrollers. It presents an example
program in Parallax assembly language for reading a typical encoder
and displaying the results as an up/down count on a seven-segment
LED display.
CLOCKWISE
Phase 1
Phase 2
COUNTER CW
CLOCKWISE
Phase 1 11001100110
Phase 2 01100110011
COUNTER CW
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 107
Note 4: Reading Rotary Encoders
LED/sensor pair is arranged so that the devices face each other through
the slots in the wheel. As the wheel turns, it alternately blocks and
passes light, resulting in square wave outputs from the sensors.
Vcc
Rotary Encoder
(Digi-Key GH6102)
1k 1k
V+
p1 6
5
p2 4
gnd 1
1 18
Vcc RA2 RA1
2 17
RA3 RA0 220 pF
3 16
RTCC OSC1
4 15
MCLR PIC OSC2 NC 10k Vcc
5 14
16C54
Vss Vdd
6 13
RB0 RB7 NC
7 12 470
RB1 RB6 a
8 11 470
RB2 RB5 b
9 10 470 a
RB3 RB4 c
f b
470
d g
470
e c
e
470
f d
470
g
Common-Cathode
LED Display
Page 108 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 4: Reading Rotary Encoders
direction. For instance, if phase 1 is high and phase 2 is rising, the
direction is clockwise (CW). If phase 1 is low and phase 2 is rising, the
direction is counterclockwise (CCW).
When the encoder shaft is turning CW, you get a different sequence of
numbers (01,00,10,11) than when it is turning CCW (01,11,10,00). You
may recognize this sequence as Gray code. It is distinguished by the fact
that only one bit changes in any transition. Gray code produces no
incorrect intermediate values when the count rolls over. In normal
binary counting, 11 rolls over to 00. If one bit changed slightly before the
other, the intermediate number value could be incorrectly read as 01 or
10 before settling into the correct state of 00.
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 109
Note 4: Reading Rotary Encoders
The program begins by setting up the I/O ports and clearing the
variable counter. It gets an initial input from the encoder, which goes
into the variable old, and strips off all but the two least-significant bits
(LSBs).
The body of the program, starting with :loop, calls check_encoder and
then displays the latest value of counter on the LED display.
If the value has changed, the routine moves the value in old one bit to the
left in order to align its LSB with the high bit of the two-bit value in new.
It XORs the variables together. It then examines the bit old.1. If the bit is
1, counter is incremented; if it’s 0, counter is decremented.
Page 110 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 4: Reading Rotary Encoders
; PROGRAM: Read Rotary Encoder (RD_ENCDR.SRC)
; This program accepts input from a rotary encoder through bits RA .0 and RA .1,
; determines the direction of rotation, and increments or decrements a counter
; appropriately. It displays the hexadecimal contents of the four-bit counter on a
; seven-segment LED display connected to port RB .
encoder = ra
display = rb
temp ds 1
counter ds 1
old ds 1
new ds 1
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 111
Note 4: Reading Rotary Encoders
:up inc counter
and counter, #00001111b
mov old,new
:return ret
Page 112 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
BLANK PAGE
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 113
BLANK PAGE
Page 114 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 5: Producing Sound & Music
Introduction. This application note presents a subroutine for produc-
ing tones (or musical notes) by specifying values for frequency and
duration. The example program plays a brief tune through a speaker.
The circuit uses two PIC outputs driven differentially to produce a 10-
volt peak-to-peak signal from a single-ended power supply.
0.047µF
Speaker
1 18
+5
RA2 RA1
2 17
+5
RA3 RA0
3 16 10k
1k RTCC OSC1
4 15 4.7 pF
MCLR OSC2
5 PIC 14
Reset Vss 16C54 Vdd
6 13
RB0 RB7
7 12
RB1 RB6
8 11
RB2 RB5
9 10
RB3 RB4
The problem with counting cycles is that the duration ends up varying
with the frequency. A 1000-hertz (Hz) tone is made up of 1-millisecond
(ms) cycles. If your program counts out 200 cycles, the resulting tone
lasts 200 ms. But if you change the frequency to 5000 Hz, each cycle takes
only 0.2 milliseconds, so 200 cycles last only 40 ms.
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 115
Note 5: Producing Sound & Music
An eight-bit counter controls the frequency of the sound. If the fre-
quency value is 100, then the routine inverts the speaker lines every
100th execution of the main loop. The larger the frequency value, the
lower the output frequency.
How it works. The circuit in figure 1 plays a short tune each time the PIC
is powered up or reset (if you are using the Parallax downloader, you
can omit the switch and use the built-in reset button). The speaker
connects through a capacitor to two of the PIC’s input/output pins.
Most PIC circuits switch a load between a single pin and ground or +5
volts. As a result, the largest voltage swing they can generate is 5 volts.
In this case, the program ensures that RA.0 and RA.1 are always comple-
mented; when RA.0 is 1, RA.1 is 0 and vice versa. The speaker therefore
sees a 10-volt swing. This makes a noticeably louder sound, especially
with piezo devices, which are more efficient at higher voltages.
The program that controls the PIC begins by setting port RA to output
and loading a pattern of alternating 0’s and 1’s into it. The program then
looks up two values from ROM tables* notes and lengths. It stores these
values in the variables freq and duratn, and calls the subroutine beep.
Beep accepts the values and produces a tone of the specified frequency
and duration. The key to this routine is the ability of the exclusive-OR
(XOR) logic function to selectively invert bits. XOR’s truth table is:
A XOR B Result
0 0 0
0 1 1
1 0 1
1 1 0
*You can stuff a series of bytes into the program ROM for later use by your program. Just set
up a subroutine beginning with jmp pc+w followed by the directive retw byte0, byte1, byte2...
When you need to access one of these numbers from your program, just move the number
corresponding to the byte value you want into the w register, and call the table. Upon return, the
byte value will be in the w register.
Page 116 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 5: Producing Sound & Music
Each time beep loops, it XOR’s the speaker lines with the variable tgl.
Most of the time, this variable contains 0’s, so the XOR has no effect. The
counter variable f_temp is decremented each time the loop executes.
When f_temp reaches 0, tgl gets loaded with 1’s. Now XOR’ing the
speaker lines with tgl inverts them. The routine reloads f_temp with the
value freq, and the process starts again.
After beep returns, the main program increments the variable index and
checks to see whether all the notes have played. If they haven’t, the
program loops. If they have, it enters an endless do-nothing loop
waiting to be reset or shut off.
To program a tune, look up each note in the table and put the corre-
sponding freq into notes. To calculate values for lengths, pick an appro-
priate duration for a whole note, and scale half-note, quarter-notes,
eighths and so on correspondingly. The duration in milliseconds of the
note will be approximately 5 x duratn. So, if you pick a value of 128 for
a whole note, it will last 640 ms.
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 117
Note 5: Producing Sound & Music
When you’re done filling in notes and lengths, count the notes and set the
constant end_note equal to this number. Also make sure that the number
of notes is equal to the number of lengths.
; PROGRAM: CHARGE.SRC
; This program in Parallax assembly language plays a short tune, “Charge,” from
; data stored in a pair of tables. It uses a general-purpose routine called beep to
; generate the notes from frequency and duration data. The tune will play when the
; PIC or Downloader is first powered up, and any time the device is reset. Note that
; although beep uses seven file registers, five of these may be reused elsewhere in
; the program for counting, or any use that does not require their values to be
; preserved after beep is called.
Page 118 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 5: Producing Sound & Music
; Device data and reset vector. Remember to change these entries if programming
; another type of PIC.
device pic16c54,rc_osc,wdt_off,protect_off
reset start
; For 8-MHz operation (e.g., the downloader w/ built-in xtal) substitute the sequence
; below for Notes:
; retw 180, 134, 104, 88, 104, 88
; For 8-MHz operation (e.g., the downloader w/ built-in xtal) substitute the sequence
; below for Lengths:
; retw 70, 70, 70, 110, 60, 255
beep mov t_pat, #255 ; All ones to invert all bits in port A.
mov f_temp, freq ; If freq is zero, fill pattern with
; zeros.
jnz :cont ; ..for a silent pause.
mov t_pat, #0
:cont mov d_hi, duratn ; Variable duratn goes into the
; high byte
clr d_lo ; ..of a 16-bit counter.
mov tgl, t_pat
:main xor spkr, tgl ; XORing the speaker bits with 1s
; inverts them.
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 119
Note 5: Producing Sound & Music
:delay nop ; Zeros have no effect.
nop ; Nops pad main loop to 20µs.
nop
djnz f_temp, :noRoll1 ; When f_temp reaches zero,
; reload the freq.
mov f_temp, freq ; ..value and put tgl_pat into tgl in
; order to
mov tgl, t_pat ; ..invert the speaker bits on the
; next loop.
:dur_lo sub d_lo, #1 ; Decrement low byte of duration.
jc :noRoll2 ; If no borrow, go to noRoll2.
sub d_hi, #1 ; If borrow occurs, decrement the
sc ; ..high byte of duration. If the high
; byte
ret ; ..needs a borrow, routine is done.
jmp :main ; Else loop to :main.
Page 120 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
BLANK PAGE
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 121
BLANK PAGE
Page 122 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 6: Driving an LCD Display
Introduction. This application note shows how to interface PIC micro-
controllers to common Hitachi liquid-crystal display (LCD) modules.
The program, in Parallax assembly language, writes text to the display,
reads display status, and creates custom character patterns.
1 18
RA2 RA1
2 17
+5 TO LCD
Vdd RA3 RA0
3 16 ceramic
1k RTCC OSC1 resonator
4 15
MCLR OSC2
5 PIC 14
+5
Reset Vss 16C54 Vdd
6 13
RB0 RB7 6 5 4
7 12 14
DB7
RB1 RB6 13
DB6
E R/W RS
8 11 12 DB5
11
RB2 RB5 10
DB4
DB3
9 10 9 DB2
RB3 RB4 8 DB1
7 DB0 Vdd Vo Vss
2 3 1
10k
FROM RA.3
Hitachi LCD modules display the standard ASCII character set, plus
selected Japanese, Greek, and math symbols. They operate from a
single-ended 5-volt supply, and communicate with a bus or controller
through 11 input/output (I/O) lines. The data lines are tri-state; they go
into a high-impedance state when the LCD is not enabled.
The three control lines ‘control’ the LCD. The enable (E) line determines
whether the LCD listens to the other control and data lines. When
disabled, the LCD ignores all data and control signals. When enabled,
the LCD checks the state of the other two control lines and responds
accordingly.
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 123
Note 6: Driving an LCD Display
The read/write (R/W) line determines whether the LCD reads bits
from the data lines, or writes bits to them.
E 0 LCD disabled.
1 LCD enabled.
R/W 0 Write to LCD.
1 Read from LCD.
RS 0 Instructions.
1 Characters/bytes.
Writing to the LCD requires the basic steps listed below. (Reading from
the LCD follows the same sequence, but the R/W bit must be set.)
When power is applied to the LCD, it resets itself and waits for
instructions. Typically these instructions turn on the display, turn on
the cursor, and set the display to print from left to right.
Page 124 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 6: Driving an LCD Display
CG RAM determines the bit maps of the characters corresponding to
codes 0 through 7 (in normal ASCII, these are control codes). To
download bit maps to the LCD, first set the CG RAM address to the
desired starting point (usually 0), and then write the bytes to the LCD.
Because the pointer increments with each write, you don’t need to keep
specifying addresses. Figure 2 is an example pattern definition. The
program listing shows how to define custom characters.
Address in
Character “retw”
Generator RAM Bit Map Data Data
0000 01111 15
0001 10001 17
0010 10001 17
0011 01111 15
0100 00001 1
0101 00001 1
0110 00001 1
0111 00000 0
Before you can write to DD RAM after defining custom characters, the
program must set a DD RAM address. The LCD reads and writes
whichever RAM bank (DD or CG) was last specified in a set-address
instruction. Once you have set an address in DD RAM, the next data
write will display a character at the corresponding location on the
screen.
Until now, we have talked about reading and writing to the LCD as
though it were regular memory. It’s not. The LCD’s controller takes 40
to 120 microseconds (µs) to complete a read or write. Other operations
can take as long as 5 milliseconds. To avoid making the PIC wait a
worst-case delay between operations, the LCD has a 1µs instruction that
reads the address counter and a busy flag. When the busy flag is set (1),
the LCD cannot handle a read or write. The program listing includes a
subroutine (blip_E) that makes sure the busy flag is cleared (0) before
talking to the LCD.
The address returned along with the busy flag is either the DD or CG
RAM pointer, depending on which address was last set.
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 125
Note 6: Driving an LCD Display
Figure 3 is a list of LCD instructions for reading and writing memory.
Some other useful instructions appear as constants in the beginning of
the program listing.
Power to the LCD is controlled by a PIC I/O bit. In this way, the PIC
ensures that the 5-volt supply is up and stable before switching on the
LCD. If the circuit used the PIC’s sleep mode, it could shut down the
LCD to save approximately 1.5 mA. If you use this feature, make sure
that the data and control lines are cleared to 0’s or set to input before
putting the PIC to sleep. Otherwise, leakage through the LCD’s protec-
tion diodes might continue to power it.
Page 126 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 6: Driving an LCD Display
Program listing. This program may be downloaded from the Parallax
BBS as LCD_DRVR.SRC. You can reach the BBS at (916) 624-7101.
; Declare constants for common LCD instructions. To perform the functions listed
; below, clear bit RS and send #constant to the display. Remember to set RS again
; before sending characters to the LCD.
clear = 1 ; Clears the display (fills it with
; blanks).
home = 2 ; Returns display to the home
; position.
shift_l = 24 ; Shifts display to the left.
shift_r = 28 ; Shifts display to the right.
crsr_l = 16 ; Moves cursor to the left.
crsr_r = 20 ; Moves cursor to the right.
blink_c = 11 ; Blinks whole character to indicate
; cursor position.
no_crsr = 8 ; Turns off the cursor.
; Set RAM origin above special registers, declare variables, and set code origin.
org 8
temp ds 1 ; Temporary counter.
temp2 ds 1 ; Pass data or instructions to
; blip_E.
counter ds 1 ; Index variable.
org 0
; Device data
device pic16c54,xt_osc,wdt_off,protect_off
reset start
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 127
Note 6: Driving an LCD Display
mov !ra,#0h ; set control lines to output
mov !rb,#0h ; set data lines to output
setb LCD_pwr
call wait
Page 128 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 6: Driving an LCD Display
clrb E ; Disable LCD.
snb temp.7 ; Is the LCD busy?
jmp :loop ; Yes, try again later.
movb RS, pa2 ; No, send the data or instruction.
clrb RW
mov !rb, #0
mov data, temp2
setb E
nop
clrb E
ret
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 129
BLANK PAGE
Page 130 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 7: Direct & Indirect Addressing
Introduction. This application note describes direct and indirect ad-
dressing and shows a method for avoiding the gaps in the PIC16C57’s
banked memory.
This instruction, which moves the decimal number 100 into register 10
hexadecimal (h), is an example of direct addressing. Most of the instruc-
tions in a typical PIC program use this addressing mode.
The Parallax assembler has several helpful features for direct address-
ing. The first of these is labeling. Instead of referring to registers by
Address
(hex) Description
0 indirect Reads/writes address pointed to by fsr.
1 rtcc Real-time clock/counter.
2 pc Program counter—9 to 11 bits wide; lower 8 may be read/written.
3 status Flag bits for arithmetic operations, sleep and reset, and ROM page selects.
4 fsr Pointer; address of data accessed through indirect.
5 ra I/O port ra.
6 rb I/O port rb.
7 rc I/O port rc on ’55 and ’57; general-purpose register on ’54 and ’56.
8–1F General-purpose RAM (’54, ’55, ’56) and RAM bank 0 of ’57
20–2F RAM warp; reads and writes to 0–F.
30–3F RAM bank 1 (’57 only)
40–4F RAM warp; reads and writes to 0–F. RAM Banks 1–3, 16C57
50–5F RAM bank 2 (’57 only)
60–6F RAM warp; reads and writes to 0–F.
70–7F RAM bank 3 (’57 only)
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 131
Note 7: Direct & Indirect Addressing
address, you may assign names to them:
You can also define variables without specifying their address by using
the ds (define space) directive:
Using ds assigns the label to the next available register. This ensures
that no two labels apply to the same register, making variable assign-
ments more portable from one program to another. The only caution in
using ds is that you must set the origin using the org directive twice; once
for the starting point of variables in RAM, and again (usually at 0) for
the starting point of your program in ROM.
Labels can be assigned to individual bits in two ways. First, if the bit
belongs to a labeled byte, add .x to the label, where x is the bit number
(0–7). Or assign the bit its own label:
Page 132 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 7: Direct & Indirect Addressing
registers, and the bits of the status register. See your manual for a list.
The PIC’s indirect addressing mode allows the use of pointers and the
high-level data structures that go with them, such as stacks and queues.
Using indirect addressing for the earlier example (writing 100 to
register 10h) would look like this:
The value in the file select register (fsr; register 04h) is used as the
address in any instruction that reads/writes indirect (register 00h). So
storing 10h in the fsr and then writing 100 to indirect is the same as
writing 100 to address 10h.
7 6 5 4 3 2 1 0
address, 0–Fh
banked memory enable;
Figure 2. The 16C57 1 = on, 0 = off
file-select register.
bank select, 0–3h
unused; reads as 1
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 133
Note 7: Direct & Indirect Addressing
A more practical example would be to store a series of values from an
I/O port to sequential registers in memory. All it takes is a loop like this:
PIC’s with 32 bytes of RAM (’54, ’55, and ’56) have a five-bit-wide fsr.
Since all registers are eight bits wide, the highest three bits of the fsr in
these devices are fixed, and always read as 1’s. Keep this in mind if you
plan to perform comparisons (such as the last line of the example above)
directly on the fsr. It will always read 224 (11100000b) higher than the
actual address it points to.
The 16C57 has 80 bytes of RAM and a seven-bit-wide fsr. The highest bit
of its fsr is fixed and reads as a 1. Seven bits allows for 128 addresses, but
only 80 are used. The remaining 48 addresses are accounted for by three
16-byte gaps in the 57’s memory map. See the RAM warps in figure 1.
Because these warps map to the lowest file registers of the PIC, they can
cause real trouble by altering data in the special-purpose registers. To
avoid this problem, consider using a subroutine to straighten out the
memory map and avoid the warps. Below is an excerpt from a program
that uses the registers from 10h on up as a storage buffer for up to 64
characters of ASCII text. For the purposes of the program, address10h
is location 0 in the buffer; 7F is location 63.
Page 134 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 7: Direct & Indirect Addressing
buf_ptr mov temp,w
mov fsr, temp
cjae temp,#030h,:bank3
cjae temp,#020h,:bank2
cjae temp,#010h,:bank1
jmp :bank0
:bank3 add fsr,#010h
:bank2 add fsr,#010h
:bank1 add fsr,#010h
:bank0 add fsr,#010h
ret
This model explains the warps in the memory map. Each of the three
warp addresses (20h, 40h, and 60h) has a 0 in the bit-4 position. This
disables banked memory, causing the PIC to disregard all but bits 0
through 3 of the address.
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 135
BLANK PAGE
Page 136 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 8: The PIC16C71 A/D Converter
Introduction. This application note presents a program in Parallax
assembly language that uses the PIC16C71’s built-in analog-to-digital
converter (ADC) to measure an input voltage and flash an LED at a
proportional rate.
1k
1 18
5k pot
RA2/Ain2 RA1/Ain1
2 17
RA3/Ain3 RA0/Ain0
3 16 10k
+5 RTCC/RA4 OSC1
4 15 4.7 pF
MCLR OSC2
5 14
Vss PIC Vdd
6 13
16C71
RB0 RB7
LED 7 12
RB1 RB6
8 11
220
RB2 RB5
9 10
RB3 RB4
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 137
Note 8: The PIC16C71 A/D Converter
reference can be the +5-volt power-supply rail, or some other voltage
source between 3 volts and the power supply voltage + 0.3 volts. The
ADC is most accurate with a reference voltage of 5.12 volts, according
to the manufacturer’s specifications.
Clock Source. The PIC’s ADC, like the PIC itself, requires a clock signal.
The ADC performs a conversion in 10 of its clock cycles, which must be
no shorter than 2µs. Clock signals for the ADC can come from two
sources, the PIC’s own clock or an on-chip resistor-capacitor (RC)
oscillator exclusive to the ADC.
The tradeoff in using the RC oscillator is that its period can vary from
2 to 6µs, depending on temperature and manufacturing tolerances.
Interrupt Enable. The ADC is relatively slow—at 20 MHz the PIC can
execute 100 instructions in the 20µs the ADC takes to make a conver-
sion. In some cases, it makes sense not to force a PIC program to wait in
a loop for a conversion to finish. The alternative is to configure the ADC
to announce “conversion complete” through an interrupt. To keep
things as simple as possible, the example program does not take
advantage of interrupt capability.
Pin Configuration and Voltage Reference. Pins RA.0 through RA.3 can serve
as inputs to the ADC. One of the choices you must make when setting
up the ADC is which pins to configure as analog inputs, which (if any)
as digital inputs, and what to use as a voltage reference. Figure 2 shows
Page 138 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 8: The PIC16C71 A/D Converter
the range of available choices.
Note that the control register containing the configuration and voltage
reference bits is in register page 1. To access it, you must first set bit RP0.
The program listing shows how.
Input Selection. Only one of the pins configured for analog input can
actually sample at any one time. In other words, if you want ADC input
from two or more channels, your program must select a channel, wait
long enough for the sample-and-hold circuit to charge up, command a
conversion, get the result, and select the next channel...
0 0 0 0 0 0 ADIF ADON
7 6 5 4 3 2 1 0
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 139
Note 8: The PIC16C71 A/D Converter
How long should the program wait for the sample-and-hold? Micro-
chip suggests a worst case of 4.67µs plus two ADC clock cycles (after a
conversion, the sample-and-hold takes a two-cycle break before it
begins sampling again).
How it works. The PIC in figure 1 accepts a voltage from a pot wired as
variable voltage divider. The PIC’s ADC, which is set up to use Vdd as
a reference, outputs a one-byte value that’s proportional to the input
voltage. This value controls a timing routine that flashes an LED. When
the input voltage is near 5 volts, the LED flashes about once a second.
When it’s near 0, the LED flashes very rapidly.
The program listing shows how it’s done. Most of the code is devoted
to setting up the ADC. Constants at the beginning of the program are
assigned with values that, when loaded into the appropriate ADC
control registers, turn the ADC’s various features on and off. If you wish
to change, for instance, the pin that the circuit uses for analog input, just
comment out the line containing AD_ch = 0 and uncomment the desired
channel (“commenting” and “uncommenting” are handy techniques
for temporarily removing and restoring instructions in source code.
Putting a semicolon (;) in front of a line causes the assembler to ignore
it, as though it were a comment).
Page 140 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 8: The PIC16C71 A/D Converter
; PROGRAM: Using the 16C71’s analog-to-digital converter (ADC 71.SRC )
; This program demonstrates use of the ADC in a simple circuit that samples a
; voltage and flashes an LED at a proportional rate. The header contains a number
; of constants representing setup constants for the ADC control registers.
; Uncomment the constant corresponding to the desired ADC setting.
; The following constants set the ADC clock source and speed. Uncomment one.
;AD_clk = 0 ; Oscillator x 2 (<= 1 MHz).
;AD_clk = 64 ; Oscillator x 8 (<= 4 MHz).
;AD_clk = 128 ; Oscillator x 32 (<= 16 MHz).
AD_clk = 192 ; RC oscillator, 2–6 us.
; The following constants select a pin for ADC input. Uncomment one.
AD_ch = 0 ; ADC channel 0 (Ain0, pin 17).
;AD_ch = 8 ; ADC channel 1 (Ain1, pin 18).
;AD_ch = 16 ; ADC channel 2 (Ain0, pin 1).
;AD_ch = 24 ; ADC channel 3 (Ain0, pin 2).
; The following constants determine which pins will be usable by the ADC and
; whether Vdd or RA .3 will serve as the voltage reference. Uncomment one.
AD_ref = 0 ; RA .0-3 usable, Vdd reference.
;AD_ref = 1 ; RA .0-3 usable, RA .3 reference.
;AD_ref = 2 ; RA .0/1 usable, Vdd reference.
;AD_ref = 3 ; All unusable—digital inputs only.
device rc_osc,wdt_off,pwrt_off,protect_off
id ‘ADC1’
org 0Ch
counter1 ds 1
counter2 ds 1
; Set starting point in program ROM to zero. Jump past interrupt vector to beginning
; of program. (This program doesn’t use interrupts, so this is really not needed, but it
; will be easier to add interrupts later if required.)
org 0
jmp 5
org 5
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 141
Note 8: The PIC16C71 A/D Converter
:loop call wait ; Delay for time determined by
; ADC input.
setb rb.0 ; Turn LED on.
call wait ; Delay for time determined by
; ADC input.
clrb rb.0 ; Turn LED off.
goto :loop ; Endless loop.
; The number of loops this delay routine makes is dependent on the result of the AD
; conversion. The higher the voltage, the longer the delay.
:loop djnz counter1, :loop
djnz counter2, :loop
ret
Page 142 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
BLANK PAGE
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 143
BLANK PAGE
Page 144 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 9: Managing Multiple Tasks
Introduction. This application note presents a program in Parallax
assembly language that demonstrates a technique for organizing a
program into multiple tasks.
It’s often useful to have the controller do more than one thing at a time,
or at least seem to. The first step in this direction is often to exploit the
dead time from one task—the time it would normally spend in a delay
loop, for instance—to handle a second task. The PIC’s speed makes this
quite practical in many cases.
When several tasks must be handled at once, this approach can quickly
become unworkable. What we need is a framework around which to
organize the tasks. We need an operating system.
The “system” portion of the program acts like a spinning rotary switch.
Each time it executes, it increments the task number and switches to the
next task. It does this by taking advantage of the PIC’s ability to modify
the program counter. Once the task number is loaded into the working
register, the program executes the instruction jmp pc+w. The destina-
tions of these jumps contain jmp instructions themselves, and send the
program to one of the eight tasks. Not surprisingly, a list of jmp
instructions arranged like this is called a “jump table.”
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 145
Note 9: Managing Multiple Tasks
1 18
RA2 RA1
2 17 ceramic resonator
RA3 RA0 w/integral capacitors
+5 3 16
RTCC OSC1
4 15
MCLR OSC2 +5
5 PIC 14
Vss 16C54 Vdd
6 13 470 LED
RB0 RB7
7 12 470 LED
RB1 RB6
8 11 470 LED
RB2 RB5
9 10 470 LED
RB3 RB4
470 LED
470 LED
470 LED
470 LED
With many possible paths through the code for each task, this may seem
like another problem. A straightforward solution is to use the PIC’s
RTCC to time how long a particular task took, then use that number to
set a delay to use up all of the task’s remaining time. All you need to
know is the worst-case timing for a given task.
Page 146 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 9: Managing Multiple Tasks
; PROGRAM: TASK .SRC
; This program demonstrates task switching using the PIC’s relative addressing
; mode. It handles eight tasks, each of which flashes an LED at a different rate. The
; flashing routines base their timing on a master clock variable called ticks.
LEDs = rb
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 147
Note 9: Managing Multiple Tasks
task0 cjne ticks, #255,:cont ; Every 255 ticks of system clock
inc time0 ; increment task timer. Every 3
; ticks
cjne time0, #3, :cont ; of task timer, toggle LED, and
clr time0 ; reset task timer.
xor LEDs, #00000001b
:cont jmp system
Page 148 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 9: Managing Multiple Tasks
task7 cjne ticks, #255,:cont
inc time7
cjne time7, #9,:cont
clr time7
xor LEDs, #10000000b
:cont jmp system
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 149
BLANK PAGE
Page 150 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 10: An External A/D Converter
Introduction. This application note shows how to interface an 8-bit
serial analog-to-digital converter to 16C5x-series PICs.
Interfacing the 831 requires only three input/output lines, and of these,
two can be multiplexed with other functions (or additional 831s). Only
the chip-select ( CS) pin requires a dedicated line. The ADC’s range of
input voltages is controlled by the V REF and VIN(–) pins. V REF sets the
voltage at which the ADC will return a full-scale output of 255, while
VIN(–) sets the voltage that will return 0.
+5
1 8
CS Vcc
2 7
0–5V in Vin(+) ADC CLK
3 0831 6
Vin(–) DO
4 5 +5
GND Vref
1 18
RA2 RA1
2 17
RA3 RA0
470 3 16 ceramic resonator
LED
RTCC OSC1 w/integral capacitors
+5 4 15
MCLR OSC2
5 PIC 14
Vss 16C54 Vdd +5
6 13
RB0 RB7
7 12
RB1 RB6
8 11
RB2 RB5
9 10
RB3 RB4
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 151
Note 10: An External A/D Converter
How it works. The sample program reads the voltage at the 831’s input
pin and uses the eight-bit result to control a timing routine that flashes
an LED. The LED flashes slowly when the input is 5 volts, and very
rapidly as it approaches ground.
The subroutine convert handles the details of getting data out of the
ADC. It enables the ADC by pulling the CS line low, then pulses the clock
(CLK) line to signal the beginning of a conversion. The program then
enters a loop in which it pulses CLK, gets the bit on pin data, and shifts
it into the received byte using the rotate left (rl) instruction. Remember
that rl affects not only the byte named in the instruction, but the carry
bit as well.
When all bits have been shifted into the byte, the program turns off the
ADC by returning CS high. The subroutine returns with the conversion
result in the variable ADresult. The whole process takes 74 instruction
cycles.
Modifications. You can add more 831s to the circuit as follows: Connect
each additional ADC to the same clock and data lines, but assign
separate CS pins. Modify convert to take the appropriate CS pin low when
it needs to acquire data from a particular ADC. That’s it.
; PROGRAM: AD 831.SRC
; Program demonstrates the use of an external serial ADC (National ADC0831) with
; PIC16C5x-series controllers. A variable dc voltage (0-5V) at pin 2 of the ADC
; controls the blinking rate of an LED connected to PIC pin ra.3.
clk = ra.0
data = ra.1
CS = ra.2
LED = ra.3
counter1 ds 1
counter2 ds 1
ADresult ds 1
Page 152 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 10: An External A/D Converter
; Remember to change device info when programming part.
device pic16c54,xt_osc,wdt_off,protect_off
reset start
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 153
BLANK PAGE
Page 154 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 11: Using Serial EEPROMs
Introduction. This application note shows how to use the Microchip
93LC56 EEPROM to provide 256 bytes of nonvolatile storage. It pro-
vides a tool kit of subroutines for reading, writing, and erasing the
EEPROM. (Note that EEPROMs made by other manufacturers will not
work with the PIC16Cxx.)
+5
1 8
CS Vcc
2 7
CK 93LC56 NC
3 6
DI ORG
4 5
DO Vss
1k
1 18
RA2 RA1
2 17
RA3 RA0
3 16 ceramic resonator
+5 RTCC OSC1 w/integral capacitors
4 15
MCLR PIC OSC2
5 14
Vss 16C54 Vdd +5
6 13
RB0 RB7
7 12
RB1 RB6
8 11
RB2 RB5
9 10
RB3 RB4
470
LEDs
(all)
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 155
Note 11: Using Serial EEPROMs
(including the time required to send the instruction opcode and ad-
dress). Once a program has begun reading data from the EEPROM, it
can continue reading subsequent bytes without stopping. These are
clocked in at the full 2 Mbps rate; 1 byte every 4 microseconds.
How it works. The circuit in the figure specifies a 93LC56 EEPROM, but
a 93C56 will work as well. The difference is that the LC device has a
wider Vcc range (2.5–5.5 V, versus 4–5.5 V), lower current consumption
(3 mA versus 4 mA), and can be somewhat slower in completing
internal erase/write operations, presumably at lower supply voltages.
In general, the LC type is less expensive, and a better match for the
operating characteristics of the PIC.
The schematic shows the data in and data out (DI, DO) lines of the
EEPROM connected together to a single PIC I/O pin. The 1k resistor
prevents the PIC and DO from fighting over the bus during a read
operation. During a read, the PIC sends an opcode and an address to the
EEPROM. As soon as it has received the address, the EEPROM activates
DO and puts a 0 on it. If the last bit of the address is a 1, the PIC could
end up sourcing current to ground through the EEPROM. The resistor
limits the current to a reasonable level.
Page 156 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 11: Using Serial EEPROMs
The program listing is a collection of subroutines for reading, writing,
and erasing the EEPROM. All of these rely on Shout, a routine that shifts
bits out to the EEPROM. To perform an EEPROM operation, the
software loads the number of clock cycles into clocks and the data to be
output into temp. It then calls Shout, which does the rest.
If you don’t have the EEPROM data handy (Microchip Data Book,
DS00018D, 1991), you should know about a couple of subtleties. First,
when the EEPROM powers up, it is write protected. You must call
EEnable before trying to write or erase it. It’s a good idea to call EEdisbl
(disable writes) as soon as possible after you’re done. Otherwise, a
power glitch could alter the contents of your EEPROM. Also, you
cannot write all locations (EEWrall) without first erasing all locations
(EEwipe).
If you plan to run your PIC faster than 8 MHz, add one or two nops
where marked in the listing. The clock must be high for at least 500
nanoseconds. The low time must also be greater than 500 ns, but the
move-data, rotate, and looping instructions provide enough delay.
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 157
Note 11: Using Serial EEPROMs
; PROGRAM: EEPROM.SRC
; This program is a collection of subroutines for reading, writing, and erasing the
; 93LC56 (or 'C56) serial EEPROM. As a demonstration, it writes a scanning pattern
; to the 256 bytes of the EEPROM, and then reads it back to eight LEDs connected
; to port rb.
org 8
temp ds 1 ; Temporary variable for EE
; routines
EEdata ds 1 ; Passes data to EEwrite/wrall,
; from EEread
EEaddr ds 1 ; Passes address to EErase,
; EEwrite, EEread
clocks ds 1 ; Number of clock cycles for
; SHiftOUT
tick1 ds 1 ; Timer for Delay--not required for
; EE routines
tick2 ds 1 ; Timer for Delay--not required for
; EE routines
Page 158 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 11: Using Serial EEPROMs
rr EEdata
ijnz EEaddr,:loop
call EEdisbl ; Turn write/erase protection back
; on
mov EEaddr,#0
:loop2 call EEread
mov rb,EEdata
inc EEaddr
call delay
goto :loop2
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 159
Note 11: Using Serial EEPROMs
; Call to protect against accidental write/erasure.
EEdisbl setb CS
mov clocks,#12
mov temp,#EWDS
call Shout
clrb CS
ret
; Erase the byte in EEaddr. Erasure leaves FFh (all 1s) in the byte.
EErase mov temp,#ERAS
mov clocks,#4
setb CS
call Shout
mov clocks,#8
mov temp,EEaddr
call Shout
ret
; Erase the entire EEPROM--all 256 bytes. Call before using EEwrall below.
EEwipe setb CS
mov temp,#ERAL
mov clocks,#12
call Shout
clrb CS
ret
Page 160 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 11: Using Serial EEPROMs
; Check flag to determine whether the EEPROM has finished its self-timed erase/
; write. Caution: This will lock up your program until D goes high.
Busy nop
mov !ra,#1
setb CS
:wait jnb D,:wait
clrb CS
mov !ra,#0
ret
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 161
BLANK PAGE
Page 162 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 12: Using Dynamic RAM
Introduction. This application note covers the use of dynamic RAM
(DRAM) with PIC16C5x series PICs. It presents a circuit using a
Motorola 1-Mb x 1 DRAM IC, and a program in Parallax assembly
language showing how to refresh, write, and read the DRAM’s 1,048,576
bits of storage.
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 163
Note 12: Using Dynamic RAM
Background. When a project requires a large amount of memory at the
lowest possible cost and in the smallest available package, dynamic
RAM (DRAM) is currently the only choice. Unfortunately, DRAM has
a bad reputation for being difficult to work with. That reputation is built
on the experiences of designers squeezing the greatest possible speed
out of the large memory arrays used in general-purpose computers. In
PIC applications, where speeds are more leisurely and 1 kByte is still a
lot of memory, DRAMs can be downright mild-mannered.
DRAM uses even simpler storage cells, consisting of just a capacitor and
a transistor. The state of the cell, set or cleared, is stored as a charge on
the capacitor. However, the capacitor inevitably leaks and loses its
charge over time. When this happens, the stored data is lost.
Page 164 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 12: Using Dynamic RAM
would need 8 rows and 8 columns (28 x 28 = 65,536) and a 1M DRAM,
10 rows and 10 columns (210 x 210 = 1M).
The RAS and CAS lines play an important role in the refresh process.
DRAM manufacturers know that refresh is a pain in the neck, so they
add features to make it easier. For example, just cycling through the
DRAM’s row addresses will satisfy refresh requirements. The DRAM’s
internal circuitry takes care of the rest. This is known as RAS-only
refresh, because all the user has to do is put a sequential row address on
the bus, and blip the RAS line. The MCM 511000A DRAM shown in the
figure supports RAS-only refresh. Although it has 10 bits worth of row
addresses, the DRAM requires that only the lower 9 bits (512 addresses)
be accessed in RAS-only refresh.
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 165
Note 12: Using Dynamic RAM
Not all DRAMs support all refresh schemes, so it’s important to review
the manufacturer’s specifications before finalizing a design. Data on the
MCM 511000A for this application note came from the Motorola Memory
Data book, DL113/D, Rev 6, 1990.
How it works. The sample application shown in the figure and program
listing accepts a stream of input bits, such as the output from a square-
wave generator, and records them into sequential addresses in the
DRAM. At the same time, it echoes these bits to a speaker. When the
DRAM is full, the program plays back the recorded bits through the
speaker until the circuit is shut off or reset.
To demonstrate the circuit, reset the PIC and twiddle the tone-generator
frequency knob. It will take about 52 seconds for the PIC to fill the
DRAM’s 1,048,576 bits of storage. When it does, you will hear the
sequence of tones played back through the speaker. Because the play-
back routine requires fewer instructions than recording, the pitch of the
tones will be slightly higher and the playback time shorter.
What you’re hearing is known as aliasing noise or foldover. The only way
to faithfully reproduce an input frequency is to record two or more
samples per cycle. You will hear this referred to as the Nyquist theorem
or Nyquist limit. If you are interested in modifying this application to
build a recording logic probe or tapeless audio recorder, keep Nyquist
in mind.
Page 166 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 12: Using Dynamic RAM
means that 512 rows are refreshed every 15 milliseconds. Although this
exceeds the maximum refresh time allowed by the DRAM specification,
DRAMs are rated conservatively. Further, you are unlikely to hear the
data errors that may be occurring because of inadequate refresh!
If you want to organize data stored in the DRAM as bytes (or nibbles,
16-bit words, etc.) instead of bits, consult the DRAM specs on “fast page
mode” reads and writes. Using this method of accessing the DRAM,
you issue the row address just once, then read or write multiple
columns of the same row. This would be faster and simpler than eight
calls to the single-bit read and write routines presented here.
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 167
Note 12: Using Dynamic RAM
; Set starting point in program ROM to zero
org 0
Page 168 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 12: Using Dynamic RAM
clrb CAS ; Strobe in the column address.
movb Sout,Din ; Copy the DRAM data to the
; speaker.
setb RAS ; Conclude transaction by
; restoring
setb CAS ; RAS and CAS high (inactive).
ret
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 169
BLANK PAGE
Page 170 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 13: Running at 32 kHz
Introduction. This application note presents a method for operating
the Parallax Downloader from a watch crystal. Example programs
show how to receive RS-232 serial data at 300 and 1200 baud with a PIC
running at 32.768 kHz.
This makes it easy to forget about the LP-series PICs, whose virtue is
their ability to go very slow. At 32 kHz, these devices draw as little as
15µA; good news for battery- or solar-powered applications.
Life in the slow lane requires some slightly different techniques than
multi-megahertz PIC design. First of all, you’ll need to get acquainted
with the 32.768-kHz quartz crystal. This is the crystal of choice for LP
PICs. Why 32.768 kHz? It’s the standard timing reference for electronic
watches. It resonates exactly 2 15 times per second, making it easy and
inexpensive to build a chain of counters to generate 1-pulse-per-second
ticks. Because of common use in watches, 32.768-kHz crystals are
inexpensive (often less than a buck in single quantities) and accurate
[±20 parts per million (ppm), compared to the ±50 ppm common in
garden-variety clock crystals, or ±3000 ppm of ceramic resonators).
At a clock rate of 32.768 kHz, the PIC executes 8192 instructions per
second, with instruction cycles taking about 122.1 microseconds each.
Whether or not this is slow depends on your perspective—many
applications spend most of their time in delay loops anyway.
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 171
Note 13: Running at 32 kHz
for the ’5160, you will have to 10k
play with the values of the
CA5160 +5
feedback resistor (10k) and To Downloader
2 7 OSC1 terminal
capacitor (0.001µF) to get the 0.001µF –
circuit to oscillate. If you use 3 + 4
6
With the help of one of these oscillators, you can have Downloader
convenience in the development of LP applications.
Page 172 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 13: Running at 32 kHz
oscillator is running at 4 MHz, resolution is a respectable 3 microsec-
onds. However, at 32.768 kHz, the resolution of a djnz loop is 366.3
microseconds!
RS-232
serial in 22k 1 18
RA2 RA1
2 17
RA3 RA0 32,768-Hz 15- to 30-pF
+5 3 16 XTAL caps
RTCC OSC1
4 15
MCLR OSC2
5 PIC 14
Vss Vdd +5
16C54
6 13 470 LED
RB0 RB7
7 12 470 LED
RB1 RB6
8 11 470 LED
RB2 RB5
9 10 470 LED
RB3 RB4
470 LED
470 LED
470 LED
470 LED
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 173
Note 13: Running at 32 kHz
to use a two-step approach that creates most of the delay using loops
and then pads the result with nops. Otherwise, you could end up filling
most of your code space with nops.
Listing 2 uses the same circuit to receive 1200-baud serial data. A bit
delay at 1200 baud is 833.33 µs, which is 6.8 instruction cycles at 32.768
kHz. There’s no instruction that offers a 0.8-cycle delay, so the routine
gets bit 0 as early as possible after the start bit is detected (7 instruction
cycles) and then uses a 7-cycle delay between subsequent bits. The
program is written so that it samples the first bit early, and spreads the
timing error over the rest of the reception of the byte.
Page 174 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 13: Running at 32 kHz
org 8
bit_cntr ds 1 ; number of received bits
rcv_byte ds 1 ; the received byte
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 175
Note 13: Running at 32 kHz
ret ; w = 15—executes 0 nops
; If w > 15, the program will jump into unprogrammed code memory, causing a reset.
Page 176 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 13: Running at 32 kHz
nop ; (1)
nop ; (1)
movb rcv_byte.4,/serial_in ; (4) Get bit 4.
nop ; (1)
nop ; (1)
nop ; (1)
movb rcv_byte.5,/serial_in ; (4) Get bit 5.
nop ; (1)
nop ; (1)
nop ; (1)
movb rcv_byte.6,/serial_in ; (4) Get bit 6.
nop ; (1)
nop ; (1)
nop ; (1)
movb rcv_byte.7,/serial_in ; (4) Get bit 7.
mov data_out,rcv_byte ; (2) Data to LEDs.
jmp :start_bit ; (2) Do it again
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 177
BLANK PAGE
Page 178 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 14: Generating/mixing Sine Waves
Introduction. This application note illustrates methods for generating
audio-frequency waveforms using lookup tables.
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 179
Note 14: Generating/mixing Sine Waves
How it works. The resistors in figure 1 are connected in an array known
as an R-2R ladder. This arrangement has an interesting property. It
divides each voltage present at its inputs by increasing powers of two,
and presents the sum of all these divided voltages at its output. Since the
PIC is capable of driving its outputs from rail to rail (0 to +5 volts), the
R-2R ladder converts the binary number present on port B into a
proportional voltage from 0 to 5 volts in steps of approximately 20
millivolts.
RB7 RB0
analog
voltage out
The program that drives the D/A converter begins by setting port rb to
output and clearing its variables. Next it enters this loop:
Page 180 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 14: Generating/mixing Sine Waves
The loop always takes the same amount of time to execute, so how do
freq1 and freq2 control the frequency? If the value of freq1 is 1 and acc1
starts out at 0, the program will complete 255 loops before acc1 over-
flows, generating a carry. Phase1 will increment once in every 256 loops.
This will produce a low output frequency. If freq1 is 100, acc1 will
overflow on the third trip through the loop, so phase1 will increment
much faster, producing a higher frequency.
Perhaps the most useful modification is this: Set freq1 and freq2 to the
same value, say 100. Run the program and listen to the tone or observe
it on the ‘scope. If you use a scope, make note of the peak-to-peak
amplitude of the tone. Now substitute mov phase1, #7 for clr phase1 at the
beginning of the program. Run the program again. Do you hear (see)
how the amplitude of the tone has fallen off? Try once more with mov
phase1,#8. No tone at all. This is a graphic illustration of how out-of-
phase sine waves of the same frequency progressively cancel each
other. The 16 sine table entries represent amplitudes at intervals of 22.5
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 181
Note 14: Generating/mixing Sine Waves
degrees. When phase1 is initialized with a value of 8, while phase2 is zero,
the phase shift between the two is 22.5 x 8 = 180 degrees. Two sine waves
180 degrees out of phase cancel each other totally. Smaller phase shifts
produce proportionally less attenuation.
Given the PIC’s limited math capabilities, this phase shifting technique
is an easy way to control the overall amplitude (volume) of the tones
you generate.
; Device data and reset vector (remember to change if programming a different part).
device pic16c54,xt_osc,wdt_off,protect_off
reset start
org 0
Page 182 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 14: Generating/mixing Sine Waves
mov temp,w ; Store 1st sine value in temp.
mov w,phase2
call sine ; Get value from table.
add temp,w ; Add sines together.
mov output,temp ; Output to D/A.
goto :loop ; Do forever.
; Notice that the sine values in the table below are scaled so that no pair adds to
; more than 254. This prevents overflowing the variable temp when the phases are
; added together. If you add more phases, adjust the maximum values in this table
; appropriately. The values are in increments of 22.5 degrees (0.3927 radians).
sine jmp pc+w
retw 64,88,109,122,127,122,109
retw 88,64,39,19,5,0,5,19,39
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 183
BLANK PAGE
Page 184 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 15: Using Interrupts
Introduction. This application note shows how to use the interrupt
capabilities built into the PIC 16Cxx series controllers with a simple
example in Parallax assembly language.
If there were no fire bell, the job would be much different. The fire crew
would have to go out and look for fires, and somehow still make sure
that the hoses were fixed and the truck maintained. In their scurry to get
everything done, they might respond late to some fires, and miss others
completely.
The newer PIC 16Cxx controllers have interrupts, which work like the
fire bell in the first example. When an interrupt occurs, the PIC stops
what it’s doing and handles the cause of the interrupt. When it’s done,
the PIC returns to the point in the program at which it was interrupted.
How interrupts work. For the examples here, we’re going to talk
about the 16C84. The same principles apply to the other interrupt-
capable PICs, such as the 16C71 and 16C64, but registers and interrupt
sources may vary.
First of all, the 16Cxx PICs awaken from power-up with all interrupts
disabled. If you don’t want to use interrupts, don’t enable them. It’s that
simple.
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 185
Note 15: Using Interrupts
• Changing inputs to pins RB4 through RB7.
• Timer (RTCC) overflow from 0FFh to 0.
• Completion of the data EEPROM programming cycle.
You can enable any combination of these sources. If you enable more
than one, it will be up to your code to determine which interrupt
occurred and respond appropriately. More on that later.
The program’s startup code configures the RTCC for its initial 500-µs
timing period, and enables the interrupt. To do so, it turns on the first
two bit switches shown in figure 1. For any interrupt to occur, the
global-interrupt enable (GIE) bit must be set. For the timer interrupt to
occur, the RTCC inter-
rupt enable (RTIE) bit
INTERRUPT
must be set. Once those Global Timer Timer
two switches are Interrupt Interrupt Interrupt
Enable Enable Flag
closed, only one switch (GIE) (RTIE) (RTIF)
remains before the in-
terrupt “alarm bell”
goes off—the RTCC in-
terrupt flag (RTIF).
Page 186 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 15: Using Interrupts
the stack, then jumps to location 4. This process takes four instruction
cycles for an internal interrupt like the RTCC, five for an external
interrupt like RB0/INT.
Once at location 4, the PIC executes the code there until it encounters a
ret, retw, or reti instruction. Any of these will pop the value from the top
of the stack and cause a jump back to the point at which the program was
interrupted. However, the normal way to return from an interrupt is the
reti instruction. It automatically re-enables interrupts by setting GIE.
The other two returns do not.
In the program listing, you will notice that the first thing the interrupt
handler does is clear RTIF. Whenever the RTCC rolls over from 0FFh to
0, the PIC automatically sets RTIF. It does this regardless of the state of
the interrupt bits. And it never turns RTIF back off. So it’s the respon-
sibility of the interrupt handler to clear RTIF. This is true of all of the
interrupt flags. If the handler doesn’t clear the appropriate flag, the
same interrupt will occur again as soon as interrupts are re-enabled. The
resulting endless loop is what the Microchip documentation calls
“recursive interrupts.”
Imagine that right after delta is loaded into w, the interrupt takes over.
It performs, for instance, the instruction mov rb,data. This instruction
loads the variable data into w, then moves w into rb. When it’s done, w
contains a copy of data.
When the handler returns, the PIC completes the interrupted addition.
But w contains data, not the intended delta, causing an error.
There are two ways to prevent this. One is to disable interrupts before
a two-part instruction, then enable them again afterwards. If the inter
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 187
Note 15: Using Interrupts
rupt event occurs while interrupts are disabled, the PIC will set the
interrupt flag, but won’t jump to the handler until your program re-
enables interrupts. The PIC will not miss the interrupt, it will just be
slightly delayed in handling it. To use this method, the example above
would be changed to:
This takes care of compound instructions that use w, but leaves another
group of instructions vulnerable; the ones that use the status register.
Conditional jumps and skips like jump-if-zero (jz) and compare-and-
jump-if-equal (cje) and their many cousins are probably obvious. More
subtle are the rotate instructions rr and rl (which pull the carry bit into
the most- or least-significant bit of the byte being rotated). If the
interrupt handler affects any of the status bits, it may alter the outcome
of the interrupted instruction.
To protect w and status, you must make copies of them at the beginning
of a handler, then restore those copies at the end. In order to prevent the
action of restoring w from affecting status, you can use a sneaky trick.
Moving a file register into w will set or clear the zero bit, but moving a
nibble-swapped copy of the register into w does not. Neither does
swapping the nibbles of a file register. The program listing shows how
to use these loopholes to accurately copy both w and status.
Once you understand how the mechanism works with a single inter
Page 188 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 15: Using Interrupts
rupt source, you’ll be relieved to know that it’s not that much more
difficult to handle multiple interrupt sources. Figure 2 shows the alarm-
bell diagram for multiple interrupts on the 16C84. If you have all of the
16C84’s interrupts enabled, your handler at 04h should begin with
something like:
Code at each of those labeled locations (rb0_edge, etc.) would then deal
with that particular type of interrupt. Remember that each of the
handlers must clear its
corresponding flag; for
example, rb0_edge EEIE EEIF
must include the instruc-
tion clrb INTF. RTIE RTIF INTERRUPT
an interrupt? At that
time, nothing. Remem-
ber that the PIC clears
GIE automatically in re-
sponse to an interrupt, INTE/F = RB0 interrupt enable/flag bits
then sets it when rti ex- RBIE/F = RB4–7 change interrupt enable/flag bits
RTIE/F = RTCC overflow interrupt enable/flag bits
ecutes. Any interrupt EEIE/F = EEPROM write complete interrupt enable/flag bits
event that occurs in the
meantime will set the
appropriate flag. That Figure 2. Logic of all four 16C84
interrupt will be delayed interrupts.
until after the current
one is finished.
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 189
Note 15: Using Interrupts
; Program: INTRPT.SRC (Interrupt demonstration)
; This program illustrates the use of the RTCC interrupt
; in the PIC 16C84. The foreground program blinks an LED on
; pin ra.0, while an interrupt task outputs a 1-kHz square
; wave through pin ra.1 (assuming a 4-MHz clock).
Page 190 • PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333
Note 15: Using Interrupts
; Here’s the startup routine and the main program loop.
; In the line that initializes “intcon,” bit 7 is GIE and bit 5
; is RTIE. Writing 1s to these enables interrupts generally (GIE)
; and the RTCC interrupt specifically (RTIE).
Start
mov !ra,#0 ; Make ra pins outputs.
setb rp0 ; Switch to register page 1.
clr wdt ; Assign prescaler to rtcc.
mov option,#0 ; Set prescaler to divide by 2.
clrb rp0 ; Restore to register page 1.
mov intcon, #10100000b ; Set up RTCC interrupt.
PIC16Cxx Applications Handbook 1.1 • Parallax, Inc. • (916) 624-8333 • Page 191