As a principle, program written in C-language can be in any form, even in one line, because the compiler assumes only the following of syntax rules. However, it is advisable to take care of program coding style for clearness and simplicity. Typical structure of a C-language program:

/* Include header files */ #include <avr/io.h> #include <stdio.h> /* Makro declarations */ #define PI 3.141 /* Data type definitions */ typedef struct { int a, b; } element; /* Global variables */ element e; /* Functions */ int main(void) { // Local variables int x; // Program code printf("Tere maailm!\n"); }

Programmer can write random text into program code for notes and explanations that is no compiled. Comments can also be used for temporally excluding some parts of code from compiling. Examples of two commenting methods:

// Line comment is on one line. // Text after two slash signs is considered as comment. /* Block comment can be used to include more than one line. The beginning and the end of a comment is assigned with slash and asterisk signs. */

C-language basic data types:

Type | Minimum | Maximum | Bits | Bytes |
---|---|---|---|---|

(signed) char | -128 | 127 | 8 | 1 |

unsigned char | 0 | 255 | 8 | 1 |

(signed) short | -32768 | 32767 | 16 | 2 |

unsigned short | 0 | 65535 | 16 | 2 |

(signed) long | -2147483648 | 2147483647 | 32 | 4 |

unsigned long | 0 | 4294967295 | 32 | 4 |

float | -3.4^{38} | 3.4^{38} | 32 | 4 |

double | -1.7^{308} | 1.7^{308} | 64 | 8 |

The word “signed” in brackets is not necessary to use because data types are bipolar by default.

AVR microcontroller has *int* = *short*

PC has *int* = *long*

There is no special string data type in C-language. Instead *char* type arrays (will be covered later) and ASCII alphabet is used where every char has its own queue number.

Program can use defined type of memory slots - variables. Variable names can include latin aplhabet characters, numbers and underdashes. Beginning with a number is not allowed. When declarations to variables are being made, data type is written in front of it. Value is given to variable by using equal sign (. Example about using variables:

// char type variable c declaration char c; // Value is given to variable c. c = 65; c = 'A'; // A has in ASCII character map also value 65 // int type variable i20 declaration and initialization int i20 = 55; // Declaration of several unsigned short type variables unsigned short x, y, test_variable;

Constants are declarated in the same way as variables, exept *const* keyword is added in front of data type. Constants are not changeable during program work. Example about using them:

// int type constant declaration const int x_factor = 100;

Basic data types can be arranged into structures by using *struct* keyword. Structure is a combined data type. Type is declarated with *typedef* keyword. Example about structures by creating and using data type:

// Declaration of a new data type "point" typedef struct { // x and y coordinates and color code int x, y; char color; } point; // declaration of a variable as data type of point point p; // Assigning values for point variable p.x = 3; p.y = 14;

Data types can be arranged into arrays. Array can have more than one dimensions (table, cube etc). Example about using one- and two-dimensional arrays:

// Declaration of one- and two-dimensional arrays char text[3]; int table[10][10]; // Creating a string from char array text[0] = 'H'; // Char text[1] = 'i'; // Char text[2] = 0; // Text terminator (0 B) // Assigning new value for one element. table[4][3] = 1;

Variables, constants and value returning functions can be used for composing operations. The result of and operation can be assigned to a variable, it can be used as a function parameter and in different control structures.

C-language supported artithmetic operations are addition (+), subtraction (-), multiplication (*), division (/) and modulo (%). Some examples about using operators:

int x, y; // Modulo, multiplication and assigning value // x gets value of 9 x = (13 % 5) * 3; // Adding-assigning operator // x gets value of 14 x += 5; // Quick style method for subtracting 1 // x gets value of 13 x--;

Logical operators are negation NOT (!), logic multiplication AND (&&) and logic addition OR (||). Example about using them:

bool a, b, c; // Initialization a = true; b = false; // Negation // c will get a value of false because a is true c = !a; // Logic multiplication // c will get a value of false because one of the operators is false c = a && b; // Logic addition // c will get a value of true because one of the operators is true c = a || b;

**NB!** *bool* data type in C-language is actually missing and instead integers are used where 0 marks false and every other value marks true. For example, in HomeLab library *bool* is defined as *unsigned char*. Constant *true* marks a value of 1 and *false* a value of 0.

Logical values are a result of comparison of variable values. Equality operators are equal to (=, not equal to (!, greater than (>), greater than or equal to (>, less than (<) and less than or equal to (⇐). Exaple about using them:

int x = 10, y = 1; // greater than operation which is true // brackets around the operation are only for clarity bool b = (5 > 4); // Not equal to operation // The result is false b = (4 != 4); // Arithmetic, equality and logic operations alltogether // b is false because the first operator of logic multiplication is false b = (x + 4 > 15) && (y < 4);

Bit operations are for data manipulation in binary numeral system. These can be applied only to integer type data. Bit operations are quite similar to logic operations but differ from them because operation is carried out with every single bit not the whole number. Bit operations in C-language are inversion (~), conjunction (&), disjunction (|), antivalency (^), left shift («) and right shift (»).

// Declaration of unsigned 8 bit char type variable // Variable value is 5 in decimal system, 101 in binary system unsigned char c = 5; // Disjunction of c with a digit 2 (010 in binary) // c value will become 7 (111 in binary) c = c | 2; // Bit left shift by 2 // c value will become 28 (11100 in binary) c = c << 2;

Bit operations are essential when using the registers of microcontroller. These are described in AVR register chapter.

Functions are part of a program that can be called by its name. Function can include parameters as input and can return one output. If the function is not returning a parameter, it has type *void*. If the function has no parameters as its input, in older C-language compilers *void* must also be written besides parameter declaration. Example about addition function and a function without return:

// Declaration of 2 int type parameter function // The function returns int type value int sum(int a, int b) { // Addition of 2 variables and returning of their sum return a + b; } // Function without parameters and no return output void power_off(void) { }

To use a function, it must be called. It is required that a function is declared before call. Example about calling addition function:

int x; int y = 3; // Calling an addition function // Parameetriteks on muutuja ja konstandi väärtus // The parameters are variable and constant x = sum(y, 5); // The call of a power off function // No parameters power_off();

The execution of a C-language program is started from *main* function which makes it compulsory function.

Conditional statements enable to execute or skip program code based on based on logic and relational operations. Conditional statement uses a keyword *if*. Example about using it:

// Statement is true and operation x = 5 will be executed // because 2 + 1 is higher than 2 if ((2 + 1) > 2) x = 5; // If x equals 5 and y equals 3 then the following code will be executed if ((x == 5) && (y == 3)) { // Random action y = 4; my_function(); }

*If* statement can be longer and include code which will be executed in case the statement is false. For this, after *if* statement, *else* statement can be used. Example:

// Is x equal with 5 ? if (x == 5) { // Random action z = 3; } // If this is false then x might be equal with 6 else if (x == 6) { // Random action q = 3; } // If x was not 5 nor 6 ... else { // Random action y = 0; }

When required to compare operations and variables with many different values, it is reasonable to use comparison statement with *switch* keyword. Example about using this:

int y; // Switch statement for comparing y switch (y) { // is y equal to 1 ? case 1: // Random action function1(); break; // is y equal to 2 ? case 2: // Random action function2(); break; // All other cases default: // Random action functionX(); // break operation not needed, // because the comparison ends anyway }

Loops can be used for executing code several times.

Code marked with *while* keyword is executed until condition in brackets is true. Example:

int x = 0; // Loop will execute until x is smaller than 5 while (x < 5) { // x incrementation x++; }

*for* keyword loop is similar to *while* loop exept there are described operation executed before the loop and operation executed in the end of every loop cycle. Example:

int i, x = 0; // i is equal to 1 at the beginning of the loop. // Loop will be executed until i is smaller than 5. // i will be incremented in the end of every loop cycle. for (i = 0; i < 5; i++) { // x addition by 2 x += 2; } // here x value is 10

As and exception exit from *while* and *for* loops can be made with keyword *break*. To start the next loop cycle without executing the remaining code in loop, *continue* keyword can be used. For example:

int x = 0, y = 0; // Infinite loop because 1 is logic true while (1) { // Exit the the loop cycle if x becomes 100 if (x >= 100) break; // x incrementation to end loop at some time x++; // If x is 10 or less then the next cycle is started if (x <= 10) continue; // y incrementation y++; } // Here y value is 90

Text operations are needed for microcontrollers foremost for displaying characters and text on LCD.

*sprintf* function is similar to ordinary *printf* function commonly used in C-language. The difference is that the result of this function is loaded into variable not standard output.

return = sprintf(variable, parameter_text, parameters);

Example:

int r = sprintf(buffer, "%d pluss %d on %d", a, b, a+b);

It will load formated text into variable which is given from the function second to n parameter. *sprintf* will simplify composing more sophisticated statements. Easier is to use variables in text that will be replaced by values. Function returns the length of text loaded into variable. In case of error occurrence, negative value is returned.

Example:

sprintf(x, "%d. is first", 1); // the same result can be achieved also: x = "1. is first"; sprintf(x, "%s is %d years old", "Juku", 10); // the same result can be achieved also: x = "Juku is 10 years old";

%s and %d are in this case parameters that will be repalaced accordingly by variable values which are the last parameters to function. The number of parameters must be the same as variables. In the first example, the parameter was %d which was replaced by variable value 1. In the second example parameters were %s and %d which were replaced by variable values “Juku” and 10. It was strictly in this order because %s was waiting value in form of a text and %d value of a number. There are special variable descriptions for different data types:

Parameter | Description | Example |
---|---|---|

%c | Char | a |

%i or %d | Integer | 123 |

%f | Real number | 3,14 |

%s | Text | example |

%X | Hexadecimal number | 3F |

#include <stdio.h> int main () { char buffer [50]; int n, a=5, b=3; n=sprintf (buffer, "%d plus %d is %d", a, b, a+b); printf ("\"%s\" is %d digits long\n",buffer,n); return 0; }

Standard functions library (stdlib.h) includes functions to simplify different common operations and conversions.

Generating a random number is not so simple for AVR microcontroller.

At first the random number generator must be inputed with a number to be the basis of random number array generation. The array based on one number is always the same. To make the result more random, the function can be inputed with a values taken from free floating ADC.

Example:

srand(100); rand();

Example about generating a random number in range of 16:

#include <stdlib.h> int x; x=rand() % 16;

The more in-depth english description about C-language functions is in: