Professional Documents
Culture Documents
-...r- MICROCONTROLLERS
FROM
David Benson
Tirne'n and Count'n
FROM
DAVID BENSON
VERSION 2.0
NOTICE
TRADEMARKS
PIC
MPLAB
MPASM
MPSIM
PUBLISHER
Square 1 Electronics
P.O. Box 501
Kelseyville,CA 95451 U.S.A.
FROM
PREFACE 1
INTRODUCTION 3
This material presented in this book is the timing and counting information which previously
appeared in PIC'n Techniques. Unfortunately, because of trademark issues, it has become
mandatory that we change the titles of four of our books . The old and new titles appear on our
web site. Since the titles are changing, we are using this as an opportunity to move some topics
from one book to another to improve the flow from one topic to the next. Again, the details
appear on our web site. We regret any inconvenience and confusion that results from these
changes.
The more current PIC16F870 is substituted here for the PIC16C63 that was used in some of the
examples in PIC'n Techniques. The F870 has in-circuit debugging (ICD) capability which is
very useful. If you choose to use the lCD, the test/demo circuit must be modified slightly to
make use of Microchip's ICD possible (via ports RB7,6) . The code must be modified slightly
for the same reason. Details appear in Appendix F - Using The ICD.
The examples based on the PIC16F84 remain essentially unchanged. The PIC16F84A is the
current version of this device. I will simply refer to it as the F84. The demonstration circuit
module is called the '84 on a board to be compatible with our previous books which use the
same circuit. Other small PIC ® devices may be used instead if you prefer as long as the code is
adapted as necessary.
Finally, "Thank You" to all the readers who have made suggestions over the years which have
contributed to the refinement of this material.
GENERAL INFORMATION
See our web site at http://www.sq-l.com for updates, for errata, and for downloading the code
in this book at no cost.
1
2
INTRODUCTION
'nme'n and Count'n is an intermediate level book. I am assuming you know all the beginner
information included in Easy PIC'n or Easy MlC1'OCOntrol'n (our beginner books) either from
using the book or from other experience. Some of the circuits used in
PIC'n Up The Pace orMicrocontrol'n Apps are used in this book as well. These circuits are
shown in appendices in the back of this book. Complete explanations may be found in PIC'n Up
The Pace or MiCl'OCOntrol'n A~
The programs included in this book are examples to help you learn. My hope is that you will
study the examples in this book and write your own borrowing from what you see here. If you
want to borrow from the code in this book, it is currently available for downloading at the
Square 1 website (no charge) .
For those of you who already know a little bit about PIC microcontrollers, here is my philosophy
about some of the topics to be covered :
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 microcontroller programming,
you may find them useful.
My objective is to write code that you can understand rather than try to optimize for minimum
number of program steps and/or for fastest possible execution . Where programs used previously
in this book or borrowed from PIC'n Up The Pace or Microcontrol'n Apps are combined for
use in a more exotic application, I did not rewrite the code to achieve double duty (shared) use
of file registers.
The PIC 16F870 test circuit and code examples in this book are presented as they would be when
using a device programmer to program the F870 . The circuit and code examples may be easily
changed for ICD use per the instructions in Appendix F - Using The ICD.
The F870 is used as the example in this book, however the material is device independent.
I think you will particularly enjoy the test equipment projects which combine the techniques you
will learn in functional equipment. The real fun, however, is to take all this a step further on
your own by using these techniques to design and build PIC microcontroller
based systems for your own applications.
3
TEST EQUIPMENT FOR
TIMING AND COUNTING EXPERIMENTS
Since I don't have a storage oscilloscope, I built a PIC microcontroller-based pulse detector
which measures the width of a single pulse . This device can be used to test the output of an
example circuit when a short pulse (4 to 255 microseconds range) is produced. To develop this,
I used two '84 on a board circuits, one to generate a pulse of known length and the other to
detect it and measure (verify) the pulse width . The '84 on a board circuit for experimenting is
presented in Appendix C.
128.asm pgenlsl.asm
PIC16F84A PIC16F84A
8 LEDs
.....r---L...
RBO RAO Port B r--
.. ~
-
680
::! !!:
--
For initial test purposes, the sending '84 generates a 128 microsecond pulse and the receiving '84
counts up in microseconds while the pulse is high and displays the result via LEDs at port B.
Simple! Then the detection/measuring device can be used to look for a short pulse generated by
a PIC16F870 using the techniques we will develop later in this book.
4
The pulse generator (sender) looks like this:
ROO
+5VDC
PIC16F84A
10K .. ~
RB1
The program used to generate the 128 microsecond test pulse is:
Setup
Send
No
Test
No
Count = 128?
5
i=======128.ASM=====================================4/17/02==
itimer/counter demo
single time interval
internal clock
128 microsecond pulse out
i----------------------------------------------------- - - - - - - -
list p=16f84a
__config h'3ffl'
radix hex
j----------------------------------------------------- - - - - - - -
cpu equates (memory map)
tmrO equ OxOl
status equ Ox03
portb equ Ox06
intcon equ OxOb
opt reg equ Ox8l
trisb equ Ox86
j--------------------- -------------------------------- - - - - - - -
bit equates
rpO equ 5
j------ --------------- ----------------- --------------- - - - - - - -
org OxOOO
end
j--------------------------------------------- -------- - - - - - - -
6
iat device program time, select:
code protection off
watchdog timer disabled (default is enabled)
standard crystal XT (using 4 MHz osc for test)
power-up timer on
;============================================================
The width of the pulse is actually 129 microseconds because an additional microsecond is need-
ed to clear port B, bit 0 after the timer times out.
Signal RAO
+SVDC PIC16F84A
SLEDs
10K
.-----1 RA1 Port B
680
~'~l -
No
-.
The object is to count pulses from a source of known frequency (internal instruction clock, 1
MHz) while the incoming pulse to be measured is high. The count will be the pulse width in
microseconds.
This is similar in concept to using an AND gate . An unknown time interval may be measured
by using the time interval signal to gate a second signal of known frequency.
Unknown TIme
Interval
TIme Interval = Pulses = Pulses
Frequency PulseslTime
The signal of known frequency will appear at the output of the AND gate only while both sig-
nals are high. The pulses appearing at the output of the AND gate are then counted . The num-
ber of pulses divided by the frequency (multiplied by the period) of the reference signal is the
time interval.
7
The flow chart for the program is:
Setup
No
Yes
No
--r- ?
No
~?
DisplayTMRO At Port B
LEOs
8
The code follows:
;=======PGENTST.ASM=================================4/17/02==
list p=16f84a
__config h'3ff1'
radix hex
j----------------------------------------------------- - - - - - - -
cpu equates (memory map)
tmrO equ Ox01
status equ Ox03
porta equ OxOS
portb equ Ox06
opt reg equ Ox81
trisa equ Ox8S
trisb equ Ox86
j----------------------------------------------------- - - - - - - -
bit equates
rpO equ S
,
e _
org OxOOO
end
,
e _
9
Code for generating pulses of four different width follows. The code will be used in conjunction
with an '84 on a board to test circuits presented later in the book.
ABO
+5VDC
PIC16F84A
10K "10'
AB1
;=======32.ASM======================================4/17/02==
;timer/counter demo
single time interval
internal clock
32 microsecond pulse out
j -------------- --------------------------------------- - - - - - - -
list p=16f84a
__config h'3ff1'
radix hex
i----------------------------------------------------- - - - - - - -
cpu equates (memory map)
tmrO equ Ox01
status equ Ox03
portb equ Ox06
intcon equ OxOb
opt reg equ Ox81
trisb equ Ox86
i-------------------------------------------------- --- - - - - - - -
bit equates
rpO equ 5
i---------------------- ------ - --- - ------ -------------- - - - - - - -
org OxOOO
10
bcf intcon,2 iclear TMRO interrupt flag
bcf intcon,7 idisable global interrupts
bcf intcon,5 idisable TMRO interrupts
clrf tmrO iclear TMRO
clrwdt iclr WDT prep prescale assign
bsf status,rpO ito bank 1
movlw b'l1011111' iset up timer/counter
movwf opt reg
bcf status,rpO iback to bank 0
send btfss portb,l iswitch open?
goto send inot yet
clrf tmrO istart timer/c, clr prescaler
bsf portb,O istart pulse
test btfss tmrO,5 ilook for count=32
goto test inot yet
bcf portb,O iend pulse
circle goto circle idone
end
;------------------------------------------------------------
iat device program time, select:
code protection off
watchdog timer disabled (default is enabled)
standard crystal XT (using 4 MHz osc for test)
power-up timer on
j============================================================
The width of the pulse is actually 33 microseconds because an additional microsecond is needed
to clear port B, bit 0 after the timer times out.
The 33 microsecond pulse can be detected and its width measured using a second '84 on a board
and pgentst.asm as was done for thel28 microsecond example.
11
Main
Program
Send
No
Start Count
Port B, Bit 0 HI
Start Pulse
Interrupt
ClearTMRO
Service Interrupt Flag
Routine
~
Port B, Bit 0 LO
End Pulse
~
Return From Interrupt
12
i=======2000.ASM====================================4/17/02==
itimer/counter demo
single time interval
internal clock divided by 8
2000 microsecond pulse out
,._-----------------------------------------------------------
list p=16f84a
__config h'3ff1'
radix hex
,
e _
13
iserv bcf intcon,2 iclear TMRO interrupt flag
bcf portb,O iend pulse
retfie idone
end
;------------------------------------------------------------
iat device program time, select:
code protection off
watchdog timer disabled (default is enabled)
standard crystal XT (using 4 MHz osc for test)
power-up timer on
j===================================================== =======
As with the previous example, power up with the send switch closed. Open the switch to send
the pulse. The pulse is too wide to be measured with the F84 pulse detector, so an oscilloscope
is needed .
Finally, we will need a program to output a pulse 65280 microseconds wide . This program uses
timer 0 and a file register counter called "count" to count the number of times timer 0 rolls over.
The sequence starts with timer 0 clear and the count register loaded with OxFF. When the num-
ber of pulses fed into timer 0 reaches 65,280, timer 0 rolls over for the 255th time and the count
register contains zero . To look at this another way, the program decrements the count register
each time timer 0 overflows . When the contents of count reaches zero, the game is over and the
number of pulses received by timer 0 is 65,280 .
RBO
+SVDC
PIC16F84A
10K ....
RB1
14
Main
Program
Disable Global
Interrupts
No
Port B, Bit 0 HI
Start Pulse
DECFSZ
Port B, Bit 0 LO
End Pulse
15
i=======65280.ASM=================================== 4/17/02==
itimer/counte r demo
single time interval
internal clock
65280 microsecond pulse out
;-- - - - -- - - ---- -- - - -- - ---- - - - - -- - -- - --- - - --- - - - - -- - - - - - --- - - --
list p=1 6f84a
__config h'3ff1'
radix hex
;------------- ----- -------------- ----------------------------
cpu equates (memory map)
tmrO equ Ox01
status equ Ox03
portb equ Ox06
intcon equ OxOb
count equ OxOc
opt reg equ Ox81
trisb equ Ox86
;----------------------- - - - - ---------- ----- ------------------
bit equates
z equ 2
rpO equ 5
; ---- - -------------- ----- -------- ----------------------------
org OxOOO
goto start iskip over location pointed
to by interrupt vector
org OxOO4
goto iserv
16
bsf intcon,7 ;enable global interrupts
bcf intcon,2 ;clear TMRO interrupt flag
bsf intcon,5 ;enable TMRO interrupts
circle goto circle ;wait for interrupt
end
;------------------------------------------------------------
;at device program time, select:
code protection off
watchdog timer disabled (default is enabled)
standard crystal XT (using 4 MHz osc for test)
power-up timer on
;============================================================
As with the previous example, power up with the send switch closed . Open the switch to send
the pulse. The pulse is too wide to be measured with the F84 pulse detector, so an oscilloscope
is needed .
An '84 on a board can be used easily to generate a 100 KHz square wave for test purposes. A
simple software delay loop does the job.
REO 1------
PIC16F84A
17
Initialize
Again
10J,l.Sec
2
10 Cycles Total
i=======FREQOUT.ASM=================================4/17/02==
itimer/counter demo
100 KHz out
internal clock
i-------------------------------- - -------------------- - - - - - - -
list p=16f84a
__config h'3ff1'
radix hex
;------------------------------------------------------------
cpu equates (memory map)
status equ Ox03
portb equ Ox06
opt reg equ Ox81
trisb equ Ox86
j----------------------------------------------- ------ - - - - - - -
bit equates
rpO equ 5
;------------------------------------------------------------
org OxOOO
18
nop
nop
bcf portb,O ;output low
nop
nop
goto again
end
;------------------------------------------------------------
;at device program time, select:
code protection off
watchdog timer disabled (default is enabled)
standard crystal XT (using 4 MHz osc for test)
power-up timer on
;============================================================
19
USING TIMER 1, TIMER 2
AND
THE CAPTURE/COMPARE/PWM MODULE
Timer 1 (TMRl), timer 2 (TMR2), and capture/compare/PWM (CCP) modules are found in
many PIC parts . A test circuit based on the PIC 16F870 is shown here as an example you may
use for experiments. I elected to use a 16-pin DIP socket as a connector for port B so that the
keypad board described in "PIC' n Up The Pace" or "Microcontrol'n Apps" (see Appendix E)
can be connected via a 16-conductor ribbon cable with DIP plugs. This scheme requires putting
the LEDs for port B on a separate small board with a 16-pin DIP socket used as a connector.
The LED board is connected for all experiments except those utilizing the keypad .
20
Gnd +SV
T r t T T t I() () ,
DIP Socket
6 432 S o 10!1.: 0.1 EL
L..-.,---r-~----r-..-----r----r-.....,.~-.1 Tesl T T
Point
+SV.--t---1t-t---1_h
==- +SV
RB7 RB6 RBS RB4 RB3 RB2 RB1 RBO Vdd Vss RC7 RCG RCS RC4
PIC16F870
+SV ~ TOCKI ClKI ClKO CCP1
Vpp RAO RA1 RA2 RA3 RM RAS Vss OSC1 OSC2 RCO RC1 RC2 RC3
L
N.C.
~
"
1000,--_-+_t--I_t--I--it4.--f-----1t----+---.-+-_+-__-+----'
Reset 1 . ~ .. ~ . ~
+sv
.- t--
-
cilp Xtal Cap
Serial Output TMRO Input +SV • Sockets
To PIC/lCD,
Input
i TMR1 Input CCP1
4.0 MHz
All Pullup Resistors 10K CIockOsc • Cap = 22 pI (2 reqd'
Xtal =32.768 KHz
1-i.
N.C.
Sockets to allow removal.
Parts used lor external clock
experiment only
TC BOARD
21
LED BOARD
6800
8LEDs
Port B
I like to use SIP resistor networks (10-pin, 9 resistors bussed) and LED bargraph displays. The
bargraphs I have found have 10 LEDs, so I cut two off with a hacksaw and filed the cut end
smooth. The result is a neat, small board.
• Eight port B pins brought out to a 16-pin DIP socket for use with LED board or
keypad board.
• Three DIP switches with pullup resistors on port B for use with the keypad.
• Connections for TMRO (input), TMR1 (input), and the CCP1 module (input/output).
• Two DIP switches with pullup resistors for use as inputs (RAO, RA2).
• Sockets for a 32.768 KHz crystal and two 22 pF capacitors for use with TMR1 .
• Serial output pin for use with a PIC/LCD circuit (RA1)(see PIC'n Up The Pace or
Microcontrol'nAppsz, and Appendi x D for details).
• Pullup resistors on the unused pins .
On my breadboard, I used the following DIP switch and terminal block assignments/layout. To
help avoid confusion, a list of switch settings will be shown for each experiment so you won't
have to think so hard about which switches should be open and which ones should be closed.
22
,.....- RAO
- RA1
- RA2
~ RA4ITOCKI
- RCOIT10S0
,.....- RC1/T10S1
+SVDC
~ RC2ICCP1
T
10K"~ .. ~
100001
- CCP1
.. ~ .....~_ ............
- . 10K - TMR11npul
- TMROlnput
DIP Switches
1234567
ococccc
I leave the LED board connected to the TC board for all experiments except those involving the
keypad. This way, I know the port B lines are not left floating. The 3 port B DIP switches are
open except when the keypad is connected.
23
The simple program shown may be used to see if your PIC16F870 circuit comes alive. The
LEDs at port B bits 7, 6, 5,4 should be off and the remaining four should be on.
DIP Switches
1 2 345 6 7
o C 0 C C C C
i=======PGMR1.ASM==========================12/20/01==
list p=16f870
__config h'3f71'
radix hex
;----------------------------------------------------
cpu equates (memory map)
status equ Ox03
porta equ Ox05
portb equ Ox06
portc equ Ox07
trisa equ Ox85
trisb equ Ox86
trisc equ Ox87
adconl equ Ox9f
i----------------------------------------------------
bit equates
rpO equ 5
i----------------------------------------------------
org OxOOO
start bsf status,rpO iswitch to bank 1
movlw b' 00000110' iturn off A/D, port A
movwf adconl
movlw b'OOOOOOOO' iinputs/outputs
movwf trisa
movwf trisb
movwf trisc
bcf status,rpO iback to bank 0
movlw OxOf iload w with bit pattern
movwf portb iload port B with contents of W
circle goto circle idone
end
i-----------------------------------------------------
iat device programming time, select:
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal (using 4 MHz osc for test) XT
power-up timer on
brown-out reset enabled
lvp disabled
debug mode disabled
;=====================================================
24
BEFORE WE TAKE OFF
The register addresses used in the examples are for the PIC16F870. If you plan to use a different
device, check the Microchip data book to be sure the addresses are correct for the device you
intend to use.
The PIC16F870 peripheral control register descriptions are in Appendix B called "Control
Registers" in the back of the book so you can find them easily for reference.
TMRl, TMR2 and the CCP modules are "peripherals" . The list of modules considered "periph-
erals" is device (part number) dependent. Note that timer 0 (TMRO) is not called a peripheral
and that the register bits that control it are not in the peripheral control registers (they are in the
status register).
There is a peripheral interrupt enable (pIE) register and a peripheral interrupt (flag) register
(pIR). Note that there is a peripheral interrupt enable bit in the interrupt control (INTCON) reg-
ister which must be set to allow interrupts from any of the peripherals. Remember also that the
global interrupt enable bit in the INTCON register must be set to allow peripheral interrupts.
Remember that an "interrupt" flag may be polled to determine its status instead of using it to
trigger an interrupt.
The INTCON register in the PIC16F870 is not the same as for the PIC16F84. The difference is
bit 6 which is the peripheral interrupt enable bit in the F870 where as in the F84 it is the EE
write complete interrupt.
The PIC16F870 has two CCP modules designated CCPl and CCP2 . We will use only CCPl
(and will ignore the existence of CCP2) to simplify the learning process .
Finally, the output of the timing and counting examples will, in general, be slightly inaccurate
because of things like a program loop looking for a bit to change state catching it a cycle or two
after it actually occurs or because of program steps taking a few extra instruction cycles. In
most cases, the error will be very small and inconsequential. If these errors are significant in
your particular application, you can analyze the code and compensate by changing the value(s)
loaded into the timer to correct the results . Or you can simply change the values used to correct
the output and forget about analysis (assuming your measuring equipment is more accurate than
a crystal-controlled PIC microcontroller).
25
TIMER 2 (TMR2): 8-BIT TIMER
• 8-bit timer.
• Source of pulses is the internal instruction clock (timing applications only).
• Prescaler divides the incoming pulse train by 1,4, or 16.
• Postscaler divides the comparator output by 1,2,3 .... 16
• 8-bit period register (PR2) .
• Comparator to look for TMR2/PR2 match .
• TMR2 may be cleared, written to, or read at any time.
• The period register may be written to or read.
• TMR2 may be used as a general purpose timer.
• TMR2 may be used with the CCP module for PWM.
• TMR2 may be used with the SSP module for baud rate generation.
TMR2 Description
Reset
TMR2
Internal Prescaler Postscaler Interrupt
Clock
Flag
1,4,6 1,2,3,---,16
TMR2 is incremented by the internal instruction clock (fosc/4) (prescaled) from OxOO until it's
contents match the period register. On the next increment, it is reset to OxOO. For each match of
TMR2 and its period register, a pulse is output to a postscaler. The postscaler output sets the
TMR2 interrupt flag in the PIRI register. The output of the TMR2 module may be :
• Read TMR2.
• TMR2 interrupt flag.
The match output from the comparator (directly) is used to reset TMR2 in PWM applications
(see PWM section), and is used in SSP serial applications (baud rate).
26
The interrupt generated by TMR2 is called both the TMR2 interrupt and the TMR2 match inter-
rupt in the Microchip literature. The term match interrupt implies that an interrupt occurs at
every match, which may not be true depending on the postscaler ratio. We will refer to this
interrupt as the TMR2 interrupt.
TMR2 can be turned on or off via a control bit in the TMR2 control register T2CON.
• Write to TMR2.
• Write to T2CON, the TMR2 control register.
• Any device reset (pOR, BOR, MCLR, WDT).
T2CON register:
Bit(s)
Interrupts
Bit
Bit
Bit
27
TMR2 Application· Free Running Mode (via TMR2 interrupt)
The first example is similar to the TMRO free running mode with internal clock example in
Sug Ple'n or Sug Microcontrol'n.
Use internal clock, prescaler 1:16, postscaler 1:16, period 255.
Time interval 65 milliseconds.
Output to port B, bit o.
PIC16F870
RBO
680
-...
28
Main Interrupt
Clear TMR2 Interrupt
Program Service
Flag
Routine
Disable Global
Interrupts
Disable Peripheral
Interrupts
29
Unimplemented
I Postscaler 1:16
T2CON --------- 1 I0
<c-:
DIP Switches
1 2 345 6 7
o C 0 C C C C
POR = OxOO
L Prescaler 1:16
TMR20ff
i=======TMR2.ASM====================================4/28/02==
list p=16f870
__config h'3f71'
radix hex
;------------------------------------------------------------
itimer 2 demo
free running, time interval 65 milliseconds
internal clock, prescaler 1:16, postscaler 1:16,
period 255
;------------------------------------------------------------
cpu equates (memory map)
status equ Ox03
portb equ Ox06
intcon equ OxOb
pir1 equ OxOc
tmr2 equ Ox11
t2con equ Ox12
trisb equ Ox86
pie1 equ Ox8c
pr2 equ Ox92
adcon1 equ Ox9f
;------------------------------------------------------------
bit equates
rpO equ 5
j----------------------------------------------------- - - - - - - -
org OxOOO
goto start iskip over location pointed to by
interrupt vector
org Ox004
goto iserv
30
bcf status,rpO ibank 0
bcf pir1,1 iclear tmr2 interrupt flag
movlw b' 01111010' iprescaler and postscaler setup,
movwf t2con tmr2 off
clrf tmr2 iclear timer 2
bsf status,rpO ibank 1
movlw b'llllllll' iperiod=255
movwf pr2
bcf status,rpO ibank 0
bsf intcon,7 ienable global interrupts
bsf intcon,6 ienable peripheral interrupts
bsf status,rpO ibank 1
bsf pie1,1 ienable tmr2 interrupt
bcf status,rpO ibank 0
bsf t2con,2 itimer 2 on
circle goto circle idone
end
;------------------------------------------------------------
iat device programming time, select:
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal XT (using 4 MHz osc for test)
power-up timer on
brown-out reset enabled
lvp disabled
debug mode disabled
;============================================================
Example:
with a 4 MHz clock oscillator, the internal instruction clock will have
a frequency of 1 MHz and each cycle will be 1 microsecond in
duration (ie. period = 1 microsecond) .
1 microsecond multiplied by 16 = 16 microseconds between pulses out of
the prescaler.
Count to 255 in TMR2 = 4080 microseconds between pulses out of TMR2.
Multiply by 16 in postscaler = 65,280 microseconds = 65 millisecond
output interval.
31
65 msec
This is the time between each HI/LO or LO/HI transition at the port
line. The time to execute the interrupt service routine adds to
this slightly .
When thinking in terms of frequency, the prescaler divides the frequency. When thinking in
terms of period, the prescaler multiplies the period .
This time, we will use the period register and poll (watch) the TMR2 interrupt flag (won't use
interrupts). The prescaler will divide the internal instruction clock by 16 giving 16 microsec-
onds per pulse into TMR2 . The period register PR2 will be loaded with decimal 10. The
postscaler will divide by 10.
1.6 msec
The prescaler output will increment TMR2 until its contents match the contents ofPR2 (match
occurs) sending a pulse to the postscaler and resetting TMR2 .
PIC16F870
RBO
680
32
Disable Global
Interrupts
Disable Peripheral
Interrupts
c1rbit
- - . l------~
Clear TMR2 Interrupt
Flag
33
Unimplemented
I Postscaler 1:10
DIP Switches
T2CON --------- 1 I0
<c-:
1 2 345 6 7
o C 0 C C C C
POR .. OxOO
L Prescaler 1:16
TMR20ff
i=======TSTTMR2.ASM=========================4/28/02==
itimer 2 demo
free running
internal clock divided by 16 (prescaler)
period value = 10
postscaler 1:10
;--------------------------------- -------------------
list p=16f870
__config h'3f71'
radix he x
;----------------------------------------------------
cpu equates (memory map)
tmrO equ Ox01
status equ Ox03
portb equ Ox06
intcon equ OxOb
pir1 equ OxOc
tmr2 equ Ox11
t2con equ Ox12
trisb equ Ox86
pie1 equ Ox8c
pr2 equ Ox92
adcon1 equ Ox9f
;----------------------------------------------------
bit equates
rpO equ 5
;---- ------------------------------- -----------------
org OxOOO
34
bcf intcon,7 idisable global interrupts
bcf intcon,6 idisable periphe ral inte r rupts
bsf status,rpO ito bank 1
bcf pie1,1 idisable tmr2 interrupt
bcf status,rpO ito bank 0
bcf pir1,1 iclear tmr2 interrupt flag
movlw b'01001010' iprescaler = 1 :16,
postscaler = 1:10
movwf t2con itmr2 off
clrf tmr2 iclear tmr2
bsf status,rpO ibank 1
movlw d' 10' idecimal 10
movwf pr2 iload period register
bcf status,rpO ibank 0
bsf t2con,2 itmr2 on
t20vfl btfss pir1,1 iwatch tmr2 interrupt flag
goto t20vfl inot yet
bcf pir1,1 iflag set, so clear flag
btfss portb,O iport B, bit 0 status?
goto setbit ibit is clear
clrbit bcf portb,O iclear port B, bit 0
goto t20vfl irepeat
setbit bsf portb,O iset port B, bit 0
goto t20vfl irepeat
end
i-----------------------------------------------------
iat device programming time, select:
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal XT (using 4 MHz osc for test)
power-up timer on
brown-out reset e n a b l e d
lvp disabled
debug mode disabled
;=====================================================
Run the program and look at port B with an oscilloscope. The pulse width should be 1.6 mil-
liseconds pulse a hair for software overhead.
You have a design choice of polling the TMR2 interrupt flag or waiting for an interrupt and ser-
vicing it. Either way, the interrupt flag must be cleared in software each time it pops up.
35
TMR1: 16-81T TIMER/COUNTER AND CAPTURE/COMPARE MODULE
TMR1/CCP Simplified
Timer 1 (TMRl) is a 16-bit timer/counter. The resolution it provides is quite useful. A cap-
ture/compare module may be used in conjunction with timer 1 to do some neat tricks. We will
try a few of them .
First, timer 1 may be used in the typical way be reading its contents or looking at the overflow
flag.
TMR1 - Timer/Counter
TMR1
16-bit
The contents of timer 1 may be captured (grabbed) for use triggered by a signal edge from cir-
cuitry external to the PIC microcontroller.
TMR1 • Capture
..J" TMR1/CCP
or
"""l..
Pulses coming into timer 1 increment the counter. When a capture command signal edge
arrives , the counter contents are captured and an interrupt flag is set. The captured value is
available to be read .
36
The contents of timer 1 may be continuously compared to the contents ofa compare register
which has been loaded previously with some value. When the contents of timer 1 are increment-
ed to a value equal to the contents of the compare register, an output occurs which may be a
level change on the capture/compare module's output pin, an interrupt, or both .
TMR1 - Compare
TMR1/CCP
CCP Pin ....r or L....
(output)
Using the CCP module makes it possible to read timer 1 and store its contents for later use when
a signal edge (external) is detected while the PIC microcontroller is busy doing other things
(capture). Using the CCP module also makes it possible to drive a pin high or low when the
contents of timer 1 are incremented to a predetermined value totally independent from other
tasks the PIC microcontroller may be performing at the moment (compare).
The source of pulses feeding timer 1 may be the internal clock for timing applications. This
allows fine resolution (1 microsecond for 4 MHz clock oscillator). Alternatively, the source of
pulses might be an external clock or it could be a circuit which has a pulse output for an applica-
tion based on counting pulses.
37
TMR1 Description
TMRI used in conjunction with the CCP module has the following features:
Input
Circuit TMR1
Prescaler
TMR1L TMR1H Interrupt
cr
I
Flag
1,2,4,8
Internal
Clock
Special Event
Trigger From
CCP Module
First, note that the source of pulses input to TMRl may be the internal instruction clock (fosc/4)
for timing applications or an external source for either timing or counting applications. The
selection of source is determined by a bit in the Tl CON register. Second, notice that a prescaler
is used to divide the incoming pulse train by 1,2,4, or 8 as determined by two bits in the
TICON register. TMRI may be turned on or off using a bit in the TICON register. TMRI itself
consists of a register pair (8 bits each). On TMRl overflow, a flag bit is set in the PIRI register
and an interrupt occurs if enabled by a bit in the PIEI register.
38
External inputs to TMRI may be one of two types. The most common is via the TICKI pin.
.....rL
T1CKI
Pin
TMR1
When pulses are fed to pin TICKI from an external source, TMRI increments on every rising
edge (exception noted later) on the TICKI pin (divided by the prescaler). This mode of opera-
tion is selected by setting the TMRICS bit in the TICON register. When external pulses are fed
into TMRI via the TICKI pin (port C, bit 0), the pin must be configured as an input.
We will use only what is called the synchronous mode for our examples and this is selected by
clearing the TISYNC bit in the TICON register.
You won't need to concern yourself with this now, but there are some external clock input timing
specs (synchronous counter mode) to be aware of.
Prescaler 1:1.
The external input at the T1CKI pin must be high for at least 2 Tos c and
low for at least 2 Tos c where Tos c is the period of the external clock
oscillator.
The external input at the T1CKI pin must be high or low for at least
4 Tos c divided by the prescaler value Also, the minimum pulse width
requirements called out in the "Electrical Specifications" in the
Microchip data book must not be violated.
39
The other circuit possibility is a crystal clock oscillator created by connecting a crystal between
pins TIOSI and TIOSO. The oscillator may operate up to 200 KHz. The primary application is
real-time using a 32.768 KHz crystal (details later).
PIC16F870
nCON Bit3
T10SCI T10SCO
32.768 KHz D
22pl J J 22pl
CCP1 Pin
Edge Detect Prescaler
(Input)
Rising 1,4,16
vs.
Falling TMR1 TMR1H TMR1L
The I6-bit contents ofTMRI is captured when one of the following events occurs on pin CCPI :
40
When the selected event occurs, the contents ofTMRl are captured in a capture register and the
CCPl interrupt flag is set (flag must be cleared in software). The number captured is available
for whatever use the programmer intends.
Special Event
Trigger Clears
Set CCP1 TMR1
Interrupt Flag
CCP1 Pin
Comparator Logic
(Ouput)
- Driven high.
- Driven low.
- Remains unchanged .
• A special event trigger may be used to reset TMRI when a match occurs.
Note that the special event trigger does n.Q1 set the TMRI interrupt flag.
41
CCP1 Pin
The CCPl pin must be initialized as an input or output as part of the program. The pin is forced
low when a bit pattern calling for the compare mode is loaded into the CCPICON register.
If the CCPl pin is configured as an output, a write to the port can cause a capture condition.
Therefore, the CCPl interrupt enable bit should be cleared to disable interrupts prior to writing
to the port and the CCPl interrupt flag should be cleared following writing to the port.
The CCPRIL and CCPRIH register pair is used as the capture register in the capture mode and
as the compare register in the compare mode. We will refer to this register pair as the capture
register or as the compare register depending on the application.
Bit (s)
Bit (s)
42
Interrupts
Bit
Bit
Bit
IfTMRl can be stopped, reading and writing is simply a mater of reading or writing the high
and low registers (individually). Reading or writing TMRI while it is running is another matter.
First, clear the TMRIL register to ensure that a rollover into the TMRIH register will not occur
soon. Load TMRIH. Then load TMRIL. All interrupts must be disabled while the write opera-
tion takes place and re-enabled afterwards .
Reading the l6-bit TMRI involves reading two 8-bit values. The danger is that a TMRI over-
flow may occur between reads. If an overflow occurs, it must be detected in software.
Detection of an overflow must cause TMRI to be read a second time to obtain valid data. All
interrupts must be disabled while the read operation takes place and re-enabled afterwards .
43
;subroutine - read timer 1 on-the-fly
movf tmrlh,w ;read high byte
movwf t l hi ;store
movf tmrll,w ;read low byte
movwf tl 10 ;store
movf tmrlh,w ;read high byte again
subwf tl_hi,w ;subtract first read from second read
btfsc status,z ;is result O?
return ;read valid
movf tmrlh,w ;rollover occurred, read high byte again
movwf t l hi ; store
movf tmrll,w ;read low byte
movwf tl 10 ;store
return
When using the compare mode, the CCPI pin must be made an output via the TRISC register.
Turning on the CCPI module in the compare mode (by writing to the CCPICON register) forces
the CCPI pin low (no matter what). The version ofMPSIM built in to MPLAB that I am cur-
rently using does not do this, but the hardware does, which is what counts in the end.
This means that if you want to generate a single time interval output via the CCPI pin so as to
take advantage of the "auto off' feature, you will need to use a trick to force the pin high at the
beginning of the time interval. The trick is to load the compare register with the value OxOOOI
and put the CCPI module in the compare mode programmed to force the CCPI pin high on
match which will occur right away (TMRI counts to I) . Then load the compare register with the
value corresponding to the desired time interval and flip the bit in CCPICON which will tell the
CCPI pin to go low on the next match .
44
More Than One Way To Do Timing Stuff
As usual, there is more than one way to do things. Here are some concepts to stimulate your
thinking about timing applications and the compare mode.
TMRI can be turned on to start a time interval which ends automatically via the CCPI module
operating in the compare mode . This is fine ifTMRI is being used for only the one application
at the moment. The trick for controlling the CCPI pin described earlier must be used .
Compare Mode
J L
Start TMR1 And Auto End
I
Start
I
Auto
TMR1 End
IfTMRI is being shared by more than one function at (the same time), TMRI may be operated
in the free running mode. Generating a time interval begins with reading TMRl, adding the
required time interval to the contents ofTMRl just obtained, and storing the result in the com-
pare register. When TMRI is incremented to that number, an output is automatically generated .
Compare Mode
J L
TMR1 Free Running
1
Read TMR1 .
1
Auto
Add Value To End
Interval And
Store In Compare
Register
Compare Mode
TMR1 Free Running
Add To Compare Register To
Create Periodic Waveform
• Use Interrupt Service Routine
• Must Toggle Rise/Fall Bit
45
TIMING AND COUNTING EXPERIMENTS
To begin your hands-on familiarization with timer 1, we will start with an example using the
same techniques used previously with timer 0 and timer 2. We will set up TMRI to free run and
use an interrupt service routine to toggle an output pin.
PIC16F870
RBO
680
-
oN
The code is written in a logical sequence for ease of understanding, especially at the flow chart
level. You can eliminate some bank switching by combining some of the bank 1 steps if you
want to streamline the code .
46
Main Interrupt
Clear TMR1 Interrupt
Program Service
Flag
Routine
CiearsTMR1
Prescaler
I Unimplemented
I I Prescaler 1:8
DIP Switches
~~
1 234 5 6 7
o C 0 C C C C
TMR10ff
paR = OxOO
Internal Clock
Ignore With
Internal Clock
Oscillator Off
47
;=======TMR1.ASM====================================4/28/02==
list p=16f870
__config h'3f71'
radix hex
j--------------------------------- ------- - --------- --- - - - - - - -
;timer 1 demo
free running, time interval 524 milliseconds
internal clock, prescaler 1:8, count to 65,536
;--------------------------------- ---------------------------
cpu equates (memory map)
status equ Ox03
portb equ Ox06
intcon equ OxOb
pir1 equ OxOc
tmr1l equ OxOe
tmr1h equ OxOf
t1con equ Ox10
trisb equ Ox86
pie1 equ Ox8c
adcon1 equ Ox9f
j----------------------------------------------------- - - - - - - -
bit equates
rpO equ 5
;-------------------------------------- ----------------------
org OxOOO
goto start ;skip over location pointed to by
interrupt vector
org Ox004
goto iserv
48
iserv bcf pi rl,O iclear TMRl interrupt flag,
enable further interrupts
bt fss portb,O iport B, bit 0 status?
goto setbit ibit is clear
clrbit bcf portb,O iclear port B, bit 0
nop iequalize paths
retfie ireturn from interrupt
setbit bsf portb ,O iset port B, bit 0
retfie ireturn from interrupt
end
;----------------------- -------------------------------------
iat device programming time, select:
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal XT (using 4 MHz osc for test)
power-up timer on
brown-out reset enabled
lvp disabled
debug mode disabled
i===================================================== =======
PULSER CIRCUIT
..n..
Momentary 3300
Contact
T =300C =161l5ec
+5V
74HC14
0
Set
+5V
49
Event Counting (via TMR1)
For this example, the contents of timer 1 will be displayed continuously using a program loop.
A pulser is used to inject pulses into TMRI .
T1CKI
PIC16F870
SLEDs
Port B
Timer 1 is supposed to increment on every rising edge. Timer 1 has a "weird" in that what con-
stitutes the first rising edge is determined by the initial logic level of the TICKI pin when timer
1 is turned on. If it is high initially (on reset with this experimental setup), the count indeed will
begin on the first rising edge (increment on every rising edge).
Count = 1
!
U-
On Reset J t
1st Rising
Edge
50
If the level at TICKI is low on reset, the first rising edge won't cause TMRI to increment (i.e.
not every rising edge will be counted).
Count = 1
!
_-----In I
OnResot J i
2nd Rising
Edge
.
Port Setup
~
CCP1 Module Off,
Clear CCP1 Prescaler
~
TMR1 Setup, TMR1 Off
i CiearsTMR1
CiearTMR1
Prescaler
~
TMR10n
......
,r
ReadTMR1
Register Low
+
Display Number
At Port B
51
I Unimplemented
I I Prescaler 1:1
DIP Switches
~~
1234567
T1CON
o C 0 C 0 C C
TMR10ff
POR= OxOO
External Clock
Sync External
Clock Input
Oscillator Off
i=======READ.ASM====================================4/28/02==
list p=16f870
__config h'3f71'
radix hex
i------------------------------------------------------------
itimer 1 - read event count on-the-fly demo
;------------------------------------------------------------
cpu equates (memory map)
status equ Ox03
portb equ Ox06
intcon equ OxOb
pirl equ OxOc
tmrll equ OxOe
tmrlh equ OxOf
tlcon equ OxlO
ccplcon equ Ox17
t r i sb equ Ox86
trisc equ Ox87
piel equ Ox8c
adconl equ Ox9f
;------------------- -----------------------------------------
bit equates
rpO equ 5
i------------------------------------------------------------
org OxOOO
end
i--- - ----- - -- ----- -- -- - - ---- - - -- ---- - - - - - --- - - - --- - - - - - - - - - - -
;at devi c e programmi ng t i me , select :
memo r y unprot ect e d
watch d og t i mer disab led (d ef a ult i s e n a bled)
stand ard c r y s t a l XT (using 4 MH z osc f or test)
power-up time r o n
b ro wn-ou t reset enabled
lvp d i s a ble d
d e b u g mode di sabled
; = = = = = = = = = = = = = = ============= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
T1CKI
+SVDC PIC16F870
8 LEDs
10K
CCP1 Port B
Capture
Count
1 680
-
-
For this experiment, we will use a pulser to inject pulses into timer I via the TICKI pin. The
objective is to increment TMRI (via the prescaler) on every rising edge. The input at TICKI pin
must be high on reset or the result will be one count short. The count will be displayed in binary
via the port B LEDs.
A pullup resistor and switch are used to generate a capture on a rising edge via the CCPI pin
which is configured as an input. Power-up the circuit with the switch closed (LEDs will be oft)
and then open the switch (rising edge) when you want to capture the contents of timer 1.
53
Inject a few pulses at the TICKI pin. Capture the count using the switch on the CCPI pin and
see if the displayed count equals the number of rising edges you injected.
Assumes:
Count .. 1
J
ur---
CnRese' J 1
1st Rising
Edge
Main Interrupt
Clear Capture Interrupt
Program Service
Flag
Routine
Disable Interrupts And
Clear Interrupt Flags
+
Read Capture Register
Low
CiearsTMR1
Prescaler
•
Return from Interrupt
CCP1 Setup-
Capture Mode
CCP1 ModuleOn
54
I Unimplemented
I I Prescaler 1:1
~~
T1CON
TMR10ff
POR. oxoo
External Clock
Sync External
Clock Input
Oscillator Off
I Unimplemented
I I NotUsed
DIP SwItches
~~
1 2 3 4 5 6 7 [OEGTOlr-0~'-1--'--1-0-.,-
-- 1I
-------
CCP1CON
o C 0 C 0 C C
C losed On Reset
Open To Capture
J POR = axoo
L Capture Mode,
Every Rising Edge
i =======CAPT.ASM====================================4/28/02==
list p=l6f870
__config h'3f7l'
radix hex
j------- --------------------------- ------------------- - - - - - - -
it imer land ccpl module - capture mode demo
j - - - - - - - - --- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
cpu equates (memory map)
status equ Ox03
portb equ Ox06
intcon equ OxOb
pirl equ OxOc
tmrll equ OxOe
tmrlh equ OxOf
tlcon equ OxlO
ccprll equ OxlS
ccprlh equ Oxl6
ccplcon equ Oxl7
trisb equ Ox86
trisc equ Ox87
piel equ Ox8c
adconl equ Ox9f
j----------------------------------------------------- - - - - - - -
55
bit equates
rpO equ 5
ccpl equ 2 ;ccpl bit 2, port C
i--- ---------- ------------ --------------- - - - - --------- - - - - - - -
org OxOOO
goto start ;skip over location pointed to by
interrupt vector
org Ox004
goto iserv
end
56
i----------------------------------------------------- - - - - - - -
iat device programming time, select:
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal XT (using 4 MHz osc for test)
power-up timer on
brown-out reset enabled
lvp disabled
debug mode disabled
i============================================================
T1CKI
PIC16F870
CCP1
680
-.....
For the compare mode experiment, we will load the compare register (low byte) with a small
number such as binary 8. The CCPI pin must be configured as an output. We will input 8 rising
edges via the TICKI pin and that should trigger an output at the CCPI pin (goes high), lighting
the LED connected to it via a current limiting resistor. Remember that the TI CKI input pin must
be high on reset. Try some other numbers to get a feel for how this works .
Assumes :
Count = 1
J
J u-
DnRese'
1
1st Rising
Edge
57
Disab le Interrupts And
Clear Interrupt Flags
CiearsTMR1
Prescaler
CCP1 Setup -
Compare Mode
CCP1 Module On
I Unimplemented I Unimplemented
~/'--.... ~~
T1CON CCP1CON ~'-1-'-
1 0-'-
10~10-1
POR = OxOO
TMR10ff
External Clock
POR = OxOO -------- I
Compare Mode,
Sync External
Clock Input Set Output On Match
Oscillator Off
58
DIP Switches
1 2 345 6 7
o C 0 C 0 C 0
i=======CMPR.ASM====================================4/28/02==
list p=16f870
__config h'3f71'
radix hex
;------------------------------------------------------------
itimer 1 and ccpl module - compare mode demo
;------------------------------------------------------------
cpu equates (memory map)
status equ Ox03
portc equ Ox07
intcon equ OxOb
pirl equ OxOc
tmrll equ OxOe
tmrlh equ OxOf
tlcon equ OxlO
ccprll equ Ox15
ccprlh equ Ox16
ccplcon equ Ox17
trisc equ Ox87
piel equ Ox8c
adconl equ Ox9f
;------------------------------------------------------------
bit equates
rpO equ 5
ccpl equ 2 iccpl bit 2, port C
;------------------------------------------------------------
org OxOOO
59
movwf tlcon tmrl off
clrf tmrlh iclear timer 1 high
clrf tmrll iclear timer 1 low
clrf ccprlh iclear compare register high
movlw d'8 ' iload compare register low with dec 8
movwf ccprll
movlw b'OOOOlOOO' iccpl compare mode, ccpl pin high
on match, ccp module on,
ccpl pin low
movwf ccplcon
bsf tlcon,O itimer 1 on
circle goto circle idone
end
;------ ------------------------------------------------------
iat device programming time, select:
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal XT (using 4 MHz osc for test)
power-up timer on
brown-out reset enabled
lvp disabled
debug mode disabled
;================ === = == == ==== ================================
60
Single Time Interval Output (via TMR1 and CCP, compare mode)
The clock input for TMRI may be the internal instruction clock, an external clock connected to
the Tl CKI pin, or an external crystal (details on external crystal later). We will use the internal
clock for this example. The output is via the CCPI pin and an LED .
+SVDC PIC16F870
~ L
10K
Generating a single time interval represented by a positive-going pulse output on the CCPl pin
requires some gymnastics. First, the CCPl pin must be assigned as an output using the TRISC
register. Second, when the CCPl module is turned on (by writing the compare mode bit pattern
to the CCPI CON register), the CCPI pin is forced low (no matter what). To accomplish our
objective, which is to indicate the start of the time interval with a rising edge, we will:
The arrival of the first pulse at the input of timer 1 will result in a match causing a CCPl inter-
rupt. The interrupt service routine will:
61
Timeout
CCP1 Pin
CCP1
Module On
TMR10n
Turning on the CCPl module forces the CCPl pin low (previously initialized low). Timer 1
starts counting and a match occurs as soon as the first clock pulse is received resulting in a
CCPl interrupt and forcing the CCPl pin high. Timer 1 continues to be incremented. Bit a in
the CCPlCON register is set by the interrupt service routine so that when the next match occurs,
the CCPl pin will be forced low. The interrupt service routine loads the compare registers with
the desired value and then returns control to the main program . Timer 1 increments until a
match occurs and the output pin (CCPl) goes low.
Notice that 3 internal clock cycles are used by the single pulse compare gymnastics. You can
shave the value used for the second compare to compensate.
Timer 1 is incremented until its contents match the value stored in the compare register. This is
how the duration of the time interval is controlled .
OxF424
~
I = 4
L== 2x16 = 32
4x 256 = 1024
15x4096 = .6..l..4.iQ.
62500
62
Disable Interrupts And
Clear Interrupt Flags
CiearsTMR1
Prescaler
ready
No
I Unimplemented
I I Prescaler 1:8
TMR10ff
CCP1 Compare Mode, paR = OxOO
CCP1 Pin HI On Match, Internal Clock
CCP1 Module On,
CCp1 Pin La Ignore With
Internal Clock
Oscillator Off
go hi
I Unimplemented
No I I NotUsed
~~
CCP1CON ~~1--'--10--'--10-----'-10-\
Load Compare Register
With Real Value
paR = OxOO -------- I
Compare Mode,
Set Output On Match
63
DIP Switches
1 2 3 4 5 6 7
ceo C ceo
L Closed On Reset
Open When Ready
i=======SNGL.ASM====================================4/28/02==
list p=16f870
__config h'3f7l'
radix hex
i------------------------------------- - --------------- - - - - - - -
itimer 1 and ccpl module - single time interval demo
i----------------------------------------------------- - - - - - - -
cpu equates (memory map)
status equ Ox03
porta equ Ox05
portc equ Ox07
intcon equ OxOb
pirl equ OxOc
tmrll equ OxOe
tmrlh equ OxOf
tlcon equ OxlO
ccprll equ Ox15
ccprlh equ Ox16
ccplcon equ Ox17
trisa equ Ox85
trisc equ Ox87
piel equ Ox8c
adconl equ Ox9f
i----------------------------------------------------- - - - - - - -
bit equates
rpO equ 5
ccpl equ 2 iccpl bit 2, port C
.
e
org OxOOO
_
64
bcf pirl,2 iclear ccpl interrupt flag
clrf ccplcon iccpl module off
movlw b' 00110000 I itmrl prescaler and tmrl setup,
movwf tlcon tmrl off
clrf tmrlh iclear timer 1 high
clrf tmrll iclear timer 1 low
ready btfss porta, 0 iready?
goto ready inot yet
trick clrf ccprlh iclear compare register high
movlw OxOl iload compare register low
movwf ccprll
movlw b'OOOOlOOO' iccpl compare mode, ccpl pin high
movwf ccplcon on match, ccpl module on,
ccpl pin low
bsf tlcon,O itimer 1 on
gohi btfss pirl,2 iccpl interrupt flag set?
goto gohi inot yet
movlw Oxf4 iload compare register high
movwf ccprlh
movlw Ox24 iload compare register low
movwf ccprll
bsf ccplcon,O iccpl pin l o w on match
circle goto circle idone
end
i----------------------------------------------------- - - - - - - -
iat device programming time, select:
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal XT (using 4 MHz osc for test)
power-up timer on
brown-out reset enabled
lvp disabled
debug mode disabled
;========================================= == = = = = == === = =======
Let's go back to testing the F870. This time, we will use a 128 microsecond time interval and
test the output using the '84 on a board running pgentst.asm.
+5VDC
RAO
PIC16F84A
PIC16F870
8 LEDs
. CCP1
.-.r--L
RAO Port B -
..~ 680
.....
::! ~ .....
- ~
65
I found that the measurement result was always a little bit low. First, the 128 microsecond pulse
generated may not be exactly 128 microseconds long because the program loop which tests
TMRO, bit 7 may not be testing the bit at the very instant it is set. At the receiving end, the
loops looking at the input may not detect the leading and trailing edges of the pulse at exactly
the right time . For the 128 microsecond example, my readings were a mix of 123 and 129
microseconds. This error mayor may not be significant, depending on the application. The
longer the pulse, the less significant the error (few microseconds) becomes .
i=======ONE128.ASM==================================4/28/02==
list p=16f870
__eonfig h'3f71'
radix hex
j------------------------------------------------------------
itimer 1 and eepl module - single time interval demo
;------------------------------------------------------------
cpu equates (memory map)
status equ Ox03
porta equ Ox05
porte equ Ox07
inteon equ OxOb
pirl equ OxOe
tmrll equ OxOe
tmrlh equ OxOf
tleon equ OxlO
eeprll equ Ox15
eeprlh equ Ox16
eepleon equ Ox17
trisa equ Ox85
trise equ Ox87
piel equ Ox8e
adeonl equ Ox9f
j------------------------------------------------------------
bit equates
rpO equ 5
eepl equ 2 ieepl bit 2, port C
;------------------------------------------------------------
org OxOOO
66
movwf tlcon tmrl off
clrf tmrlh ;clear timer 1 high
clrf tmrll ;clear timer 1 low
ready btfss porta, 0 ; ready?
goto ready ;not yet
trick clrf ccprlh ;clea r compare register high
movlw OxOl ;load compare register low
movwf ccprll
movlw b'OOOOlOOO' ;ccpl compare mode, ccpl pin high
movwf ccplcon on match, ccpl module on,
ccpl pin low
bsf tlcon,O ;timer 1 on
gohi btfss pirl,2 ;ccpl interrupt flag set?
goto gohi ;not yet
movlw OxOO ;load compare register high
movwf ccprlh
movlw Ox40 ;load compare register low
movwf ccprll
bsf ccplcon,O ;ccpl pin low on match
circle goto circle ;done
end
j----------------------------------------------------- - - - - - - -
;at device programming time, select:
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal XT (using 4 MHz osc for test)
power-up timer on
brown-out reset enabled
lvp disabled
debug mode disabled
;============================================================
Generating a free running output works in much the same way as creating the single interval in
the example shown earlier. Here, the state of the output pin (CCPl) is changed every time the
timer value matches the compare register value. Notice that the bit in the CCPICON register
which determines whether the CCPl pin goes high or low on timeout must also be toggled .
PIC16F870
JUl..SL
CCPl JUUL ~l-
680 500 msec
-"'"
67
Main Interrupt
Clear Compare Interrupt
Program Service
Flag
Routine
CiearsTMR1
Prescaler
I Unimplemented I Unimplemented
~~ ~~
~'----1----'--10----'--10----'--
-------
T1CON CCP1CON 1 0-1
TMR10ff
paR = OxOO paR = oxoo I
Internal Clock
Compare Mode,
Ignore With
Set Output On Match
Internal Clock
Oscillator Off
68
DIP Switches
1 2 3 4 5 6 7
ceo C ceo
L Closed On Reset
Open When Ready
i=======FREE .ASM====================================4/28/02==
list p=16f870
__config h'3f71'
radix hex
;------------------------------------------------------------
itimer 1 and ccpl module - free running compare mode demo
;------------------------------------------------------------
cpu equates (memory map)
status equ Ox03
portc equ Ox07
intcon equ OxOb
pirl equ OxOc
tmrll equ OxOe
tmrlh equ OxOf
tlcon equ OxlO
ccprll equ OxlS
ccprlh equ Ox16
ccplcon equ Ox17
trisc equ Ox87
piel equ Ox8c
adconl equ Ox9f
;------------------------------------------------------------
bit equates
rpO equ S
ccpl equ 2 iccpl bit 2, port C
i------------------------------------------------- ---- - - - - - - -
org OxOOO
goto start iskip over location pointed to by
interrupt v e c t o r
org Ox004
goto iserv
69
bcf status,rpO ibank 0
bcf pirl,2 iclear ccpl interrupt flag
clrf ccplcon iccpl module off
movlw b' 00110000' itmrl prescaler and tmrl setup,
movwf tlcon tmrl off
clrf tmrlh iclear timer 1 high
clrf tmrll iclear timer 1 low
movlw Oxf4 iload compare register high
movwf ccprlh
movlw Ox24 i load compare register low
movwf ccprll
bsf intcon,7 ienable global interrupts
bsf intcon,6 ienable peripheral interrupts
bsf status,rpO ibank 1
bsf piel,2 ienable ccpl compare interrupt
bcf status,rpO ibank 0
movlw b'OOOOlOOO' iccpl compare mode, ccpl pin high
movwf ccplcon on match, ccpl module on,
ccpl pin low
bsf tlcon,O itimer 1 on
circle goto circle idone
end
;------------------------------------------------------------
iat device programming time, select:
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal XT (using 4 MHz osc for test)
power-up timer on
brown-out reset enabled
lvp disabled
debug mode disabled
;============================================================
70
Free Running Output (via TMR1 and CCP, compare mode)
• Free Running TMR1, Add Interval Value To Compare Register Each Cycle
This example is useful in situations where timer 1 is used for more than one application simulta-
neously. The free running output is initiated by reading TMRl while it is running, adding the
time interval value to the TMRI reading, and storing the result in the compare register. From
then on, the interval value is added to the compare register contents each time a CCPl interrupt
occurs. We will use the subroutine for reading timer 1 while it is running and double precision
addition.
PIC16F870
.ri.n.ri.
CCP1 ..n.n.n. -I l-
680 500 msec
"I"
--
Since you are getting used to this stuffby now, the flow charts will be less detailed .
71
Main Interrupt
Clear CCP1 Interrupt
Program Service
Flag
Routine
Circle = Do
Something Else
I Unimplemented I Unimplemented
~~ ~~
Internal Clock
POR = OxOO ---------
I
Compare Mode,
Ignore With
Clear Output On Match
Internal Clock
Oscillator Off
72
DIP Switches
1 2 3 4 5 6 7
o C 0 C ceo
i=======FREEADD.ASM=================================4/28/02==
list p=16f870
__config h'3f7l'
radix hex
j----------------------------------------------------- - - - - - - -
itimer 1 and ccpl module - free running compare mode demo
read timer 1 on-the-fly
j----------------------------------------------------- - - - - - - -
cpu equates (memory map)
status equ Ox03
portc equ Ox07
intcon equ OxOb
pirl equ OxOc
tmrll equ OxOe
tmrlh equ OxOf
tlcon equ OxlO
ccprll equ Ox15
ccprlh equ Ox16
ccplcon equ Ox17
trisc equ Ox87
piel equ Ox8c
adconl equ Ox9f
t l hi equ Ox20
tl 10 equ Ox2l
lsb2 equ Ox22
msb2 equ Ox23
int hi equ Ox24
int 10 equ Ox25
j----------------------------------------------------- - - - - - - -
bit equates
c equ 0
z equ 2
rpO equ 5
ccpl equ 2 iccpl bit 2, port C
;------------------------------------------------------------
org OxOOO
goto start iskip over location pointed to by
interrupt vector
org Ox004
goto iserv
73
movwf adconl
bcf status,rpO ;switch back to bank 0
bcf portc,ccpl ;ccpl pin low
bcf intcon,7 ;disable global interrupts
bcf intcon,6 ;disable peripheral interrupts
bsf status,rpO ;bank 1
bcf piel,O ;disable timer 1 interrupts
bcf piel,2 ;disable ccpl interrupts
bcf status,rpO ;bank 0
bcf pirl,2 ;clear ccpl interrupt flag
clrf ccplcon ;ccpl module off
movlw b' 00110000' ;tmrl prescaler and tmrl setup,
movwf tlcon tmrl off
clrf tmrlh ;clear timer 1 high
clrf tmrll ;clear timer 1 low
bsf tlcon,O ;timer 1 on
nop ;fake do something else
nop
nop ;ready to output
call read ;read timer 1 on-the-fly
movlw Oxf4 ;add interval to timer 1 reading
movwf msb2 ;load interval high
movlw Ox24 ;load interval low
movwf lsb2
dblplus movf tl_lo,w ;fetch timer 1 reading low
addwf lsb2,f ;add low bytes, result in lsb2
btfsc status,c ;carry set?
incf msb2,f ;yes, add 1 to msb result
movf tl_hi,w ;fetch timer 1 reading high
addwf msb2,f ;add high bytes, result in msb2
trick clrf ccprlh ;clear compare register high
movlw OxOl ;load compare register low
movwf ccprll
movlw b'OOOOlOOO' ;ccpl compare mode, ccpl pin high
movwf ccplcon on match, ccpl module on,
ccpl pin low
gohi btfss pirl,2 ;ccpl interrupt flag set?
goto gohi ;not yet
movf msb2,w ;load compare register high
movwf ccprlh
movf lsb2,w ;load compare register low
movwf ccprll
bsf ccplcon,O ;ccpl pin low on match
bsf intcon,7 ;enable global interrupts
bsf intcon,6 ;enable peripheral interrupts
bsf status,rpO ;bank 1
bsf piel,2 ;enable ccpl compare interrupt
bcf status,rpO ;bank 0
circle goto circle ;done
j----------------------------------------------------- - - - - - - -
;note that interrupts must be disabled when using the
read subroutine
read movf tmrlh,w ;read high byte
movwf tl hi ;store
74
movf tmrll,w iread low byte
movwf tl 10 istore
movf tmrlh,w iread high byte again
subwf tl_hi,w isubtract first read from second read
btfsc status,z iis result O?
return iread valid
movf tmrlh,w irollover occurred, read high byte again
movwf t l hi istore
movf tmrll,w iread low byte
movwf tl 10 istore
return
j----------------------------------------------------- - - - - - - -
iserv bcf pirl,2 iclear ccpl interrupt flag,
enable further interrupts
movlw Oxf4 iload interval high
movwf int hi
movlw Ox24 iload interval low
movwf int 10
dbladd movf int_lo,w ifetch interval low
addwf Isb2,f iadd low bytes, result in Isb2
btfsc status,c icarry set?
incf msb2,f iyes, add 1 to msb result
movf int_hi,w ifetch interval high
addwf msb2,f iadd high bytes, result in msb2
movf msb2,w iload compare register high
movwf ccprlh
movf Isb2,w iload compare register low
movwf ccprll
btfss ccplcon,O icontrol bit status?
goto sbit ibit is clear
cbit bcf ccplcon,O iclear control bit
nop idelay 1 cycle to equalize paths
retfie ireturn from interrupt
sbit bsf ccplcon,O iset control bit
retfie ireturn from interrupt
j----------------------------------------------------- - - - - - - -
end
j----------------------------------------------------- - - - - - - -
iat device programming time, select:
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal XT (using 4 MHz osc for test)
power-up timer on
brown-out reset enabled
Ivp disabled
debug mode disabled
j===================================================== =======
75
Time Measurement (period/interval/time between events)
• Via TMR1 Read
This is similar in concept to using an AND gate. An unknown time interval may be measured
by using the time interval signal to gate a second signal of known frequency.
Unknown Time
Interval
Time Interval = Pulses = Pulses
Frequency PulsesITime
The signal of known frequency will appear at the output of the AND gate only while both sig-
nals are high. The pulses appearing at the output of the AND gate are then counted. The num-
ber of pulses divided by the frequency (multiplied by the period) of the reference signal is the
time interval.
A time interval generated by some circuit external to a PIC16F870 may be measured using
timer 1. The time interval might be the time between two pulses or the time a single pulse is
high. For this experiment, we will use a PIC16F84 to generate a single pulse of known length
and use timer 1 in a PIC16F870 to measure the time it is high.
76
+SVDC
10K .. ~
2000.asm
~
RB1 RBO RA1
+SVDC
PIC16F870
.. ~ 10K .. ~
PIC16F84A
"=:=" RAO
Display
. ~ 680
Low
Byte
1. - '-
-
:!! ~ .....
The selection of numbers used here is arbitrary. We will use a time interval of 2000 microsec-
onds generated by a PICI6F84. The circuit and software are in the chapter Test Equipment For
Timing And Counting Experiments.
The internal clock of the PIC16F870 will be used as the signal of known frequency (1 MHz,
period 1 microsecond). The internal clock pulses will be fed into timer 1 (prescaler 1:1) during
the time the port line connected to the F84 is high. A "ready" switch will be used so that mea-
surement does not begin until everything is stable . The program displays the timer 1 high byte
at the port B LEDs as soon as the measurement is complete. The timer 1 low byte may subse-
quently be displayed by opening the "display low byte" switch .
77
No
Port A, Bit 0
Yes
No
Port A, Bit 1
No
Port A, Bit 1
No
Port A, Bit 2
78
I Unimplemented
I I Prescaler 1:1
DIP Switches
~~
1 2 3 4 5 6 7
T1CON
C 0 C C C C C
POR - OxOO
TMR10ff
Internal Clock L Closed On Reset
Open To Display Low Byte
Ignore With
Internal Clock
Closed On Reset
Oscillator Off Open When Ready
i=======PERIOD.ASM==================================4/28/02==
list p=16f870
__config h'3f71'
radix hex
;------------------------------------------------------------
iperiod measurement demo
internal clock, prescaler 1:1
;------------------------------------------------------------
cpu equates (memory map)
status equ Ox03
porta equ OxOS
portb equ Ox06
intcon equ OxOb
pir1 equ OxOc
tmr1l equ OxOe
tmr1h equ OxOf
t1con equ Ox10
trisa equ Ox8S
trisb equ Ox86
pie1 equ Ox8c
adcon1 equ Ox9f
:------------------------------------------------------------
bit equates
rpO equ S
:------------------------------------------------------------
org OxOOO
79
bcf piel,O idisable tmrl inter rupt
bcf status,rpO ibank 0
bcf pirl,O iclear tmrl interrupt flag
movlw b'OOOOOOOO' iprescaler and tmrl setup,
movwf tlcon tmrl off
clrf tmrlh iclear timer 1 high
clrf tmrll iclear timer 1 low, clear prescaler
ready btfss porta, 0 iready?
goto ready
istart btfss porta,l ;watch for rising edge
goto istart
bsf tlcon,O itimer 1 on
iend btfsc porta,l iwatch for falling edge
goto iend
bcf tlcon,O itimer 1 off
movf tmrlh,w iget timer 1 high
movwf portb idisplay via port B LEDs
disp_lo btfss porta,2 iwatch display low byte switch
goto disp_lo
movf tmrll,w iget timer 1 low
movwf portb idisplay via port B LEDs
circle goto circle idone
end
;------------------------------------------------ ----- -- -- -- -
iat device programming time, select:
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal XT (using 4 MHz osc for test)
power-up timer on
brown-out reset enabled
lvp disabled
debug mode disabled
;============================================================
Procedure:
Decoding result:
0000011 1 1 1 0 1 0 000
l ~~'2256 l ~2:' L 16
Total: 2000
80
• TMR1 And CCP, Capture Mode
A time interval may be measured using another technique. Timer 1 may be in the free run mode.
The time interval signal is fed into the CCPl pin and used to capture the time values from
timer 1 at the start and end of the time interval.
J L
1
1st Capture
1
2nd Capture
The first capture is on a rising edge and the second is on a falling edge.
TMR1 CONTENTS
TIME
TMR1 Rolls
Over
Timer 1 will be part of the way to a full count when the first capture occurs. We are really inter-
ested in obtaining the time remaining to rollover. This can be obtained by complementing the
captured value. Complementing a value means changing all the 1s to Os and visa versa . The
result is the complement of the value and is equal to the difference between the value and
OxFFFF for a 16-bit number. There is an instruction COMF which does this .
The complement of the first capture value is added to second capture value . The second value
captured represents the time from rollover to the second capture . The result is the number of
pulses corresponding to the time interval between the two captures .
Two flags are used , one to indicate that the first capture has occurred and the other to indicate
that the task has been completed.
81
The objectives for the interrupt service routine are:
+5VDC
10K . ~
2000 .asm
--r-----1.-
RB1 RBO CCP1
+5VDC
PIC16F870
... 10K .. ~
PIC16F84A
. RAO
A""l. 8 LEOs
RA2 Port B
Display
. ~ 680
Low
Byte
1. ~~
-...
-N
82
Main Interrupt
Program Service
Routine
Yes
No I Unimplemented
I I Prescaler 1:1
Yes
~~
T1CON
No
TMR10ff
paR = OxOO
Internal Clock
Ignore With
Internal Clock
Oscillator Off
I Unimplemented
I I NotUsed
~~
CCP1CON l -1I
~-o----'-I-1--'-I-o'----
1 2 345 6 7
C C C C C C c
L Closed On Reset
OpenTo Display Low Byte
Closed On Reset
Open When Ready
;=======PDCCP.ASM===================================4/28/0 2==
list p=16f870
__config h'3f7I'
radix hex
;------------- ---------------------------------------- ---- ---
;time r 1 and ccpI module - period measurement demo
timer 1 free running
capture at start and end of period pulse
;------------------------------------------------------------
cpu equates (memory map)
status equ Ox03
porta equ OxOS
portb equ Ox06
po r tc equ Ox07
intcon equ OxOb
pi rl e qu OxOc
t mrIl equ OxOe
t mr I h e qu OxOf
tIcon equ OxIO
ccprIl equ OxIS
ccprIh equ Ox16
ccpIcon equ Ox17
trisa equ Ox8S
trisb equ Ox86
trisc equ Ox87
piel equ Ox8c
adconl equ Ox9f
one hi equ Ox 20
one 10 e q u Ox2I
I sb2 equ Ox 22
msb2 e qu Ox 23
flags equ Ox2 4 ; Ist captu re flag bit 0
done flag bit 1
;----------- --- -- - - - - - - ---- - ---- - - --- - - --- --- - ------- - - - - -- - -
bit equates
c equ 0
z equ 2
rpO equ S
c cp I equ 2 ; c c p I bit 2, p ort C
84
;------------------------------------ -- --------- - --- ---- --- --
o rg OxOOO
goto start iskip over location point ed to b y
inte rrupt v e c t o r
org Ox004
goto iserv
85
bcf pirl,2 ;clear ccpl interrupt flag,
enable second interrupt
bcf ccplcon,O ;second capture on falling edge
movf ccprlh,w ;get 1st capture high
movwf one hi ;store
movf ccprll,w ;get 1st capture low
movwf one 10 ;store
retfie
cap2 bsf status,rpO ;bank 1
bcf piel,2 ;disable ccp1 interrupts
bcf status,rpO ;bank 0
comf one_hi,f ;complement 1st capture high
comf one_lo,f ;complement 1st capture low
movf ccprlh,w ;get 2nd capture high
movwf msb2 ;store
movf ccpr11,w ;get 2nd capture low
movwf lsb2 ; store
dblplus movf one_lo,w ;fetch complement of 1st low
addwf lsb2,f ;add low bytes, result in lsb2
btfsc status,c ;carry set?
incf msb2,f ;yes, add 1 to msb result
movf one_hi,w ;fetch complement of 1st high
addwf msb2,f ;add high bytes, result in msb2
bsf flags,l ;set "done" flag
retfie
i----------------------------------------------------- - - - - - - -
end
;------------------------------------------------------------
;at device programming time, select:
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal XT (using 4 MHz osc for test)
power-up timer on
brown-out reset enabled
lvp disabled
debug mode disabled
;============================================================
Procedure:
86
Frequency Measurement (via TMR1 and CCP, gate via TMRO)
Measuring frequency is the flip side of measuring a time interval. This is similar in concept to
using an AND gate. Frequency may be measured by using the known time interval signal to
gate a second signal of unknown frequency .
Known Time
Interval
The signal of unknown frequency will appear at the output of the AND gate only while both sig-
nals are high . The pulses appearing at the output of the AND gate are then counted . The num-
ber of pulses divided by the time interval is the frequency.
The frequency of a signal generated by some circuit external to a PIC 16F870 may be measured
using timer 1. For this experiment, we will use a PIC 16F84 to generate a signal of "unknown"
frequency and use timer 1 in a PIC16F870 to measure that frequency.
lreqout.asm
..J'UUL.
RBO T1CKI
+SVDC
PIC16F84A
.. ~ 10K .. . PIC16F870
RAO
Ae'~l
8 LEDs
Display
RA2 Port B
. ~ 680
Low
Byte
- I-
-
:!~ .....
87
Again the selection of numbers used here is arbitrary. We will use a frequency of 100 KHz gen-
erated by a PIC 16F84. This is done using a very simple program involving software time delays
(freqout.asm).
In the PIC 16F870, we will use timer 0 to generate a sample time of 0.1 second which should
result in 10,000 pulses being counted by timer 1. Using a timer 1 prescaler value of 1:1 will
result in maximum resolution.
Since timer 0 is an 8-bit counter, it will roll over every 256 counts . We will need a file register
counter to count TMRO rollovers.
The file register counter will count up to 255 and roll over on the next count. We will have the
program watch for this to happen and then look for the file register counter to reach 134 as it
counts up the second time. Next, the program will look to see when the count in TMRO reaches
160. It will do this by watching bit 7 to be set (128), followed by watching for bit 5 to be set
(32). The sum of 128 and 32 is 160.
Bit 7 6 5 4 3 2 1 0
UW
128 64 32 16 8 4 2
I
There are, of course, other ways to do this . This method does not require use of interrupts and
uses a minimum of program steps once the final count in TMRO is reached (source of error).
• Clear TMRI.
• Start TMRl , count signal pulses coming from the F84.
• Do timing via 256 TMRO rollovers, 134 more TMRO rollovers, 160 TMRO counts.
• Stop TMRI.
• Read TMRI .
• Display TMRI high byte .
• Display TMRI low byte when "display low byte" switch is opened .
The frequency is the number of pulses counted by timer 1 during the 0.1 second sample period
times 10.
88
~NO
ClearTMRoOverflow
Flag
Known IncrementTimer 0
Gate Time Rollover Counter
No
No
Yes
No
Clear Timer 0 Overflow
Flag
oflow1
No
ReadTimer 1 High
And Display
No
IncrementTMRO
Rollover Counter
Display Timer 1
No Low Byte
89
I Unimplemented
I I Prescaler 1:1
~~
T1CON
TMR10ff
POR= oxoo
External Clock
Sync External
Clock Input
Oscillator Off
Option Register
DIP Switches
1 2 3 4 5 6 7
C C C c o C C
L Closed On Reset
Open To Display Low Byte
Closed On Reset
Open When Ready
90
i=======FREQ.ASM====================================4/28/02==
list p=16f870
__config h'3f71'
radix hex
j----------------------------------------------------- - - - - - - -
ifrequency measurement demo
gate via tmrO, internal clock, prescaler 1:1
j----------------------------------------------------- - - - - - - -
cpu equates (memory map)
tmrO equ Ox01
status equ Ox03
porta equ Oxos
portb equ Ox06
intcon equ OxOb
tmr11 equ OxOe
tmr1h equ OxOf
t1con equ Ox10
opt equ Ox81
trisa equ Ox8S
trisb equ Ox86
trisc equ Ox87
adcon1 equ Ox9f
pie1 equ Ox8c
count equ Ox20
j----------------------------------------------------- - - - - - - -
bit equates
z equ 2
rpO equ S
j----------------------------------------------------- - - - - - - -
org OxOOO
91
clrf tmrO iclear timer 0
clrwdt iclr WDT, prep prescaler assign
bsf status,rpO ibank 1
movlw b'11011111' iset up timer 0
movwf opt
bcf status,rpO ibank 0
clrf count iclear tmrO rollover counter
ready btfss porta, 0 iready?
goto ready
bsf t1con,0 iturn on timer 1
clrf tmrO iclear timer 0
bcf intcon,2 iclear timer 0 interrupt flag
oflow1 btfss intcon,2 itimer 0 overflow?
goto oflow1 inot yet
bcf intcon,2 iclear timer 0 interrupt flag
incf count,f iinc timer 0 overflow counter
movf count,w icompare
sublw Oxff idecimal 255
btfss status,z itest z flag, skip next instruction
if flag is set
goto oflow1 iagain
oflow2 btfss intcon,2 itimer 0 overflow?
goto oflow2 inot yet
bcf intcon,2 iclear tmrO interrupt flag
incf count,f iinc timer 0 overflow counter
movf count,w icompare
sublw Ox86 idecimal 134
btfss status,z itest z flag, skip next instruction
i f flag is set
goto oflow2 iagain
clrf tmrO iclear timer 0
tl28 btfss tmrO,7 ilook for timer 1=128
goto tl28
t32 btfss tmrO,5 ilook for timer 1=32 (128+32=160)
goto t32
bcf t1con,0 istop timer 1
movf tmr1h,w iget timer 1 high
movwf portb idisplay via port B LEDs
disp_lo btfss porta,2 iwatch display low byte switch
goto disp_Io
movf tmr11,w iget timer 1 low
movwf portb idisplay via port B LEDs
circle goto circle idone
end
j----------------------------------------------------- - - - - - - -
iat device programming time, select:
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal XT (using 4 MHz osc for test)
power-up timer on
brown-out reset enabled
lvp disabled
debug mode disabled
j===================================================== = = = = = = =
92
Procedure:
The input of timer 1 can be connected to a crystal oscillator circuit which is on-chip . A crystal
and two capacitors are connected externally. The principal application of this is real-time keep-
ing. Watch crystals are readily available which have a frequency is 32,768 Hz.
PIC16F870
Tl0SCI Tl0SCO
32.768 KHz
n
22 pi I I 22pf
--
When the timer 1 oscillator is enabled (TICON bit 3 set), the TI0S0 and TI0SI pins become
inputs. The corresponding bits in the TRISC register are ignored.
As it turns out, 32,768 is a power of2, which is very convenient. Timer 1 is a 16-bit counter.
The number 32,768 is represented by 15 bits . We can handle this by setting bit 15 (16th bit) in
timer 1 after each rollover so that inputting 32,768 pulses will cause a rollover.
To get this working in a simplistic way, we will write a program to blink an LED connected to
port B, bit 0 at the rate of one blink per second (precisely).
93
Main Interrupt
Clear Timer 1
Program Service
Interrupt Flag
Routine
1
Set Up Timer 1 To Roll
Over At 32,768
+
Togg le LED
~
Return From Interrupt
i=======SECONDS.ASM=================================4/28/02==
list p=16f870
__config h'3f71'
radix hex
;------------------------------------------------------------
iseconds demo
external oscillator, 32768 Hz, timer 1, prescaler 1:1
;------------------------------------------------------------
cpu equates (memory map)
status equ Ox03
portb equ Ox06
intcon equ OxOb
pir1 equ OxOc
tmr1l equ OxOe
tmr 1h equ OxOf
t1con equ Ox10
trisb equ Ox86
pie1 equ Ox8c
adcon1 equ Ox9f
i----------------------------------------------------- - - - - - - -
bit equates
rpO equ 5
i----------------------------------------------------- - - - - - - -
erg OxOOO
goto start iskip over location pointed to by
interrupt vector
org Ox004
goto iserv
94
movwf portb
bcf intcon,7 idisable global interrupts
bcf intcon,6 idisable peripheral interrupts
bsf status,rpO ibank 1
bcf piel,O idisable tmrl interrupts
bcf status,rpO ibank 0
bcf pirl,O iclear timer 1 interrupt flag
movlw b'OOOOlOlO' iprescaler and tmrl setup,
movwf tlcon tmrl off
clrf tmrlh iclear timer 1 high
clrf tmrll iclear timer 1 low, clear prescaler
bsf intcon,7 ienable global interrupts
bsf intcon,6 ienable peripheral interrupts
bsf status,rpO ibank 1
bsf piel,O ienable tmrl interrupts
bcf status,rpO ibank 0
bsf tlcon,O itimer 1 on
circle goto circle
;------------------------------------------------------------
iserv bcf pirl,O iclear timer 1 interrupt flag
bsf tmrlh,7 iset up timer 1 to rollover at
32,768 counts
btfss portb,O iport B, bit 0 status?
goto setbit ibit is clear
clrbit bcf portb,O iclear port B, bit 0
retfie ireturn from interrupt
setbit bsf portb,O iset port B, bit 0
retfie ireturn from interrupt
j----------------------------------------------------- - - - - - - -
end
j----------------------------------------------------- - - - - - - -
iat device programming time, select:
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal XT (using 4 MHz osc for test)
power-up timer on
brown-out reset enabled
lvp disabled
debug mode disabled
j===================================================== = = = = = = =
When the oscillator is operating properly, a 32.768 KHz sine wave with an amplitude of approx-
imately 3.5 volts will be present at the TI0S0 pin (pin 11, PICI6F870). If the example pro-
gram does not run, check pin 11 with an oscilloscope to be sure that the oscillator is functioning
properly. The values for the capacitors called out in Microchip's data books are not consistent
(15 pF and 33 pF). 22 pF caps worked for me.
The user must provide a software delay to ensure proper oscillator startup. This has not been
done in this example and so you will notice that the time from power-up to first blink is more
than one second. This is something to keep in mind when you design your own applications.
To illustrate real-time keeping, we can create a very simple clock. This is not meant for your
office or living room . It will serve as a simple example and may be used as a basis for control or
data logging applications.
95
+5VDC
10K 10K
t----1 RAO
~~l PIC16F870
-. 8LEDs
' - - - - - - - - 1 RA2 Port B 1----,
32 .768 KHz
o -
N
22 Pf I 22pf
I .
A timer 1 interrupt is generated at precisely 1 second intervals. Software will be used to develop
minutes and hours as illustrated by the following flow chart. The default display is seconds in
binary via the port B LEDs. Opening the minutes switch will cause minutes to be displayed as
long as the switch is open. Similarly, opening the hours switch will result in hours being dis-
played until the switch is closed . The clock runs for 24 hours from the time the F870 is reset
and rolls over meaning all counters are cleared and counting starts over.
Again, note that the most significant bit of timer 1 is set after each rollover so that 32,768 oscil-
lator pulses will cause an overflow.
96
Main
Program Setup
display
No
Interrupt
Clear Timer 1 Interrupt
Service
Flag
Routine
97
I Unimplemented
I I Prescaler 1:1
DIP Switches
~~
1234567
T1CON
C C ceo 0 C
paR = OxOO TMR10ff
;=======TIME.ASM====================================4/28/02 ==
list p=16f8 70
__config h'3f71'
radix hex
j------------------------------------------------------------
; seconds, minutes, hours demo
exte rnal oscil lator, 32768 Hz, timer 1, prescaler 1 :1
j------ ------------------ ------------------------------------
cpu equates (memory map)
status equ Ox03
porta equ OxOS
portb equ Ox06
i nt c on equ OxOb
pir1 equ OxOc
tmr1l equ OxOe
tmr1h equ OxOf
t1 c on equ Ox10
t r i sa equ Ox 8S
tr isb equ Ox86
pie1 equ Ox8 c
adcon1 equ Ox 9f
sec equ Ox20
min equ Ox21
hr equ Ox22
j------------------------------------------------------------
bit equates
z equ 2
rpO equ S
j------------------------------------------------------------
org OxOOO
goto start ;skip over location pointed to by
interrupt vector
org Ox004
goto iserv
98
movwf trisb
movlw b '00000110 I ;turn off A/D, port A
movwf adconl
movlw b '00011111' ;port A inputs
movwf trisa
bcf status,rpO ;switch back to bank 0
movlw b'OOOOOOOO' ;port B lines low
movwf portb
bcf intcon,7 ;disable global interrupts
bcf intcon,6 ;disable periphe ral inter rupts
bsf status,rpO ;bank 1
bcf piel,O ;disable tmrl interrupts
bcf status,rpO ;bank 0
bcf pirl,O ;clear timer 1 interrupt flag
movlw b'OOOOlOlO' ;prescaler and tmrl setup,
movwf tlcon tmrl off
clrf tmrlh ;clear timer 1 high
clrf tmrll ;clear timer 1 low, clear prescaler
clrf sec
clrf min
clrf hr
bsf intcon,7 ;enable global interrupts
bsf intcon,6 ;enable peripheral interrupts
bsf status,rpO ;bank 1
bsf piel,O ;enable tmrl interrupts
bcf status,rpO ;bank 0
bsf tlcon,O ;timer 1 on
display movf sec,w ;get seconds
movwf portb ;display seconds
minutes btfss porta, 0 ;display minutes?
goto hours ;no
movf min,w ;get minutes
movwf portb ;display minutes
goto minutes
hours btfss porta,2 idisplay hours?
goto display ;no
movf hr,w iget hours
movwf portb ;display hours
goto hours
;------------------------------------------------------------
iserv bcf pirl,O iclear timer 1 interrupt flag
bsf tmrlh,7 iset up timer 1 to roll over at
32,768 counts
incf sec,f
movf sec,w icompare
sublw d' 60' iseconds = 60?
btfss status,z itest z flag, skip n ext instruction
i f flag is set
retfie
clrf sec iclear seconds
incf min,f iincrement minutes
movf min,w icompare
sublw d'60' iminutes = 60?
btfss status,z itest z flag, skip next instruction
99
if flag is set
retfie
clrf min ;clear minutes
incf hr,f ;increment hours
movf hr,w ; compare
sublw d'24' ;hours = 24?
btfsc status,z ;test z flag, skip next instruction
if flag is clear
clrf hr ;clear hours
retfie
i----------------------------------------------------- - - - - - - -
end
i------------------------------------------------------ - - - - - -
;at device programming time, select:
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal XT (using 4 MHz osc for test)
power-up timer on
brown-out reset enabled
lvp disabled
debug mode disabled
;============================================================
100
PULSE WIDTH MODULATION (PWM) USING TMR2 AND THE CCP MODULE
The fundamentals ofPWM are explained in Ple'n Up The Pace or Microcontrorn Apps along
with techniques for do-it-yourselfPWM using software. Here we will talk about doing PWM
using hardware peripherals built into many of the PIC microcontroller variants.
A PWM output may be generated on the CCP 1 pin by using TMR2, PR2 and CCP 1 module .
We will use 8 bits to represent the duty cycle for now to keep things simple .
CCP1
Module
PWM Output
PR2
Period
~
JU
TMR2 = PR2 J LL TMR2 - PR2
TMR2 increments. A comparator looks for a match between TMR2 and the duty cycle register.
When a match occurs, the CCPl pin is driven low. A second comparator looks for a match
between TMR2 and the period number in the PR2 register. When a match occurs, the CCPl pin
is driven high and TMR2 is cleared to start the next period . This process repeats over and over
giving a PWM output. The duty cycle may be changed on-the-fly to change the analog voltage
output on the CCPl pin by loading a different duty cycle number in the duty cycle register
which is CCPRIL.
101
Notice that the TMR2 postscaler is not involved in PWM applications.
Generating a PWM output via the CCP1 pin (8-bit duty cycle) requires:
A short program will serve to demonstrate how all this works. The object is to generate a PWM
output on the CCP1 pin. Timer 2 is fed by the internal instruction clock and the prescaler choic-
es are 1:1, 1:4, and 1:16. I arbitrarily chose to use 1:4 as the prescaler value and OxFF (for deci-
mal 256 counts) as the period register value.
102
The duty cycle for our demonstration is 50 percent, so Ox7F is loaded into CCPRIL which
serves as the duty cycle register (8 bits) .
Unimplemented
TMR20ff
I Unimplemented
I I Not Used
~~
,---,---.,.--.,----,
[O]YTOJ?J
-------
CCP1CON 1 11 1 0 1 0 I
POR = OxOO I
PWM Mode (11 xx)
103
DIP Switches
1 2 345 6 7
ceo C ceo
i=== ====HDWPWMX.ASM=================================4/28/02==
list p=16f870
__config h'3f71'
radix hex
j----------------------------------------------------- - - - - - - -
cpu equates (memory map)
status equ Ox03
portc equ Ox07
intcon equ OxOb
tmr2 equ Ox11
t2con equ Ox12
ccprll equ Ox15
ccp lcon equ Ox1 7
trisc equ Ox87
piel equ Ox8c
pr2 equ Ox92
adconl equ Ox9f
j----------------------------------------------------- - - - - - - -
bit equates
rpO equ 5
ccpl equ 2 iccpl bit 2, port C
j----------------------------------------------------- - - - - - - -
org OxOOO
104
movwf t2con tmr2 off
clrf tmr2 iclear tmr2
movlw b' 00001100 I iccpl pwm mode, ccpl module on
movwf ccplcon
bsf t2con,2 itmr2 on
circle goto circle idone
end
i------- ----------------------------------- ----------- - - - - - - -
iat device programming time, select:
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal XT (using 4 MHz osc for test)
power-up timer on
brown-out reset enabled
lvp disabled
debug mode disabled
;================================================== === == = = = = =
An oscilloscope may be used to observe the output signal. The duty cycle will be 50 percent.
The next example shows how an adjustable analog output on the CCPl pin can be created using
PWM via TMR2, PR2 and the CCPl module. The circuit is controlled by an increase (voltage)
button and a decrease button . 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 proportional to the time interval generated by the time delay code (change it if you wish).
+SVDC
10K . ~ 10K c ~
RAO
Incr ~ Dea~
PIC16F870
l l
- RA2 CCP1 PWMOutpuI
105
OVERVIEW
repeat
Yes
No
Yes
No
Main
Program
repeat
Look For
Key Press-
Inc Or Dec
If Find One
106
Subroutine
pressck
No
decduty
Yes
No
Yes
Unimplemented
------
I Postscaler Not Used In
I PWM Applications
T2CON
~
POR .. OxOO
L Prescaler 1:4
TMR20ff
DIP Switches
1 2 345 6 7
000 C ceo I Unimplemented
I I
L Decrease When
Closed ~~
Not Used
.---.------.-----.-----
CCP1CON [OJ?TOTOJ 1 11 10101
Increase When
Closed
POR .. OxOO -------- I
PWM Mode (11xx)
107
i=======CCPPWM.ASM==================================4/2 8 / 02==
list p=16f870
__eonfig h'3f71'
radix hex
i----------------------------------------------------- - - - - - - -
cpu equates (memory map)
status equ Ox03
porta equ Ox05
porte equ Ox07
inteon equ OxOb
tmr2 equ Ox11
t2eon equ Ox12
eeprll equ Ox15
eepleon equ Ox17
duty equ Ox20
meount equ Ox21
neount equ Ox22
trisa equ Ox85
trise equ Ox87
piel equ Ox8e
pr2 equ Ox92
adeonl equ Ox9f
i----------------------------------------------------- - - - - - - -
bit equates
z equ 2
rpO equ 5
eepl equ 2 ieepl bit 2, port C
i----------------------------------------------------- - - - - - - -
org OxOOO
108
movlw b'OOOOOOOl' ipresca1er = 1:4,
movwf t2con tmr2 off
clrf tmr2 ic1ear tmr2
movlw b' 00001100 I iccp1 pwm mode, ccp1 module on
movwf ccp1con
bsf t2con,2 itmr2 on
;------------------------------------------------------------
repeat call pressck ilook for incr/decr button press
movlw Oxff idelay 200 milliseconds
movwf mcount
loadn movlw Oxff
movwf ncount
decn decfsz ncount,f idecrement N
goto decn iagain
decfsz mcount,f idecrement M
goto loadn iagain
goto repeat
:---------------------------------------------------- --------
pressck btfss porta,2 idecrease button pressed?
goto decduty iyes, decrement duty cycle
btfss porta, 0 iincrease button pressed?
goto incduty iyes, increment duty cycle
return
incduty movf duty,w iget duty cycle into W
sublw Oxff iduty cycle=Oxff?
btfsc status,z
return
incf duty,f iincrement duty cycle
movf duty,w iget duty cycle into W
movwf ccpr11 iduty cycle into ccp register
return ipress check done
decduty movf duty,w iget duty cycle into W
sublw OxOO iduty cycle=O?
btfsc status,z
return
decf duty,f idecrement duty cycle
movf duty,w iget duty cycle into W
movwf ccpr11 iduty cycle into ccp register
return ipress check done
end
:------------------------------------------------------------
iat device programming time, select:
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal XT (using 4 MHz osc for test)
power-up timer on
brown-out reset enabled
lvp disabled
debug mode disabled
:============================================================
109
An oscilloscope may be used to observe the output signal. The duty cycle will be 50 percent ini-
tially. Close the increase switch and observe the results on the scope.
CCPR1L CCP1CON
7654 321 o I5 4
,--------,--------,------,---,-----,----,--CO
[ITT]
8 Bits (9-2) 2 Bits (1,O)
The high 8 bits (bits 9 - 2) are the CCPRIL register. The low 2 bits are bits 1 and 0 of the
CCPICON register. Resolution up to 10 bits is possible.
The most significant 8 bits and least significant 2 bits must be loaded separately requiring a little
thought in programming.
Many PWM applications involve incrementing or decrementing the duty cycle. To do this, the
current duty cycle value needs to be stored in two file registers and incremented or decremented
there. Then a copy of the contents of those registers is transferred to the CCP module to change
the duty cycle. In the 10-bit mode, doing this is an extra challenge. For the purpose of incre-
menting or decrementing, the low 8 bits need to be in an 8-bit register and the two remaining
(high) bits should be in a second register. The challenge is that the opposite arrangement is used
in the CCP module registers. The high 8 bits are written to the CCPRIL register and the low 2
bits are written to the middle of the CCPICON register.
110
Here is an example of IO-bit hardware PWM. The duty cycle is stored in two registers. The low
8 bits are in the duty Io register. The high 2 bits are in the duty_hi register. A subroutine called
"dutychg" moves the bits to their proper places in the CCP module registers.
dutyJo
[TTJ] I
_ _-,I I II
~\ I II I
I I----!-_ _J
[TTJ],----,------,--O I------L------'
5 4
CCPR1L CCP1CON
PIC16F870
111
dutychg
Clear
Bits 1,0 Of
Clear
Duty Cycle
Clear
Clear
temp Into W,
Duty Cycle Bits 9-2
DIP Switches
112
Unimplemented I Unimplemented
~
I
Postscaler Not Used In I I NotUsed
--------
PWM Applications
~~
POR = OxOO
~
L Prescaler 1:4
POR = OxOO --------
I
PWM Mode (11xx)
TMR20ff
;=======HDWPWMY.ASM=================================4/28/02==
list p=16f870
__config h'3f71'
radix hex
;------------------------------------------------------------
cpu equates (memory map)
status equ Ox03
portc equ Ox07
intcon equ OxOb
tmr2 equ Ox11
t2con equ Ox12
ccprll equ Ox15
ccplcon equ Ox17
duty_lo equ Ox20
duty_hi equ Ox21
temp equ Ox22
trisc equ Ox87
piel equ Ox8c
pr2 equ Ox92
adconl equ Ox9f
j----------------------------------------------------- - - - - - - -
bit equates
c equ o
rpO equ 5
ccpl equ 2 ;ccpl bit 2, port C
j----------------------------------------------------- - - - - - - -
org OxOOO
113
bcf piel,2 ;disable ccpl interrupts
bcf status,rpO ;bank 0
clrf ccplcon ;ccpl module off
bsf status,rpO ;bank 1
movlw Oxff ;decimal 255
movwf pr2 ;load period register
bcf status,rpO ;bank 0
movlw OxOO ;duty cycle 25 percent
movwf duty_lo
movlw b'OOOOOOOl' ;duty cycle hi 2 bits
movwf duty_hi
call dutychg ;change duty cycle via subroutine
movlw b'OOOOOOOl' ;prescaler = 1:4,
movwf t2con tmr2 off
clrf tmr2 ;clear tmr2
movlw b' 00001100 1 ;ccpl pwm mode, ccpl module on
movwf ccplcon
bsf t2con,2 ;tmr2 on
circle goto circle ;done
,-------------------------------------------------------------
dutychg bcf status,c ;clear carry flag
rrf duty_lo,w ;rotate duty right, result in w
movwf temp ;store in temp
bcf status,c ;clear carry flag
rrf temp,f ;bits 7-2 of duty cycle
btfsc duty_hi, 1 ;duty cycle hi bit 1 = l?
bsf temp, 7 ;yes, set duty register bit 9
btfsc duty_hi, 0 ;duty cycle hi bit 0 = l?
bsf temp, 6 ;yes, set duty register bit 8
movf temp,w ;duty cycle bits 9-2
movwf ccprll ;into duty cycle register
bcf ccplcon,5 ;clear bit 1 of duty cycle reg
bcf ccplcon,4 ;clear bit 0 of duty cycle reg
btfsc duty_lo,l ;duty cycle bit 1 = l?
bsf ccplcon,5 ;yes, set duty register bit 1
btfsc duty_lor 0 ;duty cycle bit 0 = l?
bsf ccplcon,4 ;yes, set duty register bit 0
return
i----------------------------------------------------- - - - - - - -
end
i----------------------------------------------------- - - - - - - -
;at device programming time, select:
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal XT (using 4 MHz osc for test)
power-up timer on
brown-out reset enabled
Ivp disabled
debug mode disabled
i===================================================== =======
114
When the program runs , a PWM signal is generated on the CCPl pin. The duty cycle is 25 per-
cent.
The next challenge is to increment and decrement a regist er pair wh ere only the least significa nt
2 bits of the upper register are used . Notice how the increment and decrement instructions affect
the zero flag .
When the lower register is incremented, we need to know when it overflows (OxFF to OxOO) so
that a check can be made to see if the upper register should be incremented. We can use the state
of the ze ro flag to tell us .
When the lower reg ister is decremented, we need to know when it underflows (OxFF to OxOO) so
that a check can be made to see if the upper register should be decremented . The state of the
zero flag won't tell us, so we will have to use a comparison to test for this .
Increment:
FF to 00
Decrement:
00 to FF
The flow charts which follow show one method for doing this .
Again, the duty cycle is stored in two registers. The low 8 bits are in the dutyJo register. The
high 2 bits are in the duty_hi register.
The increment/decrement program must keep the values cont rollin g the duty cycl e within these
boundaries.
115
Increment
11111111
Yes
No
Decrement
116
i------------------------------------------------------ - - - - - -
incduty movf duty_lo,w itest for maximum
sublw Oxff
btfss status,z
goto do i inot at maximum
movf duty_hi,w
sublw b' 00000011' icompare
btfsc status,z
return iat maximum
do i incf duty_lo,f iincrement
btfss status,z
goto inc
movf duty_hi,w
sublw b' 00000011' icompare
btfsc status,z
goto inc
incf duty_hi,f
inc call dutychg ichange duty cycle
return ipress check done
i----------------------------------------------------- - - - - - - -
decduty movf duty_lo,w itest for minimum
sublw OxOO
btfss status,z
goto do d inot at minimum
movf duty_hi,w
sublw b'OOOOOOOO'
btfsc status,z
return iat minimum
do d decf duty_lo,f idecrement
movf duty_lo,w
sublw Oxff
btfss status,z
goto dec
movf duty_hi,w
sublw b'OOOOOOOO' icompare
btfsc status,z
goto dec
decf duty_hi,f
dec call dutychg ichange duty cycle
return ipress check done
i-------------------------------------------------- --- - - - - - - -
117
ANALOG OUTPUT - INCREASE/DECREASE BUTTONS· PWM - 1a-bit Mode
The next example shows how to generate a PWM output with increase/decrease capability using
10 bits to represent the duty cycle. The rate of increase/decrease is controlled by a software time
delay loop . When you test this circuit and program, you can change the delay if you wish.
+5VDC
Dea~
PIC16F870
- l
RA2 CCP1 PNMOuipul
118
OVERVIEW
repeat
Yes
No
Yes
Main
Program
repeat
Look For
Key Press -
Inc Or Dec
If Find One
119
Subroutine
pressck
No
decduty
Yes
No
Yes
DIP Switches
1 2 3 4 5 6 7
a a a c c c a
LDecrease When
Closed
Increase When
Closed
Unimplemented I Unimplemented
-------
I PWM Applications
~~
L Prescaler 1:4
paR - OxOO --------
I
PWM Mode (11 xx)
TMR20ff
120
i=======CCPPWMX.ASM=================================4/ 28102==
list p=16f870
__config h'3f7I'
radix hex
i--------------------------- ------- ------------------- - - - - - - -
cpu equates (memory map)
status equ Ox03
porta equ Ox05
portc equ Ox07
intcon equ OxOb
tmr2 equ Ox11
t2con equ Ox12
ccprIl equ Ox15
ccpIcon equ Ox17
duty_l 0 equ Ox20
duty_hi equ Ox2I
temp equ Ox22
mcount equ Ox23
ncount equ Ox24
trisa equ Ox85
trisc equ Ox87
piel equ Ox8c
pr2 equ Ox92
adconl equ Ox9f
;------------------------------------------------------------
bit equates
c equ o
z equ 2
rpO equ 5
ccpI equ 2 iccpI bit 2, port C
i----------------------------------------------------- - - - - - - -
org OxOOO
121
movlw b'OOOOOOOl' iduty cycle hi 2 bits
movwf duty_hi
call dutychg ichange duty cycle via subroutine
movlw b'OOOOOOOl' iprescaler = 1:4,
movwf t2con tmr2 off
clrf tmr2 iclear tmr2
movlw b' 00001100' iccp1 pwm mode, ccp1 module on
movwf ccp1con
bsf t2con,2 itmr2 on
i----------------------------------------------------- - - - - - - -
repeat call pressck ilook for incr/decr button press
movlw Ox7f idelay 100 milliseconds
movwf mcount
loadn movlw Oxff
movwf ncount
decn decfsz ncount,f idecrement N
goto decn iagain
decfsz mcount,f idecrement M
goto loadn iagain
goto repeat
j----------------------------------------------------- - - - - - - -
pressck btfss porta, 2 idecrease button pressed?
call decduty iyes, decrement duty cycle
btfss porta,O iincrease button pressed?
call incduty iyes, increment duty cycle
return
j------------------------- ---------------------------- - - - - - - -
incduty movf duty_lo,w itest for maximum
sublw Oxff
btfss status,z
goto do i inot at maximum
movf duty_hi,w
sublw b' 00000011' icompare
btfsc status,z
return iat maximum
do i incf duty_lo,f iincrement
btfss status,z
goto inc
movf duty_hi,w
sublw b' 00000011' icompare
btfsc status,z
goto inc
incf duty_hi,f
inc call dutychg ichange duty cycle
return ipress check done
j----------------------------------------------------- - - - - - - -
decduty movf duty_lo,w itest for minimum
sublw OxOO
btfss status,z
goto do d inot at minimum
movf duty_hi,w
sublw b'OOOOOOOO'
btfsc status,z
return iat minimum
122
do d decf duty_lo,f ; decrement
movf duty_lo,w
sublw Oxff
btfss status,z
goto dec
movf duty_hi,w
sublw b'OOOOOOOO' ; compare
btfsc status,z
goto dec
decf duty_hi,f
dec call dutychg ;change duty cycle
return ;press check done
;-------------------------------------- ----- - --- -------------
dutychg bcf status,c ;clear carry flag
rrf duty_lo,w ;rotate duty right, result in W
movwf temp ;store in temp
bcf status,c ;clear carry flag
rrf temp,f ;bits 7-2 of duty cycle
movf temp,w
btfsc duty_hi, 1 ;duty cycle hi bit 1 = 1?
bsf temp, 7 ; yes, set duty register bit 9
btfsc duty_hi, a ;duty cycle hi bit a = 1?
bsf temp, 6 ;yes, set duty register bit 8
movf temp,w ;duty cycle bits 9-2
movwf ccpr11 ;into duty cycle register
bcf ccp1con,5 ;clear bit 1 of duty cycle reg
bcf ccp1con,4 ;clear bit a of duty cycle reg
btfsc duty_lo,l ;duty cycle bit 1 = 1?
bsf ccp1con,5 ;yes, set duty register bit 1
btfsc duty_10,0 ;duty cycle bit a = 1?
bsf ccp1con,4 ;yes, set duty register bit a
return
end
;------------------------------------------------------------
;at device programming time, select:
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal XT (using 4 MHz osc for test)
power-up timer on
brown-out reset enabled
lvp disabled
debug mode disabled
;============================================================
An oscilloscope may be used to observe the output signal. The duty cycle will be 50 percent ini-
tially.
123
DESIGNING AND BUILDING
YOUR OWN TEST EQUIPMENT
Designing and building your own lab test equipment is a great way to have some fun and learn
more about the applications for microcontrollers in projects of your own choosing. The projects
presented are not intended to be the ultimate device of their type. They are intended as simple
examples which demonstrate PIC microcontroller techniques you can use for your own
amazement.
To add to the fun and to create more useful experiments, we need a user interface which will
allow us to key in numbers corresponding to pulse width, frequency, etc. Serial communication,
interfacing an alphanumeric LCD, scanning keypads, and double precision arithmetic are
explained in P IC'n Up The Pace or MlC1'OCOntrol'n App!!. An interface using a 3x4 telephone
keypad (switch matrix) and a 1 line by 16 character alphanumeric display along with a 3-digit
decimal to 8-bit binary conversion program are presented there.
The hardware for the remaining timing and counting experiments utilizes the TC board used thus
far plus the keypad and the PICILCD boards described in PIC'n Up The Pace or
MlCl'OCOntrol'nApp!! (see Appendix D and Appendix E in this book).
Thus, there are three modules and a 5 volt power supply involved.
Since we are using a 16-bit timer here, we will need 5-digit decimal to 16-bit binary conversion
capability. The Decimal Interface chapter in PIC'n Up The Pace or Microcontrol'n Apps
describes 3-digit decimal to 8-bit binary conversion . The programming example is decentry.asm
which includes the routines for scanning the keypad, serial output of the information to be dis-
played, and decimal-to-binary conversion . Following will be an adaptation of that program.
The changes are:
124
TCBOARD PICILCD
RA1 RAO
10 RD
II
LCD
II
1
PortS
V
'" 7
KEYPAD BOARD
1 2 3
* 0 #
• 'n . •
- - ~
f~- - - _
125
5-digit Decimal To 16-bit Binary Entry Program
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 pair which accumulates the total value of the number.
The first digit entered is the 10,000's place digit so it is multiplied by 10,000 and added to the
addition registers named "numsum ". The second digit entered is multiplied by 1,000, and so on,
until the binary equivalent of the number has been assembled in the numsum locations.
10,000'5
11 11
1 '0~~'~'s
10'5
1'5
n n n n n
I x 10000=
x 1000=
x10 0 ..
x 10=
Binary Sum =
To suppress high order zeros, we will need a most significant digit flag for each digit down to
100's. The first non-zero digit encountered will set the flag . From that point on, a zero should
be displayed rather than being replaced with a blank.
126
BlankTo Display RAM
Ox20
Yes
Etc.
127
i=======DECENT63.ASM================================4/28/02==
list p=l6f870
__config h'3f7l'
radix hex
j----------------------------------------------- ------- - - - - - -
cpu equates (memory map)
tmrO equ OxOl
status equ Ox03
porta equ Ox05
portb equ Ox06
intcon equ OxOb
sendreg equ Ox20
count equ Ox2l
instr equ Ox22
char equ Ox23
addr equ Ox24
digctr equ Ox25
rowctr equ Ox26
colctr equ Ox27
rowbits equ Ox28
colbits equ Ox29
temp equ Ox2a
ncount equ Ox2b
mcount equ Ox2c
test n equ Ox2d
math equ Ox2e
copy_8xn equ Ox2f
numsuml equ Ox30
numsumh equ Ox3l
tenthou equ Ox32
thou equ Ox33
hund equ Ox34
ten equ Ox35
one equ Ox36
hold equ Ox37
lobyte equ Ox38
hibyte equ Ox39
copylo equ Ox3a
copyhi equ Ox3b
flags equ Ox3c
opt reg equ Ox8l
trisa equ Ox85
trisb equ Ox86
adconl equ Ox9f
j----------------------------------------------------- - - - - - - -
bit equates
c equ o
z equ 2
rpO equ 5
j------------------------------------ ---------- ------- - - - - - - -
org OxOOO
128
start bsf status,rpO ;switch to bank 1
movlw b' 00000110' ;turn off A/D, port A
movwf adcon1
movlw b'OOOOOOOO' ;port A outputs
movwf trisa
movlw b' 01110000' ;port B inputs/outputs
movwf trisb
bcf status,rpO ;switch bac k t o bank 0
bsf porta, 1 ;output mark, bit 1 (serial - LCD)
bsf portb,O ;rows high
bsf portb,l
bsf portb,2
bsf portb,3
bcf portb,? ;unused line low
call debounce
call debounce
movlw OxOO ;blanks to display RAM
movwf instr
call sndstf isend instruction to LCD module
call debounce
movlw Ox01 ;send 16 characters to display
movwf instr
call sndstf ;send instruction to LCD module
call debounce
clrf numsumh ;clean out
clrf numsuml ;clean out
clrf flags
do10000 call scan10
movf digctr,w ;get 10000's digit
movwf tenthou ;save copy
sublw OxOO ;compare - digit=O?
btfsc status,z
goto tthzero ;yes
bsf flags,O ;no, this is ms digit
movf tenthou,w
movwf lobyte
clrf hibyte
call decmult ;times 10
call decmult ;times 10
call decmult ;times 10
call decmult ;times 10, result = x 1 0 0 0 0
call addnum ;add .1 0 0 0 0 ' s to num sum registers
movf tenthou,w ;get 10000's digit
call hex2asc ;convert binary digit to ascii
movwf char
movlw Ox 20 ;display RAM address
movwf addr
movlw Ox03 ;ascii char follows, send to display RAM
movwf instr
call sndstf ;send 10000's digit to display RAM
call debounce ;time delay - debounce switches
do1000 call scan10
movf digctr,w ;get 1000's digit
movwf thou ;save copy
129
sublw OxOO icompare - digit=O?
btfsc status,z
goto thzero iyes
bsf flags,O i no, this could be ms digit
movf thou,w
movwf lobyte
clrf hibyte
call decmult i times 10
call decmult itimes 10
call decmult itimes 10, result = x 1 0 0 0
call addnum iadd 1000's to num sum registers
movf thou,w ;get 1000's digit
call hex2asc iconvert binary digit to ascii
movwf char
movlw Ox21 idisplay RAM address
movwf addr
movlw Ox03 iascii char follows, send to display RAM
movwf instr
call sndstf isend 1000's digit to display RAM
call debounce itime delay - debounce switches
do100 call scan10
movf digctr,w iget 100's digit
movwf hund isave copy
sublw OxOO icompare - digit=O?
btfsc status,z
goto hzero iyes
bsf flags, 0 ino, this could be ms digit
movf hund,w
movwf lobyte
clrf hibyte
call decmult ; times 10
call decmult itimes 10, result = x100
call addnum iadd 100's to num sum registers
movf hund,w iget 100's digit
call hex2asc iconvert binary digit to ascii
movwf char
movlw Ox22 idisplay RAM address
movwf addr
movlw Ox03 iascii char follows, send to display RAM
movwf instr
call sndstf isend 100's digit to display RAM
call debounce itime delay - debounce switches
dolO call scan10
movf digctr,w iget 10's digit
movwf ten isave copy
sublw OxOO icompare - digit=O?
btfsc status,z
goto tzero iyes
movf ten,w
movwf lobyte
clrf hibyte
call decmult itimes 10
call addnum iadd 10's to num sum registers
movf ten,w i g e t 10's digit
130
call hex2asc iconvert binary digit to ascii
movwf char
movlw Ox23 idisplay RAM address
movwf addr
movlw Ox03 iascii char follows, send to display RAM
movwf instr
call sndstf isend 10's digit to display RAM
call debounce itime delay - debounce switches
dol call scan10
movf digctr,w iget l's digit
movwf one isave copy
movwf lobyte
clrf hibyte
call addnum iadd l's to num sum registers
movf one,w iget one's digit
call hex2asc iconvert binary digit to ascii
movwf char
movlw Ox24 ;display RAM address
movwf addr
movlw Ox03 ;ascii char follows, send to display RAM
movwf instr
call sndstf ;send l's digit to display RAM
call debounce
send movlw Ox01 ;send 16 characters to display
movwf instr
call sndstf ito LCD module
;------------------------------------------------------------
call debounce idelay, display decimal entry
call debounce
call debounce
call debounce
call debounce
call debounce
call debounce
call debounce
call debounce
call debounce
,._---------------------- ---- ---------------------------------
idisplay numsum contents high byte first with time delay
movf numsumh,w iget total high byte
movwf char
movlw Ox04 ihex byte follows, convert and display
movwf instr
call sndst f
call debounce ;delay, display high byte
call debounce
call debounce
call debounce
call debounce
call debounce
call debounce
call debounce
call debounce
call debounce
131
rnovf nurnsurnl,w iget total low byte
rnovwf char
rnovlw Ox04 ihex byte follows, convert and display
rnovwf instr
call sndstf
circle goto circle idone
i----------------------------------------------------- - - - - - - -
tthzero rnovlw Ox20 iascii blank
rnovwf char
rnovlw Ox20 idisplay RAM address
rnovwf addr
rnovlw Ox03 iascii character to display RAM
rnovwf instr
call sndstf
call debounce
goto dolOOO
j----------------------------------------------------- - - - - - - -
thzero btfsc flags, 0 irns digit entered?
goto zeroth iyes
rnovlw Ox20 iascii blank
thchar rnovwf char
rnovlw Ox2l idisplay RAM address
rnovwf addr
rnovlw Ox03 iascii character to display RAM
rnovwf instr
call sndstf
call debounce
goto dolOO
zeroth rnovlw Ox30 iascii 0
goto thchar
i----------------------------------------------------- - - - - - - -
hzero btfsc flags, 0 irns digit entered?
goto zeroh iyes
rnovlw Ox20 iascii blank
hchar rnovwf char
rnovlw Ox22 idisplay RAM address
rnovwf addr
rnovlw Ox03 iascii character to display RAM
rnovwf instr
call sndstf
call debounce
goto dolO
zeroh rnovlw Ox30 iascii 0
goto hchar
j----------------------------------------------------- - - - - - - -
tzero btfsc flags, 0 irns digit entered?
goto zerot iyes
rnovlw Ox20 iascii blank
tchar rnovwf char
rnovlw Ox23 idisplay RAM address
rnovwf addr
rnovlw Ox03 iascii character to display RAM
rnovwf instr
call sndstf
132
call debounce
goto dol
zerot movlw Ox30 ;ascii 0
goto tchar
j----------------------------------------------------- - - - - - - -
;returns with digit in digctr
133
debounce movlw Ox02 ito counter
movwf count
dbloop movlw Oxff iM
movwf mcount ito M counter
loadn movlw Oxff iN
movwf ncount ito N counter
decn decfsz ncount,f idecrement N
goto decn iagain
decfsz mcount,f idecrement M
goto loadn iagain
decfsz count,f
goto dbloop ithru loop within a loop twice -
400 milliseconds
return idone
;------------------------------------------------------------
sndstf movf instr,w iget instruction
movwf sendreg ito be sent
call ser out ito serial out subroutine
movf char,w iget character or hex byte
movwf sendreg ito be sent
call ser out ito serial out subroutine
movf addr,w iget address
movwf sendreg ito be sent
call ser out ito serial out subroutine
return
;------------------------------------------------------------
ser out bcf intcon,5 idisable tmrO interrupts
bcf intcon,7 idisable global interrupts
clrf tmrO iclear timer/counter
clrwdt iclear wdt prep prescaler assign
bsf status,rpO ito page 1
movlw b' 11011000 I iset up timer/counter
movwf opt reg
bcf status,rpO iback to page 0
movlw Ox08 iinit shift counter
movwf count
bcf porta,1 istart bit
clrf tmrO istart timer/counter
bcf intcon,2 iclear tmrO overflow flag
time1 btfss intcon,2 itimer overflow?
goto time1 ino
bcf intcon,2 iyes, clear overflow flag
nxtbit rlf sendreg,f irotate msb into carry flag
bcf porta, 1 iclear port A, bit 1
btfsc status,c itest carry flag
bsf porta, 1 ibit is set
time2 btfss intcon,2 itimer overflow?
goto time2 ino
bcf intcon,2 iclear overflow flag
decfsz count,f ishifted 8?
goto n xtbit ino
bsf porta, 1 iyes, output mark
time3 btfss intcon,2 i t i me r overflow?
goto time3 ino
134
return idone
;--------------------------------------------------------------------
imultiply 2-byte binary number by 10 decimal
ienter sub with number in hibyte and lobyte - e xit with result
in hybyte and lobyte
135
;------------------------------------------------------------
iat device programming time, select:
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal XT (using 4 MHz osc for test)
power-up timer on
brown-out reset enabled
lvp disabled
debug mode disabled
;============================================================
The number keyed in will be displayed and will be in the "numsum" registers . The most signifi-
cant byte will be displayed on completion of a time delay followed by the least significant byte
after a second time delay.
Examples:
------------------------------------------
Key In Hex High Byte Low Byte
------------------------------------------
00000 OxOOOO 0000 0000 0000 0000
00015 OxOOOF 0000 0000 0000 1111
00016 Ox0010 0000 0000 0001 0000
65535 OxFFFF 1111 1111 1111 1111
65536 OxOOOO 0000 0000 0000 0000
12345 Ox3039 0011 0000 0011 1001
The resulting number may be loaded into a counter or used for set point comparison or whatever.
Hit the reset switch on both the TC board and PICILCD board between entries.
136
DIGITAL PULSE GENERATOR
The object here is to be able to key in the desired pulse width in microseconds and to have that
pulse output when the "ready" switch is opened. The 5-digit decimal number keyed in must be
displayed on the LCD and converted to 16-bit binary for use in the compare register to deter-
mine the pulse width. The pulse is output via the CCPl pin and is terminated when the contents
of timer 1 match the contents of the compare register. The pulse is positive going.
The range of possible pulse widths is 25 to 65,535 microseconds. The range could be extended
to longer pulses by using an external clock providing 1 millisecond or 1 second pulses (as exam-
ples) .
+5VDC
10K . ~
TCBOARD PICJ1..CD
RO.d'l
- ..n.. CCP1
I I LCD
II
1-
Port B
680 ....
1 2 3
4 5 6
Note : Use 3 keypad pulJup
resistors on TC board .
7 8 9
* 0 #
137
No
gohi
No
DIP Switches
1 2 345 6 7
COO C ceo
L Closed On Reset
Open When Ready
138
; =======PULSGEN.ASM=================================4/28/02==
list p=l6f870
__config h'3f7l'
radix hex
;------------------------------------------------------------
cpu equates (memory map)
tmrO equ OxOl
status equ Ox03
porta equ OxOS
portb equ Ox06
portc equ Ox07
intcon equ OxOb
pirl equ OxOc
tmrll equ OxOe
tmrlh equ OxOf
tlcon equ OxlO
ccprll equ OxlS
ccprlh equ Oxl6
ccplcon equ Oxl7
sendreg equ Ox20
count equ Ox21
instr equ Ox22
char equ Ox23
addr equ Ox24
digctr equ Ox2S
rowctr equ Ox26
colctr equ Ox27
rowbits equ Ox28
colbits equ Ox29
temp equ Ox2a
ncount equ Ox2b
mcount equ Ox2c
test n equ Ox2d
math equ Ox2e
copy_8xn equ Ox2f
numsuml equ Ox30
numsumh equ Ox3l
tenthou equ Ox32
thou equ Ox33
hund equ Ox34
ten equ Ox3S
one equ Ox36
hold equ Ox37
lobyte equ Ox38
hibyte equ Ox39
copylo equ Ox3a
copyhi equ Ox3b
flags equ Ox3c
opt reg equ Ox8l
trisa equ Ox8S
trisb equ Ox86
trisc equ Ox87
piel equ Ox8c
adconl equ Ox9f
139
i------------------------ --------------------- --- ----- - - - - - - -
bit equates
c equ 0
z equ 2
rpO equ 5
ccp1 equ 2 ;ccp1 bit 2, port C
j------------------ ----------------------------------- - - - - - - -
org OxOOO
140
movf tenthou,w ;get 10000's digit
call hex2asc ;convert binary digit to ascii
movwf char
movlw Ox20 ;display RAM address
movwf addr
movlw Ox03 ;ascii char follows, send to display RAM
movwf instr
call sndstf ;send 10000' s digit to display RAM
call debounce ;time delay - debounce switches
do1000 call scan10
movf digctr,w ;get 1000's digit
movwf thou ;save copy
sublw OxOO ; compare - digit=O?
btfsc status,z
goto thzero ;yes
bsf flags, 0 ;no, this could be ms digit
movf thou,w
movwf lobyte
clrf hibyte
call decmult ;times 10
call decmult ;times 10
call decmult ;times 10, result = x 1 0 0 0
call addnum ;add 1000's to num sum registers
movf thou,w ;get 1000's digit
call hex2asc ;convert binary digit to ascii
movwf char
movlw Ox21 ;display RAM address
movwf addr
movlw Ox03 ;ascii char follows, send to display RAM
movwf instr
call sndstf ;send 1000's digit to display RAM
call debounce ;time delay - debounce switches
do100 call scan10
movf digctr,w ;get 100's digit
movwf hund ;save copy
sublw OxOO ; compare - digit=O?
btfsc status,z
goto hzero ;yes
bsf flags,O ; no, this could be ms digit
movf hund,w
movwf lobyte
clrf hibyte
call decmult ;times 10
call decmult ;times 10, r esul t = x 1 0 0
call addnum ;add 100 's to num sum registers
movf hund,w ;get 100's digit
call hex2asc ; convert binary digit to ascii
movwf char
movlw Ox22 ;display RAM address
movwf addr
movlw Ox03 ; a s ci i char follows, send t o d ispl a y RAM
movwf instr
call sndstf ;send 100's digit to display RAM
call debounce ; time delay - debounce switches
141
dolO call scan10
movf digctr,w ;get 10's digit
movwf ten ;save copy
sublw OxOO ;compare - digit=O?
btfsc status,z
goto tzero ;yes
movf ten,w
movwf lobyte
clrf hibyte
call decmult ;times 10
call addnum ;add 10'5 to num sum registers
movf ten,w ;get 10's digit
call hex2asc ;convert binary digit to ascii
movwf char
movlw Ox23 ;display RAM address
movwf addr
movlw Ox03 ;ascii char follows, send to display RAM
movwf instr
call sndstf ;send 10'5 digit to display RAM
call debounce ;time delay - debounce switches
dol call scan10
movf digctr,w ;get 1'5 digit
movwf one ;save copy
movwf lobyte
clrf hibyte
call addnum ;add 1'5 to num sum registers
movf one,w ;get one's digit
call hex2asc ;convert binary digit to ascii
movwf char
movlw Ox24 ;display RAM address
movwf addr
movlw Ox03 ;ascii char follows, send to display RAM
movwf instr
call sndstf ;send 1'5 digit to display RAM
call debounce
send movlw Ox01 ;send 16 characters to display
movwf instr ·
call sndstf ;to LCD module
call debounce ;delay, display decimal entry
;------------------------------------------------------------
bcf intcon,7 ;disable global interrupts
bcf intcon,6 ;disable peripheral interrupts
bsf status,rpO ;bank 1
bcf pie1,0 ;disable timer 1 interrupts
bcf pie1,2 ;disable ccp1 interrupts
bcf status,rpO ;bank 0
bcf pir1,2 ;clear ccp1 interrupt flag
clrf ccp1con ;ccp1 module off
movlw b'OOOOOOOO' ;tmr1 prescaler and tmr1 setup,
movwf t1con tmr1 off
clrf tmr1h ;clear timer 1 high
clrf tmr11 ;clear timer 1 low
ready btfss porta, 0 ; ready?
goto ready ;not yet
142
trick clrf ccprlh iclear compare register high
movlw OxOl iload compare r egister low
movwf ccprll
movlw b'OOOOlOOO' iccpl compare mode, ccpl pin high
movwf ccplcon on match, ccpl module on,
ccpl pin low
bsf tlcon,O itimer 1 on
gohi btfss pirl,2 iccpl interrupt flag set?
goto gohi inot yet
movf numsurnh,w iget interval high byte
movwf ccprlh iload compare register high
movf numsuml,w iget interval low byte
movwf ccprll iload compare register low
bsf ccplcon,O iccpl pin low on match
circle goto circle idone
i----------------------------------------------------- - - - - - - -
tthzero movlw Ox20 iascii blank
movwf char
movlw Ox20 idisplay RAM address
movwf addr
movlw Ox03 iascii character to display RAM
movwf instr
call sndstf
call debounce
goto dolOOO
j----------------------------------------------------- - - - - - - -
thzero btfsc flags,O ims digit entered?
goto zeroth iyes
movlw Ox20 iascii blank
thchar movwf char
movlw Ox2l idisplay RAM address
movwf addr
movlw Ox03 iascii character to display RAM
movwf instr
call sndstf
call debounce
goto dolOO
zeroth movlw Ox30 iascii 0
goto thchar
;------------------------------------------------------------
hzero btfsc flags, 0 ims digit entered?
goto zeroh iyes
movlw Ox20 iascii blank
hchar movwf char
movlw Ox22 idisplay RAM address
movwf addr
movlw Ox03 iascii character to display RAM
movwf instr
call sndstf
call debounce
goto dolO
zeroh movlw Ox30 iascii 0
goto hchar
j----------------------------------------------------- - - - - - - -
143
tzero btfsc flags, 0 ims digit entered?
goto zerot iyes
movlw Ox20 iascii blank
tchar movwf char
movlw Ox23 idisplay RAM address
movwf addr
movlw Ox03 iascii character to display RAM
movwf instr
call sndstf
call debounce
goto dol
zerot movlw Ox30 iascii 0
goto tchar
;------------------------------------------------------------
ireturns with digit in digctr
144
sublw Ox03
btfsc status,z i=3 ?
goto scan10 iscan 10 digit keys again
rlf rowbits,f ishift row bits
bcf rowbits,O ifi x carry flag garbage
incf rowctr,f
incf digctr,f
goto rowout
;------------------------------------------------------------
debounce movlw Ox02 ito counter
movwf count
dbloop movlw Oxff iM
movwf mcount ito M counter
loadn movlw Oxff iN
movwf ncount ito N counter
decn decfsz ncount,f idecrement N
goto decn iagain
decfsz mcount,f idecrement M
goto loadn iagain
decfsz count,f
goto dbloop ithru loop within a loop twice -
400 milliseconds
return idone
,-- - - - - - - - - - - - - - - - - - - - - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sndstf movf instr,w iget instruction
movwf sendreg ito be sent
call ser out ito serial out subroutine
movf char,w iget character or hex byte
movwf sendreg ito be sent
call ser out ito serial out subroutine
movf addr,w iget address
movwf sendreg ito be sent
call ser out ito serial out subroutine
return
;------------------------------------------------------------
ser out bcf intcon,5 idisable tmrO interrupts
bcf intcon,7 idisable global interrupts
clrf tmrO iclear timer/counter
clrwdt iclear wdt prep prescaler assign
bsf status,rpO ito page 1
movlw b' 11011000' iset up timer/counter
movwf opt reg
bcf status,rpO iback to page 0
movlw Ox08 iinit shift counter
movwf count
bcf porta, 1 istart bit
clrf tmrO istart timer/counter
bcf intcon,2 iclear tmrO overflow f l a g
time1 btfss intcon, 2 i t i me r overflow?
goto time1 ino
bcf intcon, 2 iyes, clear overflow flag
n xtbit rlf sendreg,f irotate msb into carry flag
bcf porta, 1 iclear port A, bit 1
btfsc status,c itest carry flag
145
bsf porta, 1 ibit is set
time2 btfss intcon,2 itimer overflow?
goto time2 ino
bcf intcon,2 iclear overflow flag
decfsz count,f ishifted 8?
goto nxtbit ino
bsf porta, 1 i yes, output mark
time3 btfss intcon,2 itimer overflow?
goto time3 ino
return idone
;--------------------------------------------------------------------
imultiply 2-byte binary number by 10 decimal
ienter sub with number in hibyte and lobyte - e xit with result
in hybyte and lobyte
146
goto add30
add37 movf hold, w ;get hex digit
addlw Ox37
return ;return with ascii in w
add30 movf hold,w ;get hex digit
addlw Ox30
return ;return with ascii in w
i----------------------------------------------------- - - - - - - -
end
;------------------------------------------------------------
iat device programming time, select:
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal XT (using 4 MHz osc for test)
power-up timer on
brown-out reset enabled
lvp disabled
debug mode disabled
;============================================================
This device may be tested by using a PIC16F84 to measure pulse width. An example was given
earlier which measures pulse width up to 255 microseconds (pgentst.asm). This program may
be modified to measure pulse widths covering the range of the device (25 to 65,535 microsec-
onds).
Notice that short pulses can not be seen with the eye. I can't see a 1,000 microsecond pulse, but
I can see a 5,000 microsecond pulse.
Procedure:
147
DIGITAL FREQUENCY GENERATOR
Building a frequency generator is more fun and the output can be observed more easily using an
oscilloscope. The object here is to be able to key in the desired pulse width (time the output is
high or low) in microseconds. The 5-digit decimal number keyed in must be displayed on the
LCD and converted to 16-bit binary for use in the compare register to determine the pulse width.
The signal is output via the CCPl pin. The signal changes level when the contents of timer 1
match the contents of the compare register. Each time a match occurs, the interval value is
added to the compare register and the process is repeated .
The range of possible pulse widths is 25 to 65,535 microseconds which translates to a frequency
range of 7.6 Hz to 20 KHz . The range could be extended to lower frequencies by using an exter-
nal clock providing 1 millisecond or 1 second pulses (as examples) . The upper frequency limit
is largely determined by the PIC16F870 clock oscillator frequency which gets divided to gener-
ate the output signal. The software overhead also is a factor in determining the maximum fre-
quencyattainable. So - for lower frequencies, use a slower time base. For higher frequencies,
use a faster clock oscillator for the PIC16F870.
TCBOARD PICIlCD
RA1 RAO
TD RD
...n.. CCP1
II
LCD
II
1-
PortS
680 .. ~
::! !:~ ,- V7
-=;:: KEYPAD BOARD
1 2 3
4 5 6
Note: Use 3 keypad pullup
resistors on Te board .
7 8 9
• 0 #
148
Main Interrupt
Clear CCP1 Interrupt
Program Service
Flag
Routine
+
Add Time Interval To
Compare Register
+
•
Toggle Output
gohi
No
Circle
DIP Switches
1 2 345 6 7
o 0 0 C ceo
149
;=======FREQGEN.ASM=================================4/28/02==
list p=16f870
__config h'3f71'
radix hex
i----------------------------------------------------- - - - - - - -
cpu equates (memory map)
tmrO equ OxOl
status equ Ox03
porta equ OxOS
portb equ Ox06
portc equ Ox07
intcon equ OxOb
pirl equ OxOc
tmrll equ OxOe
tmrlh equ OxOf
tlcon equ OxlO
ccprll equ OxlS
ccprlh equ Ox16
ccplcon equ Ox17
sendreg equ Ox20
count equ Ox21
instr equ Ox22
char equ Ox23
addr equ Ox24
digctr equ Ox2S
rowctr equ Ox26
colctr equ Ox27
rowbits equ Ox28
colbits equ Ox29
temp equ Ox2a
ncount equ Ox2b
mcount equ Ox2c
test n equ Ox2d
math equ Ox2e
copy_8xn equ Ox2f
numsuml equ Ox30
numsumh equ Ox31
tenthou equ Ox32
thou equ Ox33
hund equ Ox34
ten equ Ox3S
one equ Ox36
hold equ Ox37
lobyte equ Ox38
hibyte equ Ox39
copylo equ Ox3a
copyhi equ Ox3b
flags equ Ox3c
150
trisb equ Ox86
trisc equ Ox87
pie1 equ Ox8c
adcon1 equ Ox9f
;------------------------------------------------------------
bit equates
c equ 0
z equ 2
rpO equ 5
ccp1 equ 2 iccp1 bit 2, port C
;------------------------------------------------------------
org OxOOO
goto start iskip over location pointed to by
interrupt vector
org Ox004
goto iserv
151
movwf lobyte
clrf hibyte
call decmult itimes 10
call decmult itimes 10
call decmult itimes 10
call decmult itimes 10, result = x10000
call addnum iadd 10000' s to num sum registers
movf tenthou,w iget 10000' s digit
call hex2asc iconvert binary digit to ascii
movwf char
movlw Ox20 idisplay RAM address
movwf addr
movlw Ox03 iascii char follows, send to display RAM
movwf instr
call sndstf isend 10000' s digit to display RAM
call debounce itime delay - debounce switches
do1000 call scan10
movf digctr,w iget 1000's digit
movwf thou isave copy
sublw OxOO icompare - digit=O?
btfsc status,z
goto thzero iyes
bsf flags,O r no , this could be ms digit
movf thou,w
movwf lobyte
clrf hibyte
call decmult itimes 10
call decmult itimes 10
call decmult itimes 10, result = x1000
call addnum iadd 1000's to num sum registers
movf thou,w iget 1000's digit
call hex2asc iconvert binary digit to ascii
movwf char
movlw Ox21 idisplay RAM address
movwf addr
movlw Ox03 iascii char follows, send to display RAM
movwf instr
call sndstf isend 1000's digit to display RAM
call debounce itime delay - debounce switches
do100 call scan10
movf digctr,w iget 100's digit
movwf hund isave copy
sublw OxOO icompare - digit=O?
btfsc status,z
goto hzero iyes
bsf flags,O i no, this could be ms digit
movf hund,w
movwf lobyte
clrf hibyte
call decmult itimes 10
call decmult itimes 10, result = x100
call addnum iadd 100's to num sum registers
movf hund,w iget 100's digit
call hex2asc iconvert binary digit to ascii
152
movwf char
movlw Ox22 idisplay RAM address
movwf addr
movlw Ox03 i a s c i i char follows, send to display RAM
movwf instr
call sndstf isend 100's digit to display RAM
call debounce itime delay - debounce switches
dolO call scan10
movf digctr,w iget 10's digit
movwf ten isave copy
sublw OxOO icompare - digit=O?
btfsc status,z
goto tzero iyes
movf ten,w
movwf lobyte
clrf hibyte
call decmult itimes 10
call addnum iadd 10's to num sum registers
movf ten,w iget 10's digit
call hex2asc iconvert binary digit to ascii
movwf char
movlw Ox23 idisplay RAM address
movwf addr
movlw Ox03 iascii char follows, send to display RAM
movwf instr
call sndstf isend 10's digit to display RAM
call debounce itime delay - debounce switches
dol call scan10
movf digctr,w iget l's digit
movwf one isave copy
movwf lobyte
clrf hibyte
call addnum iadd l's to num sum r e g i s t e r s
movf one,w iget one's digit
call hex2asc iconvert binary digit to ascii
movwf char
movlw Ox24 idisplay RAM address
movwf addr
movlw Ox03 iascii char foll ows, se nd to display RAM
movwf instr
call sndstf isend l's digit to displa y RAM
call debounce
send movlw Ox01 isend 16 characters to display
movwf instr
call sndstf ito LCD module
call debounce idelay, display d ecimal entry
;-------------------------------------- -- ---- ----------------
bcf intcon,7 idisable global interrupts
bcf intcon,6 idisable peripheral i nterrupts
bsf status,rpO iba n k 1
bcf pie1,0 idisable timer 1 i n t e r r u p t s
bcf pie1,2 idisable ccp1 interrupts
bcf status,rpO ibank 0
bcf pir1, 2 iclear ccp1 interrupt flag
153
clrf ccplcon iccpl module off
movlw b'OOOOOOOO' itmrl prescaler and tmrl setup,
movwf tlcon tmrl off
clrf tmrlh iclear timer 1 high
clrf tmrll iclear timer 1 low
trick clrf ccprlh iclear compare register high
movlw OxOl iload compare register low
movwf ccprll
movlw b'OOOOlOOO' iccpl compare mode, ccpl pin high
movwf ccplcon on match, ccpl module on,
ccpl pin low
bsf tlcon,O itimer 1 on
gohi btfss pirl,2 iccpl interrupt flag set?
goto gohi inot yet
movf numsumh,w iget interval high byte
movwf ccprlh iload compare register high
movf numsuml,w iget interval low byte
movwf ccprll iload compare register low
bsf ccplcon,O iccpl pin low on match
bsf intcon,7 ienable global interrupts
bsf intcon,6 ienable peripheral interrupts
bsf status,rpO ibank 1
bsf piel,2 ienable ccpl compare interrupt
bcf status,rpO ibank 0
circle goto circle idone
;------------------------------------------------------------
tthzero movlw Ox20 iascii blank
movwf char
movlw Ox20 idisplay RAM address
movwf addr
movlw Ox03 iascii character to display RAM
movwf instr
call sndstf
call debounce
goto dolOOO
;------------------------------------------------------------
thzero btfsc flags,O ims digit entered?
goto zeroth iyes
movlw Ox20 iascii blank
thchar movwf char
movlw Ox2l idisplay RAM address
movwf addr
movlw Ox03 iascii character to display RAM
movwf instr
call sndstf
call debounce
goto dolOO
zeroth movlw Ox30 iascii 0
goto thchar
;------------------------------------------------------------
hzero btfsc flags,O ims digit entered?
goto zeroh iyes
movlw Ox20 iascii blank
hchar movwf char
154
movlw Ox22 idisplay RAM address
movwf addr
movlw Ox03 iascii character to display RAM
movwf instr
call sndstf
call debounce
goto dolO
zeroh movlw Ox30 iascii 0
goto hchar
i----------------------------------------------------- - - - - - - -
tzero btfsc flags, 0 ims digit entered?
goto zerot iyes
movlw Ox20 iascii blank
tchar movwf char
movlw Ox23 idisplay RAM address
movwf addr
movlw Ox03 iascii character to display RAM
movwf instr
call sndstf
call debounce
goto dol
zerot movlw Ox30 iascii 0
goto tchar
i----------------------------------------------------- - - - - - - -
ireturns with digit in digctr
155
lastc movf colctr,w ;get column count
sublw Ox03
btfsc status,z ;=3 ?
goto lastr
rlf colbits,f ;shift column bits
bcf colbits,O ;fix carry flag garbage
incf colctr,f
incf digctr,f
goto tstcol
lastr movf rowctr,w ;get row count
sublw Ox03
btfsc status,z ;=3 ?
goto scanlO ;scan 10 digit keys again
rlf rowbits,f ;shift row bits
bcf rowbits,O ;fix carry flag garbage
incf rowctr,f
incf digctr,f
goto rowout
j----------------------------------------------------- - - - - - - -
debounce movlw Ox02 ;to counter
movwf count
dbloop movlw Oxff ;M
movwf mcount ;to M counter
loadn movlw Oxff ;N
movwf ncount ;to N counter
decn decfsz ncount,f ;decrement N
goto decn ;again
decfsz mcount,f ;decrement M
goto loadn ;again
decfsz count,f
goto dbloop ;thru loop within a loop twice -
400 milliseconds
return ; done
j----------------------------------------------------- - - - - - - -
sndstf movf instr,w ;get instruction
movwf sendreg ;to be sent
call ser out ;to serial out subroutine
movf char,w ;get character or hex byte
movwf sendreg ;to be sent
call ser out ;to serial out subroutine
movf addr,w ;get address
movwf sendreg ;to be sent
call ser out ;to serial out subroutine
return
j------------------------------------------------ ----- - - - - - - -
ser out bcf intcon,5 ;disable tmrO interrupts
bcf intcon,7 ;disable global interrupts
clrf tmrO ;clear timer/counter
clrwdt ;clear wdt prep prescaler assign
bsf status,rpO ;to page 1
movlw b'll011000' ;set up timer/counter
movwf opt reg
bcf status,rpO ;back to page 0
movlw Ox08 ;init shift counter
156
movwf count
bcf porta, 1 istart bit
clrf tmrO istart timer/counter
bcf intcon,2 iclear tmrO overflow flag
time1 btfss intcon,2 itimer overflow?
goto time1 ino
bcf intcon,2 iyes, clear overflow flag
nxtbit rlf sendreg,f irotate msb into carry flag
bcf porta, 1 iclear port A, bit 1
btfsc status,c itest carry flag
bsf porta, 1 ibit is set
time2 btfss intcon,2 itimer overflow?
goto time2 ino
bcf intcon,2 iclear overflow flag
decfsz count,f ishifted 8?
goto nxtbit ino
bsf porta, 1 iyes, output mark
time3 btfss intcon,2 itimer overflow?
goto time3 ino
return idone
;--------------------------------------------------------------------
imultiply 2-byte binary number by 10 decimal
ienter sub with number in hibyte and lobyte - exit with result
in hybyte and lobyte
157
movf hibyte,w ifetch high byte
addwf numsumh,f iadd high bytes, result in numsumh
return
i--------------- -------------------------------------- - - - - - - -
ienter with hex digit in w
158
With an oscilloscope connected to the output, key in various pulse widths from 25 to 65,535
microseconds and observe the output signal. Try keying in 20 and 65,536 microseconds. What
happens and why?
Procedure:
1) Power-up F870.
2) Key in the pulse width of the output signal in microseconds.
3) Observe the output using an oscilloscope.
159
TIME INTERVAL MEASUREMENT INSTRUMENT
This instrument will measure time intervals from approximately 25 microseconds to 65,535
microseconds. The internal instruction clock is used as the known frequency which is a big fac-
tor in determining the range. A clock oscillator of much higher frequency would be needed to
measure shorter time intervals (impractical) and a slower clock oscillator is needed to measure
lower frequencies (no problem). A selection of two time bases (internal instruction clock or
external clock selected via a switch and software) could be used to extend the range of this
instrument. You might like to try it.
The measurement portion of the software works like pdccp.asm. The 16-bit result is converted
to 5-digit BCD. The digits are converted to ASCII for display purposes. High order zeros are
suppressed.
160
+5VDC
10K .. ;.
TCBOARD PICILCD
. II
LCD
.n. CCP1 II
'84 ON A BOARD
1.
RBO
+5 VDC
10K ....
RS1
161
Main Interrupt
Program Service
Routine
Yes
No
Yes
No
DIP Switches
1 2 3 4 5 6 7
COO C ceo
L Closed On Reset
Open When Ready
162
i=======PDCK.ASM====================================4/29/02==
list p=l6f870
__config h'3f7l'
radix hex
;------------------------------------------------------------
itimer land ccpl module - period measurement demo - lcd
timer 1 free running
capture at start and end of period pulse
;------------------------------------------------------------
cpu equates (memory map)
indf equ OxOO
tmrO equ OxOl
pc equ Ox02
status equ Ox03
fsr equ Ox04
porta equ Ox05
portc equ Ox07
intcon equ OxOb
pirl equ OxOc
tmrll equ OxOe
tmrlh equ OxOf
tlcon equ Ox10
ccpr11 equ OxlS
ccpr1h equ Ox16
ccp1con equ Ox17
tenk equ Ox20
onek equ Ox21
hund equ Ox22
ten equ Ox23
one equ Ox24
sendreg equ Ox2S
count equ Ox26
instr equ Ox27
char equ Ox28
addr equ Ox29
ncount equ Ox2a
mcount equ Ox2b
hold equ Ox2c
index equ Ox2d
dig_ctr equ Ox2e
Isb1 equ Ox2f
msb1 equ Ox30
Isb2 equ Ox31
msb2 equ Ox32
flags equ Ox33 idone 3, 1st capture 2, overflow 1,
ms digit 0
one hi equ Ox34
one 10 equ Ox3S
-
opt reg equ Ox81
trisa equ Ox8S
trisc equ Ox87
pie1 equ Ox8c
adcon1 equ Ox9f
163
;------------------------------------------------------------
bit equates
c equ 0
ovflw equ 1
z equ 2
rpO equ 5
ccp1 equ 2 ;ccp1 bit 2, port C
;------------------------------------------------------------
org OxOOO
goto start ;skip over location pointed to by
interrupt vector and tables
org Ox004
goto iserv
;------------------------------------------------------------
tbl 10 addwf pc,f ;add index to program counter
retlw Ox10 ;10,000 decimal
retlw Oxe8 ;1,000 decimal
retlw Ox64 ;100 decimal
retlw OxOa ;10 decimal
,
e _
164
movwf t1con tmr1 off
clrf tmr1h iclear timer 1 high
clrf tmr11 iclear timer 1 low
bsf t1con,0 itimer 1 on, free running
movlw b'00000101' icapture on rising edge, ccp1
movwf ccp1con module on
bcf flags,2 iclear 1st capture flag
bcf flags,3 iclear done flag
bsf intcon,7 ienable global interrupts
bsf intcon,6 ienable peripheral interrupts
bsf status,rpO ibank 1
bsf pie1,2 ienable ccp1 interrupts
bcf status,rpO ibank 0
ready btfss porta, 0 iready?
goto ready
done btfss flags, 3 idone?
goto done
;------------------------------------------------------------
iperiod high byte in msb2
iperiod low byte in Isb2i
165
dohund movf hund,w iget 100's digit
sublw OxOO icompare - digit=O?
btfsc status,z
goto hzero iyes
movf hund,w iget 100's digit
call hex2asc iconvert binary digit to ascii
movwf char
movlw Ox22 idisplay RAM address
movwf addr
movlw Ox03 iascii char follows, send to display RAM
movwf instr
call sndstf isend 100's digit to display RAM
call debounce itime delay
doten movf ten,w iget 10's digit
sublw OxOO icompare - digit=O?
btfsc status,z
goto tzero iyes
movf ten,w iget 10's digit
call hex2asc iconvert binary digit to ascii
movwf char
movlw Ox23 idisp1ay RAM address
movwf addr
movlw Ox03 iascii char follows, send to display RAM
movwf instr
call sndstf isend 10's digit to display RAM
call debounce itime delay
doone movf one,w iget l's digit
call hex2asc iconvert binary digit to ascii
movwf char
movlw Ox24 idisplay RAM address
movwf addr
movlw Ox03 iascii char follows, send to display RAM
movwf instr
call sndstf isend l's digit to display RAM
call debounce
isend time units to display ram
m movlw Ox6d iascii m
movwf char
movlw Ox26 idisplay RAM address
movwf addr
movlw Ox03 iascii character to display RAM
movwf instr
call sndstf
call debounce
i movlw Ox69 iascii i
movwf char
movlw Ox27 idisplay RAM address
movwf addr
movlw Ox03 iascii character to display RAM
movwf inst r
call sndstf
call debounce
cee1 movlw Ox63 iascii c
movwf char
166
movlw Ox28 ;display RAM address
movwf addr
movlw Ox03 ;ascii character to display RAM
movwf instr
call sndstf
call debounce
r movlw Ox72 ;ascii r
movwf char
movlw Ox29 ;display RAM address
movwf addr
movlw Ox03 ;ascii character to display RAM
movwf instr
call sndstf
call debounce
o movlw Ox6f ;ascii 0
movwf char
movlw Ox2a ;display RAM address
movwf addr
movlw Ox03 ;ascii character to display RAM
movwf instr
call sndstf
call debounce
s movlw Ox73 ;ascii s
movwf char
movlw Ox2b ;display RAM address
movwf addr
movlw Ox03 ;ascii character to display RAM
movwf instr
call sndstf
call debounce
e movlw Ox65 ;ascii e
movwf char
movlw Ox2c ;display RAM address
movwf addr
movlw Ox03 ;ascii character to display RAM
movwf instr
call sndstf
call debounce
cee2 movlw Ox63 ;ascii c
movwf char
movlw Ox2d ;display RAM address
movwf addr
movlw Ox03 ;ascii character to display RAM
movwf instr
call sndstf
call debounce
send movlw Ox01 ;send 16 characters to display
movwf instr
call sndstf ito LCD module
circle goto circle ; done
i----------------------------------------------------- - - - - - - -
iserv btfsc flags,2 ;lst capture flag set?
goto cap2 ;yes, goto 2nd capture
bsf flags,2 ;no, set 1st capture flag
167
bcf pir1,2 ;clear ccp1 interrupt flag,
enable second interrupt
bcf ccp1con,0 ;second capture on falling edge
movf ccpr1h,w ;get 1st capture high
movwf one hi ;store
movf ccpr11,w ;get 1st capture low
movwf one 10 ;store
retfie
cap2 bsf status,rpO ;bank 1
bcf pie1,2 ;disable ccp1 interrupts
bcf status,rpO ;bank 0
comf one_hi,f ;complement 1st capture high
comf one_lo,f ;complement 1st capture low
movf ccpr1h,w ;get 2nd capture high
movwf msb2 ;store
movf ccpr11,w ;get 2nd capture low
movwf lsb2 ;store
dbladd movf one_lo,w ;fetch complement of 1st low
addwf lsb2,f ;add low bytes, result in lsb2
btfsc status,c ;carry set?
incf msb2,f ;yes, add 1 to msb result
movf one_hi,w ifetch complement of 1st high
addwf msb2,f iadd high bytes, result in msb2
bsf flags,3 iset "done" flag
retfie
;------------------------------------------------------------
debounce movlw Ox02 ito counter
movwf count
dbloop movlw Oxff iM
movwf mcount ito M counter
loadn movlw Oxff iN
movwf ncount ito N counter
decn decfsz ncount,f ;decrement N
goto decn iagain
decfsz mcount,f idecrement M
goto loadn iagain
decfsz count,f
goto dbloop ;thru loop within a loop twice -
400 milliseconds
return idone
;------------------------------------------------------------
sndstf movf instr,w ;get instruction
movwf sendreg ito be sent
call ser out ito serial out subroutine
movf char,w iget character or hex byte
movwf sendreg ito be sent
call ser out ito serial out subroutine
movf addr,w iget address
movwf sendreg ito be sent
call ser out ito serial out subroutine
return
;------------------------------------------------------------
ser out bcf intcon,5 ;disable tmrO interrupts
bcf intcon,7 idisable global interrupts
168
clrf tmrO ;clear timer/counter
clrwdt ;clear wdt prep prescaler assign
bsf status,rpO ito page 1
movlw b' 11011000' ;set up timer/counter
movwf opt reg
bcf status,rpO ;back to page 0
movlw Ox08 ;init shift counter
movwf count
bcf porta,l ;start bit
clrf tmrO ;start timer/counter
bcf intcon,2 ;clear tmrO overflow flag
timel btfss intcon,2 ;timer overflow?
goto timel ;no
bcf intcon,2 ;yes, clear overflow flag
nxtbit rlf sendreg,f ;rotate msb into carry flag
bcf porta,l ;clear port A, bit 1
btfsc status,c ;test carry flag
bsf porta,l ;bit is set
time2 btfss intcon,2 ;timer overflow?
goto time2 ;no
bcf intcon,2 ;clear overflow flag
decfsz count,f ;shifted 8?
goto n xtbit ;no
bsf porta,l ;yes, output mark
time3 btfss intcon,2 ;timer overflow?
goto time3 ;no
return ;done
;-------- ------------------------------ ----------------------
;enter with hex digit in w
169
movlw Ox20 ;ascii blank
thchar movwf char
movlw Ox2l ;display RAM address
movwf addr
movlw Ox03 ;ascii character to display RAM
movwf instr
call sndstf
call debounce
goto dohund
zeroth movlw Ox30 ;ascii 0
goto thchar
i----------------------------------------------------- - - - - - - -
hzero btfsc flags, 0 ;ms digit entered?
goto zeroh ;yes
movlw Ox20 ;ascii blank
hchar movwf char
movlw Ox22 ;display RAM address
movwf addr
movlw Ox03 ;ascii character to display RAM
movwf instr
call sndstf
call debounce
goto dot en
zeroh movlw Ox30 ;ascii 0
goto hchar
;------------------------------------------------------------
tzero btfsc flags,O ;ms digit entered?
goto zerot ;yes
movlw Ox20 ;ascii blank
tchar movwf char
movlw Ox23 ;display RAM address
movwf addr
movlw Ox03 ;ascii character to display RAM
movwf instr
call sndstf
call debounce
goto doone
zerot movlw Ox30 ;ascii 0
goto tchar
;------------------------------------------------------------
;16-bit binary to S-digit bcd conversion
170
call tbl hi ;get ms chunk for subtraction
movwf msbl
call dblsub ;to double precision subtraction
btfsc status,c ;test carry flag
goto incdig
movlw Ox20 ;load base address of table
movwf fsr
movf index,w ;get index
addwf fsr,f ; add offset
movf dig_ctr,w ;get digit counter contents
movwf indf ;store at digit loc (indexed)
movf index,w ;get index
call tbl- 10 ;get Is chunk for addition
movwf lsbl
movf index,w ;get index
call tbl hi ;get ms chunk for addition
movwf msbl
bcf flags,ovflw
call dblplus ;to double precision addition
movf index,w ;get index
sublw Ox03 ;index=3?
btfsc status,z
goto finish
incf index,f ; increment digit index
clrf dig_ctr
goto subtr
j----------------------------------------------------- - - - - - - -
incdig incf dig_ctr,f ;increment digit counter
goto subtr
j----------------------------------------------------- - - - - - - -
finish movf lsb2,w ;get l's=remainder
movwf one
return ; done
j----------------------------------------------------- - - - - - - -
dblsub bcf flags,ovflw ;clear overflow flag
comf lsbl,f ;2's complement stuff
comf msbl, f
movf lsbl,w
addlw OxOl
movwf lsbl
btfsc status,c
incf msbl, f
dblplus movf lsbl,w
addwf lsb2,f ;add low bytes
btfsc status,c
bsf flags,ovflw ;indicate overflow occurred
movf msbl, w
addwf msb2,f ;add high bytes
btfss flags,ovflw
goto dblx
btfsc status,c
goto db11
movlw OxOl
addwf msb2,f
171
goto dblx
db11 incf msb2, f
dbl x return
i- --- ------------------- -- --------------- ------------- -------
end
j------------------------------------------------------------
iat device programming time, select:
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal XT (using 4 MHz osc for test)
power-up timer on
brown-out reset enabled
lvp disabled
debug mode disabled
j============================================================
Procedure:
172
FREQUENCY MEASUREMENT INSTRUMENT
This instrument will measure frequencies from 100 Hz (0.1 KHz) to 655.4 KHz . The sample
time is 0.1 second which is a big factor in determining the range. A shorter sample time is
required for higher frequencies and a longer sample time is needed to measure lower frequen-
cies . Switch selectable sample times (via code blocks) could be used to extend the range of this
instrument. You might like to try it.
The measurement portion of the software works like freq.asm. The 16-bit result is converted to
5-digit BCD. The least significant digit is rounded off. Then the remaining digits are converted
to ASCII for display purposes. High order zeros are suppressed and the decimal point is insert-
ed.
L
supressJ
Hi Order
L Zero Not
Supressed
Blank
Zeros
173
+5VDC
10K .. ~
TCBOARD PICIlCD
174
Clear TMRO Rollover
Counter
No
DIP SwItches
1 2 345 6 7
COO C 0 C C
L Closed On Reset
Open When Ready
175
Once the frequency is in decimal form, it should be rounded off as the measurement is accurate
to within approximately 0.1 KHz .
We will round off the decimal result to the nearest tenth of a KHz.
A little thought reveals that the rounding off process can ripple back all the way to the most sig-
nificant digit. The round off routine rounds off the least significant digit. It does not clean up
trash left in it's place because that information will not be displayed.
i=======FREQCK.ASM==================================4/28/02==
list p=16f870
__config h'3f71'
radix hex
i------------------------------- - ---------------- ----- - - - - - - -
ifrequency measurement demo - lcd
gate via tmrO, internal clock, prescaler 1:1
;------------------------------------------------------------
cpu equates (memory map)
indf equ OxOO
tmrO equ Ox01
pc equ Ox02
status equ Ox03
fsr equ Ox04
porta equ OxOS
portc equ Ox07
intcon equ OxOb
tmr1l equ OxOe
tmr1h equ OxOf
t1con equ Ox10
tenk equ Ox20
onek equ Ox21
hund equ Ox22
ten equ Ox23
one equ Ox24
sendreg equ Ox2S
count equ Ox26
instr equ Ox27
char equ Ox28
addr equ Ox29
ncount equ Ox2a
mcount equ Ox2b
hold equ Ox2c
index equ Ox2d
dig_ctr equ Ox2e
lsb1 equ Ox2f
msb1 equ Ox30
lsb2 equ Ox31
msb2 equ Ox32
176
flags equ Ox33
opt reg equ Ox81
trisa equ Ox85
trisc equ Ox87
piel equ Ox8c
adconl equ Ox9f
j----------------------------------------------------- - - - - - - -
bit equates
c equ 0
ovflw equ 1
z equ 2
rpO equ 5
j----------------------------------------------------- - - - - - - -
org OxOOO
177
movlw b'00000010' iprescaler and tmr1 setup,
movwf t1con tmr1 off
clrf tmr1h i c l e a r time r 1 high
clrf tmr11 iclea r timer 1 l o w, clear p rescaler
clrf tmrO iclear timer 0
clrwdt iclr WDT, prep prescaler assign
bsf status,rpO ibank 1
movlw b '11011111' iset up timer 0
movwf opt reg
bcf status,rpO ibank 0
clrf count iclear tmrO rollover counter
ready btfss porta, 0 iready?
goto ready
bsf t1con,0 iturn on timer 1
clrf tmrO iclear timer 0
bcf intcon,2 iclear timer 0 interrupt flag
oflow1 btfss intcon,2 itimer 0 overflow?
goto oflow1 inot yet
bcf intcon,2 iclear timer 0 interrupt flag
incf count,f iinc timer 0 overflow counter
movf count,w icompare
sublw Oxff idecimal 255
btfss status,z itest z flag, skip next instruction
if flag is set
goto oflow1 iagain
oflow2 btfss intcon,2 itimer 0 overflow?
goto oflow2 inot yet
bcf intcon,2 iclear tmrO interrupt flag
incf count,f iinc timer 0 overflow counter
movf count,w icompare
sublw Ox86 idecimal 134
btfss status,z itest z flag, skip ne xt instruction
if flag is set
goto oflow2 iagain
clrf tmrO iclear timer 0
tl28 btfss tmrO,7 ilook for timer 1 128
goto t128
t32 btfss tmrO,5 ilook for timer 1 128+32=160
goto t32
bcf t1con,0 istop timer 1
;- -----------------------------------------------------------
iprep for calling conversion subroutine
movf tmr1h,w iget timer 1 high
movwf msb2
movf tmr11,w iget timer 1 low
movwf lsb2
call dblb2d icall conversion subroutine
iround off l's digit
call decrnd icall round off subroutine
isend digits to display ram
bcf flags,O i c l e a r ms digit flag
dotenk movf tenk,w i g e t 10000's digit
sublw OxOO icompare - digit=O?
btfsc status, z
178
goto tthzero iyes
bsf flags, 0 ino, this is ms digit
movf tenk,w iget 10000's digit
call hex2asc iconvert binary digit to ascii
movwf char
movlw Ox20 idisplay RAM address
movwf addr
movlw Ox03 iascii char follows, send to display RAM
movwf instr
call sndstf isend 10000's digit to display RAM
call debounce itime delay
doonek movf onek,w iget 1000's digit
sublw OxOO icompare - digit=O?
btfsc status,z
goto thzero iyes
movf onek,w iget 1000's digit
call hex2asc iconvert binary digit to ascii
movwf char
movlw Ox21 idisplay RAM address
movwf addr
movlw Ox03 iascii char follows, send to display RAM
movwf instr
call sndstf isend 1000's digit to display RAM
call debounce itime delay
dohund movf hund,w iget 100's digit
call hex2asc iconvert binary digit to ascii
movwf char
movlw Ox22 idisplay RAM address
movwf addr
movlw Ox03 iascii char follows, send to display RAM
movwf instr
call sndstf isend 100's digit to display RAM
call debounce itime delay
doten movf ten,w iget 10's digit
call hex2asc iconvert binary digit to ascii
movwf char
movlw Ox24 idisplay RAM address
movwf addr
movlw Ox03 iascii char follows, send to display RAM
movwf instr
call sndstf isend 10's digit to display RAM
call debounce
isend decimal point and frequency units to display ram
decpt movlw Ox2e iascii decimal point
movwf char
movlw Ox23 idisplay RAM address
movwf addr
movlw Ox03 iascii character to display RAM
movwf instr
call sndstf
call debounce
k movlw Ox4b iascii K
movwf char
movlw Ox26 idisplay RAM address
179
movwf addr
movlw Ox03 iascii character to display RAM
movwf instr
call sndstf
call debounce
h movlw Ox48 iascii H
movwf char
movlw Ox27 idisplay RAM address
movwf addr
movlw Ox03 iascii character to display RAM
movwf instr
call sndstf
call debounce
zee movlw Ox7a iascii z
movwf char
movlw Ox28 idisplay RAM address
movwf addr
movlw Ox03 iascii character to display RAM
movwf instr
call sndstf
call debounce
send movlw Ox01 isend 16 characters to display
movwf instr
call sndstf ito LCD module
circle goto circle idone
i- --- ------------- ------------------------------------ - - - - - - -
debounce movlw Ox02 ito counter
movwf count
dbloop movlw Oxff iM
movwf mcount ito M counter
loadn movlw Oxff iN
movwf ncount ito N counter
decn decfsz ncount,f idecrement N
goto decn iagain
decfsz mcount,f idecrement M
goto loadn iagain
decfsz count,f
goto dbloop ithru loop within a loop twice -
400 milliseconds
return idone
i----- ------------------------ --- --------------------- - - - - - - -
sndstf movf instr,w iget instruction
movwf sendreg ito be sent
call ser out ito serial out subroutine
movf char,w iget character or hex byte
movwf sendreg ito be sent
call ser out ito serial out subroutine
movf addr,w iget address
movwf sendreg ito be sent
call ser out ito serial out subroutine
return
i------------------------------------------------- ---- - - - - - - -
s er out bcf intcon,5 idisable tmrO interrupts
bcf intcon,7 idisable global interrupts
clrf tmrO iclear timer/counter
180
clrwdt iclear wdt prep prescaler assign
bsf status,rpO ito page 1
movlw b' 11011000' iset up timer/counter
movwf opt reg
bcf status,rpO iback to page 0
movlw Ox08 iinit shift counter
movwf count
bcf porta,1 istart bit
clrf tmrO istart time r/counter
bcf intcon,2 iclear tmrO overflow flag
time1 btfss intcon,2 itimer overflow?
goto time1 ino
bcf intcon,2 iyes, clear overflow flag
n xtbit rlf sendreg,f irotate msb into ca rry flag
bcf porta,1 iclear port A, bit 1
btfsc status,c itest carry flag
bsf porta, 1 ibit is set
time2 btfss intcon,2 itimer ove rflow?
goto time2 ino
bcf intcon,2 iclear overflow flag
decfsz count,f ishifted 8?
goto nxtbit ino
bsf porta, 1 iyes, output mark
time3 btfss intcon,2 itimer overflow?
goto time3 ino
return idone
i----------------------------------------------------- - - - - - - -
ienter with hex digit in w
181
movlw Ox20 ;ascii blank
thchar movwf char
movlw Ox2l ;display RAM address
movwf addr
movlw Ox03 ;ascii character to display RAM
movwf instr
call sndstf
call debounce
goto dohund
zeroth movlw Ox30 ;ascii 0
goto thchar
;------------------------------------------------------------
;l6-bit binary to S-digit bcd conversion
182
goto subtr
;------------------------------------------------------------
finish movf lsb2,w ;get l's=remainder
movwf one
return ;done
i----------------------------------------------------- - - - - - - -
dblsub bcf flags,ovflw ;clear overflow flag
comf lsbl,f ;2's complement stuff
comf msbl, f
movf lsbl,w
addlw OxOl
movwf lsbl
btfsc status,c
incf msbl,f
dblplus movf lsbl,w
addwf lsb2,f ;add low bytes
btfsc status,c
bsf flags,ovflw ;indicate overflow occurred
movf msbl,w
addwf msb2,f ;add high bytes
btfss flags,ovflw
goto dblx
btfsc status,c
goto db11
movlw OxOl
addwf msb2,f
goto dblx
db11 incf msb2,f
dblx return
;------------------------------------------------------------
;decimal roundoff subroutine
;rounds off the least significant digit of a
S-digit decimal number
;the contents of file register one are left as trash
183
btfss status,z
return inot 10
clrf onek
incf tenk
return
-------------------------------------------------------------
,
end
;------------------------------------------------------------
iat device programming time, select:
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal XT (using 4 MHz osc for test)
power-up timer on
brown-out reset enabled
lvp disabled
debug mode disabled
; ============================================================
Procedure:
Try measuring frequencies from 0.1 to 655.4 KHz. The "ready" switch is not really necessary.
Once under way, new measurements may be taken by resetting the F870.
You will doubtless think of ways to improve this instrument and I would encourage you to do so.
My suggestions would include:
There is lots of opportunity to expand on what you have learned by designing and building your
own combination device . You have probably noticed that the hardware involved in the four sig-
nal generator/instruments is almost identical. The keypad is not used in the two measurement
instruments, but it is not in the way either. It has two function keys that are not being used (so
far) . We have talked about selectable time bases and selectable sample times . A third PIC
microcontroller could be used to generate multiple time bases and the F870 could tell the third
PIC microcontroller what to do.
HMMmmmmm
184
APPENDIX A
PROGRAM LISTINGS vs. PAGE NUMBER
128.asm 6 128.asm 6
pgentst.asm 9 2000.asm 13
32.asm 10 32.asm 10
2000.asm 13 65280.asm 16
65280.asm 16 capt.asm 55
freqout.asm 18 ccppwm.asm 108
pgmr1.asm 24 ccppwmx.asm 121
tmr2.asm 30 cmpr.asm 59
tsttmr2.asm 34 decent63.asm 128
tmr1.asm 48 free.asm 69
read.asm 52 freeadd.asm 73
capt.asm 55 freq.asm 91
cmpr.asm 59 freqck.asm 176
sngl.asm 64 freqgen.asm 150
one128.asm 66 freqout.asm 18
free.asm 69 hdwpwmx.asm 104
freeadd.asm 73 hdwpwmy.asm 113
period.asm 79 icd2.asm 212
pdccp.asm 84 lcdtst.asm 196
freq.asm 91 lcdslv.asm 199
seconds.asm 94 one128.asm 66
time.asm 98 pdccp.asm 84
hdwpwmx. asm 104 pdck.asm 163
ccppwm.asm 108 period.asm 79
hdwpwmy . asm 113 pgentst.asm 9
ccppwmx.asm 121 pgmr1.asm 24
decent63.asm 128 pulsgen.asm 139
pulsgen.asm 139 read.asm 52
freqgen.asm 150 seconds.asm 94
pdck.asm 163 sngl.asm 64
freqck.asm 176 time.asm 98
lcdtst.asm 196 tmr1.asm 48
lcdslv.asm 199 tmr2.asm 30
icd2.asm 212 tsttmr2.asm 34
185
APPENDIX 8
PIC16F870 CONTROL REGISTERS
186
T1CON
_ _ _- - ' - !
T_1_C_K_P_S1_1 T1CKPSO T10SCEN
'-1 ! T1SYNC TMR1CS I TMR10N I Ox10
7 o
R = Readablebit
W .. Writeable bit
U = Unimplementedbit, read as ·0·
Power on reset 00000000
187
T2CON
7 0
R = Readable bit
W = Writeable bit
U = Unimplemented bit. read as ·0·
Power on reset 00000000
188
CCP1CON
7 o
R = Readab le bit
W = Writeable bit
U = Unimplemented bit, read as "0"
Power on reset 00000000
189
INTCON
190
PIE1
a
ADIE RCIE TXIE SSP IE CCP11E TMR21E TMR11E I Ox8C
7 o
R .. Readable bit
W .. Writeable bit
a .. Reserved, ANY, maintain as "0"
Power on reset 00000000
191
PIR1
Q R R
7 o
R = Readable bit
W = Writeable bit
Q = Reserved, RNV, maintain as "0"
Power on reset 00000000
A simple circuit module may be assembled for use in the experiments in this book. It includes
an I 8-pin zero insertion force (ZIF) socket for a PICI6F84 with clock oscillator, reset, power
supply terminal block, power supply decoupling capacitors, and screw terminal blocks as a
means of connecting the microcontroller port lines to the other circuitry used in the experiments .
These items are required in or are common to all of the experiments which use the PICI6F84.
Port A Port B
God +5V 4 3 2 1 0 7 6 543 2 o
10 01 10 ) 0 ) 0 I I) 0 ( o ( ~ ( ql
RA4 RA3 RA2 RA1 RAO RB7 RB6 RB5 RB4 RB3 RB2 RBl RBOI
Vdd I INT
~~
10
--
+
==
0.1 ILl TOCKI
Vss
PIC16F84A
i
NC
7
Reset ~r
1! NC
193
I would definitely use a ZIF socket for the F84 to avoid bending or damaging the pins. 18-pin
ZIF sockets are becoming expensive and difficult to find. The once common part made by the
TEXTOOL division of 3M is still available from Digi-Key. It is the gold plated (literally) ver-
sion (3M part number 218-3341-00-0602J) and the cost is around $18.
A 24-pin Aries socket is available from JDR Microdevices, JAMECO, Digi-Key and others.
The Aries part number is 24-6554-10 (tin plated contacts) and the price will be in the $8 range.
Simply ignore the extra 6 pins.
For the experiments in this book, there are no unused input port lines, so pullup resistors for
unused inputs are not needed .
The additional components specific to each of the experiments may be installed on a solderless
breadboard. The number of components and wiring installed on the solderless breadboard will
be 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) .
Two '84 on a board modules are needed for some of the experiments.
194
APPENDIX 0
PIC/LCD
The PIC/LCD circuit presented in PIC'n Up The Pace and Microcontrol'n Appg is shown here
along with code to test it after it is assembled as well as the code needed to use it as a serial slave
LCD unit as part of the experiments in this book.
PIC/LCD Circuit
+5V _.....-
.....,
10K .. ~ .. -
;.- lRA2 RAl 18 -
2 RA3 RAO 17 Serial Input
3 RA4fTOCKI OSCl 16
--
4 MCLR OSC2 15 - N.C.
+5V
5 Vss
PIC16F84A
Vdd 14 ~+5V
1
.::b. 6 RBOIINT RB7 13
4MHz
Clock
Oscillator
+5V 7 RBl RB6 12
Reset ~
~ Goo +5V
0 7
10 (
E
AS
10 ILl + 0.1 J.1l
+5V
= ==
;::
--b
==- +5V
00000000000000
LCD
I I
195
Testing 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.
i=======LCDTST.ASM====================================4/21/02
list p=16F84a
__config h'3ff1'
radix hex
;------------------------------------------------------------
cpu equates (memory map)
status equ Ox03
porta equ Ox05
portb equ Ox06
count1 equ OxOc
count 2 equ OcOd
trisa equ Ox85
trisb equ Ox86
;------------------------------ ------------------------------
bit equates
rpO equ 5
;------------------------------------------------- - ----------
org OxOOO
196
movwf porta
movwf portb
call del 5 iallow lcd time to initialize itself
call initlcd iinitialize display
circle goto circle idone
j----------------------------------------------------- - - - - - - -
initlcd bcf porta, 1 iE line low
bcf porta,2 iRS line low, set up for control
call del 125 idelay 125 microseconds
movlw Ox38 i8-bit, 5X7
movwf portb i 0011 1000
call pulse ipulse and delay
movlw OxOf idisplay on, cursor blinking
movwf portb i 0000 1111
call pulse
movlw Ox01 iclear display
movwf portb iOOOO 0001
call pulse
call del 5 idelay 5 milliseconds after in it
return
j----------------------------------------------------- - - - - - - -
del 125 movlw Ox2a iapprox 42x3 cycles (decimal)
movwf count1 iload counter
repeat decfsz count1,f idecrement counter
goto repeat inot 0
return icounter 0, ends delay
j----------------------------------------------------- - - - - - - -
del 5 movlw Ox28 idecimal 40
movwf count2 ito counter
delay call del 125 idelay 125 microseconds
decfsz count2,f ido it 40 times = 5 milliseconds
goto delay
return icounter 0, ends delay
j----------------------------------------------------- - - - - - - -
pulse bsf porta, 1 iPulse E line
nop idelay
bcf porta, 1
call del 125 idelay 125 microseconds
return
j----------------------------------------------------- - - - - - - -
end
j-------------------- ------------------------------ --- - - - - - - -
iat device program time, select:
code protection off
watchdog timer disabled (default is enabled)
standard crystal XT (using 4 MHz osc for test)
power-up timer on
j====================================================== = = = = = =
197
LCD MODULE SERIAL INTERFACE
It is useful to employ the LCD module as part of a more complex system by connecting it to the
TC board via a I-wire serial interface. We can do it by combining techniques and boards we
already have . The TC board will be the master and the PICILCD unit will be the slave.
1 Wire
MASTER SLAVE
RA1 RAO
TO RO PICILCD
TCBOARD
II LCD
II
-
My list of functions the slave should perform under direction of the master is:
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. See PICln Up The Pace or Microcontrol'n Apps
for details .
Any time something is sent to the display, an instruction must be included to tell the slave what
to do. 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.
198
Packets - 3 bytes (2nd and 3rd may be garbage).
OxOO
Ox01
OX02
OX03 Ox (char) Ox (addr)
Ox04 Ox(hex)
The PIC16F84 code for operating the PICILCD module as a slave follows . The code for the
PIC16F870 on the TC board used in the experiments in this book includes the code to perform
the master function for communication between the two boards.
;=======LCDSLV.ASM==================================4/16/02 ==
list p=16f84a
__config h'3ff1'
radix hex
i----------------------------------------------------- - - - - - - -
cpu equates (memory map)
indf equ OxOO
tmrO equ Ox01
pc equ Ox02
status equ Ox03
fsr equ Ox04
porta equ OxOS
portb equ Ox06
intcon equ OxOb
hexbyte equ OxOc
mS_dig equ OxOd
Is_dig equ OxOe
hold equ OxOf
sa equ Ox10
sb equ Oxll
sc equ Ox12
199
sd equ Ox13
count1 equ Ox14
count2 equ Ox15
rcvreg equ Ox16
count equ Ox17
temp equ Ox18
instr equ Ox19
char equ Ox1a
addr equ Ox1b
holdbits equ Ox1c
opt reg equ Ox81
trisa equ Ox85
trisb equ Ox86
i----------------------------------------------------- - - - - - - -
bit equates
c equ o
z equ 2
rpO equ 5
i----------------------------------------------------- - - - - - - -
org OxOOO
200
movf instr,w iget copy of instruction
sublw OxOl icompare with OxOl
btfsc status,z iZ flag set i f bytes are equal
goto send16 ibytes equal
movf instr,w iget copy of instruction
sublw Ox02 icompare with Ox02
btfsc status,z i z flag set if bytes are equal
goto sndtst ibytes equal
movf instr,w iget copy of instruction
sublw Ox03 icompare with Ox03
btfsc status,z i z flag set i f bytes are equal
goto chr ram ibytes equal
movf instr,w iget copy of instruction
sublw Ox04 icompare with Ox04
btfsc status,z i z flag set if bytes are equal
goto convhex ibytes equal
goto enterm iwait for next transmission
i---------------------- --- ---------------------------- - - - - - - -
blnkram call blanks ifill display ram with blanks
goto enterm iback to main
i------------------------- ---------------------------- - - - - - - -
send16 call disp16 isend display RAM contents to LCD
goto enterm iback to main
;-------------------------- ----------------------------------
sndtst call test iload display RAM with msg "TEST"
call disp16 isend display RAM contents to LCD
goto enterm iback to main
;------------------------------------------------------------
chr ram movf addr,w iget copy of display RAM address
movwf fsr istore in file select register
movf char,w iget copy of character to be display
movwf indf ito RAM address pointed to by FSR
goto enterm iback to main
.-------------------------------------------------------------
convhex movf char,w iget copy of hex byte to be converted
call disphex iconvert hex byte for display
call disp16 isend display RAM contents to LCD
goto enterm iback to main
;------------------------------------------------------------
disphex movwf hexbyte istore copy of hex byte
call blanks ifill display RAM with blanks
call sephex iseparate hex byte into 2 ASCII digits
movf mS_dig,w iget MS digit
movwf Ox20 ito display RAM
movf lS_dig,w iget LS digit
movwf Ox2l ito display RAM
swapf hexbyte,w iget copy of hex byte, swap MS/LS
call hexbits icall hex to bits
movf sa,w iget first bit
movwf Ox23 ito display RAM
movf sb,w iget second bit
movwf Ox24 ito display RAM
movf sc,w ietc.
movwf Ox25
201
movf s d,w
movw f Ox 26
movf he xbyte ,w ;get copy of hex byte
ca l l hexb i t s ;call he x to bits
mov f sa,w ;get first bit
movwf Ox 28 ;to disp lay RAM
movf s b,w ;get second bit
movwf Ox29 ; t o display RAM
movf sc,w ;etc.
movwf Ox 2a
mo vf sd,w
movwf Ox2b
return
i - - ------- ----------- ---- ----------------------------- - - - - - - -
s ephe x movf hexbyte ,w ;get copy of hex byte
andlw OxOf ;mask hi nybble
call hex2asc ;hex to ASCII conversion
movwf ls_dig ;store
swapf hexbyte,w ;get copy of he x byte, swap MS/LS
andlw OxOf ;mask hi nybble
call he x2asc ;hex to ASCII convers ion
movwf ms_dig ;store
return
i- ---------- - - ---------- ------------------------------ - - - - - - -
h e x2asc movwf hold ; store copy of hex d igit
sublw Ox09 ; subtract w from 1 less than Ox Oa
btfss status,c ;carry flag set i f w < OxOa
goto add37
goto add30
add37 movf hold,w ;get hex digit
addlw Ox37
ret urn ; return with ascii in w
add30 movf hold,w ;get hex digit
a d dlw Ox30
re turn ; return with ascii in w
i - - - - - - - ---- - - - - - - ----------------- --- --- - - ------ ----- - - - - - - -
hexbits movwf hold ;save c opy of hex digit
movlw sd ;st a rt wi t h last scratch pad address
mov wf fsr ;put it in file select register
movl w OxfO ; f ill the most s i gnificant four bits of he x digit
i orwf hold , w with l's for use as markers
movw f holdbits ; a n d store
b cf s t a t u s, c ;clear carry flag so that 0 will be
shifted in with rotate
b itslp movlw a' O' ;assume ASCI I 0 is needed
b tf sc holdbits,O ; i f LSB is 0 , then ASCII 0 is correct,
skip ne xt instruction
movl w a'l ' ; ASCII 1 needed instead
mov wf indf ; 0 or 1 to proper scratch pad register using
indirect addressing via the FSR
de c f f sr,f ;point to ne xt lower scratch pad register
a d d re s s wh i c h which will ho ld the ASCII
charact e r for the next most significant bit
rrf holdbits ,f ;rotate the lsb out, rotate marker bits right
202
btfsc holdbits,4 iis bit 4 a 0 yet? If so, it came from the
carry flag and we are done.
goto bitslp iii not, bits loop until done
return
j-------------------------------------------------- -- - - - - - - - -
blanks movlw Ox10 icount=16
movwf count1
movlw Ox20 ifirst display RAM address
movwf fsr iindexed addressing
movlw Ox20 iascii blank
store movwf indf i s t o r e in display RAM location
pointed to by file select register
decfsz countl,f i16?
goto incfsr ino
return iyes, done
incfsr incf fsr,f iincrement file select register
goto store
j----------------------------------------------------- - - - - - - -
hello movlw 'H'
movwf Ox20
movlw 'E'
movwf Ox21
movlw 'L'
movwf Ox22
movwf Ox23
movlw '0'
movwf Ox24
return
j----------------------------------------------------- - - - - - - -
test movlw 'T'
movwf Ox20
movwf Ox23
movlw 'E'
movwf Ox21
movlw 'S'
movwf Ox22
movlw
movwf Ox24
return
j--------------------------- -------------------------- - - - - - - -
initlcd bcf porta, 1 iE line low
bcf porta,2 iRS line low, set up for control
call del 125 idelay 125 microseconds
movlw Ox38 i8-bit, 5X7
movwf portb ; 0011 1000
call pulse ipulse and dela y
movlw OxOc idisplay on, cursor off
movwf portb i 0000 1100
call pulse
movlw Ox06 iincrement mode, no display shift
movwf po rtb i 0000 0110
call pulse
call del 5 idelay 5 milliseconds - required
before sending data
203
return
i------------------------------------------------------ - - - - - -
disp16 bcf porta, 1 iE line low
bcf porta,2 iRS line low, set up for control
call del 125 idelay 125 microseconds
movlw Ox80 icontrol word = address first half
movwf portb
call pulse ipulse and delay
bsf porta,2 iRS=1, set up for data
call del 125 idelay 125 microseconds
movlw Ox20 iinitialze file select register
movwf fsr
getchar movf OxOO,w iget character from display RAM
location pointed to by file select
register
movwf portb
call pulse isend data to display
movlw Ox27 i8th character sent?
subwf fsr,w isubtract w from fsr
btfsc status,z itest z flag
goto half iset up for last 8 characters
movlw 2f itest number
subwf fsr,w
btfsc status,z itest z flag
return i16 characters sent to lcd
incf fsr,f imove to next character location
goto getchar
half bcf porta,2 iRS=O, set up for control
call del 125 idelay 125 microseconds
movlw OxcO icontrol word = address second half
movwf portb
call pulse ipulse and delay
bsf porta,2 iRS=1, set up for data
incf fsr,f iincrement file select register to
select next character
call del 125 idelay 125 microseconds
goto get char
;------------------------------------------------------------
del 125 movlw Ox2a iapprox 42x3 cycles (decimal)
movwf count1 iload counter
repeat decfsz count1,f idecrement counter
goto repeat inot 0
return icounter 0, ends delay
i----------------------------------------------------- - - - - - - -
del 5 movlw Ox28 idecimal 40
movwf count2 ito counter
delay call del 125 idelay 125 microseconds
decfsz count2,f ido it 40 times = 5 milliseconds
goto delay
return icounter 0, ends delay
;------------------------------------------------------------
pulse bsf porta, 1 ipulse Eline
nop idelay
bcf porta, 1
204
call del 125 idelay 125 microseconds
return
j----------------------------------------------------- - - - - - - -
ser in bcf intcon,5 idisable tmrO interrupts
bcf intcon,7 idisable global interrupts
clrf tmrO iclear timer/counter
clrwdt iclear wdt prep prescaler assign
bsf status,rpO ito page 1
movlw b111011000 I iset up timer/counter
movwf opt reg
bcf status,rpO iback to page 0
movlw Ox08 iinit shift counter
movwf count
sbit btfsc porta, 0 ilook for start bit
goto sbit imark
movlw Ox80 istart bit received, half bit time
movwf tmrO iload and start timer/counter
bcf intcon,2 iclear tmrO overflow flag
time1 btfss intcon,2 itimer overflow?
goto time1 ino
btfsc porta, 0 istart bit still low?
goto sbit ifalse start, go back
clrf tmrO iyes, half bit time - start timer/ctr
bcf intcon,2 iclear tmrO overflow flag
time2 btfss intcon,2 itimer overflow?
goto time2 ino
bcf intcon,2 iyes, clear tmrO overflow flag
movf porta,w iread port A
movwf temp istore
rrf temp,f irotate bit 0 into carry flag
rlf rcvreg,f irotate carry into rcvreg bit 0
decfsz count,f ishifted 8?
goto time2 ino
time3 btfss intcon,2 itimer overflow?
goto time3 ino
return iyes, byte received
j------------------------------------------------------ - - - - - -
end
j----------------------------------------------------- - - - - - - -
iat device program time, select:
code protection off
watchdog timer disabled (default is enabled)
standard crystal XT (using 4 MHz osc for test)
power-up timer on
j===================================================== =======
205
206
APPENDIX E
KEYPAD
TCBOARD PIC/LCD
RA1 RAO
TO RD
II LCD
II
~
Port B
, '"7
KEYPAD BOARD
+5VDC
.. ~
<. <~
1000 Use Pull up Resistors
0
j
, 1 2 3 On TC Board
1
j
, 4 5 6
2
j
, 7 8 9
Port B
3 A
, * 0 #
4
5
207
The keypad shown 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
2 3
2--1--+-1--+-1--+-
ROWS
3- -+_1_-+_1_-+-
4--fl---+--fl---+--4---+--
COLUMN
+5VDC
..> 10K
Key ~r'
Output Port
... ~ ROW
1000
The 5-digit decimal to 16-bit binary entry program in the Designing And Building Your Own
Test Equipment chapter can be used to test your keypad if you are using it the first time.
Details on scanning keypads are available in Ple'n Up The Pace or Microcontrorn Apps.
208
APPENDIX F
USING THE leo
Port B bits 7 and 6 are used by the ICD which means some minor changes are necessary. The
easiest thing to do is swap the upper 4 bits of ports Band C. This effects only those programs
which include the following:
• Displaying data using 8 LEDs which must now be split between the two ports
• Scanning the 10-key keypad.
209
The modified schematic is shown below.
Gnd +SV
r ~ f f f f ~ J:. I( o
~ DIP Socket
I 7 G S 4 3 2 1 0 10 ILl +
= ~
0.11Jf
:: =
....-- Test
Point
~
+SV
~ +SV
Keypad
Column +SV
Pullups
RC7 ReG ReS RC4 RB3 RB2 RB1 RBO Vdd Vss RB7 RBG RBS RB4
PIC16F870
+SV MCLR TOCKI CLKI CLKO CCP1
Vpp RAO RA1 RA2 RA3 RA4 RAS Vss OSC1 OSC2 RCO RC1 RC2 RC3
47K"~
L
.I N.C.
W'
ck~iaIte~
• Sockets
Serial Output TMRO Input +SV
To PIC/LCD,
Input
T TMR1 Input CCP1
4.0 MHz
All Pull4J Resistors 10K ClockOsc • Cap = 22 pI (2 reqd'
Xtal = 32.768 KHz
Sockets to allow removal.
Note: Port B and Port C Unes
are not shown in their physical
ll-
N.C.
Parts used lor external clock
experiment only
locations on the device.
210
The F870 programs in this book are listed in the following table. The programs which need to
be modified for F870 use in conjunction with the leD are identified.
F870 Programs
By Page Number Modification Required
In this situation where a byte-wide port is not available for displaying data or a bit pattern via
8 LEDs, we can solve the problem by splitting the bits between two ports.
Port C Port B
1 1 1
76543210
Bits
211
i=======ICD2.ASM===========================l2/29/01==
li s t p=l6f870
radix hex
; -- - -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
cpu equates (memory map)
status equ Ox03
po rta equ OxOS
po rtb equ Ox06
porte equ Ox07
t risa equ Ox8S
t risb equ Ox86
trisc equ Ox87
adconl equ Ox9f
crack equ Ox20 isave reg for split subroutine
e _
,
bit equates
rpO equ S
i------------------------ ----------------------------
org OxOOO
nop
start bsf status,rpO iswitch to bank 1
movlw b'OOOOOllO' iturn off A/D, port A
movwf adconl
movlw b'OOOOOOOO' iinputs/outputs
movwf trisa
movwf trisb
movwf trisc
bcf status,rpO iback to bank 0
movlw OxOf iload w with bit pattern
i--- --------------------------------------------------
movwf crack isave
call split
i - - - - - - - - - - - - - - - - - --- -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ci rcle goto circle idone
; - - - - - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - - - --- - - - - - - - - - - - - - -
split btfss crack, 0
goto clr- 0
bsf po r tb,O
do 1 btfss crack,l
goto clr- 1
bsf portb,l
do 2 btfss crack,2
goto clr 2
bsf portb,2
do 3 btf ss crac k, 3
goto clr 3
bsf po rtb,3
do 4 btfss c r ac k , 4
goto clr 4
bsf porte, 4
do S bt f s s c r a ck , S
g ot o clr S
bs f porte,S
212
do 6 btfss crack, 6
goto elr 6
bsf porte, 6
do 7 btfss eraek,7
goto elr 7
bsf porte,7
return
elr 0 bef portb,O
goto do 1
elr 1 bef portb,l
goto do 2
elr 2 bef portb,2
goto do 3
elr 3 bef portb,3
goto do 4
elr 4 bef porte, 4
goto do S
elr S bef porte,S
goto do 6
elr 6 bef porte, 6
goto do 7
elr 7 bef porte,7
return
;-----------------------------------------------------
end
;-----------------------------------------------------
iat device programming time, select:
memory unprotected
watchdog timer disabled (default is enabled)
standard crystal (using 4 MHz ose for test) XT
power-up timer on
brown-out reset disabled
lvp disabled
debug mode enabled
i=====================================================
For the F870 programs which use 8 LEDs on port B (identified in the table as needing a split
LED display) , define the register "crack" in the equates and call the subroutine shown in the
demonstration program. In other words, substitute the guts of the demo program
for movwf portb in the F870 program .
213
Keypad Connections
A keypad is used in three projects in the chapter on Designing And building Your Own Test
Equipment.
TCBOARD PICIlCD
RAl RAO
TO RD
II
LCD
II
Port B
, ~
PortC
, ~
1
4 3
KEYPAD BOARD
+5VDC
oC~
.~
oC
~
1
j
, 4 5 6
2 A
, 7 8 9
Port B
3 A
, • 0 #
4
5
The lines connected to port B bits 4, 5, and 6 are moved to port C bits 4, 5 and 6 (see, also,
schematic shown previously). The keypad code modifications are straightforward. The pro-
grams effected are:
214
The code changes which follow apply to all three programs.
DIP switches 5, 6, and 7 are closed to enable the pullup resistors (see schematic).
Programming Considerations
• Configuration bits:
- LVP disabled, RB3 is digital I/O
- DEBUG enabled (lCD mode enabled) .
• Cannot use port B bits 6 and 7 (used by ICD).
• Lose 1 level of stack when ICD is used .
• Program memory
- Address OxOOO must contain NOP instruction.
I recommend removing the _CONFIG directive from the program listing (for use with the
LCD) because it has no effect and may be confusing
215
216
APPENDIX G - SOURCES
217
Milford Instruments PIC Development Kits
120 High Street
South Milford, LEEDS UK LS25 5AQ
Tel 01977 683 665
Fax 01977 681465
Web http://www.milinst.demon.co.uk
eMail sales@milinst.com
218