<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="fr">
	<id>https://projets-se.plil.fr/mediawiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Abiernac</id>
	<title>projets-se.plil.fr - Contributions [fr]</title>
	<link rel="self" type="application/atom+xml" href="https://projets-se.plil.fr/mediawiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Abiernac"/>
	<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php/Sp%C3%A9cial:Contributions/Abiernac"/>
	<updated>2026-05-16T03:24:12Z</updated>
	<subtitle>Contributions</subtitle>
	<generator>MediaWiki 1.39.1</generator>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2025-1&amp;diff=8770</id>
		<title>SE4Binome2025-1</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2025-1&amp;diff=8770"/>
		<updated>2026-01-24T11:48:13Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Shield Arduino =&lt;br /&gt;
== Hardware ==&lt;br /&gt;
Afin de tester notre futur carte réseau, nous avons fait un shield d'arduino qui prendra le rôle de la carte mère. &lt;br /&gt;
&lt;br /&gt;
=== Schématique ===&lt;br /&gt;
Nous nous sommes évidemment aidés de la datasheet de l'atmega328p ainsi que celle de l'arduino uno afin de sélectionner les bon pins.&lt;br /&gt;
[[Fichier:Atmel-7810-Automotive-Microcontrollers-ATmega328P Datasheet.pdf|centré|vignette|Datasheet ATmega328p]]&lt;br /&gt;
[[Fichier:A000066-datasheet.pdf|centré|vignette|Datasheet Arduino Uno R3]]&lt;br /&gt;
Plus précisément nous nous sommes inspirés très fortement du schéma page 10 de la datasheet de l'arduino :&lt;br /&gt;
[[Fichier:Screenshot 2025-11-07 11-08-46.png|centré|vignette|Schéma pinouts]]&lt;br /&gt;
Nous sommes donc parti de l'exemple fourni par Mr Redon. Mais nous avons utilisé une template disponible dans kicad permettant de créer des shields d'arduino Uno R3.[[Fichier:Tyetyuy.png|vignette|Schématique shield arduino|centré|438x438px]]&lt;br /&gt;
=== Routage ===&lt;br /&gt;
Au niveau du routage, nous avons tenté de faire simple (sans trop abuser des vias). Nous avons positionné le lecteur de carte SD au bord de la carte afin de ne pas avoir de problèmes avec d'autres composants lorsque nous voudrons mettre ou enlever la carte SD.&lt;br /&gt;
[[Fichier:Routage shield arduino.png|vignette|Routage shield arduino|centré|434x434px]]&lt;br /&gt;
&lt;br /&gt;
===Soudage===&lt;br /&gt;
La schématique et le routage terminés, nous avons soudé les différents pins permettant de connecter la carte shield à l'arduino, le reste n'étant pas forcément utile pour le moment (il est important de noter que notre shield est arrivé avec des composants pré-soudés).&lt;br /&gt;
[[Fichier:Shield soudage de base .jpg|centré|vignette]]&lt;br /&gt;
&lt;br /&gt;
===Tests===&lt;br /&gt;
====Leds====&lt;br /&gt;
&lt;br /&gt;
Il faudra ensuite faire des test d'allumage des leds, afin de vérifier le bon fonctionnement du shield&lt;br /&gt;
[[Fichier:VID leds.mp4|centré|vignette]]&lt;br /&gt;
&lt;br /&gt;
Les leds fonctionnent à merveille.&lt;br /&gt;
&lt;br /&gt;
====Carte SD====&lt;br /&gt;
&lt;br /&gt;
Nous vérifions maintenant la carte SD (même si elle nous sera inutile pour notre projet).&lt;br /&gt;
&lt;br /&gt;
Nous utilisons le programme fourni par arduino qui permet de récupérer les informations de la carte SD.&lt;br /&gt;
[[Fichier:Test sd card.png|centré|vignette]]&lt;br /&gt;
La carte SD est bien identifié, le lecteur de carte fonctionne donc normalement.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
&lt;br /&gt;
=== Ordonnanceur basique ===&lt;br /&gt;
La première étape consiste à définir la structure d'un process, il sera composé :&lt;br /&gt;
&lt;br /&gt;
*D'un pointeur de pile&lt;br /&gt;
*De l'adresse de la fonction&lt;br /&gt;
*D'un temps de sommeil&lt;br /&gt;
*D'un état : 0 pour en cours et 1 pour terminé ou vide&lt;br /&gt;
&lt;br /&gt;
Ces deux derniers points nous serviront plus tard.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
typedef struct {&lt;br /&gt;
	uint16_t stackPointer;&lt;br /&gt;
	void (*functionAddress)(void);&lt;br /&gt;
	int sleep_time;&lt;br /&gt;
	int state;&lt;br /&gt;
} process;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On initialise donc notre tableau de processus de la façon suivante : &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
process Tasks_list[NBTASKS] = {&lt;br /&gt;
                                {0, led1_blink, 0,0},&lt;br /&gt;
				...&lt;br /&gt;
			       };&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Concernant les fonction liées aux leds, nous utilisons une simple boucle while contenant un changement d'état. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void led_init() {&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
void led1_blink() {&lt;br /&gt;
	while(1) {&lt;br /&gt;
		PORTC ^= (1&amp;lt;&amp;lt;PLED1);&lt;br /&gt;
		_delay_ms(100);&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
void led2_blink() {&lt;br /&gt;
...	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_stackPointer_tasks() permet de diviser la pile &amp;quot;réel&amp;quot; en plusieurs piles de taille fixe pour chacun des processus.  Ces sous piles commencent à la position FIRST_STACK_POSITION, afin de ne pas réécrire par dessus des données. Toutes les sous piles disposent d'une même taille de pile STACK_LENGTH. La fonction init_piles() initialise correctement la pile avec le tableau de processus si le processus est actif. Elle sauvegarde d'abord le pointeur de pile actuel (pas celui du processus) afin de revenir là où elle en était. Ensuite l'adresse de retour de la fonction (sur 16 bits) dans la pile de la tâche, sauvegarde les registres, puis restaure le pointeur de pile initial.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void init_stackPointer_tasks(int Cprocess) { //initialise le pointer de pile&lt;br /&gt;
	if(Tasks_list[Cprocess].state == 0) {&lt;br /&gt;
		Tasks_list[Cprocess].stackPointer = FIRST_STACK_POSITION - (Cprocess * STACK_LENGTH);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void init_piles(int Cprocess){ //initilalise la pile&lt;br /&gt;
	if(Tasks_list[Cprocess].state == 0) {&lt;br /&gt;
		int save = SP;&lt;br /&gt;
		SP = Tasks_list[Cprocess].stackPointer;&lt;br /&gt;
		uint16_t address = (uint16_t)Tasks_list[Cprocess].functionAddress;&lt;br /&gt;
		asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (address &amp;amp; 0x00ff) );&lt;br /&gt;
		asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((address &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
		SAVE_REGISTERS();&lt;br /&gt;
		Tasks_list[Cprocess].stackPointer = SP;&lt;br /&gt;
		SP = save;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Le scheduler permet de passer à la tâche suivante&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
	Current_task++;&lt;br /&gt;
	if (Current_task &amp;gt;= NBTASKS) {&lt;br /&gt;
		Current_task = 0; &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;L'atmega328p ne dispose pas de fonction en assembleur permettant de push ou de pop tout les registres, on doit donc en créer par nous mêmes. On défini alors les macros suivantes :  &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
#define SAVE_REGISTERS() \&lt;br /&gt;
	asm volatile ( \&lt;br /&gt;
		&amp;quot;push r0 	 \n\t&amp;quot; \&lt;br /&gt;
		...\&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#define RESTORE_REGISTERS() \&lt;br /&gt;
	asm volatile ( \&lt;br /&gt;
		&amp;quot;pop r31 	  \n\t&amp;quot; \&lt;br /&gt;
		...\&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;L'ISR gère les interruptions, en commençant par sauvegarder l'état de la pile ainsi que le stack pointeur propre au processus qui s'interrompt. L'appel au schedruler permet de changer de processus pour cela il faut restaurer le stack pointer propre au nouveau processus actif et de la pile liée à ce processus. La dernière ligne arrête l'ISR.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED) {&lt;br /&gt;
	SAVE_REGISTERS();&lt;br /&gt;
	Tasks_list[Current_task].stackPointer = SP;&lt;br /&gt;
	scheduler();&lt;br /&gt;
	SP = Tasks_list[Current_task].stackPointer;&lt;br /&gt;
	RESTORE_REGISTERS();&lt;br /&gt;
	asm volatile(&amp;quot;reti&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Test ====&lt;br /&gt;
&lt;br /&gt;
Les processus de clignotement de leds ont tous un délai d'attente différent, l'interruption se produit toutes les millisecondes. On obtient ceci :[[Fichier:Ordonnanceur basique.mp4|centré|vignette]]Il est intéressant de remarqué que la vitesse à laquelle les leds changent d'état ne correspond pas au délai qui leur a été donnée. Cela parait logique puisque l'interruption met la fonction _delay_ms en pause, ainsi la vitesse se voit divisé par le nombre de processus actif.&lt;br /&gt;
&lt;br /&gt;
=== Ordonnanceur plus complexe ===&lt;br /&gt;
&lt;br /&gt;
==== Ajout d'un système d'endormissement des processus ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
La fonction wait va permettre d'endormir un processus, elle va donné un temps de sommeil au processus puis lancer une interruption (car on veut changer de processus directement après que le précédent ait été endormi).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time) { // met un process en veille pour une durée donné&lt;br /&gt;
	// valeur max de time 32000 car int sur atmega328p code sur 16 bits donc 32000 max&lt;br /&gt;
	cli();&lt;br /&gt;
	Tasks_list[Current_task].sleep_time = time;&lt;br /&gt;
	TCNT1=0;&lt;br /&gt;
	sei();&lt;br /&gt;
	TIMER1_COMPA_vect();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour vérifier si un processus a besoin d'être lancé, on ajoute une boucle while dans le scheduler afin de vérifier si il y a un temps de sommeil. Le scheduler va aussi servir à diminuer le temps de sommeil de tout les processus (avec un minimum de 0).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
	for (int i=0 ; i&amp;lt;NBTASKS ; i++) {&lt;br /&gt;
		if (Tasks_list[i].sleep_time - SLEEP_DEC &amp;lt; 0) {&lt;br /&gt;
			Tasks_list[i].sleep_time = 0;&lt;br /&gt;
		} else {&lt;br /&gt;
			Tasks_list[i].sleep_time -= SLEEP_DEC;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	do {&lt;br /&gt;
		Current_task++;&lt;br /&gt;
		if (Current_task &amp;gt;= NBTASKS) {&lt;br /&gt;
			Current_task = 0;&lt;br /&gt;
		}&lt;br /&gt;
	} while (Tasks_list[Current_task].sleep_time &amp;gt; 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Tableau dynamique des tâches====&lt;br /&gt;
&lt;br /&gt;
En premier lieu on va initialiser les état de tout les cases du tableau de processus. On choisit 1 la case est vide, 0 sinon.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void init_state() { //initialise state&lt;br /&gt;
	for (int i= 0; i&amp;lt;NBTASKS; i++) {&lt;br /&gt;
		if (Tasks_list[i].functionAddress == NULL) {&lt;br /&gt;
			Tasks_list[i].state = 1;&lt;br /&gt;
		}&lt;br /&gt;
		else {&lt;br /&gt;
			Tasks_list[i].state = 0;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Nous avons programmé deux fonction d'arrêt et une fonction d'ajout de processus :&lt;br /&gt;
&lt;br /&gt;
* finish : stop le processus en cours et le supprime de tableau, puis lance une interruption&lt;br /&gt;
&lt;br /&gt;
* kill : stop un processus donné et le supprime du tableau&lt;br /&gt;
&lt;br /&gt;
* add : ajoute un processus sur la première case vide du tableau, initialise son pointeur de position et sa pile.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Pour finish et kill, on met le temps de sommeil à 0 au cas où on arrête un processus endormi. C'est une mesure de sécurité pour finish, mais une obligation pour kill.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void finish() { //supprime un process lorsque celui-ci est terminé&lt;br /&gt;
	cli();&lt;br /&gt;
		Tasks_list[Current_task].state =1;&lt;br /&gt;
		Tasks_list[Current_task].sleep_time = 0;&lt;br /&gt;
		Tasks_list[Current_task].functionAddress = NULL;&lt;br /&gt;
	TCNT1=0; &lt;br /&gt;
	sei();&lt;br /&gt;
	TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void kill(void (*function)(void)) { //tue le process passé en paramètre&lt;br /&gt;
	cli();&lt;br /&gt;
	for(int i = 0; i&amp;lt;NBTASKS; i++) {&lt;br /&gt;
		if(Tasks_list[i].functionAddress == function) {&lt;br /&gt;
			Tasks_list[i].state =1;&lt;br /&gt;
			Tasks_list[i].sleep_time = 0;&lt;br /&gt;
			Tasks_list[i].functionAddress = NULL;&lt;br /&gt;
		}&lt;br /&gt;
	} &lt;br /&gt;
	sei();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void add(void (*newFunction)(void)) { //ajoute un process&lt;br /&gt;
	cli();&lt;br /&gt;
	int i =0;&lt;br /&gt;
	while(Tasks_list[i].state != 1) {&lt;br /&gt;
		i++;&lt;br /&gt;
	}&lt;br /&gt;
	Tasks_list[i].functionAddress = newFunction;&lt;br /&gt;
	Tasks_list[i].state = 0;&lt;br /&gt;
	init_stackPointer_tasks(i);&lt;br /&gt;
	init_piles(i);&lt;br /&gt;
&lt;br /&gt;
	sei();&lt;br /&gt;
	&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Il suffit maintenant de modifier le scheduler afin de ne pas prendre les processus terminé, puis utiliser add, finish et kill dans les fonctions choisies.&lt;br /&gt;
&lt;br /&gt;
==== Test ====&lt;br /&gt;
Pour tester les fonction add et finish, on réalise le test suivant :&lt;br /&gt;
&lt;br /&gt;
* on créer un process qui ajoute le process led2_blink (avec add) au bout d'un certain temps&lt;br /&gt;
* le process led2_blink s'arrête (avec finish) au bout de 20 changement d'état (c'est à dire 10 clignotement).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On obtient le résultat escompté qui est le suivant :[[Fichier:Demo fonction add et finish.mp4|centré|vignette]]&lt;br /&gt;
====Lecture et écriture sur le port série====&lt;br /&gt;
Afin de lire et écrire sur le port série, on utilise les fonctions USART_Init, USART_Transmit et USART_Receive  vu en cours de microP l'année précédente. Le but sera donc d'écrire le message qui vient d'être reçu, on utilise donc le processus suivant :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Test ====&lt;br /&gt;
&lt;br /&gt;
Pour tester notre processus de communication, on utilise minicom.[[Fichier:Test lecture et écriture port série.mp4|centré|vignette]]On notera que si la période entre les interruptions est trop élevé, certains caractères ne seront pas lus.&lt;br /&gt;
&lt;br /&gt;
====Afficheur 7 segments====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void seven_seg() {&lt;br /&gt;
	while (1) {&lt;br /&gt;
        spi_activer((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
		spi_echange(0x7E);&lt;br /&gt;
		spi_echange(0b1101111);&lt;br /&gt;
		spi_desactiver((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
&lt;br /&gt;
		wait(500);&lt;br /&gt;
&lt;br /&gt;
		spi_activer((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
		spi_echange(0x76);&lt;br /&gt;
		spi_desactiver((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
&lt;br /&gt;
		wait(500);&lt;br /&gt;
    	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Le processus seven_seg est ajouté au tableau des processus. Avant d'échanger en spi il faut activer la communication, et la désactiver après l'échange. La ligne 4 permet de sélectionner le 7 seg sur lequel on souhaite modifier l'affichage. La ligne 5 permet d'afficher le chiffre 9. Enfin la ligne 11 permet de clear le display. Voir tableau ci-dessous.&lt;br /&gt;
[[Fichier:Tab 7 seg sparkfun.png|centré|vignette]]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void) {                                 // Initialisation du bus SPI&lt;br /&gt;
	SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);   // Définition des sorties&lt;br /&gt;
	SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // Définition de l'entrée                          &lt;br /&gt;
	SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
        	                                             // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
	SPI_DDR |= (1&amp;lt;&amp;lt;CS1) | (1&amp;lt;&amp;lt;CS4);;&lt;br /&gt;
	DDRD |= (1&amp;lt;&amp;lt;CS5) | (1&amp;lt;&amp;lt;CS6);&lt;br /&gt;
	DDRC |= (1&amp;lt;&amp;lt;CS2) | (1&amp;lt;&amp;lt;CS3);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void spi_activer(uint16_t port, uint8_t cs) { 	// Activer le périphérique&lt;br /&gt;
	volatile uint8_t *reg = (volatile uint8_t*)port;&lt;br /&gt;
	*reg &amp;amp;= ~(1&amp;lt;&amp;lt;cs);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(uint16_t port, uint8_t cs) {                           // Désactiver le périphérique&lt;br /&gt;
	volatile uint8_t *reg = (volatile uint8_t*)port;&lt;br /&gt;
	*reg |= (1&amp;lt;&amp;lt;cs);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi) {                  // Communication sur le bus SPI&lt;br /&gt;
	SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
	while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
	return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de rendre nos fonctions les plus réutilisables possibles nous avons passer en paramètre le port ainsi que le CS qui correspond au slave select. Le type réel du port est volatile uint8* cependant le compilateur n'accepte que le uint16* ce qui explique le cast un peu étrange.&lt;br /&gt;
&lt;br /&gt;
=====Implémentation=====&lt;br /&gt;
[[Fichier:Video7segvideo.mp4|vignette|centré]]L'implémentation correspond à nos attentes, seul un 7 seg affiche le chiffre 9.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Choix du processus sur le port série====&lt;br /&gt;
Afin de pouvoir démontrer le bon fonctionnement de la partie dynamique, on décide de pouvoir ajouter et tuer des processus à partir des touches du clavier. On utilisera donc les fonction de l'USART défini plus au au travers de la fonction suivante :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void call_process() {&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1) {&lt;br /&gt;
        data = USART_Receive();&lt;br /&gt;
        if(data == '1') {&lt;br /&gt;
            add(led1_blink);&lt;br /&gt;
        }&lt;br /&gt;
        ...&lt;br /&gt;
        else if(data == '6') {&lt;br /&gt;
            kill(led1_blink);&lt;br /&gt;
        }&lt;br /&gt;
        ...&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On remarquera que c'est une sorte d'amélioration de la fonction Serial_Message vu plus haut.&lt;br /&gt;
&lt;br /&gt;
Cette fonction aura la fonction de process de base, toujours présent dans l'ordonnaceur.&lt;br /&gt;
&lt;br /&gt;
==== Démonstation ====&lt;br /&gt;
[[Fichier:Process via USART.mp4|centré|vignette]]&lt;br /&gt;
&lt;br /&gt;
Ici on lance les processus ledN_blink avec les touches 1 à 5 et on les tues avec les touches 6 à 0. Pour le 7 segments, on l'ajoute avec s et le tue avec d. &lt;br /&gt;
&lt;br /&gt;
=Carte Réseau=&lt;br /&gt;
Lors de la répartition des tâches, nous avons opté pour la carte réseau. &lt;br /&gt;
==Description==&lt;br /&gt;
Le sujet nous permettait de choisir parmi plusieurs microcontrôleurs. Nous avons retenu l’ATmega32U4, qui nous semble représenter un juste milieu entre l’ATmega16U2 et l’AT90USB. Cependant ce choix se révélera peu judicieux par la suite du projet. En effet la capacité de la mémoire est un point clé pour une carte réseau qui gère des paquets souvent de tailles conséquentes. &lt;br /&gt;
==Hardware==&lt;br /&gt;
Notre carte intègre des LED permettant d’afficher différents états de communication (que nous définirons ultérieurement).&lt;br /&gt;
&lt;br /&gt;
À la demande de M. Redon, nous avons ajouté un MAX232 ainsi que des connecteurs DB9 et DB25. Nous savons que ces éléments pourront être utiles et servirons à utiliser la carte sur un terminal.&lt;br /&gt;
&lt;br /&gt;
En dehors de ça, la carte reste assez basique car son composant principal reste l'ATmega.&lt;br /&gt;
===Schématique===&lt;br /&gt;
les broches PF n'étant pas utilisé, on les branches à un connecteur 6x1, notre carte pourra donc être utiliser pour d'autre projet si nécéssaire.&lt;br /&gt;
&lt;br /&gt;
On fait le choix d'utiliser 5 leds pour la connections, 1 led de power et 1 pour la connection ISP.[[Fichier:Schématique CReseau.png|vignette|540x540px|centré]]&lt;br /&gt;
===Routage===&lt;br /&gt;
[[Fichier:Routage Creseau.png|vignette|521x521px|centré]]Après avoir soudé les composants principaux, il est temps de passer à la partie programmation de la carte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Programmation== &lt;br /&gt;
&lt;br /&gt;
Notre carte utilisant un connecteur USB, nous allons donc faire passer notre carte pour une carte réseau en utilisant la demo RNDIS de la LUFA.&lt;br /&gt;
&lt;br /&gt;
Il est important de noter que nous avons choisi un Atmega32u4. Ainsi des modification devrons être apporté à la taille des paquets ethernet et sur le choix des protocoles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Protocoles impémentés=== &lt;br /&gt;
&lt;br /&gt;
La demo RNDISEthernet de la LUFA inclut les protocole suivant&lt;br /&gt;
&lt;br /&gt;
* ARP : Résolution d'adresses MAC.&lt;br /&gt;
* IP : Gestion des paquets IPv4.&lt;br /&gt;
* ICMP : Messages de contrôle (ping).&lt;br /&gt;
* TCP : Communication fiable (exemple : serveur TCP).&lt;br /&gt;
* UDP : Communication non fiable (exemple : serveur UDP).&lt;br /&gt;
* DHCP : Attribution dynamique d'adresse IP.&lt;br /&gt;
&lt;br /&gt;
Aussi, on remarquera que la démo utilise un modèle en quatre couche : Le modèle TCP/IP.&lt;br /&gt;
&lt;br /&gt;
le sujet nous propose trois possibilité :&lt;br /&gt;
&lt;br /&gt;
* viser Ethernet&lt;br /&gt;
* viser UDP&lt;br /&gt;
* viser TCP&lt;br /&gt;
&lt;br /&gt;
En regardant ce qui à été fait les années précédentes, on a remarqué que les groupes partaient principalement sur la première option. Nous nous avons décidé de viser UDP.&lt;br /&gt;
&lt;br /&gt;
Ainsi, afin de d'alléger notre code pour le faire rentrer dans notre carte, nous avons choisi de ne pas inclure le protocole TCP et de modifier la taille max de paquets ethernet à 400 octets.&lt;br /&gt;
&lt;br /&gt;
Il nous restera donc de l'espace pour recevoir des paquets Ethernet :&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
avr-size --mcu=atmega32u4 --format=avr RNDISEthernet.elf&lt;br /&gt;
AVR Memory Usage&lt;br /&gt;
----------------&lt;br /&gt;
Device: atmega32u4&lt;br /&gt;
&lt;br /&gt;
Program:    9434 bytes (28.8% Full)&lt;br /&gt;
(.text + .data + .bootloader)&lt;br /&gt;
&lt;br /&gt;
Data:       1037 bytes (40.5% Full)&lt;br /&gt;
(.data + .bss + .noinit)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Une fois la LUFA réduite et flashé, on donne une adresse IP à notre interface avec ip link eth2 up et  ip address add 10.0.0.1/24 dev eth2.  on test un ping sur l'adresse IP de la carte (10.0.0.2).[[Fichier:Ping creseau.mp4|centré|vignette]]Le premier test que nous décidons de faire, afin de vérifié notre compréhension du code de la LUFA, est de faire clignoter une LED si la carte reçoit un paquet ethernet. Pour cela on ajoute l'allumage de la LED dans la fonction EthernetTask du fichier principal (RNDISEthernet.c) :[[Fichier:Ping allume led.mov|vignette|La led s'éteint à chaque ping reçue|centré]]&lt;br /&gt;
&lt;br /&gt;
===Création du protocole=== &lt;br /&gt;
&lt;br /&gt;
En plus de pouvoir communiquer, notre carte dois être capable d'effectuer 3 fonction.&lt;br /&gt;
&lt;br /&gt;
On décide de créer notre propre protocole ProtocolAntique décrit ci-dessous :  &lt;br /&gt;
&lt;br /&gt;
ProtocolAntique (256 octets) &lt;br /&gt;
&lt;br /&gt;
Entete du ProtocolAntique (3 octets)&lt;br /&gt;
&lt;br /&gt;
    operation (1 octet)&lt;br /&gt;
&lt;br /&gt;
    longueur (1 octet)&lt;br /&gt;
&lt;br /&gt;
    numero (1 octet)&lt;br /&gt;
&lt;br /&gt;
Contenu du ProtocolAntique (256 - 3 = 253 octets)&lt;br /&gt;
&lt;br /&gt;
Exemples :&lt;br /&gt;
&lt;br /&gt;
LS :&lt;br /&gt;
&lt;br /&gt;
    Carte reseau :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x01       // requete LS&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]     &lt;br /&gt;
&lt;br /&gt;
        -numero = 0             // la requete n'est pas fragmentée&lt;br /&gt;
&lt;br /&gt;
        -contenu                // chemin ou effectuer le ls&lt;br /&gt;
&lt;br /&gt;
    Serveur :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x11       // reponse au LS&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]&lt;br /&gt;
&lt;br /&gt;
        -numero = [0-255]       // entre 1 et 255 =&amp;gt; numero du paquet =&amp;gt; reponse fragmentée, si 0 dernier paquet&lt;br /&gt;
&lt;br /&gt;
        -contenu                // nom de fichier ou rien si numero = 0&lt;br /&gt;
&lt;br /&gt;
READ :&lt;br /&gt;
&lt;br /&gt;
    Carte reseau :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x02       // requete READ&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]&lt;br /&gt;
&lt;br /&gt;
        -numero = 0             // la requete n'est pas fragmentée&lt;br /&gt;
&lt;br /&gt;
        -contenu                // chemin/nom_fichier&lt;br /&gt;
&lt;br /&gt;
    Serveur :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x12       // reponse au READ&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]&lt;br /&gt;
&lt;br /&gt;
        -numero = [0-255]       // entre 1 et 255 =&amp;gt; numero du paquet =&amp;gt; reponse fragmentée, si 0 dernier paquet&lt;br /&gt;
&lt;br /&gt;
        -contenu                // contenu d'une ligne ou rien si numero = 0&lt;br /&gt;
&lt;br /&gt;
WRITE :&lt;br /&gt;
&lt;br /&gt;
    Carte reseau :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x03       // requete WRITE creation du fichier&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]&lt;br /&gt;
&lt;br /&gt;
        -numero = 0             // entre 1 et 255 =&amp;gt; numero du paquet =&amp;gt; reponse fragmentée, si 0 dernier paquet&lt;br /&gt;
&lt;br /&gt;
        -contenu                // Chemin pour ouvrir le fichier avce le nom du fichier : chemin/fichier&lt;br /&gt;
&lt;br /&gt;
    Carte reseau :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x13       // requete WRITE ecriture dans le fichier&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]&lt;br /&gt;
&lt;br /&gt;
        -numero = [1-252]       // entre 1 et 255 =&amp;gt; numero du paquet =&amp;gt; reponse fragmentée, si 0 dernier paquet&lt;br /&gt;
&lt;br /&gt;
        -contenu                // ligne a ecrire&lt;br /&gt;
&lt;br /&gt;
    Carte reseau :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x23       // requete WRITE fin&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]&lt;br /&gt;
&lt;br /&gt;
        -numero = 0             // 0 dernier paquet&lt;br /&gt;
&lt;br /&gt;
        -contenu                // rien&lt;br /&gt;
&lt;br /&gt;
Comme nous avons choisit de viser UDP, le protocole doit pocédé un numéro de port, on choisit un numéro supérieur à 1023 pour ne pas devoir passer en root, Le port choisi est 3333.&lt;br /&gt;
&lt;br /&gt;
Dans le programme UDP.c on peut maintenant inclure notre protocole de la façon suivante :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
        switch (SwapEndian_16(UDPHeaderIN-&amp;gt;DestinationPort))&lt;br /&gt;
        {&lt;br /&gt;
    /*&lt;br /&gt;
                case UDP_PORT_DHCP_REQUEST:&lt;br /&gt;
                        RetSize = DHCP_ProcessDHCPPacket(IPHeaderInStart,&lt;br /&gt;
                                                         &amp;amp;((uint8_t*)UDPHeaderInStart)[sizeof(UDP_Header_t)],&lt;br /&gt;
                                                     &amp;amp;((uint8_t*)UDPHeaderOutStart)[sizeof(UDP_Header_t)]);&lt;br /&gt;
                        break;&lt;br /&gt;
    */&lt;br /&gt;
                case UDP_PORT_PROTOCOL_ANTIQUE:       &lt;br /&gt;
                        RetSize = ProtocolAntique_ProcessProtocolAntiquePacket(IPHeaderInStart,&lt;br /&gt;
                                                         &amp;amp;((uint8_t*)UDPHeaderInStart)[sizeof(UDP_Header_t)],&lt;br /&gt;
                                                     &amp;amp;((uint8_t*)UDPHeaderOutStart)[sizeof(UDP_Header_t)]);&lt;br /&gt;
                        break;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Partie serveur ===&lt;br /&gt;
Lorsque la carte mère a besoin de faire une action (ls, read, write) sur l'ordinateur qui est connecté en USB via la carte réseau elle transmet son besoin à la carte réseau. Cette dernière créer un requête UDP qui encapsule notre protocole (ProtocolAntique) et la transmet donc au PC. Sur ce dernier un serveur doit donc fonctionner afin de recevoir les rêquetes de la carte réseau, les traiter et y répondre. Cette partie est donc consacrée au code ainsi qu'aux tests du serveur.&lt;br /&gt;
&lt;br /&gt;
==== Code du serveur ====&lt;br /&gt;
Pour pouvoir fonctionner correctement le serveur doit initialiser une socket UDP et ensuite doit lancer un fonctionne qui boucle indéfiniment afin de recevoir chaque message UDP. Cette partie n'a pas été codé par nous et est trouvable sur rex.plil.fr (Département IMA -&amp;gt; support de cours de la programmation réseau -&amp;gt; exemple de serveur 2/2). Il en est de même du code la fonction pour envoyer un message UDP qui est trouvable au même endroit section exemple de client 2/2.&lt;br /&gt;
&lt;br /&gt;
La carte réseau est toujours à l'initiative des requêtes, par conséquent le serveur commence par recevoir un requête et la traiter. Pour ce faire à chaque requête reçue par la fonction boucleServeurUDP la fonction traitementMessageUDP est appelée.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
int traitementMessageUDP (unsigned char* message, int nboctets);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Cette fonction s'occupe d'extraire la partie opération de l'entête de protocolAntique et d'appeler la fonction de traitement correspondante à l'opération&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Opération&lt;br /&gt;
!Requête&lt;br /&gt;
!Fonction appelée&lt;br /&gt;
|-&lt;br /&gt;
|0x01&lt;br /&gt;
|LS&lt;br /&gt;
|void traitement_ls (unsigned char*);&lt;br /&gt;
|-&lt;br /&gt;
|0x02&lt;br /&gt;
|READ&lt;br /&gt;
|void traitement_read (unsigned char*);&lt;br /&gt;
|-&lt;br /&gt;
|0x03&lt;br /&gt;
|WRITE (début)&lt;br /&gt;
|void traitement_write (unsigned char*);&lt;br /&gt;
|-&lt;br /&gt;
|0x13&lt;br /&gt;
|WRITE (données et fin)&lt;br /&gt;
|void traitement_write (unsigned char*);&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Traitement LS =====&lt;br /&gt;
La fonction traitement_ls commence par récupérer le chemin (relatif ou absolu) où effectuer le LS. Si la section longueur de l'entête de la requête est à 0 alors le chemin par défaut est celui depuis où le serveur à été lancé. Le code pour récupérer le chemin  est le suivant :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
unsigned char chemin[longueur+1];&lt;br /&gt;
for (int i=0 ; i&amp;lt;longueur ; i++) {&lt;br /&gt;
        chemin[i] = message[i+3]; // Recuperation du chemin&lt;br /&gt;
}&lt;br /&gt;
chemin[longueur] = '\0';&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Par la suite le dossier est correspondant au chemin est ouvert via la fonction opendir puis chaque entrée du dossier est récupérée et engendre un message de réponse du serveur (un message par entrée).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
while ((entree = readdir(dossier)) != NULL) {&lt;br /&gt;
   // Message UDP pour chaque entree&lt;br /&gt;
   strcpy(contenu, entree-&amp;gt;d_name);&lt;br /&gt;
   printf(&amp;quot;    %s  &amp;quot;, contenu);&lt;br /&gt;
   reponse[OPERATION] = REPONSE_LS;&lt;br /&gt;
   reponse[LONGUEUR] = strlen(contenu);&lt;br /&gt;
   reponse[NUMERO] = num++;&lt;br /&gt;
   for (int i=0 ; i&amp;lt;reponse[LONGUEUR] ; i++) {&lt;br /&gt;
      reponse[i+3] = contenu[i];&lt;br /&gt;
   }&lt;br /&gt;
   messageUDP(IP_CARTE, PORT_CARTE, (unsigned char *)reponse, (int)reponse[LONGUEUR] + LONGUEUR_ENTETE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;OPERATION est la premiére section et vaut donc 0, LONGUEUR 2 et NUMERO 3. OPERATION est une réponse à un LS donc 0x11, LONGUEUR dépend de l'entrée du dossier et NUMERO augmente de 1 à chaque entrée. Enfin on remplie la requête du nom de l'entrée et on envoie le message.&lt;br /&gt;
&lt;br /&gt;
Enfin une fois tous les entrées envoyées on envoie un dernier message UDP de type reponse_LS de longueur 0 et de numéro 0 afin d'indiquer que la transmission est terminée et ce correctement.&lt;br /&gt;
&lt;br /&gt;
===== Traitement READ =====&lt;br /&gt;
Cette requête est très proche de celle du LS. On commence par récupérer le chemin avec le nom du fichier de la même façon que pour le LS. Cependant ici si le message ne contient pas de chemin aucun traitement ne sera effectué. Pour ouvrir le fichier on utilise la fonction fopen. Chaque ligne, récupérée via fgets, engendre une réponse UDP formulée de la même façon que pour les entrées de dossier. Evidemment l'opération est de type réponse read soit 0x12. Enfin un message similaire de fin de transmission est envoyé seulement si il n'y a pas eu d'erreur et que la dernière ligne à été lue.&lt;br /&gt;
&lt;br /&gt;
===== Traitement WRITE =====&lt;br /&gt;
Cette requête est un peu plus complexe à gérer niveau serveur par conséquent que je vais commencer par décrire le principe de la fonction.&lt;br /&gt;
&lt;br /&gt;
* La carte réseau envoie un message de type début de write (OPERATION 0x03) avec le chemin et nom du fichier que le serveur va récupérer et mémoriser.&lt;br /&gt;
&lt;br /&gt;
* La carte réseau envoie un massage pour chaque ligne à écrite (OPERATION 0x13). Le serveur va vérifier si la section NUMERO des entêtes se suivent afin de s'assurer que aucun message n'est été perdu.&lt;br /&gt;
&lt;br /&gt;
* La carte réseau envoie un message de type fin de write (OPERATION 0x013) mais de numéro 0. Le serveur indique que tout s'est bien passé en envoyant une réponse au write (OPERATION 0x23) donc le contenu est 0x00.&lt;br /&gt;
* Si un message a été perdu un message d'erreur est envoyé de la par du serveur (OPERATION 0x23) de contenu 0x01.&lt;br /&gt;
&lt;br /&gt;
La récupération du contenu de la requête est du même type que celle du LS. Les messages de retour sont construits de la même façon que pour le message de retour du LS. Enfin on utilise fopen une nouvelle fois pour ouvrir le fichier, fwrite pour y écrire et fclose pour le fermer.&lt;br /&gt;
&lt;br /&gt;
==== Préparation du test ====&lt;br /&gt;
Avant de pouvoir tester notre serveur avec la carte réseau (ce qui n'aura jamais été fait car la carte réseau n'envoie rien) nous avons souhaité validé le fonctionnement du serveur en simulant des requêtes de la carte réseau. On voit ce que le serveur fait via des printf et en créant un autre serveur (plus rudimentaire) on peut vérifier que le serveur répond correctement. Sur notre git le dossier testUDP est consacré à cette phase de tests.&lt;br /&gt;
&lt;br /&gt;
* Les requêtes simulées de la carte réseau sont envoyées sur l'IP loopback de la machine et sur le port du serveur (ici 4242)&lt;br /&gt;
* Le serveur écoute le port serveur (4242) et répond en loopback sur le port du serveur qui simule la carte (ici 3333)&lt;br /&gt;
* Le serveur qui simule la carte écoute le port 3333&lt;br /&gt;
&lt;br /&gt;
On lance ces différents serveurs et les requêtes via les commandes du fichiers fonctionnement.txt de notre git.&lt;br /&gt;
&lt;br /&gt;
==== Tests ====&lt;br /&gt;
Le test est réalisé via 3 commandes :&lt;br /&gt;
&lt;br /&gt;
* LS sans chemin&lt;br /&gt;
* WRITE de 3 lignes dans un fichier test.txt créé par la commande&lt;br /&gt;
* READ du fichier test.txt&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Test1.png|centré|vignette|Requêtes envoyées]]&lt;br /&gt;
[[Fichier:Test2.png|centré|vignette|Traitement du serveur]]&lt;br /&gt;
[[Fichier:Test3.png|centré|vignette|Réponse reçu du serveur]]On peut constater que les tests fonctionnent. En effet le serveur a envoyé 9 res ls (8 entrées + fin de transmissions), 1 res write (fin d'écriture correcte) et 6 res read (5 lignes + 1 fin de transmissions).&lt;br /&gt;
&lt;br /&gt;
Enfin on décide de tester la réception des paquets UDP, on fait à nouveau clignoter une led quand un paquet UDP et reçu. Ici on envoi la réponse d'un LS, d'où la reception de plusieurs paquets: &lt;br /&gt;
[[Fichier:Test udp.mp4|centré|vignette]]&lt;br /&gt;
== Conclusion ==&lt;br /&gt;
La partie shield et ordonnanceur est finie et testée. La carte réseau n'a pas pu être finie par manque de temps. En faisant allumer une LED lorsqu'elle reçoit une trame Ethernet, UDP, STMP nous avons constaté qu'elle reçoit correctement ces protocoles. Cependant lorsque que nous avons voulu modifier la LUFA pour qu'une LED en plus s'allume lorsque UDP contient protocole antique cela ne fonctionnait pas. La carte ne trouvait jamais le protocole Antique. La communication avec la carte mère (shield) n'a pas été faite par manque de temps (cependant la communication SPI est vérifiée à l'étape de l'ordonnanceur). Le serveur côté PC qui doit communiquer avec la carte réseau est fini et testé.&lt;br /&gt;
&lt;br /&gt;
Notre problème peut venir du fait que l'atmega32u4 n'a pas assez de mémoire. Il ne faut donc pas choisir ce micro contrôleur pour ce projet mais un avec plus de mémoire.&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2025-1&amp;diff=8769</id>
		<title>SE4Binome2025-1</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2025-1&amp;diff=8769"/>
		<updated>2026-01-24T11:32:56Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Shield Arduino =&lt;br /&gt;
== Hardware ==&lt;br /&gt;
Afin de tester notre futur carte réseau, nous avons fait un shield d'arduino qui prendra le rôle de la carte mère. &lt;br /&gt;
&lt;br /&gt;
=== Schématique ===&lt;br /&gt;
Nous nous sommes évidemment aidés de la datasheet de l'atmega328p ainsi que celle de l'arduino uno afin de sélectionner les bon pins.&lt;br /&gt;
[[Fichier:Atmel-7810-Automotive-Microcontrollers-ATmega328P Datasheet.pdf|centré|vignette|Datasheet ATmega328p]]&lt;br /&gt;
[[Fichier:A000066-datasheet.pdf|centré|vignette|Datasheet Arduino Uno R3]]&lt;br /&gt;
Plus précisément nous nous sommes inspirés très fortement du schéma page 10 de la datasheet de l'arduino :&lt;br /&gt;
[[Fichier:Screenshot 2025-11-07 11-08-46.png|centré|vignette|Schéma pinouts]]&lt;br /&gt;
Nous sommes donc parti de l'exemple fourni par Mr Redon. Mais nous avons utilisé une template disponible dans kicad permettant de créer des shields d'arduino Uno R3.[[Fichier:Tyetyuy.png|vignette|Schématique shield arduino|centré|438x438px]]&lt;br /&gt;
=== Routage ===&lt;br /&gt;
Au niveau du routage, nous avons tenté de faire simple (sans trop abuser des vias). Nous avons positionné le lecteur de carte SD au bord de la carte afin de ne pas avoir de problèmes avec d'autres composants lorsque nous voudrons mettre ou enlever la carte SD.&lt;br /&gt;
[[Fichier:Routage shield arduino.png|vignette|Routage shield arduino|centré|434x434px]]&lt;br /&gt;
&lt;br /&gt;
===Soudage===&lt;br /&gt;
La schématique et le routage terminés, nous avons soudé les différents pins permettant de connecter la carte shield à l'arduino, le reste n'étant pas forcément utile pour le moment (il est important de noter que notre shield est arrivé avec des composants pré-soudés).&lt;br /&gt;
[[Fichier:Shield soudage de base .jpg|centré|vignette]]&lt;br /&gt;
&lt;br /&gt;
===Tests===&lt;br /&gt;
====Leds====&lt;br /&gt;
&lt;br /&gt;
Il faudra ensuite faire des test d'allumage des leds, afin de vérifier le bon fonctionnement du shield&lt;br /&gt;
[[Fichier:VID leds.mp4|centré|vignette]]&lt;br /&gt;
&lt;br /&gt;
Les leds fonctionnent à merveille.&lt;br /&gt;
&lt;br /&gt;
====Carte SD====&lt;br /&gt;
&lt;br /&gt;
Nous vérifions maintenant la carte SD (même si elle nous sera inutile pour notre projet).&lt;br /&gt;
&lt;br /&gt;
Nous utilisons le programme fourni par arduino qui permet de récupérer les informations de la carte SD.&lt;br /&gt;
[[Fichier:Test sd card.png|centré|vignette]]&lt;br /&gt;
La carte SD est bien identifié, le lecteur de carte fonctionne donc normalement.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
&lt;br /&gt;
=== Ordonnanceur basique ===&lt;br /&gt;
La première étape consiste à définir la structure d'un process, il sera composé :&lt;br /&gt;
&lt;br /&gt;
*D'un pointeur de pile&lt;br /&gt;
*De l'adresse de la fonction&lt;br /&gt;
*D'un temps de sommeil&lt;br /&gt;
*D'un état : 0 pour en cours et 1 pour terminé ou vide&lt;br /&gt;
&lt;br /&gt;
Ces deux derniers points nous serviront plus tard.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
typedef struct {&lt;br /&gt;
	uint16_t stackPointer;&lt;br /&gt;
	void (*functionAddress)(void);&lt;br /&gt;
	int sleep_time;&lt;br /&gt;
	int state;&lt;br /&gt;
} process;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On initialise donc notre tableau de processus de la façon suivante : &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
process Tasks_list[NBTASKS] = {&lt;br /&gt;
                                {0, led1_blink, 0,0},&lt;br /&gt;
				...&lt;br /&gt;
			       };&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Concernant les fonction liées aux leds, nous utilisons une simple boucle while contenant un changement d'état. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void led_init() {&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
void led1_blink() {&lt;br /&gt;
	while(1) {&lt;br /&gt;
		PORTC ^= (1&amp;lt;&amp;lt;PLED1);&lt;br /&gt;
		_delay_ms(100);&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
void led2_blink() {&lt;br /&gt;
...	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_stackPointer_tasks() permet de diviser la pile &amp;quot;réel&amp;quot; en plusieurs piles de taille fixe pour chacun des processus.  Ces sous piles commencent à la position FIRST_STACK_POSITION, afin de ne pas réécrire par dessus des données. Toutes les sous piles disposent d'une même taille de pile STACK_LENGTH. La fonction init_piles() initialise correctement la pile avec le tableau de processus si le processus est actif. Elle sauvegarde d'abord le pointeur de pile actuel, place l'adresse de la fonction (sur 16 bits) dans la pile de la tâche, sauvegarde les registres, puis restaure le pointeur de pile initial.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void init_stackPointer_tasks(int Cprocess) { //initialise le pointer de pile&lt;br /&gt;
	if(Tasks_list[Cprocess].state == 0) {&lt;br /&gt;
		Tasks_list[Cprocess].stackPointer = FIRST_STACK_POSITION - (Cprocess * STACK_LENGTH);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void init_piles(int Cprocess){ //initilalise la pile&lt;br /&gt;
	if(Tasks_list[Cprocess].state == 0) {&lt;br /&gt;
		int save = SP;&lt;br /&gt;
		SP = Tasks_list[Cprocess].stackPointer;&lt;br /&gt;
		uint16_t address = (uint16_t)Tasks_list[Cprocess].functionAddress;&lt;br /&gt;
		asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (address &amp;amp; 0x00ff) );&lt;br /&gt;
		asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((address &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
		SAVE_REGISTERS();&lt;br /&gt;
		Tasks_list[Cprocess].stackPointer = SP;&lt;br /&gt;
		SP = save;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Le scheduler permet de passer à la tâche suivante&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
	Current_task++;&lt;br /&gt;
	if (Current_task &amp;gt;= NBTASKS) {&lt;br /&gt;
		Current_task = 0; &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;L'atmega328p ne dispose pas de fonction en assembleur permettant de push ou de pop tout les registres, on doit donc en créer par nous mêmes. On défini alors les macros suivantes :  &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
#define SAVE_REGISTERS() \&lt;br /&gt;
	asm volatile ( \&lt;br /&gt;
		&amp;quot;push r0 	 \n\t&amp;quot; \&lt;br /&gt;
		...\&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#define RESTORE_REGISTERS() \&lt;br /&gt;
	asm volatile ( \&lt;br /&gt;
		&amp;quot;pop r31 	  \n\t&amp;quot; \&lt;br /&gt;
		...\&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;L'ISR gère les interruptions, en commençant par sauvegarder l'état de la pile ainsi que le stack pointeur propre au processus qui s'interrompt. L'appel au schedruler permet de changer de processus pour cela il faut restaurer le stack pointer propre au nouveau processus actif et de la pile liée à ce processus. La dernière ligne arrête l'ISR.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED) {&lt;br /&gt;
	SAVE_REGISTERS();&lt;br /&gt;
	Tasks_list[Current_task].stackPointer = SP;&lt;br /&gt;
	scheduler();&lt;br /&gt;
	SP = Tasks_list[Current_task].stackPointer;&lt;br /&gt;
	RESTORE_REGISTERS();&lt;br /&gt;
	asm volatile(&amp;quot;reti&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Test ====&lt;br /&gt;
&lt;br /&gt;
Les processus de clignotement de leds ont tous un délai d'attente différent, l'interruption se produit toutes les millisecondes. On obtient ceci :[[Fichier:Ordonnanceur basique.mp4|centré|vignette]]Il est intéressant de remarqué que la vitesse à laquelle les leds changent d'état ne correspond pas au délai qui leur a été donnée. Cela parait logique puisque l'interruption met la fonction _delay_ms en pause, ainsi la vitesse se voit divisé par le nombre de processus actif.&lt;br /&gt;
&lt;br /&gt;
=== Ordonnanceur plus complexe ===&lt;br /&gt;
&lt;br /&gt;
==== Ajout d'un système d'endormissement des processus ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
La fonction wait va permettre d'endormir un processus, elle va donné un temps de sommeil au processus puis lancer une interruption (car on veut changer de processus directement après que le précédent ait été endormi).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time) { // met un process en veille pour une durée donné&lt;br /&gt;
	// valeur max de time 32000 car int sur atmega328p code sur 16 bits donc 32000 max&lt;br /&gt;
	cli();&lt;br /&gt;
	Tasks_list[Current_task].sleep_time = time;&lt;br /&gt;
	TCNT1=0;&lt;br /&gt;
	sei();&lt;br /&gt;
	TIMER1_COMPA_vect();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour vérifier si un processus a besoin d'être lancé, on ajoute une boucle while dans le scheduler afin de vérifier si il y a un temps de sommeil. Le scheduler va aussi servir à diminuer le temps de sommeil de tout les processus (avec un minimum de 0).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
	for (int i=0 ; i&amp;lt;NBTASKS ; i++) {&lt;br /&gt;
		if (Tasks_list[i].sleep_time - SLEEP_DEC &amp;lt; 0) {&lt;br /&gt;
			Tasks_list[i].sleep_time = 0;&lt;br /&gt;
		} else {&lt;br /&gt;
			Tasks_list[i].sleep_time -= SLEEP_DEC;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	do {&lt;br /&gt;
		Current_task++;&lt;br /&gt;
		if (Current_task &amp;gt;= NBTASKS) {&lt;br /&gt;
			Current_task = 0;&lt;br /&gt;
		}&lt;br /&gt;
	} while (Tasks_list[Current_task].sleep_time &amp;gt; 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Tableau dynamique des tâches====&lt;br /&gt;
&lt;br /&gt;
En premier lieu on va initialiser les état de tout les cases du tableau de processus. On choisit 1 la case est vide, 0 sinon.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void init_state() { //initialise state&lt;br /&gt;
	for (int i= 0; i&amp;lt;NBTASKS; i++) {&lt;br /&gt;
		if (Tasks_list[i].functionAddress == NULL) {&lt;br /&gt;
			Tasks_list[i].state = 1;&lt;br /&gt;
		}&lt;br /&gt;
		else {&lt;br /&gt;
			Tasks_list[i].state = 0;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Nous avons programmé deux fonction d'arrêt et une fonction d'ajout de processus :&lt;br /&gt;
&lt;br /&gt;
* finish : stop le processus en cours et le supprime de tableau, puis lance une interruption&lt;br /&gt;
&lt;br /&gt;
* kill : stop un processus donné et le supprime du tableau&lt;br /&gt;
&lt;br /&gt;
* add : ajoute un processus sur la première case vide du tableau, initialise son pointeur de position et sa pile.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Pour finish et kill, on met le temps de sommeil à 0 au cas où on arrête un processus endormi. C'est une mesure de sécurité pour finish, mais une obligation pour kill.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void finish() { //supprime un process lorsque celui-ci est terminé&lt;br /&gt;
	cli();&lt;br /&gt;
		Tasks_list[Current_task].state =1;&lt;br /&gt;
		Tasks_list[Current_task].sleep_time = 0;&lt;br /&gt;
		Tasks_list[Current_task].functionAddress = NULL;&lt;br /&gt;
	TCNT1=0; &lt;br /&gt;
	sei();&lt;br /&gt;
	TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void kill(void (*function)(void)) { //tue le process passé en paramètre&lt;br /&gt;
	cli();&lt;br /&gt;
	for(int i = 0; i&amp;lt;NBTASKS; i++) {&lt;br /&gt;
		if(Tasks_list[i].functionAddress == function) {&lt;br /&gt;
			Tasks_list[i].state =1;&lt;br /&gt;
			Tasks_list[i].sleep_time = 0;&lt;br /&gt;
			Tasks_list[i].functionAddress = NULL;&lt;br /&gt;
		}&lt;br /&gt;
	} &lt;br /&gt;
	sei();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void add(void (*newFunction)(void)) { //ajoute un process&lt;br /&gt;
	cli();&lt;br /&gt;
	int i =0;&lt;br /&gt;
	while(Tasks_list[i].state != 1) {&lt;br /&gt;
		i++;&lt;br /&gt;
	}&lt;br /&gt;
	Tasks_list[i].functionAddress = newFunction;&lt;br /&gt;
	Tasks_list[i].state = 0;&lt;br /&gt;
	init_stackPointer_tasks(i);&lt;br /&gt;
	init_piles(i);&lt;br /&gt;
&lt;br /&gt;
	sei();&lt;br /&gt;
	&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Il suffit maintenant de modifier le scheduler afin de ne pas prendre les processus terminé, puis utiliser add, finish et kill dans les fonctions choisies.&lt;br /&gt;
&lt;br /&gt;
==== Test ====&lt;br /&gt;
Pour tester les fonction add et finish, on réalise le test suivant :&lt;br /&gt;
&lt;br /&gt;
* on créer un process qui ajoute le process led2_blink (avec add) au bout d'un certain temps&lt;br /&gt;
* le process led2_blink s'arrête (avec finish) au bout de 20 changement d'état (c'est à dire 10 clignotement).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On obtient le résultat escompté qui est le suivant :[[Fichier:Demo fonction add et finish.mp4|centré|vignette]]&lt;br /&gt;
====Lecture et écriture sur le port série====&lt;br /&gt;
Afin de lire et écrire sur le port série, on utilise les fonctions USART_Init, USART_Transmit et USART_Receive  vu en cours de microP l'année précédente. Le but sera donc d'écrire le message qui vient d'être reçu, on utilise donc le processus suivant :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Test ====&lt;br /&gt;
&lt;br /&gt;
Pour tester notre processus de communication, on utilise minicom.[[Fichier:Test lecture et écriture port série.mp4|centré|vignette]]On notera que si la période entre les interruptions est trop élevé, certains caractères ne seront pas lus.&lt;br /&gt;
&lt;br /&gt;
====Afficheur 7 segments====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void seven_seg() {&lt;br /&gt;
	while (1) {&lt;br /&gt;
        spi_activer((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
		spi_echange(0x7E);&lt;br /&gt;
		spi_echange(0b1101111);&lt;br /&gt;
		spi_desactiver((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
&lt;br /&gt;
		wait(500);&lt;br /&gt;
&lt;br /&gt;
		spi_activer((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
		spi_echange(0x76);&lt;br /&gt;
		spi_desactiver((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
&lt;br /&gt;
		wait(500);&lt;br /&gt;
    	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Le processus seven_seg est ajouté au tableau des processus. Avant d'échanger en spi il faut activer la communication, et la désactiver après l'échange. La ligne 4 permet de sélectionner le 7 seg sur lequel on souhaite modifier l'affichage. La ligne 5 permet d'afficher le chiffre 9. Enfin la ligne 11 permet de clear le display. Voir tableau ci-dessous.&lt;br /&gt;
[[Fichier:Tab 7 seg sparkfun.png|centré|vignette]]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void) {                                 // Initialisation du bus SPI&lt;br /&gt;
	SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);   // Définition des sorties&lt;br /&gt;
	SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // Définition de l'entrée                          &lt;br /&gt;
	SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
        	                                             // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
	SPI_DDR |= (1&amp;lt;&amp;lt;CS1) | (1&amp;lt;&amp;lt;CS4);;&lt;br /&gt;
	DDRD |= (1&amp;lt;&amp;lt;CS5) | (1&amp;lt;&amp;lt;CS6);&lt;br /&gt;
	DDRC |= (1&amp;lt;&amp;lt;CS2) | (1&amp;lt;&amp;lt;CS3);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void spi_activer(uint16_t port, uint8_t cs) { 	// Activer le périphérique&lt;br /&gt;
	volatile uint8_t *reg = (volatile uint8_t*)port;&lt;br /&gt;
	*reg &amp;amp;= ~(1&amp;lt;&amp;lt;cs);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(uint16_t port, uint8_t cs) {                           // Désactiver le périphérique&lt;br /&gt;
	volatile uint8_t *reg = (volatile uint8_t*)port;&lt;br /&gt;
	*reg |= (1&amp;lt;&amp;lt;cs);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi) {                  // Communication sur le bus SPI&lt;br /&gt;
	SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
	while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
	return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de rendre nos fonctions les plus réutilisables possibles nous avons passer en paramètre le port ainsi que le CS qui correspond au slave select. Le type réel du port est volatile uint8* cependant le compilateur n'accepte que le uint16* ce qui explique le cast un peu étrange.&lt;br /&gt;
&lt;br /&gt;
=====Implémentation=====&lt;br /&gt;
[[Fichier:Video7segvideo.mp4|vignette|centré]]L'implémentation correspond à nos attentes, seul un 7 seg affiche le chiffre 9.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Choix du processus sur le port série====&lt;br /&gt;
Afin de pouvoir démontrer le bon fonctionnement de la partie dynamique, on décide de pouvoir ajouter et tuer des processus à partir des touches du clavier. On utilisera donc les fonction de l'USART défini plus au au travers de la fonction suivante :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void call_process() {&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1) {&lt;br /&gt;
        data = USART_Receive();&lt;br /&gt;
        if(data == '1') {&lt;br /&gt;
            add(led1_blink);&lt;br /&gt;
        }&lt;br /&gt;
        ...&lt;br /&gt;
        else if(data == '6') {&lt;br /&gt;
            kill(led1_blink);&lt;br /&gt;
        }&lt;br /&gt;
        ...&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On remarquera que c'est une sorte d'amélioration de la fonction Serial_Message vu plus haut.&lt;br /&gt;
&lt;br /&gt;
Cette fonction aura la fonction de process de base, toujours présent dans l'ordonnaceur.&lt;br /&gt;
&lt;br /&gt;
==== Démonstation ====&lt;br /&gt;
[[Fichier:Process via USART.mp4|centré|vignette]]&lt;br /&gt;
&lt;br /&gt;
Ici on lance les processus ledN_blink avec les touches 1 à 5 et on les tues avec les touches 6 à 0. Pour le 7 segments, on l'ajoute avec s et le tue avec d. &lt;br /&gt;
&lt;br /&gt;
=Carte Réseau=&lt;br /&gt;
Lors de la répartition des tâches, nous avons opté pour la carte réseau. &lt;br /&gt;
==Description==&lt;br /&gt;
Le sujet nous permettait de choisir parmi plusieurs microcontrôleurs. Nous avons retenu l’ATmega32U4, qui nous semble représenter un juste milieu entre l’ATmega16U2 et l’AT90USB.&lt;br /&gt;
==Hardware==&lt;br /&gt;
Notre carte intègre des LED permettant d’afficher différents états de communication (que nous définirons ultérieurement).&lt;br /&gt;
&lt;br /&gt;
À la demande de M. Redon, nous avons ajouté un MAX232 ainsi que des connecteurs DB9 et DB25. Nous savons que ces éléments pourront être utiles et servirons à utiliser la carte sur un terminal.&lt;br /&gt;
&lt;br /&gt;
En dehors de ça, la carte reste assez basique car son composant principal reste l'ATmega.&lt;br /&gt;
===Schématique===&lt;br /&gt;
les broches PF n'étant pas utilisé, on les branches à un connecteur 6x1, notre carte pourra donc être utiliser pour d'autre projet si nécéssaire.&lt;br /&gt;
&lt;br /&gt;
On fait le choix d'utiliser 5 leds pour la connections, 1 led de power et 1 pour la connection ISP.[[Fichier:Schématique CReseau.png|vignette|540x540px|centré]]&lt;br /&gt;
===Routage===&lt;br /&gt;
[[Fichier:Routage Creseau.png|vignette|521x521px|centré]]Après avoir soudé les composants principaux, il est temps de passer à la partie programmation de la carte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Programmation== &lt;br /&gt;
&lt;br /&gt;
Notre carte utilisant un connecteur USB, nous allons donc faire passer notre carte pour une carte réseau en utilisant la demo RNDIS de la LUFA.&lt;br /&gt;
&lt;br /&gt;
Il est important de noter que nous avons choisi un Atmega32u4. Ainsi des modification devrons être apporté à la taille des paquets ethernet et sur le choix des protocoles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Protocoles impémentés=== &lt;br /&gt;
&lt;br /&gt;
La demo RNDISEthernet de la LUFA inclut les protocole suivant&lt;br /&gt;
&lt;br /&gt;
* ARP : Résolution d'adresses MAC.&lt;br /&gt;
* IP : Gestion des paquets IPv4.&lt;br /&gt;
* ICMP : Messages de contrôle (ping).&lt;br /&gt;
* TCP : Communication fiable (exemple : serveur TCP).&lt;br /&gt;
* UDP : Communication non fiable (exemple : serveur UDP).&lt;br /&gt;
* DHCP : Attribution dynamique d'adresse IP.&lt;br /&gt;
&lt;br /&gt;
Aussi, on remarquera que la démo utilise un modèle en quatre couche : Le modèle TCP/IP.&lt;br /&gt;
&lt;br /&gt;
le sujet nous propose trois possibilité :&lt;br /&gt;
&lt;br /&gt;
* viser Ethernet&lt;br /&gt;
* viser UDP&lt;br /&gt;
* viser TCP&lt;br /&gt;
&lt;br /&gt;
En regardant ce qui à été fait les années précédentes, on a remarqué que les groupes partaient principalement sur la première option. Nous nous avons décidé de viser UDP.&lt;br /&gt;
&lt;br /&gt;
Ainsi, afin de d'alléger notre code pour le faire rentrer dans notre carte, nous avons choisi de ne pas inclure le protocole TCP et de modifier la taille max de paquets ethernet à 400 octets.&lt;br /&gt;
&lt;br /&gt;
Il nous restera donc de l'espace pour recevoir des paquets Ethernet :&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
avr-size --mcu=atmega32u4 --format=avr RNDISEthernet.elf&lt;br /&gt;
AVR Memory Usage&lt;br /&gt;
----------------&lt;br /&gt;
Device: atmega32u4&lt;br /&gt;
&lt;br /&gt;
Program:    9434 bytes (28.8% Full)&lt;br /&gt;
(.text + .data + .bootloader)&lt;br /&gt;
&lt;br /&gt;
Data:       1037 bytes (40.5% Full)&lt;br /&gt;
(.data + .bss + .noinit)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Une fois la LUFA réduite et flashé, on donne une adresse IP à notre interface avec ip link eth2 up et  ip address add 10.0.0.1/24 dev eth2.  on test un ping sur l'adresse IP de la carte (10.0.0.2).[[Fichier:Ping creseau.mp4|centré|vignette]]Le premier test que nous décidons de faire, afin de vérifié notre compréhension du code de la LUFA, est de faire clignoter une LED si la carte reçoit un paquet ethernet. Pour cela on ajoute l'allumage de la LED dans la fonction EthernetTask du fichier principal (RNDISEthernet.c) :[[Fichier:Ping allume led.mov|vignette|La led s'éteint à chaque ping reçue|centré]]&lt;br /&gt;
&lt;br /&gt;
===Création du protocole=== &lt;br /&gt;
&lt;br /&gt;
En plus de pouvoir communiquer, notre carte dois être capable d'effectuer 3 fonction.&lt;br /&gt;
&lt;br /&gt;
On décide de créer notre propre protocole ProtocolAntique décrit ci-dessous :  &lt;br /&gt;
&lt;br /&gt;
ProtocolAntique (256 octets) &lt;br /&gt;
&lt;br /&gt;
Entete du ProtocolAntique (3 octets)&lt;br /&gt;
&lt;br /&gt;
    operation (1 octet)&lt;br /&gt;
&lt;br /&gt;
    longueur (1 octet)&lt;br /&gt;
&lt;br /&gt;
    numero (1 octet)&lt;br /&gt;
&lt;br /&gt;
Contenu du ProtocolAntique (256 - 3 = 253 octets)&lt;br /&gt;
&lt;br /&gt;
Exemples :&lt;br /&gt;
&lt;br /&gt;
LS :&lt;br /&gt;
&lt;br /&gt;
    Carte reseau :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x01       // requete LS&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]     &lt;br /&gt;
&lt;br /&gt;
        -numero = 0             // la requete n'est pas fragmentée&lt;br /&gt;
&lt;br /&gt;
        -contenu                // chemin ou effectuer le ls&lt;br /&gt;
&lt;br /&gt;
    Serveur :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x11       // reponse au LS&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]&lt;br /&gt;
&lt;br /&gt;
        -numero = [0-255]       // entre 1 et 255 =&amp;gt; numero du paquet =&amp;gt; reponse fragmentée, si 0 dernier paquet&lt;br /&gt;
&lt;br /&gt;
        -contenu                // nom de fichier ou rien si numero = 0&lt;br /&gt;
&lt;br /&gt;
READ :&lt;br /&gt;
&lt;br /&gt;
    Carte reseau :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x02       // requete READ&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]&lt;br /&gt;
&lt;br /&gt;
        -numero = 0             // la requete n'est pas fragmentée&lt;br /&gt;
&lt;br /&gt;
        -contenu                // chemin/nom_fichier&lt;br /&gt;
&lt;br /&gt;
    Serveur :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x12       // reponse au READ&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]&lt;br /&gt;
&lt;br /&gt;
        -numero = [0-255]       // entre 1 et 255 =&amp;gt; numero du paquet =&amp;gt; reponse fragmentée, si 0 dernier paquet&lt;br /&gt;
&lt;br /&gt;
        -contenu                // contenu d'une ligne ou rien si numero = 0&lt;br /&gt;
&lt;br /&gt;
WRITE :&lt;br /&gt;
&lt;br /&gt;
    Carte reseau :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x03       // requete WRITE creation du fichier&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]&lt;br /&gt;
&lt;br /&gt;
        -numero = 0             // entre 1 et 255 =&amp;gt; numero du paquet =&amp;gt; reponse fragmentée, si 0 dernier paquet&lt;br /&gt;
&lt;br /&gt;
        -contenu                // Chemin pour ouvrir le fichier avce le nom du fichier : chemin/fichier&lt;br /&gt;
&lt;br /&gt;
    Carte reseau :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x13       // requete WRITE ecriture dans le fichier&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]&lt;br /&gt;
&lt;br /&gt;
        -numero = [1-252]       // entre 1 et 255 =&amp;gt; numero du paquet =&amp;gt; reponse fragmentée, si 0 dernier paquet&lt;br /&gt;
&lt;br /&gt;
        -contenu                // ligne a ecrire&lt;br /&gt;
&lt;br /&gt;
    Carte reseau :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x23       // requete WRITE fin&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]&lt;br /&gt;
&lt;br /&gt;
        -numero = 0             // 0 dernier paquet&lt;br /&gt;
&lt;br /&gt;
        -contenu                // rien&lt;br /&gt;
&lt;br /&gt;
Comme nous avons choisit de viser UDP, le protocole doit pocédé un numéro de port, on choisit un numéro supérieur à 1023 pour ne pas devoir passer en root, Le port choisi est 3333.&lt;br /&gt;
&lt;br /&gt;
Dans le programme UDP.c on peut maintenant inclure notre protocole de la façon suivante :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
        switch (SwapEndian_16(UDPHeaderIN-&amp;gt;DestinationPort))&lt;br /&gt;
        {&lt;br /&gt;
    /*&lt;br /&gt;
                case UDP_PORT_DHCP_REQUEST:&lt;br /&gt;
                        RetSize = DHCP_ProcessDHCPPacket(IPHeaderInStart,&lt;br /&gt;
                                                         &amp;amp;((uint8_t*)UDPHeaderInStart)[sizeof(UDP_Header_t)],&lt;br /&gt;
                                                     &amp;amp;((uint8_t*)UDPHeaderOutStart)[sizeof(UDP_Header_t)]);&lt;br /&gt;
                        break;&lt;br /&gt;
    */&lt;br /&gt;
                case UDP_PORT_PROTOCOL_ANTIQUE:       &lt;br /&gt;
                        RetSize = ProtocolAntique_ProcessProtocolAntiquePacket(IPHeaderInStart,&lt;br /&gt;
                                                         &amp;amp;((uint8_t*)UDPHeaderInStart)[sizeof(UDP_Header_t)],&lt;br /&gt;
                                                     &amp;amp;((uint8_t*)UDPHeaderOutStart)[sizeof(UDP_Header_t)]);&lt;br /&gt;
                        break;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Partie serveur ===&lt;br /&gt;
Lorsque la carte mère a besoin de faire une action (ls, read, write) sur l'ordinateur qui est connecté en USB via la carte réseau elle transmet son besoin à la carte réseau. Cette dernière créer un requête UDP qui encapsule notre protocole (ProtocolAntique) et la transmet donc au PC. Sur ce dernier un serveur doit donc fonctionner afin de recevoir les rêquetes de la carte réseau, les traiter et y répondre. Cette partie est donc consacrée au code ainsi qu'aux tests du serveur.&lt;br /&gt;
&lt;br /&gt;
==== Code du serveur ====&lt;br /&gt;
Pour pouvoir fonctionner correctement le serveur doit initialiser une socket UDP et ensuite doit lancer un fonctionne qui boucle indéfiniment afin de recevoir chaque message UDP. Cette partie n'a pas été codé par nous et est trouvable sur rex.plil.fr (Département IMA -&amp;gt; support de cours de la programmation réseau -&amp;gt; exemple de serveur 2/2). Il en est de même du code la fonction pour envoyer un message UDP qui est trouvable au même endroit section exemple de client 2/2.&lt;br /&gt;
&lt;br /&gt;
La carte réseau est toujours à l'initiative des requêtes, par conséquent le serveur commence par recevoir un requête et la traiter. Pour ce faire à chaque requête reçue par la fonction boucleServeurUDP la fonction traitementMessageUDP est appelée.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
int traitementMessageUDP (unsigned char* message, int nboctets);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Cette fonction s'occupe d'extraire la partie opération de l'entête de protocolAntique et d'appeler la fonction de traitement correspondante à l'opération&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Opération&lt;br /&gt;
!Requête&lt;br /&gt;
!Fonction appelée&lt;br /&gt;
|-&lt;br /&gt;
|0x01&lt;br /&gt;
|LS&lt;br /&gt;
|void traitement_ls (unsigned char*);&lt;br /&gt;
|-&lt;br /&gt;
|0x02&lt;br /&gt;
|READ&lt;br /&gt;
|void traitement_read (unsigned char*);&lt;br /&gt;
|-&lt;br /&gt;
|0x03&lt;br /&gt;
|WRITE (début)&lt;br /&gt;
|void traitement_write (unsigned char*);&lt;br /&gt;
|-&lt;br /&gt;
|0x13&lt;br /&gt;
|WRITE (données et fin)&lt;br /&gt;
|void traitement_write (unsigned char*);&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Traitement LS =====&lt;br /&gt;
La fonction traitement_ls commence par récupérer le chemin (relatif ou absolu) où effectuer le LS. Si la section longueur de l'entête de la requête est à 0 alors le chemin par défaut est celui depuis où le serveur à été lancé. Le code pour récupérer le chemin  est le suivant :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
unsigned char chemin[longueur+1];&lt;br /&gt;
for (int i=0 ; i&amp;lt;longueur ; i++) {&lt;br /&gt;
        chemin[i] = message[i+3]; // Recuperation du chemin&lt;br /&gt;
}&lt;br /&gt;
chemin[longueur] = '\0';&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Par la suite le dossier est correspondant au chemin est ouvert via la fonction opendir puis chaque entrée du dossier est récupérée et engendre un message de réponse du serveur (un message par entrée).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
while ((entree = readdir(dossier)) != NULL) {&lt;br /&gt;
   // Message UDP pour chaque entree&lt;br /&gt;
   strcpy(contenu, entree-&amp;gt;d_name);&lt;br /&gt;
   printf(&amp;quot;    %s  &amp;quot;, contenu);&lt;br /&gt;
   reponse[OPERATION] = REPONSE_LS;&lt;br /&gt;
   reponse[LONGUEUR] = strlen(contenu);&lt;br /&gt;
   reponse[NUMERO] = num++;&lt;br /&gt;
   for (int i=0 ; i&amp;lt;reponse[LONGUEUR] ; i++) {&lt;br /&gt;
      reponse[i+3] = contenu[i];&lt;br /&gt;
   }&lt;br /&gt;
   messageUDP(IP_CARTE, PORT_CARTE, (unsigned char *)reponse, (int)reponse[LONGUEUR] + LONGUEUR_ENTETE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;OPERATION est la premiére section et vaut donc 0, LONGUEUR 2 et NUMERO 3. OPERATION est une réponse à un LS donc 0x11, LONGUEUR dépend de l'entrée du dossier et NUMERO augmente de 1 à chaque entrée. Enfin on remplie la requête du nom de l'entrée et on envoie le message.&lt;br /&gt;
&lt;br /&gt;
Enfin une fois tous les entrées envoyées on envoie un dernier message UDP de type reponse_LS de longueur 0 et de numéro 0 afin d'indiquer que la transmission est terminée et ce correctement.&lt;br /&gt;
&lt;br /&gt;
===== Traitement READ =====&lt;br /&gt;
Cette requête est très proche de celle du LS. On commence par récupérer le chemin avec le nom du fichier de la même façon que pour le LS. Cependant ici si le message ne contient pas de chemin aucun traitement ne sera effectué. Pour ouvrir le fichier on utilise la fonction fopen. Chaque ligne, récupérée via fgets, engendre une réponse UDP formulée de la même façon que pour les entrées de dossier. Evidemment l'opération est de type réponse read soit 0x12. Enfin un message similaire de fin de transmission est envoyé seulement si il n'y a pas eu d'erreur et que la dernière ligne à été lue.&lt;br /&gt;
&lt;br /&gt;
===== Traitement WRITE =====&lt;br /&gt;
Cette requête est un peu plus complexe à gérer niveau serveur par conséquent que je vais commencer par décrire le principe de la fonction.&lt;br /&gt;
&lt;br /&gt;
* La carte réseau envoie un message de type début de write (OPERATION 0x03) avec le chemin et nom du fichier que le serveur va récupérer et mémoriser.&lt;br /&gt;
&lt;br /&gt;
* La carte réseau envoie un massage pour chaque ligne à écrite (OPERATION 0x13). Le serveur va vérifier si la section NUMERO des entêtes se suivent afin de s'assurer que aucun message n'est été perdu.&lt;br /&gt;
&lt;br /&gt;
* La carte réseau envoie un message de type fin de write (OPERATION 0x013) mais de numéro 0. Le serveur indique que tout s'est bien passé en envoyant une réponse au write (OPERATION 0x23) donc le contenu est 0x00.&lt;br /&gt;
* Si un message a été perdu un message d'erreur est envoyé de la par du serveur (OPERATION 0x23) de contenu 0x01.&lt;br /&gt;
&lt;br /&gt;
La récupération du contenu de la requête est du même type que celle du LS. Les messages de retour sont construits de la même façon que pour le message de retour du LS. Enfin on utilise fopen une nouvelle fois pour ouvrir le fichier, fwrite pour y écrire et fclose pour le fermer.&lt;br /&gt;
&lt;br /&gt;
==== Préparation du test ====&lt;br /&gt;
Avant de pouvoir tester notre serveur avec la carte réseau (ce qui n'aura jamais été fait car la carte réseau n'envoie rien) nous avons souhaité validé le fonctionnement du serveur en simulant des requêtes de la carte réseau. On voit ce que le serveur fait via des printf et en créant un autre serveur (plus rudimentaire) on peut vérifier que le serveur répond correctement. Sur notre git le dossier testUDP est consacré à cette phase de tests.&lt;br /&gt;
&lt;br /&gt;
* Les requêtes simulées de la carte réseau sont envoyées sur l'IP loopback de la machine et sur le port du serveur (ici 4242)&lt;br /&gt;
* Le serveur écoute le port serveur (4242) et répond en loopback sur le port du serveur qui simule la carte (ici 3333)&lt;br /&gt;
* Le serveur qui simule la carte écoute le port 3333&lt;br /&gt;
&lt;br /&gt;
On lance ces différents serveurs et les requêtes via les commandes du fichiers fonctionnement.txt de notre git.&lt;br /&gt;
&lt;br /&gt;
==== Tests ====&lt;br /&gt;
Le test est réalisé via 3 commandes :&lt;br /&gt;
&lt;br /&gt;
* LS sans chemin&lt;br /&gt;
* WRITE de 3 lignes dans un fichier test.txt créé par la commande&lt;br /&gt;
* READ du fichier test.txt&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Test1.png|centré|vignette|Requêtes envoyées]]&lt;br /&gt;
[[Fichier:Test2.png|centré|vignette|Traitement du serveur]]&lt;br /&gt;
[[Fichier:Test3.png|centré|vignette|Réponse reçu du serveur]]On peut constater que les tests fonctionnent. En effet le serveur a envoyé 9 res ls (8 entrées + fin de transmissions), 1 res write (fin d'écriture correcte) et 6 res read (5 lignes + 1 fin de transmissions).&lt;br /&gt;
&lt;br /&gt;
Enfin on décide de tester la réception des paquets UDP, on fait à nouveau clignoter une led quand un paquet UDP et reçu. Ici on envoi la réponse d'un LS, d'où la reception de plusieurs paquets: &lt;br /&gt;
[[Fichier:Test udp.mp4|centré|vignette]]&lt;br /&gt;
== Conclusion ==&lt;br /&gt;
La partie shield et ordonnanceur est finie et testée. La carte réseau n'a pas pu être finie par manque de temps. En faisant allumer une LED lorsqu'elle reçoit une trame Ethernet, UDP, STMP nous avons constaté qu'elle reçoit correctement ces protocoles. Cependant lorsque que nous avons voulu modifier la LUFA pour qu'une LED en plus s'allume lorsque UDP contient protocole antique cela ne fonctionnait pas. La carte ne trouvait jamais le protocole Antique. La communication avec la carte mère (shield) n'a pas été faite par manque de temps (cependant la communication SPI est vérifiée à l'étape de l'ordonnanceur). Le serveur côté PC qui doit communiquer avec la carte réseau est fini et testé.&lt;br /&gt;
&lt;br /&gt;
Notre problème peut venir du fait que l'atmega32u4 n'a pas assez de mémoire. Il ne faut donc pas choisir ce micro contrôleur pour ce projet mais un avec plus de mémoire.&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2025-1&amp;diff=8768</id>
		<title>SE4Binome2025-1</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2025-1&amp;diff=8768"/>
		<updated>2026-01-24T11:21:34Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Shield Arduino =&lt;br /&gt;
== Hardware ==&lt;br /&gt;
Afin de tester notre futur carte réseau, nous avons fait un shield d'arduino qui prendra le rôle de la carte mère. &lt;br /&gt;
=== Schématique ===&lt;br /&gt;
Nous nous sommes évidemment aidés de la datasheet de l'atmega328p ainsi que celle de l'arduino uno afin de sélectionner les bon pins.&lt;br /&gt;
[[Fichier:Atmel-7810-Automotive-Microcontrollers-ATmega328P Datasheet.pdf|centré|vignette|Datasheet ATmega328p]]&lt;br /&gt;
[[Fichier:A000066-datasheet.pdf|centré|vignette|Datasheet Arduino Uno R3]]&lt;br /&gt;
Plus précisément nous nous sommes inspirés très fortement du schéma page 10 de la datasheet de l'arduino :&lt;br /&gt;
[[Fichier:Screenshot 2025-11-07 11-08-46.png|centré|vignette|Schéma pinouts]]&lt;br /&gt;
Nous sommes donc parti de l'exemple fourni par Mr Redon. Mais nous avons utilisé une template disponible dans kicad permettant de créer des shields d'arduino Uno R3.[[Fichier:Tyetyuy.png|vignette|Schématique shield arduino|centré|438x438px]]&lt;br /&gt;
=== Routage ===&lt;br /&gt;
Au niveau du routage, nous avons tenté de faire simple (sans trop abuser des vias). Nous avons positionné le lecteur de carte SD au bord de la carte afin de ne pas avoir de problèmes avec d'autres composants lorsque nous voudrons mettre ou enlever la carte SD.&lt;br /&gt;
[[Fichier:Routage shield arduino.png|vignette|Routage shield arduino|centré|434x434px]]&lt;br /&gt;
&lt;br /&gt;
===Soudage===&lt;br /&gt;
La schématique et le routage terminés, nous avons soudé les différents pins permettant de connecter la carte shield à l'arduino, le reste n'étant pas forcément utile pour le moment (il est important de noter que notre shield est arrivé avec des composants pré-soudés).&lt;br /&gt;
[[Fichier:Shield soudage de base .jpg|centré|vignette]]&lt;br /&gt;
&lt;br /&gt;
===Tests===&lt;br /&gt;
====Leds====&lt;br /&gt;
&lt;br /&gt;
Il faudra ensuite faire des test d'allumage des leds, afin de vérifier le bon fonctionnement du shield&lt;br /&gt;
[[Fichier:VID leds.mp4|centré|vignette]]&lt;br /&gt;
&lt;br /&gt;
Les leds fonctionnent à merveille.&lt;br /&gt;
&lt;br /&gt;
====Carte SD====&lt;br /&gt;
&lt;br /&gt;
Nous vérifions maintenant la carte SD (même si elle nous sera inutile pour notre projet).&lt;br /&gt;
&lt;br /&gt;
Nous utilisons le programme fourni par arduino qui permet de récupérer les informations de la carte SD.&lt;br /&gt;
[[Fichier:Test sd card.png|centré|vignette]]&lt;br /&gt;
La carte SD est bien identifié, le lecteur de carte fonctionne donc normalement.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
=== Ordonnanceur ===&lt;br /&gt;
==== Ordonnanceur basique ====&lt;br /&gt;
La première étape consiste à définir la structure d'un process, il sera composé :&lt;br /&gt;
&lt;br /&gt;
*D'un pointeur de pile&lt;br /&gt;
*De l'adresse de la fonction&lt;br /&gt;
*D'un temps de sommeil&lt;br /&gt;
*D'un état : 0 pour en cours et 1 pour terminé ou vide&lt;br /&gt;
&lt;br /&gt;
Ces deux derniers points nous serviront plus tard.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
typedef struct {&lt;br /&gt;
	uint16_t stackPointer;&lt;br /&gt;
	void (*functionAddress)(void);&lt;br /&gt;
	int sleep_time;&lt;br /&gt;
	int state;&lt;br /&gt;
} process;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On initialise donc notre tableau de processus de la façon suivante : &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
process Tasks_list[NBTASKS] = {&lt;br /&gt;
                                {0, led1_blink, 0,0},&lt;br /&gt;
				...&lt;br /&gt;
			       };&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Concernant les fonction liées aux leds, nous utilisons une simple boucle while contenant un changement d'état. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void led_init() {&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
void led1_blink() {&lt;br /&gt;
	while(1) {&lt;br /&gt;
		PORTC ^= (1&amp;lt;&amp;lt;PLED1);&lt;br /&gt;
		_delay_ms(100);&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
void led2_blink() {&lt;br /&gt;
...	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_stackPointer_tasks() permet de diviser la pile &amp;quot;réel&amp;quot; en plusieurs piles de taille fixe pour chacun des processus.  Ces sous piles commencent à la position FIRST_STACK_POSITION, afin de ne pas réécrire par dessus des données. Toutes les sous piles disposent d'une même taille de pile STACK_LENGTH. La fonction init_piles() initialise correctement la pile avec le tableau de processus si le processus est actif. Elle sauvegarde d'abord le pointeur de pile actuel, place l'adresse de la fonction (sur 16 bits) dans la pile de la tâche, sauvegarde les registres, puis restaure le pointeur de pile initial.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void init_stackPointer_tasks(int Cprocess) { //initialise le pointer de pile&lt;br /&gt;
	if(Tasks_list[Cprocess].state == 0) {&lt;br /&gt;
		Tasks_list[Cprocess].stackPointer = FIRST_STACK_POSITION - (Cprocess * STACK_LENGTH);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void init_piles(int Cprocess){ //initilalise la pile&lt;br /&gt;
	if(Tasks_list[Cprocess].state == 0) {&lt;br /&gt;
		int save = SP;&lt;br /&gt;
		SP = Tasks_list[Cprocess].stackPointer;&lt;br /&gt;
		uint16_t address = (uint16_t)Tasks_list[Cprocess].functionAddress;&lt;br /&gt;
		asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (address &amp;amp; 0x00ff) );&lt;br /&gt;
		asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((address &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
		SAVE_REGISTERS();&lt;br /&gt;
		Tasks_list[Cprocess].stackPointer = SP;&lt;br /&gt;
		SP = save;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Le scheduler permet de passer à la tâche suivante&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
	Current_task++;&lt;br /&gt;
	if (Current_task &amp;gt;= NBTASKS) {&lt;br /&gt;
		Current_task = 0; &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;L'atmega328p ne dispose pas de fonction en assembleur permettant de push ou de pop tout les registres, on doit donc en créer par nous mêmes. On défini alors les macros suivantes :  &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
#define SAVE_REGISTERS() \&lt;br /&gt;
	asm volatile ( \&lt;br /&gt;
		&amp;quot;push r0 	 \n\t&amp;quot; \&lt;br /&gt;
		...\&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#define RESTORE_REGISTERS() \&lt;br /&gt;
	asm volatile ( \&lt;br /&gt;
		&amp;quot;pop r31 	  \n\t&amp;quot; \&lt;br /&gt;
		...\&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;L'ISR gère les interruptions, en commençant par sauvegarder l'état de la pile ainsi que le stack pointeur propre au processus qui s'interrompt. L'appel au schedruler permet de changer de processus pour cela il faut restaurer le stack pointer propre au nouveau processus actif et de la pile liée à ce processus. La dernière ligne arrête l'ISR.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED) {&lt;br /&gt;
	SAVE_REGISTERS();&lt;br /&gt;
	Tasks_list[Current_task].stackPointer = SP;&lt;br /&gt;
	scheduler();&lt;br /&gt;
	SP = Tasks_list[Current_task].stackPointer;&lt;br /&gt;
	RESTORE_REGISTERS();&lt;br /&gt;
	asm volatile(&amp;quot;reti&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=====Test=====&lt;br /&gt;
Les processus de clignotement de leds ont tous un délai d'attente différent, l'interruption se produit toutes les millisecondes. On obtient ceci :[[Fichier:Ordonnanceur basique.mp4|centré|vignette]]Il est intéressant de remarqué que la vitesse à laquelle les leds changent d'état ne correspond pas au délai qui leur a été donnée. Cela parait logique puisque l'interruption met la fonction _delay_ms en pause, ainsi la vitesse se voit divisé par le nombre de processus actif.&lt;br /&gt;
&lt;br /&gt;
====Ajout d'un système d'endormissement des processus====&lt;br /&gt;
&lt;br /&gt;
La fonction wait va permettre d'endormir un processus, elle va donné un temps de sommeil au processus puis lancer une interruption (car on veut changer de processus directement après que le précédent ait été endormi).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time) { // met un process en veille pour une durée donné&lt;br /&gt;
	// valeur max de time 32000 car int sur atmega328p code sur 16 bits donc 32000 max&lt;br /&gt;
	cli();&lt;br /&gt;
	Tasks_list[Current_task].sleep_time = time;&lt;br /&gt;
	TCNT1=0;&lt;br /&gt;
	sei();&lt;br /&gt;
	TIMER1_COMPA_vect();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour vérifier si un processus a besoin d'être lancé, on ajoute une boucle while dans le scheduler afin de vérifier si il y a un temps de sommeil. Le scheduler va aussi servir à diminuer le temps de sommeil de tout les processus (avec un minimum de 0).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
	for (int i=0 ; i&amp;lt;NBTASKS ; i++) {&lt;br /&gt;
		if (Tasks_list[i].sleep_time - SLEEP_DEC &amp;lt; 0) {&lt;br /&gt;
			Tasks_list[i].sleep_time = 0;&lt;br /&gt;
		} else {&lt;br /&gt;
			Tasks_list[i].sleep_time -= SLEEP_DEC;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	do {&lt;br /&gt;
		Current_task++;&lt;br /&gt;
		if (Current_task &amp;gt;= NBTASKS) {&lt;br /&gt;
			Current_task = 0;&lt;br /&gt;
		}&lt;br /&gt;
	} while (Tasks_list[Current_task].sleep_time &amp;gt; 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Tableau dynamique des tâches====&lt;br /&gt;
&lt;br /&gt;
En premier lieu on va initialiser les état de tout les cases du tableau de processus. On choisit 1 la case est vide, 0 sinon.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void init_state() { //initialise state&lt;br /&gt;
	for (int i= 0; i&amp;lt;NBTASKS; i++) {&lt;br /&gt;
		if (Tasks_list[i].functionAddress == NULL) {&lt;br /&gt;
			Tasks_list[i].state = 1;&lt;br /&gt;
		}&lt;br /&gt;
		else {&lt;br /&gt;
			Tasks_list[i].state = 0;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Nous avons programmé deux fonction d'arrêt et une fonction d'ajout de processus :&lt;br /&gt;
&lt;br /&gt;
* finish : stop le processus en cours et le supprime de tableau, puis lance une interruption&lt;br /&gt;
&lt;br /&gt;
* kill : stop un processus donné et le supprime du tableau&lt;br /&gt;
&lt;br /&gt;
* add : ajoute un processus sur la première case vide du tableau, initialise son pointeur de position et sa pile.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Pour finish et kill, on met le temps de sommeil à 0 au cas où on arrête un processus endormi. C'est une mesure de sécurité pour finish, mais une obligation pour kill.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void finish() { //supprime un process lorsque celui-ci est terminé&lt;br /&gt;
	cli();&lt;br /&gt;
		Tasks_list[Current_task].state =1;&lt;br /&gt;
		Tasks_list[Current_task].sleep_time = 0;&lt;br /&gt;
		Tasks_list[Current_task].functionAddress = NULL;&lt;br /&gt;
	TCNT1=0; &lt;br /&gt;
	sei();&lt;br /&gt;
	TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void kill(void (*function)(void)) { //tue le process passé en paramètre&lt;br /&gt;
	cli();&lt;br /&gt;
	for(int i = 0; i&amp;lt;NBTASKS; i++) {&lt;br /&gt;
		if(Tasks_list[i].functionAddress == function) {&lt;br /&gt;
			Tasks_list[i].state =1;&lt;br /&gt;
			Tasks_list[i].sleep_time = 0;&lt;br /&gt;
			Tasks_list[i].functionAddress = NULL;&lt;br /&gt;
		}&lt;br /&gt;
	} &lt;br /&gt;
	sei();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void add(void (*newFunction)(void)) { //ajoute un process&lt;br /&gt;
	cli();&lt;br /&gt;
	int i =0;&lt;br /&gt;
	while(Tasks_list[i].state != 1) {&lt;br /&gt;
		i++;&lt;br /&gt;
	}&lt;br /&gt;
	Tasks_list[i].functionAddress = newFunction;&lt;br /&gt;
	Tasks_list[i].state = 0;&lt;br /&gt;
	init_stackPointer_tasks(i);&lt;br /&gt;
	init_piles(i);&lt;br /&gt;
&lt;br /&gt;
	sei();&lt;br /&gt;
	&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Il suffit maintenant de modifier le scheduler afin de ne pas prendre les processus terminé, puis utiliser add, finish et kill dans les fonctions choisies.&lt;br /&gt;
&lt;br /&gt;
=====Test=====&lt;br /&gt;
Pour tester les fonction add et finish, on réalise le test suivant :&lt;br /&gt;
&lt;br /&gt;
* on créer un process qui ajoute le process led2_blink (avec add) au bout d'un certain temps&lt;br /&gt;
* le process led2_blink s'arrête (avec finish) au bout de 20 changement d'état (c'est à dire 10 clignotement).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On obtient le résultat escompté qui est le suivant :[[Fichier:Demo fonction add et finish.mp4|centré|vignette]]&lt;br /&gt;
====Lecture et écriture sur le port série====&lt;br /&gt;
Afin de lire et écrire sur le port série, on utilise les fonctions USART_Init, USART_Transmit et USART_Receive  vu en cours de microP l'année précédente. Le but sera donc d'écrire le message qui vient d'être reçu, on utilise donc le processus suivant :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Test=====&lt;br /&gt;
Pour tester notre processus de communication, on utilise minicom.[[Fichier:Test lecture et écriture port série.mp4|centré|vignette]]On notera que si la période entre les interruptions est trop élevé, certains caractères ne seront pas lus.&lt;br /&gt;
&lt;br /&gt;
====Afficheur 7 segments====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void seven_seg() {&lt;br /&gt;
	while (1) {&lt;br /&gt;
        spi_activer((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
		spi_echange(0x7E);&lt;br /&gt;
		spi_echange(0b1101111);&lt;br /&gt;
		spi_desactiver((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
&lt;br /&gt;
		wait(500);&lt;br /&gt;
&lt;br /&gt;
		spi_activer((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
		spi_echange(0x76);&lt;br /&gt;
		spi_desactiver((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
&lt;br /&gt;
		wait(500);&lt;br /&gt;
    	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Le processus seven_seg est ajouté au tableau des processus. Avant d'échanger en spi il faut activer la communication, et la désactiver après l'échange. La ligne 4 permet de sélectionner le 7 seg sur lequel on souhaite modifier l'affichage. La ligne 5 permet d'afficher le chiffre 9. Enfin la ligne 11 permet de clear le display. Voir tableau ci-dessous.&lt;br /&gt;
[[Fichier:Tab 7 seg sparkfun.png|centré|vignette]]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void) {                                 // Initialisation du bus SPI&lt;br /&gt;
	SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);   // Définition des sorties&lt;br /&gt;
	SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // Définition de l'entrée                          &lt;br /&gt;
	SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
        	                                             // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
	SPI_DDR |= (1&amp;lt;&amp;lt;CS1) | (1&amp;lt;&amp;lt;CS4);;&lt;br /&gt;
	DDRD |= (1&amp;lt;&amp;lt;CS5) | (1&amp;lt;&amp;lt;CS6);&lt;br /&gt;
	DDRC |= (1&amp;lt;&amp;lt;CS2) | (1&amp;lt;&amp;lt;CS3);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void spi_activer(uint16_t port, uint8_t cs) { 	// Activer le périphérique&lt;br /&gt;
	volatile uint8_t *reg = (volatile uint8_t*)port;&lt;br /&gt;
	*reg &amp;amp;= ~(1&amp;lt;&amp;lt;cs);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(uint16_t port, uint8_t cs) {                           // Désactiver le périphérique&lt;br /&gt;
	volatile uint8_t *reg = (volatile uint8_t*)port;&lt;br /&gt;
	*reg |= (1&amp;lt;&amp;lt;cs);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi) {                  // Communication sur le bus SPI&lt;br /&gt;
	SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
	while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
	return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de rendre nos fonctions les plus réutilisables possibles nous avons passer en paramètre le port ainsi que le CS qui correspond au slave select. Le type réel du port est volatile uint8* cependant le compilateur n'accepte que le uint16* ce qui explique le cast un peu étrange.&lt;br /&gt;
&lt;br /&gt;
=====Implémentation=====&lt;br /&gt;
[[Fichier:Video7segvideo.mp4|vignette|centré]]L'implémentation correspond à nos attentes, seul un 7 seg affiche le chiffre 9.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Choix du processus sur le port série====&lt;br /&gt;
Afin de pouvoir démontrer le bon fonctionnement de la partie dynamique, on décide de pouvoir ajouter et tuer des processus à partir des touches du clavier. On utilisera donc les fonction de l'USART défini plus au au travers de la fonction suivante :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void call_process() {&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1) {&lt;br /&gt;
        data = USART_Receive();&lt;br /&gt;
        if(data == '1') {&lt;br /&gt;
            add(led1_blink);&lt;br /&gt;
        }&lt;br /&gt;
        ...&lt;br /&gt;
        else if(data == '6') {&lt;br /&gt;
            kill(led1_blink);&lt;br /&gt;
        }&lt;br /&gt;
        ...&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On remarquera que c'est une sorte d'amélioration de la fonction Serial_Message vu plus haut.&lt;br /&gt;
&lt;br /&gt;
Cette fonction aura la fonction de process de base, toujours présent dans l'ordonnaceur.&lt;br /&gt;
&lt;br /&gt;
=====Démonstation===== &lt;br /&gt;
[[Fichier:Process via USART.mp4|centré|vignette]]&lt;br /&gt;
&lt;br /&gt;
Ici on lance les processus ledN_blink avec les touches 1 à 5 et on les tues avec les touches 6 à 0. Pour le 7 segments, on l'ajoute avec s et le tue avec d. &lt;br /&gt;
&lt;br /&gt;
=Carte Réseau=&lt;br /&gt;
Lors de la répartition des tâches, nous avons opté pour la carte réseau. &lt;br /&gt;
==Description==&lt;br /&gt;
Le sujet nous permettait de choisir parmi plusieurs microcontrôleurs. Nous avons retenu l’ATmega32U4, qui nous semble représenter un juste milieu entre l’ATmega16U2 et l’AT90USB.&lt;br /&gt;
==Hardware==&lt;br /&gt;
Notre carte intègre des LED permettant d’afficher différents états de communication (que nous définirons ultérieurement).&lt;br /&gt;
&lt;br /&gt;
À la demande de M. Redon, nous avons ajouté un MAX232 ainsi que des connecteurs DB9 et DB25. Nous savons que ces éléments pourront être utiles et servirons à utiliser la carte sur un terminal.&lt;br /&gt;
&lt;br /&gt;
En dehors de ça, la carte reste assez basique car son composant principal reste l'ATmega.&lt;br /&gt;
===Schématique===&lt;br /&gt;
les broches PF n'étant pas utilisé, on les branches à un connecteur 6x1, notre carte pourra donc être utiliser pour d'autre projet si nécéssaire.&lt;br /&gt;
&lt;br /&gt;
On fait le choix d'utiliser 5 leds pour la connections, 1 led de power et 1 pour la connection ISP.[[Fichier:Schématique CReseau.png|vignette|540x540px|centré]]&lt;br /&gt;
===Routage===&lt;br /&gt;
[[Fichier:Routage Creseau.png|vignette|521x521px|centré]]Après avoir soudé les composants principaux, il est temps de passer à la partie programmation de la carte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Programmation== &lt;br /&gt;
&lt;br /&gt;
Notre carte utilisant un connecteur USB, nous allons donc faire passer notre carte pour une carte réseau en utilisant la demo RNDIS de la LUFA.&lt;br /&gt;
&lt;br /&gt;
Il est important de noter que nous avons choisi un Atmega32u4. Ainsi des modification devrons être apporté à la taille des paquets ethernet et sur le choix des protocoles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Protocoles impémentés=== &lt;br /&gt;
&lt;br /&gt;
La demo RNDISEthernet de la LUFA inclut les protocole suivant&lt;br /&gt;
&lt;br /&gt;
* ARP : Résolution d'adresses MAC.&lt;br /&gt;
* IP : Gestion des paquets IPv4.&lt;br /&gt;
* ICMP : Messages de contrôle (ping).&lt;br /&gt;
* TCP : Communication fiable (exemple : serveur TCP).&lt;br /&gt;
* UDP : Communication non fiable (exemple : serveur UDP).&lt;br /&gt;
* DHCP : Attribution dynamique d'adresse IP.&lt;br /&gt;
&lt;br /&gt;
Aussi, on remarquera que la démo utilise un modèle en quatre couche : Le modèle TCP/IP.&lt;br /&gt;
&lt;br /&gt;
le sujet nous propose trois possibilité :&lt;br /&gt;
&lt;br /&gt;
* viser Ethernet&lt;br /&gt;
* viser UDP&lt;br /&gt;
* viser TCP&lt;br /&gt;
&lt;br /&gt;
En regardant ce qui à été fait les années précédentes, on a remarqué que les groupes partaient principalement sur la première option. Nous nous avons décidé de viser UDP.&lt;br /&gt;
&lt;br /&gt;
Ainsi, afin de d'alléger notre code pour le faire rentrer dans notre carte, nous avons choisi de ne pas inclure le protocole TCP et de modifier la taille max de paquets ethernet à 400 octets.&lt;br /&gt;
&lt;br /&gt;
Il nous restera donc de l'espace pour recevoir des paquets Ethernet :&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
avr-size --mcu=atmega32u4 --format=avr RNDISEthernet.elf&lt;br /&gt;
AVR Memory Usage&lt;br /&gt;
----------------&lt;br /&gt;
Device: atmega32u4&lt;br /&gt;
&lt;br /&gt;
Program:    9434 bytes (28.8% Full)&lt;br /&gt;
(.text + .data + .bootloader)&lt;br /&gt;
&lt;br /&gt;
Data:       1037 bytes (40.5% Full)&lt;br /&gt;
(.data + .bss + .noinit)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Une fois la LUFA réduite et flashé, on donne une adresse IP à notre interface avec ip link eth2 up et  ip address add 10.0.0.1/24 dev eth2.  on test un ping sur l'adresse IP de la carte (10.0.0.2).[[Fichier:Ping creseau.mp4|centré|vignette]]Le premier test que nous décidons de faire, afin de vérifié notre compréhension du code de la LUFA, est de faire clignoter une LED si la carte reçoit un paquet ethernet. Pour cela on ajoute l'allumage de la LED dans la fonction EthernetTask du fichier principal (RNDISEthernet.c) :[[Fichier:Ping allume led.mov|vignette|La led s'éteint à chaque ping reçue|centré]]&lt;br /&gt;
&lt;br /&gt;
===Création du protocole=== &lt;br /&gt;
&lt;br /&gt;
En plus de pouvoir communiquer, notre carte dois être capable d'effectuer 3 fonction.&lt;br /&gt;
&lt;br /&gt;
On décide de créer notre propre protocole ProtocolAntique décrit ci-dessous :  &lt;br /&gt;
&lt;br /&gt;
ProtocolAntique (256 octets) &lt;br /&gt;
&lt;br /&gt;
Entete du ProtocolAntique (3 octets)&lt;br /&gt;
&lt;br /&gt;
    operation (1 octet)&lt;br /&gt;
&lt;br /&gt;
    longueur (1 octet)&lt;br /&gt;
&lt;br /&gt;
    numero (1 octet)&lt;br /&gt;
&lt;br /&gt;
Contenu du ProtocolAntique (256 - 3 = 253 octets)&lt;br /&gt;
&lt;br /&gt;
Exemples :&lt;br /&gt;
&lt;br /&gt;
LS :&lt;br /&gt;
&lt;br /&gt;
    Carte reseau :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x01       // requete LS&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]     &lt;br /&gt;
&lt;br /&gt;
        -numero = 0             // la requete n'est pas fragmentée&lt;br /&gt;
&lt;br /&gt;
        -contenu                // chemin ou effectuer le ls&lt;br /&gt;
&lt;br /&gt;
    Serveur :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x11       // reponse au LS&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]&lt;br /&gt;
&lt;br /&gt;
        -numero = [0-255]       // entre 1 et 255 =&amp;gt; numero du paquet =&amp;gt; reponse fragmentée, si 0 dernier paquet&lt;br /&gt;
&lt;br /&gt;
        -contenu                // nom de fichier ou rien si numero = 0&lt;br /&gt;
&lt;br /&gt;
READ :&lt;br /&gt;
&lt;br /&gt;
    Carte reseau :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x02       // requete READ&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]&lt;br /&gt;
&lt;br /&gt;
        -numero = 0             // la requete n'est pas fragmentée&lt;br /&gt;
&lt;br /&gt;
        -contenu                // chemin/nom_fichier&lt;br /&gt;
&lt;br /&gt;
    Serveur :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x12       // reponse au READ&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]&lt;br /&gt;
&lt;br /&gt;
        -numero = [0-255]       // entre 1 et 255 =&amp;gt; numero du paquet =&amp;gt; reponse fragmentée, si 0 dernier paquet&lt;br /&gt;
&lt;br /&gt;
        -contenu                // contenu d'une ligne ou rien si numero = 0&lt;br /&gt;
&lt;br /&gt;
WRITE :&lt;br /&gt;
&lt;br /&gt;
    Carte reseau :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x03       // requete WRITE creation du fichier&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]&lt;br /&gt;
&lt;br /&gt;
        -numero = 0             // entre 1 et 255 =&amp;gt; numero du paquet =&amp;gt; reponse fragmentée, si 0 dernier paquet&lt;br /&gt;
&lt;br /&gt;
        -contenu                // Chemin pour ouvrir le fichier avce le nom du fichier : chemin/fichier&lt;br /&gt;
&lt;br /&gt;
    Carte reseau :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x13       // requete WRITE ecriture dans le fichier&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]&lt;br /&gt;
&lt;br /&gt;
        -numero = [1-252]       // entre 1 et 255 =&amp;gt; numero du paquet =&amp;gt; reponse fragmentée, si 0 dernier paquet&lt;br /&gt;
&lt;br /&gt;
        -contenu                // ligne a ecrire&lt;br /&gt;
&lt;br /&gt;
    Carte reseau :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x23       // requete WRITE fin&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]&lt;br /&gt;
&lt;br /&gt;
        -numero = 0             // 0 dernier paquet&lt;br /&gt;
&lt;br /&gt;
        -contenu                // rien&lt;br /&gt;
&lt;br /&gt;
Comme nous avons choisit de viser UDP, le protocole doit pocédé un numéro de port, on choisit un numéro supérieur à 1023 pour ne pas devoir passer en root, Le port choisi est 3333.&lt;br /&gt;
&lt;br /&gt;
Dans le programme UDP.c on peut maintenant inclure notre protocole de la façon suivante :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
        switch (SwapEndian_16(UDPHeaderIN-&amp;gt;DestinationPort))&lt;br /&gt;
        {&lt;br /&gt;
    /*&lt;br /&gt;
                case UDP_PORT_DHCP_REQUEST:&lt;br /&gt;
                        RetSize = DHCP_ProcessDHCPPacket(IPHeaderInStart,&lt;br /&gt;
                                                         &amp;amp;((uint8_t*)UDPHeaderInStart)[sizeof(UDP_Header_t)],&lt;br /&gt;
                                                     &amp;amp;((uint8_t*)UDPHeaderOutStart)[sizeof(UDP_Header_t)]);&lt;br /&gt;
                        break;&lt;br /&gt;
    */&lt;br /&gt;
                case UDP_PORT_PROTOCOL_ANTIQUE:       &lt;br /&gt;
                        RetSize = ProtocolAntique_ProcessProtocolAntiquePacket(IPHeaderInStart,&lt;br /&gt;
                                                         &amp;amp;((uint8_t*)UDPHeaderInStart)[sizeof(UDP_Header_t)],&lt;br /&gt;
                                                     &amp;amp;((uint8_t*)UDPHeaderOutStart)[sizeof(UDP_Header_t)]);&lt;br /&gt;
                        break;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Partie serveur ===&lt;br /&gt;
Lorsque la carte mère a besoin de faire une action (ls, read, write) sur l'ordinateur qui est connecté en USB via la carte réseau elle transmet son besoin à la carte réseau. Cette dernière créer un requête UDP qui encapsule notre protocole (ProtocolAntique) et la transmet donc au PC. Sur ce dernier un serveur doit donc fonctionner afin de recevoir les rêquetes de la carte réseau, les traiter et y répondre. Cette partie est donc consacrée au code ainsi qu'aux tests du serveur.&lt;br /&gt;
&lt;br /&gt;
==== Code du serveur ====&lt;br /&gt;
Pour pouvoir fonctionner correctement le serveur doit initialiser une socket UDP et ensuite doit lancer un fonctionne qui boucle indéfiniment afin de recevoir chaque message UDP. Cette partie n'a pas été codé par nous et est trouvable sur rex.plil.fr (Département IMA -&amp;gt; support de cours de la programmation réseau -&amp;gt; exemple de serveur 2/2). Il en est de même du code la fonction pour envoyer un message UDP qui est trouvable au même endroit section exemple de client 2/2.&lt;br /&gt;
&lt;br /&gt;
La carte réseau est toujours à l'initiative des requêtes, par conséquent le serveur commence par recevoir un requête et la traiter. Pour ce faire à chaque requête reçue par la fonction boucleServeurUDP la fonction traitementMessageUDP est appelée.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
int traitementMessageUDP (unsigned char* message, int nboctets);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Cette fonction s'occupe d'extraire la partie opération de l'entête de protocolAntique et d'appeler la fonction de traitement correspondante à l'opération&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Opération&lt;br /&gt;
!Requête&lt;br /&gt;
!Fonction appelée&lt;br /&gt;
|-&lt;br /&gt;
|0x01&lt;br /&gt;
|LS&lt;br /&gt;
|void traitement_ls (unsigned char*);&lt;br /&gt;
|-&lt;br /&gt;
|0x02&lt;br /&gt;
|READ&lt;br /&gt;
|void traitement_read (unsigned char*);&lt;br /&gt;
|-&lt;br /&gt;
|0x03&lt;br /&gt;
|WRITE (début)&lt;br /&gt;
|void traitement_write (unsigned char*);&lt;br /&gt;
|-&lt;br /&gt;
|0x13&lt;br /&gt;
|WRITE (données et fin)&lt;br /&gt;
|void traitement_write (unsigned char*);&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Traitement LS =====&lt;br /&gt;
La fonction traitement_ls commence par récupérer le chemin (relatif ou absolu) où effectuer le LS. Si la section longueur de l'entête de la requête est à 0 alors le chemin par défaut est celui depuis où le serveur à été lancé. Le code pour récupérer le chemin  est le suivant :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
unsigned char chemin[longueur+1];&lt;br /&gt;
for (int i=0 ; i&amp;lt;longueur ; i++) {&lt;br /&gt;
        chemin[i] = message[i+3]; // Recuperation du chemin&lt;br /&gt;
}&lt;br /&gt;
chemin[longueur] = '\0';&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Par la suite le dossier est correspondant au chemin est ouvert via la fonction opendir puis chaque entrée du dossier est récupérée et engendre un message de réponse du serveur (un message par entrée).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
while ((entree = readdir(dossier)) != NULL) {&lt;br /&gt;
   // Message UDP pour chaque entree&lt;br /&gt;
   strcpy(contenu, entree-&amp;gt;d_name);&lt;br /&gt;
   printf(&amp;quot;    %s  &amp;quot;, contenu);&lt;br /&gt;
   reponse[OPERATION] = REPONSE_LS;&lt;br /&gt;
   reponse[LONGUEUR] = strlen(contenu);&lt;br /&gt;
   reponse[NUMERO] = num++;&lt;br /&gt;
   for (int i=0 ; i&amp;lt;reponse[LONGUEUR] ; i++) {&lt;br /&gt;
      reponse[i+3] = contenu[i];&lt;br /&gt;
   }&lt;br /&gt;
   messageUDP(IP_CARTE, PORT_CARTE, (unsigned char *)reponse, (int)reponse[LONGUEUR] + LONGUEUR_ENTETE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;OPERATION est la premiére section et vaut donc 0, LONGUEUR 2 et NUMERO 3. OPERATION est une réponse à un LS donc 0x11, LONGUEUR dépend de l'entrée du dossier et NUMERO augmente de 1 à chaque entrée. Enfin on remplie la requête du nom de l'entrée et on envoie le message.&lt;br /&gt;
&lt;br /&gt;
Enfin une fois tous les entrées envoyées on envoie un dernier message UDP de type reponse_LS de longueur 0 et de numéro 0 afin d'indiquer que la transmission est terminée et ce correctement.&lt;br /&gt;
&lt;br /&gt;
===== Traitement READ =====&lt;br /&gt;
Cette requête est très proche de celle du LS. On commence par récupérer le chemin avec le nom du fichier de la même façon que pour le LS. Cependant ici si le message ne contient pas de chemin aucun traitement ne sera effectué. Pour ouvrir le fichier on utilise la fonction fopen. Chaque ligne, récupérée via fgets, engendre une réponse UDP formulée de la même façon que pour les entrées de dossier. Evidemment l'opération est de type réponse read soit 0x12. Enfin un message similaire de fin de transmission est envoyé seulement si il n'y a pas eu d'erreur et que la dernière ligne à été lue.&lt;br /&gt;
&lt;br /&gt;
===== Traitement WRITE =====&lt;br /&gt;
Cette requête est un peu plus complexe à gérer niveau serveur par conséquent que je vais commencer par décrire le principe de la fonction.&lt;br /&gt;
&lt;br /&gt;
* La carte réseau envoie un message de type début de write (OPERATION 0x03) avec le chemin et nom du fichier que le serveur va récupérer et mémoriser.&lt;br /&gt;
&lt;br /&gt;
* La carte réseau envoie un massage pour chaque ligne à écrite (OPERATION 0x13). Le serveur va vérifier si la section NUMERO des entêtes se suivent afin de s'assurer que aucun message n'est été perdu.&lt;br /&gt;
&lt;br /&gt;
* La carte réseau envoie un message de type fin de write (OPERATION 0x013) mais de numéro 0. Le serveur indique que tout s'est bien passé en envoyant une réponse au write (OPERATION 0x23) donc le contenu est 0x00.&lt;br /&gt;
* Si un message a été perdu un message d'erreur est envoyé de la par du serveur (OPERATION 0x23) de contenu 0x01.&lt;br /&gt;
&lt;br /&gt;
La récupération du contenu de la requête est du même type que celle du LS. Les messages de retour sont construits de la même façon que pour le message de retour du LS. Enfin on utilise fopen une nouvelle fois pour ouvrir le fichier, fwrite pour y écrire et fclose pour le fermer.&lt;br /&gt;
&lt;br /&gt;
==== Préparation du test ====&lt;br /&gt;
Avant de pouvoir tester notre serveur avec la carte réseau (ce qui n'aura jamais été fait car la carte réseau n'envoie rien) nous avons souhaité validé le fonctionnement du serveur en simulant des requêtes de la carte réseau. On voit ce que le serveur fait via des printf et en créant un autre serveur (plus rudimentaire) on peut vérifier que le serveur répond correctement. Sur notre git le dossier testUDP est consacré à cette phase de tests.&lt;br /&gt;
&lt;br /&gt;
* Les requêtes simulées de la carte réseau sont envoyées sur l'IP loopback de la machine et sur le port du serveur (ici 4242)&lt;br /&gt;
* Le serveur écoute le port serveur (4242) et répond en loopback sur le port du serveur qui simule la carte (ici 3333)&lt;br /&gt;
* Le serveur qui simule la carte écoute le port 3333&lt;br /&gt;
&lt;br /&gt;
On lance ces différents serveurs et les requêtes via les commandes du fichiers fonctionnement.txt de notre git.&lt;br /&gt;
&lt;br /&gt;
==== Tests ====&lt;br /&gt;
Le test est réalisé via 3 commandes :&lt;br /&gt;
&lt;br /&gt;
* LS sans chemin&lt;br /&gt;
* WRITE de 3 lignes dans un fichier test.txt créé par la commande&lt;br /&gt;
* READ du fichier test.txt&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Test1.png|centré|vignette|Requêtes envoyées]]&lt;br /&gt;
[[Fichier:Test2.png|centré|vignette|Traitement du serveur]]&lt;br /&gt;
[[Fichier:Test3.png|centré|vignette|Réponse reçu du serveur]]On peut constater que les tests fonctionnent. En effet le serveur a envoyé 9 res ls (8 entrées + fin de transmissions), 1 res write (fin d'écriture correcte) et 6 res read (5 lignes + 1 fin de transmissions).&lt;br /&gt;
&lt;br /&gt;
Enfin on décide de tester la reception des paquets UDP, on fait à nouveau clignotter une led quand un paquet UDP et reçu. Ici on envoi la réponse d'un LS, d'où la reception de plusieurs paquets: &lt;br /&gt;
[[Fichier:Test udp.mp4|centré|vignette]]&lt;br /&gt;
== Conclusion ==&lt;br /&gt;
La partie shield et ordonnanceur est finie et testée. La carte réseau n'a pas pu être finie par manque de temps. En faisant allumer une LED lorsqu'elle reçoit une trame Ethernet, UDP, STMP nous avons constaté qu'elle reçoit correctement ces protocoles. Cependant lorsque que nous avons voulu modifier la LUFA pour qu'une LED en plus s'allume lorsque UDP contient protocole antique cela ne fonctionnait pas. La carte ne trouvait jamais le protocole Antique. La communication avec la carte mère (shield) n'a pas été faite par manque de temps (cependant la communication SPI est vérifiée à l'étape de l'ordonnanceur). Le serveur côté PC qui doit communiquer avec la carte réseau est fini et testé.&lt;br /&gt;
&lt;br /&gt;
Notre problème peut venir du fait que l'atmega32u4 n'a pas assez de mémoire. Il ne faut donc pas choisir ce micro contrôleur pour ce projet mais un avec plus de mémoire.&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2025-1&amp;diff=8698</id>
		<title>SE4Binome2025-1</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2025-1&amp;diff=8698"/>
		<updated>2026-01-04T16:41:23Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Shield Arduino =&lt;br /&gt;
== Hardware ==&lt;br /&gt;
Afin de tester notre futur carte réseau, nous avons fait un shield d'arduino qui prendra le rôle de la carte mère durant. &lt;br /&gt;
=== Schématique ===&lt;br /&gt;
Nous nous sommes évidemment aider de la datasheet de l'atmega328p ainsi que celle de l'arduino uno afin de sélectionner les bon pins.&lt;br /&gt;
[[Fichier:Atmel-7810-Automotive-Microcontrollers-ATmega328P Datasheet.pdf|centré|vignette|Datasheet ATmega328p]]&lt;br /&gt;
[[Fichier:A000066-datasheet.pdf|centré|vignette|Datasheet Arduino Uno R3]]&lt;br /&gt;
Plus précisément nous nous inspirons très fortement du schéma page 10 de la datasheet de l'arduino :&lt;br /&gt;
[[Fichier:Screenshot 2025-11-07 11-08-46.png|centré|vignette|Schéma pinouts]]&lt;br /&gt;
Nous sommes donc parti de l'exemple fourni par Mr Redon. Mais nous avons utilisé une template disponible dans kicad permettant de créer des shields d'arduino Uno R3.[[Fichier:Tyetyuy.png|vignette|Schématique shield arduino|centré|438x438px]]&lt;br /&gt;
=== Routage ===&lt;br /&gt;
Au niveau du routage, nous avons tenté de faire simple (sans trop abuser sur les vias. Nous avons positionner le lecteur de carte sd au bord de la carte afin de ne pas avoir de problèmes avec d'autres composants lorsque nous voudrons mettre ou enlever la carte sd.&lt;br /&gt;
[[Fichier:Routage shield arduino.png|vignette|Routage shield arduino|centré|434x434px]]&lt;br /&gt;
&lt;br /&gt;
===Soudage===&lt;br /&gt;
La schématique et le routage terminés, nous avons soudé les différents pins permettant de souder la carte shield à l'arduino, le reste n'étant pas forcément utile pour le moment (il est important de noter que notre shield est arrivé avec des composants pré-soudés).&lt;br /&gt;
[[Fichier:Shield soudage de base .jpg|centré|vignette]]&lt;br /&gt;
&lt;br /&gt;
===Tests===&lt;br /&gt;
====Leds====&lt;br /&gt;
&lt;br /&gt;
Il faudra ensuite faire des test d'allumage des leds, afin de vérifier le bon fonctionnement du shield&lt;br /&gt;
[[Fichier:VID leds.mp4|centré|vignette]]&lt;br /&gt;
&lt;br /&gt;
Les leds fonctionnent à merveille.&lt;br /&gt;
&lt;br /&gt;
====Carte SD====&lt;br /&gt;
&lt;br /&gt;
Nous vérifions maintenant la carte sd (même si elle nous sera inutile pour notre projet)&lt;br /&gt;
&lt;br /&gt;
Nous utilisons le programme fourni par arduino qui permet de récuopéré les informatiuons de la carte sd.&lt;br /&gt;
[[Fichier:Test sd card.png|centré|vignette]]&lt;br /&gt;
La carte SD est bien identifié, le lecteur de carte fonctionne donc normalement.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
=== Ordonnanceur ===&lt;br /&gt;
[à completer  et commenter , seulement des codes pour le moment !!!!]&lt;br /&gt;
==== Ordonnanceur basique ====&lt;br /&gt;
La première étape consiste à définir la structure d'un process, il sera composé :&lt;br /&gt;
&lt;br /&gt;
-d'un pointeur de pile&lt;br /&gt;
&lt;br /&gt;
-de l'adresse de la fonction&lt;br /&gt;
&lt;br /&gt;
-d'un temps de sommeil &lt;br /&gt;
&lt;br /&gt;
-d'un état : 0 pour en cours et 1 pour terminé ou vide&lt;br /&gt;
&lt;br /&gt;
Ces deux derniers points nous servirons plus tard.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
typedef struct {&lt;br /&gt;
	uint16_t stackPointer;&lt;br /&gt;
	void (*functionAddress)(void);&lt;br /&gt;
	int sleep_time;&lt;br /&gt;
	int state;&lt;br /&gt;
} process;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On initialise donc notre tableau de processus de la façon suivante : &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
process Tasks_list[NBTASKS] = {&lt;br /&gt;
                                {0, led1_blink, 0,0},&lt;br /&gt;
				...&lt;br /&gt;
			       };&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Concernant les fonction liés leds, on utilise une simple boucle while contenant un changement d'état &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void led_init() {&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
void led1_blink() {&lt;br /&gt;
	while(1) {&lt;br /&gt;
		PORTC ^= (1&amp;lt;&amp;lt;PLED1);&lt;br /&gt;
		_delay_ms(100);&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
void led2_blink() {&lt;br /&gt;
...	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_stackPointer_tasks() permet de diviser la pile &amp;quot;réel&amp;quot; en plusieurs piles pour chaque processus.  Ces sous piles commence à la position FIRST_STACK_POSITION, afin de ne pas réécrire par dessus des données. Toutes les sous piles diposent d'une même taille de pile STACK_LENGTH.&lt;br /&gt;
&lt;br /&gt;
La fonction init_piles() initialise correctement la pile avec le tableau de processus si le processus est actif.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void init_stackPointer_tasks(int Cprocess) { //initialise le pointer de pile&lt;br /&gt;
	if(Tasks_list[Cprocess].state == 0) {&lt;br /&gt;
		Tasks_list[Cprocess].stackPointer = FIRST_STACK_POSITION - (Cprocess * STACK_LENGTH);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void init_piles(int Cprocess){ //initilalise la pile&lt;br /&gt;
	if(Tasks_list[Cprocess].state == 0) {&lt;br /&gt;
		int save = SP;&lt;br /&gt;
		SP = Tasks_list[Cprocess].stackPointer;&lt;br /&gt;
		uint16_t address = (uint16_t)Tasks_list[Cprocess].functionAddress;&lt;br /&gt;
		asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (address &amp;amp; 0x00ff) );&lt;br /&gt;
		asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((address &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
		SAVE_REGISTERS();&lt;br /&gt;
		Tasks_list[Cprocess].stackPointer = SP;&lt;br /&gt;
		SP = save;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;le scheduler permet de passer à la tâche suivante&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
	Current_task++;&lt;br /&gt;
	if (Current_task &amp;gt;= NBTASKS) {&lt;br /&gt;
		Current_task = 0; &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;l'atmega328p ne dispose pas de de fonction en assembleur permettant de push ou de pop tout les registres. on doit donc le faire un par un.&lt;br /&gt;
&lt;br /&gt;
On défini alors les macros suivantes :  &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
#define SAVE_REGISTERS() \&lt;br /&gt;
	asm volatile ( \&lt;br /&gt;
		&amp;quot;push r0 	 \n\t&amp;quot; \&lt;br /&gt;
		...\&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#define RESTORE_REGISTERS() \&lt;br /&gt;
	asm volatile ( \&lt;br /&gt;
		&amp;quot;pop r31 	  \n\t&amp;quot; \&lt;br /&gt;
		...\&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;L'ISR gère les interruptions, en commençant par sauvegarder l'état de la pile ainsi que le stack pointeur propre au processus qui s'interrompt. L'appel au schedruler permet de changer de processus pour cela il faut restorer le stack pointer propre au nouveau processus actif et de la pile liée à ce processus. La dernière ligne arrête l'ISR.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED) {&lt;br /&gt;
	SAVE_REGISTERS();&lt;br /&gt;
	Tasks_list[Current_task].stackPointer = SP;&lt;br /&gt;
	scheduler();&lt;br /&gt;
	SP = Tasks_list[Current_task].stackPointer;&lt;br /&gt;
	RESTORE_REGISTERS();&lt;br /&gt;
	asm volatile(&amp;quot;reti&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=====test=====&lt;br /&gt;
Les processus de clignotement de leds ont tous un délai d'attente différent, l'interruption se produit toutes les millisecondes. On obtient ceci :[[Fichier:Ordonnanceur basique.mp4|centré|vignette]]Il est intéressant de remarqué que la vitesse à laquelle les leds changent d'état ne correspond pas au délai qui leur à été donné. Cela parait logique puisque l'interruption met la fonction _delay_ms en pause, ainsi la vitesse se voit divisé par le nombre de processus actif.&lt;br /&gt;
&lt;br /&gt;
====Ajout d'un système d'endormissement des processus====&lt;br /&gt;
&lt;br /&gt;
La fonction wait va permettre d'endormir un processus, elle va donné un temps de sommeil au processus puis lancer une interruption (car on veut changer de processus directement après que le précédent ait été endormi).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time) { // met un process en veille pour une durée donné&lt;br /&gt;
	// valeur max de time 32000 car int sur atmega328p code sur 16 bits donc 32000 max&lt;br /&gt;
	cli();&lt;br /&gt;
	Tasks_list[Current_task].sleep_time = time;&lt;br /&gt;
	TCNT1=0;&lt;br /&gt;
	sei();&lt;br /&gt;
	TIMER1_COMPA_vect();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour verifier si un processus a besoin d'être lancé, on ajoute une boucle while dans le scheduler afin de vérifier si il y a un temps de sommeil. Le scheduler va aussi servir à diminuer le temps de sommeil de tout les processus (avec un minimum de 0).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
	for (int i=0 ; i&amp;lt;NBTASKS ; i++) {&lt;br /&gt;
		if (Tasks_list[i].sleep_time - SLEEP_DEC &amp;lt; 0) {&lt;br /&gt;
			Tasks_list[i].sleep_time = 0;&lt;br /&gt;
		} else {&lt;br /&gt;
			Tasks_list[i].sleep_time -= SLEEP_DEC;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	do {&lt;br /&gt;
		Current_task++;&lt;br /&gt;
		if (Current_task &amp;gt;= NBTASKS) {&lt;br /&gt;
			Current_task = 0;&lt;br /&gt;
		}&lt;br /&gt;
	} while (Tasks_list[Current_task].sleep_time &amp;gt; 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Tableau dynamique des tâches====&lt;br /&gt;
&lt;br /&gt;
En premier lieu on va initialiser les état de tout les cases du tableau de processus. On choisit 1 la case est vide, 0 sinon.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void init_state() { //initialise state&lt;br /&gt;
	for (int i= 0; i&amp;lt;NBTASKS; i++) {&lt;br /&gt;
		if (Tasks_list[i].functionAddress == NULL) {&lt;br /&gt;
			Tasks_list[i].state = 1;&lt;br /&gt;
		}&lt;br /&gt;
		else {&lt;br /&gt;
			Tasks_list[i].state = 0;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Nous avons programmé deux fonction d'arrêt et une fonction d'ajout de processus :&lt;br /&gt;
&lt;br /&gt;
-finish stop le processus en cours et le supprime de tableau, puis lance une interruption&lt;br /&gt;
&lt;br /&gt;
-kill stop un processus donné et le supprime du tableau &lt;br /&gt;
&lt;br /&gt;
-add ajoute un processus sur la première case vide du tableau, initialise son pointeur de position et sa pile.&lt;br /&gt;
&lt;br /&gt;
Pour finish et kill, on met le temps de sommeil à 0 au cas où on arrête un processus endormi. C'est une mesure de sécurité pour finish, mais une obligation pour kill.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void finish() { //supprime un process lorsque celui-ci est terminé&lt;br /&gt;
	cli();&lt;br /&gt;
		Tasks_list[Current_task].state =1;&lt;br /&gt;
		Tasks_list[Current_task].sleep_time = 0;&lt;br /&gt;
		Tasks_list[Current_task].functionAddress = NULL;&lt;br /&gt;
	TCNT1=0; &lt;br /&gt;
	sei();&lt;br /&gt;
	TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void kill(void (*function)(void)) { //tue le process passé en paramètre&lt;br /&gt;
	cli();&lt;br /&gt;
	for(int i = 0; i&amp;lt;NBTASKS; i++) {&lt;br /&gt;
		if(Tasks_list[i].functionAddress == function) {&lt;br /&gt;
			Tasks_list[i].state =1;&lt;br /&gt;
			Tasks_list[i].sleep_time = 0;&lt;br /&gt;
			Tasks_list[i].functionAddress = NULL;&lt;br /&gt;
		}&lt;br /&gt;
	} &lt;br /&gt;
	sei();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void add(void (*newFunction)(void)) { //ajoute un process&lt;br /&gt;
	cli();&lt;br /&gt;
	int i =0;&lt;br /&gt;
	while(Tasks_list[i].state != 1) {&lt;br /&gt;
		i++;&lt;br /&gt;
	}&lt;br /&gt;
	Tasks_list[i].functionAddress = newFunction;&lt;br /&gt;
	Tasks_list[i].state = 0;&lt;br /&gt;
	init_stackPointer_tasks(i);&lt;br /&gt;
	init_piles(i);&lt;br /&gt;
&lt;br /&gt;
	sei();&lt;br /&gt;
	&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Il suffit maintenant de modifier le scheduler afin de ne pas prendre les processus terminé, puis utiliser add, finish et kill dans les fonctions choisis.&lt;br /&gt;
&lt;br /&gt;
=====test=====&lt;br /&gt;
Pour tester les fonction add et finish, on fait le test suivant :&lt;br /&gt;
&lt;br /&gt;
-on créer un process qui ajoute le process led2_blink (avec add) au bout d'un certain temps&lt;br /&gt;
&lt;br /&gt;
-le process led2_blink s'arrête (avec finish) au bout de 20 changement d'état (c'est à dire 10 clignotement).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
on obtient le résultat suivant :[[Fichier:Demo fonction add et finish.mp4|centré|vignette]]&lt;br /&gt;
====lecture et écriture sur le port série====&lt;br /&gt;
Afin de lire et écrire sur le port série, on utilise les fonctions USART_Init, USART_Transmit et USART_Receive  vu en cours de microP l'année précédente. Le but sera donc d'écrire le message qui vient d'être reçu, on utilise donc le processus suivant :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====test=====&lt;br /&gt;
Pour tester notre processus de communication, on utilise minicom.[[Fichier:Test lecture et écriture port série.mp4|centré|vignette]]On notera que si la période entre les interruptions est trop élevé, certains caractères ne seront pas lus.&lt;br /&gt;
&lt;br /&gt;
====afficheur 7 segments====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void seven_seg() {&lt;br /&gt;
	while (1) {&lt;br /&gt;
        spi_activer((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
		spi_echange(0x7E);&lt;br /&gt;
		spi_echange(0b1101111);&lt;br /&gt;
		spi_desactiver((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
&lt;br /&gt;
		wait(500);&lt;br /&gt;
&lt;br /&gt;
		spi_activer((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
		spi_echange(0x76);&lt;br /&gt;
		spi_desactiver((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
&lt;br /&gt;
		wait(500);&lt;br /&gt;
    	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Le processus seven_seg est ajouté au tableau des processus. Avant d'échanger en spi il faut activer la communication, et la désactiver après l'échange. La ligne 4 permet de sélectionner le 7 seg sur lequel on souhaite modifier l'affichage. La ligne 5 permet d'afficher le chiffre 9. Enfin la ligne 11 permet de clear le display. Voir tableau ci-dessous.&lt;br /&gt;
[[Fichier:Tab 7 seg sparkfun.png|centré|vignette]]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void) {                                 // Initialisation du bus SPI&lt;br /&gt;
	SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);   // Définition des sorties&lt;br /&gt;
	SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // Définition de l'entrée                          &lt;br /&gt;
	SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
        	                                             // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
	SPI_DDR |= (1&amp;lt;&amp;lt;CS1) | (1&amp;lt;&amp;lt;CS4);;&lt;br /&gt;
	DDRD |= (1&amp;lt;&amp;lt;CS5) | (1&amp;lt;&amp;lt;CS6);&lt;br /&gt;
	DDRC |= (1&amp;lt;&amp;lt;CS2) | (1&amp;lt;&amp;lt;CS3);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void spi_activer(uint16_t port, uint8_t cs) { 	// Activer le périphérique&lt;br /&gt;
	volatile uint8_t *reg = (volatile uint8_t*)port;&lt;br /&gt;
	*reg &amp;amp;= ~(1&amp;lt;&amp;lt;cs);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(uint16_t port, uint8_t cs) {                           // Désactiver le périphérique&lt;br /&gt;
	volatile uint8_t *reg = (volatile uint8_t*)port;&lt;br /&gt;
	*reg |= (1&amp;lt;&amp;lt;cs);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi) {                  // Communication sur le bus SPI&lt;br /&gt;
	SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
	while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
	return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de rendre nos fonctions les plus réutilisables possibles nous avons passer en paramètre le port ainsi que le CS qui correspond au slave select. Le type réel du port est volatile uint8* cependant le compilateur n'accepte que le uint16* ce qui explique le cast un peu étrange.&lt;br /&gt;
&lt;br /&gt;
=====Implémentation=====&lt;br /&gt;
[[Fichier:Video7segvideo.mp4|vignette|centré]]L'implémentation correspond à nos attentes, seul un 7 seg affiche le chiffre 9.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====choix du processus sur le port série====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
afin de pouvoir démontrer le bon fonctionnement de la partie dynamique, on décide de pouvoir ajouter et tuer des processus à partir des touches du clavier. On utilisera donc les fonction de l'USART défini plus au au travers de la fonction suivante:&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void call_process() {&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1) {&lt;br /&gt;
        data = USART_Receive();&lt;br /&gt;
        if(data == '1') {&lt;br /&gt;
            add(led1_blink);&lt;br /&gt;
        }&lt;br /&gt;
        ...&lt;br /&gt;
        else if(data == '6') {&lt;br /&gt;
            kill(led1_blink);&lt;br /&gt;
        }&lt;br /&gt;
        ...&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On remarquera que c'est une sorte d'amélioration de la fonction Serial_Message vu plus haut.&lt;br /&gt;
&lt;br /&gt;
Cette fonction aura la fonction de process de base, toujours présent dans l'ordonnaceur.&lt;br /&gt;
&lt;br /&gt;
=====Démonstation===== &lt;br /&gt;
[[Fichier:Process via USART.mp4|centré|vignette]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ici on lance les processus ledN_blink avec les touches 1 à 5 et on les tues avec les touches 6 à 0. Pour le 7 segments, on l'ajoute avec s et le tue avec d. &lt;br /&gt;
&lt;br /&gt;
=Carte Réseau=&lt;br /&gt;
Lors de la répartition des tâches, nous avons opté pour la carte réseau. &lt;br /&gt;
==Description==&lt;br /&gt;
Le sujet nous permettait de choisir parmi plusieurs microcontrôleurs. Nous avons retenu l’ATmega32U4, qui nous semble représenter un juste milieu entre l’ATmega16U2 et l’AT90USB.&lt;br /&gt;
==Hardware==&lt;br /&gt;
Notre carte intègre des LED permettant d’afficher différents états de communication (que nous définirons ultérieurement).&lt;br /&gt;
&lt;br /&gt;
À la demande de M. Redon, nous avons ajouté un MAX232 ainsi que des connecteurs DB9 et DB25. Nous espérons que ces éléments pourront être utiles.&lt;br /&gt;
&lt;br /&gt;
En dehors de ça, la carte reste assez basique car son composant principal reste l'ATmega.&lt;br /&gt;
===Schématque===&lt;br /&gt;
les broches PF n'étant pas utilisé, on les branches à un connecteur 6x1, notre carte pourra donc être utiliser pour d'autre projet si nécéssaire.&lt;br /&gt;
&lt;br /&gt;
On fait le choix d'utiliser 5 leds pour la connections, 1 led de power et 1 pour la connection ISP.[[Fichier:Schématique CReseau.png|vignette|540x540px|centré]]&lt;br /&gt;
===Routage===&lt;br /&gt;
[[Fichier:Routage Creseau.png|vignette|521x521px|centré]]Après avoir soudé les composants pricnipaux. il est temps de passer à la partie programmation de la carte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Programmation== &lt;br /&gt;
&lt;br /&gt;
Notre carte utilsant un USB, on va donc la faire passer pour une carte réseau en utilisant la demo RNDIS de la LUFA.&lt;br /&gt;
&lt;br /&gt;
Il est important de noter que nous avons choisi un Atmega32u4. Ainsi des modification devrons être apporté à la taille des paquets ethernet et sur le choix des protocoles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Protocoles impémentés=== &lt;br /&gt;
&lt;br /&gt;
La demo RNDISEthernet de la LUFA inclut les protocole suivant&lt;br /&gt;
&lt;br /&gt;
* ARP : Résolution d'adresses MAC.&lt;br /&gt;
* IP : Gestion des paquets IPv4.&lt;br /&gt;
* ICMP : Messages de contrôle (ping).&lt;br /&gt;
* TCP : Communication fiable (exemple : serveur TCP).&lt;br /&gt;
* UDP : Communication non fiable (exemple : serveur UDP).&lt;br /&gt;
* DHCP : Attribution dynamique d'adresse IP.&lt;br /&gt;
&lt;br /&gt;
Aussi, on remarquera que la démo utilise un modèle en quatre couche : Le modèle TCP/IP.&lt;br /&gt;
&lt;br /&gt;
le sujet nous propose trois possibilité :&lt;br /&gt;
&lt;br /&gt;
* viser Ethernet&lt;br /&gt;
* viser UDP&lt;br /&gt;
* viser TCP&lt;br /&gt;
&lt;br /&gt;
En regardant ce qui à été fait les années précédentes, on a remarqué que les groupes partaient principalement sur la première option. Nous nous avons décidé de viser UDP.&lt;br /&gt;
&lt;br /&gt;
Ainsi, afin de d'alléger notre code pour le faire rentrer dans notre carte, nous avons choisi de ne pas inclure le protocole TCP et de modifier la taille max de paquets ethernet à 400 octets.&lt;br /&gt;
&lt;br /&gt;
Il nous restera donc de l'espace pour recevoir des paquets Ethernet :&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
avr-size --mcu=atmega32u4 --format=avr RNDISEthernet.elf&lt;br /&gt;
AVR Memory Usage&lt;br /&gt;
----------------&lt;br /&gt;
Device: atmega32u4&lt;br /&gt;
&lt;br /&gt;
Program:    9434 bytes (28.8% Full)&lt;br /&gt;
(.text + .data + .bootloader)&lt;br /&gt;
&lt;br /&gt;
Data:       1037 bytes (40.5% Full)&lt;br /&gt;
(.data + .bss + .noinit)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Une fois la lufa réduite et flashé, on donne une adresse ip à notre inteface avec ip link eth2 up et  ip address add 10.0.0.1/24 dev eth2.  on test un ping sur l'adresse ip de la carte (10.0.0.2).[[Fichier:Ping creseau.mp4|centré|vignette]]&lt;br /&gt;
[[Fichier:Ping allume led.mov|vignette|centré]]Le premier test que nous décidons de faire, afin de vérifié notre comprehesion du code de la LUFA est de de faire clignioter si la carte reçoit un paquet ethernet, pour celà on ajoute l'allumage de la led dans la fonction EthernetTask du fichier principal ( RNDISEthernet.c) :[[Fichier:Ping allume led.mov|vignette|La led s'éteint à chaque ping reçue|centré]]&lt;br /&gt;
&lt;br /&gt;
===Création du protocole=== &lt;br /&gt;
&lt;br /&gt;
En plus de pouvoir communiquer, notre carte dois être capable d'effectuer 3 fonction.&lt;br /&gt;
&lt;br /&gt;
On décide de créer notre propre protocole ProtocolAntique décrit ci-dessous :  &lt;br /&gt;
&lt;br /&gt;
ProtocolAntique (256 octets) &lt;br /&gt;
&lt;br /&gt;
Entete du ProtocolAntique (3 octets)&lt;br /&gt;
&lt;br /&gt;
    operation (1 octet)&lt;br /&gt;
&lt;br /&gt;
    longueur (1 octet)&lt;br /&gt;
&lt;br /&gt;
    numero (1 octet)&lt;br /&gt;
&lt;br /&gt;
Contenu du ProtocolAntique (256 - 3 = 253 octets)&lt;br /&gt;
&lt;br /&gt;
Exemples :&lt;br /&gt;
&lt;br /&gt;
LS :&lt;br /&gt;
&lt;br /&gt;
    Carte reseau :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x01       // requete LS&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]     &lt;br /&gt;
&lt;br /&gt;
        -numero = 0             // la requete n'est pas fragmentée&lt;br /&gt;
&lt;br /&gt;
        -contenu                // chemin ou effectuer le ls&lt;br /&gt;
&lt;br /&gt;
    Serveur :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x11       // reponse au LS&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]&lt;br /&gt;
&lt;br /&gt;
        -numero = [0-255]       // entre 1 et 255 =&amp;gt; numero du paquet =&amp;gt; reponse fragmentée, si 0 dernier paquet&lt;br /&gt;
&lt;br /&gt;
        -contenu                // nom de fichier ou rien si numero = 0&lt;br /&gt;
&lt;br /&gt;
READ :&lt;br /&gt;
&lt;br /&gt;
    Carte reseau :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x02       // requete READ&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]&lt;br /&gt;
&lt;br /&gt;
        -numero = 0             // la requete n'est pas fragmentée&lt;br /&gt;
&lt;br /&gt;
        -contenu                // chemin/nom_fichier&lt;br /&gt;
&lt;br /&gt;
    Serveur :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x12       // reponse au READ&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]&lt;br /&gt;
&lt;br /&gt;
        -numero = [0-255]       // entre 1 et 255 =&amp;gt; numero du paquet =&amp;gt; reponse fragmentée, si 0 dernier paquet&lt;br /&gt;
&lt;br /&gt;
        -contenu                // contenu d'une ligne ou rien si numero = 0&lt;br /&gt;
&lt;br /&gt;
WRITE :&lt;br /&gt;
&lt;br /&gt;
    Carte reseau :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x03       // requete WRITE creation du fichier&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]&lt;br /&gt;
&lt;br /&gt;
        -numero = 0             // entre 1 et 255 =&amp;gt; numero du paquet =&amp;gt; reponse fragmentée, si 0 dernier paquet&lt;br /&gt;
&lt;br /&gt;
        -contenu                // Chemin pour ouvrir le fichier avce le nom du fichier : chemin/fichier&lt;br /&gt;
&lt;br /&gt;
    Carte reseau :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x13       // requete WRITE ecriture dans le fichier&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]&lt;br /&gt;
&lt;br /&gt;
        -numero = [1-252]       // entre 1 et 255 =&amp;gt; numero du paquet =&amp;gt; reponse fragmentée, si 0 dernier paquet&lt;br /&gt;
&lt;br /&gt;
        -contenu                // ligne a ecrire&lt;br /&gt;
&lt;br /&gt;
    Carte reseau :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x23       // requete WRITE fin&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]&lt;br /&gt;
&lt;br /&gt;
        -numero = 0             // 0 dernier paquet&lt;br /&gt;
&lt;br /&gt;
        -contenu                // rien&lt;br /&gt;
&lt;br /&gt;
Comme nous avons choisit de viser UDP, le protocole doit pocédé un numéro de port, on choisit un numéro supérieur à 1023 pour ne pas devoir passer en root, Le port choisi est 3333.&lt;br /&gt;
&lt;br /&gt;
Dans le programme UDP.c on peut maintenant inclure notre protocole de la façon suivante :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
        switch (SwapEndian_16(UDPHeaderIN-&amp;gt;DestinationPort))&lt;br /&gt;
        {&lt;br /&gt;
    /*&lt;br /&gt;
                case UDP_PORT_DHCP_REQUEST:&lt;br /&gt;
                        RetSize = DHCP_ProcessDHCPPacket(IPHeaderInStart,&lt;br /&gt;
                                                         &amp;amp;((uint8_t*)UDPHeaderInStart)[sizeof(UDP_Header_t)],&lt;br /&gt;
                                                     &amp;amp;((uint8_t*)UDPHeaderOutStart)[sizeof(UDP_Header_t)]);&lt;br /&gt;
                        break;&lt;br /&gt;
    */&lt;br /&gt;
                case UDP_PORT_PROTOCOL_ANTIQUE:       &lt;br /&gt;
                        RetSize = ProtocolAntique_ProcessProtocolAntiquePacket(IPHeaderInStart,&lt;br /&gt;
                                                         &amp;amp;((uint8_t*)UDPHeaderInStart)[sizeof(UDP_Header_t)],&lt;br /&gt;
                                                     &amp;amp;((uint8_t*)UDPHeaderOutStart)[sizeof(UDP_Header_t)]);&lt;br /&gt;
                        break;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Partie Application===&lt;br /&gt;
&lt;br /&gt;
(A compléter)&lt;br /&gt;
&lt;br /&gt;
Afin de tester la reception du paquet UDP, on fait à nouveau clignotter une led quand un paquet UDP et reçu (video)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Partie serveur ===&lt;br /&gt;
Lorsque la carte mère a besoin de faire une action (ls, read, write) sur l'ordinateur qui est connecté en USB via la carte réseau elle transmet son besoin à la carte réseau. Cette dernière créer un requête UDP qui encapsule notre protocole (ProtocolAntique) et la transmet donc au PC. Sur ce dernier un serveur doit donc fonctionner afin de recevoir les rêquetes de la carte réseau, les traiter et y répondre. Cette partie est donc consacrée au code ainsi qu'aux tests du serveur.&lt;br /&gt;
&lt;br /&gt;
==== Code du serveur ====&lt;br /&gt;
Pour pouvoir fonctionner correctement le serveur doit initialiser une socket UDP et ensuite doit lancer un fonctionne qui boucle indéfiniment afin de recevoir chaque message UDP. Cette partie n'a pas été codé par nous et est trouvable sur rex.plil.fr (Département IMA -&amp;gt; support de cours de la programmation réseau -&amp;gt; exemple de serveur 2/2). Il en est de même du code la fonction pour envoyer un message UDP qui est trouvable au même endroit section exemple de client 2/2.&lt;br /&gt;
&lt;br /&gt;
La carte réseau est toujours à l'initiative des requêtes, par conséquent le serveur commence par recevoir un requête et la traiter. Pour ce faire à chaque requête reçue par la fonction boucleServeurUDP la fonction traitementMessageUDP est appelée.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
int traitementMessageUDP (unsigned char* message, int nboctets);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Cette fonction s'occupe d'extraire la partie opération de l'entête de protocolAntique et d'appeler la fonction de traitement correspondante à l'opération&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Opération&lt;br /&gt;
!Requête&lt;br /&gt;
!Fonction appelée&lt;br /&gt;
|-&lt;br /&gt;
|0x01&lt;br /&gt;
|LS&lt;br /&gt;
|void traitement_ls (unsigned char*);&lt;br /&gt;
|-&lt;br /&gt;
|0x02&lt;br /&gt;
|READ&lt;br /&gt;
|void traitement_read (unsigned char*);&lt;br /&gt;
|-&lt;br /&gt;
|0x03&lt;br /&gt;
|WRITE (début)&lt;br /&gt;
|void traitement_write (unsigned char*);&lt;br /&gt;
|-&lt;br /&gt;
|0x13&lt;br /&gt;
|WRITE (données et fin)&lt;br /&gt;
|void traitement_write (unsigned char*);&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Traitement LS =====&lt;br /&gt;
La fonction traitement_ls commence par récupérer le chemin (relatif ou absolu) où effectuer le LS. Si la section longueur de l'entête de la requête est à 0 alors le chemin par défaut est celui depuis où le serveur à été lancé. Le code pour récupérer le chemin  est le suivant :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
unsigned char chemin[longueur+1];&lt;br /&gt;
for (int i=0 ; i&amp;lt;longueur ; i++) {&lt;br /&gt;
        chemin[i] = message[i+3]; // Recuperation du chemin&lt;br /&gt;
}&lt;br /&gt;
chemin[longueur] = '\0';&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Par la suite le dossier est correspondant au chemin est ouvert via la fonction opendir puis chaque entrée du dossier est récupérée et engendre un message de réponse du serveur (un message par entrée).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
while ((entree = readdir(dossier)) != NULL) {&lt;br /&gt;
   // Message UDP pour chaque entree&lt;br /&gt;
   strcpy(contenu, entree-&amp;gt;d_name);&lt;br /&gt;
   printf(&amp;quot;    %s  &amp;quot;, contenu);&lt;br /&gt;
   reponse[OPERATION] = REPONSE_LS;&lt;br /&gt;
   reponse[LONGUEUR] = strlen(contenu);&lt;br /&gt;
   reponse[NUMERO] = num++;&lt;br /&gt;
   for (int i=0 ; i&amp;lt;reponse[LONGUEUR] ; i++) {&lt;br /&gt;
      reponse[i+3] = contenu[i];&lt;br /&gt;
   }&lt;br /&gt;
   messageUDP(IP_CARTE, PORT_CARTE, (unsigned char *)reponse, (int)reponse[LONGUEUR] + LONGUEUR_ENTETE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;OPERATION est la premiére section et vaut donc 0, LONGUEUR 2 et NUMERO 3. OPERATION est une réponse à un LS donc 0x11, LONGUEUR dépend de l'entrée du dossier et NUMERO augmente de 1 à chaque entrée. Enfin on remplie la requête du nom de l'entrée et on envoie le message.&lt;br /&gt;
&lt;br /&gt;
Enfin une fois tous les entrées envoyées on envoie un dernier message UDP de type reponse_LS de longueur 0 et de numéro 0 afin d'indiquer que la transmission est terminée et ce correctement.&lt;br /&gt;
&lt;br /&gt;
===== Traitement READ =====&lt;br /&gt;
Cette requête est très proche de celle du LS. On commence par récupérer le chemin avec le nom du fichier de la même façon que pour le LS. Cependant ici si le message ne contient pas de chemin aucun traitement ne sera effectué. Pour ouvrir le fichier on utilise la fonction fopen. Chaque ligne, récupérée via fgets, engendre une réponse UDP formulée de la même façon que pour les entrées de dossier. Evidemment l'opération est de type réponse read soit 0x12. Enfin un message similaire de fin de transmission est envoyé seulement si il n'y a pas eu d'erreur et que la dernière ligne à été lue.&lt;br /&gt;
&lt;br /&gt;
===== Traitement WRITE =====&lt;br /&gt;
Cette requête est un peu plus complexe à gérer niveau serveur par conséquent que je vais commencer par décrire le principe de la fonction.&lt;br /&gt;
&lt;br /&gt;
* La carte réseau envoie un message de type début de write (OPERATION 0x03) avec le chemin et nom du fichier que le serveur va récupérer et mémoriser.&lt;br /&gt;
&lt;br /&gt;
* La carte réseau envoie un massage pour chaque ligne à écrite (OPERATION 0x13). Le serveur va vérifier si la section NUMERO des entêtes se suivent afin de s'assurer que aucun message n'est été perdu.&lt;br /&gt;
&lt;br /&gt;
* La carte réseau envoie un message de type fin de write (OPERATION 0x013) mais de numéro 0. Le serveur indique que tout s'est bien passé en envoyant une réponse au write (OPERATION 0x23) donc le contenu est 0x00.&lt;br /&gt;
* Si un message a été perdu un message d'erreur est envoyé de la par du serveur (OPERATION 0x23) de contenu 0x01.&lt;br /&gt;
&lt;br /&gt;
La récupération du contenu de la requête est du même type que celle du LS. Les messages de retour sont construits de la même façon que pour le message de retour du LS. Enfin on utilise fopen une nouvelle fois pour ouvrir le fichier, fwrite pour y écrire et fclose pour le fermer.&lt;br /&gt;
&lt;br /&gt;
==== Préparation du test ====&lt;br /&gt;
Avant de pouvoir tester notre serveur avec la carte réseau (ce qui n'aura jamais été fait car la carte réseau n'envoie rien) nous avons souhaité validé le fonctionnement du serveur en simulant des requêtes de la carte réseau. On voit ce que le serveur fait via des printf et en créant un autre serveur (plus rudimentaire) on peut vérifier que le serveur répond correctement. Sur notre git le dossier testUDP est consacré à cette phase de tests.&lt;br /&gt;
&lt;br /&gt;
* Les requêtes simulées de la carte réseau sont envoyées sur l'IP loopback de la machine et sur le port du serveur (ici 4242)&lt;br /&gt;
* Le serveur écoute le port serveur (4242) et répond en loopback sur le port du serveur qui simule la carte (ici 3333)&lt;br /&gt;
* Le serveur qui simule la carte écoute le port 3333&lt;br /&gt;
&lt;br /&gt;
On lance ces différents serveurs et les requêtes via les commandes du fichiers fonctionnement.txt de notre git.&lt;br /&gt;
&lt;br /&gt;
==== Tests ====&lt;br /&gt;
Le test est réalisé via 3 commandes :&lt;br /&gt;
&lt;br /&gt;
* LS sans chemin&lt;br /&gt;
* WRITE de 3 lignes dans un fichier test.txt créé par la commande&lt;br /&gt;
* READ du fichier test.txt&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Test1.png|centré|vignette|Requêtes envoyées]]&lt;br /&gt;
[[Fichier:Test2.png|centré|vignette|Traitement du serveur]]&lt;br /&gt;
[[Fichier:Test3.png|centré|vignette|Réponse reçu du serveur]]On peut constater que les tests fonctionnent. En effet le serveur a envoyé 9 res ls (8 entrées + fin de transmissions), 1 res write (fin d'écriture correcte) et 6 res read (5 lignes + 1 fin de transmissions).&lt;br /&gt;
&lt;br /&gt;
== Conclusion ==&lt;br /&gt;
La partie shield et ordonnanceur est finie et testée. La carte réseau n'a pas pu être finie par manque de temps. En faisant allumer une LED lorsqu'elle reçoit une trame Ethernet, UDP, STMP nous avons constaté qu'elle reçoit correctement ces protocoles. Cependant lorsque que nous avons voulu modifier la LUFA pour qu'une LED en plus s'allume lorsque UDP contient protocole antique cela ne fonctionnait pas. La carte ne trouvait jamais le protocole Antique. La communication avec la carte mère (shield) n'a pas été faite par manque de temps (cependant la communication SPI est vérifiée à l'étape de l'ordonnanceur). Le serveur côté PC qui doit communiquer avec la carte réseau est fini et testé.&lt;br /&gt;
&lt;br /&gt;
Notre problème peut venir du fait que l'atmega32u4 n'a pas assez de mémoire. Il ne faut donc pas choisir ce micro contrôleur pour ce projet mais un avec plus de mémoire.&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2025-1&amp;diff=8697</id>
		<title>SE4Binome2025-1</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2025-1&amp;diff=8697"/>
		<updated>2026-01-04T16:08:03Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Shield Arduino =&lt;br /&gt;
== Hardware ==&lt;br /&gt;
Afin de tester notre futur carte réseau, nous avons fait un shield d'arduino qui prendra le rôle de la carte mère durant. &lt;br /&gt;
=== Schématique ===&lt;br /&gt;
Nous nous sommes évidemment aider de la datasheet de l'atmega328p ainsi que celle de l'arduino uno afin de sélectionner les bon pins.&lt;br /&gt;
[[Fichier:Atmel-7810-Automotive-Microcontrollers-ATmega328P Datasheet.pdf|centré|vignette|Datasheet ATmega328p]]&lt;br /&gt;
[[Fichier:A000066-datasheet.pdf|centré|vignette|Datasheet Arduino Uno R3]]&lt;br /&gt;
Plus précisément nous nous inspirons très fortement du schéma page 10 de la datasheet de l'arduino :&lt;br /&gt;
[[Fichier:Screenshot 2025-11-07 11-08-46.png|centré|vignette|Schéma pinouts]]&lt;br /&gt;
Nous sommes donc parti de l'exemple fourni par Mr Redon. Mais nous avons utilisé une template disponible dans kicad permettant de créer des shields d'arduino Uno R3.[[Fichier:Tyetyuy.png|vignette|Schématique shield arduino|centré|438x438px]]&lt;br /&gt;
=== Routage ===&lt;br /&gt;
Au niveau du routage, nous avons tenté de faire simple (sans trop abuser sur les vias. Nous avons positionner le lecteur de carte sd au bord de la carte afin de ne pas avoir de problèmes avec d'autres composants lorsque nous voudrons mettre ou enlever la carte sd.&lt;br /&gt;
[[Fichier:Routage shield arduino.png|vignette|Routage shield arduino|centré|434x434px]]&lt;br /&gt;
&lt;br /&gt;
===Soudage===&lt;br /&gt;
La schématique et le routage terminés, nous avons soudé les différents pins permettant de souder la carte shield à l'arduino, le reste n'étant pas forcément utile pour le moment (il est important de noter que notre shield est arrivé avec des composants pré-soudés).&lt;br /&gt;
[[Fichier:Shield soudage de base .jpg|centré|vignette]]&lt;br /&gt;
&lt;br /&gt;
===Tests===&lt;br /&gt;
====Leds====&lt;br /&gt;
&lt;br /&gt;
Il faudra ensuite faire des test d'allumage des leds, afin de vérifier le bon fonctionnement du shield&lt;br /&gt;
[[Fichier:VID leds.mp4|centré|vignette]]&lt;br /&gt;
&lt;br /&gt;
Les leds fonctionnent à merveille.&lt;br /&gt;
&lt;br /&gt;
====Carte SD====&lt;br /&gt;
&lt;br /&gt;
Nous vérifions maintenant la carte sd (même si elle nous sera inutile pour notre projet)&lt;br /&gt;
&lt;br /&gt;
Nous utilisons le programme fourni par arduino qui permet de récuopéré les informatiuons de la carte sd.&lt;br /&gt;
[[Fichier:Test sd card.png|centré|vignette]]&lt;br /&gt;
La carte SD est bien identifié, le lecteur de carte fonctionne donc normalement.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
=== Ordonnanceur ===&lt;br /&gt;
[à completer  et commenter , seulement des codes pour le moment !!!!]&lt;br /&gt;
==== Ordonnanceur basique ====&lt;br /&gt;
La première étape consiste à définir la structure d'un process, il sera composé :&lt;br /&gt;
&lt;br /&gt;
-d'un pointeur de pile&lt;br /&gt;
&lt;br /&gt;
-de l'adresse de la fonction&lt;br /&gt;
&lt;br /&gt;
-d'un temps de sommeil &lt;br /&gt;
&lt;br /&gt;
-d'un état : 0 pour en cours et 1 pour terminé ou vide&lt;br /&gt;
&lt;br /&gt;
Ces deux derniers points nous servirons plus tard.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
typedef struct {&lt;br /&gt;
	uint16_t stackPointer;&lt;br /&gt;
	void (*functionAddress)(void);&lt;br /&gt;
	int sleep_time;&lt;br /&gt;
	int state;&lt;br /&gt;
} process;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On initialise donc notre tableau de processus de la façon suivante : &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
process Tasks_list[NBTASKS] = {&lt;br /&gt;
                                {0, led1_blink, 0,0},&lt;br /&gt;
				...&lt;br /&gt;
			       };&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Concernant les fonction liés leds, on utilise une simple boucle while contenant un changement d'état &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void led_init() {&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
void led1_blink() {&lt;br /&gt;
	while(1) {&lt;br /&gt;
		PORTC ^= (1&amp;lt;&amp;lt;PLED1);&lt;br /&gt;
		_delay_ms(100);&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
void led2_blink() {&lt;br /&gt;
...	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_stackPointer_tasks() permet de diviser la pile &amp;quot;réel&amp;quot; en plusieurs piles pour chaque processus.  Ces sous piles commence à la position FIRST_STACK_POSITION, afin de ne pas réécrire par dessus des données. Toutes les sous piles diposent d'une même taille de pile STACK_LENGTH.&lt;br /&gt;
&lt;br /&gt;
La fonction init_piles() initialise correctement la pile avec le tableau de processus si le processus est actif.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void init_stackPointer_tasks(int Cprocess) { //initialise le pointer de pile&lt;br /&gt;
	if(Tasks_list[Cprocess].state == 0) {&lt;br /&gt;
		Tasks_list[Cprocess].stackPointer = FIRST_STACK_POSITION - (Cprocess * STACK_LENGTH);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void init_piles(int Cprocess){ //initilalise la pile&lt;br /&gt;
	if(Tasks_list[Cprocess].state == 0) {&lt;br /&gt;
		int save = SP;&lt;br /&gt;
		SP = Tasks_list[Cprocess].stackPointer;&lt;br /&gt;
		uint16_t address = (uint16_t)Tasks_list[Cprocess].functionAddress;&lt;br /&gt;
		asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (address &amp;amp; 0x00ff) );&lt;br /&gt;
		asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((address &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
		SAVE_REGISTERS();&lt;br /&gt;
		Tasks_list[Cprocess].stackPointer = SP;&lt;br /&gt;
		SP = save;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;le scheduler permet de passer à la tâche suivante&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
	Current_task++;&lt;br /&gt;
	if (Current_task &amp;gt;= NBTASKS) {&lt;br /&gt;
		Current_task = 0; &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;l'atmega328p ne dispose pas de de fonction en assembleur permettant de push ou de pop tout les registres. on doit donc le faire un par un.&lt;br /&gt;
&lt;br /&gt;
On défini alors les macros suivantes :  &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
#define SAVE_REGISTERS() \&lt;br /&gt;
	asm volatile ( \&lt;br /&gt;
		&amp;quot;push r0 	 \n\t&amp;quot; \&lt;br /&gt;
		...\&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#define RESTORE_REGISTERS() \&lt;br /&gt;
	asm volatile ( \&lt;br /&gt;
		&amp;quot;pop r31 	  \n\t&amp;quot; \&lt;br /&gt;
		...\&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;L'ISR gère les interruptions, en commençant par sauvegarder l'état de la pile ainsi que le stack pointeur propre au processus qui s'interrompt. L'appel au schedruler permet de changer de processus pour cela il faut restorer le stack pointer propre au nouveau processus actif et de la pile liée à ce processus. La dernière ligne arrête l'ISR.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED) {&lt;br /&gt;
	SAVE_REGISTERS();&lt;br /&gt;
	Tasks_list[Current_task].stackPointer = SP;&lt;br /&gt;
	scheduler();&lt;br /&gt;
	SP = Tasks_list[Current_task].stackPointer;&lt;br /&gt;
	RESTORE_REGISTERS();&lt;br /&gt;
	asm volatile(&amp;quot;reti&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=====test=====&lt;br /&gt;
Les processus de clignotement de leds ont tous un délai d'attente différent, l'interruption se produit toutes les millisecondes. On obtient ceci :[[Fichier:Ordonnanceur basique.mp4|centré|vignette]]Il est intéressant de remarqué que la vitesse à laquelle les leds changent d'état ne correspond pas au délai qui leur à été donné. Cela parait logique puisque l'interruption met la fonction _delay_ms en pause, ainsi la vitesse se voit divisé par le nombre de processus actif.&lt;br /&gt;
&lt;br /&gt;
====Ajout d'un système d'endormissement des processus====&lt;br /&gt;
&lt;br /&gt;
La fonction wait va permettre d'endormir un processus, elle va donné un temps de sommeil au processus puis lancer une interruption (car on veut changer de processus directement après que le précédent ait été endormi).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time) { // met un process en veille pour une durée donné&lt;br /&gt;
	// valeur max de time 32000 car int sur atmega328p code sur 16 bits donc 32000 max&lt;br /&gt;
	cli();&lt;br /&gt;
	Tasks_list[Current_task].sleep_time = time;&lt;br /&gt;
	TCNT1=0;&lt;br /&gt;
	sei();&lt;br /&gt;
	TIMER1_COMPA_vect();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour verifier si un processus a besoin d'être lancé, on ajoute une boucle while dans le scheduler afin de vérifier si il y a un temps de sommeil. Le scheduler va aussi servir à diminuer le temps de sommeil de tout les processus (avec un minimum de 0).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
	for (int i=0 ; i&amp;lt;NBTASKS ; i++) {&lt;br /&gt;
		if (Tasks_list[i].sleep_time - SLEEP_DEC &amp;lt; 0) {&lt;br /&gt;
			Tasks_list[i].sleep_time = 0;&lt;br /&gt;
		} else {&lt;br /&gt;
			Tasks_list[i].sleep_time -= SLEEP_DEC;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	do {&lt;br /&gt;
		Current_task++;&lt;br /&gt;
		if (Current_task &amp;gt;= NBTASKS) {&lt;br /&gt;
			Current_task = 0;&lt;br /&gt;
		}&lt;br /&gt;
	} while (Tasks_list[Current_task].sleep_time &amp;gt; 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Tableau dynamique des tâches====&lt;br /&gt;
&lt;br /&gt;
En premier lieu on va initialiser les état de tout les cases du tableau de processus. On choisit 1 la case est vide, 0 sinon.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void init_state() { //initialise state&lt;br /&gt;
	for (int i= 0; i&amp;lt;NBTASKS; i++) {&lt;br /&gt;
		if (Tasks_list[i].functionAddress == NULL) {&lt;br /&gt;
			Tasks_list[i].state = 1;&lt;br /&gt;
		}&lt;br /&gt;
		else {&lt;br /&gt;
			Tasks_list[i].state = 0;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Nous avons programmé deux fonction d'arrêt et une fonction d'ajout de processus :&lt;br /&gt;
&lt;br /&gt;
-finish stop le processus en cours et le supprime de tableau, puis lance une interruption&lt;br /&gt;
&lt;br /&gt;
-kill stop un processus donné et le supprime du tableau &lt;br /&gt;
&lt;br /&gt;
-add ajoute un processus sur la première case vide du tableau, initialise son pointeur de position et sa pile.&lt;br /&gt;
&lt;br /&gt;
Pour finish et kill, on met le temps de sommeil à 0 au cas où on arrête un processus endormi. C'est une mesure de sécurité pour finish, mais une obligation pour kill.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void finish() { //supprime un process lorsque celui-ci est terminé&lt;br /&gt;
	cli();&lt;br /&gt;
		Tasks_list[Current_task].state =1;&lt;br /&gt;
		Tasks_list[Current_task].sleep_time = 0;&lt;br /&gt;
		Tasks_list[Current_task].functionAddress = NULL;&lt;br /&gt;
	TCNT1=0; &lt;br /&gt;
	sei();&lt;br /&gt;
	TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void kill(void (*function)(void)) { //tue le process passé en paramètre&lt;br /&gt;
	cli();&lt;br /&gt;
	for(int i = 0; i&amp;lt;NBTASKS; i++) {&lt;br /&gt;
		if(Tasks_list[i].functionAddress == function) {&lt;br /&gt;
			Tasks_list[i].state =1;&lt;br /&gt;
			Tasks_list[i].sleep_time = 0;&lt;br /&gt;
			Tasks_list[i].functionAddress = NULL;&lt;br /&gt;
		}&lt;br /&gt;
	} &lt;br /&gt;
	sei();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void add(void (*newFunction)(void)) { //ajoute un process&lt;br /&gt;
	cli();&lt;br /&gt;
	int i =0;&lt;br /&gt;
	while(Tasks_list[i].state != 1) {&lt;br /&gt;
		i++;&lt;br /&gt;
	}&lt;br /&gt;
	Tasks_list[i].functionAddress = newFunction;&lt;br /&gt;
	Tasks_list[i].state = 0;&lt;br /&gt;
	init_stackPointer_tasks(i);&lt;br /&gt;
	init_piles(i);&lt;br /&gt;
&lt;br /&gt;
	sei();&lt;br /&gt;
	&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Il suffit maintenant de modifier le scheduler afin de ne pas prendre les processus terminé, puis utiliser add, finish et kill dans les fonctions choisis.&lt;br /&gt;
&lt;br /&gt;
=====test=====&lt;br /&gt;
Pour tester les fonction add et finish, on fait le test suivant :&lt;br /&gt;
&lt;br /&gt;
-on créer un process qui ajoute le process led2_blink (avec add) au bout d'un certain temps&lt;br /&gt;
&lt;br /&gt;
-le process led2_blink s'arrête (avec finish) au bout de 20 changement d'état (c'est à dire 10 clignotement).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
on obtient le résultat suivant :[[Fichier:Demo fonction add et finish.mp4|centré|vignette]]&lt;br /&gt;
====lecture et écriture sur le port série====&lt;br /&gt;
Afin de lire et écrire sur le port série, on utilise les fonctions USART_Init, USART_Transmit et USART_Receive  vu en cours de microP l'année précédente. Le but sera donc d'écrire le message qui vient d'être reçu, on utilise donc le processus suivant :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====test=====&lt;br /&gt;
Pour tester notre processus de communication, on utilise minicom.[[Fichier:Test lecture et écriture port série.mp4|centré|vignette]]On notera que si la période entre les interruptions est trop élevé, certains caractères ne seront pas lus.&lt;br /&gt;
&lt;br /&gt;
====afficheur 7 segments====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void seven_seg() {&lt;br /&gt;
	while (1) {&lt;br /&gt;
        spi_activer((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
		spi_echange(0x7E);&lt;br /&gt;
		spi_echange(0b1101111);&lt;br /&gt;
		spi_desactiver((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
&lt;br /&gt;
		wait(500);&lt;br /&gt;
&lt;br /&gt;
		spi_activer((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
		spi_echange(0x76);&lt;br /&gt;
		spi_desactiver((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
&lt;br /&gt;
		wait(500);&lt;br /&gt;
    	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Le processus seven_seg est ajouté au tableau des processus. Avant d'échanger en spi il faut activer la communication, et la désactiver après l'échange. La ligne 4 permet de sélectionner le 7 seg sur lequel on souhaite modifier l'affichage. La ligne 5 permet d'afficher le chiffre 9. Enfin la ligne 11 permet de clear le display. Voir tableau ci-dessous.&lt;br /&gt;
[[Fichier:Tab 7 seg sparkfun.png|centré|vignette]]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void) {                                 // Initialisation du bus SPI&lt;br /&gt;
	SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);   // Définition des sorties&lt;br /&gt;
	SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // Définition de l'entrée                          &lt;br /&gt;
	SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
        	                                             // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
	SPI_DDR |= (1&amp;lt;&amp;lt;CS1) | (1&amp;lt;&amp;lt;CS4);;&lt;br /&gt;
	DDRD |= (1&amp;lt;&amp;lt;CS5) | (1&amp;lt;&amp;lt;CS6);&lt;br /&gt;
	DDRC |= (1&amp;lt;&amp;lt;CS2) | (1&amp;lt;&amp;lt;CS3);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void spi_activer(uint16_t port, uint8_t cs) { 	// Activer le périphérique&lt;br /&gt;
	volatile uint8_t *reg = (volatile uint8_t*)port;&lt;br /&gt;
	*reg &amp;amp;= ~(1&amp;lt;&amp;lt;cs);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(uint16_t port, uint8_t cs) {                           // Désactiver le périphérique&lt;br /&gt;
	volatile uint8_t *reg = (volatile uint8_t*)port;&lt;br /&gt;
	*reg |= (1&amp;lt;&amp;lt;cs);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi) {                  // Communication sur le bus SPI&lt;br /&gt;
	SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
	while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
	return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de rendre nos fonctions les plus réutilisables possibles nous avons passer en paramètre le port ainsi que le CS qui correspond au slave select. Le type réel du port est volatile uint8* cependant le compilateur n'accepte que le uint16* ce qui explique le cast un peu étrange.&lt;br /&gt;
&lt;br /&gt;
=====Implémentation=====&lt;br /&gt;
[[Fichier:Video7segvideo.mp4|vignette|centré]]L'implémentation correspond à nos attentes, seul un 7 seg affiche le chiffre 9.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====choix du processus sur le port série====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
afin de pouvoir démontrer le bon fonctionnement de la partie dynamique, on décide de pouvoir ajouter et tuer des processus à partir des touches du clavier. On utilisera donc les fonction de l'USART défini plus au au travers de la fonction suivante:&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void call_process() {&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1) {&lt;br /&gt;
        data = USART_Receive();&lt;br /&gt;
        if(data == '1') {&lt;br /&gt;
            add(led1_blink);&lt;br /&gt;
        }&lt;br /&gt;
        ...&lt;br /&gt;
        else if(data == '6') {&lt;br /&gt;
            kill(led1_blink);&lt;br /&gt;
        }&lt;br /&gt;
        ...&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On remarquera que c'est une sorte d'amélioration de la fonction Serial_Message vu plus haut.&lt;br /&gt;
&lt;br /&gt;
Cette fonction aura la fonction de process de base, toujours présent dans l'ordonnaceur.&lt;br /&gt;
&lt;br /&gt;
=====Démonstation===== &lt;br /&gt;
[[Fichier:Process via USART.mp4|centré|vignette]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ici on lance les processus ledN_blink avec les touches 1 à 5 et on les tues avec les touches 6 à 0. Pour le 7 segments, on l'ajoute avec s et le tue avec d. &lt;br /&gt;
&lt;br /&gt;
=Carte Réseau=&lt;br /&gt;
Lors de la répartition des tâches, nous avons opté pour la carte réseau. &lt;br /&gt;
==Description==&lt;br /&gt;
Le sujet nous permettait de choisir parmi plusieurs microcontrôleurs. Nous avons retenu l’ATmega32U4, qui nous semble représenter un juste milieu entre l’ATmega16U2 et l’AT90USB.&lt;br /&gt;
==Hardware==&lt;br /&gt;
Notre carte intègre des LED permettant d’afficher différents états de communication (que nous définirons ultérieurement).&lt;br /&gt;
&lt;br /&gt;
À la demande de M. Redon, nous avons ajouté un MAX232 ainsi que des connecteurs DB9 et DB25. Nous espérons que ces éléments pourront être utiles.&lt;br /&gt;
&lt;br /&gt;
En dehors de ça, la carte reste assez basique car son composant principal reste l'ATmega.&lt;br /&gt;
===Schématque===&lt;br /&gt;
les broches PF n'étant pas utilisé, on les branches à un connecteur 6x1, notre carte pourra donc être utiliser pour d'autre projet si nécéssaire.&lt;br /&gt;
&lt;br /&gt;
On fait le choix d'utiliser 5 leds pour la connections, 1 led de power et 1 pour la connection ISP.[[Fichier:Schématique CReseau.png|vignette|540x540px|centré]]&lt;br /&gt;
===Routage===&lt;br /&gt;
[[Fichier:Routage Creseau.png|vignette|521x521px|centré]]Après avoir soudé les composants pricnipaux. il est temps de passer à la partie programmation de la carte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Programmation== &lt;br /&gt;
&lt;br /&gt;
Notre carte utilsant un USB, on va donc la faire passer pour une carte réseau en utilisant la demo RNDIS de la LUFA.&lt;br /&gt;
&lt;br /&gt;
Il est important de noter que nous avons choisi un Atmega32u4. Ainsi des modification devrons être apporté à la taille des paquets ethernet et sur le choix des protocoles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Protocoles impémentés=== &lt;br /&gt;
&lt;br /&gt;
La demo RNDISEthernet de la LUFA inclut les protocole suivant&lt;br /&gt;
&lt;br /&gt;
* ARP : Résolution d'adresses MAC.&lt;br /&gt;
* IP : Gestion des paquets IPv4.&lt;br /&gt;
* ICMP : Messages de contrôle (ping).&lt;br /&gt;
* TCP : Communication fiable (exemple : serveur TCP).&lt;br /&gt;
* UDP : Communication non fiable (exemple : serveur UDP).&lt;br /&gt;
* DHCP : Attribution dynamique d'adresse IP.&lt;br /&gt;
&lt;br /&gt;
Aussi, on remarquera que la démo utilise un modèle en quatre couche : Le modèle TCP/IP.&lt;br /&gt;
&lt;br /&gt;
le sujet nous propose trois possibilité :&lt;br /&gt;
&lt;br /&gt;
* viser Ethernet&lt;br /&gt;
* viser UDP&lt;br /&gt;
* viser TCP&lt;br /&gt;
&lt;br /&gt;
En regardant ce qui à été fait les années précédentes, on a remarqué que les groupes partaient principalement sur la première option. Nous nous avons décidé de viser UDP.&lt;br /&gt;
&lt;br /&gt;
Ainsi, afin de d'alléger notre code pour le faire rentrer dans notre carte, nous avons choisi de ne pas inclure le protocole TCP et de modifier la taille max de paquets ethernet à 400 octets.&lt;br /&gt;
&lt;br /&gt;
Il nous restera donc de l'espace pour recevoir des paquets Ethernet :&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
avr-size --mcu=atmega32u4 --format=avr RNDISEthernet.elf&lt;br /&gt;
AVR Memory Usage&lt;br /&gt;
----------------&lt;br /&gt;
Device: atmega32u4&lt;br /&gt;
&lt;br /&gt;
Program:    9434 bytes (28.8% Full)&lt;br /&gt;
(.text + .data + .bootloader)&lt;br /&gt;
&lt;br /&gt;
Data:       1037 bytes (40.5% Full)&lt;br /&gt;
(.data + .bss + .noinit)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Une fois la lufa réduite et flashé, on donne une adresse ip à notre inteface avec ip link eth2 up et  ip address add 10.0.0.1/24 dev eth2.  on test un ping sur l'adresse ip de la carte (10.0.0.2).[[Fichier:Ping creseau.mp4|centré|vignette]]&lt;br /&gt;
[[Fichier:Ping allume led.mov|vignette|centré]]Le premier test que nous décidons de faire, afin de vérifié notre comprehesion du code de la LUFA est de de faire clignioter si la carte reçoit un paquet ethernet, pour celà on ajoute l'allumage de la led dans la fonction EthernetTask du fichier principal ( RNDISEthernet.c) :[[Fichier:Ping allume led.mov|vignette|La led s'éteint à chaque ping reçue|centré]]&lt;br /&gt;
&lt;br /&gt;
===Création du protocole=== &lt;br /&gt;
&lt;br /&gt;
En plus de pouvoir communiquer, notre carte dois être capable d'effectuer 3 fonction.&lt;br /&gt;
&lt;br /&gt;
On décide de créer notre propre protocole ProtocolAntique décrit ci-dessous :  &lt;br /&gt;
&lt;br /&gt;
ProtocolAntique (256 octets) &lt;br /&gt;
&lt;br /&gt;
Entete du ProtocolAntique (3 octets)&lt;br /&gt;
&lt;br /&gt;
    operation (1 octet)&lt;br /&gt;
&lt;br /&gt;
    longueur (1 octet)&lt;br /&gt;
&lt;br /&gt;
    numero (1 octet)&lt;br /&gt;
&lt;br /&gt;
Contenu du ProtocolAntique (256 - 3 = 253 octets)&lt;br /&gt;
&lt;br /&gt;
Exemples :&lt;br /&gt;
&lt;br /&gt;
LS :&lt;br /&gt;
&lt;br /&gt;
    Carte reseau :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x01       // requete LS&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]     &lt;br /&gt;
&lt;br /&gt;
        -numero = 0             // la requete n'est pas fragmentée&lt;br /&gt;
&lt;br /&gt;
        -contenu                // chemin ou effectuer le ls&lt;br /&gt;
&lt;br /&gt;
    Serveur :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x11       // reponse au LS&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]&lt;br /&gt;
&lt;br /&gt;
        -numero = [0-255]       // entre 1 et 255 =&amp;gt; numero du paquet =&amp;gt; reponse fragmentée, si 0 dernier paquet&lt;br /&gt;
&lt;br /&gt;
        -contenu                // nom de fichier ou rien si numero = 0&lt;br /&gt;
&lt;br /&gt;
READ :&lt;br /&gt;
&lt;br /&gt;
    Carte reseau :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x02       // requete READ&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]&lt;br /&gt;
&lt;br /&gt;
        -numero = 0             // la requete n'est pas fragmentée&lt;br /&gt;
&lt;br /&gt;
        -contenu                // chemin/nom_fichier&lt;br /&gt;
&lt;br /&gt;
    Serveur :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x12       // reponse au READ&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]&lt;br /&gt;
&lt;br /&gt;
        -numero = [0-255]       // entre 1 et 255 =&amp;gt; numero du paquet =&amp;gt; reponse fragmentée, si 0 dernier paquet&lt;br /&gt;
&lt;br /&gt;
        -contenu                // contenu d'une ligne ou rien si numero = 0&lt;br /&gt;
&lt;br /&gt;
WRITE :&lt;br /&gt;
&lt;br /&gt;
    Carte reseau :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x03       // requete WRITE creation du fichier&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]&lt;br /&gt;
&lt;br /&gt;
        -numero = 0             // entre 1 et 255 =&amp;gt; numero du paquet =&amp;gt; reponse fragmentée, si 0 dernier paquet&lt;br /&gt;
&lt;br /&gt;
        -contenu                // Chemin pour ouvrir le fichier avce le nom du fichier : chemin/fichier&lt;br /&gt;
&lt;br /&gt;
    Carte reseau :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x13       // requete WRITE ecriture dans le fichier&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]&lt;br /&gt;
&lt;br /&gt;
        -numero = [1-252]       // entre 1 et 255 =&amp;gt; numero du paquet =&amp;gt; reponse fragmentée, si 0 dernier paquet&lt;br /&gt;
&lt;br /&gt;
        -contenu                // ligne a ecrire&lt;br /&gt;
&lt;br /&gt;
    Carte reseau :&lt;br /&gt;
&lt;br /&gt;
        -operation = 0x23       // requete WRITE fin&lt;br /&gt;
&lt;br /&gt;
        -longueur = [0-252]&lt;br /&gt;
&lt;br /&gt;
        -numero = 0             // 0 dernier paquet&lt;br /&gt;
&lt;br /&gt;
        -contenu                // rien&lt;br /&gt;
&lt;br /&gt;
Comme nous avons choisit de viser UDP, le protocole doit pocédé un numéro de port, on choisit un numéro supérieur à 1023 pour ne pas devoir passer en root, Le port choisi est 3333.&lt;br /&gt;
&lt;br /&gt;
Dans le programme UDP.c on peut maintenant inclure notre protocole de la façon suivante :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
        switch (SwapEndian_16(UDPHeaderIN-&amp;gt;DestinationPort))&lt;br /&gt;
        {&lt;br /&gt;
    /*&lt;br /&gt;
                case UDP_PORT_DHCP_REQUEST:&lt;br /&gt;
                        RetSize = DHCP_ProcessDHCPPacket(IPHeaderInStart,&lt;br /&gt;
                                                         &amp;amp;((uint8_t*)UDPHeaderInStart)[sizeof(UDP_Header_t)],&lt;br /&gt;
                                                     &amp;amp;((uint8_t*)UDPHeaderOutStart)[sizeof(UDP_Header_t)]);&lt;br /&gt;
                        break;&lt;br /&gt;
    */&lt;br /&gt;
                case UDP_PORT_PROTOCOL_ANTIQUE:       &lt;br /&gt;
                        RetSize = ProtocolAntique_ProcessProtocolAntiquePacket(IPHeaderInStart,&lt;br /&gt;
                                                         &amp;amp;((uint8_t*)UDPHeaderInStart)[sizeof(UDP_Header_t)],&lt;br /&gt;
                                                     &amp;amp;((uint8_t*)UDPHeaderOutStart)[sizeof(UDP_Header_t)]);&lt;br /&gt;
                        break;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Partie Application===&lt;br /&gt;
&lt;br /&gt;
(A compléter)&lt;br /&gt;
&lt;br /&gt;
Afin de tester la reception du paquet UDP, on fait à nouveau clignotter une led quand un paquet UDP et reçu (video)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Partie serveur ===&lt;br /&gt;
Lorsque la carte mère a besoin de faire une action (ls, read, write) sur l'ordinateur qui est connecté en USB via la carte réseau elle transmet son besoin à la carte réseau. Cette dernière créer un requête UDP qui encapsule notre protocole (ProtocolAntique) et la transmet donc au PC. Sur ce dernier un serveur doit donc fonctionner afin de recevoir les rêquetes de la carte réseau, les traiter et y répondre. Cette partie est donc consacrée au code ainsi qu'aux tests du serveur.&lt;br /&gt;
&lt;br /&gt;
==== Code du serveur ====&lt;br /&gt;
Pour pouvoir fonctionner correctement le serveur doit initialiser une socket UDP et ensuite doit lancer un fonctionne qui boucle indéfiniment afin de recevoir chaque message UDP. Cette partie n'a pas été codé par nous et est trouvable sur rex.plil.fr (Département IMA -&amp;gt; support de cours de la programmation réseau -&amp;gt; exemple de serveur 2/2). Il en est de même du code la fonction pour envoyer un message UDP qui est trouvable au même endroit section exemple de client 2/2.&lt;br /&gt;
&lt;br /&gt;
La carte réseau est toujours à l'initiative des requêtes, par conséquent le serveur commence par recevoir un requête et la traiter. Pour ce faire à chaque requête reçue par la fonction boucleServeurUDP la fonction traitementMessageUDP est appelée.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
int traitementMessageUDP (unsigned char* message, int nboctets);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Cette fonction s'occupe d'extraire la partie opération de l'entête de protocolAntique et d'appeler la fonction de traitement correspondante à l'opération&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Opération&lt;br /&gt;
!Requête&lt;br /&gt;
!Fonction appelée&lt;br /&gt;
|-&lt;br /&gt;
|0x01&lt;br /&gt;
|LS&lt;br /&gt;
|void traitement_ls (unsigned char*);&lt;br /&gt;
|-&lt;br /&gt;
|0x02&lt;br /&gt;
|READ&lt;br /&gt;
|void traitement_read (unsigned char*);&lt;br /&gt;
|-&lt;br /&gt;
|0x03&lt;br /&gt;
|WRITE (début)&lt;br /&gt;
|void traitement_write (unsigned char*);&lt;br /&gt;
|-&lt;br /&gt;
|0x13&lt;br /&gt;
|WRITE (données et fin)&lt;br /&gt;
|void traitement_write (unsigned char*);&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Traitement LS =====&lt;br /&gt;
La fonction traitement_ls commence par récupérer le chemin (relatif ou absolu) où effectuer le LS. Si la section longueur de l'entête de la requête est à 0 alors le chemin par défaut est celui depuis où le serveur à été lancé. Le code pour récupérer le chemin  est le suivant :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
unsigned char chemin[longueur+1];&lt;br /&gt;
for (int i=0 ; i&amp;lt;longueur ; i++) {&lt;br /&gt;
        chemin[i] = message[i+3]; // Recuperation du chemin&lt;br /&gt;
}&lt;br /&gt;
chemin[longueur] = '\0';&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Par la suite le dossier est correspondant au chemin est ouvert via la fonction opendir puis chaque entrée du dossier est récupérée et engendre un message de réponse du serveur (un message par entrée).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
while ((entree = readdir(dossier)) != NULL) {&lt;br /&gt;
   // Message UDP pour chaque entree&lt;br /&gt;
   strcpy(contenu, entree-&amp;gt;d_name);&lt;br /&gt;
   printf(&amp;quot;    %s  &amp;quot;, contenu);&lt;br /&gt;
   reponse[OPERATION] = REPONSE_LS;&lt;br /&gt;
   reponse[LONGUEUR] = strlen(contenu);&lt;br /&gt;
   reponse[NUMERO] = num++;&lt;br /&gt;
   for (int i=0 ; i&amp;lt;reponse[LONGUEUR] ; i++) {&lt;br /&gt;
      reponse[i+3] = contenu[i];&lt;br /&gt;
   }&lt;br /&gt;
   messageUDP(IP_CARTE, PORT_CARTE, (unsigned char *)reponse, (int)reponse[LONGUEUR] + LONGUEUR_ENTETE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;OPERATION est la premiére section et vaut donc 0, LONGUEUR 2 et NUMERO 3. OPERATION est une réponse à un LS donc 0x11, LONGUEUR dépend de l'entrée du dossier et NUMERO augmente de 1 à chaque entrée. Enfin on remplie la requête du nom de l'entrée et on envoie le message.&lt;br /&gt;
&lt;br /&gt;
Enfin une fois tous les entrées envoyées on envoie un dernier message UDP de type reponse_LS de longueur 0 et de numéro 0 afin d'indiquer que la transmission est terminée et ce correctement.&lt;br /&gt;
&lt;br /&gt;
===== Traitement READ =====&lt;br /&gt;
Cette requête est très proche de celle du LS. On commence par récupérer le chemin avec le nom du fichier de la même façon que pour le LS. Cependant ici si le message ne contient pas de chemin aucun traitement ne sera effectué. Pour ouvrir le fichier on utilise la fonction fopen. Chaque ligne, récupérée via fgets, engendre une réponse UDP formulée de la même façon que pour les entrées de dossier. Evidemment l'opération est de type réponse read soit 0x12. Enfin un message similaire de fin de transmission est envoyé seulement si il n'y a pas eu d'erreur et que la dernière ligne à été lue.&lt;br /&gt;
&lt;br /&gt;
===== Traitement WRITE =====&lt;br /&gt;
Cette requête est un peu plus complexe à gérer niveau serveur par conséquent que je vais commencer par décrire le principe de la fonction.&lt;br /&gt;
&lt;br /&gt;
* La carte réseau envoie un message de type début de write (OPERATION 0x03) avec le chemin et nom du fichier que le serveur va récupérer et mémoriser.&lt;br /&gt;
&lt;br /&gt;
* La carte réseau envoie un massage pour chaque ligne à écrite (OPERATION 0x13). Le serveur va vérifier si la section NUMERO des entêtes se suivent afin de s'assurer que aucun message n'est été perdu.&lt;br /&gt;
&lt;br /&gt;
* La carte réseau envoie un message de type fin de write (OPERATION 0x013) mais de numéro 0. Le serveur indique que tout s'est bien passé en envoyant une réponse au write (OPERATION 0x23) donc le contenu est 0x00.&lt;br /&gt;
* Si un message a été perdu un message d'erreur est envoyé de la par du serveur (OPERATION 0x23) de contenu 0x01.&lt;br /&gt;
&lt;br /&gt;
La récupération du contenu de la requête est du même type que celle du LS. Les messages de retour sont construits de la même façon que pour le message de retour du LS. Enfin on utilise fopen une nouvelle fois pour ouvrir le fichier, fwrite pour y écrire et fclose pour le fermer.&lt;br /&gt;
&lt;br /&gt;
==== Préparation du test ====&lt;br /&gt;
Avant de pouvoir tester notre serveur avec la carte réseau (ce qui n'aura jamais été fait car la carte réseau n'envoie rien) nous avons souhaité validé le fonctionnement du serveur en simulant des requêtes de la carte réseau. On voit ce que le serveur fait via des printf et en créant un autre serveur (plus rudimentaire) on peut vérifier que le serveur répond correctement. Sur notre git le dossier testUDP est consacré à cette phase de tests.&lt;br /&gt;
&lt;br /&gt;
* Les requêtes simulées de la carte réseau sont envoyées sur l'IP loopback de la machine et sur le port du serveur (ici 4242)&lt;br /&gt;
* Le serveur écoute le port serveur (4242) et répond en loopback sur le port du serveur qui simule la carte (ici 3333)&lt;br /&gt;
* Le serveur qui simule la carte écoute le port 3333&lt;br /&gt;
&lt;br /&gt;
On lance ces différents serveurs et les requêtes via les commandes du fichiers fonctionnement.txt de notre git.&lt;br /&gt;
&lt;br /&gt;
==== Tests ====&lt;br /&gt;
Le test est réalisé via 3 commandes :&lt;br /&gt;
&lt;br /&gt;
* LS sans chemin&lt;br /&gt;
* WRITE de 3 lignes dans un fichier test.txt créé par la commande&lt;br /&gt;
* READ du fichier test.txt&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Test1.png|centré|vignette|Requêtes envoyées]]&lt;br /&gt;
[[Fichier:Test2.png|centré|vignette|Traitement du serveur]]&lt;br /&gt;
[[Fichier:Test3.png|centré|vignette|Réponse reçu du serveur]]On peut constater que les tests fonctionnent. En effet le serveur a envoyé 9 res ls (8 entrées + fin de transmissions), 1 res write (fin d'écriture correcte) et 6 res read (5 lignes + 1 fin de transmissions).&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2025-1&amp;diff=8695</id>
		<title>SE4Binome2025-1</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2025-1&amp;diff=8695"/>
		<updated>2026-01-04T16:00:22Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Shield Arduino =&lt;br /&gt;
== Hardware ==&lt;br /&gt;
Afin de tester notre futur carte réseau, nous avons fait un shield d'arduino qui prendra le rôle de la carte mère durant. &lt;br /&gt;
=== Schématique ===&lt;br /&gt;
Nous nous sommes évidemment aider de la datasheet de l'atmega328p ainsi que celle de l'arduino uno afin de sélectionner les bon pins.&lt;br /&gt;
[[Fichier:Atmel-7810-Automotive-Microcontrollers-ATmega328P Datasheet.pdf|centré|vignette|Datasheet ATmega328p]]&lt;br /&gt;
[[Fichier:A000066-datasheet.pdf|centré|vignette|Datasheet Arduino Uno R3]]&lt;br /&gt;
Plus précisément nous nous inspirons très fortement du schéma page 10 de la datasheet de l'arduino :&lt;br /&gt;
[[Fichier:Screenshot 2025-11-07 11-08-46.png|centré|vignette|Schéma pinouts]]&lt;br /&gt;
Nous sommes donc parti de l'exemple fourni par Mr Redon. Mais nous avons utilisé une template disponible dans kicad permettant de créer des shields d'arduino Uno R3.[[Fichier:Tyetyuy.png|vignette|Schématique shield arduino|centré|438x438px]]&lt;br /&gt;
=== Routage ===&lt;br /&gt;
Au niveau du routage, nous avons tenté de faire simple (sans trop abuser sur les vias. Nous avons positionner le lecteur de carte sd au bord de la carte afin de ne pas avoir de problèmes avec d'autres composants lorsque nous voudrons mettre ou enlever la carte sd.&lt;br /&gt;
[[Fichier:Routage shield arduino.png|vignette|Routage shield arduino|centré|434x434px]]&lt;br /&gt;
&lt;br /&gt;
===Soudage===&lt;br /&gt;
La schématique et le routage terminés, nous avons soudé les différents pins permettant de souder la carte shield à l'arduino, le reste n'étant pas forcément utile pour le moment (il est important de noter que notre shield est arrivé avec des composants pré-soudés).&lt;br /&gt;
[[Fichier:Shield soudage de base .jpg|centré|vignette]]&lt;br /&gt;
&lt;br /&gt;
===Tests===&lt;br /&gt;
====Leds====&lt;br /&gt;
&lt;br /&gt;
Il faudra ensuite faire des test d'allumage des leds, afin de vérifier le bon fonctionnement du shield&lt;br /&gt;
[[Fichier:VID leds.mp4|centré|vignette]]&lt;br /&gt;
&lt;br /&gt;
Les leds fonctionnent à merveille.&lt;br /&gt;
&lt;br /&gt;
====Carte SD====&lt;br /&gt;
&lt;br /&gt;
Nous vérifions maintenant la carte sd (même si elle nous sera inutile pour notre projet)&lt;br /&gt;
&lt;br /&gt;
Nous utilisons le programme fourni par arduino qui permet de récuopéré les informatiuons de la carte sd.&lt;br /&gt;
[[Fichier:Test sd card.png|centré|vignette]]&lt;br /&gt;
La carte SD est bien identifié, le lecteur de carte fonctionne donc normalement.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
=== Ordonnanceur ===&lt;br /&gt;
[à completer  et commenter , seulement des codes pour le moment !!!!]&lt;br /&gt;
==== Ordonnanceur basique ====&lt;br /&gt;
La première étape consiste à définir la structure d'un process, il sera composé :&lt;br /&gt;
&lt;br /&gt;
-d'un pointeur de pile&lt;br /&gt;
&lt;br /&gt;
-de l'adresse de la fonction&lt;br /&gt;
&lt;br /&gt;
-d'un temps de sommeil &lt;br /&gt;
&lt;br /&gt;
-d'un état : 0 pour en cours et 1 pour terminé ou vide&lt;br /&gt;
&lt;br /&gt;
Ces deux derniers points nous servirons plus tard.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
typedef struct {&lt;br /&gt;
	uint16_t stackPointer;&lt;br /&gt;
	void (*functionAddress)(void);&lt;br /&gt;
	int sleep_time;&lt;br /&gt;
	int state;&lt;br /&gt;
} process;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On initialise donc notre tableau de processus de la façon suivante : &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
process Tasks_list[NBTASKS] = {&lt;br /&gt;
                                {0, led1_blink, 0,0},&lt;br /&gt;
				...&lt;br /&gt;
			       };&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Concernant les fonction liés leds, on utilise une simple boucle while contenant un changement d'état &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void led_init() {&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
void led1_blink() {&lt;br /&gt;
	while(1) {&lt;br /&gt;
		PORTC ^= (1&amp;lt;&amp;lt;PLED1);&lt;br /&gt;
		_delay_ms(100);&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
void led2_blink() {&lt;br /&gt;
...	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_stackPointer_tasks() permet de diviser la pile &amp;quot;réel&amp;quot; en plusieurs piles pour chaque processus.  Ces sous piles commence à la position FIRST_STACK_POSITION, afin de ne pas réécrire par dessus des données. Toutes les sous piles diposent d'une même taille de pile STACK_LENGTH.&lt;br /&gt;
&lt;br /&gt;
La fonction init_piles() initialise correctement la pile avec le tableau de processus si le processus est actif.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void init_stackPointer_tasks(int Cprocess) { //initialise le pointer de pile&lt;br /&gt;
	if(Tasks_list[Cprocess].state == 0) {&lt;br /&gt;
		Tasks_list[Cprocess].stackPointer = FIRST_STACK_POSITION - (Cprocess * STACK_LENGTH);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void init_piles(int Cprocess){ //initilalise la pile&lt;br /&gt;
	if(Tasks_list[Cprocess].state == 0) {&lt;br /&gt;
		int save = SP;&lt;br /&gt;
		SP = Tasks_list[Cprocess].stackPointer;&lt;br /&gt;
		uint16_t address = (uint16_t)Tasks_list[Cprocess].functionAddress;&lt;br /&gt;
		asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (address &amp;amp; 0x00ff) );&lt;br /&gt;
		asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((address &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
		SAVE_REGISTERS();&lt;br /&gt;
		Tasks_list[Cprocess].stackPointer = SP;&lt;br /&gt;
		SP = save;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;le scheduler permet de passer à la tâche suivante&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
	Current_task++;&lt;br /&gt;
	if (Current_task &amp;gt;= NBTASKS) {&lt;br /&gt;
		Current_task = 0; &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;l'atmega328p ne dispose pas de de fonction en assembleur permettant de push ou de pop tout les registres. on doit donc le faire un par un.&lt;br /&gt;
&lt;br /&gt;
On défini alors les macros suivantes :  &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
#define SAVE_REGISTERS() \&lt;br /&gt;
	asm volatile ( \&lt;br /&gt;
		&amp;quot;push r0 	 \n\t&amp;quot; \&lt;br /&gt;
		...\&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#define RESTORE_REGISTERS() \&lt;br /&gt;
	asm volatile ( \&lt;br /&gt;
		&amp;quot;pop r31 	  \n\t&amp;quot; \&lt;br /&gt;
		...\&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;L'ISR gère les interruptions, en commençant par sauvegarder l'état de la pile ainsi que le stack pointeur propre au processus qui s'interrompt. L'appel au schedruler permet de changer de processus pour cela il faut restorer le stack pointer propre au nouveau processus actif et de la pile liée à ce processus. La dernière ligne arrête l'ISR.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED) {&lt;br /&gt;
	SAVE_REGISTERS();&lt;br /&gt;
	Tasks_list[Current_task].stackPointer = SP;&lt;br /&gt;
	scheduler();&lt;br /&gt;
	SP = Tasks_list[Current_task].stackPointer;&lt;br /&gt;
	RESTORE_REGISTERS();&lt;br /&gt;
	asm volatile(&amp;quot;reti&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=====test=====&lt;br /&gt;
Les processus de clignotement de leds ont tous un délai d'attente différent, l'interruption se produit toutes les millisecondes. On obtient ceci :[[Fichier:Ordonnanceur basique.mp4|centré|vignette]]Il est intéressant de remarqué que la vitesse à laquelle les leds changent d'état ne correspond pas au délai qui leur à été donné. Cela parait logique puisque l'interruption met la fonction _delay_ms en pause, ainsi la vitesse se voit divisé par le nombre de processus actif.&lt;br /&gt;
&lt;br /&gt;
====Ajout d'un système d'endormissement des processus====&lt;br /&gt;
&lt;br /&gt;
La fonction wait va permettre d'endormir un processus, elle va donné un temps de sommeil au processus puis lancer une interruption (car on veut changer de processus directement après que le précédent ait été endormi).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time) { // met un process en veille pour une durée donné&lt;br /&gt;
	// valeur max de time 32000 car int sur atmega328p code sur 16 bits donc 32000 max&lt;br /&gt;
	cli();&lt;br /&gt;
	Tasks_list[Current_task].sleep_time = time;&lt;br /&gt;
	TCNT1=0;&lt;br /&gt;
	sei();&lt;br /&gt;
	TIMER1_COMPA_vect();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour verifier si un processus a besoin d'être lancé, on ajoute une boucle while dans le scheduler afin de vérifier si il y a un temps de sommeil. Le scheduler va aussi servir à diminuer le temps de sommeil de tout les processus (avec un minimum de 0).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
	for (int i=0 ; i&amp;lt;NBTASKS ; i++) {&lt;br /&gt;
		if (Tasks_list[i].sleep_time - SLEEP_DEC &amp;lt; 0) {&lt;br /&gt;
			Tasks_list[i].sleep_time = 0;&lt;br /&gt;
		} else {&lt;br /&gt;
			Tasks_list[i].sleep_time -= SLEEP_DEC;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	do {&lt;br /&gt;
		Current_task++;&lt;br /&gt;
		if (Current_task &amp;gt;= NBTASKS) {&lt;br /&gt;
			Current_task = 0;&lt;br /&gt;
		}&lt;br /&gt;
	} while (Tasks_list[Current_task].sleep_time &amp;gt; 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Tableau dynamique des tâches====&lt;br /&gt;
&lt;br /&gt;
En premier lieu on va initialiser les état de tout les cases du tableau de processus. On choisit 1 la case est vide, 0 sinon.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void init_state() { //initialise state&lt;br /&gt;
	for (int i= 0; i&amp;lt;NBTASKS; i++) {&lt;br /&gt;
		if (Tasks_list[i].functionAddress == NULL) {&lt;br /&gt;
			Tasks_list[i].state = 1;&lt;br /&gt;
		}&lt;br /&gt;
		else {&lt;br /&gt;
			Tasks_list[i].state = 0;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Nous avons programmé deux fonction d'arrêt et une fonction d'ajout de processus :&lt;br /&gt;
&lt;br /&gt;
-finish stop le processus en cours et le supprime de tableau, puis lance une interruption&lt;br /&gt;
&lt;br /&gt;
-kill stop un processus donné et le supprime du tableau &lt;br /&gt;
&lt;br /&gt;
-add ajoute un processus sur la première case vide du tableau, initialise son pointeur de position et sa pile.&lt;br /&gt;
&lt;br /&gt;
Pour finish et kill, on met le temps de sommeil à 0 au cas où on arrête un processus endormi. C'est une mesure de sécurité pour finish, mais une obligation pour kill.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void finish() { //supprime un process lorsque celui-ci est terminé&lt;br /&gt;
	cli();&lt;br /&gt;
		Tasks_list[Current_task].state =1;&lt;br /&gt;
		Tasks_list[Current_task].sleep_time = 0;&lt;br /&gt;
		Tasks_list[Current_task].functionAddress = NULL;&lt;br /&gt;
	TCNT1=0; &lt;br /&gt;
	sei();&lt;br /&gt;
	TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void kill(void (*function)(void)) { //tue le process passé en paramètre&lt;br /&gt;
	cli();&lt;br /&gt;
	for(int i = 0; i&amp;lt;NBTASKS; i++) {&lt;br /&gt;
		if(Tasks_list[i].functionAddress == function) {&lt;br /&gt;
			Tasks_list[i].state =1;&lt;br /&gt;
			Tasks_list[i].sleep_time = 0;&lt;br /&gt;
			Tasks_list[i].functionAddress = NULL;&lt;br /&gt;
		}&lt;br /&gt;
	} &lt;br /&gt;
	sei();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void add(void (*newFunction)(void)) { //ajoute un process&lt;br /&gt;
	cli();&lt;br /&gt;
	int i =0;&lt;br /&gt;
	while(Tasks_list[i].state != 1) {&lt;br /&gt;
		i++;&lt;br /&gt;
	}&lt;br /&gt;
	Tasks_list[i].functionAddress = newFunction;&lt;br /&gt;
	Tasks_list[i].state = 0;&lt;br /&gt;
	init_stackPointer_tasks(i);&lt;br /&gt;
	init_piles(i);&lt;br /&gt;
&lt;br /&gt;
	sei();&lt;br /&gt;
	&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Il suffit maintenant de modifier le scheduler afin de ne pas prendre les processus terminé, puis utiliser add, finish et kill dans les fonctions choisis.&lt;br /&gt;
&lt;br /&gt;
=====test=====&lt;br /&gt;
Pour tester les fonction add et finish, on fait le test suivant :&lt;br /&gt;
&lt;br /&gt;
-on créer un process qui ajoute le process led2_blink (avec add) au bout d'un certain temps&lt;br /&gt;
&lt;br /&gt;
-le process led2_blink s'arrête (avec finish) au bout de 20 changement d'état (c'est à dire 10 clignotement).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
on obtient le résultat suivant :[[Fichier:Demo fonction add et finish.mp4|centré|vignette]]&lt;br /&gt;
====lecture et écriture sur le port série====&lt;br /&gt;
Afin de lire et écrire sur le port série, on utilise les fonctions USART_Init, USART_Transmit et USART_Receive  vu en cours de microP l'année précédente. Le but sera donc d'écrire le message qui vient d'être reçu, on utilise donc le processus suivant :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====test=====&lt;br /&gt;
Pour tester notre processus de communication, on utilise minicom.[[Fichier:Test lecture et écriture port série.mp4|centré|vignette]]On notera que si la période entre les interruptions est trop élevé, certains caractères ne seront pas lus.&lt;br /&gt;
&lt;br /&gt;
====afficheur 7 segments====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void seven_seg() {&lt;br /&gt;
	while (1) {&lt;br /&gt;
        spi_activer((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
		spi_echange(0x7E);&lt;br /&gt;
		spi_echange(0b1101111);&lt;br /&gt;
		spi_desactiver((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
&lt;br /&gt;
		wait(500);&lt;br /&gt;
&lt;br /&gt;
		spi_activer((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
		spi_echange(0x76);&lt;br /&gt;
		spi_desactiver((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
&lt;br /&gt;
		wait(500);&lt;br /&gt;
    	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Le processus seven_seg est ajouté au tableau des processus. Avant d'échanger en spi il faut activer la communication, et la désactiver après l'échange. La ligne 4 permet de sélectionner le 7 seg sur lequel on souhaite modifier l'affichage. La ligne 5 permet d'afficher le chiffre 9. Enfin la ligne 11 permet de clear le display. Voir tableau ci-dessous.&lt;br /&gt;
[[Fichier:Tab 7 seg sparkfun.png|centré|vignette]]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void) {                                 // Initialisation du bus SPI&lt;br /&gt;
	SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);   // Définition des sorties&lt;br /&gt;
	SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // Définition de l'entrée                          &lt;br /&gt;
	SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
        	                                             // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
	SPI_DDR |= (1&amp;lt;&amp;lt;CS1) | (1&amp;lt;&amp;lt;CS4);;&lt;br /&gt;
	DDRD |= (1&amp;lt;&amp;lt;CS5) | (1&amp;lt;&amp;lt;CS6);&lt;br /&gt;
	DDRC |= (1&amp;lt;&amp;lt;CS2) | (1&amp;lt;&amp;lt;CS3);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void spi_activer(uint16_t port, uint8_t cs) { 	// Activer le périphérique&lt;br /&gt;
	volatile uint8_t *reg = (volatile uint8_t*)port;&lt;br /&gt;
	*reg &amp;amp;= ~(1&amp;lt;&amp;lt;cs);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(uint16_t port, uint8_t cs) {                           // Désactiver le périphérique&lt;br /&gt;
	volatile uint8_t *reg = (volatile uint8_t*)port;&lt;br /&gt;
	*reg |= (1&amp;lt;&amp;lt;cs);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi) {                  // Communication sur le bus SPI&lt;br /&gt;
	SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
	while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
	return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de rendre nos fonctions les plus réutilisables possibles nous avons passer en paramètre le port ainsi que le CS qui correspond au slave select. Le type réel du port est volatile uint8* cependant le compilateur n'accepte que le uint16* ce qui explique le cast un peu étrange.&lt;br /&gt;
&lt;br /&gt;
=====Implémentation=====&lt;br /&gt;
[[Fichier:Video7segvideo.mp4|vignette|centré]]L'implémentation correspond à nos attentes, seul un 7 seg affiche le chiffre 9.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====choix du processus sur le port série====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
afin de pouvoir démontrer le bon fonctionnement de la partie dynamique, on décide de pouvoir ajouter et tuer des processus à partir des touches du clavier. On utilisera donc les fonction de l'USART défini plus au au travers de la fonction suivante:&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void call_process() {&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1) {&lt;br /&gt;
        data = USART_Receive();&lt;br /&gt;
        if(data == '1') {&lt;br /&gt;
            add(led1_blink);&lt;br /&gt;
        }&lt;br /&gt;
        ...&lt;br /&gt;
        else if(data == '6') {&lt;br /&gt;
            kill(led1_blink);&lt;br /&gt;
        }&lt;br /&gt;
        ...&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On remarquera que c'est une sorte d'amélioration de la fonction Serial_Message vu plus haut.&lt;br /&gt;
&lt;br /&gt;
Cette fonction aura la fonction de process de base, toujours présent dans l'ordonnaceur.&lt;br /&gt;
&lt;br /&gt;
=====Démonstation===== &lt;br /&gt;
[[Fichier:Process via USART.mp4|centré|vignette]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ici on lance les processus ledN_blink avec les touches 1 à 5 et on les tues avec les touches 6 à 0. Pour le 7 segments, on l'ajoute avec s et le tue avec d. &lt;br /&gt;
&lt;br /&gt;
=Carte Réseau=&lt;br /&gt;
Lors de la répartition des tâches, nous avons opté pour la carte réseau. &lt;br /&gt;
==Description==&lt;br /&gt;
Le sujet nous permettait de choisir parmi plusieurs microcontrôleurs. Nous avons retenu l’ATmega32U4, qui nous semble représenter un juste milieu entre l’ATmega16U2 et l’AT90USB.&lt;br /&gt;
==Hardware==&lt;br /&gt;
Notre carte intègre des LED permettant d’afficher différents états de communication (que nous définirons ultérieurement).&lt;br /&gt;
&lt;br /&gt;
À la demande de M. Redon, nous avons ajouté un MAX232 ainsi que des connecteurs DB9 et DB25. Nous espérons que ces éléments pourront être utiles.&lt;br /&gt;
&lt;br /&gt;
En dehors de ça, la carte reste assez basique car son composant principal reste l'ATmega.&lt;br /&gt;
===Schématque===&lt;br /&gt;
les broches PF n'étant pas utilisé, on les branches à un connecteur 6x1, notre carte pourra donc être utiliser pour d'autre projet si nécéssaire.&lt;br /&gt;
&lt;br /&gt;
On fait le choix d'utiliser 5 leds pour la connections, 1 led de power et 1 pour la connection ISP.[[Fichier:Schématique CReseau.png|vignette|540x540px|centré]]&lt;br /&gt;
===Routage===&lt;br /&gt;
[[Fichier:Routage Creseau.png|vignette|521x521px|centré]]Après avoir soudé les composants pricnipaux. il est temps de passer à la partie programmation de la carte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Programmation== &lt;br /&gt;
&lt;br /&gt;
Notre carte utilsant un USB, on va donc la faire passer pour une carte réseau en utilisant la demo RNDIS de la LUFA.&lt;br /&gt;
&lt;br /&gt;
Il est important de noter que nous avons choisi un Atmega32u4. Ainsi des modification devrons être apporté à la taille des paquets ethernet et sur le choix des protocoles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Protocoles impémentés=== &lt;br /&gt;
&lt;br /&gt;
La demo RNDISEthernet de la LUFA inclut les protocole suivant&lt;br /&gt;
&lt;br /&gt;
* ARP : Résolution d'adresses MAC.&lt;br /&gt;
* IP : Gestion des paquets IPv4.&lt;br /&gt;
* ICMP : Messages de contrôle (ping).&lt;br /&gt;
* TCP : Communication fiable (exemple : serveur TCP).&lt;br /&gt;
* UDP : Communication non fiable (exemple : serveur UDP).&lt;br /&gt;
* DHCP : Attribution dynamique d'adresse IP.&lt;br /&gt;
&lt;br /&gt;
Aussi, on remarquera que la démo utilise un modèle en quatre couche : Le modèle TCP/IP.&lt;br /&gt;
&lt;br /&gt;
le sujet nous propose trois possibilité :&lt;br /&gt;
&lt;br /&gt;
* viser Ethernet&lt;br /&gt;
* viser UDP&lt;br /&gt;
* viser TCP&lt;br /&gt;
&lt;br /&gt;
En regardant ce qui à été fait les années précédentes, on a remarqué que les groupes partaient principalement sur la première option. Nous nous avons décidé de viser UDP.&lt;br /&gt;
&lt;br /&gt;
Ainsi, afin de d'alléger notre code pour le faire rentrer dans notre carte, nous avons choisi de ne pas inclure le protocole TCP et de modifier la taille max de paquets ethernet à 400 octets.&lt;br /&gt;
&lt;br /&gt;
Il nous restera donc de l'espace pour recevoir des paquets Ethernet :&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
avr-size --mcu=atmega32u4 --format=avr RNDISEthernet.elf&lt;br /&gt;
AVR Memory Usage&lt;br /&gt;
----------------&lt;br /&gt;
Device: atmega32u4&lt;br /&gt;
&lt;br /&gt;
Program:    9434 bytes (28.8% Full)&lt;br /&gt;
(.text + .data + .bootloader)&lt;br /&gt;
&lt;br /&gt;
Data:       1037 bytes (40.5% Full)&lt;br /&gt;
(.data + .bss + .noinit)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Une fois la lufa réduite et flashé, on donne une adresse ip à notre inteface avec ip link eth2 up et  ip address add 10.0.0.1/24 dev eth2.  on test un ping sur l'adresse ip de la carte (10.0.0.2).[[Fichier:Ping creseau.mp4|centré|vignette]]&lt;br /&gt;
[[Fichier:Ping allume led.mov|vignette|centré]]Le premier test que nous décidons de faire, afin de vérifié notre comprehesion du code de la LUFA est de de faire clignioter si la carte reçoit un paquet ethernet, pour celà on ajoute l'allumage de la led dans la fonction EthernetTask du fichier principal ( RNDISEthernet.c) :[[Fichier:Ping allume led.mov|vignette|La led s'éteint à chaque ping reçue|centré]]&lt;br /&gt;
&lt;br /&gt;
===Création du protocole=== &lt;br /&gt;
&lt;br /&gt;
En plus de pouvoir communiquer, notre carte dois être capable d'effectuer 3 fonction.&lt;br /&gt;
&lt;br /&gt;
On décide donc de créer un protocole (nommé ProtocolAntique) dont l'un des octet va transporter le choix de la focntion, le modèle du protocole sera le suivant : &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
typedef struct {&lt;br /&gt;
    uint8_t operation; /* 0x01 ls, 0x02 send, 0x03 recieve */&lt;br /&gt;
    uint8_t longeur; &lt;br /&gt;
    uint8_t numero;&lt;br /&gt;
} ProtocolAntique_Header_t;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Comme nous avons choisit de viser UDP, le protocole doit pocédé un numéro de port, on choisit un numéro supérieur à 1023 pour ne pas devoir passer en root, Le port choisi est 3333.&lt;br /&gt;
&lt;br /&gt;
Dans le programme UDP.c on peut maintenant inclure notre protocole de la façon suivante :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
        switch (SwapEndian_16(UDPHeaderIN-&amp;gt;DestinationPort))&lt;br /&gt;
        {&lt;br /&gt;
    /*&lt;br /&gt;
                case UDP_PORT_DHCP_REQUEST:&lt;br /&gt;
                        RetSize = DHCP_ProcessDHCPPacket(IPHeaderInStart,&lt;br /&gt;
                                                         &amp;amp;((uint8_t*)UDPHeaderInStart)[sizeof(UDP_Header_t)],&lt;br /&gt;
                                                     &amp;amp;((uint8_t*)UDPHeaderOutStart)[sizeof(UDP_Header_t)]);&lt;br /&gt;
                        break;&lt;br /&gt;
    */&lt;br /&gt;
                case UDP_PORT_PROTOCOL_ANTIQUE:       &lt;br /&gt;
                        RetSize = ProtocolAntique_ProcessProtocolAntiquePacket(IPHeaderInStart,&lt;br /&gt;
                                                         &amp;amp;((uint8_t*)UDPHeaderInStart)[sizeof(UDP_Header_t)],&lt;br /&gt;
                                                     &amp;amp;((uint8_t*)UDPHeaderOutStart)[sizeof(UDP_Header_t)]);&lt;br /&gt;
                        break;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Partie Application===&lt;br /&gt;
&lt;br /&gt;
(A compléter)&lt;br /&gt;
&lt;br /&gt;
Afin de tester la reception du paquet UDP, on fait à nouveau clignotter une led quand un paquet UDP et reçu (video)&lt;br /&gt;
&lt;br /&gt;
=== Partie serveur ===&lt;br /&gt;
Lorsque la carte mère a besoin de faire une action (ls, read, write) sur l'ordinateur qui est connecté en USB via la carte réseau elle transmet son besoin à la carte réseau. Cette dernière créer un requête UDP qui encapsule notre protocole (ProtocolAntique) et la transmet donc au PC. Sur ce dernier un serveur doit donc fonctionner afin de recevoir les rêquetes de la carte réseau, les traiter et y répondre. Cette partie est donc consacrée au code ainsi qu'aux tests du serveur.&lt;br /&gt;
&lt;br /&gt;
==== Code du serveur ====&lt;br /&gt;
Pour pouvoir fonctionner correctement le serveur doit initialiser une socket UDP et ensuite doit lancer un fonctionne qui boucle indéfiniment afin de recevoir chaque message UDP. Cette partie n'a pas été codé par nous et est trouvable sur rex.plil.fr (Département IMA -&amp;gt; support de cours de la programmation réseau -&amp;gt; exemple de serveur 2/2). Il en est de même du code la fonction pour envoyer un message UDP qui est trouvable au même endroit section exemple de client 2/2.&lt;br /&gt;
&lt;br /&gt;
La carte réseau est toujours à l'initiative des requêtes, par conséquent le serveur commence par recevoir un requête et la traiter. Pour ce faire à chaque requête reçue par la fonction boucleServeurUDP la fonction traitementMessageUDP est appelée.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
int traitementMessageUDP (unsigned char* message, int nboctets);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Cette fonction s'occupe d'extraire la partie opération de l'entête de protocolAntique et d'appeler la fonction de traitement correspondante à l'opération&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Opération&lt;br /&gt;
!Requête&lt;br /&gt;
!Fonction appelée&lt;br /&gt;
|-&lt;br /&gt;
|0x01&lt;br /&gt;
|LS&lt;br /&gt;
|void traitement_ls (unsigned char*);&lt;br /&gt;
|-&lt;br /&gt;
|0x02&lt;br /&gt;
|READ&lt;br /&gt;
|void traitement_read (unsigned char*);&lt;br /&gt;
|-&lt;br /&gt;
|0x03&lt;br /&gt;
|WRITE (début)&lt;br /&gt;
|void traitement_write (unsigned char*);&lt;br /&gt;
|-&lt;br /&gt;
|0x13&lt;br /&gt;
|WRITE (données et fin)&lt;br /&gt;
|void traitement_write (unsigned char*);&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Traitement LS =====&lt;br /&gt;
La fonction traitement_ls commence par récupérer le chemin (relatif ou absolu) où effectuer le LS. Si la section longueur de l'entête de la requête est à 0 alors le chemin par défaut est celui depuis où le serveur à été lancé. Le code pour récupérer le chemin  est le suivant :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
unsigned char chemin[longueur+1];&lt;br /&gt;
for (int i=0 ; i&amp;lt;longueur ; i++) {&lt;br /&gt;
        chemin[i] = message[i+3]; // Recuperation du chemin&lt;br /&gt;
}&lt;br /&gt;
chemin[longueur] = '\0';&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Par la suite le dossier est correspondant au chemin est ouvert via la fonction opendir puis chaque entrée du dossier est récupérée et engendre un message de réponse du serveur (un message par entrée).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
while ((entree = readdir(dossier)) != NULL) {&lt;br /&gt;
   // Message UDP pour chaque entree&lt;br /&gt;
   strcpy(contenu, entree-&amp;gt;d_name);&lt;br /&gt;
   printf(&amp;quot;    %s  &amp;quot;, contenu);&lt;br /&gt;
   reponse[OPERATION] = REPONSE_LS;&lt;br /&gt;
   reponse[LONGUEUR] = strlen(contenu);&lt;br /&gt;
   reponse[NUMERO] = num++;&lt;br /&gt;
   for (int i=0 ; i&amp;lt;reponse[LONGUEUR] ; i++) {&lt;br /&gt;
      reponse[i+3] = contenu[i];&lt;br /&gt;
   }&lt;br /&gt;
   messageUDP(IP_CARTE, PORT_CARTE, (unsigned char *)reponse, (int)reponse[LONGUEUR] + LONGUEUR_ENTETE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;OPERATION est la premiére section et vaut donc 0, LONGUEUR 2 et NUMERO 3. OPERATION est une réponse à un LS donc 0x11, LONGUEUR dépend de l'entrée du dossier et NUMERO augmente de 1 à chaque entrée. Enfin on remplie la requête du nom de l'entrée et on envoie le message.&lt;br /&gt;
&lt;br /&gt;
Enfin une fois tous les entrées envoyées on envoie un dernier message UDP de type reponse_LS de longueur 0 et de numéro 0 afin d'indiquer que la transmission est terminée et ce correctement.&lt;br /&gt;
&lt;br /&gt;
===== Traitement READ =====&lt;br /&gt;
Cette requête est très proche de celle du LS. On commence par récupérer le chemin avec le nom du fichier de la même façon que pour le LS. Cependant ici si le message ne contient pas de chemin aucun traitement ne sera effectué. Pour ouvrir le fichier on utilise la fonction fopen. Chaque ligne, récupérée via fgets, engendre une réponse UDP formulée de la même façon que pour les entrées de dossier. Evidemment l'opération est de type réponse read soit 0x12. Enfin un message similaire de fin de transmission est envoyé seulement si il n'y a pas eu d'erreur et que la dernière ligne à été lue.&lt;br /&gt;
&lt;br /&gt;
===== Traitement WRITE =====&lt;br /&gt;
Cette requête est un peu plus complexe à gérer niveau serveur par conséquent que je vais commencer par décrire le principe de la fonction.&lt;br /&gt;
&lt;br /&gt;
* La carte réseau envoie un message de type début de write (OPERATION 0x03) avec le chemin et nom du fichier que le serveur va récupérer et mémoriser.&lt;br /&gt;
&lt;br /&gt;
* La carte réseau envoie un massage pour chaque ligne à écrite (OPERATION 0x13). Le serveur va vérifier si la section NUMERO des entêtes se suivent afin de s'assurer que aucun message n'est été perdu.&lt;br /&gt;
&lt;br /&gt;
* La carte réseau envoie un message de type fin de write (OPERATION 0x013) mais de numéro 0. Le serveur indique que tout s'est bien passé en envoyant une réponse au write (OPERATION 0x23) donc le contenu est 0x00.&lt;br /&gt;
* Si un message a été perdu un message d'erreur est envoyé de la par du serveur (OPERATION 0x23) de contenu 0x01.&lt;br /&gt;
&lt;br /&gt;
La récupération du contenu de la requête est du même type que celle du LS. Les messages de retour sont construits de la même façon que pour le message de retour du LS. Enfin on utilise fopen une nouvelle fois pour ouvrir le fichier, fwrite pour y écrire et fclose pour le fermer.&lt;br /&gt;
&lt;br /&gt;
==== Préparation du test ====&lt;br /&gt;
Avant de pouvoir tester notre serveur avec la carte réseau (ce qui n'aura jamais été fait car la carte réseau n'envoie rien) nous avons souhaité validé le fonctionnement du serveur en simulant des requêtes de la carte réseau. On voit ce que le serveur fait via des printf et en créant un autre serveur (plus rudimentaire) on peut vérifier que le serveur répond correctement. Sur notre git le dossier testUDP est consacré à cette phase de tests.&lt;br /&gt;
&lt;br /&gt;
* Les requêtes simulées de la carte réseau sont envoyées sur l'IP loopback de la machine et sur le port du serveur (ici 4242)&lt;br /&gt;
* Le serveur écoute le port serveur (4242) et répond en loopback sur le port du serveur qui simule la carte (ici 3333)&lt;br /&gt;
* Le serveur qui simule la carte écoute le port 3333&lt;br /&gt;
&lt;br /&gt;
On lance ces différents serveurs et les requêtes via les commandes du fichiers fonctionnement.txt de notre git.&lt;br /&gt;
&lt;br /&gt;
==== Tests ====&lt;br /&gt;
Le test est réalisé via 3 commandes :&lt;br /&gt;
&lt;br /&gt;
* LS sans chemin&lt;br /&gt;
* WRITE de 3 lignes dans un fichier test.txt créé par la commande&lt;br /&gt;
* READ du fichier test.txt&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Test1.png|centré|vignette|Requêtes envoyées]]&lt;br /&gt;
[[Fichier:Test2.png|centré|vignette|Traitement du serveur]]&lt;br /&gt;
[[Fichier:Test3.png|centré|vignette|Réponse reçu du serveur]]On peut constater que les tests fonctionnent. En effet le serveur a envoyé 9 res ls (8 entrées + fin de transmissions), 1 res write (fin d'écriture correcte) et 6 res read (5 lignes + 1 fin de transmissions).&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2025-1&amp;diff=8694</id>
		<title>SE4Binome2025-1</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2025-1&amp;diff=8694"/>
		<updated>2026-01-04T15:57:05Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Shield Arduino =&lt;br /&gt;
== Hardware ==&lt;br /&gt;
Afin de tester notre futur carte réseau, nous avons fait un shield d'arduino qui prendra le rôle de la carte mère durant. &lt;br /&gt;
=== Schématique ===&lt;br /&gt;
Nous nous sommes évidemment aider de la datasheet de l'atmega328p ainsi que celle de l'arduino uno afin de sélectionner les bon pins.&lt;br /&gt;
[[Fichier:Atmel-7810-Automotive-Microcontrollers-ATmega328P Datasheet.pdf|centré|vignette|Datasheet ATmega328p]]&lt;br /&gt;
[[Fichier:A000066-datasheet.pdf|centré|vignette|Datasheet Arduino Uno R3]]&lt;br /&gt;
Plus précisément nous nous inspirons très fortement du schéma page 10 de la datasheet de l'arduino :&lt;br /&gt;
[[Fichier:Screenshot 2025-11-07 11-08-46.png|centré|vignette|Schéma pinouts]]&lt;br /&gt;
Nous sommes donc parti de l'exemple fourni par Mr Redon. Mais nous avons utilisé une template disponible dans kicad permettant de créer des shields d'arduino Uno R3.[[Fichier:Tyetyuy.png|vignette|Schématique shield arduino|centré|438x438px]]&lt;br /&gt;
=== Routage ===&lt;br /&gt;
Au niveau du routage, nous avons tenté de faire simple (sans trop abuser sur les vias. Nous avons positionner le lecteur de carte sd au bord de la carte afin de ne pas avoir de problèmes avec d'autres composants lorsque nous voudrons mettre ou enlever la carte sd.&lt;br /&gt;
[[Fichier:Routage shield arduino.png|vignette|Routage shield arduino|centré|434x434px]]&lt;br /&gt;
&lt;br /&gt;
===Soudage===&lt;br /&gt;
La schématique et le routage terminés, nous avons soudé les différents pins permettant de souder la carte shield à l'arduino, le reste n'étant pas forcément utile pour le moment (il est important de noter que notre shield est arrivé avec des composants pré-soudés).&lt;br /&gt;
[[Fichier:Shield soudage de base .jpg|centré|vignette]]&lt;br /&gt;
&lt;br /&gt;
===Tests===&lt;br /&gt;
====Leds====&lt;br /&gt;
&lt;br /&gt;
Il faudra ensuite faire des test d'allumage des leds, afin de vérifier le bon fonctionnement du shield&lt;br /&gt;
[[Fichier:VID leds.mp4|centré|vignette]]&lt;br /&gt;
&lt;br /&gt;
Les leds fonctionnent à merveille.&lt;br /&gt;
&lt;br /&gt;
====Carte SD====&lt;br /&gt;
&lt;br /&gt;
Nous vérifions maintenant la carte sd (même si elle nous sera inutile pour notre projet)&lt;br /&gt;
&lt;br /&gt;
Nous utilisons le programme fourni par arduino qui permet de récuopéré les informatiuons de la carte sd.&lt;br /&gt;
[[Fichier:Test sd card.png|centré|vignette]]&lt;br /&gt;
La carte SD est bien identifié, le lecteur de carte fonctionne donc normalement.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
=== Ordonnanceur ===&lt;br /&gt;
[à completer  et commenter , seulement des codes pour le moment !!!!]&lt;br /&gt;
==== Ordonnanceur basique ====&lt;br /&gt;
La première étape consiste à définir la structure d'un process, il sera composé :&lt;br /&gt;
&lt;br /&gt;
-d'un pointeur de pile&lt;br /&gt;
&lt;br /&gt;
-de l'adresse de la fonction&lt;br /&gt;
&lt;br /&gt;
-d'un temps de sommeil &lt;br /&gt;
&lt;br /&gt;
-d'un état : 0 pour en cours et 1 pour terminé ou vide&lt;br /&gt;
&lt;br /&gt;
Ces deux derniers points nous servirons plus tard.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
typedef struct {&lt;br /&gt;
	uint16_t stackPointer;&lt;br /&gt;
	void (*functionAddress)(void);&lt;br /&gt;
	int sleep_time;&lt;br /&gt;
	int state;&lt;br /&gt;
} process;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On initialise donc notre tableau de processus de la façon suivante : &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
process Tasks_list[NBTASKS] = {&lt;br /&gt;
                                {0, led1_blink, 0,0},&lt;br /&gt;
				...&lt;br /&gt;
			       };&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Concernant les fonction liés leds, on utilise une simple boucle while contenant un changement d'état &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void led_init() {&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
void led1_blink() {&lt;br /&gt;
	while(1) {&lt;br /&gt;
		PORTC ^= (1&amp;lt;&amp;lt;PLED1);&lt;br /&gt;
		_delay_ms(100);&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
void led2_blink() {&lt;br /&gt;
...	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_stackPointer_tasks() permet de diviser la pile &amp;quot;réel&amp;quot; en plusieurs piles pour chaque processus.  Ces sous piles commence à la position FIRST_STACK_POSITION, afin de ne pas réécrire par dessus des données. Toutes les sous piles diposent d'une même taille de pile STACK_LENGTH.&lt;br /&gt;
&lt;br /&gt;
La fonction init_piles() initialise correctement la pile avec le tableau de processus si le processus est actif.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void init_stackPointer_tasks(int Cprocess) { //initialise le pointer de pile&lt;br /&gt;
	if(Tasks_list[Cprocess].state == 0) {&lt;br /&gt;
		Tasks_list[Cprocess].stackPointer = FIRST_STACK_POSITION - (Cprocess * STACK_LENGTH);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void init_piles(int Cprocess){ //initilalise la pile&lt;br /&gt;
	if(Tasks_list[Cprocess].state == 0) {&lt;br /&gt;
		int save = SP;&lt;br /&gt;
		SP = Tasks_list[Cprocess].stackPointer;&lt;br /&gt;
		uint16_t address = (uint16_t)Tasks_list[Cprocess].functionAddress;&lt;br /&gt;
		asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (address &amp;amp; 0x00ff) );&lt;br /&gt;
		asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((address &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
		SAVE_REGISTERS();&lt;br /&gt;
		Tasks_list[Cprocess].stackPointer = SP;&lt;br /&gt;
		SP = save;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;le scheduler permet de passer à la tâche suivante&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
	Current_task++;&lt;br /&gt;
	if (Current_task &amp;gt;= NBTASKS) {&lt;br /&gt;
		Current_task = 0; &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;l'atmega328p ne dispose pas de de fonction en assembleur permettant de push ou de pop tout les registres. on doit donc le faire un par un.&lt;br /&gt;
&lt;br /&gt;
On défini alors les macros suivantes :  &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
#define SAVE_REGISTERS() \&lt;br /&gt;
	asm volatile ( \&lt;br /&gt;
		&amp;quot;push r0 	 \n\t&amp;quot; \&lt;br /&gt;
		...\&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#define RESTORE_REGISTERS() \&lt;br /&gt;
	asm volatile ( \&lt;br /&gt;
		&amp;quot;pop r31 	  \n\t&amp;quot; \&lt;br /&gt;
		...\&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;L'ISR gère les interruptions, en commençant par sauvegarder l'état de la pile ainsi que le stack pointeur propre au processus qui s'interrompt. L'appel au schedruler permet de changer de processus pour cela il faut restorer le stack pointer propre au nouveau processus actif et de la pile liée à ce processus. La dernière ligne arrête l'ISR.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED) {&lt;br /&gt;
	SAVE_REGISTERS();&lt;br /&gt;
	Tasks_list[Current_task].stackPointer = SP;&lt;br /&gt;
	scheduler();&lt;br /&gt;
	SP = Tasks_list[Current_task].stackPointer;&lt;br /&gt;
	RESTORE_REGISTERS();&lt;br /&gt;
	asm volatile(&amp;quot;reti&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=====test=====&lt;br /&gt;
Les processus de clignotement de leds ont tous un délai d'attente différent, l'interruption se produit toutes les millisecondes. On obtient ceci :[[Fichier:Ordonnanceur basique.mp4|centré|vignette]]Il est intéressant de remarqué que la vitesse à laquelle les leds changent d'état ne correspond pas au délai qui leur à été donné. Cela parait logique puisque l'interruption met la fonction _delay_ms en pause, ainsi la vitesse se voit divisé par le nombre de processus actif.&lt;br /&gt;
&lt;br /&gt;
====Ajout d'un système d'endormissement des processus====&lt;br /&gt;
&lt;br /&gt;
La fonction wait va permettre d'endormir un processus, elle va donné un temps de sommeil au processus puis lancer une interruption (car on veut changer de processus directement après que le précédent ait été endormi).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time) { // met un process en veille pour une durée donné&lt;br /&gt;
	// valeur max de time 32000 car int sur atmega328p code sur 16 bits donc 32000 max&lt;br /&gt;
	cli();&lt;br /&gt;
	Tasks_list[Current_task].sleep_time = time;&lt;br /&gt;
	TCNT1=0;&lt;br /&gt;
	sei();&lt;br /&gt;
	TIMER1_COMPA_vect();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour verifier si un processus a besoin d'être lancé, on ajoute une boucle while dans le scheduler afin de vérifier si il y a un temps de sommeil. Le scheduler va aussi servir à diminuer le temps de sommeil de tout les processus (avec un minimum de 0).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
	for (int i=0 ; i&amp;lt;NBTASKS ; i++) {&lt;br /&gt;
		if (Tasks_list[i].sleep_time - SLEEP_DEC &amp;lt; 0) {&lt;br /&gt;
			Tasks_list[i].sleep_time = 0;&lt;br /&gt;
		} else {&lt;br /&gt;
			Tasks_list[i].sleep_time -= SLEEP_DEC;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	do {&lt;br /&gt;
		Current_task++;&lt;br /&gt;
		if (Current_task &amp;gt;= NBTASKS) {&lt;br /&gt;
			Current_task = 0;&lt;br /&gt;
		}&lt;br /&gt;
	} while (Tasks_list[Current_task].sleep_time &amp;gt; 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Tableau dynamique des tâches====&lt;br /&gt;
&lt;br /&gt;
En premier lieu on va initialiser les état de tout les cases du tableau de processus. On choisit 1 la case est vide, 0 sinon.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void init_state() { //initialise state&lt;br /&gt;
	for (int i= 0; i&amp;lt;NBTASKS; i++) {&lt;br /&gt;
		if (Tasks_list[i].functionAddress == NULL) {&lt;br /&gt;
			Tasks_list[i].state = 1;&lt;br /&gt;
		}&lt;br /&gt;
		else {&lt;br /&gt;
			Tasks_list[i].state = 0;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Nous avons programmé deux fonction d'arrêt et une fonction d'ajout de processus :&lt;br /&gt;
&lt;br /&gt;
-finish stop le processus en cours et le supprime de tableau, puis lance une interruption&lt;br /&gt;
&lt;br /&gt;
-kill stop un processus donné et le supprime du tableau &lt;br /&gt;
&lt;br /&gt;
-add ajoute un processus sur la première case vide du tableau, initialise son pointeur de position et sa pile.&lt;br /&gt;
&lt;br /&gt;
Pour finish et kill, on met le temps de sommeil à 0 au cas où on arrête un processus endormi. C'est une mesure de sécurité pour finish, mais une obligation pour kill.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void finish() { //supprime un process lorsque celui-ci est terminé&lt;br /&gt;
	cli();&lt;br /&gt;
		Tasks_list[Current_task].state =1;&lt;br /&gt;
		Tasks_list[Current_task].sleep_time = 0;&lt;br /&gt;
		Tasks_list[Current_task].functionAddress = NULL;&lt;br /&gt;
	TCNT1=0; &lt;br /&gt;
	sei();&lt;br /&gt;
	TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void kill(void (*function)(void)) { //tue le process passé en paramètre&lt;br /&gt;
	cli();&lt;br /&gt;
	for(int i = 0; i&amp;lt;NBTASKS; i++) {&lt;br /&gt;
		if(Tasks_list[i].functionAddress == function) {&lt;br /&gt;
			Tasks_list[i].state =1;&lt;br /&gt;
			Tasks_list[i].sleep_time = 0;&lt;br /&gt;
			Tasks_list[i].functionAddress = NULL;&lt;br /&gt;
		}&lt;br /&gt;
	} &lt;br /&gt;
	sei();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void add(void (*newFunction)(void)) { //ajoute un process&lt;br /&gt;
	cli();&lt;br /&gt;
	int i =0;&lt;br /&gt;
	while(Tasks_list[i].state != 1) {&lt;br /&gt;
		i++;&lt;br /&gt;
	}&lt;br /&gt;
	Tasks_list[i].functionAddress = newFunction;&lt;br /&gt;
	Tasks_list[i].state = 0;&lt;br /&gt;
	init_stackPointer_tasks(i);&lt;br /&gt;
	init_piles(i);&lt;br /&gt;
&lt;br /&gt;
	sei();&lt;br /&gt;
	&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Il suffit maintenant de modifier le scheduler afin de ne pas prendre les processus terminé, puis utiliser add, finish et kill dans les fonctions choisis.&lt;br /&gt;
&lt;br /&gt;
=====test=====&lt;br /&gt;
Pour tester les fonction add et finish, on fait le test suivant :&lt;br /&gt;
&lt;br /&gt;
-on créer un process qui ajoute le process led2_blink (avec add) au bout d'un certain temps&lt;br /&gt;
&lt;br /&gt;
-le process led2_blink s'arrête (avec finish) au bout de 20 changement d'état (c'est à dire 10 clignotement).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
on obtient le résultat suivant :[[Fichier:Demo fonction add et finish.mp4|centré|vignette]]&lt;br /&gt;
====lecture et écriture sur le port série====&lt;br /&gt;
Afin de lire et écrire sur le port série, on utilise les fonctions USART_Init, USART_Transmit et USART_Receive  vu en cours de microP l'année précédente. Le but sera donc d'écrire le message qui vient d'être reçu, on utilise donc le processus suivant :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====test=====&lt;br /&gt;
Pour tester notre processus de communication, on utilise minicom.[[Fichier:Test lecture et écriture port série.mp4|centré|vignette]]On notera que si la période entre les interruptions est trop élevé, certains caractères ne seront pas lus.&lt;br /&gt;
&lt;br /&gt;
====afficheur 7 segments====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void seven_seg() {&lt;br /&gt;
	while (1) {&lt;br /&gt;
        spi_activer((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
		spi_echange(0x7E);&lt;br /&gt;
		spi_echange(0b1101111);&lt;br /&gt;
		spi_desactiver((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
&lt;br /&gt;
		wait(500);&lt;br /&gt;
&lt;br /&gt;
		spi_activer((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
		spi_echange(0x76);&lt;br /&gt;
		spi_desactiver((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
&lt;br /&gt;
		wait(500);&lt;br /&gt;
    	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Le processus seven_seg est ajouté au tableau des processus. Avant d'échanger en spi il faut activer la communication, et la désactiver après l'échange. La ligne 4 permet de sélectionner le 7 seg sur lequel on souhaite modifier l'affichage. La ligne 5 permet d'afficher le chiffre 9. Enfin la ligne 11 permet de clear le display. Voir tableau ci-dessous.&lt;br /&gt;
[[Fichier:Tab 7 seg sparkfun.png|centré|vignette]]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void) {                                 // Initialisation du bus SPI&lt;br /&gt;
	SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);   // Définition des sorties&lt;br /&gt;
	SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // Définition de l'entrée                          &lt;br /&gt;
	SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
        	                                             // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
	SPI_DDR |= (1&amp;lt;&amp;lt;CS1) | (1&amp;lt;&amp;lt;CS4);;&lt;br /&gt;
	DDRD |= (1&amp;lt;&amp;lt;CS5) | (1&amp;lt;&amp;lt;CS6);&lt;br /&gt;
	DDRC |= (1&amp;lt;&amp;lt;CS2) | (1&amp;lt;&amp;lt;CS3);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void spi_activer(uint16_t port, uint8_t cs) { 	// Activer le périphérique&lt;br /&gt;
	volatile uint8_t *reg = (volatile uint8_t*)port;&lt;br /&gt;
	*reg &amp;amp;= ~(1&amp;lt;&amp;lt;cs);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(uint16_t port, uint8_t cs) {                           // Désactiver le périphérique&lt;br /&gt;
	volatile uint8_t *reg = (volatile uint8_t*)port;&lt;br /&gt;
	*reg |= (1&amp;lt;&amp;lt;cs);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi) {                  // Communication sur le bus SPI&lt;br /&gt;
	SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
	while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
	return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de rendre nos fonctions les plus réutilisables possibles nous avons passer en paramètre le port ainsi que le CS qui correspond au slave select. Le type réel du port est volatile uint8* cependant le compilateur n'accepte que le uint16* ce qui explique le cast un peu étrange.&lt;br /&gt;
&lt;br /&gt;
=====Implémentation=====&lt;br /&gt;
[[Fichier:Video7segvideo.mp4|vignette|centré]]L'implémentation correspond à nos attentes, seul un 7 seg affiche le chiffre 9.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====choix du processus sur le port série====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
afin de pouvoir démontrer le bon fonctionnement de la partie dynamique, on décide de pouvoir ajouter et tuer des processus à partir des touches du clavier. On utilisera donc les fonction de l'USART défini plus au au travers de la fonction suivante:&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void call_process() {&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1) {&lt;br /&gt;
        data = USART_Receive();&lt;br /&gt;
        if(data == '1') {&lt;br /&gt;
            add(led1_blink);&lt;br /&gt;
        }&lt;br /&gt;
        ...&lt;br /&gt;
        else if(data == '6') {&lt;br /&gt;
            kill(led1_blink);&lt;br /&gt;
        }&lt;br /&gt;
        ...&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On remarquera que c'est une sorte d'amélioration de la fonction Serial_Message vu plus haut.&lt;br /&gt;
&lt;br /&gt;
Cette fonction aura la fonction de process de base, toujours présent dans l'ordonnaceur.&lt;br /&gt;
&lt;br /&gt;
=====Démonstation===== &lt;br /&gt;
[[Fichier:Process via USART.mp4|centré|vignette]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ici on lance les processus ledN_blink avec les touches 1 à 5 et on les tues avec les touches 6 à 0. Pour le 7 segments, on l'ajoute avec s et le tue avec d. &lt;br /&gt;
&lt;br /&gt;
=Carte Réseau=&lt;br /&gt;
Lors de la répartition des tâches, nous avons opté pour la carte réseau. &lt;br /&gt;
==Description==&lt;br /&gt;
Le sujet nous permettait de choisir parmi plusieurs microcontrôleurs. Nous avons retenu l’ATmega32U4, qui nous semble représenter un juste milieu entre l’ATmega16U2 et l’AT90USB.&lt;br /&gt;
==Hardware==&lt;br /&gt;
Notre carte intègre des LED permettant d’afficher différents états de communication (que nous définirons ultérieurement).&lt;br /&gt;
&lt;br /&gt;
À la demande de M. Redon, nous avons ajouté un MAX232 ainsi que des connecteurs DB9 et DB25. Nous espérons que ces éléments pourront être utiles.&lt;br /&gt;
&lt;br /&gt;
En dehors de ça, la carte reste assez basique car son composant principal reste l'ATmega.&lt;br /&gt;
===Schématque===&lt;br /&gt;
les broches PF n'étant pas utilisé, on les branches à un connecteur 6x1, notre carte pourra donc être utiliser pour d'autre projet si nécéssaire.&lt;br /&gt;
&lt;br /&gt;
On fait le choix d'utiliser 5 leds pour la connections, 1 led de power et 1 pour la connection ISP.[[Fichier:Schématique CReseau.png|vignette|540x540px|centré]]&lt;br /&gt;
===Routage===&lt;br /&gt;
[[Fichier:Routage Creseau.png|vignette|521x521px|centré]]Après avoir soudé les composants pricnipaux. il est temps de passer à la partie programmation de la carte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Programmation== &lt;br /&gt;
&lt;br /&gt;
Notre carte utilsant un USB, on va donc la faire passer pour une carte réseau en utilisant la demo RNDIS de la LUFA.&lt;br /&gt;
&lt;br /&gt;
Il est important de noter que nous avons choisi un Atmega32u4. Ainsi des modification devrons être apporté à la taille des paquets ethernet et sur le choix des protocoles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Protocoles impémentés=== &lt;br /&gt;
&lt;br /&gt;
La demo RNDISEthernet de la LUFA inclut les protocole suivant&lt;br /&gt;
&lt;br /&gt;
* ARP : Résolution d'adresses MAC.&lt;br /&gt;
* IP : Gestion des paquets IPv4.&lt;br /&gt;
* ICMP : Messages de contrôle (ping).&lt;br /&gt;
* TCP : Communication fiable (exemple : serveur TCP).&lt;br /&gt;
* UDP : Communication non fiable (exemple : serveur UDP).&lt;br /&gt;
* DHCP : Attribution dynamique d'adresse IP.&lt;br /&gt;
&lt;br /&gt;
Aussi, on remarquera que la démo utilise un modèle en quatre couche : Le modèle TCP/IP.&lt;br /&gt;
&lt;br /&gt;
le sujet nous propose trois possibilité :&lt;br /&gt;
&lt;br /&gt;
* viser Ethernet&lt;br /&gt;
* viser UDP&lt;br /&gt;
* viser TCP&lt;br /&gt;
&lt;br /&gt;
En regardant ce qui à été fait les années précédentes, on a remarqué que les groupes partaient principalement sur la première option. Nous nous avons décidé de viser UDP.&lt;br /&gt;
&lt;br /&gt;
Ainsi, afin de d'alléger notre code pour le faire rentrer dans notre carte, nous avons choisi de ne pas inclure le protocole TCP et de modifier la taille max de paquets ethernet à 400 octets.&lt;br /&gt;
&lt;br /&gt;
Il nous restera donc de l'espace pour recevoir des paquets Ethernet :&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
avr-size --mcu=atmega32u4 --format=avr RNDISEthernet.elf&lt;br /&gt;
AVR Memory Usage&lt;br /&gt;
----------------&lt;br /&gt;
Device: atmega32u4&lt;br /&gt;
&lt;br /&gt;
Program:    9434 bytes (28.8% Full)&lt;br /&gt;
(.text + .data + .bootloader)&lt;br /&gt;
&lt;br /&gt;
Data:       1037 bytes (40.5% Full)&lt;br /&gt;
(.data + .bss + .noinit)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Une fois la lufa réduite et flashé, on donne une adresse ip à notre inteface avec ip link eth2 up et  ip address add 10.0.0.1/24 dev eth2.  on test un ping sur l'adresse ip de la carte (10.0.0.2).[[Fichier:Ping creseau.mp4|centré|vignette]]&lt;br /&gt;
[[Fichier:Ping allume led.mov|vignette|centré]]Le premier test que nous décidons de faire, afin de vérifié notre comprehesion du code de la LUFA est de de faire clignioter si la carte reçoit un paquet ethernet, pour celà on ajoute l'allumage de la led dans la fonction EthernetTask du fichier principal ( RNDISEthernet.c) :[[Fichier:Ping allume led.mov|vignette|La led s'éteint à chaque ping reçue|centré]]&lt;br /&gt;
&lt;br /&gt;
===Création du protocole=== &lt;br /&gt;
&lt;br /&gt;
En plus de pouvoir communiquer, notre carte dois être capable d'effectuer 3 fonction.&lt;br /&gt;
&lt;br /&gt;
On décide donc de créer un protocole (nommé ProtocolAntique) dont l'un des octet va transporter le choix de la focntion, le modèle du protocole sera le suivant : &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
typedef struct {&lt;br /&gt;
    uint8_t operation; /* 0x01 ls, 0x02 send, 0x03 recieve */&lt;br /&gt;
    uint8_t longeur; &lt;br /&gt;
    uint8_t numero;&lt;br /&gt;
} ProtocolAntique_Header_t;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Comme nous avons choisit de viser UDP, le protocole doit pocédé un numéro de port, on choisit un numéro supérieur à 1023 pour ne pas devoir passer en root, Le port choisi est 3333.&lt;br /&gt;
&lt;br /&gt;
Dans le programme UDP.c on peut maintenant inclure notre protocole de la façon suivante :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
        switch (SwapEndian_16(UDPHeaderIN-&amp;gt;DestinationPort))&lt;br /&gt;
        {&lt;br /&gt;
    /*&lt;br /&gt;
                case UDP_PORT_DHCP_REQUEST:&lt;br /&gt;
                        RetSize = DHCP_ProcessDHCPPacket(IPHeaderInStart,&lt;br /&gt;
                                                         &amp;amp;((uint8_t*)UDPHeaderInStart)[sizeof(UDP_Header_t)],&lt;br /&gt;
                                                     &amp;amp;((uint8_t*)UDPHeaderOutStart)[sizeof(UDP_Header_t)]);&lt;br /&gt;
                        break;&lt;br /&gt;
    */&lt;br /&gt;
                case UDP_PORT_PROTOCOL_ANTIQUE:       &lt;br /&gt;
                        RetSize = ProtocolAntique_ProcessProtocolAntiquePacket(IPHeaderInStart,&lt;br /&gt;
                                                         &amp;amp;((uint8_t*)UDPHeaderInStart)[sizeof(UDP_Header_t)],&lt;br /&gt;
                                                     &amp;amp;((uint8_t*)UDPHeaderOutStart)[sizeof(UDP_Header_t)]);&lt;br /&gt;
                        break;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Partie Application===&lt;br /&gt;
&lt;br /&gt;
(A compléter)&lt;br /&gt;
&lt;br /&gt;
Afin de tester la reception du paquet UDP, on fait à nouveau clignotter une led quand un paquet UDP et reçu (video)&lt;br /&gt;
&lt;br /&gt;
=== Partie serveur ===&lt;br /&gt;
Lorsque la carte mère a besoin de faire une action (ls, read, write) sur l'ordinateur qui est connecté en USB via la carte réseau elle transmet son besoin à la carte réseau. Cette dernière créer un requête UDP qui encapsule notre protocole (ProtocolAntique) et la transmet donc au PC. Sur ce dernier un serveur doit donc fonctionner afin de recevoir les rêquetes de la carte réseau, les traiter et y répondre. Cette partie est donc consacrée au code ainsi qu'aux tests du serveur.&lt;br /&gt;
&lt;br /&gt;
==== Code du serveur ====&lt;br /&gt;
Pour pouvoir fonctionner correctement le serveur doit initialiser une socket UDP et ensuite doit lancer un fonctionne qui boucle indéfiniment afin de recevoir chaque message UDP. Cette partie n'a pas été codé par nous et est trouvable sur rex.plil.fr (Département IMA -&amp;gt; support de cours de la programmation réseau -&amp;gt; exemple de serveur 2/2). Il en est de même du code la fonction pour envoyer un message UDP qui est trouvable au même endroit section exemple de client 2/2.&lt;br /&gt;
&lt;br /&gt;
La carte réseau est toujours à l'initiative des requêtes, par conséquent le serveur commence par recevoir un requête et la traiter. Pour ce faire à chaque requête reçue par la fonction boucleServeurUDP la fonction traitementMessageUDP est appelée.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
int traitementMessageUDP (unsigned char* message, int nboctets);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Cette fonction s'occupe d'extraire la partie opération de l'entête de protocolAntique et d'appeler la fonction de traitement correspondante à l'opération&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Opération&lt;br /&gt;
!Requête&lt;br /&gt;
!Fonction appelée&lt;br /&gt;
|-&lt;br /&gt;
|0x01&lt;br /&gt;
|LS&lt;br /&gt;
|void traitement_ls (unsigned char*);&lt;br /&gt;
|-&lt;br /&gt;
|0x02&lt;br /&gt;
|READ&lt;br /&gt;
|void traitement_read (unsigned char*);&lt;br /&gt;
|-&lt;br /&gt;
|0x03&lt;br /&gt;
|WRITE (début)&lt;br /&gt;
|void traitement_write (unsigned char*);&lt;br /&gt;
|-&lt;br /&gt;
|0x13&lt;br /&gt;
|WRITE (données et fin)&lt;br /&gt;
|void traitement_write (unsigned char*);&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Traitement LS =====&lt;br /&gt;
La fonction traitement_ls commence par récupérer le chemin (relatif ou absolu) où effectuer le LS. Si la section longueur de l'entête de la requête est à 0 alors le chemin par défaut est celui depuis où le serveur à été lancé. Le code pour récupérer le chemin  est le suivant :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
unsigned char chemin[longueur+1];&lt;br /&gt;
for (int i=0 ; i&amp;lt;longueur ; i++) {&lt;br /&gt;
        chemin[i] = message[i+3]; // Recuperation du chemin&lt;br /&gt;
}&lt;br /&gt;
chemin[longueur] = '\0';&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Par la suite le dossier est correspondant au chemin est ouvert via la fonction opendir puis chaque entrée du dossier est récupérée et engendre un message de réponse du serveur (un message par entrée).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
while ((entree = readdir(dossier)) != NULL) {&lt;br /&gt;
   // Message UDP pour chaque entree&lt;br /&gt;
   strcpy(contenu, entree-&amp;gt;d_name);&lt;br /&gt;
   printf(&amp;quot;    %s  &amp;quot;, contenu);&lt;br /&gt;
   reponse[OPERATION] = REPONSE_LS;&lt;br /&gt;
   reponse[LONGUEUR] = strlen(contenu);&lt;br /&gt;
   reponse[NUMERO] = num++;&lt;br /&gt;
   for (int i=0 ; i&amp;lt;reponse[LONGUEUR] ; i++) {&lt;br /&gt;
      reponse[i+3] = contenu[i];&lt;br /&gt;
   }&lt;br /&gt;
   messageUDP(IP_CARTE, PORT_CARTE, (unsigned char *)reponse, (int)reponse[LONGUEUR] + LONGUEUR_ENTETE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;OPERATION est la premiére section et vaut donc 0, LONGUEUR 2 et NUMERO 3. OPERATION est une réponse à un LS donc 0x11, LONGUEUR dépend de l'entrée du dossier et NUMERO augmente de 1 à chaque entrée. Enfin on remplie la requête du nom de l'entrée et on envoie le message.&lt;br /&gt;
&lt;br /&gt;
Enfin une fois tous les entrées envoyées on envoie un dernier message UDP de type reponse_LS de longueur 0 et de numéro 0 afin d'indiquer que la transmission est terminée et ce correctement.&lt;br /&gt;
&lt;br /&gt;
===== Traitement READ =====&lt;br /&gt;
Cette requête est très proche de celle du LS. On commence par récupérer le chemin avec le nom du fichier de la même façon que pour le LS. Cependant ici si le message ne contient pas de chemin aucun traitement ne sera effectué. Pour ouvrir le fichier on utilise la fonction fopen. Chaque ligne, récupérée via fgets, engendre une réponse UDP formulée de la même façon que pour les entrées de dossier. Evidemment l'opération est de type réponse read soit 0x12. Enfin un message similaire de fin de transmission est envoyé seulement si il n'y a pas eu d'erreur et que la dernière ligne à été lue.&lt;br /&gt;
&lt;br /&gt;
===== Traitement WRITE =====&lt;br /&gt;
Cette requête est un peu plus complexe à gérer niveau serveur par conséquent que je vais commencer par décrire le principe de la fonction.&lt;br /&gt;
&lt;br /&gt;
* La carte réseau envoie un message de type début de write (OPERATION 0x03) avec le chemin et nom du fichier que le serveur va récupérer et mémoriser.&lt;br /&gt;
&lt;br /&gt;
* La carte réseau envoie un massage pour chaque ligne à écrite (OPERATION 0x13). Le serveur va vérifier si la section NUMERO des entêtes se suivent afin de s'assurer que aucun message n'est été perdu.&lt;br /&gt;
&lt;br /&gt;
* La carte réseau envoie un message de type fin de write (OPERATION 0x013) mais de numéro 0. Le serveur indique que tout s'est bien passé en envoyant une réponse au write (OPERATION 0x23) donc le contenu est 0x00.&lt;br /&gt;
* Si un message a été perdu un message d'erreur est envoyé de la par du serveur (OPERATION 0x23) de contenu 0x01.&lt;br /&gt;
&lt;br /&gt;
La récupération du contenu de la requête est du même type que celle du LS. Les messages de retour sont construits de la même façon que pour le message de retour du LS. Enfin on utilise fopen une nouvelle fois pour ouvrir le fichier, fwrite pour y écrire et fclose pour le fermer.&lt;br /&gt;
&lt;br /&gt;
==== Préparation du test ====&lt;br /&gt;
Avant de pouvoir tester notre serveur avec la carte réseau (ce qui n'aura jamais été fait car la carte réseau n'envoie rien) nous avons souhaité validé le fonctionnement du serveur en simulant des requêtes de la carte réseau. On voit ce que le serveur fait via des printf et en créant un autre serveur (plus rudimentaire) on peut vérifier que le serveur répond correctement. Sur notre git le dossier testUDP est consacré à cette phase de tests.&lt;br /&gt;
&lt;br /&gt;
* Les requêtes simulées de la carte réseau sont envoyées sur l'IP loopback de la machine et sur le port du serveur (ici 4242)&lt;br /&gt;
* Le serveur écoute le port serveur (4242) et répond en loopback sur le port du serveur qui simule la carte (ici 3333)&lt;br /&gt;
* Le serveur qui simule la carte écoute le port 3333&lt;br /&gt;
&lt;br /&gt;
On lance ces différents serveurs et les requêtes via les commandes du fichiers fonctionnement.txt de notre git.&lt;br /&gt;
&lt;br /&gt;
==== Tests ====&lt;br /&gt;
Le test est réalisé via 3 commandes :&lt;br /&gt;
&lt;br /&gt;
* LS sans chemin&lt;br /&gt;
* WRITE de 3 lignes dans un fichier test.txt créé par la commande&lt;br /&gt;
* READ du fichier test.txt&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Test1.png|centré|vignette|Requêtes envoyées]]&lt;br /&gt;
[[Fichier:Test2.png|centré|vignette|Traitement du serveur]]&lt;br /&gt;
[[Fichier:Test3.png|centré|vignette|Réponse reçu du serveur]]&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Test3.png&amp;diff=8693</id>
		<title>Fichier:Test3.png</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Test3.png&amp;diff=8693"/>
		<updated>2026-01-04T15:56:10Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;test3&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Test2.png&amp;diff=8692</id>
		<title>Fichier:Test2.png</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Test2.png&amp;diff=8692"/>
		<updated>2026-01-04T15:55:17Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;test2&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Test1.png&amp;diff=8691</id>
		<title>Fichier:Test1.png</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Test1.png&amp;diff=8691"/>
		<updated>2026-01-04T15:53:31Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;test1&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Ls.png&amp;diff=8690</id>
		<title>Fichier:Ls.png</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Ls.png&amp;diff=8690"/>
		<updated>2026-01-04T15:52:01Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;ls&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Test_1.png&amp;diff=8689</id>
		<title>Fichier:Test 1.png</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Test_1.png&amp;diff=8689"/>
		<updated>2026-01-04T15:41:42Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;test 1&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2025-1&amp;diff=8688</id>
		<title>SE4Binome2025-1</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2025-1&amp;diff=8688"/>
		<updated>2026-01-04T15:33:22Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Shield Arduino =&lt;br /&gt;
== Hardware ==&lt;br /&gt;
Afin de tester notre futur carte réseau, nous avons fait un shield d'arduino qui prendra le rôle de la carte mère durant. &lt;br /&gt;
=== Schématique ===&lt;br /&gt;
Nous nous sommes évidemment aider de la datasheet de l'atmega328p ainsi que celle de l'arduino uno afin de sélectionner les bon pins.&lt;br /&gt;
[[Fichier:Atmel-7810-Automotive-Microcontrollers-ATmega328P Datasheet.pdf|centré|vignette|Datasheet ATmega328p]]&lt;br /&gt;
[[Fichier:A000066-datasheet.pdf|centré|vignette|Datasheet Arduino Uno R3]]&lt;br /&gt;
Plus précisément nous nous inspirons très fortement du schéma page 10 de la datasheet de l'arduino :&lt;br /&gt;
[[Fichier:Screenshot 2025-11-07 11-08-46.png|centré|vignette|Schéma pinouts]]&lt;br /&gt;
Nous sommes donc parti de l'exemple fourni par Mr Redon. Mais nous avons utilisé une template disponible dans kicad permettant de créer des shields d'arduino Uno R3.[[Fichier:Tyetyuy.png|vignette|Schématique shield arduino|centré|438x438px]]&lt;br /&gt;
=== Routage ===&lt;br /&gt;
Au niveau du routage, nous avons tenté de faire simple (sans trop abuser sur les vias. Nous avons positionner le lecteur de carte sd au bord de la carte afin de ne pas avoir de problèmes avec d'autres composants lorsque nous voudrons mettre ou enlever la carte sd.&lt;br /&gt;
[[Fichier:Routage shield arduino.png|vignette|Routage shield arduino|centré|434x434px]]&lt;br /&gt;
&lt;br /&gt;
===Soudage===&lt;br /&gt;
La schématique et le routage terminés, nous avons soudé les différents pins permettant de souder la carte shield à l'arduino, le reste n'étant pas forcément utile pour le moment (il est important de noter que notre shield est arrivé avec des composants pré-soudés).&lt;br /&gt;
[[Fichier:Shield soudage de base .jpg|centré|vignette]]&lt;br /&gt;
&lt;br /&gt;
===Tests===&lt;br /&gt;
====Leds====&lt;br /&gt;
&lt;br /&gt;
Il faudra ensuite faire des test d'allumage des leds, afin de vérifier le bon fonctionnement du shield&lt;br /&gt;
[[Fichier:VID leds.mp4|centré|vignette]]&lt;br /&gt;
&lt;br /&gt;
Les leds fonctionnent à merveille.&lt;br /&gt;
&lt;br /&gt;
====Carte SD====&lt;br /&gt;
&lt;br /&gt;
Nous vérifions maintenant la carte sd (même si elle nous sera inutile pour notre projet)&lt;br /&gt;
&lt;br /&gt;
Nous utilisons le programme fourni par arduino qui permet de récuopéré les informatiuons de la carte sd.&lt;br /&gt;
[[Fichier:Test sd card.png|centré|vignette]]&lt;br /&gt;
La carte SD est bien identifié, le lecteur de carte fonctionne donc normalement.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
=== Ordonnanceur ===&lt;br /&gt;
[à completer  et commenter , seulement des codes pour le moment !!!!]&lt;br /&gt;
==== Ordonnanceur basique ====&lt;br /&gt;
La première étape consiste à définir la structure d'un process, il sera composé :&lt;br /&gt;
&lt;br /&gt;
-d'un pointeur de pile&lt;br /&gt;
&lt;br /&gt;
-de l'adresse de la fonction&lt;br /&gt;
&lt;br /&gt;
-d'un temps de sommeil &lt;br /&gt;
&lt;br /&gt;
-d'un état : 0 pour en cours et 1 pour terminé ou vide&lt;br /&gt;
&lt;br /&gt;
Ces deux derniers points nous servirons plus tard.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
typedef struct {&lt;br /&gt;
	uint16_t stackPointer;&lt;br /&gt;
	void (*functionAddress)(void);&lt;br /&gt;
	int sleep_time;&lt;br /&gt;
	int state;&lt;br /&gt;
} process;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On initialise donc notre tableau de processus de la façon suivante : &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
process Tasks_list[NBTASKS] = {&lt;br /&gt;
                                {0, led1_blink, 0,0},&lt;br /&gt;
				...&lt;br /&gt;
			       };&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Concernant les fonction liés leds, on utilise une simple boucle while contenant un changement d'état &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void led_init() {&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
void led1_blink() {&lt;br /&gt;
	while(1) {&lt;br /&gt;
		PORTC ^= (1&amp;lt;&amp;lt;PLED1);&lt;br /&gt;
		_delay_ms(100);&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
void led2_blink() {&lt;br /&gt;
...	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_stackPointer_tasks() permet de diviser la pile &amp;quot;réel&amp;quot; en plusieurs piles pour chaque processus.  Ces sous piles commence à la position FIRST_STACK_POSITION, afin de ne pas réécrire par dessus des données. Toutes les sous piles diposent d'une même taille de pile STACK_LENGTH.&lt;br /&gt;
&lt;br /&gt;
La fonction init_piles() initialise correctement la pile avec le tableau de processus si le processus est actif.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void init_stackPointer_tasks(int Cprocess) { //initialise le pointer de pile&lt;br /&gt;
	if(Tasks_list[Cprocess].state == 0) {&lt;br /&gt;
		Tasks_list[Cprocess].stackPointer = FIRST_STACK_POSITION - (Cprocess * STACK_LENGTH);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void init_piles(int Cprocess){ //initilalise la pile&lt;br /&gt;
	if(Tasks_list[Cprocess].state == 0) {&lt;br /&gt;
		int save = SP;&lt;br /&gt;
		SP = Tasks_list[Cprocess].stackPointer;&lt;br /&gt;
		uint16_t address = (uint16_t)Tasks_list[Cprocess].functionAddress;&lt;br /&gt;
		asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (address &amp;amp; 0x00ff) );&lt;br /&gt;
		asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((address &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
		SAVE_REGISTERS();&lt;br /&gt;
		Tasks_list[Cprocess].stackPointer = SP;&lt;br /&gt;
		SP = save;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;le scheduler permet de passer à la tâche suivante&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
	Current_task++;&lt;br /&gt;
	if (Current_task &amp;gt;= NBTASKS) {&lt;br /&gt;
		Current_task = 0; &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;l'atmega328p ne dispose pas de de fonction en assembleur permettant de push ou de pop tout les registres. on doit donc le faire un par un.&lt;br /&gt;
&lt;br /&gt;
On défini alors les macros suivantes :  &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
#define SAVE_REGISTERS() \&lt;br /&gt;
	asm volatile ( \&lt;br /&gt;
		&amp;quot;push r0 	 \n\t&amp;quot; \&lt;br /&gt;
		...\&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#define RESTORE_REGISTERS() \&lt;br /&gt;
	asm volatile ( \&lt;br /&gt;
		&amp;quot;pop r31 	  \n\t&amp;quot; \&lt;br /&gt;
		...\&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;L'ISR gère les interruptions, en commençant par sauvegarder l'état de la pile ainsi que le stack pointeur propre au processus qui s'interrompt. L'appel au schedruler permet de changer de processus pour cela il faut restorer le stack pointer propre au nouveau processus actif et de la pile liée à ce processus. La dernière ligne arrête l'ISR.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED) {&lt;br /&gt;
	SAVE_REGISTERS();&lt;br /&gt;
	Tasks_list[Current_task].stackPointer = SP;&lt;br /&gt;
	scheduler();&lt;br /&gt;
	SP = Tasks_list[Current_task].stackPointer;&lt;br /&gt;
	RESTORE_REGISTERS();&lt;br /&gt;
	asm volatile(&amp;quot;reti&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=====test=====&lt;br /&gt;
Les processus de clignotement de leds ont tous un délai d'attente différent, l'interruption se produit toutes les millisecondes. On obtient ceci :[[Fichier:Ordonnanceur basique.mp4|centré|vignette]]Il est intéressant de remarqué que la vitesse à laquelle les leds changent d'état ne correspond pas au délai qui leur à été donné. Cela parait logique puisque l'interruption met la fonction _delay_ms en pause, ainsi la vitesse se voit divisé par le nombre de processus actif.&lt;br /&gt;
&lt;br /&gt;
====Ajout d'un système d'endormissement des processus====&lt;br /&gt;
&lt;br /&gt;
La fonction wait va permettre d'endormir un processus, elle va donné un temps de sommeil au processus puis lancer une interruption (car on veut changer de processus directement après que le précédent ait été endormi).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time) { // met un process en veille pour une durée donné&lt;br /&gt;
	// valeur max de time 32000 car int sur atmega328p code sur 16 bits donc 32000 max&lt;br /&gt;
	cli();&lt;br /&gt;
	Tasks_list[Current_task].sleep_time = time;&lt;br /&gt;
	TCNT1=0;&lt;br /&gt;
	sei();&lt;br /&gt;
	TIMER1_COMPA_vect();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour verifier si un processus a besoin d'être lancé, on ajoute une boucle while dans le scheduler afin de vérifier si il y a un temps de sommeil. Le scheduler va aussi servir à diminuer le temps de sommeil de tout les processus (avec un minimum de 0).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
	for (int i=0 ; i&amp;lt;NBTASKS ; i++) {&lt;br /&gt;
		if (Tasks_list[i].sleep_time - SLEEP_DEC &amp;lt; 0) {&lt;br /&gt;
			Tasks_list[i].sleep_time = 0;&lt;br /&gt;
		} else {&lt;br /&gt;
			Tasks_list[i].sleep_time -= SLEEP_DEC;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	do {&lt;br /&gt;
		Current_task++;&lt;br /&gt;
		if (Current_task &amp;gt;= NBTASKS) {&lt;br /&gt;
			Current_task = 0;&lt;br /&gt;
		}&lt;br /&gt;
	} while (Tasks_list[Current_task].sleep_time &amp;gt; 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Tableau dynamique des tâches====&lt;br /&gt;
&lt;br /&gt;
En premier lieu on va initialiser les état de tout les cases du tableau de processus. On choisit 1 la case est vide, 0 sinon.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void init_state() { //initialise state&lt;br /&gt;
	for (int i= 0; i&amp;lt;NBTASKS; i++) {&lt;br /&gt;
		if (Tasks_list[i].functionAddress == NULL) {&lt;br /&gt;
			Tasks_list[i].state = 1;&lt;br /&gt;
		}&lt;br /&gt;
		else {&lt;br /&gt;
			Tasks_list[i].state = 0;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Nous avons programmé deux fonction d'arrêt et une fonction d'ajout de processus :&lt;br /&gt;
&lt;br /&gt;
-finish stop le processus en cours et le supprime de tableau, puis lance une interruption&lt;br /&gt;
&lt;br /&gt;
-kill stop un processus donné et le supprime du tableau &lt;br /&gt;
&lt;br /&gt;
-add ajoute un processus sur la première case vide du tableau, initialise son pointeur de position et sa pile.&lt;br /&gt;
&lt;br /&gt;
Pour finish et kill, on met le temps de sommeil à 0 au cas où on arrête un processus endormi. C'est une mesure de sécurité pour finish, mais une obligation pour kill.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void finish() { //supprime un process lorsque celui-ci est terminé&lt;br /&gt;
	cli();&lt;br /&gt;
		Tasks_list[Current_task].state =1;&lt;br /&gt;
		Tasks_list[Current_task].sleep_time = 0;&lt;br /&gt;
		Tasks_list[Current_task].functionAddress = NULL;&lt;br /&gt;
	TCNT1=0; &lt;br /&gt;
	sei();&lt;br /&gt;
	TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void kill(void (*function)(void)) { //tue le process passé en paramètre&lt;br /&gt;
	cli();&lt;br /&gt;
	for(int i = 0; i&amp;lt;NBTASKS; i++) {&lt;br /&gt;
		if(Tasks_list[i].functionAddress == function) {&lt;br /&gt;
			Tasks_list[i].state =1;&lt;br /&gt;
			Tasks_list[i].sleep_time = 0;&lt;br /&gt;
			Tasks_list[i].functionAddress = NULL;&lt;br /&gt;
		}&lt;br /&gt;
	} &lt;br /&gt;
	sei();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void add(void (*newFunction)(void)) { //ajoute un process&lt;br /&gt;
	cli();&lt;br /&gt;
	int i =0;&lt;br /&gt;
	while(Tasks_list[i].state != 1) {&lt;br /&gt;
		i++;&lt;br /&gt;
	}&lt;br /&gt;
	Tasks_list[i].functionAddress = newFunction;&lt;br /&gt;
	Tasks_list[i].state = 0;&lt;br /&gt;
	init_stackPointer_tasks(i);&lt;br /&gt;
	init_piles(i);&lt;br /&gt;
&lt;br /&gt;
	sei();&lt;br /&gt;
	&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Il suffit maintenant de modifier le scheduler afin de ne pas prendre les processus terminé, puis utiliser add, finish et kill dans les fonctions choisis.&lt;br /&gt;
&lt;br /&gt;
=====test=====&lt;br /&gt;
Pour tester les fonction add et finish, on fait le test suivant :&lt;br /&gt;
&lt;br /&gt;
-on créer un process qui ajoute le process led2_blink (avec add) au bout d'un certain temps&lt;br /&gt;
&lt;br /&gt;
-le process led2_blink s'arrête (avec finish) au bout de 20 changement d'état (c'est à dire 10 clignotement).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
on obtient le résultat suivant :[[Fichier:Demo fonction add et finish.mp4|centré|vignette]]&lt;br /&gt;
====lecture et écriture sur le port série====&lt;br /&gt;
Afin de lire et écrire sur le port série, on utilise les fonctions USART_Init, USART_Transmit et USART_Receive  vu en cours de microP l'année précédente. Le but sera donc d'écrire le message qui vient d'être reçu, on utilise donc le processus suivant :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====test=====&lt;br /&gt;
Pour tester notre processus de communication, on utilise minicom.[[Fichier:Test lecture et écriture port série.mp4|centré|vignette]]On notera que si la période entre les interruptions est trop élevé, certains caractères ne seront pas lus.&lt;br /&gt;
&lt;br /&gt;
====afficheur 7 segments====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void seven_seg() {&lt;br /&gt;
	while (1) {&lt;br /&gt;
        spi_activer((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
		spi_echange(0x7E);&lt;br /&gt;
		spi_echange(0b1101111);&lt;br /&gt;
		spi_desactiver((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
&lt;br /&gt;
		wait(500);&lt;br /&gt;
&lt;br /&gt;
		spi_activer((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
		spi_echange(0x76);&lt;br /&gt;
		spi_desactiver((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
&lt;br /&gt;
		wait(500);&lt;br /&gt;
    	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Le processus seven_seg est ajouté au tableau des processus. Avant d'échanger en spi il faut activer la communication, et la désactiver après l'échange. La ligne 4 permet de sélectionner le 7 seg sur lequel on souhaite modifier l'affichage. La ligne 5 permet d'afficher le chiffre 9. Enfin la ligne 11 permet de clear le display. Voir tableau ci-dessous.&lt;br /&gt;
[[Fichier:Tab 7 seg sparkfun.png|centré|vignette]]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void) {                                 // Initialisation du bus SPI&lt;br /&gt;
	SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);   // Définition des sorties&lt;br /&gt;
	SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // Définition de l'entrée                          &lt;br /&gt;
	SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
        	                                             // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
	SPI_DDR |= (1&amp;lt;&amp;lt;CS1) | (1&amp;lt;&amp;lt;CS4);;&lt;br /&gt;
	DDRD |= (1&amp;lt;&amp;lt;CS5) | (1&amp;lt;&amp;lt;CS6);&lt;br /&gt;
	DDRC |= (1&amp;lt;&amp;lt;CS2) | (1&amp;lt;&amp;lt;CS3);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void spi_activer(uint16_t port, uint8_t cs) { 	// Activer le périphérique&lt;br /&gt;
	volatile uint8_t *reg = (volatile uint8_t*)port;&lt;br /&gt;
	*reg &amp;amp;= ~(1&amp;lt;&amp;lt;cs);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(uint16_t port, uint8_t cs) {                           // Désactiver le périphérique&lt;br /&gt;
	volatile uint8_t *reg = (volatile uint8_t*)port;&lt;br /&gt;
	*reg |= (1&amp;lt;&amp;lt;cs);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi) {                  // Communication sur le bus SPI&lt;br /&gt;
	SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
	while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
	return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de rendre nos fonctions les plus réutilisables possibles nous avons passer en paramètre le port ainsi que le CS qui correspond au slave select. Le type réel du port est volatile uint8* cependant le compilateur n'accepte que le uint16* ce qui explique le cast un peu étrange.&lt;br /&gt;
&lt;br /&gt;
=====Implémentation=====&lt;br /&gt;
[[Fichier:Video7segvideo.mp4|vignette|centré]]L'implémentation correspond à nos attentes, seul un 7 seg affiche le chiffre 9.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====choix du processus sur le port série====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
afin de pouvoir démontrer le bon fonctionnement de la partie dynamique, on décide de pouvoir ajouter et tuer des processus à partir des touches du clavier. On utilisera donc les fonction de l'USART défini plus au au travers de la fonction suivante:&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void call_process() {&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1) {&lt;br /&gt;
        data = USART_Receive();&lt;br /&gt;
        if(data == '1') {&lt;br /&gt;
            add(led1_blink);&lt;br /&gt;
        }&lt;br /&gt;
        ...&lt;br /&gt;
        else if(data == '6') {&lt;br /&gt;
            kill(led1_blink);&lt;br /&gt;
        }&lt;br /&gt;
        ...&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On remarquera que c'est une sorte d'amélioration de la fonction Serial_Message vu plus haut.&lt;br /&gt;
&lt;br /&gt;
Cette fonction aura la fonction de process de base, toujours présent dans l'ordonnaceur.&lt;br /&gt;
&lt;br /&gt;
=====Démonstation===== &lt;br /&gt;
[[Fichier:Process via USART.mp4|centré|vignette]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ici on lance les processus ledN_blink avec les touches 1 à 5 et on les tues avec les touches 6 à 0. Pour le 7 segments, on l'ajoute avec s et le tue avec d. &lt;br /&gt;
&lt;br /&gt;
=Carte Réseau=&lt;br /&gt;
Lors de la répartition des tâches, nous avons opté pour la carte réseau. &lt;br /&gt;
==Description==&lt;br /&gt;
Le sujet nous permettait de choisir parmi plusieurs microcontrôleurs. Nous avons retenu l’ATmega32U4, qui nous semble représenter un juste milieu entre l’ATmega16U2 et l’AT90USB.&lt;br /&gt;
==Hardware==&lt;br /&gt;
Notre carte intègre des LED permettant d’afficher différents états de communication (que nous définirons ultérieurement).&lt;br /&gt;
&lt;br /&gt;
À la demande de M. Redon, nous avons ajouté un MAX232 ainsi que des connecteurs DB9 et DB25. Nous espérons que ces éléments pourront être utiles.&lt;br /&gt;
&lt;br /&gt;
En dehors de ça, la carte reste assez basique car son composant principal reste l'ATmega.&lt;br /&gt;
===Schématque===&lt;br /&gt;
les broches PF n'étant pas utilisé, on les branches à un connecteur 6x1, notre carte pourra donc être utiliser pour d'autre projet si nécéssaire.&lt;br /&gt;
&lt;br /&gt;
On fait le choix d'utiliser 5 leds pour la connections, 1 led de power et 1 pour la connection ISP.[[Fichier:Schématique CReseau.png|vignette|540x540px|centré]]&lt;br /&gt;
===Routage===&lt;br /&gt;
[[Fichier:Routage Creseau.png|vignette|521x521px|centré]]Après avoir soudé les composants pricnipaux. il est temps de passer à la partie programmation de la carte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Programmation== &lt;br /&gt;
&lt;br /&gt;
Notre carte utilsant un USB, on va donc la faire passer pour une carte réseau en utilisant la demo RNDIS de la LUFA.&lt;br /&gt;
&lt;br /&gt;
Il est important de noter que nous avons choisi un Atmega32u4. Ainsi des modification devrons être apporté à la taille des paquets ethernet et sur le choix des protocoles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Protocoles impémentés=== &lt;br /&gt;
&lt;br /&gt;
La demo RNDISEthernet de la LUFA inclut les protocole suivant&lt;br /&gt;
&lt;br /&gt;
* ARP : Résolution d'adresses MAC.&lt;br /&gt;
* IP : Gestion des paquets IPv4.&lt;br /&gt;
* ICMP : Messages de contrôle (ping).&lt;br /&gt;
* TCP : Communication fiable (exemple : serveur TCP).&lt;br /&gt;
* UDP : Communication non fiable (exemple : serveur UDP).&lt;br /&gt;
* DHCP : Attribution dynamique d'adresse IP.&lt;br /&gt;
&lt;br /&gt;
Aussi, on remarquera que la démo utilise un modèle en quatre couche : Le modèle TCP/IP.&lt;br /&gt;
&lt;br /&gt;
le sujet nous propose trois possibilité :&lt;br /&gt;
&lt;br /&gt;
* viser Ethernet&lt;br /&gt;
* viser UDP&lt;br /&gt;
* viser TCP&lt;br /&gt;
&lt;br /&gt;
En regardant ce qui à été fait les années précédentes, on a remarqué que les groupes partaient principalement sur la première option. Nous nous avons décidé de viser UDP.&lt;br /&gt;
&lt;br /&gt;
Ainsi, afin de d'alléger notre code pour le faire rentrer dans notre carte, nous avons choisi de ne pas inclure le protocole TCP et de modifier la taille max de paquets ethernet à 400 octets.&lt;br /&gt;
&lt;br /&gt;
Il nous restera donc de l'espace pour recevoir des paquets Ethernet :&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
avr-size --mcu=atmega32u4 --format=avr RNDISEthernet.elf&lt;br /&gt;
AVR Memory Usage&lt;br /&gt;
----------------&lt;br /&gt;
Device: atmega32u4&lt;br /&gt;
&lt;br /&gt;
Program:    9434 bytes (28.8% Full)&lt;br /&gt;
(.text + .data + .bootloader)&lt;br /&gt;
&lt;br /&gt;
Data:       1037 bytes (40.5% Full)&lt;br /&gt;
(.data + .bss + .noinit)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Une fois la lufa réduite et flashé, on donne une adresse ip à notre inteface avec ip link eth2 up et  ip address add 10.0.0.1/24 dev eth2.  on test un ping sur l'adresse ip de la carte (10.0.0.2).[[Fichier:Ping creseau.mp4|centré|vignette]]&lt;br /&gt;
[[Fichier:Ping allume led.mov|vignette|centré]]Le premier test que nous décidons de faire, afin de vérifié notre comprehesion du code de la LUFA est de de faire clignioter si la carte reçoit un paquet ethernet, pour celà on ajoute l'allumage de la led dans la fonction EthernetTask du fichier principal ( RNDISEthernet.c) :[[Fichier:Ping allume led.mov|vignette|La led s'éteint à chaque ping reçue|centré]]&lt;br /&gt;
&lt;br /&gt;
===Création du protocole=== &lt;br /&gt;
&lt;br /&gt;
En plus de pouvoir communiquer, notre carte dois être capable d'effectuer 3 fonction.&lt;br /&gt;
&lt;br /&gt;
On décide donc de créer un protocole (nommé ProtocolAntique) dont l'un des octet va transporter le choix de la focntion, le modèle du protocole sera le suivant : &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
typedef struct {&lt;br /&gt;
    uint8_t operation; /* 0x01 ls, 0x02 send, 0x03 recieve */&lt;br /&gt;
    uint8_t longeur; &lt;br /&gt;
    uint8_t numero;&lt;br /&gt;
} ProtocolAntique_Header_t;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Comme nous avons choisit de viser UDP, le protocole doit pocédé un numéro de port, on choisit un numéro supérieur à 1023 pour ne pas devoir passer en root, Le port choisi est 3333.&lt;br /&gt;
&lt;br /&gt;
Dans le programme UDP.c on peut maintenant inclure notre protocole de la façon suivante :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
        switch (SwapEndian_16(UDPHeaderIN-&amp;gt;DestinationPort))&lt;br /&gt;
        {&lt;br /&gt;
    /*&lt;br /&gt;
                case UDP_PORT_DHCP_REQUEST:&lt;br /&gt;
                        RetSize = DHCP_ProcessDHCPPacket(IPHeaderInStart,&lt;br /&gt;
                                                         &amp;amp;((uint8_t*)UDPHeaderInStart)[sizeof(UDP_Header_t)],&lt;br /&gt;
                                                     &amp;amp;((uint8_t*)UDPHeaderOutStart)[sizeof(UDP_Header_t)]);&lt;br /&gt;
                        break;&lt;br /&gt;
    */&lt;br /&gt;
                case UDP_PORT_PROTOCOL_ANTIQUE:       &lt;br /&gt;
                        RetSize = ProtocolAntique_ProcessProtocolAntiquePacket(IPHeaderInStart,&lt;br /&gt;
                                                         &amp;amp;((uint8_t*)UDPHeaderInStart)[sizeof(UDP_Header_t)],&lt;br /&gt;
                                                     &amp;amp;((uint8_t*)UDPHeaderOutStart)[sizeof(UDP_Header_t)]);&lt;br /&gt;
                        break;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Partie Application===&lt;br /&gt;
&lt;br /&gt;
(A compléter)&lt;br /&gt;
&lt;br /&gt;
Afin de tester la reception du paquet UDP, on fait à nouveau clignotter une led quand un paquet UDP et reçu (video)&lt;br /&gt;
&lt;br /&gt;
=== Partie serveur ===&lt;br /&gt;
Lorsque la carte mère a besoin de faire une action (ls, read, write) sur l'ordinateur qui est connecté en USB via la carte réseau elle transmet son besoin à la carte réseau. Cette dernière créer un requête UDP qui encapsule notre protocole (ProtocolAntique) et la transmet donc au PC. Sur ce dernier un serveur doit donc fonctionner afin de recevoir les rêquetes de la carte réseau, les traiter et y répondre. Cette partie est donc consacrée au code ainsi qu'aux tests du serveur.&lt;br /&gt;
&lt;br /&gt;
==== Code du serveur ====&lt;br /&gt;
Pour pouvoir fonctionner correctement le serveur doit initialiser une socket UDP et ensuite doit lancer un fonctionne qui boucle indéfiniment afin de recevoir chaque message UDP. Cette partie n'a pas été codé par nous et est trouvable sur rex.plil.fr (Département IMA -&amp;gt; support de cours de la programmation réseau -&amp;gt; exemple de serveur 2/2). Il en est de même du code la fonction pour envoyer un message UDP qui est trouvable au même endroit section exemple de client 2/2.&lt;br /&gt;
&lt;br /&gt;
La carte réseau est toujours à l'initiative des requêtes, par conséquent le serveur commence par recevoir un requête et la traiter. Pour ce faire à chaque requête reçue par la fonction boucleServeurUDP la fonction traitementMessageUDP est appelée.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
int traitementMessageUDP (unsigned char* message, int nboctets);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Cette fonction s'occupe d'extraire la partie opération de l'entête de protocolAntique et d'appeler la fonction de traitement correspondante à l'opération&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Opération&lt;br /&gt;
!Requête&lt;br /&gt;
!Fonction appelée&lt;br /&gt;
|-&lt;br /&gt;
|0x01&lt;br /&gt;
|LS&lt;br /&gt;
|void traitement_ls (unsigned char*);&lt;br /&gt;
|-&lt;br /&gt;
|0x02&lt;br /&gt;
|READ&lt;br /&gt;
|void traitement_read (unsigned char*);&lt;br /&gt;
|-&lt;br /&gt;
|0x03&lt;br /&gt;
|WRITE (début)&lt;br /&gt;
|void traitement_write (unsigned char*);&lt;br /&gt;
|-&lt;br /&gt;
|0x13&lt;br /&gt;
|WRITE (données et fin)&lt;br /&gt;
|void traitement_write (unsigned char*);&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===== Traitement LS =====&lt;br /&gt;
La fonction traitement_ls commence par récupérer le chemin (relatif ou absolu) où effectuer le LS. Si la section longueur de l'entête de la requête est à 0 alors le chemin par défaut est celui depuis où le serveur à été lancé. Le code pour récupérer le chemin  est le suivant :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
unsigned char chemin[longueur+1];&lt;br /&gt;
for (int i=0 ; i&amp;lt;longueur ; i++) {&lt;br /&gt;
        chemin[i] = message[i+3]; // Recuperation du chemin&lt;br /&gt;
}&lt;br /&gt;
chemin[longueur] = '\0';&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Par la suite le dossier est correspondant au chemin est ouvert via la fonction opendir puis chaque entrée du dossier est récupérée et engendre un message de réponse du serveur (un message par entrée).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
while ((entree = readdir(dossier)) != NULL) {&lt;br /&gt;
   // Message UDP pour chaque entree&lt;br /&gt;
   strcpy(contenu, entree-&amp;gt;d_name);&lt;br /&gt;
   printf(&amp;quot;    %s  &amp;quot;, contenu);&lt;br /&gt;
   reponse[OPERATION] = REPONSE_LS;&lt;br /&gt;
   reponse[LONGUEUR] = strlen(contenu);&lt;br /&gt;
   reponse[NUMERO] = num++;&lt;br /&gt;
   for (int i=0 ; i&amp;lt;reponse[LONGUEUR] ; i++) {&lt;br /&gt;
      reponse[i+3] = contenu[i];&lt;br /&gt;
   }&lt;br /&gt;
   messageUDP(IP_CARTE, PORT_CARTE, (unsigned char *)reponse, (int)reponse[LONGUEUR] + LONGUEUR_ENTETE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;OPERATION est la premiére section et vaut donc 0, LONGUEUR 2 et NUMERO 3. OPERATION est une réponse à un LS donc 0x11, LONGUEUR dépend de l'entrée du dossier et NUMERO augmente de 1 à chaque entrée. Enfin on remplie la requête du nom de l'entrée et on envoie le message.&lt;br /&gt;
&lt;br /&gt;
Enfin une fois tous les entrées envoyées on envoie un dernier message UDP de type reponse_LS de longueur 0 et de numéro 0 afin d'indiquer que la transmission est terminée et ce correctement.&lt;br /&gt;
&lt;br /&gt;
===== Traitement READ =====&lt;br /&gt;
Cette requête est très proche de celle du LS. On commence par récupérer le chemin avec le nom du fichier de la même façon que pour le LS. Cependant ici si le message ne contient pas de chemin aucun traitement ne sera effectué. Pour ouvrir le fichier on utilise la fonction fopen. Chaque ligne, récupérée via fgets, engendre une réponse UDP formulée de la même façon que pour les entrées de dossier. Evidemment l'opération est de type réponse read soit 0x12. Enfin un message similaire de fin de transmission est envoyé seulement si il n'y a pas eu d'erreur et que la dernière ligne à été lue.&lt;br /&gt;
&lt;br /&gt;
===== Traitement WRITE =====&lt;br /&gt;
Cette requête est un peu plus complexe à gérer niveau serveur par conséquent que je vais commencer par décrire le principe de la fonction.&lt;br /&gt;
&lt;br /&gt;
* La carte réseau envoie un message de type début de write (OPERATION 0x03) avec le chemin et nom du fichier que le serveur va récupérer et mémoriser.&lt;br /&gt;
&lt;br /&gt;
* La carte réseau envoie un massage pour chaque ligne à écrite (OPERATION 0x13). Le serveur va vérifier si la section NUMERO des entêtes se suivent afin de s'assurer que aucun message n'est été perdu.&lt;br /&gt;
&lt;br /&gt;
* La carte réseau envoie un message de type fin de write (OPERATION 0x013) mais de numéro 0. Le serveur indique que tout s'est bien passé en envoyant une réponse au write (OPERATION 0x23) donc le contenu est 0x00.&lt;br /&gt;
* Si un message a été perdu un message d'erreur est envoyé de la par du serveur (OPERATION 0x23) de contenu 0x01.&lt;br /&gt;
&lt;br /&gt;
La récupération du contenu de la requête est du même type que celle du LS. Les messages de retour sont construits de la même façon que pour le message de retour du LS. Enfin on utilise fopen une nouvelle fois pour ouvrir le fichier, fwrite pour y écrire et fclose pour le fermer.&lt;br /&gt;
&lt;br /&gt;
==== Préparation du test ====&lt;br /&gt;
Avant de pouvoir tester notre serveur avec la carte réseau (ce qui n'aura jamais été fait car la carte réseau n'envoie rien) nous avons souhaité validé le fonctionnement du serveur en simulant des requêtes de la carte réseau. On voit ce que le serveur fait via des printf et en créant un autre serveur (plus rudimentaire) on peut vérifier que le serveur répond correctement. Sur notre git le dossier testUDP est consacré à cette phase de tests.&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2025-1&amp;diff=8621</id>
		<title>SE4Binome2025-1</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2025-1&amp;diff=8621"/>
		<updated>2025-12-11T16:00:10Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Shield Arduino =&lt;br /&gt;
== Hardware ==&lt;br /&gt;
Afin de tester notre futur carte réseau, nous avons fait un shield d'arduino qui prendra le rôle de la carte mère durant. &lt;br /&gt;
=== Schématique ===&lt;br /&gt;
Nous nous sommes évidemment aider de la datasheet de l'atmega328p ainsi que celle de l'arduino uno afin de sélectionner les bon pins.&lt;br /&gt;
[[Fichier:Atmel-7810-Automotive-Microcontrollers-ATmega328P Datasheet.pdf|centré|vignette|Datasheet ATmega328p]]&lt;br /&gt;
[[Fichier:A000066-datasheet.pdf|centré|vignette|Datasheet Arduino Uno R3]]&lt;br /&gt;
Plus précisément nous nous inspirons très fortement du schéma page 10 de la datasheet de l'arduino :&lt;br /&gt;
[[Fichier:Screenshot 2025-11-07 11-08-46.png|centré|vignette|Schéma pinouts]]&lt;br /&gt;
Nous sommes donc parti de l'exemple fourni par Mr Redon. Mais nous avons utilisé une template disponible dans kicad permettant de créer des shields d'arduino Uno R3.[[Fichier:Tyetyuy.png|vignette|Schématique shield arduino|centré|438x438px]]&lt;br /&gt;
=== Routage ===&lt;br /&gt;
Au niveau du routage, nous avons tenté de faire simple (sans trop abuser sur les vias. Nous avons positionner le lecteur de carte sd au bord de la carte afin de ne pas avoir de problèmes avec d'autres composants lorsque nous voudrons mettre ou enlever la carte sd.&lt;br /&gt;
[[Fichier:Routage shield arduino.png|vignette|Routage shield arduino|centré|434x434px]]&lt;br /&gt;
&lt;br /&gt;
===Soudage===&lt;br /&gt;
La schématique et le routage terminés, nous avons soudé les différents pins permettant de souder la carte shield à l'arduino, le reste n'étant pas forcément utile pour le moment (il est important de noter que notre shield est arrivé avec des composants pré-soudés).&lt;br /&gt;
[[Fichier:Shield soudage de base .jpg|centré|vignette]]&lt;br /&gt;
&lt;br /&gt;
===Tests===&lt;br /&gt;
====Leds====&lt;br /&gt;
&lt;br /&gt;
Il faudra ensuite faire des test d'allumage des leds, afin de vérifier le bon fonctionnement du shield&lt;br /&gt;
[[Fichier:VID leds.mp4|centré|vignette]]&lt;br /&gt;
&lt;br /&gt;
Les leds fonctionnent à merveille.&lt;br /&gt;
&lt;br /&gt;
====Carte SD====&lt;br /&gt;
&lt;br /&gt;
Nous vérifions maintenant la carte sd (même si elle nous sera inutile pour notre projet)&lt;br /&gt;
&lt;br /&gt;
Nous utilisons le programme fourni par arduino qui permet de récuopéré les informatiuons de la carte sd.&lt;br /&gt;
[[Fichier:Test sd card.png|centré|vignette]]&lt;br /&gt;
La carte SD est bien identifié, le lecteur de carte fonctionne donc normalement.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
=== Ordonnanceur ===&lt;br /&gt;
[à completer  et commenter , seulement des codes pour le moment !!!!]&lt;br /&gt;
==== Ordonnanceur basique ====&lt;br /&gt;
La première étape consiste à définir la structure d'un process, il sera composé :&lt;br /&gt;
&lt;br /&gt;
-d'un pointeur de pile&lt;br /&gt;
&lt;br /&gt;
-de l'adresse de la fonction&lt;br /&gt;
&lt;br /&gt;
-d'un temps de sommeil &lt;br /&gt;
&lt;br /&gt;
-d'un état : 0 pour en cours et 1 pour terminé ou vide&lt;br /&gt;
&lt;br /&gt;
Ces deux derniers points nous servirons plus tard.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
typedef struct {&lt;br /&gt;
	uint16_t stackPointer;&lt;br /&gt;
	void (*functionAddress)(void);&lt;br /&gt;
	int sleep_time;&lt;br /&gt;
	int state;&lt;br /&gt;
} process;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On initialise donc notre tableau de processus de la façon suivante : &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
process Tasks_list[NBTASKS] = {&lt;br /&gt;
                                {0, led1_blink, 0,0},&lt;br /&gt;
				...&lt;br /&gt;
			       };&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Concernant les fonction liés leds, on utilise une simple boucle while contenant un changement d'état &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void led_init() {&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
void led1_blink() {&lt;br /&gt;
	while(1) {&lt;br /&gt;
		PORTC ^= (1&amp;lt;&amp;lt;PLED1);&lt;br /&gt;
		_delay_ms(100);&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
void led2_blink() {&lt;br /&gt;
...	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_stackPointer_tasks() permet de diviser la pile &amp;quot;réel&amp;quot; en plusieurs piles pour chaque processus.  Ces sous piles commence à la position FIRST_STACK_POSITION, afin de ne pas réécrire par dessus des données. Toutes les sous piles diposent d'une même taille de pile STACK_LENGTH.&lt;br /&gt;
&lt;br /&gt;
La fonction init_piles() initialise correctement la pile avec le tableau de processus si le processus est actif.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void init_stackPointer_tasks(int Cprocess) { //initialise le pointer de pile&lt;br /&gt;
	if(Tasks_list[Cprocess].state == 0) {&lt;br /&gt;
		Tasks_list[Cprocess].stackPointer = FIRST_STACK_POSITION - (Cprocess * STACK_LENGTH);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void init_piles(int Cprocess){ //initilalise la pile&lt;br /&gt;
	if(Tasks_list[Cprocess].state == 0) {&lt;br /&gt;
		int save = SP;&lt;br /&gt;
		SP = Tasks_list[Cprocess].stackPointer;&lt;br /&gt;
		uint16_t address = (uint16_t)Tasks_list[Cprocess].functionAddress;&lt;br /&gt;
		asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (address &amp;amp; 0x00ff) );&lt;br /&gt;
		asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((address &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
		SAVE_REGISTERS();&lt;br /&gt;
		Tasks_list[Cprocess].stackPointer = SP;&lt;br /&gt;
		SP = save;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;le scheduler permet de passer à la tâche suivante&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
	Current_task++;&lt;br /&gt;
	if (Current_task &amp;gt;= NBTASKS) {&lt;br /&gt;
		Current_task = 0; &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;l'atmega328p ne dispose pas de de fonction en assembleur permettant de push ou de pop tout les registres. on doit donc le faire un par un.&lt;br /&gt;
&lt;br /&gt;
On défini alors les macros suivantes :  &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
#define SAVE_REGISTERS() \&lt;br /&gt;
	asm volatile ( \&lt;br /&gt;
		&amp;quot;push r0 	 \n\t&amp;quot; \&lt;br /&gt;
		...\&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#define RESTORE_REGISTERS() \&lt;br /&gt;
	asm volatile ( \&lt;br /&gt;
		&amp;quot;pop r31 	  \n\t&amp;quot; \&lt;br /&gt;
		...\&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;L'ISR gère les interruptions, en commençant par sauvegarder l'état de la pile ainsi que le stack pointeur propre au processus qui s'interrompt. L'appel au schedruler permet de changer de processus pour cela il faut restorer le stack pointer propre au nouveau processus actif et de la pile liée à ce processus. La dernière ligne arrête l'ISR.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED) {&lt;br /&gt;
	SAVE_REGISTERS();&lt;br /&gt;
	Tasks_list[Current_task].stackPointer = SP;&lt;br /&gt;
	scheduler();&lt;br /&gt;
	SP = Tasks_list[Current_task].stackPointer;&lt;br /&gt;
	RESTORE_REGISTERS();&lt;br /&gt;
	asm volatile(&amp;quot;reti&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=====test=====&lt;br /&gt;
Les processus de clignotement de leds ont tous un délai d'attente différent, l'interruption se produit toutes les millisecondes. On obtient ceci :[[Fichier:Ordonnanceur basique.mp4|centré|vignette]]Il est intéressant de remarqué que la vitesse à laquelle les leds changent d'état ne correspond pas au délai qui leur à été donné. Cela parait logique puisque l'interruption met la fonction _delay_ms en pause, ainsi la vitesse se voit divisé par le nombre de processus actif.&lt;br /&gt;
&lt;br /&gt;
====Ajout d'un système d'endormissement des processus====&lt;br /&gt;
&lt;br /&gt;
La fonction wait va permettre d'endormir un processus, elle va donné un temps de sommeil au processus puis lancer une interruption (car on veut changer de processus directement après que le précédent ait été endormi).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time) { // met un process en veille pour une durée donné&lt;br /&gt;
	// valeur max de time 32000 car int sur atmega328p code sur 16 bits donc 32000 max&lt;br /&gt;
	cli();&lt;br /&gt;
	Tasks_list[Current_task].sleep_time = time;&lt;br /&gt;
	TCNT1=0;&lt;br /&gt;
	sei();&lt;br /&gt;
	TIMER1_COMPA_vect();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour verifier si un processus a besoin d'être lancé, on ajoute une boucle while dans le scheduler afin de vérifier si il y a un temps de sommeil. Le scheduler va aussi servir à diminuer le temps de sommeil de tout les processus (avec un minimum de 0).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
	for (int i=0 ; i&amp;lt;NBTASKS ; i++) {&lt;br /&gt;
		if (Tasks_list[i].sleep_time - SLEEP_DEC &amp;lt; 0) {&lt;br /&gt;
			Tasks_list[i].sleep_time = 0;&lt;br /&gt;
		} else {&lt;br /&gt;
			Tasks_list[i].sleep_time -= SLEEP_DEC;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	do {&lt;br /&gt;
		Current_task++;&lt;br /&gt;
		if (Current_task &amp;gt;= NBTASKS) {&lt;br /&gt;
			Current_task = 0;&lt;br /&gt;
		}&lt;br /&gt;
	} while (Tasks_list[Current_task].sleep_time &amp;gt; 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Tableau dynamique des tâches====&lt;br /&gt;
&lt;br /&gt;
En premier lieu on va initialiser les état de tout les cases du tableau de processus. On choisit 1 la case est vide, 0 sinon.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void init_state() { //initialise state&lt;br /&gt;
	for (int i= 0; i&amp;lt;NBTASKS; i++) {&lt;br /&gt;
		if (Tasks_list[i].functionAddress == NULL) {&lt;br /&gt;
			Tasks_list[i].state = 1;&lt;br /&gt;
		}&lt;br /&gt;
		else {&lt;br /&gt;
			Tasks_list[i].state = 0;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Nous avons programmé deux fonction d'arrêt et une fonction d'ajout de processus :&lt;br /&gt;
&lt;br /&gt;
-finish stop le processus en cours et le supprime de tableau, puis lance une interruption&lt;br /&gt;
&lt;br /&gt;
-kill stop un processus donné et le supprime du tableau &lt;br /&gt;
&lt;br /&gt;
-add ajoute un processus sur la première case vide du tableau, initialise son pointeur de position et sa pile.&lt;br /&gt;
&lt;br /&gt;
Pour finish et kill, on met le temps de sommeil à 0 au cas où on arrête un processus endormi. C'est une mesure de sécurité pour finish, mais une obligation pour kill.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void finish() { //supprime un process lorsque celui-ci est terminé&lt;br /&gt;
	cli();&lt;br /&gt;
		Tasks_list[Current_task].state =1;&lt;br /&gt;
		Tasks_list[Current_task].sleep_time = 0;&lt;br /&gt;
		Tasks_list[Current_task].functionAddress = NULL;&lt;br /&gt;
	TCNT1=0; &lt;br /&gt;
	sei();&lt;br /&gt;
	TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void kill(void (*function)(void)) { //tue le process passé en paramètre&lt;br /&gt;
	cli();&lt;br /&gt;
	for(int i = 0; i&amp;lt;NBTASKS; i++) {&lt;br /&gt;
		if(Tasks_list[i].functionAddress == function) {&lt;br /&gt;
			Tasks_list[i].state =1;&lt;br /&gt;
			Tasks_list[i].sleep_time = 0;&lt;br /&gt;
			Tasks_list[i].functionAddress = NULL;&lt;br /&gt;
		}&lt;br /&gt;
	} &lt;br /&gt;
	sei();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void add(void (*newFunction)(void)) { //ajoute un process&lt;br /&gt;
	cli();&lt;br /&gt;
	int i =0;&lt;br /&gt;
	while(Tasks_list[i].state != 1) {&lt;br /&gt;
		i++;&lt;br /&gt;
	}&lt;br /&gt;
	Tasks_list[i].functionAddress = newFunction;&lt;br /&gt;
	Tasks_list[i].state = 0;&lt;br /&gt;
	init_stackPointer_tasks(i);&lt;br /&gt;
	init_piles(i);&lt;br /&gt;
&lt;br /&gt;
	sei();&lt;br /&gt;
	&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Il suffit maintenant de modifier le scheduler afin de ne pas prendre les processus terminé, puis utiliser add, finish et kill dans les fonctions choisis.&lt;br /&gt;
&lt;br /&gt;
=====test=====&lt;br /&gt;
Pour tester les fonction add et finish, on fait le test suivant :&lt;br /&gt;
&lt;br /&gt;
-on créer un process qui ajoute le process led2_blink (avec add) au bout d'un certain temps&lt;br /&gt;
&lt;br /&gt;
-le process led2_blink s'arrête (avec finish) au bout de 20 changement d'état (c'est à dire 10 clignotement).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
on obtient le résultat suivant :[[Fichier:Demo fonction add et finish.mp4|centré|vignette]]&lt;br /&gt;
====lecture et écriture sur le port série====&lt;br /&gt;
Afin de lire et écrire sur le port série, on utilise les fonctions USART_Init, USART_Transmit et USART_Receive  vu en cours de microP l'année précédente. Le but sera donc d'écrire le message qui vient d'être reçu, on utilise donc le processus suivant :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====test=====&lt;br /&gt;
Pour tester notre processus de communication, on utilise minicom.[[Fichier:Test lecture et écriture port série.mp4|centré|vignette]]On notera que si la période entre les interruptions est trop élevé, certains caractères ne seront pas lus.&lt;br /&gt;
&lt;br /&gt;
====afficheur 7 segments====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void seven_seg() {&lt;br /&gt;
	while (1) {&lt;br /&gt;
        spi_activer((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
		spi_echange(0x7E);&lt;br /&gt;
		spi_echange(0b1101111);&lt;br /&gt;
		spi_desactiver((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
&lt;br /&gt;
		wait(500);&lt;br /&gt;
&lt;br /&gt;
		spi_activer((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
		spi_echange(0x76);&lt;br /&gt;
		spi_desactiver((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
&lt;br /&gt;
		wait(500);&lt;br /&gt;
    	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Le processus seven_seg est ajouté au tableau des processus. Avant d'échanger en spi il faut activer la communication, et la désactiver après l'échange. La ligne 4 permet de sélectionner le 7 seg sur lequel on souhaite modifier l'affichage. La ligne 5 permet d'afficher le chiffre 9. Enfin la ligne 11 permet de clear le display. Voir tableau ci-dessous.&lt;br /&gt;
[[Fichier:Tab 7 seg sparkfun.png|centré|vignette]]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void) {                                 // Initialisation du bus SPI&lt;br /&gt;
	SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);   // Définition des sorties&lt;br /&gt;
	SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // Définition de l'entrée                          &lt;br /&gt;
	SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
        	                                             // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
	SPI_DDR |= (1&amp;lt;&amp;lt;CS1) | (1&amp;lt;&amp;lt;CS4);;&lt;br /&gt;
	DDRD |= (1&amp;lt;&amp;lt;CS5) | (1&amp;lt;&amp;lt;CS6);&lt;br /&gt;
	DDRC |= (1&amp;lt;&amp;lt;CS2) | (1&amp;lt;&amp;lt;CS3);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void spi_activer(uint16_t port, uint8_t cs) { 	// Activer le périphérique&lt;br /&gt;
	volatile uint8_t *reg = (volatile uint8_t*)port;&lt;br /&gt;
	*reg &amp;amp;= ~(1&amp;lt;&amp;lt;cs);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(uint16_t port, uint8_t cs) {                           // Désactiver le périphérique&lt;br /&gt;
	volatile uint8_t *reg = (volatile uint8_t*)port;&lt;br /&gt;
	*reg |= (1&amp;lt;&amp;lt;cs);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi) {                  // Communication sur le bus SPI&lt;br /&gt;
	SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
	while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
	return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de rendre nos fonctions les plus réutilisables possibles nous avons passer en paramètre le port ainsi que le CS qui correspond au slave select. Le type réel du port est volatile uint8* cependant le compilateur n'accepte que le uint16* ce qui explique le cast un peu étrange.&lt;br /&gt;
&lt;br /&gt;
=====Implémentation=====&lt;br /&gt;
[[Fichier:Video7segvideo.mp4|vignette|centré]]L'implémentation correspond à nos attentes, seul un 7 seg affiche le chiffre 9.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====choix du processus sur le port série====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
afin de pouvoir démontrer le bon fonctionnement de la partie dynamique, on décide de pouvoir ajouter et tuer des processus à partir des touches du clavier. On utilisera donc les fonction de l'USART défini plus au au travers de la fonction suivante:&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void call_process() {&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1) {&lt;br /&gt;
        data = USART_Receive();&lt;br /&gt;
        if(data == '1') {&lt;br /&gt;
            add(led1_blink);&lt;br /&gt;
        }&lt;br /&gt;
        ...&lt;br /&gt;
        else if(data == '6') {&lt;br /&gt;
            kill(led1_blink);&lt;br /&gt;
        }&lt;br /&gt;
        ...&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On remarquera que c'est une sorte d'amélioration de la fonction Serial_Message vu plus haut.&lt;br /&gt;
&lt;br /&gt;
Cette fonction aura la fonction de process de base, toujours présent dans l'ordonnaceur.&lt;br /&gt;
&lt;br /&gt;
=====Démonstation===== &lt;br /&gt;
[[Fichier:Process via USART.mp4|centré|vignette]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ici on lance les processus ledN_blink avec les touches 1 à 5 et on les tues avec les touches 6 à 0. Pour le 7 segments, on l'ajoute avec s et le tue avec d. &lt;br /&gt;
&lt;br /&gt;
=Carte Réseau=&lt;br /&gt;
Lors de la répartition des tâches, nous avons opté pour la carte réseau. &lt;br /&gt;
==Description==&lt;br /&gt;
Le sujet nous permettait de choisir parmi plusieurs microcontrôleurs. Nous avons retenu l’ATmega32U4, qui nous semble représenter un juste milieu entre l’ATmega16U2 et l’AT90USB.&lt;br /&gt;
==Hardware==&lt;br /&gt;
Notre carte intègre des LED permettant d’afficher différents états de communication (que nous définirons ultérieurement).&lt;br /&gt;
&lt;br /&gt;
À la demande de M. Redon, nous avons ajouté un MAX232 ainsi que des connecteurs DB9 et DB25. Nous espérons que ces éléments pourront être utiles.&lt;br /&gt;
===Schématque===&lt;br /&gt;
[[Fichier:Schématique CReseau.png|vignette|540x540px|centré]]&lt;br /&gt;
===Routage===&lt;br /&gt;
[[Fichier:Routage Creseau.png|vignette|521x521px|centré]]Une fois la lufa réduite et flashé, on donne une adresse ip à notre inteface avec ip link eth2 up et  ip address add 10.0.0.1/24 dev eth2.  on test un ping sur l'adresse ip de la carte (10.0.0.2).&lt;br /&gt;
[[Fichier:Ping creseau.mp4|centré|vignette]]&lt;br /&gt;
[[Fichier:Ping allume led.mov|vignette|La led s'éteint à chaque ping reçue]]&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Ping_allume_led.mov&amp;diff=8620</id>
		<title>Fichier:Ping allume led.mov</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Ping_allume_led.mov&amp;diff=8620"/>
		<updated>2025-12-11T15:55:52Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;La led s'allume à chaque ping reçu&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2025-1&amp;diff=8515</id>
		<title>SE4Binome2025-1</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2025-1&amp;diff=8515"/>
		<updated>2025-11-24T10:15:18Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : /* test */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Shield Arduino =&lt;br /&gt;
== Hardware ==&lt;br /&gt;
Afin de tester notre futur carte réseau, nous avons fait un shield d'arduino qui prendra le rôle de la carte mère durant. &lt;br /&gt;
=== Schématique ===&lt;br /&gt;
Nous nous sommes évidemment aider de la datasheet de l'atmega328p ainsi que celle de l'arduino uno afin de sélectionner les bon pins.&lt;br /&gt;
[[Fichier:Atmel-7810-Automotive-Microcontrollers-ATmega328P Datasheet.pdf|centré|vignette|Datasheet ATmega328p]]&lt;br /&gt;
[[Fichier:A000066-datasheet.pdf|centré|vignette|Datasheet Arduino Uno R3]]&lt;br /&gt;
Plus précisément nous nous inspirons très fortement du schéma page 10 de la datasheet de l'arduino :&lt;br /&gt;
[[Fichier:Screenshot 2025-11-07 11-08-46.png|centré|vignette|Schéma pinouts]]&lt;br /&gt;
Nous sommes donc parti de l'exemple fourni par Mr Redon. Mais nous avons utilisé une template disponible dans kicad permettant de créer des shields d'arduino Uno R3.[[Fichier:Tyetyuy.png|vignette|Schématique shield arduino|centré|438x438px]]&lt;br /&gt;
=== Routage ===&lt;br /&gt;
Au niveau du routage, nous avons tenté de faire simple (sans trop abuser sur les vias. Nous avons positionner le lecteur de carte sd au bord de la carte afin de ne pas avoir de problèmes avec d'autres composants lorsque nous voudrons mettre ou enlever la carte sd.&lt;br /&gt;
[[Fichier:Routage shield arduino.png|vignette|Routage shield arduino|centré|434x434px]]&lt;br /&gt;
&lt;br /&gt;
===Soudage===&lt;br /&gt;
La schématique et le routage terminés, nous avons soudé les différents pins permettant de souder la carte shield à l'arduino, le reste n'étant pas forcément utile pour le moment (il est important de noter que notre shield est arrivé avec des composants pré-soudés).&lt;br /&gt;
[[Fichier:Shield soudage de base .jpg|centré|vignette]]&lt;br /&gt;
&lt;br /&gt;
===Tests===&lt;br /&gt;
Il faudra ensuite faire des test d'allumage des leds, afin de vérifier le bon fonctionnement du shield&lt;br /&gt;
[[Fichier:VID leds.mp4|centré|vignette]]&lt;br /&gt;
&lt;br /&gt;
Les leds fonctionnant à merveille, Il est temps de passer de passer à l'ordonnanceur.&lt;br /&gt;
== Software ==&lt;br /&gt;
=== Ordonnanceur ===&lt;br /&gt;
[à completer  et commenter , seulement des codes pour le moment !!!!]&lt;br /&gt;
==== Ordonnanceur basique ====&lt;br /&gt;
La première étape consiste à définir la structure d'un process, il sera composé :&lt;br /&gt;
&lt;br /&gt;
-d'un pointeur de pile&lt;br /&gt;
&lt;br /&gt;
-de l'adresse de la fonction&lt;br /&gt;
&lt;br /&gt;
-d'un temps de sommeil &lt;br /&gt;
&lt;br /&gt;
-d'un état : 0 pour en cours et 1 pour terminé ou vide&lt;br /&gt;
&lt;br /&gt;
Ces deux derniers points nous servirons plus tard.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
typedef struct {&lt;br /&gt;
	uint16_t stackPointer;&lt;br /&gt;
	void (*functionAddress)(void);&lt;br /&gt;
	int sleep_time;&lt;br /&gt;
	int state;&lt;br /&gt;
} process;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On initialise donc notre tableau de processus de la façon suivante : &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
process Tasks_list[NBTASKS] = {&lt;br /&gt;
                                {0, led1_blink, 0,0},&lt;br /&gt;
				...&lt;br /&gt;
			       };&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Concernant les fonction liés leds, on utilise une simple boucle while contenant un changement d'état &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void led_init() {&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
void led1_blink() {&lt;br /&gt;
	while(1) {&lt;br /&gt;
		PORTC ^= (1&amp;lt;&amp;lt;PLED1);&lt;br /&gt;
		_delay_ms(100);&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
void led2_blink() {&lt;br /&gt;
...	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_stackPointer_tasks() permet de diviser la pile &amp;quot;réel&amp;quot; en plusieurs piles pour chaque processus.  Ces sous piles commence à la position FIRST_STACK_POSITION, afin de ne pas réécrire par dessus des données. Toutes les sous piles diposent d'une même taille de pile STACK_LENGTH.&lt;br /&gt;
&lt;br /&gt;
La fonction init_piles() initialise correctement la pile avec le tableau de processus si le processus est actif.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void init_stackPointer_tasks(int Cprocess) { //initialise le pointer de pile&lt;br /&gt;
	if(Tasks_list[Cprocess].state == 0) {&lt;br /&gt;
		Tasks_list[Cprocess].stackPointer = FIRST_STACK_POSITION - (Cprocess * STACK_LENGTH);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void init_piles(int Cprocess){ //initilalise la pile&lt;br /&gt;
	if(Tasks_list[Cprocess].state == 0) {&lt;br /&gt;
		int save = SP;&lt;br /&gt;
		SP = Tasks_list[Cprocess].stackPointer;&lt;br /&gt;
		uint16_t address = (uint16_t)Tasks_list[Cprocess].functionAddress;&lt;br /&gt;
		asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (address &amp;amp; 0x00ff) );&lt;br /&gt;
		asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((address &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
		SAVE_REGISTERS();&lt;br /&gt;
		Tasks_list[Cprocess].stackPointer = SP;&lt;br /&gt;
		SP = save;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;le scheduler permet de passer à la tâche suivante&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
	Current_task++;&lt;br /&gt;
	if (Current_task &amp;gt;= NBTASKS) {&lt;br /&gt;
		Current_task = 0; &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;l'atmega328p ne dispose pas de de fonction en assembleur permettant de push ou de pop tout les registres. on doit donc le faire un par un.&lt;br /&gt;
&lt;br /&gt;
On défini alors les macros suivantes :  &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
#define SAVE_REGISTERS() \&lt;br /&gt;
	asm volatile ( \&lt;br /&gt;
		&amp;quot;push r0 	 \n\t&amp;quot; \&lt;br /&gt;
		...\&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#define RESTORE_REGISTERS() \&lt;br /&gt;
	asm volatile ( \&lt;br /&gt;
		&amp;quot;pop r31 	  \n\t&amp;quot; \&lt;br /&gt;
		...\&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;L'ISR gère les interruptions, en commençant par sauvegarder l'état de la pile ainsi que le stack pointeur propre au processus qui s'interrompt. L'appel au schedruler permet de changer de processus pour cela il faut restorer le stack pointer propre au nouveau processus actif et de la pile liée à ce processus. La dernière ligne arrête l'ISR.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED) {&lt;br /&gt;
	SAVE_REGISTERS();&lt;br /&gt;
	Tasks_list[Current_task].stackPointer = SP;&lt;br /&gt;
	scheduler();&lt;br /&gt;
	SP = Tasks_list[Current_task].stackPointer;&lt;br /&gt;
	RESTORE_REGISTERS();&lt;br /&gt;
	asm volatile(&amp;quot;reti&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=====test=====&lt;br /&gt;
Les processus de clignotement de leds ont tous un délai d'attente différent, l'interruption se produit toutes les millisecondes. On obtient ceci :[[Fichier:Ordonnanceur basique.mp4|centré|vignette]]Il est intéressant de remarqué que la vitesse à laquelle les leds changent d'état ne correspond pas au délai qui leur à été donné. Cela parait logique puisque l'interruption met la fonction _delay_ms en pause, ainsi la vitesse se voit divisé par le nombre de processus actif.&lt;br /&gt;
&lt;br /&gt;
====Ajout d'un système d'endormissement des processus====&lt;br /&gt;
&lt;br /&gt;
La fonction wait va permettre d'endormir un processus, elle va donné un temps de sommeil au processus puis lancer une interruption (car on veut changer de processus directement après que le précédent ait été endormi).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time) { // met un process en veille pour une durée donné&lt;br /&gt;
	// valeur max de time 32000 car int sur atmega328p code sur 16 bits donc 32000 max&lt;br /&gt;
	cli();&lt;br /&gt;
	Tasks_list[Current_task].sleep_time = time;&lt;br /&gt;
	TCNT1=0;&lt;br /&gt;
	sei();&lt;br /&gt;
	TIMER1_COMPA_vect();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour verifier si un processus a besoin d'être lancé, on ajoute une boucle while dans le scheduler afin de vérifier si il y a un temps de sommeil. Le scheduler va aussi servir à diminuer le temps de sommeil de tout les processus (avec un minimum de 0).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
	for (int i=0 ; i&amp;lt;NBTASKS ; i++) {&lt;br /&gt;
		if (Tasks_list[i].sleep_time - SLEEP_DEC &amp;lt; 0) {&lt;br /&gt;
			Tasks_list[i].sleep_time = 0;&lt;br /&gt;
		} else {&lt;br /&gt;
			Tasks_list[i].sleep_time -= SLEEP_DEC;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	do {&lt;br /&gt;
		Current_task++;&lt;br /&gt;
		if (Current_task &amp;gt;= NBTASKS) {&lt;br /&gt;
			Current_task = 0;&lt;br /&gt;
		}&lt;br /&gt;
	} while (Tasks_list[Current_task].sleep_time &amp;gt; 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Tableau dynamique des tâches====&lt;br /&gt;
&lt;br /&gt;
En premier lieu on va initialiser les état de tout les cases du tableau de processus. On choisit 1 la case est vide, 0 sinon.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void init_state() { //initialise state&lt;br /&gt;
	for (int i= 0; i&amp;lt;NBTASKS; i++) {&lt;br /&gt;
		if (Tasks_list[i].functionAddress == NULL) {&lt;br /&gt;
			Tasks_list[i].state = 1;&lt;br /&gt;
		}&lt;br /&gt;
		else {&lt;br /&gt;
			Tasks_list[i].state = 0;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Nous avons programmé deux fonction d'arrêt et une fonction d'ajout de processus :&lt;br /&gt;
&lt;br /&gt;
-finish stop le processus en cours et le supprime de tableau, puis lance une interruption&lt;br /&gt;
&lt;br /&gt;
-kill stop un processus donné et le supprime du tableau &lt;br /&gt;
&lt;br /&gt;
-add ajoute un processus sur la première case vide du tableau, initialise son pointeur de position et sa pile.&lt;br /&gt;
&lt;br /&gt;
Pour finish et kill, on met le temps de sommeil à 0 au cas où on arrête un processus endormi. C'est une mesure de sécurité pour finish, mais une obligation pour kill.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void finish() { //supprime un process lorsque celui-ci est terminé&lt;br /&gt;
	cli();&lt;br /&gt;
		Tasks_list[Current_task].state =1;&lt;br /&gt;
		Tasks_list[Current_task].sleep_time = 0;&lt;br /&gt;
		Tasks_list[Current_task].functionAddress = NULL;&lt;br /&gt;
	TCNT1=0; &lt;br /&gt;
	sei();&lt;br /&gt;
	TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void kill(void (*function)(void)) { //tue le process passé en paramètre&lt;br /&gt;
	cli();&lt;br /&gt;
	for(int i = 0; i&amp;lt;NBTASKS; i++) {&lt;br /&gt;
		if(Tasks_list[i].functionAddress == function) {&lt;br /&gt;
			Tasks_list[i].state =1;&lt;br /&gt;
			Tasks_list[i].sleep_time = 0;&lt;br /&gt;
			Tasks_list[i].functionAddress = NULL;&lt;br /&gt;
		}&lt;br /&gt;
	} &lt;br /&gt;
	sei();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void add(void (*newFunction)(void)) { //ajoute un process&lt;br /&gt;
	cli();&lt;br /&gt;
	int i =0;&lt;br /&gt;
	while(Tasks_list[i].state != 1) {&lt;br /&gt;
		i++;&lt;br /&gt;
	}&lt;br /&gt;
	Tasks_list[i].functionAddress = newFunction;&lt;br /&gt;
	Tasks_list[i].state = 0;&lt;br /&gt;
	init_stackPointer_tasks(i);&lt;br /&gt;
	init_piles(i);&lt;br /&gt;
&lt;br /&gt;
	sei();&lt;br /&gt;
	&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Il suffit maintenant de modifier le scheduler afin de ne pas prendre les processus terminé, puis utiliser add, finish et kill dans les fonctions choisis.&lt;br /&gt;
&lt;br /&gt;
=====test=====&lt;br /&gt;
Pour tester les fonction add et finish, on fait le test suivant :&lt;br /&gt;
&lt;br /&gt;
-on créer un process qui ajoute le process led2_blink (avec add) au bout d'un certain temps&lt;br /&gt;
&lt;br /&gt;
-le process led2_blink s'arrête (avec finish) au bout de 20 changement d'état (c'est à dire 10 clignotement).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
on obtient le résultat suivant :[[Fichier:Demo fonction add et finish.mp4|centré|vignette]]&lt;br /&gt;
====lecture et écriture sur le port série====&lt;br /&gt;
Afin de lire et écrire sur le port série, on utilise les fonctions USART_Init, USART_Transmit et USART_Receive  vu en cours de microP l'année précédente. Le but sera donc d'écrire le message qui vient d'être reçu, on utilise donc le processus suivant :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====test=====&lt;br /&gt;
Pour tester notre processus de communication, on utilise minicom.[[Fichier:Test lecture et écriture port série.mp4|centré|vignette]]On notera que si la période entre les interruptions est trop élevé, certains caractères ne seront pas lus.&lt;br /&gt;
&lt;br /&gt;
====afficheur 7 segments====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void seven_seg() {&lt;br /&gt;
	while (1) {&lt;br /&gt;
        spi_activer((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
		spi_echange(0x7E);&lt;br /&gt;
		spi_echange(0b1101111);&lt;br /&gt;
		spi_desactiver((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
&lt;br /&gt;
		wait(500);&lt;br /&gt;
&lt;br /&gt;
		spi_activer((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
		spi_echange(0x76);&lt;br /&gt;
		spi_desactiver((uint16_t)&amp;amp;PORTB, CS4);&lt;br /&gt;
&lt;br /&gt;
		wait(500);&lt;br /&gt;
    	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Le processus seven_seg est ajouté au tableau des processus. Avant d'échanger en spi il faut activer la communication, et la désactiver après l'échange. La ligne 4 permet de sélectionner le 7 seg sur lequel on souhaite modifier l'affichage. La ligne 5 permet d'afficher le chiffre 9. Enfin la ligne 11 permet de clear le display. Voir tableau ci-dessous.&lt;br /&gt;
[[Fichier:Tab 7 seg sparkfun.png|centré|vignette]]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void) {                                 // Initialisation du bus SPI&lt;br /&gt;
	SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);   // Définition des sorties&lt;br /&gt;
	SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // Définition de l'entrée                          &lt;br /&gt;
	SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
        	                                             // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
	SPI_DDR |= (1&amp;lt;&amp;lt;CS1) | (1&amp;lt;&amp;lt;CS4);;&lt;br /&gt;
	DDRD |= (1&amp;lt;&amp;lt;CS5) | (1&amp;lt;&amp;lt;CS6);&lt;br /&gt;
	DDRC |= (1&amp;lt;&amp;lt;CS2) | (1&amp;lt;&amp;lt;CS3);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void spi_activer(uint16_t port, uint8_t cs) { 	// Activer le périphérique&lt;br /&gt;
	volatile uint8_t *reg = (volatile uint8_t*)port;&lt;br /&gt;
	*reg &amp;amp;= ~(1&amp;lt;&amp;lt;cs);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(uint16_t port, uint8_t cs) {                           // Désactiver le périphérique&lt;br /&gt;
	volatile uint8_t *reg = (volatile uint8_t*)port;&lt;br /&gt;
	*reg |= (1&amp;lt;&amp;lt;cs);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi) {                  // Communication sur le bus SPI&lt;br /&gt;
	SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
	while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
	return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de rendre nos fonctions les plus réutilisables possibles nous avons passer en paramètre le port ainsi que le CS qui correspond au slave select. Le type réel du port est volatile uint8* cependant le compilateur n'accepte que le uint16* ce qui explique le cast un peu étrange.&lt;br /&gt;
&lt;br /&gt;
=====Implémentation=====&lt;br /&gt;
[[Fichier:Video7segvideo.mp4|vignette|centré]]L'implémentation correspond à nos attentes, seul un 7 seg affiche le chiffre 9.&lt;br /&gt;
&lt;br /&gt;
=Carte Réseau=&lt;br /&gt;
Lors de la répartition des tâches, nous avons opté pour la carte réseau. &lt;br /&gt;
==Description==&lt;br /&gt;
Le sujet nous permettait de choisir parmi plusieurs microcontrôleurs. Nous avons retenu l’ATmega32U4, qui nous semble représenter un juste milieu entre l’ATmega16U2 et l’AT90USB.&lt;br /&gt;
==Hardware==&lt;br /&gt;
Notre carte intègre des LED permettant d’afficher différents états de communication (que nous définirons ultérieurement).&lt;br /&gt;
&lt;br /&gt;
À la demande de M. Redon, nous avons ajouté un MAX232 ainsi que des connecteurs DB9 et DB25. Nous espérons que ces éléments pourront être utiles.&lt;br /&gt;
===Schématque===&lt;br /&gt;
[[Fichier:Schématique CReseau.png|vignette|540x540px|centré]]&lt;br /&gt;
===Routage===&lt;br /&gt;
[[Fichier:Routage Creseau.png|vignette|521x521px|centré]]&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Tab_7_seg_sparkfun.png&amp;diff=8514</id>
		<title>Fichier:Tab 7 seg sparkfun.png</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Tab_7_seg_sparkfun.png&amp;diff=8514"/>
		<updated>2025-11-24T10:02:58Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;.&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2025-1&amp;diff=8513</id>
		<title>SE4Binome2025-1</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2025-1&amp;diff=8513"/>
		<updated>2025-11-21T11:16:21Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : /* Carte Réseau */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Shield Arduino =&lt;br /&gt;
== Hardware ==&lt;br /&gt;
Afin de tester notre futur carte réseau, nous avons fait un shield d'arduino qui prendra le rôle de la carte mère durant. &lt;br /&gt;
=== Schématique ===&lt;br /&gt;
Nous nous sommes évidemment aider de la datasheet de l'atmega328p ainsi que celle de l'arduino uno afin de sélectionner les bon pins.&lt;br /&gt;
[[Fichier:Atmel-7810-Automotive-Microcontrollers-ATmega328P Datasheet.pdf|centré|vignette|Datasheet ATmega328p]]&lt;br /&gt;
[[Fichier:A000066-datasheet.pdf|centré|vignette|Datasheet Arduino Uno R3]]&lt;br /&gt;
Plus précisément nous nous inspirons très fortement du schéma page 10 de la datasheet de l'arduino :&lt;br /&gt;
[[Fichier:Screenshot 2025-11-07 11-08-46.png|centré|vignette|Schéma pinouts]]&lt;br /&gt;
Nous sommes donc parti de l'exemple fourni par Mr Redon. Mais nous avons utilisé une template disponible dans kicad permettant de créer des shields d'arduino Uno R3.[[Fichier:Tyetyuy.png|vignette|Schématique shield arduino|centré|438x438px]]&lt;br /&gt;
=== Routage ===&lt;br /&gt;
Au niveau du routage, nous avons tenté de faire simple (sans trop abuser sur les vias. Nous avons positionner le lecteur de carte sd au bord de la carte afin de ne pas avoir de problèmes avec d'autres composants lorsque nous voudrons mettre ou enlever la carte sd.&lt;br /&gt;
[[Fichier:Routage shield arduino.png|vignette|Routage shield arduino|centré|434x434px]]&lt;br /&gt;
&lt;br /&gt;
===Soudage===&lt;br /&gt;
La schématique et le routage terminés, nous avons soudé les différents pins permettant de souder la carte shield à l'arduino, le reste n'étant pas forcément utile pour le moment (il est important de noter que notre shield est arrivé avec des composants pré-soudés).&lt;br /&gt;
[[Fichier:Shield soudage de base .jpg|centré|vignette]]&lt;br /&gt;
&lt;br /&gt;
===Tests===&lt;br /&gt;
Il faudra ensuite faire des test d'allumage des leds, afin de vérifier le bon fonctionnement du shield&lt;br /&gt;
[[Fichier:VID leds.mp4|centré|vignette]]&lt;br /&gt;
&lt;br /&gt;
Les leds fonctionnant à merveille, Il est temps de passer de passer à l'ordonnanceur.&lt;br /&gt;
== Software ==&lt;br /&gt;
=== Ordonnanceur ===&lt;br /&gt;
[à completer  et commenter , seulement des codes pour le moment !!!!]&lt;br /&gt;
==== Ordonnanceur basique ====&lt;br /&gt;
La première étape consiste à définir la structure d'un process, il sera composé :&lt;br /&gt;
&lt;br /&gt;
-d'un pointeur de pile&lt;br /&gt;
&lt;br /&gt;
-de l'adresse de la fonction&lt;br /&gt;
&lt;br /&gt;
-d'un temps de sommeil &lt;br /&gt;
&lt;br /&gt;
-d'un état : 0 pour en cours et 1 pour terminé ou vide&lt;br /&gt;
&lt;br /&gt;
Ces deux derniers points nous servirons plus tard.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
typedef struct {&lt;br /&gt;
	uint16_t stackPointer;&lt;br /&gt;
	void (*functionAddress)(void);&lt;br /&gt;
	int sleep_time;&lt;br /&gt;
	int state;&lt;br /&gt;
} process;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On initialise donc notre tableau de processus de la façon suivante : &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
process Tasks_list[NBTASKS] = {&lt;br /&gt;
                                {0, led1_blink, 0,0},&lt;br /&gt;
				...&lt;br /&gt;
			       };&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Concernant les fonction liés leds, on utilise une simple boucle while contenant un changement d'état &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void led_init() {&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
void led1_blink() {&lt;br /&gt;
	while(1) {&lt;br /&gt;
		PORTC ^= (1&amp;lt;&amp;lt;PLED1);&lt;br /&gt;
		_delay_ms(100);&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
void led2_blink() {&lt;br /&gt;
...	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_stackPointer_tasks() permet de diviser la pile &amp;quot;réel&amp;quot; en plusieurs piles pour chaque processus.  Ces sous piles commence à la position FIRST_STACK_POSITION, afin de ne pas réécrire par dessus des données. Toutes les sous piles diposent d'une même taille de pile STACK_LENGTH.&lt;br /&gt;
&lt;br /&gt;
La fonction init_piles() initialise correctement la pile avec le tableau de processus si le processus est actif.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_stackPointer_tasks(int Cprocess) { //initialise le pointer de pile&lt;br /&gt;
	if(Tasks_list[Cprocess].state == 0) {&lt;br /&gt;
		Tasks_list[Cprocess].stackPointer = FIRST_STACK_POSITION - (Cprocess * STACK_LENGTH);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void init_piles(int Cprocess){ //initilalise la pile&lt;br /&gt;
	if(Tasks_list[Cprocess].state == 0) {&lt;br /&gt;
		int save = SP;&lt;br /&gt;
		SP = Tasks_list[Cprocess].stackPointer;&lt;br /&gt;
		uint16_t address = (uint16_t)Tasks_list[Cprocess].functionAddress;&lt;br /&gt;
		asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (address &amp;amp; 0x00ff) );&lt;br /&gt;
		asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((address &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
		SAVE_REGISTERS();&lt;br /&gt;
		Tasks_list[Cprocess].stackPointer = SP;&lt;br /&gt;
		SP = save;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;le scheduler permet de passer à la tâche suivante&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
	Current_task++;&lt;br /&gt;
	if (Current_task &amp;gt;= NBTASKS) {&lt;br /&gt;
		Current_task = 0; &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;l'atmega328p ne dispose pas de de fonction en assembleur permettant de push ou de pop tout les registres. on doit donc le faire un par un.&lt;br /&gt;
&lt;br /&gt;
On défini alors les macros suivantes :  &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define SAVE_REGISTERS() \&lt;br /&gt;
	asm volatile ( \&lt;br /&gt;
		&amp;quot;push r0 	 \n\t&amp;quot; \&lt;br /&gt;
		...\&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#define RESTORE_REGISTERS() \&lt;br /&gt;
	asm volatile ( \&lt;br /&gt;
		&amp;quot;pop r31 	  \n\t&amp;quot; \&lt;br /&gt;
		...\&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;L'ISR gère les interruptions, en commençant par sauvegarder l'état de la pile ainsi que le stack pointeur propre au processus qui s'interrompt. L'appel au schedruler permet de changer de processus pour cela il faut restorer le stack pointer propre au nouveau processus actif et de la pile liée à ce processus. La dernière ligne arrête l'ISR.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED) {&lt;br /&gt;
	SAVE_REGISTERS();&lt;br /&gt;
	Tasks_list[Current_task].stackPointer = SP;&lt;br /&gt;
	scheduler();&lt;br /&gt;
	SP = Tasks_list[Current_task].stackPointer;&lt;br /&gt;
	RESTORE_REGISTERS();&lt;br /&gt;
	asm volatile(&amp;quot;reti&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=====test=====&lt;br /&gt;
Les processus de clignotement de leds ont tous un délai d'attente différent, l'interruption se produit toutes les millisecondes. On obtient ceci :[[Fichier:Ordonnanceur basique.mp4|centré|vignette]]Il est intéressant de remarqué que la vitesse à laquelle les leds changent d'état ne correspond pas au délai qui leur à été donné. Cela parait logique puisque l'interruption met la fonction _delay_ms en pause, ainsi la vitesse se voit divisé par le nombre de processus actif.&lt;br /&gt;
&lt;br /&gt;
====Ajout d'un système d'endormissement des processus====&lt;br /&gt;
&lt;br /&gt;
La fonction wait va permettre d'endormir un processus, elle va donné un temps de sommeil au processus puis lancer une interruption (car on veut changer de processus directement après que le précédent ait été endormi).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time) { // met un process en veille pour une durée donné&lt;br /&gt;
	// valeur max de time 32000 car int sur atmega328p code sur 16 bits donc 32000 max&lt;br /&gt;
	cli();&lt;br /&gt;
	Tasks_list[Current_task].sleep_time = time;&lt;br /&gt;
	TCNT1=0;&lt;br /&gt;
	sei();&lt;br /&gt;
	TIMER1_COMPA_vect();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour verifier si un processus a besoin d'être lancé, on ajoute une boucle while dans le scheduler afin de vérifier si il y a un temps de sommeil. Le scheduler va aussi servir à diminuer le temps de sommeil de tout les processus (avec un minimum de 0).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
	for (int i=0 ; i&amp;lt;NBTASKS ; i++) {&lt;br /&gt;
		if (Tasks_list[i].sleep_time - SLEEP_DEC &amp;lt; 0) {&lt;br /&gt;
			Tasks_list[i].sleep_time = 0;&lt;br /&gt;
		} else {&lt;br /&gt;
			Tasks_list[i].sleep_time -= SLEEP_DEC;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	do {&lt;br /&gt;
		Current_task++;&lt;br /&gt;
		if (Current_task &amp;gt;= NBTASKS) {&lt;br /&gt;
			Current_task = 0;&lt;br /&gt;
		}&lt;br /&gt;
	} while (Tasks_list[Current_task].sleep_time &amp;gt; 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Tableau dynamique des tâches====&lt;br /&gt;
&lt;br /&gt;
En premier lieu on va initialiser les état de tout les cases du tableau de processus. On choisit 1 la case est vide, 0 sinon.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_state() { //initialise state&lt;br /&gt;
	for (int i= 0; i&amp;lt;NBTASKS; i++) {&lt;br /&gt;
		if (Tasks_list[i].functionAddress == NULL) {&lt;br /&gt;
			Tasks_list[i].state = 1;&lt;br /&gt;
		}&lt;br /&gt;
		else {&lt;br /&gt;
			Tasks_list[i].state = 0;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Nous avons programmé deux fonction d'arrêt et une fonction d'ajout de processus :&lt;br /&gt;
&lt;br /&gt;
-finish stop le processus en cours et le supprime de tableau, puis lance une interruption&lt;br /&gt;
&lt;br /&gt;
-kill stop un processus donné et le supprime du tableau &lt;br /&gt;
&lt;br /&gt;
-add ajoute un processus sur la première case vide du tableau, initialise son pointeur de position et sa pile.&lt;br /&gt;
&lt;br /&gt;
Pour finish et kill, on met le temps de sommeil à 0 au cas où on arrête un processus endormi. C'est une mesure de sécurité pour finish, mais une obligation pour kill.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void finish() { //supprime un process lorsque celui-ci est terminé&lt;br /&gt;
	cli();&lt;br /&gt;
		Tasks_list[Current_task].state =1;&lt;br /&gt;
		Tasks_list[Current_task].sleep_time = 0;&lt;br /&gt;
		Tasks_list[Current_task].functionAddress = NULL;&lt;br /&gt;
	TCNT1=0; &lt;br /&gt;
	sei();&lt;br /&gt;
	TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void kill(void (*function)(void)) { //tue le process passé en paramètre&lt;br /&gt;
	cli();&lt;br /&gt;
	for(int i = 0; i&amp;lt;NBTASKS; i++) {&lt;br /&gt;
		if(Tasks_list[i].functionAddress == function) {&lt;br /&gt;
			Tasks_list[i].state =1;&lt;br /&gt;
			Tasks_list[i].sleep_time = 0;&lt;br /&gt;
			Tasks_list[i].functionAddress = NULL;&lt;br /&gt;
		}&lt;br /&gt;
	} &lt;br /&gt;
	sei();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void add(void (*newFunction)(void)) { //ajoute un process&lt;br /&gt;
	cli();&lt;br /&gt;
	int i =0;&lt;br /&gt;
	while(Tasks_list[i].state != 1) {&lt;br /&gt;
		i++;&lt;br /&gt;
	}&lt;br /&gt;
	Tasks_list[i].functionAddress = newFunction;&lt;br /&gt;
	Tasks_list[i].state = 0;&lt;br /&gt;
	init_stackPointer_tasks(i);&lt;br /&gt;
	init_piles(i);&lt;br /&gt;
&lt;br /&gt;
	sei();&lt;br /&gt;
	&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Il suffit maintenant de modifier le scheduler afin de ne pas prendre les processus terminé, puis utiliser add, finish et kill dans les fonctions choisis.&lt;br /&gt;
&lt;br /&gt;
=====test=====&lt;br /&gt;
Pour tester les fonction add et finish, on fait le test suivant :&lt;br /&gt;
&lt;br /&gt;
-on créer un process qui ajoute le process led2_blink (avec add) au bout d'un certain temps&lt;br /&gt;
&lt;br /&gt;
-le process led2_blink s'arrête (avec finish) au bout de 20 changement d'état (c'est à dire 10 clignotement).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
on obtient le résultat suivant :[[Fichier:Demo fonction add et finish.mp4|centré|vignette]]&lt;br /&gt;
====lecture et écriture sur le port série====&lt;br /&gt;
Afin de lire et écrire sur le port série, on utilise les fonctions USART_Init, USART_Transmit et USART_Receive  vu en cours de microP l'année précédente. Le but sera donc d'écrire le message qui vient d'être reçu, on utilise donc le processus suivant :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====test=====&lt;br /&gt;
Pour tester notre processus de communication, on utilise minicom.[[Fichier:Test lecture et écriture port série.mp4|centré|vignette]]On notera que si la période entre les interruptions est trop élevé, certains caractères ne seront pas lus.&lt;br /&gt;
&lt;br /&gt;
====afficheur 7 segments====&lt;br /&gt;
=====test=====&lt;br /&gt;
[[Fichier:Video7segvideo.mp4|vignette|centré]]&lt;br /&gt;
&lt;br /&gt;
=Carte Réseau=&lt;br /&gt;
Lors de la répartition des tâches, nous avons opté pour la carte réseau. &lt;br /&gt;
==Description==&lt;br /&gt;
Le sujet nous permettait de choisir parmi plusieurs microcontrôleurs. Nous avons retenu l’ATmega32U4, qui nous semble représenter un juste milieu entre l’ATmega16U2 et l’AT90USB.&lt;br /&gt;
==Hardware==&lt;br /&gt;
Notre carte intègre des LED permettant d’afficher différents états de communication (que nous définirons ultérieurement).&lt;br /&gt;
&lt;br /&gt;
À la demande de M. Redon, nous avons ajouté un MAX232 ainsi que des connecteurs DB9 et DB25. Nous espérons que ces éléments pourront être utiles.&lt;br /&gt;
===Schématque===&lt;br /&gt;
[[Fichier:Schématique CReseau.png|vignette|540x540px|centré]]&lt;br /&gt;
===Routage===&lt;br /&gt;
[[Fichier:Routage Creseau.png|vignette|521x521px|centré]]&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2025-1&amp;diff=8496</id>
		<title>SE4Binome2025-1</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2025-1&amp;diff=8496"/>
		<updated>2025-11-21T09:52:09Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : complement de documentation&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Shield Arduino =&lt;br /&gt;
== Hardware ==&lt;br /&gt;
Afin de tester notre futur carte réseau, nous avons fait un shield d'arduino qui prendra le rôle de la carte mère durant. &lt;br /&gt;
=== Schématique ===&lt;br /&gt;
Nous nous sommes évidemment aider de la datasheet de l'atmega328p ainsi que celle de l'arduino uno afin de sélectionner les bon pins.&lt;br /&gt;
[[Fichier:Atmel-7810-Automotive-Microcontrollers-ATmega328P Datasheet.pdf|centré|vignette|Datasheet ATmega328p]]&lt;br /&gt;
[[Fichier:A000066-datasheet.pdf|centré|vignette|Datasheet Arduino Uno R3]]&lt;br /&gt;
Plus précisément nous nous inspirons très fortement du schéma page 10 de la datasheet de l'arduino :&lt;br /&gt;
[[Fichier:Screenshot 2025-11-07 11-08-46.png|centré|vignette|Schéma pinouts]]&lt;br /&gt;
Nous sommes donc parti de l'exemple fourni par Mr Redon. Mais nous avons utilisé une template disponible dans kicad permettant de créer des shields d'arduino Uno R3.[[Fichier:Tyetyuy.png|vignette|Schématique shield arduino|centré|438x438px]]&lt;br /&gt;
=== Routage ===&lt;br /&gt;
Au niveau du routage, nous avons tenté de faire simple (sans trop abuser sur les vias. Nous avons positionner le lecteur de carte sd au bord de la carte afin de ne pas avoir de problèmes avec d'autres composants lorsque nous voudrons mettre ou enlever la carte sd.&lt;br /&gt;
[[Fichier:Routage shield arduino.png|vignette|Routage shield arduino|centré|434x434px]]&lt;br /&gt;
&lt;br /&gt;
===Soudage===&lt;br /&gt;
La schématique et le routage terminés, nous avons soudé les différents pins permettant de souder la carte shield à l'arduino, le reste n'étant pas forcément utile pour le moment (il est important de noter que notre shield est arrivé avec des composants pré-soudés).&lt;br /&gt;
[[Fichier:Shield soudage de base .jpg|centré|vignette]]&lt;br /&gt;
&lt;br /&gt;
===Tests===&lt;br /&gt;
Il faudra ensuite faire des test d'allumage des leds, afin de vérifier le bon fonctionnement du shield&lt;br /&gt;
[[Fichier:VID leds.mp4|centré|vignette]]&lt;br /&gt;
&lt;br /&gt;
Les leds fonctionnant à merveille, Il est temps de passer de passer à l'ordonnanceur.&lt;br /&gt;
== Software ==&lt;br /&gt;
=== Ordonnanceur ===&lt;br /&gt;
[à completer  et commenter , seulement des codes pour le moment !!!!]&lt;br /&gt;
==== Ordonnanceur basique ====&lt;br /&gt;
La première étape consiste à définir la structure d'un process, il sera composé :&lt;br /&gt;
&lt;br /&gt;
-d'un pointeur de pile&lt;br /&gt;
&lt;br /&gt;
-de l'adresse de la fonction&lt;br /&gt;
&lt;br /&gt;
-d'un temps de sommeil &lt;br /&gt;
&lt;br /&gt;
-d'un état : 0 pour en cours et 1 pour terminé ou vide&lt;br /&gt;
&lt;br /&gt;
Ces deux derniers points nous servirons plus tard.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
typedef struct {&lt;br /&gt;
	uint16_t stackPointer;&lt;br /&gt;
	void (*functionAddress)(void);&lt;br /&gt;
	int sleep_time;&lt;br /&gt;
	int state;&lt;br /&gt;
} process;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;On initialise donc notre tableau de processus de la façon suivante : &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
process Tasks_list[NBTASKS] = {&lt;br /&gt;
                                {0, led1_blink, 0,0},&lt;br /&gt;
				...&lt;br /&gt;
			       };&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Concernant les fonction liés leds, on utilise une simple boucle while contenant un changement d'état &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void led_init() {&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
void led1_blink() {&lt;br /&gt;
	while(1) {&lt;br /&gt;
		PORTC ^= (1&amp;lt;&amp;lt;PLED1);&lt;br /&gt;
		_delay_ms(100);&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
void led2_blink() {&lt;br /&gt;
...	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_stackPointer_tasks() permet de diviser la pile &amp;quot;réel&amp;quot; en plusieurs piles pour chaque processus.  Ces sous piles commence à la position FIRST_STACK_POSITION, afin de ne pas réécrire par dessus des données. Toutes les sous piles diposent d'une même taille de pile STACK_LENGTH.&lt;br /&gt;
&lt;br /&gt;
La fonction init_piles() initialise correctement la pile avec le tableau de processus si le processus est actif.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_stackPointer_tasks(int Cprocess) { //initialise le pointer de pile&lt;br /&gt;
	if(Tasks_list[Cprocess].state == 0) {&lt;br /&gt;
		Tasks_list[Cprocess].stackPointer = FIRST_STACK_POSITION - (Cprocess * STACK_LENGTH);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void init_piles(int Cprocess){ //initilalise la pile&lt;br /&gt;
	if(Tasks_list[Cprocess].state == 0) {&lt;br /&gt;
		int save = SP;&lt;br /&gt;
		SP = Tasks_list[Cprocess].stackPointer;&lt;br /&gt;
		uint16_t address = (uint16_t)Tasks_list[Cprocess].functionAddress;&lt;br /&gt;
		asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (address &amp;amp; 0x00ff) );&lt;br /&gt;
		asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((address &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
		SAVE_REGISTERS();&lt;br /&gt;
		Tasks_list[Cprocess].stackPointer = SP;&lt;br /&gt;
		SP = save;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;le scheduler permet de passer à la tâche suivante&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
	Current_task++;&lt;br /&gt;
	if (Current_task &amp;gt;= NBTASKS) {&lt;br /&gt;
		Current_task = 0; &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;l'atmega328p ne dispose pas de de fonction en assembleur permettant de push ou de pop tout les registres. on doit donc le faire un par un.&lt;br /&gt;
&lt;br /&gt;
On défini alors les macros suivantes :  &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define SAVE_REGISTERS() \&lt;br /&gt;
	asm volatile ( \&lt;br /&gt;
		&amp;quot;push r0 	 \n\t&amp;quot; \&lt;br /&gt;
		...\&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#define RESTORE_REGISTERS() \&lt;br /&gt;
	asm volatile ( \&lt;br /&gt;
		&amp;quot;pop r31 	  \n\t&amp;quot; \&lt;br /&gt;
		...\&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;L'ISR gère les interruptions, en commençant par sauvegarder l'état de la pile ainsi que le stack pointeur propre au processus qui s'interrompt. L'appel au schedruler permet de changer de processus pour cela il faut restorer le stack pointer propre au nouveau processus actif et de la pile liée à ce processus. La dernière ligne arrête l'ISR.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED) {&lt;br /&gt;
	SAVE_REGISTERS();&lt;br /&gt;
	Tasks_list[Current_task].stackPointer = SP;&lt;br /&gt;
	scheduler();&lt;br /&gt;
	SP = Tasks_list[Current_task].stackPointer;&lt;br /&gt;
	RESTORE_REGISTERS();&lt;br /&gt;
	asm volatile(&amp;quot;reti&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=====test=====&lt;br /&gt;
Les processus de clignotement de leds ont tous un délai d'attente différent, l'interruption se produit toutes les millisecondes. On obtient ceci :[[Fichier:Ordonnanceur basique.mp4|centré|vignette]]Il est intéressant de remarqué que la vitesse à laquelle les leds changent d'état ne correspond pas au délai qui leur à été donné. Cela parait logique puisque l'interruption met la fonction _delay_ms en pause, ainsi la vitesse se voit divisé par le nombre de processus actif.&lt;br /&gt;
&lt;br /&gt;
====Ajout d'un système d'endormissement des processus====&lt;br /&gt;
&lt;br /&gt;
La fonction wait va permettre d'endormir un processus, elle va donné un temps de sommeil au processus puis lancer une interruption (car on veut changer de processus directement après que le précédent ait été endormi).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time) { // met un process en veille pour une durée donné&lt;br /&gt;
	// valeur max de time 32000 car int sur atmega328p code sur 16 bits donc 32000 max&lt;br /&gt;
	cli();&lt;br /&gt;
	Tasks_list[Current_task].sleep_time = time;&lt;br /&gt;
	TCNT1=0;&lt;br /&gt;
	sei();&lt;br /&gt;
	TIMER1_COMPA_vect();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour verifier si un processus a besoin d'être lancé, on ajoute une boucle while dans le scheduler afin de vérifier si il y a un temps de sommeil. Le scheduler va aussi servir à diminuer le temps de sommeil de tout les processus (avec un minimum de 0).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
	for (int i=0 ; i&amp;lt;NBTASKS ; i++) {&lt;br /&gt;
		if (Tasks_list[i].sleep_time - SLEEP_DEC &amp;lt; 0) {&lt;br /&gt;
			Tasks_list[i].sleep_time = 0;&lt;br /&gt;
		} else {&lt;br /&gt;
			Tasks_list[i].sleep_time -= SLEEP_DEC;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	do {&lt;br /&gt;
		Current_task++;&lt;br /&gt;
		if (Current_task &amp;gt;= NBTASKS) {&lt;br /&gt;
			Current_task = 0;&lt;br /&gt;
		}&lt;br /&gt;
	} while (Tasks_list[Current_task].sleep_time &amp;gt; 0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====Tableau dynamique des tâches====&lt;br /&gt;
&lt;br /&gt;
En premier lieu on va initialiser les état de tout les cases du tableau de processus. On choisit 1 la case est vide, 0 sinon.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_state() { //initialise state&lt;br /&gt;
	for (int i= 0; i&amp;lt;NBTASKS; i++) {&lt;br /&gt;
		if (Tasks_list[i].functionAddress == NULL) {&lt;br /&gt;
			Tasks_list[i].state = 1;&lt;br /&gt;
		}&lt;br /&gt;
		else {&lt;br /&gt;
			Tasks_list[i].state = 0;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Nous avons programmé deux fonction d'arrêt et une fonction d'ajout de processus :&lt;br /&gt;
&lt;br /&gt;
-finish stop le processus en cours et le supprime de tableau, puis lance une interruption&lt;br /&gt;
&lt;br /&gt;
-kill stop un processus donné et le supprime du tableau &lt;br /&gt;
&lt;br /&gt;
-add ajoute un processus sur la première case vide du tableau, initialise son pointeur de position et sa pile.&lt;br /&gt;
&lt;br /&gt;
Pour finish et kill, on met le temps de sommeil à 0 au cas où on arrête un processus endormi. C'est une mesure de sécurité pour finish, mais une obligation pour kill.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void finish() { //supprime un process lorsque celui-ci est terminé&lt;br /&gt;
	cli();&lt;br /&gt;
		Tasks_list[Current_task].state =1;&lt;br /&gt;
		Tasks_list[Current_task].sleep_time = 0;&lt;br /&gt;
		Tasks_list[Current_task].functionAddress = NULL;&lt;br /&gt;
	TCNT1=0; &lt;br /&gt;
	sei();&lt;br /&gt;
	TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void kill(void (*function)(void)) { //tue le process passé en paramètre&lt;br /&gt;
	cli();&lt;br /&gt;
	for(int i = 0; i&amp;lt;NBTASKS; i++) {&lt;br /&gt;
		if(Tasks_list[i].functionAddress == function) {&lt;br /&gt;
			Tasks_list[i].state =1;&lt;br /&gt;
			Tasks_list[i].sleep_time = 0;&lt;br /&gt;
			Tasks_list[i].functionAddress = NULL;&lt;br /&gt;
		}&lt;br /&gt;
	} &lt;br /&gt;
	sei();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void add(void (*newFunction)(void)) { //ajoute un process&lt;br /&gt;
	cli();&lt;br /&gt;
	int i =0;&lt;br /&gt;
	while(Tasks_list[i].state != 1) {&lt;br /&gt;
		i++;&lt;br /&gt;
	}&lt;br /&gt;
	Tasks_list[i].functionAddress = newFunction;&lt;br /&gt;
	Tasks_list[i].state = 0;&lt;br /&gt;
	init_stackPointer_tasks(i);&lt;br /&gt;
	init_piles(i);&lt;br /&gt;
&lt;br /&gt;
	sei();&lt;br /&gt;
	&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Il suffit maintenant de modifier le scheduler afin de ne pas prendre les processus terminé, puis utiliser add, finish et kill dans les fonctions choisis.&lt;br /&gt;
&lt;br /&gt;
=====test=====&lt;br /&gt;
Pour tester les fonction add et finish, on fait le test suivant :&lt;br /&gt;
&lt;br /&gt;
-on créer un process qui ajoute le process led2_blink (avec add) au bout d'un certain temps&lt;br /&gt;
&lt;br /&gt;
-le process led2_blink s'arrête (avec finish) au bout de 20 changement d'état (c'est à dire 10 clignotement).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
on obtient le résultat suivant :[[Fichier:Demo fonction add et finish.mp4|centré|vignette]]&lt;br /&gt;
====lecture et écriture sur le port série====&lt;br /&gt;
Afin de lire et écrire sur le port série, on utilise les fonctions USART_Init, USART_Transmit et USART_Receive  vu en cours de microP l'année précédente. Le but sera donc d'écrire le message qui vient d'être reçu, on utilise donc le processus suivant :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====test=====&lt;br /&gt;
Pour tester notre processus de communication, on utilise minicom.[[Fichier:Test lecture et écriture port série.mp4|centré|vignette]]On notera que si la période entre les interruptions est trop élevé, certains caractères ne seront pas lus.&lt;br /&gt;
&lt;br /&gt;
====afficheur 7 segments====&lt;br /&gt;
=====test=====&lt;br /&gt;
=Carte Réseau=&lt;br /&gt;
Lors de la répartition des tâches, nous avons opté pour la carte réseau. &lt;br /&gt;
==Description==&lt;br /&gt;
Le sujet nous permettait de choisir parmi plusieurs microcontrôleurs. Nous avons retenu l’ATmega32U4, qui nous semble représenter un juste milieu entre l’ATmega16U2 et l’AT90USB.&lt;br /&gt;
==Hardware==&lt;br /&gt;
Notre carte intègre des LED permettant d’afficher différents états de communication (que nous définirons ultérieurement).&lt;br /&gt;
&lt;br /&gt;
À la demande de M. Redon, nous avons ajouté un MAX232 ainsi que des connecteurs DB9 et DB25. Nous espérons que ces éléments pourront être utiles.&lt;br /&gt;
===Schématque===&lt;br /&gt;
[[Fichier:Schématique CReseau.png|vignette|540x540px|centré]]&lt;br /&gt;
===Routage===&lt;br /&gt;
[[Fichier:Routage Creseau.png|vignette|521x521px|centré]]&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2025-1&amp;diff=8150</id>
		<title>SE4Binome2025-1</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2025-1&amp;diff=8150"/>
		<updated>2025-09-26T12:36:41Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Shield Arduino ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
[[Fichier:Tyetyuy.png|néant|vignette|Schématique shield arduino]]&lt;br /&gt;
[[Fichier:Routage shield arduino.png|néant|vignette|Routage shield arduino]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
La schématique et le routage sont terminés. Nous avons utilisé un template pour l'arduino différent de celui proposé car ce dernier était à l'envers.&lt;br /&gt;
&lt;br /&gt;
== Carte Réseau ==&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Tyetyuy.png&amp;diff=8148</id>
		<title>Fichier:Tyetyuy.png</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Tyetyuy.png&amp;diff=8148"/>
		<updated>2025-09-26T12:35:18Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;rgrt&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2025-1&amp;diff=8134</id>
		<title>SE4Binome2025-1</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2025-1&amp;diff=8134"/>
		<updated>2025-09-26T10:15:46Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : partie schematique/routage du shield arduino complete&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Shield Arduino ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
[[Fichier:Schématique shield arduino.png|néant|vignette|Schématique shield arduino]]&lt;br /&gt;
[[Fichier:Routage shield arduino.png|néant|vignette|Routage shield arduino]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
La schématique et le routage sont terminés. Nous avons utilisé un template pour l'arduino différent de celui proposé car ce dernier était à l'envers.&lt;br /&gt;
&lt;br /&gt;
== Carte Réseau ==&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Routage_shield_arduino.png&amp;diff=8132</id>
		<title>Fichier:Routage shield arduino.png</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Routage_shield_arduino.png&amp;diff=8132"/>
		<updated>2025-09-26T10:09:23Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Routage fini&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Sch%C3%A9matique_shield_arduino.png&amp;diff=8130</id>
		<title>Fichier:Schématique shield arduino.png</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Sch%C3%A9matique_shield_arduino.png&amp;diff=8130"/>
		<updated>2025-09-26T10:04:41Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;schématique finie&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Pico_SE4_2025/2026&amp;diff=8114</id>
		<title>Pico SE4 2025/2026</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Pico_SE4_2025/2026&amp;diff=8114"/>
		<updated>2025-09-17T13:19:39Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectif =&lt;br /&gt;
&lt;br /&gt;
Voir le sujet dans le menu englobant.&lt;br /&gt;
&lt;br /&gt;
= Organisation du travail =&lt;br /&gt;
&lt;br /&gt;
Vous déposerez votre travail dans un projet GIT sur le serveur [https://gitea.plil.fr Gitea de la platforme informatique].&lt;br /&gt;
&lt;br /&gt;
= Bouclier ordonnanceur =&lt;br /&gt;
&lt;br /&gt;
Vous devez réaliser le bouclier Arduino Uno pour l'ordonnancement et pour que chaque binôme puisse simuler une carte mère.&lt;br /&gt;
&lt;br /&gt;
A la base le bouclier permet de connecter 5 périphériques SPI via des connecteurs 8 contacts sous la forme de cartes filles. A noter qu'en plus des lignes du bus SPI, une ligne réinitialisation et une ligne interruption sont acheminées de et vers les périphériques SPI.&lt;br /&gt;
&lt;br /&gt;
Le bouclier comprend aussi une mémoire. Vous devez prévoir une carte micro-SD via un connecteur Molex 10431 mais aussi une puce mémoire AT45DB641E. Les deux mémoires doivent être prévues sur le circuit imprimé, vous déciderez plus tard laquelle sera soudée. Vu que l'Arduino fonctionne en 5V et les mémoires en 3,3V un releveur de niveau est nécessaire. La puce à utiliser est la 74LV125. Vous pouvez aussi concevoir la mémoire de masse comme une carte fille sans ligne de réinitialisation ou d'initialisation.&lt;br /&gt;
&lt;br /&gt;
[[File:2025_picoshield_schematic.pdf|thumb|left|500px|Schéma PicoShield]]&lt;br /&gt;
&lt;br /&gt;
[[File:2025_picoshield_footprints.png|thumb|right|750px|Empreintes]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Réalisations des élèves =&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Numéro du binôme !! Numéro du groupe !! Elèves !! Page &lt;br /&gt;
|-&lt;br /&gt;
| Binôme 1&lt;br /&gt;
| Groupe 1&lt;br /&gt;
| Thomas Delobelle &amp;amp; Antonin Biernacki&lt;br /&gt;
| [[SE4Binome2025-1|Binôme 1 2025/2026]]&lt;br /&gt;
|-&lt;br /&gt;
| Binôme 2&lt;br /&gt;
| Groupe 1&lt;br /&gt;
| Prénom Nom &amp;amp; Prénom Nom&lt;br /&gt;
| [[SE4Binome2025-2|Binôme 2 2025/2026]]&lt;br /&gt;
|-&lt;br /&gt;
| Binôme 3&lt;br /&gt;
| Groupe 1&lt;br /&gt;
| Prénom Nom &amp;amp; Prénom Nom&lt;br /&gt;
| [[SE4Binome2025-3|Binôme 3 2025/2026]]&lt;br /&gt;
|-&lt;br /&gt;
| Binôme 4&lt;br /&gt;
| Groupe 1&lt;br /&gt;
| Prénom Nom &amp;amp; Prénom Nom&lt;br /&gt;
| [[SE4Binome2025-4|Binôme 4 2025/2026]]&lt;br /&gt;
|-&lt;br /&gt;
| Binôme 5&lt;br /&gt;
| Groupe 1&lt;br /&gt;
| Prénom Nom &amp;amp; Prénom Nom&lt;br /&gt;
| [[SE4Binome2025-5|Binôme 5 2025/2026]]&lt;br /&gt;
|-&lt;br /&gt;
| Binôme 6&lt;br /&gt;
| Groupe 2&lt;br /&gt;
| Cédric Payet &amp;amp; Prénom Nom&lt;br /&gt;
| [[SE4Binome2025-6|Binôme 6 2025/2026]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7922</id>
		<title>SE3Groupe2024-5</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7922"/>
		<updated>2025-04-29T12:46:33Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : /* Matériel */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
&lt;br /&gt;
=== Objectif ===&lt;br /&gt;
Concevoir et réaliser un mini sonar à partir d'un émetteur-récepteur ultrason, avec un traitement des données effectué par un micro-contrôleur. Les données seront ensuite communiquées par ondes radio à un ordinateur. Le système devra être capable de fonctionner aussi bien sur batterie que connecté en USB à un ordinateur, et devra au minimum comporter des LED d'indication.&lt;br /&gt;
&lt;br /&gt;
=== Cahier des charges ===&lt;br /&gt;
&lt;br /&gt;
* Contrôle et traitement des informations de l'émetteur-récepteur ultrason&lt;br /&gt;
* Pilotage par moteur de l'angle de l'émetteur-récepteur ultrason&lt;br /&gt;
* Retour de l'information par des LED sur la carte&lt;br /&gt;
* Gestion de l'alimentation par USB&lt;br /&gt;
* Communication sans fil avec un ordinateur&lt;br /&gt;
* Gestion de l'alimentation sur batterie&lt;br /&gt;
* Interface pour visualiser les informations sur ordinateur&lt;br /&gt;
&lt;br /&gt;
=== Spécification techniques ===&lt;br /&gt;
&lt;br /&gt;
* angle de détection large (-90°,90°)&lt;br /&gt;
* deux émetteurs/récepteurs à ultrason HC-SR04&lt;br /&gt;
&lt;br /&gt;
* Recharge par USB&lt;br /&gt;
* transmission des données par onde radio via un module RF (NRFL2401)&lt;br /&gt;
* Batteries Li-ion&lt;br /&gt;
* une LED tricolore, pour notamment informer des différents niveaux de batterie&lt;br /&gt;
* un afficheur 7 segments pour le débogage&lt;br /&gt;
* interface machine via une application python&lt;br /&gt;
* microcontroleur atmega&lt;br /&gt;
&lt;br /&gt;
== Carte électronique ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique ===&lt;br /&gt;
[[Fichier:Schematique-sonar.pdf|alt=schématique de la carte|gauche|vignette|schématique de la carte de pilotage du sonar]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Routage ===&lt;br /&gt;
[[Fichier:Routage-sonar.pdf|alt=image du routage de la carte|gauche|vignette|capture d'écran du routage du sonar]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Vue 3D ===&lt;br /&gt;
[[Fichier:Vue-3D-sonar.pdf|alt=Vue 3D de la carte|gauche|vignette|Vue 3D de face du routage]]&lt;br /&gt;
[[Fichier:Vue3DdosPCB.pdf|alt=capture d'écran de la vue 3D de dos de la carte|gauche|vignette|vue 3D de dos]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== CAO de la carte du sonar ===&lt;br /&gt;
[[Fichier:Sonar.zip|vignette]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Matériel supplémentaire à commander ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CD4543 en DIP-16&lt;br /&gt;
=== Réalisation ===&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;Afin d'assurer le bon déroulement de la soudure de la carte, nous avons divisé les composants à souder dans des jalons, pour nous assurer étape par étape du bon fonctionnement de la carte.&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;Le premier jalon comporte naturellement le microcontrôleur et les composants nécessaires à son bon fonctionnement, ainsi que la connectique USB pour pouvoir charger des programmes sur la carte.&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;La liste des jalons est disponible ci-contre:&lt;br /&gt;
[[Fichier:Jalons.txt|alt=fichier texte comprenant les jalons pour la soudure|vignette]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
== Programmation ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Programmateur AVR ==&lt;br /&gt;
&lt;br /&gt;
=== Tests allumage des LEDs ===&lt;br /&gt;
Lorsque nous avons fini de souder les composants sur la carte, nous avons voulu tester que la carte fonctionnait correctement, c'est pourquoi nous avons écrit un petit programme permettant l'allumage des leds jaunes(une qui s'allume à l'appui sur le bouton bleu traversant, une qui clignote à 10 Hz).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
//avr-gcc -mmcu=atmega8u2 -Wall -Werror -I. -DF_CPU=16000000 -Os -o blink.elf blink.c&lt;br /&gt;
//avr-objcopy -j .text -j .data -O ihex blink.elf blink.hex&lt;br /&gt;
// avrdude -v -patmega8u2 -carduino -b115200 -P/dev/ttyACM0 -U flash:w:blink.hex&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;&lt;br /&gt;
int main(void){&lt;br /&gt;
CLKSEL0 = 0b00010101;   // sélection de l'horloge externe&lt;br /&gt;
CLKSEL1 = 0b00001111;   // minimum de 8Mhz&lt;br /&gt;
CLKPR = 0b10000000;     // modification du diviseur d'horloge (CLKPCE=1)&lt;br /&gt;
CLKPR = 0;              // 0 pour pas de diviseur (diviseur de 1)&lt;br /&gt;
DDRD |= 0x00;                // Sortie pour la LED&lt;br /&gt;
DDRC=0x24;             // Entrée pour le bouton          &lt;br /&gt;
&lt;br /&gt;
while(1){&lt;br /&gt;
  if(PIND &amp;amp; 0x40) PORTC =0x20;      // LED éteinte&lt;br /&gt;
  else PORTC |= 0x00;                  // LED allumée&lt;br /&gt;
  }&lt;br /&gt;
  PORTC^=0x04;&lt;br /&gt;
  _delay_ms(100);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Une fois le code compilé et uploadé, on obtient le résultat suivant:[[Fichier:Image pcb.jpg|gauche|vignette|Allumage de 2 LEDs sur la carte.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&lt;br /&gt;
Pour que le microcontroleur se comporte comme un programmateur AVR USB, il faut d'abord qu'il puisse être reconnu comme un appareil USB, c'est pourquoi nous avons utilisé la bibliothèque LUFA et avons programmé notre carte avec le code qui suit pour qu'il puisse communiquer en USB:&amp;lt;syntaxhighlight lang=&amp;quot;makefile&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
MCU          = atmega8u2&lt;br /&gt;
ARCH         = AVR8&lt;br /&gt;
BOARD        = NONE&lt;br /&gt;
F_CPU        = 16000000&lt;br /&gt;
F_USB        = $(F_CPU)&lt;br /&gt;
OPTIMIZATION = s&lt;br /&gt;
TARGET       = VirtualSerial&lt;br /&gt;
SRC          = $(TARGET).c Descriptors.c $(LUFA_SRC_USB)&lt;br /&gt;
LUFA_PATH    = ../../LUFA&lt;br /&gt;
CC_FLAGS     = -DUSE_LUFA_CONFIG_HEADER -IConfig/&lt;br /&gt;
LD_FLAGS     =&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
	char*       ReportString    = NULL;&lt;br /&gt;
	static bool ActionSent      = false;&lt;br /&gt;
	static bool button = false;&lt;br /&gt;
&lt;br /&gt;
	/* Device must be connected and configured for the task to run */&lt;br /&gt;
	if (USB_DeviceState != DEVICE_STATE_Configured)&lt;br /&gt;
	  return;&lt;br /&gt;
	/* Determine if a joystick action has occurred */&lt;br /&gt;
	if (!(PIND &amp;amp; 0x40)){&lt;br /&gt;
          if(!button){&lt;br /&gt;
	    ReportString = &amp;quot;BOUTON PRESSE\r\n&amp;quot;;&lt;br /&gt;
	    ActionSent=false;&lt;br /&gt;
	    }&lt;br /&gt;
          button=true;&lt;br /&gt;
          }&lt;br /&gt;
        else button=false;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;En faisant un lsusb, on observe que la carte est reconnue comme un appareil USB,  configuré d'après les fichiers de configuration de la LUFA.[[Fichier:Screenshot 2025-03-26 13-23-23.jpg|centré|vignette|800x800px|carte apparaissant comme appareil USB]]Le résultat est présenté dans la vidéo ci-dessous:[[Fichier:Video pcb(1).mp4|gauche|vignette|Communication USB entre ISP et PC visualisée via minicom]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tests ==&lt;br /&gt;
&lt;br /&gt;
== Rendus ==&lt;br /&gt;
&lt;br /&gt;
=== Archive GIT ===&lt;br /&gt;
https://gitea.plil.fr/abiernac/SE3_2024_B5.git&lt;br /&gt;
&lt;br /&gt;
=== Autres rendus ===&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_schema.pdf|thumb|left]]&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_PCB.png|thumb|right]]&lt;br /&gt;
&lt;br /&gt;
Projet KiCad programmateur AVR : [[Fichier:SE3-2024-G5-prog-kicad.zip]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7921</id>
		<title>SE3Groupe2024-5</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7921"/>
		<updated>2025-04-29T12:43:33Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : /* Réalisation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
&lt;br /&gt;
=== Objectif ===&lt;br /&gt;
Concevoir et réaliser un mini sonar à partir d'un émetteur-récepteur ultrason, avec un traitement des données effectué par un micro-contrôleur. Les données seront ensuite communiquées par ondes radio à un ordinateur. Le système devra être capable de fonctionner aussi bien sur batterie que connecté en USB à un ordinateur, et devra au minimum comporter des LED d'indication.&lt;br /&gt;
&lt;br /&gt;
=== Cahier des charges ===&lt;br /&gt;
&lt;br /&gt;
* Contrôle et traitement des informations de l'émetteur-récepteur ultrason&lt;br /&gt;
* Pilotage par moteur de l'angle de l'émetteur-récepteur ultrason&lt;br /&gt;
* Retour de l'information par des LED sur la carte&lt;br /&gt;
* Gestion de l'alimentation par USB&lt;br /&gt;
* Communication sans fil avec un ordinateur&lt;br /&gt;
* Gestion de l'alimentation sur batterie&lt;br /&gt;
* Interface pour visualiser les informations sur ordinateur&lt;br /&gt;
&lt;br /&gt;
=== Spécification techniques ===&lt;br /&gt;
&lt;br /&gt;
* angle de détection large (-90°,90°)&lt;br /&gt;
* deux émetteurs/récepteurs à ultrason HC-SR04&lt;br /&gt;
&lt;br /&gt;
* Recharge par USB&lt;br /&gt;
* transmission des données par onde radio via un module RF (NRFL2401)&lt;br /&gt;
* Batteries Li-ion&lt;br /&gt;
* une LED tricolore, pour notamment informer des différents niveaux de batterie&lt;br /&gt;
* un afficheur 7 segments pour le débogage&lt;br /&gt;
* interface machine via une application python&lt;br /&gt;
* microcontroleur atmega&lt;br /&gt;
&lt;br /&gt;
== Carte électronique ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique ===&lt;br /&gt;
[[Fichier:Schematique-sonar.pdf|alt=schématique de la carte|gauche|vignette|schématique de la carte de pilotage du sonar]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Routage ===&lt;br /&gt;
[[Fichier:Routage-sonar.pdf|alt=image du routage de la carte|gauche|vignette|capture d'écran du routage du sonar]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Vue 3D ===&lt;br /&gt;
[[Fichier:Vue-3D-sonar.pdf|alt=Vue 3D de la carte|gauche|vignette|Vue 3D de face du routage]]&lt;br /&gt;
[[Fichier:Vue3DdosPCB.pdf|alt=capture d'écran de la vue 3D de dos de la carte|gauche|vignette|vue 3D de dos]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== CAO de la carte du sonar ===&lt;br /&gt;
[[Fichier:Sonar.zip|vignette]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Réalisation ===&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;Afin d'assurer le bon déroulement de la soudure de la carte, nous avons divisé les composants à souder dans des jalons, pour nous assurer étape par étape du bon fonctionnement de la carte.&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;Le premier jalon comporte naturellement le microcontrôleur et les composants nécessaires à son bon fonctionnement, ainsi que la connectique USB pour pouvoir charger des programmes sur la carte.&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;La liste des jalons est disponible ci-contre:&lt;br /&gt;
[[Fichier:Jalons.txt|alt=fichier texte comprenant les jalons pour la soudure|vignette]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Matériel ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CD4543 en DIP-16&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
== Programmation ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Programmateur AVR ==&lt;br /&gt;
&lt;br /&gt;
=== Tests allumage des LEDs ===&lt;br /&gt;
Lorsque nous avons fini de souder les composants sur la carte, nous avons voulu tester que la carte fonctionnait correctement, c'est pourquoi nous avons écrit un petit programme permettant l'allumage des leds jaunes(une qui s'allume à l'appui sur le bouton bleu traversant, une qui clignote à 10 Hz).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
//avr-gcc -mmcu=atmega8u2 -Wall -Werror -I. -DF_CPU=16000000 -Os -o blink.elf blink.c&lt;br /&gt;
//avr-objcopy -j .text -j .data -O ihex blink.elf blink.hex&lt;br /&gt;
// avrdude -v -patmega8u2 -carduino -b115200 -P/dev/ttyACM0 -U flash:w:blink.hex&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;&lt;br /&gt;
int main(void){&lt;br /&gt;
CLKSEL0 = 0b00010101;   // sélection de l'horloge externe&lt;br /&gt;
CLKSEL1 = 0b00001111;   // minimum de 8Mhz&lt;br /&gt;
CLKPR = 0b10000000;     // modification du diviseur d'horloge (CLKPCE=1)&lt;br /&gt;
CLKPR = 0;              // 0 pour pas de diviseur (diviseur de 1)&lt;br /&gt;
DDRD |= 0x00;                // Sortie pour la LED&lt;br /&gt;
DDRC=0x24;             // Entrée pour le bouton          &lt;br /&gt;
&lt;br /&gt;
while(1){&lt;br /&gt;
  if(PIND &amp;amp; 0x40) PORTC =0x20;      // LED éteinte&lt;br /&gt;
  else PORTC |= 0x00;                  // LED allumée&lt;br /&gt;
  }&lt;br /&gt;
  PORTC^=0x04;&lt;br /&gt;
  _delay_ms(100);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Une fois le code compilé et uploadé, on obtient le résultat suivant:[[Fichier:Image pcb.jpg|gauche|vignette|Allumage de 2 LEDs sur la carte.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&lt;br /&gt;
Pour que le microcontroleur se comporte comme un programmateur AVR USB, il faut d'abord qu'il puisse être reconnu comme un appareil USB, c'est pourquoi nous avons utilisé la bibliothèque LUFA et avons programmé notre carte avec le code qui suit pour qu'il puisse communiquer en USB:&amp;lt;syntaxhighlight lang=&amp;quot;makefile&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
MCU          = atmega8u2&lt;br /&gt;
ARCH         = AVR8&lt;br /&gt;
BOARD        = NONE&lt;br /&gt;
F_CPU        = 16000000&lt;br /&gt;
F_USB        = $(F_CPU)&lt;br /&gt;
OPTIMIZATION = s&lt;br /&gt;
TARGET       = VirtualSerial&lt;br /&gt;
SRC          = $(TARGET).c Descriptors.c $(LUFA_SRC_USB)&lt;br /&gt;
LUFA_PATH    = ../../LUFA&lt;br /&gt;
CC_FLAGS     = -DUSE_LUFA_CONFIG_HEADER -IConfig/&lt;br /&gt;
LD_FLAGS     =&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
	char*       ReportString    = NULL;&lt;br /&gt;
	static bool ActionSent      = false;&lt;br /&gt;
	static bool button = false;&lt;br /&gt;
&lt;br /&gt;
	/* Device must be connected and configured for the task to run */&lt;br /&gt;
	if (USB_DeviceState != DEVICE_STATE_Configured)&lt;br /&gt;
	  return;&lt;br /&gt;
	/* Determine if a joystick action has occurred */&lt;br /&gt;
	if (!(PIND &amp;amp; 0x40)){&lt;br /&gt;
          if(!button){&lt;br /&gt;
	    ReportString = &amp;quot;BOUTON PRESSE\r\n&amp;quot;;&lt;br /&gt;
	    ActionSent=false;&lt;br /&gt;
	    }&lt;br /&gt;
          button=true;&lt;br /&gt;
          }&lt;br /&gt;
        else button=false;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;En faisant un lsusb, on observe que la carte est reconnue comme un appareil USB,  configuré d'après les fichiers de configuration de la LUFA.[[Fichier:Screenshot 2025-03-26 13-23-23.jpg|centré|vignette|800x800px|carte apparaissant comme appareil USB]]Le résultat est présenté dans la vidéo ci-dessous:[[Fichier:Video pcb(1).mp4|gauche|vignette|Communication USB entre ISP et PC visualisée via minicom]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tests ==&lt;br /&gt;
&lt;br /&gt;
== Rendus ==&lt;br /&gt;
&lt;br /&gt;
=== Archive GIT ===&lt;br /&gt;
https://gitea.plil.fr/abiernac/SE3_2024_B5.git&lt;br /&gt;
&lt;br /&gt;
=== Autres rendus ===&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_schema.pdf|thumb|left]]&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_PCB.png|thumb|right]]&lt;br /&gt;
&lt;br /&gt;
Projet KiCad programmateur AVR : [[Fichier:SE3-2024-G5-prog-kicad.zip]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7920</id>
		<title>SE3Groupe2024-5</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7920"/>
		<updated>2025-04-29T12:43:00Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : /* Réalisation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
&lt;br /&gt;
=== Objectif ===&lt;br /&gt;
Concevoir et réaliser un mini sonar à partir d'un émetteur-récepteur ultrason, avec un traitement des données effectué par un micro-contrôleur. Les données seront ensuite communiquées par ondes radio à un ordinateur. Le système devra être capable de fonctionner aussi bien sur batterie que connecté en USB à un ordinateur, et devra au minimum comporter des LED d'indication.&lt;br /&gt;
&lt;br /&gt;
=== Cahier des charges ===&lt;br /&gt;
&lt;br /&gt;
* Contrôle et traitement des informations de l'émetteur-récepteur ultrason&lt;br /&gt;
* Pilotage par moteur de l'angle de l'émetteur-récepteur ultrason&lt;br /&gt;
* Retour de l'information par des LED sur la carte&lt;br /&gt;
* Gestion de l'alimentation par USB&lt;br /&gt;
* Communication sans fil avec un ordinateur&lt;br /&gt;
* Gestion de l'alimentation sur batterie&lt;br /&gt;
* Interface pour visualiser les informations sur ordinateur&lt;br /&gt;
&lt;br /&gt;
=== Spécification techniques ===&lt;br /&gt;
&lt;br /&gt;
* angle de détection large (-90°,90°)&lt;br /&gt;
* deux émetteurs/récepteurs à ultrason HC-SR04&lt;br /&gt;
&lt;br /&gt;
* Recharge par USB&lt;br /&gt;
* transmission des données par onde radio via un module RF (NRFL2401)&lt;br /&gt;
* Batteries Li-ion&lt;br /&gt;
* une LED tricolore, pour notamment informer des différents niveaux de batterie&lt;br /&gt;
* un afficheur 7 segments pour le débogage&lt;br /&gt;
* interface machine via une application python&lt;br /&gt;
* microcontroleur atmega&lt;br /&gt;
&lt;br /&gt;
== Carte électronique ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique ===&lt;br /&gt;
[[Fichier:Schematique-sonar.pdf|alt=schématique de la carte|gauche|vignette|schématique de la carte de pilotage du sonar]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Routage ===&lt;br /&gt;
[[Fichier:Routage-sonar.pdf|alt=image du routage de la carte|gauche|vignette|capture d'écran du routage du sonar]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Vue 3D ===&lt;br /&gt;
[[Fichier:Vue-3D-sonar.pdf|alt=Vue 3D de la carte|gauche|vignette|Vue 3D de face du routage]]&lt;br /&gt;
[[Fichier:Vue3DdosPCB.pdf|alt=capture d'écran de la vue 3D de dos de la carte|gauche|vignette|vue 3D de dos]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== CAO de la carte du sonar ===&lt;br /&gt;
[[Fichier:Sonar.zip|vignette]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Réalisation ===&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;Afin d'assurer le bon déroulement de la soudure de la carte, nous avons divisé les composants à souder dans des jalons, pour nous assurer étape par étape du bon fonctionnement de la carte.&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;Le premier jalon comporte naturellement le microcontrôleur et les composants nécessaires à son bon fonctionnement, ainsi que la connectique USB pour pouvoir charger des programmes sur la carte.&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;La liste des jalons est disponible ci-dessous:&lt;br /&gt;
[[Fichier:Jalons.txt|alt=fichier texte comprenant les jalons pour la soudure|vignette]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
=== Matériel ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CD4543 en DIP-16&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
== Programmation ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Programmateur AVR ==&lt;br /&gt;
&lt;br /&gt;
=== Tests allumage des LEDs ===&lt;br /&gt;
Lorsque nous avons fini de souder les composants sur la carte, nous avons voulu tester que la carte fonctionnait correctement, c'est pourquoi nous avons écrit un petit programme permettant l'allumage des leds jaunes(une qui s'allume à l'appui sur le bouton bleu traversant, une qui clignote à 10 Hz).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
//avr-gcc -mmcu=atmega8u2 -Wall -Werror -I. -DF_CPU=16000000 -Os -o blink.elf blink.c&lt;br /&gt;
//avr-objcopy -j .text -j .data -O ihex blink.elf blink.hex&lt;br /&gt;
// avrdude -v -patmega8u2 -carduino -b115200 -P/dev/ttyACM0 -U flash:w:blink.hex&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;&lt;br /&gt;
int main(void){&lt;br /&gt;
CLKSEL0 = 0b00010101;   // sélection de l'horloge externe&lt;br /&gt;
CLKSEL1 = 0b00001111;   // minimum de 8Mhz&lt;br /&gt;
CLKPR = 0b10000000;     // modification du diviseur d'horloge (CLKPCE=1)&lt;br /&gt;
CLKPR = 0;              // 0 pour pas de diviseur (diviseur de 1)&lt;br /&gt;
DDRD |= 0x00;                // Sortie pour la LED&lt;br /&gt;
DDRC=0x24;             // Entrée pour le bouton          &lt;br /&gt;
&lt;br /&gt;
while(1){&lt;br /&gt;
  if(PIND &amp;amp; 0x40) PORTC =0x20;      // LED éteinte&lt;br /&gt;
  else PORTC |= 0x00;                  // LED allumée&lt;br /&gt;
  }&lt;br /&gt;
  PORTC^=0x04;&lt;br /&gt;
  _delay_ms(100);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Une fois le code compilé et uploadé, on obtient le résultat suivant:[[Fichier:Image pcb.jpg|gauche|vignette|Allumage de 2 LEDs sur la carte.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&lt;br /&gt;
Pour que le microcontroleur se comporte comme un programmateur AVR USB, il faut d'abord qu'il puisse être reconnu comme un appareil USB, c'est pourquoi nous avons utilisé la bibliothèque LUFA et avons programmé notre carte avec le code qui suit pour qu'il puisse communiquer en USB:&amp;lt;syntaxhighlight lang=&amp;quot;makefile&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
MCU          = atmega8u2&lt;br /&gt;
ARCH         = AVR8&lt;br /&gt;
BOARD        = NONE&lt;br /&gt;
F_CPU        = 16000000&lt;br /&gt;
F_USB        = $(F_CPU)&lt;br /&gt;
OPTIMIZATION = s&lt;br /&gt;
TARGET       = VirtualSerial&lt;br /&gt;
SRC          = $(TARGET).c Descriptors.c $(LUFA_SRC_USB)&lt;br /&gt;
LUFA_PATH    = ../../LUFA&lt;br /&gt;
CC_FLAGS     = -DUSE_LUFA_CONFIG_HEADER -IConfig/&lt;br /&gt;
LD_FLAGS     =&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
	char*       ReportString    = NULL;&lt;br /&gt;
	static bool ActionSent      = false;&lt;br /&gt;
	static bool button = false;&lt;br /&gt;
&lt;br /&gt;
	/* Device must be connected and configured for the task to run */&lt;br /&gt;
	if (USB_DeviceState != DEVICE_STATE_Configured)&lt;br /&gt;
	  return;&lt;br /&gt;
	/* Determine if a joystick action has occurred */&lt;br /&gt;
	if (!(PIND &amp;amp; 0x40)){&lt;br /&gt;
          if(!button){&lt;br /&gt;
	    ReportString = &amp;quot;BOUTON PRESSE\r\n&amp;quot;;&lt;br /&gt;
	    ActionSent=false;&lt;br /&gt;
	    }&lt;br /&gt;
          button=true;&lt;br /&gt;
          }&lt;br /&gt;
        else button=false;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;En faisant un lsusb, on observe que la carte est reconnue comme un appareil USB,  configuré d'après les fichiers de configuration de la LUFA.[[Fichier:Screenshot 2025-03-26 13-23-23.jpg|centré|vignette|800x800px|carte apparaissant comme appareil USB]]Le résultat est présenté dans la vidéo ci-dessous:[[Fichier:Video pcb(1).mp4|gauche|vignette|Communication USB entre ISP et PC visualisée via minicom]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tests ==&lt;br /&gt;
&lt;br /&gt;
== Rendus ==&lt;br /&gt;
&lt;br /&gt;
=== Archive GIT ===&lt;br /&gt;
https://gitea.plil.fr/abiernac/SE3_2024_B5.git&lt;br /&gt;
&lt;br /&gt;
=== Autres rendus ===&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_schema.pdf|thumb|left]]&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_PCB.png|thumb|right]]&lt;br /&gt;
&lt;br /&gt;
Projet KiCad programmateur AVR : [[Fichier:SE3-2024-G5-prog-kicad.zip]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Jalons.txt&amp;diff=7919</id>
		<title>Fichier:Jalons.txt</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Jalons.txt&amp;diff=7919"/>
		<updated>2025-04-29T12:41:42Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;jalons pour la soudure&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7918</id>
		<title>SE3Groupe2024-5</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7918"/>
		<updated>2025-04-29T12:40:26Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : /* Réalisation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
&lt;br /&gt;
=== Objectif ===&lt;br /&gt;
Concevoir et réaliser un mini sonar à partir d'un émetteur-récepteur ultrason, avec un traitement des données effectué par un micro-contrôleur. Les données seront ensuite communiquées par ondes radio à un ordinateur. Le système devra être capable de fonctionner aussi bien sur batterie que connecté en USB à un ordinateur, et devra au minimum comporter des LED d'indication.&lt;br /&gt;
&lt;br /&gt;
=== Cahier des charges ===&lt;br /&gt;
&lt;br /&gt;
* Contrôle et traitement des informations de l'émetteur-récepteur ultrason&lt;br /&gt;
* Pilotage par moteur de l'angle de l'émetteur-récepteur ultrason&lt;br /&gt;
* Retour de l'information par des LED sur la carte&lt;br /&gt;
* Gestion de l'alimentation par USB&lt;br /&gt;
* Communication sans fil avec un ordinateur&lt;br /&gt;
* Gestion de l'alimentation sur batterie&lt;br /&gt;
* Interface pour visualiser les informations sur ordinateur&lt;br /&gt;
&lt;br /&gt;
=== Spécification techniques ===&lt;br /&gt;
&lt;br /&gt;
* angle de détection large (-90°,90°)&lt;br /&gt;
* deux émetteurs/récepteurs à ultrason HC-SR04&lt;br /&gt;
&lt;br /&gt;
* Recharge par USB&lt;br /&gt;
* transmission des données par onde radio via un module RF (NRFL2401)&lt;br /&gt;
* Batteries Li-ion&lt;br /&gt;
* une LED tricolore, pour notamment informer des différents niveaux de batterie&lt;br /&gt;
* un afficheur 7 segments pour le débogage&lt;br /&gt;
* interface machine via une application python&lt;br /&gt;
* microcontroleur atmega&lt;br /&gt;
&lt;br /&gt;
== Carte électronique ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique ===&lt;br /&gt;
[[Fichier:Schematique-sonar.pdf|alt=schématique de la carte|gauche|vignette|schématique de la carte de pilotage du sonar]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Routage ===&lt;br /&gt;
[[Fichier:Routage-sonar.pdf|alt=image du routage de la carte|gauche|vignette|capture d'écran du routage du sonar]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Vue 3D ===&lt;br /&gt;
[[Fichier:Vue-3D-sonar.pdf|alt=Vue 3D de la carte|gauche|vignette|Vue 3D de face du routage]]&lt;br /&gt;
[[Fichier:Vue3DdosPCB.pdf|alt=capture d'écran de la vue 3D de dos de la carte|gauche|vignette|vue 3D de dos]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== CAO de la carte du sonar ===&lt;br /&gt;
[[Fichier:Sonar.zip|vignette]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Réalisation ===&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;Afin d'assurer le bon déroulement de la soudure de la carte, nous avons divisé les composants à souder dans des jalons, pour nous assurer étape par étape du bon fonctionnement de la carte.&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;Le premier jalon comporte naturellement le microcontrôleur et les composants nécessaires à son bon fonctionnement, ainsi que la connectique USB pour pouvoir charger des programmes sur la carte.&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;La liste des jalons est disponible ci-dessous:&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
=== Matériel ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CD4543 en DIP-16&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
== Programmation ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Programmateur AVR ==&lt;br /&gt;
&lt;br /&gt;
=== Tests allumage des LEDs ===&lt;br /&gt;
Lorsque nous avons fini de souder les composants sur la carte, nous avons voulu tester que la carte fonctionnait correctement, c'est pourquoi nous avons écrit un petit programme permettant l'allumage des leds jaunes(une qui s'allume à l'appui sur le bouton bleu traversant, une qui clignote à 10 Hz).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
//avr-gcc -mmcu=atmega8u2 -Wall -Werror -I. -DF_CPU=16000000 -Os -o blink.elf blink.c&lt;br /&gt;
//avr-objcopy -j .text -j .data -O ihex blink.elf blink.hex&lt;br /&gt;
// avrdude -v -patmega8u2 -carduino -b115200 -P/dev/ttyACM0 -U flash:w:blink.hex&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;&lt;br /&gt;
int main(void){&lt;br /&gt;
CLKSEL0 = 0b00010101;   // sélection de l'horloge externe&lt;br /&gt;
CLKSEL1 = 0b00001111;   // minimum de 8Mhz&lt;br /&gt;
CLKPR = 0b10000000;     // modification du diviseur d'horloge (CLKPCE=1)&lt;br /&gt;
CLKPR = 0;              // 0 pour pas de diviseur (diviseur de 1)&lt;br /&gt;
DDRD |= 0x00;                // Sortie pour la LED&lt;br /&gt;
DDRC=0x24;             // Entrée pour le bouton          &lt;br /&gt;
&lt;br /&gt;
while(1){&lt;br /&gt;
  if(PIND &amp;amp; 0x40) PORTC =0x20;      // LED éteinte&lt;br /&gt;
  else PORTC |= 0x00;                  // LED allumée&lt;br /&gt;
  }&lt;br /&gt;
  PORTC^=0x04;&lt;br /&gt;
  _delay_ms(100);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Une fois le code compilé et uploadé, on obtient le résultat suivant:[[Fichier:Image pcb.jpg|gauche|vignette|Allumage de 2 LEDs sur la carte.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&lt;br /&gt;
Pour que le microcontroleur se comporte comme un programmateur AVR USB, il faut d'abord qu'il puisse être reconnu comme un appareil USB, c'est pourquoi nous avons utilisé la bibliothèque LUFA et avons programmé notre carte avec le code qui suit pour qu'il puisse communiquer en USB:&amp;lt;syntaxhighlight lang=&amp;quot;makefile&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
MCU          = atmega8u2&lt;br /&gt;
ARCH         = AVR8&lt;br /&gt;
BOARD        = NONE&lt;br /&gt;
F_CPU        = 16000000&lt;br /&gt;
F_USB        = $(F_CPU)&lt;br /&gt;
OPTIMIZATION = s&lt;br /&gt;
TARGET       = VirtualSerial&lt;br /&gt;
SRC          = $(TARGET).c Descriptors.c $(LUFA_SRC_USB)&lt;br /&gt;
LUFA_PATH    = ../../LUFA&lt;br /&gt;
CC_FLAGS     = -DUSE_LUFA_CONFIG_HEADER -IConfig/&lt;br /&gt;
LD_FLAGS     =&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
	char*       ReportString    = NULL;&lt;br /&gt;
	static bool ActionSent      = false;&lt;br /&gt;
	static bool button = false;&lt;br /&gt;
&lt;br /&gt;
	/* Device must be connected and configured for the task to run */&lt;br /&gt;
	if (USB_DeviceState != DEVICE_STATE_Configured)&lt;br /&gt;
	  return;&lt;br /&gt;
	/* Determine if a joystick action has occurred */&lt;br /&gt;
	if (!(PIND &amp;amp; 0x40)){&lt;br /&gt;
          if(!button){&lt;br /&gt;
	    ReportString = &amp;quot;BOUTON PRESSE\r\n&amp;quot;;&lt;br /&gt;
	    ActionSent=false;&lt;br /&gt;
	    }&lt;br /&gt;
          button=true;&lt;br /&gt;
          }&lt;br /&gt;
        else button=false;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;En faisant un lsusb, on observe que la carte est reconnue comme un appareil USB,  configuré d'après les fichiers de configuration de la LUFA.[[Fichier:Screenshot 2025-03-26 13-23-23.jpg|centré|vignette|800x800px|carte apparaissant comme appareil USB]]Le résultat est présenté dans la vidéo ci-dessous:[[Fichier:Video pcb(1).mp4|gauche|vignette|Communication USB entre ISP et PC visualisée via minicom]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tests ==&lt;br /&gt;
&lt;br /&gt;
== Rendus ==&lt;br /&gt;
&lt;br /&gt;
=== Archive GIT ===&lt;br /&gt;
https://gitea.plil.fr/abiernac/SE3_2024_B5.git&lt;br /&gt;
&lt;br /&gt;
=== Autres rendus ===&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_schema.pdf|thumb|left]]&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_PCB.png|thumb|right]]&lt;br /&gt;
&lt;br /&gt;
Projet KiCad programmateur AVR : [[Fichier:SE3-2024-G5-prog-kicad.zip]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Sonar.zip&amp;diff=7917</id>
		<title>Fichier:Sonar.zip</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Sonar.zip&amp;diff=7917"/>
		<updated>2025-04-29T12:33:31Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : Abiernac a téléversé une nouvelle version de Fichier:Sonar.zip&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Fichiers KiCad de la carte sonar comprenant la schématique et le routage.&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7916</id>
		<title>SE3Groupe2024-5</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7916"/>
		<updated>2025-04-29T12:31:45Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
&lt;br /&gt;
=== Objectif ===&lt;br /&gt;
Concevoir et réaliser un mini sonar à partir d'un émetteur-récepteur ultrason, avec un traitement des données effectué par un micro-contrôleur. Les données seront ensuite communiquées par ondes radio à un ordinateur. Le système devra être capable de fonctionner aussi bien sur batterie que connecté en USB à un ordinateur, et devra au minimum comporter des LED d'indication.&lt;br /&gt;
&lt;br /&gt;
=== Cahier des charges ===&lt;br /&gt;
&lt;br /&gt;
* Contrôle et traitement des informations de l'émetteur-récepteur ultrason&lt;br /&gt;
* Pilotage par moteur de l'angle de l'émetteur-récepteur ultrason&lt;br /&gt;
* Retour de l'information par des LED sur la carte&lt;br /&gt;
* Gestion de l'alimentation par USB&lt;br /&gt;
* Communication sans fil avec un ordinateur&lt;br /&gt;
* Gestion de l'alimentation sur batterie&lt;br /&gt;
* Interface pour visualiser les informations sur ordinateur&lt;br /&gt;
&lt;br /&gt;
=== Spécification techniques ===&lt;br /&gt;
&lt;br /&gt;
* angle de détection large (-90°,90°)&lt;br /&gt;
* deux émetteurs/récepteurs à ultrason HC-SR04&lt;br /&gt;
&lt;br /&gt;
* Recharge par USB&lt;br /&gt;
* transmission des données par onde radio via un module RF (NRFL2401)&lt;br /&gt;
* Batteries Li-ion&lt;br /&gt;
* une LED tricolore, pour notamment informer des différents niveaux de batterie&lt;br /&gt;
* un afficheur 7 segments pour le débogage&lt;br /&gt;
* interface machine via une application python&lt;br /&gt;
* microcontroleur atmega&lt;br /&gt;
&lt;br /&gt;
== Carte électronique ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique ===&lt;br /&gt;
[[Fichier:Schematique-sonar.pdf|alt=schématique de la carte|gauche|vignette|schématique de la carte de pilotage du sonar]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Routage ===&lt;br /&gt;
[[Fichier:Routage-sonar.pdf|alt=image du routage de la carte|gauche|vignette|capture d'écran du routage du sonar]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Vue 3D ===&lt;br /&gt;
[[Fichier:Vue-3D-sonar.pdf|alt=Vue 3D de la carte|gauche|vignette|Vue 3D de face du routage]]&lt;br /&gt;
[[Fichier:Vue3DdosPCB.pdf|alt=capture d'écran de la vue 3D de dos de la carte|gauche|vignette|vue 3D de dos]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== CAO de la carte du sonar ===&lt;br /&gt;
[[Fichier:Sonar.zip|vignette]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Réalisation ===&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
=== Matériel ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CD4543 en DIP-16&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
== Programmation ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Programmateur AVR ==&lt;br /&gt;
&lt;br /&gt;
=== Tests allumage des LEDs ===&lt;br /&gt;
Lorsque nous avons fini de souder les composants sur la carte, nous avons voulu tester que la carte fonctionnait correctement, c'est pourquoi nous avons écrit un petit programme permettant l'allumage des leds jaunes(une qui s'allume à l'appui sur le bouton bleu traversant, une qui clignote à 10 Hz).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
//avr-gcc -mmcu=atmega8u2 -Wall -Werror -I. -DF_CPU=16000000 -Os -o blink.elf blink.c&lt;br /&gt;
//avr-objcopy -j .text -j .data -O ihex blink.elf blink.hex&lt;br /&gt;
// avrdude -v -patmega8u2 -carduino -b115200 -P/dev/ttyACM0 -U flash:w:blink.hex&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;&lt;br /&gt;
int main(void){&lt;br /&gt;
CLKSEL0 = 0b00010101;   // sélection de l'horloge externe&lt;br /&gt;
CLKSEL1 = 0b00001111;   // minimum de 8Mhz&lt;br /&gt;
CLKPR = 0b10000000;     // modification du diviseur d'horloge (CLKPCE=1)&lt;br /&gt;
CLKPR = 0;              // 0 pour pas de diviseur (diviseur de 1)&lt;br /&gt;
DDRD |= 0x00;                // Sortie pour la LED&lt;br /&gt;
DDRC=0x24;             // Entrée pour le bouton          &lt;br /&gt;
&lt;br /&gt;
while(1){&lt;br /&gt;
  if(PIND &amp;amp; 0x40) PORTC =0x20;      // LED éteinte&lt;br /&gt;
  else PORTC |= 0x00;                  // LED allumée&lt;br /&gt;
  }&lt;br /&gt;
  PORTC^=0x04;&lt;br /&gt;
  _delay_ms(100);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Une fois le code compilé et uploadé, on obtient le résultat suivant:[[Fichier:Image pcb.jpg|gauche|vignette|Allumage de 2 LEDs sur la carte.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&lt;br /&gt;
Pour que le microcontroleur se comporte comme un programmateur AVR USB, il faut d'abord qu'il puisse être reconnu comme un appareil USB, c'est pourquoi nous avons utilisé la bibliothèque LUFA et avons programmé notre carte avec le code qui suit pour qu'il puisse communiquer en USB:&amp;lt;syntaxhighlight lang=&amp;quot;makefile&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
MCU          = atmega8u2&lt;br /&gt;
ARCH         = AVR8&lt;br /&gt;
BOARD        = NONE&lt;br /&gt;
F_CPU        = 16000000&lt;br /&gt;
F_USB        = $(F_CPU)&lt;br /&gt;
OPTIMIZATION = s&lt;br /&gt;
TARGET       = VirtualSerial&lt;br /&gt;
SRC          = $(TARGET).c Descriptors.c $(LUFA_SRC_USB)&lt;br /&gt;
LUFA_PATH    = ../../LUFA&lt;br /&gt;
CC_FLAGS     = -DUSE_LUFA_CONFIG_HEADER -IConfig/&lt;br /&gt;
LD_FLAGS     =&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
	char*       ReportString    = NULL;&lt;br /&gt;
	static bool ActionSent      = false;&lt;br /&gt;
	static bool button = false;&lt;br /&gt;
&lt;br /&gt;
	/* Device must be connected and configured for the task to run */&lt;br /&gt;
	if (USB_DeviceState != DEVICE_STATE_Configured)&lt;br /&gt;
	  return;&lt;br /&gt;
	/* Determine if a joystick action has occurred */&lt;br /&gt;
	if (!(PIND &amp;amp; 0x40)){&lt;br /&gt;
          if(!button){&lt;br /&gt;
	    ReportString = &amp;quot;BOUTON PRESSE\r\n&amp;quot;;&lt;br /&gt;
	    ActionSent=false;&lt;br /&gt;
	    }&lt;br /&gt;
          button=true;&lt;br /&gt;
          }&lt;br /&gt;
        else button=false;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;En faisant un lsusb, on observe que la carte est reconnue comme un appareil USB,  configuré d'après les fichiers de configuration de la LUFA.[[Fichier:Screenshot 2025-03-26 13-23-23.jpg|centré|vignette|800x800px|carte apparaissant comme appareil USB]]Le résultat est présenté dans la vidéo ci-dessous:[[Fichier:Video pcb(1).mp4|gauche|vignette|Communication USB entre ISP et PC visualisée via minicom]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tests ==&lt;br /&gt;
&lt;br /&gt;
== Rendus ==&lt;br /&gt;
&lt;br /&gt;
=== Archive GIT ===&lt;br /&gt;
https://gitea.plil.fr/abiernac/SE3_2024_B5.git&lt;br /&gt;
&lt;br /&gt;
=== Autres rendus ===&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_schema.pdf|thumb|left]]&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_PCB.png|thumb|right]]&lt;br /&gt;
&lt;br /&gt;
Projet KiCad programmateur AVR : [[Fichier:SE3-2024-G5-prog-kicad.zip]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7915</id>
		<title>SE3Groupe2024-5</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7915"/>
		<updated>2025-04-29T12:31:14Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : /* Vue 3D */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
&lt;br /&gt;
=== Objectif ===&lt;br /&gt;
Concevoir et réaliser un mini sonar à partir d'un émetteur-récepteur ultrason, avec un traitement des données effectué par un micro-contrôleur. Les données seront ensuite communiquées par ondes radio à un ordinateur. Le système devra être capable de fonctionner aussi bien sur batterie que connecté en USB à un ordinateur, et devra au minimum comporter des LED d'indication.&lt;br /&gt;
&lt;br /&gt;
=== Cahier des charges ===&lt;br /&gt;
&lt;br /&gt;
* Contrôle et traitement des informations de l'émetteur-récepteur ultrason&lt;br /&gt;
* Pilotage par moteur de l'angle de l'émetteur-récepteur ultrason&lt;br /&gt;
* Retour de l'information par des LED sur la carte&lt;br /&gt;
* Gestion de l'alimentation par USB&lt;br /&gt;
* Communication sans fil avec un ordinateur&lt;br /&gt;
* Gestion de l'alimentation sur batterie&lt;br /&gt;
* Interface pour visualiser les informations sur ordinateur&lt;br /&gt;
&lt;br /&gt;
=== Spécification techniques ===&lt;br /&gt;
&lt;br /&gt;
* angle de détection large (-90°,90°)&lt;br /&gt;
* deux émetteurs/récepteurs à ultrason HC-SR04&lt;br /&gt;
&lt;br /&gt;
* Recharge par USB&lt;br /&gt;
* transmission des données par onde radio via un module RF (NRFL2401)&lt;br /&gt;
* Batteries Li-ion&lt;br /&gt;
* une LED tricolore, pour notamment informer des différents niveaux de batterie&lt;br /&gt;
* un afficheur 7 segments pour le débogage&lt;br /&gt;
* interface machine via une application python&lt;br /&gt;
* microcontroleur atmega&lt;br /&gt;
&lt;br /&gt;
== Carte électronique ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique ===&lt;br /&gt;
[[Fichier:Schematique-sonar.pdf|alt=schématique de la carte|gauche|vignette|schématique de la carte de pilotage du sonar]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Routage ===&lt;br /&gt;
[[Fichier:Routage-sonar.pdf|alt=image du routage de la carte|gauche|vignette|capture d'écran du routage du sonar]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Vue 3D ===&lt;br /&gt;
[[Fichier:Vue-3D-sonar.pdf|alt=Vue 3D de la carte|gauche|vignette|Vue 3D de face du routage]]&lt;br /&gt;
[[Fichier:Vue3DdosPCB.pdf|alt=capture d'écran de la vue 3D de dos de la carte|gauche|vue 3D de dos]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== CAO de la carte du sonar ===&lt;br /&gt;
[[Fichier:Sonar.zip|vignette]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Réalisation ===&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
=== Matériel ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CD4543 en DIP-16&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
== Programmation ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Programmateur AVR ==&lt;br /&gt;
&lt;br /&gt;
=== Tests allumage des LEDs ===&lt;br /&gt;
Lorsque nous avons fini de souder les composants sur la carte, nous avons voulu tester que la carte fonctionnait correctement, c'est pourquoi nous avons écrit un petit programme permettant l'allumage des leds jaunes(une qui s'allume à l'appui sur le bouton bleu traversant, une qui clignote à 10 Hz).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
//avr-gcc -mmcu=atmega8u2 -Wall -Werror -I. -DF_CPU=16000000 -Os -o blink.elf blink.c&lt;br /&gt;
//avr-objcopy -j .text -j .data -O ihex blink.elf blink.hex&lt;br /&gt;
// avrdude -v -patmega8u2 -carduino -b115200 -P/dev/ttyACM0 -U flash:w:blink.hex&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;&lt;br /&gt;
int main(void){&lt;br /&gt;
CLKSEL0 = 0b00010101;   // sélection de l'horloge externe&lt;br /&gt;
CLKSEL1 = 0b00001111;   // minimum de 8Mhz&lt;br /&gt;
CLKPR = 0b10000000;     // modification du diviseur d'horloge (CLKPCE=1)&lt;br /&gt;
CLKPR = 0;              // 0 pour pas de diviseur (diviseur de 1)&lt;br /&gt;
DDRD |= 0x00;                // Sortie pour la LED&lt;br /&gt;
DDRC=0x24;             // Entrée pour le bouton          &lt;br /&gt;
&lt;br /&gt;
while(1){&lt;br /&gt;
  if(PIND &amp;amp; 0x40) PORTC =0x20;      // LED éteinte&lt;br /&gt;
  else PORTC |= 0x00;                  // LED allumée&lt;br /&gt;
  }&lt;br /&gt;
  PORTC^=0x04;&lt;br /&gt;
  _delay_ms(100);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Une fois le code compilé et uploadé, on obtient le résultat suivant:[[Fichier:Image pcb.jpg|gauche|vignette|Allumage de 2 LEDs sur la carte.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&lt;br /&gt;
Pour que le microcontroleur se comporte comme un programmateur AVR USB, il faut d'abord qu'il puisse être reconnu comme un appareil USB, c'est pourquoi nous avons utilisé la bibliothèque LUFA et avons programmé notre carte avec le code qui suit pour qu'il puisse communiquer en USB:&amp;lt;syntaxhighlight lang=&amp;quot;makefile&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
MCU          = atmega8u2&lt;br /&gt;
ARCH         = AVR8&lt;br /&gt;
BOARD        = NONE&lt;br /&gt;
F_CPU        = 16000000&lt;br /&gt;
F_USB        = $(F_CPU)&lt;br /&gt;
OPTIMIZATION = s&lt;br /&gt;
TARGET       = VirtualSerial&lt;br /&gt;
SRC          = $(TARGET).c Descriptors.c $(LUFA_SRC_USB)&lt;br /&gt;
LUFA_PATH    = ../../LUFA&lt;br /&gt;
CC_FLAGS     = -DUSE_LUFA_CONFIG_HEADER -IConfig/&lt;br /&gt;
LD_FLAGS     =&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
	char*       ReportString    = NULL;&lt;br /&gt;
	static bool ActionSent      = false;&lt;br /&gt;
	static bool button = false;&lt;br /&gt;
&lt;br /&gt;
	/* Device must be connected and configured for the task to run */&lt;br /&gt;
	if (USB_DeviceState != DEVICE_STATE_Configured)&lt;br /&gt;
	  return;&lt;br /&gt;
	/* Determine if a joystick action has occurred */&lt;br /&gt;
	if (!(PIND &amp;amp; 0x40)){&lt;br /&gt;
          if(!button){&lt;br /&gt;
	    ReportString = &amp;quot;BOUTON PRESSE\r\n&amp;quot;;&lt;br /&gt;
	    ActionSent=false;&lt;br /&gt;
	    }&lt;br /&gt;
          button=true;&lt;br /&gt;
          }&lt;br /&gt;
        else button=false;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;En faisant un lsusb, on observe que la carte est reconnue comme un appareil USB,  configuré d'après les fichiers de configuration de la LUFA.[[Fichier:Screenshot 2025-03-26 13-23-23.jpg|centré|vignette|800x800px|carte apparaissant comme appareil USB]]Le résultat est présenté dans la vidéo ci-dessous:[[Fichier:Video pcb(1).mp4|gauche|vignette|Communication USB entre ISP et PC visualisée via minicom]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tests ==&lt;br /&gt;
&lt;br /&gt;
== Rendus ==&lt;br /&gt;
&lt;br /&gt;
=== Archive GIT ===&lt;br /&gt;
https://gitea.plil.fr/abiernac/SE3_2024_B5.git&lt;br /&gt;
&lt;br /&gt;
=== Autres rendus ===&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_schema.pdf|thumb|left]]&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_PCB.png|thumb|right]]&lt;br /&gt;
&lt;br /&gt;
Projet KiCad programmateur AVR : [[Fichier:SE3-2024-G5-prog-kicad.zip]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7914</id>
		<title>SE3Groupe2024-5</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7914"/>
		<updated>2025-04-29T12:30:11Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
&lt;br /&gt;
=== Objectif ===&lt;br /&gt;
Concevoir et réaliser un mini sonar à partir d'un émetteur-récepteur ultrason, avec un traitement des données effectué par un micro-contrôleur. Les données seront ensuite communiquées par ondes radio à un ordinateur. Le système devra être capable de fonctionner aussi bien sur batterie que connecté en USB à un ordinateur, et devra au minimum comporter des LED d'indication.&lt;br /&gt;
&lt;br /&gt;
=== Cahier des charges ===&lt;br /&gt;
&lt;br /&gt;
* Contrôle et traitement des informations de l'émetteur-récepteur ultrason&lt;br /&gt;
* Pilotage par moteur de l'angle de l'émetteur-récepteur ultrason&lt;br /&gt;
* Retour de l'information par des LED sur la carte&lt;br /&gt;
* Gestion de l'alimentation par USB&lt;br /&gt;
* Communication sans fil avec un ordinateur&lt;br /&gt;
* Gestion de l'alimentation sur batterie&lt;br /&gt;
* Interface pour visualiser les informations sur ordinateur&lt;br /&gt;
&lt;br /&gt;
=== Spécification techniques ===&lt;br /&gt;
&lt;br /&gt;
* angle de détection large (-90°,90°)&lt;br /&gt;
* deux émetteurs/récepteurs à ultrason HC-SR04&lt;br /&gt;
&lt;br /&gt;
* Recharge par USB&lt;br /&gt;
* transmission des données par onde radio via un module RF (NRFL2401)&lt;br /&gt;
* Batteries Li-ion&lt;br /&gt;
* une LED tricolore, pour notamment informer des différents niveaux de batterie&lt;br /&gt;
* un afficheur 7 segments pour le débogage&lt;br /&gt;
* interface machine via une application python&lt;br /&gt;
* microcontroleur atmega&lt;br /&gt;
&lt;br /&gt;
== Carte électronique ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique ===&lt;br /&gt;
[[Fichier:Schematique-sonar.pdf|alt=schématique de la carte|gauche|vignette|schématique de la carte de pilotage du sonar]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Routage ===&lt;br /&gt;
[[Fichier:Routage-sonar.pdf|alt=image du routage de la carte|gauche|vignette|capture d'écran du routage du sonar]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Vue 3D ===&lt;br /&gt;
[[Fichier:Vue-3D-sonar.pdf|alt=Vue 3D de la carte|gauche|vignette|Vue 3D de face du routage]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
[[Fichier:Vue3DdosPCB.pdf|alt=capture d'écran de la vue 3D de dos de la carte|vignette|vue 3D de dos]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
=== CAO de la carte du sonar ===&lt;br /&gt;
[[Fichier:Sonar.zip|vignette]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Réalisation ===&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
=== Matériel ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CD4543 en DIP-16&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
== Programmation ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Programmateur AVR ==&lt;br /&gt;
&lt;br /&gt;
=== Tests allumage des LEDs ===&lt;br /&gt;
Lorsque nous avons fini de souder les composants sur la carte, nous avons voulu tester que la carte fonctionnait correctement, c'est pourquoi nous avons écrit un petit programme permettant l'allumage des leds jaunes(une qui s'allume à l'appui sur le bouton bleu traversant, une qui clignote à 10 Hz).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
//avr-gcc -mmcu=atmega8u2 -Wall -Werror -I. -DF_CPU=16000000 -Os -o blink.elf blink.c&lt;br /&gt;
//avr-objcopy -j .text -j .data -O ihex blink.elf blink.hex&lt;br /&gt;
// avrdude -v -patmega8u2 -carduino -b115200 -P/dev/ttyACM0 -U flash:w:blink.hex&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;&lt;br /&gt;
int main(void){&lt;br /&gt;
CLKSEL0 = 0b00010101;   // sélection de l'horloge externe&lt;br /&gt;
CLKSEL1 = 0b00001111;   // minimum de 8Mhz&lt;br /&gt;
CLKPR = 0b10000000;     // modification du diviseur d'horloge (CLKPCE=1)&lt;br /&gt;
CLKPR = 0;              // 0 pour pas de diviseur (diviseur de 1)&lt;br /&gt;
DDRD |= 0x00;                // Sortie pour la LED&lt;br /&gt;
DDRC=0x24;             // Entrée pour le bouton          &lt;br /&gt;
&lt;br /&gt;
while(1){&lt;br /&gt;
  if(PIND &amp;amp; 0x40) PORTC =0x20;      // LED éteinte&lt;br /&gt;
  else PORTC |= 0x00;                  // LED allumée&lt;br /&gt;
  }&lt;br /&gt;
  PORTC^=0x04;&lt;br /&gt;
  _delay_ms(100);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Une fois le code compilé et uploadé, on obtient le résultat suivant:[[Fichier:Image pcb.jpg|gauche|vignette|Allumage de 2 LEDs sur la carte.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&lt;br /&gt;
Pour que le microcontroleur se comporte comme un programmateur AVR USB, il faut d'abord qu'il puisse être reconnu comme un appareil USB, c'est pourquoi nous avons utilisé la bibliothèque LUFA et avons programmé notre carte avec le code qui suit pour qu'il puisse communiquer en USB:&amp;lt;syntaxhighlight lang=&amp;quot;makefile&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
MCU          = atmega8u2&lt;br /&gt;
ARCH         = AVR8&lt;br /&gt;
BOARD        = NONE&lt;br /&gt;
F_CPU        = 16000000&lt;br /&gt;
F_USB        = $(F_CPU)&lt;br /&gt;
OPTIMIZATION = s&lt;br /&gt;
TARGET       = VirtualSerial&lt;br /&gt;
SRC          = $(TARGET).c Descriptors.c $(LUFA_SRC_USB)&lt;br /&gt;
LUFA_PATH    = ../../LUFA&lt;br /&gt;
CC_FLAGS     = -DUSE_LUFA_CONFIG_HEADER -IConfig/&lt;br /&gt;
LD_FLAGS     =&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
	char*       ReportString    = NULL;&lt;br /&gt;
	static bool ActionSent      = false;&lt;br /&gt;
	static bool button = false;&lt;br /&gt;
&lt;br /&gt;
	/* Device must be connected and configured for the task to run */&lt;br /&gt;
	if (USB_DeviceState != DEVICE_STATE_Configured)&lt;br /&gt;
	  return;&lt;br /&gt;
	/* Determine if a joystick action has occurred */&lt;br /&gt;
	if (!(PIND &amp;amp; 0x40)){&lt;br /&gt;
          if(!button){&lt;br /&gt;
	    ReportString = &amp;quot;BOUTON PRESSE\r\n&amp;quot;;&lt;br /&gt;
	    ActionSent=false;&lt;br /&gt;
	    }&lt;br /&gt;
          button=true;&lt;br /&gt;
          }&lt;br /&gt;
        else button=false;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;En faisant un lsusb, on observe que la carte est reconnue comme un appareil USB,  configuré d'après les fichiers de configuration de la LUFA.[[Fichier:Screenshot 2025-03-26 13-23-23.jpg|centré|vignette|800x800px|carte apparaissant comme appareil USB]]Le résultat est présenté dans la vidéo ci-dessous:[[Fichier:Video pcb(1).mp4|gauche|vignette|Communication USB entre ISP et PC visualisée via minicom]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tests ==&lt;br /&gt;
&lt;br /&gt;
== Rendus ==&lt;br /&gt;
&lt;br /&gt;
=== Archive GIT ===&lt;br /&gt;
https://gitea.plil.fr/abiernac/SE3_2024_B5.git&lt;br /&gt;
&lt;br /&gt;
=== Autres rendus ===&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_schema.pdf|thumb|left]]&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_PCB.png|thumb|right]]&lt;br /&gt;
&lt;br /&gt;
Projet KiCad programmateur AVR : [[Fichier:SE3-2024-G5-prog-kicad.zip]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7913</id>
		<title>SE3Groupe2024-5</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7913"/>
		<updated>2025-04-29T12:28:59Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : /* Vue 3D */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
&lt;br /&gt;
=== Objectif ===&lt;br /&gt;
Concevoir et réaliser un mini sonar à partir d'un émetteur-récepteur ultrason, avec un traitement des données effectué par un micro-contrôleur. Les données seront ensuite communiquées par ondes radio à un ordinateur. Le système devra être capable de fonctionner aussi bien sur batterie que connecté en USB à un ordinateur, et devra au minimum comporter des LED d'indication.&lt;br /&gt;
&lt;br /&gt;
=== Cahier des charges ===&lt;br /&gt;
&lt;br /&gt;
* Contrôle et traitement des informations de l'émetteur-récepteur ultrason&lt;br /&gt;
* Pilotage par moteur de l'angle de l'émetteur-récepteur ultrason&lt;br /&gt;
* Retour de l'information par des LED sur la carte&lt;br /&gt;
* Gestion de l'alimentation par USB&lt;br /&gt;
* Communication sans fil avec un ordinateur&lt;br /&gt;
* Gestion de l'alimentation sur batterie&lt;br /&gt;
* Interface pour visualiser les informations sur ordinateur&lt;br /&gt;
&lt;br /&gt;
=== Spécification techniques ===&lt;br /&gt;
&lt;br /&gt;
* angle de détection large (-90°,90°)&lt;br /&gt;
* deux émetteurs/récepteurs à ultrason HC-SR04&lt;br /&gt;
&lt;br /&gt;
* Recharge par USB&lt;br /&gt;
* transmission des données par onde radio via un module RF (NRFL2401)&lt;br /&gt;
* Batteries Li-ion&lt;br /&gt;
* une LED tricolore, pour notamment informer des différents niveaux de batterie&lt;br /&gt;
* un afficheur 7 segments pour le débogage&lt;br /&gt;
* interface machine via une application python&lt;br /&gt;
* microcontroleur atmega&lt;br /&gt;
&lt;br /&gt;
== Carte électronique ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique ===&lt;br /&gt;
[[Fichier:Schematique-sonar.pdf|alt=schématique de la carte|gauche|vignette|schématique de la carte de pilotage du sonar]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Routage ===&lt;br /&gt;
[[Fichier:Routage-sonar.pdf|alt=image du routage de la carte|gauche|vignette|capture d'écran du routage du sonar]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Vue 3D ===&lt;br /&gt;
[[Fichier:Vue-3D-sonar.pdf|alt=Vue 3D de la carte|gauche|vignette|Vue 3D de face du routage]]&lt;br /&gt;
[[Fichier:Vue3DdosPCB.pdf|alt=capture d'écran de la vue 3D de dos de la carte|vignette|vue 3D de dos]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
=== CAO de la carte du sonar ===&lt;br /&gt;
[[Fichier:Sonar.zip|vignette]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Réalisation ===&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
=== Matériel ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CD4543 en DIP-16&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
== Programmation ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Programmateur AVR ==&lt;br /&gt;
&lt;br /&gt;
=== Tests allumage des LEDs ===&lt;br /&gt;
Lorsque nous avons fini de souder les composants sur la carte, nous avons voulu tester que la carte fonctionnait correctement, c'est pourquoi nous avons écrit un petit programme permettant l'allumage des leds jaunes(une qui s'allume à l'appui sur le bouton bleu traversant, une qui clignote à 10 Hz).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
//avr-gcc -mmcu=atmega8u2 -Wall -Werror -I. -DF_CPU=16000000 -Os -o blink.elf blink.c&lt;br /&gt;
//avr-objcopy -j .text -j .data -O ihex blink.elf blink.hex&lt;br /&gt;
// avrdude -v -patmega8u2 -carduino -b115200 -P/dev/ttyACM0 -U flash:w:blink.hex&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;&lt;br /&gt;
int main(void){&lt;br /&gt;
CLKSEL0 = 0b00010101;   // sélection de l'horloge externe&lt;br /&gt;
CLKSEL1 = 0b00001111;   // minimum de 8Mhz&lt;br /&gt;
CLKPR = 0b10000000;     // modification du diviseur d'horloge (CLKPCE=1)&lt;br /&gt;
CLKPR = 0;              // 0 pour pas de diviseur (diviseur de 1)&lt;br /&gt;
DDRD |= 0x00;                // Sortie pour la LED&lt;br /&gt;
DDRC=0x24;             // Entrée pour le bouton          &lt;br /&gt;
&lt;br /&gt;
while(1){&lt;br /&gt;
  if(PIND &amp;amp; 0x40) PORTC =0x20;      // LED éteinte&lt;br /&gt;
  else PORTC |= 0x00;                  // LED allumée&lt;br /&gt;
  }&lt;br /&gt;
  PORTC^=0x04;&lt;br /&gt;
  _delay_ms(100);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Une fois le code compilé et uploadé, on obtient le résultat suivant:[[Fichier:Image pcb.jpg|gauche|vignette|Allumage de 2 LEDs sur la carte.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&lt;br /&gt;
Pour que le microcontroleur se comporte comme un programmateur AVR USB, il faut d'abord qu'il puisse être reconnu comme un appareil USB, c'est pourquoi nous avons utilisé la bibliothèque LUFA et avons programmé notre carte avec le code qui suit pour qu'il puisse communiquer en USB:&amp;lt;syntaxhighlight lang=&amp;quot;makefile&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
MCU          = atmega8u2&lt;br /&gt;
ARCH         = AVR8&lt;br /&gt;
BOARD        = NONE&lt;br /&gt;
F_CPU        = 16000000&lt;br /&gt;
F_USB        = $(F_CPU)&lt;br /&gt;
OPTIMIZATION = s&lt;br /&gt;
TARGET       = VirtualSerial&lt;br /&gt;
SRC          = $(TARGET).c Descriptors.c $(LUFA_SRC_USB)&lt;br /&gt;
LUFA_PATH    = ../../LUFA&lt;br /&gt;
CC_FLAGS     = -DUSE_LUFA_CONFIG_HEADER -IConfig/&lt;br /&gt;
LD_FLAGS     =&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
	char*       ReportString    = NULL;&lt;br /&gt;
	static bool ActionSent      = false;&lt;br /&gt;
	static bool button = false;&lt;br /&gt;
&lt;br /&gt;
	/* Device must be connected and configured for the task to run */&lt;br /&gt;
	if (USB_DeviceState != DEVICE_STATE_Configured)&lt;br /&gt;
	  return;&lt;br /&gt;
	/* Determine if a joystick action has occurred */&lt;br /&gt;
	if (!(PIND &amp;amp; 0x40)){&lt;br /&gt;
          if(!button){&lt;br /&gt;
	    ReportString = &amp;quot;BOUTON PRESSE\r\n&amp;quot;;&lt;br /&gt;
	    ActionSent=false;&lt;br /&gt;
	    }&lt;br /&gt;
          button=true;&lt;br /&gt;
          }&lt;br /&gt;
        else button=false;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;En faisant un lsusb, on observe que la carte est reconnue comme un appareil USB,  configuré d'après les fichiers de configuration de la LUFA.[[Fichier:Screenshot 2025-03-26 13-23-23.jpg|centré|vignette|800x800px|carte apparaissant comme appareil USB]]Le résultat est présenté dans la vidéo ci-dessous:[[Fichier:Video pcb(1).mp4|gauche|vignette|Communication USB entre ISP et PC visualisée via minicom]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tests ==&lt;br /&gt;
&lt;br /&gt;
== Rendus ==&lt;br /&gt;
&lt;br /&gt;
=== Archive GIT ===&lt;br /&gt;
https://gitea.plil.fr/abiernac/SE3_2024_B5.git&lt;br /&gt;
&lt;br /&gt;
=== Autres rendus ===&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_schema.pdf|thumb|left]]&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_PCB.png|thumb|right]]&lt;br /&gt;
&lt;br /&gt;
Projet KiCad programmateur AVR : [[Fichier:SE3-2024-G5-prog-kicad.zip]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Vue3DdosPCB.pdf&amp;diff=7912</id>
		<title>Fichier:Vue3DdosPCB.pdf</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Vue3DdosPCB.pdf&amp;diff=7912"/>
		<updated>2025-04-29T12:26:53Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Vue de dos du modèle 3D de la carte&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7911</id>
		<title>SE3Groupe2024-5</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7911"/>
		<updated>2025-04-29T12:25:47Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : /* Vue 3D */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
&lt;br /&gt;
=== Objectif ===&lt;br /&gt;
Concevoir et réaliser un mini sonar à partir d'un émetteur-récepteur ultrason, avec un traitement des données effectué par un micro-contrôleur. Les données seront ensuite communiquées par ondes radio à un ordinateur. Le système devra être capable de fonctionner aussi bien sur batterie que connecté en USB à un ordinateur, et devra au minimum comporter des LED d'indication.&lt;br /&gt;
&lt;br /&gt;
=== Cahier des charges ===&lt;br /&gt;
&lt;br /&gt;
* Contrôle et traitement des informations de l'émetteur-récepteur ultrason&lt;br /&gt;
* Pilotage par moteur de l'angle de l'émetteur-récepteur ultrason&lt;br /&gt;
* Retour de l'information par des LED sur la carte&lt;br /&gt;
* Gestion de l'alimentation par USB&lt;br /&gt;
* Communication sans fil avec un ordinateur&lt;br /&gt;
* Gestion de l'alimentation sur batterie&lt;br /&gt;
* Interface pour visualiser les informations sur ordinateur&lt;br /&gt;
&lt;br /&gt;
=== Spécification techniques ===&lt;br /&gt;
&lt;br /&gt;
* angle de détection large (-90°,90°)&lt;br /&gt;
* deux émetteurs/récepteurs à ultrason HC-SR04&lt;br /&gt;
&lt;br /&gt;
* Recharge par USB&lt;br /&gt;
* transmission des données par onde radio via un module RF (NRFL2401)&lt;br /&gt;
* Batteries Li-ion&lt;br /&gt;
* une LED tricolore, pour notamment informer des différents niveaux de batterie&lt;br /&gt;
* un afficheur 7 segments pour le débogage&lt;br /&gt;
* interface machine via une application python&lt;br /&gt;
* microcontroleur atmega&lt;br /&gt;
&lt;br /&gt;
== Carte électronique ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique ===&lt;br /&gt;
[[Fichier:Schematique-sonar.pdf|alt=schématique de la carte|gauche|vignette|schématique de la carte de pilotage du sonar]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Routage ===&lt;br /&gt;
[[Fichier:Routage-sonar.pdf|alt=image du routage de la carte|gauche|vignette|capture d'écran du routage du sonar]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Vue 3D ===&lt;br /&gt;
[[Fichier:Vue-3D-sonar.pdf|alt=Vue 3D de la carte|gauche|vignette|Vue 3D de face du routage]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
=== CAO de la carte du sonar ===&lt;br /&gt;
[[Fichier:Sonar.zip|vignette]]&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Réalisation ===&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
=== Matériel ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CD4543 en DIP-16&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
== Programmation ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Programmateur AVR ==&lt;br /&gt;
&lt;br /&gt;
=== Tests allumage des LEDs ===&lt;br /&gt;
Lorsque nous avons fini de souder les composants sur la carte, nous avons voulu tester que la carte fonctionnait correctement, c'est pourquoi nous avons écrit un petit programme permettant l'allumage des leds jaunes(une qui s'allume à l'appui sur le bouton bleu traversant, une qui clignote à 10 Hz).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
//avr-gcc -mmcu=atmega8u2 -Wall -Werror -I. -DF_CPU=16000000 -Os -o blink.elf blink.c&lt;br /&gt;
//avr-objcopy -j .text -j .data -O ihex blink.elf blink.hex&lt;br /&gt;
// avrdude -v -patmega8u2 -carduino -b115200 -P/dev/ttyACM0 -U flash:w:blink.hex&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;&lt;br /&gt;
int main(void){&lt;br /&gt;
CLKSEL0 = 0b00010101;   // sélection de l'horloge externe&lt;br /&gt;
CLKSEL1 = 0b00001111;   // minimum de 8Mhz&lt;br /&gt;
CLKPR = 0b10000000;     // modification du diviseur d'horloge (CLKPCE=1)&lt;br /&gt;
CLKPR = 0;              // 0 pour pas de diviseur (diviseur de 1)&lt;br /&gt;
DDRD |= 0x00;                // Sortie pour la LED&lt;br /&gt;
DDRC=0x24;             // Entrée pour le bouton          &lt;br /&gt;
&lt;br /&gt;
while(1){&lt;br /&gt;
  if(PIND &amp;amp; 0x40) PORTC =0x20;      // LED éteinte&lt;br /&gt;
  else PORTC |= 0x00;                  // LED allumée&lt;br /&gt;
  }&lt;br /&gt;
  PORTC^=0x04;&lt;br /&gt;
  _delay_ms(100);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Une fois le code compilé et uploadé, on obtient le résultat suivant:[[Fichier:Image pcb.jpg|gauche|vignette|Allumage de 2 LEDs sur la carte.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&lt;br /&gt;
Pour que le microcontroleur se comporte comme un programmateur AVR USB, il faut d'abord qu'il puisse être reconnu comme un appareil USB, c'est pourquoi nous avons utilisé la bibliothèque LUFA et avons programmé notre carte avec le code qui suit pour qu'il puisse communiquer en USB:&amp;lt;syntaxhighlight lang=&amp;quot;makefile&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
MCU          = atmega8u2&lt;br /&gt;
ARCH         = AVR8&lt;br /&gt;
BOARD        = NONE&lt;br /&gt;
F_CPU        = 16000000&lt;br /&gt;
F_USB        = $(F_CPU)&lt;br /&gt;
OPTIMIZATION = s&lt;br /&gt;
TARGET       = VirtualSerial&lt;br /&gt;
SRC          = $(TARGET).c Descriptors.c $(LUFA_SRC_USB)&lt;br /&gt;
LUFA_PATH    = ../../LUFA&lt;br /&gt;
CC_FLAGS     = -DUSE_LUFA_CONFIG_HEADER -IConfig/&lt;br /&gt;
LD_FLAGS     =&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
	char*       ReportString    = NULL;&lt;br /&gt;
	static bool ActionSent      = false;&lt;br /&gt;
	static bool button = false;&lt;br /&gt;
&lt;br /&gt;
	/* Device must be connected and configured for the task to run */&lt;br /&gt;
	if (USB_DeviceState != DEVICE_STATE_Configured)&lt;br /&gt;
	  return;&lt;br /&gt;
	/* Determine if a joystick action has occurred */&lt;br /&gt;
	if (!(PIND &amp;amp; 0x40)){&lt;br /&gt;
          if(!button){&lt;br /&gt;
	    ReportString = &amp;quot;BOUTON PRESSE\r\n&amp;quot;;&lt;br /&gt;
	    ActionSent=false;&lt;br /&gt;
	    }&lt;br /&gt;
          button=true;&lt;br /&gt;
          }&lt;br /&gt;
        else button=false;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;En faisant un lsusb, on observe que la carte est reconnue comme un appareil USB,  configuré d'après les fichiers de configuration de la LUFA.[[Fichier:Screenshot 2025-03-26 13-23-23.jpg|centré|vignette|800x800px|carte apparaissant comme appareil USB]]Le résultat est présenté dans la vidéo ci-dessous:[[Fichier:Video pcb(1).mp4|gauche|vignette|Communication USB entre ISP et PC visualisée via minicom]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tests ==&lt;br /&gt;
&lt;br /&gt;
== Rendus ==&lt;br /&gt;
&lt;br /&gt;
=== Archive GIT ===&lt;br /&gt;
https://gitea.plil.fr/abiernac/SE3_2024_B5.git&lt;br /&gt;
&lt;br /&gt;
=== Autres rendus ===&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_schema.pdf|thumb|left]]&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_PCB.png|thumb|right]]&lt;br /&gt;
&lt;br /&gt;
Projet KiCad programmateur AVR : [[Fichier:SE3-2024-G5-prog-kicad.zip]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Vue-3D-sonar.pdf&amp;diff=7910</id>
		<title>Fichier:Vue-3D-sonar.pdf</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Vue-3D-sonar.pdf&amp;diff=7910"/>
		<updated>2025-04-29T12:25:22Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : Abiernac a téléversé une nouvelle version de Fichier:Vue-3D-sonar.pdf&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Vue 3D sonar&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Routage-sonar.pdf&amp;diff=7909</id>
		<title>Fichier:Routage-sonar.pdf</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Routage-sonar.pdf&amp;diff=7909"/>
		<updated>2025-04-29T12:23:00Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : Abiernac a téléversé une nouvelle version de Fichier:Routage-sonar.pdf&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;routage sonar&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7757</id>
		<title>SE3Groupe2024-5</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7757"/>
		<updated>2025-03-26T12:34:09Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Description ==&lt;br /&gt;
&lt;br /&gt;
=== Objectif ===&lt;br /&gt;
Concevoir et réaliser un mini sonar à partir d'un émetteur-récepteur ultrason, avec un traitement des données effectué par un micro-contrôleur. Les données seront ensuite communiquées par ondes radio à un ordinateur. Le système devra être capable de fonctionner aussi bien sur batterie que connecté en USB à un ordinateur, et devra au minimum comporter des LED d'indication.&lt;br /&gt;
&lt;br /&gt;
=== Cahier des charges ===&lt;br /&gt;
&lt;br /&gt;
* Contrôle et traitement des informations de l'émetteur-récepteur ultrason&lt;br /&gt;
* Pilotage par moteur de l'angle de l'émetteur-récepteur ultrason&lt;br /&gt;
* Retour de l'information par des LED sur la carte&lt;br /&gt;
* Gestion de l'alimentation par USB&lt;br /&gt;
* Communication sans fil avec un ordinateur&lt;br /&gt;
* Gestion de l'alimentation sur batterie&lt;br /&gt;
* Interface pour visualiser les informations sur ordinateur&lt;br /&gt;
&lt;br /&gt;
=== Spécification techniques ===&lt;br /&gt;
&lt;br /&gt;
* angle de détection large (-90°,90°)&lt;br /&gt;
* deux émetteurs/récepteurs à ultrason HC-SR04&lt;br /&gt;
&lt;br /&gt;
* Recharge par USB&lt;br /&gt;
* transmission des données par onde radio via un module RF (NRFL2401)&lt;br /&gt;
* Batteries Li-ion&lt;br /&gt;
* une LED tricolore, pour notamment informer des différents niveaux de batterie&lt;br /&gt;
* un afficheur 7 segments pour le débogage&lt;br /&gt;
* interface machine via une application python&lt;br /&gt;
* microcontroleur atmega&lt;br /&gt;
&lt;br /&gt;
== Carte électronique ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique ===&lt;br /&gt;
&lt;br /&gt;
=== Routage ===&lt;br /&gt;
&lt;br /&gt;
=== Réalisation ===&lt;br /&gt;
&lt;br /&gt;
=== Matériel ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CD4543 en DIP-16&lt;br /&gt;
&lt;br /&gt;
== Programmation ==&lt;br /&gt;
&lt;br /&gt;
== Programmateur AVR ==&lt;br /&gt;
&lt;br /&gt;
=== Tests allumage des LEDs ===&lt;br /&gt;
Lorsque nous avons fini de souder les composants sur la carte, nous avons voulu tester que la carte fonctionnait correctement, c'est pourquoi nous avons écrit un petit programme permettant l'allumage des leds jaunes(une qui s'allume à l'appui sur le bouton bleu traversant, une qui clignote à 10 Hz).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
//avr-gcc -mmcu=atmega8u2 -Wall -Werror -I. -DF_CPU=16000000 -Os -o blink.elf blink.c&lt;br /&gt;
//avr-objcopy -j .text -j .data -O ihex blink.elf blink.hex&lt;br /&gt;
// avrdude -v -patmega8u2 -carduino -b115200 -P/dev/ttyACM0 -U flash:w:blink.hex&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;&lt;br /&gt;
int main(void){&lt;br /&gt;
CLKSEL0 = 0b00010101;   // sélection de l'horloge externe&lt;br /&gt;
CLKSEL1 = 0b00001111;   // minimum de 8Mhz&lt;br /&gt;
CLKPR = 0b10000000;     // modification du diviseur d'horloge (CLKPCE=1)&lt;br /&gt;
CLKPR = 0;              // 0 pour pas de diviseur (diviseur de 1)&lt;br /&gt;
DDRD |= 0x00;                // Sortie pour la LED&lt;br /&gt;
DDRC=0x24;             // Entrée pour le bouton          &lt;br /&gt;
&lt;br /&gt;
while(1){&lt;br /&gt;
  if(PIND &amp;amp; 0x40) PORTC =0x20;      // LED éteinte&lt;br /&gt;
  else PORTC |= 0x00;                  // LED allumée&lt;br /&gt;
  }&lt;br /&gt;
  PORTC^=0x04;&lt;br /&gt;
  _delay_ms(100);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Une fois le code compilé et uploadé, on obtient le résultat suivant:[[Fichier:Image pcb.jpg|gauche|vignette|Allumage de 2 LEDs sur la carte.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&lt;br /&gt;
Pour que le microcontroleur se comporte comme un programmateur AVR USB, il faut d'abord qu'il puisse être reconnu comme un appareil USB, c'est pourquoi nous avons utilisé la bibliothèque LUFA et avons programmé notre carte avec le code qui suit pour qu'il puisse communiquer en USB:&amp;lt;syntaxhighlight lang=&amp;quot;makefile&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
MCU          = atmega8u2&lt;br /&gt;
ARCH         = AVR8&lt;br /&gt;
BOARD        = NONE&lt;br /&gt;
F_CPU        = 16000000&lt;br /&gt;
F_USB        = $(F_CPU)&lt;br /&gt;
OPTIMIZATION = s&lt;br /&gt;
TARGET       = VirtualSerial&lt;br /&gt;
SRC          = $(TARGET).c Descriptors.c $(LUFA_SRC_USB)&lt;br /&gt;
LUFA_PATH    = ../../LUFA&lt;br /&gt;
CC_FLAGS     = -DUSE_LUFA_CONFIG_HEADER -IConfig/&lt;br /&gt;
LD_FLAGS     =&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
	char*       ReportString    = NULL;&lt;br /&gt;
	static bool ActionSent      = false;&lt;br /&gt;
	static bool button = false;&lt;br /&gt;
&lt;br /&gt;
	/* Device must be connected and configured for the task to run */&lt;br /&gt;
	if (USB_DeviceState != DEVICE_STATE_Configured)&lt;br /&gt;
	  return;&lt;br /&gt;
	/* Determine if a joystick action has occurred */&lt;br /&gt;
	if (!(PIND &amp;amp; 0x40)){&lt;br /&gt;
          if(!button){&lt;br /&gt;
	    ReportString = &amp;quot;BOUTON PRESSE\r\n&amp;quot;;&lt;br /&gt;
	    ActionSent=false;&lt;br /&gt;
	    }&lt;br /&gt;
          button=true;&lt;br /&gt;
          }&lt;br /&gt;
        else button=false;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;En faisant un lsusb, on observe que la carte est reconnue comme un appareil USB,  configuré d'après les fichiers de configuration de la LUFA.[[Fichier:Screenshot 2025-03-26 13-23-23.jpg|centré|vignette|800x800px|carte apparaissant comme appareil USB]]Le résultat est présenté dans la vidéo ci-dessous:[[Fichier:Video pcb(1).mp4|gauche|vignette|Communication USB entre ISP et PC visualisée via minicom]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tests ==&lt;br /&gt;
&lt;br /&gt;
== Rendus ==&lt;br /&gt;
&lt;br /&gt;
=== Archive GIT ===&lt;br /&gt;
&lt;br /&gt;
=== Autres rendus ===&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_schema.pdf|thumb|left]]&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_PCB.png|thumb|right]]&lt;br /&gt;
&lt;br /&gt;
Projet KiCad programmateur AVR : [[Fichier:SE3-2024-G5-prog-kicad.zip]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Screenshot_2025-03-26_13-23-23.jpg&amp;diff=7756</id>
		<title>Fichier:Screenshot 2025-03-26 13-23-23.jpg</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Screenshot_2025-03-26_13-23-23.jpg&amp;diff=7756"/>
		<updated>2025-03-26T12:32:01Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;terminal linux&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7755</id>
		<title>SE3Groupe2024-5</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7755"/>
		<updated>2025-03-26T12:28:30Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Description ==&lt;br /&gt;
&lt;br /&gt;
=== Objectif ===&lt;br /&gt;
Concevoir et réaliser un mini sonar à partir d'un émetteur-récepteur ultrason, avec un traitement des données effectué par un micro-contrôleur. Les données seront ensuite communiquées par ondes radio à un ordinateur. Le système devra être capable de fonctionner aussi bien sur batterie que connecté en USB à un ordinateur, et devra au minimum comporter des LED d'indication.&lt;br /&gt;
&lt;br /&gt;
=== Cahier des charges ===&lt;br /&gt;
&lt;br /&gt;
* Contrôle et traitement des informations de l'émetteur-récepteur ultrason&lt;br /&gt;
* Pilotage par moteur de l'angle de l'émetteur-récepteur ultrason&lt;br /&gt;
* Retour de l'information par des LED sur la carte&lt;br /&gt;
* Gestion de l'alimentation par USB&lt;br /&gt;
* Communication sans fil avec un ordinateur&lt;br /&gt;
* Gestion de l'alimentation sur batterie&lt;br /&gt;
* Interface pour visualiser les informations sur ordinateur&lt;br /&gt;
&lt;br /&gt;
=== Spécification techniques ===&lt;br /&gt;
&lt;br /&gt;
* angle de détection large (-90°,90°)&lt;br /&gt;
* deux émetteurs/récepteurs à ultrason HC-SR04&lt;br /&gt;
&lt;br /&gt;
* Recharge par USB&lt;br /&gt;
* transmission des données par onde radio via un module RF (NRFL2401)&lt;br /&gt;
* Batteries Li-ion&lt;br /&gt;
* une LED tricolore, pour notamment informer des différents niveaux de batterie&lt;br /&gt;
* un afficheur 7 segments pour le débogage&lt;br /&gt;
* interface machine via une application python&lt;br /&gt;
* microcontroleur atmega&lt;br /&gt;
&lt;br /&gt;
== Carte électronique ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique ===&lt;br /&gt;
&lt;br /&gt;
=== Routage ===&lt;br /&gt;
&lt;br /&gt;
=== Réalisation ===&lt;br /&gt;
&lt;br /&gt;
=== Matériel ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CD4543 en DIP-16&lt;br /&gt;
&lt;br /&gt;
== Programmation ==&lt;br /&gt;
&lt;br /&gt;
== Programmateur AVR ==&lt;br /&gt;
&lt;br /&gt;
=== Tests allumage des LEDs ===&lt;br /&gt;
Lorsque nous avons fini de souder les composants sur la carte, nous avons voulu tester que la carte fonctionnait correctement, c'est pourquoi nous avons écrit un petit programme permettant l'allumage des leds jaunes(une qui s'allume à l'appui sur le bouton bleu traversant, une qui clignote à 10 Hz).&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
//avr-gcc -mmcu=atmega8u2 -Wall -Werror -I. -DF_CPU=16000000 -Os -o blink.elf blink.c&lt;br /&gt;
//avr-objcopy -j .text -j .data -O ihex blink.elf blink.hex&lt;br /&gt;
// avrdude -v -patmega8u2 -carduino -b115200 -P/dev/ttyACM0 -U flash:w:blink.hex&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;&lt;br /&gt;
int main(void){&lt;br /&gt;
CLKSEL0 = 0b00010101;   // sélection de l'horloge externe&lt;br /&gt;
CLKSEL1 = 0b00001111;   // minimum de 8Mhz&lt;br /&gt;
CLKPR = 0b10000000;     // modification du diviseur d'horloge (CLKPCE=1)&lt;br /&gt;
CLKPR = 0;              // 0 pour pas de diviseur (diviseur de 1)&lt;br /&gt;
DDRD |= 0x00;                // Sortie pour la LED&lt;br /&gt;
DDRC=0x24;             // Entrée pour le bouton          &lt;br /&gt;
&lt;br /&gt;
while(1){&lt;br /&gt;
  if(PIND &amp;amp; 0x40) PORTC =0x20;      // LED éteinte&lt;br /&gt;
  else PORTC |= 0x00;                  // LED allumée&lt;br /&gt;
  }&lt;br /&gt;
  PORTC^=0x04;&lt;br /&gt;
  _delay_ms(100);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Une fois le code compilé et uploadé, on obtient le résultat suivant:[[Fichier:Image pcb.jpg|gauche|vignette|Allumage de 2 LEDs sur la carte.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&lt;br /&gt;
Pour que le microcontroleur se comporte comme un programmateur AVR USB, il faut d'abord qu'il puisse être reconnu comme un appareil USB, c'est pourquoi nous avons utilisé la bibliothèque LUFA et avons programmé notre carte avec le code qui suit pour qu'il puisse communiquer en USB:&amp;lt;syntaxhighlight lang=&amp;quot;makefile&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
MCU          = atmega8u2&lt;br /&gt;
ARCH         = AVR8&lt;br /&gt;
BOARD        = NONE&lt;br /&gt;
F_CPU        = 16000000&lt;br /&gt;
F_USB        = $(F_CPU)&lt;br /&gt;
OPTIMIZATION = s&lt;br /&gt;
TARGET       = VirtualSerial&lt;br /&gt;
SRC          = $(TARGET).c Descriptors.c $(LUFA_SRC_USB)&lt;br /&gt;
LUFA_PATH    = ../../LUFA&lt;br /&gt;
CC_FLAGS     = -DUSE_LUFA_CONFIG_HEADER -IConfig/&lt;br /&gt;
LD_FLAGS     =&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
	char*       ReportString    = NULL;&lt;br /&gt;
	static bool ActionSent      = false;&lt;br /&gt;
	static bool button = false;&lt;br /&gt;
&lt;br /&gt;
	/* Device must be connected and configured for the task to run */&lt;br /&gt;
	if (USB_DeviceState != DEVICE_STATE_Configured)&lt;br /&gt;
	  return;&lt;br /&gt;
	/* Determine if a joystick action has occurred */&lt;br /&gt;
	if (!(PIND &amp;amp; 0x40)){&lt;br /&gt;
          if(!button){&lt;br /&gt;
	    ReportString = &amp;quot;BOUTON PRESSE\r\n&amp;quot;;&lt;br /&gt;
	    ActionSent=false;&lt;br /&gt;
	    }&lt;br /&gt;
          button=true;&lt;br /&gt;
          }&lt;br /&gt;
        else button=false;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Video pcb(1).mp4|gauche|vignette|Communication USB entre ISP et PC visualisée via minicom]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tests ==&lt;br /&gt;
&lt;br /&gt;
== Rendus ==&lt;br /&gt;
&lt;br /&gt;
=== Archive GIT ===&lt;br /&gt;
&lt;br /&gt;
=== Autres rendus ===&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_schema.pdf|thumb|left]]&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_PCB.png|thumb|right]]&lt;br /&gt;
&lt;br /&gt;
Projet KiCad programmateur AVR : [[Fichier:SE3-2024-G5-prog-kicad.zip]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7754</id>
		<title>SE3Groupe2024-5</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7754"/>
		<updated>2025-03-26T12:19:51Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Description ==&lt;br /&gt;
&lt;br /&gt;
=== Objectif ===&lt;br /&gt;
Concevoir et réaliser un mini sonar à partir d'un émetteur-récepteur ultrason, avec un traitement des données effectué par un micro-contrôleur. Les données seront ensuite communiquées par ondes radio à un ordinateur. Le système devra être capable de fonctionner aussi bien sur batterie que connecté en USB à un ordinateur, et devra au minimum comporter des LED d'indication.&lt;br /&gt;
&lt;br /&gt;
=== Cahier des charges ===&lt;br /&gt;
&lt;br /&gt;
* Contrôle et traitement des informations de l'émetteur-récepteur ultrason&lt;br /&gt;
* Pilotage par moteur de l'angle de l'émetteur-récepteur ultrason&lt;br /&gt;
* Retour de l'information par des LED sur la carte&lt;br /&gt;
* Gestion de l'alimentation par USB&lt;br /&gt;
* Communication sans fil avec un ordinateur&lt;br /&gt;
* Gestion de l'alimentation sur batterie&lt;br /&gt;
* Interface pour visualiser les informations sur ordinateur&lt;br /&gt;
&lt;br /&gt;
=== Spécification techniques ===&lt;br /&gt;
&lt;br /&gt;
* angle de détection large (-90°,90°)&lt;br /&gt;
* deux émetteurs/récepteurs à ultrason HC-SR04&lt;br /&gt;
&lt;br /&gt;
* Recharge par USB&lt;br /&gt;
* transmission des données par onde radio via un module RF (NRFL2401)&lt;br /&gt;
* Batteries Li-ion&lt;br /&gt;
* une LED tricolore, pour notamment informer des différents niveaux de batterie&lt;br /&gt;
* un afficheur 7 segments pour le débogage&lt;br /&gt;
* interface machine via une application python&lt;br /&gt;
* microcontroleur atmega&lt;br /&gt;
&lt;br /&gt;
== Carte électronique ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique ===&lt;br /&gt;
&lt;br /&gt;
=== Routage ===&lt;br /&gt;
&lt;br /&gt;
=== Réalisation ===&lt;br /&gt;
&lt;br /&gt;
=== Matériel ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CD4543 en DIP-16&lt;br /&gt;
&lt;br /&gt;
== Programmation ==&lt;br /&gt;
&lt;br /&gt;
== Programmateur AVR ==&lt;br /&gt;
&lt;br /&gt;
=== Tests allumage des LEDs ===&lt;br /&gt;
Lorsque nous avons fini de souder les composants sur la carte, nous avons voulu tester que la carte fonctionnait correctement, c'est pourquoi nous avons écrit un petit programme permettant l'allumage des leds jaunes(une qui s'allume à l'appui sur le bouton bleu traversant, une qui clignote à 10 Hz).&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Image pcb.jpg|gauche|vignette|Allumage de 2 LEDs sur la carte.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;makefile&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
MCU          = atmega8u2&lt;br /&gt;
ARCH         = AVR8&lt;br /&gt;
BOARD        = NONE&lt;br /&gt;
F_CPU        = 16000000&lt;br /&gt;
F_USB        = $(F_CPU)&lt;br /&gt;
OPTIMIZATION = s&lt;br /&gt;
TARGET       = VirtualSerial&lt;br /&gt;
SRC          = $(TARGET).c Descriptors.c $(LUFA_SRC_USB)&lt;br /&gt;
LUFA_PATH    = ../../LUFA&lt;br /&gt;
CC_FLAGS     = -DUSE_LUFA_CONFIG_HEADER -IConfig/&lt;br /&gt;
LD_FLAGS     =&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
	char*       ReportString    = NULL;&lt;br /&gt;
	static bool ActionSent      = false;&lt;br /&gt;
	static bool button = false;&lt;br /&gt;
&lt;br /&gt;
	/* Device must be connected and configured for the task to run */&lt;br /&gt;
	if (USB_DeviceState != DEVICE_STATE_Configured)&lt;br /&gt;
	  return;&lt;br /&gt;
	/* Determine if a joystick action has occurred */&lt;br /&gt;
	if (!(PIND &amp;amp; 0x40)){&lt;br /&gt;
          if(!button){&lt;br /&gt;
	    ReportString = &amp;quot;BOUTON PRESSE\r\n&amp;quot;;&lt;br /&gt;
	    ActionSent=false;&lt;br /&gt;
	    }&lt;br /&gt;
          button=true;&lt;br /&gt;
          }&lt;br /&gt;
        else button=false;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Video pcb(1).mp4|gauche|vignette|Communication USB entre ISP et PC visualisée via minicom]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tests ==&lt;br /&gt;
&lt;br /&gt;
== Rendus ==&lt;br /&gt;
&lt;br /&gt;
=== Archive GIT ===&lt;br /&gt;
&lt;br /&gt;
=== Autres rendus ===&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_schema.pdf|thumb|left]]&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_PCB.png|thumb|right]]&lt;br /&gt;
&lt;br /&gt;
Projet KiCad programmateur AVR : [[Fichier:SE3-2024-G5-prog-kicad.zip]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7753</id>
		<title>SE3Groupe2024-5</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7753"/>
		<updated>2025-03-26T11:52:27Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : /* Tests allumage des LEDs */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Description ==&lt;br /&gt;
&lt;br /&gt;
=== Objectif ===&lt;br /&gt;
Concevoir et réaliser un mini sonar à partir d'un émetteur-récepteur ultrason, avec un traitement des données effectué par un micro-contrôleur. Les données seront ensuite communiquées par ondes radio à un ordinateur. Le système devra être capable de fonctionner aussi bien sur batterie que connecté en USB à un ordinateur, et devra au minimum comporter des LED d'indication.&lt;br /&gt;
&lt;br /&gt;
=== Cahier des charges ===&lt;br /&gt;
&lt;br /&gt;
* Contrôle et traitement des informations de l'émetteur-récepteur ultrason&lt;br /&gt;
* Pilotage par moteur de l'angle de l'émetteur-récepteur ultrason&lt;br /&gt;
* Retour de l'information par des LED sur la carte&lt;br /&gt;
* Gestion de l'alimentation par USB&lt;br /&gt;
* Communication sans fil avec un ordinateur&lt;br /&gt;
* Gestion de l'alimentation sur batterie&lt;br /&gt;
* Interface pour visualiser les informations sur ordinateur&lt;br /&gt;
&lt;br /&gt;
=== Spécification techniques ===&lt;br /&gt;
&lt;br /&gt;
* angle de détection large (-90°,90°)&lt;br /&gt;
* deux émetteurs/récepteurs à ultrason HC-SR04&lt;br /&gt;
&lt;br /&gt;
* Recharge par USB&lt;br /&gt;
* transmission des données par onde radio via un module RF (NRFL2401)&lt;br /&gt;
* Batteries Li-ion&lt;br /&gt;
* une LED tricolore, pour notamment informer des différents niveaux de batterie&lt;br /&gt;
* un afficheur 7 segments pour le débogage&lt;br /&gt;
* interface machine via une application python&lt;br /&gt;
* microcontroleur atmega&lt;br /&gt;
&lt;br /&gt;
== Carte électronique ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique ===&lt;br /&gt;
&lt;br /&gt;
=== Routage ===&lt;br /&gt;
&lt;br /&gt;
=== Réalisation ===&lt;br /&gt;
&lt;br /&gt;
=== Matériel ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CD4543 en DIP-16&lt;br /&gt;
&lt;br /&gt;
== Programmation ==&lt;br /&gt;
&lt;br /&gt;
== Programmateur AVR ==&lt;br /&gt;
&lt;br /&gt;
=== Tests allumage des LEDs ===&lt;br /&gt;
[[Fichier:Image pcb.jpg|gauche|vignette|Allumage de 2 LEDs sur la carte.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;makefile&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
MCU          = atmega8u2&lt;br /&gt;
ARCH         = AVR8&lt;br /&gt;
BOARD        = NONE&lt;br /&gt;
F_CPU        = 16000000&lt;br /&gt;
F_USB        = $(F_CPU)&lt;br /&gt;
OPTIMIZATION = s&lt;br /&gt;
TARGET       = VirtualSerial&lt;br /&gt;
SRC          = $(TARGET).c Descriptors.c $(LUFA_SRC_USB)&lt;br /&gt;
LUFA_PATH    = ../../LUFA&lt;br /&gt;
CC_FLAGS     = -DUSE_LUFA_CONFIG_HEADER -IConfig/&lt;br /&gt;
LD_FLAGS     =&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
	char*       ReportString    = NULL;&lt;br /&gt;
	static bool ActionSent      = false;&lt;br /&gt;
	static bool button = false;&lt;br /&gt;
&lt;br /&gt;
	/* Device must be connected and configured for the task to run */&lt;br /&gt;
	if (USB_DeviceState != DEVICE_STATE_Configured)&lt;br /&gt;
	  return;&lt;br /&gt;
	/* Determine if a joystick action has occurred */&lt;br /&gt;
	if (!(PIND &amp;amp; 0x40)){&lt;br /&gt;
          if(!button){&lt;br /&gt;
	    ReportString = &amp;quot;BOUTON PRESSE\r\n&amp;quot;;&lt;br /&gt;
	    ActionSent=false;&lt;br /&gt;
	    }&lt;br /&gt;
          button=true;&lt;br /&gt;
          }&lt;br /&gt;
        else button=false;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Video pcb(1).mp4|gauche|vignette|Communication USB entre ISP et PC visualisée via minicom]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tests ==&lt;br /&gt;
&lt;br /&gt;
== Rendus ==&lt;br /&gt;
&lt;br /&gt;
=== Archive GIT ===&lt;br /&gt;
&lt;br /&gt;
=== Autres rendus ===&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_schema.pdf|thumb|left]]&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_PCB.png|thumb|right]]&lt;br /&gt;
&lt;br /&gt;
Projet KiCad programmateur AVR : [[Fichier:SE3-2024-G5-prog-kicad.zip]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7752</id>
		<title>SE3Groupe2024-5</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7752"/>
		<updated>2025-03-26T11:51:54Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : /* Tests allumage des LEDs */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Description ==&lt;br /&gt;
&lt;br /&gt;
=== Objectif ===&lt;br /&gt;
Concevoir et réaliser un mini sonar à partir d'un émetteur-récepteur ultrason, avec un traitement des données effectué par un micro-contrôleur. Les données seront ensuite communiquées par ondes radio à un ordinateur. Le système devra être capable de fonctionner aussi bien sur batterie que connecté en USB à un ordinateur, et devra au minimum comporter des LED d'indication.&lt;br /&gt;
&lt;br /&gt;
=== Cahier des charges ===&lt;br /&gt;
&lt;br /&gt;
* Contrôle et traitement des informations de l'émetteur-récepteur ultrason&lt;br /&gt;
* Pilotage par moteur de l'angle de l'émetteur-récepteur ultrason&lt;br /&gt;
* Retour de l'information par des LED sur la carte&lt;br /&gt;
* Gestion de l'alimentation par USB&lt;br /&gt;
* Communication sans fil avec un ordinateur&lt;br /&gt;
* Gestion de l'alimentation sur batterie&lt;br /&gt;
* Interface pour visualiser les informations sur ordinateur&lt;br /&gt;
&lt;br /&gt;
=== Spécification techniques ===&lt;br /&gt;
&lt;br /&gt;
* angle de détection large (-90°,90°)&lt;br /&gt;
* deux émetteurs/récepteurs à ultrason HC-SR04&lt;br /&gt;
&lt;br /&gt;
* Recharge par USB&lt;br /&gt;
* transmission des données par onde radio via un module RF (NRFL2401)&lt;br /&gt;
* Batteries Li-ion&lt;br /&gt;
* une LED tricolore, pour notamment informer des différents niveaux de batterie&lt;br /&gt;
* un afficheur 7 segments pour le débogage&lt;br /&gt;
* interface machine via une application python&lt;br /&gt;
* microcontroleur atmega&lt;br /&gt;
&lt;br /&gt;
== Carte électronique ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique ===&lt;br /&gt;
&lt;br /&gt;
=== Routage ===&lt;br /&gt;
&lt;br /&gt;
=== Réalisation ===&lt;br /&gt;
&lt;br /&gt;
=== Matériel ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CD4543 en DIP-16&lt;br /&gt;
&lt;br /&gt;
== Programmation ==&lt;br /&gt;
&lt;br /&gt;
== Programmateur AVR ==&lt;br /&gt;
&lt;br /&gt;
=== Tests allumage des LEDs ===&lt;br /&gt;
[[Fichier:Image pcb.jpg|gauche|vignette|Allumage de 2 LEDs sur la carte.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;makefile&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
MCU          = atmega8u2&lt;br /&gt;
ARCH         = AVR8&lt;br /&gt;
BOARD        = NONE&lt;br /&gt;
F_CPU        = 16000000&lt;br /&gt;
F_USB        = $(F_CPU)&lt;br /&gt;
OPTIMIZATION = s&lt;br /&gt;
TARGET       = VirtualSerial&lt;br /&gt;
SRC          = $(TARGET).c Descriptors.c $(LUFA_SRC_USB)&lt;br /&gt;
LUFA_PATH    = ../../LUFA&lt;br /&gt;
CC_FLAGS     = -DUSE_LUFA_CONFIG_HEADER -IConfig/&lt;br /&gt;
LD_FLAGS     =&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
	char*       ReportString    = NULL;&lt;br /&gt;
	static bool ActionSent      = false;&lt;br /&gt;
	static bool button = false;&lt;br /&gt;
&lt;br /&gt;
	/* Device must be connected and configured for the task to run */&lt;br /&gt;
	if (USB_DeviceState != DEVICE_STATE_Configured)&lt;br /&gt;
	  return;&lt;br /&gt;
	/* Determine if a joystick action has occurred */&lt;br /&gt;
	if (!(PIND &amp;amp; 0x40)){&lt;br /&gt;
          if(!button){&lt;br /&gt;
	    ReportString = &amp;quot;BOUTON PRESSE\r\n&amp;quot;;&lt;br /&gt;
	    ActionSent=false;&lt;br /&gt;
	    }&lt;br /&gt;
          button=true;&lt;br /&gt;
          }&lt;br /&gt;
        else button=false;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Video pcb(1).mp4|gauche|vignette|Communication USB entre ISP et PC visualisée via minicom]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tests ==&lt;br /&gt;
&lt;br /&gt;
== Rendus ==&lt;br /&gt;
&lt;br /&gt;
=== Archive GIT ===&lt;br /&gt;
&lt;br /&gt;
=== Autres rendus ===&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_schema.pdf|thumb|left]]&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_PCB.png|thumb|right]]&lt;br /&gt;
&lt;br /&gt;
Projet KiCad programmateur AVR : [[Fichier:SE3-2024-G5-prog-kicad.zip]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7751</id>
		<title>SE3Groupe2024-5</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7751"/>
		<updated>2025-03-26T11:50:46Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : /* Programmateur AVR */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Description ==&lt;br /&gt;
&lt;br /&gt;
=== Objectif ===&lt;br /&gt;
Concevoir et réaliser un mini sonar à partir d'un émetteur-récepteur ultrason, avec un traitement des données effectué par un micro-contrôleur. Les données seront ensuite communiquées par ondes radio à un ordinateur. Le système devra être capable de fonctionner aussi bien sur batterie que connecté en USB à un ordinateur, et devra au minimum comporter des LED d'indication.&lt;br /&gt;
&lt;br /&gt;
=== Cahier des charges ===&lt;br /&gt;
&lt;br /&gt;
* Contrôle et traitement des informations de l'émetteur-récepteur ultrason&lt;br /&gt;
* Pilotage par moteur de l'angle de l'émetteur-récepteur ultrason&lt;br /&gt;
* Retour de l'information par des LED sur la carte&lt;br /&gt;
* Gestion de l'alimentation par USB&lt;br /&gt;
* Communication sans fil avec un ordinateur&lt;br /&gt;
* Gestion de l'alimentation sur batterie&lt;br /&gt;
* Interface pour visualiser les informations sur ordinateur&lt;br /&gt;
&lt;br /&gt;
=== Spécification techniques ===&lt;br /&gt;
&lt;br /&gt;
* angle de détection large (-90°,90°)&lt;br /&gt;
* deux émetteurs/récepteurs à ultrason HC-SR04&lt;br /&gt;
&lt;br /&gt;
* Recharge par USB&lt;br /&gt;
* transmission des données par onde radio via un module RF (NRFL2401)&lt;br /&gt;
* Batteries Li-ion&lt;br /&gt;
* une LED tricolore, pour notamment informer des différents niveaux de batterie&lt;br /&gt;
* un afficheur 7 segments pour le débogage&lt;br /&gt;
* interface machine via une application python&lt;br /&gt;
* microcontroleur atmega&lt;br /&gt;
&lt;br /&gt;
== Carte électronique ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique ===&lt;br /&gt;
&lt;br /&gt;
=== Routage ===&lt;br /&gt;
&lt;br /&gt;
=== Réalisation ===&lt;br /&gt;
&lt;br /&gt;
=== Matériel ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CD4543 en DIP-16&lt;br /&gt;
&lt;br /&gt;
== Programmation ==&lt;br /&gt;
&lt;br /&gt;
== Programmateur AVR ==&lt;br /&gt;
&lt;br /&gt;
=== Tests allumage des LEDs ===&lt;br /&gt;
[[Fichier:Image pcb.jpg|gauche|vignette|Allumage de 2 LEDs sur la carte.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;[[Fichier:Video pcb(1).mp4|gauche|vignette|Communication USB entre ISP et PC visualisée via minicom]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;makefile&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
MCU          = atmega8u2&lt;br /&gt;
ARCH         = AVR8&lt;br /&gt;
BOARD        = NONE&lt;br /&gt;
F_CPU        = 16000000&lt;br /&gt;
F_USB        = $(F_CPU)&lt;br /&gt;
OPTIMIZATION = s&lt;br /&gt;
TARGET       = VirtualSerial&lt;br /&gt;
SRC          = $(TARGET).c Descriptors.c $(LUFA_SRC_USB)&lt;br /&gt;
LUFA_PATH    = ../../LUFA&lt;br /&gt;
CC_FLAGS     = -DUSE_LUFA_CONFIG_HEADER -IConfig/&lt;br /&gt;
LD_FLAGS     =&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
	char*       ReportString    = NULL;&lt;br /&gt;
	static bool ActionSent      = false;&lt;br /&gt;
	static bool button = false;&lt;br /&gt;
&lt;br /&gt;
	/* Device must be connected and configured for the task to run */&lt;br /&gt;
	if (USB_DeviceState != DEVICE_STATE_Configured)&lt;br /&gt;
	  return;&lt;br /&gt;
	/* Determine if a joystick action has occurred */&lt;br /&gt;
	if (!(PIND &amp;amp; 0x40)){&lt;br /&gt;
          if(!button){&lt;br /&gt;
	    ReportString = &amp;quot;BOUTON PRESSE\r\n&amp;quot;;&lt;br /&gt;
	    ActionSent=false;&lt;br /&gt;
	    }&lt;br /&gt;
          button=true;&lt;br /&gt;
          }&lt;br /&gt;
        else button=false;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tests ==&lt;br /&gt;
&lt;br /&gt;
== Rendus ==&lt;br /&gt;
&lt;br /&gt;
=== Archive GIT ===&lt;br /&gt;
&lt;br /&gt;
=== Autres rendus ===&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_schema.pdf|thumb|left]]&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_PCB.png|thumb|right]]&lt;br /&gt;
&lt;br /&gt;
Projet KiCad programmateur AVR : [[Fichier:SE3-2024-G5-prog-kicad.zip]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Video_pcb(1).mp4&amp;diff=7750</id>
		<title>Fichier:Video pcb(1).mp4</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Video_pcb(1).mp4&amp;diff=7750"/>
		<updated>2025-03-26T11:43:46Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Video pcb&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7749</id>
		<title>SE3Groupe2024-5</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7749"/>
		<updated>2025-03-26T11:35:57Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : /* Tests allumage des LEDs */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Description ==&lt;br /&gt;
&lt;br /&gt;
=== Objectif ===&lt;br /&gt;
Concevoir et réaliser un mini sonar à partir d'un émetteur-récepteur ultrason, avec un traitement des données effectué par un micro-contrôleur. Les données seront ensuite communiquées par ondes radio à un ordinateur. Le système devra être capable de fonctionner aussi bien sur batterie que connecté en USB à un ordinateur, et devra au minimum comporter des LED d'indication.&lt;br /&gt;
&lt;br /&gt;
=== Cahier des charges ===&lt;br /&gt;
&lt;br /&gt;
* Contrôle et traitement des informations de l'émetteur-récepteur ultrason&lt;br /&gt;
* Pilotage par moteur de l'angle de l'émetteur-récepteur ultrason&lt;br /&gt;
* Retour de l'information par des LED sur la carte&lt;br /&gt;
* Gestion de l'alimentation par USB&lt;br /&gt;
* Communication sans fil avec un ordinateur&lt;br /&gt;
* Gestion de l'alimentation sur batterie&lt;br /&gt;
* Interface pour visualiser les informations sur ordinateur&lt;br /&gt;
&lt;br /&gt;
=== Spécification techniques ===&lt;br /&gt;
&lt;br /&gt;
* angle de détection large (-90°,90°)&lt;br /&gt;
* deux émetteurs/récepteurs à ultrason HC-SR04&lt;br /&gt;
&lt;br /&gt;
* Recharge par USB&lt;br /&gt;
* transmission des données par onde radio via un module RF (NRFL2401)&lt;br /&gt;
* Batteries Li-ion&lt;br /&gt;
* une LED tricolore, pour notamment informer des différents niveaux de batterie&lt;br /&gt;
* un afficheur 7 segments pour le débogage&lt;br /&gt;
* interface machine via une application python&lt;br /&gt;
* microcontroleur atmega&lt;br /&gt;
&lt;br /&gt;
== Carte électronique ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique ===&lt;br /&gt;
&lt;br /&gt;
=== Routage ===&lt;br /&gt;
&lt;br /&gt;
=== Réalisation ===&lt;br /&gt;
&lt;br /&gt;
=== Matériel ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CD4543 en DIP-16&lt;br /&gt;
&lt;br /&gt;
== Programmation ==&lt;br /&gt;
&lt;br /&gt;
== Programmateur AVR ==&lt;br /&gt;
&lt;br /&gt;
=== Tests allumage des LEDs ===&lt;br /&gt;
[[Fichier:Image pcb.jpg|gauche|vignette|Allumage de 2 LEDs sur la carte.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;makefile&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
MCU          = atmega8u2&lt;br /&gt;
ARCH         = AVR8&lt;br /&gt;
BOARD        = NONE&lt;br /&gt;
F_CPU        = 16000000&lt;br /&gt;
F_USB        = $(F_CPU)&lt;br /&gt;
OPTIMIZATION = s&lt;br /&gt;
TARGET       = VirtualSerial&lt;br /&gt;
SRC          = $(TARGET).c Descriptors.c $(LUFA_SRC_USB)&lt;br /&gt;
LUFA_PATH    = ../../LUFA&lt;br /&gt;
CC_FLAGS     = -DUSE_LUFA_CONFIG_HEADER -IConfig/&lt;br /&gt;
LD_FLAGS     =&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
	char*       ReportString    = NULL;&lt;br /&gt;
	static bool ActionSent      = false;&lt;br /&gt;
	static bool button = false;&lt;br /&gt;
&lt;br /&gt;
	/* Device must be connected and configured for the task to run */&lt;br /&gt;
	if (USB_DeviceState != DEVICE_STATE_Configured)&lt;br /&gt;
	  return;&lt;br /&gt;
	/* Determine if a joystick action has occurred */&lt;br /&gt;
	if (!(PIND &amp;amp; 0x40)){&lt;br /&gt;
          if(!button){&lt;br /&gt;
	    ReportString = &amp;quot;BOUTON PRESSE\r\n&amp;quot;;&lt;br /&gt;
	    ActionSent=false;&lt;br /&gt;
	    }&lt;br /&gt;
          button=true;&lt;br /&gt;
          }&lt;br /&gt;
        else button=false;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tests ==&lt;br /&gt;
&lt;br /&gt;
== Rendus ==&lt;br /&gt;
&lt;br /&gt;
=== Archive GIT ===&lt;br /&gt;
&lt;br /&gt;
=== Autres rendus ===&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_schema.pdf|thumb|left]]&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_PCB.png|thumb|right]]&lt;br /&gt;
&lt;br /&gt;
Projet KiCad programmateur AVR : [[Fichier:SE3-2024-G5-prog-kicad.zip]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7748</id>
		<title>SE3Groupe2024-5</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7748"/>
		<updated>2025-03-26T11:32:41Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : /* Tests allumage des LEDs */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Description ==&lt;br /&gt;
&lt;br /&gt;
=== Objectif ===&lt;br /&gt;
Concevoir et réaliser un mini sonar à partir d'un émetteur-récepteur ultrason, avec un traitement des données effectué par un micro-contrôleur. Les données seront ensuite communiquées par ondes radio à un ordinateur. Le système devra être capable de fonctionner aussi bien sur batterie que connecté en USB à un ordinateur, et devra au minimum comporter des LED d'indication.&lt;br /&gt;
&lt;br /&gt;
=== Cahier des charges ===&lt;br /&gt;
&lt;br /&gt;
* Contrôle et traitement des informations de l'émetteur-récepteur ultrason&lt;br /&gt;
* Pilotage par moteur de l'angle de l'émetteur-récepteur ultrason&lt;br /&gt;
* Retour de l'information par des LED sur la carte&lt;br /&gt;
* Gestion de l'alimentation par USB&lt;br /&gt;
* Communication sans fil avec un ordinateur&lt;br /&gt;
* Gestion de l'alimentation sur batterie&lt;br /&gt;
* Interface pour visualiser les informations sur ordinateur&lt;br /&gt;
&lt;br /&gt;
=== Spécification techniques ===&lt;br /&gt;
&lt;br /&gt;
* angle de détection large (-90°,90°)&lt;br /&gt;
* deux émetteurs/récepteurs à ultrason HC-SR04&lt;br /&gt;
&lt;br /&gt;
* Recharge par USB&lt;br /&gt;
* transmission des données par onde radio via un module RF (NRFL2401)&lt;br /&gt;
* Batteries Li-ion&lt;br /&gt;
* une LED tricolore, pour notamment informer des différents niveaux de batterie&lt;br /&gt;
* un afficheur 7 segments pour le débogage&lt;br /&gt;
* interface machine via une application python&lt;br /&gt;
* microcontroleur atmega&lt;br /&gt;
&lt;br /&gt;
== Carte électronique ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique ===&lt;br /&gt;
&lt;br /&gt;
=== Routage ===&lt;br /&gt;
&lt;br /&gt;
=== Réalisation ===&lt;br /&gt;
&lt;br /&gt;
=== Matériel ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CD4543 en DIP-16&lt;br /&gt;
&lt;br /&gt;
== Programmation ==&lt;br /&gt;
&lt;br /&gt;
== Programmateur AVR ==&lt;br /&gt;
&lt;br /&gt;
=== Tests allumage des LEDs ===&lt;br /&gt;
[[Fichier:Image pcb.jpg|gauche|vignette|Allumage de 2 LEDs sur la carte.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;makefile&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
MCU          = atmega8u2&lt;br /&gt;
ARCH         = AVR8&lt;br /&gt;
BOARD        = NONE&lt;br /&gt;
F_CPU        = 16000000&lt;br /&gt;
F_USB        = $(F_CPU)&lt;br /&gt;
OPTIMIZATION = s&lt;br /&gt;
TARGET       = VirtualSerial&lt;br /&gt;
SRC          = $(TARGET).c Descriptors.c $(LUFA_SRC_USB)&lt;br /&gt;
LUFA_PATH    = ../../LUFA&lt;br /&gt;
CC_FLAGS     = -DUSE_LUFA_CONFIG_HEADER -IConfig/&lt;br /&gt;
LD_FLAGS     =&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tests ==&lt;br /&gt;
&lt;br /&gt;
== Rendus ==&lt;br /&gt;
&lt;br /&gt;
=== Archive GIT ===&lt;br /&gt;
&lt;br /&gt;
=== Autres rendus ===&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_schema.pdf|thumb|left]]&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_PCB.png|thumb|right]]&lt;br /&gt;
&lt;br /&gt;
Projet KiCad programmateur AVR : [[Fichier:SE3-2024-G5-prog-kicad.zip]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7747</id>
		<title>SE3Groupe2024-5</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE3Groupe2024-5&amp;diff=7747"/>
		<updated>2025-03-26T11:32:03Z</updated>

		<summary type="html">&lt;p&gt;Abiernac : /* Tests allumage des LEDs */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Description ==&lt;br /&gt;
&lt;br /&gt;
=== Objectif ===&lt;br /&gt;
Concevoir et réaliser un mini sonar à partir d'un émetteur-récepteur ultrason, avec un traitement des données effectué par un micro-contrôleur. Les données seront ensuite communiquées par ondes radio à un ordinateur. Le système devra être capable de fonctionner aussi bien sur batterie que connecté en USB à un ordinateur, et devra au minimum comporter des LED d'indication.&lt;br /&gt;
&lt;br /&gt;
=== Cahier des charges ===&lt;br /&gt;
&lt;br /&gt;
* Contrôle et traitement des informations de l'émetteur-récepteur ultrason&lt;br /&gt;
* Pilotage par moteur de l'angle de l'émetteur-récepteur ultrason&lt;br /&gt;
* Retour de l'information par des LED sur la carte&lt;br /&gt;
* Gestion de l'alimentation par USB&lt;br /&gt;
* Communication sans fil avec un ordinateur&lt;br /&gt;
* Gestion de l'alimentation sur batterie&lt;br /&gt;
* Interface pour visualiser les informations sur ordinateur&lt;br /&gt;
&lt;br /&gt;
=== Spécification techniques ===&lt;br /&gt;
&lt;br /&gt;
* angle de détection large (-90°,90°)&lt;br /&gt;
* deux émetteurs/récepteurs à ultrason HC-SR04&lt;br /&gt;
&lt;br /&gt;
* Recharge par USB&lt;br /&gt;
* transmission des données par onde radio via un module RF (NRFL2401)&lt;br /&gt;
* Batteries Li-ion&lt;br /&gt;
* une LED tricolore, pour notamment informer des différents niveaux de batterie&lt;br /&gt;
* un afficheur 7 segments pour le débogage&lt;br /&gt;
* interface machine via une application python&lt;br /&gt;
* microcontroleur atmega&lt;br /&gt;
&lt;br /&gt;
== Carte électronique ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique ===&lt;br /&gt;
&lt;br /&gt;
=== Routage ===&lt;br /&gt;
&lt;br /&gt;
=== Réalisation ===&lt;br /&gt;
&lt;br /&gt;
=== Matériel ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CD4543 en DIP-16&lt;br /&gt;
&lt;br /&gt;
== Programmation ==&lt;br /&gt;
&lt;br /&gt;
== Programmateur AVR ==&lt;br /&gt;
&lt;br /&gt;
=== Tests allumage des LEDs ===&lt;br /&gt;
[[Fichier:Image pcb.jpg|gauche|vignette|Allumage de 2 LEDs sur la carte.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;makefile&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
MCU          = atmega8u2&lt;br /&gt;
ARCH         = AVR8&lt;br /&gt;
BOARD        = NONE&lt;br /&gt;
F_CPU        = 16000000&lt;br /&gt;
F_USB        = $(F_CPU)&lt;br /&gt;
OPTIMIZATION = s&lt;br /&gt;
TARGET       = VirtualSerial&lt;br /&gt;
SRC          = $(TARGET).c Descriptors.c $(LUFA_SRC_USB)&lt;br /&gt;
LUFA_PATH    = ../../LUFA&lt;br /&gt;
CC_FLAGS     = -DUSE_LUFA_CONFIG_HEADER -IConfig/&lt;br /&gt;
LD_FLAGS     =&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tests ==&lt;br /&gt;
&lt;br /&gt;
== Rendus ==&lt;br /&gt;
&lt;br /&gt;
=== Archive GIT ===&lt;br /&gt;
&lt;br /&gt;
=== Autres rendus ===&lt;br /&gt;
&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_schema.pdf|thumb|left]]&lt;br /&gt;
[[Fichier:SE3_2024_G5_prog_PCB.png|thumb|right]]&lt;br /&gt;
&lt;br /&gt;
Projet KiCad programmateur AVR : [[Fichier:SE3-2024-G5-prog-kicad.zip]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p style=&amp;quot;clear: both;&amp;quot; /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Abiernac</name></author>
	</entry>
</feed>