TP Atmega
TP Atmega
TP Atmega
2024 – 2025
Atmega32u4 – Langage C
Session d’Automne
Enseignant: BABA
youssef.baba@univh2c.ma
Objectifs :
¨ Exploiter une chaîne de développement : avr-gcc (compilateur), teensy_loader et avrdude
¨ Mettre en œuvre la gestion des entrées-sorties du microcontrôleur atmega32u4.
¨ Écrire un programme en langage C pour microcontrôleur (structure de base : variables, boucles, tests).
Matériel :
TP1 – TP2
¨ Carte Teensy 2.0 (i/o: 5V – quartz: 16MHz).
¨ Boutons poussoirs utilisateurs : 02 (PB1 ; PB2)
¨ LEDs : 03 (PD4 ; PD5 ; PD6)
¨ Sur la planche de test, les pins PB2 et PD0 sont connectés par un fil sous la carte Teensy
TP 0 – Setup et Installations
i. Avr-gcc
ii. Programmeur
iii. Atmel Studio
iv. Arduino Ide
TP 2 – USART
Application 5 : UART
Application 6 : Interruptions UART
TP 0 – Setup et Installations
i. Avr-gcc
L’outil libre avr-gcc est nécessaire pour compiler un code C écrit pour la famille des microcontrôleurs AVR
de MICROCHIP. Avr-gcc permet de créer un fichier hex qui sera téléversé dans la carte microcontrôleur
pour la programmer l’atmega32u4.
Appuyer sur le bouton Boot pour laisser le bootloader charger le fichier binaire et exécuter le code.
Atmel Studio permet de développer facilement votre projet C/C++ (plusieurs étudiants préfèrent cette
solution). Atmel Studio intègre le compilateur Avr-gcc et il peut être configuré pour programmer également
la carte à microcontrôleur. C’est un bon choix puisqu’il permet de déboguer le code C/C++ en offrant la
possibilité de voir les valeurs des différents registres de l’Atmega32u4 durant l’exécution du programme.
Cocher la première option pour utiliser les microcontrôleurs AVR 8-bits et ignorer par exemple d’installer
les prérequis pour les microcontrôleurs SAM (ARM). Une fois installé, chercher si une mise à jour est
disponible. Suivre ce tuto pour commencer à utiliser le logiciel : https://www.pololu.com/docs/0J36/3.b
Installer Teensyduino (une extension Arduino) pour utiliser la carte Teensy avec Arduino Ide :
https://www.pjrc.com/teensy/td_download.html
Le logiciel Arduino utilise un langage dédié qui se base sur le langage C++ dit simplement Arduino. Ce
langage est basé sur deux fonctions principales :
void setup() {
// put your setup code here, to run once:
}
void loop() {
// put your main code here, to run repeatedly:
}
Cette approche cache une utilisation non souhaitée des ressources du microcontrôleur : à cause de la
méthode de compilation implémentée par Arduino. On peut donc utiliser le logiciel (avec prudence) en
supprimant les deux fonctions par défaut, et en utilisant une fonction int main() {} standard. Noter que la
fonction doit absolument retourner un type int. Un autre intérêt de l’utilisation du logiciel Arduino est la
possibilité de téléverser le fichier hex de façon automatique en utilisant l’outil teensy_loader :
https://www.pjrc.com/teensy/loader.html
Créer le dossier app_1 puis y ajouter le fichier source chenillard.c dont le code est donné ci-dessous.
#include <io.h>
#include <delay.h>
int main() {
CLKPR = 0x80; CLKPR = 0x00;//required for this board version
while(1) {
PORTD ^=(7<<4); //toogle D6-D5-D4
DELAY_ms(500);//delay 0.5s
}
return 0;
}
#include "usb.h"
#include <stdbool.h>
int main(void) {
CLKPR = 0x80; CLKPR = (0);
char value;
usb_init();
while(!usb_isconnected()); // wait for a connection
while(1) {
if(usb_rx_available())
{ value = usb_rx_char();
usb_tx_char(value);
if(usb_rx_available()==0) usb_tx_char('\n'); }
} return 0;
}
Remarque : le code ci-dessus ne fonctionne pas dans Arduino. Car Arduino implémente sa propre classe
usb-cdc notée Serial, et qui utilise les mêmes routines d’interruptions dans usb.c
Q2.1 : Proposer un code qui permettra d’inverser l’état de la led jaune à chaque appui sur le bouton PB1.
Q2.2 : Que constatez-vous ?
Q2.3 : Modifier le code pour afficher (sur un moniteur série dans votre PC) l’état de la led et le nombre
de fois d’appui sur le bouton poussoir.
// software debounce
ISR(INT0_vect) {PORTB ^= 1<<PD6; _delay_ms(100);}
int main(void)
{ CLKPR = 0x80; CLKPR = 0x00;//required for this Teensy
MCUCR &=~(1<<PUD);//
DDRD &= ~(1<<PD0) ; //PD0 input (int0)
DDRD |= (1<<PD6) ; //PD6 output (LED_D6)
PORTD |= (1<<PD0) ; //enable pullup on PD0
DDRB |=(1<<PB0) ; //PB0 output (LED_B0)
EIMSK = 1<<INT0 ; //enable int0
sei();
while(1) {PORTB^=1<<PORTB0;_delay_ms(200);}
}//fin main
Q3.1 : Que constatez-vous si vous maintenez enfoncé le bouton sur PD0? Pourquoi ?
Q3.2 : Proposer une solution déclenchant un drapeau dans l’ISR et gérant les conséquences de ce drapeau
(changement d’état de la LED_PD6) dans la fonction principale (main()). On pourra réactiver les
interruptions (sei()) une fois le drapeau traité dans le programme principal.
Q3.3 : Modifier le code pour déclencher l’interruption sur un front descendant.
0 0 0 inactif 0 0 0 inactif
0 0 1 /1 0 0 1 /1
0 1 0 /8 0 1 0 /8
0 1 1 /64 0 1 1 /64
1 0 0 /256 1 0 0 /256
1 0 1 /1024 1 0 1 /1024
Configuration de l’horloge du Timer0 Configuration de l’horloge du Timer1
Soit le code source app_4/main.c
#define F_CPU 16000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
volatile char c = 0;
Q4.1 : Sachant que F_CPU=16000000, quelle est la fréquence de clignotement de LED5 et LED4 ?
Q4.2 : Quelle condition sur c faudrait-il ajouter pour que la diode commute à 0.5 Hz ?
Q4.3 : Modifier le programme du fichier app_4/main.c, pour que les deux Timer fonctionnent en mode
CTC. La boucle (while(1)) de la fonction main() doit être vide. L’évolution du motif des LEDs est donnée
exclusivement dans le gestionnaire d’interruption ISR.
Application 5 : UART
void uart_init(void)
{ unsigned int baud = BAUD_PRESCALE;
UBRR1H = (unsigned char) (baud >> 8 );
UBRR1L = (unsigned char)baud;
UCSR1B = ( 1 << RXEN1 ) | ( 1 << TXEN1 );
UCSR1C = ( 3 << UCSZ10 ) ;//8N1
UCSR1A = ( 1<<U2X1 );}
//int uart_dataAvailable(void);
int main(void)
{ CLKPR = 0x80; CLKPR = 0x00;//required for this teensy
MCUCR &=~(1<<PUD);// char c=42;
uart_init();
while (1)
{ _delay_ms(10); uart_transmit(c);
c++; if (c==127) {c=32;uart_transmit('\n');}}
return 0;
}
Q5.1 : Qu’affiche le code ci-dessus ? Quelle est la durée de transmission de chaque caractère ?
Q5.2 : Modifier le programme pour recevoir un caractère obtenu sur le port série, et le transformer en la
majuscule si le caractère reçu est une lettre minuscule, et réciproquement.
Afin de libérer le CPU, il est souhaitable d’interrompre l’exécution séquentielle qu’un caractère est reçu.
Cependant, nous ne voulons pas passer de temps inutilement dans l’interruption qui doit se réduire
uniquement au code de réception d’un caractère. À ces fins, nous définissons un flag qui indique au
programme principal la réception d’un caractère et qu’une action doit être prise en conséquent.
Reprendre le code ci-dessous dans un nouveau projet. Compiler, programmer et tester.
#define F_CPU 16000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h> // _delay_ms
#define USART_BAUDRATE 9600
#define BAUD F_CPU/USART_BAUDRATE/16UL - 1
int main(void){
CLKPR = 0x80; CLKPR = 0x00;//required for this teensy
MCUCR &=~(1<<PUD);// char c=42;
DDRD |=1 << PORTD6;
PORTD |= 1 << PORTD6;
UCSR1A = 0; // importantly U2X1 = 0
unsigned int baud = BAUD;
UBRR1H = (unsigned char) (baud >> 8 );
UBRR1L = (unsigned char) baud;
UCSR1B = (1 << RXEN1) | (1 << TXEN1);
UCSR1C = (3 << UCSZ10);
UCSR1A = (1<<U2X1);
sei();
while (1)
if (flag!=0) {flag=0;uart_transmit(received);PORTD ^=(1<<PD6);}
return 0;
}
Q6.1 : Justifier de la définition de variables globales pour échanger des informations entre programme
principal et gestionnaire d’interruption.
Q6.2 : Proposer une solution pour recevoir plusieurs caractères entre deux traitements du flag par le
programme principal. Le traitement se fera dans la gestionnaire d’interruption.
Q6.3 : Proposer un code C qui fait clignoter une LED6 périodiquement, détecte une transition d’état sur
PB1, et communique par UART, en limitant la boucle infinie dans la fonction principale main() à while
(1); Penser à éliminer le flag et aussi la fonction uart_transmit (received).