« SE3Groupe2024-3 » : différence entre les versions
Aucun résumé des modifications |
|||
(36 versions intermédiaires par 2 utilisateurs non affichées) | |||
Ligne 1 : | Ligne 1 : | ||
== Programmateur AVR == | |||
=== Description du projet === | |||
Pour notre module de Premier Système Embarqué (PSE), il nous a été demandé de concevoir un PCB et programmer un microcontrôleur permettant de programmer un autre microcontrôleur (qui sera testé sur une Arduino Uno). | |||
'''<u>Etape 1 : Conception du circuit électronique</u>''' | |||
La première étape fut de mettre en place le circuit électronique via KiCad, cette carte est composée de : | |||
* 1 Atmega8U2-A qui est notre microcontrôleur | |||
* 1 quartz 8 Mhz | |||
* 1 LED de contrôle présence tension | |||
* 2 LED de test | |||
* 1 port USB-A pour la communication avec l'ordinateur | |||
* 1 connecteur ISP 2x3 pour la connection avec l'AVR à programmer | |||
* 1 bouton de BOOT | |||
* 1 bouton de RESET | |||
* 1 bouton de test | |||
Nous avons conçu le schéma suivant pour notre carte selon les indications données. Il a fallu environ entre 2 et 3 séances de deux heures pour la concevoir. | |||
[[Fichier:Schéma du programmateur.png|néant|vignette|<i>Schéma du programmateur AVR du binôme 3</i>]] | |||
'''<u>Etape 2 : Routage de la carte</u>''' | |||
Après avoir fait le schéma, nous avons fait une première version du routage de la carte qui fut modifié par souci d'optimisation (pour avoir notamment les composants sur une seule couche) par M.Boé, et nous avons obtenu ce routage suivant qui a été tiré en plusieurs fois. | |||
[[Fichier:Schéma prototype.png|vignette|240x240px|<i>Routage du programmateur AVR du binôme 3, version 1</i>|gauche]] | |||
[[Fichier:Routage v1.png|right|vignette|207x207px|<i>Routage du programmateur AVR du binôme 3, version modifié</i>]] | |||
'''<u>Etape 3.0 : Fonctions pratiques</u>''' | |||
Nous avons conçu 3 fonctions primaires, permettant de nous simplifier la gestion des Entrées/Sorties. | |||
Nous avons la fonction ''setup_io'', qui permet, pour un pin et un port donné, de décider de l'assigner à une entrée ou une sortie, et d'activer ou non la résistance de PULL UP interne. | |||
De plus, pour simplifier et éviter la répétition de code, le port utilisé est temporairement remplacé par un pointeur ayant l'adresse du port utilisé. | |||
void setup_io(int pin, int is_output, int pull_up_active, char port){ | |||
volatile uint8_t* PORTx; | |||
volatile uint8_t* PINx; | |||
volatile uint8_t* DDRx; | |||
if (port == 'b'){ | |||
PORTx = &PORTB; | |||
PINx = &PINB; | |||
DDRx = &DDRB; | |||
} | |||
if (port == 'c'){ | |||
PORTx = &PORTC; | |||
PINx = &PINC; | |||
DDRx = &DDRC; | |||
} | |||
if (port == 'd'){ | |||
PORTx = &PORTD; | |||
PINx = &PIND; | |||
DDRx = &DDRD; | |||
} | |||
if (is_output){ | |||
(*DDRx) |= 1<<pin;//met la led D1 en output | |||
}else{ | |||
(*DDRx) |= 0<<pin;//met la led D1 en input | |||
if (pull_up_active){ | |||
(*PORTx) |= 1<<pin; | |||
}else{ | |||
(*PORTx) &= ~(1<<pin); | |||
} | |||
} | |||
} | |||
Nous avons la fonction ''active_o'', qui permet, pour un pin et un port donné, de le mettre à 1 ou à 0. La même méthode est utilisé pour la gestion de port via un pointeur. | |||
Remarque : Cette fonction est destinée à agir sur des pins qui ont été paramétrés en sortie au préalable. | |||
void active_o(int pin, int is_active, char port ){ | |||
volatile uint8_t* PORTx; | |||
volatile uint8_t* PINx; | |||
volatile uint8_t* DDRx; | |||
if (port == 'b'){ | |||
PORTx = &PORTB; | |||
PINx = &PINB; | |||
DDRx = &DDRB; | |||
} | |||
if (port == 'c'){ | |||
PORTx = &PORTC; | |||
PINx = &PINC; | |||
DDRx = &DDRC; | |||
} | |||
if (port == 'd'){ | |||
PORTx = &PORTD; | |||
PINx = &PIND; | |||
DDRx = &DDRD; | |||
} | |||
if (is_active){ | |||
(*PORTx) &= ~(1<<pin); //allume la led | |||
}else{ | |||
(*PORTx) |= 1<<pin; | |||
} | |||
} | |||
Nous avons la fonction ''read_i'', qui permet, pour un pin et un port donné, de lire sa valeur. | |||
Remarque : Cette fonction est destinée à lire sur des pins qui ont été paramétrés en entrée au préalable. | |||
int read_i(int pin, char port){ | |||
int val = 0; | |||
if (port == 'b'){ | |||
val = PINB; | |||
}else if (port == 'c'){ | |||
val = PINC; | |||
}else if (port == 'd'){ | |||
val = PIND; | |||
} | |||
int mask = 0; | |||
mask = 1 << pin; | |||
return (val & mask); | |||
} | |||
'''<u>Etape 3.1 : Premier programme, interaction bouton/LED</u>''' | |||
int main (void) { | |||
CLKSEL0 = 0b00010101; // sélection de l'horloge externe | |||
CLKSEL1 = 0b00001111; // minimum de 8Mhz | |||
CLKPR = 0b10000000; // modification du diviseur d'horloge (CLKPCE=1) | |||
CLKPR = 0; // 0 pour pas de diviseur (diviseur de 1) | |||
setup_io(LED_1, 1, 1, 'd'); // Led définie en OUTPUT sur le Port D | |||
setup_io(LED_2, 1, 1, 'd'); // | |||
setup_io(BUTTON, 0, 1, 'b'); // Bouton INPUT sur le Port B avec résistance de PULL UP interne | |||
active_o(LED_2, 0, 'd'); // La LED 2 est éteinte | |||
while(1) { | |||
if( !read_i(BUTTON, 'b') ){ | |||
active_o(LED_1, 0, 'd'); //Si le bouton est activé, on allume la LED, sinon on l'éteint | |||
}else{ | |||
active_o(LED_1, 1, 'd'); | |||
} | |||
_delay_ms(100); | |||
} | |||
} | |||
Ce programme permet basiquement d'allumer la LED lorsque que le bouton est appuyé. Il utilise les fonctions vues précédemment. | |||
====== Vidéo démonstrative ci dessous : ====== | |||
[[Fichier:Video bouton.mov|néant|vignette]] | |||
'''<u>Etape 4 : Deuxième programme, communication série PC/AVR</u>''' | |||
Pour communiquer avec le PC en série, nous avons utilisé la librairie LUFA. | |||
'''Voici les modifications que nous avons apportées :''' | |||
A la fin du ''main'', nous avons paramétrés nos pins et rajouter une variable qui permettra de n'afficher sur la liaison série uniquement les changements d'états. | |||
#define LED_1 0 // Port D | |||
#define LED_2 1 // Port D | |||
#define BUTTON 4 // Port B | |||
int button_toggle = -1; //evite d'imprimer un texte tout le temps | |||
//Initialisation | |||
setup_io(LED_1, 1, 1, 'd'); // Led OUTPUT | |||
setup_io(LED_2, 1, 1, 'd'); // Led | |||
setup_io(BUTTON, 0, 1, 'b'); // Bouton INPUT | |||
Nous avons ensuite modifié la fonction ''CDC_Task'' pour y implémenter la logique souhaitée : | |||
Quand on appuie sur le bouton, le PC recevra "Button pressed\r\n", et quand on le relâche, le PC recevra "Button not pressed\r\n" | |||
void CDC_Task(void) | |||
{ | |||
... //LUFA Code | |||
//Notre code | |||
int is_button_pressed = !read_i(BUTTON, 'b'); | |||
if( button_toggle != 0 && is_button_pressed ){ | |||
active_o(LED_1, 0, 'd'); //Si le bouton est activé, on allume la LED, sinon on l'éteint | |||
ReportString = "Button pressed\r\n"; | |||
button_toggle = 0; | |||
ActionSent = false; | |||
} | |||
if(button_toggle != 1 && !is_button_pressed ){ | |||
active_o(LED_1, 1, 'd'); | |||
button_toggle = 1; | |||
ReportString = "Button not pressed\r\n"; | |||
ActionSent = false; | |||
} | |||
... //LUFA Code | |||
} | |||
'''Vidéo démonstrative ci dessous :''' | |||
[[Fichier:Communication serie.mov|néant|vignette]] | |||
[https://gitea.plil.fr/tduwez/se3_2024_binome3/src/branch/main/LUFA Lien Gitea : LUFA] | |||
[https://gitea.plil.fr/tduwez/se3_2024_binome3/src/branch/main/carte_PSE Lien Gitea : Programmes] | |||
== Description == | == Description == | ||
'''<u>Sujet 1 : Manette sans fil</u>''' | |||
=== Objectif === | === Objectif === | ||
Ligne 31 : | Ligne 262 : | ||
ReX : mieux expliciter les deux parties : la manette radio autonome et la base radio connectée en USB au terminal de jeu. | ReX : mieux expliciter les deux parties : la manette radio autonome et la base radio connectée en USB au terminal de jeu. | ||
== Carte électronique == | == Carte électronique == | ||
Version actuelle datée du 11 avril 2025 à 15:11
Programmateur AVR
Description du projet
Pour notre module de Premier Système Embarqué (PSE), il nous a été demandé de concevoir un PCB et programmer un microcontrôleur permettant de programmer un autre microcontrôleur (qui sera testé sur une Arduino Uno).
Etape 1 : Conception du circuit électronique
La première étape fut de mettre en place le circuit électronique via KiCad, cette carte est composée de :
- 1 Atmega8U2-A qui est notre microcontrôleur
- 1 quartz 8 Mhz
- 1 LED de contrôle présence tension
- 2 LED de test
- 1 port USB-A pour la communication avec l'ordinateur
- 1 connecteur ISP 2x3 pour la connection avec l'AVR à programmer
- 1 bouton de BOOT
- 1 bouton de RESET
- 1 bouton de test
Nous avons conçu le schéma suivant pour notre carte selon les indications données. Il a fallu environ entre 2 et 3 séances de deux heures pour la concevoir.
Etape 2 : Routage de la carte
Après avoir fait le schéma, nous avons fait une première version du routage de la carte qui fut modifié par souci d'optimisation (pour avoir notamment les composants sur une seule couche) par M.Boé, et nous avons obtenu ce routage suivant qui a été tiré en plusieurs fois.
Etape 3.0 : Fonctions pratiques
Nous avons conçu 3 fonctions primaires, permettant de nous simplifier la gestion des Entrées/Sorties.
Nous avons la fonction setup_io, qui permet, pour un pin et un port donné, de décider de l'assigner à une entrée ou une sortie, et d'activer ou non la résistance de PULL UP interne.
De plus, pour simplifier et éviter la répétition de code, le port utilisé est temporairement remplacé par un pointeur ayant l'adresse du port utilisé.
void setup_io(int pin, int is_output, int pull_up_active, char port){ volatile uint8_t* PORTx; volatile uint8_t* PINx; volatile uint8_t* DDRx; if (port == 'b'){ PORTx = &PORTB; PINx = &PINB; DDRx = &DDRB; } if (port == 'c'){ PORTx = &PORTC; PINx = &PINC; DDRx = &DDRC; } if (port == 'd'){ PORTx = &PORTD; PINx = &PIND; DDRx = &DDRD; } if (is_output){ (*DDRx) |= 1<<pin;//met la led D1 en output }else{ (*DDRx) |= 0<<pin;//met la led D1 en input if (pull_up_active){ (*PORTx) |= 1<<pin; }else{ (*PORTx) &= ~(1<<pin); } } }
Nous avons la fonction active_o, qui permet, pour un pin et un port donné, de le mettre à 1 ou à 0. La même méthode est utilisé pour la gestion de port via un pointeur.
Remarque : Cette fonction est destinée à agir sur des pins qui ont été paramétrés en sortie au préalable.
void active_o(int pin, int is_active, char port ){ volatile uint8_t* PORTx; volatile uint8_t* PINx; volatile uint8_t* DDRx; if (port == 'b'){ PORTx = &PORTB; PINx = &PINB; DDRx = &DDRB; } if (port == 'c'){ PORTx = &PORTC; PINx = &PINC; DDRx = &DDRC; } if (port == 'd'){ PORTx = &PORTD; PINx = &PIND; DDRx = &DDRD; } if (is_active){ (*PORTx) &= ~(1<<pin); //allume la led }else{ (*PORTx) |= 1<<pin; } }
Nous avons la fonction read_i, qui permet, pour un pin et un port donné, de lire sa valeur.
Remarque : Cette fonction est destinée à lire sur des pins qui ont été paramétrés en entrée au préalable.
int read_i(int pin, char port){ int val = 0; if (port == 'b'){ val = PINB; }else if (port == 'c'){ val = PINC; }else if (port == 'd'){ val = PIND; } int mask = 0; mask = 1 << pin; return (val & mask); }
Etape 3.1 : Premier programme, interaction bouton/LED
int main (void) { CLKSEL0 = 0b00010101; // sélection de l'horloge externe CLKSEL1 = 0b00001111; // minimum de 8Mhz CLKPR = 0b10000000; // modification du diviseur d'horloge (CLKPCE=1) CLKPR = 0; // 0 pour pas de diviseur (diviseur de 1) setup_io(LED_1, 1, 1, 'd'); // Led définie en OUTPUT sur le Port D setup_io(LED_2, 1, 1, 'd'); // setup_io(BUTTON, 0, 1, 'b'); // Bouton INPUT sur le Port B avec résistance de PULL UP interne active_o(LED_2, 0, 'd'); // La LED 2 est éteinte while(1) { if( !read_i(BUTTON, 'b') ){ active_o(LED_1, 0, 'd'); //Si le bouton est activé, on allume la LED, sinon on l'éteint }else{ active_o(LED_1, 1, 'd'); } _delay_ms(100); } }
Ce programme permet basiquement d'allumer la LED lorsque que le bouton est appuyé. Il utilise les fonctions vues précédemment.
Vidéo démonstrative ci dessous :
Etape 4 : Deuxième programme, communication série PC/AVR
Pour communiquer avec le PC en série, nous avons utilisé la librairie LUFA.
Voici les modifications que nous avons apportées :
A la fin du main, nous avons paramétrés nos pins et rajouter une variable qui permettra de n'afficher sur la liaison série uniquement les changements d'états.
#define LED_1 0 // Port D #define LED_2 1 // Port D #define BUTTON 4 // Port B int button_toggle = -1; //evite d'imprimer un texte tout le temps //Initialisation setup_io(LED_1, 1, 1, 'd'); // Led OUTPUT setup_io(LED_2, 1, 1, 'd'); // Led setup_io(BUTTON, 0, 1, 'b'); // Bouton INPUT
Nous avons ensuite modifié la fonction CDC_Task pour y implémenter la logique souhaitée :
Quand on appuie sur le bouton, le PC recevra "Button pressed\r\n", et quand on le relâche, le PC recevra "Button not pressed\r\n"
void CDC_Task(void) { ... //LUFA Code //Notre code int is_button_pressed = !read_i(BUTTON, 'b'); if( button_toggle != 0 && is_button_pressed ){ active_o(LED_1, 0, 'd'); //Si le bouton est activé, on allume la LED, sinon on l'éteint ReportString = "Button pressed\r\n"; button_toggle = 0; ActionSent = false; } if(button_toggle != 1 && !is_button_pressed ){ active_o(LED_1, 1, 'd'); button_toggle = 1; ReportString = "Button not pressed\r\n"; ActionSent = false; } ... //LUFA Code }
Vidéo démonstrative ci dessous :
Description
Sujet 1 : Manette sans fil
Objectif
Concevoir et réaliser une manette de jeu sans fil basée sur un microcontrôleur avec communication radio. La manette permettra d’envoyer des commandes à un récepteur connecté à un système de jeu (par exemple, un PC ou une console), tout en respectant les contraintes d'autonomie et de modularité.
Cahier des charges
- Commandes analogiques via deux joysticks : un pour les déplacements, un pour la caméra.
- Retour visuel via des LED indiquant l’état de la manette (connexion, batterie faible, etc.).
- Commandes numériques : plusieurs boutons pour des actions spécifiques (tir, saut, pause, etc.).
- Communication radio entre la manette et le PC
- Gestion de l’alimentation hybride (filaire/batterie)
Spécification techniques
- Transmission des commandes au récepteur via le module radio NRF24L01
- Double alimentation hybride [Filaire/autonome]
- Batterie Lithium
- Recharge via USB
- Port USB pour programmer et utiliser en mode filaire
- Batterie Lithium
- Utilisation du processeur ATmega32u4 pour que la manette soit reconnue comme telle par un ordinateur.
- LED multicolores pour indiquer :
- le niveau de batterie ;
- la connexion avec le récepteur ;
- les différents modes de jeu.
ReX : mieux expliciter les deux parties : la manette radio autonome et la base radio connectée en USB au terminal de jeu.
Carte électronique
Schématique
Routage
Réalisation
Programmation
Tests
Rendus
Archive GIT
Autres rendus
Projet KiCAd programmateur AVR : Fichier:2024-PSE-G3-Prog.zip