Embedded C and The PIC Micro Controller
Embedded C and The PIC Micro Controller
Real-World Interfacing
A good resource for help with the PIC programmed with the CCS C-compiler is
given at http://www.ccsinfo.com/forum/.
The PIC microcontroller comes in a wide range of variants. You can check them
out in data books that are in the lab, or at the MicroChip web site. A -controller
is distinguished from a -processor in that it has many capabilities useful for real-
world interfacing built into the chip. The PIC has a RISC-based Harvard
architecture with separate memory for data and program. The one we will be using
is the PIC16F873 (link to data sheet) It has an on-board RAM (Random Access
Memory), EPROM (Erasable Programmable Read Only Memory), an oscillator, a
couple of timers, and several Input/Output (I/O) pins, serial ports and 8 channel
A/D convertor (if you don’t know what all of those things are don’t worry; suffice
it to say there can be an impressive array of peripherals built into the chip).
However, the -controller is less computationally capable than most -processors
due to the fact that they are used for simple control applications rather than
spreadsheets and elaborate calculations. As an example, the PIC16F873 has 4096
words of memory for program, and only 192 bytes of RAM, and can only operate
with clocks up to 20 MHz on 8 bits of data (compared to megabytes of RAM,
Speeds of a GHZ or more and 32 or even 64 bits of data for many desktop
systems). It also has no facilities for floating point numbers... A pinout of the
PIC16F873 is shown below.
There are several pins that are used to power the device. Many of the other pins
have multiple uses depending on how the device is programmed.
This week, and the next, you will be using a -controller in the lab. These
laboratories will serve as a brief introduction to the processor and to programming
in C.
output_low(pin_C1);
output_high(pin_C1);
}
This program has many common features of C programs. The first line is a
comment that is ignored by the compiler. It is simply there to document what the
program code does. A comment is anything that occurs between a "/*" and the
subsequent "*/". The next line is a "directive". All directives begin with a "#" and
are used to convey information to the compiler. The directive in this program tells
the compiler to include a header file ("16F873.h") which is necessary when using
the microcontroller’s input and output capabilities. The next two directives tell it
how to configure the device, and how fast it goes. The next line tells the compiler
that this is the "main" program, and that everything between the opening brace, {,
and the matching closing brace, , constitutes the main program. The main program
itself is only two lines. The first line (not a comment) is a call to the
"output_low" function, which sets output pin pin_C1 low, and a call to
output_high, which sets it high. . Note that after every program statement there is
a semi-colon. This is very important.
Variables
Almost all programs will use variables which are simply units of information
stored in the computers memory. The standard C language has a wide variety of
variable types available, however the dialect we will be using is more restricted.
The version of C that we will be using has a quite unstandard set of variable types
that are suited to its architecture.
Again we have a fairly simple program that shows many different features of C.
Note the semicolon after every program statement. We declare 3 char’s, "i", "j" and
"k". A char is simply an 8 bit variable. You should use chars whenever possible
because the PIC is designed to work on data 8 bits at a time.
Numerical manipulations
C has a variety of built in operations for performing math. These are listed below
along with an example where a=0x03, and b=0x11:
Result
Name of Operand Symbol Example a=0x03
b=0x11
Addition + a+b 0x14
Subtraction - b-a 0x0E
Multiplication * a*b 0x33
Division / b/a 0x05
Modulus
Binary Operators (Two % b%a 0x02
(remainder)
Operands)
Bitwise and & b&a 0x01
Bitwise or | b|a 0x13
Bitwise xor ^ b^a 0x12
Shift right >> b>>a 0x02
Shift left << b<<a 0x88
increment ++ ++a 0x04
decrement -- --a 0x03
Unary Operators (One
Operand) negate - -a -0x03
logical
~ ~a 0xFC
complement
Logical Expressions
In addition ot manipulating numbers, C is also capable of handling logical
expressions. When using these expressions TRUE is taken to be anything that is
not zero, and FALSE is always equal to zero. Again, a=0x03, and b=0x11:
Result
Name of Operand Symbol Example a=0x03
b=0x11
Greater than > a>b FALSE
Less than < a<b TRUE
Equal == a==b FALSE
Greater than or
>= a>=b FALSE
Binary Operators equal
Less than or equal <= a<=b TRUE
Not equal != a!=b TRUE
Logical AND && a&&b TRUE
Logical OR || a||b TRUE
Unary operators
Logical complement ! !a FALSE
(one operand)
Digital Output
There are several functions that are used for output from the PIC. A full listing is
in the PCB manual. Four commonly used functions are:
Output_high(pin)
Sets the specified pin to a logic 1 (about 5 volts).
Output_low(pin)
Sets the specified pin to a logic 0 (about 0 volts)
Output_float(pin)
Sets the specified pin to a high-impedance (or tri-state) state.
In this state it is as if the pin has no connections to the chip.
Current can neither go in or out of the pin.
Output_bit(pin, value)
This function sets the specified pin to the specified value
(which must be 0 or 1).
Digital Input
There is only one input function you will need for the PIC.
Input(pin)
Reads the value on a specified pin. The value is returned in a
short int. A proper use of the function would be something
like:
while( !input(pin_B0)) { ... }
You specify that IO is to take place through the debugger by properly defining
serial connections (usually in your codes header file):
#use rs232(DEBUGGER)
You can then print to the monitor window by using "putc()" which sends a
character to the monitor window, "puts()" which sends a string, or "printf()" which
sends a formatted string. The "printf()" command is most useful, but also the most
complicated (and takes the most memory).
Printing Examples
The special form %b is used to format the printing of an integer in binary format.
Only the low byte of the number is printed.
Example 5: Printing a floating point number. The following statement prints the
value of the floating point variable n as a floating point number.
printf("Value is %f\n", n);
The special form %f is used to format the printing of floating point number.
%d
Type: int Description: decimal number
%x
Type: int Description: hexadecimal number
%b
Type: int Description: low byte as binary number
%c
Type: int Description: low byte as ASCII character
%f
Type: float Description: floating point number
%s
Type: char array Description: char array (string)
Format Command Data Type Description
%d int decimal number
%x int hexadecimal number
%b int low byte as binary number
%c int low byte as ASCII character
%f float floating point number
%s char array char array (string)
Your circuit has the pushbutton switch connected to RB0, and the LED's to pins
RC0 through RC7.
Input
Unfortunately, you can only receive input from the keyboard one character at a
time using the getc() command. Be aware:
As an example, the following code gets the ascii value in k, converts to a number,
and prints the number.
k=getc(); %Get ascii value of
keyboard input.
k=k-'0'; %Subtract value of '0'
to convert to number.
printf(" ... k=%d\n",k); %print the number.
Control of Flow
What you have learned up to this point has been useful but is of limited utility
because it does not allow for decision making capabilities by the computer. C has a
variety of mechanisms to control the flow of a program. These are listed below:
If the logical expression is true then evaluate the statements between the braces.
The following code sets RC1 if a is even.
if ((a%2) == 0) {
Output_high(pin_C1);
}
If the logical expression is true then evaluate the "if" statements between the
braces, otherwise execute the "else" statements. The following code decides if a
number if is even or odd.
if ((a%2) == 0) {
Output_high(pin_C1);
}
else {
Output_low(pin_C1);
}
While the logical expression is true, the statments (of which there is an arbitrary
number) between the braces is executed. The following code cycles through the
even numbers from 0 to 9 (the variables must have been declared elsewhere in the
program).
a=0;
while (a<10) {
...statements...
a=a+2;
}
Set the initial condition, then while the logical expression is true execute the
statement between the braces while changing the loop counter as specified once at
the end of each loop. This code segment is functionally equivalent to the one for
the "while" loop.
for (a=0; a<10; a=a+2) {
...statements...
}
Functions
Often a series of instruction must be repeated over and over again. Instead of
repeating the same operations repetitively it is useful to use a function that
performs the repetitive operations. For instance to set a value on RC1 and then read
from RB0 and set RC0 to that value, and returning the value of RB0 you might use
a function called "RB0toRC0". (Note: this program isn't meant to be particularly
useful, but to introduce the syntax for function declaration, and use).
/*simpleFunc.c -- to demonstrate function calls*/
#INCLUDE <16F873.h>
#USE DELAY (CLOCK=4000000)
short int RB0toRC0(RC1val)
short int RC1val;
{
Output_bit(pin_C1, RC1val); /*Set RC1 to the specified value*/
if (input(pin_B0)) { /*Read RB0*/
Output_high(pin_C0); /*If RB0 is high, RC0 set high*/
}
else {
Output_low(pin_C0); /*else set RC0 low*/
}
return(input(pin_B0)); /*Return RB0*/
}
void main() {
short int b;
b=RB0toRC0(1);
b=RB0toRC0(0);
}
This program introduces some new constructs. The most obvious is the function
"RB0toRC0" which is at the top. The first line of the function declares that the
function returns a short int, and has one argument. The type of the argument is
given before the function's opening brace. The body of the function (between the
braces) outputs a value to RC1, and reads from RB0 and echos to RC1. The last
line tells that compiler to return the value of RB0 to the calling function.
The function is called in the main program with different arguments. The first call
would set RC1 high, and return the current value of RB0 to the variable "b". The
next line would set RC1 low, and return the value of RB0 to the variable "b".
Wrapping up
You should now know enough to do some fairly simple things with the
microcontroller. This has been a very brief introduction to C and did not even
begin to touch the richness available with the language. If you would like to know
more look in the manuals in the lab, or some of the books in the library.