« I2L 2023 Groupe4 » : différence entre les versions
Aucun résumé des modifications |
(Alignement vidéos) |
||
(10 versions intermédiaires par 3 utilisateurs non affichées) | |||
Ligne 2 : | Ligne 2 : | ||
=== Description === | === Description === | ||
Notre idée serait de faire un "pendu" | Notre idée serait de faire un "pendu" : jeu qui consiste à deviner un mot en soumettant des lettres. Pour cela, les lettres trouvées seraient affichées sur un écran LCD qui afficherait également la lettre à proposer, celle-ci pourrait être changée avec 2 boutons (avant/après dans l'alphabet), et un 3ème bouton de validation est également présent. | ||
Pour | Pour représenter le nombre de vies restantes (et donc d'échecs possibles) il y aurait 3 LEDs qui s'éteindraient au fur et à mesure des erreurs du joueur. | ||
Le mot à trouver serait pioché au hasard dans un dictionnaire de mots | Le mot à trouver serait pioché au hasard dans un dictionnaire de mots qui pourrait être changé grâce à un échange de données via le port USB. | ||
=== Matériel requis === | === Matériel requis === | ||
- 3 boutons (pour les actions flèche haut, flèche bas, entrée) | * 1 micro-contrôleur ; | ||
* 3 boutons (pour les actions flèche haut, flèche bas, entrée) ; | |||
* 3 LEDs (nombre de vies) ; | |||
* Écran LCD à 2 lignes à contrôleur HD44780 ; | |||
* Port USB afin de changer le dictionnaire des mots. | |||
- 3 LEDs | = Contre-proposition = | ||
Le périphérique USB doit être de type spécifique (classe 0) et utiliser un point d'accès interruption, vous pouvez vous appuyer sur cet exemple LUFA de base : [[Média:LUFA_Minimal.zip]]. | |||
Pour remettre à zéro votre dictionnaire et ajouter des mots, vous écrirez une application avec la bibliothèque <code>libusb</code>. | |||
= Proposition définitive = | |||
= Carte = | |||
Même carte que le groupe 3. | |||
= Travail réalisé = | |||
== Code de test == | |||
Avant de réaliser nos tests, nous avons créé un script Bash afin de compiler et transverser automatiquement notre code vers notre carte ATmega32U4 afin de gagner du temps.[[Fichier:Carte.jpg|vignette|Photo de notre carte ATmega32U4]]<syntaxhighlight lang="bash" line="1"> | |||
#!/bin/bash | |||
# Supprimer le fichier de sortie s'il existe | |||
if [[ -f out/$1.o ]] | |||
then | |||
rm out/$1.o | |||
fi | |||
# Compilation | |||
avr-gcc -mmcu=atmega32u4 -DF_CPU=16000000UL -c -Wall -I. -Os src/$1.c -o out/$1.o | |||
if [[ -f out/$1.o ]] | |||
then | |||
avr-gcc -mmcu=atmega32u4 -g -lm -Wl,--gc-sections -o out/$1.elf out/$1.o | |||
avr-objcopy -j .text -j .data -O ihex out/$1.elf out/$1.hex | |||
# Transverser vers la carte | |||
dfu-programmer atmega32u4 erase | |||
dfu-programmer atmega32u4 flash out/$1.hex | |||
dfu-programmer atmega32u4 reset | |||
fi | |||
</syntaxhighlight>Nous avons commencé par développer 2 codes de test pour vérifier le fonctionnement des boutons et des LEDs. | |||
Dans le fichier led.c, les boutons allument leur LED respective sauf le dernier bouton qui allume toutes les LEDs :<syntaxhighlight lang="c" line="1"> | |||
#include <avr/io.h> | |||
#define LED1 4 | |||
#define LED2 6 | |||
#define LED3 7 | |||
#define LED4 4 | |||
#define BOUTON1 5 | |||
#define BOUTON2 6 | |||
#define BOUTON3 6 | |||
#define BOUTON4 7 | |||
= | int main(void) { | ||
DDRD |= (1<<LED1); // LED 1 | |||
DDRD |= (1<<LED2); // LED 2 | |||
DDRD |= (1<<LED3); // LED 3 | |||
DDRB |= (1<<LED4); // LED 4 | |||
DDRB &= ~(1<<BOUTON1); // BOUTON 1 | |||
PORTB |= (1<<BOUTON1); | |||
DDRB &= ~(1<<BOUTON2); // BOUTON 2 | |||
PORTB |= (1<<BOUTON2); | |||
DDRC &= ~(1<<BOUTON3); // BOUTON 3 | |||
PORTC |= (1<<BOUTON3); | |||
DDRC &= ~(1<<BOUTON4); // BOUTON 4 | |||
PORTC |= (1<<BOUTON4); | |||
while(1) { | |||
if ((PINB & (1<<BOUTON1)) && (PINC & (1<<BOUTON4))) { | |||
PORTD &= ~(1<<LED1); // LED1 éteinte | |||
} else { | |||
PORTD |= (1<<LED1); // LED1 allumée | |||
} | |||
if ((PINB & (1<<BOUTON2)) && (PINC & (1<<BOUTON4))) { | |||
PORTD &= ~(1<<LED2); // LED2 éteinte | |||
} else { | |||
PORTD |= (1<<LED2); // LED2 allumée | |||
} | |||
= | if ((PINC & (1<<BOUTON3)) && (PINC & (1<<BOUTON4))) { | ||
PORTD &= ~(1<<LED3); // LED3 éteinte | |||
} else { | |||
PORTD |= (1<<LED3); // LED3 allumée | |||
} | |||
= | if (PINC & (1<<BOUTON4)) { | ||
PORTB &= ~(1<<LED4); // LED4 éteinte | |||
} else { | |||
PORTB |= (1<<LED4); // LED4 allumée | |||
} | |||
} | |||
} | |||
</syntaxhighlight>Dans le fichier led2.c, les LEDs s'allument à tour de rôle tous les 100 millisecondes.<syntaxhighlight lang="c" line="1"> | |||
#include <avr/io.h> | |||
#include <util/delay.h> | |||
#define LED1 4 | |||
#define LED2 6 | |||
#define LED3 7 | |||
#define LED4 4 | |||
= | int main(void) { | ||
DDRD |= (1<<LED1); // LED 1 | |||
DDRD |= (1<<LED2); // LED 2 | |||
DDRD |= (1<<LED3); // LED 3 | |||
DDRB |= (1<<LED4); // LED 4 | |||
== | while(1) { | ||
PORTD |= (1<<LED1); // LED1 allumée | |||
_delay_ms(100); | |||
PORTD |= (1<<LED2); // LED2 allumée | |||
PORTD &= ~(1<<LED1); // LED1 éteinte | |||
_delay_ms(100); | |||
PORTD |= (1<<LED3); // LED3 allumée | |||
PORTD &= ~(1<<LED2); // LED2 éteinte | |||
_delay_ms(100); | |||
PORTB |= (1<<LED4); // LED4 allumée | |||
PORTD &= ~(1<<LED3); // LED3 éteinte | |||
_delay_ms(100); | |||
PORTB &= ~(1<<LED4); // LED4 éteinte | |||
} | |||
} | |||
</syntaxhighlight> | |||
== Réalisation == | == Réalisation == | ||
Premièrement, nous avons récupéré une liste de mots sur la page Wikipédia : [https://fr.wiktionary.org/wiki/Wiktionnaire:Liste_de_1750_mots_fran%C3%A7ais_les_plus_courants Liste de 1750 mots français les plus courants]. Le code JavaScript ci-dessous nous a permis de récupérer uniquement les noms communs respectant certaines caractéristiques. Dû à la mémoire de notre carte, nous avons ensuite dû limiter la liste à 100 mots.<syntaxhighlight lang="javascript"> | |||
let words = []; | |||
document.querySelectorAll('.mw-parser-output > p').forEach(p => { | |||
if (p.innerText.indexOf('Noms : ') > -1) { | |||
const filteredWords = p.innerText | |||
.split(' : ')[1] | |||
.split(',') | |||
// Retirer accents + majuscules | |||
.map(s => s.trim().normalize('NFD').replace(/[\u0300-\u036f]/g, '').toUpperCase().replace(/Œ/g, 'OE')) | |||
// Mots entre 5 et 10 lettres sans espaces/apostrophes/tirets | |||
.filter(s => | |||
s.length >= 5 && | |||
s.length <= 10 && | |||
s.indexOf(' ') == -1 && | |||
s.indexOf("'") == -1 && | |||
s.indexOf('-') == -1 | |||
); | |||
words = words.concat(filteredWords); | |||
} | |||
}); | |||
// Retirer doublons et tri aléatoire | |||
words = [...new Set(words)]; | |||
words = words.sort((a, b) => 0.5 - Math.random()); | |||
console.log(words.join('\n')); | |||
</syntaxhighlight> | |||
= Démonstrations = | = Démonstrations = | ||
[[Fichier:Partie perdue.mp4|thumb|left|Enregistrement d'une partie de notre jeu de pendu perdue]] | |||
[[Fichier:Partie gagnée.mp4|thumb|left|Enregistrement d'une partie de notre jeu de pendu gagnée]] | |||
<p style="clear: both;" /> | |||
= Rendus = | = Rendus = |
Version actuelle datée du 22 décembre 2023 à 23:33
Proposition de système
Description
Notre idée serait de faire un "pendu" : jeu qui consiste à deviner un mot en soumettant des lettres. Pour cela, les lettres trouvées seraient affichées sur un écran LCD qui afficherait également la lettre à proposer, celle-ci pourrait être changée avec 2 boutons (avant/après dans l'alphabet), et un 3ème bouton de validation est également présent.
Pour représenter le nombre de vies restantes (et donc d'échecs possibles) il y aurait 3 LEDs qui s'éteindraient au fur et à mesure des erreurs du joueur.
Le mot à trouver serait pioché au hasard dans un dictionnaire de mots qui pourrait être changé grâce à un échange de données via le port USB.
Matériel requis
- 1 micro-contrôleur ;
- 3 boutons (pour les actions flèche haut, flèche bas, entrée) ;
- 3 LEDs (nombre de vies) ;
- Écran LCD à 2 lignes à contrôleur HD44780 ;
- Port USB afin de changer le dictionnaire des mots.
Contre-proposition
Le périphérique USB doit être de type spécifique (classe 0) et utiliser un point d'accès interruption, vous pouvez vous appuyer sur cet exemple LUFA de base : Média:LUFA_Minimal.zip.
Pour remettre à zéro votre dictionnaire et ajouter des mots, vous écrirez une application avec la bibliothèque libusb
.
Proposition définitive
Carte
Même carte que le groupe 3.
Travail réalisé
Code de test
Avant de réaliser nos tests, nous avons créé un script Bash afin de compiler et transverser automatiquement notre code vers notre carte ATmega32U4 afin de gagner du temps.
#!/bin/bash
# Supprimer le fichier de sortie s'il existe
if [[ -f out/$1.o ]]
then
rm out/$1.o
fi
# Compilation
avr-gcc -mmcu=atmega32u4 -DF_CPU=16000000UL -c -Wall -I. -Os src/$1.c -o out/$1.o
if [[ -f out/$1.o ]]
then
avr-gcc -mmcu=atmega32u4 -g -lm -Wl,--gc-sections -o out/$1.elf out/$1.o
avr-objcopy -j .text -j .data -O ihex out/$1.elf out/$1.hex
# Transverser vers la carte
dfu-programmer atmega32u4 erase
dfu-programmer atmega32u4 flash out/$1.hex
dfu-programmer atmega32u4 reset
fi
Nous avons commencé par développer 2 codes de test pour vérifier le fonctionnement des boutons et des LEDs. Dans le fichier led.c, les boutons allument leur LED respective sauf le dernier bouton qui allume toutes les LEDs :
#include <avr/io.h>
#define LED1 4
#define LED2 6
#define LED3 7
#define LED4 4
#define BOUTON1 5
#define BOUTON2 6
#define BOUTON3 6
#define BOUTON4 7
int main(void) {
DDRD |= (1<<LED1); // LED 1
DDRD |= (1<<LED2); // LED 2
DDRD |= (1<<LED3); // LED 3
DDRB |= (1<<LED4); // LED 4
DDRB &= ~(1<<BOUTON1); // BOUTON 1
PORTB |= (1<<BOUTON1);
DDRB &= ~(1<<BOUTON2); // BOUTON 2
PORTB |= (1<<BOUTON2);
DDRC &= ~(1<<BOUTON3); // BOUTON 3
PORTC |= (1<<BOUTON3);
DDRC &= ~(1<<BOUTON4); // BOUTON 4
PORTC |= (1<<BOUTON4);
while(1) {
if ((PINB & (1<<BOUTON1)) && (PINC & (1<<BOUTON4))) {
PORTD &= ~(1<<LED1); // LED1 éteinte
} else {
PORTD |= (1<<LED1); // LED1 allumée
}
if ((PINB & (1<<BOUTON2)) && (PINC & (1<<BOUTON4))) {
PORTD &= ~(1<<LED2); // LED2 éteinte
} else {
PORTD |= (1<<LED2); // LED2 allumée
}
if ((PINC & (1<<BOUTON3)) && (PINC & (1<<BOUTON4))) {
PORTD &= ~(1<<LED3); // LED3 éteinte
} else {
PORTD |= (1<<LED3); // LED3 allumée
}
if (PINC & (1<<BOUTON4)) {
PORTB &= ~(1<<LED4); // LED4 éteinte
} else {
PORTB |= (1<<LED4); // LED4 allumée
}
}
}
Dans le fichier led2.c, les LEDs s'allument à tour de rôle tous les 100 millisecondes.
#include <avr/io.h>
#include <util/delay.h>
#define LED1 4
#define LED2 6
#define LED3 7
#define LED4 4
int main(void) {
DDRD |= (1<<LED1); // LED 1
DDRD |= (1<<LED2); // LED 2
DDRD |= (1<<LED3); // LED 3
DDRB |= (1<<LED4); // LED 4
while(1) {
PORTD |= (1<<LED1); // LED1 allumée
_delay_ms(100);
PORTD |= (1<<LED2); // LED2 allumée
PORTD &= ~(1<<LED1); // LED1 éteinte
_delay_ms(100);
PORTD |= (1<<LED3); // LED3 allumée
PORTD &= ~(1<<LED2); // LED2 éteinte
_delay_ms(100);
PORTB |= (1<<LED4); // LED4 allumée
PORTD &= ~(1<<LED3); // LED3 éteinte
_delay_ms(100);
PORTB &= ~(1<<LED4); // LED4 éteinte
}
}
Réalisation
Premièrement, nous avons récupéré une liste de mots sur la page Wikipédia : Liste de 1750 mots français les plus courants. Le code JavaScript ci-dessous nous a permis de récupérer uniquement les noms communs respectant certaines caractéristiques. Dû à la mémoire de notre carte, nous avons ensuite dû limiter la liste à 100 mots.
let words = [];
document.querySelectorAll('.mw-parser-output > p').forEach(p => {
if (p.innerText.indexOf('Noms : ') > -1) {
const filteredWords = p.innerText
.split(' : ')[1]
.split(',')
// Retirer accents + majuscules
.map(s => s.trim().normalize('NFD').replace(/[\u0300-\u036f]/g, '').toUpperCase().replace(/Œ/g, 'OE'))
// Mots entre 5 et 10 lettres sans espaces/apostrophes/tirets
.filter(s =>
s.length >= 5 &&
s.length <= 10 &&
s.indexOf(' ') == -1 &&
s.indexOf("'") == -1 &&
s.indexOf('-') == -1
);
words = words.concat(filteredWords);
}
});
// Retirer doublons et tri aléatoire
words = [...new Set(words)];
words = words.sort((a, b) => 0.5 - Math.random());
console.log(words.join('\n'));
Démonstrations
Rendus
Projet KiCAD : Fichier:I2L-2023-Carte-G4.zip
Programmes : Fichier:I2L-2022-Programmes-G4.zip