Fads to Obsessions and Beyond...

Free domain for life, exceptional technical support, website transfer

Learning PIC Microcontrollers

The table below lists specific items, components and or parts in relation to use or interfacing with various PIC microcontrollers. The remainder of this page gives general background information about using and programming PIC microcontrollers.

Click column title to change sort order
PIC Part Number Component Description Data Sheet
PIC 16F876 Timer0 Module Demonstrate the use of the on-board Timer0 module PIC16F876
PIC 16F876 Capture/Compare/Pulse Width Modulation (CCP) Demonstrate the use of the on-board CCP module for pulse width modulation (PWM) signal generation PIC16F876
PIC 16F876 Analog Digital Converter (ADC) Demonstrate the use of the on-board ADC module for converting voltage to a digital quantity. PIC16F876
PIC 16F876 USART (RS232) Serial Comms Module Demonstrate the use of the on-board Universal Synchronous Asynchronous Receiver Transmitter (USART) module for serial I/O (RS232) with a PC. PIC16F876
PIC 18F248 In-Circuit Serial Programming (ICSP) - Flashing a LED Demonstrate the minimum circuit for a PIC microcontroller - In-Circuit Serial Programming (ICSP) and flashing a LED. PIC18F248
PIC 18F248 Software Button Debounce Demonstrate debounce of hardware buttons using a software approach with PIC microcontroller and interrupts. PIC18F248

PIC Microcontroller and C Programming

The following sections record some general information (and some specifics to CSS C compiler) about using and programming the PIC microcontroller. This is rather an 'eclectic' grouping of information, and more represents areas of difficulty in understanding I had over time, rather than an orderly approach to learning the PIC microcontroller and or C programming.


Bit-masking is a programming/coding technique to selectively modify individual bits within a discrete 'chunk' of RAM or whatever (e.g. within a byte or bytes that are the locations of 'variables' or similar information) generally without affecting other bits from within the same 'chunk' (1). Remember, 'setting' a bit means that bit will have a value of '1', and 're-setting' a bit means a value of '0'. Eight 'bits' to a 'byte' etc.


To set a bit, use the OR operator, which is denoted by the | symbol. To set a bit, a memory location/variable is OR with a bit number, and the corresponding bit number in the memory location will be set (i.e. equal 1).

For example, there is a memory location called REGISTER, by performing the operation

    REGISTER = REGISTER | 0x80; 
    REGISTER |= 0x80; //same as previous line - 'short hand' way

This would would cause bit number 7 within the variable REGISTER to be 'set' (i.e. have a value of 1). If REGISTER had the value of zero before the operation (i.e. binary 00000000), after the operation the value of REGISTER would be binary 10000000 (i.e. decimanl 255).


To reset a bit, instead of using OR, the AND logical statement is used (the & symbol is used when writing the actual instructions). Again, for example, there is a memory location called REGISTER, by performing the operation

    REGISTER = REGISTER & 0x7F;     //0x7F = 0b01111111 = decimal 127
    //the next instruction reset's bit 7 as-well
    REGISTER = REGISTER & ~(0x80);  //0x80 = 0b10000000 = decimal 128

The use of the tilde '~', which is the negation or 'not' operator, is perhaps easier in the above examples.

Bit checking

Suppose you want to wait for a register's bit#7 to set or reset:

    while(!(REG & (1 << 7)));   //waiting until bit 7 is set
    while(REG & (1 << 7) != 0); //waiting until bit 7 is reset

Clock Oscillator and Instruction Cycle

The 'clock' frequency or crystal frequency and instruction cycle time can be a little confusing when first coming to grips with using micrcontrollers. At the most basic view, the operation of a micrcontroller (PIC, ARM, etc) is just a succession of instructions, each dependent on the previous instruction and whatever inputs from peripherals etc. Therefore, it is necessary to have a 'clock' signal to coordinate these instructions.

The overall speed of a microcontroller is absolutely dependent on this clock frequency. This clock frequency provides the timing for the CPU, but also for various counters and timers that in turn enable functions such as communications, ADC etc. The higher the clock frequency generally the higher the power consumption.

The microcontoller performs 'instructions' in succession ('coordinated' by the clock frequency), but each 'instruction' requires sub-steps (due to the way micrcontrollers actually physically operate at the circuit/transistor level). That is way the 'main' clock frequency (e.g with a PIC circuit, this is the 'crystal' frequency) is automatically sub-divided by the micrcontroller into a fixed lower frequency signal. This lower frequency signal becomes the 'machine cycle' or 'instruction cycle' that is actually the fundamental unit of action that a microcontroller can actually perform a 'physical' action (eg like loading a memory location etc). In the case of PIC microcontrollers, this is called the instruction cycle. In PIC 16 microcontrollers the 'crystal' frequency is divided by 4 to produce the instruction cycle time.

Clock Frequency ('crystal' frequency) Instruction Cycle
Frequency Period
20 MHz 5 MHz 200 ns
10 MHz 2.5 MHz 400 ns
4 MHz 1 MHz 1 us
32.768 kHz 8.192 kHz 122.1 us

Pointer Variables in C/Arithmetic

Memory usage in microcontrollers is very important, as RAM is generally very limited (particularly in the "usual" PIC parts used by hobbyists). Pointers are the way in the C programming language of directly working with individual memory locations, and therefore are important to understand for utilising microcontrollers efficiently.`The "why" of using pointers in C is covered succinctly in (2). Whereas, "what" are pointers in C is explained well in (3). The following are my notes regarding pointers in C from these references, and some examples/practice using actual CCS C compiler code on a PIC18F248 (output via RS232 to PC serial terminal programme - see USART (RS232) Serial Comms Module for circuit and details).

PIC microcontroller RAM is a series of sequential locations, each with a numeric address starting at zero, that can store an 8-bit data item. Depending upon the exact PIC part in question, not all the RAM is usable as there may be special function registers taking up RAM.

A "variable" in C is just a "label" that is attached to a particular memory location, i.e., a descriptive label (to help the programmer) assigned to an address in RAM (and also has a specific type which tells the compiler the amount of RAM required). Such "normal" variables then store data at the particular RAM locations which represent integers (8-bit, 16-bit, 32-bit), floating-point, character (ASCII code) etc.

A "pointer" in C is "just" another variable, but a pointer variable stores the RAM address of another variable (not data that represents an interger or floating-point number etc).

A pointer variable is declared by giving a type (int, float, char etc) as for any other variable, but preceding the name of the pointer variable with an asterisk * which is called the indirection or dereferencing operator.

To get the RAM address of variable, which can then be stored in a pointer variable, the address operator (amperand &) is used.

The following CCS C code demonstrates the use of a pointer variable, with the output shown in the following figure:

void main() {
   int8 myIntVar; 
   char myArray[] = "hello";
   int8 *myIntPtr;   //a pointer to a int variable
   char *myArrayPtr; //a pointer to a char variable
   myIntVar=99;          //store the value 99 in myIntVar
   myIntPtr = &myIntVar; //store the RAM address of myIntVar
   myArrayPtr = myArray; //store the RAM address of the start of myArray
   printf("  value of myIntVar = %u\n\r",myIntVar);
   printf("address of myIntVar = 0x%x\n\r",&myIntVar); //print as hex value 
   printf("  value of myIntPtr = %Lu\n\r",myIntPtr);
   printf("address of myIntPtr = 0x%x\n\r",&myIntPtr); //print as hex value

C Pointers Diagram

The previous figure shows the contents of the file main.sym which the CCS C compiler produces showing the RAM addresses of the various variables used in the program. This clearly shows how a pointer variable contains the RAM address of another variable.

The unary operator * (i.e., the indirection operator) other than being used to define a pointer variable, is also used to return the value at the indicated memory location. It is not a direct memory access but rather an indirect access (hence the term indirection operator). So in the previous example code, if the statement prinf("value =%u\n\r",*myIntPtr); was included at the end, the output would have included the line value=99.

Serial Peripheral Interface (SPI) Modes

The Serial Peripheral Interface (SPI) bus is a synchronous serial communication interface specification used for short distance communication, primarily in embedded systems. The interface was developed by Motorola and has become a de facto standard.

The following table is useful for determining SPI mode parameters.

SPI Mode Motorola Microchip CCS Clock Line Idle Data Clocked IN
0 0 0 0 1 SPI_L_TO_H | SPI_XMIT_L_TO_H Low L to H
1 0 1 0 0 SPI_L_TO_H Low H to L
2 1 0 1 1 SPI_H_TO_L High H to L
3 1 1 1 0 SPI_H_TO_L | SPI_XMIT_L_TO_H High L to H



No comments yet.

Add Comment/Question

Only Logged-In Members can add comments

"If we could sell our experiences for what they cost us, we'd all be millionaires".

Please donate any amount to help with hosting this web site.

If you subscribe (only $2/annum) you can view the site without advertisements and get emails abouts updates etc.