PIC C Routines

copyright, Peter H. Anderson, Baltimore, MD, Nov, '99

This consists of some 375 pages of routines and descriptions together with a disk which includes all routines. The binding is a 2 inch 3-ring binder. The cost is $49.00 plus shipping. Shipping in the US is $6.35. To all other countries shipping via AIR is $20.00).

Ordering Info Note that this item may also be ordered via Amazon zShops.

A review of this book appears at Keyghost.Com

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.

More Info


This is a collection of C language routines for the popular Microchip PIC series of micro controllers.

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" grade.

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 than myself.

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.

Technical Support.

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 hundred.

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.

Standard Definitions.

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 required.

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 16F877.

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.

PIC16F84 Routines.

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 S_IN_84.C.

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 sturctures.

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 addition.

PCF8591_1.C - Interfaces with Philips PCF8591 to use the D/A converter to generate a sawtooth.

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 power mode.

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 measurements.

DS1821_2.C - Places DS1821 is measurement mode, displays thermostat settings, sets thermostat settings.

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 differential voltage.

5832_1.C - Interface with a UCN5832 32-bit shift register to display data on four 7-segment LEDs.

5832_2.C - An alternate implementation to experiment with the amount of program memory required.

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.

PIC12C509 Routines.

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 PIC16F84.

EEPROM_1.C. Illustrates how to write to and read from the internal EEPROM associated with the PIC12CE519.

1820_1.C - Interface with two Dallas DS1820 thermometers. (1-W).

PIC12C67X Routines.

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 OSCCAL register.

LCD12C67.C - Standard serial routines for interfacing with a serial LCD.

A_D.C - Illustrates how to use the on-board A/D converters.

PIC16F877 Routines.

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 bitfields.

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 Devices TMP04.

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.