I2L 2022 Groupe5

De wiki-se.plil.fr
Révision datée du 4 juillet 2023 à 11:54 par Rex (discussion | contributions) (→‎Éléments notables du code)
(diff) ← Version précédente | Voir la version actuelle (diff) | Version suivante → (diff)
Aller à la navigation Aller à la recherche


Proposition de système

Notre projet est de faire un système de jeu type "juste prix" où le but est de trouver une valeur numérique. Au plus on se rapproche de la valeur recherchée, au plus le son émis par le système est fort.

Contre-proposition

Il est demandé à ce que le périphérique puisse fonctionner en autonomie ou connecté à un PC. Si le périphérique est connecté à un PC, le périphérique se comporte comme un port série et communique avec le joueur via un terminal série (e.g. minicom ou putty). Si le périphérique est simplement alimenté par une batterie USB, le joueur utilise uniquement les deux touches et le retour se fait par les 3 LED multicolores et des effets sonores. En mode autonome, peut être serait-il plus pratique de trouver 3 couleurs qu'un nombre ?

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

Proposition définitive

Le but de ce projet est de concevoir un dispositif USB sur lequel tourne un jeu mélangeant "Juste prix" et "Mastermind".

En effet, le joueur devra trouver une combinaison de couleurs en paramétrant les trois LED colorées du dispositif.

À chaque couleur est associée une lettre et une valeur numérique :

  • Noir (la LED est éteinte) → N - 0
  • Rouge → R - 1
  • Jaune (diodes rouge et verte allumées) → J - 2
  • Vert → V - 3
  • Cyan (diodes verte et bleue allumées) → C - 4
  • Bleu → B - 5
  • Magenta (diodes bleue et rouge allumées) → M - 6
  • Blanc (toutes les diodes de la LED sont allumées) → W - 7

Lorsque le joueur valide une combinaison, le dispositif émet une mélodie via un haut-parleur intégré (différente en fonction de "perdu"/"gagné").

Il est possible de jouer de deux façons :

  • Le dispositif est branché à un ordinateur. Pour paramétrer la combinaison à tester, le joueur saisit via un clavier les 3 lettres correspondant aux 3 couleurs souhaitées. Si la combinaison envoyée est erronée, une indication est affichée au joueur, à savoir, une combinaison de "+", "-" et ".". Le caractère "." signifie que la couleur envoyée est correcte, le "+" signifie que le joueur doit essayer une couleur avec une valeur numérique associée plus grande et le "-" signifie que la valeur numérique associée attendue est inférieure à celle proposée.
  • Le dispositif est en mode autonome (branché sur une batterie). Pour paramétrer la combinaison à tester, le joueur utilise les deux boutons intégrés au dispositif. Le premier permet de sélectionner la LED à configurer, le second permet de choisir sa couleur. Les couleurs défilent alors selon l'ordre mentionné ci-dessus (du noir au blanc et ainsi de suite). Pour valider une combinaison, le joueur fait un appui long sur le bouton de sélection de LED. En cas de combinaison fausse, après mélodie "perdu", trois signaux sonores sont joués, à savoir, un LA 440Hz si la couleur est juste, un DO (264Hz) si la valeur numérique de la couleur est trop haute et un DO (528Hz) si la valeur numérique de la couleur est trop basse (en d'autres termes, un son aigu indique qu'il faut tester une couleur avec une valeur numérique plus haute et vice-versa).

Carte

Schéma
Carte

Carte soudée :

I2L-2022-G5-carte-soudée.jpg

Éléments notables du code

Au lancement de l'application on vient définir les sorties et les entrées pour les LEDs et les boutons.

Setup LED et bouton

On crée une méthode pour simplifier la modification des couleurs des LEDs de manière à pouvoir attribuer les mêmes valeurs pour les mêmes couleurs qu'importe les LEDs en ignorant leur positionnement sur la carte.

Dans le cas où le joueur gagne nous jouons une musique. Ici le code va venir altérer le rythme et la tonalité du haut parleur de manière à pouvoir reproduire une mélodie de jeu vidéo.

Fonctions permettant de jouer la musique de victoire

Ensuite nous venons développer le jeu en lui-même. Il va donc s'agir de générer une suite de chiffres aléatoire. Chaque chiffre va correspondre à une couleur.

développement du jeu

Enfin nous venons récupérer les valeurs d'entrée donné par l'utilisateur. Nous vérifions dans un premier temps leur validité puis nous les traduisons en un chiffre à avec le code aléatoire généré précédemment. En cas de victoire la musique est jouée.

Détails d’éléments du code

Main

La fonction main() correspond aux instructions suivantes :
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)

	SetupHardware();

	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
	GlobalInterruptEnable();

	for (;;)
	{
		CDC_Task();
		USB_USBTask();
	}
}
  • Paramétrage de l’horloge ;
  • Configuration du matériel ;
  • Définition des LED devant d'allumer ou non pour indiquer que l'USB n'est pas encore prêt ;
  • Autorisation des interruptions du code ;
  • Jusqu’au reset / à l'interruption du dispositif :
    • Traitement des événements du jeu (exp : validation des touches saisies par l’utilisateur en mode connecté à un PC) ;
    • Traitement des événements USB propres à LUFA.

Changement de couleur d’une LED

Le changement de couleur d’une LED est réalisé grâce à la fonction switchLedColor().

Elle reçoit trois paramètres : ce sont les valeurs hexadécimales des couleurs à paramétrer pour chaque LED.

Voici les instructions qui la composent :
void switchLedColor(int L1, int L2, int L3)
{
	if (!(L1 == -1))
	{
		PORTD = (PORTD & 0xf8) | L1;
	}

	if (!(L2 == -1))
	{
		PORTD = (PORTD & 0xc7) | L2 << 3;
	}

	if (!(L3 == -1))
	{
		PORTC = (PORTC & 0x1f) | L3 << 5;
	}
}


Celles-ci décrivent le processus suivant :

Pour chaque LED, si la valeur reçue en paramètre vaut -1 : aucune modification n’est apportée.

Sinon, on sélectionne les bits correspondants et on les modifie en fonction de la valeur hexadécimale de la couleur voulue.


Seuls les bits à modifier sont mis à jour grâce à l’utilisation du “&”.

L’utilisation de “<< n” permet de décaler le bit de départ de n.

Donc pour la LED 2, celle-ci correspondant aux bits 3 à 5 du port D, on décale de 3 bits.

Pour rappel, une LED est composée de 3 diodes, chaque diode est reliée à un bit. Quand la valeur de ce dernier est à 1, la diode s’allume.


Le jeu se base sur un ensemble de 8 couleurs listées dans la section “Proposition définitive”.

Mélodie de victoire

Lorsque le joueur a trouvé la solution, une mélodie de jeu vidéo est jouée (mélodie de résolution d’une énigme dans les jeux de la saga The Legend of Zelda de Nintendo).

La partition est la suivante :

Pour jouer une note, il faut que la membrane d’un haut-parleur bouge à une certaine vitesse (plus ou moins vite pour une note plus ou moins aigüe). Cela revient donc à faire varier l’ensemble des bits du haut-parleur entre 0 et 1 pour faire vibrer sa membrane, ce, sur un laps de temps prédéfini.

La fonction play_note() permet de jouer une note en prenant en paramètres la fréquence en Hertz de la note et le nombre de périodes où la note sera jouée.

Une période correspond à l’étendue/la durée de la courbe représentant les oscillations entre 0 et 1 des bits du haut-parleur.

Formule de calcul d’une période (avec une durée en seconde) :
(Fréquence en Hz de la note * (60 / Durée de la note)) / Tempo


En musique, le tempo est la vitesse d'exécution d’un mouvement. Son unité est en nombre de battements par minute.

La durée de la note correspond à 2 par exemple si la note est une croche car un temps vaut 1 noire et 2 croches valent 1 noire.

Cette fonction appelle make_note_delay() qui est chargée d’attendre la moitié de la période (car la moitié est en valeur de bit 0 et l’autre 1). Nous avons dû mettre en place un switch car la fonction _delay_us() de la bibliothèque AVR ne reçoit en paramètre que des constantes connues à la compilation.

En paramètre de _delay_us(), nous avons appliqué pour chaque note la formule :
1000000 / fréquence de la note / 2


Voici le tableau que nous avons mis en place pour déterminer la fréquence et la période de chaque note :

Note Calcul de la fréquence Fréquence (Hz) Calcul période Période
sol 396*2 792 (792*(60/3))/80 198
fa # 371.25*2 742.5 (742,5*(60/3))/80 185,625
mi ♭ 316.8*2 633.6 (633,6*(60/3))/80 158,4
la 440 440 (440*(60/3))/80 110
sol # 412.50 412.50 (412,5*(60/3))/80 103,125
mi 330*2 660 (660*(60/3))/80 165
sol # 412.5*2 825 (825*(60/2))/80 309,375
do 528*2 1056 (1056*60)/80 792
do 528*2 1056 (1056*60)/80 792

Le calcul de la fréquence d’une note se base sur la fréquence de la note dans la gamme d’un La 440Hz * 2 ^ n, où n représente le nombre d’octaves à monter ou descendre (ici 1 octave plus haute. Si l’on avait voulu une octave plus bas, il aurait fallu prendre la valeur -1).

Démonstration (connecté à un PC)

Avec Putty, on commence par sélectionner le dispositif USB :

Configuration de Putty.png

Au départ, toutes les diodes sont éteintes, ce qui équivaut à avoir pour couleur "Noir" :

Dispositif connecté à un PC (avant essais de combinaisons).jpg


On saisit 3 caractères correspondant à la combinaison des 3 couleurs de LEDs que l'on veut tester :

Premier essai de combinaison de couleurs.png


En dessous des caractères envoyés, la combinaison de +, - et/ou = indique les modifications à apporter. Ici, il faut essayer une valeur de couleur plus haute que le Rouge, une autre plus basse que le Cyan et une dernière plus basse que le Magenta.

Les diodes s'allument aux couleurs correspondantes :

Essai combinaison Rouge Cyan Magenta.jpg


Lorsque l'on a trouvé la bonne combinaison, la mélodie de victoire se joue, puis un message s'affiche dans le terminal, indiquant la réussite et le nombre d'essais :

Terminal Putty après résolution de l'énigme.png


Les LEDs sont ici colorées en Blanc (W), Rouge et Rouge :

Combinaison finale.jpg

Fichiers

Projet KiCAD : Fichier:I2L-2022-GENESTE-DECLOITRE.zip

Programme sonore : Fichier:I2L-2022-G5-Music.zip

Projet LUFA "nombre mystère" : Fichier:I2L-2022-G5-mystere.zip

Ceci est le code final écrit en C. Fichier:MysteryColor.zip

Pour compiler le projet LUFA, il faut commencer par récupérer la bibliothèque lufa-LUFA-210130. Il faut ensuite placer le répertoire de l'archive dans un nouveau répertoire I2L créé dans le répertoire de la bibliothèque : lufa-LUFA-210130/I2L/Serial. Un simple make compile le projet et un make dfu télécharge le binaire dans le périphérique USB. Pour jouer, utilisez par exemple l'utilitaire minicom. La commande minicom -b 9600 -D /dev/ttyACM0 fonctionne très bien sous Linux.