Atmega Tutorial PDF
Atmega Tutorial PDF
microcontroller
Benjamin Reh
Contents
1. Preface 3
3. The basics 4
3.1. Pins and Ports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
4. First steps 5
4.1. Controlling a LED . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
4.1.1. Plugging in the LED . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
4.1.2. Switching it on . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
4.1.3. Making the LED blink . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
4.1.4. Making the LED blink (advanced) . . . . . . . . . . . . . . . . . . . . . 8
4.2. Reading an input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
4.2.1. Detecting an edge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
4.2.2. Providing a clean signal . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
5. Timer/Counter 11
5.1. Hardware timer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
5.2. Servo control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
5.2.1. About servos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
5.2.2. Servos in basis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
5.3. Timer for software interrupt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
6. Analogue-Digital-Converter (ADC) 13
6.1. ADC in basis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1
Version 1.1 IWR - robotics lab
7. Serial connection(UART) 13
7.1. UART in basis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
7.1.1. Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
7.2. The terminal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
A. Appendix 15
A.1. Algebra with bits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
A.1.1. Shifting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
A.1.2. Bit-wise logic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
A.1.3. Setting a bit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
A.1.4. Clearing a bit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
A.2. Pin out of the Atmega 168 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
B. References 18
2
Version 1.1 IWR - robotics lab
1. Preface
This document an introduction into the programming of an Atmega microcontroller. It is
separated into the first part guiding like a tutorial for beginners and a second part which is a
reference book to the functions provided in the basis.
The examples and explanations provided are neither exhaustive nor complete. The only aim
of this document is to lower the burden of getting started. Only a basic knowledge in C is
required.
Prerequisites
To compile your programs and transfer them to the microcontroller, a few tools have to be
installed. If you are working on a PC in the Lab, then you can skip this section.
First, I assume you are working with Linux, so I also assume you already have your favorite
editor. If you do not, I recommend geany, which is a light, but powerful editor using gnome.
For the Atmega you need the avr port of the gcc, a program for uploading the code to the
device (avrdude) and make for running Makefiles.
Everything can be installed on Debian/Ubuntu systems with the following command
sudo apt-get install make avr-libc avrdude binutils-avr gcc-avr gdb-avr
For other distributions please take a look inside your documentation how to install new packages
and how to find their names.
2.1.1. Basis
For a clean start you should get a fresh copy of the basic programming environment we call
basis. You can either check it out from the svn-repository with
svn checkout http://ornella.iwr.uni-heidelberg.de/svn/basis
3
Version 1.1 IWR - robotics lab
The make command produces a binary output file called basis.elf which now needs to be
transferred to the microcontroller. You should supply power to the board and plug in the
programming device.
By typing
make prog
a program called avrdude will be started to initiate the transfer.
Since there is more than just one possible programmer, maybe the Makefile has to be adjusted
to the one you are using.
...
#select programmer
prog: prog-usb
#prog: prog-ser
#prog: prog-funk
...
In this example the usb-programmer is chosen because it is the only line that does not start
with a #.
If you encounter problems that look like a problem with permissions you can try executing
the command as root with for example sudo make prog. For being able to program as a
normal unprivileged user, you can modify your udev-rules accordingly. In the lab this has
already been done. This problem should therefor not occur.
2.1.3. Fuse-bits
A really essential part of initializing a new controller is setting the so called fuse-bits. You
should take a look at the board’s documentation how to do that in detail or visit http:
//www.engbedded.com/fusecal.
From this point of view it is sufficient to just call
make fuse
once every time you put a new controller chip in your board. If your are in doubt whether
your controller has already been fused, just it again. Fusing more than once doesn’t hurt.
3. The basics
In this chapter you learn what registers and ports are and how to set a pin on a certain port.
4
Version 1.1 IWR - robotics lab
Ports
As the reader may recall from lectures in computer engineering2 , a processor has a set of
registers which contain data or control the peripheral devices. A microcontroller typically is
nothing more than a microprocessor with memory, some special hardware (counter, ADCs,. . . )
and direct access to IO.
The Atmega series we are using has a 8 bit architecture. It can calculate values of the size of
1 byte at normally one clock cycle.
For this reason 8 pins are combined to 1 port, which simply is represented by one register in
the CPU.
Ports are enumerated with capital letters (A,B,C,. . . ), pins with number from 0 . . . 7. For
example PIND6 represents the pin no. 6 on port D
Each bit in a register for IO represents a (physical) pin. This makes it necessary to know how
to manipulate just several bits at a time while leaving the others untouched.
If your are not familiar with bit shifting and bit algebra in expressions like a |= (1<<5); you
can take a look at A.1 to learn the basics.
4. First steps
This chapter elaborates about setting an output, reading an input and programming simple
time depending tasks. If you are not familiar with the bit expressions used in this section feel
free to take a look at A.1.
1
An example is the reset pin which can also be used for normal IO. This tutorial keeps on the usage that is
recommended by an unchanged board with unchanged software.
2
Technische Informatik, typically Informatik II
5
Version 1.1 IWR - robotics lab
3 2 1
+ -
(a) Hold LED against (b)
light to see the polar-
ity
To find out the polarity of the LED, it can simply he held against the light, see 1(a). The
smaller piece inside the plastic housing is the anode (+). It will be plugged on the board on
the pin next to the microcontroller. The controller will provide its signal there.
The other pin, the cathode (-), is plugged to the pin which is the most far away from the
controller. This pin is on ground. If you do not have a board, take a look at 1(b).
The LED will be placed on PORTC5, which is located in the corner of the MC at pin no 28.
Take a look at A.2.
4.1.2. Switching it on
In the previous paragraph the LED was placed in PORTC5. In the file main.c where the main-
loop is located the following changes need to be made:
1. Set pin 5 in PORTC to output mode with the Data Direction Register for the port DDRC.
6
Version 1.1 IWR - robotics lab
...
You can now type make to see if the program compiles.
After connecting the board to power and plugging in the programmer, the binary can be
transferred with the command make prog.
After the transfer the LED should now emit light. If it does not, check for possible errors during
the transfer on the screen. Or maybe the LED is placed with the wrong polarity. Simply turn
it around for a try, wrong polarity does not damage the LED.
...
int main(void) {
//Set the Data Direction Register to output
DDRC |= (1<<5);
while (1) {
//Set the signal to high
PORTC |= (1<<5);
//wait 0.5 sec
_delay_ms(500);
//Set the signal to low
PORTC &= ~(1<<5);
//wait 0.5 sec
_delay_ms(500);
}
}
...
After compiling and transferring the program with make prog the led should blink in a fre-
quency of 1 sec.
If it is blinking faster or slower then you maybe have forgotten to fuse the controller. Try make
fuse and see if it changes.
This program does what it is supposed to, but it can be written shorter and with a reduction
of redundant code. First the bit is set and later cleared, this can also be done with the toggle
function which is the equivalent of the XOR operator (see A.1):
...
#include <util/delay.h>
...
7
Version 1.1 IWR - robotics lab
int main(void) {
//Set the Data Direction Register to output
DDRC |= (1<<5);
while (1) {
//Toggle the signal
PORTC ^= (1<<5);
//wait 0.5 sec
_delay_ms(500);
}
}
...
...
8
Version 1.1 IWR - robotics lab
Example
In the following example a switch is placed on pin C3. While the switch is pushed, the LED
(still placed at C5) is turned off. In both examples the so called internal pull-up resistor is
switched on. Please refer to section 4.2.2 for its meaning.
...
int main(void) {
init();
//Set the Data Direction Register for the LED to output
DDRC |= (1<<5);
//Set the Data Direction Register for the switch to input
DDRC &= ~(1<<3);
//Enable the pullup resistor for the switch
PORTC|=(1<<3);
while (1) {
if (PINC & (1<<3))
PORTC|=(1<<5);
else
PORTC&=~(1<<5);
}
}
...
while (1) {
if ((oldc & (1<<3)) != (PINC & (1<<3)) ) {
//Switch LED
PORTC^=(1<<5);
//save new state
oldc=PINC;
}
}
}
...
9
Version 1.1 IWR - robotics lab
VCC
VCC
100K
R1
JP1 1 JP2 JP3
1 2 1 1
3
TL36YO
TL36YO
S1
3
TL36YO
S2
S3
2
2
GND GND GND
Figure 2: Differently connected switches: (a) between 5V and GND, (b) between pin and GND
with an external pull-up resistor, (c) as (b) but with an internal pull-up
...
Be aware of the fact that by using a pull-up the logic of the switch is inverted!
10
Version 1.1 IWR - robotics lab
5. Timer/Counter
This is the end of the basic tutorial section of this document. The following sections describe
the usage of functions provided in the basis-code.
Example calculation
As an example we calculate the frequency in which Timer1
overflows. Timer1 is a 16-bit timer.
11
Version 1.1 IWR - robotics lab
Unfortunately there is no way of asking the servo about its position. If for example the
counter momentum is too large and the motor is too weak to reach the desired position, there
is no way of knowing it on the microcontroller. So there is no guarantee that a servo actually
reaches a position.
A servo normally has three connectors. One for
Ground, the middle for supply voltage (typically 2
Example
This example sets the first servo to one boundary position.
...
int main(void) {
servoInit();
setServo(0, 1000);
while (1) { }
}
...
12
Version 1.1 IWR - robotics lab
To get the actual time the function uint32 t getMsTimer() must be used. Be aware of the
fact that the return value is a uint32 t. Storing it in a container of smaller size will probably
not work. Even if a 32-bit variable seems quite large it will overflow every 49.7 days. For
long-time applications another way of storing the time must be developed.
6. Analogue-Digital-Converter (ADC)
An input pin in default mode is only able to distinguish between a high and a low signal. Some
pins can be configured as ADCs. They can be read in a resolution of up to 10 bit (210 = 1024).
The controller has only one ADC but uses a multiplexer or mux to switch between the pins.
On an Atmega168 those are C0 to C5.
example
...
int main(void) {
ADCInit(0);
uint16_t value;
value = getADCValue(2);
while (1) { }
}
...
7. Serial connection(UART)
The Atmega controller has a so called Universal Asynchronous Receiver Transmitter (UART)
which can be used to communicate with any other RS-232 device like a PC. The only hardware
required is a signal converter that connects the 0 . . . 5V signal of the microcontroller to the
−12 . . . 12V of the PC. We provide such converters in the lab.
When programming uart one should always be aware of two pitfalls:
1. Buffersize: The hardware buffer for input and output on the Controller only hold 1 byte.
That means
a) If the program does not read fast enough, it loses bytes.
b) It is only possible to send one byte at a time.
To prevent data loss and blocking calls for sending it is possible to use interrupts. Those
functions are currently not implemented in the basis.
13
Version 1.1 IWR - robotics lab
• uart puts pgm (const prog char * str) sends a string like uart puts(). The only
difference is, that this string is stored in flash memory and therefor does not waste
valueable SRAM.
• uart puti (int16 t i) sends an integer. Be careful that cannot be longer than 16 bit.
• unsigned char uart getc() receives a char. It blocks until one is in the in buffer.
• uart data waiting() determines if the input buffer stores a valid byte. This can be used
as a test before calling uart getc() because uart data waiting() is non-blocking.
7.1.1. Example
...
int main(void) {
uartInit();
//This string wastes RAM, because it’s static and could be stored in flash
uart_puts("Hello World\n\r");
//This string is stored in program memory
uart_puts_pgm(PSTR("Hello World!\r\n");
if (uart_data_waiting())
uart_puts_pgm(PSTR("There is already data in the input buffer!\r\n");
while (1) {
//get a character (blocking)
uint8_t c = uart_getc();
//send it back, aka echo
uart_putc(c);
}
}
...
14
Version 1.1 IWR - robotics lab
A. Appendix
A.1. Algebra with bits
This section shortly introduces how to set, unset and toggle3 a single or multiple bits in a 8bit
register or variable in your program memory.
There are of course more things that can be done in bit-manipulation. If you are interested,
feel free to search the web for it. The following part is focusing on the basics.
A.1.1. Shifting
In C there are the shifting operators << and >>.
They must not be confused with the stream operators in C++!
Therefore it is strongly recommended to use brackets around them.
An expression like (a << b) will be evaluated as the binary representation of a will be shifted
b times to the left, the value is getting larger. (a >> b) shifts the to the right and therefor
decreases the value. Empty spaces are filled with 0.
The example demonstrates:
15
Version 1.1 IWR - robotics lab
The obvious way to define bit no. n is using the expression. (1 << n).
Boolean bit-wise
AND && &
OR || |
XOR != ^
NOT ! ~
// ...or shorter
a |= (1 << 5);
16
Version 1.1 IWR - robotics lab
// elaborately
ption a = a & ~(1 << 5);
// ...or shorter
40µA a &= ~(1 << 5);
5µA (including
ForOscillator)
example:
de: 101100102
& ~ 001000002
101100102
& 110111112
100100102
urations =
PDIP
TQFP TopFigure
View 5: Pin out of the controller excerpt from the data sheet[1].
MLFFor
Top View
orientation use the
PC4 (ADC4/SDA/PCINT12)
PC5 (ADC5/SCL/PCINT13)
PC4 (ADC4/SDA/PCINT12)
marking on top
PC5 (ADC5/SCL/PCINT13)
PC6 (RESET/PCINT14)
PC6 (RESET/PCINT14)
PC3 (ADC3/PCINT11)
PC2 (ADC2/PCINT10)
PC3 (ADC3/PCINT11)
PC2 (ADC2/PCINT10)
PD2 (INT0/PCINT18)
PD0 (RXD/PCINT16)
PD1 (TXD/PCINT17)
PD2 (INT0/PCINT18)
PD0 (RXD/PCINT16)
PD1 (TXD/PCINT17)
32
31
30
29
28
27
26
25
32
31
30
29
28
27
26
25
17
10
11
12
13
14
15
16
10
11
12
13
14
15
16
9
9
T21/OC0B/T1) PD5
22/OC0A/AIN0) PD6
PCINT23/AIN1) PD7
T0/CLKO/ICP1) PB0
PCINT1/OC1A) PB1
INT2/SS/OC1B) PB2
3/OC2A/MOSI) PB3
(PCINT4/MISO) PB4
T21/OC0B/T1) PD5
2/OC0A/AIN0) PD6
CINT23/AIN1) PD7
0/CLKO/ICP1) PB0
PCINT1/OC1A) PB1
NT2/SS/OC1B) PB2
3/OC2A/MOSI) PB3
PCINT4/MISO) PB4
B. References
References
[1] Atmel Corporation. Datasheet to atmega48/88/168, 2005.
[2] Wikipedia. Servo — wikipedia, die freie enzyklopädie, 2011. [Online; Stand 23. November
2011].
Version
This document was created from git commit 2874ba28f297718d16661fa9a4aee6fd6ce3efb0
18