C Programming with Arduino

Page 1

Warwick A. Smith Warwick A. Smith lives in South Africa and works as an Electronics Engineer and Embedded System Programmer. He is a bestselling author of the books C Programming for Embedded Microcontrollers, ARM Microcontroller Interfacing and Open Source Electronics on Linux.

ISBN 978-1-907920-46-2

Arduino is the hardware platform used to teach the C programming language as Arduino boards are available worldwide and contain the popular AVR microcontrollers from Atmel. Atmel Studio is used as the development environment for writing C programs for AVR microcontrollers. It is a full-featured integrated development environment (IDE) that uses the GCC C software tools for AVR microcontrollers and is free to download. •

Start learning to program from the very first chapter

No programming experience is necessary

Learn by doing - type and run the example programs

A fun way to learn the C programming language

Ideal for electronic hobbyists, students and engineers wanting to learn the C programming language in an embedded environment on AVR microcontrollers

Use the free full-featured Atmel Studio IDE software for Windows

Write C programs for 8-bit AVR microcontrollers as found on the Arduino Uno and MEGA boards

Example code runs on Arduino Uno and Arduino MEGA 2560 boards and can be adapted to run on other AVR microcontrollers or boards

Use the AVR Dragon programmer / debugger in conjunction with Atmel Studio to debug C programs

DESIGN

www.elektor.com

Technology is constantly changing. New microcontrollers become available every year. The one thing that has stayed the same is the C programming language used to program these microcontrollers. If you would like to learn this standard language to program microcontrollers, then this book is for you!

AVR MICROCONTROLLERS AND ATMEL STUDIO FOR

C

PROGRAMMING WITH ARDUINO

LEARN

Elektor International Media BV

C

PROGRAMMING WITH ARDUINO

C PROGRAMMING WITH ARDUINO ● WARWICK A. SMITH

AVR MICROCONTROLLERS AND ATMEL STUDIO FOR

Warwick A. Smith LEARN

DESIGN

SHARE

SHARE

LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● S ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE GN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE


Introduction

Introduction This book will teach you the C programming language using AVR microcontroller based Arduino boards, such as the Uno and MEGA, as a teaching platform. Atmel Studio for Windows operating systems is the IDE and software tool used in this book for writing, compiling and loading C programs to the Arduino boards. Atmel Studio and the standard C language are used as an alternative to the Arduino IDE which was designed to help those with less technical knowledge of electronics and microcontrollers to get started with microcontroller projects. Standard C is taught by Universities as part of electronic engineering courses and is used throughout industry for programming microcontrollers. C programming can be used on any microcontroller for which C programming tools are available and is not restricted to Arduino. Arduino is used with this book for teaching C as it is very convenient to use and readily available.

Learning C Learning a new programming language and learning how to program embedded systems covers a lot of ground as there are many things to learn: the C programming language itself, some knowledge of microcontroller architecture, some electronics, microcontroller peripherals, number systems and logic. There is also the software programming toolchain and IDE to learn, which in the case of this book is the Atmel Studio IDE that uses the GNU toolchain for AVR microcontrollers. It may seem to be a daunting task to learn about all these aspects of an embedded system and programming language, but taking it one step at a time as this book does makes it easy, enjoyable and a lot of fun.

Technical Terms IDE – Integrated Development Environment. An IDE is software that provides a complete development environment for writing and editing programs, compiling, loading programs to the target board and debugging. Toolchain – the C toolchain is a set of software programs that are used to convert a C program into a file that can be loaded to a microcontroller. Atmel Studio – an IDE that runs on Windows operating systems and is used to program Atmel AVR and other Atmel microcontrollers. Atmel Studio can be downloaded for free from the Atmel website.

Target Audience This book has been written for the hobbyist, student and engineer wanting to learn the C programming language in an embedded environment using microcontrollers.

AVR Microcontrollers AVR microcontrollers, the microcontrollers found on Arduino boards such as the Uno and MEGA are used in this book. The C language applies equally to other microcontrollers, but when learning to program, a particular microcontroller architecture must be chosen as hardware differences between microcontrollers will change how they are programmed.

The AVR Architecture AVR microcontrollers from Atmel (www.atmel.com) are RISC microcontrollers available

● 17


C Programming with Arduino in 8-bit and 32-bit series. These microcontrollers contain a “AVR core” that is interfaced to memory and peripheral devices and packaged in a single chip. Only 8-bit AVR microcontrollers are presented in this text.

Technical Terms RISC – RISC stands for Reduced Instruction Set Computer and is a processor that is designed with a simplified instruction set in order to produce higher performance. The AVR architecture has been designed this way.

Atmel AVR Microcontrollers

Embedded Systems An embedded system is an electronic circuit board that contains a microprocessor or microcontroller and other electronic parts, running a software program and used for a specific purpose rather than a general purpose as a Personal Computer (PC) would be used.

Technical Terms Microprocessor – A microprocessor is a silicon chip, also known as an Integrated Circuit or I.C., containing a Central Processing Unit (CPU) that will fetch program instructions from memory and execute or run them. The memory required by the microprocessor is external to the microprocessor chip – it must be put on the circuit board by the hardware engineer designing the system, whether it is to be used as an embedded system or general purpose computer. There are a number of microprocessor architectures such as Intel’s x86 architecture, ARM architecture, AVR from Atmel and many others. Microcontroller – A microcontroller contains a microprocessor and a number of peripheral devices such as timers, serial ports, general purpose input/output (I/O) pins, counters, analogue inputs, etc. all inside a single silicon chip. A microcontroller will usually have memory on the chip as well. Some microcontrollers will be able to support external memory and others have enough memory on-chip and do not have the ability to support external memory. Microcontrollers are designed to be used in embedded systems as their on-chip peripherals and memory enable an embedded system designer to save circuit board space by not having to add these items as external devices on the circuit board.

● 18


Introduction An example of an embedded system is a calculator. It is specifically made to perform mathematical calculations input by a user on the keypad – it is a dedicated device. A PC on the other hand is a general purpose computer that can be used for any number of purposes such as word processing, playing games, a file server, web server, etc. (i.e. not an embedded system). Other examples of embedded systems are cell phones and computer keyboards as they contain embedded microcontrollers that give these devices their functionality. Smartphones, however, have become more like PCs than dedicated embedded systems, even running their own operating systems. A washing machine may contain an embedded system that responds to button presses on its front panel and controls washing cycles. Although Arduino boards are general purpose boards that can be used for many different tasks, they are still embedded systems as their end use is for a specific task, such as a temperature monitoring system, animated robot, chocolate dispensing machine, or any other project that you can think of.

Abbreviations Microprocessor – the word microprocessor is often abbreviated to μP. Microcontroller – the word microcontroller is often abbreviated to μC or MCU. μ – is the symbol for “micro” and is also used in electronic or other engineering measurements such as microfarad μF for capacitor values.

Choosing an Embedded System to Learn C On Arduino has been chosen as the embedded system for this book, and specifically Arduino boards that have 8-bit AVR microcontrollers on-board and can be fitted with the standard add-on boards called shields. Arduino has been chosen because it is so widely available, is an open source project and has many second-source compatible boards available. Before Arduino became popular, a specific proprietary board would have to be recommended for any embedded programming book. With Arduino we now have standard off-the-shelf hardware that is open source, allowing anyone to view and modify the circuit diagram and board. Here are some of the reasons that Arduino was chosen: •

Powered by USB – no external power supply needed

Easy to connect hardware using an electronic breadboard and jumper wires

USB port on-board that is configured as a virtual COM port on the PC for serial communications

Widely available with alternative sources and clone boards / derivative boards

Has ICSP header for programming and debugging

In the pages that follow, you will learn to write programs that run on an Arduino board or embedded system and switch LEDs on and off, read switches to see if they are being pressed or released, send messages out of the serial port to be displayed on a PC and more.

● 19


C Programming with Arduino

Arduino MEGA 2560 (left) and Arduino Uno (right)

Why use the C Programming Language? If I think of all the technology changes that have taken place in the world of microelectronics since the start of my career as an embedded programmer, the one thing that has stayed the same is the C language. Processor architectures and systems have come and gone, but the common thing between all of them is that they were programmed in C. The reason for the popularity and use of C is that C is a standard language and ideally suited to embedded programming where access to the hardware of a system is required. C programming tools produce small and fast programs – a requirement when you have limited amounts of memory available on an embedded system. Whenever a new processor architecture comes on the market, you can be pretty sure that there will be C programming tools available for it. C programming is necessary to move beyond Arduino in order to program other embedded systems that are not supported by the Arduino IDE, as well as gain more control over Arduino boards. You may have heard that C is cryptic and difficult to learn, but this is nonsense. C is a simple language with very few keywords and is easy to learn. As with any new language, you need to become familiar with the syntax of the language. This book will explain everything to you, starting with simple and easy programs. When I leaned to program in C, I thoroughly enjoyed it and I hope that you will too.

Prerequisites In order to use this book you will need to be able to operate a computer running Windows and know how to download and install software on a Windows system. Any knowledge of electronics will help, for example you should know what an LED is, a switch, I.C. and a resistor. I will refer to basic electronic components such as these in the text. If you don’t know what these items are, there are plenty of books available that teach basic electronics. A good online resource for basic electronics, breadboard circuits and an introduction to Arduino is: startingelectronics.org/beginners/start-electronics-now/ Any knowledge of programming in any language will help, but is not required. Basic mathematics is also assumed. i.e. addition, subtraction, multiplication, division, counting and a little algebra. If you are not good at mathematics, that is not a problem as the mathematics is very basic and the programs that you will write will actually help you to understand mathematics better.

â—? 20


Introduction You will need to have an Internet connection in order to download software programs and example programs used with this book (all software used is free).

Hardware Requirements A standard USB cable will be needed for powering the Arduino board and communicating between the Arduino and PC. An external power supply can be used to power the Arduino board, but a USB cable will still be needed for serial communications with the PC. Electronic components such as LEDs, resistors and switches will be needed and are listed in each section of the book when they are required. When using the Atmel Studio IDE, a programming device is needed to load programs to the microcontroller on the Arduino board. The programmer is connected to the PC using a USB cable and to the 6-pin header on the Arduino board labelled ICSP. More details of the Arduino board and programmer required can be found below.

Arduino Board An Arduino Uno with an Atmega328P microcontroller or Arduino MEGA 2560 will be needed to follow the example programs in this book. An Arduino Uno R3 and Arduino MEGA 2560 R3 were used when developing the code examples. If you have not yet bought an Arduino board, I would recommend getting the Arduino MEGA 2560 as it has more memory and input / output pins than the Uno.

Atmel AVRISP mkII Programmer and Arduino Uno

â—? 21


C Programming with Arduino

Programmer An AVRISP mkII programmer (part number ATAVRISP2) or AVR Dragon programmer / debugger (part number ATAVRDRAGON) is required for loading programs to the Arduino board. Both of these programmers are Atmel devices and are fully compatible with Atmel Studio. I would recommend getting the AVR Dragon as it has debugging capabilities as well as the ability to do HV programming that can be used to unbrick a DIP packaged AVR microcontroller. The AVRISP mkII can only program AVR microcontrollers and has no debugging capabilities. The AVR Dragon does not come with any cables, you will need a standard USB cable as well as a 6-way ribbon cable with female 6-way (2 by 3) headers on each end. There are other AVR programmers on the market made by various manufacturers that may be cheaper than the programmers from Atmel, but these programmers will need external software in order to use them. They will also require extra set-up steps in order to use them in Atmel Studio and will most likely not have any debugging abilities.

Atmel AVR Dragon Programmer / Debugger and Arduino Uno

Technical Terms Debugging – Debugging refers to finding and fixing program errors. An embedded programmer or software engineer will write a program and then test it to see if it works as intended. If there is a problem with the program, e.g. “Why does the LED not switch on when it is supposed to?”, the embedded programmer will debug the program. AVR microcontrollers on the Arduino boards used in this book can be debugged using the AVR Dragon attached to the ICSP header on the board. When a software program called a debugger is run on the PC from within Atmel Studio, it accesses the embedded system through the ICSP header via the AVR Dragon and enables the programmer to step through the program and examine the contents of the microcontroller’s memory. This helps the programmer to find the bug (program error) and fix it.

● 22


Introduction

The Approach Taken in this Book This book uses free or open source software only. You will start learning to program right from chapter 1 after installing and setting up programming tools. The first 7 chapters of the book teach the basics of the C language, concentrating on the language by sending output from C programs running on an Arduino to the PC for display in a terminal window, and receiving data from the terminal window typed in by a user. Chapter 8 and beyond builds on the C basics already learned in the first chapters and starts to look at programs that use the microcontroller’s peripherals for more practical embedded applications.

Some Good Advice Take your time to learn and understand how the programs work before moving to the next chapter. Experiment with the code by changing it to see what happens and try to write your own programs, or modified versions of the example programs to aid in learning as you progress through the book. If you can’t type, learn to type while learning C. This is what I did when learning to program and have never regretted it. I always entered the example programs by typing them in rather than just running the downloaded example programs from disk. Learning C and embedded systems is great fun and a big adventure, so it is my wish that you will thoroughly enjoy using this book and learning new things.

Accompanying Files and Support Website An accompanying zipped file is available for download from Elektor that contains all of the C source code for the example programs in this book. Download the accompanying files from the Elektor website at www.elektor.com by browsing for the book from the books menu or using the search box to find the book’s page. An accompanying website can be found at wspublishing.net/avr-c that contains extra articles and information related to this book and will be updated with any errata found.

● 23


Chapter 1 • Your First C Program

Chapter 1 •  Your First C Program What you will do in this chapter: •

Download and install Atmel Studio

Download and install a terminal emulator program

Install template files to make creating new projects easier

Connect the Arduino board and programmer to a PC

Write your first C program

Compile, load and run your first program

1.1 • Download and Install Atmel Studio Downloading and installing Atmel Studio is straightforward and should not pose any problems. Brief download and installation instructions are presented below. More detailed instructions with screen captures can be found on the supporting website at: wspublishing.net/avr-c.

1.1.1 • Downloading Atmel Studio Atmel Studio can be downloaded by visiting the Atmel Studio web page and scrolling down the page to find a link to the Atmel Studio installer. Atmel Studio web page: www.atmel.com/tools/atmelstudio.aspx Two downloads of Atmel Studio are available – a web installer version and an offline installer version. I would suggest downloading the offline installer version which will allow Atmel Studio to be installed to any PC whether it is connected to the Internet or not.

Figure 1-1  Download Atmel Studio Click the image of the disk to the left of the chosen version of Atmel Studio (Figure 1-1) and you will be taken to a new web page. You can now either create an Atmel account, sign in with an existing Atmel account, or download the file as a guest. To download Atmel Studio as a guest, enter your details and a valid email address. A link to the file to download will be emailed to you, which you can click to open a page that contains a link to the Atmel Studio installation file. Click the link to start the download. The advantage of creating an Atmel account is that after Atmel Studio is installed, updates and addons for Atmel Studio can be installed which require signing into an Atmel

● 25


C Programming with Arduino account. If you do the download as a guest, you can always create an Atmel account later. When the download has finished, a file with a name such as as-installer-7.0.582-full.exe will be found in the download folder. The exact file name may be different, depending on whether the downloaded file is a newer version or not.

1.1.2 • Installing Atmel Studio To install Atmel Studio, simply double-click the downloaded file to run it, which will start the installation. You will need to agree with the license to be able to continue with the installation. Do a standard full installation and leave the installation folder names at their defaults.

1.2 • Download and Install a Terminal Emulator A terminal emulator program called Tera Term is used for program input / output between a PC and Arduino board using a USB cable. Tera Term can be downloaded from: en.osdn.jp/projects/ttssh2/releases/

Download the zipped Tera Term file, which was at version 4.88 at the time of writing, and named teraterm-4.88.zip containing a folder called teraterm-4.88. It is not necessary to install Tera Term, simply copy the teraterm-4.88 folder from the zipped file to any convenient location on the PC, e.g. to the desktop. Double-click the file called ttermpro.exe in the teraterm-4.88 folder to run Tera Term. It is best to enable Windows to show file extensions in the file manager to more easily identify file types. Enabling file extensions to be visible will show the .exe extension of ttermpro.exe as well as the .c extension of C program files.

Displaying File Name Extensions in Windows 7 File Manager To display file name extensions in file manager, first open file manager and then click Organize → Folder and search options to pop up the Folder Options dialog box. In the dialog box, click the View tab. In the Advanced settings box, uncheck the Hide extensions for known file types box. Click the OK button in the dialog box to save the changes.

1.3 • Install Template Files Included with the accompanying download from Elektor are two template files used to start new projects in Atmel Studio called template_mega_dragon.zip and template_ uno_dragon.zip found in the Templates folder of the download file. To install these template files, open your Documents folder and then Atmel Studio → 7.0 → Templates → ProjectTemplates and copy the files into the ProjectTemplates sub-folder. If you are using a newer version of Atmel Studio, substitute the new version number in place of 7.0 in the above path. The full path to the ProjectTemplates folder is: C:\Users\<your user name>\Documents\Atmel Studio\7.0\Templates\ ProjectTemplates

● 26


Chapter 2 • C Basics

Chapter 2 •  C Basics What you will do in this chapter: •

Write some more simple C programs

Learn about input, output and variables

Do some simple mathematical calculations

Learn how to find and fix program errors

There are a number of example programs in this chapter and the chapters that follow. It is advisable to enter and run all the example programs in this book. Feel free to change the programs and experiment with them once you understand how they work. This will help you to learn C.

2.1 • Input, Output and Variables All programs work with input and output. The hello program worked with output only by displaying a message in the terminal emulator window. The message was sent from the Arduino making it output from the Arduino. If the terminal program is used to send a character to the Arduino, this is know as input because it is sent into the Arduino. Most programs will receive some input, do processing on the input and then produce an output that is useful. An embedded system may read the temperature (input), decide whether the temperature is too high or too low and then switch off or on a heating element (output) as shown in Figure 2-1.

Figure 2-1  Example of Input and Output in an Embedded System If we are to get an external measurement or value into the Arduino to do some processing on, we need to store the value in the AVR microcontroller memory so that we can then use it in our program. The value that is read is stored in a variable. A variable is a piece of memory set aside to store a variable value as opposed to a fixed or constant value. A temperature is an example of a variable value. When it is read by the Arduino it is not known by the Arduino and could be any value within a range. If I say that the Arduino reads an external temperature, what is happening is that the Arduino is running a program and the program tells the Arduino to read a value. The act of reading the value is the act of getting the value and storing it in memory as a variable.

● 41


C Programming with Arduino To demonstrate input, output and variables on the Arduino in a useful way, we will get a number from the user of the program (typed in by the user on the keyboard), perform addition with the number and then output the result to the terminal program. Before we can do this, we need to be able to: 1. get a value that the user types in on the keyboard 2. store the value on the Arduino so that we can add a number to it 3. be able to display the result of the addition to the user in the terminal program. Let’s start by looking at how to print a number to the terminal program. We’ll use the printf() function again. Create a new C project from the template file called number and add the following lines of code to the C file. Project name: number Project location: CH2\number main.c #include <stdio.h> #include "stdio_setup.h" int main(void) { UartInit(); printf("Printing a number: 19\r\n"); printf("Printing a number: %d", 19);

}

while(1) { }

Program Output Printing a number: 19 Printing a number: 19

Save, build and load the program. The program shows that you can print a number as part of the text as with the first printf() function; or as an external number that gets substituted into the text. In the second printf() function, the number 19 gets substituted in place of the %d format specifier. We will look at format specifiers in more detail in later programs. We will need the second method of printing a number that is variable (in this program the number is a constant and we are substituting a constant into the string – it is hard-coded into the program and can’t be changed after compiling). The first way of printing the number will not allow a stored value entered by a user of the program to be displayed on the screen because it is fixed as part of the text string (it is known as a string constant). We will substitute a stored variable value into the string just like the number 19 is substituted into the second text message. The number program might not make much sense right now, as the two printf() statements produce exactly the same output although they do so in a different way.

● 42


Chapter 3 • Comparative Operators and Decisions

Chapter 3 •  Comparative Operators and Decisions What you will do in this chapter: •

Learn how to compare integer values

Write programs that make decisions

3.1 • Comparative Operators Comparative operators are used to compare values, for example – is the value of variable X bigger than the value of variable Y?. These values can be stored as constants or variables. Comparative operators are also known as relational operators.

3.1.1 • True and False When an expression containing a comparative operator is evaluated, it will evaluate to either true or false. Logic systems and computers represent true by the value 1 and false by the value 0. The next example program called compare will show what this means. Project name: compare Project location: CH3\compare main.c #include <stdio.h> #include "stdio_setup.h" int main(void) { int temper = 20; UartInit(); printf("Is the temperature less than 23? %d\r\n", temper < 23); printf("Is the temperature more than 23? %d\r\n", temper > 23); printf("\nTemperature is now increasing...\r\n\r\n"); temper = 50; printf("Is the temperature less than 23? %d\r\n", temper < 23); printf("Is the temperature more than 23? %d\r\n", temper > 23);

}

while(1) { }

Program Output Is the temperature less than 23? 1 Is the temperature more than 23? 0 Temperature is now increasing... Is the temperature less than 23? 0 Is the temperature more than 23? 1

● 61


C Programming with Arduino In this example, a variable called temper is defined in order to store a temperature. The initial value assigned to the variable is 20, representing 20 degrees Celsius. As can be seen in the example, a variable can be defined and initialised with a value in one line; the examples in the previous chapter used two lines to do this. In the first printf() statement, the value stored in temper is compared to the constant value 23 using the mathematical "less than" sign: temper < 23. In other words we are saying "Is the value stored in the variable temper less than 23?" When this expression is evaluated in C, it will evaluate to either true (1) or false (0). The result is then substituted in place of the format specifier. As can be seen when the program is run, the result of asking whether 20 (stored in temper) is less than 23 evaluates to 1 (true). Logically this is because 20 is less than 23. See Figure 3-1.

Figure 3-1  A Comparative Operator in Action In the second printf() statement, we ask whether 20 is greater than (>) 23 and get a result of 0 (false). When the value that temper is holding is changed to 50, and we ask the same questions, we get a result of false for our question "Is 50 less than 23?" and true for "Is 50 greater than 23?" as we would expect.

3.1.2 • C Comparative Operators Table 3-1 shows the comparative operators available in C. You have already seen the less than and greater than operators in use. Table 3-1 C Comparative Operators Operator

Meaning

Example

Result (where 1 = true and 0 = false)

<

Less than

A<B

1 if A is less than B , else 0

>

Greater than

A>B

1 if A is greater than B , else 0

<=

Less than or equal to

A <= B

1 if A is less than or equal to B , else 0

>=

Greater than or equal to A >= B

1 if A is greater than or equal to B , else 0

==

Equal to

A == B

1 if A is equal to B , else 0

!=

Not equal to

A != B

1 if A is not equal to B , else 0

3.2 • Decisions Comparative operators are used to make decisions in a C program. So far you have seen programs that execute or run each statement in the program line for line from top to bottom. Decisions can be used to jump into or over a particular part of a program. Getting back to our temperature controller example from Chapter 2 (Figure  2-1 on page 41), a decision must be made to switch the element of the system on or off. The

● 62


Chapter 4 • The while Loop and Commenting Code

Chapter 4 •  The while Loop and Commenting Code What you will do in this chapter: •

Learn how to use the while loop

Improve the temperature controller example

Learn about commenting a program and programming style

In the previous chapter we saw that a program can be made to branch when making a decision. Branching causes the regular flow of a program, from top to bottom through a list of statements, to change. Loops also change the flow of a program as explained in this chapter.

4.1 • The while Loop The while loop will cause a block of program code to run repeatedly from top to bottom while a certain condition is true. Running the code repeatedly is called looping. The water program demonstrates the while loop. Project name: water Project location: CH4\water main.c #include <stdio.h> #include "stdio_setup.h" int main(void) { int water_level = 0; UartInit(); printf("Pumping 10L of water...\r\n\r\n"); while (water_level < 10) { water_level = water_level + 1; printf("Progress: %d\r\n", water_level); } printf("\r\nFinished.");

}

while(1) { }

Program Output Pumping 10L of water... Progress: Progress: Progress: Progress:

1 2 3 4

● 73


C Programming with Arduino Progress: Progress: Progress: Progress: Progress: Progress:

5 6 7 8 9 10

Finished.

The while loop evaluates a comparative expression to see if it is true or false in the same way as the if statement did in the previous chapter. The block of code between the braces under the while loop will run continually until the condition that it is evaluating becomes false. When the loop is run for the first time, the expression water_level < 10 is evaluated. Because water_level was initialised to the value of 0, the result of the evaluation is true (1). The code under the loop will now run because of this. If the evaluation had been false, the program flow would have ignored or "jumped over" the entire block of code inside the loop and carried on running any statements that occurred after this. The first line of code that runs in the loop adds 1 to the value of the variable water_level and then stores this result back in the water_level variable (0 + 1 = 1). This result is printed to the terminal window. Program flow has now reached the bottom of the loop, so the water_level < 10 expression is evaluated again. The value of water_level is 1, and 1 is less than 10, so the evaluation result is true again and the first statement within the loop block is run again. Running of this first statement again results in the water_level variable now containing the value 2 (1 + 1 = 2). As before, the result is printed to the terminal window and the loop expression is evaluated again. This process will continue looping and will increment water_level by one each time through the loop and print the result to the terminal window.

Figure 4-1  The while Loop When the value of water_level reaches 9, the loop expression will still evaluate to true. After the incrementing of this variable on the next pass through the loop, it will be 10. The value of 10 is printed out to the terminal window. The loop expression gets evaluated again and evaluates to false because 10 is not less than 10. The code in the loop will now not be run again. Program flow continues at the printf() statement under the body of the while loop. Figure 4-1 shows how the while loop works. Upon running the two statements in this loop, the expression will be evaluated again.

● 74


Chapter 5 • Functions

Chapter 5 •  Functions What you will do in this chapter: •

Learn how to write functions

Use preprocessor directives

Learn about header files

See how functions relate to linking and library files

You have already used the printf() and scanf() functions. You have also written a function each time that you have written a C program – the function main(). The printf() function was supplied with the GCC toolchain that is installed with Atmel Studio. The actual C code that makes up this function is rather large and complex as the function has a lot of text formatting capabilities. If you had to write this code each time you wanted to print text to the screen, programs would be very large, hence the advantage of writing functions – the code for the function is written once and the function is used many times over. Another advantage of using functions is that your program can be split over multiple files. If a large program is stored in a single file, it would become very difficult to read and maintain. By breaking a program up into functions it can be split across two or more files. When splitting up a program into files, similar functions can be grouped together. You may decide to save all of the functions to do with serial communications into a file called serial.c and the functions to do with timers to timer.c. Code can also be easily reused when it is divided up into separate files. For a particular piece of hardware, or algorithm you only need to write the functions once and then include the file that contains the functions in each program that you wish to write that uses them. For example we used printf() in all of our programs without ever writing the printf() function. If printf() had been a function that you had written, you would only have to create it once and then use it whenever you wanted to.

Technical Terms Algorithm – An algorithm is a method or set of tasks for solving a problem. An example of an algorithm is code used to recognise a fingerprint scanned in by a fingerprint scanner. We would refer to the method used in this code that processes, compares and recognises a fingerprint as a fingerprint recognition algorithm.

5.1 • Your Second Function This will be the second function that you are going to write as you have already written the function main() each time that you have written a C program. The program countfunc shows how to write a function.

● 89


C Programming with Arduino Project name: countfunc Project location: CH5\countfunc main.c #include <stdio.h> #include "stdio_setup.h" void Count(void);

/* function prototype */

int main(void) { UartInit(); printf("Counting to 5\r\n"); Count(); /* call the function */ printf("Counting to 5 again\r\n"); Count(); /* call the function */

}

while(1) { }

/* the function */ void Count(void) { int count = 1;

}

while (count <= 5) { printf("%d\r\n", count); count = count + 1; }

/* count from 1 */ /* count to 5 */ /* display the count */ /* increment the count */

Program Output Counting to 5 1 2 3 4 5 Counting to 5 again 1 2 3 4 5

In this example, a function called Count() is created and then called twice in the main program as shown in Figure  5-1 on page 91. The function simply prints out a count of 1 to 5. Near the top of the source file is the "function prototype" terminated with a semicolon i.e. void Count(void);. The function prototype tells the compiler that this function will be used in the program, similar to defining a variable that will be used in a program. The main() function is a special function that does not require a function prototype. The actual function is written below the closing brace of the main() function. The body of this function is contained between opening and closing braces. The use of the function in

â—? 90


Chapter 6 • Number Systems

Chapter 6 •  Number Systems What you will do in this chapter: •

Learn why we use binary numbers

See how the binary numbering system works

Learn to read and use hexadecimal numbers

Use hexadecimal numbers in C programs

The ASCII Alphanumeric code

Everything in a computer or microcontroller is stored as a binary number, whether it is text, a program, a photograph or video. A computer only works with binary numbers. It is therefore important to know how number systems work and this chapter will explain what you need to know about numbers as an embedded C programmer.

6.1 • Binary Basics Here is an example of a binary number: 11001000 This number is said to be an 8 bit number as it consists of 8 digits or bits. Each binary digit is either a zero (0) or a one (1). The digit to the very right of the number is known as the least significant bit (LSB) or least significant digit (LSD). The digit to the very left of the number is known as the most significant bit (MSB) or most significant digit (MSD). This is always the case, no matter how many bits the number consists of.

The word "bit" comes from the words binary digit. When memory is referred to in relation to computers, it is usually specified in bytes e.g. 16 kilo bytes. A byte consists of 8 bits. A nibble is half a byte or 4 bits. The length of a word is dependent on the system architecture to which it applies and may be 8, 16 or 32 bits for example. A word with a length of 32 bits is referred to as a 32-bit word. 1 1 1 1

bit = nibble = byte = word =

a single binary digit and can have a value of 0 or 1 a sequence of 4 bits a sequence of 8 bits depends on data bus width of processor

When a binary number is written in text, it is usually terminated with the letter ‘B’ to distinguish it from a decimal number or a number from a different numbering system. Here are some examples: 1 1 1 1

bit nibble byte 16 bit word

1B 1010B 00101111B 1000100100001101B

Some texts may use a lower case b at the end of a binary number e.g. 1001b. Others

● 111


C Programming with Arduino may use a small 2 e.g. 111001012 where the 2 represents the two digit values (0 and 1) of the binary system.

6.2 • The Need for Binary Numbers Numbers represented on a computer consist of voltage levels. Only two voltage levels are used: zero volts (0V) and a positive voltage e.g. five volts (5V). Binary numbers consist of only two digits zero (0) and one (1). A binary digit 0 is stored as a voltage level of 0 volts and a binary digit 1 is stored as a positive voltage, 5V for example. If you could open up a memory chip that is attached to a computer system and could use a voltmeter (or multi-meter set to voltage) to measure each binary digit in the chip, you could write out what was stored in the chip. Every time you measured 5V you would write down a 1 and every time that you measured 0V you would write down a 0. So a series of measurements as follows: 5V, 0V, 0V, 5V, 0V, 0V, 0V, 5V would represent the binary number: 10010001 The actual voltage used to represent a binary digit 1 is dependent on the system that it is used in. In the past, digital systems always used 5V to represent the binary digit 1. Many modern microprocessors run on lower voltages like 1.8V. On these systems a binary 1 would be represented by 1.8V. Memory interfaced to one of these systems would then have to consist of 1.8V memory chips. AVR microcontrollers on the Arduino Uno and MEGA boards are capable of running at voltages below 5V, but the power supply on the these Arduino boards is set to 5V. On these Arduinos a binary digit 1 would be represented by 5V.

6.3 • Numbering Systems 6.3.1 • A Quick Look at Decimal Numbers To help understand how binary numbers work, we will have a quick review of the decimal numbering system. The decimal number system should be familiar to you. Decimal numbers consist of ten digits 0 to 9 (1 to 9 = 9 digits, 0 to 9 = 10 digits). The decimal system is therefore said to have a base of ten. The use of only ten digits does not prevent us from counting higher than nine. When counting to a value larger than 9, we use two or more digits. The position of each digit in the number tells us what size the digit is. This is known as a weighted numbering system, for example the number 44 contains the same two digits (symbols), but their position in the number determines the value of each digit. The weight of each digit is a power of 10 increasing from right to left, with the first digit on the right being 1. For the example of the number 44, the first digit on the right has a weight of 1 and the second digit from the right has a weight of 10: 4 × 10 + 4×1 = 44 (4 10s and 4 1s) The "power of ten" is a mathematical term and is written mathematically as: 10° = 1

(ten to the power of zero equals one)

10¹ = 10

(ten to the power of one equals ten)

10² = 100

(ten to the power of two equals one hundred)

● 112


Chapter 7 • Memory and Microcontrollers

Chapter 7 •  Memory and Microcontrollers What you will do in this chapter: •

Find out how memory works

Learn how a microprocessor accesses memory and peripherals

See how to access memory by using the address of the memory

Learn about other data types in C

7.1 • Memory Basics Two main types of memory are present on microcontrollers and embedded systems, namely ROM and RAM. These memory types are used for storing program instructions from a compiled C program and data variables that are defined in a C program.

7.1.1 • ROM (Read Only Memory) This type of memory is used to store the program that is written and compiled. It is nonvolatile memory meaning that it will retain its contents even if the power is switched off. ROM on a modern microcontroller is usually present as Flash memory as it is on the Arduino AVR microcontrollers. The contents of the Flash memory are normally not altered when a user application program is running, although some microcontrollers’ Flash memory is in-application programmable. The program stored in ROM memory will be the program that is run when power is supplied to the microcontroller.

7.1.2 • RAM (Random Access Memory) RAM is used to store variables and data from our program that can be changed while the program is running. This type of memory is volatile meaning the contents of the chip will be lost when power is removed. Microcontrollers usually contain some SRAM (Static RAM) as the AVR microcontrollers do.

Figure 7-1  Memory Showing How Data is Stored

7.1.3 • Data Stored in Memory Data is stored in memory as an array of bytes. Each byte has a unique address and can be individually addressed. Data is stored to memory by a write operation and retrieved from memory by a read operation. Each bit in a byte of a memory chip is called a cell and can hold either a 1 or a 0 logic level as shown in Figure 7-1. The capacity of the memory

● 129


C Programming with Arduino chip is determined by how many addressable bytes it contains.

7.2 • A Look at a Memory Chip Let’s take a look at how a SRAM memory chip works in order to better understand memory. Figure 7-2 shows the top view of a 2kB (two kilo byte) memory chip. Figure  7-3 on page 131 shows a block diagram of the same chip. The size of the memory is determined by how many bytes it can address. This is determined by the number of address lines on the chip. The chip has 11 address lines and so can address 211 bytes = 2048 bytes (or 2 kilo bytes because 1 kilo byte = 1024 bytes or 210).

Figure 7-2  An 8-Bit SRAM Memory Chip A bus is just a group of wires on a computer system. An address bus is a group of wires that are used for addressing memory and peripheral devices and is 11 bits wide on the memory chip shown. A data bus is the group of wires used for sending and receiving data to and from memory and peripheral devices. The data bus on the memory chip in the figure is 8 bits wide. A control bus is the group of wires used to control a memory chip or peripheral device. There are 3 control lines on the memory chip. A peripheral device is any piece of hardware interfaced to the microcontroller, whether it is an internal device or external to the microcontroller.

● 130


Chapter 8 • Accessing AVR Ports in C

Chapter 8 •  Accessing AVR Ports in C What you will do in this chapter: •

Write to AVR hardware registers using pointers

Set an AVR microcontroller port as an output port

Switch LEDs on and off using an AVR register

Learn about the increment and decrement operator

Start a new Atmel Studio project from scratch without using a template

8.1 • AVR Pins and Ports AVR microcontrollers have a number of pins that are known as general purpose input/ output (I/O) pins. These pins can be individually configured as either output pins to drive a load – e.g. to drive or switch an LED on and off; or as input pins used to read a logic level placed on the pin – e.g. to test whether an attached switch is open or closed. Additionally, these pins have an alternative function in that they can be configured to connect to an internal hardware device, such as a UART used for serial communications or ADC to read analogue values. In this chapter, we will look at configuring pins as outputs to drive LEDs. AVR 8-bit microcontrollers have 8-bit ports which are groups of I/O pins that are named with letters – e.g. port A, port B, port C, etc. These ports are each controlled by their own set of registers that allow the pins to be configured as inputs or outputs. Registers are just like memory locations and can therefore be written to using pointers in C. The actual names and functions of the registers can be found in the microcontroller’s datasheet.

Figure 8-1  ATmega328P Pin Numbering and Ports Figure 8-1 shows a top view of the physical package of an ATmega328P microcontroller found on the Arduino Uno showing the pin numbering (pin 1 to pin 28) and individual numbering of pins that make up the ports, namely PB0 to PB7, PC0 to PC6 and PD0 to PD7. At the right of the figure, the ports are shown in a block diagram with port B and port D being 8 bits wide and port C being 7 bits wide. Figure  8-2 on page 146 shows a block diagram of the pins and ports of an ATmega2560 microcontroller found on the Arduino MEGA 2560.

● 145


C Programming with Arduino

Figure 8-2  ATmega2560 Ports The above figures show unused ports of the microcontrollers, however, when the microcontrollers are placed on a board, such as the Arduino, some of the port pins are dedicated to certain functions such as the serial port. The figures that follow show which port pins are used for dedicated functions on the Arduino boards and which pins are free for general purpose use.

Figure 8-3  ATmega328P on the Arduino Uno with Used Pins (L) and Free Pins (R) Figure 8-3 shows port pins of the ATmega328P that are used by the Arduino Uno board on the left of the figure. Pins that are available for general purpose use are shown on the right. PB3, PB4 and PB5 are used by the ICSP header along with the reset pin PC6. PC6, or reset, is connected to both the ICSP header and the reset button on the board. The ICSP header is the header that a programming device such as the AVRISP or AVR Dragon is connected to for programming. PB5 of the ICSP header is also connected to the onboard LED labelled L on the board which maps to Arduino pin 13.

● 146


Chapter 9 • I/O and Memory Maps

Chapter 9 •  I/O and Memory Maps What you will do in this chapter: •

Read the state of a switch connected to a microcontroller input pin

Work with input and output pins

See how hardware and memory are mapped in AVR microcontrollers

9.1 • Input Pins In the previous chapter we worked with output only by sending a value out of the microcontroller to switch LEDs on and off that were connected to pins on the AVR’s port. The port pins were set up as output pins and used to drive LEDs. Port pins can also be set up as inputs and the logic state of these pins can be read by the microcontroller. A switch connected to a microcontroller pin set up as an input can be read to see if the switch is open or closed.

9.1.1 • Connecting a Switch to a Port Pin In order to read the state of a switch in a C program, the switch must first be connected to the desired port pin of the AVR microcontroller on the Arduino. The switch used for this example can be almost any kind of switch that only has to close a circuit and then open a circuit. A momentary push-button switch, toggle switch, key switch or even a wire can be used to close and open a circuit.

Figure 9-1  Connecting a Switch to Pin PC0 on the Uno (left) and MEGA (right) Figure 9-1 shows a switch interfaced to port pin PC0 on an Arduino Uno and MEGA, with the only difference between the two circuits being the Arduino pin number that the switch is connected to. The common GND at one end of the resistor is connected to the GND connection on the Arduino.

● 163


C Programming with Arduino When the switch is open, the 10k pull-down resistor connects the PC0 pin to GND or 0V of the power supply putting a logic level 0 onto the pin. When the switch is closed, the pin is shorted to 5V which places a logic level 1 onto the pin. The 10k resistor prevents the 5V from being shorted to GND.

9.1.2 • Reading the State of a Switch in C Create a new Atmel Studio project called switch_val using the template file and connect a switch to the Arduino using a breadboard as shown in the circuit from Figure  9-1 on page 163. Add the following code to the project. Project name: switch_val Project location: CH9\switch_val main.c #define #include #include #include #include

F_CPU 16000000UL <avr/io.h> <util/delay.h> <stdio.h> "stdio_setup.h"

int main(void) { DDRC = 0x00; UartInit();

}

// set port C pins as outputs

while(1) { printf("PORT C: 0x%02x\r\n", PINC); // print the port state _delay_ms(200); }

Example Program Output PORT PORT PORT PORT PORT PORT ...

C: C: C: C: C: C:

0x00 0x01 0x01 0x01 0x00 0x00

When the switch is open, the value of port C displayed in the terminal window is 0x00. When the switch is closed, the value displayed is 0x01. At the beginning of the program, DDRC is assigned a value of 0x00 to configure all of the port pins of port C as inputs. This is actually not necessary because the port pins are configured as inputs by default, but it does show the intention of the programmer that the entire port will be used as an input port, although we are only using one pin of the input port in the example program. In the while(1) loop, the value of the PINC register is printed to the terminal program running on the PC. The value in this register is used directly in the printf() statement without first reading it into an intermediate variable. The printf() statement is followed by a 200ms delay that prevents the terminal program from being swamped with too many consecutive messages. The PINC register is another register that is part of a set of registers used for configuring, reading and writing to AVR I/O ports. PINC is the register used for reading the value of

● 164


Chapter 10 • Previous C Topics Revisited

Chapter 10 •  Previous C Topics Revisited What you will do in this chapter: •

Look at previous C topics in more detail

More on format specifiers, field width specifiers and escape sequences

Additional loops – the do-while and for loops are introduced

Programming the AVR USART / serial port

Nested loops and decisions

Decision making with the switch construct and conditional operator

Functions and pointers

Scope of variables and static variables

More on floating point variables

Casts in C

10.1 • Format Specifiers Table  10-1 on page 174 shows the format specifiers in C, you have already used some of them. The formats program makes use of some of the new format specifiers. Create this project using the template file and view the output in the terminal program on the PC. Project name: formats Project location: CH10\formats main.c #include <stdio.h> #include "stdio_setup.h" int main(void) { UartInit(); /* characters and strings */ printf("%s %c\r\n", "This is the letter", 't'); /* integers */ printf("Ints:%d, %i, %u\r\n", -1000, -123, 958); printf("Oct:%o, hex:%x, HEX:%X\r\n", 191, 191, 191); /* floating point numbers */ printf("%f, %e, %E\r\n", 45.345, 45.345, 45.345);

}

while(1) { }

Program Output This is the letter t Ints:-1000, -123, 958 Oct:277, hex:bf, HEX:BF 45.345001, 4.534500e+01, 4.53400E+01

● 173


C Programming with Arduino %s and %c are used to print a string and character respectively. You have already seen %d for printing integer decimal numbers, %i does the same thing and %u works with unsigned integers. %x and %X are for printing hexadecimal numbers. %o prints out a number in octal format. Octal is another number system like binary or hexadecimal, but uses base 8. %f is familiar to you and is used to print a floating point number. %e and %E print a number in exponential notation, which is a notation used by scientists and engineers. Table 10-1 C Format Specifiers Format Specifier

Data Type

Print Format

%d or %i

int

Decimal number

%u

unsigned int

Unsigned decimal number

%x

unsigned int

Lowercase hexadecimal

%X

unsigned int

Uppercase hexadecimal

%o

unsigned int

Octal unsigned integer

%c

char or int

Character

%s

string

A string of characters

%f

float

Floating point number

%e

float

Lowercase exponential notation

%E

float

Uppercase exponential notation

10.2 • Field Width Specifiers Revisited We have already seen field width specifiers used with floating point numbers to set the number of digits to print after the decimal point. The number of digits can also be set before the decimal point, or in the case of decimal and hexadecimal numbers, set the number of place holders to the left of the number. As an embedded programmer, you may wish to use this to show the width of a number when using hexadecimal numbers, or to align numbers. For example, the number 0x5 is a 3 bit number (1012), but in a microcontroller or computer, memory is always displayed in multiples of bytes, so we may wish to display this number with padding zeros to represent all 8 bits – 0x05 (0000 01012). The next program, padding, shows how to pad different numbers with zeros or spaces. Create the project using the template file. Project name: padding Project location: CH10\padding main.c #include <stdio.h> #include "stdio_setup.h" int main(void) { UartInit(); // a 3 bit hex number padded to 8 bits printf("0x%X\n", 0x5); // unpadded printf("0x%2X\n", 0x5); // pad with spaces printf("0x%02X\n\n", 0x5); // pad with 0 // a 3 bit hex number padded to 16 bits printf("0x%4X\n", 0x5); // pad with spaces printf("0x%04X\n\n", 0x5); // pad with 0

● 174


Chapter 11 • Arrays and Strings

Chapter 11 •  Arrays and Strings What you will do in this chapter: •

See how arrays are used to access sequential memory locations

See how strings are used and stored in memory

Use C standard library string functions

Write functions that take strings and arrays as arguments

You have already worked with strings in C when using the printf() function. C does not have a string data type but instead uses arrays of characters. An array of characters is simply a number of sequential characters in memory. In C a string is an array of characters, but it is also possible to have an array of a different data type. We will start by looking at arrays in general and see how to define and use arrays in C. We will then take a closer look at strings and some standard library functions used to manipulate them.

11.1 • Arrays An array is a set of consecutive memory locations that store data of a specified type. The key principal here is consecutive, as this is what makes arrays possible. As an example, in C an array of 5 integers is defined as follows:

int arr_num[5]; This tells the compiler to make space for an array that consists of five integer numbers. Each element (integer) in the array can be accessed using array notation in C. If we wanted to assign a value to each element in the array, it can be done as follows:

arr_num[0] arr_num[1] arr_num[2] arr_num[3] arr_num[4]

= = = = =

20; 34; 9; 1023; 700;

There are five elements in this array, but they are indexed starting at 0, so the five elements are accessed with indexes from 0 to 4 and not 1 to 5. The array definition:

int arr_num[5]; is similar to defining 5 separate integer variables:

int arr_num0, arr_num1, arr_num2, arr_num3, arr_num4; Defining separate variables, however does not guarantee that they are consecutively placed in memory. The separate variables can also not be referenced with array notation which, as we will see, is very useful. The index_array program initialises an array of integers and then use a for loop to move through the list of integers and send them out of the serial port.

● 205


C Programming with Arduino Project name: index_array Project location: CH11\index_array main.c #include <stdio.h> #include "stdio_setup.h" int main(void) { int num_list[5] = {34, 789, 327, 1000, 45}; int index; UartInit();

}

for (index = 0; index < 5; index++) { printf("Element %d = %d\r\n", index, num_list[index]); } while (1);

Program Output Element Element Element Element Element

0 1 2 3 4

= = = = =

34 789 327 1000 45

The first line inside main() defines an array of 5 integers and initialises each of these integers to a value that appears between braces after the = sign. The initialisation has the same effect as assigning a value to each element of the array as follows:

int num_list[5]; num_list[0] = 34; num_list[1] = 789; num_list[2] = 327; num_list[3] = 1000; num_list[4] = 45; A for loop is used to count from 0 to 4. Inside this loop, the current count value (the variable index) and each element of the array is printed out. By referencing each element in the array with the current count that is counting from 0 through 4, we access each element in the array from 0 to 4. When index contains the value 0, then num_list[index] takes on the value of the first element in the array i.e. 34 in this example. After index has been incremented to 1, num_list[index], which is equivalent to num_list[1], now has the value of the second element in the array i.e. 789. Remember that we are counting from 0, so the first element in the array is indexed at position 0, the second at position 1 the third at position 2, etc. Figure  11-1 on page 207 shows the array used in this example in diagrammatic format as it would appear in memory.

â—? 206


Chapter 12 • Bit Manipulation and Logical Operators

Chapter 12 •  Bit Manipulation and Logical Operators What you will do in this chapter: •

See how to change individual bits inside a variable by using bitwise operators

Move the contents of a variable left or right using the shift operators

Use logical operators to combine expressions

12.1 • Bit Manipulation with Bitwise Operators Bitwise operators enable a programmer to modify individual bits in a memory location and can be used to operate on bytes or larger groups of bits. The C programming language has four Boolean bitwise operators and two shift operators as shown in Table 12-1. The bitwise AND operator (&) should be familiar to you. Table 12-1 Boolean Bitwise and Shift Operators Boolean Bitwise Operators Operator Operation

Example

Result

&

AND

1101 & 0111

0101

|

OR

1101 | 1001

1101

^

XOR (Exclusive OR)

1101 ^ 1001

0100

~

NOT (Compliment)

~1101

0010

Shift Operators Operator

Operation

Example

Result

<<

Left Shift

1010 << 1

10100

>>

Right Shift

1010 >> 1

0101

Windows calculator will again come in handy when learning about bitwise operators as it has all of the bitwise operators available. Figure  12-1 on page 230 shows the Windows calculator and the equivalent C bitwise operators below it. The bitwise operators can be tested with the calculator in binary or hexadecimal mode and it is possible to change between these modes at any time while performing an operation. The keystrokes used to calculate the examples in Table 12-1 on the calculator are shown below from top to bottom – first put the calculator into Programmer mode and then click the Bin radio button. An explanation of each bitwise operator follows. 1101 And 111 = Note that the 0 place holder to the left of the second number is left out when entering the second number and is not displayed on the calculator in the result i.e. the result displayed is 101 and not 0101. 1101 Or 1001 = 1101 Xor 1001 = 1101 Not The result of this operation on the calculator turns all of the invisible 0 place holders to

● 229


C Programming with Arduino the left of the number into 1s and that is why the number is filled with 1s to its left. Click the Byte radio button to shorten the number to 8 bits which is easier to read. 1010 Lsh 1 = (Left shift by 1 bit) 1010 Rsh 1 = (Right shift by 1 bit)

Figure 12-1  Bitwise Operations on the Windows Calculator In Windows Calculator, the buttons have the following meaning with the equivalent operators used in C shown in the middle: Or

|

bitwise OR – the symbol used in C is the vertical pipe found on the \ key

Xor

^

bitwise XOR (exclusive OR)

Lsh

<<

left shift

Rsh

>>

right shift

Not ~

compliment

And

bitwise AND

&

Although RoL (rotate left) and RoR (rotate right) operate on bits in Windows Calculator, they do not have an equivalent in the C language. In order to understand what the Boolean bitwise operators do, we need to look at the truth tables of these operators. The truth tables are shown in Figure 12-2. The truth tables show the output of each bitwise operator when it is performed on the input bit(s).

Figure 12-2  Truth Tables for the Boolean Bitwise Operators

● 230


Chapter 13 • Programming Hardware

Chapter 13 •  Programming Hardware What you will do in this chapter: •

Use the hardware / timer counter in the AVR to make accurate time delays

Read external analogue values using the analogue to digital converter

See how the watchdog timer works

Look at I/O ports in more detail

We have covered most of the C language up to now. This chapter deals with using this knowledge to program more hardware devices on the microcontroller, namely, timers, the watchdog timer and the analogue to digital converter (ADC). We also take a look at I/O ports in more detail. After learning the C language, moving from one embedded system to another or one microcontroller architecture to another is all about learning how the new hardware works and then programming it. Because this is a book on learning the C language, we will not cover every detail of the microcontroller hardware, but rather demonstrate how various hardware devices are set up and used.

13.1 • Timer Counter Hardware The timer counters (TC) in AVR microcontrollers can be used for multiple purposes such as event counting, pulse generation, delay timing and more. More information about the timer/counters can be found in the AVR datasheet for the specific AVR being used. Microcontrollers on the Arduino Uno and Arduino MEGA 2560 have the following on-chip timer/counters. Arduino Uno (ATmega328P) •

Timer/Counter0, 8-bit

Timer/Counter1, 16-bit

Timer/Counter2, 8-bit

Arduino MEGA 2560 (ATmega2560) •

Timer/Counter0, 8-bit

Timer/Counter1, 16-bit

Timer/Counter2, 8-bit

Timer/Counter3, 16-bit

Timer/Counter4, 16-bit

Timer/Counter5, 16-bit

A hardware timer works by feeding a clock pulse into it which causes it to count up every clock cycle. The count value is stored in one of the timer's registers and updated by the hardware every clock cycle. A C program can read the value in the count register which is a 16-bit value in a 16-bit timer, or an 8-bit value if the timer is an 8-bit timer. If we had a 1Hz clock fed into a timer, then a count would occur every 1s because 1Hz is one clock cycle per second. A 5s time period could be generated by starting the timer and checking when the timer reaches a count of 5. Microcontrollers usually have clock sources that

● 251


C Programming with Arduino are a lot faster than 1Hz and are most often derived from the system clock which would normally be in the MHz range. If a 16MHz system clock is fed into a 16-bit timer, the timer would overflow after approximately 4ms. An overflow occurs when the timer counts from zero to its maximum value of 65535 and then wraps around to zero again. To get a longer time period from a 16-bit timer, a prescaler is used to divide the system clock down into a smaller value before being fed into the timer. The prescaler can be enabled from one of the timer / counter registers and has a number of different values that it can divide the system clock by. The duration or time period of a clock cycle can be calculated using the following formula: t=

1 f

Where :

t =time period

ƒ =clock frequency For a 1Hz clock, the calculation is very simple: 1 = 1s 1 Hz

= t

A 16MHz clock has a period of: t= =

1 f

1 16 MHz

=

1 16, 000, 000

= 0.0000000625 = 62.5 ns

A 16MHz clock has a period of 62.5 nanoseconds. In a timer, we can easily generate a specific time period once we know how long one clock cycle takes. The timer will increment every clock cycle or clock period, therefore:

ttimer = tperiod x count Where :

ttimer = period generated by timer tperiod = clock period of clock fed into timer count = timer count The timer can therefore time in multiples of the clock period from the clock source that it is using.

13.1.1 • Polled Timer Time Delay The example program called timer that follows uses timer/counter1, which is a 16-bit timer/counter found on both the Uno and MEGA AVRs, for generating a delay period much like the Delay() and _delay_ms() functions that we have used in previous programs. Using the hardware timer to generate a delay is a much more accurate method than

● 252


Chapter 14 • Debugging

Chapter 14 •  Debugging What you will do in this chapter: •

Use the AVR Dragon or simulator in conjunction with Atmel Studio to debug a program

Single-step through source code in Atmel Studio

Look inside variables, registers and memory using the debugging tools

An AVR Dragon used with Atmel Studio can single-step through C code in a project in order to find program errors as part of the debugging process. Contents of variables, memory and registers can be examined using the AVR Dragon. If you do not have an AVR Dragon, the AVR simulator can be used instead, but changes to externally interfaced hardware like LEDs switching on can not be seen with the simulator.

14.1 • Configuring Arduino Boards for Debugging AVR microcontrollers on the Arduino Uno and MEGA have an on-chip debug system called debugWIRE that interfaces debugging software to the AVR through a device such as the AVR Dragon connected to the ICSP header. In order for debugWIRE to work on the AVR on the Arduino boards, reset circuitry must be disconnected from the reset pin. Modern Arduino boards have a solder link labelled RESET-EN that consists of two solder pads connected by a circuit board track. The track must be cut through in order to disconnect part of the reset circuitry from the reset pin when using debugWIRE. The connection can be remade by soldering the two solder pads together.

Figure 14-1  Location of the RESET-EN Solder Pads on the Arduino MEGA 2560 (left) and Arduino Uno (right) Figure 14-1 shows where the RESET-EN solder pads are found. Use a sharp blade from a craft knife or scalpel to cut through the track that joins the two solder pads. Be very careful not to slip and cut other tracks on the board. It is usual to make several cuts on the track to try to remove the track so that the pads are properly disconnected.

14.2 • Debugging Example Program Create the debug program below by starting a new Atmel Studio GCC C executable

● 267


C Programming with Arduino project from scratch without the template file. This project is used to demonstrate how to use the debugger. Use the circuit from Appendix C page 335 for this project. Project name: debug Project location: CH14\debug main.c #include <avr/io.h> void Delay(void); int main(void) { int var = 1; int result, val1, val2; float flt_res; unsigned char LED_val = 0; DDRC |= 0x0F; PORTC |= 0x0A;

// four LEDs // switch two LEDs on

val1 = 25; val2 = 39; result = val1 * val2; result /= 100; flt_res = result / 100.0; while (!(PINC & (1 << PINC4)));

}

while (1) { if (PINC & 1 << PINC5) { LED_val = 0; } PORTC &= 0xF0; PORTC |= LED_val; LED_val++; if (LED_val > 0x0F) { LED_val = 0; } Delay(); var++; }

// wait for switch press // reset count

// display count on LEDs // keep count within range

void Delay(void) { volatile unsigned long del = 100000;

}

while (del) { del = del - 1; }

Program Output 1010 is displayed on the LEDs followed by some calculations that can only be seen by using the debugger. When the button on pin PC4 is pressed a count is displayed on the LEDs. Pushing the button on pin PC5 resets the count switching all the LEDs off.

â—? 268


Chapter 15 • Interrupts

Chapter 15 •  Interrupts What you will do in this chapter: •

Find out how interrupts work

Use interrupts for servicing hardware instead of using polling

Use timer interrupts

Up until now we have been "polling" hardware – continually checking it in our program to see if some condition has occurred. If you look at the timer program in section 13.1.2 on page 255, you will see one of the disadvantages of polling hardware. When the TC1Delay() function is called, it uses up all of the microcontroller’s processing time to check or poll the timer. If this function was to be used in a more useful program, the rest of the embedded system would not be able to respond to user button presses or other hardware that may need to be serviced while this function was running. Interrupts on a microcontroller are available to solve this problem.

15.1 • Handling Interrupts in C There is no standard way of handling interrupts in C. Interrupt configuration depends on on how interrupts have been implemented in the architecture of a specific microcontroller and how interrupts have been implemented in the compiler. Different C compilers for the same microcontroller may use different code to configure interrupts, so always check the compiler documentation to see how to use interrupts. Interrupts can be configured on the microcontroller so that, for example, when using the timer, it can be started and left to run on its own while the main program continues to run. When the timer reaches the time-out value e.g. after 1ms, an interrupt will be triggered. This interrupts the current flow of the main program and a function called an Interrupt Service Routine (ISR) is run in order to service the timer. When the interrupt occurs, the current state of the microcontroller is saved, a jump occurs to the ISR function where code is run that will respond to the timer. When the ISR function has finished running, a jump occurs back to where the main program left off and the saved state of the microcontroller is restored. The program carries on running normally after this until another interrupt occurs.

15.2 • Using the Timer Interrupt The timer_interrupt program uses 16-bit timer/counter 1 to generate an interrupt every second. When the timer time-out is reached after 1s, the interrupt service routine is run which increments a count value representing seconds elapsed. In the while(1) loop of the program an if statement checks if the count value has changed. Only if the count value has changed will the new count value be sent to the terminal window so as not to flood the terminal with count values which would happen if the count value was continually sent in the main loop. Create the timer_interrupt program using the template file.

● 279


C Programming with Arduino Project name: timer_interrupt Project location: CH15\timer_interrupt main.c #include #include #include #include

<stdio.h> <avr/io.h> <avr/interrupt.h> "stdio_setup.h"

volatile unsigned long g_count_s = 0; int main(void) { unsigned long saved_count = 0; OCR1A = 15624; TCCR1B = (1 << WGM12) | (1 << CS12) | (1 << CS10); TIMSK1 = (1 << OCIE1A); sei(); UartInit();

}

while(1) { if (saved_count != g_count_s) { printf("%lu\r\n", g_count_s); saved_count = g_count_s; } }

ISR(TIMER1_COMPA_vect) { g_count_s++; }

Sample Program Output 1 2 3 4 ...

In the above code the timer is set up and started as before, but this time it is set to trigger an interrupt every second. When the timer times out and triggers the interrupt, the code that is running in the while(1) loop is "interrupted" and the ISR(TIMER1_COMPA_vect) interrupt service routine is run. This ISR function simply increments the global variable g_count_s by one. When the ISR function returns, the code in the while(1) loop continues running where it left off when the interrupt occurred. Let’s have a look at how the code works. In the following two lines of code timer/counter 1 is set up with a 1 second period, prescaler division of 1024 and CTC mode as done in the polled timer example. OCR1A = 15624; TCCR1B = (1 << WGM12) | (1 << CS12) | (1 << CS10);

â—? 280


Chapter 16 • Wrapping Up the C Language

Chapter 16 •  Wrapping Up the C Language What you will do in this chapter: •

Use structures to group different data types together

Use pointers to access structures

Learn about unions

See how the enumerated data type works

Look at miscellaneous topics in C to complete coverage of the C language

16.1 • Structures Arrays allow us to store and access more than one variable of the same type. Structures can be used to group data of different types, for example a structure can contain a float, int and a char, but an array can only consist of one of these types.

16.1.1 • Using Structures in C Programs The sample_struct project uses a structure to group a time-stamp value and sample data value together in order to demonstrate the use of structures in C. Create this project using the template file. Project name: sample_struct Project location: CH16\sample_struct main.c #include <stdio.h> #include "stdio_setup.h" int main(void) { struct sample { int time; float data; }; struct sample samp1;

/* declare a data type structure */ /* integer member of structure */ /* float member of structure */ /* define a structure of type sample */

UartInit();

}

/* assign values to struct members samp1.time = 20; samp1.data = 56.23; printf("\r\nTime in seconds is: %d\r\n", samp1.time); printf("Sampled data is: %.2f", samp1.data); while (1);

*/

Program Output Time in seconds is: 20 Sampled data is: 56.23

● 285


C Programming with Arduino A structure can contain any number of different data types and the compiler therefore does not know what you are going to put in a structure, so the structure must first be declared. In the sample_struct program, this is done with the following statement: struct sample { int time; float data; };

This declares a new data type called struct sample which has two member variables. The name sample is known as a tag and is a type name – i.e. we have declared a new data type that can now be used in our program. Figure 16-1 shows the details of a C structure declaration.

Figure 16-1  A C Structure Declaration In the same way that we can use the keyword int to define an integer variable in a program, we can use the new data type struct sample to define a new structure of this type. This is what the next statement in the program does: struct sample samp1;

The declaration of the new structure type did not allocate any memory for the structure, it just tells the compiler of the new data type that we are going to use in our program. The above statement now creates a new variable called samp1 of type struct sample. This allocates memory for the structure and the variable name for this structure is now samp1. We could declare another variable in the program of type struct sample as follows: struct sample samp2;

This will define another structure in the program of type struct sample with its own name. In other words a second structure of the same type would exist in memory that can be accessed by using its name – samp2, just like we could define two integers or other variable types in a program:

int val1; int val2; struct sample samp1; struct sample samp2; Each member variable of the structure can be accessed with the dot (.) operator as we can see in the following lines from the program: samp1.time = 20; samp1.data = 56.23;

● 286


Chapter 17 • C Projects

Chapter 17 •  C Projects What you will do in this chapter: •

Write serial port driver functions to replace printf()

Write functions to convert numbers to decimal and hexadecimal strings

Make a voltmeter project

Create a stopwatch

This chapter consists of a series of C code projects that demonstrate the use of the C language already learned in the previous chapters. Several C topics are added to and expanded in the explanations that follow each project.

17.1 • Serial Port Driver Functions As already discussed, the printf() functions tends to use up a fair amount of memory which is a scarce resource on 8-bit AVR microcontrollers, especially the smaller parts that have less memory. The solutions suggested in Chapter 10 was to write serial port functions that can send and receive text and characters over the UART serial port. The project in this section modifies the code from the serial_port project found in section 10.5.2 of Chapter 10 on page 184. The following modifications are made to the serial_ port project. •

The serial port / UART driver functions are put into their own C file

UART baud rate settings and microcontroller clock frequency are set in global.h

An extra function is added that transmits a null-terminated string

The use of commenting is demonstrated in the program

The serial port driver functions allow strings to be sent over the Arduino serial / USB port in the same way as the printf() function does when a project is created using the template file, but the serial port driver functions do not have the formatting capabilities of printf(). Using the serial port function for transmitting a string instead of printf() reduces program memory usage.

17.1.1 • Serial Port Driver Design Notes Although the hardware device in the AVR microcontroller that handles serial port communications is called a USART, it is used as a UART in the serial port driver code so file names and function names to do with using the USART are named UART and not USART. The uart_driver project that contains the serial port driver functions is split into four separate source code files, namely main.c, uart.c, uart.h and global.h. main.c contains the code that demonstrates the use of the serial port functions from uart.c. uart.h is the header file for uart.c and must be included in any C source file that uses the serial port driver functions. global.h contains the clock frequency of the embedded system that the code will be compiled for, defined as F_CPU, as well as the baud rate setting for the UART. It was decided to put the baud rate setting into the global header file so that the baud rate can be changed without making any changes to the UART driver

● 301


C Programming with Arduino files. In this way the driver files can be copied from project to project without any need to modify them. Any changes to the baud rate or microcontroller frequency can be made in the global.h header file.

17.1.2 • Serial Port Driver Code Code listings for all four source code files of the uart_driver project are shown below. Project name: uart_driver Project location: CH17\uart_driver main.c /*-----------------------------------------------------------------------------FILE NAME: main.c from uart_driver project DESCRIPTION:

Tests the UART driver functions from uart.c

AUTHOR:

W.A. Smith

DATE: 30 October 2015 ------------------------------------------------------------------------------*/ #include <avr/io.h> #include "uart.h" int main(void) { // stores data received from the UART int rx_data; // initialize the UART to the baud rate set in global.h UartInit();

// test the UartTxString() and UartTxByte() functions UartTxString("Start of UART driver test program.\r\n"); UartTxString("Transmitting a character:"); UartTxByte('C'); UartTxString("\r\nEchoing typed characters:\r\n");

}

// echo back any character typed in the terminal window and terminate with // carriage return and newline characters while(1) { // get a byte from the UART if available rx_data = UartRxByte(); // was a byte received if (rx_data > -1) { // echo the received byte back over the UART UartTxByte(rx_data); // terminal window cursor to new line UartTxString("\r\n"); } }

global.h #ifndef GLOBAL_H_ #define GLOBAL_H_ // microcontroller clock frequency #define F_CPU 16000000UL // USART baud rate settings #define BAUD 38400 #define BAUD_TOL 1 #endif /* GLOBAL_H_ */

â—? 302


Index

Index Symbols

|= 238, 242 || 239, 242 ~ 229, 242

^ 229, 242

8-bit AVR double 199

^= 238, 242

8-bit AVR long double 199

- 51, 242

%c 141

-- 242

#define 99, 110

-= 238, 242

%d or %i 141

-> 242

#include 102, 110

: 242

%u 141

! 239, 242

%x 141

!= 62, 242

%X 141

? 242 . 242 () 242 [] 242 * 51, 242 *= 238, 242 / 51, 242 /= 238, 242 & 229, 242 && 239, 242 &= 238, 242

A ADC 145, 256 Adding Watches 271 Additional Resources 337 Addresses 133 Algorithm 89 AND Bitwise Operator 167 Application Notes 337 Arduino Board 21 Arduino I/O Circuit 335

% 51, 242

Arduino MEGA 2560 20, 21, 145, 147, 152, 332

%= 238, 242

Arduino MEGA 2560 Circuit 154

+ 51, 242

Arduino MEGA AVR 153

++ 242

Arduino Uno 146, 152, 331

+= 238, 242

Arduino Uno AVR 153

< 62, 242

Arduino Uno Circuit 154

<< 229, 242

Arithmetic Operators 49

<<= 238, 242

array definition 205

<= 62, 242

Array Element Addresses 214

= 238, 242

Array of Integers 207

== 62, 242

Arrays 205

> 62, 242

ASCII Table 124, 329

>= 62, 242

Assignment Operators 238

>> 229, 242

ATmega328P 21, 34, 142, 145, 149

>>= 238, 242

ATmega2560 34, 142, 147, 150

| 229, 242

â—? 339


C Programming with Arduino ATmega2560 Ports 146

continue 178, 179, 296

Atmel Studio 17, 25

default 192, 296

AVR Architecture 17

do 178, 180, 181, 202, 296

AVR C Library 306

double 199, 200, 296

AVR Dragon 32, 267

else 63, 64, 67, 68, 296

AVR Forum 337

enum 292, 296

AVRISP 32

extern 294, 296, 299

AVR Libc Reference 337

float 48, 285, 289, 295, 296

AVR Memory Map 169

for 296

AVR microcontroller 17, 41, 163, 301

goto 295, 296, 299

AVR Pins and Ports 145

if 63, 293, 295, 296, 320

AVR Port Pin Mapping 331

int 92, 98, 124, 138, 296

B

long 138, 141, 142, 296

Baud Rate 186 Binary Basics 111 binary digit 111 binary numbers 111, 113 Bitwise NOT Operator 234 Bitwise XOR Operator 235 Boolean Bitwise Operators 229 bounce 223 braces {} 40 break Statement 179 Button Message 226 Button Wait 227 bytes 111, 130

register 133, 137, 231, 243, 296 return 95, 96, 296 short 139, 141, 296 signed 139, 141, 296 sizeof 139, 140, 208, 226, 296 static 294, 296, 319 struct 286, 288, 296 switch 293, 296 typedef 293, 294, 296, 299 union 288, 296, 299 unsigned 293, 294, 296, 298 void 36, 91, 296 volatile 98, 296 while 178, 180, 202, 296

C

Class Specifiers 294

C99 Variable Types 298

clock cycle 251

Casts 200

C Macros 246

char 58

Code Listings 30

Characters 35

Code Timing 319

Character Variables 48

Commenting Programs 79

C Keywords 296

Communication Parameters 186

auto 294, 296

Comparative Operators 61, 72

break 178, 179, 192, 202, 296

Compiler Optimisation 269

case 192, 296

Compile-time 247

char 58, 231, 285, 296, 298

Compiling 52

const 295, 296, 299

Conditional Operator 193

â—? 340


Warwick A. Smith Warwick A. Smith lives in South Africa and works as an Electronics Engineer and Embedded System Programmer. He is a bestselling author of the books C Programming for Embedded Microcontrollers, ARM Microcontroller Interfacing and Open Source Electronics on Linux.

ISBN 978-1-907920-46-2

Arduino is the hardware platform used to teach the C programming language as Arduino boards are available worldwide and contain the popular AVR microcontrollers from Atmel. Atmel Studio is used as the development environment for writing C programs for AVR microcontrollers. It is a full-featured integrated development environment (IDE) that uses the GCC C software tools for AVR microcontrollers and is free to download. •

Start learning to program from the very first chapter

No programming experience is necessary

Learn by doing - type and run the example programs

A fun way to learn the C programming language

Ideal for electronic hobbyists, students and engineers wanting to learn the C programming language in an embedded environment on AVR microcontrollers

Use the free full-featured Atmel Studio IDE software for Windows

Write C programs for 8-bit AVR microcontrollers as found on the Arduino Uno and MEGA boards

Example code runs on Arduino Uno and Arduino MEGA 2560 boards and can be adapted to run on other AVR microcontrollers or boards

Use the AVR Dragon programmer / debugger in conjunction with Atmel Studio to debug C programs

DESIGN

www.elektor.com

Technology is constantly changing. New microcontrollers become available every year. The one thing that has stayed the same is the C programming language used to program these microcontrollers. If you would like to learn this standard language to program microcontrollers, then this book is for you!

AVR MICROCONTROLLERS AND ATMEL STUDIO FOR

C

PROGRAMMING WITH ARDUINO

LEARN

Elektor International Media BV

C

PROGRAMMING WITH ARDUINO

C PROGRAMMING WITH ARDUINO ● WARWICK A. SMITH

AVR MICROCONTROLLERS AND ATMEL STUDIO FOR

Warwick A. Smith LEARN

DESIGN

SHARE

SHARE

LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● S ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE GN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE ● LEARN ● DESIGN ● SHARE


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.