This lesson is the second in the Energy Micro University series. It aims to give a brief overview over the syntax and basic concepts of programming in C. The goal is to be able to use C when programming microcontrollers.
1 An Example
1.1 A short microcontroller program
The following code example turns on the USER LED on a STK and makes it stay turned on. It is a very simple example, but shows some general syntax which will be explained in this lesson. Comments are
written between /* and */.
Example 1.1. A short microcontroller programming example
1.2 Detailed code comments
Line 1-4: Here are the included files for this example. They are files in the emlib which includes configuration of the different peripherals, i.e. variable declarations, variable initializations, function prototypes and function definitions.
Line 6: Here starts the main function where the program begins its execution. The main function is written between two curly brackets (Line 7 and Line 35).
Line 10: This is a variable declaration of data type 8 bit unsigned integer, named pin_number. The variable is initialized to 2.
Line 13: This is a function call to a function defined in one of the included files. Notice the semicolon after a statement.
Line 18: Another function call. This function has two input values. The variable cmuClock_GPIO is declared and initialized in one of the included files.
Line 23: Here starts the register operations to configure the LED (pin 2 on the microchip) to be able to light. This is a built in function in the emlib library. This function sets the mode for the GIPO pin, i.e. sets the port to gpioPortE and the pin to 2. The third inputparameter sets the pin mode to push-pull output and the last parameter is set to 1. This makes the LED light. Line 25-28: A while loop that continues whenever the input is 1 (or true). In this case the input is set to 1 and it does never change, which makes this an infinite loop. The program will never reach the end of the main function.
2.1 Data Types
C has several data types that is used to define different variables. When defining a variable, the data type will assign storage in the memory. The different data types are:
• int: defines integer numbers
• char: defines characters
• float: defines floating point numbers
• double: defines large floating point numbers
• bool: defines a logical data type that have two possible values, ie true and false
• enum: defines a list of named integer constants
It is possible to specify the size of an integer by writing intN_t, where N is the number of bits you need. Further on, the data types can be modified into signed or unsigned data types, where signed can take both positive and negative values and unsigned can take only non-negative values. When choosing unsigned data types you can allow greater range of positive values. Table 2.1 shows some of the common data types and their ranges.
Table 2.1. Data Types
The two data types float and double are not available in the hardware of most microcontrollers, and if they are to be used in calculations it must be done in software. Thus, they are usually not used when programming microcontrollers.
2.2 Declaration and initialization
The declaration of a variable consists of giving the variable a name and to assign it a data type. Initializing the variable means to assign it a start value. Semicolon is used to end a statement. Comments are written between /* and */
Example 2.1. Declaring and initializing a variable
float length; /* declares the variable “length”
as a floating number */
length = 20.3; /* initialize “length” by giving
it the value 20.3 */
2.3 Blocks and scopes
A block is the content of code inside two curly brackets. Blocks can be nested, i.e. there can be blocks inside blocks. A scope defines the accessibility of variables from different parts of the code. Within a block variables that are declared in the same block or an enclosing block are available.
Example 2.2. An example of accessibility of variables in nested blocks
Note that the variables c and d declared in the inner block of the code snippet in Example 2.2 only are available within that block. When leaving this block, the two variables do not longer exist. The d declared in the outer block is totally independent of the d declared in the inner block.
2.4 Global variables
A global variable is available in every scope of a program. When a variable is frequently used, declaring a global variable will simplify the code. However, it can cause problems that the variable accidentally can be changed anywhere in the code. Global variables can also make the code hard to read and understand, and are generally not advised.
2.5 External variables
An external variable is a variable defined outside any block. When declaring a so called global variable, it is restricted to the single file it is declared in, and not available in other files of a larger program. In C t is possible to make the variable available in another file by declaring it again using the keyword extern.
Example 2.3. External variables
2.6 Static variables
A static variable is a variable that has been allocated statically. This means that the memory allocated for this variable is allocated for the whole program run, unlike local variables where the memory is deallocated once we exit the scope. In C the keyword static has an additional meaning. When declaring a variable as static, it is only available within the scope, and not across files. The two different explanations of definitions of a static variable are independent of each other.
Example 2.4. An example of declaring a static variable.
2.7 Constant variables
A constant variable is a read only variable, i.e. once it is declared it can not be changed. It can be used in the same way as any other variable. The syntax for declaring a constant variable is to add the keyword const before the data type.
Example 2.5. An example of declaring a const variable.
An enum defines a set of named integer identifiers. By declaring an enum set, the names will be numerated from 0 and upwards by default, unless you specify the numbers you want. Enum are useful because it can be easier holding track of words than numbers.
Example 2.6. An example of defining an enum
An array is a collection of variables of the same type that might be one dimensional or multi dimensional. An array can be of fixed or dynamic size. The size of a static array is declared from the beginning, and can not be changed during the program. On the other hand, the size of a dynamic array is flexible and can be changed. 2.9.1 One dimensional arrays and C stringsWhen declaring an array you have to specify the data type and size:
Example 2.7. Declaring and initializing an one dimensional array
When declaring an array you have to specify the data type and size:
A C string is an array of data type char terminated by the null character ”. When initializing a C string you put the text between two double quotes.
Example 2.8. C string
2.9.2 Multidimensional arrays
There are no restrictions of how many dimensions an array can have. Two dimensional array are common when expressing tables or matrices. When declaring a multi dimensional array the number of paired square brackets decide the dimension of the array.
Example 2.9. Declaring a 3 dimensional array
A struct is a collection of variables into a single object. Unlike arrays, structs can have variables of different data types.
Example 2.10. Defining a struct
A struct is a variable type in the same way as an int or a char. Struct variables can be put into arrays, or even be a member variable of a struct itself. This is called nested structs.
Sometimes it can be useful to give a new name to an already existing type to for example clarify what it is used for. An example could be a float variable time. One might want to specify the type to seconds (sec). The usual way to declare the variable time would be:
By using typedef you could declare the variable time as follows:
typedef float sec;
sec time; /*declares a variable time of type sec */
Typedef is also used to simplify the declaration of a struct variable. One can omit the word struct when declaring a variable by writing:
data a; /* declares a new variable of type data */
2.12 Volatile variables
When adding the keyword volatile in front of a variable declaration, it tells the compiler that the variable may change at any time, even though it does not look so in the code. A variable can be changed in the hardware, and without being told, the compiler will not necessarily check this. Thus, a variable should be declared volatile if it could change unexpectedly to tell the compiler to deal with this correctly. This is common when it comes to programming microcontrollers, especially when dealing with interrupts which will be explained in detail in lesson 4.
A pointer is a variable that contains a memory address. When declaring a variable as in Chapter 2 you allocate memory depending on the data type, see Table 2.1. A pointer points to the place in the memory where the variable is stored. The syntax of a pointer is shown in the example below:
Example 3.1. An example of a pointer
When you have declared a pointer you can set a value to the variable the pointer is pointing to. To access this value you have to dereference the pointer by using * again.
Example 3.2. Dereference of a pointer
3.2 Constant pointers
A constant pointer is a constant memory address. The pointer can not be changed to point to other places in the memory, but the variable it is pointing to can be changed.
There are different ways to declare constant pointers as shown in the following example:
Example 3.3. Different types of constant pointers
3.3 Pointers and structs
If you have a pointer, a_ptr, to a struct variable, for example the struct defined in Section 2.10, and you want to access and set the member variables, you use the following syntax:
Example 3.4. Pointer to a struct
3.4 Pointers and arrays
You can define a pointer pointing to the first element of an array. By use of pointer arithmetic you can go to anywhere in the array:
pointer = &array;
Now: *(pointer + i) = array[i]. Since the array is declared to contain the data type int32_t
the increment i jumps 8 byte automatically. You can make multidimensional arrays by making an array of pointers pointing to new arrays. These arrays may have different length.
Figure 3.1. Showing how to make a two dimensional array using pointers.
Another way of making a multidimensional array is to allocate memory for all the elements and calculate the index.
Example 3.5. Allocates memory for a m*n two dimensional array.
int32_t *a = (int32_t) malloc(sizeof(int32_t)*m*n);
The indices are calculated as follows:
a[i][j] = a[m*j +i]
Energy Micro University is a program developed by Energy Micro to encourage learning and to help institutions develop their own programs for teaching microcontroller development. To download learning materials in pdf, please click here: Energy Micro University Program
For technical questions about this project, please use our support forum.