Table des matières

AVR Studio 6

AVR Studio est un environnement de développement gratuit réalisé par Atmel.

Télécharger AVR Studio

Programmation en C avec AVRGCC

AVR Studio 6 intègre par défaut un compilateur C.

Création d'un projet

Démarrez AVR Studio

Cliquez sur “New project”

Sélectionnez “GCC C Executable project”
Indiquez un nom de projet (mon_projet) et un emplacement Exemple : C:\Projet_AVR\mon_projet\:

Sélectionner votre microcontrôleur

Cliquez sur “OK”

Mon 1er programme

Entrez le code suivant dans le fichier mon_projet.c :

/*
 * Test.c
 * Mise à la masse du bit 0 du port R pour l'allumage d'une LED 
 * Created: 20/08/2014 00:24:08
 *  Author: -JP-
 */ 
 
 
#include <avr/io.h>
 
int main(void)
{
    PORTR.DIR |=0b00000001; //Met le bit 0 port R en sortie
    PORTR.OUT &=~0b00000001; //Met le bit 0 port R à la masse
 
    while(1)
    {
        //TODO:: Please write your application code 
    }
}

Sauvegardez le projet : Fichier → Enregistrer Tout
Compilez le projet : Générer → Générer la solution

Vous ne devriez pas avoir d'erreur :

Simulation

Dans Project → Propriétés de votre projet, sélectionner “Simulator” dans Tools → Selected Debugger/programmer

Positionner un point d’arrêt à la ligne “PORTR.OUT &=~0b00000001;” en cliquant à gauche de la ligne.
Aller dans le menu Déboguer → Continuer.
Votre programme va alors s’exécuter jusqu'au point d’arrêt. Cliquer sur le bouton “I/O view”, sélectionner le PORTR. Vous voyez dans le registre “DIR” que le premier bit a bien été mis à 1 pour indiquer que la pin doit être utilisée en sortie.

ASF Atmel Software Framework

Introduction

ASF est un framwork developpé pour faciliter le développement de vos applications.

Création d'un projet

Pour commencer, nous allons créer un projet du type “GCC ASF Board Project”. Spécifier le microcontroleur que vous utilisez puis “User Board template”. Dans la fenetre ASF Wizard“ selectionner votre projet.

La fonction board_init qui apparait dans le main de votre projet est prévue pour initialiser vos entrées/sorties. Par defaut, celle-ci est vide. Vous être libre de l'utiliser ou non askip

Ajouter une librairie

Aller dans ASF → ASF Wizard
Dans project, sélectionner votre projet
Selectionner “GPIO - General purpose Input/Output (service)
Cliquer sur “Add”cliquer sur Add pour l'intégrer à votre projet.

Cliquer sur “Apply” pour confirmer l'importation.

Vous pouvez maintenant utiliser les fonctions de cette librairie. Pour accéder à la descriptions détaillées de ces fonctionner aller dans ASF Explorer → GPIO → API Documentation

GPIO - IOPORT

La librairie GPIO contient les fonctions de base permettant de lire, configurer ou commander une pin d'entrée/sortie.

La librairie IOPORT est également incluse dans le “pack” GPIO et vous offre quelques fonctionnalités supplémentaires en se basant sur la librairie GPIO.

Nous allons ajouter dans notre projet

#include <ioport.h>

pour pouvoir utiliser certains mot-clés.

Commander une sortie

La première chose à faire et de définir quelle pin vous souhaitez commander. Pour ma part, je souhaite piloter une led qui est connectée à PD4. Pour simplifier la lisibilité du code, nous allons définir un nom pour cette sortie :

#define LED_ROUGE IOPORT_CREATE_PIN(PORTD, 4)

Ensuite, il faut initialiser les fonctions IOPORT avant de pouvoir les utiliser.

ioport_init();

Vous devez également définir la direction de votre pin

ioport_set_pin_dir(LED_ROUGE, IOPORT_DIR_OUTPUT);

Ma led est allumée quand PD4 est à 0V. Les XMEGA permettent d'inverser facilement la commande d'une sortie et ensuite avoir une code plus “logique” avec un allumage de la led quand la sortie est mise à “1”.

ioport_set_pin_mode(LED_ROUGE,IOPORT_MODE_INVERT_PIN);

Pour finir par la mettre à l'état haut

ioport_set_pin_level(LED_ROUGE, 1);

Ce qui vous fait, au final

#include <avr/io.h>
#include <ioport.h>
 
#define LED_ROUGE IOPORT_CREATE_PIN(PORTD, 4) //LED_Rouge = PD4
 
int main(void)
{
	//Initialisation des entrées/sorties
	ioport_init();						//Initialisation d'IOPORT
	ioport_set_pin_dir(LED_ROUGE, IOPORT_DIR_OUTPUT);	//LED_ROUGE est une sortie
	ioport_set_pin_mode(LED_ROUGE,IOPORT_MODE_INVERT_PIN);	//Inverse la commande de la pin LED_ROUGE 
 
	ioport_set_pin_level(LED_ROUGE,1);			//LED_Rouge à l'état haut
 
    while(1)
    {
        //TODO:: Please write your application code 
    }
}

Lire une entrée

On va ajouter à notre code la lecture d'un bouton et modifier l'état de la led en fonction de l'appui du bouton. De la même maniére que pour la LED, nous allons nommer cette entrée bouton.

#define BOUTON IOPORT_CREATE_PIN(PORTF, 1)		//BOUTON = PF1

Mon bouton met une masse sur l'entrée lors de l'appui. Tout comme pour la LED, il est plus logique d'inverser cette entrée afin d'avoir un état “1” lors de l'appui.

	ioport_set_pin_dir(BOUTON, IOPORT_DIR_INPUT);			//BOUTON en entrée
	ioport_set_pin_mode(BOUTON,IOPORT_MODE_INVERT_PIN);		//Inverse l'état de la pin

Nous allons ensuite tester de manière permanente l'état du bouton. Si le bouton est appuyé, la LED sera allumée.

if(ioport_get_pin_level(BOUTON))		//Appui sur le bouton
	ioport_set_pin_level(LED_ROUGE,1);	//Allume la LED
else						//Relachement du bouton
	ioport_set_pin_level(LED_ROUGE,0);	//Eteind la LED

Voici le code complet :

#include <avr/io.h>
#include <ioport.h>
 
#define LED_ROUGE IOPORT_CREATE_PIN(PORTD, 4)	//LED_Rouge = PD4
#define BOUTON IOPORT_CREATE_PIN(PORTF, 1)	//BOUTON = PF1
 
int main(void)
{
	//Initialisation des entrées/sorties
	ioport_init();							//Initialisation d'IOPORT
	ioport_set_pin_dir(LED_ROUGE, IOPORT_DIR_OUTPUT);		//LED_ROUGE est une sortie
	ioport_set_pin_mode(LED_ROUGE,IOPORT_MODE_INVERT_PIN);		//Inverse la commande de la pin  
 
	ioport_set_pin_dir(BOUTON, IOPORT_DIR_INPUT);			//BOUTON en entrée
	ioport_set_pin_mode(BOUTON,IOPORT_MODE_INVERT_PIN);		//Inverse l'état de la pin
 
	while(1)
	{
		if(ioport_get_pin_level(BOUTON))		//Appui sur le bouton
			ioport_set_pin_level(LED_ROUGE,1);	//Allume la LED
		else						//Relachement du bouton
			ioport_set_pin_level(LED_ROUGE,0);	//Eteind la LED		
	}
}

Horloge

Lors de la création d'un projet ASF avec comme template “Userboard” des fichiers de configuration par défaut sont créés.

Ces fichiers se trouvent dans le répertoire “config”. L'un d'eux, conf_clock.h, premet la configuration de l'horloge lors de son démarrage.

Par défaut, l'horloge utilisée est l'oscillateur interne de 2Mhz:

#define CONFIG_SYSCLK_SOURCE          SYSCLK_SRC_RC2MHZ

CONFIG_SYSCLK_SOURCE définit la source de votre horloge système qui peut être :

SYSCLK_SRC_RC2MHZ Oscillateur 2Mhz interne
SYSCLK_SRC_RC32MHZ Oscillateur 32Mhz interne
SYSCLK_SRC_XOSC Oscillateur externe
SYSCLK_SRC_XOSC PLL

Dans le cas de l'utilisation d'un oscillateur externe, il faudra également définir son type et sa fréquence dans le fichier user_board.h

Sans prédivision de cette horloge :

#define CONFIG_SYSCLK_PSADIV          SYSCLK_PSADIV_1
#define CONFIG_SYSCLK_PSBCDIV         SYSCLK_PSBCDIV_1_1

Le microcontrôleur fonctionne donc à 2Mhz.

Pour plus d'informations sur le fonctionnement des horloges, vous pouvez voir le tuto sur les XMEGA

Temporisation

Dans cette exemple, nous allons simplement faire clignoter une LED. Pour cela, nous allons avoir besoin de créer une temporisation avec la fonction “delay” de l'ASF.

Il est très facile de mettre en place ce type de temporisation néanmoins cette méthode accapare les ressources du microcontrôleur pendant toute l’exécution de la fonction de temporisation. Il est donc déconseillé de l'utiliser.

Importer les librairies qui sont nécessaires. Cliquer sur ASF → ASF Wizard. Chercher les librairies suivants :

Cliquer sur Add pour importer les librairies dans votre projet.

La fonction delay est directement liée à la fréquence de fonctionnement de votre micro.
Il est donc important de la définir dans votre projet.
Ouvrez ensuite le fichier “conf_clock.h” dans le répertoire config de votre projet.

Sélectionner le type d'horloge que vous utilisez.

Ouvrez le fichier main.c du projet et complétez avec :

#define LED IOPORT_CREATE_PIN(PORTR, 0)	//LED = PR0
 
int main (void)
{
	sysclk_init();	//Initialisation horloge système
 
	board_init();	//Initialisation de la carte
 
	//Initialisation des entrées/sorties
	ioport_init();					//Initialisation d'IOPORT
	ioport_set_pin_dir(LED, IOPORT_DIR_OUTPUT);	//LED_ROUGE est une sortie
 
	while(1)
	{
		ioport_toggle_pin_level(LED);	//Inverse l'état de la LED1
		delay_ms(250);			//Tempo de 250ms
	}
}
Comme vous le savez les oscillateurs internes de l'XMEGA sont calibrés. Les valeurs de qualibration sont stockées dans le microcontrôleur mais ne sont pas cherchées automatiquement au démarrage. La fonction sysclk_init se charge de charger ces valeurs de calibration et paramétrer vos horloges comme vous l'avez indiqué dans votre projet

Timer

Comparaison simple

Créer un nouveau projet ASF.

Importer les librairies qui sont nécessaires. Cliquer sur ASF → ASF Wizard. Chercher les librairies suivantes :

Nous allons utiliser l'horloge par défaut de 2Mhz.
L'objectif de cette exemple sera de faire clignoter une LED toutes les secondes.

Dans le principe de fonctionnement, le timer est cadencé par une horloge. A chaque coup d'horloge, le compteur va s'incrémenter.

Nous utiliserons le Timer 0 qui est un timer de 16bits. Il a donc, au maximum, 65535 pas d'incrémentation.

Nous voulons que la LED s'allume toutes les secondes. Le timer doit donc déclencher un interruption toutes les 500ms.

Avec un horloge à 2Mhz cela nous fait un pas d'incrémentation toutes 0.5µs même si le compteur allait jusqu'à 65535 cela nous ferait 33ms de temps entre chaque interruption sachant que nous voulons environ 500ms.

Nous avons le choix entre les diviseurs suivants :

    TC_CLKSEL_DIV1_gc = (0x01<<0),  /* System Clock */
    TC_CLKSEL_DIV2_gc = (0x02<<0),  /* System Clock / 2 */
    TC_CLKSEL_DIV4_gc = (0x03<<0),  /* System Clock / 4 */
    TC_CLKSEL_DIV8_gc = (0x04<<0),  /* System Clock / 8 */
    TC_CLKSEL_DIV64_gc = (0x05<<0),  /* System Clock / 64 */
    TC_CLKSEL_DIV256_gc = (0x06<<0),  /* System Clock / 256 */
    TC_CLKSEL_DIV1024_gc = (0x07<<0),  /* System Clock / 1024 */

Nous allons donc diviser la fréquence par 64. Ce qui nous fera un pas d'incrémentation toutes les 32µs. Pour avoir un période de 500ms, il faudra que notre compteur compte jusqu'à 500 000 / 32 = 15625

#include <asf.h>
 
//Led
#define LED IOPORT_CREATE_PIN(PORTR, 1)
 
//Déclenchement toutes les 500ms
static void timer0_tick(void)
{
	ioport_toggle_pin_level(LED); //Inverse l'état de la LED
}
 
int main (void)
{
	//Initialisation du controleur d'interruptions
	pmic_init();	
	//Initialisation de l'horloge	
	sysclk_init();		
 
	//Initialisation des entrées/sorties
	ioport_set_pin_dir(LED, IOPORT_DIR_OUTPUT);
 
	//Initialisation du Timer 0
	tc_enable(&TCC0);	
	tc_set_overflow_interrupt_callback(&TCC0, timer0_tick); //Création d'un callback qui sera executé quand un overflow du timer sera déclenché.
	tc_set_wgm(&TCC0, TC_WG_NORMAL);		//Choix du mode du timer0, dans ce cas il comptera jusqu'à sa valeur "TOP" et retombera à 0
	tc_write_period(&TCC0, 15625);			//Définition de la valeur "TOP"	
	tc_set_overflow_interrupt_level(&TCC0, TC_INT_LVL_LO);	//Activation de l'interruption du timer 
	cpu_irq_enable();										//Activation de l'interruption globale					
	tc_write_clock_source(&TCC0, TC_CLKSEL_DIV64_gc);		//Activation de l'horloge du timer 0
 
	board_init();
 
	while(1)
	{
 
	}
}

Explications :

pmic_init();

Initialise le controleur d'interruption. Sans ca, les interruptions du timer ne se déclencheront pas.

sysclk_init();

Initialise l'horloge système. Cf conf_clock.h (Horloge de 2Mhz sans prédivison)

tc_enable(&TCC0);

Active le timer0

tc_set_overflow_interrupt_callback(&TCC0, timer0_tick);

Définit que la fonction timer0_tick sera appelée à chaque interruption du timer 0. La fonction :

static void timer0_tick(void)
{
	ioport_toggle_pin_level(LED); //Inverse l'état de la LED
}

sera executée toutes les 500ms

tc_set_wgm(&TCC0, TC_WG_NORMAL);

Définit le mode de fonctionnement “Normal” du timer. Dans ce cas il comptera jusqu'à sa valeur “TOP”, déclenchera l'interruption overflow, repassera à 0 et ainsi de suite …

cpu_irq_enable();

Activation globale des interruptions

tc_write_clock_source(&TCC0, TC_CLKSEL_DIV64_gc);

On alimente le timer avec l'horloge système / 64

Comparaison double

Nous avons vu dans l'exemple précédente qu'il est possible de déclencher une interruption quand un timer arrive à une certaine valeur. Il est également possible de déclencher 2 interruptions sur 2 valeurs différentes :

#include <asf.h>
 
//Led
#define LED IOPORT_CREATE_PIN(PORTR, 1)
 
static void timer0_tickA(void)
{
	ioport_set_pin_level(LED,1); //Allumage de la LED
}
 
static void timer0_tickB(void)
{
	ioport_set_pin_level(LED,0);	//Extinction de la LED
}
 
int main (void)
{
	//Initialisation du controleur d'interruptions
	pmic_init();	
	//Initialisation de l'horloge	
	sysclk_init();		
 
	//Initialisation des entrées/sorties
	ioport_set_pin_dir(LED, IOPORT_DIR_OUTPUT);
	ioport_set_pin_mode(LED,IOPORT_MODE_INVERT_PIN);
 
	//Initialisation du Timer 0
	tc_enable(&TCC0);	
	tc_set_cca_interrupt_callback(&TCC0, timer0_tickA); //Création d'un callback qui sera executé quand le timer arrivera à CCA
	tc_set_ccb_interrupt_callback(&TCC0, timer0_tickB); //Création d'un callback qui sera executé quand le timer arrivera à CCB
	tc_set_wgm(&TCC0, TC_WG_NORMAL);		//Choix du mode du timer0, dans ce cas il comptera jusqu'à sa valeur max et retombera à 0
	tc_write_period(&TCC0, 32250);			//Définition de la valeur qui déclenchera un reset du timer 0 : 32250 (1 seconde)
	tc_write_cc(&TCC0, TC_CCA, 3125);		//Valeur comparée A : 3125 (100ms)
	tc_write_cc(&TCC0, TC_CCB, 6250);		//Valeur comparée B : 6250 (200ms)
	tc_set_cca_interrupt_level(&TCC0, TC_INT_LVL_LO);		//Activation de l'interruption du timer 
	tc_set_ccb_interrupt_level(&TCC0, TC_INT_LVL_MED);
	cpu_irq_enable();										//Activation de l'interruption globale					
	tc_write_clock_source(&TCC0, TC_CLKSEL_DIV64_gc);		//Activation de l'horloge du timer 0
 
	board_init();
 
	while(1)
	{
 
	}
}

Ce qui nous donne :

PWM

#include <asf.h>
 
#define LED_VERTE IOPORT_CREATE_PIN(PORTD, 5) //LED
 
#define Periode 1075	
 
int main (void)
{
	//Initialisation du controleur d'interruptions
	pmic_init();	
	//Initialisation de l'horloge	
	sysclk_init();		
 
	//Initialisation des entrées/sorties
	ioport_set_pin_dir(LED_VERTE, IOPORT_DIR_OUTPUT);
 
	//Initialisation du Timer 1
	tc_enable(&TCD1);	
	tc_set_wgm(&TCD1, TC_WGMODE_SINGLESLOPE_gc);	//Choix du mode du timer1 et du mode PWM
	tc_write_period(&TCD1, Periode);		//Définition de la période du PWM
	tc_write_cc(&TCD1, TC_CCB, Periode/100);	//Allume la LED à 1% de la luminosité
	tc_enable_cc_channels(&TCD1,TC_CCBEN);		//Active la sortie CCB du Timer 1 - Donc PD5
	cpu_irq_enable();				//Activation de l'interruption globale					
	tc_write_clock_source(&TCD1, TC_CLKSEL_DIV8_gc);//Activation de l'horloge du timer 1 fclksys/8
 
	board_init();
 
	while(1)
	{
		//Augemente progressivement la luminosité
		for(int i=1;i<=100;i++)
		{
			tc_write_cc(&TCD1, TC_CCB, Periode/100*i);
			delay_ms(10);			
		}
 
		//Diminue progressivement la luminosité
		for(int i=100;i>=1;i--)
		{
			tc_write_cc(&TCD1, TC_CCB, Periode/100*i);
			delay_ms(10);			
		}
 
	}
}

Interruptions

USB

CDC

La classe CDC permet d’établir une communication série (RS232) via l'USB du microcontrôleur.
La liaison sera équivalente à une liaison UART avec les contrôles de flux en plus.

Créer un projet ASF et ajouter la librairie USB Device (service) dans le menu déroulant, sélectionner “cdc”

La première chose à faire est de configurer l'horloge. Pour fonctionner, le module USB a besoin d'une horloge de 12 ou 48Mhz. L'oscillateur interne de 32Mhz sera utilisé. En effet sa fréquence peut être réglée entre 30 et 55Mhz grâce à une PLL numérique. Nous allons donc le faire fonctionner à 48Mhz et nous utiliserons une prédiviseur /2 pour fournir une horloge de 24Mhz au CPU.

Editer le fichier conf_clock.h et supprimer toutes les lignes et mettez à la place :

#ifndef CONF_CLOCK_H_INCLUDED
#define CONF_CLOCK_H_INCLUDED
 
//Horloge USB
#define CONFIG_USBCLK_SOURCE     USBCLK_SRC_RCOSC		//Choix de l'horloge interne pour l'USB
#define CONFIG_OSC_RC32_CAL      48000000UL			//Calibration de l'horloge pour qu'elle fonctionne à 48Mhz
#define CONFIG_OSC_AUTOCAL_RC32MHZ_REF_OSC  OSC_ID_USBSOF	//Utilisation d'une calibration automatique lors de la reception de la premiere trame USB	
 
//Horloge CPU qui doit être > à 12Mhz pour les applications USB
#define CONFIG_SYSCLK_SOURCE     SYSCLK_SRC_RC32MHZ		//Choix de l'horloge interne (qui fonctionne à 48Mhz)
#define CONFIG_SYSCLK_PSADIV     SYSCLK_PSADIV_2		//Prescaler A divise la fréquence par 2 = 24Mhz
#define CONFIG_SYSCLK_PSBCDIV    SYSCLK_PSBCDIV_1_1		//Prescaler B pas de division. Donc le CPU fonctionne à 24Mhz
 
 
#endif /* CONF_CLOCK_H_INCLUDED */

Ajouter au début du main, les lignes d'initialisation suivantes :

//Initialisation système
sysclk_init();
irq_initialize_vectors();
cpu_irq_enable();
 
board_init();

Nous allons maintenant nous occuper de la configuration USB. Informations qui seront transmises au controleur USB du PC afin de pouvoir identifier notre carte. Ouvrez le fichier conf_usb.f et indiquer les informations suivantes :

#define  USB_DEVICE_VENDOR_ID             USB_VID_ATMEL			//VID ATMEL
#define  USB_DEVICE_PRODUCT_ID            USB_PID_ATMEL_ASF_CDC		//PID CDC
#define  USB_DEVICE_MAJOR_VERSION         1				//Version du périphérique
#define  USB_DEVICE_MINOR_VERSION         0
#define  USB_DEVICE_POWER                 100				//Consommation de notre carte
#define  USB_DEVICE_ATTR                  USB_CONFIG_ATTR_BUS_POWERED	//La carte est alimentée par le bus USB

Chaque fabricant de périphérique achete auprès d'usb.org des plages identifiants uniques qui permettent à votre ordinateur de l'identifier et charger le driver adéquate. C'est identifiant est composé d'un VID vendor ID USB_DEVICE_VENDOR_ID (Numéro d'identification du fabricant) et d'un PID product ID USB_DEVICE_PRODUCT_ID (Numéro d'identification du produit). Si vous souhaitez avoir votre propre VID/PID, il vous en coutera environ 2000$.8-) En attendant, nous allons garder les VID/PID d'Atmel. ;-)

Si vous souhaitez faire des essais avec des VIP/PID différents, vous pouvez utiliser ceux de LUFA qui ont été donnés par ATMEL. Il est totalement interdit d'utiliser ces PID dans un autre cadre que le test. J'ai également lu que certains fabricants en fournissent à leurs clients sur demande (Microchip, FTDI)

La ligne suivante indique quelle version USB utiliser 1,2 etc …

USB_DEVICE_POWER sera la valeur de consommation de courant max de notre carte. Cette information sera transmise au PC afin qu'il adapte sa gestion de courant.

USB_DEVICE_ATTR indique au contrôleur si le périphérique s'alimente via le port USB ou s'il dispose d'une alimentation indépendante. Dans notre cas, il sera alimenté par le port USB.

Puis ajouter la ligne ci dessous dans votre fichier main.c pour démarrer la pile USB

udc_start(); 

A ce stade, votre PC doit déjà pouvoir détecter votre carte et installer les drivers.

Nous allons voir maintenant comment envoyer et recevoir des données via cette connexion. Aller dans le fichier conf_usb.f et modifier les lignes suivantes :

//! Interface callback definition
#define  UDI_CDC_ENABLE_EXT(port)	callback_cdc_enable()		
extern bool callback_cdc_enable(void);
#define  UDI_CDC_DISABLE_EXT(port)	callback_cdc_disable()			
extern void callback_cdc_disable(void);

Les fonctions callback_cdc_enable et callback_cdc_disable seront appelés dès que la connexion sera établie ou rompue.

Vérifier également les lignes suivantes qui definissent le débit de la liaison :

//! Define it when the transfer CDC Device to Host is a low rate (<512000 bauds)
//! to reduce CDC buffers size
#define  UDI_CDC_LOW_RATE
 
//! Default configuration of communication port
#define  UDI_CDC_DEFAULT_RATE             115200
#define  UDI_CDC_DEFAULT_STOPBITS         CDC_STOP_BITS_1
#define  UDI_CDC_DEFAULT_PARITY           CDC_PAR_NONE
#define  UDI_CDC_DEFAULT_DATABITS         8

Vous pouvez augmenter le baudrate jusqu'à 512 200 bauds. Au delà, il vous suffit de commenter la ligne #define UDI_CDC_LOW_RATE pour aller plus haut. Il faut savoir sur le debit est limité par la vitesse du CPU et par les fonctions utilisés. Atmel fournit un document montrant les limites de fonctionnement. On peut voir figure 6-4 qu'en utilisant les fonctions ReadBuf et WriteBuf qu'il est possible de monter jusqu'à environ 900Kbauds/s.

Dans votre fichier main.c ajouter les deux callback et le petit bout de code suivant qui renvoi “ok 1” dès que vous taper “1” et “error” si vous envoyé n'importe quoi d'autre.

#include <asf.h>
 
static bool flag_autorize_cdc_transfert = false; //Flag d'autorisation de transfert envoyé par l'hote.
char ch;										//Caractère reçu
 
//Lors de l'établissement de la connexion
bool callback_cdc_enable(void)
{
	flag_autorize_cdc_transfert = true;
 
	return true;
}
//Lors de la deconnexion
void callback_cdc_disable(void)
{
	flag_autorize_cdc_transfert = false;
}
 
 
int main (void)
{
	//Initialisation système
	sysclk_init();
	irq_initialize_vectors();
	cpu_irq_enable();
 
	board_init();
 
	//Démarrage de l'USB
	udc_start(); 
 
	while(1)
	{
		if (udi_cdc_is_rx_ready() && flag_autorize_cdc_transfert) //Si la transmission est autorisé et si nous avons reçu quelque chose
		{
			ch = udi_cdc_getc();
			switch(ch)
			{
				case '1': 
					udi_cdc_write_buf("ok 1\r\n", 6); 
				break;
				default : 
					udi_cdc_write_buf("error\r\n", 7); 
				break;
			};
 
		}
	}
}

Brancher, Compiler, programmer démarrer votre terminal préféré (Hyperterminal, putty, etc …). Indiquer le port COM de votre carte et le débit (115200) :

et taper 1 ou autre chose

LUFA Library