Introduction to PIC Microcontrollers

Microcontrollers are wonderfully useful devices. They incorporate all necessary parts of a complete computer into a single IC that need almost no external parts to run. Microcontrollers usually cost from $1-$20 depending on features and size.

Where are Microcontrollers Used?

Anything that is computerized but does not have a full-fledged PC inside most likely uses a microcontroller. This includes things such as audio/video equipment, watches, microwaves ovens, and more. A microcontroller is different from a microprocessor in that a microprocessor usually requires a number of external parts such as RAM or ROM to operate. A microprocessor such as a PC processor can’t do anything by itself without a motherboard and associated chips connected.

A microcontroller is sometimes referred to as an embedded processor because it can be embedded into a device that has some function other than being a general purpose computer. This generally implies that microcontrollers are less expensive and less powerful than a full-fledged microprocessor, but don’t be fooled! Because a microcontroller can be dedicated to a specific task, it can actually do many things that a full PC is not very good at. This is because a microcontroller and its program are very tightly integrated. Time-critical applications are very well suited to a microcontroller. Often in PCs, timing-sensitive tasks are performed by a microcontroller. A keyboard or mouse is a good example. If a PC spent all its time scanning the keyboard and mouse, it would have trouble doing other tasks. Instead each device contains a microcontroller that monitors user input. When something happens that the computer needs to know about, it sends a message to the computer. The computer doesn’t care about the keyboard or mouse except when there is input. This also give others advantages such as reducing the number of wires needed to connect peripherals. The first PIC ever designed, long before Microchip Inc. was around (General Instruments were the original PIC developers) was made for the specific purpose of offloading work of I/O and other tasks from the main CPU in a large computer.

Parts of a Microcontroller

In most microcontrollers all components are contained inside a single chip. Only a few external parts are usually required to make the micro run. The major parts of a microcontroller are:

  • CPU – The CPU core. Many small micros use an 8-bit CPU, although 16 and 32-bit CPUs also exist.
  • Program Memory – Memory used to store the program to be run. Flash RAM is used on modern micros.
  • RAM – Temporary memory used during program execution. SRAM is usually used.
  • EEPROM – Permanent storage to allow programs to save settings and other data when the power is off.
  • Oscillator – Support for different types of clock sources are usually available, including crystals, resonators, external clock sources, and internal clocks. The clock affects the speed of the program execution, timers and other parts. Speeds from 4-40MHz are typical.
  • I/O Ports – Pins for interfacing the micro to other devices. Most micros allow individual control of each pin, making them very flexible.
  • Peripherals – Many useful peripherals are common, such as:
    • USARTs – Serial ports which can send and receive data at up to 1Mbps or more.
    • Comparators and A/D Converters – For sensing and measuring analog signals.
    • Timers – For counting pulses and measuring accurate time intervals.
    • Interrupts – A method of responding to external triggers or special conditions of the other peripherals. (such as data being received on a USART)
    • Pulse Width Modulators (PWM) – For controlling motors, lamps, LEDs and other power control devices.

Getting Started with PIC Microcontrollers

Perhaps you’ve got a project in mind that you think would be good with a micro. Or maybe you’ve heard about microcontrollers and don’t know where to start. This page should help you learn how to use microcontrollers in your own applications. We will focus on the PIC brand of microcontrollers made by Microchip in this article.

Unlike other electronics projects, using a micro involves both software and hardware. You can build a circuit with a PIC, but unless you put some software into it, the circuit will probably be useless. But this is great for people that want to play with electronics but come from the purely software side of things. Imagine coding for a device of your very own design! It’s also great because you can make simple circuits that do very sophisticated things. I can’t remember the last time I built a circuit that didn’t have a micro in it. Modern circuits can almost always benefit from being computerized.

Required Parts and Supplies

Playing with PIC microcontrollers can be a lot of fun, but you need to have a basic set of parts, tools, and software before you begin. The following is a list of parts and supplies that are recommended:

  • PIC Microcontroller – The PIC16F627A is recommended as a good device for beginners. Start with a DIP style package. Surface mounted (SMT) devices are only useful in production prototypes, or when a DIP of your chosen part isn’t available.
  • PIC Datasheet – Make sure you download the PDF datasheet for the PIC that you are using. You should at least read your first PIC datasheet cover to cover so that you understand all the aspects of the micro. You’ll find that other PICs (and indeed other brands of micros) have many of the same features, and once you know one part, you can easily master others.
  • Prototyping Parts – A basic assortment of resistors, capacitors, LEDs, switches, batteries, etc. will help you a lot. Also, some white plug-in prototyping board will allow you to try out different circuits easily.
  • Development Software / Compiler – You need some way of writing code and compiling it. The Sourceboost IDE and compiler are highly recommended. A free version supports all the features of the PIC16F627A.
  • PIC Programmer Hardware / Software – You need some way of getting your compiled program into the PIC. There are many free plans for PIC programmers on the web, but the TechTools QuickWriter is worth every penny. I built and used many of the free programmers on the web, and none of them were ever as good as the QuickWriter. You need reliable tools for reliable results.

A Simple PIC Circuit

Once you’ve got all the bits and pieces you need, you’re ready to get started. But you might be wondering: How the heck do I get something happening? With a mix of hardware and software, it’s hard to know where to begin. You’re probably eager to make something real, so don’t bother playing with simulators and the like. The most important thing is to make something happen on a real circuit so that you can feel the excitement that comes from powering up a micro and having it run your program and do something, even if it’s just blinking an LED.

Let’s consider the simple PIC circuit shown here. You might want to open it in another window to have a better look while we discuss it. This circuit uses a PIC16F627A microcontroller. It has a power supply that runs from a 9 volt battery. It has a few switches for input, and a few LEDs for output. In addition it has an in-circuit programming port so that code can be put into the chip while it is in the circuit. To make sure you understand what’s going on in the circuit, let’s do a quick circuit analysis:

  • U1 is a PIC16F627A – This is the core of our circuit. It’s pretty much the reason the circuit is useful at all.
  • the power supply – The PIC would like +5V or so to run. (smaller voltages work too)
    • U2 is a LM78L05 low current +5V regulator – It takes 9V from the battery and makes 5V.
    • C1 is a filter capacitor – It stabilizes the power supply in case the battery is far from the circuit.
    • C2 is a bypass capacitor – It filters high frequency noise off the 5V line.
    • D4/R4 is a power indicator – This is highly useful to make sure your circuit is on when you think it should be doing something!
  • the microcontroller circuit – The PIC has some stuff connected to it.
    • C3 is a bypass capacitor – It filters high frequency noise off the 5V line. Be very sure to ALWAYS BYPASS TO GROUND THE POWER SUPPLY PINS OF EVERY DIGIAL CHIP YOU EVER USE! Ok? OK. Failure to do this will cause you and/or your circuit to lose your mind and behave badly.
    • P1 – This is the in-circuit programming port. It lets us upload software to the PIC while it’s in the circuit. This is very convenient! Note that the QuickWriter comes with its in-circuit cable wired slightly differently. This pinout is preferred because it takes fewer pins, which makes the connector smaller.
    • S2 and S3 are pushbutton switches – This lets us send some data into the PIC to make it do stuff.
    • D1/R1, D2/R2, D3/R3 are indicators of different colours – This lets our PIC program turn on and off LEDs to show status from the program.

So, the basic idea is that we have all the stuff to make the PIC go, a couple of buttons to act as our keyboard and a couple of LEDs to act as our display. Remember that there is no keyboard or monitor port on a PIC. Without some I/O, things are pretty boring. The switches and LEDs will let us do lots of interesting things.

Before Making Some Code

Now that we’ve got our lovely little PIC circuit, we need some code to make it go. If you don’t know anything about how a processor works, you should go and do a little reading about the basics of processors, program counters, opcodes and operands, etc. This next section assumes that you are at least a bit familiar with how programs run on processors. Before we make some code, we need to understand a bit more about how the PIC works.

Clock Cycles, Oscillators and Fuses

A great thing about PICs is that unlike many other processors, all instructions take the same amount of time to run, except for instructions that jump somewhere else in the program. In fact, all instructions take 1 instruction cycle, except for the jump instructions which take 2. And in the case of the PIC, an instruction cycle is 0.25x the clock frequency. (4 clock cycles are required to complete one instruction cycle) You might notice that in our circuit there is no crystal or clock oscillator. That’s because our handy PIC16F627A has a built-in oscillator. You can run the PIC from your own oscillator, but for simplicity we chose to use the one built-in. It’s an RC type, but is factory-calibrated. Even over its entire temperature range it’s guaranteed to be within about 1%.

We need to tell the PIC which kind of oscillator we want it to use. This needs to happen before any code can run. So we need some way of setting up a few basic options before our code starts to run. To do this we set some fuses. In old PICs, these fuses were links that would be permanently changed by the programming procedure. In modern PICs these settings can be changed many times, so the term “fuse” is somewhat of a misnomer. Some of the basic PIC fuses are follows:

  • Oscillator Type – Crystal oscillator, external clock source, internal oscillator, etc.
  • Power-Up Timer Enable – This lets the power supply voltage settle before starting to run code. Otherwise the PIC might crash if the power supply takes a long time to turn on and stabilize. The delay is short, so you should always use it unless you have a specific situation where it adds too much startup time. (I have always used it)
  • Watchdog Timer Enable – If your program goes funny for some reason and crashes, the watchdog timer can reset the PIC automatically. Normally you clear the watchdog in your program on a regular basis to prevent it from going off. You should always clear the watchdog timer instead of using the NOP instruction. Start with the watchdog timer off during development because it can be confusing to have your program restarting all the time. Only enable it once you have things somewhat working.
  • Brownout Reset Enable – If the power supply voltage dips too low, the RAM or other parts of the PIC might get messed up and have weird values. This is generally bad. If you turn on the brownout reset function, the PIC will be reset automatically if the power supply voltage goes too low. There is no need to push your luck and set this too high. Most PICs can work over quite a large range of voltages. Don’t make life hard for yourself, set it to a low value unless you have a reason not to.

Program Memory and Program Counter

So what happens when we turn on the power to our circuit? Well, the lovely little program that you have loaded into the PIC is all set up to start from the beginning. And where is the beginning of the program you might ask? It’s at address 0! Program memory is not normally writable by your program (except in some PICs under certain circumstances) so you can generally think of program memory as ROM. The program memory is totally separate from RAM and other parts of the processor, so program memory addresses have nothing to do with addresses that you will use to access RAM. (more on this later)

When the program starts up, the program counter starts at address 0. Some of the other low addresses are reserved for interrupt vectors, so normally you immediately jump somewhere else to start running the rest of the program. If you use a C compiler you don’t have to worry about this. It knows how to deal with this, and generally you never really have to worry about program memory addresses.

Unlike probably every other program you’ve ever written, a PIC program never exits. Other than hardware that is set up to turn its own power off, your PIC programs will generally run forever as long as power is applied. This means that most programs are structured around a while(1) { do stuff; } loop. Unless you’re making a very low power battery application, there is usually nothing wrong with just spinning in the main loop while nothing is happening. Even the largest PIC micros take very little power compared with even a single LED. So it’s advisable to simply make a main loop and keep going around and around. Certain peripheral use will cause higher power consumption, but unless the PIC is the highest consumer of power in your circuit, don’t worry about this.

RAM: The Abundant Resource

Sorry, just joking! Probably one of the first things you will notice when looking at PIC specs compared with the computer you are probably reading this with, is that PICs have a seemingly tiny amount of memory. The smallest PIC has only 16 bytes of RAM, and the largest PICs with built-in memory have only a few K. Sometimes you’ll wish that you had more, but generally you’ll find that you never really get close to running out. Remember that in a PC the RAM is used for loading huge applications. But on a micro the application is in program memory, and RAM is only used for temporary storage.

So other than some state variables, maybe a serial buffer and some counters, many applications get along fine with almost no RAM at all. You will soon find that the power of the micro is in the peripherals and the tight integration of code and hardware, not in its storage capacity. Don’t think of a micro as a tiny general purpose PC. Think of it as an easy way to make a circuit that you can write programs for. A micro ultimately results in simpler, more flexible circuits than can be achieved by building the same behaviour with actual circuits.

A quick note about registers. In the PIC, RAM, I/O ports, and config registers, etc. are all memory mapped into the same address space. The locations within this space are usually referred to as registers. Registers can be RAM locations (file registers), I/O ports, or a number of other things. Near the beginning of the manual for every PIC is a memory map. You should look at it to make sure you see how everything fits together. Remember that the PIC is designed in such a way that program memory and data memory are separate. This is called Harvard Architecture and is used on many modern processors. You need to make sure you don’t confuse program memory locations (stored in Flash memory) with data memory and working registers such as RAM, I/O ports, and so on. The addresses of the instructions in your program might look similar to the address of the various registers used by your program. But they are on different busses and have nothing to do with each other.

I/O Ports and Peripherals are Your Friend

The last thing you need to know about before we get started with a code example are peripherals. The fun and power of the PIC is in the peripherals that it has. In my first PIC project I used a PIC with no USART, except one of the main goals of my application was to send serial MIDI data at 31.25kbps. If I’d known that there were PICs with hardware specifically for sending and receiving serial data I would have spent a lot less time fighting with my program. Instead I wrote code (in assembler) to generate perfectly timed MIDI data. And all without an oscilloscope. I proved that the timing was correct by drawing graphs of the program flow and counting all of the instructions. The moral of the story is to use a PIC that has the hardware peripherals that will make your life easier. Although you might feel cool coming up with a crazy hack like the one above, those are actually poor solutions that waste development time and result in code which is delicate and can’t be reused very easily.

The simplest peripherals are basic I/O ports. All PICs have these. They allow simple digital input and output. You can read or write single bits, or whole bytes of data. Turn on and off something, or read the status of a switch. The PIC16F627A has two ports: A and B. Each of these ports has 8 lines/pins. And each of these 8 lines can do something different. The I/O lines are arranged in ports of 8 bits wide or less because sometimes it’s useful to be able to access all 8 bits at once. But often you will use the lines individually.

The important thing to remember about I/O lines is that each line can do a multitude of things. The people at Microchip pack so many features into even small PICs that each line or pin of a port has a lot of different functions. You need to understand the implications of this before using each I/O line, or else you might spend hours wondering why it doesn’t work the way you expect. As you work with larger PICs the number of modes and functions for each pin increases. Some have five or six different functions. The good thing about the PIC is that all registers come up with known values upon power on. This means that you don’t necessarily have to change a register setting if you know that the PIC boots up with it in the right state. But it’s often a good idea to go through the steps of explicitly configuring things, just so that it’s clear. Code runs fast, and extra start-up code is not likely to cause even a noticable delay. Also, PICs have lots of program memory so you’re not likely to run out of code space. If you do, a PIC with twice the code memory is probably only $1 more than the one you’re using.

The best way to ensure that you use each I/O line properly is to look at the table for each I/O port which lists the pin function of each I/O line. You need to make sure that the pins can do what you want them to do, and then make sure that other peripherals which use each pin are configured to not interfere with your intended use of the pin. For instance, on the PIC16F627A the capture and compare module needs to be specifically disabled for PORTA to work normally. Also, some of the pins on PORTA are open drain outputs. This means that they can pull down to ground, but not up to +5V. When designing your circuit you need to check to make sure that you don’t decide on bogus hookups that won’t work. You’ll generally find that there are many options for which way to wire your PIC to external circuits. Generally it’s best to group things together by function because not only does it usually look neater on the schematic. It often ends up being easier to physically wire as well.

The First PIC Program

Let’s work through an example program that can run on the hardware described above. In this first program we’ll use simple digital input and output, and nothing else. Let’s make a program that lights the red LED when button A is pressed. Not very exciting, but you’ll see a number of concepts in action.

This example uses the SourceBoost IDE and development environment for all examples. You should read the help file that comes with it to get an idea of how to set up new projects, select which device you’re using, compile, etc. before trying to compile this code yourself.

/*
 * PIC Demo Program
 *
 * Copyright 2006 - Andrew Kilpatrick
 *
 * Written by: Andrew Kilpatrick
 *
 * Hardware:
 *
 *	RA0 - green LED - active high
 *	RA1 - yellow LED - active high
 *	RA2 - red LED - active high
 *
 *	RB0 - A button - active low
 *	RB1 - B button - active low
 *
 */
#include <system.h>
#pragma DATA _CONFIG, _BODEN_OFF & _BOREN_OFF & _CP_OFF & _DATA_CP_OFF & _PWRTE_ON \
& _WDT_OFF & _LVP_OFF & _MCLRE_OFF & _INTOSC_OSC_CLKOUT

// clock frequency - for delay routines
#pragma CLOCK_FREQ	4000000

void main() {
	// set up I/O
	trisa = 0xf8;  // make porta.0,1,2 outputs
	porta = 0x00;  // clear porta latches
	cmcon = 0x07;  // disable comparators on porta
	trisb = 0x03;  // make portb.0,1 inputs
	option_reg.NOT_RBPU = 0;  // turn on weak pull-ups on portb

	while(1) {
		if(portb.0 == 0) porta.2 = 1;
		else porta.2 = 0;
	}
}

Code Details

Since this is the first PIC program example, you might be seeing a lot of things that are new to you. Even if you are an experienced coder, you will certainly see things here that are new. Let’s go through the various sections in detail.

Comment Section

A nice big title block is good at the top of every source file. This program only has one source file, but bigger applications usually have more than one. It’s a good habit to get into copying pin assignments and other details from your schematic into the title block of the related source file. Do this right at the beginning and then you won’t have to go back and look at the schematic as often. Note that this implies that your circuit is all done (at least the decisions about which pins on the PIC are connected to which things in your circuit) before you start writing code. Everyone has their own style, but I personally believe that it’s best to design your circuit as completely as possible before writing any code. If you’re constantly rearranging the wiring on the PIC after you’ve started coding it’s a sign that maybe you didn’t do your research as to which pins should be used for which functions. Modifying the code and the pin assignments at the same time will be very confusing and should be avoided.

Notice the hardware section shows pins that are connected to things in our circuit. The ”active high” and ”active low” notes help you remember which way on is. There are many times when 1 doesn’t mean on. It’s really confusing when you have bits which are inverted, but that’s a fact of life sometimes. If you can wire things up in a logically way, great. But don’t add extra parts unless you absolutely need them. Remember, the best electronics are those with the fewest parts. Contradictary? No. Efficient and reliable. Hopefully! The RA0, RA1, etc. are the shortforms used on the datasheets for the pin names. You’ll see that there are several ways of labelling the pins, but generally you need to know the port letter (A, B, C, etc.) and the bit number (0-7 usually) where 0 is the 1s bit and 7 is the 128s bit. If you can’t do hex and binary conversions in your head, you’d better learn because PICs programs are all about bit flipping. If you can think in binary and hex you’ll be way ahead.

Includes, Pragma, etc.

The next section includes ‘’system.h” which is just a header file that SourceBoost uses so that pins and registers within the PIC have convenient names. This file actually just includes a header specific to the device which you have set in the SourceBoost configuration, as each device is different. It’s useful to look in the include/ directory under the SourceBoost installation directory. If you look in p16f627a.h you’ll see all the register names and bit/pin names which can be used. Sometimes they are slightly different than what you would expect from reading the datasheet.

The #pragma DATA _CONFIG line sets the fuses that we were discussing earlier. The pragma line just tells the compiler to set up some non-code sections of the compiled output file so that the programming software will know the fuse values. In this case we have turned on the power-up timer and selected the internal oscillator. We will ignore the other options for now.

The #pragma CLOCK_FREQ line sets a compiler variable telling the compiler how fast we expect that our instruction clock will be. (in Hz) The internal oscillator is 4MHz, but if we used an external crystal we would set this to the speed of the crystal. When you use some of the built-in functions that SourceBoost provides, they need to know how fast the processor is running. So, for instance, when you use delay_s(1); to delay for 1 second, the compiler adjusts the routine to magically cause a 1 second delay when running at the specified clock frequency. If you change your crystal, remember to change this setting or your delays will go at the wrong speed.

Main!

The void main() section is where our program does stuff. All programs need a main section, even if they do most of their work somewhere else. But in our case our entire program exists within the main section. Notice that unlike normal C programs on a PC, main doesn’t take any arguments or return anything. The reasons for this should be obvious, as it can’t take command-line arguments or return success or error codes!

The first thing we do in the main code block is to set up the I/O pins for our application. You should read about how this works in the PIC manual. But basically the idea is that each pin can be an input or output. (or some other function, if set up with other registers) This is configured by setting or clearing bits in the corresponding TRIS register. Setting a bit (bit=1) makes the corresponding I/O pin an input. Clearing a bit (bit=0) makes the corresponding I/O pin an output.

This is all pretty straight forward, however note the cmcon line. We want to make sure that the capture and compare module is disabled so that it doesn’t interfere with PORTA pins that we’re using to control the LEDs.

The next line with the option_reg commands demonstrates a neat feature. PORTB contains internal pull-ups that can be turned on. This means that if you’re using PORTB as inputs which are normally left unconnected as is the case with our switches, the internal pull-ups can pull the inputs up to the power supply voltage. This saves external parts. You should never leave an input floating. Its very high impedance and could easily pick up noise, causing it to twiddle on and off unexpectedly. The weak pull-ups are enabled by clearing the NOT_RBPU bit in the OPTION register.

Ok, now that we have everything set up, now comes the fun part! Unfortunately this example is kind of a downer, after learning about all the background info you need, our entire program only has a few lines! But hopefully it inspires you to think of more interesting and useful things that you can do with the PIC.

First of all, the while(1) line gets us into an endless loop. Most programs will have one of these, and the main section is a good place to put it. If you don’t use interrupts, you can simply call polling routines from your loop as fast as possible. If you are using interrupts and there is nothing to do in the while loop, you can just clear the watchdog timer and let the loop spin freely.

So the meat of our little program is the final two lines. First we check to see if RB0 is low, which would indicate that the switch is closed and the pin is shorted to ground. If it is low, we turn on the red LED by setting RA2. Otherwise, we turn off the red LED by clearing RA2.

And that’s it! Now you know how to make stuff work on a PIC. If you can make this go on your own circuit, then you’ve successfully gotten over the most overwhelming and daunting part of PIC development. The rest is just a matter of writing bigger programs, learning how to use peripherals, and learning good quality design so that you can make programs that work with the least amount of debugging possible. You’ll soon see that unlike programming on a PC, it’s really not that convenient to just fiddle around making little changes in your program. Just like I’m sure the people that used computers with punch-cards did, you’ll quickly get good at visualizing programs running in your head and solving problems before you ever try running the code in your actual circuit.

Something to Try

If you’ve gotten the above program to work, try to modify the program to add more functionality. Here are a few ideas to try:

  • make the LED blink on and off when the button is held down
  • make the LEDs toggle back and forth
  • simulate gates with the two inputs such as AND, OR, NAND, NOR, XOR by turning on and off the LED
  • make something that times repeated presses of the button and continue to flash the LED at the same speed after the button has stopped being pressed
  • make the LEDs fade in and out by pulsing them and adjusting the duty cycle – then learn to use the PWM to do this
  • connect more LEDs and design a simple game that can be played with one or two buttons and some LEDs

Programming Notes

Sometimes you might run into problems programming your PIC. The details I’ve been able to find outlining the various troubles seems sketchy at best, and seem more like rules of thumb than anything. If your PIC refuses to program or verify, it’s probably your circuit. Try a second PIC just to be sure it’s not the chip, but generally you’ll find that something in your circuit is upsetting things. You can try some of these tricks to see if they might help you:

  • Check the Wiring of the Programmer – Double, triple and quadruple check your wiring.
  • Confirm the Right Signals – Watch the programming signals on a scope with your probe touching the actual PIC pins. Make sure you really do see clock, data, VPP and VCC on all the appropriate pins. Use on ohm meter to ensure that the ground pin from the chip is grounded all the way back to the programmer.
  • Isolate your PIC - Disconnect other parts of your circuit either with a diode or jumper on the PIC’s power pins so that you’re not feeding the rest of your circuit with your programmer.
  • Power the PIC Yourself During Programming – The QuickWriter (and probably others) allow you to provide the power for your circuit. If you use it manually the programming software will tell you when to turn the circuit on and off. If you implement an auto power control, some programmers can control your circuit themselves. I sometimes use a relay driven from a small transistor to allow the programmer to control my power supply.
  • Remove IOs from PIC Pins – If you have devices which are feeding voltage into the PIC (like other logic devices that are high) this may interfere with programming. Disconnect these devices or isolate their power supplies so that they’re off when you’re programming.
  • Use Low Voltage Programming – If you programmer supports LVP (low-voltage programming) this can be a way to get around problems of the PIC not power cycling or resetting properly. Using this mode will take up an I/O pin, which may or may not be a problem for you.

Happy PICing!