Anda di halaman 1dari 143

ImperiaEmbedded Systems

Handout

Embedded Systems

WELCOME to the WORLD of C


C is a programming language of many different dialects, similar to the way that each spoken language has many different dialects. In C, dialects don't exist because the speakers live in the North or South. Instead, they're there because there are many different compilers that support slightly different features. There are several common compilers: in particular, Borland C++, Microsoft C++, and GNU C. There are also many front-end environments for the different compilers--the most common is DevC++ around GNU's G++ compiler. Some, such as GCC, are free, while others are not. Please see the compiler listing for more information on how to get a compiler and set it up. You should note that if you are programming in C on a C++ compiler, then you will want to make sure that your compiler attempts to compile C instead of C++ to avoid small compatability issues. Each of the compilers available is slightly different. Each one should support the ANSI standard C functions, but each compiler will also have nonstandard functions (these functions are similar to slang spoken in different parts of a country). Sometimes the use of nonstandard functions will cause problems when you attempt to compile source code (the actual C code written by a programmer and saved as a text file) with a different compiler. The sessions use ANSI standard C and should not suffer from this problem; fortunately, since C has been around for quite a while, there shouldn't be too many compatability issues except when your compiler tries to create C++ code. If you don't yet have a compiler, I strongly recommend finding one now. A simple compiler is sufficient for our use, but make sure that you do get one in order to get the most from these sessions.

Lets begin with First C Program


Every full C program begins inside a function called "main". A function is simply a collection of commands that do "something". The main function is always called when the program first executes. From main, we can call other functions, whether they be written by us or by others or use built-in language features. To access the standard functions that comes with your compiler, you need to include a header with the #include directive. What this does is effectively take everything in the header and paste it into your program. Let's look at a working program:

#include <stdio.h> int main() { printf( "I am alive! getchar(); return 0; }

Beware.\n" );

Let's look at the elements of the program. The #include is a "preprocessor" directive that tells the compiler to put code from the header called stdio.h into our program before actually creating 1 www.thinklabs.in Page the

Embedded Systems

executable. By including header files, you can gain access to many different functions--both the printf and getchar functions are included in stdio.h. The semicolon is part of the syntax of C. It tells the compiler that you're at the end of a command. You will see later that the semicolon is used to end most commands in C. The next imporant line is int main(). This line tells the compiler that there is a function named main, and that the function returns an integer, hence int. The "curly braces" ({ and }) signal the beginning and end of functions and other code blocks. If you have programmed in Pascal, you will know them as BEGIN and END. Even if you haven't programmed in Pascal, this is a good way to think about their meaning. The printf function is the standard C way of displaying output on the screen. The quotes tell the compiler that you want to output the literal string as-is (almost). The '\n' sequence is actually treated as a single character that stands for a newline (we'll talk about this later in more detail); for the time being, just remember that there are a few sequences that, when they appear in a string literal, are actually not displayed literally by printf and that '\n' is one of them. The actual effect of '\n' is to move the cursor on your screen to the next line. Again, notice the semicolon: it is added onto the end of all lines, such as function calls, in C. The next command is getchar(). This is another function call: it reads in a single character and waits for the user to hit enter before reading the character. This line is included because many compiler environments will open a new console window, run the program, and then close the window before you can see the output. This command keeps that window from closing because the program is not done yet because it waits for you to hit enter. Including that line gives you time to see the program run. Finally, at the end of the program, we return a value from main to the operating system by using the return statement. This return value is important as it can be used to tell the operating system whether our program succeeded or not. A return value of 0 means success. The final brace closes off the function. You should try compiling this program and running it. You can cut and paste the code into a file, save it as a .c file, and then compile it. If you are using a command-line compiler, such as Borland C++ 5.5, you should read the compiler instructions for information on how to compile. Otherwise compiling and running should be as simple as clicking a button with your mouse (perhaps the "build" or "run" button). You might start playing around with the printf function and get used to writing simple C programs.

Explaining your Code


Comments are critical for all but the most trivial programs and this tutorial will often use them to explain sections of code. When you tell the compiler a section of text is a comment, it will ignore it when running the code, allowing you to use any text you want to describe the real code. To create a www.thinklabs.in Page 2 comment

Embedded Systems

in C, you surround the text with /* and then */ to block off everything between as a comment. Certain compiler environments or text editors will change the color of a commented area to make it easier to spot, but some will not. Be certain not to accidentally comment out code (that is, to tell the compiler part of your code is a comment) you need for the program. When you are learning to program, it is also useful to comment out sections of code in order to see how the output is affected.

Using Variables
So far you should be able to write a simple program to display information typed in by you, the programmer and to describe your program with comments. That's great, but what about interacting with your user? Fortunately, it is also possible for your program to accept input. But first, before you try to receive input, you must have a place to store that input. In programming, input and data are stored in variables. There are several different types of variables; when you tell the compiler you are declaring a variable, you must include the data type along with the name of the variable. Several basic types include char, int, and float. Each type can store different types of data. A variable of type char stores a single character, variables of type int store integers (numbers without decimal places), and variables of type float store numbers with decimal places. Each of these variable types - char, int, and float - is each a keyword that you use when you declare a variable. Some variables also use more of the computer's memory to store their values. It may seem strange to have multiple variable types when it seems like some variable types are redundant. But using the right variable size can be important for making your program efficient because some variables require more memory than others. For now, suffice it to say that the different variable types will almost all be used! Before you can use a variable, you must tell the compiler about it by declaring it and telling the compiler about what its "type" is. To declare a variable you use the syntax <variable type> <name of variable>;. (The brackets here indicate that your replace the expression with text described within the brackets.) For instance, a basic variable declaration might look like this:
int myVariable;

Note once again the use of a semicolon at the end of the line. Even though we're not calling a function, a semicolon is still required at the end of the "expression". This code would create a variable called myVariable; now we are free to use myVariable later in the program. It is permissible to declare multiple variables of the same type on the same line; each one should be separated by a comma. If you attempt to use an undefined variable, your program will not run, and www.thinklabs.in Page 3 you

Embedded Systems

will receive an error message informing you that you have made a mistake. Here are some variable declaration examples:

int x; int a, b, c, d; char letter; float the_float;

While you can have multiple variables of the same type, you cannot have multiple variables with the same name. Moreover, you cannot have variables and functions with the same name. A final restriction on variables is that variable declarations must come before other types of statements in the given "code block" (a code block is just a segment of code surrounded by { and }). So in C you must declare all of your variables before you do anything else: Wrong
#include <stdio.h> int main() { /* wrong! The variable declaration must appear first */ printf( "Declare x next" ); int x; return 0; }

Fixed
#include <stdio.h> int main() { int x; printf( "Declare x first" ); return 0; }

Reading input
Using variables in C for input or output can be a bit of a hassle at first, but bear with it and it will make sense. We'll be using the scanf function to read in a value and then printf to read it back out. Let's look at the program and then pick apart exactly what's going on. You can even compile this and run it if it helps you follow along. www.thinklabs.in Page 4

Embedded Systems

#include <stdio.h> int main() { int this_is_a_number; printf( "Please enter a number: " ); scanf( "%d", &this_is_a_number ); printf( "You entered %d", this_is_a_number ); getchar(); return 0; }

So what does all of this mean? We've seen the #include and main function before; main must appear in every program you intend to run, and the #include gives us access to printf (as well as scanf). (As you might have guessed, the io in stdio.h stands for "input/output"; std just stands for "standard.") The keyword int declares this_is_a_number to be an integer. This is where things start to get interesting: the scanf function works by taking a string and some variables modified with &. The string tells scanf what variables to look for: notice that we have a string containing only "%d" -- this tells the scanf function to read in an integer. The second argument of scanf is the variable, sort of. We'll learn more about what is going on later, but the gist of it is that scanf needs to know where the variable is stored in order to change its value. Using & in front of a variable allows you to get its location and give that to scanf instead of the value of the variable. Think of it like giving someone directions to the soda aisle and letting them go get a coca-cola instead of fetching the coke for that person. The & gives the scanf function directions to the variable. When the program runs, each call to scanf checks its own input string to see what kinds of input to expect, and then stores the value input into the variable. The second printf statement also contains the same '%d'--both scanf and printf use the same format for indicating values embedded in strings. In this case, printf takes the first argument after the string, the variable this_is_a_number, and treats it as though it were of the type specified by the "format specifier". In this case, printf treats this_is_a_number as an integer based on the format specifier. So what does it mean to treat a number as an integer? If the user attempts to type in a decimal number, it will be truncated (that is, the decimal component of the number will be ignored) when stored in the variable. Try typing in a sequence of characters or a decimal number when you run the example program; the response will vary from input to input, but in no case is it particularly pretty. Of course, no matter what type you use, variables are uninteresting without the ability to modify them. Several operators used with variables include the following: *, -, +, /, =, ==, >, <. The * multiplies, the / divides, the - subtracts, and the + adds. It is of course important to realize that to modify the value www.thinklabs.in Page 5 of a variable inside the program it is rather important to use the equal sign. In some languages, the equal

Embedded Systems

sign compares the value of the left and right values, but in C == is used for that task. The equal sign is still extremely useful. It sets the value of the variable on the left side of the equals sign equal to the value on the right side of the equals sign. The operators that perform mathematical functions should be used on the right side of an equal sign in order to assign the result to a variable on the left side. Here are a few examples:

a = 4 * 6; /* (Note use of comments and of semicolon) a is 24 */ a = a + 5; /* a equals the original value of a with five added to it */ a == 5/* Does NOT assign five to a. Rather, it checks to see if a equals 5.*/

The other form of equal, ==, is not a way to assign a value to a variable. Rather, it checks to see if the variables are equal. It is extremely useful in many areas of C; for example, you will often use == in such constructions as conditional statements and loops. You can probably guess how < and > function. They are greater than and less than operators. For example:

a < 5 /* Checks to see if a is less than five */ a > 5 /* Checks to see if a is greater than five */ a == 5 /* Checks to see if a equals five, for good measure */

If statements
The ability to control the flow of your program, letting it make decisions on what code to execute, is valuable to the programmer. The if statement allows you to control if a program enters a section of code or not based on whether a given condition is true or false. One of the important functions of the if statement is that it allows the program to select an action based upon the user's input. For example, by using an if statement to check a user-entered password, your program can decide whether a user is allowed access to the program. Without a conditional statement such as the if statement, programs would run almost the exact same way every time, always following the same sequence of function calls. If statements allow the flow of the program to be changed, which leads to more interesting code. Before discussing the actual structure of the if statement, let us examine the meaning of TRUE and FALSE in computer terminology. A true statement is one that evaluates to a nonzero number. A false statement evaluates to zero. When you perform comparison with the relational operators, the operator will return 1 if the comparison is true, or 0 if the comparison is false. For example, the check 0 == 2 evaluates to 0. The check 2 == 2 evaluates to a 1. If this confuses you, try to use a printf statement to output the result of those various comparisons (for example printf ( "%d", 2 == 1 );) www.thinklabs.in Page 6

Embedded Systems

When programming, the aim of the program will often require the checking of one value stored by a variable against another value to determine whether one is larger, smaller, or equal to the other. There are a number of operators that allow these checks. Here are the relational operators, as they are known, along with examples: > greater than5 > 4 is TRUE < less than4 < 5 is TRUE >= greater than or equal 4 >= 4 is TRUE <= less than or equal3 <= 4 is TRUE == equal to5 == 5 is TRUE != not equal to5 != 4 is TRUE

It is highly probable that you have seen these before, probably with slightly different symbols. They should not present any hindrance to understanding. Now that you understand TRUE and FALSE well as the comparison operators, let us look at the actual structure of if statements. The structure of an if statement is as follows: if ( statement is TRUE ) Execute this line of code Here is a simple example that shows the syntax: if ( 5 < 10 ) printf( "Five is now less than ten, that's a big surprise" ); Here, we're just evaluating the statement, "is five less than ten", to see if it is true or not; with any luck, it's not! If you want, you can write your own full program including stdio.h and put this in the main function and run it to test. To have more than one statement execute after an if statement that evaluates to true, use braces, like we did with the body of the main function. Anything inside braces is called a compound statement, or a block. When using if statements, the code that depends on the if statement is called the "body" of the if For example: statement. if ( TRUE ) { /* between the braces is the body of the if statement */ Execute all statements inside the body }

www.thinklabs.in

Page 7

Embedded Systems

I recommend always putting braces following if statements. If you do this, you never have to remember to put them in when you want more than one statement to be executed, and you make the body of the if statement more visually clear.

Else
Sometimes when the condition in an if statement evaluates to false, it would be nice to execute some code instead of the code executed when the statement evalutes to true. The "else" statement effectively says that whatever code after it (whether a single line or code between brackets) is executed if the if statement is FALSE. It can look like this: if ( TRUE ) { /* Execute these statements if TRUE */ } else { /* Execute these statements if FALSE */
}

Else if
Another use of else is when there are multiple conditional statements that may all evaluate to true, yet you want only one if statement's body to execute. You can use an "else if" statement following an if statement and its body; that way, if the first statement is true, the "else if" will be ignored, but if the if statement is false, it will then check the condition for the else if statement. If the if statement was true the else statement will not be checked. It is possible to use numerous else if statements to ensure that look at a simple program for you to try out on your own. Let's only one block of code is executed. #include <stdio.h> int main() */ { int age; /* Most important part of the program!

/* Need a variable... */

printf( "Please enter your age" ); /* Asks for age */ scanf( "%d", &age );/* The input is put in age */ if ( age < 100 ) {/* If the age is less than 100 */ printf ("You are pretty young!\n" ); /* Just to show you it works... */ } else if ( age == 100 ) {/* I use else just to show an example */ printf( "You are old\n" ); } else { www.thinklabs.in

Page 8

Embedded Systems

printf( "You are really old\n" ); /* Executed if no other statement is */ } return 0; }

Loops
Loops are used to repeat a block of code. Being able to have your program repeatedly execute a block of code is one of the most basic but useful tasks in programming -- many programs or websites that produce extremely complex output (such as a message board) are really only executing a single task many times. (They may be executing a small number of tasks, but in principle, to produce a list of messages only requires repeating the operation of reading in some data and displaying it.) Now, think about what this means: a loop lets you write a very simple statement to produce a significantly greater result simply by repetition. One caveat: before going further, you should understand the concept of C's true and false, because it will be necessary when working with loops (the conditions are the same as with if statements). There are three types of loops: for, while, and do..while. Each of them has their specific uses. They are all outlined below. FOR - for loops are the most useful type. The syntax for a for loop is

for ( variable initialization; condition; variable update ) { Code to execute while the condition is true }

The variable initialization allows you to either declare a variable and give it a value or give a value to an already existing variable. Second, the condition tells the program that while the conditional expression is true the loop should continue to repeat itself. The variable update section is the easiest way for a for loop to handle changing of the variable. It is possible to do things like x++, x = x + 10, or even x = random ( 5 ), and if you really wanted to, you could call other functions that do nothing to the variable but still have a useful effect on the code. Notice that a semicolon separates each of these sections, that is important. Also note that every single one of the sections may be empty, though the semicolons still have to be there. If the condition is empty, it is evaluated as true and the loop will repeat until something else stops it.

www.thinklabs.in

Page 9

Embedded Systems

Example:

#include <stdio.h> int main() { int x; /* The loop goes while x < 10, and x increases by one every loop*/ for ( x = 0; x < 10; x++ ) { /* Keep in mind that the loop condition checks the conditional statement before it loops again. consequently, when x equals 10 the loop breaks. x is updated before the condition is checked. */ printf( "%d\n", x ); } getchar(); }

This program is a very simple example of a for loop. x is set to zero, while x is less than 10 it calls printf to display the value of the variable x, and it adds 1 to x until the condition is met. Keep in mind also that the variable is incremented after the code in the loop is run for the first time. WHILE - WHILE loops are very simple. The basic structure is while ( condition ) { Code to execute while the condition is true } The true represents a boolean expression which could be x == 1 or while ( x != 7 ) (x does not equal 7). It can be any combination of boolean statements that are legal. Even, (while x ==5 || v == 7) which says execute the code while x equals five or while v equals 7. Notice that a while loop is like a stripped-down version of a for loop-it has no initialization or update section. However, an empty condition is not legal for a while loop as it is with a for loop. Example:

#include <stdio.h> int main() { int x = 0;

/* Don't forget to declare variables */

while ( x < 10 ) { /* While x is less than 10 */ printf( "%d\n", x ); x++;/* Update x so the condition can be met eventually */ } getchar(); }

www.thinklabs.in

Page 10

Embedded Systems

This was another simple example, but it is longer than the above FOR loop. The easiest way to think of the loop is that when it reaches the brace at the end it jumps back up to the beginning of the loop, which checks the condition again and decides whether to repeat the block another time, or stop and move to the next statement after the block. DO..WHILE - DO..WHILE loops are useful for things that want to loop at least once. The structure is
do { } while ( condition );

Notice that the condition is tested at the end of the block instead of the beginning, so the block will be executed at least once. If the condition is true, we jump back to the beginning of the block and execute it again. A do..while loop is almost the same as a while loop except that the loop body is guaranteed to execute at least once. A while loop says "Loop while the condition is true, and execute this block of code", a do..while loop says "Execute this block of code, and then continue to loop while the condition is true". Example:

#include <stdio.h> int main() { int x; x = 0; do { /* "Hello, world!" is printed at least one time even though the condition is false*/ printf( "%d\n", x ); } while ( x != 0 ); getchar(); }

Keep in mind that you must include a trailing semi-colon after the while in the above example. A common error is to forget that a do..while loop must be terminated with a semicolon (the other loops should not be terminated with a semicolon, adding to the confusion). Notice that this loop will execute once, because it automatically executes before checking the condition.

Break and Continue Two keywords that are very important to looping are break and continue. The break command will exit the most immediately surrounding loop regardless of what the conditions of the loop are. Break is useful if we want to exit a loop under special circumstances. For example, let's say the program we're working on is a two-person checkers game. The basic structure of the program might look like this: www.thinklabs.in Page 11

Embedded Systems

while (true) { take_turn(player1); take_turn(player2); }

This will make the game alternate between having player 1 and player 2 take turns. The only problem with this logic is that there's no way to exit the game; the loop will run forever! Let's try something like this instead:
while(true) { if (someone_has_won() || someone_wants_to_quit() == TRUE) {break;} take_turn(player1); if (someone_has_won() || someone_wants_to_quit() == TRUE) {break;} take_turn(player2); }

This code accomplishes what we want--the primary loop of the game will continue under normal circumstances, but under a special condition (winning or exiting) the flow will stop and our program will do something else. Continue is another keyword that controls the flow of loops. If you are executing a loop and hit a continue statement, the loop will stop its current iteration, update itself (in the case of for loops) and begin to execute again from the top. Essentially, the continue statement is saying "this iteration of the loop is done, let's continue with the loop without executing whatever code comes after me." Let's say we're implementing a game of Monopoly. Like above, we want to use a loop to control whose turn it is, but controlling turns is a bit more complicated in Monopoly than in checkers. The basic structure of our code might then look something like this:
for (player = 1; someone_has_won == FALSE; player++) { if (player > total_number_of_players) {player = 1;} if (is_bankrupt(player)) {continue;} take_turn(player); }

www.thinklabs.in

Page 12

Embedded Systems

Functions
Now that you should have learned about variables, loops, and conditional statements it is time to learn about functions. You should have an idea of their uses as we have already used them and defined one in the guise of main. Getchar is another example of a function. In general, functions are blocks of code that perform a number of pre-defined commands to accomplish something productive. You can either use the built-in library functions or you can create your own functions. Functions that a programmer writes will generally require a prototype. Just like a blueprint, the prototype gives basic structural information: it tells the compiler what the function will return, what the function will be called, as well as what arguments the function can be passed. When I say that the function returns a value, I mean that the function can be used in the same manner as a variable would be. For example, a variable can be set equal to a function that returns a value between zero and four. For example: #include <stdlib.h> /* Include rand() */ int a = rand(); /* rand is a standard function that all compilers have */ Do not think that 'a' will change at random, it will be set to the value returned when the function is called, but it will not change again. The general format for a prototype is simple: return-type function_name ( arg_type arg1, ..., arg_type argN ); arg_type just means the type for each argument -- for instance, an int, a float, or a char. It's exactly the same thing as what you would put if you were declaring a variable. There can be more than one argument passed to a function or none at all (where the parentheses are empty), and it does not have to return a value. Functions that do not return values have a return type of void. Let's look at a function prototype: int mult ( int x, int y ); This prototype specifies that the function mult will accept two arguments, both integers, and that it will return an integer. Do not forget the trailing semi-colon. Without it, the compiler will probably think that you are trying to write the actual definition of the function. When the programmer actually defines the function, it will begin with the prototype, minus the semicolon. Then there should always be a block (surrounded by curly braces) with the code that the function is to execute, just as you would write it for the main function. Any of the arguments passed to the function can be used as if they were declared in the block. Finally, end it all with a cherry and a closing brace. Okay, maybe not a cherry. www.thinklabs.in Page 13

Embedded Systems

Let's look at an example program: #include <stdio.h> int mult ( int x, int y ); int main() { int x; int y; printf( "Please input two numbers to be multiplied: " ); scanf( "%d", &x ); scanf( "%d", &y ); printf( "The product of your two numbers is %d\n", mult( x, y ) ); getchar(); } int mult (int x, int y) { return x * y; } This program begins with the only necessary include file. Next is the prototype of the function. Notice that it has the final semi-colon! The main function returns an integer, which you should always have to conform to the standard. You should not have trouble understanding the input and output functions if Notice followed the previous tutorials. you've how printf actually takes the value of what appears to be the mult function. What is really happening is printf is accepting the value returned by mult, not mult itself. The result would be the same as if we had use this print instead printf( "The product of your two numbers is %d\n", x * y ); The mult function is actually defined below main. Because its prototype is above main, the compiler still recognizes it as being declared, and so the compiler will not give an error about mult being undeclared. As long as the prototype is present, a function can be used even if there is no definition. However, the code cannot be run without a definition even though it will compile. Prototypes are declarations of the function, but they are only necessary to alert the compiler about the existence of a function if we don't want to go ahead and fully define the function. If mult were defined before it is used, we could do away with the prototype--the definition basically acts as a prototype as well. www.thinklabs.in Page 14

Embedded Systems

Return is the keyword used to force the function to return a value. Note that it is possible to have a function that returns no value. If a function returns void, the retun statement is valid, but only if it does not have an expression. In otherwords, for a function that returns void, the statement "return;" is legal, but usually redundant. (It can be used to exit the function before the end of the function.) The most important functional (pun semi-intended) question is why do we need a function? Functions have many uses. For example, a programmer may have a block of code that he has repeated forty times throughout the program. A function to execute that code would save a great deal of space, and it would also make the program more readable. Also, having only one copy of the code makes it easier to make changes. Would you rather make forty little changes scattered all throughout a potentially large program, or one change to the function body? So would I. Another reason for functions is to break down a complex program into logical parts. For example, take a menu program that runs complex code when a menu choice is selected. The program would probably best be served by making functions for each of the actual menu choices, and then breaking down the complex tasks into smaller, more manageable tasks, which could be in their own functions. In this way, a program can be designed that makes sense when read. And has a structure that is easier to understand quickly. The worst programs usually only have the required function, main, and fill it with pages of jumbled code.

switch case
Switch case statements are a substitute for long if statements that compare a variable to several "integral" values ("integral" values are simply values that can be expressed as an integer, such as the value of a char). The basic format for using switch case is outlined below. The value of the variable given into switch is compared to the value following each of the cases, and when one value matches the value of the variable, the computer continues executing the program from that point. switch ( <variable> ) { case this-value: Code to execute if <variable> == this-value break; case that-value: Code to execute if <variable> == that-value break; ... default: Code to execute if <variable> does not equal the value following any of the cases break; }

www.thinklabs.in

Page 15

Embedded Systems

The condition of a switch statement is a value. The case says that if it has the value of whatever is after that case then do whatever follows the colon. The break is used to break out of the case statements. Break is a keyword that breaks out of the code block, usually surrounded by braces, which it is in. In this case, break prevents the program from falling through and executing the code in all the other case statements. An important thing to note about the switch statement is that the case values may only be constant integral expressions. Sadly, it isn't legal to use case like this: int a = 10; int b = 10; int c = 20; switch ( a ) { case b: /* Code */ break; case c: /* Code */ break; default: /* Code */ break; }

The default case is optional, but it is wise to include it as it handles any unexpected cases. It can be useful to put some kind of output to alert you to the code entering the default case if you don't expect it to. Switch statements serve as a simple way to write long if statements when the requirements are met. Often it can be used to process input from a user. Below is a sample program, in which not all of the proper functions are actually declared, but which shows how one would use switch in a program. #include <stdio.h> void playgame(); void loadgame(); void playmultiplayer(); int main() { int input; printf( "1. Play game\n" ); printf( "2. Load game\n" ); printf( "3. Play multiplayer\n" ); printf( "4. Exit\n" ); printf( "Selection: " ); scanf( "%d", &input ); switch ( input ) { www.thinklabs.in

Page 16

Embedded Systems

case 1:/* Note the colon, not a semicolon */ playgame(); break; case 2: loadgame(); break; case 3: playmultiplayer(); break; case 4: printf( "Thanks for playing!\n" ); break; default: printf( "Bad input, quitting!\n" ); break;

} getchar(); } This program will compile, but cannot be run until the undefined functions are given bodies, but it serves as a model (albeit simple) for processing input. If you do not understand this then try mentally putting in if statements for the case statements. Default simply skips out of the switch case construction and allows the program to terminate naturally. If you do not like that, then you can make a loop around the whole thing to have it wait for valid input. You could easily make a few small functions if you wish to test the code.

www.thinklabs.in

Page 17

Embedded Systems

Arrays
Arrays are useful critters that often show up when it would be convenient to have one name for a group of variables of the same type that can be accessed by a numerical index. For example, a tic-tac-toe board can be held in an array and each element of the tic-tac-toe board can easily be accessed by its position (the upper left might be position 0 and the lower right position 8). At heart, arrays are essentially a way to store many values under the same name. You can make an array out of any datatype including structures and classes. One way to visualize an array is like this:

[][][][][][] Each of the bracket pairs is a slot in the array, and you can store information in slot--the information stored in the array is called an element of the array. It is very much as though you have a group of variables lined up side by side. Let's look at the syntax for declaring an array. int examplearray[100]; /* This declares an array */ This would make an integer array with 100 slots (the places in which values of an array are stored). To access a specific part element of the array, you merely put the array name and, in brackets, an index number. This corresponds to a specific element of the array. The one trick is that the first index number, and thus the first element, is zero, and the last is the number of elements minus one. The indices for a 100 element array range from 0 to 99. Be careful not to "walk off the end" of the array by trying to access element 100! this simple knowledge? Lets say you want to store a string, because C has What can you do with no built-in datatype for strings, you can make an array of characters. For example: char astring[100]; will allow you to declare a char array of 100 elements, or slots. Then you can receive input into it from the user, and when the user types in a string, it will go in the array, the first character of the string will be at position 0, the second character at position 1, and so forth. It is relatvely easy to work with strings in this way because it allows support for any size string you can imagine all stored in a single variable with each element in the string stored in an adjacent location--think about how hard it would be to store nearly arbitrary sized strings using simple variables that only store one value. Since we can write loops that increment integers, it's very easy to scan through a string: www.thinklabs.in Page 18

Embedded Systems

char astring[10]; int i = 0; /* Using scanf isn't really the best way to do this; we'll talk about that in the next tutorial, on strings */ scanf( "%s", astring ); for ( i = 0; i < 10; ++i ) { if ( astring[i] == 'a' ) { printf( "You entered an a!\n" ); } }

Let's look at something new here: the scanf function call is a tad different from what we've seen before. First of all, the format string is '%s' instead of '%d'; this just tells scanf to read in a string instead of an integer. Second, we don't use the ampersand! It turns out that when we pass arrays into functions, the compiler automatically converts the array into a pointer to the first element of the array. In short, the array without any brackets will act like a pointer. So we just pass the array directly into scanf without using notice that to accessit works perfectly. array, we just use the brackets and put in the index Also, the ampersand and the element of the whose value interests us; in this case, we go from 0 to 9, checking each element to see if it's equal to the character a. Note that some of these values may actually be uninitialized since the user might not input a string that fills the whole array--we'll look into how strings are handled in more detail in the next tutorial; for now, the key is simply to understand the power of accessing the array using a numerical index. Imagine how you would write that if you didn't have access to arrays! Oh boy. Multidimensional arrays are arrays that have more than one index: instead of being just a single line of slots, multidimensional arrays can be thought of as having values that spread across two or more dimensions. Here's an easy way to visualize a two-dimensional array: [][][][][] [][][][][] [][][][][] [][][][][] [][][][][] The syntax used to actually declare a two dimensional array is almost the same as that used for declaring a one-dimensional array, except that you include a set of brackets for each dimension, and include the size of the dimension. For example, here is an array that is large enough to hold a standard checkers board, with 8 rows and 8 columns: int two_dimensional_array[8][8]; You can easily use this to store information about some kind of game or to write something like tictactoe. To access it, all you need are two variables, one that goes in the first slot and one that goes in the second slot. You can make three dimensional, four dimensional, or even higher dimensional arrays, www.thinklabs.in Page 19 though past three dimensions, it becomes quite hard to visualize.

Embedded Systems

Setting the value of an array element is as easy as accessing the element and performing an assignment. For instance, <arrayname>[<arrayindexnumber>] = <value> for instance, /* set the first element of my_first to be the letter c */ my_string[0] = 'c'; or, for two dimensional arrays <arrayname>[<arrayindexnumber1>][<arrayindexnumber2>] = <whatever>; Let us note again that you should never attempt to write data past the last element of the array, such as when you have a 10 element array, and you try to write to the [10] element. The memory for the array that was allocated for it will only be ten locations in memory, (the elements 0 through 9) but the next location could be anything. Writing to random memory could cause unpredictable effects--for example you might end up writing to the video buffer and change the video display, or you might write to memory being used by an open document and altering its contents. Usually, the operating system will not allow this kind of reckless behavior and will crash the program if it tries to write to unallocated You will find lots of useful things to do with arrays, from storing information about certain things memory. under one name, to making games like tic-tac-toe. We've already seen one example of using loops to access arrays; here is another, more interesting, example! #include <stdio.h> int main() { int x; int y; int array[8][8]; /* Declares an array like a chessboard */ for ( x = 0; x < 8; x++ ) { for ( y = 0; y < 8; y++ ) array[x][y] = x * y; /* Set each element to a value */ } printf( "Array Indices:\n" ); for ( x = 0; x < 8;x++ ) { for ( y = 0; y < 8; y++ ) { printf( "[%d][%d]=%d", x, y, array[x][y] ); } printf( "\n" ); } getchar();

} ww.thinklabs.in w

Page 20

Embedded Systems

Just to touch upon a final point made briefly above: arrays don't require a reference operator (the ampersand) when you want to have a pointer to them. For example: char *ptr; char str[40]; ptr = str; /* Gives the memory address without a reference operator(&) */ As opposed to int *ptr; int num; ptr = &num; /* Requires & to give the memory address to the ptr */

An introduction to pointers
Pointers are an extremely powerful programming tool. They can make some things much easier, help improve your program's efficiency, and even allow you to handle unlimited amounts of data. For example, using pointers is one way to have a function modify a variable passed to it. It is also possible to use pointers to dynamically allocate memory, which means that you can write programs that can handle nearly unlimited amounts of data on the fly--you don't need to know, when you write the program, how much memory you need. Wow, that's kind of cool. Actually, it's very cool, as we'll see in some of the next tutorials. For now, let's just get a basic handle on what pointers are and how you use them. What are pointers? Why should you care? Pointers are aptly name: they "point" to locations in memory. Think of a row of safety deposit boxes of various sizes at a local bank. Each safety deposity box will have a number associated with it so that you can quickly look it up. These numbers are like the memory addresses of variables. A pointer in the world of safety deposit box would simply be anything that stored the number of another safety deposit box. Perhaps you have a rich uncle who stored valuables in his safety deposit box, but decided to put the real location in another, smaller, safety deposit box that only stored a card with the number of the large box with the real jewelery. The safety deposit box with the card would be storing the location of another The cool thing is equivalentcanatalk about the address of apointers are justthen be able tostore that box; it would be that once to pointer. In the computer, variable, you'll variables that go to address memory and retrieve the data stored in it. If you happen to have a huge piece of data that you want to pass into a function, it's a lot easier other variables. addresses, usually the addresses of to pass its location to the function that to copy every element of the data! Moreover, if you need more memory for your program, you can request more memory from the system--how do you get "back" that memory? The system tells you where it is located in memory; that is to say, you get a memory address back. And you need pointers to store the memory address. A note about terms: the word pointer can refer either to a memory address itself, or to a variable that www.thinklabs.in Page 21 stores a memory address. Usually, the distinction isn't really that important: if you pass a pointer

Embedded Systems

variable into a function, you're passing the value stored in the pointer--the memory address. When I want to talk about a memory address, I'll refer to it as a memory address; when I want a variable that stores a memory address, I'll call it a pointer. When a variable stores the address of another variable, I'll say that it is "pointing to" that variable. Pointer Syntax Pointers require a bit of new syntax because when you have a pointer, you need the ability to both request the memory location it stores and the value stored at that memory location. Moreover, since pointers are somewhat special, you need to tell the compiler when you declare your pointer variable that the variable is a pointer, and tell the compiler what type of memory it points to.

The pointer declaration looks like this: <variable_type> *<name>; For example, you could declare a pointer that stores the address of an integer with the following syntax: int *points_to_integer; Notice the use of the *. This is the key to declaring a pointer; if you add it directly before the variable name, it will declare the variable to be a pointer. Minor gotcha: if you declare multiple pointers on the same line, you must precede each of them with an asterisk: /* one pointer, one regular int */ int *pointer1, nonpointer1; /* two pointers */ int *pointer1, *pointer2; As I mentioned, there are two ways to use the pointer to access information: it is possible to have it give the actual address to another variable. To do so, simply use the name of the pointer without the *. However, to access the actual memory location, use the *. The technical name for this doing this is dereferencing the pointer; in essence, you're taking the reference to some memory address and following it, to retrieve the actual value. It can be tricky to keep track of when you should add the asterisk. Remember that the pointer's natural use is to store a memory address; so when you use the pointer: call_to_function_expecting_memory_address(pointer); then it evaluates to the address. You have to add something extra, the asterisk, in order to retrieve the value stored at the address. You'll probably do that an awful lot. Nevertheless, the pointer itself is supposed to store an address, so when you use the bare pointer, you get that address back. www.thinklabs.in Page 22

Embedded Systems

Pointing to Something: Retrieving an Address In order to have a pointer actually point to another variable it is necessary to have the memory address of that variable also. To get the memory address of a variable (its location in memory), put the & sign in front of the variable name. This makes it give its address. This is called the address-of operator, because it returns the memory address. Conveniently, both ampersand and address-of start with a; that's a useful way to remember that you use & to get the address of a variable. For example: #include <stdio.h> int main() { int x; int *p;

/* A normal integer*/ /* A pointer to an integer ("*p" is an integer, so p must be a pointer to an integer) */

p = &x;/* Read it, "assign the address of x to p" */ scanf( "%d", &x );/* Put a value in x, we could also use p here */ printf( "%d\n", *p ); /* Note the use of the * to get the value */ getchar(); } The printf outputs the value stored in x. Why is that? Well, let's look at the code. The integer is called x. A pointer to an integer is then defined as p. Then it stores the memory location of x in pointer by using the address operator (&) to get the address of the variable. Using the ampersand is a bit like looking at the label on the safety deposit box to see its number rather than looking inside the box, to get what it stores. The user then inputs a number that is stored in the variable x; remember, this is the same location that is pointed to by p. In fact, since we use an ampersand to pass the value to scanf, it should The nextthat scanf passes *p into value in the address pointed to by p. (Inoperation on p; it looks at be clear line then is putting the printf. *p performs the "dereferencing" fact, scanf works becuase the of address stored in p, and goes to that address and returns the value. This is akin to looking inside a pointers!) safety deposit box only to find the number of (and, presumably, the key to ) another box, which you then open. Notice that in the above example, the pointer is initialized to point to a specific memory address before it is used. If this was not the case, it could be pointing to anything. This can lead to extremely unpleasant consequences to the program. For instance, the operating system will probably prevent you from accessing memory that it knows your program doesn't own: this will cause your program to crash. If it let you use the memory, you could mess with the memory of any running program--for instance, if you had a document opened in Word, you could change the text! Fortunately, Windows and other modern operating systems will stop you from accessing that memory and cause your program to crash. To avoid It is also possible to initializeshould always initialize pointers before you use them. www.thinklabs.in Page 23 crashing your program, you pointers using free memory. This allows dynamic allocation of memory. It is

Embedded Systems

useful for setting up structures such as linked lists or data trees where you don't know exactly how much memory will be needed at compile time, so you have to get memory during the program's execution. We'll look at these structures later, but for now, we'll simply examine how to request memory from and return memory to the operating system. The function malloc, residing in the stdlib.h header file, is used to initialize pointers with memory from free store (a section of memory available to all programs). malloc works just like any other function call. The argument to malloc is the amount of memory requested (in bytes), and malloc gets a block of memory of that size and then returns a pointer to the block of memory allocated. Since different variable types have different memory requirements, we need to get a size for the amount of memory malloc should return. So we need to know how to get the size of different variable types. This can be done using the keyword sizeof, which takes an expression and returns its size. For example, sizeof(int) would return the number of bytes required to store an integer. #include <stdlib.h> int *ptr = malloc( sizeof(int) ); This code set ptr to point to a memory address of size int. The memory that is pointed to becomes unavailable to other programs. This means that the careful coder should free this memory at the end of its usage lest the memory be lost to the operating system for the duration of the program (this is often called a memory leak because the program is not keeping track of all of its memory). Note that it is slightly cleaner to write malloc statements by taking the size of the variable pointed to by using the pointer directly: int *ptr = malloc( sizeof(*ptr) ); What's going on here? sizeof(*ptr) will evaluate the size of whatever we would get back from dereferencing ptr; since ptr is a pointer to an int, *ptr would give us an int, so sizeof(*ptr) will return the size of an integer. So why do this? Well, if we change ptr to point to something else like a float, then we don't have to go back and correct the malloc call to use sizeof(float). Since ptr would be pointing to a float, *ptr would be a float, so sizeof(*ptr) would still give the right size! The free function returns memory to the operating system. free( ptr ); After freeing a pointer, it is a good idea to reset it to point to 0. When 0 is assigned to a pointer, the pointer becomes a null pointer, in other words, it points to nothing. By doing this, when you do something foolish with the pointer (it happens a lot, even with experienced programmers), you find out immediately instead of later, when you have done considerable damage. The concept of the null pointer is frequently used as a way of indicating a problem--for instance, malloc returns 0 when it cannot correctly allocate memory. You want to be sure to handle this correctly-sometimes your operating system might actually run out of memory and give you this value! www.thinklabs.in Page 24

Embedded Systems

Taking Stock of Pointers Pointers may feel like a very confusing topic at first but I think anyone can come to appreciate and understand them. If you didn't feel like you absorbed everything about them, just take a few deep breaths and re-read the lesson. You shouldn't feel like you've fully grasped every nuance of when and why you need to use pointers, though you should have some idea of some of their basic uses.

Recursion
Recursion is a programming technique that allows the programmer to express operations in terms of themselves. In C, this takes the form of a function that calls itself. A useful way to think of recursive functions is to imagine them as a process being performed where one of the instructions is to "repeat the process". This makes it sound very similar to a loop because it repeats the same code, and in some ways it is similar to looping. On the other hand, recursion makes it easier to express ideas in which the result of the recursive call is necessary to complete the task. Of course, it must be possible for the "process" to sometimes be completed without the recursive call. One simple example is the idea of building a wall that is ten feet high; if I want to build a ten foot high wall, then I will first build a 9 foot high wall, and then add an extra foot of bricks. Conceptually, this is like saying the "build wall" function takes a height and if that height is greater than one, first calls itself to build a lower wall, and then adds one a foot of bricks. A simple example of recursion would be: void recurse() { recurse(); /* Function calls itself */ } int main() { recurse(); /* Sets off the recursion */ return 0; } This program will not continue forever, however. The computer keeps function calls on a stack and once too many are called without ending, the program will crash. Why not write a program to see how many times the function is called before the program terminates? #include <stdio.h> void recurse ( int count ) /* Each call gets its own copy of count */ { www.thinklabs.in

Page 25

Embedded Systems

printf( "%d\n", count ); /* It is not necessary to increment count since each function's variables are separate (so each count will be initialized one greater) */ recurse ( count + 1 ); } int main() { recurse ( 1 ); /* First function call, so it starts at one */ return 0; } This simple program will show the number of times the recurse function has been called by initializing each individual function call's count variable one greater than it was previous by passing in count + 1. Keep in mind that it is not a function call restarting itself; it is hundreds of function calls that are each The best way unfinished. to think of recursion is that each function call is a "process" being carried out by the computer. If we think of a program as being carried out by a group of people who can pass around information about the state of a task and instructions on performing the task, each recursive function call is a bit like each person asking the next person to follow the same set of instructions on some part of the task while the first person waits for the result. At some point, we're going to run out of people to carry out the instructions, just as our previous recursive functions ran out of space on the stack. There needs to be a way to avoid this! To halt a series of recursive calls, a recursive function will have a condition that controls when the function will finally stop calling itself. The condition where the function will not call itself is termed the base case of the function. Basically, it will usually be an if-statement that checks some variable for a condition (such as a number being less than zero, or greater than some other number) and if that condition is true, it will not allow the function to call itself again. (Or, it could check if a certain condition is true and only then allow A quick example: itself). the function to call void count_to_ten ( int count ) { /* we only keep counting if we have a value less than ten if ( count < 10 ) { count_to_ten( count + 1 ); } } int main() { count_to_ten ( 0 ); }

www.thinklabs.in

Page 26

Embedded Systems

This program ends when we've counted to ten, or more precisely, when count is no longer less than ten. This is a good base case because it means that if we have an input greater than ten, we'll stop immediately. If we'd chosen to stop when count equalled ten, then if the function were called with the input 11, it would run of of memory before stopping. Notice that so far, we haven't done anything with the result of a recursive function call. Each call takes place and performs some action that is then ignored by the caller. It is possible to get a value back from the caller, however. It's also possible to take advantage of the side effects of the previous call. In either case, once a function has called itself, it will be ready to go to the next line after the call. It can still perform operations. One function you could write could print out the numbers 123456789987654321. How can you use recursion to write a function to do this? Simply have it keep incrementing a void printnum ( int begin ) variable { passed in, and then output the variable twice: once before the function recurses, and once after. printf( "%d", begin ); if ( begin < 9 )/* The base case is when begin is no longer */ {/* less than 9 */ printnum ( begin + 1 ); } /* display begin again after we've already printed everything from 1 to 9 * and from 9 to begin + 1 */ printf( "%d", begin ); } This function works because it will go through and print the numbers begin to 9, and then as each printnum function terminates it will continue printing the value of begin in each function from 9 to begin.

This is, however, just touching on the usefulness of recursion. Here's a little challenge: use recursion to write a program that returns the factorial of any number greater than 0. (Factorial is number*number1*number-2...*1). Hint: Your function should recursively find the factorial of the smaller numbers first, i.e., it takes a number, finds the factorial of the previous number, and multiplies the number times that factorial...have fun. :-) To know more abt POINTERS AND ARRAYS, please refer the pdf given with ebooks folder in CD.

Storage Classes
A storage class defines the scope (visibility) and life time of variables and/or functions within a C Program. www.thinklabs.in Page 27

Embedded Systems

There are following storage classes which can be used in a C Program


auto register static extern

auto - Storage Class auto is the default storage class for all local variables. { int Count; auto int Month; } The example above defines two variables with the same storage class. auto can only be used within functions, i.e. local variables. register - Storage Class register is used to define local variables that should be stored in a register instead of RAM. This means that the variable has a maximum size equal to the register size (usually one word) and cant have the unary '&' operator applied to it (as it does not have a memory location). { register int Miles; } Register should only be used for variables that require quick access - such as counters. It should also be noted that defining 'register' goes not mean that the variable will be stored in a register. It means that it MIGHT be stored in a register - depending on hardware and implimentation restrictions. static - Storage Class static is the default storage class for global variables. The two variables below (count and road) both have a static storage class. static int Count; int Road; { printf("%d\n", Road); } www.thinklabs.in Page 28

Embedded Systems

static variables can be 'seen' within all functions in this source file. At link time, the static variables defined here will not be seen by the object modules that are brought in. static can also be defined within a function. If this is done the variable is initalised at run time but is not reinitalized when the function is called. This inside a function static variable retains its value during vairous calls.

void func(void); static count=10; /* Global variable - static is the default */ main() { while (count--) { func(); }

} void func( void ) { static i = 5; i++; printf("i is %d and count is %d\n", i, count); }

This will produce following result i i i i i i i i i i is is is is is is is is is is 6 and count is 9 7 and count is 8 8 and count is 7 9 and count is 6 10 and count is 5 11 and count is 4 12 and count is 3 13 and count is 2 14 and count is 1 15 and count is 0

NOTE : Here keyword void means function does not return anything and it does not take any parameter. You can memoriese void as nothing. static variables are initialized to 0 automatically. www.thinklabs.in Page 29

Embedded Systems

Definition vs Declaration : Before proceeding, let us understand the difference between defintion and declaration of a variable or function. Definition means where a variable or function is defined in realityand actual memory is allocated for variable or function. Declaration means just giving a reference of a variable and function. Through declaration we assure to the complier that this variable or function has been defined somewhere else in the program and will be provided at the time of linking. In the above examples char *func(void) has been put at the top which is a declaration of this function where as this function has been defined below to main() function. There is one more very important use for 'static'. Consider this bit of code. char *func(void); main() { char *Text1; Text1 = func(); } char *func(void) { char Text2[10]="martin"; return(Text2); }

Now, 'func' returns a pointer to the memory location where 'text2' starts BUT text2 has a storage class of 'auto' and will disappear when we exit the function and could be overwritten but something else. The answer is to specify static char Text[10]="martin";

The storage assigned to 'text2' will remain reserved for the duration if the program.

extern - Storage Class extern is used to give a reference of a global variable that is visible to ALL the program files. When you use 'extern' the variable cannot be initalized as all it does is point the variable name at a storage location that has been previously defined. When you have multiple files and you define a global variable or function which will be used in other files also, then extern will be used in another file to give reference of defined variable or function. Just www.thinklabs.in for understanding extern is used to decalre a global variable or function in another files.Page 30

Embedded Systems

File 1: main.c int count=5; main() { write_extern(); }

File 2: write.c void write_extern(void); extern int count; void write_extern(void) { printf("count is %i\n", count); } Here extern keyword is being used to declare count in another file. Now compile these two files as follows gcc main.c write.c -o write This fill produce write program which can be executed to produce result. Count in 'main.c' will have a value of 5. If main.c changes the value of count - write.c will see the new value

Type Modifiers
Type modifiers include: short, long, unsigned, signed. Not all combinations of types and modifiers are availble. Data type modifiers We have so far learned about the fundamental data types, why they are used, their default sizes and values. Now let us understand the need for data type modifiers and the way they can be used. www.thinklabs.in Page 31

Embedded Systems

Let us consider an example of a program, which will accept an age from the user to do some processing. Because the age is represented in numbers, so we will have to use the integer data type int. We all know that even under exceptional case an age of a person cannot exceed more than 150. Now, that we are using an integer data type it occupies 2 Bytes of memory, which would not be required to represent the value 150. Instead the value 150 could easily be saved in an integer of 1 Byte in size, but the default size not that we cant solve. To override the default nature of a data type, C has provided us with Well, of an integer is 2 Bytes. So we have a problem here. data type modifiers as follows: signed By default all data types are declared as signed. Signed means that the data type is capable of storing negative values. unsigned To modify a data types behavior so that it can only store positive values, we require to use the data type unsigned. For example, if we were to declare a variable age, we know that an age cannot be represented by negative values and hence, we can modify the default behavior of the int data type as follows: unsigned int age; This declaration allows the age variable to store only positive values. An immediate effect is that the range changes from (-32768 to 32767) to (0 to 65536) long Many times in our programs we would want to store values beyond the storage capacity of the basic data types. In such cases we use the data type modifier long. This doubles the storage capacity of the data type being used. E.g. long int annualsalary will make the storage capacity of variable annualsalary to 4 exception to this is long double, which modifies the size of the double data type to 10 bytes. The bytes. Please note that in some compilers this has no effect. short If long data type modifier doubles the size, short on the other hand reduces the size of the data type to half. Please refer to the example of age variable to explain the concept of data type modifiers. The same will be achieved by providing the declaration of age as follows: short int age; This declaration above, will provide the variable age with only 1 byte and its data range will be from -128 to 127.

www.thinklabs.in

Page 32

Embedded Systems

Type Qualifiers
Type qualifiers include the keywords: const and volatile. The const qualifier places the assigned variable in the constant data area of memory which makes the particular variable unmodifiable (technically it still is though). volatile is used less frequently and tells the compiler that this value can be modified outside Since 'Standard C' (C89), all the control of the program. variables are considered "unqualified" if none of the available qualifiers is used in the definition of the variable. Additionally, since all three qualifiers are completely independent from one another, for each unqualified simple type, we may have seven (23 1) forms of qualified types. Beware that qualifiers change the properties of their variables only for the scope and context in which they are used. A variable declared 'const' is a constant only as far as the current scope and context is concerned. If we widen the scope (and regard, for instance, the callers of the function) or the context (for instance, other threads or tasks, interrupt service routines, or different autonomous systems), the Const variable may 'const' is most often used in modern 'volatile' and 'restrict', similar understood. The The qualifier very well be not constant at all. For programs, and probably best arguments exist addition of a 'const' qualifier indicates that the (relevant part of the) program may not modify the variable. Such variables may even be placed in read-only storage (cf. section ""). It also allows certain kinds of optimizations, based on the premise that the variables value cannot change. Please note, however, that "const-ness" may be cast away explicitly. Since 'const' variables cannot change their value during runtime (at least not within the scope and context considered), they must be initialized at their point of definition. Example: const int i = 5; An alternate form is also acceptable, since the order of type specifiers and qualifiers does not matter: int const i = 5; Order becomes important when composite types with pointers are used: int * const cp = &i; /* const pointer to int */ const int * ptci; /* pointer to const int */ int const * ptci; /* pointer to const int */ The pointer cp is itself const, i.e. the pointer cannot be modified; the integer variable it points to can. The pointer ptci can be modified, however, the variable it points to cannot. Using typedef complicates the placement issue even more: typedef int * ip_t; const ip_t cp1 = &i; /* const pointer to int */ ip_t const cp2 = &i; /* const pointer to int!! */ www.thinklabs.in

Page 33

Embedded Systems

Casting away 'const-ness' is possible, but considered dangerous. Modifying a const-qualified variable in that way is not only dangerous, but may even lead to run-time errors, if the values are placed in read-only storage: const int * ptci; int *pti, i; const int ci; ptci = pti = &i; ptci = &ci; *ptci = 5; /* Compiler error */ pti = &ci; /* Compiler error */ pti = ptci; /* Compiler error */ pti = (int *)&ci; /* OK, but dangerous */ *pti = 5; /* OK, dangerous and potential runtime error */

Placement Placement of variables in actual memory is hardly standardized, because of the many requirements of specific compilers, processor architectures and requirements. But especially for const-qualified variables, it is a very interesting topic, and needs some discussion. First of all, placement is compilerspecific. This means, that a compiler may specify how a programmer or system architect may direct the linker an loader as to where to place which variables or categories of variables. This may be done using extra configuration files, or using #pragma's, or some other way. Refer to your compiler manual, especially when writing code for embedded systems. If you revert to the compiler defaults, the compiler/linker/loader1 may put const-qualified variables (not such combinations like 'pointer-toconst', since here the variable is a 'pointer' and non-const!) into readonly storage. If the compiler has no other indication, and can oversee the full scope of the variable (for instance, a static const int const_int = 5; at the global level in some C source file), it may even optimize in such a way, that the variable If the compiler retains the variable as such (i.e. the variable is still present in the object-file), effectively qualified (replacing each occurrence with an immediate value), though not all compilers provide disappears with the property 'const', the linker combines all corresponding references throughout all modules this into kind of optimization. one, complaining if the qualifications do not match, and the loader gets to decide, where the variable is placed in memory (dynamic linkers are even more complex, and disregarded here). If a memory area with read-only storage is available, const-qualified variables may end up there, at the discretion of the Volatile loader. The qualifier 'volatile' is normally avoided, understood only marginally, and quite often forgotten. It indicates to the compiler, that a variable may be modified outside the scope of the program. Such situations may occur for example in multitasking/-threading systems, when writing drivers with interrupt service routines, or in embedded systems, where the peripheral registers may also be modified by hardware alone. The following fragment is a classical example of an endless loop: int ready = 0; www.thinklabs.in

Page 34

Embedded Systems

while (!ready); An aggressively optimizing compiler may very well create a simple endless loop (Microsoft Visual Studio 6.0, Release build with full optimization): $L837: ;5: ;6: 00000 eb fe int ready = 0; while (!ready); jmp SHORT $L837

If we now add 'volatile', indicating that the variable may be changed out of context, the compiler is not allowed to eliminate the variable entirely: volatile int ready = 0; while (!ready); becomes (using the option "favor small code"): ;5:volatile int ready = 0; 00004 33 c0 xor eax, eax 00006 89 45 mov DWORD PTR _ready$[ebp], eax $L845: ; 6 : while (!ready); 00009 39 45 fc cmp DWORD PTR _ready$[ebp], eax 0000c 74 fb je SHORT $L845

As you can see, even with aggressive, full optimization, the code still checks the variable every time through the loop. Most compilers do not optimize this aggressively by default, but it is good to know that it is possible. The ordering issues as discussed in the section for the qualifier 'const' also apply for 'volatile'. When do you need to use 'volatile'? The basic principle is simple: Every time when a variable is used in more than one context, qualify it with 'volatile': Whenever you use a common variable in more than one task or thread; Whenever you use a variable both in a task and one or more interrupt service routines; Whenever a variable corresponds to processor-internal registers configured as input (consider the processor or external hardware to be an extra context). Does it hurt to use 'volatile' unnecessarily? Well, yes and no. The functionality of your code will still be correct. However, the timing and memory footprint of your application will change: Your program will run slower, because of the extra read operations, and your program will be larger, since the compiler is not allowed to optimize as thoroughly, although that would have been possible. Why dont we declare all variables 'volatile'? Well, we partially do: On DEBUG-builds, all optimization is usually disabled. This is not quite the www.thinklabs.in Page 35 same,

Embedded Systems

since the read operations needed extra are not necessarily inserted, but for most practical purposes, no optimizations involving the (missing) 'volatile' qualification are executed. This can be considered at least partially equivalent. We dont, however, deliver DEBUG-builds to the customer: They usually are too big and too slow (among a few other properties), just like if we declare all variables to be 'volatile'. But, whenever in doubt, it is better to use 'volatile' unnecessarily, than to forget it when really necessary. Combining qualifiers In the introduction the existence of seven different qualified types for each (simple) unqualified one has been stated. Using three qualifiers, this means that qualifiers can be combined. In C89, each qualifier may only be used once, in C99, multiple occurrences of each single qualifier are explicitly allowed and silently ignored. But now, take 'volatile' and 'const': What does it mean to have a variable qualified with both: const volatile unsigned int * const ptcvi = 0xFFFFFFCAUL; OK, the initialization value is hexadecimal, unsigned long, and taken from an imaginary embedded processor. The pointer is const, so I cannot change the pointer. And the value it points to is "const volatile unsigned int": I cannot change the value (within my current scope and context), and the value may be changed out of context. So, imagine a free running counter, counting upwards from 0 to 65535 (hexadecimal 0xFFFF or 16 bit), and rolling over again to 0. If this counter is automatically started by the hardware, or started by the (assembly-coded) startup-routine (outside the cope of the C program), is never stopped, and only used for relative time measurements, we have exactly this situation: The counter is read-only, so I want the compiler to supervise all programmers, that they do not try to write the counter register. At the same time, the value is constantly changed, so if I want to use the value, the compiler better make sure to re-read the value in every single case.You can also imagine a battery backed-up clock chip, running autonomously, with values for the current date and time memory-mapped into the processors virtual memory space. OK, such situations will not occur every day, and for many programmers they will never occur. But it is not unimaginable. And now go out and ask the most experienced C programmer you know, whether It is possible, allowed and/or useful. Youll be amazed about the answers youll get (or maybe not).

Thinking about Bits

The byte is the lowest level at which we can access data; there's no "bit" type, and we can't ask for an individual bit. In fact, we can't even perform operations on a single bit -- every bitwise operator will be applied to, at a minimum, an entire byte at a time. This means we'll be considering the whole representation of a number whenever we talk about applying a bitwise operator. (Note that this doesn't mean we can't ever change only one bit at a time; it just means we have to be smart about how we do it.) Understanding what it means to apply a bitwise operator to an entire string of bits is probably www.thinklabs.in Page 36 easiest to see with the shifting operators. By convention, in C and C++ you can think about binary numbers as starting with the most significant bit to the left (i.e., 10000000 is 128, and 00000001 is 1).

Embedded Systems

Regardless of underlying representation, you may treat this as true. As a consequence, the results of the left and right shift operators are not implementation dependent for unsigned numbers (for signed numbers, the right shift operator is implementation defined). The leftshift operator is the equivalent of moving all the bits of a number a specified number of places to the left:
[variable]<<[number of places]

For instance, consider the number 8 written in binary 00001000. If we wanted to shift it to the left 2 places, we'd end up with 00100000; everything is moved to the left two places, and zeros are added as padding. This is the number 32 -- in fact, left shifting is the equivalent of multiplying by a power of two.
int mult_by_pow_2(int number, int power) { return number<<power; }

Note that in this example, we're using integers, which are either 2 or 4 bytes, and that the operation gets applied to the entire sequence of 16 or 32 bits. But what happens if we shift a number like 128 and we're only storing it in a single byte: 10000000? Well, 128 * 2 = 256, and we can't even store a number that big in a byte, so it shouldn't be surprising that the result is 00000000. It shouldn't surprise you that there's a corresponding right-shift operator: >> (especially considering that I mentioned it earlier). Note that a bitwise right-shift will be the equivalent of integer division by 2. Why is it integer division? Consider the number 5, in binary, 00000101. 5/2 is 2.5, but if you are performing integer division, 5/2 is 2. When you perform a right shift by one: (unsigned int)5>>1, you end up with 00000010, as the rightmost 1 gets shifted off the end; this is the representation of the number 2. Note that this only holds true for unsigned integers; otherwise, we are not guaranteed that the padding bits will be all 0s. Generally, using the left and write shift operators will result in significantly faster code than calculating and then multiplying by a power of two. The shift operators will also be useful later when we look at how to manipulating individual bits. For now, let's look at some of the other binary operators to see what they can do for us.

Bitwise AND
The bitwise AND operator is a single ampersand: &. A handy mneumonic is that the small version of the www.thinklabs.in Page 37 boolean AND, &&, works on smaller pieces (bits instead of bytes, chars, integers, etc). In essence, a

Embedded Systems

binary AND simply takes the logical AND of the bits in each position of a number in binary form. For instance, working with a byte (the char type):
01001000 & 10111000 = -------00001000

The most significant bit of the first number is 0, so we know the most significant bit of the result must be 0; in the second most significant bit, the bit of second number is zero, so we have the same result. The only time where both bits are 1, which is the only time the result will be 1, is the fifth bit from the left. Consequently,
72 & 184 = 8

Bitwise OR
Bitwise OR works almost exactly the same way as bitwise AND. The only difference is that only one of the two bits needs to be a 1 for that position's bit in the result to be 1. (If both bits are a 1, the result will also have a 1 in that position.) The sybmol is a pipe: |. Again, this is similar to boolean logical operator, which is ||.
01001000 | 10111000 = -------11111000

and consequently
72 | 184 = 248

Let's take a look at an example of when you could use just these four operators to do something potentially useful. Let's say that you wanted to keep track of certain boolean attributes about something -- for instance, you might have eight cars (!) and want to keep track of which are in use. Let's assign each of the cars a number from 0 to 7. Since we have eight items, all we really need is a single byte, and we'll use each of its eight bits to indicate whether or not a car is in use. To do this, we'll declare a char called in_use, and set it to zero. (We'll assume that none of the cars are initially "in use".)
char in_use = 0;

Now, how can we check to make sure that a particular car is free before we try to use it? Well, we need to isolate the one bit that corresponds to that car. The strategy is simple: use bitwise operators to ensure every bit of the result is zero except, possibly, for the bit we want to extract. Consider trying to extract the fifth bit from the right of a number: XX?XXXXX We want to know what the question mark is, and we aren't concerned about the Xs. We'd like to be sure that the X bits don't interfere with our result, so we probably need to use a bitwise AND of some kind to make sure they www.thinklabs.in Page 38 are

Embedded Systems

all zeros. What about the question mark? If it's a 1, and we take the bitwise AND of XX?XXXXX and 00100000, then the result will be 00100000:
XX1XXXXX & 00100000 = -------00100000

Whereas, if it's a zero, then the result will be 00000000:


XX0XXXXX & 00100000 = -------00000000

So we get a non-zero number if, and only if, the bit we're interested in is a 1. This procedure works for finding the bit in the nth position. The only thing left to do is to create a number with only the one bit in the correct position turned on. These are just powers of two, so one approach might be to do something like:
int is_in_use(int car_num) { // pow returns an int, but in_use will also be promoted to an int // so it doesn't have any effect; we can think of this as an operation // between chars return in_use & pow(2, car_num); }

While this function works, it can be confusing. It obscures the fact that what we want to do is shift a bit over a certain number of places, so that we have a number like 00100000 -- a couple of zeros, a one, and some more zeros. (The one could also be first or last -- 10000000 or 00000001.) We can use a bitwise leftshift to accomplish this, and it'll be much faster to boot. If we start with the number 1, we are guaranteed to have only a single bit, and we know it's to the far-right. We'll keep in mind that car 0 will have its data stored in the rightmost bit, and car 7 will be the leftmost.
int is_in_use(int car_num) { return in_use & 1<<car_num; }

Note that shifting by zero places is a legal operation -- we'll just get back the same number we started with. All we can do right now is check whether a car is in use; we can't actually set the in-use bit for it. There are two cases to consider: indicating a car is in use, and removing a car from use. In one case, we need to turn a bit on, and in the other, turn a bit off. Let's tackle the problem of turning the bit on. What does this suggest we should do? If we have a bit set to zero, the only way we know right now to set it to 1 is to do a bitwise OR. Conveniently, if we perform www.thinklabs.in Page 39 a bitwise OR with only a single bit set to 1 (the rest are 0), then we won't affect the rest of the number

Embedded Systems

because anything ORed with zero remains the same (1 OR 0 is 1, and 0 OR 0 is 0). Again we need to move a single bit into the correct position: void set_in_use(int car_num) { in_use = in_use | 1<<car_num; } What does this do? Take the case of setting the rightmost bit to 1: we have some number 0XXXXXXX | 10000000; the result, 1XXXXXXX. The shift is the same as before; the only difference is the operator and that we store the result. Setting a car to be no longer in use is a bit more complicated. For that, we'll need another operator.

The Bitwise Complement


The bitwise complement operator, the tilde, ~, flips every bit. A useful way to remember this is that the tilde is sometimes called a twiddle, and the bitwise complement twiddles every bit: if you have a 1, it's a 0, and if you have a 0, it's a 1. This turns out to be a great way of finding the largest possible value for an unsigned number:
unsigned int max = ~0;

0, of course, is all 0s: 00000000 00000000. Once we twiddle 0, we get all 1s: 11111111 11111111. Since max is an unsigned int, we don't have to worry about sign bits or twos complement. We know that all 1s is the largest possible number. Note that ~ and ! cannot be used interchangeably. When you take the logical NOT of a non-zero number, you get 0 (FALSE). However, when you twiddle a non-zero number, the only time you'll get 0 is when every bit is turned on. (This non-equivalence principle holds true for bitwise AND too, unless you know that you are using strictly the numbers 1 and 0. For bitwise OR, to be certain that it would be equivalent, you'd need to make sure that the underlying representation of 0 is all zeros to use it interchangeably. But don't do that! It'll make your code harder to understand.) Now that we have a way of flipping bits, we can start thinking about how to turn off a single bit. We know that we want to leave other bits unaffected, but that if we have a 1 in the given position, we want it to be a 0. Take some time to think about how to do this before reading further. We need to come up with a sequence of operations that leaves 1s and 0s in the non-target position unaffected; before, we used a bitwise OR, but we can also use a bitwise AND. 1 AND 1 is 1, and 0 AND 1 is 0. Now, to turn off a bit, we just need to AND it with 0: 1 AND 0 is 0. So if we want to indicate that car 2 is no longer in use, we want to take the bitwise AND of XXXXX1XX with 11111011. How can we get that number? This is where the ability to take the complement of a number comes in handy: we already know how to turn a single bit on. If we turn one bit on and take the complement of the number, we get every bit on except that bit: www.thinklabs.in Page 40
~(1<<position)

Embedded Systems

Now that we have this, we can just take the bitwise AND of this with the current field of cars, and the only bit we'll change is the one of the car_num we're interested in.
int set_unused(int car_num) { in_use = in_use & ~(1<<position); }

You might be thinking to yourself, but this is kind of clunky. We actually need to know whether a car is in use or not (if the bit is on or off) before we can know which function to call. While this isn't necessarily a bad thing, it means that we do need to know a little bit about what's going on. There is an easier way, but first we need the last bitwise operator: exclusive-or.

Bitwise Exclusive-Or (XOR)


There is no boolean operator counterpart to bitwise exclusive-or, but there is a simple explanation. The exclusive-or operation takes two inputs and returns a 1 if either one or the other of the inputs is a 1, but not if both are. That is, if both inputs are 1 or both inputs are 0, it returns 0. Bitwise exclusive-or, with the operator of a carrot, ^, performs the exclusive-or operation on each pair of bits. Exclusive-or is commonly abbreviated XOR. For instance, if you have two numbers represented in binary as 10101010 and 01110010 then taking the bitwise XOR results in 11011000. It's easier to see this if the bits are lined up correctly:
01110010 ^ 10101010 -------11011000

You can think of XOR in the following way: you have some bit, either 1 or 0, that we'll call A. When you take A XOR 0, then you always get A back: if A is 1, you get 1, and if A is 0, you get 0. On the other hand, when you take A XOR 1, you flip A. If A is 0, you get 1; if A is 1, you get 0. So you can think of the XOR operation as a sort of selective twiddle: if you apply XOR to two numbers, one of which is all 1s, you get the equivalent of a twiddle. Additionally, if you apply the XOR operation twice -- say you have a bit, A, and another bit B, and you set C equal to A XOR B, and then take C XOR B: you get A XOR B XOR B, which essentially either flips every bit of A twice, or never flips the bit, so you just get back A. (You can also think of B XOR B as cancelling out.) As an exercise, can you think of a way to use this to exchange two integer variables without a temporary variable? (Once you've figured it out, check the solution.) How does that help us? Well, remember the first principle: XORing a bit with 0 results in the same bit. So what we'd really like to be able to do is just call one function that flips the bit of the car we're interested in -- it doesn't matter if it's being turned on or turned off -- and leaves the rest of the bits unchanged. www.thinklabs.in Page 41

Embedded Systems

This sounds an awful lot like the what we've done in the past; in fact, we only need to make one change to our function to turn a bit on. Instead of using a bitwise OR, we use a bitwise XOR. This leaves everything unchanged, but flips the bit instead of always turning it on:
void flip_use_state(int car_num) { in_use = in_use ^ 1<<car_num; }

When should you use bitwise operators?


Bitwise operators are good for saving space -- but many times, space is hardly an issue. And one problem with working at the level of the individual bits is that if you decide you need more space or want to save some time -- for instance, if we needed to store information about 9 cars instead of 8 -then you might have to redesign large portions of your program. On the other hand, sometimes you can use bitwise operators to cleverly remove dependencies, such as by using ~0 to find the largest possible integer. And bit shifting to multiply by two is a fairly common operation, so it doesn't affect readability in the way that advanced use of bit manipulation can in some cases (for instance, using XOR to switch the values stored in two variables). There are also times when you need to use bitwise operators: if you're working with compression or some forms of encryption, or if you're working on a system that expects bit fields to be used to store boolean attributes.

Summary
You should now be familiar with six bitwise operators: Works on bits for left argument, takes an integer as a second argument
bit_arg<<shift_arg

Shifts bits to of bit_arg shift_arg places to the left -- equivalent to mulitplication by 2^shift_arg
bit_arg>>shift_arg

Shifts bits to of bit_arg shift_arg places to the right -- equivalent to integer division by 2^shift_arg Works on the bits of both arguments
left_arg & right_arg

Takes the bitwise AND of left_arg and right_arg


left_arg ^ right_arg

Takes the bitwise XOR of left_arg and right_arg www.thinklabs.in

Page 42

Embedded Systems

left_arg | right_arg

Works on the bits of only argument


~arg

Reverses the bits of arg Skills and knowledge You also know a couple of neat tricks that you can use when performance is critical, or space is slow, or you just need to isolate and manipulate individual bits of a number. And you now should have a better sense of what goes on at the lowest levels of your computer.

C Programming Assignments:

1. Add two integers. 2. Compute powers of 2 up to nth power. 3. Create the Pattern * ** *** 4. Create the Pattern (pascal triangle) * ** ***

5. Find out the sum of even and odd numbers upto nth number 6. Swap two numbers without using third variable 7. Compute the factorial of a number 8. Determine if a number is a prime 9. Find all the proper factors of a number 10. Compute Fibonacci series 11. Write a menu driven program to calculate a+b,a-b,a%b,a/b 12. Find the reverse of a number 13. Find the sum of all elements in an integer array 14. Reverse an integer array 15. Find the biggest and smallest number in an array 16. Printing only the Block Letters in an array 17. Convert all the Block letters to small letters and vice versa in an array 18. Print the no: of occurrences of a character in an array 19. Write a menu driven program for a. Addition b. Subtraction
www.thinklabs.in Page 43

Embedded Systems

c. Multiplication 20. Transpose of a matrix 21. Sum of the diagonal elements of a matrix 22. Compare two character arrays 23. Read a line from input and echo that to output 24. Write a program to implement a menu driven program with security password 25. Write a program to generate Fibonacci series consisting of COUNT number of elements using recursion. 26. Write a program to detect the number of times a character appears in a string entered by a user. 27. Write a program to reverse a string. 28. Write a program to convert an integer from decimal to binary. 29. Write a program to input two 3x3 matrices from user and display the sum and product of the matrices. 30. Write a program to find the transpose of a square matrix of order n entered by the user. 31. Write a program to store user inputted strings in a 2D character array and rearrange the strings in alphabetical order. (Hint: use Strcmp). 32. Write a program to make the user enter a sentence and display those words which contain a particular character. 33. Write a program to swap two variables without using a third variable. 34. Write a program to detect if the number entered by the user is a prime number or not. 35. Write a program to find the GCD and LCM of 2 numbers. 36. Write a program to determine if the string entered by the user is a palindrome or not. 37. Write a program to find the product of digits of a number entered by a user. 38. Write a program to find whether a number is even or odd without using the modulo (%) operator. 39. Write a program to append two arrays of variable size and return the appended array. 40. Write a program to implement linear search for an element in an unsorted array. Dynamically allocate elements of the array. (Hint: Use pointer)

www.thinklabs.in

Page 44

Embedded Systems

Definitions of Embedded systems:


Using the term "Embedded Systems" in our name is confusing to some. In this case, people either have no idea what the term means - or they have a very strict definition in mind, such as "assembly language on a chip". But the work that we do is so much broader than that! A general-purpose definition of embedded systems is that they are devices used to control, monitor or assist the operation of equipment, machinery or plant. "Embedded" reflects the fact that they are an integral part of the system. In many cases their embedded nature may be such that their presents is far from obvious to the casual observer and even the more technically skilled might need to examine the operations of a piece of equipment for some time before being able to conclude that an embedded control system was involved in its function. " Huh?.....Doesnt this sound like Blah Blah Blah Blah Blah Lets make it very simple An embedded system is a special-purpose computer system designed to perform one or a few dedicated functions, often with real-time computing constraints. It is usually embedded as part of a complete device including hardware and mechanical parts. In contrast, a general-purpose computer, such as a personal computer, can do many different tasks depending on programming. Embedded systems control many of the common devices in use today. Another one: Any electronic system that uses a computer chip, but that is not a general-purpose workstation, desktop or laptop computer. Such systems use microcontrollers (MCUs) or microprocessors (MPUs), or they may use custom-designed chips. Deployed by the billions each year in myriad applications, the embedded systems market uses the lion's share of all the electronic components in the world. Most of the definitions of embedded systems revolve around the idea of it being a general purpose computer designed to perform a specific task.

www.thinklabs.in

Page 45

Embedded Systems

Uses: Embedded systems are employed in automobiles, planes, trains, space vehicles, machine tools, cameras, consumer electronics, office appliances, network appliances, video games, cell phones, PDAs, GPS navigation as well as robots and toys. Low-cost consumer products can use microcontroller chips that cost less than a dollar. Characteristics: 1) Embedded systems are designed to do some specific task, rather than be a generalpurpose computer for multiple tasks. Some also have real time performance constraints that must be met, for reasons such as safety and usability; others may have low or no performance requirements, allowing the system hardware to be simplified to reduce costs. 2) Embedded systems are not always standalone devices. Many embedded systems consist of small, computerized parts within a larger device that serves a more general purpose. For example, the Gibson Robot Guitar features an embedded system for tuning the strings, but the overall purpose of the Robot Guitar is, of course, to play music. Similarly, an embedded system in an automobile provides a specific function as a subsystem of the car itself. 3) The program instructions written for embedded systems are referred to as firmware, and are stored in read-only memory or Flash Memory chips. They run with limited computer hardware resources: little memory, small or non-existent keyboard and/or screen.

Listing buzz-words (Micro-controllers, micro-processors, ARM, Thumb, AVR, PIC, 8051, OS, Real time, RTOS, firmware, Linux, RT Linux, Assembly language, C, Java, BSP, Endian-ness, (cross)compiler, CISC, RISC, Debugger, Emulator, Simulator, POSIX, MISRA, Device driver, Programmer, Flash, DSP, platform, architecture, system Programmer, system software, application software, GUI, HMI, fuzzy logic, GNU, kernel, scheduler, context switch, data structures, linker, locator, multi-processing, multi-tasking, multithreading, interrupts, hex code, object code, polling, pre-emption, protocol stack, TCP/IP, CAN, I2C, SPI, Zigbee, profiler, reentrant, recursive, simulator, interpreter, UML, Vxworks, Watchdog, Wince, FSF, open source, closed source)

www.thinklabs.in

Page 46

Embedded Systems

These are some of the Buzz Words that one comes across whenever we talk about Embedded Systems. The Layered Architecture categorizes them into different layers. The layered Architecture:

Architecture Exclusions

Since embedded system use microcontrollers (MCUs), lets get to know microcontrollers more into details: www.thinklabs.in Page 47

Embedded Systems

Get a feel of Microcontrollers


Microcontrollers are, for us robotists, a godsend. They showed us how we can make interesting projects in the seemingly dull course structure. They had us addicted to the pure pleasure of creating things and made us feel powerful. They gave us the first glimpses of what its like to be an Engineer. How did such a thing as a microcontroller come into existence? Was it an outcome of an experiment meant for something else or did anyone conceptualize it long before its birth? Microcontrollers could be understood very easily by reading some very good books. But understanding its history will make you feel more closer. This is an attempt to that effect. Lets have a look at what it was like before the microcontrollers. The computers started getting recognition during the 2nd World War. They were made of vacuum tubes and switches. Needless to say, they were BIG! John Bardeen, Walter Brattain and William Shockley discovered the transistor effect and developed the first device in December 1947, while the three were members of the technical staff at Bell Laboratories in Murray Hill, NJ. In 1950's Shockley leaves Bell Labs to establish Shockley Labs in California. Some of the best young electronic engineers and solid-state physicists come to work with him. These include Robert Noyce and Gordon Moore. Intel was started-up in 1969 in Santa Clara, headed by Noyce and Moore. In 1970, A Japanese company, Busicom placed an order with Intel for custom calculator chips. But Intel had problems working with the chip designs. Whiz Federico Faggin joins Intel and solves the problems in weeks. The result is the 4004, a 4-bit processor. This is how the Busicom calculator looked like. It is the 1st comercial product which uses a microprocessor.

Riding on its success, Intel begins its work on an 8bit microprocessor 8008, and soon after that, 8080. Both these devices were well recieved. Suddenly there was a surge of interest in microprocessors. Fagin left Intel to form his own company, Zilog. Z80, an 8-bit microprocessor was the 1st product of Zilog. www.thinklabs.in Page 48

Embedded Systems

Motorola, a car radio company, jumps into the field of microprocessors with its 6800 an 8-bit microprocessor. Note that microcontrollers were not invented yet! All these devices were microprocessors. In 1976- Intel introduce an 8-bit microcontroller, the MCS-48. 4 years later, Intel comes up with another 8-bit microcontroller the 8051. This was a legend. Variants of the 8051 are still used dearly by many people. Later, Intel kept the architecture of 8051 on market. Many companies adopted this architecture and started making variants of 8051. The momentum kept growing. And Companies like Atmel and Microchip are coming out with more advanced microcontrollers like AVR and PIC respectively. George Moore, co-founder of Intel, predicted that the number of transistors on a chip will double every year. This was just an observation, which happened to be true during the last two decades. It is famously known as Moores Law. The quest for better and bigger processors continued. Today, we have attained the expertise to design a 64-bit microprocessor. So lets answer some questions that we call silly, but still need to be cleared.. What is a microprocessor? Microprocessor is a collection of commonly used functions, (like arithmetic operations, logical operations..) integrated in an IC. This device enables us to use these function on our choice of data, in any order we want, any number of times. That is why we call it a general purpose device. Then what is a microcontroller? Microprocessors lack the ability to store data permanently. Hence it needs to be connected to external memories for essential operations. Hence, microprocessor cannot be used as a stand-alone device. This generated the need for microcontrollers. Microcontrollers come with a microprocessor and memory integrated in a single IC. Microcontrollers are also packed with other features like I/O pins, timers etc.. Different families of Microcontrollers Some widely used families and what communities have to say about them (courtesy: Spark fun electronics) 8051 - The '8051 core' was the de facto standard in 8-bit (and 4-bit!) microcontrollers. Developed by Intel in the 1980s, it still seems to be the instruction set they love to teach you in college. They are based on archaic, but field proven instruction sets. Very old tech in my humble opinion, but these ICs www.thinklabs.in Page 49 have been significantly improved over the years (now Flash based, ADC, SPI, etc.).

Embedded Systems

68HC08/11 - Another very common instruction set developed by Motorola. Extremely popular, and a micro commonly taught at university, it's the microcontroller I love to hate. These original micros often lack on-board RAM and flash based memory. PIC - This is the classic micro from Microchip. Very simple, very proven, but it lacks many of the features that other mfg's are building into their chips. This is a big deal for me. I was a die-hard PIC person for years and I've started to see the limits of PICs and the benefits of other micros! AVR - This (Atmel) is basically a direct competitor of PICs. They do everything a PIC does, but in my new opinion, better, faster, cheaper, and simpler. MSP - These are very good micros by Texas Instruments (TI), not as beefy as AVR or PICs. However they truly excel at low-power applications. More on this later, but imagine running a complete system on one AA battery for 5 years. This is in the realm of nano-amp current consumption years. Crazy! ARM - Why are all these three letters? I don't know actually... ARMs are the new kids on the block and they are huge. Very powerful, very low-cost, extremely low power consumption they are taking over the world (85% of 32-bit market is owned by ARM) but can be really intimidating if you've never played with a micro before. Overkill in majority of applications except mobiles, consumer multimedia items and SBCs

Getting used to AVR


The 1st Feature that needs to be learnt in any microcontroller is its Input-Output function. ATmega128 has a total of 64 pins. Of these, 53 pins can be used as Input or Outputs. These pins are divided into 7 ports : PORT PORT PORT PORT PORT PORT PORT ABCDEFG8 8 8 8 8 8 5 pins pins pins pins pins pins pins

Each of these pins can can be individually programmed as Inputs or Outputs. So you can use all 53 pins as input or all 53 pins as outputs or any how... But there are some steps that we need to perform to configure the pins as either. Each port is associated with 3 registers: DDRx, PORTx, PINx. Each bit of these registers correspond to www.thinklabs.in Page 50 each pin of the port.

Embedded Systems

For example, the pin 3 of port D is associated with BIT 3 of DDRD, BIT 3 of PORTD and BIT 3 of PIND Here, we review how to configure pins as required.

Output:
DDRx: Data Direction Register Whichever pin is supposed to be an output, write 1 in the corresponding DDRx bit. PORTx: Write whatever data that needs to be output in the corresponding pins. Example: Make pins 1,2,3 and 4 of PORTB as an output port and write 1 0 1 0 on those pins respectively: DDRB: 7 6 5 4 3 2 1 0 Data: 0 0 0 1 1 1 1 0 = 1E (Hexadecimal)

-----------------------------------------------------------------------------------------------------------------------------------PORTB: 7 Data: 0 6 0 5 0 4 1 3 0 2 1 1 0 0 0 = 14 (Hexadecimal)

Code: DDRD = 0x1E; PORTD = 0x14;

Input:
DDRx: Data Direction Register Whichever pin is supposed to be an input, write 0 in the corresponding DDRx bit. PORTx: To enable pull up registers, (which should always be done if not for any special cases), write 1 in the corresponding PORTx bit. PINx: Read the input of the pins at the corresponding bits. Example: Configure the pins 0,1,2 & 3 of port D as input and read the value at the pins. DDRD: 7 6 5 4 3 2 1 0 Data: 0 0 0 0 0 0 0 0 = 00 (Hexadecimal)

-----------------------------------------------------------------------------------------------------------------------------------PORTB: 7 Data: 0 6 0 5 0 4 0 3 1 2 1 1 1 0 1 = 0F (Hexadecimal) Page 51

www.thinklabs.in

Embedded Systems

Code: DDRD = 0x00; PORTD = 0x0F; Value = PIND; //read status of Input Pins

Value = Value & 0x0F; //to mask the higher 4 bits.

The Concept of Pull Up Resistors:


Pull up resistors are used on the input side so that the input pins are at an expected logic level even if they are disconnected from the input switches. If Pull Up resistors are not used, the voltage level at the input pin will be floating in such a case and hence the outcome of the circuit is unpredictable. Consider the following circuit:
/ _____/ | | \/ GND -------| ---| ---| ------------|--|--|---

Here, a switch is connected at the input pin of a microcontroller. Note the absence of a pull up resistor. When the switch is closed, the pin is directly grounded and the input pin reads a logic level 0. Thus logic level 0 should indicate that the switch is closed. Now consider when the switch is open. The input pin is not connected to anything else, hence the pin in open. Thus the input pin is said to be kept floating. i.e. the voltage at the pin may vary from 0 V to 5V randomly. Thus we cannot be sure every time that when Now consider the circuit below: the logic at pin is 0, it is because of the closed switch or the floating voltage. Hence this circuit is not appropriate.
VCC /\ | | |-------------||-----||-----||---------

/ _____/ | | \/ GND

This circuit will eliminate our problem of floating pin. It is obvious that when the pin is open, the voltage at the input pin is Vcc. But now imagine what will happen if the switch is closed.. What do you think will the voltage be at the input pin? You dont have the time to calculate that! You have shorted Vcc and ground of your Power Supply! This is a very wrong method to eliminate our original problem of floating voltage. www.thinklabs.in Page 52

Embedded Systems

Now see whats happening here:


VCC /\ | | \ / Pull-up resistor \ | | |-------------||-----||-----||---------

/ _____/ | | \/ GND

When the switch is closed, the pin is directly connected to ground and reads logic level 0. When the switch is opened, the pin is connected to Vcc through a high value resistor; hence it reads a logic value 1. Thus, the use of pull up resistor has solved our problem. Note that a high value pull up resistor must be used to limit the current flow to ground when the switch is closed.

http://www.thinklabs.in T hi

www.thinklabs.in

Page 53

Embedded Systems

LCD PROGRAMMING
LCD or Liquid Crystal Display is nowadays fast becoming a preferred choice for an interface device due to its ease of use, cheap rates and value for money performance. Every LCD needs a LCD driver to interface between the microcontroller and LCD module. This driver is included on the LCD module. The LCD we are using is 16 X 2 LCD, which means 16 columns and 2 rows. 1 . . . . . . . . . . . . . . . . . . . . . . . . .16

The pin configuration of the LCD is given below:

The LCD uses three control lines. They are referred to as EN, RS, and RW. www.thinklabs.in Page 54

Embedded Systems

The EN line is called "Enable." This control line is used to tell the LCD that you are sending it data. To send data to the LCD, your program should make sure this line is low (0) and then set the other two control lines and/or put data on the data bus. When the other lines are completely ready, bring EN high (1) and wait for the minimum amount of time required by the LCD datasheet (this varies from LCD to LCD), and end by bringing it low (0) again. The RS line is the "Register Select" line. When RS is low (0), the data is to be treated as a command or special instruction (such as clear screen, position cursor, etc.). When RS is high (1), the data being sent is text data which should be displayed on the screen. For example, to display the letter "T" on the screen The RW line is the "Read/Write" control line. When RW is low (0), the information on the data bus is you would set RS high. being written to the LCD. When RW is high (1), the program is effectively querying (or reading) the LCD. Only one instruction ("Get LCD status") is a read command. All others are write commands--so RW will almost always be low.

4 Bit Mode:

The LCD can work in 8 bit parallel mode or a 4 bit mode. We will use the 4 bit mode as it reduces the number of pins and simplifies the circuit. The only difference with the 8bit version is DB0, DB1, DB2 and DB3 on the display module side. These lines are not connected to the processor. Leave those lines unconnected. In 4-bit mode, we have to read and write data bytes and command bytes in two separate 'nibbles' (4bit parts).

INITIALIZING THE LCD


Before you may really use the LCD, you must initialize and configure it. This is accomplished by sending a number of initialization instructions to the LCD. 1. The first instruction we send must tell the LCD we'll be communicating with it with a 4-bit data bus. We also select a 5x8 dot character font. These two options are selected by sending the command 28h to the LCD as a command. After powering up the LCD, it is in 8-bit mode. Because only four bits are connected, the LCD receives only 20 this sets it to the 4 bit mode. 2. We've now sent the first byte of the initialization sequence. The second byte of the initialization sequence is the instruction 0Fh. This command is sent to instruct Display on, Cursor blinking 3. Other commands may be sent in this way (higher nibble 1st. then lower nibble). Refer to table below for the command codes. 4. Now we are ready to send the data to be displayed in packs to two nibbles.

To initialize some more parameters, or otherwise, you can use the following command table: www.thinklabs.in Page 55

Embedded Systems

www.thinklabs.in

Page 56

Embedded Systems

Refer the following table for ASCII codes of characters.

www.thinklabs.in

Page 57

Embedded Systems

UART Universal Asynchronus Reciever Transmitter


Although it has a big name, this module of AVR is one of the easiest to use. UART is a protocol which has been standardized and commonly used by many devices. It is so popular, that even the serial port behind out computer CPUs uses this protocol to communicate with other devices. UART is a serial protocol, which means that it transmits data, one bit at a time. So, we need only on conductor to transmit data. It is a very use full practice of developers to use the UART as a debugging tool. When a connectivity between the PC and microcontroller is established, data could be obtained from PC or Displayed on the Monitor. Computers using Windows have a utility called has Hyper Terminal in their Start Menu > Programs > Accessories > Communications > Hyper Terminal. Linux users can use same type of utility called as GTKterm. Note that AVR actually has a USART module (Universal Synchronous Asynchronous Receiver Transmitter). But communication with the computer requires UART protocol. Hence we focus our attention on UART. This goes for all the features of AVR: All you need to do to start using the function is just configure the associated registers.
UART:

The initialization process normally consists of setting the baud rate, setting frame format and enabling the Transmitter or the Receiver depending on the usage.

USART Registers UCSRnA

Bit 7 RXCn: USART Receive Complete This flag bit is set when there are unread data in the receive buffer and cleared when the receive buffer is empty (i.e. does not contain any unread data). If the Receiver is disabled, the receive buffer will be www.thinklabs.in Page 58

Embedded Systems

flushed and consequently the RXC bit will become zero. The RXC Flag can be used to generate a Receive Complete interrupt. Bit 6 TXCn: USART Transmit Complete This flag bit is set when the entire frame in the Transmit Shift Register has been shifted out and there are no new data currently present in the transmit buffer (UDR). The TXC Flag bit is automatically cleared when a transmit complete interrupt is executed, or it can be cleared by writing a one to its bit location. The TXC Flag can generate a Transmit Complete interrupt. Bit 5 UDREn: USART Data Register Empty The UDRE Flag indicates if the transmit buffer (UDR) is ready to receive new data. If UDRE is one, the buffer is empty, and therefore ready to be written. The UDRE Flag can generate a Data Register Empty interrupt. UDRE is set after a reset to indicate that the Transmitter is ready. Bit 4 FEn: Frame Error This bit is set if the next character in the receive buffer had a Frame Error when received (i.e., when the first stop bit of the next character in the receive buffer is zero). This bit is valid until the receive buffer (UDR) is read. The FE bit is zero when the stop bit of received data is one. Always set this bit to zero when writing to UCSRA. Bit 3 DORn: Data OverRun This bit is set if a Data OverRun condition is detected. A Data OverRun occurs when the receive buffer is full (two characters), it is a new character waiting in the Receive Shift Register, and a new start bit is detected. This bit is valid until the receive buffer (UDR) is read. Always set this bit to zero when writing to UCSRA. Bit 2 PEn: Parity Error This bit is set if the next character in the receive buffer had a Parity Error when received and the parity checking was enabled at that point (UPM1 = 1). This bit is valid until the receive buffer (UDR) is read. Always set this bit to zero when writing to UCSRA. Bit 1 U2Xn: Double the USART transmission speed This bit only has effect for the asynchronous operation. Write this bit to zero when using synchronous operation. Bit 0 MPCMn: Multi-processor Communication Mode This bit enables the Multi-processor Communication mode. When the MPCM bit is written to one, all the incoming frames received by the USART Receiver that do not contain address information will www.thinklabs.in Page 59 be ignored. The Transmitter is unaffected by the MPCM setting.

Embedded Systems

UCSRnB

Bit 7 RXCIEn: RX Complete Interrupt Enable Writing this bit to one enables interrupt on the RXC Flag. A USART Receive Complete interrupt will be generated only if the RXCIE bit is written to one, the Global Interrupt Flag in SREG is written to one and the RXC bit in UCSRA is set. Bit 6 TXCIEn: TX Complete Interrupt Enable Writing this bit to one enables interrupt on the TXC Flag. A USART Transmit Complete interrupt will be generated only if the TXCIE bit is written to one, the Global Interrupt Flag in SREG is written to one and the TXC bit in UCSRA is set. Bit 5 UDRIEn: USART Data Register Empty Interrupt Enable Writing this bit to one enables interrupt on the UDRE Flag. A Data Register Empty interrupt will be generated only if the UDRIE bit is written to one, the Global Interrupt Flag in SREG is written to one and the UDRE bit in UCSRA is set. Bit 4 RXENn: Receiver Enable Writing this bit to one enables the USART Receiver. The Receiver will override normal port operation for the RxD pin when enabled. Disabling the Receiver will flush the receive buffer invalidating the FE, DOR and PE Flags. Bit 3 TXENn: Transmitter Enable Writing this bit to one enables the USART Transmitter. The Transmitter will override normal port operation for the TxD pin when enabled. The disabling of the Transmitter (writing TXEN to zero) will not become effective until ongoing and pending transmissions are completed (i.e., when the Transmit Shift Register and Transmit Buffer Register do not contain data to be transmitted). When disabled, the Transmitter will no longer override the TxD port. Bit 2 UCSZ2n: Character Size The UCSZ2 bits combined with the UCSZ1:0 bit in UCSRC sets the number of data bits (Character Size) in a frame the Receiver and Transmitter use. www.thinklabs.in Page 60

Embedded Systems

Bit 1 RXB8n: Receive Data Bit 8 RXB8 is the ninth data bit of the received character when operating with serial frames with nine data bits. Must be read before reading the low bits from UDR. Bit 0 TXB8n: Transmit Data Bit 8 TXB8 is the ninth data bit in the character to be transmitted when operating with serial frames with nine data bits. Must be written before writing the low bits to UDR.

UCSRnC

Bit 6 UMSELn: USART Mode Select This bit selects between Asynchronous and Synchronous mode of operation. Bit 5:4 UPMn1:0: Parity Mode These bits enable and set type of Parity Generation and Check. If enabled, the Transmitter will automatically generate and send the parity of the transmitted data bits within each frame. The Receiver will generate a parity value for the incoming data and compare it to the UPM0 setting. If a mismatch is detected, the PE Flag in UCSRA will be set. Bit 3 USBSn: Stop Bit Select This bit selects the number of stop bits to be inserted by the transmitter. The Receiver ignores this setting. Bit 2:1 UCSZn1:0: Character Size The UCSZ1:0 bits combined with the UCSZ2 bit in UCSRB sets the number of data bits (Character Size) in a frame the Receiver and Transmitter use. Bit 0 UCPOLn: Clock Polarity This bit is used for Synchronous mode only. Write this bit to zero when Asynchronous mode is used. The UCPOL bit sets the relationship between data output change and data input sample, and the synchronous clock (XCK). UMSEL bit setting www.thinklabs.in Page 61

Embedded Systems

UMSELn 0 1

Mode Asynchronous Operation Synchronous Operation

UPMn1 0 0 1 1

UPMn0 0 1 0 1

UPM Bits setting Mode Disabled Reserved Enable, Even Parity Enabled, Odd Parity

USBS Bit Setting USBSn 0 1 UCSZ Bits Setting UCSZn2 UCSZn1 0 0 0 0 1 1 1 1 0 0 1 1 0 0 1 1 UCSZn0 Character Size 0 1 0 1 0 1 0 1 5-bit 6-bit 7-bit 8-bit Reserved Reserved Reserved 9-bit Page 62 Stop Bits(s) 1-bit 2-bit

www.thinklabs.in

Embedded Systems

USBS 0 1

UCPOLn Bit Setting Transmitted Data Changed Received Data Sampled (Input on RxDn Pin) (Output of TxDn Pin) Falling XCKn Edge Rising XCKn Edge Falling XCKn Edge Rising XCKn Edge

UBRRnX

Bit 15:12 Reserved Bits These bits are reserved for future use. For compatibility with future devices, these bit must be written to zero when UBRRH is written. Bit 11:0 UBRR11:0: USART Baud Rate Register This is a 12-bit register which contains the USART baud rate. The UBRRH contains the four most significant bits, and the UBRRL contains the eight least significant bits of the USART baud rate. Ongoing transmissions by the Transmitter and Receiver will be corrupted if the baud rate is changed. Writing UBRRL will trigger an immediate update of the baud rate prescaler.

www.thinklabs.in

Page 63

Embedded Systems

Example of UBRR setting for commonly Used oscillator Frequencies (Continued)


Fosc = 20,0000 MHz U2X = 0 UBRR 520 259 129 86 64 42 32 21 15 10 4 4 Error 0.0% 0.2% 0.2% -0.2% 0.2% 0.9% -1.4% -1.4% 1.7% -1.4% 8.5% 0.0% U2X = 1 UBRR 1041 520 259 173 129 86 64 42 32 21 10 9 4 Error 0.0% 0.0% 0.2% -0.2% 0.2% -0.2% 0.2% 0.9% -1.4% -1.4% -1.4% 0.0% 0.0% -

Fosc = 16,0000 MHz Baud Rate (bps) U2X = 0 UBRR 2400 4800 9600 14.4k 19.2k 28.8k 38.4k 57.6k 76.8k 115.2k 230.4k 250k 0.5M 1M Max
(1)

Fosc = 18,4320 MHz U2X = 0 UBRR 479 239 119 79 59 39 29 19 14 9 4 4 Error 0.0% 0.0% 0.0% 0.0% 0.0% 0.0% 0.0% 0.0% 0.0% 0.0% 0.0% -7.8% U2X = 1 UBRR 959 479 239 159 119 79 59 39 29 19 9 8 4 Error 0.0% 0.0% 0.0% 0.0% 0.0% 0.0% 0.0% 0.0% 0.0% 0.0% 0.0% 2.4% -7.8% -

U2X = 1 UBRR 832 416 207 138 103 68 51 34 25 16 8 7 3 1 Error 0.0% -0.1% 0.2% 0.1% 0.2% 0.6% 0.2% -0.8% 0.2% 2.1% -3.5% 0.0% 0.0% 0.0% 2Mbps

Error -0.1% 0.2% 0.2% 0.6% 0.2% -0.8% 0.2% 2.1% 0.2% -3.5% 8.5% 0.0% 0.0% 0.0%

416 207 103 68 51 34 25 16 12 8 3 3 1 0

1Mbps

1.158 Mbps

2.304Mbps

1.25 Mbps

25 Mbps

Frame Formats : A serial frame is defined to be one character of data bits with synchronization bits (start and stop bits), and optionally a parity bit for error checking. The USART accepts all 30 combinations of the following as valid frame formats: 1 start bit 5, 6, 7, 8, or 9 data bits no, even or odd parity bit www.thinklabs.in 1 or 2 stop bits Page 64

Embedded Systems

A frame starts with the start bit followed by the least significant data bit. Then the next data bits, up to a total of nine, are succeeding, ending with the most significant bit. If enabled, the parity bit is inserted after the data bits, before the stop bits. When a complete frame is transmitted, it can be directly followed by a new frame, or the communication line can be set to an idle (high) state. Figure Below illustrates the possible combinations of the frame formats. Bits inside brackets are optional.

Frame Formats St ---Start bit, always low. (n) ----Data bits (0 to 8). P ----Parity bit. Can be odd or even. Sp ----Stop bit, always high. IDLE ----No transfers on the communication line (RxD or TxD). An IDLE line must be high. The frame format used by the USART is set by the UCSZ2:0, UPM1:0 and USBS bits in UCSRB and UCSRC. The receiver and transmitter use the same setting. Note that changing the setting of any of these bits will corrupt all ongoing communication for both the receiver and transmitter. The USART Character SiZe (UCSZ2:0) bits select the number of data bits in the frame. The USART Parity mode (UPM1:0) bits enable and set the type of parity bit. The selection between one or two stop bits is done by the USART Stop Bit Select (USBS) bit. The receiver ignores the second stop bit. An FE (Frame Error) will therefore only be detected in the cases where the first stop bit is zero.

www.thinklabs.in

Page 65

Embedded Systems

Some Functions for UART:


Since you have become comfortable with UART, Lets us look at some funtions that you may use from now in whenever you need to use it. A good practice is to save these funtions in a header file, say UART.h, and include the header file whenever you start writing the program. Functions for UART: unsigned char d1, d2, d3, d4, d5, k; // First define these variable globally, as they will be used for unsigned int temp; //the functions. void uart_init (void)//Function to initialise UART { UCSRB= (1<<TXCIE)|(1<<TXEN);//Transmission complete enable and transmission enable UCSRC= (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);//Select UART and 8 Bit mode UBRR=103;// Baud Rate = 9600 for 16Mhz Crystal }

void hextobcd(unsigned int hex) { d1 = hex / 10000; temp = hex % 10000; d2 = temp / 1000; temp = hex % 1000; d3 = temp / 100; temp = hex % 100; d4 = temp / 10; d5 = temp % 10; }

// Function to convert the hexadecimal number in decimal // // // // This is a famous method to seperate digits of a number by taking the quotient of its division by 10000, 1000, 100 and 10 to get the respective digits. Read and Understand the function

void trans(unsigned char t) // Function to transmit single character { UDR= t; // write the argument into the UDR to start transmission _delay_ms(2); } void transmit( unsigned char str[k]) { // Function to Transmit more than one character for (k=0; k<=9; k++) { trans(str[k]); // this function is just a loop form of the trans() function } // it treats the set of characters as a string and calls trans() for } // element of the string. // to change size of the string, change the number in the for // loop (here it is 9).

www.thinklabs.in

Page 66

Embedded Systems

ADC Analog to Digital Converter


As the name says, this module of the AVR converts an input analog signal to a digital signal. Why? All the microprocessors and microcontrollers are digital devices. This means that they only understand 1 and 0? Now how do you represent analog values in this format? For example, if I want to sense the temperature using a thermostat, how do I read its value? There should be a device which converts this analog output of the thermostat and send it to the controller in interpretable terms. This device is the ADC. ATmega8 has In Built 8 ADCs. In effect, I could connect 6 different thermostats to 8 pins of the ATmega8 and sense temperatures of 8 different places. Again, use of ADC boils down to the correct configuration of the following registers:

ADC Registers ADMUX

Bit 7:6 REFS1:0: Reference Selection Bits These bits select the voltage reference for the ADC. If these bits are changed during a conversion, the change will not go in effect until this conversion is complete (ADIF in ADCSRA is set). The internal voltage reference options may not be used if an external reference voltage is being applied to the AREF pin. Bit 5 ADLAR: ADC Left Adjust Result The ADLAR bit affects the presentation of the ADC conversion result in the ADC Data Register. Write one to ADLAR to left adjust the result. Otherwise, the result is right adjusted. Changing the ADLAR bit will affect the ADC Data Register immediately, regardless of any ongoing conversions. Bits 4:0 MUX4:0: Analog Channel Selection Bits The value of these bits selects which analog inputs are connected to the ADC. If these bits are changed during a conversion, the change will not go in effect until this conversion is complete (ADIF in ADCSRA is set). www.thinklabs.in Page 67

Embedded Systems

REFS1 0

Voltage Reference selections for ADC Voltage Reference Selection REFS0 0 AREF, Internal Vref turned off

REFS1 0 1 1

REFS0 1 0 1

Voltage Reference selections for ADC Voltage Reference Selection AVcc with external capacitor at AREF pin Reserved Internal 2.56V Voltage Reference with external capacitor at AREF pin

Input Channel Selections


MUX3..0 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111 Single Ended Input ADC0 ADC1 ADC2 ADC3 ADC4 ADC5 ADC6 ADC7 1.22V (VBG) 0V (GND)

www.thinklabs.in

Page 68

Embedded Systems

ADCSRA

Bit 7 ADEN: ADC Enable Writing this bit to one enables the ADC. By writing it to zero, the ADC is turned off. Turning the ADC off while a conversion is in progress, will terminate this conversion. Bit 6 ADSC: ADC Start Conversion In Single Conversion mode, write this bit to one to start each conversion. In Free Running mode, write this bit to one to start the first conversion. The first conversion after ADSC has been written after the ADC has been enabled, or if ADSC is written at the same time as the ADC is enabled, will take 25 ADC clock cycles instead of the normal 13. This first conversion performs initialization of the ADC. ADSC will read as one as long as a conversion is in progress. When the conversion is complete, it returns to zero. 5 ADFR: ADC Free Running Select Bit Writing zero to this bit has no effect. When this bit is set (one) the ADC operates in Free Running mode. In this mode, the ADC samples and updates the Data Registers continuously. Clearing this bit (zero) will terminate Free Running mode. Bit 4 ADIF: ADC Interrupt Flag This bit is set when an ADC conversion completes and the Data Registers are updated. The ADC Conversion Complete Interrupt is executed if the ADIE bit and the I-bit in SREG are set. ADIF is cleared by hardware when executing the corresponding interrupt Handling Vector. Alternatively, ADIF is cleared by writing a logical one to the flag. Beware that if doing a Read-Modify- Write on ADCSRA; a pending interrupt can be disabled. Bit 3 ADIE: ADC Interrupt Enable When this bit is written to one and the I-bit in SREG is set, the ADC Conversion Complete Interrupt is activated. Bits 2:0 ADPS2:0: ADC Prescaler Select Bits These bits determine the division factor between the XTAL frequency and the input clock to the ADC.

www.thinklabs.in

Page 69

Embedded Systems

ADC Prescaler Selections Division Factor 2 2 4 8 16 32 64 128

ADPS2 0 0 0 0 1 1 1 1

ADPS1 0 0 1 1 0 0 1 1

ADPS0 0 1 0 1 0 1 0 1

ADC Data Register ADCH & ADCL

www.thinklabs.in

Page 70

Embedded Systems

When an ADC conversion is complete, the result is found in these two registers. If differential channels are used, the result is presented in twos complement form. When ADCL is read, the ADC Data Register is not updated until ADCH is read. Consequently, if the result is left adjusted and no more than 8-bit precision is required, it is sufficient to read ADCH. Otherwise, ADCL must be read first, then ADCH. The ADLAR bit in ADMUX, and the MUXn bits in ADMUX affect the way the result is read from the registers. If ADLAR is set, the result is left adjusted. If ADLAR is cleared (default), the result is right adjusted.

www.thinklabs.in

Page 71

Embedded Systems

Timers in AVR
Timers are inseparable from microcontrollers. Any kind of controller, no mater how basic the model is, will always have the feature of timers. But AVR developers have gone farther than that. Apart from the basic function of timers, it also has integrated PWM generation modules. There are a total of four timers in Atmega128: Two 8 bit timers(Timer 0 and Timer 2) & two 16 Bit Timers (Timer 1 & Timer 3) Lets have a look at the functions of the timer. We will consider Timer 0 as an example.

Operation of Timer 0 is divided in the following modes. Normal Timer operation: This is the most basic feature of the timer, and actually, the reason why timers were developed. There is a 8-bit register called TCNT0. For every clock pulse, it increaments its count by 1. So, in 0xFF ( 255, in decimal) clock pulses, the value of TCNT0 can go from 0 to 0xFF to 0 again. Since the clock pulses are of a fixed period, the value of TCNT0 can tell me how much time has passed since the timer was started. This is the basic concept of normal timer operation. When the value of the timer rolls over from 0xFF to 0, the timer gives a signal that the value has overflowed. We can use this signal to keep track to time passed. Lets say, for example that we want to count 100 clock pulses instead of 255. So now we should right a value of (255 100) = 155 in our TCNT0 before starting the timer. Now, we willl get a signal after 100 pulses are over. If, instead of counting clock pulses, lets say we want to count events. We have an option of counting the pulses at a particular pin of the microcontroller. Lets say our project is to count the number of people entering a room. Now we connect our people sensor to this pin. It will give a single pulse when a person enters the room. Thus, the value of TCNT0 will increment by 1 when a person enters. The final value of TCNT0 will tell us total number of people entered.

www.thinklabs.in

Page 72

Embedded Systems

CTC: Clear Timer on Compare Match: This is a special case where you can set the top value of the timer. Lets say you want your timer to count from 0 to 200. Then write the value 200 in a register called OCR0. Then start the timer. As soon as the value in TCNT0 reaches 200, a compare match occurs and the TCNT0 clears to 00. At the same time, the status of a PIN, OC0, will toggle every time the timer clears itself. Observe the diagram below.

Fast PWM Mode: This mode is an AVR specific feature. We can use the timer to create Pulse Width Modulated Signals. Changing the duty cycle of this PWM is very easy. Observe the diagram below. Here, TCNT0 continuously counts from 0 to 255. We can change the duty cycle by writing an appropriate value in the OCR0 register. Obviously, this value will be between 0 and 255. There are 2 sub-modes in picture: In the Non-Inverting mode, the status at the OC0 pin becomes 0 when a compare match occurs between TCNT0 and OCR0. The pin becomes 1 at the bottom (ie when TCNT0 = 00). So greater the value of OCR0, greater is the ON time.In the Inverting mode, this operation is reversed. Pin is set when compare match occurs and cleared when TCNT0 = 00. So greater the value of OCR0, lesser the ON time.

www.thinklabs.in

Page 73

Embedded Systems

Phase correct PWM Mode: This is another type of mode. See the Diagram. In this mode, the TCNT0 counts from 0 to 255 to 0 in a double slope ( Upcounting and Downcounting). The duty cycle can be changed by writing an appropriate value in the OCR0 register. In the NonInverting mode, the OC0 pin is cleared on compare match while upcounting and it is set on compare match while downcounting. So greater the value of OCR0, greater is the ON time. In the Inverting mode, the status is opposite. So greater the value of OCR0, lesser is the ON time.

You have aquainted yourselves to the TIMER 0 of Atmega128. Now here are the registers required to configure it: www.thinklabs.in Page 74

Embedded Systems

TIMER 0 Registers TCCR0

Bit 7 FOC0: Force Output Compare The FOC0 bit is only active when the WGM bits specify a non-PWM mode. However, for ensuring compatibility with future devices, this bit must be set to zero when TCCR0 is written when operating in PWM mode. When writing a logical one to the FOC0 bit, an immediate compare match is forced on the waveform generation unit. The OC0 output is changed according to its COM01:0 bits setting. Note that the FOC0 bit is implemented as a strobe. Therefore it is the value present in the COM01:0 bits that determines the effect of the forced compare. A FOC0 strobe will not generate any interrupt, nor will it clear the timer in CTC mode using OCR0 as TOP. The FOC0 bit is always read as zero. Bit 6, 3 WGM01:0: Waveform Generation Mode These bits control the counting sequence of the counter, the source for the maximum (TOP) counter value, and what type of waveform generation to be used. Modes of operation supported by the Timer/Counter unit are: Normal mode, Clear Timer on Compare match (CTC) mode, and two types of Pulse Width Modulation (PWM) modes.

Bit 5:4 COM01:0: Compare Match Output Mode These bits control the output compare pin (OC0) behavior. If one or both of the COM01:0 bits are set, the OC0 output overrides the normal port functionality of the I/O pin it is connected to. However, note that the Data Direction Register (DDR) bit corresponding to OC0 pin must be set in order to enable the www.thinklabs.in Page 75 output driver.

Embedded Systems

Compare Output Mode, non-PWM Mode

Compare Output Mode, Fast-PWM Mode

Compare Output Mode, Phase Correct PWM Mode

www.thinklabs.in

Page 76

Embedded Systems

Bit 2:0 CS02:0: Clock Select

CS02 0 0 0 0 1 1 1 1

SC01 0 0 1 1 0 0 1 1

CS00 0 1 0 1 0 1 0 1

Description No Clock source (Timer/Counter stopped). clk clk clk clk clk
I/O

/(No prescaling) /8(From prescler) /64(From prescaler) /256(From prescaler) /1024(From prescaler)

I/O

I/O

I/O

I/O

External clock source on T0 pin. Clock on falling edge. External clock source on T0 pin. Clock on rising edge.

TCNT0

TIMSK

Bit 1 OCIE0: Timer/Counter0 Output Compare Match Interrupt Enable When the OCIE0 bit is written to one, and the I-bit in the Status Register is set (one), the Timer/Counter0 Compare Match interrupt is enabled. The corresponding interrupt is executed if a compare match in Timer/Counter0 occurs, i.e., when the OCF0 bit is set in the Timer/Counter Interrupt Flag Register www.thinklabs.in Page 77 TIFR.

Embedded Systems

Bit 0 TOIE0: Timer/Counter0 Overflow Interrupt Enable When the TOIE0 bit is written to one, and the I-bit in the Status Register is set (one), the Timer/Counter0 Overflow interrupt is enabled. The corresponding interrupt is executed if an overflow in Timer/Counter0 occurs, i.e., when the TOV0 bit is set in the Timer/Counter Interrupt Flag Register TIFR.

TIFR

Bit 1 OCF0: Output Compare Flag 0 The OCF0 bit is set (one) when a compare match occurs between the Timer/Counter0 and the data in OCR0 Output Compare Register0. OCF0 is cleared by hardware when executing the corresponding interrupt handling vector. Alternatively, OCF0 is cleared by writing a logic one to the flag. When the Ibit in SREG, OCIE0 (Timer/Counter0 Compare Match Interrupt Enable), and OCF0 are set (one), the Timer/Counter0 Compare Match Interrupt is executed. Bit 0 TOV0: Timer/Counter0 Overflow Flag The bit TOV0 is set (one) when an overflow occurs in Timer/Counter0. TOV0 is cleared by hardware when executing the corresponding interrupt handling vector. Alternatively, TOV0 is cleared by writing a logic one to the flag. When the SREG I-bit, TOIE0 (Timer/Counter0 Overflow Interrupt Enable), and TOV0 are set (one), the Timer/Counter0 Overflow Interrupt is executed. In PWM mode, this bit is set when Timer/Counter0 changes counting direction at $00.

Bit 7 TSM: Timer/Counter Synchronization Mode Writing the TSM bit to one activates the Timer/Counter Synchronization mode. In this mode, the value that is written to the PSR0 and PSR321 bits is kept, hence keeping the corresponding prescaler reset signals asserted. This ensures that the corresponding Timer/Counters are halted and can be configured to the same value without the risk of one of them advancing during configuration. When the TSM bit is written to zero, the PSR0 and PSR321 bits are cleared by hardware, and the Timer/Counters start counting simultaneously. Bit 1 PSR0: Prescaler Reset Timer/Counter0 When this bit is one, the Timer/Counter0 prescaler will be reset. This bit is normally cleared immediately by hardware. If this bit is written when Timer/Counter0 is operating in asynchronous mode, the bit will www.thinklabs.in Page 78

Embedded Systems

remain one until the prescaler has been reset. The bit will not be cleared by hardware if the TSM bit is set. Registers of other Timers are given for future use:

TIMER1/3 Registers TCCR1/3A

Bit 7:6 COMnA1:0: Compare Output Mode for Channel A Bit 5:4 COMnB1:0: Compare Output Mode for Channel B Bit 3:2 COMnC1:0: Compare Output Mode for Channel C The COMnA1:0, COMnB1:0, and COMnC1:0 control the output compare pins (OCnA, OCnB, and OCnC respectively) behavior. If one or both of the COMnA1:0 bits are written to one, the OCnA output overrides the normal port functionality of the I/O pin it is connected to. If one or both of the COMnB1:0 bits are written to one, the OCnB output overrides the normal port functionality of the I/O pin it is connected to. If one or both of the COMnC1:0 bits are written to one, the OCnC output overrides the normal port functionality of the I/O pin it is connected to. However, note that the Data Direction Register (DDR) bit corresponding to the OCnA, OCnB or OCnC pin must be set in order to enable the output driver.
Compare Output Mode, non-PWM

www.thinklabs.in

Page 79

Embedded Systems

Compare Output Mode, Fast PWM

Compare Output Mode, Phase Correct and Phase and Frequency Correct PWM

www.thinklabs.in

Page 80

Embedded Systems

Waveform Generation Mode Bit Description

Bit 7 ICNCn: Input Capture Noise Canceller

Setting this bit (to one) activates the Input Capture Noise Canceller. When the Noise Canceller is activated, the input from the Input Capture Pin (ICPn) is filtered. The filter function requires four successive equal valued samples of the ICPn pin for changing its output. The Input Capture is therefore delayed by four Oscillator cycles when the noise canceler is enabled. Bit 6 ICESn: Input Capture Edge Select This bit selects which edge on the Input Capture Pin (ICPn) that is used to trigger a capture event. When the ICESn bit is written to zero, a falling (negative) edge is used as trigger, and when the ICESn bit is written to one, a rising (positive) edge will trigger the capture. When a capture is triggered according www.thinklabs.in Page 81 to the ICESn setting, the counter value is copied into the Input Capture Register (ICRn). The event will also

Embedded Systems

set the Input Capture Flag (ICFn), and this can be used to cause an Input Capture Interrupt, if this interrupt is enabled. When the ICRn is used as TOP value (see description of the WGMn3:0 bits located in the TCCRnA and the TCCRnB Register), the ICPn is disconnected and consequently the Input Capture function is disabled. Bit 5 Reserved Bit This bit is reserved for future use. For ensuring compatibility with future devices, this bit must be written to zero when TCCRnB is written. Bit 4:3 WGMn3:2: Waveform Generation Mode See TCCRnA Register description. Bit 2:0 CSn2:0: Clock Select

CS02 0 0 0 0 1 1 1 1

SC01 0 0 1 1 0 0 1 1

CS00 0 1 0 1 0 1 0 1

Description No Clock source (Timer/Counter stopped). clk clk clk clk clk
I/O

/1 (No prescaling) /8 (From prescler) /64 (From prescaler) /256 (From prescaler) /1024(From prescaler)

I/O

I/O

I/O

I/O

External clock source on T1 pin. Clock on falling edge. External clock source on T1 pin. Clock on rising edge.

www.thinklabs.in

Page 82

Embedded Systems

Bit 7 FOCnA: Force Output Compare for Channel A

Bit 6 FOCnB: Force Output Compare for Channel B Bit 5 FOCnC: Force Output Compare for Channel C The FOCnA/FOCnB/FOCnC bits are only active when the WGMn3:0 bits specifies a non-PWM mode. When writing a logical one to the FOCnA/FOCnB/FOCnC bit, an immediate compare match is forced on the waveform generation unit. The OCnA/OCnB/OCnC output is changed according to its COMnx1:0 bits setting. Note that the FOCnA/FOCnB/FOCnC bits are implemented as strobes. Therefore it is the value present in the COMnx1:0 bits that determine the effect of the forced compare. A FOCnA/FOCnB/FOCnC strobe will not generate any interrupt nor will it clear the timer in Clear Timer on Compare Match (CTC) Bit 4:0 Reserved Bits mode using OCRnA as TOP. The FOCnA/FOCnB/FOCnB bits are always read as zero. These bits are reserved for future use. For ensuring compatibility with future devices, these bits must be written to zero when TCCRnC is written.

The two Timer/Counter I/O locations (TCNTnH and TCNTnL, combined TCNTn) give direct access, both for read and for write operations, to the Timer/Counter unit 16-bit counter. To ensure that both the high and low bytes are read and written simultaneously when the CPU accesses these registers, the access is performed using an 8-bit temporary High Byte Register (TEMP). This Temporary Register is shared by all the other 16-bit registers

Bit 5 TICIE1: Timer/Counter1, Input Capture Interrupt Enable When this bit is written to one, and the I-flag in the Status Register is set (interrupts globally enabled), the Timer/Counter1 Input Capture interrupt is enabled. The corresponding interrupt vector is executed when the ICF1 flag, located in TIFR, is set. www.thinklabs.in Page 83

Embedded Systems

Bit 4 OCIE1A: Timer/Counter1, Output Compare A Match Interrupt Enable When this bit is written to one, and the I-flag in the Status Register is set (interrupts globally enabled), the Timer/Counter1 Output Compare A Match Interrupt is enabled. The corresponding interrupt vector (see Interrupts on page 60) is executed when the OCF1A flag, located in TIFR, is set. Bit 3 OCIE1B: Timer/Counter1, Output Compare B Match Interrupt Enable When this bit is written to one, and the I-flag in the Status Register is set (interrupts globally enabled), the Timer/Counter1 Output Compare B Match Interrupt is enabled. The corresponding interrupt vector (see Interrupts on page 60) is executed when the OCF1B flag, located in TIFR, is set. Bit 2 TOIE1: Timer/Counter1, Overflow Interrupt Enable When this bit is written to one, and the I-flag in the Status Register is set (interrupts globally enabled), the Timer/Counter1 overflow interrupt is enabled. The corresponding interrupt vector (see Interrupts on page 60) is executed when the TOV1 flag, located in TIFR, is set.

Bit 7:6 Reserved Bits

These bits are reserved for future use. For ensuring compatibility with future devices, these bits must be set to zero when ETIMSK is written. Bit 5 TICIE3: Timer/Counter3, Input Capture Interrupt Enable When this bit is written to one, and the I-flag in the Status Register is set (interrupts globally enabled), the Timer/Counter3 Input Capture Interrupt is enabled. The corresponding interrupt vector (see Interrupts on page 60) is executed when the ICF3 flag, located in ETIFR, is set. Bit 4 OCIE3A: Timer/Counter3, Output Compare A Match Interrupt Enable When this bit is written to one, and the I-flag in the Status Register is set (interrupts globally enabled), the Timer/Counter3 Output Compare A Match Interrupt is enabled. The corresponding interrupt vector is executed when the OCF3A flag, located in ETIFR, is set. Bit 3 OCIE3B: Timer/Counter3, Output Compare B Match Interrupt Enable When this bit is written to one, and the I-flag in the Status Register is set (interrupts globally enabled), the Timer/Counter3 Output Compare B Match Interrupt is enabled. The corresponding interrupt vector is executed when the OCF3B flag, located in ETIFR, is set. Bit 2 TOIE3: Timer/Counter3, Overflow Interrupt Enable When this bit is written to one, and the I-flag in the Status Register is set (interrupts globally enabled), the Timer/Counter3 Overflow Interrupt is enabled. The corresponding interrupt vector is executed when the TOV3 flag, located in ETIFR, is set. www.thinklabs.in Page 84

Embedded Systems

Bit 1 OCIE3C: Timer/Counter3, Output Compare C Match Interrupt Enable When this bit is written to one, and the I-flag in the Status Register is set (interrupts globally enabled), the Timer/Counter3 Output Compare C Match Interrupt is enabled. The corresponding interrupt vector is executed when the OCF3C flag, located in ETIFR, is set. Bit 0 OCIE1C: Timer/Counter1, Output Compare C Match Interrupt Enable When this bit is written to one, and the I-flag in the Status Register is set (interrupts globally enabled), the Timer/Counter1 Output Compare C Match Interrupt is enabled. The corresponding interrupt vector is executed when the OCF1C flag, located in ETIFR, is set.

Bit 5 ICF1: Timer/Counter1, Input Capture Flag This flag is set when a capture event occurs on the ICP1 pin. When the Input Capture Register (ICR1) is set by the WGMn3:0 to be used as the TOP value, the ICF1 flag is set when the counter reaches the TOP value. ICF1 is automatically cleared when the Input Capture Interrupt vector is executed. Alternatively, ICF1 can OCF1A: Timer/Counter1,logic one to its bit A Match Flag Bit 4 be cleared by writing a Output Compare location. This flag is set in the timer clock cycle after the counter (TCNT1) value matches the Output Compare Register A (OCR1A). Note that a forced output compare (FOC1A) strobe will not set the OCF1A flag. OCF1A is automatically cleared when the Output Compare Match A interrupt vector is executed. Alternatively, OCF1A can be cleared by writing a logic one to its bit location. Bit 3 OCF1B: Timer/Counter1, Output Compare B Match Flag This flag is set in the timer clock cycle after the counter (TCNT1) value matches the Output Compare Register B (OCR1B). Note that a forced output compare (FOC1B) strobe will not set the OCF1B flag. OCF1B is automatically cleared when the Output Compare Match B interrupt vector is executed. Alternatively, OCF1B can be cleared by writing a logic one to its bit location. Bit 2 TOV1: Timer/Counter1, Overflow Flag The setting of this flag is dependent of the WGMn3:0 bits setting. In normal and CTC modes, the TOV1 flag is set when the timer overflows. TOV1 is automatically cleared when the Timer/Counter1 Overflow interrupt vector is executed. Alternatively, TOV1 can be cleared by writing a logic one to its bit location.

www.thinklabs.in

Page 85

Embedded Systems

Bit 7:6 Reserved Bits These bits are reserved for future use. For ensuring compatibility with future devices, these bits must be set to zero when ETIFR is written. Bit 5 ICF3: Timer/Counter3, Input Capture Flag This flag is set when a capture event occurs on the ICP3 pin. When the Input Capture Register (ICR3) is set by the WGM3:0 to be used as the TOP value, the ICF3 flag is set when the counter reaches the TOP value. ICF3 is automatically cleared when the Input Capture 3 interrupt vector is executed. Alternatively, ICF3 can OCF3A: Timer/Counter3,logic one to its bit A Match Flag Bit 4 be cleared by writing a Output Compare location. This flag is set in the timer clock cycle after the counter (TCNT3) value matches the Output Compare Register A (OCR3A). Note that a forced output compare (FOC3A) strobe will not set the OCF3A flag. OCF3A is automatically cleared when the Output Compare Match 3 A interrupt vector is executed. Alternatively, OCF3A can be cleared by writing a logic one to its bit location. Bit 3 OCF3B: Timer/Counter3, Output Compare B Match Flag This flag is set in the timer clock cycle after the counter (TCNT3) value matches the Output Compare Register B (OCR3B). Note that a forced output compare (FOC3B) strobe will not set the OCF3B flag. OCF3B is automatically cleared when the Output Compare Match 3 B interrupt vector is executed. Alternatively, OCF3B can be cleared by writing a logic one to its bit location. Bit 2 TOV3: Timer/Counter3, Overflow Flag The setting of this flag is dependent of the WGM3:0 bits setting. In normal and CTC modes, the TOV3 flag is set when the timer overflows. Refer to Table 52 on page 105 for the TOV3 flag behavior when using another WGM3:0 bit setting. TOV3 is automatically cleared when the Timer/Counter3 Overflow interrupt vector is executed. Alternatively, TOV3 can be cleared by writing a logic one to its bit location. Bit 1 OCF3C: Timer/Counter3, Output Compare C Match Flag This flag is set in the timer clock cycle after the counter (TCNT3) value matches the Output Compare Register C (OCR3C). Note that a forced output compare (FOC3C) strobe will not set the OCF3C flag. OCF3C is automatically cleared when the Output Compare Match 3 C interrupt vector is executed. Alternatively, OCF3C can be cleared by writing a logic one to its bit location. Bit 0 OCF1C: Timer/Counter1, Output Compare C Match Flag This flag is set in the timer clock cycle after the counter (TCNT1) value matches the Output Compare Register C (OCR1C).

www.thinklabs.in

Page 86

Embedded Systems

EXTERNAL INTERRUPTS
The External Interrupts are triggered by the INT7:0 pins. Observe that, if enabled, the interrupts will trigger even if the INT7:0 pins are configured as outputs. This feature provides a way of generating a software interrupt. The External Interrupts can be triggered by a falling or rising edge or a low level. This is set up as indicated in the specification for the External Interrupt Control Registers EICRA (INT3:0) and EICRB (INT7:4). When the external interrupt is enabled and is configured as level triggered, the interrupt will trigger as long as the pin is held low. Note that recognition of falling or rising edge interrupts on INT7:4 requires the presence of an I/O clock. Low level interrupts and the edge interrupt on INT3:0 are detected asynchronously. This implies that these interrupts can be used for waking the part also from sleep modes other than Idle mode. The I/O clock is halted in all sleep modes except Idle mode.

External Interrupt Control Register A EICRA(3-0)

www.thinklabs.in

Page 87

Embedded Systems

External Interrupt Control Register B EICRB(7-4)

External Interrupt Mask Register EIMSK

www.thinklabs.in

Page 88

Embedded Systems

External Interrupt Flag Register (EIFR) :

When an edge or logic change on the INT7:0 pin triggers an interrupt request, INTF7:0 becomes set (one). If the I-bit in SREG and the corresponding interrupt enable bit, INT7:0 in EIMSK, are set (one), the MCU will jump to the interrupt vector. The flag is cleared when the interrupt routine is executed. Alternatively, the flag can be cleared by writing a logical one to it. These flags are always cleared when INT7:0 are configured as level interrupt.

www.thinklabs.in

Page 89

Embedded Systems

EEPROM Data Memory

EEPROM (also written E2PROM and pronounced "e-e-prom," "double-e prom" or simply "e-squared") stands for Electrically Erasable Programmable Read-Only Memory and is a type of non-volatile memory used in computers and other electronic devices to store small amounts of data that must be saved when power is removed, e.g., calibration tables or device configuration. When larger amounts of static data are to be stored (such as in USB flash drives) a specific type of EEPROM such as flash memory is more economical than traditional EEPROM devices. EEPROMs are realized as arrays of floating-gate transistors. BIOS stands for Basic Input/Output System. When you turn on your computer the BIOS chip executes a program called CMOS (Complementary Metal Oxide Semiconductor) that holds settings, which enables the computer to recognize your hardware. You can enter the CMOS program during boot-up to modify BIOS settings. You might need to do this, for instance, when you get a new hard drive. After you modify advent of EEPROM, manufacturers could also update the BIOS program itself. In the past With the the settings the BIOS will save the new copy of instructions to EEPROM. this wasn't possible, and an outdated BIOS chip meant having to replace the chip by getting a newer motherboard. A BIOS chip that is upgradeable using EEPROM capability is called a flash BIOS, because the EEPROM is updated using electrical charges or flashes. EEPROM is slower than RAM, but is perfectly fine for applications such as storing saved BIOS settings. EEPROM would not be chosen for applications with dynamic read/write requirements, as in the case of a digital camera, memory stick, or flash card. For these purposes a newer hybrid form of EEPROM is used called flash memory. Flash memory differs from EEPROM in that its data can be selectively rewritten. It can also be erased and rewritten in entire blocks, rather then one byte at a time. This makes it much faster than EEPROM. Newer flash BIOS chips may or may not use flash memory, rather than EEPROM. The BIOS is only called a flash BIOS because the memory it uses -- in both cases -- is reprogrammed by The ATmega128 contains 4Kbyte atof data EEPROM memory. It is organized as a separate flashing the chip, either one bytes a time, or in blocks. data space, in which single bytes can be read and written. The EEPROM has an endurance of at least 100,000 write/erase cycles. The access between the EEPROM and the CPU is described in the following, specifying the EEPROM Address Registers, the EEPROM Data Register, and the EEPROM Control Register. EEPROM Read/Write Access The EEPROM access registers are accessible in the I/O space. The write access time for the EEPROM is given at the end of the handout. A self-timing function, however, lets the user software detect when the next byte can be written. If the user code contains instructions that write the EEPROM, some precautions must be taken. In heavily filtered power supplies, VCC is likely to rise or fall slowly on Power-up/down. This causes the device for some period of time to run at a voltage lower than specified as minimum for the clock frequency used. www.thinklabs.in Page 90

Embedded Systems

In order to prevent unintentional EEPROM writes, a specific write procedure must be followed. Refer to the description of the EEPROM Control Register for details on this.When the EEPROM is read, the CPU is halted for four clock cycles before the next instruction is executed. When the EEPROM is written, the CPU is halted for two clock cycles before the next instruction is executed.

Bits 15..12 Res: Reserved Bits These are reserved bits and will always read as zero. When writing to this address location, write these bits to zero for compatibility with future devices. Bits 11..0 EEAR11..0: EEPROM Address The EEPROM Address Registers EEARH and EEARL specify the EEPROM address in the 4K bytes EEPROM space. The EEPROM data bytes are addressed linearly between 0 and 4096. The initial value of EEAR is undefined. A proper value must be written before the EEPROM may be accessed

Bits 7..0 EEDR7.0: EEPROM Data For the EEPROM write operation, the EEDR Register contains the data to be written to the EEPROM in the address given by the EEAR Register. For the EEPROM read operation, the EEDR contains the data read out from the EEPROM at the address given by EEAR.

Bits 7..4 Res: Reserved Bits www.thinklabs.in These bits are reserved bits in the ATmega128 and will always read as zero.

Page 91

Embedded Systems

Bit 3 EERIE: EEPROM Ready Interrupt Enable Writing EERIE to one enables the EEPROM Ready Interrupt if the I-bit in SREG is set. Writing EERIE to zero disables the interrupt. The EEPROM Ready interrupt generates a constant interrupt when EEWE is cleared. Bit 2 EEMWE: EEPROM Master Write Enable The EEMWE bit determines whether setting EEWE to one causes the EEPROM to be written. When EEMWE is written to one, writing EEWE to one within four clock cycles will write data to the EEPROM at the selected address. If EEMWE is zero, writing EEWE to one will have no effect. When EEMWE has been written to one by software, hardware clears the bit to zero after four clock cycles. See the description of the EEWE bit for an EEPROM write procedure. Bit 1 EEWE: EEPROM Write Enable The EEPROM Write Enable Signal EEWE is the write strobe to the EEPROM. When address and data are correctly set up, the EEWE bit must be set to write the value into the EEPROM. The EEMWE bit must be set when the logical one is written to EEWE, otherwise no EEPROM write takes place. The following procedure should be followed when writing the EEPROM (the order of steps 3 and 4 is not essential): 1. Wait until EEWE becomes zero. 2. Wait until SPMEN in SPMCSR becomes zero. 3. Write new EEPROM address to EEAR (optional). 4. Write new EEPROM data to EEDR (optional). 5. Write a logical one to the EEMWE bit while writing a zero to EEWE in EECR. 6. Within four clock cycles after setting EEMWE, write a logical one to EEWE.

The EEPROM can not be programmed during a CPU write to the Flash memory. The software must check that the Flash programming is completed before initiating a new EEPROM write. Step 2 is only relevant if the software contains a boot loader allowing the CPU to program the Flash. If the Flash is never being updated by the CPU, step 2 can be omitted. Caution: An interrupt between step 5 and step 6 will make the write cycle fail, since the EEPROM Master Write Enable will time-out. If an interrupt routine accessing the EEPROM is interrupting another EEPROM access, the EEAR or EEDR Register will be modified, causing the interrupted EEPROM access to fail. It is recommended to have the global interrupt flag cleared during the four last steps to avoid these problems. When the write access time has elapsed, the EEWE bit is cleared by hardware. The user software can poll this bit and wait for a zero before writing the next byte. When EEWE has been set, the CPU is halted for two cycles before the next instruction is executed. Bit 0 EERE: EEPROM Read Enable The EEPROM Read Enable Signal EERE is the read strobe to the EEPROM. When the correct address is set up in the EEAR Register, the EERE bit must be written to a logic one to trigger the EEPROM read. The EEPROM read access takes one instruction, and the requested data is available immediately. When the EEPROM is read, the CPU is halted for four cycles before the next instruction is executed. The user www.thinklabs.in Page 92 should poll the EEWE bit before starting the read operation. If a write operation is in progress, it is neither possible to read the EEPROM, nor to change the EEAR Register.

Embedded Systems

SPI
The serial peripheral interface (SPI) allows high-speed synchronous data transfer between the P89V51RD2 and peripheral devices or between several P89V51RD2 devices. So what is SPI? SPI Interface or Serial Peripheral Interface bus is as the name suggests will shift data out (and in) one bit at a time. It transmits data from master to slave over short distance at high speeds. SPI is nothing but a back to back connected two shift registers, shifting entirely controlled by the Master. It is as simple as that. I2C there is no concept of changing ownership of bus, there are no slave device addresses. SPI Unlike is a much simpler protocol and because of this you can operate it at speeds greater than 10MHz (compared with the 3.4MHz maximum for I2C). The best feature of SPI is that you can do full duplex data transfers (data in both directions at the same time) which you can not do with I2C and you can do it fast which is the best part. Principles of SPI: The Serial Peripheral Interface is used primarily for a synchronous serial communication of host processor and peripherals. We use four lines for SPI communication. The data input DI accepts data from the microcontroller it and the data output DO is used for the reading back of data, however it also provides the possibility to cascade several devices. The data output of the preceding device then forms the data input for the next IC. There is a MASTER and a SLAVE mode. The MASTER device provides the clock signal and determines which SLAVE it wants to communicate with. CS and SCK are outputs from the master. The SLAVE device receives the clock and chip select from the MASTER, CS and SCK are therefore inputs. This means there is one master, while the number of slaves is only limited by the number of SLAVE SELECT lines the master is having. A SPI device can be a simple shift register up to an independent subsystem. The basic principle of a shift register is always present. The data is serially transferred, pumped into a shift register and is then internally available for parallel processing. The most important thing to keep in mind is SPI is bidirectional and before you read something you have to transmit a dummy data so that data is emerges out from the slave when it sees something coming from the master. SPI Interface: Signals

www.thinklabs.in

Page 93

Embedded Systems

Here is the block diagram for a single SPI device connection:

Now let us see what advantages SPI brings to you Very fast > 10 MHz. Simple interface Supports full duplex data streaming.

Let us now see the flip side of SPI The clock scheme may not be the same between devices. The data length can vary from device to device. Travels short distances only

Data transmission

between Master and Slave

The interaction between a master and a slave AVR is shown in Figure 1 on page 1. Two identical SPI units are displayed. The left unit is configured as master while the right unit is configured as slave. The MISO, MOSI and SCK lines are connected with the corresponding lines of the other part. The mode in which a part is running determines if they are input or output signal lines. Because a bit is shifted from the master to the slave and from the slave to the master simultaneously in one clock cycle both 8-bit shift registers can be considered as one 16-bit circular shift register. This means that after eight SCK clock pulses the data between master and slave will be exchanged. The system is single buffered in the transmit direction and double buffered in the receive direction. This influences the data handling in the following ways: 1. New bytes to be sent can not be written to the data register (SPDR) / shift register before the entire shift cycle is completed. 2. Received bytes are written to the Receive Buffer immediately after the transmission is completed. 3. The Receive Buffer has to be read before the next transmission is completed or data will be lost. 4. Reading the SPDR will return the data of the Receive Buffer. After a transfer is completed the SPI Interrupt Flag (SPIF) will be set in the SPI Status Register (SPSR). This will cause the corresponding interrupt to be executed if this interrupt and the global interrupts are enabled. Setting the SPI Interrupt Enable (SPIE) bit in the SPCR enables the interrupt of the SPI while setting the I bit in the SREG enables the global interrupts. Pins of the SPI The SPI consists of four different signal lines. These lines are the shift clock (SCK), the Master Out Slave In line (MOSI), the Master In Slave Out line (MISO) and the active low Slave Select line (SS). When the SPI www.thinklabs.in Page 94 is enabled, the data direction of the MOSI, MISO, SCK and SS pins are overridden according to the following table.

Embedded Systems

Multi Slave Systems -SS pin Functionality The Slave Select (SS) pin plays a central role in the SPI configuration. Depending on the mode the part is running in and the configuration of this pin, it can be used to activate or deactivate the devices. The SS pin can be compared with a chip select pin which has some extra features. In master mode, the SS pin must be held high to ensure master SPI operation if this pin is configured as an input pin. A low level will switch the SPI into slave mode and the hardware of the SPI will perform the 1. The master bit (MSTR) in the SPI Control Register (SPCR) is cleared and the SPI following actions: system becomes a slave. The direction of the pins will be switched 2. The SPI Interrupt Flag (SPIF) in the SPI Status Register (SPSR) will be set. If the SPI interrupt and the global interrupts are enabled the interrupt routine will be executed. This can be useful in systems with more than one master to avoid that two masters are accessing the SPI bus at the same time. If the SS pin is configured as output pin it can be used as a general purpose output pin which does not affect the SPI system. Note: In cases where the AVR is configured for master mode and it can not be ensured that the SS pin will stay high between two transmissions, the status of the MSTR bit has to be checked before a new byte is written. Once the MSTR bit has been cleared by a low level on the SS line, it must be set by the application to re-enable SPI master mode. In slave mode the SS pin is always an input. When SS is held low, the SPI is activated and MISO becomes output if configured so by the user. All other pins are inputs. When SS is driven high, all pins are inputs, and the SPI is passive, which means that it will not receive incoming data. Note: In slave mode, the SPI logic will be reset once the SS pin is brought high. If the SS pin is brought high during a transmission, the SPI will stop sending and receiving immediately and both data received and data sent must be considered as lost.

www.thinklabs.in

Page 95

Embedded Systems

The ability to connect several devices to the same SPI-bus is based on the fact that only one master and only one slave is active at the same time. The MISO, MOSI and SCK lines of all the other slaves are tristated (configured as input pins of high impedance with no pull-up resistors enabled). A false implementation (e.g. if two slaves are activated at the same time) can cause a driver contention which can lead to a CMOS latch up state and must be avoided. Resistances of 1 to 10 k ohms in series with the pins of the SPI can be used to prevent the system from latching up. However this affects the maximum usable data rate, depending on the loading capacitance on the SPI pins. Unidirectional SPI devices require just the clock line and one of the data lines. If the device is using the MISO line or the MOSI line depends on its purpose. Simple sensors for instance are just sending data while an external DAC usually just receives data.

www.thinklabs.in

Page 96

Embedded Systems

I2C(Inter-Integrated-Circuit)
The Inter-Integrated-Circuit, or I2C bus specification was originally developed by Philips Inc. for the transfer of data between ICs at the PCB level. The physical interface for the bus consists of two lines; one for the clock (SCL) and one for data (SDA). The SDA and SCL lines are pulled high by resistors connected to the VDD. The bus may have a one Master/many Slave configuration or may have multiple master devices. The master device is responsible for generating the clock source for the linked Slave devices. The I2C protocol supports 7-bit addressing mode, permitting 128 physical devices to be on the bus. In practice, the bus specification reserves certain addresses so slightly fewer usable addresses are available. For example, the 7-bit addressing mode allows 112 usable addresses. All data transfers on the bus are initiated by the master device and are done eight bits at a time, MSB first. There is no limit to the amount of data that can be sent in one transfer. After each 8-bit transfer, a 9th clock pulse is sent by the master. At this time, the transmitting device on the bus releases the SDA line and the receiving device on the bus acknowledges the data sent by the transmitting device. An ACK (SDA held low) is sent if the data was received successfully, or a NACK (SDA left high) is sent if it was Atmel refers to I2C communication as Two Wire Interface (TWI) not received successfully. A NACK is also used to terminate a data transfer after the last byte is received. The ATmega16 has an inbuilt TWI capability. This allows us to easily interface it with other ICs having I2C capabilities. We will use this feature to interface the ATmega16 to a Real Time Clock (RTC) IC DS1307. TWI Terminology

Data Transfer and Frame Format Transferring Bits Each data bit transferred on the TWI bus is accompanied by a pulse on the clock line. The level of the data line must be stable when the clock line is high. The only exception to this rule is for generating start and stop conditions. www.thinklabs.in Page 97

Embedded Systems

START and STOP Conditions The Master initiates and terminates a data transmission. The transmission is initiated when the Master issues a START condition on the bus, and it is terminated when the Master issues a STOP condition. Between a START and a STOP condition, the bus is considered busy, and no other Master should try to seize control of the bus. A special case occurs when a new START condition is issued between a START and STOP condition. This is referred to as a REPEATED START condition, and is used when the Master wishes to initiate a new transfer without releasing control of the bus. After a REPEATED START, the bus is considered busy until the next STOP. This is identical to the START behaviour, and therefore START is used to describe both START and REPEATED START for the conditions are signaled by changing otherwise of the SDA line As depicted below, START and STOP remainder of this datasheet, unless the level noted. when the SCL line is high.

Address Packet Format All address packets transmitted on the TWI bus are nine bits long, consisting of seven address bits, one READ/WRITE control bit and an acknowledge bit. If the READ/WRITE bit is set, a read operation is to be performed, otherwise a write operation should be performed. When a Slave recognizes that it is being addressed, it should acknowledge by pulling SDA low in the ninth SCL (ACK) cycle. If the addressed Slave is busy, or for some other reason can not service the Masters request, the SDA line should be left high in the ACK clock cycle. The Master can then transmit a STOP condition, or a REPEATED START Slave addresses can freely be allocated by the designer, but the address 0000 000 is reserved for a condition general call.new transmission. Anis issued,packet consisting respond by pulling and SDA lineor a in the to initiate a When a general call address all Slaves should of a Slave address the a READ low ACK cycle. A general call is used when a Master wishes to transmit the same message to several WRITE Slaves in bit is called SLA+R or SLA+W, respectively. The MSB of the address byte is transmitted first. the system. When the general call address followed by a Write bit is transmitted on the bus, all Slaves www.thinklabs.in Page 98

Embedded Systems

set up to acknowledge the general call will pull the SDA line low in the ACK cycle. The following data packets will then be received by all the Slaves that acknowledged the general call.

Data Packet Format All data packets transmitted on the TWI bus are nine bits long, consisting of one data byte and an acknowledge bit. During a data transfer, the Master generates the clock and the START and STOP conditions, while the receiver is responsible for acknowledging the reception. An Acknowledge (ACK) is signaled by the receiver pulling the SDA line low during the ninth SCL cycle. If the receiver leaves the SDA line high, a NACK is signaled. When the receiver has received the last byte, or for some reason cannot receive any more bytes, it should inform the transmitter by sending a NACK after the final byte. The MSB of the data byte is transmitted first.

Combining Address and Data Packets into a Transmission A transmission basically consists of a START condition, a SLA+R/W, one or more data packets and a STOP condition. An empty message, consisting of a START followed by a STOP condition, is illegal. Note that the wired-ANDing of the SCL line can be used to implement handshaking between the Master and the Slave. The Slave can extend the SCL low period by pulling the SCL line low. This is useful if the clock speed set up by the Master is too fast for the Slave, or the Slave needs extra time for processing between the data transmissions. The Slave extending the SCL low period will not affect the SCL high period, which is determined by the Master. As a consequence, the Slave can reduce the TWI data transfer speed by prolonging the SCL duty cycle.

www.thinklabs.in

Page 99

Embedded Systems

TWI Register Description TWI Bit Rate Register TWBR

Bits 7..0 TWI Bit Rate Register TWBR selects the division factor for the bit rate generator. The bit rate generator is a frequency divider which generates the SCL clock frequency in the Master modes.

TWBR = Value of the TWI Bit Rate Register TWPS = Value of the prescaler bits in the TWI Status Register TWI Control Register TWCR

The TWCR is used to control the operation of the TWI. It is used to enable the TWI, to initiate a Master access by applying a START condition to the bus, to generate a receiver acknowledge, to generate a stop condition, and to control halting of the bus while the data to be written to the bus are written to the TWDR. It also indicates a write collision if data is attempted written to TWDR while the register is inaccessible. Bit 7 TWINT: TWI Interrupt Flag This bit is set by hardware when the TWI has finished its current job and expects application software response. If the I-bit in SREG and TWIE in TWCR are set, the MCU will jump to the TWI Interrupt Vector. While the TWINT Flag is set, the SCL low period is stretched. The TWINT Flag must be cleared by software by writing a logic one to it. Note that this flag is not automatically cleared by Page 100 hardware www.thinklabs.in when executing the interrupt routine. Also note that clearing this flag starts the operation of the TWI, so all

Embedded Systems

accesses to the TWI Address Register (TWAR), TWI Status Register (TWSR), and TWI Data Register (TWDR) must be complete before clearing this flag. Bit 6 TWEA: TWI Enable Acknowledge Bit The TWEA bit controls the generation of the acknowledge pulse. If the TWEA bit is written to one, the SCK pulse is generated on the TWI bus if the following conditions are met: 1. The devices own Slave address has been received. 2. A general call has been received, while the TWGCE bit in the TWAR is set. 3. A data byte has been received in Master Receiver or Slave Receiver mode. By writing the TWEA bit to zero, the device can be virtually disconnected from the Two-wire Serial Bus temporarily. Address recognition can then be resumed by writing the TWEA bit to one again. Bit 5 TWSTA: TWI START Condition Bit The application writes the TWSTA bit to one when it desires to become a Master on the Two Wire Serial Bus. The TWI hardware checks if the bus is available, and generates a START condition on the bus if it is free. However, if the bus is not free, the TWI waits until a STOP condition is detected, and then generates a new START condition to claim the bus Master status. TWSTA must be cleared by software when the START condition has been transmitted. Bit 4 TWSTO: TWI STOP Condition Bit Writing the TWSTO bit to one in Master mode will generate a STOP condition on the Two-wire Serial Bus. When the STOP condition is executed on the bus, the TWSTO bit is cleared automatically. In Slave mode, setting the TWSTO bit can be used to recover from an error condition. This will not generate a STOP condition, but the TWI returns to a well-defined unaddressed Slave mode and releases the SCL and SDA lines to a high impedance state. Bit 3 TWWC: TWI Write Collision Flag The TWWC bit is set when attempting to write to the TWI Data Register TWDR when TWINT is low. This flag is cleared by writing the TWDR Register when TWINT is high. Bit 2 TWEN: TWI Enable Bit The TWEN bit enables TWI operation and activates the TWI interface. When TWEN is written to one, the TWI takes control over the I/O pins connected to the SCL and SDA pins, enabling the slew-rate limiters and spike filters. If this bit is written to zero, the TWI is switched off and all TWI transmissions are terminated, regardless of any ongoing operation. Bit 1 Res: Reserved Bit This bit is a reserved bit and will always read as zero. www.thinklabs.in

Page 101

Embedded Systems

Bit 0 TWIE: TWI Interrupt Enable When this bit is written to one, and the I-bit in SREG is set, the TWI interrupt request will be activated for as long as the TWINT Flag is high. TWI Status Register TWSR

Bits 7..3 TWS: TWI Status These five bits reflect the status of the TWI logic and the Two-wire Serial Bus. The different status codes are described later in this section. Note that the value read from TWSR contains both the 5-bit status value and the 2-bit prescaler value. The application designer should mask the prescaler bits to zero when checking the Status bits. This makes status checking independent of prescaler setting. This approach is used in this datasheet, unless otherwise noted.

Bit 2 Res: Reserved Bit This bit is reserved and will always read as zero. Bits 1..0 TWPS: TWI Prescaler Bits These bits can be read and written, and control the bit rate prescaler.

TWI Data Register TWDR

In Transmit mode, TWDR contains the next byte to be transmitted. In Receive mode, the TWDR contains the last byte received. It is writable while the TWI is not in the process of shifting a byte. This occurs www.thinklabs.in Page be when the TWI Interrupt Flag (TWINT) is set by hardware. Note that the Data Register cannot 102

Embedded Systems

initialized by the user before the first interrupt occurs. The data in TWDR remains stable as long as TWINT is set. While data is shifted out, data on the bus is simultaneously shifted in. TWDR always contains the last byte present on the bus, except after a wake up from a sleep mode by the TWI interrupt. In this case, the contents of TWDR are undefined. In the case of lost bus arbitration, no data is lost in the transition from Master to Slave. Handling of the ACK bit is controlled automatically by the TWI logic, the CPU cannot access the ACK bit directly. TWI (Slave) Address Register TWAR

The TWAR should be loaded with the 7-bit Slave address (in the seven most significant bits of TWAR) to which the TWI will respond when programmed as a Slave Transmitter or receiver. In multi-master systems, TWAR must be set in Masters which can be addressed as Slaves by other Masters. The LSB of TWAR is used to enable recognition of the general call address ($00). There is an associated address comparator that looks for the Slave address (or general call address if enabled) in the received serial address. If a match is found, an interrupt request is generated. Bits 7..1 TWA: TWI (Slave) Address Register These seven bits constitute the Slave address of the TWI unit Bit 0 TWGCE: TWI General Call Recognition Enable Bit If set, this bit enables the recognition of a General Call given over the Two-wire Serial Bus. Interfacing the Application to the TWI in a Typical Transmission

www.thinklabs.in

Page 103

Embedded Systems

Procedure to conduct I2C communication: Master Transmitter mode: 1. Configure the bit rate register, TWBR, according to the speed desired. 2. Configure the TWCR (control register) considering the following parameters: Enable interrupts transmit start condition, enable TWI. 3. Check if TWINT flag is set. If not, transmit start again. 4. Send SLA+W (Slave Address plus Write) to TWDR. Write one to TWINT (to clear it). This initiates transmission. 5. Wait for TWINT flag. 6. Transmit the data (by writing it to the TWDR register) and clear TWINT (by writing 1 to it). 7. Wait for TWINT, and then send the next byte. 8. For stopping transmission, configure the control register to transmit stop condition. Please note that TWDR register should be written to only if the TWINT bit is set.

Master Receiver mode: 1. Configure the bit rate register, TWBR, according to the speed desired. 2. Configure the TWCR (control register) considering the following parameters: Enable acknowledge, transmit start condition, enable TWI. 3. Check if TWINT flag is set. If not, transmit start again. 4. Send SLA+R (Slave Address plus Write) to TWDR. Write one to TWINT (to clear it). 5. Wait for TWINT flag. 6. Clear TWINT (by writing 1 to it) and wait for it to be set. The received data can be read from the TWDR. 7. Wait for TWINT, check status code and then read the next byte. 8. Keep reading until the last byte is received. Send a NO ACK after the last byte is received (by clearing the Enable Acknowledge Bit in the TWCR). This conveys end of transmission to the master. 9. For stopping transmission, configure the control register to transmit stop condition.

Slave Transmitter/Reciever mode: 1. Write the 7 bit slave address in the TWDR. 2. Configure the TWCR (control register) considering the following parameters: Enable TWI. 3. Wait until slave is addressed by the master. Depending upon the W/R bit, the slave enters the transmitter or receiver mode. (If bit = 0, receiver mode. If bit = 1, transmitter mode.) 4. After the TWINT is set, read the status code.

www.thinklabs.in

Page 104

Embedded Systems

RTC DS1307 GENERAL DESCRIPTION The DS1307 serial real-time clock (RTC) is a low-power, full binary-coded decimal (BCD) clock/calendar plus 56 bytes of NV SRAM. Address and data are transferred serially through An I2C, bidirectional bus. The clock/calendar provides seconds, minutes, hours, day, date, month, and year information. The end of the month date is automatically adjusted for months with fewer than 31 days, including corrections for leap year. The clock operates in either the 24-hour or 12-hour format with AM/PM indicator. The DS1307 has a built-in power-sense circuit that detects power failures and automatically switches to the backup supply. Timekeeping operation continues while the part operates from the backup supply.

www.thinklabs.in

Page 105

Embedded Systems

TIME KEEPING REGISTERS

CONTROL REGISTER The DS1307 control register is used to control the operation of the SQW/OUT pin. www.thinklabs.in Page 106

Embedded Systems

Bit 7: Output Control (OUT). This bit controls the output level of the SQW/OUT pin when the square wave output is disabled. If SQWE = 0, the logic level on the SQW/OUT pin is 1 if OUT = 1 and is 0 if OUT = 0. Bit 4: Square-Wave Enable (SQWE). This bit, when set to logic 1, enables the oscillator output. The frequency of the square-wave output depends upon the value of the RS0 and RS1 bits. With the square wave output set to 1Hz, the clock registers update on the falling edge of the square wave. Bits 1, 0: Rate Select (RS1, RS0). These bits control the frequency of the square-wave output when the square-wave output has been enabled. The following table lists the square-wave frequencies that can be selected with the RS bits.

I2C DATA BUS The DS1307 supports the I2C protocol. A device that sends data onto the bus is defined as a transmitter and a device receiving data as a receiver. The device that controls the message is called a master. The devices that are controlled by the master are referred to as slaves. The bus must be controlled by a master device that generates the serial clock (SCL), controls the bus access, and generates the START and Data transfer may DS1307 operateswhen slave onis not busy. STOP conditions. The be initiated only as a the bus the I2C bus. During data transfer, the data line must remain stable whenever the clock line is HIGH. Changes in the data line while the clock line is high will be interpreted as control signals. Accordingly, the following bus conditions have been defined: Bus not busy: Both data and clock lines remain HIGH. Start data transfer: A change in the state of the data line, from HIGH to LOW, while the clock is HIGH, defines a START condition. Stop data transfer: A change in the state of the data line, from LOW to HIGH, while the clock line is HIGH, defines the STOP condition. www.thinklabs.in Page 107

Embedded Systems

Data valid: The state of the data line represents valid data when, after a START condition, the data line is stable for the duration of the HIGH period of the clock signal. The data on the line must be changed during the LOW period of the clock signal. There is one clock pulse per bit of data. Each data transfer is initiated with a START condition and terminated with a STOP condition. The number of data bytes transferred between START and STOP conditions is not limited, and is determined by the master device. The information is transferred byte-wise and each receiver acknowledges with a ninth bit. Within the I2C bus specifications a standard mode (100 kHz clock rate) and a fast mode (400 kHz clock rate) are Acknowledge: Each receiving device, standard mode (100obliged to generate an acknowledge after defined. The DS1307 operates in the when addressed, is kHz) only. the reception of each byte. The master device must generate an extra clock pulse which is associated with this acknowledge bit. A device that acknowledges must pull down the SDA line during the acknowledge clock pulse in such a way that the SDA line is stable LOW during the HIGH period of the acknowledge related clock pulse. Of course, setup and hold times must be taken into account. A master must signal an end of data to the slave by not generating an acknowledge bit on the last byte that has been clocked out of the slave. In this case, the slave must leave the data line HIGH to enable the master to generate the STOP condition.

The DS1307 may operate in the following two modes: 1. Slave Receiver Mode (Write Mode): Serial data and clock are received through SDA and SCL. After each byte is received an acknowledge bit is transmitted. START and STOP conditions are recognized as the beginning and end of a serial transfer. Hardware performs address recognition after reception of the slave address and direction bit (see Figure 4). The slave address byte is the first byte received after the master generates the START condition. The slave address byte contains the 7-bit DS1307 address, which is 1101000, followed by the direction www.thinklabs.in Page 108 bit (R/W), which for a write is 0. After receiving and decoding the slave address byte, the DS1307 outputs an acknowledge on SDA. After the DS1307 acknowledges the slave address + write bit, the

Embedded Systems

master transmits a word address to the DS1307. This sets the register pointer on the DS1307, with the DS1307 acknowledging the transfer. The master can then transmit zero or more bytes of data with the DS1307 acknowledging each byte received. The register pointer automatically increments after each 2. Slave Transmitter Mode masterMode): The first byte is receivedto terminate the in thewrite. data byte are written. The (Read will generate a STOP condition and handled as data slave receiver mode. However, in this mode, the direction bit will indicate that the transfer direction is reversed. The DS1307 transmits serial data on SDA while the serial clock is input on SCL. START and STOP conditions are recognized as the beginning and end of a serial transfer (see Figure 5). The slave address byte is the first byte received after the START condition is generated by the master. The slave address byte contains the 7-bit DS1307 address, which is 1101000, followed by the direction bit (R/W), which is 1 for a read. After receiving and decoding the slave address the DS1307 outputs an acknowledge on SDA. The DS1307 then begins to transmit data starting with the register address pointed to by the register pointer. If the register pointer is not written to before the initiation of a read mode the first address that is read is the last one stored in the register Data WriteSlave Receiver Mode pointer. The register pointer automatically increments after each byte are read. The DS1307 must receive a Not Acknowledge to end a read.

Data ReadSlave Transmitter Mode

Data Read (Write Pointer, Then Read)Slave Receive and Transmit www.thinklabs.in

Page 109

Embedded Systems

www.thinklabs.in

Page 110

WIRELESS CC2500 TRANSCEIVER RF MODULE


This project is basically developed to demonstrate how to use the CC2500 transceiver module to communicate between two devices. BLOCK DIAGRAM:

COMPUTER SERIAL PORT TX

uNiBoard RX

ANTENNA

RXTX (CC2500 BASED) 2G4 INTERFACE BOARD

ANTENNA

(CC2500 BASED) TX 2G4 INTERFACE BOARD RX

RX uNiBoard TX

COMPUTER SERIAL PORT

The CC2500 is a low-cost 2.4 GHz transceiver designed for very low-power wireless applications. The operation of this module is based on SPI (Serial Peripheral Interface) protocol, but here we are going to use specially designed 2G4 Interface Board which will allow us to use this module using RS232 protocol (over a serial port at 38400 bps). PIN-OUT: Pin 4 Reset. Pin 7- Tx (used to send a byte through UART). Pin 8 Rx (Receives a byte through UART). Pin 9 Vcc. Pin 10 Gnd.

The protocol for initialization and data transfer through 2G4 Interface Board is explained below After reset (system power on) it expects 3-configuration bytes. Byte-1: Self address: (1-254) (0 or 255 for broadcast) Byte-2: Remote address: (1-254) (0 or 255 for broadcast) Byte-3: channel number: (1-254) Where 1. Self address: The address which will be used by other devices to address your device. 2. Remote address: The address of the device with whom you want to communicate. 3. Channel number: The 8-bit unsigned channel number, which is multiplied by the channel spacing (199.950000 kHz) setting and added to the base frequency (2433.000000 MHz).

If no addressing is needed means all the devices wants to communicate with each other or one central device wants to broadcast data to all other devices just transmit 3-bytes of zeros (0x00, 0x00, 0x00). The self/remote address can be changed at any time by just giving a active low pulse on reset pin (pin4)and transmitting 3-bytes (self address, remote address, channel number)

Here we are using only 2 transceiver modules one at the computer end and second on the other computer end, in our program we are initializing 1st transceiver module as Self address= 1 Remote address= 2 (address of the remote device i.e. address of transceiver connected at computer end) Channel as = 3 (selecting channel frequency over which device wants to communicate)

So at the other computer end we will have initialization as Self address= 2 Remote address= 1 (address of the remote device i.e. address of transceiver connected on iBOT) Channel as= 3 (selecting channel frequency over which device wants to communicate)

Initialization of the transceiver on uNiBoard has to be done in microcontroller by sending first three byte of self address, remote address and channel no over the Tx Pin of the microcontroller at 38400 bps (with data parity=none, stop bit=1).In our case it is 1, 2, and 3. Wherein for transceiver module at computer end it bits=8, has to be entered through hyper terminal with same baud rate of 38400 bps(with data bits=8, parity=none,

stop bit=1,flow control=none) as 2, 1, and 3 for doing this open the hyper terminal make initial setting as below.
guided Configuring HyperTerminal: 1. To create a new hyper terminal connection go to Start/All programs/Accessories/communications/Hyper Terminal And give name to it

2. Now select the COM port on which you have connected your serial cable.eg if serial cable is connected at COM Port 1 select connect using tab as COM1.

3. Now select bits per second as 38400 bps (with data bits=8, parity=none, stop bit=1,flow

control=none)
and press OK.

Now once you are connected to hyper terminal firstly we need to initialize the transceiver module for this just enter the self address, remote address and channel no using numpad keys 2,1, and 3.

Once the Initialization is over we are now ready for data transmission in-between these two devices.

XBee & XBee PRO OEM RF Modules Product Manual v1.0

1. XBee & XBee PRO OEM RF Modules


XBee and XBee-PRO Modules were engineered to meet ZigBee/IEEE 802.15.4 standards and address the unique needs of low-cost, low-power wireless sensor networks. The modules require minimal power and provide reliable delivery of critical data between devices.

The modules operate within the ISM 2.4 GHz frequency band and are pin-for-pin compatible with each other.

1.1. Features Overview


High Performance at a Low Cost XBee x Indoor/Urban: up to 100 (30 m) x Outdoor line-of-sight: up to 300 (100 m) x Transmit Power: 1 mW (0 dBm) x Receiver Sensitivity: -92 dBm XBee-PRO x Indoor/Urban: up to 300 (100 m) x Outdoor line-of-sight: up to 4000 (300 m) x Transmit Power: 100 mW (20 dBm) EIRP x Receiver Sensitivity: -100 dBm RF Data Rate: 250,000 bps Advanced Networking & Security Retries and Acknowledgements DSSS (Direct Sequence Spread Spectrum) for reliable long range delivery 16 direct sequence channels, each with over 65,000 unique network addresses available 128-bit Encryption (coming soon) Self-routing/Self-healing mesh networking (coming soon) Low Power XBee x TX Current: 45 mA (@3.3 V) x RX Current: 50 mA (@3.3 V) x Power-down Current: < 10 A XBee-PRO x TX Current: 270 mA (@3.3 V) x RX Current: 55 mA (@3.3 V) x Power-down Current: < 10 A Easy-to-Use XBee & XBee-PRO Modules are interchangeable & pin-for-pin compatible Small Form Factor No configuration necessary for out-of-box RF communications Free Testing and Configuration Software included (X-CTU Software) Software-selectable interface data rates Free & Unlimited Technical Support

1.1.1. Worldwide Acceptance


FCC Approval Pending (USA) Refer to Appendix A [p22] for FCC Requirements. Devices that contain XBee Modules inherit MaxStreams FCC Certification ISM (Industrial, Scientific & Medical) 2.4 GHz frequency band Manufactured under ISO 9001:2000 registered standards XBee & XBee-PRO OEM RF Modules are optimized for use in US, Canada, Australia, Israel and Europe (contact MaxStream for complete list of approvals).

distributed by:

2005 MaxStream, Inc. Confidential and Proprietary

XBee & XBee PRO OEM RF Modules Product Manual v1.0

1.4. Pin Signals


Figure 1 02. XBee & XBee PRO Module Pin Numbers (top sides shown shield on bottom)

Table 1 01. Pin Assignments for the XBee and XBee PRO Modules Low asserted signals are distinguished with a horizontal line above signal name. Pin # 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 PWM0 / RSSI [reserved] [reserved] DTR / SLEEP_RQ / DI8 GND AD4 / DIO4 / RF_TX DIO7 / ON / VREF AD5 / DIO5 / Associate AD6 / DIO6 / AD3 / DIO3 / COORD_SEL AD2 / DIO2 AD1 / DIO1 AD0 / DIO0 Name VCC DOUT DIN / CD / DOUT_EN / DO8 Direction Output Input Output Input Output Input Either Either Output Input Either Either Either Either Either Either Description Power supply UART Data Out UART Data In Carrier Detect, TX_enable or Digital Output 8 Module Reset PWM Output 0 or RX Signal Strength Indicator Do not connect Do not connect Pin Sleep Control Line or Digital Input 8 Ground Analog Input 4, Digital I/O 4 or Transmission Indicator Digital I/O 7 or Clear-to-Send Flow Control Module Status Indicator Voltage Reference for A/D Inputs Analog Input 5, Digital I/O 5 or Associated Indicator Analog Input 6, Digital I/O 6 or Request-to-Send Flow Control Analog Input 3, Digital I/O 3 or Coordinator Select Analog Input 2 or Digital I/O 2 Analog Input 1 or Digital I/O 1 Analog Input 0 or Digital I/O 0

Minimum connections are: VCC, GND, DOUT and DIN. Signal Direction is specified with respect to the module Functions listed in descriptions are software selectable and may not all be available at time of release. Module includes a 50k pull up resistor attached to . Unused inputs should be tied to GND / Unused outputs should be left disconnected.

1.5. Electrical Characteristics


Table 1 02. DC Characteristics of the XBee & XBee PRO (VCC = 2.8 3.4 VDC) Symbol VIL VIH VOL VOH IIIN IIOZ TX RX PWR-DWN Parameter Input Low Voltage Input High Voltage Output Low Voltage Output High Voltage Input Leakage Current Condition All Digital Inputs All Digital Inputs IOL = 2 mA, VCC >= 2.7 V IOH = -2 mA, VCC >= 2.7 V Min 0.7 * VCC VCC - 0.5 Typical 0.025 0.025 45 (XBee) 50 (XBee) 270 (PRO) 55 (PRO) Max 0.35 * VCC 0.5 1 1 Units V V V V uA uA mA mA uA

VIN = VCC or GND, all inputs, per pin -

High Impedance Leakage Current VCC or GND, all I/O High-Z, per pin VIN = Transmit Current Receive Current Power-down Current VCC = 3.3 V VCC = 3.3 V SM parameter = 1 -

< 10

2005 MaxStream, Inc. Confidential and Proprietary

XBee & XBee PRO OEM RF Modules Product Manual v1.0

3.3. XBee Command Descriptions


Command descriptions in this section are listed alphabetically. Command categories are designated within < > symbols that follow each command title. XBee Modules expect parameter numerical values in hexadecimal (designated by the 0x prefix). BD (Interface Data Rate) Command <Serial Interfacing> The BD command is used to set and read the serial interface data rate (baud rate) that is used between the module and host. This parameter specifies the rate at which serial data is sent to the module from the host. AT Command: ATBD Parameter Range: 0 7 Parameter 0 1 2 3 4 5 6 7 Configuration (bps) 1200 2400 4800 9600 19200 38400 57600 115200

Modified interface data rates do not take effect until the CN (Exit AT Command Mode) command is issued and the system returns the OK response. The modules fixed RF data rate is not affected by the BD parameter.

When parameters 0-7 are sent, the respective Default Parameter Value: 3 interface data rates are used (as shown in the table on the right). When parameters greater than 7 are sent, the closest interface data rate represented by the number is stored in the BD register and used. Custom Interface Data Rates: The BD command allows users to specify an interface data rate by entering the hexadecimal value for the desired interface rate. For example, a rate of 19200 bps can be set by sending "ATBD4B00". When the BD command is sent with a parameter greater than 7, the UART will adjust to accommodate the requested interface rate. In most cases, the clock resolution will cause the stored BD parameter to vary from the parameter that was sent (refer to the table below). Reading the BD command (send "ATBD" command without an associated parameter value) will return the value that was actually stored to the BD register (If BD parameter > 7).

Table 3 02. Custom Interface Data Rate Examples BD Parameter Sent (HEX) 0 4 7 12C 1C200 CC (Command Sequence Character) Command AT Command: ATCC<AT Command Mode Options> The CC command is used to set and read the ASCII character usedParameter Range: 0 0xFF between Guard Times of the AT Command ModeDefault Parameter Value: 0x2B (ASCII +) Sequence (GT + CC + GT). The sequence enters Related Commands: AT (Guard Time After), the module into AT Command Mode. The ATBT (Guard Time Before) Command Mode Sequence activates AT Command Mode (from Idle Mode) so that data entering the module through the data in port is recognized as commands instead of payload. Interface Data Rate (Decimal Baud) 1200 bps 19.2 kbps 115.2 kbps 300 bps 115.2 bps BD Parameter Stored (HEX) 0 4 7 12B 1B207

The default sequence used to enter AT Command Mode is as follows: x No characters sent for 1 second [GT (Guard Times) parameter = 0x0A] x Send three plus characters +++ [CC (Command Sequence Character) parameter = 0x2B] x No characters sent for 1 second [GT (Guard Times) parameter = 0x0A]
distributed by:

2005 MaxStream, Inc. Confidential and Proprietary

16

XBee & XBee PRO OEM RF Modules Product Manual v1.0


CH (Channel) Command <Networking & Security> The CH command is used to set and read the channel on which RF connections are made between modules. The channel is one of three network layers available to the module. PAN ID and destination addresses are the other layers. AT Command: ATCH Parameter Range: 0x0B 0x19 Default Parameter Value: 0x0C (12 decimal) Related Commands: ID (PAN ID), DH (Destination Address High), DL (Destination Address Low)

In order for modules to communicate with each other, the modules must share the same channel number. Different channels can be used to prevent modules in one network from listening to transmissions of another. The module uses channel numbers of the 802.15.4 standard. Frequency = 2.405 + (CH 11) * 5 GHz CN (Exit AT Command Mode) Command <AT Command Mode Options> The CN command is used to explicitly exit the module from AT Command Mode. CT (Command Mode Timeout) Command <AT Command Mode Options> The CT command is used to set and read the amount of inactive time that elapses before the module automatically exits from AT Command Mode and returns to Idle Mode. Use the CN (Exit AT Command Mode) command to exit AT Command Mode manually. AT Command: ATCT Parameter Range: 2 0xFFFF [x 100 milliseconds] Default Parameter Value: 0x64 (100 decimal, which equals 10 decimal seconds) Number of bytes returned: 2 DB (Received Signal Strength) Command AT Command: ATDB<Diagnostics> The DB parameter is used to read the received signal strength (in dBm) of the lastParameter Range: 0 0x64 [read-only] packet received. Reported values are accurate between -40 dBm and the modules receiver sensitivity. Absolute values are reported. For example: 0x58 = -88 dBm. DH (Destination Address High) Command <Networking & Security> The DH command is used to set and read the upper 32 bits of the modules 64-bit destination address. When combined with the DL (Destination Address Low) parameter, it defines the destination address used for transmission. AT Command: ATDH Parameter Range: 0 0xFFFFFFFF Default Parameter Value: 0 Related Commands: DL (Destination Address Low), CH (Channel), ID (PAN VID), MY (Source Address) AT Command: ATCN

Modules will only communicate with other modules having the same channel (CH parameter), PAN ID (ID parameter) and destination address (DH + DL parameters). To transmit using a 16-bit address, set the DL parameter to zero and the DH parameter less than 0xFFFF. 0x000000000000FFFF (DH concatenated to DL) is the broadcast address for the PAN. Refer to the Addressing section [p12] for more information.

distributed by:

2005 MaxStream, Inc. Confidential and Proprietary

17

XBee & XBee PRO OEM RF Modules Product Manual v1.0


DL (Destination Address Low) Command <Networking & Security> The DL command is used to set and read the lower 32 bits of the modules 64-bit destination address. When combined with the DH (Destination Address High) parameter, it defines the destination address used for transmission. AT Command: ATDL Parameter Range: 0 0xFFFFFFFF Default Parameter Value: 0 Related Commands: DH (Destination Address High), CH (Channel), ID (PAN VID), MY (Source Address)

Modules will only communicate with other modules having the same channel (CH parameter), PAN ID (ID parameter) and destination address (DH, DL parameters). To transmit using a 16-bit address, set the DL parameter to zero and the DH parameter less than 0xFFFF. 0x000000000000FFFF (DH concatenated to DL) is the broadcast address for the PAN. Refer to the Addressing section [p12] for more information. GT (Guard Times) Command <AT Command Mode Options> AT Command is used to set the DI time-of-silence that surround the AT command sequence character (CC Command) of the AT Command Mode sequence (GT + CC + GT). The DI time-of-silence is used to prevent inadvertent entrance into AT Command Mode. AT Command: ATGT Parameter Range: 0x02 0xFFFF [x 1 millisecond] Default Value: 0x3E8 (1000 decimal, which is 1 decimal second) Related Commands: CC (AT Command Sequence Character)

The default sequence used to enter AT Command Mode is as follows: x No characters sent for 1 second [GT (Guard Time) parameter = 0x0A] x Send three plus characters +++ [CC (Command Sequence Character) parameter = 0x2B] x No characters sent for 1 second [GT (Guard Time) parameter = 0x0A] ID (PAN ID) Command <Networking & Security> The ID command is used to set and read the PAN (Personal Area Network) ID of the module. Only modules with matching PAN IDs can communicate with each other. Modules with non-matching PAN IDs will not receive unintended data transmission. AT Command: ATID Parameter Range: 0 - 0xFFFF Default Parameter Value: 0x3332 (13106 decimal)

Setting ID to 0xFFFF indicates a global message for all PANs. MY (16-bit Source Address) Command <Networking & Security> The MY command is used to set and read the 16-bit source address of the module. By setting MY to 0xFFFF, the reception of RF packets having a 16-bit address is disabled. The 64-bit address is the module serial number and is always enabled. AT Command: ATMY Parameter Range: 0 0xFFFF Default Parameter Value: 0 Related Commands: DH (Destination Address High), DL (Destination Address Low), CH (Channel), ID (PAN ID)

P0 (PWM0 Configuration) Command <Diagnostics> The P0 command is used to select and read the function for PWM0 (pin 6 of the OEM RF module). AT Command: ATP0 Parameter Range: 0 1 Parameter 0 1 Default Parameter Value: 1 Configuration Disabled RSSI PWM

distributed by:

2005 MaxStream, Inc. Confidential and Proprietary

18

XBee & XBee PRO OEM RF Modules Product Manual v1.0


PL (Power Level) Command <RF Interfacing> The PL command is used to select and read the power level at which the module transmits. AT Command: ATPL Parameter Range: 0 4 Parameter 0 1 2 3 4 XBee -11.5 dBm -5.5 dBm -4.5 dBm -2 dBm 0 dBm XBee-PRO 10 dBm 12 dBm 14 dBm 16 dBm 18 dBm

Default Parameter Value: 4

RE (Restore Defaults) Command AT Command: ATRE<(Special)> The RE command is used to restore all configurable parameters to their factory default settings. The RE command does not write restored values to non-volatile (persistent) memory. Issue the WR (Write) command after the RE command to save restored parameter values to nonvolatile memory.

RN (Random Delay Slots) Command AT Command: ATRN<Networking & Security> The RN command is used to set and read the minimum value of theParameter Range: 0 5 back-off exponent in the CSMA-CA algorithm. TheDefault Parameter Value: 0 CSMA-CA algorithm was engineered to insert random delays and prevent loss of data caused by data collisions. If RN = 0, collisions avoidance is disabled during the first iteration of the algorithm (802.15.4 macMinBE). CSMA-CA stands for Carrier Sense Multiple Access - Collision Avoidance. Unlike CSMA-CD (reacts to network transmissions after collisions have been detected), CSMA-CA acts to prevent data collisions before they occur. As soon as a module receives a packet that is to be transmitted, it checks if the channel is clear (no other module is transmitting). If the channel is clear, the packet is sent over-the-air. If the channel is not clear, the module waits for a randomly selected period of time, then checks again to see if the channel is clear. This process continues until the module is able to transmit.

RO (Packetization Timeout) Command AT Command: ATRO<Serial Interfacing> The RO command is used to set and read the number of character times ofParameter Range: 0 0xFF [x character times]inter-character delay required before Default Parameter Value: 3transmission. RF transmission commences when data is detected in the DI buffer and RO character times of silence are detected on the UART receive lines (after receiving at least 1 byte). (RF transmission will also commence when 106 bytes (maximum buffer size) are received in the DI buffer.) Set the RO parameter to 0 to transmit characters as they arrive instead of buffering them into one RF packet.

distributed by:

2005 MaxStream, Inc. Confidential and Proprietary

19

XBee & XBee PRO OEM RF Modules Product Manual v1.0


RP (RSSI PWM Timer) Command AT Command: ATRP<Diagnostics> The RP command is used to enable PWM (Pulse Width Modulation) output on pin 3 ofParameter Range: 0 - 0xFF [x 100 milliseconds]the XBee Modules. The output is calibrated to Default Parameter Value: 0x28 (40 decimal)show the level the received RF signal is above the sensitivity level of the module. The PWM pulses vary from zero to 95 percent. Zero percent means the received RF signal is at or below the published sensitivity level of the module. The following table shows levels above sensitivity and PWM values.

The total period of the PWM output is 8.32 ms. Because there are 40 steps in the PWM output, the minimum step size is 0.208 ms. Table 3 03. PWM Percentages dBm above Sensitivity 10 20 30 PWM percentage * (high period / total period) 46.0% 63.0% 80.1%

* PWM % = (295 + (17.5 * dBm above sensitivity)) / 10.24 A non-zero value defines the time that the PWM output will be active with the RSSI value of the last received RF packet. After the set time when no RF packets are received, the PWM output will be set low (0 percent PWM) until another RF packet is received. The PWM output will also be set low at power-up until the first RF packet is received. A parameter value of 0xFF permanently enables the PWM output and it will always reflect the value of the last received RF packet.

SH (Serial Number High) Command <Diagnostics> The SH command is used to read the high 32 bits of the modules unique IEEE 64bit address. The module serial number is set at the factory. AT Command: ATSH Parameter Range: 0 0xFFFFFFFF [read-only] Related Commands: SL (Serial Number Low), MY (Source Address)

SL (Serial Number Low) Command <Diagnostics> The SL command is used to read the low 32 bits of the modules unique IEEE 64-bit address. The module serial number is set at the factory. SM (Sleep Mode) Command <Sleep Mode (Low Power)> The SM command is used to set and read module Sleep Mode settings. By default, Sleep Modes are disabled (SM = 0) and the module remains in Idle/Receive Mode. When in this state, the module is constantly ready to respond to either serial or RF activity. AT Command: ATSM Parameter Range: 0 6 Parameter 0 1 Refer to the Sleep Mode section [p9] for information regarding each Sleep Mode option. 2 3 4 5 6 Configuration Disabled Pin Hibernate Pin Doze (reserved) Cyclic Sleep Remote Cyclic Sleep Remote (with Pin Wake-up) Cyclic Sleep Coordinator AT Command: ATSL Parameter Range: 0 0xFFFFFFFF [read-only] Related Commands: SH (Serial Number High), MY (Source Address)

Default Parameter Value: 0 Related Commands: SP (Cyclic Sleep Period), ST (Time before Sleep)

distributed by:

2005 MaxStream, Inc. Confidential and Proprietary

20

XBee & XBee PRO OEM RF Modules Product Manual v1.0


SP (Cyclic Sleep Period) Command <Sleep Mode (Low Power)> The SP command is used to set and read the sleep period for cyclic sleeping remote modules. The maximum sleep period is 268 seconds (SP = 0x68B0). The SP parameter is only valid if the module is configured to operate in Cyclic Sleep (SM = 4-6). AT Command: ATSP Parameter Range: 1 0x68B0 [x 10 milliseconds] Default Parameter Value: 0x64 (100 decimal) Related Commands: SM (Sleep Mode), ST (Time before Sleep)

ST (Time before Sleep) Command <Sleep Mode (Low Power)> The ST command is used to set and read the period of time that the module remains inactive (no transmitting or receiving) before entering into Sleep Mode. AT Command: ATST Parameter Range: 1 0xFFFF [x 1 millisecond] Default Parameter Value: 0x1388 (5000 decimal)

For example, if the ST parameter is set to its Related Commands: SM (Sleep Mode), SP default value of 0x1388 (5000 decimal), the (Cyclic Sleep Period) module will enter into Sleep mode after 5 seconds of inactivity. This command can only be used if Cyclic Sleep settings have been selected using SM (Sleep Mode) Command (SM = 4-6). VR (Firmware Version) Command <Diagnostics> The VR command is used to read which firmware version is stored in the module. AT Command: ATVR Parameter Range: 0 0xFFFF [read-only]

WR (Write) Command AT Command: ATWR<(Special)> The WR command is used to write configurable parameters to the modules nonvolatile memory (Parameter values remain in modules memory until overwritten by future use of WR Command). If changes are made without writing them to non-volatile memory, the module reverts back to previously saved parameters the next time the module is powered-on.

distributed by:

2005 MaxStream, Inc. Confidential and Proprietary

21

1. Introduction
1.1. Overview
Parani-ESD is a module device for wireless serial communication using Bluetooth technology that is international a standard for short range wireless communications. Parani-ESD can communicate with other Bluetooth devices that support the Serial Port Profile. Parani-ESD lineup has several models with different communication ranges from 30m (ParaniESD200/210) up to 100m (Parani-ESD100/110) for use with various applications. The Parani-ESD delivers better quality of communication than a standard RS232 cables. Parani-ESD has a compact design and can be placed conveniently into devices or equipment. Its detachable antenna optimizes the quality and distance for wireless communications. Parani-ESD supports FHSS (Frequency Hopping Spread Spectrum), which is a technique, native to Bluetooth that allows the Parani-ESD minimize radio interference while decreasing the likelihood of over-air hijacking. Parani-ESD also supports authentication and Bluetooth data encryption. Parani-ESD can be configured and controlled by typical AT commands. Users can easily configure Parani-ESD by using a terminal program such as HyperTerminal and can use Bluetooth wireless communication without modifying users existing serial communication program. In addition to the basic AT commands, Parani-ESD provides some expanded AT commands for various functions. User friendly ParaniWizard and ParaniWIN are also provided for easy setup on Microsoft Windows.

1.2. Package Check List


1.2.1. Single/Bulk Unit Package
z Parani -ESD100/200 - Parani -ESD100/200 module - on-board chip antenna Parani -ESD110/210 - Parani -ESD110/210 module - Stub Antenna - Antenna extension cable

1.2.2. Starter Kit


- Jig board - Serial data cable - DC Power Adapter - A hardcopy of Quick Start Guide - CD-ROM including the Configuration S/W and User Guide

1.3. Product Specification


Parani-ESD100/110Parani-ESD200/210 Serial speeds 1200bps to 230400bps Flow Control: None, Hardware RTS/CTS 2.54mm Header 2X62.54mm Header 1X4X2 Bluetooth v1.2 Protocol: RFCOMM, L2CAP, SDP Profile: Serial Port Profile Class 1Class 2 Level: 18dBmLevel: Max. 4dBm Parani-ESD100-Working distance:Parani-ESD200-Working distance: Nominal 100mNominal 30m Parani-ESD210-Working distance:Parani-ESD110-Working distance: DefaultDefault Antenna 100mDefaultDefault Antenna 30m DefaultDipole Antenna 150mDefaultDipole Antenna 50m DipoleDipole Antenna 200mDipoleDipole Antenna 80m PatchDipole Antenna150mPatchDipole Antenna400m PatchPatch Antenna1000mPatchPatch Antenna300m ParaniWIN, ParaniWizard, Modem AT command set ParaniUpdater Supply voltage: 3.3V DC Supply current: - Parani-ESD100/110 : minimum 300mA - Parani-ESD200/210 : minimum 150mA Nominal power consumption Parani-ESD100 : 43mA@9600bps, 61mA@115Kbps Parani-ESD110 : 44mA@9600bps, 57mA@115Kbps Parani-ESD200 : 33mA@9600bps, 40mA@115Kbps Parani-ESD210 : 31mA@9600bps, 39mA@115Kbps Operating temperature: -10 ~ 55 oC Storage temperature: -20 ~ 70 o C Humidity : 90% (Non-condensing) Parani-ESD100 DimensionDimension 27.5 mm L (1.08 in.)18 mm L (0.7 in.) 30 mm W (1.18 in.)20 mm W (0.78 in.) 14 mm H (0.55 in.)12 mm H (0.47 in.) Parani-ESD110 Dimension 27.5 mm L (1.08 in.) 27.7 mm W (1.09 in.) 14 mm H (0.55 in.) WeightWeight 5g2g FCC(A), MIC, CE, SIG 3-year limited warranty

Serial Interface

Bluetooth Interface

Configuration Firmware Update Power

Environmental

Physical properties

Approvals Warranty

A.1.2. Parani-ESD200/210

Antenna
GND VDD DCD RST 1 2 3 4 8 7 6 5 RXD TXD RTS CTS

Figure A-2 Pin Assignment of Parani-ESD200/210 Table A-2 Pin Assignment of Parani-ESD200/210

Pin # 1 2 3 4 5 6 7 8

Signal GND VDD DCD RST CTS RTS TxD RxD

Direction Input Output Input Input Output Output Input

Description Power Ground DC Input (3.0~3.3V) Bluetooth Connect Detect (Active Low) Reset (Active Low) UART Clear to Send UART Ready to Send UART Data Output UART Data Input

Signal Level Ground Power TTL TTL TTL TTL TTL TTL

A.1.3. DCD Signal (Status: Bluetooth Connect Detect)


Status of Bluetooth connection will be delivered to Host PC via DCD line. Connection Module low signal

A.1.4. RST Signal


RST signal will be used for setting the Parani-ESD to factory defaults. RST should be on 0V status for at least 1 second for the reset to occur.

30

3. Configuration
3.1. Operation Modes
In addition to the serial port configurations, the Parani-ESD requires also includes some settings for Bluetooth. For getting the most out of Parani-ESD, user should understand the following Bluetooth connection schemes. A Bluetooth device can play a role as a master or slave. Master tries to connect itself to other Bluetooth devices, and slave is waiting to be connected from other Bluetooth devices. A Bluetooth connection is always made by a pair of master and slave devices. A slave can be in two modes, Inquiry Scan or Page Scan mode. Inquiry Scan mode is waiting for a packet of inquiry from other Bluetooth device and Page Scan mode is waiting for a packet of connection from other Bluetooth device. Every Bluetooth device has its unique address, called BD (Bluetooth Device) address, which is composed of 12 hexa-decimal numbers.

Parani-ESD has 4 operation modes as follows:

Table 3-1 The Parani-ESD Operation Modes


Mode Mode0 Description In this mode, there is no response when power on or software reset, and Parani- ESD is just waiting for AT command input. Neither master nor slave is assigned to Parani-ESD in mode0. User can change the configuration parameters of Parani-ESD in this mode. Parani -ESD must be in Mode0, when it is directly controlled by AT commands. The factory default is set to Mode0. Mode1 Parani -ESD tries to connect the last connected Bluetooth device. Parani -ESD in Mode1 is to be a master and tries to connect the last connected Bluetooth device. Parani-ESD always stores the BD address of the Bluetooth device to which ParaniESD has connected last. When Parani-ESD is initially used or after hardware reset, there is no BD address stored in Parani-ESD. In this case, Mode1 will not be able to work properly. The mode change to Mode1 can be made after Parani- ESD succeeds to connect to one other Bluetooth device. Once changed to Mode1, Parani-ESD will try to connect automatically the last connected Bluetooth device whenever the unit is powered on or software reset. Parani -ESD in Mode1 cannot be discovered or connected by other Bluetooth devices. Parani -ESD is waits for a connection from the last connected Bluetooth device. Parani -ESD in Mode2 is to be a slave and waiting for the connection only from the last connected Bluetooth device. Just like Mode1, if there is no BD address stored in Parani-ESD, the mode change from other operation modes to Mode2 is not work properly. Once changed to Mode2, Parani-ESD will wait for the connection from the last connected Bluetooth device whenever the unit is powered on or software reset. Parani -ESD in Mode2 cannot be discovered or connected to Bluetooth devices other than the last connected device. Parani -ESD is waiting for the connection from any other Bluetooth devices. In Mode 3 the Parani -ESD is discoverable and can be connected to by other Bluetooth devices.

Mode2

Mode3

13

Appendix B: AT Commands

B.1. Terminology

B.1.1. AT Command
AT command set is a in fact standard language for controlling modems . The AT command set was developed by Hayes and is recognized by virtually all personal computer modems. Parani-ESD provides the extended AT command set to control and configure the serial parameters and Bluetooth connection.
HT TH HT TH HT HT HT TH HT TH

B.1.2. AT Response
Parani-ESD replies to AT commands with 4 kinds of message, OK, ERROR, CONNECT and DISCONNECT.

B.1.3. Operation Mode


Mode Mode0 Mode1 Mode2 Mode3 Description Waiting for AT commands Attempting to connect to the last connected Bluetooth device Waiting for a connection from the last connected Bluetooth device Waiting for the connection from another Bluetooth device

B.1.4. Operation Status


Status Standby Pending Connect Description Waiting for AT commands Executing tasks Transmitting data

B.1.5. Security
Security Authentication Encryption Description Pin Code (or Pass key) Data encryption

36

B.1.6. Symbols
The symbols are used for the description of command syntax as follows:
Symbols Meaning Carriage return Line feed Carriage return + Line feed 00112233445566 Bluetooth device address N or m To One digit decimal number Timeout in seconds ASCII Code 0x0D 0x0A

B.2. Command Category


Command Category RESET SERIAL PORT BLUETOOTH Information Index 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 AT Commands ATZ AT&F AT AT+UARTCONFIG,b,p,s,h AT+BTINFO? AT+BTINQ? AT+BTLAST? AT+BTVER? AT+BTRSSI,n AT+BTMODEn +++ AT+SETESC,nn ATO AT+BTCANCEL AT+BTSCAN AT+BTSCAN,n,to AT+BTSCAN112233445566,to ATD ATD112233445566 ATA ATA112233445566 ATH AT+BTKEY=$string AT+BTSD? AT+BTCSD AT+BTFP,n AT+BTSEC,a,e AT+BTNAME=$string AT+BTLPM,n AT&V ATSnn? ATSnn=mm

Mode Status

Connection

Security

Miscellaneous S-REGISTER

37

B.3. Command Description


B.3.1. ATZ
Response Purpose Description OK Software Reset This has the same effects as Powercycling the unit. This command disconnects any connected Bluetooth device, and stops ongoing tasks. After rebooting, the status will be decided by the preset operation mode. Some AT commands require the ATZ command be run so that the commands can take effect. AT&F, AT+BTCSD, AT+UARTCONFIG

Reference

B.3.2. AT&F
Response Purpose Description Reference OK Hardware reset This has the same effect as initialization by pressing the factory reset button. All parameters are initialized to factory defaults ATZ

B.3.3. AT
Response Purpose Description OK Check the connection status with host equipment Check if the connection to host equipment is operating normally. The serial parameters of Parani-ESD must be same as those of host equipment. If not, the Parani-ESD will not respond or ERROR message will appear or an abnormal sequence of strings will appear. AT+UARTCONFIG, ATZ, AT&F

Reference

B.3.4. AT+UARTCONFIG,Baudrate,Parity,Stopbit,Hwfc
Response Purpose Parameters OK Set Serial parameters Baudrate=1200/2400/9600/14400/19200/38400/57600/115200/230400 (Default=9600) Parity=N/E/O (Default=N) Stopbit=1/2 (Default=1) Hwfc(Hardware Flow Control)=0/1 (Default=1) The Serial parameters can be set or changed. The factory default is 9600, N, 1. To take effect the ATZ command must be used or Powercycle the unit. AT, ATZ, AT&F, ATS AT+UARTCONFIF,9600,N,1

Description Reference Example

38

B.3.5. AT+BTINFO?
Response Purpose Description 112233445566,DeviceName,Mode,Status,Auth,Encryp,FlowControl OK Display Bluetooth settings The current Bluetooth settings are displayed including BD address, Device name, Operation mode, Operation status, Authentication, Data Encryption, and Hardware Flow Control. The initial value of Device name is ESD100v1.1.3-445566. ESD stands for Parani-ESD, v1.1.3 for the version of firmware, and 445566 for the last 6 digits of BD address. Mode=MODE0/MODE1/MODE2/MODE3 Status=STANDBY/PENDING/CONNECT Auth=0/1 (Authentication is not activated when 0) Encrypt=0/1 (Encryption is not activated when 0) FlowControl=HWFC/NoFC AT+BTNAME, AT+BTMODE, AT+BTSEC, ATS14? 000B530011FF,SENA,MODE0,PENDING,1,1,HWFC

Reference Example

B.3.6. AT+BTINQ?
Response 112233445566,FriendlyName,CoD 112233445566,FriendlyName,CoD 112233445566,FriendlyName,CoD OK Search Bluetooth devices nearby The Bluetooth devices in Inquiry scan mode nearby are displayed with their BD addresses, Device names, and Class of device. Maximum 15 devices are scanned for 30 seconds. (Default 10 value in S-register 6) AT+BTSCAN, ATD, AT+BTINFO?

Purpose Description

Reference

B.3.7. AT+BTLAST?
Response Purpose Description Reference 112233445566 Display the BD address of the last connected device The Bluetooth device last connected to this Parani-ESD is displayed with its BD address. AT+BTSCAN, ATD, AT+BTINFO?, AT+BTINQ?

B.3.8. AT+BTVER?
Response Purpose Description Reference ESD100v1.1.3 OK Display device firmware version Display device firmware version AT+BTINFO?

B.3.9. AT+BTRSSI,n
Response OK 0,255,0,0 (repeatedly)

39

Purpose Parameters Description

Test signal strength n=0: Stop signal strength test n=1: Start signal strength test When Bluetooth connection is established, you can use this command in Standby status. The signal strength will be displayed repeatedly in order of Status, LinkQuality, Status, RSSI. If the LinkQuality is close to 255 and RSSI is close to 0, the signal strength is in good standing. +++ AT+BTRSSI,1 OK 0,255,0,0

Example

B.3.10. AT+BTMODE,n
Response EPurpose Parameters OK Set operation mode n=0: MODE0 (Default) n=1: MODE1 n=2: MODE2 n=3: MODE3 When the operation status is Pending currently, change the status to Standby with AT+BTCANCEL prior to this command. To take effect the ATZ must be executed or Powercycle the unit AT+BTINFO? AT+BTMODE,2 OK ATZ

Description

Reference Example

B.3.11. +++
Response Purpose Description OK Convert the operation status of Connect to Standby In Connect status, data from host is transmitted to the other side Bluetooth device, and any AT command is not accepted but this command, which is not echoed on the screen. When Parani-ESD encounters a character + from host, it stops the data transmission and waits for next 2 characters. If the next 2 characters arent both +, it restart to transmit data including the first + as well. If not, it converts the operation status to Standby. If the data from host includes +++, it will convert the operation status to Standby. Notice that Parani-ESD holds data transmission when it encounters +, until receiving next character. + is an escape sequence character by default, which is changeable by AT+SETESC. AT+SETESC, ATO, AT+BTCANCEL

Reference

B.3.12. AT+SETESC,nn
Response Purpose Description Reference OK Change the escape sequence character Escape sequence character set to + by default is changeable. The parameter nn must be a printable character. +++, ATO

40

Example

AT+SETESC,42

B.3.13. ATO
Response Purpose Description Reference None Convert the operation status of Standby to Connect You can convert the operation status of Standby to Connect ready to transmit data. +++, AT+SETESC

B.3.14. AT+BTCANCEL
Response Purpose Description Reference OK Terminate the current executing task This terminates a current executing task, such as Inquiry scan and Page scan, then converts the operation status to Standby AT+BTSCAN, ATD, AT+BTINQ?

B.3.15. AT+BTSCAN
Response Purpose Description OK CONNECT 112233445566 Wait for inquiry and connection from other Bluetooth devices This allows the inquiry and connection from the other Bluetooth devices. The operation status will be in Pending after this command. When connection is made and released, the operation status is back to Pending. To convert the operation status to Standby AT+BTCANCEL must be used. This has the same effect as AT+BTSCAN,3,0. When connection is made with other Bluetooth device, response will be CONNECT with its BD address. ATD, AT+BTINQ?, AT+BTCANCEL

Reference

B.3.16. AT+BTSCAN,n,to
Response OK CONNECT 112233445566 or OK ERROR Wait for inquiry and connection from other Bluetooth devices for a given duration n=1: Allows Inquiry scan n=2: Allows Page scan n=3: Allows both of Inquiry scan and Page scan to= Time duration in seconds For the given to, Parani-ESD is waiting for the inquiry and connection from other Bluetooth devices. If the parameter of to is 0, it will wait forever. When connection is made with other Bluetooth device, response will be CONNECT with its BD address. If there is no connection made within this time duration, response is ERROR and the operation status becomes to Standby. ATD, AT+BTINQ?, AT+BTCANCEL AT+BTSCAN,2,30

Purpose Parameters

Description

Reference Example

41

B.3.17. AT+BTSCAN112233445566,to
Response OK CONNECT 112233445566 or OK ERROR Wait for connection by the Bluetooth device with given BD address 112233445566=BD address to= time duration in seconds Parani-ESD will wait to be connected to by the Bluetooth device with the given BD address. If the parameter of to is 0, it will wait forever. When connection is made with the Bluetooth device, response will be CONNECT with its BD address. If there is no connection made within this time duration, response is ERROR and the operation status becomes to Standby. ATD, AT+BTINQ?, AT+BTCANCEL AT+BTSCAN000B530011FF,30

Purpose Parameters Description

Reference Example

B.3.18. ATD
Response OK CONNECT 112233445566 or OK ERROR Connect to the last connected Bluetooth device Parani-ESD saves the BD address of the Bluetooth device most recently connected to. If it fails to make a connection, response will display an ERROR. AT+BTINQ?, AT+BTSCAN

Purpose Description Reference

B.3.19. ATD112233445566
Response OK CONNECT 112233445566 or OK ERROR Connect to a specific Bluetooth device with a given BD address 112233445566=BD address Parani-ESD attempts to connect to the Bluetooth device with the given BD address. To make successful connection, the Bluetooth device must be in Page scan mode. This attempt continues for 5 minutes. If it fails to make connection, response is ERROR. AT+BTINQ?, AT+BTSCAN ATD000B530011FF

Purpose Parameters Description

Reference Example

42

B.3.20. ATA
Response OK Start ACL Open ACL Connect Success or ACL Connect Fail ACL connect to the last connected Bluetooth device If it make connection, response will display an ACL Connect Success, and if fail to connection, display ACL Connection Fail. Must have reboot for new ACL connection.

Purpose Description

B.3.21. ATA112233445566
Response OK Start ACL Open ACL Connect Success or ACL Connect Fail ACL connect to a specific Bluetooth device with a given BD address 112233445566 = BD address Parani-ESD attempts to ACL connect to the Bluetooth device with the given BD address. To make successful ACL connection, the Bluetooth device must be in Page scan mode. If it make connection, response will display an ACL Connect Success, and if fail to connection, display ACL Connection Fail. Must have reboot for new ACL connection. ATA000B530011FF

Purpose Parameters Description

Example

B.3.22. ATH
Response Purpose Description Reference OK DISCONNECT Release the current connection The current Bluetooth connection will be disconnected. It takes about 30 seconds to detect an abnormal disconnection such as power off and moving out of service range. ATD, AT+BTSCAN

B.3.23. AT+BTKEY=$string
Response Purpose Parameters Description Reference Example OK Change pin code $string= New pin code (Default= 1234 ) Pin code is a string, which allows up to 16 alpha-numeric characters. Based on this pin code, Parani-ESD generates a link key which is used in actual authentication process AT+BTCSD, AT+BTFP, AT+BTSD?, AT+BTSEC, ATZ, AT&F AT+BTKEY= apple

B.3.24. AT+BTSD?
Response 112233445566 OK

43

Purpose Description

Display a list of Bluetooth devices sharing the same pin code Once a connection is made with a pin code, Parani- ESD saves the Bluetooth device with its link key, generated by the pin code. The connection to a device listed in Parani- ESD can be made automatically without the authentication process. The maximum number kept on the list is 5. AT+BTCSD, AT+BTFP, AT+BTKEY, AT+BTSEC, ATZ, AT&F

Reference

B.3.25. AT+BTCSD
Response Purpose Description Reference OK Clear the list of Bluetooth devices sharing the same pin code This clears the list of Bluetooth devices linked with the same key in flash memory. To take effect the ATZ command must be used or Powercycle the unit. AT+BTFP, AT+BTKEY, AT+BTSD?, AT+BTSEC, ATZ, AT&F

B.3.26. AT+BTFP,n
Response Purpose Parameters Description Reference OK Set generation of link key every time of connection n=0: Inactivate (Default) n=1: Activate If n is set to 1, Parani-ESD asks for the pin code every time a connection is made. This can be used to increase security. AT+BTCSD, AT+BTKEY, AT+BTSD?, AT+BTSEC, ATD, ATZ, AT&F

B.3.27. AT+BTSEC,Authentication,Encryption
Response Purpose Parameters OK Set authentication and data encryption Authentication=0: Inactivate (Default) Authentication=1: Activate Encryption=0: Inactivate (Default) Encryption=1: Activate If the authentication is activated, the pin code must be set by AT+BTKEY command. Data encryption cannot be used when authentication is not enabled, i.e. Authentication=0 and Encryption=1 will not work properly. AT+BTCSD, AT+BTFP, AT+BTSD?, AT+BTSD?, ATZ, AT&F

Description

Reference

B.3.28. AT+BTNAME=$string
Response Purpose Parameters Description Reference Example OK Change device name $string= New device name (Default= ESDv1.1.3-445566 ) Parani-ESD can have a user friendly name for easy identification. The name allows up to 30 alpha-numeric characters. AT+BTINFO?, AT+BTINQ? AT+BTNAME= My-Parani-ESD

44

B.3.29. AT+BTLPM,n
Response Purpose Parameters Description OK Set low power mode n=0: Inactivate (Default) n=1: Activate During no data transmission, Parani-ESD can be in low power mode to save the power. It takes a few seconds to wake the Parani-ESD out of low power mode.

B.3.30. AT&V
Response Purpose Description Reference S0:m0;S1:m1; OK Sn:mn

Display all the S-register All parameters are stored at S-register in flash memory. These values are sustained until hardware reset. ATS

B.3.31. ATSnn?
Response Purpose Parameters Description Reference value OK Display a given S-register nn= Address of S-register A specific S-register will be displayed. AT&V

B.3.32. ATSnn=mm
Response Purpose Parameters Description OK Change S-register value nn= Address of S-register mm= New value of S-register Some S-registers are optimized for the overall performance and protected and cannot be changed. When users try to change these S-registers, response is ERROR. For details of S-register, refer Appendix. B. AT&V ATS10=0

Reference Example

B.4. Command Validity


AT Command Standby AT Operation Status Pending Connect

45

SIM300 Hardware Interface Description Confidential

SIMCOM

2 Product concept
Designed for global market, SIM300 is a Tri-band GSM/GPRS engine that works on frequencies EGSM 900 MHz, DCS 1800 MHz and PCS1900 MHz. SIM300 provides GPRS multi-slot class 10/ class 8 (optional) capability and support the GPRS coding schemes CS-1, CS-2, CS-3 and CS-4.

With a tiny configuration of 40mm x 33mm x 2.85 mm , SIM300 can fit almost all the space requirement in your application, such as Smart phone, PDA phone and other mobile device.

The physical interface to the mobile application is made through a 60 pins board-to-board connector, which provides all hardware interfaces between the module and customers boards except the RF antenna interface. z The keypad and SPI LCD interface will give you the flexibility to develop customized applications.

z z

Two serial ports can help you easily develop your applications. Two audio channels include two microphones inputs and two speaker outputs. This can be easily configured by AT command.

SIM300 provide RF antenna interface with two alternatives: antenna connector and antenna pad. The antenna connector is MURATA MM9329-2700. And customers antenna can be soldered to the antenna pad. The SIM300 is designed with power saving technique, the current consumption to as low as 2.5mA in SLEEP mode. The SIM300 is integrated with the TCP/IP protocol Extended TCP/IP AT commands are developed for customers to use the TCP/IP protocol easily, which is very useful for those data transfer applications.

SIM300_HD_V2.03

Page 11 of 55

SIM300 Hardware Interface Description Confidential

SIMCOM

2.1 SIM300 key features at a glance


Table 3 SIM300 key features
Feature Power supply Power saving Frequency bands Implementation Single supply voltage 3.4V 4.5V Typical power consumption in SLEEP mode to 2.5mA z SIM300 Tri-band: EGSM 900, DCS 1800, PCS 1900. The band can be set by AT COMMAND, and default band is EGSM 900 and DCS 1800. Compliant to GSM Phase 2/2+

z GSM class Transmit power GPRS connectivity Small MS z z z z z z z z z z z z Class 4 (2W) at EGSM900 Class 1 (1W) at DCS1800 and PCS 1900 GPRS multi-slot class 8 default GPRS multi-slot class 10 (option) GPRS mobile station class B Normal operation: -20C to +55C Restricted operation: -25C to -20C and +55C to +70C Storage temperature -40C to +80C GPRS data downlink transfer: max. 85.6 kbps GPRS data uplink transfer: max. 42.8 kbps Coding scheme: CS-1, CS-2, CS-3 and CS-4 SIM300 supports the protocols PAP (Password Authentication Protocol) usually used for PPP connections. The SIM300 integrates the TCP/IP protocol. Support Packet Switched Broadcast Control Channel (PBCCH) CSD transmission rates: 2.4, 4.8, 9.6, 14.4 kbps, non-transparent Unstructured Supplementary Services Data (USSD) support

Temperature range

DATA GPRS:

CSD:

z z z z z z z

SMS

MT, MO, CB, Text and PDU mode SMS storage: SIM card Support transmission of SMS alternatively over CSD or GPRS. User can choose preferred mode.

FAX SIM interface External antenna Audio features

Group 3 Class 1 Supported SIM card: 1.8V ,3V Connected via 50 Ohm antenna connector or antenna pad Speech codec modes: z Half Rate (ETS 06.20) z Full Rate (ETS 06.10) z Enhanced Full Rate (ETS 06.50 / 06.60 / 06.80) z Echo suppression

Two serial interfaces SIM300_HD_V2.03

Serial Port 1 Seven lines on Serial Port Interface Page 12 of 55

AT COMMAND SET :ATE0 Echo off ATE1 Echo on ATD call to dail a number Syntax: ATD 9885622502; ATDL redail last teliphone number ATA answer an incomming call ATH Disconnect existing connection AT+CMGD to delete SMS Syntax: AT+CMGD=1 -> deletes 1 sms in sim card AT+CMGR to read SMS Syntax: AT+CMGR=1 -> reads 1st sms in sim card AT+CMGS to send SMS Syntax: AT+CMGS=9885622502 press enter Type text and press ctrl+z

DATA ON THE SERIAL PORT(HYPER TERMINAL):+CREG: 2 // SIM UNREGISTERED

+CREG: 1,"4E2F","0067" // SIM REGISTERED RING // CALL STATUS // RECEIVED CALL NUMBER FOR //EXAMPLE

+CLIP: "+919866166124",145,"",,"",0

RING +CLIP: "+919866166124",145,"",,"",0 RING +CLIP: "+919866166124",145,"",,"",0 NO CARRIER

+CREG: 2 +CREG: 0 Call Ready +CREG: 2

// SIM UNREGISTERED

Message -> Disconnected. +CREG: 2 +CREG: 1,"4E2F","0067" Call Ready // SIM UNREGISTERED

Anda mungkin juga menyukai