« I2L 2023 Groupe5 » : différence entre les versions

De wiki-se.plil.fr
Aller à la navigation Aller à la recherche
Aucun résumé des modifications
 
(19 versions intermédiaires par 2 utilisateurs non affichées)
Ligne 6 : Ligne 6 :
* un bouton ENTER pour confirmer une proposition.
* un bouton ENTER pour confirmer une proposition.
Enfin, un port USB permettant de jouer au jeu en mode non-autonome depuis une console texte (avec affichage d'un historique).
Enfin, un port USB permettant de jouer au jeu en mode non-autonome depuis une console texte (avec affichage d'un historique).
=== <u>Proposition de carte:</u> ===
[[Fichier:SchemaMasterMindPdf.pdf|centré|sans_cadre]]
[[Fichier:SchemaMasterMindPdf.pdf|centré|sans_cadre]]


Ligne 16 : Ligne 18 :
Vous n'avez pas à écrire de programme PC avec la bibliothèque <code>libusb</code>.
Vous n'avez pas à écrire de programme PC avec la bibliothèque <code>libusb</code>.


= Proposition définitive =
Si cela peut aider, voici une démonstration LUFA pour faire un simple écho dans un terminal série : [[Média:2023-I2L-SerialEcho.zip]].
 
= Répartition du travail =


= Carte =
= Carte =
Ligne 42 : Ligne 42 :
= Code =
= Code =


== Conception ==
== Conception de programmes de tests ==


* Mise en place d'un programme simple de test qui inverse l'état de deux LED lors de l'appui sur un bouton
* Mise en place d'un programme simple de test qui inverse l'état de deux LED lors de l'appui sur un bouton
Ligne 67 : Ligne 67 :


* Création d'un programme pour manipuler les LEDs multicolores:
* Création d'un programme pour manipuler les LEDs multicolores:
<syntaxhighlight>
<syntaxhighlight lang="c">
void init_LED_Drivers(int nb) {
void init_LED_Drivers(int nb) {
     // LED drivers I/O as outputs
     // LED drivers I/O as outputs
Ligne 107 : Ligne 107 :
     PORT_DLED &= ~(1 << PIN_DLED_LATCH);
     PORT_DLED &= ~(1 << PIN_DLED_LATCH);
}
}
</syntaxhighlight>''Problème: faible intensité lumineuse, probablement un défaut de la carte''
</syntaxhighlight>''Problème rencontré: faible intensité lumineuse, qui s'est avéré être un défaut de la première carte''


* Création du cœur du système de jeu:
* Création du cœur du système de jeu, jouable sur un terminal local:
<syntaxhighlight lang="c">
<syntaxhighlight lang="c">
couleur *random_series(int n, couleur *bank) {
couleur *random_series(int n, couleur *bank) {
Ligne 135 : Ligne 135 :
}
}
</syntaxhighlight>
</syntaxhighlight>
* Création d'un programme pour permettre une connexion avec un terminal externe:
== Réalisation du programme finale ==
* Nous avons tout d'abord réalisé un programme permettant de jouer en communiquant avec la carte depuis un terminal en utilisant VirtualSerial, cf le fichier "[[:Fichier:I2L-2022-Programmes-G5-Version-Terminal.zip|I2L-2022-Programmes-G5-Version-Terminal.zip]]"
<u>Extrait de code permettant de gérer la commande reçue:</u>
<syntaxhighlight lang="c">
/* Handle command */
        if (i < size) {
            Endpoint_Write_8('\r');
            Endpoint_Write_8('\n');
            if (cpt < NB_COLORS) {
                if (!strcmp(cmd, "r")) {
                    strcat(history, "R");
                    Endpoint_Write_Stream_LE(history, strlen(history), NULL);
                    cpt++;
                } else if (!strcmp(cmd, "v")) {
                    strcat(history, "V");
                    Endpoint_Write_Stream_LE(history, strlen(history), NULL);
                    cpt++;
                } else if (!strcmp(cmd, "b")) {
                    strcat(history, "B");
                    Endpoint_Write_Stream_LE(history, strlen(history), NULL);
                    cpt++;
                } else if (!strcmp(cmd, "j")) {
                    strcat(history, "J");
                    Endpoint_Write_Stream_LE(history, strlen(history), NULL);
                    cpt++;
                } else if (!strcmp(cmd, "p")) {
                    strcat(history, "P");
                    Endpoint_Write_Stream_LE(history, strlen(history), NULL);
                    cpt++;
                }
                Endpoint_Write_8(cpt + '0');


                Endpoint_Write_8('\r');
                Endpoint_Write_8('\n');
            }
            if (cpt >= NB_COLORS) {
                char *msg = "Your guess :";
                Endpoint_Write_Stream_LE(msg, strlen(msg), NULL);
                Endpoint_Write_Stream_LE(history, strlen(history), NULL);
                Endpoint_Write_8('\r');
                Endpoint_Write_8('\n');
                if(strcmp(serie,history))
                    Endpoint_Write_Stream_LE(WRONG, strlen(WRONG), NULL);
                else
                    Endpoint_Write_Stream_LE(CORRECT, strlen(CORRECT), NULL);
                Endpoint_Write_8('\r');
                Endpoint_Write_8('\n');
            }
        }
</syntaxhighlight>


== Réalisation ==
 
*Nous avons ensuite réalisé un programme permettant de jouer en communiquant avec la carte depuis les boutons, cf le fichier "[[:Fichier:I2L-2022-Programmes-G5-Version-Terminal.zip|I2L-2022-Programme-G5-Version-Terminal-et-Bouton.zip]]"
<u>Extrait de code permettant de gérer les couleurs associées aux boutons:</u>
<syntaxhighlight lang="c">
void button(void) {
    if (cpt < NB_COLORS) {
        if (!(PINB & (1 << 0))) {
            strcat(history, "R");
            setLED(cpt, 0, MAX_COLOR_INTENSITY, 0);
            cpt++;
        } else if (!(PINB & (1 << 1))) {
            strcat(history, "V");
            setLED(cpt, MAX_COLOR_INTENSITY, 0, 0);
            cpt++;
        } else if (!(PINB & (1 << 5))) {
            strcat(history, "B");
            setLED(cpt, 0, 0, MAX_COLOR_INTENSITY);
            cpt++;
        } else if (!(PINB & (1 << 3))) {
            strcat(history, "J");
            setLED(cpt, MAX_COLOR_INTENSITY, MAX_COLOR_INTENSITY, 0);
            cpt++;
        } else if (!(PINB & (1 << 6))) {
            strcat(history, "P");
            setLED(cpt, 0, MAX_COLOR_INTENSITY, MAX_COLOR_INTENSITY);
            cpt++;
        }
        _delay_ms(200);
    }
    if (!(PINB & (1 << 2))) { // si bouton effacer pressé
        if (cpt > 0) {
            cpt--;
            setLED(cpt, 0, 0, 0); // éteindre LED précécente
            history[cpt] = '\0';
            _delay_ms(200);
        }
    }
    if (!(PINB & (1 << 4))) {
        if (cpt >= NB_COLORS) {
            int check = 1;
            for (int y = 0; y < NB_COLORS; y++) {
                if (serie[y] == history[y]) {
                    setLED(7 - y, MAX_COLOR_INTENSITY, 0, 0);
                } else if (strchr(serie, history[y]) != NULL) {
                    setLED(7 - y, 0, 0, MAX_COLOR_INTENSITY);
                    check = 0;
                } else {
                    setLED(7 - y, 0, MAX_COLOR_INTENSITY, 0);
                    check = 0;
                }
            }
            if (check) {
                serie[0] = '\0';
                victory();
                serie = random_series(NB_COLORS, COLOR_BANK);
            }
            cpt = 0;
            history[0] = '\0';
        }
    }
</syntaxhighlight>
<u>La fonction main détecte si une connexion USB est active, et écoute donc les boutons ou l'entrée USB:</u>
<syntaxhighlight lang="c">
    for (;;) {
        CDC_Task();
        USB_USBTask();
        if (USB_DeviceState != DEVICE_STATE_Configured)
            button();
    }
</syntaxhighlight>
*Nous avons enfin amélioré le programme existant en retravaillant la génération de la chaîne aléatoire (lecture de PIN inutilisée), cf le fichier "[[:Fichier:I2L-2022-Programme-G5-Version-Finale.zip|Ficher:I2L-2022-Programme-G5-Version-Finale.zip]]"
<syntaxhighlight lang="c">
int main(void) {
    (...)
    DDRD &= ~0x0F;
    srand(PIND);
    (...)
}
 
char *random_series(int n, char *bank) {
    char *res = (char *) malloc(n * sizeof(char));
    for (int i = 0; i < n; i++)
        res[i] = bank[rand() % MAX_COLORS];
    return res;
}
   
</syntaxhighlight>


= Démonstrations =
= Démonstrations =


Exemple d'une partie sur console:[[Fichier:Demo M2I2L Grp5 TeleversementV2.mov|néant|vignette]]
Exemple avec l'utilisation des boutons:
[[Fichier:M2I2L Grp5 Demo Boutons.mov|néant|vignette]]
= Rendus =
= Rendus =


Projet KiCAD : [[File:I2L-2023-Carte-G5.zip]]
Projet KiCAD : [[File:I2L-2023-Carte-G5.zip]]


Programmes : [[File:I2L-2022-Programmes-G5.zip]]
Programmes :  
 
[[:Fichier:I2L-2022-Programmes-G5-Version-Terminal.zip]]
 
[[:Fichier:I2L-2022-Programmes-G5.zip|Fichier:I2L-2022-Programme-G5-Version-Terminal-et-Bouton.zip]]
 
[[:Fichier:I2L-2022-Programme-G5-Version-Finale.zip|Ficher:I2L-2022-Programme-G5-Version-Finale.zip]]

Version actuelle datée du 21 décembre 2023 à 15:49

Proposition de système

Le projet consiste en un Mastermind où un joueur doit deviner une série de 4 couleurs en proposant des séries une à une. La carte comprend deux séries de 4 LEDS multicolores, l'une pour les propositions faites par le joueur, la seconde pour valider ou non les couleurs proposées. En dessous se trouve un clavier de 6 boutons permettant de :

  • proposer les couleurs (1 par couleur donc 4 en tout)
  • un bouton RESET
  • un bouton ENTER pour confirmer une proposition.

Enfin, un port USB permettant de jouer au jeu en mode non-autonome depuis une console texte (avec affichage d'un historique).

Proposition de carte:

SchemaMasterMindPdf.pdf

Contre-proposition

Il doit être aussi possible de jouer du PC quand la carte y est connectée. Pour ce faire vous utiliserez un terminal série comme minicom ou putty. Votre carte doit donc implanter un périphérique USB de type émulation de port série.

Pour la programmation du périphèrique USB vous utilisez, comme base, la démonstration LUFA Demos/Device/LowLevel/VirtualSerial.

Vous n'avez pas à écrire de programme PC avec la bibliothèque libusb.

Si cela peut aider, voici une démonstration LUFA pour faire un simple écho dans un terminal série : Média:2023-I2L-SerialEcho.zip.

Carte

I2L-2023-Carte3D-G5.png
I2L-2023-CarteSchema-G5.pdf

A droite le schéma de la carte, à gauche une vue 3D du circuit imprimé et au centre la première version, soudée, de la carte.

M2I2L-Groupe5-Carte.jpg
I2L-2023-Carte3D-G5-bis.png
I2L-2023-Carte-G5-bis.jpg

Sur la première version de la carte les LED multicolores ne fonctionnaient pas correctement. Une seconde version de la carte a été fabriquée avec juste une modification mineure pour que les deux résistances liées au pilote de LED soient au plus proche des broches sur la face inférieure. Une vidéo permet de constater que les LED fonctionnent maintenant correctement. Deux pistes pour expliquer le meilleur fonctionnement de la version 2 : les LED ne sont pas du même modèle, le TLC5947 peut être mieux soudé. Le programme de test est certainement identique à celui produit en séance, à tout hasard je le joins ici : Fichier:I2L-2022-G5-TLC5947.zip

Code

Conception de programmes de tests

  • Mise en place d'un programme simple de test qui inverse l'état de deux LED lors de l'appui sur un bouton
    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)

    DDRC    |= (1 << 4);
    DDRC    |= (1 << 5);
    DDRB    &= ~(1 << BUT_BIT);
    PORTB   |= (1 << BUT_BIT);

    PORTC |= (1 << 4);
    while(1) {
        if (!(PINB & (1 << BUT_BIT))) {
            PORTC ^= (1 << 4);
            PORTC ^= (1 << 5);
            _delay_ms(1000);
        }
    }
  • Création d'un programme pour manipuler les LEDs multicolores:
void init_LED_Drivers(int nb) {
    // LED drivers I/O as outputs
    DDR_DLED |= (1 << PIN_DLED_CLOCK) | (1 << PIN_DLED_DATA) | (1 << PIN_DLED_LATCH);
    // Set LATCH output low
    PORT_DLED &= ~(1 << PIN_DLED_LATCH);
}


void set_LED_Drivers(unsigned int pwm[], int nb) {
    int c, b;
    // Set LATCH output low
    PORT_DLED &= ~(1 << PIN_DLED_LATCH);
    // 24 channels per TLC5947
    for (c = DLED_CHANNELS * nb - 1; c >= 0; c--) {
        // 12 bits per channel, send MSB first
        int v = pwm[c];
        for (b = 0; b < 12; b++) {
            // Set CLOCK output low
            PORT_DLED &= ~(1 << PIN_DLED_CLOCK);

            // Set DATA as stated by bit #b of c
            if (v & 0x0800)
                PORT_DLED |= (1 << PIN_DLED_DATA);
            else
                PORT_DLED &= ~(1 << PIN_DLED_DATA);

            // Set CLOCK output HIGH
            PORT_DLED |= (1 << PIN_DLED_CLOCK);
            v <<= 1;
        }
    }
    // Set CLOCK output low
    PORT_DLED &= ~(1 << PIN_DLED_CLOCK);

    // Set LATCH output high
    PORT_DLED |= (1 << PIN_DLED_LATCH);
    // Set LATCH output low
    PORT_DLED &= ~(1 << PIN_DLED_LATCH);
}

Problème rencontré: faible intensité lumineuse, qui s'est avéré être un défaut de la première carte

  • Création du cœur du système de jeu, jouable sur un terminal local:
couleur *random_series(int n, couleur *bank) {
    srand(time(NULL));
    couleur *res = (couleur *) malloc(n * sizeof(couleur));
    for (int i = 0; i < n; i++)
        res[i] = bank[rand() % MAX_COLORS];
    return res;
}

int equals(couleur c1, couleur c2) {
    if ((c1.r == c2.r) &&
        (c1.g == c2.g) &&
        (c1.b == c2.b))
        return 1;
    return 0;
}

int contains(couleur c1, couleur *series, size_t length) {
    for (size_t i = 0; i < length; i++) {
        if (equals(c1, series[i]))
            return 1;
    }
    return 0;
}

Réalisation du programme finale

Extrait de code permettant de gérer la commande reçue:

/* Handle command */
        if (i < size) {
            Endpoint_Write_8('\r');
            Endpoint_Write_8('\n');
            if (cpt < NB_COLORS) {
                if (!strcmp(cmd, "r")) {
                    strcat(history, "R");
                    Endpoint_Write_Stream_LE(history, strlen(history), NULL);
                    cpt++;
                } else if (!strcmp(cmd, "v")) {
                    strcat(history, "V");
                    Endpoint_Write_Stream_LE(history, strlen(history), NULL);
                    cpt++;
                } else if (!strcmp(cmd, "b")) {
                    strcat(history, "B");
                    Endpoint_Write_Stream_LE(history, strlen(history), NULL);
                    cpt++;
                } else if (!strcmp(cmd, "j")) {
                    strcat(history, "J");
                    Endpoint_Write_Stream_LE(history, strlen(history), NULL);
                    cpt++;
                } else if (!strcmp(cmd, "p")) {
                    strcat(history, "P");
                    Endpoint_Write_Stream_LE(history, strlen(history), NULL);
                    cpt++;
                }
                Endpoint_Write_8(cpt + '0');

                Endpoint_Write_8('\r');
                Endpoint_Write_8('\n');
            }
            if (cpt >= NB_COLORS) {
                char *msg = "Your guess :";
                Endpoint_Write_Stream_LE(msg, strlen(msg), NULL);
                Endpoint_Write_Stream_LE(history, strlen(history), NULL);
                Endpoint_Write_8('\r');
                Endpoint_Write_8('\n');

                if(strcmp(serie,history))
                    Endpoint_Write_Stream_LE(WRONG, strlen(WRONG), NULL);
                else
                    Endpoint_Write_Stream_LE(CORRECT, strlen(CORRECT), NULL);
                Endpoint_Write_8('\r');
                Endpoint_Write_8('\n');
            }
        }


Extrait de code permettant de gérer les couleurs associées aux boutons:

void button(void) {
    if (cpt < NB_COLORS) {
        if (!(PINB & (1 << 0))) {
            strcat(history, "R");
            setLED(cpt, 0, MAX_COLOR_INTENSITY, 0);
            cpt++;
        } else if (!(PINB & (1 << 1))) {
            strcat(history, "V");
            setLED(cpt, MAX_COLOR_INTENSITY, 0, 0);
            cpt++;
        } else if (!(PINB & (1 << 5))) {
            strcat(history, "B");
            setLED(cpt, 0, 0, MAX_COLOR_INTENSITY);
            cpt++;
        } else if (!(PINB & (1 << 3))) {
            strcat(history, "J");
            setLED(cpt, MAX_COLOR_INTENSITY, MAX_COLOR_INTENSITY, 0);
            cpt++;
        } else if (!(PINB & (1 << 6))) {
            strcat(history, "P");
            setLED(cpt, 0, MAX_COLOR_INTENSITY, MAX_COLOR_INTENSITY);
            cpt++;
        }
        _delay_ms(200);
    }
    if (!(PINB & (1 << 2))) { // si bouton effacer pressé
        if (cpt > 0) {
            cpt--;
            setLED(cpt, 0, 0, 0); // éteindre LED précécente
            history[cpt] = '\0';
            _delay_ms(200);
        }
    }
    if (!(PINB & (1 << 4))) {
        if (cpt >= NB_COLORS) {
            int check = 1;
            for (int y = 0; y < NB_COLORS; y++) {
                if (serie[y] == history[y]) {
                    setLED(7 - y, MAX_COLOR_INTENSITY, 0, 0);
                } else if (strchr(serie, history[y]) != NULL) {
                    setLED(7 - y, 0, 0, MAX_COLOR_INTENSITY);
                    check = 0;
                } else {
                    setLED(7 - y, 0, MAX_COLOR_INTENSITY, 0);
                    check = 0;
                }
            }
            if (check) {
                serie[0] = '\0';
                victory();
                serie = random_series(NB_COLORS, COLOR_BANK);
            }
            cpt = 0;
            history[0] = '\0';
        }
    }

La fonction main détecte si une connexion USB est active, et écoute donc les boutons ou l'entrée USB:

    for (;;) {
        CDC_Task();
        USB_USBTask();
        if (USB_DeviceState != DEVICE_STATE_Configured)
            button();
    }
int main(void) {
    (...)
    DDRD &= ~0x0F;
    srand(PIND);
    (...)
}

char *random_series(int n, char *bank) {
    char *res = (char *) malloc(n * sizeof(char));
    for (int i = 0; i < n; i++)
        res[i] = bank[rand() % MAX_COLORS];
    return res;
}

Démonstrations

Exemple d'une partie sur console:


Exemple avec l'utilisation des boutons:

Rendus

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

Programmes :

Fichier:I2L-2022-Programmes-G5-Version-Terminal.zip

Fichier:I2L-2022-Programme-G5-Version-Terminal-et-Bouton.zip

Ficher:I2L-2022-Programme-G5-Version-Finale.zip