Fly Electric!

PIC and C for Beginners

This is my 'getting started in C programming for PICs' page. It is intended to help beginners get past the early hurdles quicker than I did. I would like to thank James Hopper for his help. Please go to my PIC PROJECTS page for some useful gadgets.

There are many different microprocessor brands. I've been guided towards the Microchip 'PIC' family and I'm happy with this choice. They are pretty cheap and I'm not likely to outgrow them. C vs Assembler vs Basic vs JAL prgramming language ... everyone has a view so presumably none are perfect. This page will help you with C if you decide to go that way. It seemed hard to learn but much easier now that I have 'got it'.

Please note that I am a novice so I am probably demonstrating some poor practices. The examples and advice will get you started nicely but be willing to accept that there may be better ways of doing some things. The page and examples are orientated around the free version of the CC5X compiler but I have starting using the BoostC compiler for larger projects.


Building blocks
Basic programming & PIC tips
Compiling with the CC5X compiler
Programming your PIC with WinPic
Differences between CC5X and BoostC

PIC PROJECTS (different page)
PIC DATA LOGGING (different page)


The simplest way to mirror what I have done will be to use the same components:

1.1 Crimson Editor text editor (free)
1.2 CC5X or BoostC C compilers (free)
1.3 WinPic programming interface software (free)
1.4 PIC-PG1 programming interface hardware ('programmer') - cheap to make or buy one to match your PC...
1.5 A PC with a serial port (a USB/Serial dongle is not likely to work; PCI-based Serial interfaces are available. USB (and Parallel) programmers are also available)
1.6 MPLabfrom Microchip needed by WinPic for device definition files (free)
1.7 12F683 or any other suitable PIC
1.8 A home-made prototyping board (more on this below)
1.9 I found the first few chapters of this Learning C guide helpful (free)
1.10 The EXCELLENT Learn to Program in C with FED has been my greatest help (free)
1.11 The various CC5X/BoostC guides to do things 'their' way, PIC datasheets and Google.


To get something working it is always best to start with a simple example and then build on that. These are my building blocks that have built incrementally into my PIC PROJECTS. You should find the little programs below helpful if you are learning PICs and C programming. The code in the 'projects' has become more refined as I have learnt more but they do start assuming a basic knowledge which I try to impart on this page. Please note that in C programs, layout and structure are meaningful and important. To see this properly including certain text in colour, you need a 'programmers' text editor. I have used 'Crimson Editor' (link above).

LED Everyone recommends you start by making LEDs flash. This teaches you the basic PIC configuration, how to enable ports and how to do simple timing tasks. This program flashes two LEDs at different intervals. LEDs are also very useful tool (with temporary tweaks) to reveal the values of various registers or to confirm successful operation of a function.

ADC Since I want to monitor voltages, I needed to understand Analogue to Digital Converters. This circuit monitors a voltage that is varied by a pot and toggles the LEDs when the voltage goes over a pre-determined threshold. The PICs 10bit ADC divides a reference voltage into 1023 steps which are used to convert the measured voltage into a value ranging from 0 to 1023.

SERVO CONTROLLER My next circuit was the servo controller which also appears on my Projects Page. This program extends the first two by using the ADC to monitor a pot and the LED timing principles to generate the pulse to move a servo. I might try using the PWM module to generate the servo signal one day.

PULSE WIDTH This program is very short but took me ages to research and get working! All it does is look for the high part of a signal from a receiver and works out how long it is (so we know the TX/RX throttle position). I've since improved it using a proper timer in 'Port Mirror' below for more predictable results.

INTERRUPT This is a simple implementation of an 'interrupt'. It is also a way of doing a form of 'multi-tasking' with a PIC. This program needs the standard CC5X interrupt.h file (if you get errors on compile try my modified version). The program interrupts the main program whenever the Rx signal changes state so that these changes are mirrored to the ESC. This is a nice simple and robust way of mirroring ports accurately.

PORT MIRROR In order to reduce LVC false triggering, perform error checking and to synchronise writes to memory, the program needed to know the throttle position which this program developed. It also improved the approach to generating pulses. It is a nice example of configuring the 8bit Timer2. However, in LVC1 I have moved on to the 10bit Timer1 for more precision. This spreadsheet will help you work out the pre-scaler settings and relationship with clock frequency for different time periods.

DATA LOGGING Most Flash-based PICs have a data memory called EEPROM. It usually has (up to) 256 locations, each 1 byte in size. This is very useful for storing values of variables as a program executes (eg: for testing) or for data logging. However, each write takes 2-3ms which can be a constraint in time-critical programs so writes are synchronised with the long low pulse from the Rx.

PWM The world's simplest 'Pulse Width Modulation' program. Set to generate a 1ms 'high' every 20ms. The PICs PWM feature is one of its few inherent multi-tasking capabilities. The parameters need settings but then it just runs. Three timing parameters have to be set (clock frequency, period and duty cycle) and this spreadsheet will help you select values.

DELAY These files all need this delay file. It's worth looking at to help you understand timers. It is based on the CC5X delay file but reformated and commented to explain what each step does.


Here are some tips in no particular order:

2.1 It is ESSENTIAL that you understand bits, bytes, decimal and hex. Make sure you know how to count to at least 15 or 16 using all of these. The Microsoft calculator has a scientific mode to help you convert between these types. The HEX2DEC and similar functions in Excel can also be useful. Note that while humans normally start counting from 1, computers (and PICs) start from 0.

2.2 The expression 0xFF is the same as FFh and FFH. All are hex FF (ie: decimal 255). The expression 0b1111111 is the same but using binary (8bits). CC5X allows you to write 0b1111.1111 making it easier to read (you can put the dots anywhere to aid readibility when using CC5X). Numbers are taken to be decimals unless otherwise indicated.

2.3 Data is stored in 'variables' sometimes called constants or registers or locations or addresses. These are normally 8bits in length on PICs. An 8bit variable is often set using a 'char' statement. A 16bit variable is often set with the 'uns16' or 'short' statements which are also not signed (ie: only positive). On the PICs I have used the 16bit is actually two 8bit registers.

2.4 CC5X (and probably other compliers) sometimes struggle with variables of different size especially when the code becomes complex. If you are writing an 8bit value into a 16bit variable, help it by being more precise (eg: 16BITVARIABLE.low8 = 8BITVALUE) - this puts the 8bit value into the 'least significant' (right) 8bit part of the 16bit variable. This approach also saves you code instructions (which become a constraint on larger programs). Similarly you can take part of a 16bit (the 'most significant' part in the following example) and put it into an 8bit variable (eg: 8BITVARIABLE = 16BITVALUE.high8).

2.5 Again I have observed in the more complex programs I have written that 'reusing' a variable can cause problems. Simple counters and timers often use a variable with a short name (eg: 'i'). If you use this in more than one place it can sometimes get cranky in which case declare a new value (eg: 'j').

2.6 "Flash" based PIC devices can be programmed many times and are the ones to choose. They have an 'F' in the name. You also want the modern ones with built-in oscillators. Just as a mechanical clock has a 'ticking' mechanism, the oscillator is a pulsing mechanism to make PICs move on to the next instruction.

2.7 Your program code (the "Functions") are stored in what the PIC data sheets refer to as 'Program Memory' (ROM) and the size is referred to as 'words'. A word is 2 bytes, a dword is a double word, and one 'kword' is 1k in size (ie: 1024). The 1k also often refers to the maximum number of instructions and the free version of CC5X will only generate code that does not exceed 1024 instructions. One option if you need more code is to write this to separate 'code pages'. Multiple pages seem to only exist on PICs with program code of 4096 or greater (2048 seems to be one code page). This might guide your choice of PIC for large programs. The free version of BoostC can handle 2k.

2.8 'Pragma' and 'Include' statements and Variables seem to be held in the memory called RAM or SRAM. This is usually quite small (eg: 64 to 256 byes). Program memory (rom) is usually much bigger and it is possible to force some larger variables into that memory using '#pragma rambank ...' (CC5X) and 'rom char ...' (BoostC) statements.

2.9 'Data logging' is done most easily to the "EEPROM" data memory. This is usually 128 to 256bytes. You can buffer data in variables and move this to external SD/MMC cards or to special memory chips ('Serial EEPROM') and I believe the Microchip 24xxxx family are a suitable choice.

2.10 Make sure your compiler (CC5X) and programmer (WinPic) can handle your chosen PIC when selecting new ones for projects. Both can be modified by you for new chips but this is more complex and they may not work. In addition to CC5X and it's big brother CC8E, you may want to consider the BoostC compiler one day. The latter only supports 14 and 16bit cores (eg: described as '14 program memory space' in PIC data sheets) so although this narrows your choice a little more it gives you more flexibility later. ICProg is another popular programmer which supports some different devices.

2.11 There may be some exceptions but PICs are essentially single not multi-tasking processors. Programs tend to run consecutively and loops are used to repeat tasks until conditions are fulfilled. 'Timers' and 'PWM' features can run concurrently with other tasks but to determine if they have reached a threshold you either need to keep checking its value regularly ('polling') or get it to trigger an interrupt. Interrupts can be troublesome.

2.12 Why program in C? It helps you concentrate on program logic rather than the nitty-gritty operation of the PIC. The PIC does not have much of an 'operating system' so your code has to instruct the processor to do many things which have nothing to do with the logic you are trying to design. C buffers you from this, but this can make it less efficient and harder to debug. As a beginner, I've been happy to reduce the things I needed to grasp initially.

2.13 'Comments' are text which explains the operation of a program. Most compilers seem to allow you to use // or /* followed by */. Blank spaces and line breaks aid readability and are ignored by the compiler. Programe code is case-sensitive.

2.14 Your program usually starts with a statement to "include" a file about your chip. This creates the link between names of registers referred to in the PIC data sheets (and used in your programs) and the exact location of the register inside the PIC.

2.15 In the 'Variables' section of my programs, it is common to "define" your own names for inputs and outputs (eg: LED1) and assign these to ports (pins). Again, this provides the link between recognisable names in your program to a command that the complier will create that the PIC can recognise. Commands/Statements in a program usually have to end in a semi-colon; the #define command is one of few exceptions.

2.16 Registers are usually 8bits in length and usually have a name (eg: TRISIO). Each of the individual bits in that register can be for a specific function which can have its own name (eg: GP1). You can sometimes refer to the GP1 part using its own name but sometimes you have to use the name of the 'parent' register and specify which bit you are refering to. Which of these work depends on the device file (point 2.14 above). GP1 is set by bit 1 of the 12F683's TRISIO register and can be identified either as TRISIO1 or TRISIO.1.

2.17 You will soon learn that PICs are very 'picky'. You have to be very precise and tell them everything. The compiler checks most things and does not let many senseless commands through. You have to read the data sheets over and over again to find out the exact PIC requirements.

2.18 For initial prototyping you need a 'proto' board (schematic). I've simply used a piece of veroboard and mounted a 5v regulator with a plug for a 9v feed, an 8 pin IC socket, two LEDs, two trim pots, a servo lead and plug and the ICSP plug (programming interface). It is helpful if you can connect different peripherals to different pins on the PIC from time to time so do these via fly leads. A low current regulator is advisable (eg: 0.1A) to help prevent the PIC from drawing excessive current if you get things wrong. Once you are more familiar you should be able to design and build 'proper' circuit boards before writing the code which means you should not need proto boards for every project.

2.19 Understand True and False, 1 and 0... A condition that is 'true' is often considered to be '1' and '0' if 'false'. For instance, the 'while' statement executes the stuff between its curly brackets {} if the condition in plain brackets () is true. It checks this condition each time it loops and if still true executes everything again. So while(1) will loop forever because the '1' is considered to be the same as 'true'. while(RX==0) will loop each time it checks that RX still has a value of 0 (ie: the condition is true even though there is no '1'). Should RX not be 0 when next checked, the condition would no longer be true and the stuff between {} would not be executed and the program would move on to whatever follows. Taking this a step further, while(RX==1) is the same as while(RX) and while(RX==0) the same as while(!RX). The statement while(i=0; i<2; i++) will loop twice because starting from '0' (i=0 part) and incrementing by one with every loop (i++ part), it will be true that 'i' is less than 2 (i<2 part) for two iterations (when i is 0 and 1).

2.20 That's it. Now work through the 'building blocks' above to see how it is done in practice.


3.1 Create a working folder on your C drive. You have to navigate to this in DOS so keep it short.

3.2 Put a copy of CC5X.exe, the device file (eg: 12F683.H), delay_ms.h and your program source file (eg: led_1.c) in same folder so that you have everything in one place.

3.3 Open the DOS/CMD prompt and navigate to chosen folder ('cd..' (enter) takes you up a level, 'cd c:\pic\led' (enter) takes you to the example folder).

3.4 'cc5x.exe led_1.c' (enter) runs the compiler

3.5 Make sure no errors. They will appear on the screen and usually try to identify the location of the error.


4.1 Plug programming interface into PC (not connected to PIC board yet)

4.2 Open Winpic software

4.3 Load hex file just generated (eg: led_1.hex)

4.4 Select the correct device (12F683) on Device Config tab (1st time only)

4.5 Set the path to the MPlabs device definition file on the Options tab (probably C:\Program Files\Microchip\MPLAB IDE\Device) - 1st time only

4.6 Close and reopen Winpic now that these settings are in place (only necessary when you change the device type)

4.7 Load hex file again if necessary ('Control L' shortcut)

4.8 Only errors on Messages tab should be because there is no PIC yet

4.9 Connect proto board with PIC installed

4.10 Power up proto board (if not being powered by the programmer interface)

4.11 Click the 'Program device' icon

4.12 Check foot of the window or messages tab for errors. If there are some, repeat step 4.11 as another attempt often sorts things out. Sometimes you have to close and open WinPic to make it program correctly.

4.13 Power down PIC before disconnecting from programmer (if using a separate power supply)


The free version of CC5X is very nice but the free version of 'BoostC' from SourceBoost allows you to compile twice as much code and does not restrict optimisation. However, of greater importance is the fact that their licenced versions are much cheaper and they have a useful help forum. Some of my early observations converting are as follows:

5.1 Create a new 'Project'. Navigate to a sensible location to store files and enter a project name

5.2 Select the second 'empty source file' option if no C source file exists yet (new project). If a source file does exist already, select first 'empty' option

5.3 To add an existing file to a project, right-click over 'Workspace' window on the left and 'add file'. Double-click on the source file name to see it in the editor on the right. Find and Replace don't seem to work so you may still need Crimson Editor.

5.4 NB NB NB - Select your PIC device from 'Settings/Target' menu

5.5 Click on 'Browse' at the bottom of the Workspace window. This reveals the contents of the 'include' file for your device. Double-click on any item to open the actual file in the right-hand window.

5.6 Write your program. 'Ctrl S' to save. F7 to Build (including compile)

5.7 Double-click on errors in lower 'Output' window to find the row in your code. The 'Missing semicolon' error is usually meaningless - to find what is wrong you often have to look at everything related to the line indicated (ie: not only the line itself but anything that could be implicated such as variables, port configurations, etc). Incomplete comment tags are an easy error.

5.8 BoostC vs CC5X differences:
* The names of control registers (eg: trisio, porta, etc) are all lower case in BoostC and upper case in CC5X. The names available appear in the 'Variables' section when following 5.5 above.
* Individual bits in control registers often have their own names (eg: GIE at bit 7 of INTCON). CC5X allows you to use GIE in your program; BoostC requires you to use intcon.7.
* BoostC does not allow the dots in binary numbers (2.2 above).
* BoostC seems to use 'eedata' not 'eedat' for EEPROM writing.
* BoostC interrupts are much simpler to define as it sorts out the correct location itself and saves registers as appropriate.
* Boostc 'Delay' functions are 'included' automatically by BoostC if called. However, parameters are only 8 bit (0-255) instead of 16.
* BoostC has a LOBYTE(dst, src) command instead of .low8 to extract the least significant 8 bits (HIBYTE... vs .high8).
* BoostC 'pre-processor' section is set in a different way.
* Other than these, the code can be largely the same. An example using both compilers is here.

Top of page
Click on the links below for other pages.

Home Art of the Possible Absence of Matter Links Updates Email