Free download avr controller c programming books






















The block of statements will be skipped if the expression result is TRUE. An else statement must always follow the if statement it is associated with. If the first expression, expr1, is TRUE, then statement1 will be executed and the remainder of the statements will be bypassed. If expr2 is TRUE, then statement2 will be executed and the remainder bypassed, and so on. After being used as a mask, it is shifted one bit to the left, using the compound notation, to test the next bit during the next pass through the for loop.

Execution begins at the statement following the constant that matches the value of the expression. The constants must be integer or character values. All of the statements following the matching constant will be executed, to the end of the switch construct.

The default case is optional, but it allows for statements that need to be executed when there are no matching constants. It compares the value of the lower nibble from port A against the constants in the case statement. Once the appropriate case statements have been executed, the program will return to the top of the while loop and repeat. If the statements are nested one inside the other, the break statement will exit only from the immediate block of statements.

The following program will print the value of c to the standard output as it is continuously incremented from 0 to , then reinitialized to 0.

In the inner while loop, c is incremented until it reaches , and then the break statement is executed. The break statement causes the program execution to exit the inner while loop and continue execution of the outer while loop. In the outer while loop, c is set to 0, and control is returned to the inner while loop. This process continues to repeat itself forever. The continue statement is like the break statement in that both stop the execution of the loop statements at that point.

The difference is that the continue statement starts the loop again, from the top, where break exits the loop entirely. The program will appear at this point as if it has stopped, when in fact, it is still running. It is simply skipping the increment and printf statements. The label can be before or after the goto statement in a function.

The form of the goto statement is as follows: goto identifier; If c is less than or equal to , execution falls through to the increment c statement. The value of c is printed and the while loop begins again. The values of c and d will continue to differ by 1 until c becomes greater than With c at a value of , the continue statement will cause the increment c and printf statements to be skipped.

The result would be the value of c printing from 0 to , over and over again. Chapter 1 Example Project: Part A This is the first portion of a project that will be used to demonstrate some of the concepts presented here in Chapter 1.

This example project will be based on a simple game according to the following situation: You have been asked to build a Pocket Slot Machine as a mid-semester project by your favorite instructor, who gave you some basic specifications that include the following: 1.

The duration of the press and the release can be used to generate a pseudo-random number to create three columns of figures. There are four kinds of figures that can appear in a column: a. Bar b. Bell c. Lemon d. Cherry Embedded C Language Tutor ial 31 5. The payout of the machine has the following rules: a.

Three of a kind pays a Nickel. A Cherry anywhere pays a Dime. Three Cherries are a Jackpot. Everything else loses. In this first step we will develop a brief program that touches on several of the concepts. We will develop a main that contains various types of control statements to create the desired operation. Exclusive ORing in the moving seed can really stir up the numbers. Some languages refer to functions as subroutines or procedures.

Functions are generally written to break up the operational elements of a program into its fundamental parts. This allows a programmer to debug each element and then use that element again and again.

This saves time and maintains stability, since the functions developed get used and reused, tested and retested. A function may perform an isolated task requiring no parameters whatsoever. A function may accept parameters in order to have guidance in performing its designed task. A function may not only accept parameters but return a value as well. Even though a function may accept multiple parameters, it can only return one. The parentheses, or function operator, indicate to the compiler that the name is to be executed as a function.

The type of a function or its parameters can be any valid variable type such as int, char, or float. The type can also be empty or void. The type void is a valid type and is used indicate a parameter or returned value of zero size.

The default type of a function is int. The getchar function is one of the many library functions provided in the C compiler. This can be accomplished in a couple of ways: One is the order of the declarations of the functions, and the other is the use of function prototypes. Ordering the functions is always a good idea. It allows the compiler to have all the information about the function in place before it is used. There are many occasions when functions use one another to accomplish a task and you simply cannot declare them in such a way that they are all in a top-down order.

Function prototypes are used to allow the compiler to know the requirements and the type of the function before it is actually declared, reducing the need for a top-down order. The compiler simply would not have enough information about the functions that are called in main , or their format, and would be unable to generate the proper code. As long as the actual declared function matches the prototype, everything is fine. In previous examples, we used the function printf.

The printf function itself is declared elsewhere, but its prototype exists in the stdio. This allows the programmer to simply include the header file at the top of the program and start writing code. The control word return is used to indicate an exit point in a function or, in the case of a non-void type function, to select the value that is to be returned to the caller. In a function whose type is not void, the return control word will also send the execution back to the caller.

In addition, the return will place the value of the expression, to the right of the return, on the stack in the form of the type specified in the declaration of the function.

The following function is of type float. The ability to generate recursive code is one of the more powerful aspects of the C language. When a function is called, its local variables are placed on a stack or heap-space, along with the address of the caller, so that it knows how to get back.

Each time the function is called, these allocations are made once again. The most common example of a recursive operation is calculating factorials. A factorial of a number is the product of that number and all of the numbers that lead up to it.

For example, 5! Each time it calls itself it reduces n by 1. When n equals 0, the function returns instead of calling itself again. As powerful as recursion can be to perform factorials, quick sorts, and linked-list searches, it is a memory-consuming operation.

Each time the function calls itself, it allocates memory for the local variables of the function, the return value, the return address for the function, and any parameters that are passed during the call. In the previous example, this would include the following: int n passed parameter 2 bytes Return value Return address Total 2 bytes 2 bytes 6 bytes, per recursion, minimum.

This makes this type of operation dangerous and impractical for a small microcontroller. Chapter 1 Example Project: Part B In this phase of the development of the Pocket Slot Machine, we are going to create a couple of functions to break up the main loop into smaller chunks of code and make the code slightly more readable. The parts of code that flash the lights and compute payout will be moved into functions, shortening the main function and making it a bit easier to follow.

For example, the address of a memory location in a typical microcontroller will be described in 16 bits. So in a typical microcontroller, a pointer to a character will be a bit value, even though the character itself is only an 8-bit value. Once a pointer is declared, you are now dealing with the address of the variable it is pointing to, not the value of the variable itself.

You must think in terms of locations and contents of locations. When executed, the indirection operator causes the value of p, an address, to be used to look up a location in memory. The value at this location is then read from or written to E X A M P L E Pointers and arrays are widely used in the C language because they allow programs to perform more generalized and more efficient operations.

Operations that require gathering data may use these methods to easily access and manipulate the data without moving the data around in memory. They also allow for the grouping of associated variables such as communications buffers and character strings. Semantically speaking, they are most likely not what was intended. With power and simplicity comes the opportunity to make simple and powerful mistakes.

Pointer manipulation is one of the leading causes of programming misfortune. But exercising a little care, and reading the syntax aloud, can greatly reduce the risk of changing memory in an unintended fashion.

In fact, there really is no limit to the depth of this type of indirection, except for the confusion that it may cause. Since pointers are effectively addresses, they offer the ability to move, copy, and change memory in all sorts of ways with very little instruction. When it comes to performing address arithmetic, the C compiler makes sure that the proper address is computed based on the type of the variable or constant being addressed.

For example, listed below are pre-increment and post-increment operations that are part of an assignment. Since a function inherently can return only one item using the return control, passing pointers as parameters to a function allows the function an avenue for returning additional values. This process of passing pointers is frequently used and can be found in standard library functions like scanf.

The scanf function defined in Embedded C Language Tutor ial stdio. An array is a data set of a declared type, arranged in order.

The index can range from 0 to the length of the declared array less 1. In a variable array, the initialization values will be placed in the program memory area and copied into the actual array before main is executed. A constant array differs in that the values will be allocated in program memory, saving RAM memory, which is usually in short supply on a microcontroller.

The C language has no provision for checking the boundaries of an array. If the index were to be assigned a value that exceeds the boundaries of an array, memory could be altered in an unexpected way, leading to unpredictable results. Reading digits[5] in the example above will cause the processor to go to the location of the first index of the array and then read the data 5 locations above that.

Therefore, the second line of code above will cause the processor to read the data 12 spaces above the starting point for the array. Whatever data exists at that location will be assigned to numb and may cause many strange results. So, as in many other programming areas, some caution and forethought should be exercised. With a pointer, only an address reference location is allocated, and it is up to the programmer to declare and define the actual memory areas variables to be accessed. The most common array type is the character array.

It is typically referred to as a string or character string. A string variable is defined as an array of characters, while a constant string is typically declared by placing a line of text in quotes. In the case of a constant string, the C compiler will null-terminate, or add a zero to the end of the string.

An array name followed by an index may reference the individual elements of an array of any type. It is also possible to reference the first element of any array by its name alone. When no index is specified, the array name is treated as the address of the first element in the array.

The example below shows how array indexing and pointer indirection function nearly interchangeably. The for loop counter is used as the index to retrieve each character of the array so that it can be passed to the putchar function.

The second portion uses a pointer to access each element of the array. The for loop then uses the pointer post-incrementing it each time to retrieve the array elements and pass them to putchar. When a multidimensional array is declared, it should be thought of as arrays of arrays. Multidimensional arrays can be constructed to have two, three, four, or more dimensions.

The adjacent memory locations are always referenced by the right-most index of the declaration. For instance, assume we have a telephone keypad that generates a row and column indication, or scan-code, whenever a key is pressed. A two-dimensional array could be used as a 47 48 look-up-table to convert the scan-code to the actual ASCII character for the key.

We will assume for this example that the routine getkeycode scans the keys and sets the row and col values to indicate the position of the key that is pressed. The compiler places the null terminator after the last character in the string no matter how long the string may be. Any wasted locations in memory are left uninitialized. Functions such as printf print the string until they encounter the null-terminator character, thus being able to print strings of various lengths correctly.

To access the fourth day of the week and print the associated string, we will use printf. Stating only the first dimension is effectively referencing the entire string as the second dimension. Using a pointer to a function allows for functions to be called from the result of look-up-table operation. Pointers to functions also allow functions to be passed by reference to other functions. Consider an example that calls a function from a table of pointers to functions.

In the following example, the scanf function gets a value from the standard input. The value is checked to make sure it is in range 1—6. The parentheses, or function operator, indicate to the compiler that the identifier is to be treated as a function. In this case, fp contains the address of a function.

The indirection operator is added to obtain the address of the function from the pointer fp. Instead of printing numbers for the column values and referencing numbers in our payout calculations, we will give these values names. Objectoriented programming OOP refers to the method in which a program deals with data on a relational basis.

A structure or union can be thought of as an object. The members of the structure or union are the properties variables of that object. The object name, then, provides a means to identify the association of the properties to the object throughout the program. The variables within a structure are called members. This method allows for a collection of members to be referenced from a single name. Some high-level languages refer to this type of object as a record or based-variable. Unlike an array, the variables contained within a structure do not need to be of the same type.

It should be noted that when a template is defined, no memory space is allocated. Memory is allocated when the actual structure variable is declared. Members within a structure are accessed using the member operator. The only difference is in the indexing of the structure variable itself.

One method of doing this is to use a pointer to reference the structure, for example, passing a pointer to a structure to a function instead of passing the entire structure. Just as with any other type, a pointer must be assigned a value that points to something tangible, like a variable that has already been declared. A variable declaration guarantees memory has been allocated for a purpose. Structures can contain pointers to other structures but can also contain pointers to structures of the same type.

A structure cannot contain itself as a member, because that would be a recursive declaration, and the compiler would lack the information required to resolve the declaration.

Pointers are always the same size regardless of what they point to. This would be equivalent to item2. More often, a union is used as a method of extracting smaller parts of data from a larger data object.

This is shown in the previous example. The position of the actual data depends on the data types used and how a particular compiler handles numbers larger than type char 8 bits. The example above assumes big-endian most significant byte first storage. Compilers vary in how they store data. The data could be byte order swapped, word order swapped, or both! This example could be used as a test for a compiler in order to find out how the data is organized in memory.

Union declarations can save steps in coding to convert the format of data from one organization to another. Shown below are two examples where two 8-bit input ports are combined in one bit value. The typedef operator allows for a name to be declared synonymous with an existing type. Some compilers support a type bit, which is automatically allocated by the compiler and is referenced as a variable of its own.

The width of the member can be from 1 to the size of type unsigned int 16 bits. This allows several bitfields within a structure to be represented in a single unsigned integer memory location.

Remember, define is treated as a textual substitution directive by the preprocessor. This operator is a compile-time feature that creates a constant value related to the size of a data object or its type. Data that will not change should be stored in one type of memory, while data that must be read from and written to repetitively in a program should be stored in another type of memory.

A third type of memory can be used to store variable data that must be retained even when power is removed from the system.

When special memory types such as pointers and register variables are accessed, additional factors must be considered. The default or automatic allocation of variables, where no memory descriptor keyword is used, is in SRAM. When declarations are made, the positions of the flash and eeprom keywords become part of the meaning. If const, flash, or eeprom appear first, this states to the compiler that the actual allocation of storage or the location of data is in that memory area.

FLASH space is an excellent area for nonchanging data. The program code itself resides in this region. Declaring items such as text strings and arithmetic look-up-tables in this region directly frees up valuable SRAM space.

This is a waste of 30 bytes of SRAM unless the string is intended for alteration by the program during run time. EEPROM also has a life—it has a maximum number of write cycles that can be performed before it will electrically fail. In many cases, this memory area will have a rating of 10, write operations, maximum. Newer technologies are being developed all the time, increasing the number of write operation to the hundreds of thousands, even millions.

There are no limitations on the number of times the data can be read. Data that needs to be kept and does not change frequently can be stored in this area.

This region is great for low-speed data logging, calibration tables, runtime hour meters, and software setup and configuration values. In these cases, the allocations are normal char, int, and so on but the type of memory being referenced must be described so that the compiler can generate the proper code for accessing the desired region.

To instruct the compiler to allocate a variable to a register or registers, the storage class modifier register must be used. In order to prevent a variable from being allocated to a register or registers, the volatile modifier must be used. This warns the compiler that the variable may be subject to outside change during evaluation.

Sleep is a stopped, low-power mode typically used in battery applications. This allows the value in SRAM to be valid each time the microcontroller is awakened and returned to normal operation. These header files are typically related to a particular processor. Listed below is a typical include file that might be provided with a compiler MEGA Not so!

Embedded systems can, in many cases, perform on a more real-time basis than a large system. A simple program may run its course over and over.

It may be able to respond to changes to the hardware environment it operates in, but it will do so in its own time. The term may also indicate that a program has the ability to respond immediately to outside hardware input stimulus.

The AVR, with its rich peripheral set, has the ability to not only respond to hardware timers, but to input changes as well.

The ability of a program to respond to these real-world changes is called interrupt or exception processing. An interrupt is, in effect, a hardware-generated function call. The result is that the interrupt will cause the flow of execution to pause while the interrupt function, called the interrupt service routine ISR , is executed.

Upon completion of the ISR, the program flow will resume, continuing from where it was interrupted. In an AVR, an interrupt will cause the status register and program counter to be placed on the stack, and, based on the source of the interrupt, the program counter will be assigned a value from a table of addresses.

These addresses are referred to as vectors. Once a program has been redirected by interrupt vectoring, it can be returned to normal operation through the machine instruction RETI RETurn from Interrupt. The RETI instruction restores the status register to its pre-interrupt value and sets the program counter to the next machine instruction following the one that was interrupted. The larger the AVR, the more sources that are available. Listed below are some of the possibilities.

These definitions are usually found in a header file, at the top of program, and are specific to a given microprocessor. These would be found in a header for an ATMega, Mega To create an ISR, the function that is called by the interrupt system, the ISR, is declared using the reserved word interrupt as a function type modifier.

The vector numbers start with [1], but since the first vector is the reset vector, the actual interrupt vectors available to the programmer begin with [2]. ISRs can be executed at any time, once the interrupt sources are initialized and the global interrupts are enabled.

It is for this same reason that nothing can be passed to the ISR. Interrupts in an embedded environment can genuinely create a real-time execution. It is not uncommon in a peripheral-rich system to see an empty while 1 loop in the main function. In these cases, main simply initializes the hardware and the interrupts perform all the necessary tasks when they need to happen.

Note that main sits in a while 1 loop while the blinking goes on. There are many real-time executives available for the AVR. Some are in the public domain and are free of charge. Others are commercially licensed and supported but are still inexpensive. An RTX utilizes a time-based interrupt i. The beauty of an RTX is that the program operation, from a timing perspective, is defined in a header block and the tasks are usually configured with a call into an RTX initialization function.

Characteristics such as the number of tasks allowed to be executing within the system, how often the operation is to switch from one task to another, and whether tasks are to run in a round-robin or top-to-bottom sometimes called preemptive or priority fashion, are defined by the header. Since each subprogram stands somewhat alone, each is given its own stack space to work in—keeping the processes truly independent.

See docs for details. Priority is important in that if for some reason a task could not complete its function within the allocated amount of time, the RTX can take the operation back to the highest priority task and start again.

This allows for the important and generally time-critical tasks to get processor time no matter what is going on with lower priority or less important tasks. In the following example, two LEDs are being flashed by two independent tasks.

You will see that each task is simply written as a C function of type void and that each function contains a while 1 loop. This is because the functions do not return to a caller—they are each running as stand-alone programs. In a typical application development, the slow operations such as printf or scanf would be performed in main and global variables would be used to communicate needed information to the other tasks in the program.

State machines also offer a better opportunity to change the function and flow of a program without a rewrite, simply because states can be added, changed, and moved without impacting the other states that surround it. State machines allow for the primary logical operation of a program to happen somewhat in background.

Since typically very little time is spent actually processing each state, more free CPU time is left available for time-critical tasks like gathering analog information, processing serial communications, and performing complex mathematics. The additional CPU time is often devoted to communicating with humans: user interfaces, displays, keyboard services, data entry, alarms, and parameter editing. This keeps the example simple. In real life, this time could be used for a myriad of other tasks and functions, and the timing of the lights could be controlled by an interrupt from a hardware timer.

The example system functions as a normal stoplight. The North-South light is green when the East-West light is red. The traffic is allowed to flow for thirty-second periods in each direction. There is a five-second yellow warning light during the change from a green-light to a red-light condition. This conversion will happen only during the warning yellow light transition to make it safe for traffic. User interfaces, displays, keyboard services, data entry, alarms, and parameter editing can also be performed using state machines.

More things are being dealt with continuously without becoming stuck waiting for a condition to change. There are many considerations that fall outside of writing the code and the desired operation of a program. Items such as header block format, bracket and parentheses placement, naming conventions for variables and definitions, and rules for variable types and usage will be outlined.

This may sound a bit ominous, but once you begin writing using a defined style and development criteria, you will find it easier to collaborate and share effort with others in your organization, and you will have fewer errors in your code from the outset, as well.

The beginning concepts demonstrated the basic structure of a C program. Variables, constants, enumerations, their scope and construction, both simple as well as in arrays, structures, and unions, have been shown to be useful in defining how memory is to be allocated and how the data within that memory is to be interpreted by a C program.

The advanced concepts of real-time programming using interrupts executives and state machines were explored to demonstrate how to streamline the execution of programs, improve their readability, and provide a timely control of the processes within a C language project. Define the terms variable and constant Section 1.

Create an appropriate declaration for the following Section 1. A variable array that will have ten elements, each holding numbers from —23 to Evaluate the following Section 1. Evaluate as true or false as if used in a conditional statement Section 1. Evaluate the value of the variables after the fragment of code runs Section 1. Write a fragment of C code to declare an appropriate array and then fill the array with the powers of 2 from 21 to 26 Section 1.

Modify the program to use a for loop to print the same phrase four times. Repeat using a while loop to print the phrase three times. Create a program to calculate the capacity of a septic tank. The three dimensions height, width, and length should be read from three parallel ports A, B, and C in feet and the result printed to the standard output device.

Modify the program in Activity 2 so that if any of the three inputs exceeds the allowed range, the program says The input exceeds the program range. Create a program to print the powers of 2 from 20 to Create a program that can search an array of structures for specific values. Initialize the array to contain one and only one instance of your own birthday. However, the month, day, and year of your birthday must show up in other places in the array, just not all at the same point.

The program must search the array to find your birthday and then print a message to indicate at what index in the array the birthday resides. Modify the program in Activity 7 to search the array of structures using pointers. Embedded C Language Tutor ial 9. Create a program to use the standard input function getchar to retrieve one character and compare its value to the value placed on port A.

If they match, print a message to that effect on the standard output device using printf. Otherwise, output a 0x01 to Port B if port A is higher in value than the character received, or output an 0x80 if port A is lower. Use an external hardware interrupt to print a message to the standard output device each time an interrupt occurs. Also print the number of times the interrupt has occurred.

You may not use a global variable to count the interrupt occurrences. It is based on the premise that in order to be successful, designers must be as intimately familiar with the hardware as they are with the programming language. The chapter begins with the basic overview of the processor, its architecture, and its functions.

Next, the memory spaces are discussed in detail so that you can identify and understand where your variables are stored and why. The uses of interrupts are next discussed, along with the most common built-in peripherals. These topics are then combined into the process of allocating processor resources for a project. A variety of the peripherals common to many of the Atmel microcontrollers are discussed.

Many of the Atmel parts have additional peripherals or extended 87 88 functionality in their peripherals. Consult the specification for your particular part to discover the full range of peripheral functionality for your particular microcontroller. Each of the peripherals is shown as it applies to projects. This one sentence says volumes about the architecture of the devices. First, they are RISC devices. This reduced number of instructions contributes to the speed due to the fact that, with a limited number of machine instructions, most can run in a single cycle of the processor clock.

Secondly, the devices are microcontrollers. We do not store files not owned by us, or without the permission of the owner. We also do not have links that lead to sites DMCA copyright infringement. If You feel that this book is belong to you and you want to unpublish it, Please Contact us. Download e-Book. Posted on. Author s : Milan Verle. NA Pages. Product Description: Enter the world of embedded programming and microcontroller applications!

One of the only books available today that uses the increasingly popular and cost-effective Atmel AVR embedded controller as the platform and application for learning, Embedded C Programming and the Atmel AVR, 2E is the perfect choice for novices.



0コメント

  • 1000 / 1000