C Programming Notes

 

Reading: Internal representations of numbers (signed, unsigned, floating point, etc)  H&H 8.03, 10.23

C is an excellent programming language to use for programming microcontrollers such as the HC11 or HC12.  It's level is such that you can build complex and powerful programs fairly quickly, but you also can have control over the lowest level functions of the microcontroller. 

C References:    The Art and Science of C, Roberts   (A good book for people new to the language)
                         The C Programming Language, Kernighan and Ritchie (Great reference book, written by the guys who wrote C)

 

What follows are some tips for having an elegant program.  Good programming style will save you time in the long run by having programs that are easy for others to understand, easy to modify, and easy to debug.

Have a plan -  Writing code without designing it first is like building a house without plans.  It will probably be ugly, troublesome, and take longer to get working than the combined proper process of design + implementation.  Design can be whatever method works for you: flow charts, pseudocode, etc.  Always check the limits of your code - if it works at the extremes, it will probably work inbetween them.

Comments - You can never have too many comments.   Even if the purpose of a line of code looks obvious, it won't when you come back to it a month later.  Add comments as you write your code.  Not only will others be able to understand your code, but it will help you too.

#defines - You shouldn't have any magic numbers sprinkled throughout your code.  All constants should be defined at the top of the file with #define statements.  They should have names that reflect the purpose of the number.   This will also make it easier to adjust these constants if you only have to change one #define statement instead of 20 instances throughout the program.  example:
#define PROPORTIONAL_GAIN  42

Functions - When you design your code, the job on hand should naturally decompose into a number of basic functions (possibly hierarchical).  These functions may get invoked from various parts of the program at various times , or perhaps only once.  Either way, the function performs a clear, well defined task.  The function also has well defined inputs and outputs.  When implementing the design, implement theses specific tasks as C functions.  This way, you can write a little segment of code to test each function before putting them all together.  It's much easier to debug 10 functions with 10 lines of code each than one function of 100 lines.

Specific to Microcontrollers - Microcontrollers are small and have limited resouces.  They don't have much RAM (on the order of 1K - compare to 64 Megabytes for a typical desktop, 1:64000), program space is limited, and they run about 100 times slower (in terms of MHz) than desktops.  So, to get the most bang for your buck, think small when designing code.  If a number only goes between 0 and 100, declare it as a char (0-255).  This will save 8 bits over an unnecessary int declaration, as well as making arithmetic with this variable execute faster. 
    Being able to print to the screen is invaluable.  printf() is the common way of doing this, but unfortunately this is a rather large function that can slow down your code (and the downloading of your code) significantly.  Last year, by inserting printf() statments in our code, we threw off the timing of our control loop so that a previously stable vehicle could no longer follow the track.  puts() and putc() are two functions which can be used similarly for debugging but which run much faster.