There are a number of PIC C complilers available on the web. As you look at each, you will see the the C language was mapped to the Pic hardware and instruction set in different ways. There is a trade off usually in holding true to the C language vs implementing desired features. This is necessary because:
Why use C.
I would estimate that developing and debugging a program in C is about 10 times
quicker than in assembly. Just having the branch instructions correct is worth
alot ( should that be branch carry clear or carry set?? ). And the Pic branch
instuctions are not easy if you are used to other micro programming. ( I want
a branch carry clear, so that is skip carry set?? ).
Usually with C, the program structure is easy to set up. No need to flow
chart. Just put a few function calls in main() and then code the functions to
do the real work.
Native 8 bit data
char data type is implemented. Arrays of char. Structures of char.
No divide and mult instructions.
The modulus, divide and multiply operators are not supported.
I really like modulus operations, but did you know:
You can implement buffers on a power of two in size and use masking
to implement the same thing.
char buf[16]; /* size must be a power of 2 */
/* instead of count = ( count + 2 ) % 16 - implies division */
count = ( count + 2 ) & 15; /* does the same thing */
Arrays are only single subscript.
Data initialization.
Normally this is a job done by the program loader. There is no loader
for the pic, so the data area is not initialized to all zero's ( nor to
any previously defined values ). The pic powers up with the data ram
in an unknown state.
eeprom data
This data area does retain its values between power cycles. I used
the extern keyword to denote eeprom locations.
extern char values[] = { 1, 2, 0x255}; /* eeprom data */
special instuctions
I tried to keep this area to a minimum. There are no psuedo functions as some
other C pic compilers implement. You can use assembly at anytime to
do something special.
#asm bsf PORTA,2 swapf PORTB,F #endasm
My 16f84.h file
This file defines all the hardware, so you can access any of the hardware
using the common standard names. I also provide calls to the main function and an
_interupt function.
The compiler considers any function beginning with '_' underscore character
as an interupt function and will generate a retfie at the end.
I also implemented a loop such that main is called over and over. Most if not
all pic programs will want to loop, and this is implemented in the header.
You will want to copy and edit the header for each program so as to provide the
correct fuses in the config.
The header also contains a very small run time consisting of a couple of shift
routines ( logical shifts as in C ) and the eeprom addressing routine.
Avoiding cumbersome code
The compiler will generate a message that the code should be simplified if ever
the generated code would require temporay storage of intermediate results. This
will be most evident when arrays are used as there is only one indirect register.
array[i] = array[i + 1]; /* this won't work */ /* you must provide your own cumbersome code */ temp = array[i + 1]; array[i] = temp;
b = c + 20; a = b + 4; /* you can instead say */ a = ( b = c + 20 ) + 4; /* this is how K & R did things */Sometimes the compiler will generate a logical instruction that appears bogus. This is to generate the status bits that are needed in logical expressions.
What about the form of expression: b+= 6;
Alot of people and books are going to tell you that b+= 6; is just
an alternate way of writing b = b + 6; and you can use either one.
That is not so
If you were to look at the PDP-11 architecture and
instuction set, you would see that the arithmetic and the logical instructions
have a form that maps to the shorthand notation. And the 16f84 pic has that
same type of instruction form. With form b+= 6; you are telling the
compiler that the destination of the assignment is also one of the source operands.
The PDP-11 used a logical expression, dest <-- dest + source , to denote these
instructions.
b += 6; /* compiles to two instructions */ b = b + 6; /* compiles to three instructions */ ; b += 6 ; movlw 6 addwf b,F ; b = b + 6 ; movf b,W addlw 6 movwf b
The compiler generates special loops when a do{ } while(--var) type of loop is specified.
I have never had much use for typedef and enum and the compiler does not recognize these keywords. Also, the #define is only of the simple form and substitution macros are not allowed.
mcpic.exe - the compiler mkpic.bat - a simple make file pic16f84.h - the required header file sample.c - empty C file with minimum required elementsTo install, create a directory(folder) named mcpic. Unzip the files to the new folder. You can include this folder in your PATH to make things easy, otherwise you will need to include the path in your command to compile. The mkpic.bat assumes you have the assembler set up in C:\mpasm directory. Feel free to edit the .bat and change things for your setup.