Вы находитесь на странице: 1из 238

Version 1.

RMIT University, Melbourne, Australia

OPEN USB USER GUIDE


An Introduction to Embedded C Programming and OUSB Command line

Authors
Troy Boswell
Peter Radcliffe
Heiko Rudolph

4/20/2010
Table of Contents
Introduction .................................................................................................................................................. 4
Chapter 1 - OUSB Command Line ................................................................................................................. 5
1. Downloading the OUSB Command Line Interface......................................................................... 5
2. Preparing a Windows PC for the OUSB Command Line Interface ................................................. 6
3. Preparing a Linux PC for the OUSB Command Line Interface ....................................................... 9
4. Preparing an RMIT Linux Live-DVD for the OUSB Command Line Interface ................................. 9
5. Testing the OUSB Development Board ....................................................................................... 10
Testing the Atmega32 Input/Output (IO) Pins .................................................................................... 11
Testing the Atmega32 Analogue to Digital Conversion (ADC) ............................................................ 12
Testing the Atmega32 Pulse Width Modulation (PWM) .................................................................... 13
6. Command Line Interface Directives ............................................................................................ 14
IO Command Line Directives ............................................................................................................... 17
PWM Command Line Directives ......................................................................................................... 19
ADC Command Line Directives............................................................................................................ 21
7. Introduction to Combining Command Line Directives ................................................................ 22
8. Combining Command Line Directives in Batch script files (Windows users) .............................. 22
9. Combining Command Line Directives in BASH script files (Linux users) ..................................... 24
10. Bash scripts mini projects (Linux Only)........................................................................................ 28
LED BOUNCE ....................................................................................................................................... 28
LED READ DIP SWITCH ........................................................................................................................ 29
LED READ TRIM PORT.......................................................................................................................... 30
LED PWM READ DIP SWITCH .............................................................................................................. 31
LED PWM READ TRIM POT .................................................................................................................. 32
USART .................................................................................................................................................. 33
11. Creating C++ programs that interact with the OUSB Command line interface........................... 34
12. C++ driven OUSB command line mini projects ............................................................................ 47
LED_BOUNCE ...................................................................................................................................... 47
LED READ DIP SWITCH ........................................................................................................................ 48
LED READ TRIM PORT.......................................................................................................................... 49
LED PWM READ DIP SWITCH .............................................................................................................. 50
LED PWM READ TRIM POT .................................................................................................................. 51
USART .................................................................................................................................................. 52

1|Page
Chapter 2 – Preparing For Embedded C ..................................................................................................... 54
1. Do You Really Need To Complete This Chapter .......................................................................... 54
2. What you need and where to get it ............................................................................................ 55
3. Preparing a Windows PC ............................................................................................................. 55
4. Preparing a Linux PC .................................................................................................................... 55
5. Developing your first Embedded C program in Eclipse ............................................................... 60
6. Loading your first program into Atmega 32 on the OUSB development board.......................... 70
Using STK-200 ..................................................................................................................................... 70
Using the an USBasp Programmer ...................................................................................................... 76
Installing USBasp on a 64 bit Windows OS ......................................................................................... 76
Using the AVR ISP mkII Programmer .................................................................................................. 84
Installing AVR ISP mkII on 32 bit and 64 bit Windows OS ................................................................... 84
How to Restore The OUSB Firmware .................................................................................................. 94
Chapter 3 – C Programming for the Atmega32 ........................................................................................ 102
1. Introduction to embedded C programming .............................................................................. 102
2. Bitwise manipulation ................................................................................................................. 102
Bitwise operators .............................................................................................................................. 102
Shifting Bits ....................................................................................................................................... 104
Bit Manipulation ............................................................................................................................... 105
LED Toggle an Atmega32 Code using Bit Manipulation ........................................................................ 107
3. State machines in C ................................................................................................................... 108
4. Atmega32 peripherals ............................................................................................................... 112
Interrupts .......................................................................................................................................... 112
External Interrupts ............................................................................................................................ 115
Reset Interrupt .................................................................................................................................. 118
IO Ports ............................................................................................................................................. 119
Watch Dog Timer .............................................................................................................................. 121
Timers/Counters ............................................................................................................................... 125
Analogue Peripherals ........................................................................................................................ 152
USART ................................................................................................................................................ 158
5. Mini Projects .............................................................................................................................. 168
LED BOUNCE ..................................................................................................................................... 168
LED READ DIP SWITCH ...................................................................................................................... 169
LED READ TRIM PORT........................................................................................................................ 170

2|Page
PWM READ DIP SWITCH ................................................................................................................... 171
PWM READ TRIM POT ....................................................................................................................... 172
USART ................................................................................................................................................ 173
Annex A Eclipse Installation For Windows ............................................................................................... 174
Annex B Eclipse Help For Linux ................................................................................................................ 210
Annex C OUSB Schematic Diagram .......................................................................................................... 212
Annex D Atmega32 Registers “iom32.h” ................................................................................................. 213
ANNEX E Windows XP Setup for STK 200................................................................................................. 227
References ................................................................................................................................................ 237

3|Page
Introduction
Welcome to the Open USB (OUSB) user manual, this manual is designed to introduce you to the OUSB
development board and will demonstrate how to use the development board in either a Windows or Linux
environment.

The OUSB project is a current project running at RMIT Melbourne and is designed to provide students
with a low cost method of learning real skills in embedded programming and hardware interfacing.
It was developed by Dr P J Radcliffe and it is powered by a versatile microcontroller, the Atmega 32.
Currently the project has developed the board and a command line program that operates in Linux and
Windows. This command line interface allows you to directly access the Atmega 32 through predefined
commands, as you progress through this manual we will start out with basic tasks commanded by the
command line interface (command line interfaces are covered in chapter 1) to build your basic knowledge
and to get you performing measurable tasks immediately. Once you have explored the command line
interface it is then time to move onto more advanced topics such as creating C/C++ programs that drive
the OUSB command line interface, and finally to the stage where you can create real embedded programs
in C and upload them into the Atmega 32 to perform the tasks we performed with the simpler command
line interface.

The Atmega 32 has many built-in peripherals and this manual will teach you how to use most of them,
including, universal synchronous and asynchronous receiver-transmitter (USART) for serial
communications, parallel input/output ports, analogue to digital converters, timers and pulse width
modulators.

Upon completion of this manual you will have a real insight into the workings of embedded c
programming with an Atmega microcontroller and once you are finished will be in no way limited to just
having to use an Atmega 32, but you will be able to apply your knowledge to program an Atmega
microcontroller supported by the AVR-GCC standard.

4|Page
Chapter 1 - OUSB Command Line
Prerequisites
 A PC running either a Linux or Windows (XP, Vista, 7) OS and a spare USB port.
 An OUSB Development Board with the OUSB firmware loaded (comes preloaded)
 Understand basic operations of your operating system (save, create, move and find, files
and folders)
 Access to the internet
 Linux users may also find it advantageous if they know some basic BASH programming
 Obtain a standard USB - AB cable
o http://www.jbhifionline.com.au/computers-laptops/computer-accessories/soniq-2m-usb-a-
b-printer-cable/435964
o http://www.jaycar.com.au/productView.asp?ID=WC7700&keywords=usb+cable&form=
KEYWORD
 Able to convert 8 bits of data between decimal, binary and hexadecimal.
o http://www.computerhope.com/binhex.htm
o http://www.easycalculation.com/decimal-converter.php

1. Downloading the OUSB Command Line Interface

The OUSB command line interface is an executable program and can be downloaded from the sources
listed below. What you will be downloading is the appropriate zipped folder for your operating system
(OS), when extracted contains the command line interface program that we are going to use for the
remainder of this chapter.

Figure 1. 1

To download this executable click the download link below the appropriate file for your OS (there are
two versions for each platform, with CO USB and without CO USB) as shown above in figure 1.1, you
will be asked whether you wish to open or save this file, select save, and save it to your desktop.

o Source 1 – OUSB Users Manual Google site, file page


http://sites.google.com/site/openusbboard/file-cabinet

o Source 2 – OUSB Users Manual Google site, Chapter 1 (bottom of page)


http://sites.google.com/site/openusbboard/chapter-1

5|Page
2. Preparing a Windows PC for the OUSB Command Line Interface

To prepare a Windows PC for the command line interface, it is a relatively simple task of extracting the
downloaded zipped folder into the default directory pointed to by your command prompt.

To find this directory lets open command prompt by clicking on start > run and then typing „cmd‟ into
the open window. Once you have done this command prompt will open and it is just a matter of
interpreting what directory your command prompt uses by default.

NOTE: Windows 7 does not have run you will need to type 'cmd' into the search bar after clicking on
start.

From figure 1.2 you can see that the default directory of my Windows XP machine is C drive, the folder
Documents and Settings then folder Troy which is written as C:\ Documents and Settings\Troy in
command prompt.

Figure 1. 2

So let us investigate this further by opening my computer (just computer for Windows 7) by clicking on
start > my computer > C drive > Documents and Settings > Troy. You are now at your command
prompts default directory.

Our next step is to extract the ousbexe_os.zip folder that you had previously downloaded into this default
directory. The simplest way of executing this is to right click on the ousbexe_os.zip on your desktop and
select Extract All… as displayed in figure 1.3.

6|Page
Figure 1. 3

Once the extraction wizard starts, select Next and you will be prompted to select the destination of your
extraction. As displayed in figure 1.4 click on Browse and expand Local Disk (C:) until you reach your
default directory and click OK.
Now that you have selected your default directory as the destination, back in the extraction wizard
window click Next to extract the file, after the file is extracted, finally click finish.

Figure 1. 4

7|Page
Now that we have downloaded and extracted the ousb.exe file to the default directory, our final step in
preparing a Windows PC for the OUSB command line interface is to test the program opens
successfully.

Follow the these steps to test the OUSB command line interface
1. open command prompt
2. Type ousb in the command prompt window
3. Press enter
4. You should observer the same output in command prompt as displayed in figure 1.5
5. If you did not get a result similar to that in figure 1.5, redo this section.

Figure 1. 5

You may now delete the zipped folder containing the ousb.exe file from your desktop if you wish.

8|Page
3. Preparing a Linux PC for the OUSB Command Line Interface
Preparing a Linux installation for the OUSB command line is very similar to that of Windows except for
the fact that Linux uses a different file structure, so where you store the ousb.exe file is different.
For a Linux installation the ousb.exe file should be stored at the directory /usr/local/bin as displayed in
figure 1.6, and ensuring the execute permissions are set, you will need root access to complete this.

Figure 1. 6

Finally we need to test that the OUSB command line is working, we do this by opening a terminal, menu
> system > terminals>terminal, and type ousb into the terminal screen and press enter, the OUSB
options window should be displayed as seen in figure 1.5.

4. Preparing an RMIT Linux Live-DVD for the OUSB Command Line


Interface
Preparation of the OUSB Linux Live-DVD is unnecessary as the Linux environment is already set up
with the OUSB command line configured. To test the OUSB command line, open a terminal, menu >
system > terminals>Konsole - Terminal Program and type ousb into the terminal and press enter; the
terminal should output the result as displayed in figure 1.5.

9|Page
5. Testing the OUSB Development Board
Now that you have successfully installed the OUSB executable it is now time to connect the OUSB
development board to a spare USB port of your PC using an A to B USB cable (links provided in
prerequisites). The OUSB development board does not need any specialized drivers; you can just
connect the board to your PC. For those running Vista or Windows 7, the operating system may display a
warning that you have plugged in an unrecognized device, this is standard for the OUSB development
board and there is no need to be concerned about this message.
Once you have attached the board to the USB port you should notice that the power LED lights up, the
power LED is located next to the 8 dip switches in the corner of the board as indicated in figure 1.7.

8 Dip Switches Power LED


Connected to Port C
LED’s Connected to
Port B

Atmega 32
Reset Button

Figure 1. 7

Now that your board connected and the OUSB executable is correctly installed we can test the board to
ensure the OUSB firmware is installed on the Atmega32.

Before conducting the following tests ensure that J10 is shorted and that all of the dip switches are in the
on state as indicated by the dip switches packaging, these are both indicated in figure 1.8.

10 | P a g e
All dip switches on J10

Figure 1. 8

To perform these tests open command prompt on a Windows platforms or open a terminal on a Linux
platforms. Type the following OUSB commands into the terminal screen and compare their results with
the expected terminal responses found in figure 1.10, physical results of the commands which can be
seen on the OUSB development board that are described under each of the commands.

NOTE: The basic tests that you are about to undertake are not too designed to test the full capability of
the OUSB development board but to just perform a few basic operations of the board and to provide you
with a base level introduction. I strongly advise that you have a copy of the OUSB schematic available
(ANNEX C) while performing these tests so that you can identify the devices connected the Atmega32.

Testing the Atmega32 Input/Output (IO) Pins


IO executes commands on the parallel interfaces of the Atmega32. There are four ports on the Atmega32
and each has the capability of being configured as an IO port, however because the OUSB development
board uses PORTD to perform special functions it should not be used for IO applications when using the
OUSB command line.

Please note that I am using hexadecimal input values, you the user can input these values in either
decimal or binary. I believe you should stick with hexadecimal, as it allows you to think in four bits at a
time and proves more efficient when working with 8 bits, which commonly occurs when using a device
like the Atmega32 which uses 8 bits to describe register values, pin states and port states.

ousb io PORTB 0xFF

The effect of this command is to set PORTB of the Atmega32 to hex 0xFF, since each port of the
Atmega32 has 8 pins, 0xFF represents all 8 pins becoming active, as you may have noticed the 8 LED‟s
on the OUSB development board have light up, therefore you can deduce the 8 LED‟s are connected to
PORTB of the Atmega32.

ousb io PORTB

11 | P a g e
This command has no effect on the board itself, but it reads the state of the output pins of PORTB.
ousb io PORTB 0x0F

Now you have set PORTB so that the first four LED‟s will light up and the last four LED‟s will turn off,
this is done by making PORTB the hex value of 0x0F and can be proved by converting the value to
binary, which is simply 0b 0000 1111.

ousb io PORTB 0xF0

Similar to the previous command, we now set PORTB so that the last four LED‟s will light up and the
first four LED‟s will turn off, this is done by making PORTB the hex value of 0xF0 and can be proved
by converting the value to binary, which is simply 0b 1111 0000.

ousb io PINC

Now that we know that PORTB is connect to the LED‟s and are set to output, let us explore PORTC.
PORTC on the Atmega32 is set for input, therefore to read the input value of the dip switches we use the
command ousb io PINC. As you may notice the result of this command is zero, but all of the dip
switches are on, this it because not logic in employed, therefore when the switch is on, zero volts is
present on PORTC for a particular pin you have set to on, resulting in that pin being off, and vice versa.
Therefore turning all switches on results in a decimal value of zero.

Testing the Atmega32 Analogue to Digital Conversion (ADC)


The tests that we perform for the ADC will retrieve the current analogue value of the Light Dependent
Resistor (LDR) and the current analogue value of the Trim Pot in digital form, therefore performing an
analogue to digital conversion. Both of these components can be found in figure 1.9.

Trim Pot

Light Dependent Resistor

Figure 1. 9

12 | P a g e
ousb adc 6

This command retrieves the digital value of the LDR and displays its result as a 10-bit binary value, or in
the range of zero to 1023. Therefore exposing the LDR to light will decrease its value and hiding it from
light will increase its value. (Your result may not match the value in figure 1.10)

ousb adc 5

The other ADC that we test is the trim pot, this is simply a 10K ohm variable resistor with 5 volts on one
side and ground on the other, the ADC reads the tapped of value of the pot, this value can be adjusted by
adjusting the tap position with a screw driver. (Your result may not match the value in figure 1.10)

Testing the Atmega32 Pulse Width Modulation (PWM)


PWM is an operation performed by specific pins of the Atmega32 to output a square wave with a constant
or varying duty cycle. Note we will be only testing PWM 1 which is located at pin 4 of the Atmega32, or
LED 3 attached to PORTB and will vary the brightness of the LED attached.

ousb pwm-freq 1 1000

The Atmega32 can only achieve certain frequencies that depend on its input clock; therefore this
command asks the Atmega32 to set PWM 1 to a frequency near 1000 Hz.

ousb pwm 1 10

We now will start off with a very dim LED at PORTB pin 3 by setting the duty cycle to 10%.

ousb pwm 1 50

The same LED will now become brighter by setting the duty cycle to 50%.

ousb pwm 1 100

Finally we have set the LED to its maximum brightness by setting the duty cycle to 100%.

ousb pwm 1 0

Finally we have set the LED to its minimum brightness to allow the PWM to be turned off.

13 | P a g e
Figure 1. 10

6. Command Line Interface Directives


The figure 1.11 displays the command line directives, there are many more advanced directive that call
interrupts and registers, which fall into the final box of the io branch. These will not be discussed in this
chapter, but will be introduced in chapter 3 using the C programming language.

14 | P a g e
ousb
- Prints help information

io pwm adc ousb -multi


- set io registers - set PWM - reads the adc pin value - connects multiple
commands for a single
exectution
DDRx ‘Value’
-freq
- set io port x as - reads the digital
- set PWM frequency
an input or output value of the
- must be set prior to
- x is the port selected ADC
using PWM
identifier, ‘commands’
a, b, c or d. quit
- ousb is not needed for
individual commands
‘Value’ ‘Value’ - terminates on quit.
- convert decimal to 8 - select which PWM
bit binary or hex - 1,2, or 3
- pin = 0 pin =input 1=OC0 PB3, pin 4
-pin =1 pin =output 1=OC1A PD5, pin 19
1=OC1B PD4, pin 18

PORTx
- x is the port
identifier,
a, b, c or d. ‘Value’
-When port is - desired frequency
output, acts as a - actually frequency
write command will be closest
- when port is available
input, sets input to
pull up mode or
high z mode

‘Value’ ‘Value’
- sets the output - select which PWM
port pins - 1,2, or 3
1=OC0 PB3, pin 4
1=OC1A PD5, pin 19
PINx 1=OC1B PD4, pin 18
- read port value
- use when port is
an input
- x is the port
identifier,
a, b, c or d. ‘Value’
- set duty cycle

Atmega32
Register values.
Can be found in
data sheet,
Advanced users
only

Figure 1. 11

The remainder of this section will be dedicated to explaining figure 1.11 and demonstrating how it can be
used to perform specific commands on the Atmega32.

15 | P a g e
Before starting we must cover the base options first, the base options determine to what base a value will
be returned to the command line, please read the following which is and extract from the Open-USB-IO
Reference manual.

Base options: any ousb command that results in an output can have a base option put
Immediately after the ousb command-
• No option: decimal
• -b : print output in binary
• -h : print output in hexadecimal
• -r : just print the decimal value without other text, useful for script files

Therefore using the base options in your OUSB command line directives you can create useful actions
with the Atmega32 which can output to real hardware and return a value in many different formats to
software, thus making life simpler when working with the OUSB development board and its command
line interface.

Examples of base options:

ousb io PORTB 0x55

This command will return a result in form of the no option format, which is simply the decimal value of
hexadecimal 0x55, which is 85 and therefore the result is PORTB = 85.

ousb –b io PORTB 0x55

This command will return a result in binary format, which is the binary value of hexadecimal 0x55, which
is 0b01010101 and therefore the result is PORTB = 0b01010101.

ousb –h io PORTB 0x55

This command will return a result in hexadecimal format, which is simply the input 0x55, therefore the
output is PORTB = 0x55.

ousb –r io PORTB 0x55

This command will return a result in decimal format without the preceding string, which is the just
decimal 85.

16 | P a g e
To understand how we can modify the conditions of each port, first you must understand the power up
conditions of the OUSB development board and what individual pins cannot be accessed as they
perform special functions, such as USB communications or RS-232 communications. In addition to the
previous the Atmega32 also has limitations, where only certain ports and pins can perform certain
functions, this information will be briefly described but detailed information can be found in the
Atmega32‟s datasheet.

The power up state information is provided in the table below and describes that PORTA is initially setup
for ADC conversions, PORTB is setup for IO output, PORTC is setup for IO sensing or input and
PORTD has very limited availability due to its connections to hardware on the OUSB development
board and therefore is not recommended to be changed.

IO Command Line Directives


If you observe the first branch of figure 1.11 you will notice that only io commands are available. So what
is io?
io stands for input/output and it is exactly just that, you can set any of the four ports of the Atmega32 so
that they are either all input, all outputs or a combination of both, as stated PORTD should not be
modified using OUSB commands as it provides special functionality on the OUSB development board.
DDRx in the io branch stands for Data Direction Register, and its value for a specific port determines
whether that port is an input, an output or a combination.

17 | P a g e
For example:
 To change DDRB so that all pins are inputs rather that an output we would type:

ousb io DDRB 0x00

 To change DDRB back so that all pins are outputs rather that an input we would type:

ousb io DDRB 0xFF

 To change DDRB so that the first four pins are outputs and the last four pins input we would
type:

ousb io DDRB 0xF0

Now that we have seen how to set the io state of a port let us explore further down the tree to PORTx.
This command has different functions depending on whether the port is set as an output or input. Let us
investigate its implementation when the port is an output.

When a port is set as an output, the PORTx command acts as a write function, writing to the value to a
given IO port described in the command.
For example:
 Set an output port such that the first and last pins are high and the rest are low, you would type:

ousb io PORTB 0x81

 Set an output port such that the first pin is high and every second pin after that is high (or every
red LED on the OUSB development board) you would type:

ousb io PORTB 0x55

However when the port is set to input the PORTx command performs an entirely different function than
the write command described above. Input ports have an additional configuration option where the port
can be put in a high impedance state or in a pull up mode. To enable the input port to read applied
voltages we must set the input port to the pull up mode.
For example:
 Set up an input port such that it is in the high impedance state, you would type:

ousb io PORTC 0x00

 Set up an input port such that it is in the pull up mode, you would type (this is the setting
typically used):

ousb io PORTC 0xFF

18 | P a g e
The final io command discussed in the chapter is the PINx command, for an io port this command is
considered to be the read command, and reads the current state of the pins of a port whether it is
configured as an output or input. Since PORTB is configured as an output and PORTC is configured as
an input we can use the PINx command to find the current states of both.
For example:
 Find the current state of PORTB, note this will be 85 because of your last write command to
PORTB, hence 85 is decimal for hexadecimal 0x55.

ousb io PINB

 Find the current state of PORTC, the result of this command depends entirely on the state of the
dip switches, as you will notice, on the OUSB development board the dip switches are labeled 0
to 7, set them to any combination and determine the decimal value of the dip switches, and
compare your expected result with actual result.

ousb io PINC

Was your expected result correct? If not, remember on is LOW and off is HIGH.

NOTE: the DDRA command can interfere with ADC operations, so before any executing any ADC
operations either reset the board or set DDRA back to all inputs.

PWM Command Line Directives


The PWM is a significant device; it is relatively simple in the fact that it is just a square wave of which
you have the ability to change its duty cycle at any point in time by the means of sending a simple
command. However the practical uses of the PWM are more complicated and are beyond the scope of this
manual, but by filtering the output of the PWM you can capture the time average of the PWM signal;
hence create a digital to analogue conversion.
This manual demonstrates the PWM by applying the square wave produced to an LED, resulting in a time
averaging of the PWM signal through the LED which is physical shown by the light intensity of the LED.
If the duty cycle of the PWM is 100% the LED will be bright because the LED is constantly on, however
if the duty cycle is reduced to 50%, then the LED will be dulled because for half of the period of the
PWM signal applied to the LED will be in an off state.

Before we can use the PWM with the command line we must first set the PWM frequency. Referring
back to figure 1.11, in the PWM branch you can see the first command is pwm–freq (no space).
This is the command that sets the PWM frequency. This frequency is totally dependent on the PWM used
and the clock speed of the Atmega32, because the OUSB development board uses a clock of 12MHz his
frequency is partly dependent on 12MHz. The following provides the available PWM frequencies
available on the OUSB development board.

19 | P a g e
PWM 1, located at PORTB 3, pin 4
The available frequencies are very limited and any command line input will round to its nearest available
frequency. (Values provided for PWM 1 are approximate and may differ on each board)

PWM 1 , PB3 , pin 4


Lowest Available Freq 47.7 Hz
183.1 Hz
732.4 Hz
5859.4 Hz
Highest Available Freq 46875 Hz

PWM 2, located at PORTD 5, pin 19


The available frequencies for this PWM differ dramatically from PWM 1 proving it more capable. PWM
2 has a frequency range from 183 Hz to 3 MHz, however not every precise frequency is available due the
Atmega32 being a digital device, however the device will round to the nearest possible value that it can
obtain. Typically very close if not exactly the frequency that you have requested.

PWM 3, located at PORTD 4, pin18


This is exactly the same as PWM 2 and has a frequency range of 183 Hz to 3 MHz.

Examples of setting the PWM frequency:


 Setting PWM 1 to 47.7 Hz

ousb pwm-freq 1 47

Setting the frequency of the PWM is all you have to do for the PWM to become active, now set the
desired duty cycle of the PWM and you will have a working PWM.

Example of using PWM 1:


 Since we have configured PWM 1 to run at 47 Hz we can now turn the LED on at PORTB 3 by
setting PWM 1 to 100% duty cycle:

ousb pwm 1 100

 We can now dim the light by setting the duty cycle to a value lower than 100%, for effect lets set
it to 25%

ousb pwm 1 25

By visual inspecting LED 3 you may be able to visually detect the light flicking; this is due to the duty
cycle causing the light to turn on and off every period.

20 | P a g e
To deactivate the PWM so that it can be used for io operations we need to set the PWM to zero duty
cycle.

ousb PWM 1 0

ADC Command Line Directives


ADC command accesses the Analog to Digital capability of the Atmega32 that is available on PORTA.
As stated by the name it simply takes an analogue input and converts it to a digital value.

Because the Atmega32 is a digital device it can only read analogue values between 0 volts to 5 volts.
Therefore it has a voltage range of 5 volts and is quantized or approximated into 1024 levels, thus making
level 1023 approximately 5 volts and level 0 approximately 0 volts.

To determine the voltage resolution or difference between each level we can use the following formula:

NOTE: any input over 5 volts will result in the input being saturated and record as a 5 volt input or 1023.

For the OUSB development board two ADC are connected to provide ADC functionality without
having to configure any hardware, making ADC implementation simple. These pre-fitted ADC devices
are a trim pot connected to ADC 5 and a Light Dependent Resistor (LDR) fitted to ADC 6. Find them on
the schematic diagram (Annex C), you will see that one side is VCC (5v) and the other is 0v, providing a
voltage range of 5 volts. This means that these ADC devices have the capability of providing ADC inputs
from level 0 to level 1023.

As for the OUSB ADC command line directives they provide read functionality to the user to read the
digital value of an analogue input at any point in time.

Examples of ADC 5 and ADC 6:


 ADC 5 is connected to the trim pot and is located in the centre of the OUSB development board.
The digital value of the trim pot can be adjusted by simply turning the pot; you will notice turning
the pot fully clockwise will generate an ADC output of 1023, or 5 volts. While turning the pot
fully anti-clockwise will result in the ADC output of 0, or 0 volts.

ousb ADC 5

 An LDR is a resistor whose value is proportional to the amount of light it is receiving. Therefore
exposing the LDR to a bright light will result in the voltage sensed by the ADC to be low.
Obviously exposing the OUSB development board to a dark environment (note LED‟s will
effect reading) the voltage sensed by the ADC will increase, resulting in a values close to 1023.

ousb ADC 6

21 | P a g e
NOTE: the DDRA 0xFF command effects the operation of the ADC, this is either overcome by setting
the PORTA pins need for ADC to input mode, or simply reset the board as a reset will set the board up
for ADC operations.

7. Introduction to Combining Command Line Directives


The remaining branch in figure 1.11 is a method of executing multiple OUSB command line directives
in one command.

-multi
The –multi command is relatively simple, it is declared and followed by multiple commands that are to
be executed and is terminated by the keyword quit.

Example of –multi:

ousb –multi io PORTB 0x55 io PORTB 0xFF io PORTB 0x00 quit

Results in:

PORTB = 85
PORTB = 255
PORTB = 0

Multiple commands may be effective, but there is simply a better way, and that is by using script files.
However script files in windows are rather limited and are called Batch files. Those using Linux are
luckier as Linux provides a script file language called BASH script. BASH script will allow you to test
conditional statements and perform loops similar to that of the C language.

8. Combining Command Line Directives in Batch script files (Windows


users)
Batch files are very simple, by the fact that you simply create a text file full of command with notepad,
and save the file with the batch file association .bat. This now tells a Windows PC that this is a file of
commands to be executed in the command line.

Since the functionality of batch files is limited this manual will only display one example of how these
types of files can be used with the OUSB command line interface.

The example that we will demonstrate teaches you how to combine the tests that we performed early in
section 5 of this chapter to create a simple test batch file for the OUSB development board.

First let‟s direct a window to the command lines default directory that we found in section 2.
Note: my default directory on my windows XP system is C:\Documents and Setting\ Troy.

Next right click on this window and select New>Text File as shown in figure 1.12 and open it.

22 | P a g e
Figure 1. 12

Now type the following commands into the new text document:

ousb io PORTB 0xFF

ousb io PORTB

ousb io PORTB 0x0F

ousb io PORTB 0xF0

ousb io PINC

ousb adc 6

ousb adc 5

ousb pwm-freq 1 1000

ousb pwm 1 10

ousb pwm 1 50

ousb pwm 1 100

ousb pwm 1 0

23 | P a g e
We are now ready to convert this text file into a batch file, to do this we select File>Save As, and save the
file as ousbtest.bat.

You should now see an icon similar to one of those displayed in figure 1.13 (left is an XP icon the right is
a Windows 7 icon). Now to test the OUSB development board ensure that it is connected by a USB
cable to your PC, open command prompt then type „ousbtest‟ into the command prompt window and
press enter. You should get the same results as in figure 1.10.

Figure 1. 13

9. Combining Command Line Directives in BASH script files (Linux


users)
BASH scripts are a method of combining command line directives in a file that is executable by a
terminal. BASH can be a very powerful tool for executing command line statements, because BASH
provides loop, conditional statements and variables, which means that you can create a script that will
execute commands a lot quicker than actually having to type every individual command.
However there is a downside to them, which is that the BASH language doesn‟t provide any significant
means of error checking or fault indication, thus making it not an entirely simple language to use.

This section should be treated as an overview on BASH script programming and an introduction of how
you can incorporate its use with OUSB command line directives, to create small yet efficient programs.

The following link provides a very basic introduction if you wish to learn some BASH programming
before we develop some short and simple BASH scripts.
http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO.html

Before we start our first BASH script we must cover some basics:
 The first line must begin with „#!/bin/bash‟.
 The OUSB command line must be located in „/usr/local/bin‟.
 It is helpful to use „set –u‟ which will ensure variables are not auto declared.
 Variables have no data type
 Variables are declared by name then assignment operator, „var_name=‟
 To use a variable in a statement you must use the $ operator, „$var_name‟
 The „echo‟ command outputs to the terminal echo “hello World”.

To start off with let us group the tests that we performed in section 5, so that we can automate our
previous tests in a simple executable BASH script.

24 | P a g e
Go to /home/user/Documents, or any other convenient directory where you have RWX permission on
your Linux installation.
This manual will demonstrate BASH script files using the directory /home/user/Documents. Right click
and create a new text file and name it ousbtest as demonstrated in figure 1.14.

Figure 1. 14

You now need to set permission, right click on the file you just creates and select properties from the
drop list, once the properties window appears select the Permissions tab and set the Is Executable box
and the click Ok, as shown in figure 1.15.

Figure 1. 15

25 | P a g e
Before we can start our BASH script you need to open the text file, to do this simply right click on the
ousbtest file from the drop list select Open With > KWrite.
You are now ready to develop your first BASH script. Next type the following into the text file:

#!/bin/bash
ousb io PORTB 0xFF

ousb io PORTB

ousb io PORTB 0x0F

ousb io PORTB 0xF0

ousb io PINC

ousb adc 6

ousb adc 5

ousb pwm-freq 1 1000

ousb pwm 1 10

ousb pwm 1 50

ousb pwm 1 100

ousb pwm 1 0

Now form the directory where your ousbtest file lives, /home/user/Documents, press F4 and bring up a
terminal and type ./ousbtest. The reason why we need the „./‟ before our file is to let the terminal know to
find the ousbtest file in our current directory.

Your terminal response should look like the result in figure 1.16.

26 | P a g e
Figure 1. 16

Now that you have created a very simple but effective BASH script, the next section will provide some
more capable example of the use of BASH script programming with the OUSB command line.

27 | P a g e
10. Bash scripts mini projects (Linux Only)
LED BOUNCE
#!/bin/bash

#----- stop auto declaration of variables.


set -u
#----- LED Bounce, ctrl-C to stop.

Delay=0.01

# Forever Loop
until [ 0 != 0 ]
do
# For loop to control forward bounce
for i in 1 2 4 8 16 32 64 128
do
ousb io PORTB $i
echo " LED Output = $i"
sleep $Delay
done

# For loop to control backward bounce


for i in 64 32 16 8 4
do
ousb io PORTB $i
echo " LED Output = $i"
sleep $Delay
done

done

28 | P a g e
LED READ DIP SWITCH
#!/bin/bash
set -u

#------ Read the Dip Switches and write to the LEDs.


Write=
until [ 0 != 0 ]
do
sleep 0.01
# read the dipswitch
Write=$(ousb io pinc)

# write the dipswitch value to the LEDs


let "Write = Write"
ousb io PORTB $Write
done

29 | P a g e
LED READ TRIM PORT
#!/bin/bash
set -u

#------ Read the Trimpot and write to the LEDs.


Write=

# Forever Loop
until [ 0 != 0 ]
do
sleep 0.01

# Read the Trimpot value


Write=$(ousb adc 5)

# Write the Trimpot value to the LEDs


let "Write = Write/4"
ousb io PORTB $Write
done

30 | P a g e
LED PWM READ DIP SWITCH
#!/bin/bash
set -u

#------ Read the Dip Switches and write to the PWM.


Write=
x=

# Setup PWM 1
ousb io portb 0
ousb pwm-freq 1 45

# Forever Loop
until [ 0 != 0 ]
do
sleep 0.01

# Read the Dip Switches


Write=$(ousb io pinc)
let "x = Write"

# Perform a float mathematical operation


# to convert the dip switch value to a percentage
Write=$(echo "scale=3; ($x / 255)*100" | bc)

# Write the dip switch value to PWM 1


ousb pwm 1 $Write

done

31 | P a g e
LED PWM READ TRIM POT
#!/bin/bash
set -u

#------ Read the Trimpot and write to PWM.


Write=
x=

# Setup PWM 1
ousb io portb 0
ousb pwm-freq 1 45

# Forever loop
until [ 0 != 0 ]
do
sleep 0.01

# Read the trimpot


Write=$(ousb adc 5)
let "x = Write"

# Perform a float mathematical operation


# to convert the dip switch value to a percentage
Write=$(echo "scale=3; ($x / 1023)*100" | bc)

# write the trimpot value to PWM1


ousb pwm 1 $Write

done

32 | P a g e
USART
#!/bin/bash
set -u

#------ Initialize ports and the uart.


DDRD=$(ousb -r io DDRD)
let "DDRD = (DDRD & 0xFE) | 2" # TX to output, RX to input.
ousb io DDRD $DDRD

ousb io UBRRL 75 # baud rate to 9600 baud.


UCSRB=$(ousb -r io UCSRB)
let "UCSRB = UCSRB | 0x18" # Enable TX and RX.
ousb io UCSRB $UCSRB

#------ Loop to receive, add one, and transmit back.


while [ 0 == 0 ]
do
#--- wait for RX of byte.
UCSRA=0
while [ $UCSRA == 0 ]
do
UCSRA=$(ousb -r io UCSRA)
let "UCSRA = UCSRA & 0x80"
done
#--- get received byte, incr, and send.
UDR=$(ousb -r io UDR)
let "UDR = UDR + 1"
ousb io UDR $UDR

done

33 | P a g e
11.Creating C++ programs that interact with the OUSB Command line
interface
Congratulations on making it to the final topic in chapter one, this section will focus on how you can
create C++ programs that will run on a host desktop and control the OUSB development board to
perform useful commands by running an executable program. This method of programming can be highly
effective as C++ is a more capable programming language than those previously covered, as the C++
standard ensures that certain tests are carried out during the compilation of executables which makes
mistakes easier to find and correct.

I strongly recommend you install the Eclipse IDE as this is the IDE that the manual was created for and
all codes have be written specifically for this IDE. The Eclipse C/C++ IDE is available in both Linux and
Windows, for Windows users the installation information needed is available in ANNEX A.
Unfortunately for Linux users because RMIT provides a LIVE-DVD of PC Linux OS 2009 with Eclipse
installed and setup, only some general information is located in ANNEX B to assist existing Linux users.
Those Linux users using the RMIT LIVE-DVD as previously stated are lucky enough to have the Eclipse
IDE already installed and ready to go, it is located at Menu>More
Applications>Development>Development Environments>Eclipse.

Before we get into programming we first need to discuss some fundamental information that will allow
your C++ programs to access the command line interface. These fundamental are pipes, system calls,
sprint() and fgets().

PIPES
A pipe is a method of outputting or inputting via a command, rather than the stand methods of outputting
to a terminal or inputting from the key board. Pipes are referred to as uni-directional, therefore a single
pipe call must be read-only or write-only, never both. The read only operation seems odd at first, because
if you execute a command for the OUSB command line interface, by definition, for read only you would
expect a result to be returned by the function with no action. This is not the case, if you open a pipe, in
read-only mode you will actually execute a command and whatever the return result from that command
will then be buffered into your program and no output will be sent to the standard output. If we use this
information to describe the write-only pipe, the write-only pipe will write a command and will expect no
return value from the OUSB development board, however the board will always respond to a command.
So since this response cannot be returned to the write-only pipe, it must be returned to the standard
output, or command line, resulting in an unexpected result on the command line. As you can see, read-
only or write-only pipes both do the same job, I recommend using write-only pipes for testing and read-
only pipes for final development so that only important information is returned to the command line.

How do you create a pipe?


All the headers needed to create pipes belong in:

#include <iostream>

34 | P a g e
Pipes work with FILE pointers; therefore we must declare a FILE pointer first:

FILE *fp;

Now that we have our FILE pointer we can now use it with the popen() function:

fp = popen("command as a string","read or write option");

As you can see, you need to enter your command as a string, therefore “C:\\ousb io PORTB”, as you
know this is the command to read the value of the LED port of the Atmega32, but notice how C drive is
called, this is telling the program to look in directory C for the ousb.exe. Why have I used C drive (This
is a Windows only problem) and not C:\\Documents and Settings\Troy\. The simple answer is because I
could not get it to work. I recommend you copy and paste the ousb.exe file to your C: drive for use with
C++ code, or you may have difficulty accessing the command line interface (Windows users only).
Linux users simply have to enter the desired OUSB command line directive as a string and the operation
will execute with no need to address a specific directory location.

Notice the second string is the read-only or write-only option:


 Read-only is selected by the string - “r”
 Write-only is selected by the string - “w”

Note: The read and write string are very particular and are not characters, but a string in double quotation
marks.

Directly after the pipe has been used it must be closed, if you do not close your pipes and to many become
open due to iterative processes you risk vulnerability and your program could possibly crash. So once you
are finished with your pipe ensure you close it.

pclose(fp);

System calls
System calls are a much easier method of sending OUSB command line directives to the board;
however they are much slower and provide no option to suppress the OUSB returned value.

As you would expect, the method to call them is very simple, a string is used exactly the same way as in
the popen() command, where Windows users must assign the path of the ousb.exe file and Linux users
need only specify the command. This string is placed in the parameter list of the system() function.

system("command as a string");

system() simply writes the command to a terminal and executes the command as though it were just typed
in.

35 | P a g e
FGETS
Fgets is a function that takes the returned value of a stream and stores the value in a character string. For
your use, fgets will take the returned value of a read-only popen() operation and store the stream value in
a character array.

fgets(char_array, sizeof char_array, fp);

The following implements this using the pipes return value of the command ousb io PORTB 0xFF,
where the return value is buffered into a character array which is then outputted to the standard output via
the program. REMEMBER Linux users do not use C:\\, it is for windows users only.

#include <iostream>
using namespace std;

int main()
{
char char_array[100];
FILE *fp;
fp = popen("C:\\ousb io PORTB 0xFF","r");
fgets(char_array, sizeof char_array, fp);
pclose(fp);

cout<<char_array<<endl;

return 0;
}

SPRINTF
This function is very similar to printf, in that it creates a formatted output, except printf outputs to the
standard output and sprintf outputs to a string.

The standard form of sprint is:

sprintf(output, "string + tags", input1, input2);

Where „output‟ is a character array large enough to hold the result of the string at the second parameter
and all of the appended inputs, together combine to create one formatted character array.

The second parameter for sprintf is a string that may contain formatting flags. The formatting flags are
signified in a string by a preceding percentage symbol. Below is a list of some available formatting
options.

Symbol Formats
%c Character
%d or %i Signed decimal integer
%e Scientific notation with lower case e
%E Scientific notation with upper case E

36 | P a g e
%f floating point
%g Use the shorter of %e or %f
%G Use the shorter of %E or %f
%o Signed octal
%s String of characters
%u Unsigned decimal integer
%x Unsigned hexadecimal integer
%X Unsigned hexadecimal integer (capital letters)

The final parameters are the inputs that relate to the formatting flags in the second parameter, these input
data types need to match the assigned formatting flags previously described. The inputs need to be in the
correct order and quantity as you describe in the string of the second parameter.

Below is an example of formating a character array called „output‟ with a string and an integer. This
formatted array is then used in a write-only pipe which writes the command ousb io PORTB 255 and
will get the result PORTB = 255 returned. Again note Linux users must not add C:\\.

#include <iostream>
using namespace std;

int main()
{

char output[100];
char char_input[100] = "C:\\ousb io PORTB ";
int val_input = 255;

sprintf(output, "%s%d", char_input, val_input);


FILE *fp;
fp = popen(output,"w");
pclose(fp);

return 0;
}

37 | P a g e
Now that you have been introduced to some methods of accessing to the OUSB command line
directives via C++ programming, it is now time to introduce you to the Eclipse IDE and how to configure
the IDE so that you can create C++ programs.
Please take note of the minor differences between the Linux version and the Windows version of Eclipse,
they are only minor but all of the following is performed in Windows, however I clearly note the
differences by the use of, LINUX USERS.

ALSO NOTE THAT I HAVE RECOGNISED A REOCURRING PROBLEM WITH THE


EXECUTABLE BECOMING LOCKED UP, WHICH CAUSES AN ERROR WHERE YOU
CANNOT BUILD YOUR PROJECT. IF THIS OCCURS SIMPLY SELECT PROJECT FROM
THE TOOLBAR, AND FROM THE DROP LIST SELECT CLEAN TO DELETE ALL FILES
AND REBUILD.

1. Open Eclipse
a. Linux, menu> More Applications>Development>Development
Environments>eclipse
b. Windows, by the shortcut that has been created on the desktop.

2. You may be presented with a warning in Windows asking if you wish to open this program, if
you accept the warning click the appropriate button the proceed.

3. You will then be asked to create a workspace, in Eclipse a workspace is a directory you would
like to work from. This workspace will be created if it does not exist, and if you select an
existing workspace Eclipse will load any existing projects in that workspace. However for now
just select ok, this is displayed in figure 1.17.

LINUX USERS: note that your directory structure for the default workspace is
/home/user/workspace.

Figure 1. 17

38 | P a g e
4. Your first action in developing your program is to open a new C++ project. This is done by
selecting File > New > C++ Project, as shown in the figure below, figure 1.18.

LINUX USERS: note that your welcome page looks different, but the actions are the same.

Figure 1. 18

39 | P a g e
5. Your next step is to name the new project as LED_Write and select the project as an Executable
C++ project as shown in figure 1.19. By selecting the Hello World C++ Project the compiler
will automatically insert the standard header and namespace. Once this is done select Next.

Figure 1. 19

6. The next screen will allow you to add some comments to your code that will be assigned by the
IDE. When you are happy with your comments select Next.

7. Finally before the project is created by Eclipse you need to select whether you wish to create
Debug and Release versions. Both selected is fine, make your choice and select Finish.

40 | P a g e
8. This will differ between users depending on what steps you have been taken, but you may be at
the Eclipse welcome window displayed in figure 1.20, if you are simply click on the workbench
icon circled in red.

LINUX USERS: note that your welcome page looks different, but the actions are the same.

Figure 1. 20

41 | P a g e
9. You should now be at the workbench and in the right hand side of the workbench you will see
the project explorer tab. In this tab you will see the LED_Write project folder that you have just
created, expand the project folder to LED_Write > src > LED_Write.cpp, now double click on
LED_Write.cpp to open the source file in the text window of Eclipse, as shown in figure 1.21.

Figure 1. 21

10. Note: for Windows users ensure that you have the ousb.exe file located in your C drive, and
Linux users remember not to add any reference to the C drive before any OUSB command line
directives or you will have errors in compilation.

11. I recommend that you set the following project preferences so that the project will auto save
before building each time; I have found that I have to do this every time I open Eclipse as it does
not auto save many of your preference options. This can be done by selecting Window >
Preferences from the menu bar, then expand General >Workspace, you should then tick the
third option down which is Save automatically before build as shown in figure 1.22.

42 | P a g e
Figure 1. 22

12. Another preference you may be interested in is turning on line numbers, this can be done again by
selecting Window > Preferences from the menu bar however the line numbers option is found
by expanding General > Editors > Text Editor, form there select the fourth option down as
shown in figure 1.23.

Figure 1. 23

43 | P a g e
13. Now that the environment is setup lets create a C++ program that will write to the LED port of
the Atmega32, PORTB from user inputs.

14. The following C++ code program was developed as an introduction; feel free to modify it, as it
has several problems, mainly in the form of error checking the input.
LINUX USERS: note that in #define OUSB that the file path is incorrect, you need to remove
the C:\\ when creating your code in Linux.

#include <iostream>
using namespace std;
#define INPUT_SIZE 4
#define OUTPUT_SIZE 100
#define MAX 255
#define MIN 0
#define OUSB "C:\\ousb io PORTB "
int main()
{
FILE *fp;
char input[INPUT_SIZE];
char output[OUTPUT_SIZE];
int test;

while(1)
{
cout<<"Input a value between zero and 255, q to quit:"<<endl;
cin>>input;

if(input[0]== 'q')
{
cout<<"Bye"<<endl;
return 0;
}

test = atoi(input);
if(test < MIN || test > MAX)
{
cout<<"Input Error"<<endl;
continue;
}

sprintf(output, "%s%s", OUSB , input);


fp = popen(output,"w");
pclose(fp);

}
return 0;
}

What does this program do? To start off with we set numerous constants using #define
statements, which defines the sizes of the input character array, the output character array, test
parameters and lastly the string to be used with sprint() to create our OUSB command line
directive to be used in a pipe. The operation of this program resides in a forever loop and outputs
a user input to the program to the OUSB development board‟s LED‟s.

44 | P a g e
15. Once you have typed the code into the text window of the IDE, you are ready to build your
program. To do this, you need to highlight the LED_Write folder in the project explorer tab, and
then click on the Hammer icon to build your program. Finally any errors will be flagged in the
problems tab below the text editor window. This all can be seen in figure 1.24.

Figure 1. 24

45 | P a g e
16. The final step in creating your program is to test it; this can be done directly from the IDE by
clicking on the Run icon, which is signified by the play symbol on a green circle. Once the Run
button has been pressed the IDE will respond by changing the tab below the text editor to the
Console tab. In this console tab will display exactly what would be seen in any terminal window
if you were to run you program in a terminal. You can now place the cursor in the Console tab
and type in your desired user input between zero and 255, and see it displayed on the LED‟s of
the OUSB development board.

Figure 1. 25

46 | P a g e
12.C++ driven OUSB command line mini projects

LED_BOUNCE
#include <iostream>
#include <unistd.h>

using namespace std;

// Hash Define Constants


#define OUSB "C:\\ousb io PORTB "
#define DELAY 500
#define OUTPUT_SIZE 100

// Global Variable
char output[OUTPUT_SIZE];

// PORT B Write Function


// This function writes the integer value input
// to the LEDs of the OUSB Board
void PORTB_WRITE(int input)
{
FILE *fp;
sprintf(output, "%s%d", OUSB , input);
fp = popen(output,"w");
pclose(fp);
}
int main()
{
int i = 0; // Initialise the counter
while(1) // Forever Loop
{
// Bounce the LEDs forwards
for(i = 1; i <= 128; i=i*2)
{
PORTB_WRITE(i);
usleep(DELAY);
}

// Bounce the LEDs backwards


for( i = 64; i > 1; i -= i/2)
{
PORTB_WRITE(i);
usleep(DELAY);
}
}

return 0;
}

47 | P a g e
LED READ DIP SWITCH
#include <iostream>
using namespace std;

// Hash Define Constants


#define OUSB "C:\\ousb io PORTB "
#define OUTPUT_SIZE 100

// Global Variable
char output[OUTPUT_SIZE];

// PORT B Write Function


// This function writes the integer value
// to output to the LEDs of the OUSB Board
void PORTB_WRITE(int input)
{
FILE *fp;
sprintf(output, "%s%d", OUSB , input);
fp = popen(output,"w");
pclose(fp);
}

// PORT C Read Function


// This function reads the integer value input
// on the dipswitches of the OUSB Board
int PORTC_READ()
{
FILE *fp;
int value;
char PORTC_VAL[4];
fp = popen("C:\\ousb -r io pinc","r");
fgets(PORTC_VAL, sizeof PORTC_VAL, fp);

value = atoi(PORTC_VAL);

pclose(fp);
return value;
}

int main()
{
// Buffer, transfers read data to write data
int data;

while(1) // Forever Loop


{
data = PORTC_READ();
PORTB_WRITE(data);
}
return 0;
}

48 | P a g e
LED READ TRIM PORT
#include <iostream>
using namespace std;

// Hash Define Constants


#define OUSB "C:\\ousb io PORTB "
#define OUTPUT_SIZE 100

// Global Variable
char output[OUTPUT_SIZE];

// PORT B Write Function


// This function writes the integer value
// to output to the LEDs of the OUSB Board
void PORTB_WRITE(int input)
{
FILE *fp;
sprintf(output, "%s%d", OUSB , input);
fp = popen(output,"w");
pclose(fp);
}

// Read ADC 5 Function


// This function reads the 10 bit value
// of ADC 5 which is connected to the Trimpot
double TRIMPOT_READ()
{
FILE *fp;
int value;
char TRIMPOT_VAL[5];
fp = popen("C:\\ousb -r adc 5","r");
fgets(TRIMPOT_VAL, sizeof TRIMPOT_VAL, fp);

value = atoi(TRIMPOT_VAL);

pclose(fp);

return value*0.2493; // convert 10 bits to 8 bits


}

int main()
{
// Buffer, transfers read data to write data
int data;
while(1) // Forever Loop
{
data = (int)TRIMPOT_READ();
PORTB_WRITE(data);
}

return 0;
}

49 | P a g e
LED PWM READ DIP SWITCH
#include <iostream>
using namespace std;

// Hash Define Constants


#define OUSB "C:\\ousb PWM 1 "
#define OUTPUT_SIZE 100

// Global Variable
char output[OUTPUT_SIZE];

// Write PWM Function


// This function writes a percentage of the
// dipswitches turned on to the PWM
void PWM_WRITE(int input)
{
FILE *fp;
sprintf(output, "%s%d", OUSB , input);
fp = popen(output,"w");
pclose(fp);
}

// PORT C Read Function


// This function reads the integer value input
// on the dipswitches of the OUSB Board
int PORTC_READ()
{
FILE *fp;
int value;
char PORTC_VAL[4];
fp = popen("C:\\ousb -r io pinc","r");
fgets(PORTC_VAL, sizeof PORTC_VAL, fp);

value = atoi(PORTC_VAL);

pclose(fp);
return value*0.39; // Reduce 8 bit value to a percentage of 8 bits
}

int main()
{
// Buffer, transfers read data to write data
int data;

// Initialise the PWM


system("ousb pwm-freq 1 1000");

while(1) // Forever Loop


{
data = PORTC_READ();
PWM_WRITE(data);
}

return 0;
}

50 | P a g e
LED PWM READ TRIM POT
#include <iostream>
using namespace std;

// Hash Define Constants


#define OUSB "C:\\ousb PWM 1 "
#define OUTPUT_SIZE 100

// Global Variable
char output[OUTPUT_SIZE];

// Write PWM Function


// This function writes a percentage of the
// Trimpot to the PWM
void PWM_WRITE(int input)
{
FILE *fp;
sprintf(output, "%s%d", OUSB , input);
fp = popen(output,"w");
pclose(fp);
}

// Read ADC 5 Function


// This function reads the 10 bit value
// of ADC 5 which is connected to the Trimpot
double TRIMPOT_READ()
{
FILE *fp;
int value;
char TRIMPOT_VAL[5];
fp = popen("C:\\ousb -r adc 5","r");
fgets(TRIMPOT_VAL, sizeof TRIMPOT_VAL, fp);

value = atoi(TRIMPOT_VAL);

pclose(fp);

return (value*0.2493)*0.3922;
}

int main()
{
// Buffer, transfers read data to write data
int data;
// Initialise the PWM
system("C:\\ousb pwm-freq 1 50");

while(1) // Forever Loop


{
data = (int)TRIMPOT_READ();
PWM_WRITE(data);
}
return 0;
}

51 | P a g e
USART
#include <iostream>
using namespace std;

// Hash Define Constants


#define OUTPUT_SIZE 100

// Global Variables
int UCSRA;
int TX_DATA;
int RX_DATA;
char UCSRA_char[5];
char RX_char[5];
char output[OUTPUT_SIZE];
FILE *fp;

// Initialise USART
void init()
{
int value;
char DDRD[5];
char UCSRB[5];

// Activate Transmit and Receive


fp = popen("C:\\ousb -r io DDRD","r");
fgets(DDRD, sizeof DDRD, fp);
value = atoi(DDRD);
value = (value & 0xFE) | 2;
pclose(fp);

sprintf(output, "%s%d", "C:\\ousb io DDRD " , value);


fp = popen(output,"w");
pclose(fp);

fp = popen("C:\\ousb -r io UCSRB","r");
fgets(UCSRB, sizeof UCSRB, fp);
value = atoi(UCSRB);
value |= 0x18 ;
pclose(fp);

sprintf(output, "%s%d", "C:\\ousb io UCSRB " , value);


fp = popen(output,"w");
pclose(fp);

// Set the Baud rate to 9600, note 8-N-1 is set by default


sprintf(output, "%s%d", "C:\\ousb io UBRRL " , 75);
fp = popen(output,"w");
pclose(fp);

52 | P a g e
int main()
{
while(1) // Forever Loop
{
UCSRA = 0; // Initialise the UCSRA buffer

// Wait for received data


while(UCSRA == 0)
{
fp = popen("C:\\ousb -r io UCSRA","r");
fgets(UCSRA_char, sizeof UCSRA_char, fp);
UCSRA = atoi(UCSRA_char);
UCSRA &= 0x80;
pclose(fp);
}

// Receive the incoming data


fp = popen("C:\\ousb -r io UDR","r");
fgets(RX_char, sizeof RX_char, fp);
RX_DATA = atoi(RX_char);
pclose(fp);

// Add one to the received value to


// increment to the next ascii value
TX_DATA = RX_DATA + 1;

// Transmit the modified received data


sprintf(output, "%s%d", "C:\\ousb io UDR " , TX_DATA);
fp = popen(output,"w");
pclose(fp);
}

return 0;
}

53 | P a g e
Chapter 2 – Preparing For Embedded C
Prerequisites
 A PC running either a Linux or Windows (XP, Vista, 7) OS and a spare USB port.
 An OUSB Development Board with the OUSB firmware loaded (comes preloaded)
 Understand basic operations of your operating system (save, create, move and find, files
and folders)
 If you wish to learn how to upload your code to the Atmega32 independent of the OUSB
command line, you will need either an STK 200 cable, USBasp programmer or AVRISP
mkII programmer.
 Access to the internet

1. Do You Really Need To Complete This Chapter


This chapter is designed for those who wish to learn how to program an Atmel chip with their own unique
program. This will not be using the OUSB Firmware, this section will introduce you how to develop
your own standalone firmware, compile it and upload it to the Atmel chip, in this case it is the Atmega32
onboard your OUSB Development Board. The method shown could be applied to any Atmel chip
supported by the AVR-GCC project.

Details on the supports chips can be found at the following link:

http://www.nongnu.org/avr-libc/user-manual/

PLEASE BE AWARE THIS IS NOT THE CO-USB FEATURE OF THE OUSB FIRMWARE.
This manual will not be covering the CO-USB feature as it is explained in detail by Dr PJ Radcliffe in the
Open-USB-IO Reference manual which can be found at:

http://pjradcliffe.wordpress.com/open-usb-io/resources/

So it is now time to decide how you wish to create your programs for your Atmega32, do you wish to use
the CO-USB feature, if so use the link above and familarise yourself with CO-USB, then you can move
on to chapter 3 which will introduce you to embedded programming for the Atmega32.

If you wish to learn how to make standalone programs without relying on the OUSB firmware then read
on, we will be removing the OUSB firmware, but we will also cover how to restore the firmware as well.

54 | P a g e
2. What you need and where to get it
This manual will utilize the Eclipse IDE for embedded programming. The Eclipse IDE is open source
software that is very versatile and is available in either Windows or Linux versions; both versions use the
AVR-GCC complier. It should be noted that Eclipse has different installation requirements for Windows
and Linux, but once the installation is complete, navigation and use of the IDE in either operating systems
is relatively similar. Finally Eclipse is a self contained program; that is it does not require installation as it
runs directly from the downloaded folder and stores its data to a folder called workspace.

3. Preparing a Windows PC
If you are running a Windows platform you need to install the Eclipse C/C++ IDE in accordance with
Annex A. Please ensure you install the software correctly and in the order shown as it is important so that
the IDE can recognize all needed software components.

4. Preparing a Linux PC
Linux install is not fully supported in this manual, this is because RMIT uses a LIVE -DVD which is
setup with Eclipse installed, if you are not a strong Linux user, it is highly recommended you use the
LIVE -DVD or install Linux PC OS 2009 from the LIVE -DVD, as this will save you a considerable
amount of setup time.

If you are an existing Linux user and wish to install Eclipse by yourself Annex B provides useful websites
and screen shots from the Eclipse help menu to instruct you on what you need to do.

55 | P a g e
All Linux Users Please Read the Following about Adding AVR-GCC Libraries to Your
Project
The Linux version recommended to use has a problem when creating and AVR-GCC project. There is a
work around but it means you need to remember the following procedure when creating such a project.
The problem is that the AVR -GCC libraries do not get included into the project automatically as you
may be used to, so we need to add them.
The following procedure is a step through that you will have to apply later in this chapter, for the time
being read to following to understand what you need to do so that the needed libraries get added to your
project. This procedure assumes you are using the LIVE-DVD or an installation from.
Once you have created a new AVR-GCC project you will notice that you will only have a folder created
with no source files or libraries. For this example I have created the AVR -GCC project LED_Bounce.
We will highlight the project folder in the project explorer tab as seen in figure 2.1.

Figure 2. 1

56 | P a g e
Next select Project>Properties, from the properties window expand C/C++ Build > Settings, once at
Build setting select AVR Assembler > General from the list as shown in figure 2.2 and click the include
paths, Add icon.

Figure 2. 2

You will then be asked to enter the directory path, this can be found via the file system, click file system,
File system (in the places column) >usr>local>avr>avr>include and then click Ok.
An even simpler method is to type /usr/local/avr/avr/include as the directory this is shown in figure 2.3
and then click Ok.

Figure 2. 3

57 | P a g e
The path should now be visible in the include path window as shown in figure 2.4, now click Apply then
Ok.

Figure 2. 4

58 | P a g e
You should now be able to expand the LED_Bounce project folder in the Project Explorer tab and see
the Includes visible as seen in figure 2.5.

Figure 2. 5

The remainder for developing the LED_Bounce project is covered in the next section.

59 | P a g e
5. Developing your first Embedded C program in Eclipse
This section will take you through the development of your first Embedded C program, as you progress
through this section you will notice differences between embedded programming and standard desktop
programming. You will use different standard library, the need to set registers and your program will be
design to never terminate as there is no operating system to fall back on.

For the development of this program we will now go through step by step the configuration of an Eclipse
AVR-GCC project much like we did before starting C++ programming. Again I will denote the
differences between the Linux version and Windows version of Eclipse by LINUX USERS, as once
again the following was written from actions on a Windows machine.
1. Open Eclipse
a. Linux, menu>More Applications>Development>Development Environments>eclipse
b. Windows, by the shortcut that has been creates on the desktop.

2. You may be presented with a warning in Windows asking if you wish to open this program, if
you accept the warning click the appropriate button the proceed.

3. You will then be asked to create a workspace, in Eclipse a workspace is simply to a directory
you would like to work from. This workspace will be created if it doesn‟t exist, and if you select
and existing workspace Eclipse will load any existing projects in that workspace. However for
now just select ok, as seen in figure 2.6.

LINUX USERS: note that your directory structure for the default workspace is
/home/user/workspace.

Figure 2. 6

60 | P a g e
4. Our first action in developing our program is to open a new C project. This is done by selecting
File>New>C Project, as shown in figure 2.7.

Figure 2. 7

5. Our next step is to name our new project as LED_Bounce and the select our project as an AVR
Cross Target Application as shown in figure 2.8. By selecting the Empty Project the compiler
will automatically insert the standard header and namespace. Once this is done select Next.

LINUX USERS: note that for your list you can only chose the AVR Cross Target Application
and not the Empty Project template, this is what I believe is cause the Linux AVR -GCC include
issues

NOTE: All users must be aware that when naming an AVR -GCC project the name must not
contain any spaces or you will not be able to compile your project.

61 | P a g e
Figure 2. 8

6. The next screen will allow you to select whether you wish to create Debug and Release versions.
For AVR -GCC programs you must select both, make your choice and select Next.

7. The final selection that needs to be made is the AVR Target Hardware, by observing the OUSB
schematic diagram you will notice that you are using an Atmega32 and it is running at 12 MHz
(pin 12 and 13). Add these values into the selection boxes as shown in figure 2.9 and select
Finish.

62 | P a g e
Figure 2. 9

8. This will differ between users depending on what steps you have taken, but you may be at the
Eclipse welcome window as displayed in figure 2.10, if you are simply click on the workbench
icon circled in red.

LINUX USERS: note that your welcome page looks different, but the actions are the same.

Figure 2. 10

63 | P a g e
9. I recommend that you set the project preferences so that the project will auto save before building
each time; I have found that I have to do this every time I open Eclipse as it does not auto save
many of your preference options. This can be done by selecting Window > Preferences from the
menu bar, then expand General >Workspace, you should then tick the third option down which
is Save automatically before build as shown in figure 2.11. In AVR-GCC projects if you do not
save before your first build you will receive an error because no code exists to be compiled, as no
code is auto created for you.

Figure 2. 11

10. Any other preference you may be interested in is turning on line numbers, this can be done by
selecting Window > Preferences from the menu bar however the line numbers option is found
by expanding General > Editors > Text Editor, from there select the fourth option down as
shown in figure 2.12.

Figure 2. 12

64 | P a g e
11. In your workbench on the right hand side you will see the project explorer tab. Because the
AVR -GCC part of the IDE is not as automated as the C++ executable projects you need to add
your source file and for Linux users only, add the AVR-GCC libraries now.

12. Your first step is to highlight the project folder LED_Bounce in the project explorer tab; next
you right click on our project folder and select New > Source File as seen in figure 2.13. The
New Source File windows will now appear, type main.c for the name of the new source file as
shown in figure 2.14 and select Finish.

Figure 2. 13

65 | P a g e
Figure 2. 14

13. LINUX USERS: This next step is for Linux users only and just recaps what was previously
demonstrated to ensure that the AVR -GCC libraries are added correctly.

To add AVR -GCC libraries select Project>Properties, from the properties window expand
C/C++ Build > Settings, once at build setting select AVR Assembler > General from the list,
and click the include paths, Add icon.

You will then be asked to enter the directory path, type /usr/local/avr/avr/include as the
directory and click Ok.

The path should now be visible in the include path window, click Apply then Ok.

You should now be able to expand the LED_Bounce project folder in the Project Explorer tab
and see the Includes visible in the tab.

14. Now write the following program into the text editor of the IDE.

The following program is called bouncing LED‟s, as you may predict from the name the program makes
the LED‟s bounce from one end to the other repetitively. Read the comments to obtain an understanding
of the programs structure.

66 | P a g e
// AVR gcc standard library, provide iom32.h which know the basic commands
for // the Atmega32 SEE ANNEX D.
#include<avr/io.h>

// provides the header for _delay_ms()


#include<util/delay.h>

// constant used to define the delay, in milli seconds


#define delay 75

int main()
{
int i =0;

// Sets the Data Direction Register for PORTB so that all are outputs
DDRB = 0xFF; // 1111 1111

// Sets the LSB of PORTB high.


PORTB = 0x01;

/* we create our program in a forever loop so that the program will


never exit, as exiting will cause the Atmega32 to hang until it is
reset.
Embedded programming is not like standard programming, it does not
have an operating system to fall back on.
*/
while(1)
{
// for loops control our LED movements
// start at 1 and move up in multiples of two, till we reach 128

for(i = 1 ; i<=128; i=i*2)


{
// Set PORTB to the New value of i
PORTB = i;
/* cause a delay so we can visually see the LED’s
movement */
_delay_ms(delay);
}
// start at 64 and move down by divisions of two, till we reach 1
for(i=64 ; i>1; i -= i/2)
{
// Set PORTB to the New value of i
PORTB = i;
/* cause a delay so we can visually see the LED’s
movement */
_delay_ms(delay);
}
}
return 0;
}

67 | P a g e
15. Now that the program is written into the IDE it is now time to build the program, select the
LED_Bounce folder in the Project Explorer tab and click on the hammer icon to build. This
time when you build the program you will notice a warning occurs but there are no errors in the
Problems tab as shown in figure 2.16. Warnings give suggestions that you may not have done
something correctly; the warning in figure 2.16 is fine. If you remember back to when we created
this project, we created it with debug and release options selected. Let us now change our build to
release by single clicking on the drop arrow of the build hammer, you will notice the option to
select Debug or Release, select Release and re-build your program as shown in figure 2.15.

Figure 2. 15

Figure 2. 16

68 | P a g e
16. You will now notice that the warning has disappeared in the release build, that‟s not all that is
different either, if you expand the Debug and Release folders in the Project Explorer tab you
will see that the Release folder contains more objects, to add to that only the release folder holds
the LED_Bounce.hex file which is the binary file that contains the program to be uploaded to the
Atmega32 this can be seen in figure 2.17. So note that Debug can be useful for creating your
programs but only Release can actually build the hex file needed.

Figure 2. 17

69 | P a g e
17. Now that we have created and built our program we now have to upload this firmware to the
Atmega32.

6. Loading your first program into Atmega 32 on the OUSB development


board
The section describes how to upload a microprocessor executable or hex file to the Atmega32 onboard the
OUSB development board via the Eclipse IDE. However it should be noted that you will delete the
OUSB firmware which on the Atmega32 but at the end of this section we will upload the firmware back
onto the chip. There are three methods that will be demonstrated and you only need to configure one
method, they are:
 STK-200 cable
 USB programmers
o USBasp programmers
o AVRISP mkII programmer

Be aware that this is different to loading a program via the CO-USB feature of the OUSB development
board. This method is beneficial to learn as the following steps can be used to program any AVR (Atmel
microcontroller) that is supported by the AVR -GCC standard, which may be useful if you wish to create
projects without the OUSB development board or if you develop a specialized program where you need
to use PORTD.

Using STK-200
 Before commencing this section you will need a PC with a parallel port (DB 25 printer port).
 STK 200 only works for Windows XP or earlier OS (Not Vista or Windows 7)
 Windows XP users must setup parallel port IO as detailed in ANNEX E.
 Linux users do not need to setup parallel IO as it is a standard feature of Linux OS.
 You must create an STK 200 cable, schematic can be found at
http://pjradcliffe.wordpress.com/open-usb-io/resources/
 Parts for the STK 200 cable can be sourced from Jaycar or Futurlec online.

Before beginning the rest of this section the manual will assume that you have configured your parallel IO
(Windows XP users), that you have correctly created your STK 200 cable and you have just built your
code in release mode using the Eclipse IDE.

70 | P a g e
Once again you need to highlight your project folder in the Project Explorer tab, and then from the menu
bar select project > properties, shown below in figure 2.18.

Figure 2. 18

71 | P a g e
From the properties window expand AVR > AVRDude, and in the Programmer tab select New as
displayed in figure 2.19.

Figure 2. 19

72 | P a g e
For your programmer‟s configuration select STK 200 from the list and name this configuration as STK
200 as displayed in figure 2.20. Once you are satisfied with the configuration select Ok.

Figure 2. 20

73 | P a g e
Back in the properties windows ensure that the configuration that you have just created is selected, and
then click Apply followed by Ok, shown below in figure 2.21.

Figure 2. 21

74 | P a g e
Finally connect your STK 200 programming cable to the parallel port of your PC and the programming or
ISP port of the OUSB development board, J7. Once you are connected press the AVR icon as shown in
the figure 2.22 and observe the return message in the Console tab as it will inform you of any problems.

Figure 2. 22

Note: STK 200 cable holds the OUSB development board in a constant RESET state when the cable in
plugged in, your code will only to begin to execute once the STK 200 cable is removed.

75 | P a g e
Using the an USBasp Programmer
 This section requires a PC with a USB port.
 A USBasp programmer that meets the specifications at the link http://www.fischl.de/usbasp/
 If you wish to buy an USBasp AVR programmer you can purchase them from eBay for
approximately $20.
 You will need to install the driver for your USBasp, 32 bit systems should use the driver that
comes with the programmer, or the one found at the above link, you may also use the 64 bit
method except save the .inf file in the x86 folder.
 If you are using a Windows 64 bit OS you will not be able to use the drivers mentioned above
for the USBasp, as those drivers are unsigned.
 LIVE-DVD users do not need the install any drivers as the required LibUSB driver is already
installed; all you need to do is plug in your programmer.
 Other Linux user will need to ensure LibUSB is installed, typically this is a part of the
software installed for AVR-GCC, so if this environment is setup trying using your
programmer first before installing LibUSB.

Installing USBasp on a 64 bit Windows OS


To install the USBasp on a 64 bit Windows OS you will need to download the zipped folder LibUSB-
64bit from the following link to the eclipse folder on your desktop:

http://sites.google.com/site/openusbboard/file-cabinet

I recommend you stick to the version on the OUSB site as I know it works and the procedures in the
manual are for this version.

However if you have a reasonable level of competency you should have no problems with any of the
LibUSB versions after win32 - 1.2.1.0 from the project site.

http://sourceforge.net/projects/libusb-win32/files/

Before we start to install the driver you will need to plug your USBasp programmer into a spare USB port
of your PC.

Once you have downloaded the zipped folder using the extraction wizard, extract the LibUSB-64bit
folder. Open the extracted folder to the directory libusb-win32-bin-1.2.1.0 > bin >x86 and run the
program inf-wizard as shown in the figure below.

Figure 2. 23

76 | P a g e
Inf-wizard will start, click Next.

Figure 2. 24

Select the USBasp programmer from the list of USB devices and select Next.

Figure 2. 25

77 | P a g e
These are the device settings I used, verify and click Next.

Figure 2. 26

You now have to save the Information file (.inf) in the directory libusb-win32-bin-1.2.1.0 > bin
>amd64, and click Save. (32 bit users save theirs in libusb-win32-bin-1.2.1.0 > bin >x86)

You will now be prompted to install the driver, simply click Install Now..

Figure 2. 27

78 | P a g e
You may be prompted by various warning from your operating system that Windows cannot verify the
publisher of the driver, if you accept the risks click Allow or Install this driver software anyway.

Figure 2. 28

The driver will now install.

Figure 2. 29

Once the driver has been successfully installed click Ok.

Figure 2. 30

Once you have purchased your USBasp programmer and installed its driver you are ready to program the
Atmega32 on the OUSB development board.

79 | P a g e
To setup your AVRISP mkII in Eclipse you need to highlight your project folder in the Project Explorer
tab, and then from the menu bar select project > properties, as shown in figure 2.29.

Figure 2. 31

80 | P a g e
From the properties window expand AVR > AVRDude, and in the Programmer tab select New as
displayed in figure 2.32.

Figure 2. 32

81 | P a g e
For the programmers configuration select USBasp, http://www.fischl.de/usbasp/ from the list and
name this configuration as USBasp as displayed in figure 2.33. Once you are satisfied with the
configuration select Ok.

Figure 2. 33

82 | P a g e
Back in the properties windows ensure that the configuration that you have just created is selected, and
then click Apply followed by Ok, as shown below in figure 2.34.

Figure 2. 34

Finally ensure your USBasp programmer is connected to your PC and the ISP port of the OUSB
development board, J7. Once you are connected press the AVR icon as shown in the figure 2.35 and
observe the return message in the Console tab as it will inform you of any problems.

Figure 2. 35

Your code should now be executing, if not remove the programming cable as sometime programmers can
force a reset just by being plugged in which will holt the Atmega32 from executing your code.

83 | P a g e
Using the AVR ISP mkII Programmer
 This section requires a PC with a USB port.
 An AVR ISP mkII programmer made by Atmel, the makers of the Atmega32.
 If you wish to buy an AVR ISP mkII, I recommend Ocean Controls, Seaford. They cost
around $75.
 You will need to follow the instructions below to install the driver for Eclipse because it is
not the same as the driver that comes with the programmer.
 LIVE-DVD users do not need the install any drivers as the required LibUSB driver is already
installed, all you need to do is plug in you programmer.
 Other Linux user will need to ensure LibUSB is installed, typically this is a part of the
software installed from AVR-GCC, so if this environment is setup trying using your
programmer first before installing LibUSB.
 If you have previously used your programmer with AVR Studio you will need to uninstall the
Jungo driver for your AVRISP mkII programmer to work with Eclipse. If you are
comfortable using AVR Studio and know your way around it feel free to continue using that
IDE for AVR development as the code in this manual will work in either Eclipse or AVR
Studio.

Installing AVR ISP mkII on 32 bit and 64 bit Windows OS

To install the AVR ISP mkII on a 64 bit Windows OS you will need to download the zipped folder
LibUSB-64bit from the following link to the eclipse folder on your desktop:

http://sites.google.com/site/openusbboard/file-cabinet

I recommend you stick to the version on the OUSB site as I know it works and the procedures in the
manual are for this version.

However if you have a reasonable level of competency you should have no problems with any of the
LibUSB versions after win32 - 1.2.1.0 from the project site.

http://sourceforge.net/projects/libusb-win32/files/

Before we start to install the driver you will need to plug your USBasp programmer into a spare USB port
of your PC.

Once you have downloaded the zipped folder using the extraction wizard, extract the LibUSB-64bit
folder. Open the extracted folder to the directory libusb-win32-bin-1.2.1.0 > bin >x86 and run the
program inf-wizard as shown in the figure below.

84 | P a g e
Figure 2. 36

Inf-wizard will start, click Next.

Figure 2. 37

85 | P a g e
Select the AVRISP mkII programmer from the list of USB devices and select Next.

Figure 2. 38

These are the device settings I used, verify and click Next.

Figure 2. 39

86 | P a g e
You now have to save the Information file (.inf).
This is where the procedure differs for 32-bit and 64-bit users.

64 bit users
 save your .inf file at libusb-win32-bin-1.2.1.0 > bin >amd64.

32 bit users
 save your .inf file at libusb-win32-bin-1.2.1.0 > bin >x86.

You will now be prompted to install the driver, simple click Install Now..

Figure 2. 40

87 | P a g e
You may be prompted by various warning from your operating system that Windows cannot verify the
publisher of the driver, if you accept the risks click Allow or Install this driver software anyway.

Figure 2. 41

The driver will now install.

Figure 2. 42

Once the driver has successfully installer click Ok.

Figure 2. 43

Once you have purchased your AVR ISP mkII programmer and installed its driver you are ready to
program the Atmega32 on the OUSB development board.

88 | P a g e
To setup your AVRISP mkII in Eclipse you need to highlight your project folder in the Project Explorer
tab, and then from the menu bar select project > properties, as shown in figure 2.47.

Figure 2. 44

89 | P a g e
From the properties window expand AVR > AVRDude, and in the Programmer tab select New as
displayed in figure 2.48.

Figure 2. 45

90 | P a g e
For your programmer‟s configuration select Atmel AVR ISP mkII from the list and name this
configuration as AVRISP. One more option needs to be configured in this window and that is the
Override Default Port, it needs to be set as usb as displayed in figure 2.49. Once you are satisfied with
the configuration select Ok.

Figure 2. 46

91 | P a g e
Back in the properties windows ensure that the configuration that you have just created is selected; now
enter 10 for the JTAG ICE Bitclock, and then click Apply followed by Ok, as shown below in figure
2.50.

Figure 2. 47

92 | P a g e
Finally ensure your AVR ISP mkII programmer is connected to your PC and the ISP port of the OUSB
development board, J7. Once you are connected press the AVR icon as shown in the figure 2.51 and
observe the return message in the Console tab as it will inform you of any problems.

Figure 2. 48

You code should now be executing, if not remove the programming cable as sometime programmers can
force a reset just by being plugged in which will holt the Atmega32 from executing your code.

93 | P a g e
How to Restore the OUSB Firmware

This section is broke into two parts, the first part is for LIVE-DVD users and is the simplest way of
restoring the OUSB firmware, the second is for Windows users, but existing Linux users could
implement the method using a BASH script files rather than Batch script file.

LIVE-DVD Users
LIVE - DVD users who use an STK 200 cable have the easiest method of restoring the OUSB firmware,
simply open a terminal, plug your STK 200 cable into your PC and the OUSB development board then
type ousb_prog into the terminal and it will automatically restore the firmware.

For those LIVE-DVD users who program with an USBasp or the AVR ISP mkII programmers you need
to change some commands in a Makefile to automate OUSB firmware upload. Go to the directory
/home/user/projects/open-usb-io_firmware and open the file called Makefile as shown in the figure
2.48.

Figure 2. 49

94 | P a g e
Highlighted in the figure below, is the word stk200, this is written eight other times in this Makefile in
almost exactly the same format as displayed. To change this Makefile so that you can automatically
restore to OUSB firmware by typing the command ousb_prog you need to change these eight
occurrences to match that of your programmer.

Figure 2. 50

For the USBasp programmer change the word stk200 to usbasp for all eight occurrences of stk200 and
save the Makefile before closing it.

For the AVR ISP mkII programmer you will need to replace the word stk200 with avrisp2 -P usb -B 10
for all eight occurrences of stk200 and save the Makefile before closing it.

Now open a terminal, connect your programmer to your PC and the OUSB development board and type
ousb_prog into the terminal.

Finally I advise that you do some basic tests on the board to ensure that the firmware is operating
correctly as demonstrated earlier in this manual.

95 | P a g e
Windows Users

First you will need to download your version of the OUSB firmware. Be aware that there are two
versions, a CO USB version and a standard command line only version. These can be downloaded at the
bottom of the page at:

http://sites.google.com/site/openusbboard/3-chapter-2

or from the file page at:


http://sites.google.com/site/openusbboard/file-cabinet

Note: Ensure the firmware you are using matches the OUSB command line version that you are using.

Once you have decided on what firmware you want to upload, click on the Download link below it, you
will be prompted if you would like to Open or Save the firmware, select Save and save the zipped folder
to the eclipse folder on the desktop.

Figure 2. 51

96 | P a g e
Once the download is complete select Open Folder.

Figure 2. 52

Windows explorer will now open to the eclipse folder on the desktop, right click on the ousb_firmware
zipped folder and extract its contents to the default directory for command prompt. My default directory
is C:\Documents and Settings\Troy as shown in figure 2.53. On a Windows 7 machine your default
directory will be something like C:\Users\User_Name.

97 | P a g e
Figure 2. 53

Figure 2. 54

98 | P a g e
Once the file is extracted and you click Finish your default command prompt directory will open and it
should contain the file ousb.hex as shown in figure 2.54.

Figure 2. 55

Now that you have the ousb.hex (firmware) located in the default directory, you now have to create a
Batch script file that will upload the OUSB firmware onto the Atmega32 using your programmer. Just
like in chapter 1, we will make a Batch file that will execute commands, however this time we will
execute an AVRDUDE command to load the OUSB firmware.

99 | P a g e
In your default directory, (note mine is C:\Documents and Settings\Troy) check for a text file called
New Text Document, we created this earlier, if it exists open it. If the file New Text Document does not
exist, right click in the directory and select New > Text file as shown below and open the text document.

Figure 2. 56

In the text document that you have just opened type single line AVRDUDE command for your
programmer into the text document, then select File > Save As… and save the file as ousb_prog.bat.

100 | P a g e
STK 200

avrdude -p m32 -c stk200 -U lfuse:w:0xDE:m


avrdude -p m32 -c stk200 -U hfuse:w:0xC9:m
avrdude -p m32 -c stk200 -U flash:w:ousb.hex

USBasp

avrdude -p m32 -c usbasp -U lfuse:w:0xDE:m


avrdude -p m32 -c usbasp -U hfuse:w:0xC9:m
avrdude -p m32 -c usbasp -U flash:w:ousb.hex

AVR ISP mkII

avrdude -p m32 -c avrisp2 -P usb -B10 -U lfuse:w:0xDE:m


avrdude -p m32 -c avrisp2 -P usb -B10 -U hfuse:w:0xC9:m
avrdude -p m32 -c avrisp2 -P usb -U flash:w:ousb.hex -B10

Now open command prompt and connect your programmer to your PC and the OUSB development
board and type ousb_prog into the command prompt window and press enter as displayed in figure

101 | P a g e
Chapter 3 – C Programming for the Atmega32

1. Introduction to embedded C programming


This Introduction to Embedded programming intends to teach you how to use bitwise operators to modify
registers and other configurable values using the vector values in the header file iom32.h (ANNEX D)
which makes it easier to configure your ATMega32 with the correct settings. We will then cover the
implementation of state machines using C programming then finally overview of some of the peripherals
of the Atmega32 with some basic examples to get you started.

The remainder to this manual will assume from here on that you are competent in using the Eclipse IDE
with the OUSB development board. There will no longer be step by step screen shots of basic operations
and settings; they will be given in text form. Additionally we are moving into some basic and
intermediate programming topics and therefore recommend that you have an understanding of the C
programming language.

2. Bitwise manipulation
Bitwise operators

To be able to effectively create C programs in an embedded sense that are both readable and
easier to fault find you will need to understand the bitwise operators and their truth tables.

Operator symbol
Bitwise OR |
Bitwise AND &
Bitwise Not ~
Bitwise XOR ^
Shift Left <<
Shift Right >>

As you already know bitwise operators work on bits and not logical values. Therefore if you take
two individual bytes, and perform a bitwise operation on them the result will be a byte of
information according to the operation performed on each bit.

The use of bitwise operator truth tables can help explain each of the individual operations.

102 | P a g e
The OR operator truth table:

Input A Input B Output Y


0 0 0
0 1 1
1 0 1
1 1 1

Example
The OR bitwise operator is used to turn bits on as you can see below the final bit in the OR
operation is used to set the Least Significant Bit (LSB) on.

The AND operator truth table:

Input A Input B Output Y


0 0 0
0 1 0
1 0 0
1 1 1

Example
The AND bitwise operator is used to turn bits off as you can see below the final bit in the AND
operation is used to set the LSB off.

The XOR operator truth table:


Input A Input B Output Y
0 0 0
0 1 1
1 0 1
1 1 0

Example
The XOR bitwise operator is used to toggle bits as you can see below the final bit in the XOR
operation is used to set the LSB to be toggled when operated in a series of XOR operations.

103 | P a g e
The Bitwise NOT operator (~) inverts every bit, so a 1 becomes a 0, and a 0 becomes a 1.

Example
The bitwise NOT operator is used to invert bits as you can see below the entire byte is inverted
when the NOT operation is used.

Shifting Bits

Shift bits can be used to setup up a masks for use with the bitwise operators. The most commonly used
shift bit when working with embedded programming is the left shift. Below are some examples of its use.
When you are using shift bits to set your bytes you must start from one and then shift left one minus the
bit number you would like to set.

Set the 3rd bit:


(0x01 << 2) = 0000 0100

Set the 8th bit:

(0x01 << 7) = 1000 0000

Left shift can be combined with bitwise OR operators to develop a bit mask of more than one bit.

Set the 1st and 4th bits.

(0x01 << 0)|(0x01 << 3) = 0000 1001

104 | P a g e
Bit Manipulation

Bit manipulation using bitwise operations is the easiest way to write embedded C programming as it
provides a very easy to read and interpret format. However the drawback of this style of creating code is
that it greatly increases the programmer‟s key types. However it is also acceptable to use hex values, this
manual will tend to use the most appropriate method for the operation, for example it would be tedious to
use bitwise operators to set all eight bits high, therefore this manual would use 0xFF.
I recommend finding your own style; you need to be aware when using straight values such as hex as it
can make it very hard to identify a problem in your code.

Setting a bit

Setting a bit involves the use of a bitwise compound OR statement and the use of the shift left operator.
The following sets the LSB.

int i = 0x00; //place i in a known state


i |= (1 << 0); // set the LSB of i

Results in
i = 0x01

The above example uses a compound statement to set the LSB to one.
Remeber that a compound statement is just i = i | (1 << 0); or

Unsetting a bit

Unsetting a bit involves the use of a bitwise compound AND statement and the use of the shift left but
this time we need to apply a mask written using not logic for our desire value, this can be simplified by
using the bitwise not operator.
The following unsets the LSB.

Using applying desired result in not logic:

Here we are going to turn off the LSB, by applying a mask using a hex value which is the inverse of the
desired pin to turn off, since we wish to turn of the LSB the hex value will be 0xFE or 0b1111 1110.

int i = 0xFF; //place i in a known state


i &= 0xFE; // unset the LSB of i

The above example uses a compound statement to unset the LSB to zero.
Remeber that a compound statement is just i = i & ~(1 << 0); =

105 | P a g e
Using Bitwise not:

This method it simpler and achieves the same result.

int i = 0xFF; //place i in a known state


i &= ~(1 << 0); // unset the LSB of i

The above example uses a compound statement to unset the LSB to zero.
Remeber that a compound statement is just i = i & ~(1 << 0); =

Toggling a bit

Toggling a bit involves the use of a compound bitwise XOR statement, very similar to the methods used
above.
int i = 0x01; //place i in a known state 0000 0001
i ^= (1 << 0); // unset the LSB of i 0000 0000
i ^= (1 << 0); // set the LSB of i 0000 0001
i ^= (1 << 0); // unset the LSB of i 0000 0000

Setting Multiple Bits

This is where bit manipulation really comes into play. In chapter 1 I briefly explained the registers for the
parallel I/O port for the OUSB command line these registers perform the same tasks in C programming
for the Atmega32. In this example you are going to use them but before I do I recommend you look at the
table below and the values for the registers. You are going to be using them with the shift left operator to
set these register values that can be found in the iom32.h header file (ANNEX D) and not any user
defined values to set and unset the parallel I/O ports.

DDRx Registers PORTx Register PINx Registers Value that will be shifted
DDx0 PORTx0 PINx0 0
DDx1 PORTx1 PINx1 1
DDx2 PORTx2 PINx2 2
DDx3 PORTx3 PINx3 3
DDx4 PORTx4 PINx4 4
DDx5 PORTx5 PINx5 5
DDx6 PORTx6 PINx6 6
DDx7 PORTx7 PINx7 7

The following example displays the use of multiple bit manipulation to set the MSB and LSB high for
output, take notice of the bitwise OR operation between the two shift left statements.

DDRB |= (1 << DDB7)|(1 << DDB0);

Now if I want the set the output of the MSB as high and the LSB as how you could write:

PORTB |= (1 << PORTB7);


PORTB &= ~(1 << PORTB0);

106 | P a g e
LED Toggle an Atmega32 Code using Bit Manipulation

Before the program is explained let us cover some of the features used

#include <avr/io.h>

This is the standard header for all AVR's and holds the header iom32.h which is the standard header for
the Atmega32.

#include <util/delay.h>

This header contains the _delay_ms() function

while(1)

Since embedded programs like the one below do not have an operating system to fall back to when the
program finishes restarting it. You need to add a forever loop so that the program can continue to run.

As you can see the program below is rather simple. First I start by configuring to output mode then set
PORTB into a known state (I use PORTB, as PORTB is connected to the LEDs on the OUSB
development board), then I place the toggle command inside a forever loop with a delay to make the
LED flash at 500ms intervals.

#include <avr/io.h>
#include <util/delay.h>

// delay period in ms
const int delay = 500;

int main()
{
//set the LSB of PORTB for output
DDRB |= (1 << DDB0);

// set LSB PORTB in a known condition, high


PORTB |= (1 << PORTB0);

while(1)
{
// toggle LSB of PORTB
PORTB ^= (1 << PORTB0);

//Create a 500ms delay


_delay_ms(delay);

return 0;
}

107 | P a g e
3. State machines in C
State machines are a method of developing a system which performs a set task for a certain state, and the
result of events of a single state will control flow of the state machine. For small programs state machines
are ideal because they are relatively simple to develop and implement. Many of you may have developed
state machines using combinational logic, the initial steps of that process are exactly the same. First think
about what your system needs to do, second is to develop a state diagram of your system that will execute
in such a way to meet your requirements, the example state diagram for this manual is seen in figure 3.1.
Next we need to transfer your state diagram into a state machine, in C programming this is usually
implemented with a switch statement inside a forever loop, where every case statement is a different
state and a control parameter is used to determine what state to execute at every instance the switch
statement in entered.

The benefit of using a state machine method in C programming is that it can be easily modified to add
extra functionality to individual states without effect any other state in the system, it is also relatively
simple to add extra states to an existing system.

The example state machine in this manual is a very simple version and is used to illustrate a method of
implementation; the state machine will begin at the initializing state which will set PORTB for output and
PORTC for input, set PORTB to 0x00 (all off) and store the current value of PINC. State 1 will toggle
PORTB 0 then a condition will be checked. If PINC is different to that stored the system will move to
state 2, otherwise it will again toggle PORTB 0. This process will continue except for the fact that
different pins on PORTB will be toggled for each state. Once state 3 is left the state machine will restart
at state 1.

108 | P a g e
Initialize System
Set PORTB for
output and to the
value 0x00
Set PORTC for
input and
Store = PINC

State 1

Toggle PORTB 0

Check PINC
PINC
UNCHANGED
PINC
CHANGED

State 2

Toggle PORTB 1

Check PINC

PINC
UNCHANGED
PINC
CHANGED

State 3

Toggle PORTB 2

Check PINC

PINC
UNCHANGED
PINC
CHANGED

Figure 3. 1

109 | P a g e
The follow is the C programming implementation of the above state diagram.
#include <avr/io.h> // include avr/iom32.h
#include <util/delay.h>

// Hash define constants


#define DELAY 200

// Global Variables
int control = 0;
int pinc = 0;
int next_state = 0;

// State Machine Funtion


// Performs the state machine function defined by the state diagram
// The switch case statement is used to determine program flow
void State_Mach(int state)
{
switch(state)
{
case 1:
while(pinc == PINC) // Wait for PINC to change
{
PORTB ^= (1 << PB0); // Toggle PB0
_delay_ms(DELAY);
}
PORTB = 0x00;
pinc = PINC;
next_state = 2;
break;
case 2:
while(pinc == PINC) // Wait for PINC to change
{
PORTB ^= (1 << PB1); // Toggle PB1
_delay_ms(DELAY);
}
PORTB = 0x00;
pinc = PINC;
next_state = 3;
break;
case 3:
while(pinc == PINC) // Wait for PINC to change
{
PORTB ^= (1 << PB2); // Toggle PB2
_delay_ms(DELAY);
}
PORTB = 0x00;
pinc = PINC;
next_state = 1;
break;
default:
control = 1;
break;
}
}

110 | P a g e
// Setup Function
void setup()
{
DDRB = 0xFF; // Set PORTB for output
DDRC = 0x00; // Set PORTC for input
PORTC = 0xFF; // Set PORTC for internal Pull-ups
pinc = PINC; // Store the initial value of PINC
control = 1; // Set the control to state 1
}

int main()
{
setup(); // Setup the microcontroller

while(1) // Forever Loop


{
State_Mach(control);
control = next_state; // Move control to the next state
_delay_ms(DELAY);
}

return 0;
}

111 | P a g e
4. Atmega32 peripherals
The remainder of this chapter will provide an overview to many of the peripherals common to Atmega
microcontrollers and specifically the Atmega32. This section is only an overview and is not a definitive
guide to the Atmega32, if you find that you require more detailed information read the relevant section in
the Atmega32‟s data sheet as it provides detailed information on each of the peripherals and more.

The following link will take you to the Atmega32 datasheet:

http://www.atmel.com/dyn/resources/prod_documents/doc2503.pdf

Interrupts
The programs displayed in this manual so far have been structured, that is they have all been developed to
run sequentially in a specific order defined directly by the programmer; this is typically known as polling.
However programs can be written using interrupts, that is programs will respond to events rather than a
sequential order however interrupts still need to be defined by the programmer. As the name interrupt
suggests when a predefined event occurs, the program flow will be interrupted; this break in program
flow is called an Interrupt Service Routine (ISR) and performs whatever functions are defined by the
programmer for a particular interrupt. Once the instructions defined by the ISR are completed, program
flow returns to the point in the program where the program was interrupted, this return is controlled by a
built in function called a Return From Interrupt routine (RETI).

You may be wondering why you would want to program using interrupts. Well consider a program where
we wish to read the dip switches connected to PORTC and display their values on the LED's connected to
PORTB. If we wrote the program in a straight structured approach we would be using a method called
polling which would be constantly reading the dip switches and show the result on the LED's for every
cycle of the program, this approach would be high inefficient as the system clock of our Atmega32 is set
to 12MHz, therefore if it took 20 clock cycles for our program to read and display the dipswitches, then
our program would be repeating every:

Now consider how fast a human can physically change the switches, maybe maybe slower.
If our switch only needs to be read every using a simple polling program for reading and
displaying the switch values, we would be reading almost 150,000 times too many per and we
would be dramatically wasting our system clock were it could be performing other tasks.

By using interrupts we could develop a code that would interrupt program flow when a particular event
occurred triggering an ISR to read the value of the dip switches and display the value on the LED's.

To understand how an interrupt works we must learn how to unmask interrupt bits, develop individual
ISR functions and how to turn on global interrupts.

112 | P a g e
For any particular Atmel microcontroller the individual interrupt bits are located within the peripherals
registers and can be found in the data sheet for any specific peripheral. This interrupt bit will be
unmasked using bitwise OR as not to affect any other settings for the peripheral.

In C programming you may think of an ISR as an interrupt function, this function works in exactly the
same manner for every interrupt and a general example of its use is provided below.

ISR(Interrupt_vect)
{
//ISR code
}

Note: Interrupt flags must be activated before an ISR can be used in your program.

As you can see from the example above the single parameter in the ISR is the interrupt vector, the
relevant vector for an interrupt can be found in the header file iom32.h (ANNEX D).

Vector Number Source Interrupt Definition ISR Parameter


1 INT0 External Interrupt Request 0 INT0_vect
2 INT1 External Interrupt Request 1 INT1_vect
3 INT2 External Interrupt Request 2 INT2_vect
4 TIMER2_COMP Timer/Counter 2 Compare Match TIMER2_COMP_vect
5 TIMER2_OVF Timer/Counter 2 Overflow TIMER2_OVF_vect
6 TIMER1_CAPT Timer/Counter 1 Capture Event TIMER1_CAPT_vect
7 TIMER1_COMPA Timer/Counter 1 Compare Match A TIMER1_COMPA_vect
8 TIMER1_COMPB Timer/Counter 1 Compare Match B TIMER1_COMPB_vect
9 TIMER1_OVF Timer/Counter 1 Overflow TIMER1_OVF_vect
10 TIMER0_COMP Timer/Counter 0 Compare Match TIMER0_COMP_vect
11 TIMER0_OVF Timer/Counter 0 Overflow TIMER0_OVF_vect
12 SPI_STC Serial Transfer Complete SPI_STC_vect
13 USART_RXC USART, Receive Complete USART_RXC_vect
14 USART_UDRE USART, Data Register Empty USART_UDRE_vect
15 USART_TXC USART, Transmit Complete USART_TXC_vect
16 ADC ADC Conversion Complete ADC_vect
17 EE_RDY EEPROM Ready EE_RDY_vect
18 ANA_COMP Analogue Comparator ANA_COMP_vect
19 TWI 2-wire Serial Interface TWI_vect
20 SPM_RDY Store Program Memory Ready SPM_RDY_vect

113 | P a g e
Once you have the interrupt bits set and the ISR developed, finally you will need to set the Global
Interrupt Bit, this is performed simple by adding the function call sei(); into your main() after you have
set the interrupt bits.

So how does an interrupt work, as your program is executing an event will occur that is related to your
interrupt, this event will allow the current instruction to complete its execution and it will halt normal
program execution and store the next instruction to be executed on the stack. Now that program
execution has halted the ISR will be called and executed, built into the ISR is an instruction call RETI,
which stands for Return From Interrupt, this instruction will retrieve the next instruction from the stack
and resume normal program flow.

In Atmel microcontrollers all interrupts have the same priority hence another interrupt cannot take
program control from an executing interrupt.

We will now perform a basic interrupt example to demonstrate the steps needed to setup the interrupt and
most importantly how to develop an ISR.

To begin with you need to add the interrupt header <avr/interrupt.h>, this header contains all the
required information to generate your interrupt and most importantly the ISR. Next you need to setup
your interrupt and activate it. All this information is contained in register for particular peripherals and
should be done by bitwise manipulation to aid with fault detection in your code. Once the interrupt is
configured and activated you will need to set Global interrupts, this final step of activation turns on any
interrupts that have been activated. Finally you need to develop your ISR, as previously stated this is just
a function that executes for a particular interrupt event, you need to decide what you want to happen and
develop the code within this function.

The example below demonstrates how an interrupt can be used to read the dip switch value of PORTC
and display the result on PORTB at approximately every , since the program will not be
continually polling the forever loop in main() can be used to perform an entirely different function. To
execute this we will be using Timer 0, which is an 8-bit timer and we will be using an interrupt that is
activated when the timer overflows (reaches 256). Timers are devices that are configured using a Pre-
scalar (they can either run at clock speed or can divide by a scalar). Here well will be using a scalar of
1024 and we can use this to prove the time period given above.

The pre-scalar settings for Timer 0 reside in register TCCR0 and 1024 can be set by the follow piece of
code.

TCCR0 |= (1<<CS00)|(1<<CS00);

114 | P a g e
Finally to set the overflow interrupt and turn on global interrupts we will be using the follow code:

TIMSK |= (1<<TOIE0);

sei();

Below is the full code example which demonstrates this introduction to interrupt programs.

#include <avr/io.h> // include avr/iom32.h

#include <avr/interrupt.h> // include functions for interrupts

// Develop the ISR for the Timer Overflow Interrupt


ISR(TIMER0_OVF_vect)
{
PORTB = PINC; // Output the dip switch value on the LED's
TCNT0 = 0x00; // Reset the counter for Timer 0
}

int main()
{
DDRB = 0xFF; // Set PORTB for Output
DDRC = 0x00; // Set PORTC for Input
PORTC = 0xFF; // Set PORTC to PULLUP MODE

TCCR0 |= (1<<CS00)|(1<<CS00); // Set Timer 0 Pre-scalar to 1024


TCNT0 = 0x00; // Reset the counter for Timer 0

TIMSK |= (1<<TOIE0); // Activate Timer 0 Overflow Interrupt


sei(); // Turn on Global interrupts

while (1);
// Could insert an entirely different operation here
return 0;
}

External Interrupts

External Interrupts are exactly what their name describes, they are interrupts that have initiating event
occurs external to the microcontroller. These interrupts exist in the form as input pins and can be
configured to initiate in one of the four following ways:

 low level
 high level
 falling edge
 rising edge

For the Atmega32 there are three external interrupts INT0 (PORTD 2) , INT1 (PORTD 3) and INT2
(PORTB 2), however INT2 can only be triggered by rising and falling inputs.

115 | P a g e
To begin enabling the External Interrupts we will need to configure how we wish the interrupt to sense
the input. For INT0 and INT1 this is done by modifying the MCU Control Register (MCUCR) as shown
below in figure 3.2.

Figure 3. 2 - From the Atmega32 Datasheet Page 66

In the MCUCR you will find the Interrupt Sense Control (ISC) bits, you can set your desired interrupt
sense by setting the ISC bits to the appropriate combination which can be found in the table below.

ISCx1 ISCx0 Interrupt Function


0 0 External Interrupt x is triggered by a low level
0 1 External Interrupt x is triggered by any change in logic level
1 0 External Interrupt x is triggered by a falling edge
1 1 External Interrupt x is triggered by a rising edge

For INT2 the ISC is found at bit 6 in the MCU Control and Status Register (MCUCSR) as seen in figure
3.3

Figure 3. 3 - From the Atmega32 Datasheet Page 67

As stated INT2 can only be sensed for a falling or raising edge as detailed in the table below.

ISC2 Interrupt Function


1 External Interrupt 2 is triggered by a rising edge
0 External Interrupt 2 is triggered by a falling edge

NOTE : A convenient fact about the External Interrupts is that Low Levels on the INT1 or INT0 and
Falling edge interrupt on INT2 are detected synchronously, therefore they can be used to wake the
microcontroller from sleep or other idle modes.

116 | P a g e
Once the interrupts sensing method is configured you will need to activate the External Interrupt in the
General Interrupt Control Register (GICR) as displayed in figure 3.2. As you can see External Interrupt 1,
0 and 2 can be enabled by setting bits 7,6 or 5 respectively. Setting the appropriate bit to a 1 will activate
the interrupt and clear the bit to a zero will deactivate the interrupt.

Figure 3. 4 - From the Atmega32 Datasheet Page 67

For completeness of this introduction I will briefly mention the External interrupt flags. These flags are
located in the General Interrupt Flag Register (GIFR), these are the flags that initiate your interrupt when
an External Interrupt event occurs. Basically when a desired event occurs on either INT0, 1 or 2 the event
will cause the appropriate flag to set and initiate the ISR for the interrupt, upon exiting the ISR the flag
will be cleared.

Figure 3. 5 - From the Atmega32 Datasheet Page 68

The ISR for the External Interrupts uses interrupt vectors 1 to 3 or INT0_vect, INT1_vect and INT2_vect.
Therefore if you are creating an ISR for an External Interrupt you must add the appropriate vector. You
could use the value of the vector, for example for INT0 the vector parameter would need to be written as
_VECTOR(1) and not just 1, I recommend sticking to the vector descriptions as the provide be the header
file iom32.h as they provide a visual aid to what interrupt an ISR is for.

Now that we have covered the External Interrupts lets develop a simple program to demonstrate putting it
all together.

This program will use INT0 and will sense on a falling edge, that is we will provide VCC to INT0 (Pin
16) and remove it to develop a falling edge. Our ISR for our INT0 event will simply toggle PORTB 0,
which is connected to an LED. However since the OUSB development board does not provide any
connections to INT0 for use to create our falling edge we will need to be a little dodgy to get this program
to work, you will need to place a small piece of wire from VCC (PIN 10) to INT0 (PIN 16) to allow INT0
to charge to VCC, then when you remove VCC from INT0, INT0 will discharge creating a falling edge,
this is not ideal but the method will serve its purpose without having to undertake the length process of
recreating the circuit on a breadboard.

117 | P a g e
#include <avr/io.h>
#include <avr/interrupt.h>

ISR(INT0_vect)
{
// Toggle PORTB 1 by performing a compounded bitwise XOR
PORTB ^= (1<<0);
}

int main()
{
DDRB |= (1 << DDB0); // Set PORTB 0 for output

// External Interrupt 0 setup

MCUCR |= (1 << ISC01); // Set the ISC01 to sense on falling edge


GICR |= (1 << INT0); // Activate INT0
sei(); // Enable the Global interrupt enable bit

while(1);
// program
return 0;
}

Reset Interrupt

Another interrupt available on the Atmega32 is the reset interrupt. However this is not like any other
interrupt as it take precedence over any other event or program execution and can be initiated in five
different ways:
 External Reset: This is where a low logic level is applied to the RESET pin for greater
that , on the OUSB development board this is achieved by pressing the reset button.
 Power On: Part on the microcontroller's power on sequence.
 Watchdog Reset: This reset occurs when the Watchdog Timer is enabled and the Watchdog
period expires.
 Brown-out Reset: When the Brown-out Detector is enable and VCC drops below the Brown-out
Reset threshold.
 JTAG AVR reset: Apart of the JTAG system.

Reset simply takes control of the program flow, ceases it, disables all interrupts and restarts the
microcontroller which will cause the microcontroller to restart at main().

118 | P a g e
IO Ports
The parallel IO ports of the Atmega32 are general purpose IO devices and the Atmega32 has four IO
ports, A, B, C and D. Each IO port is bi-directional with optional pull-ups and is configured using the
three registers where x is either port A, B, C or D:

 Data Direction Register, DDRx


 Port Data Register, PORTx
 Port Input Pins Register, PINx

The following tables display the layout of the three registers.

Data Direction Register – DDRx (Input/Output)


The Data Direction Register is used to determine whether a specific bit of a PORT is an input or output.
The DDRx contains 8-bits that corresepond to the eight pins of a port. Every specific bit relates directly to
whether the pin is an input or output. If a bit is set to one then its corresponding pin is set as an output,
therefore if a bit is set to zero then its corresponding pin is set as an input. By default ports are set to as
inputs.

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0


DDx7 DDx6 DDx5 DDx4 DDx3 DDx2 DDx1 DDx0

Port Data Register – PORTx (Input/Output)


The port data register performs two different functions depending on whether the specific bit is set as an
input or output in the DDRx.
Inputs - Setting a Port Data Register bit to 1 will enable you to use the input bit without adding an
external pull-up resistor.
Output - Setting the Port Data Register bit to 1 will create a high output at the pin, setting the bit to 0 will
create a low output at the pin.

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0


PORTx7 PORTx6 PORTx5 PORTx4 PORTx3 PORTx2 PORTx1 PORTx0

Port Input Pins Register – PINx


This Register simple reads the current state of a port whether its bits are inputs or outputs and will output
the current value of the entire 8 bits.

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0


PINx7 PINx6 PINx5 PINx4 PINx3 PINx2 PINx1 PINx0

119 | P a g e
You should note also that the port pins are capable of sinking when Vcc is and when
Vcc is but as with all devices they are not recommended to directly drive devices from their ports.
However on page 49 of the Atmega32 datasheet Atmel state that it is safe to drive LED's directly from the
IO ports, what I'm getting at is I would not consider driving a load an larger than an LED directly from a
port pin as your program most probably will not function correctly and you could damage your
microcontroller.

The table below states the relationship between DDRx and PORTx on how to establish Input or Output
pins on the Atmega32 microcontroller.

DDRx PORTx I/O Description


0 0 Input Tri-state (Hi - Z), Pull up disabled
0 1 Input Source current if externally pulled low, Pull up enabled
1 0 Output Output Low (Sink)
1 1 Output Output High (Source)

The following program demonstrates what we have just covered. The program commences by setting all
bits of PORTB as outputs (Display on LED's) and all bits of PORTC as inputs (Read Dip Switches). Then
the program enters an initialisation sequence shown by a pattern of active LED's separated by delays
between the patterns. Finally the program enters the forever loop which demonstrates once again the
polling technique or reading a port. As you may notice this is a highly inefficient method of reading a
port, the interrupt method of using timer overflow is a much better implementation.

#include <avr/io.h>
#include <util/delay.h>
#define DELAY 500 // 500 ms delay

int main()
{
DDRC = 0x00; // Not needed as DDRx is zero by default
PORTC = 0xFF; // Set PORTC for pull-up on every pin
DDRB = 0xFF; // Set PORTB as output on every pin
PORTB = 0x00; // Set PORTB in Known state
// Start LED Sequence
PORTB = 1;
for(int i = 0 ; i < 7 ; i++)
{
_delay_ms(DELAY); // create 500ms delay

PORTB = PINB*2; // increment to the next LED


}
_delay_ms(DELAY); // create 500ms delay

while(1)
// display the Dip Switch values on the LEDs
PORTB = PINC;
return 0;
}

120 | P a g e
Watch Dog Timer
The watchdog timer is a peripheral which performs an interrupt reset if the timer is allowed to timeout.
The purpose of developing your code with the watchdog timer is to incorporate code which continually
resets the timer and ensure that under correct operation the timer will never timeout. Therefore if the
processor hangs or the program gets confused the watchdog timer will timeout and force an interrupt
reset, which will restart your entire program from the beginning of main().

The watchdog timer is clocked from a separate oscillator which is set at 1Mhz with a Vcc = 5V. The timer
reset interval is the length of time that the watchdog timer can run for before it times out. This interval is
determined by the setting the Watchdog Timer Prescaler bits (WDPx) which reside in the Watchdog
Timer Control Register (WDTCR) which is displayed below.

Figure 3. 6 - From the Atmega32 Datasheet Page 42

The WDPx bits determine how many cycles of the watchdog oscillator will occur before a timer overflow
is flagged. The time can be determined by the following formula:

However this formula cannot be entirely depended on as an oscillators frequency is dependent on Vcc, for
the OUSB development board the Vcc = 5V and the oscillator will run at the expected 1Mhz, however as
shown in the figure below if Vcc is less than 5V, say 3V the oscillator will decrease in frequency to
around 0.936 MHz thus changing the watchdog interval. The table below however displays what WDPx
bits to set from a set amount of oscillator cycles and using the formula above you can determine a rather
accurate Watchdog interval.

Figure 3. 7 - From the Atmega32 Datasheet Page 42

121 | P a g e
Once the watchdog interval has been configure the watchdog timer needs to be enabled in the WDTCR by
setting the Watchdog Enable (WDE) bit.

Because the watchdog timer is considered a safety device to disable it after enabling a certain procedure
needs to be followed, this prevents situations where the timer could be accidentally disabled.
 In the same statement write a logic 1 to the Watchdog Turn-off Enable (WDTOE) and WDE bits
of the WDTCR. (yes write 1 to WDE even if it is set)
 Within the next four clocks write a logic 0 to the WDE bit of WDTCR to disable the watchdog
timer.

The final piece of knowledge needed to create a program using a watchdog timer is the watchdog timer
reset function, wdt_reset() and the watchdog timer header file <avr/wdt.h>, both of these will allow
you to successfully create a program using the watchdog timer.

So let's create the example program. This program will set PORTB for outputs and PORTC for inputs
with pull-ups enabled. The variable halt will store the initial value of the dip switches (PORTC) and will
toggle PORTB 0 until the dip switch values is changed. Once the dip switch values are changed the
program will fall out of it current loop, store the changed value of the dip switches and setup the
watchdog timer for an interval length of about 2 seconds. The program will then enter the second loop
which will reset the watchdog timer for every repetition of the loop and toggle PORTB 7. Finally once the
dip switches change again the program will fall into a forever loop and the watchdog timer will time out
forcing a reset interrupt ceasing the forever loop and restarting the program to the start of main().

#include <avr/io.h> // include avr/iom32.h


#include <avr/wdt.h> // include functions WDT
#include <avr/delay.h> // Include _delay_ms()

#define DELAY 300 // delay 300ms


int halt = 0;

int main()
{
DDRB = 0xFF; // Set PORTB for Output
DDRC = 0x00; // Set PORTC for Input
PORTC = 0xFF; // Set PORTC to PULLUP MODE

halt = PINC; // assign the Dip Switch value to halt


// while the dip switch remains unchanged toggle PB0
while(halt == PINC)
{
PORTB ^= (1 << PB0);
_delay_ms(DELAY);
}
// setup WDT
WDTCR |= (1 << WDE)|(1 << WDP0)|(1 << WDP1)|(1 << WDP2);
halt = PINC; // assign the Dip Switch value to halt

122 | P a g e
// while the dip switch remains unchanged toggle PB7 and reset WDT
while(halt == PINC)
{
wdt_reset();

PORTB ^= (1 << PB7);


_delay_ms(DELAY);

while(1); //WDT times out

return 0;
}

However the previous example displayed the knowledge we had gained so far on how to configure the
watchdog timer in the WDTCR, however there is a simpler way. In the header <avr/wdt.h> we have
two functions wdt_enable() and wdt_disable(). These two functions perform the operations described by
their names, one enables the watchdog timer and the other disables.

However the wdt_enable() must contain a value from 0 to 7 in its parameter list which describes the
interval length of the timer, thankfully the header includes some #define statements that define the time
intervals available and is of the form WDTO_time. The available time intervals are 15 ms, 30 ms, 60 ms,
120 ms, 250 ms, 500 ms, 1 s and 2 s. The table below describes all available intervals and #defines

#define Interval Time


WDTO_15MS 15 ms
WDTO_30MS 30 ms
WDTO_60MS 60 ms
WDTO_120MS 120 ms
WDTO_250MS 250 ms
WDTO_500MS 500 ms
WDTO_1S 1s
WDTO_2S 2s

123 | P a g e
Now let's write the last program using the wdt_enable() function.

#include <avr/io.h> // include avr/iom32.h


#include <avr/wdt.h> // include functions WDT
#include <avr/delay.h> // Include _delay_ms()

#define DELAY 300 // delay 300ms


int halt = 0;

int main()
{
DDRB = 0xFF; // Set PORTB for Output
DDRC = 0x00; // Set PORTC for Input
PORTC = 0xFF; // Set PORTC to PULLUP MODE

halt = PINC; // assign the Dip Switch value to halt


// while the dip switch remains unchanged toggle PB0
while(halt == PINC)
{
PORTB ^= (1 << PB0);
_delay_ms(DELAY);
}

// setup WDT with 2s interval length


wdt_enable(WDTO_2S);

halt = PINC; // assign the Dip Switch value to halt


// while the dip switch remains unchanged toggle PB7 and reset WDT
while(halt == PINC)
{
wdt_reset();
PORTB ^= (1 << PB7);
_delay_ms(DELAY);

while(1); //WDT times out

return 0;
}

124 | P a g e
Timers/Counters
The Atmega32 has three different timers; there are two 8-bit timers, Timers 0 and 2, and one 16-bit timer,
Timer 1. These timers give the programmer the ability to measure time, create events at time intervals and
create Pulse Width Modulated (PWM) signals; however all of these operations are based around a binary
up or down counter.

To understand the operation of timer/counter of the Atmega32 you need to recognise that a timer will
count until it reaches a maximum and then rolls over. Since we have two 8-bit timers and one 16-bit timer
the maximum count will differ for the two different types. For an 8-bit timer the maximum count will be
255 and for a 16-bit timer the maximum count will be 1023. Once the maximum count is reached the next
clock pulse will reset the timer, this event can be used effectively by programmers and has an Interrupt
and flag assigned for its use.

Another general fact about timers is the timer resolution; this is the smallest amount of time a timer can
measure. Soon you will learn that the timer clock frequency differs from that supplied by the OUSB
development board's external crystal which clocks at 12MHz. The timers have a feature called
prescaling that allows you to reduce the clock frequency of the timer to make it more versatile. Therefore
the defined timer frequency directly effects the smallest single time period a timer can measure. This time
period can be determined by the following formula:

Timer Prescaler
Timer prescalers are available for each of the three timers and they simply divide the system clock to
create a desirable frequency for use with the defined timer using the Clock Select (CS) bits. Therefore
each timer has its own prescaler, Timers 0 and 1 have the same prescaling options that are shown in the
table below where x could signify 0 or 1 for Timer 0 or Timer 1:
CSx2 CSx1 CSx0 Interrupt Function
0 0 0 Stop, Timer x is stopped
0 0 1 System Clock
0 1 0 System Clock / 8
0 1 1 System Clock / 64
1 0 0 System Clock / 256
1 0 1 System Clock / 1024
1 1 0 External Pin Tx, Counts a falling edge
1 1 1 External Pin Tx, Counts a rising edge

Note Tx is a pin and once again the x signifies that Timer 0 and Timer 1 both have these external pins that
can have an external triggers supplied rather than applying the prescaler to the system clock, therefore this
feature allows for software control of counting.

125 | P a g e
Timer 2 has its own prescaler and it configuration options are shown in the table below, as you can see
Timer 2 differs and does not provide the ability to be triggered by external pulses, however Timer 2 does
provide an asynchronous mode which uses an external crystal connected to pin TOSC1, however this
mode is beyond the scope of this manual.
CS22 CS21 CS20 Interrupt Function
0 0 0 Stop, Timer 2 is stopped
0 0 1 System Clock, CK
0 1 0 System Clock / 8, CK/8
0 1 1 System Clock / 32, CK/32
1 0 0 System Clock / 64, CK/64
1 0 1 System Clock / 128, CK/128
1 1 0 System Clock / 256, CK/256
1 1 1 System Clock / 1024, CK/1024

As you now realise the CS bits modify the system clock for use with the timers, for each of the timers the
CS bit resides in the first three bits of Timer/Counter Control Register x (TCCRx) again where x signifies
0,1 or 2 for the specific timer.

Timer 0
The first timer we are going to cover is Timer 0, as previously stated it is an 8-bit timer which can be
prescaled. It has the ability to act as a counter, timer and PWM. Before we examine how Timers and
Counters work with some example codes, let us explore the registers for Timer 0 so that we can complete
the first part of any successful program, configuring the peripheral.

The control register for Timer 0 is the Timer/Counter Control Register 0 (TCCR0) and can be seen in the
figure below.

Figure 3. 8 - From the Atmega32 Datasheet Page 80

The first three bits of this register are the Clock Select bits for Timer 0 as previously defined.

CS02 CS01 CS00 Interrupt Function


0 0 0 Stop, Timer x is stopped
0 0 1 System Clock
0 1 0 System Clock / 8
0 1 1 System Clock / 64
1 0 0 System Clock / 256

126 | P a g e
1 0 1 System Clock / 1024
1 1 0 External Pin Tx, Counts a falling edge
1 1 1 External Pin Tx, Counts a rising edge

Bit 3 and bit 6 are the two bits for Timer 0 that determine the output format of the Timer; these bits are
called the Waveform Generation Mode (WGM) bits.

As you can see from the table above the combination of the WGM bits determines the Timer 0 mode
used.

Normal Mode - This mode of operation is the simplest mode of running Timer 0, in this mode the timer
counts up until it reaches its 8-bit maximum, 255 and then restarts at, 0 and continues to count up again,
this counting take place in the Timer/Counter Register 0 (TCNT0) which holds the current count up
value. In this mode the Timer/Counter Overflow Flag (TOV0) will set when the TCNT0 register is
clocked to zero. It should be noted that this flag will not automatically clear without using an interrupt.
The interrupt that is triggered by the TOV0 flag is the interrupt Timer/Counter Overflow Interrupt and
when this interrupt is enabled along with global interrupts it will be called clearing the TOV0 flag.

It should be noted that the counter register TCNT0 can be set to any 8-bit value at anytime so that the user
can develop required timing signals.

In normal mode you should not use any output compare features that utilise the output compare register as
other modes of the timer are designed for this function.

Phase Correct PWM mode - The Phase correct PWM mode provides a PWM signal that is phase
correct.
The following image depicts the phase correct PWM signal compared with a standard PWM signal. Note
the image is from AVR freaks which is a site developed for the AVR community and is a great source of
source codes and tutorials.

The link where the image is for is:

http://www.avrfreaks.net/index.php?name=PNphpBB2&file=printview&t=68302&start=100

127 | P a g e
As you can see a normal PWM signal is triggered at the beginning of a time interval, where as the phase
correct PWM signal maintains a centre point, thus the center of the active region is equal for different
pulse widths.

All PWM modes utilise the Output Compare Register (OCR), the OCR0 is Timer 0's compare register and
it holds an 8-bit value that is compared with TCNT0 every time a count occurs. For the Phase correct
PWM mode the TCNT0 counts from 0 to 255 comparing its value to OCR0 after every count, if they
match then the PWM output pin Timer/Counter0 Output Compare Match or simply OC0 (PORTB 3
needs to be set as an output) will clear to zero when the PWM is in non-inverting mode. When TCNT0
reaches its maximum it will update the OCR0 register with any pending value for the register, if OCR0 is
set to the maximum value of 255 and is not changed the PWM is set to 100 percent duty cycle or fully on.
The TCNT0 will begin to count down from its maximum, at every count down once again the OCR0
register is compared with TCNT0 for a match, if the match on the falling count the OC0 pin will be set
high in the non-inverting mode. If the OCR0 register is constantly set to the minimum value of zero, the
output will be continuously Low.
An additional feature of the phase PWM mode is that when the TCNT0 counts from 255 down to zero,
upon reaching zero the TOV0 flag will set allowing for the Timer/Counter Overflow Interrupt to be
implemented.

The following formula determines the frequency of the Phase Correct PWM:

128 | P a g e
Figure 3. 9 - From the Atmega32 Datasheet Page 76

Clear Timer on Compare Match (CTC) Mode - Yes this mode has a long name but its operation
thankfully is simple. For CTC mode we store an 8-bit value in the OCR0 register which will be used to
change the maximum count of the TCNT0 register. In CTC mode the counter register TCNT0 is cleared
when its value matches the value stored in the OCR0. As you can deduce the OCR0 defines the maximum
value that TCNT0 can count up to and thus changing the resolution or time period. This method of
counting is very efficient as it provides an accurate method of determining a time period and the majority
of the operation is performed by hardware hiding complexity from the programmer. As you may expect
when a compare occurs a flag will be set. The flag which is set is the Output Compare Flag 0 (OCF0),
which can be checked in a polling program by the following segment of code:

if(TIFR & (1 << OCF0))


{
// Do something
}

However this flag does not automatically clear itself as it is generally used by an interrupt which will reset
it. However you can clear it by writing a 1 to it, this may sound strange but this task is typically reserved
for hardware and is a point worth noting. The following code fragment will reset the OCF0 flag:

TIFR = (1 << OCF0);

Note that a single assignment symbol is used and not a compound or statement, this is very important as
the compound or will affect other flags in this register.

129 | P a g e
This mode has its own interrupt which is the Timer/Counter0 Output Compare Match Interrupt, when
enabled by the setting the OCIE0 flag with global interrupts enabled the interrupt will call the interrupts
ISR when the OCF0 becomes set when the TCNT0 counter is equal to the value stored in the OCR0. This
interrupt routine will create a situation where an event occurs at a regular time interval defined by the
time taken for TCNT0 to count up to the value of OCR0. As stated previously when the interrupt is
enabled and the interrupt is called by the OCF0 flag, the interrupt will independently reset the OCF0 flag
automatically unlike the polling method described above. The datasheet also states if the OCCR0 is
changed during the interrupt to a value lower than the current value of the TCNT0 register, the counter
will continue to count up to the absolute maximum 255 and will reset the TCNT0 register to zero before a
compare match occurs.

CTC mode can be configured to create an output on the OC0 output pin, to generate this output the OC0
pin needs to be set as an output by the Data Direction Register, this output can be set to toggle the logic
value, set to logic level high or set to logic level low upon a compare of the TCNT0 and the OCR0
registers.

When the output waveform is set to toggle the frequency is defined by the following formula:

The following diagram is from the Atmega32 datasheet and shows the resultant of CTC mode set to
toggle mode.

Figure 3. 10 - From the Atmega32 Datasheet Page 74

Fast PWM Mode - This method of PWM is similar to the phase correct PWM mode as you would
expect, however the PWM output pin OC0 is cleared when the OCR0 value is equal to the TCNT0 count,
the TCNT0 will continue to count up and reset once the maximum value of 255 has been reached. Instead

130 | P a g e
of counting down like in the phase correct mode the PWM will reset to zero and begin to count up again.
When the TCNT0 is reset the output pin OC0 will trigger and will be set assuming non-inverting mode is
being used.

This process can be seen in the figure below, as you might be able to determine if the OCR0 register is set
to the maximum value the PWM will be fully on, and if the OCR0 is set to the minimum value the PWM
is fully off.

Figure 3. 11 - From the Atmega32 Datasheet Page 75

The formula for the frequency of the PWM signal in fast PWM mode is:

Now that we have covered the operation modes of the TCCR0 register let us continue and define the rest
of the bits in TCCR0.

Bits 4 and 5 define the different available output modes of the of the OC0 pin at PORTB 3. The following
figures define the available modes which are different for the three waveform modes of CTC, Phase
Correct PWM and Fast PWM.

CTC mode has the ability to:


 Have no output
 Toggle on compare match
 Clear on compare match
 Set on compare match

131 | P a g e
Figure 3. 12 - From the Atmega32 Datasheet Page 81

Phase Correct PWM mode has the ability to:


 Have no output
 Non-Inverting Mode (Clear on Counting Up Match - Set On Counting Down Match)
 Inverting Mode (Set on Counting Up Match -Clear On Counting Down Match)

Figure 3. 13 - From the Atmega32 Datasheet Page 81

132 | P a g e
Fast PWM mode has the ability to:
 Have no output
 Inverting Mode
 Non-Inverting Mode

Figure 3. 14 - From the Atmega32 Datasheet Page 81

 Bit 7 - Force Output Compare (FOC0), this flag is used when Timer0 is in a non-PWM mode. It
causes an output on the OC0 pin defined by the settings in the COM00 and COM01 bits of the
TCCR0, and when is set high will create the desired output just as if a compare match had
occurred.

TCNT0 and OCR0 have already been defined as 8-bit buffers; OCR0 simply holds a defined value where
TCNT0 hold a value that is either incrementing or decrementing defined by its operation. They are shown
below but there is no need to discuss them in detail, just note if TCNT0 or OCR0 is modified in compare
mode and the compare is missed, the compare will not occur until the next cycle sees a match.

Figure 3. 15 - From the Atmega32 Datasheet Page 82

Figure 3. 16 - From the Atmega32 Datasheet Page 82

133 | P a g e
The final two registers that effect Timer 0 are the registers Timer/Counter Interrupt Mask Register
(TIMSK) and Timer/Counter Interrupt Flag Register (TIFR). These registers are not dedicated to just
Timer 0, they hold bits that are specifically for Timers 1 and 2 also. Therefore we will only discuss the
bits that directly affect Timer 0 at this time.

Starting with TIMSK, this register is used to enable the two available interrupts for Timer 0, being the
Timer/Compare0 Output Compare Match Interrupt and the Timer/Counter0 Overflow Interrupt, both of
their enables can be seen in the figure below.

Figure 3. 17 - From the Atmega32 Datasheet Page 82

Where:

 Bit 0 - Timer/Counter0 Overflow Interrupt Enable (TOIE0), to enable this interrupt set it and also
enable global interrupts, this interrupts ISR will be called when the TOV0 flag is set by a timer
overflow, the interrupt will automatically reset TOV0 upon calling.
 Bit 1 - Timer/Compare0 Output Compare Match Interrupt Enable (OCIE0), to enable this
interrupt set it and also enable global interrupts, this interrupts ISR will be called when the OCF0
flag is set when OCR0 and TCNT0 registers are equal, this interrupt will automatically reset
OCF0 upon calling.

The final register TIFR holds the bits for the Output Compare Flag 0 (OCF0) and Timer/Counter0
Overflow Flag (TOV0), both can be seen in the figure below.

Figure 3. 18 - From the Atmega32 Datasheet Page 83

Where:

 Bit 0 - TOV0, this flag is set when a timer overflow occurs, however in the Phase Correct PWM
mode the overflow will occur when TCNT0 changes direction at the minimum value zero. This
flag is cleared automatically only when used with an interrupt, in can be cleared manually by
writing a 1 to it, ( TIFR = (1 << TOV0);)

134 | P a g e
 Bit 1 - OCF0, this flag is set when the value of OCR0 equals TCNT0. This flag is cleared
automatically only when used with an interrupt, in can be cleared manually by writing a 1 to it,
(TIFR = (1 << OCF0);)

Below are three example codes that demonstrate the use of Timer 0 in polling programs, the three
different programs display timer overflow, timer compare and timer compare output. They provide a basic
insight into how this peripheral can be used to create accurate time delays and trigger an event at regular
time intervals.

135 | P a g e
Timer 0 Polling using Timer Overflow
#include <avr/io.h> // include avr/iom32.h

int main(void)
{
DDRB |= 0x0F;

// Timer0 Frequency set for (System Clock / 1024)


TCCR0 |= (1<<CS02)|(1 << CS00);

// Time Period between overflows


// Time Resolution = (Prescaler)/(system Clock)
// Time Period = 256 * Time Resolution
// Time Period = 256 * (1024/12MHz) = 21.84ms

TCNT0 = 0;

while(1)
{
if(TIFR & (1<<TOV0))
{
//toggle every 21.84 ms
PORTB ^= 0x0F;

TIFR = (1<<TOV0);
}
}

return 0;
}

136 | P a g e
Timer 0 polling CTC example

#include <avr/io.h> // include avr/iom32.h

int main(void)
{
DDRB |= 0x0F;

TCCR0 |= (1<<CS02)|(1 << CS00);

TCCR0 |= (1<<WGM01);

// Time Resolution = (Prescaler/system clock (Hz))


// Target Timer OCR0 Value = ((Target time(s))/(Prescaler/system
// clock(Hz)) ) - 1
// Target Time delay = 2.55ms
// OCR0 = (20.56ms)/(1024/12MHz) - 1
// OCR0 = 239.9 = 240
// As you can see the OCR0 Value is not exact and there is small error,
// this is typical with
// digital devices as there is only a finite amount of values available
// to select from.

OCR0 = 240;
TCNT0 = 0;
while(1)
{

if(TIFR & (1 << OCF0))


{
PORTB ^= 0x0F; // Toggle PORT lower nibble
TIFR = (1 << OCF0);

return 0;
}

137 | P a g e
Timer 0 polling CTC output compare example

#include <avr/io.h> // include avr/iom32.h

int main(void)
{
DDRB |= (1<< PB3); // Set PB3 to output

// Set Timer0 for CTC mode


TCCR0 |= (1<<WGM01);

// Set OC0 (PB3) to Toggle Mode


TCCR0 |= (1<< COM00);

// Time Resolution = (Prescaler/system clock (Hz))


// Target Timer OCR0 Value =
// ((Target time(s))/(Prescaler/system clock(Hz)) ) - 1
//
// Target Time delay = 2.55ms
// OCR0 = (20.56ms)/(1024/12MHz) - 1
// OCR0 = 239.9 = 240
// As you can see the OCR0 Value is not exact and there is small error,
// this is typical with
// digital devices as there is only a finite amount of values available
// to select from.

OCR0 = 240;
// Timer0 Frequency set for (System Clock / 1024)
TCCR0 |= (1<<CS02)|(1 << CS00);

TCNT0 = 0;

while(1);

return 0;
}

138 | P a g e
Timer 0 PWM

#include <avr/io.h>

int control = 0;
int output = 0;

void Initialise()
{
// IO PORTS
DDRB |= (1<<DDB3); // set PORTB 3 for output
PORTC = 0xFF;

// PWM Timer
TCCR0 |= (1<<WGM00); // 8 bit PWM0
TCCR0 |= (1<<CS01); // Clk / 8
TCCR0 |= (1<<COM01); // Compare Match Clears OC0 to zero
}

int Read()
{
control = PINC;
switch(control)
{
//NOTE: the dip switches is inverted
case 254: // PORTC reads 1
output = 31; // PWM0 Fully on 12.5%
break;
case 252: // PORTC reads 3
output = 128; // PWM0 Fully on 50%
break;
case 248: // PORTC reads 7
output = 204; // PWM0 Fully on 80%
break;
case 240: // PORTC reads 15
output = 255; // PWM0 Fully on 100%
break;

default: // anything else turn off PWM0


output = 0;
break;
}

return output;
}

int main()
{
Initialise();

while(1) // forever loop


{
OCR0 = Read(); // Set PWM to defined value
}
return 0;
}

139 | P a g e
Timer 1
Now that you have been introduced to timer 0 which contains the basic timer features of timer compare,
timer overflow and PWM it is now time to introduce Timer 1, which is a 16-bit timer which has all of the
features of Timer 0 plus additional PWM modes and an input capture mode that lets you measure how
many events occur in a time period.

Since Timer 1 is similar to Timer 0 it is still prescaled in the same manner to modify the clock speed of
the binary counter.

Since Timer 1 is a 16-bit timer its registers are different to that of Timer 0. Timer/Counter Register 1
(TCNT1) is made up of two 8-bit register TCNT1H and TCNT1L to create a 16-bit register. Unlike the
single 8-bit output compare register OCR0 of Timer 0, Timer 1 has two 16-bit output compare which are
named OCR1A which is made up of two 8-bit registers OCR1AH and OCR1AL, and OCR1B which is
made up of two 8-bit register OCR1BH and OCR1BL. Since Timer 1 has additional features it also needs
a larger control register, thus the control register for Timer 1 is also a 16-bit register divided into two
registers which are TCCR1A and TCCR1B and to account for the additional input capture feature there is
and additional 16-bit register called the Input Capture Register 1 (ICR1) and it also divides into two 8-bit
register which are ICR1H and ICR1L.

Now that we are working with two 8-bit registers for the counter TCNT1 and the compare and capture
registers we need a method of combining them to create a 16-bit value, this can be done by the following
code segment where High is the high 8-bits (65635-256) and Low is the lowest 8-bit (255-0) and result is
an unsigned integer that can store a 16-bit value. Also displayed is the situation is the need to disable any
interrupts, because an interrupt can occur between the read sequences and corrupt the data held in the
registers.
char sreg = SREG; // Save the state of the Global interrupts flag

cli(); // Disable interrupts

unsigned int Result = High*256 + Low;

SREG = sreg; // Restore Global interrupts

The method displayed above must also be employed for a write to the TCNT1 register, the example below
shows writing the value of OCR1A to the TCNT1 register, while interrupts are disabled.

char sreg = SREG; // Save the state of the Global interrupts flag

cli(); // Disable interrupts

TCNT1 = OCRA1H*256 + OCRA1L;

SREG = sreg; // Restore Global interrupts

Now that we have introduced Timer 1 let us explore the how to configure this complex timer.

140 | P a g e
We will start with the control registers TCCR1A and TCCR1B. Both of these registers contain bits that
we have already seen such as Clock Select bits, Waveform Generator Mode bits, Compare Output Mode
bits, Force Output Compare bits and now the Input Capture bits. However the combinations used in
Timer 0 are not identical and require us to explore them again to understand the capabilities of Timer 1.

As we explore TCCR1 to understand the WGM bits of timer 1 you will need to use both TCCR1A and
TCCR1B as both 8-bit register contain WGM bits, with that said let us explore the WGM bits first. Timer
1 has four WGM bits that are found in TCCR1A bits 0 and 1 and TCCR1B bits 3 and 4. The table below
from the Atmega32 datasheet describes the combinations of the WGM bits needed to create desired
waveform outputs.

Figure 3. 19 - From the Atmega32 Datasheet Page 109

From the table above you can see that different combinations signify different waveform outputs.

Normal mode - WGM bits all clear.

CTC Mode - WGM 12 set, WGM 11 and WGM 10 clear


 WGM 13 set - OCR1A
Clear Timer Compare mode, same as Timer 0 except OCR1A is a 16-bit value, so when TCNT1
is equal to the value in OCR1A in this mode TCNT1 will reset and set the OCF1A flag.
 WGM 13 clear - ICR1
Clear Timer Compare mode, same as above except ICR1is compared withTCNT1 and if they are
equal TCNT1 resets and sets the ICF1 flag.

141 | P a g e
PWM 8,9 or 10 - bit - WGM 14 clear and WGM 13 set
 Phase Correct PWM mode
This modes compare the value of TCNT1 to OCR1A or OCR1B and only count up to the
maximum value define by the formula, once the maximum is reached it counts back down as
defined in Timer 0:

PWM 8,9 or 10 - bit - WGM 14 and WGM 13 clear


 Fast PWM mode
Again this mode compares TCNT1 to OCRA1 or OCR1B and only counts up to the maximum
defined by the formula given, once the maximum is reached the register TCNT1 resets to zero
and counts back up again.

The remaining modes are 16-bit PWM modes that either us the register OCR1A or ICR1 and is very
similar to the modes previously defined in Timer 0.

Now that the WGM bits have been covered we can go back to the TCCR1A register and cover the
remaining options, TCCR1A is seen in the figure below.

Figure 3. 20 - From the Atmega32 Datasheet Page 107

Where
 Bit 2 - Force Output Compare for unit A (FOC1A), this flag is used when Timer 1 is in a non-
PWM mode. It causes an output on the OC1A pin defined by the settings in the COM1A0 and
COM1A1 bits of the TCCR1A, and when is set high will create the desired output just as if a
compare match had occurred.
 Bit 3 - Force Output Compare for unit B (FOC1B), this flag is used when Timer 1 is in a non-
PWM mode. It causes an output on the OC1B pin defined by the settings in the COM1B0 and
COM1B1 bits of the TCCR1A, and when is set high will create the desired output just as if a
compare match had occurred.

The following describes the use of the COM bits, note that COM1A 0 and 1 relate to the output pin
OC1A and is triggered by the flag OCF1A which means that TCNT1 is equal to OCR1A. The remaining
bits, COM1B relate to OC1B and that is triggered by the flag OCF1B, which means that TCNT1 is equal
to OCR1B. Note that OC1A and OC1B need to be set to output mode in the DDR for the output to occur.

142 | P a g e
CTC mode has the ability to:
 Have no output
 Toggle on compare match
 Clear on compare match
 Set on compare match

Figure 3. 21 - From the Atmega32 Datasheet Page 107

Phase Correct PWM mode has the ability to:

 Have no output
 Inverting Mode (Set on Counting Up Match - Clear On Counting Down Match)
 Non-Inverting Mode (Clear on Counting Up Match - Set On Counting Down Match

Figure 3. 22 - From the Atmega32 Datasheet Page 108

143 | P a g e
Fast PWM mode has the ability to:
 Have no output
 Inverting Mode
 Non-Inverting Mode

Figure 3. 23 - From the Atmega32 Datasheet Page 108

The second control register TCCR1B holds the Clock select bits, the other half of the WGM bits and two
new bits which are the Input Capture Noise Canceller (ICNC1) and the Input Capture Edge Select
(ICES1). The figure below displays the TCCR1B register.

Figure 3. 24 - From the Atmega32 Datasheet Page 110

144 | P a g e
The table below displays the available combinations of the CS to select the prescaler; this is identical to
that of Timer 0.
CS12 CS11 CS10 Interrupt Function
0 0 0 Stop, Timer 1 is stopped
0 0 1 System Clock
0 1 0 System Clock / 8
0 1 1 System Clock / 64
1 0 0 System Clock / 256
1 0 1 System Clock / 1024
1 1 0 External Pin Tx, Counts a falling edge
1 1 1 External Pin Tx, Counts a rising edge

Let us explore the two new bits

ICNC1 - This flag is an option for the input capture function, when set the Input Capture Pin (ICP1) is
filtered, therefore an input is required to be stable for four successive cycles of the system clock. When
this pin gets disabled it will take four clock cycles for this action to occur.

ICES1 - This flag determines what edge of the clock triggers the ICP.
 ICES1 set - sets ICP for Rising Edge Triggering (High to Low)
 ICES1 clear - set ICP for Falling Edge Triggering (Low to High)
The ICES1 works by copying the contents of TCNT1 into the ICR1 register every time the ICP1 is
triggered. This means when an event occurs you can record the time it occurred, and when the next event
occurs you can record the time of the second event and determine the time difference between them. Or
you could increment a value every time the ICP1 triggered to record how many inputs occurred over a
defined time period.
The input capture feature cannot be used when IRC1register is being used in a PWM mode. When it is
being used in a PWM mode the ICP1 pin is disabled thus input capture is disabled.

145 | P a g e
The following figures simply display the register TCNT1, OCR1A, OCR1B and ICR1to enable you to
physical quantify how they tie together. These figures below clearly demonstrate that there are two 8-bit
register that make on larger 16-bit register, each 16-bit register is made up of a high byte and low byte.

Figure 3. 25 - From the Atmega32 Datasheet Page 111

Figure 3. 26 - From the Atmega32 Datasheet Page 111

Figure 3. 27 - From the Atmega32 Datasheet Page 111

The TIMSK register is common to all three Timers, Timer 1 uses bits 2-5 and these bits enable any of the
four interrupts for Timer 1 to be enabled when global interrupts is enabled, the following describes these
four interrupts and how they are triggered.

Figure 3. 28 - From the Atmega32 Datasheet Page 112

146 | P a g e
Where:

 Bit 2 - Timer/Counter1 Overflow Interrupt Enable (TOIE1), to enable this interrupt set it and also
enable global interrupts, this interrupts ISR will be called when the TOV1 flag is set by a timer
overflow, the interrupt will automatically reset TOV1 upon calling.
 Bit 3 - Timer/ Counter1 Output Compare Match Interrupt Enable Unit B (OCIE1B), to enable this
interrupt set it and also enable global interrupts, this interrupts ISR will be called when the
OCF1B flag is set when OCR1B and TCNT1 registers are equal, the interrupt will automatically
reset OCF0 upon calling.
 Bit 4 - Timer/ Counter1 Output Compare Match Interrupt Enable Unit A (OCIE1A), to enable
this interrupt set it and also enable global interrupts, this interrupts ISR will be called when the
OCF1A flag is set when OCR1A and TCNT1 registers are equal, the interrupt will automatically
reset OCF0 upon calling.
 Bit 5 - Timer/ Counter1 Input Capture Interrupt Enable (TICIE1), to enable this interrupt set it
and also enable global interrupts, this interrupts ISR will be called when the ICF1 flag is set when
an event is triggered on the ICP1 pin, the interrupt will automatically reset OCF0 upon calling.

The Final register for Timer 1 is the TIFR register, and just like TIMSK it shares itself with the other two
Timers and contains flags that signify if an event has occurred, these flags can be used by interrupts or for
polling type programs.

Figure 3. 29 - From the Atmega32 Datasheet Page 112

Where:

 Bit 2 - TOV1, this flag is set when a timer overflow occurs, however in the Phase Correct PWM
mode the overflow will occur when TCNT1 changes direction at the minimum value zero. This
flag is cleared automatically only when used with an interrupt, in can be cleared manually by
writing a 1 to it, ( TIFR = (1 << TOV1);)
 Bit 3 - OCF1B, this flag is set when the value of OCR1B equals TCNT1. This flag is cleared
automatically only when used with an interrupt, in can be cleared manually by writing a 1 to it,
(TIFR = (1 << OCF1B);)
 Bit 4 - OCF1A, this flag is set when the value of OCR1A equals TCNT1. This flag is cleared
automatically only when used with an interrupt, in can be cleared manually by writing a 1 to it,
(TIFR = (1 << OCF1A);)
 Bit 5 - ICF1, this flag is set when a trigger event occurs on the ICP1 pin. This flag is cleared
automatically only when used with an interrupt, in can be cleared manually by writing a 1 to it,
(TIFR = (1 << ICF1);)

147 | P a g e
Below is a code example provided for the PWM of Timer 1, however this examples will require you to
make external connections to the OUSB development board using the break out pins available on J4 and
J5. There is no input capture configured on the OUSB development board and no example program is
provided, for more information on input capture use the following link:

http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=50106

Timer 1 PWM

#include <avr/io.h>

int control = 0;
int output = 0;

void Initialise()
{
// IO PORTS
DDRD |= (1<<DDD5); // set PORTD 5 for output
PORTC = 0xFF;
// PWM Timer
TCCR1A |= (1<<WGM10); // 16 bit PWM1 Phase Correct Mode
TCCR1B |= (1<<CS11); // Clk / 8
TCCR1A |= (1<<COM1A1); // Compare Match Clears OC0 to zero
}

int Read()
{
control = PINC;
switch(control)
{
case 254: // PORTC reads 1 (NOTE: the dip switches are
inverted)
output = 128; // PWM0 Fully on 12.5%
break;
case 252: // PORTC reads 3
output = 511; // PWM0 Fully on 50%
break;
case 248: // PORTC reads 7
output = 818; // PWM0 Fully on 80%
break;
case 240: // PORTC reads 15
output = 1023; // PWM0 Fully on 100%
break;

default: // anything else turn off PWM0


output = 0;
break;
}

return output;
}

148 | P a g e
int main()
{
Initialise();
while(1) // forever loop
{
OCR1A = Read(); // Set PWM to defined value
}

return 0;
}

149 | P a g e
Timer 2

Timer 2 can be used in exactly the same manner as Timer 0 as they are both 8-bit timers with identical
features except for one. Timer 2 has an asynchronous mode that allows Timer 2 to run from an
independent crystal source other than that provided by the system clock. Asynchronous mode is beyond
the scope of this manual but details can be found from page 128 in the datasheet and it is controlled by the
Asynchronous Status Register ASSR which is shown in the figure below.

Figure 3. 30 - From the Atmega32 Datasheet Page 128

Timer 2 has a similar control register to that of Timer 0, Timer/Counter1 Control Register (TCCR2), this
register is identical to that of TCCR0, however what is hidden at the moment is that fact that the Clock
Select bits provide more prescaling options. The figure below displays the TCCR2 register, when
compared with TCCR0 will look identical except that the 0's are replaced by 2's to signify this is a register
for Timer 2.

Figure 3. 31 - From the Atmega32 Datasheet Page 125

However the different operation performed by the CS bits is shown in the table below and displays the
added prescaling options. The increased prescaling options is the only difference between Timers 0 and 2
if you do not include the asynchronous features, therefore Timer 0's example codes can be easily modified
to perform function using Timer 2. Note that OC2 the output pin for Timer 2 is located at PORTD 7 and
performs that same function as OC0 does for Timer 0.

CS22 CS21 CS20 Interrupt Function


0 0 0 Stop, Timer 2 is stopped
0 0 1 System Clock
0 1 0 System Clock / 8
0 1 1 System Clock / 32
1 0 0 System Clock / 64
1 0 1 System Clock / 128
1 1 0 System Clock / 256
1 1 1 System Clock / 1024

150 | P a g e
Figure 3. 32 - From the Atmega32 Datasheet Page 130

Figure 3. 33 - From the Atmega32 Datasheet Page 130

151 | P a g e
Analogue Peripherals
The Atmega32 provides two analogue peripherals, the analogue comparator and eight individual analogue
to digital converter's (ADC). These peripherals are very important features for a microcontroller as
naturally occurring signals are generally analogue, therefore for a microcontroller to successfully
interface with the outside world it must be able to read analogue signals. Majority of this work is done by
the ADC's which will read an analogue signal at regular intervals and assign a digital 10-bit value. Where
the comparator simply takes to inputs and compares there values.

Comparator
The analogue comparator is a device that takes two analogue inputs and compares them. The input values
are input into two specific ports, PORTB 2, Analogue Comparator Positive Input (AIN0) and PORTB 3,
Analogue Comparator Negative Input (AIN1). This devices function is very self explanatory, when AIN0
(Positive) input voltage is higher than the voltage on the AIN1 (Negative) input then the output flag
Analogue Comparator Output (ACO) flag is set. This flag can be used in numerous ways, it can trigger
the Timer/Counter1 Input Capture function, or an interrupt can be configured to trigger on the ACO rising
edge, falling edge or toggle.

The register that controls the Analogue Comparator is the Analogue Comparator Control and Status
Register (ACSR); this register can be seen below.

Figure 3. 34 - From the Atmega32 Datasheet Page 199

Where bits 0 and 1 are the Analog Comparator Interrupt Mode Select (ACIS) bits, they allow the
programmer to specifically control the interrupt actions for the comparator. When these bits are being
modified the Analogue Comparator Interrupt should be disabled by clearing the Analogue Comparator
Interrupt Enable (ACIE) flag of the ACSR.

Figure 3. 35 - From the Atmega32 Datasheet Page 200

152 | P a g e
 Bit 2 - Analogue Comparator Input Capture Enable (ACIC), when this bit is set this enables the
input capture function of the Timer/Counter1 to be triggered by the ACO flag. To make the
Timer/Counter1Input Capture Interrupt trigger from ACO the TICIE1 bit of the TIMSK register
must be set.
 Bit 3 - Analogue Comparator Interrupt Enable (ACIE), this flag enables the comparator interrupt
once this flag is set along with global interrupts.
 Bit 4 - Analog Comparator Interrupt Flag (ACI), this flag is set when the Analogue Comparator
Interrupt is triggered by an event described by the comparators interrupt configuration. This flag
unsets when the interrupts ISR is executed.
 Bit 5 - Analogue Comparator Output (ACO), this is the output flag for the comparator and
signifies that AIN0 is greater than AIN1. Typically has a 1-2 clock cycle delay from when a
change in the inputs occurs.
 Bit 6 - Analogue Comparator Bandgap Select (ACBG), this is where AIN0 (positive input) is
replaced by a fixed bandgap reference voltage when the ACGB flag is set.
 Bit 7 - Analogue Comparator Disable (ACD), when this bit is set the Analogue Comparator is
turned off. If the ACIE interrupt flag is set it should be unset before changing the ACD flag as it
can trigger the Comparator Interrupt when changed.

Since the OUSB development board provides no onboard comparator hardware no example code is
provided for this device.

However a fairly simple example can be found at:

http://winavr.scienceprog.com/avr-gcc-tutorial/avr-comparator-c-programming-example.html

Analogue to Digital Converters


The Atmega32 provides a 10-bit ADC; this ADC is connected to an 8-channel analogue multiplexer. This
means that the Atmega32 is capable of reading from eight analogue sources and storing there digital
values.

The Operation of the ADC


The ADC has a separate supply voltage pin, AVCC; the voltage supplied to this pin must not differ more
than from the value of VCC. Additionally AREF should be connected to approximately the same
values as VCC as well if used. AREF allows you to set the maximum allowable input value and should
not be higher than VCC, therefore if a value on an ADC input is greater than AREF then the digital value
will saturate at a value of 1023 as it cannot read any higher since it is a 10-bit ADC.

Like the timers we need to setup a clock prescaler, the ADC requires a clock input between 50 kHz and
200 kHz to get the maximum 10-bit resolution. If a lower resolution than 10-bits is needed the input clock
can be higher than 200 kHz to get a greater sample rate.

153 | P a g e
Once again the system clock is derived from the system clock and the prescaling bits for the ADC can be
found in the ADC Control and Status Register A (ADCSRA).

The ADCSRA register is shown in the figure below.

Figure 3. 36 - From the Atmega32 Datasheet Page 216

The ADC prescaler Select Bits (ADPS) are bits 0 - 2 of the ADCSRA, the table below from the
ATmega32 datasheet shows how the different combinations of these bits divides the system clock to
determine the ADC clock rate.

Since the OUSB development board uses a 12MHz system clock and we need to get this clock scaled
down to less than 200 kHz we need to find what scaling factor gives the desired value at the highest rate.

Therefore for our 12MHz clock we should use:

Figure 3. 37 - From the Atmega32 Datasheet Page 217

154 | P a g e
The rest of the ADCSRA flags allow activation and configuration of the ADC where:
 Bit 3 - ADC Interrupt Enable (ADIE) activates the ADC interrupt when set along with global
interrupts enabled.
 Bit 4 - ADC Interrupt Flag (ADIF), If the ADIE flag is set and global interrupts is enabled this
flag will set when an ADC conversion completes, and is unset when the ISR is called.
 Bit 5 - ADC Auto Trigger Enable (ADATE), When set the ADC will start a conversion on a
positive edge of the selected trigger signal, by default this is in free running mode (the mode we
will be using), however on page 218 of the ATmega32 datasheet you can find more triggers that
can be configured by modifying the Special Function IO Register (SFIOR).
 Bit 6 - ADC Start Conversion (ADSC), In free running mode, setting this bit will start the ADC
conversion, however the ADC should be enabled and configured before setting this bit.
 Bit 7 - ADC Enable (ADEN), setting this bit enables the ADC, if cleared during a conversion the
conversion will be terminated.

The ADC has one other register that needs to be configured; it is the ADC Multiplexer Selection Register
(ADMUX). This register allows you to select the voltage reference, how the data is read from the 16-bit
buffer holding the converted value and which ADC pins are enabled.

The ADMUX register is shown in the figure below

Figure 3. 38 - From the Atmega32 Datasheet Page 214

The Analogue Channel and Gain Selection Bits (MUX) are briefly shown below, the gain feature of the
ADC is not covered in this manual therefore as shown in the figure below we are only concerned with the
MUX bits 0 - 3. The ADC pins can be found on PORT A of the ATmega32 and the pins correspond to the
particular ADC. As you can see from the figure below any combinations of the ADC can be activated.

155 | P a g e
Figure 3. 39 - From the Atmega32 Datasheet Page 215

Bit 5 ADC Left Adjust Result of the ADMUX determines how the 10-bit data is read, to simplify this I
generally use ADLAR clear for 10-bit conversions and ADLAR set for 8-bit readings.

The following figure is for when ADLAR is clear. In this when I use 10-bit resolution, to be able to read
the 10-bit resultant we must first read the ADC Data Register Lower Byte (ADCL) before the ADC Data
Register Higher Byte (ADCH), therefore to read a 10-bit conversion you must use a similar piece of code
to that shown below:

int LOWER_BYTE = ADCL; // read ADCL first (lower 8 bits)


int RESULT = ADCH*256+LOWER_BYTE; // read all 10-bits

Figure 3. 40 - From the Atmega32 Datasheet Page 217

156 | P a g e
I purposely use ADLAR set for 8-bit conversions, however this is not necessary and you could just use
ADCL with ADLAR clear for the same result, but my theory is the last thing I always want to read is
ADCH. Therefore when ADLAR is set you must read ADCH first, thus this is just the reverse of the
above definition. So to read an 8-bit conversion you can simply use the following code:

int RESULT = ADCH; // read 8-bits only

Figure 3. 41 - From the Atmega32 Datasheet Page 217

The final bits in ADMUX that can be modified are the Reference Select Bits (REFS), these two bits allow
You to configure the ADC to use internal or external reference voltages, for the OUSB development
board, you need to set REFS0 to use AVCC as AREF as this is the configuration of the board.

The code segment would be:

ADMUX |= (1<<REFS0); // set reference as AVCC

Figure 3. 42 - From the Atmega32 Datasheet Page 214

There are no examples of the ADC provided as there are two example programs displayed at the end of
this chapter call LED READ TRIMPOT and PWM READ TRIMPOT which clearly display the use of the
ADC and also demonstrate the use of 8-bit and 10-bit resolution.

157 | P a g e
USART
The Universal Synchronous and Asynchronous and Receiver and Transmitter (USART) is a peripheral
provided for serial communications on the Atmega32. USART is very useful as it can be configured to
communicate with various other devices including Personal Computers; this is easily achieved using an
RS-232 configuration and programs such as hyper terminal on a Windows platform or CuteCom and
gTerm for a Linux platform.

However the voltage levels provided by USART are TTL levels which differ from specific RS-232 levels
so a converter is needed, the ousb development board provides this conversion using a MAX232 chip
located between the DB-9 connector and the Atmega32.

The Atmega supports four different types of serial clocking modes, those being:
 Normal Asynchronous
 Double Speed Asynchronous
 Master Synchronous
 Slave Synchronous

However some Atmel microcontrollers only have a Universal Asynchronous Receiver and Transmitter
(UART) interface meaning that they do not have synchronous communications ability.

This manual will only be using one mode and that is Normal Asynchronous as this will enable us to
transmitter to an RS-232 port of a PC with relative ease.
If you wish to read more into Serial Communication and the definition of asynchronous the follow site
provides a rather light but readable introduction:

http://extremeelectronics.co.in/avr-tutorials/rs232-communication-the-basics/

However you can just accept that we are going to be operating USART in Normal Asynchronous mode
and that other modes are available for different implementation methods, for our purposes RS-232 is
asynchronous which means that both the transmitter and receiver do not need a common clock to
synchronise to, however start and stop bits are used for synchronisation. Since the transmitter and receiver
do not have a common clock and bit patterns are used for synchronisation we must ensure that the
transmitter settings match those at the receiver. The important settings are:
 Baud Rate
 Data Bits
 Parity
 Stop Bits

USART like any other peripheral must be initialised before it can be used. This process entails us
initialising the baud rate, frame format, enabling transmit and/or receive, and implementing interrupts and
ISR's if required. The USART registers allow the programmer to get rather creative with the
implementation, form a simple call to USART during normal program flow to complicated responses to
interrupt events. The implementation we are about to undertake initialises the USART at the beginning of

158 | P a g e
a program, however if you need to re-initialise or set USART interrupts during program execution ensure
there are not ongoing transmissions (Checking UDR) and the Global Interrupt Flag is cleared.

Let us begin our introduction to USART implementation with initialising the USART baud rate.
To configure the USART baud rate in the Atmega 32 we must use two registers, these are the USART
Baud Rate Register High (UBRRH) and Low (UBRRL), these are both 8-bit register and combine to
create one 16-bit (UBRR).

The value placed into the UBRR is determined by the following formula found on page 143 on the
Atmega32 datasheet.

Where
 Baud Rate - Symbols Per Second
 - System Oscillator Frequency (F_CPU)
 UBRR - Contents of UBRRH and UBRRL (0-4095)

The next part of our initialisation is to initialise the frame format. The frame format needed for this
manual is 8 Data Bits - No Parity - 1 Stop Bit. This can all be set from the USART Control and Status
Register (UCSR). The UCSR however is 24-bits long and is broken into three registers UCSRA, UCSRB
and UCSRC. The frame format flags reside in UCSRC and can be seen in the figure below.

Figure 3. 43 - From the Atmega32 Datasheet Page 162

From the above figure bit 6 USART Mode Select (UMSEL) is automatically set to 0 which is the setting
for Asynchronous Modes as shown in the figure below.

Figure 3. 44 - From the Atmega32 Datasheet Page 162

Bits 5 and 4 are the USART Parity Mode bits UPM1 and UPM0, they set the parity of the data frame and
are initially set for None. Which is the setting we will be using, this is shown in the figure below.

159 | P a g e
Figure 3. 45 - From the Atmega32 Datasheet Page 163

Bit 3 is the USART Stop Bit Select flag and is initially set to 0 which stands for 1-stop bit which is the
setting we will be using; this can be seen in the figure below.

Figure 3. 46- From the Atmega32 Datasheet Page 163

Finally in configuring the UCSRC register we need to set the USART Character Size bits (UCSZ2-0).
However UCSZ2 does not reside in the register UCSRC, it resides in register UCSRB. Lucky for our
implementation UCSZ2 is default zero as we wish to configure our setup for 8-bits; therefore we only
need to configure UCSZ1 and UCSZ0 which are bits 2 and 1 in the UCSRC.

Figure 3. 47- From the Atmega32 Datasheet Page 163

Now that we have learnt how to initialise the USART peripheral let us explore the remaining two UCSR
registers to determine how to activate USART.

160 | P a g e
The activation bits can be found in UCSRB which can be seen in the figure below.

Figure 3. 48 - From the Atmega32 Datasheet Page 161

Where:
 Bit 3 - Transmitter Enable (TXEN), this will override the normal port operation of pin TxD.
 Bit 4 - Receiver Enable (RXEN), this will override the normal port operation of pin RxD.
 Bit 5 - USART Data Register Empty Interrupt Enable (UDRIE), setting this bit high enables
interrupt on the UDRE flag in UCSRA. This interrupt will only be generated if this bit is set to
one, the Global Interrupt Flag is set to one and the UDRE bit in UCSRA goes high.
 Bit 6 - TX Complete Interrupt Enable (TXCIE), setting this bit high causes an interrupt on the
TXC flag in UCSRA. This interrupt will only be generated if this bit is set to one, the Global
Interrupt Flag is set to one and the TXC bit in UCSRA goes high.
 Bit 7 - RX Complete Interrupt Enable (RXCIE), setting this bit high causes an interrupt on the
RXC flag in UCSRA. This interrupt will only be generated if this bit is set to one, the Global
Interrupt Flag is set to one and the RXC bit in UCSRA goes high

So for our USART program will not be implementing interrupts therefore we will be setting RXEN and
TXEN to 1.

The final UCSR register is UCSRA and is displayed in the figure below.

Figure 3. 49 - From the Atmega32 Datasheet Page 160

The UCSRA holds error checking and status bits that can control program flow and interrupts under
conditions set by the programmer. Many of these bits were mentioned for the interrupts UDRIE, TXCIE
and RCIE.
Where:
 Bit 2 - Parity Error (PE), when UMP1 is set in UCSRC then parity errors can be checked. An
error will set PE high.
 Bit 3 - Data Over Run (DOR), this bit will get set when the Receive USART Data Buffer Register
(UDR) is full and a start bit is received. UDR will be covered next.
 Bit 4 - Frame Error (FE), if a received frame error is received in the UDR this flag will be set
high.

161 | P a g e
 Bit 5 - USART Data Register Empty (UDRE), The UDRE indicates if the Transmit USART Data
Buffer Register is ready to receive new data. Therefore if the UDRE is set to one then the
Transmit UDR is ready to be written to.
 Bit 6 - USART Transmit Complete (TXC), this flag is set once the final bit has been shifted out
of the Transmit UDR. If this flag is used to drive the TXCIE interrupt, was the interrupt has been
called the bit is cleared or it can be cleared manually by writing a zero to it.
 Bit 7 - USART Receive Complete (RXC), this flag is set when unread data enters the Receive
UDR and is cleared when the Receive UDR is empty.

Now that we have covered initialization and given some insight into USART control flags, the final piece
of the puzzle is the USART I/O Data Register (UDR), the register is shown below.

Figure 3. 50 - From the Atmega32 Datasheet Page 159

We have previously made reference to the UDR and you may be aware that is has two different operation,
one for transmit and the other for receive. You should now be able to see the TXB (Transmit Buffer) is
the write operation of the UDR for USART transmission operations and RXB (Receive Buffer) is for read
operation of the UDR for receiving operations. Basically the TXB shifts data in and RXB shifts data out,
the TXB and RXB registers are only active if the corresponding TXEN and RXEN bits are set in UCSRB.

Before we implement some basic USART programs we need to discuss how we can read incoming data
and send outgoing data. To do this we need to examine the two code examples give in the Atmega32
datasheet.

162 | P a g e
The following code segment is directly copied from the Atmega32 datasheet page 147 and is for
transmissions of 8 data bits or less, another code is provided in the datasheet if 9 data bits are to be
transmitted.

void usart_tx(unsigned char data)


{

//wait for empty transmit buffer


while(!(UCSRA & (1<<UDRE)));

// put data in buffer, sends data


UDR = data;

The above code is the standard polling transmit function for USART and can be used after USART is
initialised. Its function is to wait for the transmit buffer to become empty by checking the UDRE flag in
the USCRA register which signifies that the UDR transmit buffer is empty and ready to receive new data
to transmit. Once the Atmega32 has confirmed that the UDR transmit buffer is empty the data will be
buffered into the UDR and then shifted out of the buffer by the shift registers transmitting the data in
accordance with the serial configuration determined by the intialisation of the USART peripheral.

The following code segment is directly copied from the Atmega32 datasheet page 150 and is for reception
of 8 data bits or less, another code is provided in the datasheet if 9 data bits are to be received.

unsigned char usart_receive(void)


{

//wait for data to be received


while(!(UCSRA & (1<<RXC)));

// put data in buffer, sends data


return UDR;

The above code is also the standard polling receive function of USART and can be used only once
USART is initialised. This function waits for a valid start bit to be detected which allows data to be
buffered into the UDR receive which sends the RXC flag in the register USCRA high which will cause
the while loop to exit. This will allow the function to return the value in the UDR receive buffer and store
in the unsigned char defined at the calling point of the function in the code.

163 | P a g e
Now let us implement USART with 2 examples, the first example is simply implementing the datasheet
example code given on page 147.

#include<avr/io.h>

// Settings for USART BAUD RATE


#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((F_CPU/(USART_BAUDRATE* 16UL)))-1)

void usart_transmit(unsigned char data);

// USART putch function


void usart_transmit(unsigned char data)
{

//wait for empty transmit buffer


while(!(UCSRA & (1<<UDRE)));

// put data in buffer, sends data


UDR = data;

int main(void)
{
unsigned char msgwel[] = "\n\rWelcome to the OUSB development Board";

// enable USART transmit and receive


UCSRB |= (1<<RXEN)|(1<<TXEN);
// initialise frame format, 8 data bits, 1 stop bits,no parity,
// asynchronous operation
UCSRC |= (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1);
// initialise USART baud rate
UBRRL = BAUD_PRESCALE;
UBRRH =(BAUD_PRESCALE >> 8);

for(int i = 0; msgwel[i]; i++){

usart_transmit(msgwel[i]);
}

while(1);

return 0;
}

164 | P a g e
This second example implements USART using transmit and receive and preforming functions when a
key on the keyboard is pressed. When the character 'a' is pressed the LSB bit on PORTB will become
active and turn on the attached LED. When the character 'b' is pressed the MSB bit on PORTB will
become active turning on the attached LED. If any other key is pressed then all LED's will turn on as all
of PORTB will become active.

#include<avr/io.h>

// Settings for USART BAUD RATE


#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((F_CPU/(USART_BAUDRATE* 16UL)))-1)

char RXbyte;
unsigned char msg1[] = "\n\rYou have just pressed a";
unsigned char msg2[] = "\n\rYou have just pressed b";
unsigned char msg3[] = "\n\rYou have just pressed an identified key";
unsigned char msgwel[] = "\n\n\rWelcome to the OUSB development Board\n\n";

unsigned char usart_receive(void);


void state(char ch);
void usart_transmit(unsigned char data);

// USART putch function


void usart_transmit(unsigned char data)
{

//wait for empty transmit buffer


while(!(UCSRA & (1<<UDRE)));

// put data in buffer, sends data


UDR = data;

// USART getch function


unsigned char usart_receive(void)
{

//wait for data to be received


while(!(UCSRA & (1<<RXC)));

// put data in buffer, sends data


return UDR;

165 | P a g e
void state(char ch)
{
switch(ch)
{
case 'a':
PORTB = 0x01;
for(int i = 0; msg1[i]; i++)
{
usart_transmit(msg1[i]);
}
break;

case 'b':
PORTB = 0x80;
for(int i = 0; msg2[i]; i++)
{
usart_transmit(msg2[i]);
}
break;

default:
PORTB = 0xFF;
for(int i = 0; msg3[i]; i++)
{
usart_transmit(msg3[i]);
}
break;
}
}

int main(void)
{

DDRB = 0xFF;
// enable USART transmit and receive
UCSRB |= (1<<RXEN)|(1<<TXEN);
// initialise frame format, 8 data bits, 1 stop bits,no parity,
// asynchronous operation
UCSRC |= (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1);
// initialise USART baud rate
UBRRL = BAUD_PRESCALE;
UBRRH =(BAUD_PRESCALE >> 8);
for(int i = 0; msgwel[i]; i++){

usart_transmit(msgwel[i]);
}

while(1)
{
RXbyte = usart_receive();
state(RXbyte);

166 | P a g e
return 0;
}

167 | P a g e
5. Mini Projects
LED BOUNCE
// AVR gcc standard library, provide iom32.h which know the basic commands
for // the Atmega32 SEE ANNEX D.
#include<avr/io.h>

// provides the header for _delay_ms()


#include<util/delay.h>

// constant used to define the delay, in milli seconds


#define delay 75

int main()
{
int i =0;

// Sets the Data Direction Register for PORTB so that all are outputs
DDRB = 0xFF; // 1111 1111

// Sets the LSB of PORTB high.


PORTB = 0x01;

/* we create our program in a forever loop so that the program will


never exit, as exiting will cause the Atmega32 to hang until it is
reset.
Embedded programming is not like standard programming, it does not
have an operating system to fall back on.
*/
while(1)
{
// for loops control our LED movements
// start at 1 and move up in multiples of two, till we reach 128
for(i = 1 ; i<=128; i=i*2)
{
// Set PORTB to the New value of i
PORTB = i;
/* cause a delay so we can visually see the LED’s
movement */
_delay_ms(delay);
}
// start at 64 and move down by divisions of two, till we reach 1
for(i=64 ; i>1; i -= i/2)
{
// Set PORTB to the New value of i
PORTB = i;
/* cause a delay so we can visually see the LED’s
movement */
_delay_ms(delay);
}
}
return 0;
}

168 | P a g e
LED READ DIP SWITCH

#include <avr/io.h> // include avr/iom32.h

int main()
{
DDRB = 0xFF; // Set PORTB (LEDS) for Output
DDRC = 0x00; // Set PORTC (DIPSWITCH) for Input
PORTC = 0xFF; // Enable Pull-ups

while(1)
{
// read the dipswitch value and output to the LED's
PORTB = PINC;
}

return 0;
}

169 | P a g e
LED READ TRIM PORT
#include <avr/io.h>
#include <avr/interrupt.h>

// set 1 is for fine resolution (1023)


// set 2 is for coarse resolution (256)
const int set = 2;

int main(void)
{
if(set == 2) ADMUX |= (1<<ADLAR);

DDRB = 0xFF; // setup portb


//set 64 prescaler 12MHZ/64= 187.5Khz
ADCSRA |= (1<<ADPS2)|(1<<ADPS1);
ADMUX |= (1<<REFS0); // set reference as AVCC
ADMUX |= (1<<MUX0)|(1<<MUX2); // use ADC 5
ADCSRA |= (1<<ADATE); // Free running mode
ADCSRA |= (1<<ADEN); // ADC enable
ADCSRA |= (1<<ADSC); // Start conversion

if(set == 1)
{
while(1)
{
int data = ADCL; // read ADCL first (lower 8 bits)
int input = ADCH*256+data;
PORTB = input*0.24;
}

if(set == 2)
{
while(1)
{
int data = ADCH;
PORTB = data;
}
}

return 1;
}

170 | P a g e
PWM READ DIP SWITCH
#include <avr/io.h>
#include <avr/interrupt.h>

void Initialise()
{
// IO PORTS
DDRC = 0x00; // set PORTC (DIPSWITCH) for input
PORTC = 0xFF; // Set Pull-Ups
DDRB |= (1<<DDB3); // set PORTB 3 for output

// PWM Timer
TCCR0 |= (1<<WGM00); // 8 bit PWM0
TCCR0 |= (1<<CS01); // Clk / 8
TCCR0 |= (1<<COM01); // Compare Match Clears OC0 to zero

int main()
{
int data;
Initialise();
ADCSRA|= (1<<ADSC); // Start ADC conversion

while(1) // forever loop


{
data = PINC; // read ADCH first (8 bits) this works
because ADLAR is set to 1

OCR0 = data;
}

return 0;
}

171 | P a g e
PWM READ TRIM POT
#include <avr/io.h>

void Initialise()
{
// IO PORTS
DDRB |= (1<<DDB3); // set PORTB 3 for output

// PWM Timer
TCCR0 |= (1<<WGM00); // 8 bit PWM0
TCCR0 |= (1<<CS01); // Clk / 8
TCCR0 |= (1<<COM01); // Compare Match Clears OC0 to zero

// ADC Converter
//set 64 prescaler 12MHZ/64 = 187.5Khz
ADCSRA |= (1<<ADPS2)|(1<<ADPS1);
// used for 8 bit only ADCH needs to be read
ADMUX |= (1<<ADLAR);
ADMUX |= (1<<REFS0); // set reference as AVCC
ADMUX |= (1<<MUX0)|(1<<MUX2); // use ADC 5
ADCSRA|= (1<<ADATE); // Free running mode
ADCSRA|= (1<<ADEN); // ADC enable

int main()
{
int data;
Initialise();
ADCSRA|= (1<<ADSC); // Start ADC conversion

while(1) // forever loop


{
// read ADCH first (8 bits) this works because ADLAR is set to 1
data = ADCH;
OCR0 = data;
}

return 0;
}

172 | P a g e
USART
#include<avr/io.h>

// Settings for USART BAUD RATE


#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((F_CPU/(USART_BAUDRATE* 16UL)))-1)

// USART putch function


void usart_transmit(int data)
{
//wait for empty transmit buffer
while(!(UCSRA & (1<<UDRE)));

// put data in buffer, sends data


UDR = data;
}

// USART getch function


unsigned char usart_receive(void)
{
//wait for data to be received
while(!(UCSRA & (1<<RXC)));

// put data in buffer, sends data


return UDR;
}

void init()
{
// enable USART transmit and receive
UCSRB |= (1<<RXEN)|(1<<TXEN);
// initialise frame format, 8 data bits, 1 stop bits,no parity,
// asynchronous operation
UCSRC |= (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1);
// initialise USART baud rate
UBRRL = BAUD_PRESCALE;
UBRRH =(BAUD_PRESCALE >> 8);
}

int main(void)
{
unsigned char RX_DATA;
int TX_DATA;
init(); // initialise USART

while(1)
{
RX_DATA = usart_receive(); // Receive an input byte
TX_DATA = (int)RX_DATA; // Type Conversion
// Increment value to the next ascii character
TX_DATA++;
usart_transmit(TX_DATA); // Transmit the new ascii character
}
return 0;
}

173 | P a g e
Annex A Eclipse Installation For Windows
This section is provides step by step instructions on how to install Eclipse with the AVR-GCC Plug-in for
a Windows PC (XP, Vista or Windows 7). This ANNEX is aimed at new users to a Windows platform.

Step 1. Install WinAVR

WinAVR is program that installs the AVR-GCC tool chain in a Windows environment, without this
program you could not program the Atmega32 microcontroller on the OUSB Development board with the
AVR-GCC libraries.

Also it should be noted that WinAVR has to be installed first before we install Eclipse, to ensure the
Eclipse AVR -GCC compiler can use WinAVR for its plug-in. Ensure you use default install locations so
that Eclipse can find WinAVR during its installation.

To download the WinAVR installer, simply click on the link below:


WinAVR-20100110-install.exe (Note this link was current as of 20/05/2010)

For the current version go to the download page for the WinAVR project which is located at:
http://sourceforge.net/projects/winavr/files/

At this site download the newest version which will be the first one in the list, as shown in figure A.1.

Figure A. 1

174 | P a g e
You will then be prompted whether you would like to save or run the installer, simply click Run.

Figure A. 2

You will then be told that this program is from an unknown publisher, and if you accept the responsibility
of running a program not known by Windows click Run.

Figure A. 3

175 | P a g e
The installer will then want you to select your language, do so and click Ok.

Figure A. 4

WinAVR Setup Wizard will now appear, click Next.

Figure A. 5

176 | P a g e
Next the Licensing Agreement will apear, if you agree click I Agree.

Figure A. 6

Setup Wizard will now ask you where you would like to install WinAVR. It is important that you use the
default setting so that Eclipse can locate WinAVR during the Eclipse AVR-GCC Plug-in installation. If
you change this you risk not being able to program using AVR-GCC in Eclipse, so simply click Next.

177 | P a g e
Figure A. 7

Setup Wizard will now request for you to select the components to install. Ensure all 3 boxes are ticked,
click Install.

Figure A. 8

178 | P a g e
WinAVR will now install.

Figure A. 9

Once the install is complete, click Finish'.

Figure A. 10

179 | P a g e
Now that WinAVR is installed you can now install Eclipse.
Step 2. Download the Eclipse IDE and Setup the Eclipse environment.

Eclipse is a self contained file so before we install the program we will create a new folder on the desktop
and rename it eclipse so that we can easily find the folder and we can download all the needed installers
to one convenient and easy to find location.

If you are unsure how to create a new folder on the desktop, right click anywhere on the desktop, select
new, then folder and name it eclipse as shown below in Figure A.11.

Figure A. 11

Before you can install Eclipse on your machine you will need to have Java Runtime installed. You will
need to install the appropriate Java Runtime for your system, 32 bit or 64 bit. This is free and the installer
can be found at the following link:

http://www.java.com/en/download/manual.jsp

Now to download Eclipse, open the following link and save the Eclipse IDE for C/C++ Developers
download to your system.
http://www.eclipse.org/downloads/

180 | P a g e
Note: However there is a 64 bit version of Eclipse and java runtime, I do not recommend using it as I
have found it to be highly unstable at the time of creating this manual in a 64 bit Windows 7 environment.
(13/07/2010) 64 bit operating systems can handle the 32 bit version and I strongly recommend using it.

Figure A.12 below displays the Eclipse download page, and circled is the C/C++ Developers Software
and with package drop list set to Windows, click on the 32 bit or 64 bit link depending on your system .
(You will need to ensure that the Java Runtime installed matches the version of Eclipse, 32 bit or 64 bit)
Once you have clicked on the link you will be sent to a download page, from here download and save the
zipped folder to your eclipse folder on the desktop as seen in figure A.13.

Figure A. 12

181 | P a g e
Figure A. 13

Once the folder is downloaded you will be asked whether you wish to open the folder, select Open
Folder.

Figure A. 14

We now have to extract the contents of the zipped folder that you have just downloaded to a convenient
location, if you are unfamiliar with the Windows directory layout I suggest you extract the folder to its

182 | P a g e
default location, which will be in the eclipse folder you created on the desktop, if you are competent with
Windows feel free to extract this folder to where ever you feel appropriate.
To extract the zipped folder you have to open the eclipse folder that we created on the desktop. (You
should already be there by clicking Open Folder) Now right click on the zipped folder and select Extract
All… from the list, as shown below in Figure A.15.

Figure A. 15

Now the Extraction Wizard will open, simply click Next.

183 | P a g e
Figure A. 16

Below in Figure A.17 the default location is circled, this is where we wish to extract the folder to and
should automatically be the destination, click Next.

Figure A. 17

The folder will automatically be extracted.

184 | P a g e
Figure A. 18

When the Extraction Wizard has completed its task it will display the image in Figure A.19, simply click
Finish.

Figure A. 19

185 | P a g e
Once the folder has been extract you will automatically be sent to the directory where the folder was
extracted to, double click on the eclipse folder presented in the window.

Figure A. 20

In the contents of the eclipse folder will be the Eclipse launcher, as shown in Figure A.21, to start Eclipse
either double click on the icon or right click and select Open. (You will need java runtime installed to
open Eclipse)

Figure A. 21

186 | P a g e
Once you have opened the Eclipse application launcher you will be asked if you would like to run a
program from an unknown publisher to windows, if you accept click Run.

Figure A. 22

187 | P a g e
Eclipse will now run.

Figure A. 23

You will now be asked by Eclipse where you would like to store your Eclipse data, Eclipse calls this a
workspace, I recommend initially using the default workspace but as you begin developing your own
programs you may wish to make an individual workspace for each different project.

Figure A. 24

188 | P a g e
Eclipse will open to its welcome window; select the workbench icon, which is circled in Figure A.25.

Figure A. 25

Now that we have Eclipse running we need to install MinGW, which will allow us to program using
either GCC or G++ in a windows environment.

Figure A. 26

189 | P a g e
To install MinGW you need to open the help contents found in Help > Help Contents as shown in Figure
A.26. Expand the C/C++ development user guide by clicking on the plus sign in the list, as shown in
Figure A.27.

Figure A. 27

190 | P a g e
To find all the installation instructions for MinGW select before you begin and scroll down to the
Windows section. As circled in Figure A.28, you need to open the link to the MinGW site. As you may
have read this is not the recommended technique, but at the time of writing this manual the recommended
method was so troublesome that it made Eclipse virtually unusable (13/07/2010). You may try the
recommended method which is very simple to complete, however the MinGW method used in this
manual maybe longer but is proven to work.

Figure A. 28

191 | P a g e
At the MinGW homepage select download from the list as shown in figure A.29.

Figure A. 29

192 | P a g e
From the MinGW download page select Automated MinGW Installer as shown in figure A.30.

Figure A. 30

193 | P a g e
Select the latest MinGW installer, as you can see the latest available installer at the time of making this
manual was MinGW 5.1.6.

Figure A. 31

194 | P a g e
Now select the executable of the installer you want.

Figure A. 32

195 | P a g e
You will now have to wait for the file downloader to start, if it doesn‟t start automatically select Direct
Link in the sourceforge window, when it does start select Run as shown in figure A.33.

Figure A. 33

Because Windows does not recognize the publisher you have to acknowledge the risk of running a
program from an unknown publisher, if you accept this and wish to run the installer, click Run.

Figure A. 34

196 | P a g e
The MinGW install will now start, click Next.

Figure A. 35

Select download and install, click Next.

Figure A. 36

197 | P a g e
If you accept the MinGW License agreement, click I Agree.

Figure A. 37

Select the current package.

Figure A. 38

198 | P a g e
You will now have to select the MinGW components you wish to install, only tick the MinGW base
tools and g++ compiler boxes as displayed in Figure A.39.

Figure A. 39

Again use the default installation destination by simply clicking Next.

Figure A. 40

199 | P a g e
Select Install, and MinGW will begin to install.

Figure A. 41

Figure A. 42

200 | P a g e
Once the MinGW installation has completed click Finish.

Figure A. 43

Our next step is to add the GDB debugger files needed for Eclipse C/C++ debugger. You will need to
download the gdb.zip folder from the link provided below and save it to the eclipse folder on the desktop:

http://sites.google.com/site/openusbboard/file-cabinet

Once the folder has finished downloading, select Open Folder which will open the eclipse folder on the
desktop.

Figure A. 44

201 | P a g e
From the eclipse folder extract the gdb.zip folder to its default location.

Figure A. 45

Open the gdb folder until you reach the folder containing bin, include, info, lib and man as displayed in
figure A.46. These folders correspond to folders located in the MinGw install folder located at
C:\MinGW.

Figure A. 46

202 | P a g e
Open the folder C:\MinGW\bin and the bin folder located in the gdb folder, add the GDB information to
C:\MinGW\bin folder, in a similar manor to that shown in figure A.47.

Figure A. 47

Add the remaining information from the other folders in the gdb folder to the MinGW folder in C drive.

Now that you have installed Eclipse for C/C++ development, we will now continue and install the AVR-
GCC Plug-in for embedded C development on a range of AVR microcontrollers.

To do this select Help form the menu bar, and Install New Software… from the drop list.

Figure A. 48

You will now enter the install window, select the add button circled in Figure A.49. The add site window
will now appear.
For name enter: AVR Eclipse Plugin
For location enter: http://avr-eclipse.sourceforge.net/updatesite/

203 | P a g e
This is displayed in Figure A.50 and click on Ok.

Figure A. 49

Figure A. 50

204 | P a g e
Now the install window will now search for the AVR Eclipse Plug-in. Once it appears in the window tick
the box as displayed in Figure A.51 and click Next.

Figure A. 51

205 | P a g e
Click Next again.

Figure A. 52

206 | P a g e
If you accept the AVR Plug-in installation license select I accept the term of the license agreement and
click Finish.

Figure A. 53

207 | P a g e
The AVR Plug-in will now begin to install.

Figure A. 54

You may be prompted that this software contains unsigned software, if you accept click Ok.

Figure A. 55

Now that Eclipse is installed it needs to be restarted, to do this click Yes.

Figure A. 56

208 | P a g e
Finally we should create a shortcut on the desktop, this can be done by opening the Eclipse folder that we
had previously created on the desktop and then open the follow folders to reach the final Eclipse directory
eclipse-cpp-helios-win32 > eclipse.

The shortcut can be created as shown in figure A.57 by right clicking on the Eclipse icon, selecting Send
To and from the drop list selecting Desktop (create shortcut). A short cut will now be available from the
desktop which will allow easy access to the Eclipse IDE.

Figure A. 57

209 | P a g e
Annex B Eclipse Help For Linux

To install Eclipse go to the following site and save the following download to your system.
http://www.eclipse.org/downloads/
Figure B.1 below displays the Eclipse download page, as circled

Figure B. 1

210 | P a g e
Once you have installed Eclipse onto your system you will now have to install the AVR -GCC tool chain.
The installation process is described in the either of the following two links. Note the first link is the
official Eclipse instruction.

http://avr-eclipse.sourceforge.net/wiki/index.php/The_AVR_GCC_Toolchain#Linux

http://www.tuxgraphics.org/electronics/200901/avr-gcc-linux.shtml#0lfindex0

http://www.ladyada.net/learn/avr/setup-unix.html

You will also need to install the AVR -GCC plug-in for Eclipse, and all the installation information can
be found in the following link.

http://avr-eclipse.sourceforge.net/wiki/index.php/Plugin_Download

211 | P a g e
Annex C OUSB Schematic Diagram

212 | P a g e
Annex D Atmega32 Registers “iom32.h”

iom32.h
/* avr/iom32.h - definitions for Atmega32 */

#ifndef _AVR_IOM32_H_
#define _AVR_IOM32_H_ 1

/* This file should only be included from <avr/io.h>, never directly. */

#ifndef _AVR_IO_H_
# error "Include <avr/io.h> instead of this file."
#endif

#ifndef _AVR_IOXXX_H_
# define _AVR_IOXXX_H_ "iom32.h"
#else
# error "Attempt to include more than one <avr/ioXXX.h> file."
#endif

/* I/O registers */
/* TWI stands for "Two Wire Interface" or "TWI Was I2C(tm)" */
#define TWBR _SFR_IO8(0x00)
#define TWSR _SFR_IO8(0x01)
#define TWAR _SFR_IO8(0x02)
#define TWDR _SFR_IO8(0x03)

/* ADC */
#ifndef __ASSEMBLER__
#define ADC _SFR_IO16(0x04)
#endif
#define ADCW _SFR_IO16(0x04)
#define ADCL _SFR_IO8(0x04)
#define ADCH _SFR_IO8(0x05)
#define ADCSRA _SFR_IO8(0x06)
#define ADMUX _SFR_IO8(0x07)

/* analog comparator */
#define ACSR _SFR_IO8(0x08)

/* USART */
#define UBRRL _SFR_IO8(0x09)
#define UCSRB _SFR_IO8(0x0A)
#define UCSRA _SFR_IO8(0x0B)
#define UDR _SFR_IO8(0x0C)

/* SPI */
#define SPCR _SFR_IO8(0x0D)
#define SPSR _SFR_IO8(0x0E)
#define SPDR _SFR_IO8(0x0F)

/* Port D */

213 | P a g e
#define PIND _SFR_IO8(0x10)
#define DDRD _SFR_IO8(0x11)
#define PORTD _SFR_IO8(0x12)
/* Port C */
#define PINC _SFR_IO8(0x13)
#define DDRC _SFR_IO8(0x14)
#define PORTC _SFR_IO8(0x15)

/* Port B */
#define PINB _SFR_IO8(0x16)
#define DDRB _SFR_IO8(0x17)
#define PORTB _SFR_IO8(0x18)

/* Port A */
#define PINA _SFR_IO8(0x19)
#define DDRA _SFR_IO8(0x1A)
#define PORTA _SFR_IO8(0x1B)

/* EEPROM Control Register */


#define EECR _SFR_IO8(0x1C)

/* EEPROM Data Register */


#define EEDR _SFR_IO8(0x1D)

/* EEPROM Address Register */


#define EEAR _SFR_IO16(0x1E)
#define EEARL _SFR_IO8(0x1E)
#define EEARH _SFR_IO8(0x1F)

#define UBRRH _SFR_IO8(0x20)


#define UCSRC UBRRH

#define WDTCR _SFR_IO8(0x21)

#define ASSR _SFR_IO8(0x22)

/* Timer 2 */
#define OCR2 _SFR_IO8(0x23)
#define TCNT2 _SFR_IO8(0x24)
#define TCCR2 _SFR_IO8(0x25)

/* Timer 1 */
#define ICR1 _SFR_IO16(0x26)
#define ICR1L _SFR_IO8(0x26)
#define ICR1H _SFR_IO8(0x27)
#define OCR1B _SFR_IO16(0x28)
#define OCR1BL _SFR_IO8(0x28)
#define OCR1BH _SFR_IO8(0x29)
#define OCR1A _SFR_IO16(0x2A)
#define OCR1AL _SFR_IO8(0x2A)
#define OCR1AH _SFR_IO8(0x2B)
#define TCNT1 _SFR_IO16(0x2C)
#define TCNT1L _SFR_IO8(0x2C)
#define TCNT1H _SFR_IO8(0x2D)
#define TCCR1B _SFR_IO8(0x2E)
#define TCCR1A _SFR_IO8(0x2F)

214 | P a g e
#define SFIOR _SFR_IO8(0x30)

#define OSCCAL _SFR_IO8(0x31)


#define OCDR OSCCAL

/* Timer 0 */
#define TCNT0 _SFR_IO8(0x32)
#define TCCR0 _SFR_IO8(0x33)

#define MCUSR _SFR_IO8(0x34)


#define MCUCSR MCUSR
#define MCUCR _SFR_IO8(0x35)

#define TWCR _SFR_IO8(0x36)

#define SPMCR _SFR_IO8(0x37)

#define TIFR _SFR_IO8(0x38)


#define TIMSK _SFR_IO8(0x39)

#define GIFR _SFR_IO8(0x3A)


#define GIMSK _SFR_IO8(0x3B)
#define GICR GIMSK

#define OCR0 _SFR_IO8(0x3C)

/* 0x3D..0x3E SP */

/* 0x3F SREG */

/* Interrupt vectors */

/* External Interrupt Request 0 */


#define INT0_vect _VECTOR(1)
#define SIG_INTERRUPT0 _VECTOR(1)

/* External Interrupt Request 1 */


#define INT1_vect _VECTOR(2)
#define SIG_INTERRUPT1 _VECTOR(2)

/* External Interrupt Request 2 */


#define INT2_vect _VECTOR(3)
#define SIG_INTERRUPT2 _VECTOR(3)

/* Timer/Counter2 Compare Match */


#define TIMER2_COMP_vect _VECTOR(4)
#define SIG_OUTPUT_COMPARE2 _VECTOR(4)

/* Timer/Counter2 Overflow */
#define TIMER2_OVF_vect _VECTOR(5)
#define SIG_OVERFLOW2 _VECTOR(5)

/* Timer/Counter1 Capture Event */


#define TIMER1_CAPT_vect _VECTOR(6)
#define SIG_INPUT_CAPTURE1 _VECTOR(6)

215 | P a g e
/* Timer/Counter1 Compare Match A */
#define TIMER1_COMPA_vect _VECTOR(7)
#define SIG_OUTPUT_COMPARE1A _VECTOR(7)

/* Timer/Counter1 Compare Match B */


#define TIMER1_COMPB_vect _VECTOR(8)
#define SIG_OUTPUT_COMPARE1B _VECTOR(8)

/* Timer/Counter1 Overflow */
#define TIMER1_OVF_vect _VECTOR(9)
#define SIG_OVERFLOW1 _VECTOR(9)

/* Timer/Counter0 Compare Match */


#define TIMER0_COMP_vect _VECTOR(10)
#define SIG_OUTPUT_COMPARE0 _VECTOR(10)

/* Timer/Counter0 Overflow */
#define TIMER0_OVF_vect _VECTOR(11)
#define SIG_OVERFLOW0 _VECTOR(11)

/* Serial Transfer Complete */


#define SPI_STC_vect _VECTOR(12)
#define SIG_SPI _VECTOR(12)

/* USART, Rx Complete */
#define USART_RXC_vect _VECTOR(13)
#define SIG_USART_RECV _VECTOR(13)
#define SIG_UART_RECV _VECTOR(13)

/* USART Data Register Empty */


#define USART_UDRE_vect _VECTOR(14)
#define SIG_USART_DATA _VECTOR(14)
#define SIG_UART_DATA _VECTOR(14)

/* USART, Tx Complete */
#define USART_TXC_vect _VECTOR(15)
#define SIG_USART_TRANS _VECTOR(15)
#define SIG_UART_TRANS _VECTOR(15)

/* ADC Conversion Complete */


#define ADC_vect _VECTOR(16)
#define SIG_ADC _VECTOR(16)

/* EEPROM Ready */
#define EE_RDY_vect _VECTOR(17)
#define SIG_EEPROM_READY _VECTOR(17)

/* Analog Comparator */
#define ANA_COMP_vect _VECTOR(18)
#define SIG_COMPARATOR _VECTOR(18)

/* 2-wire Serial Interface */


#define TWI_vect _VECTOR(19)
#define SIG_2WIRE_SERIAL _VECTOR(19)

216 | P a g e
/* Store Program Memory Ready */
#define SPM_RDY_vect _VECTOR(20)
#define SIG_SPM_READY _VECTOR(20)

#define _VECTORS_SIZE 84

/* Bit numbers */

/* GICR */
#define INT1 7 //External interrupt 1
#define INT0 6 //External interrupt 0
#define INT2 5 //External interrupt 2
#define IVSEL 1
#define IVCE 0

/* GIFR */
#define INTF1 7
#define INTF0 6
#define INTF2 5

/* TIMSK */
#define OCIE2 7
#define TOIE2 6
#define TICIE1 5
#define OCIE1A 4
#define OCIE1B 3
#define TOIE1 2
#define OCIE0 1
#define TOIE0 0

/* TIFR */
#define OCF2 7
#define TOV2 6
#define ICF1 5
#define OCF1A 4
#define OCF1B 3
#define TOV1 2
#define OCF0 1
#define TOV0 0

/* SPMCR */
#define SPMIE 7
#define RWWSB 6
/* bit 5 reserved */
#define RWWSRE 4
#define BLBSET 3
#define PGWRT 2
#define PGERS 1
#define SPMEN 0

217 | P a g e
/* TWCR */
#define TWINT 7
#define TWEA 6
#define TWSTA 5
#define TWSTO 4
#define TWWC 3
#define TWEN 2
/* bit 1 reserved */
#define TWIE 0

/* TWAR */

#define TWA6 7
#define TWA5 6
#define TWA4 5
#define TWA3 4
#define TWA2 3
#define TWA1 2
#define TWA0 1
#define TWGCE 0

/* TWSR */
#define TWS7 7
#define TWS6 6
#define TWS5 5
#define TWS4 4
#define TWS3 3
/* bit 2 reserved */
#define TWPS1 1
#define TWPS0 0

/* MCUCR */
#define SE 7
#define SM2 6
#define SM1 5
#define SM0 4
#define ISC11 3
#define ISC10 2
#define ISC01 1 //Activate on falling edge
#define ISC00 0

/* MCUCSR */
#define JTD 7
#define ISC2 6
/* bit 5 reserved */
#define JTRF 4
#define WDRF 3
#define BORF 2
#define EXTRF 1
#define PORF 0

218 | P a g e
/* SFIOR */
#define ADTS2 7
#define ADTS1 6
#define ADTS0 5
/* bit 4 reserved */
#define ACME 3
#define PUD 2
#define PSR2 1
#define PSR10 0

/* TCCR0 */

#define FOC0 7
#define WGM00 6
#define COM01 5
#define COM00 4
#define WGM01 3
#define CS02 2
#define CS01 1
#define CS00 0

/* TCCR2 */
#define FOC2 7
#define WGM20 6
#define COM21 5
#define COM20 4
#define WGM21 3
#define CS22 2
#define CS21 1
#define CS20 0

/* ASSR */
/* bits 7-4 reserved */
#define AS2 3
#define TCN2UB 2
#define OCR2UB 1
#define TCR2UB 0

/* TCCR1A */
#define COM1A1 7
#define COM1A0 6
#define COM1B1 5
#define COM1B0 4
#define FOC1A 3
#define FOC1B 2
#define WGM11 1
#define WGM10 0

219 | P a g e
/* TCCR1B */
#define ICNC1 7
#define ICES1 6
/* bit 5 reserved */
#define WGM13 4
#define WGM12 3
#define CS12 2
#define CS11 1
#define CS10 0

/* WDTCR */
/* bits 7-5 reserved */
#define WDTOE 4
#define WDE 3
#define WDP2 2
#define WDP1 1
#define WDP0 0

/* PA7-PA0 = ADC7-ADC0 */

/* PORTA */
#define PA7 7
#define PA6 6
#define PA5 5
#define PA4 4
#define PA3 3
#define PA2 2
#define PA1 1
#define PA0 0

/* DDRA */
#define DDA7 7
#define DDA6 6
#define DDA5 5
#define DDA4 4
#define DDA3 3
#define DDA2 2
#define DDA1 1
#define DDA0 0

/* PINA */
#define PINA7 7
#define PINA6 6
#define PINA5 5
#define PINA4 4
#define PINA3 3
#define PINA2 2
#define PINA1 1
#define PINA0 0

220 | P a g e
/*
PB7 = SCK
PB6 = MISO
PB5 = MOSI
PB4 = SS#
PB3 = OC0/AIN1
PB2 = INT2/AIN0
PB1 = T1
PB0 = XCK/T0
*/

/* PORTB */
#define PB7 7
#define PB6 6
#define PB5 5
#define PB4 4
#define PB3 3
#define PB2 2
#define PB1 1
#define PB0 0

221 | P a g e
/* DDRB */
#define DDB7 7
#define DDB6 6
#define DDB5 5
#define DDB4 4
#define DDB3 3
#define DDB2 2
#define DDB1 1
#define DDB0 0

/* PINB */
#define PINB7 7
#define PINB6 6
#define PINB5 5
#define PINB4 4
#define PINB3 3
#define PINB2 2
#define PINB1 1
#define PINB0 0

/*
PC7 = TOSC2
PC6 = TOSC1
PC1 = SDA
PC0 = SCL
*/
/* PORTC */
#define PC7 7
#define PC6 6
#define PC5 5
#define PC4 4
#define PC3 3
#define PC2 2
#define PC1 1
#define PC0 0

/* DDRC */
#define DDC7 7
#define DDC6 6
#define DDC5 5
#define DDC4 4
#define DDC3 3
#define DDC2 2
#define DDC1 1
#define DDC0 0

/* PINC */
#define PINC7 7
#define PINC6 6
#define PINC5 5
#define PINC4 4
#define PINC3 3
#define PINC2 2
#define PINC1 1
#define PINC0 0

222 | P a g e
/*
PD7 = OC2
PD6 = ICP
PD5 = OC1A
PD4 = OC1B
PD3 = INT1
PD2 = INT0
PD1 = TXD
PD0 = RXD
*/

/* PORTD */
#define PD7 7
#define PD6 6
#define PD5 5
#define PD4 4
#define PD3 3
#define PD2 2
#define PD1 1
#define PD0 0

/* DDRD */
#define DDD7 7
#define DDD6 6
#define DDD5 5
#define DDD4 4
#define DDD3 3
#define DDD2 2
#define DDD1 1
#define DDD0 0

/* PIND */
#define PIND7 7
#define PIND6 6
#define PIND5 5
#define PIND4 4
#define PIND3 3
#define PIND2 2
#define PIND1 1
#define PIND0 0

/* SPSR */
#define SPIF 7
#define WCOL 6
/* bits 5-1 reserved */
#define SPI2X 0

/* SPCR */
#define SPIE 7
#define SPE 6
#define DORD 5
#define MSTR 4
#define CPOL 3
#define CPHA 2
#define SPR1 1
#define SPR0 0

223 | P a g e
/* UCSRA */
#define RXC 7
#define TXC 6
#define UDRE 5
#define FE 4
#define DOR 3
#define PE 2
#define U2X 1
#define MPCM 0

/* UCSRB */
#define RXCIE 7
#define TXCIE 6
#define UDRIE 5
#define RXEN 4
#define TXEN 3
#define UCSZ2 2
#define RXB8 1
#define TXB8 0

/* UCSRC */
#define URSEL 7
#define UMSEL 6
#define UPM1 5
#define UPM0 4
#define USBS 3
#define UCSZ1 2
#define UCSZ0 1
#define UCPOL 0

/* ACSR */
#define ACD 7
#define ACBG 6
#define ACO 5
#define ACI 4
#define ACIE 3
#define ACIC 2
#define ACIS1 1
#define ACIS0 0

/* ADCSRA */
#define ADEN 7
#define ADSC 6
#define ADATE 5
#define ADIF 4
#define ADIE 3
#define ADPS2 2
#define ADPS1 1
#define ADPS0 0

224 | P a g e
/* ADMUX */
#define REFS1 7
#define REFS0 6
#define ADLAR 5
#define MUX4 4
#define MUX3 3
#define MUX2 2
#define MUX1 1
#define MUX0 0

/* EEPROM Control Register */


#define EERIE 3
#define EEMWE 2
#define EEWE 1
#define EERE 0

/* Constants */
#define SPM_PAGESIZE 128
#define RAMEND 0x85F
#define XRAMEND RAMEND
#define E2END 0x3FF
#define E2PAGESIZE 4
#define FLASHEND 0x7FFF

/* Fuses */

#define FUSE_MEMORY_SIZE 2

/* Low Fuse Byte */


#define FUSE_CKSEL0 (unsigned char)~_BV(0)
#define FUSE_CKSEL1 (unsigned char)~_BV(1)
#define FUSE_CKSEL2 (unsigned char)~_BV(2)
#define FUSE_CKSEL3 (unsigned char)~_BV(3)
#define FUSE_SUT0 (unsigned char)~_BV(4)
#define FUSE_SUT1 (unsigned char)~_BV(5)
#define FUSE_BODEN (unsigned char)~_BV(6)
#define FUSE_BODLEVEL (unsigned char)~_BV(7)
#define LFUSE_DEFAULT (FUSE_CKSEL1 & FUSE_CKSEL2 & FUSE_CKSEL3 & FUSE_SUT0)

/* High Fuse Byte */


#define FUSE_BOOTRST (unsigned char)~_BV(0)
#define FUSE_BOOTSZ0 (unsigned char)~_BV(1)
#define FUSE_BOOTSZ1 (unsigned char)~_BV(2)
#define FUSE_EESAVE (unsigned char)~_BV(3)
#define FUSE_CKOPT (unsigned char)~_BV(4)
#define FUSE_SPIEN (unsigned char)~_BV(5)
#define FUSE_JTAGEN (unsigned char)~_BV(6)
#define FUSE_OCDEN (unsigned char)~_BV(7)
#define HFUSE_DEFAULT (FUSE_BOOTSZ0 & FUSE_BOOTSZ1 & FUSE_SPIEN &
FUSE_JTAGEN)

/* Lock Bits */
#define __LOCK_BITS_EXIST
#define __BOOT_LOCK_BITS_0_EXIST
#define __BOOT_LOCK_BITS_1_EXIST

225 | P a g e
/* Signature */
#define SIGNATURE_0 0x1E
#define SIGNATURE_1 0x95
#define SIGNATURE_2 0x02

#endif /* _AVR_IOM32_H_ */

226 | P a g e
ANNEX E Windows XP Setup for STK 200
1. The first step in preparing for STK-200 programming is to create an STK-200 programming cable as
per the specifications on P J Radcliffe's wordpress site. The diagram can be found here.

2. Download the giveio driver from P J Radcliffe's wordpress site here. Select the link
'windows_io_accesszip' and save the file to your PC.

3. Extract the zipped folder windows_io_accesszip.

Figure E 1. 1

227 | P a g e
4. Now open the extracted folder and open the HTML document „give_io_instal' for instructions how to
install this driver.

Figure E 1. 2

228 | P a g e
5. Read and understand the giveio installation procedure.

Figure E 1. 3

229 | P a g e
6. Now from the extracted folder copy the „giveio‟ file and paste it into the drivers folder located at
C:\WINDOWS\sytem32\drivers.

Figure E 1. 4

230 | P a g e
7. Now copy and paste the file „instdrv‟ into your command prompt's default directory. For my PC it is
C:\Documents and Settings\Troy.

Figure E 1. 5

8. Now open command prompt. Start > run and type „cmd‟ and click OK.

Figure E 1. 6

231 | P a g e
9. Now the command prompt window will now open and it should be pointing at the same directory the
you pasted the file „instdrv‟ into into.

Figure E 1. 7

10. From the HTML document „give_io_instal' copy the following command prompt instruction from it
„instdrv giveio \windows\system32\drivers\giveio.sys'.

232 | P a g e
Figure E 1. 8

11. Now in the command prompt window paste the copied instruction into it by right clicking in the
command prompt window as shown below.

Figure E 1. 9

233 | P a g e
12. Now the instruction should execute in the command prompt window and return 3 statements followed
by the word „SUCCESS‟. If the driver doesn‟t install correctly retry following the instructions in the
HTML document, „give_io_instal'.

13. Now open regedit. Start>run and type „regedit‟ and click OK.

Figure E 1. 10

234 | P a g e
14. In regedit find the givio register which is located at:
HKEY_LOCAL_MACHINE>SYSTEM>CurrentControlSet>Services>giveio

Figure E 1. 11

235 | P a g e
15. Now that you have opened „giveio‟ double click on Start in and set it value as 2 then Click OK.

Figure E 1. 12

236 | P a g e
References
1. 8-bit Microcontroller with 32K Bytes In-System Programmable Flash, ATmega32,
ATmega32L, Atmel, 06/2008.

2. Radcliffe, P.J, Open-USB-IO Reference V1.085, 2010.

3. Weddington, E., Programming 101,


http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=37871

4. Camera, D., Newbie's Guide to AVR Timers,


http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=50106

237 | P a g e

Вам также может понравиться