I2L 2023 Groupe4

De wiki-se.plil.fr
Aller à la navigation Aller à la recherche

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.

Photo de notre carte ATmega32U4
#!/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

Enregistrement d'une partie de notre jeu de pendu perdue
Enregistrement d'une partie de notre jeu de pendu gagnée

Rendus

Projet KiCAD : Fichier:I2L-2023-Carte-G4.zip

Programmes : Fichier:I2L-2022-Programmes-G4.zip