copyright, Peter H. Anderson, Baltimore, MD, Nov, '99
Note that this item may also be ordered via
A review of this book appears at
In addition to this book, I have subsequently developed numerous routines and the associated narrative specifically for the PIC16F87X family of processors. Although the original intent of this effort was to provide sample routines for people who purchased our PIC16F87X In Circuit Debugger (ICD) Development Package, this material may be purchased separately.
This is a continuing development. Currently the package consists of some 275 pages of material and 80 C routines. The material which has been developed to date is distributed via e-mail and followed up with new material on a monthly basis.
Although there is some duplication between these new routines and those in my "PIC C Routines" book, many of the routines are new and the effort has given me the opportunity to improve routines which were previously developed.
These new routines are specifically targeted to the PIC16F87X family of processors. Currently it is being expanded to also include the PIC16F628 which shares many of the features of the PIC16F87X family.
This is a collection of C language routines for the popular Microchip PIC series of micro
The nature of our educational system is such that students taking a course in C sit down with a
book which pretty much stands on its own and proceed from simple printf statements, through
looping, decision making, and on through to pointers, structures and pointers to structures, etc.
And, much the same is true of any course, whether it be computer architecture, circuit analysis, or
assembly language. Understand Chapter 1 and you are ready for Chapter 2. Very well organized.
Its organized. Read the book, understand the book and you will achieve your objective, an "A"
However, my experience is that beyond formal education setting, in the "real world", this nicely
developed ordered educational approach comes abruptly to a halt. The material becomes too
massive and too specialized and hopefully you begin to walk where few, if any, have walked
before or if your competitor has, they are not about to tell you about it. Educational materials
become a mixture of bits from classical texts, tips from colleagues, data sheets and previously
designed circuits or programs.
I find I learn best from examples and this work is just that, lots of examples.
Please note that it would be next to impossible to develop a work which treats C and the PIC
series of processors and assembly language and such interfaces as the Dallas 1-W and Philips I2C
protocols in such an ordered fashion as one finds in a formal educational setting. Hundreds, if
not thousands of books have been written on C. The Microchip specifications for a typical
processor runs some 200 pages and even then often leaves the reader feeling that there should be
more explanations and there are hundreds of data sheets and application notes. Pulling all of these
things together in an orderly classical presentation for someone who knows no C, nothing about
PICs, no assembly and nothing about interfacing devices would require someone far more talented
Thus, this work assumes the reader has a working knowledge of C, a familiarity with the PIC
series of processors, some knowledge of Microchip assembly and some knowledge of interfacing
devices and an understanding that life beyond formal education is a bit more disorganized.
Arriving at a working solution requires a good deal of educated trial and error type tinkering.
In purchasing this package, you may use the source code to develop a product and this includes
distribution of the resulting .hex files. However, the source code is not to be sold nor given to
any other party.
The embedded processor program at Morgan is not funded using any public funds. It is simply
funded by donations and the sale of books, kits and components and all of this money is used to
pay students and purchase materials to continue the effort. In a nutshell, I developed this for
nothing, at least in the financial sense. There is of course a satisfaction in contributing to the field
and helping others to learn and further their potential
Please consider that with the printing costs, the net "profit" is nominally $20. Clearly, I would
have to sell a few thousand to compensate for my time and I doubt I will sell more than one
My point is that in buying this package, you have not retained a consultant. Each day I receive
some 50 requests to review code, comment on designs and the like and in fact, some people are
quite uppity when they do not receive an immediate response. Please appreciate that there simply
are not enough hours in the day for me to answer these requests.
Simply put, this code is not supported. I honestly hope that it serves you well, but appreciate that
I simply do not have the time.
All of the routines in this package were written using the PCB and PCM packages from Custom
Computer Services, Inc (http://www.ccsinfo.com) which are $99.00 apiece. The two are
combined in an improved Windows environment as PCW which is $350.00.
In fact, I started with the $850 High Tech PIC C package, on the general theory that the more
you pay, the more you get. After fussing for a month where crossing the simplest of bridges took
far too long, I used a number of other compilers, ranging in price from free to $100 and finally
settled on the CCS as more than adequate and quite affordable for the hobbyist.
The CCS Compiler includes many built in packages; for timing, for RS232 communications, for
I2C interfaces and many more. I avoided using them for two reasons. I wanted to develop code
which was somewhat transportable with a minimum of difficulty to other compilers which did not
include these built in functions. The other reason is that the source code for these built in
functions is not provided and I am one who likes to understand what I am doing. I see many
postings, "I am using the I2C feature on the PIC16F877 and it doesn't work". And, indeed, the
poster doesn't have a ghost of a chance getting it to work as they don't have the source code.
The one exception to this is that I did use the CCS interrupt handler. My feeling was that most C
compilers include an interrupt handler and if not, it is easy enough to develop one.
Please appreciate that I am not saying the CCS modules are bad. Indeed, for many, they are a
selling point and if they work for you, by all means, use them.
One source of frustration in using the CCS compiler was that the user is left to declare all of the
special function registers used in a program and I developed standard header files to define all
registers and register bits.
However, I also desired have the ability to embed assembly code in my C code, notably for
timing, RS232 serial communication and the Dallas 1-W interface and thus used lower case letters
to define all register bits for C.
BCF PORTB, 7 // clear a bit in assembly rb5 = 0x05 // output 00000101 to port C
This requires using the #case directive. And, this brings on more problems as CCS has not been
all that careful with case in some of their standard libraries. For example TOUPPER in string.h.
However, these quickly come to light when one compiles and I found that only a few simple
modifications of the type of changing "TOUPPER" to "toupper" as I encountered them was
All and all, I have found this to be a workable solution. But, I was worried during those first few
days as to whether I was walking down a path into a swamp.
All routines were tested. All except those for the PIC16F877 were tested using ICE-PIC
emulators from RF Solutions (http://www.rfsolutions.co.uk). Routines for the PIC16F877 were
tested using the Microchip In Circuit Debugger (ICD).
However, please recognize that a lot can go wrong after testing.
I worked on this whenever I could find a moment and was thus working on several machines at
Morgan and on two machines I have at home. Thus, my originals are on floppy disks. I usually
copy my initial draft from a floppy to the hard drive and then debug. I have been known to forget
to copy the debugged version from the hard drive back to the floppy. Hopefully, I didn't do this,
but it is a big possibility for error.
The other potential source of errors is going back to "clean up" routines. Morgan is a confusing
place where I might have a student test some code which involves building up some interfacing
circuitry. Months later, I come back to add aesthetic touches and the interfacing circuitry is no
longer available. Of course, anyone who has done much programing knows that innocently
changing one line has a substantial likelihood if coming down on Murphy's side. I did try to be
careful in this and also recompiled all routines after adding these aesthetic touches. But, I would
be a fool to offer that I never introduced an error.
In developing these sample routines, the watch word was clarity. Thus error handling which can
actually involve more code than the task being performed was avoided. This is in keeping with
my teaching of young students; "you have to have something working before you can figure out
all that can go wrong". They are confused enough without functions passing error codes back to
the calling process.
However, recognize that we may have overlooked situations where a routine may well "break".
This collection includes routines for the PIC16F84, 12C509 (and 12CE519), 12C672 and
Most routines were developed for the PIC16F84 (or 16C558). However, samples are provided
so as to ease porting these to the other processors.
For example, routines are provided for interfacing such I2C devices as the Microchip 24LC256
EEPROM, Dallas DS1624 Digital Thermometer, DS1807 Dual Potentiometer, DS1307 Real
Time Clock, Philips PCF8383 Real Time Clock, PCF8574 I/O Expander, PCF8591 A/D and D/A
and Maxim MAX518 D/A with the PIC16F84. Rather than waste paper repeating all of this for
the 12C509 and yet again for the 16F877, I simply included routines on interfacing the 24LC256
with these other PICs.
Thus, discussions of the 12C509, 12C672 and 16F877 is limited to samples of the routines written
for the 16F84 and to illustrate special features (or limitations) of each of these processors.
DEFS_F84.H - Standard file and bit definitions.
BAR_1.C - Simple interface with LEDs, ROM arrays, "for" and "if"
BAR_2.C - Similar. Copying a ROM array to a RAM array, passing to a function by reference
BAR_3.C - Similar. Locally defined ROM arrays, use of static variables.
DIAL.C - Dials a telephone number stored in a ROM array. Then sends a three digit quantity
using beeps to a speaker.
LCD_F84.C - Includes implementations for delaying and for outputting to a serial device at 9600
baud on RA.0. This was later broken into DELAY.C, S_OUT_84.C. Note that routine
lcd_char() was written in assembly and transmits the data as inverted. In applications where a
RS232 level shifter is used, the assembly might be simply changed to provide true TTL.
SERIN.C. - Fetching a character at 9600 baud, fetching strings with defined timeouts and either
the number of characters or the terminating character. Portions of this were later moved to
EEPROM_1.C - How to initialize EEPROM and read from and write to EEPROM.
FLOAT_1.C - How to save a float to EEPROM and later retrieve it.
FLOAT_2.C - Similar, but may be adpated to any structure.
TMR0_1.C - Use of TMR0 to time for 1 ms. Generates 500 Hz tone while flashing an LED 4
secs on and 4 secs off. Use of TMR0 Interrupt.
TMR0_2.C - Similar, but adds external interrupt to toggle the state of an LED.
TMR0_3.C - Uses TMR0 to time for one second. Counts transistions on external interrupt.
TMR0_4.C - Generates 500 Hz tone for 100 ms using TMR0 interrupt.
PULSIN.C - Uses TMR0 and External Interrupt to measure the length of either a
positive or negative pulse.
SONAR.C - Lifts a lead high and times until a postive going signal on "Echo".
RCTIME.C - Charges a capacitor and then measures the amount of time until the voltage
discharges to a logic zero.
STRING_1.C - Illustrates a number of ways to overcome the inability to pass ROM arrays by
reference to a function.
PCF8574.C - Illustrates interface with Philips PCF8574 8-bit I/O expander. (I2C).
DS1803_1.C - Illustrates interface with Dallas DS1803 Dual Potentiometer. (I2C).
24_256_1.C - Interface with Microchip 24LC32, LC64, LC128 or LC256. (I2C).
DS1624.C - Interface with Dallas DS1624 Digital Thermometer and EEPROM. (I2C).
DS1307.C - Interface with Dallas DS1307 real time clock. (I2C). Illustrates date and time
PCF8583_1.C - Interface with Philips PCF8583 Real Time Clock. Writes date and time and then
reads about every second.
PCF8583_2.C - Similar. Uses dated alarm feature of the PCF8583.
PCF8583_3.C - Similar. Uses timer alarm.
PCF8583_4.C - Similar. I got rather carried away in this routine which performs eight digit BCD
PCF8591_1.C - Interfaces with Philips PCF8591 to use the D/A converter to generate a
PCF8591_2.C - Expands on the above to synthesize waveforms.
PCF8591_3.C - Illustrates how to perform four single ended A/D conversions.
MAX518_1.C - Illustrates how to interface with a MAX518 Dual D/A.
LOGGER_1.C - Illustrates a data logging arrangement where data is written to a 24LC32 and
later dumped to a terminal.
LOGGER_2.C - Expands on the above to include a DS1307 for timing and a DS1624 for
performing temperature measurements.
DS2401_1.C - Illustrates how to interface with a Dallas DS2401 Silicon Serial Number (1-W).
DS1820_1.C - Interface with four DS1820 digital thermometer devices operated in a parasitic
DS1820_2.C - Fetches 64 bit serial number from a DS1820, saves to the PIC16F84's EEPROM
and displays on LCD.
DS1820_3.C - Illustrates how to calculate an 8-bit CRC.
DS2430_1.C - Interface with DS2430A 256-bit serial number. (1-W).
DS1821_1.C - Interface with Dallas DS1821 thermometer / thermostat. Checks to see if DS1821
is in thermostat mode and if so toggles it to measurement mode and performs ten temperature
DS1821_2.C - Places DS1821 is measurement mode, displays thermostat settings, sets thermostat
BAROM.C - Interface with a Linear LTC1298 dual 12-bit A/D and Motorola MPX4115 pressure
sensor to measure and display atmospheric pressure.
TLC2543_1.C - Interface with a TI TLC2543 11-channel 12-bit A/D. (SPI).
TLC2543_2.C - Expands on this to perform sequential measurements.
LTC1392.C - Interface with a Linear LTC1392 to measure and display temperature, Vcc and a
5832_1.C - Interface with a UCN5832 32-bit shift register to display data on four 7-segment
5832_2.C - An alternate implementation to experiment with the amount of program memory
7219_1.C - Interface with a MAX7219 to control four common cathode 7-segment LEDs.
DS1602_1.C - Interface with a DS1602 elapsed time counter.
DS1867.C - Interface with a DS1867 dual digital potentiometer.
DEFS_12C.H - Standard register file and bit defintions for the 12C5 processors.
OSCCAL_1.C - Illustrates how to write RC oscillator calibration constant to register OSCCAL.
LCD_12C.C - Standard serial routines for interfacing with a serial LCD.
BAR_1.C - LED routine. Illustrates the use of ROM arrays.
EXT_EE_1.C - Interface with 24LC32, LC64, LC128 or LC256 EEPROM. Note that these I2C
routines may be used to interface all of the various I2C devices which are illustrated for the
EEPROM_1.C. Illustrates how to write to and read from the internal EEPROM associated with
1820_1.C - Interface with two Dallas DS1820 thermometers. (1-W).
D_12C67X.H - Standard register file and bit defintions for the 12C6 processors.
OSCCAL_1.C - Illustrates how to fetch the internal calibration data and write this to the
LCD12C67.C - Standard serial routines for interfacing with a serial LCD.
A_D.C - Illustrates how to use the on-board A/D converters.
DEFS_877.H - Standard register file and bit definitions for the 16F87X processors.
TST_SER.C - Illustrates use of serial routines in SER_877.C
SER_877.C - Standard serial routines.
UNION.C - A brief routine which illustrates unions.
CHKSUM_1.C - Calculates the checksum of the first 0x1000 bytes of program memory.
BITFIELD.C - A short routine which illustrates the use of bitfields.
6259_1.C - Interface with TI TPIC6259 8-bit addressable power latch. Illustrates the use of
6259_2.C - Expands on the above.
A_D_877.C - Illustrates use of on-board 10-bit A/D converters.
SIMULTAN.C - Illustrates how to solve two simultaneous equations to obtain the coefficients for
a two point NTC thermistor model.
THERMIS.C - Illustrates how to perform a temperature measurement using an NTC thermistor.
TMP04.C - Use of CCP module in input capture mode to measure temperature using an Analog
TSL_235.C - Measuring light intensity using a TI TSL235. Illustrates the use of TMR0 to count
events over a window using Timer1.
TIMER1_1.C - Illustrates the use of Timer1 and an external clock source to display elapsed time.
PWM_1.C - Use of CCP module in PWM mode.
RPM.C - Use of one CCP Module in PWM mode to turn motor. Use of the other CCP module in
Input Capture mode to determine RPM.
OUT_CMP.C - Use of CCP in Output Compare Mode.
24_256_1.C - Illustrates interface with 24LC32, LC64, LC128, LC256 EEPROM using the SSP
as an I2C Master. Note that all routines developed for the PIC16F84 in interfacing with I2C
devices may be similarly ported to the PIC16F877.
24_256_2.C - Similar. Expands to illustrate burst write and reads.
RS485_M1.C and RS485_S1.C - Illustrates a simple network where the master commands the
addressed slave to flash an LED n times.