Programming Microcontrollers in C
Daniel D. AAiT
Contents
About C, why C…?
Variables and data types
Operators
Program control
Functions
Macros and the C preprocessor
Pointers and arrays
Structures
Common C programming pitfalls
Structured programming & program quality
1. Variables and data types
All programs work by manipulating some kind of
information:
Storage is provided in the MCU for these info. with a name
and data type description
The
The data types may vary depending on the compiler
implementation
e.g. int x : a variable of type integer named x
ANSI: 16-bits are allocated to store x (signed)
Note: Check ANSI compliance first, then consult compiler
documentation to adjust all data types accordingly
…Variables and data types
Common data types:
- Integers:
int (signed and unsigned) …….. binary
short (signed and unsigned)…… binary
char (signed or unsigned)………. ASCII
long (signed and unsigned)……. binary
- floating point:
float (single precision) …………… IEEE - 32-bit
double(double precision)………. IEEE - 64-bit
- Enumerated data types
Enumerations provide a convenient way to associate
constant values with names.
…Variables and data types
… It’s an alternative to #define with the advantage that the
values can be generated for you.
e.g.
enum day {Sun = 1, Mon, Tue, Wed, Thr, Fri, Sat};
automatically, Mon =2, Tue =3, etc.
enum fruit {orange =5, mango = 8, banana = 6};
Usage:
-if(day == Sun) weeks++;
-while(fruit != mango){searchMyFruit();}
2. Operators
Once variables are defined to be a given size and type,
some sort of operation should be done using them
This is done by using operators
I. Assignment operator (=), x=y; z = 8; …
- it can be stacked a=b=1; evaluated right to left
- this is possible: a= b + (c= ave(x));
A statement can be made of many expressions
II. Arithmetic and bitwise operators
- all the usual operations are supported (*, /, +, -, %)
- unary operators (++j, --j, j++, j--)
- bitwise operators (&, |, ^, <<, >>)
…Operators
I. Logical operators (the result is true or false)
<, <=, ==, >=, >, !=, &&, ||, ~ Operate only on integers
if(x != c && C>=2) … while (n || m)
Examples:
m = x% y; … m = x – y(x/y) … x, y integers
n = n >> 8; … n is shifted right 8 times (n >>= 8)
x = ~y … x is assigned to the bitwise NOT of y
let i=4 and j = 7
k = i++ + j; … k = 11, and i will be 5
K = i + --j; … j becomes 8 and k will be 12
…Operators
Operator precedence
- operator precedence works the same way as in C++
Type Casting
- if an operation is to be performed on more than one
type of variable, conversion may be necessary:
This is called casting (can be demotion or promotion)
e.g.
short x; Int y; long z;
x = 40;
y = (int) (x * 200); //8000 is more than short, so make it int
x = (short) z & 0xFF; //Take only the lowest 8 bits of z
3. Program Control
Program control (conditional execution, loops, …) is done
the same way as in C++
- conditional executions:
if – else
switch
single line conditional expression
x = ( exp1 ? exp2 : exp3); if(exp1) x=exp2; else x=exp3;
- Loops: do, do-while, and for
- program jumps: break, continue and goto
…Program Control (Examples)
switch(character) for(i; (i<4 && j<5); j+=2, i++)
{ { statements; }
case ‘A’:
if(value)
for(; ;) //forever also while(1)
goto end;
else
get_newVal(); for( ; y[i] = a[i] * x[i]; i++);
break;
case ‘B’:
do{
continue;
input1 = PORTB;
default:
}while(!input);
break;
}
max = (x1 > x2) ? x1 : x2;
4. Functions
Function definition and usage is same as in C++
return type name (arg1, arg2, …)
- Return type: variable, pointer or void
- Arguments: variables, arrays, pointers, structures or void
e.g.
int check_key(void)
long *get_samples(volatile short *port, int n)
void fclose(file *fp) // fp is a pointer to structure file
…Functions
Storage Class, privacy and scope
In addition to type, variables and functions have a property
called storage class:
The following are common storage classes:
auto: automatic variables stored on the stack
extern: external variables stored outside the current file
static: variables known only in the current module
register: temporary variables to be stored on registers
const: constants that will never get changed once defined
volatile: variables that can be changed by external process
NB: in most MCUs data defined as const will be stored in
program memory
…Functions
Function Prototypes
Although not in the original definition of the C language,
function prototypes have become a standard C compiler
feature.
A function prototype is a statement describing a particular
function. (must end with a semicolon)
e.g. extern int average(int *samples, long length);
-This prototype indicates that average (which is in another
module) takes two arguments and returns an integer.
5- Macros and C preprocessor
The C preprocessor is one of the most useful features of C
programming language.
The C preprocessor allows conditional compilation of
program segments.
Almost any text in a program can be replaced by user
defined symbolic expressions called aliases and macros
This feature of C can be used to make a program highly
structured and readable. One can also use macros and
preprocessors to write a program that is hard to decipher
…Macros and C preprocessor
#define NAME macro associate symbol NAME with macro definition
#define CUBE(x) (x) * (x) * (x)
#define VALVE PORTA.1
#include “file” copy named file to the current module from the work space
#include <file> copy named file from the standard c library
#if expression -> conditionally compile the following code if expression is true
#ifdef symbol -> conditionally compile the following code if symbol is defined
#ifndef symbol -> conditionally compile the following code if symbol is not defined
#else -> conditionally compile the following code if the associated #if is not true
#endif -> indicates the end of previous #if, #else, #ifdef, or #ifndef
#undef macro -> Undefine previously defined macro
6. Pointers and Arrays
Pointers are mainly used for three purposes:
1. To point to different data elements within an array
2. Dynamic memory allocation
3. To access different locations in a data structure
Special pointer operators
- the indirection operator (*) and the address of operator (&)
e.g. int i, *ptr;
i = 7; /* the variable i equals 7 (the location reserved for i holds the value 7) */
ptr = &i; /* ptr holds the address of i in memory */
*ptr = 11; /* the content of the address pointed by ptr is now 11 (i =11) */
ptr++; /* now ptr points to the address next to i */
…Pointers and Arrays
Dynamic memory allocation
C has a set of standard functions that allow the programmer to dynamically change
the type and size of variables and arrays of variables stored on memory.
The ff are common functions to allocate variables on heap
- malloc allocates bytes of storage
- calloc allocates items which may be any bytes long
- free removes a previously allocated item from heap
e.g.
int *ptr, *array;
ptr = (int *) malloc (sizeof(int));
array = (int *) calloc(25, sizeof(int));
free ((int *)array);
7. Structures
Structures allow defining a list of different variables in a group, while
arrays only allow defining elements with the same data type.
struct tag_name Struct fruit //definition
{ {
type1 element_name1; int color;
type2 element_name2; char *origion;
. float price;
. };
};
OR struct fruit orange; //declaration
typedef struct
{ //initializations
type1 element_name1; orange.color = ORANGE;
type2 element_name2; orange.price = 5.0;
. orange.origion = “Awash”;
.
} struct_name;
…Structures
The use of typedef
The keyword typedef can be used to define a shorthand form of any C
data type or another typedef
e.g.
typedef UI unsigned int; // in the program UI can be used instead of “unsigned int”
typedef struct now in the program, we can define variables as:
{ COMPLEX x, y, z;
float real; z. real = x.real + y.real;
float imag; z.imag = x.imag + y.imag;
} COMPLEX;
Pointer to a structure
We can define a pointer to a structure as: COMPLEX *k;
then we can use it as: k -> real = r * cos(theta);
k -> imag = r * sin (theta);
9. Structured Programming
Program quality is measured in terms of:
Reliability
Maintainability
Extensibility (modifiability)
Efficiency
Maintainability and extensibility depends on readability.
Write programs as if you are writing for somebody else
Always use an algorithm or method that gives you the optimum
compromise between readability, reliability and efficiency
…Structured Programming
Make your Program structural
- Start by including files, defining macros and preprocessors
-Followed by function prototypes
-Then the main function
keep the main function short and easy to understand
- finally define the functions used in the program
-If your program is longer than 100-300 lines divide it in to different
modules (moudule1.c module1.h, module2.c, module2.h,….)
- Keep all macro definition and function prototypes in *.h files
…Structured programming
motor.c
motor.h
Void run_motor (Motor *dc, bool dir)
#ifndef MOTOR_H {
#define MOTOR_H if(dir == CW)
dc -> direction = CW;
#include “device.h” dc -> speed = default;
else
#define MOTOR PORTC.5 //…..
#define CW 0 }
#define CCW 1
void run_motor(MOTOR *dc,bool dir); #include “motor.h” main.c
int stop_motor(MOTOR *dc);
Void main()
#endif {
if(start == pressed)
{
run_motor(&my_ motor, CW);
}
……….
}