Académique Documents
Professionnel Documents
Culture Documents
Julien Le Guen
6 fvrier 2007
Rsum
Ce document est une introduction la programmation des AVR, no-
tamment la famille ATmega. Il prsente brivement ces microcontrleurs,
puis explique en dtail leur utilisation avec le matriel disponible au club
Esial RobotiK. Ce document s'adresse aux lectroniciens et informaticiens
du club qui ne sont pas familiers avec ce type de microcontrleur, et de-
viendra au fur et mesure de l'anne un aide mmoire et un guide de la
bonne utilisation des AVR. Chacun est convi contribuer ce document
pour l'enrichir de ses expriences.
1
Table des matires
1 Introduction 3
1.1 Prsentation des AVR . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2 Environnement de dveloppement . . . . . . . . . . . . . . . . . . 3
2 Premiers pas 4
3 Aller plus loin 6
4 HowTo congurer les fusibles 7
4.1 Programmation des fusibles . . . . . . . . . . . . . . . . . . . . . 7
4.1.1 Avrdude . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
4.1.2 uisp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
4.2 ATmega32 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
4.2.1 Conguration du JTAG . . . . . . . . . . . . . . . . . . . 8
4.2.2 Conguration de l'oscillateur . . . . . . . . . . . . . . . . 9
4.3 ATtiny2313 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
4.3.1 Conguration de l'oscillateur . . . . . . . . . . . . . . . . 10
6 Codes sources 13
6.1 Chenillard . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
6.2 Utilisation d'un tlmtre IR numrique . . . . . . . . . . . . . . 14
6.3 Utilisation d'une liaison srie . . . . . . . . . . . . . . . . . . . . 16
7 Memento 17
7.1 Programmation C . . . . . . . . . . . . . . . . . . . . . . . . . . 17
7.2 AvrDude . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
7.3 Liens utiles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2
1 Introduction
1.1 Prsentation des AVR
Les AVR sont des microcontrleurs (C) 8bits RISC d'ATMEL trs perfor-
mants (architecture de Harvard), dont la famille est trs tendue. On y trouve
des petits (ATtiny11, 8 pattes) et des trs gros (ATmega128, 64 pattes, insou-
dable sans aspirine). Ils ont tous en commun le coeur (CPU), seuls les priph-
riques, la mmoire ash, la ram, etc... dirent. Et c'est l un atout de taille, car
un code crit pour un ATmega8 fonctionnera sans modication majeure sur un
ATmega32 par exemple ( une recompilation prs). Un autre avantage en leur
faveur face d'autres C comme les PICs par exemple, c'est la suite de logiciel
libres permettant de compiler, programmer, dbugger les AVR, en live, in situ.
Nous reviendrons sur cette notion plus loin.
3
2 Premiers pas
Nous allons voir dans cette section comment crire, compiler et asher un
programme simple pour ATmega32. Tout ce qui suit est cependant valable
pour la famille ATmega. Tout d'abord, voyons un programme simple (simpliste
mme) qui fait clignoter une LED.
Ce programme initialise la patte 5 du port C en sortie, puis boucle ind-
niment autour du code faisant clignoter la led. Bien que trs simple il ncessite
quelques explications. L'instruction _BV(nb_bits) est une macro qui place 1
le bit nb_bits. les oprateurs |, & et ~ sont, dans l'ordre, le OU bits bits, le
ET bits bits et la ngation.
Listing 1 led0.c
#i n c l u d e <avr / i o . h>
v o i d mondelai ( u n s i g n e d s h o r t i )
{
/* A t t e n t e a c t i v e c r a d e */
w h i l e ( i >0) ;
}
i n t main ( v o i d )
{
/* On met l a p a t t e PC5 en s o r t i e */
DDRC |= _BV(PC5) ;
while (1)
{
/* F a i t c l i g n o t e r l a l e d */
PORTC &= ~_BV(PC5) ;
mondelai ( 6 5 0 0 0 ) ;
PORTC |= _BV(PC5) ;
mondelai ( 5 0 0 0 ) ;
}
}
Listing 2 Makele
CC=avr g c c
FILE=l e d 0
OBJCOPY=avr o b j c o p y
CFLAGS=g mmcu=atmega32 Wall Wstrict p r o t o t y p e s Os mcall
prologues
# i c i c ' e s t pour c o m p i l e r
a l l : $ ( FILE ) . hex
$ ( FILE ) . hex : $ ( FILE ) . out
4
$ (OBJCOPY) R . eeprom O i h e x $ ( FILE ) . out $ ( FILE ) . hex
$ ( FILE ) . o : $ ( FILE ) . c
$ (CC) $ (CFLAGS) c $ ( FILE ) . c
clean :
rm f * . o * . out * . map * . hex
prog_burn :
u i s p upload i f =$ ( FILE ) . hex dprog=dapa dno p o l l v
prog_verif :
u i s p v e r i f y i f =$ ( FILE ) . hex dprog=dapa dno p o l l v
prog : p r og _ e ra s e prog_burn p r o g _ v e r i f
Il n'y a pas s'inquiter devant la taille de ce chier. Il sut de taper make cprog
pour compiler le chier led0.c et le asher dans le C.
Cependant il faut encore relier l'AVR l'ordinateur, via le cable ISP. Le
branchement est simple :
l jaune/noir (16) : patte RESET
l brun (1) : patte SCK
l blanc (11) : patte MISO
l rouge (2) : patte MOSI
l gris/noir (25) : patte GND
Ils sont regroups sur un connecteur 6 points, qu'il faut brancher sur le C
en face des pattes correspondantes (attention au sens !) et le tour est jou. On
utilise l'utilitaire uisp pour papoter avec le C.
5
3 Aller plus loin
Le programme led0.c fonctionne, mais il consomme tout le temps processeur
et on ne peut rien faire d'autre en attendant. Nous allons donc modier le
programme pour qu'il utilise les interruptions.
Listing 3 led0.c
#i n c l u d e <avr / i o . h>
#i n c l u d e <avr / i n t e r r u p t . h>
#i n c l u d e <avr / s i g n a l . h>
SIGNAL(SIG_OUTPUT_COMPARE1A)
{
/* Code de l ' i n t e r r u p t i o n */
PORTC ^= _BV(PC5) ;
}
i n t main ( v o i d )
{
/* On c o n f i g u r e l a p a t t e en s o r t i e */
DDRC |= _BV(PC5) ;
PORTC &= ~_BV(PC5) ;
/* On c o n f i g u r e l e t i m e r q u i
* l a n c e r a l e s i n t e r r u p t i o n s */
TCCR1B = _BV( CS10 ) | _BV( CS11 ) | _BV(WGM12) ;
OCR1A = (F_CPU/ 2 5 6 ) ;
TIMSK = _BV(OCIE1A) ;
/* On a c t i v e l e s i n t e r r u p t i o n s */
sei () ;
/* On a t t e n d betement */
while (1) ;
}
6
4 HowTo congurer les fusibles
Les AVR ont des registres, accessibles uniquement avec un programmateur
(ISP ou JTAG), qui permettent de congurer physiquement l'AVR : utilisa-
tion ou non du JTAG, de ISP, frquence de l'oscillateur interne, etc... Ils sont
appels fusibles, et la connaissance de leur fonctionnement est primordiale : si
les fusibles sont mal positionns, on risque de ne plus pouvoir programmer le C !
Les fusibles sont moables par ISP ou JTAG. En ISP on peut utiliser
avrdude ou uisp :
4.1.1 Avrdude
Lire la conguration des fusibles :
-U lfuse:r:-:h
On accde au LowByteFuse, en lecture (r), sans valeur (-)
4.1.2 uisp
Lire la conguration des fusibles (rsultat en hxadcimal) :
7
LB2 > 1
LB1 > 1
$ u i s p dprog=dapa wr_fuse_l=0x89
4.2 ATmega32
8
Le reste des infos ne nous intressa pas ici. Le HighByte vaut 0x99, soit 0b10011001.
En mettant le bit 6 1 nous obtenons 0b11011001, soit 0xd9. On va donc crire
cette valeur dans le High Byte Fuse :
Nous pouvons dsormais utiliser le port C comme n'importe quel port. Attention
cependant, le JTAG tant dsactiv il faudra le remettre si on veut dbugger le
code.
9
On positionne le bit CKOPT (bit 4), ce qui donne une valeur de 0x89 pour le
High Byte.
Le Low Byte vaudra quant- lui 0xef.
4.3 ATtiny2313
L'ATtiny est un petit micro, qui n'a pas d'interface JTAG. Cependant il
possde 3 registres de fusibles pour congurer le fonctionnement du processeur.
Fuse High Byte Bit No Description Default Value
DWEN 7 debugWIRE Enable 1 (ud)
EESAVE 6 EEPROM memory is preserved 1 (u)
SPIEN(1) 5 Enable Serial Downloading 0 (p)
WDTON(2) 4 Watchdog Timer always on 1 (u)
BODLEVEL2 3 Brown-out Detector trigger level 1 (u)
BODLEVEL1(4) 2 Brown-out Detector trigger level 1 (u)
BODLEVEL0 1 Brown-out Detector trigger level 1 (u)
RSTDISBL 0 External Reset disable 1 (u)
10
5 Compilation avec Aversive
Aversive est un framework de dveloppement pour AVR. Il comprend une
bibliothque de fonctionnalits, utilise l'environnement de compilation gcc-avr
+ avr-binutils, et permet de programmer les chips avec avrdude ou avarice.
Utilisable sous linux ou windows. Nous ne traiterons ici que le cas sous linux.
5.1 Installation
Si vous avez besoin, pour une raison ou pour une autre, d'utiliser avrdude
la main, voici quelques informations :
Eacer le micro (l'option y sert incrmenter un compteur d'eacement
en EEPROM)
avrdude -p m32 -c dapa -y -e)
Programmer la zone ash du micro (avec chier.hex)
avrdude -p m32 -c dapa -y -U flash:w:fichier.hex
Voici comment mettre en place simplement une liaison srie entre le montage
et l'ordinateur.
Tout d'abord, crez un projet Aversive (ou modiez un existant). Dans une
console, faites un coup de make menuconfig et modiez les options relatives la
liaison srie (menu Communication Modules, cochez Uart et Create default uart config).
Un chier uart_config.h est automatiquement cr. C'est dans ce chier que
sont dnis les paramtres de la liaison. Par dfaut, liaison 38400 bauds, 8 bits,
1 stop, pas de parit. Pensez congurer le PC en consquence ! (Ctrl-A Z sous
minicom).
Dans votre chier C, incluez <uart.h>. Puis initialisez la liaison :
1 Wiki Aversive : http://wiki.droids-corp.org/mediawiki/index.php/Aversive
Snapshot Aversive : http://zer0.droids-corp.org/aversive_snapshot.tar.gz
11
Listing 9 Initialisation de l'UART
#i n c l u d e <avr / i o . h>
#i n c l u d e <w a i t . h>
#i n c l u d e <u a r t . h>
#i n c l u d e <s t d i o . h>
i n t main ( v o i d )
{
struct uart_config u ;
uart_init () ;
f d e v o p e n ( uart0_dev_send , uart0_dev_recv ) ;
sei () ;
u a r t 0 _ g e t c o n f (&u ) ;
12
6 Codes sources
Cette section regroupe des exemples de programmes.
6.1 Chenillard
Listing 10 chenillard.c
/* C h e n i l l a r d a l a K2000 ! ! ! */
#i n c l u d e <avr / i o . h>
#i n c l u d e <avr / i n t e r r u p t . h>
#i n c l u d e <avr / s i g n a l . h>
#d e f i n e F_CPU 1000000UL
#i n c l u d e <avr / d e l a y . h>
// Routine d ' i n t e r r u p t i o n
SIGNAL(SIG_OUTPUT_COMPARE1A)
{
i f ( s e n s ) PORTC = PORTC << 1 ;
e l s e PORTC = PORTC >> 1 ;
// Changement de s e n s
i f (PORTC == 1 ) s e n s = 1 ;
i f (PORTC == 0 x80 ) s e n s = 0 ;
}
i n t main ( v o i d )
{
// Tout l e p o r t C en s o r t i e
DDRC = 0xFF ;
// I n i t i a l i s a t i o n du c h e n i l l a r d
PORTC = 0xFF ;
_delay_ms ( 6 5 0 0 0 ) ;
PORTC = 1 ;
sens = 1;
// I n i t i a l i s a t i o n du t i m e r
TCCR1B = _BV( CS10 ) | _BV( CS11 ) | _BV(WGM12) ;
OCR1A = (F_CPU/ 2 0 4 8 ) ;
TIMSK = _BV(OCIE1A) ;
// Mise en p l a c e de l ' i n t e r r u p t i o n
sei () ;
13
6.2 Utilisation d'un tlmtre IR numrique
/*
* U t i l i s a t i o n d ' un t e l e m e t r e GP2D02
* Pas d ' i n t e r r u p t i o n
*/
#i n c l u d e <avr / i o . h>
#d e f i n e F_CPU 1000000UL
#i n c l u d e < u t i l / d e l a y . h>
#d e f i n e CLK PD1
#d e f i n e VOUT PD0
/* Macros c l e a r _ b i t e t s e t _ b i t */
#d e f i n e cb ( port , b i t ) ( ( p o r t ) &= ~_BV( b i t ) )
#d e f i n e sb ( port , b i t ) ( ( p o r t ) |= _BV( b i t ) )
/* L e c t u r e d ' une v a l e u r du t e l e m e t r e
* I l f a u t r e s p e c t e r un t i m i n g d e f i n i dans l a doc du t e l e m e t r e
* d ' ou l a p r e s e n c e de _delay_us ( ) */
unsigned char l e c t u r e ( )
{
u n s i g n e d c h a r temp , i ;
// A c t i v a t i o n du t e l e m e t r e
cb (PORTD, CLK) ;
// On a t t e n d ( betement ) que l e t e l e m e t r e v e u i l l e b i e n
w h i l e ( ! ( PIND & _BV(VOUT) ) ) ;
// On e n v o i e l a c l o c k e t on l i t l a v a l e u r r e n v o y e e
f o r ( i =0; i <8; i ++)
{
sb (PORTD, CLK) ;
temp = temp << 1 ;
_delay_us ( 1 0 0 ) ;
cb (PORTD, CLK) ;
_delay_us ( 1 0 0 ) ;
// On p o s i t i o n n e l e LSB s e l o n l a v a l e u r de VOUT
i f (PIND & _BV(VOUT) ) sb ( temp , 0 ) ;
e l s e cb ( temp , 0 ) ;
}
// tempo en f i n d ' i n t e r r o g a t i o n
sb (PORTD, CLK) ;
_delay_ms ( 2 ) ;
cb (PORTD, CLK) ;
r e t u r n temp ;
}
14
v o i d main ( v o i d )
{
unsigned char valeur ;
/* I n i t i a l i s a t i o n */
// PORTC en s o r t i e
DDRC = 0xFF ;
PORTC = 0xFF ;
// VOUT en e n t r e e , CLK en s o r t i e
cb (DDRD, VOUT) ;
sb (DDRD, CLK) ;
// I n i t i a l i s a t i o n t e r m i n e e
_delay_ms ( 6 5 0 0 0 ) ;
PORTC = 0 ;
while (1)
{
valeur = lecture () ;
/* Mise en forme de l a v a l e u r r e n v o y e e
* I c i on a f f i c h e un bargraph motrant l a d i s t a n c e
* Plus c ' e s t proche , p l u s l a v a l e u r e s t e l e v e e */
v a l e u r /= ( 2 5 5 / 9 ) ;
switch ( valeur )
{
c a s e 1 : PORTC = 0 x01 ; break ;
c a s e 2 : PORTC = 0 x03 ; break ;
c a s e 3 : PORTC = 0 x07 ; break ;
c a s e 4 : PORTC = 0x0F ; break ;
c a s e 5 : PORTC = 0x1F ; break ;
c a s e 6 : PORTC = 0x3F ; break ;
c a s e 7 : PORTC = 0x7F ; break ;
c a s e 8 : PORTC = 0xFF ; break ;
c a s e 0 : PORTC = 0 x0 ; break ;
} h t t p : // w i k i . d r o i d s c o r p . o r g / mediawiki / i n d e x . php/
Aversive
/* I l f a u t a t t e n d r e 70ms e n t r e chaque l e c t u r e
* On p o u r r a i t u t i l i s e r une i n t e r r u p t i o n
* t o u t e s l e s 70ms pour l i b e r e r l e cpu e t f a i r e a u t r e
* c h o s e que c e t t e b e t e a t t e n t e a c t i v e */
_delay_ms ( 7 0 ) ;
}
15
Exercice
Utiliser les interruptions pour lancer la lecture de la valeur toutes les 70ms.
Pour information, la fonction lecture() est construite d'aprs le datasheet du
sharp : http://www.junun.org/MarkIII/datasheets/GP2D02.pdf.
Cet exemple utilise la carte de Stoo (Eirbot 2005) gnreusement prte pour
qu'on puisse jouer en attendant la notre :) Rien de compliqu l dedans, mais
sert d'aide mmoire.
#i n c l u d e <avr / i o . h>
#i n c l u d e <w a i t . h>
#i n c l u d e <u a r t . h>
#i n c l u d e <s t d i o . h>
#d e f i n e LEDA 6
#d e f i n e LEDB 7
i n t main ( v o i d )
{
struct uart_config u ;
i n t i =0;
uart_init () ;
s b i (DDRC, LEDA) ;
s b i (DDRC, LEDB) ;
s b i (PORTC, LEDA) ;
f d e v o p e n ( uart0_dev_send , uart0_dev_recv ) ;
sei () ;
u a r t 0 _ g e t c o n f (&u ) ;
while (1) {
p r i n t f ( " E s i a l RobotiK %d\ r \n" , i ++) ;
PORTC ^= 0xC0 ;
wait_ms ( 1 0 0 0 ) ;
p r i n t f ( "%d %d %d %d %d / %d %l d \ r \n" ,
u . enabled , u . i n t r _ e n a b l e d , u . use_double_speed ,
u . parity , u . stop_bits , u . nbits , u . baudrate ) ;
PORTC ^= 0xC0 ;
wait_ms ( 1 0 0 0 ) ;
}
return 0;
}
16
7 Memento
7.1 Programmation C
1. Ne pas confondre le ET logique (&&) avec le ET bit bit (&). Les utilisa-
tions sont totalement direntes !
2. De mme, ne pas confondre le OU logique (||) et le OU bit bit (|).
3. Pour crire sur un port, crire dans le registre PORTx (x est le nom du
port). En revanche pour lire, il faut utiliser le registre PINx !
7.2 AvrDude
Atmel : www.atmel.com/avr
Datasheet ATmega32 : http://atmel.com/dyn/resources/prod_documents/
doc2503.pdf
Wikibook : http://en.wikibooks.org/wiki/Atmel_AVR
Ecient C Coding for AVR : http://atmel.com/dyn/resources/prod_
documents/doc1497.pdf
Application Notes : http://atmel.com/dyn/products/app_notes.asp?
family_id=607
PID sur AVR : http://atmel.com/dyn/resources/prod_documents/doc2558.
pdf
AVRfreaks : http://avrfreaks.net/
17