Projet Pacman

De troyesGEII
Révision datée du 27 mars 2014 à 12:05 par Troyesgeii (discussion | contributions) (La gomme rouge)
Aller à : navigation, rechercher


Le but de notre projet est de diriger un Pacman à l'aide de la manette Nunchuck, extension de la Wii. Le programme étant déjà fourni, nous nous occuperons de configurer, grâce au protocole I2C et d'un bus I2C la manette afin de mouvoir le Pacman à l'aide de l'accéléromètre intégré de la Nunchuck. Il faudra aussi bouger le Pacman avec le stick analogique et utiliser un des deux boutons C ou Z de la manette pour passer d'un mode "accéléromètre " à un mode "stick analogique". Nous relierons la manette au microcontrôleur intégré de la carte Spartan 3E afin de coder les mouvements du Pacman.Nous présenterons ci-dessous le fonctionnement d'un Nunchuck ainsi que celui du bus I2C.

La manette Nunchuk

Photo manette Nunchuk

Qu'est ce que le Nunchuk ?

Il s'agit de l'extension de base de la Wiimote,elle sert notamment dans la plupart des jeux. elle doit son nom "Nunchuck" à sa ressemblance avec un nunchaku.

Relié à la Wiimote par le biais d'une connexion filaire, il comprend un stick analogique(joystick) deux axes, un accéléromètre trois axes et deux boutons tout ou rien "C" et "Z". Fourni dans la boîte de la Wii à l'achat, il est équipé d’accéléromètres pour la reconnaissance des mouvements, mais n'est ni équipé de haut- parleur, ni de moteur de vibration.

Qu'est ce que la Wiimote ?

Il s'agit de la manette de jeu de la console Wii de Nintendo. De forme rectangulaire , elle principalement utilisée à une main, la manette Nunchuck occupant la main libre de la personne. Sa grande particularité est qu'elle est capable de se repérer dans l'espace et de retranscrire ses mouvements à l'écran, tout ceci à l'aide de différent capteur présent sur la manette.( elle peut prendre différents rôles en fonction du jeu : arme, baguette de chef d'orchestre raquette).


Le projet sur lequel nous allons nous baser, permettait de gérer les mouvements du Pacman à l'aide du stick analogique, notre but sera de mouvoir le Pacman avec l'accéléromètre.

Schéma de la manette Nunchuck

L'accéléromètre

Qu'est-ce qu'un accéléromètre ?

composant : accéléromètre ADXL300

Un accéléromètre est un appareil électromécanique (un capteur) qui, fixé à un mobile ou tout autre objet,permet de mesurer l’accélération linéaire de ce dernier, en mesurant les forces d'accélération. Ces forces peuvent être :

-statiques (force d'attraction de la pesanteur),utilisé dans le cas du Nunchuk afin de déterminer ses différents angles d'inclinaison;

-dynamiques (lorsque l'accéléromètre bouge ou vibre).En mesurant l'accélération dynamique, il est possible d'analyser le déplacement de l'objet sur lequel il est intégré.

On parle encore d'accéléromètre même s'il s'agit en fait de 3 accéléromètres qui calculent les 3 accélérations linéaires selon 3 axes orthogonaux(X,Y, et Z).

Exemple d'utilisations autres que le Nunchuk

Ils peuvent être utilisés dans les voitures pour déclencher les airbags.

Récemment IBM et Apple ont intégré des accéléromètres dans leurs ordinateurs portables pour protéger les disques durs. L'accéléromètre détecte les chutes soudaines et met le disque dur à l'arrêt pour que les têtes ne s'écrasent pas sur le disque.

L'accéléromètre de la manette Nunchuk

Il s'agit d'un accéléromètre trois axes (x, y et z) de type capacitif ADXL330 fournis par Analog Devices. Il permet de déterminer l'accélération du mouvement fait avec le Nunchuk, mais aussi sa rotation.

nunchuk démontée

Bien que l'accélération linéaire soit définie en m/s2 (SI), la majorité des documentations sur ces capteurs expriment l'accélération en « g » (accélération causée par la gravitation terrestre, soit environ g = 9,81 m/s2).

Le stick analogique

Le projet à pour but de déplacer le Pacman à l'aide de l'accéléromètre mais aussi grâce au stick analogique de la Nunchuck , en switchant à l'aide d'un des deux boutons C ou Z. Un stick analogique est un joystick miniature qui se manie avec le pouce. Celui de la Nunchuck est un joystick deux axes qui utilise un système analogique ce qui permet un plus grand nombre d'inclinaisons et par conséquent une meilleure réaction que le système numérique. Analogique signifie que l'information est obtenue grâce à la mesure de la variation d'une grandeur physique.

Fonctionnement d'un joystick

N'importe quel périphérique de jeu doté d’axes est parcouru par des circuits électriques. Ceux-ci font partie intégrante de la gestion des commandes analogiques. Il est question ici d’utiliser un composant électronique capable de créer une modulation analogique du courant, c’est-à-dire capable d’adopter une multitude de positions différentes. Le composant le plus couramment utilisé est le potentiomètre, ici utilisé comme une simple résistance variable. Le Joystick est le seul périphérique de jeux à commande analogique à cumuler deux axes se mouvant à l'aide d'une seule commande : le manche. L'axe X lui permet de prendre en compte les mouvements horizontaux, de gauche à droite, et l'axe Y les mouvements verticaux, de haut en bas. Il a donc fallu développer un dispositif capable de déplacer l’aiguille de deux potentiomètres différents, sur deux axes perpendiculaires.

Un manche de joystick s’incline autour de son point de rotation et est ramené au centre, en position initiale, par un système de ressorts. Le manche du joystick ne s’arrête pas à ce point de rotation et se poursuit par une pointe plus fine qui vient se loger dans la base du joystick où une structure est destinée à détecter ses mouvements. Elle est globalement composée de deux éléments perpendiculaires et superposés, non solidaires, dans lesquels la pointe du joystick peut coulisser librement. La pointe est toujours prisonnière des deux éléments d’une forme généralement proche d’un U à branches courtes et qui sont donc globalement en forme d’arcs.

Chacun des arcs est maintenu à la structure (à ses deux extrémités) par deux points de pivot, autour desquels ils peuvent, dans une certaine mesure, tourner. Les points de pivot des deux arcs sont situés sur un même plan horizontal, mais ceux-ci sont disposés de telle sorte que la pointe du joystick puisse se déplacer dans tout l’espace en faisant s’incliner les arcs. Si le manche est incliné vers la droite, l’arc vertical va alors être incliné sur la gauche par la pointe du joystick, la position de l’autre arc n’étant pas modifiée (la pointe coulisse dans sa glissière). Le premier arc tourne donc autour de ses deux points de pivot. C’est là qu’intervient le potentiomètre. Celui-ci est en effet relié à l’arc et constitue en réalité l’un des deux points de pivot. Ainsi, lorsque le manche est incliné vers la droite, l’axe du potentiomètre tourne : son aiguille est déplacée par l’arc vertical qui s’incline.Le mouvement est bien transcrit à l'aide d'une activité électrique détectable. Il ne reste plus qu’au convertisseur ADC d’associer la valeur de l’intensité relevée à une position sur l’axe x horizontal.

Fonctionnement du stick analogique de la Nunchuk

Il s'agit du même principe que le joystick, néanmoins les dimensions de ce type de stick sont sensiblement réduites par rapport à un véritable joystick, et les contraintes physiques subies nettement moindres. C'est pourquoi des éléments en plastique sont utilisés dont seul l’un des deux est en forme d’arc, orienté cette fois vers le haut. L’autre élément est, lui, rectiligne et sert de support au stick tout en permettant son inclinaison. Le fonctionnement de ce système est cependant tout à fait identique et l’on retrouve également deux petits potentiomètres fixés à une extrémité de chacun de ces éléments.

Le Protocole Utilisé: I²C

Logo I2C

Présentation

Historique

Le bus I2C (Inter Integrated Circuit) a été développé au début des années 80 par Philips semi-conductors pour permettre de relier facilement à un microprocesseur les différents circuits d'un téléviseur moderne.

Caractéristiques

Connecteur Nunchuk


  • Deux lignes uniquement (SDA et SCL) + Masse
  • Une adresse unique pour chaque périphérique
  • Bus multi-maître, détection des collisions et arbitrage
  • Bus série, 8 bits, bidirectionnel à 100 kbps (standard mode), 400 kbps (fast mode), 3,2 Mbps (high-speed-mode)
  • Filtrage intégré : réjection des pics parasites
  • Nombre de circuits uniquement limité par la capacitance maximale du bus : 400 pF




Principe

Le premier fil, SDA (Signal DAta), est utilisé pour transmettre les données. L'autre fil, SCL (Signal Clock Line) est utilisé pour transmettre un signal d'horloge synchrone (signal qui indique le rythme d'évolution de la ligne SDA(Serial Data Line)). Les tensions associées aux niveaux logiques vont dépendre de la technologie des circuits en présence (CMOS, TTL). Il faudra que tous les circuits connectés au bus I²C utilisent les mêmes potentiels pour définir les niveaux haut et bas. En définitive, cela implique que tous les composants connectés à un même bus soient alimentés de façon identique. Cela ne signifie pas que les composants doivent utiliser la même source pour s'alimenter ; il suffit que la tension d'alimentation soit à la même valeur pour tous les composants, le fil de masse permettant d'unifier les références. Il reste maintenant un problème crucial. Comment permettre à plusieurs circuits logiques de connecter leurs sorties ensemble, sachant que certains circuits voudront imposer un niveau haut tandis que d'autres voudront imposer un niveau bas ? La réponse est connue: il faut utiliser des sorties à collecteur ouvert (ou à drain ouvert pour des circuits CMOS). Le niveau résultant sur la ligne est alors une fonction « ET » de toutes les sorties connectées.


Principeee.png



Les résistances de rappel au potentiel VCC permettent aux signaux SDA et SCL d'être à 1 si toutes les sorties à collecteurs ouverts sont aussi au niveau 1 (résultat de la fonction « ET »). Si une ou plusieurs sorties tentent d'imposer un niveau bas sur une ligne, le ou les transistors associés vont conduire, ce qui entraîne un niveau bas sur la ligne correspondante (ce qui est conforme au résultat de la fonction « ET »). En ce qui concerne la lecture des signaux SDA et SCL, cela ne pose pas de problème. Les signaux peuvent être lus en permanence sans risque d'interférer sur le niveau de la ligne. Au repos, tous les circuits connectes doivent imposer un niveau haut sur leurs sorties respectives. Si les lignes SDA et SCL sont au niveau haut dans ces conditions, cela signifie qu'aucun circuit ne tente de prendre le contrôle du bus. Si une des lignes SDA ou SCL passe à un niveau bas dans les mêmes conditions, c'est qu'un des circuits désire prendre le contrôle du bus. Mais il peut aussi y avoir deux circuits qui tentent de prendre le contrôle du bus en même temps (ou à quelques nanosecondes d'écart près). Il faut donc mettre en place un protocole pour gérer les conflits possibles.

Protocole

La prise de contrôle du bus

Pour prendre le contrôle du bus, il faut que celui-ci soit au repos (SDA et SCL à '1'). Pour transmettre des données sur le bus, il faut donc surveiller deux conditions particulières :

  • La condition de départ. (SDA passe à '0' alors que SCL reste à '1')
  • La condition d'arrêt. (SDA passe à '1' alors que SCL reste à '1')

Lorsqu'un circuit, après avoir vérifié que le bus est libre, prend le contrôle de celui-ci, il en devient le maître. C'est toujours le maître qui génère le signal d'horloge.

Exemple de condition de départ et d'arrêt :

Priseee.png









Transmission d’un octet

Le maître transmet le bit de poids fort D7 sur SDA. Il valide la donnée en appliquant un niveau ‘1’ sur SCL. Lorsque SCL retombe à ‘0’, il poursuit avec D6, etc. jusqu‘à ce que l’octet complet soit transmis. Il envoie le bit ACK à ‘1’ en scrutant l’état réel de SDA. L’esclave doit imposer un niveau ‘0’ pour signaler que la transmission s’est déroulée correctement. Le maître voit le ‘0’ (collecteur ouvert) et peut passer à la suite.

Transss.png




Dans cet exemple :

SCL : Horloge imposée par le maître (tout en haut).

SDAM : Niveaux de SDA imposés par le maître.

SDAE : Niveaux de SDA imposés par l'esclave.

SDAR : Niveaux de SDA réels résultants.







Transmission d’une adresse

Le nombre de composants qu'il est possible de connecter sur un bus I²C étant largement supérieur à deux, le maître doit pouvoir choisir quel esclave est censé recevoir les données. Dans ce but, le premier octet que transmet le maître n'est pas une donnée mais une adresse. Le format de l'octet d'adresse est un peu particulier puisque le bit D0 est réservé pour indiquer si le maître demande une lecture à l'esclave ou bien au contraire si le maître impose une écriture à l'esclave.


Adresseee.png


Chaque circuit connecté au bus I²C possède une adresse, qui doit être unique. L'adresse associée à un composant est définie en partie par l'état de broches de sélections et d'autre part par sa fonction. Par exemple, le circuit PCF8574, qui est un port d'entrées/sorties bidirectionnel 8 bits, décompose son adresse de la façon suivante : [0] [1] [0] [0] [A2] [A1] [A0] [R/W]. Les bits A2, A1 et A0 reflètent l'état des broches 1, 2 et 3 du circuit. Cela permet de placer 8 circuits PCF8574 sur le bus I²C. Lors de la conception d'un système, il faut donc veiller à l'unicité des adresses attribuées aux différents composants.


Une fois l'adresse envoyée sur le bus, l'esclave concerné doit répondre en plaçant le bit ACK à 0. Si le bit ACK vaut 1, le maître comprend qu'il y a une erreur de sélection et il génère la condition arrêt. En revanche, si le bit ACK vaut 0, le maître peut continuer les opérations.


Note: Les adresses 0000 0xxx et 1111 11xx sont réservées à des modes de fonctionnement particuliers (les adresses réservées).

Ecriture d'une donnée

Si le bit R/W précédemment envoyé était à 0, cela signifie que le maître doit transmettre un ou plusieurs octets de données. Après chaque bit ACK valide, le maître peut continuer d'envoyer des octets à l'esclave ou bien il peut décider de terminer le dialogue par une condition d'arrêt.


Ecriture.png

Lecture d'une donnée

Si le bit R/W transmis en même temps que l'adresse est à 1, cela signifie que le maître veut lire des données issues de l'esclave. C'est toujours le maître qui va générer le signal d'horloge SCL. En revanche, après le bit ACK de l'adresse, c'est l'esclave qui va garder le contrôle de la ligne SDA. Pour cela, le maître va placer sa propre sortie SDA au niveau haut pour permettre à l'esclave de prendre le contrôle de la ligne SDA. L'esclave doit alors scruter la ligne SCL et attendre le niveau bas pour changer l'état de la ligne SDA, faute de quoi le maître détectera une condition arrêt et abandonnera le transfert (l'électronique intégrée dans l'esclave se doit de détecter aussi qu'il y a eu une condition arrêt, bien entendu). Après que l'esclave ait transmis les 8 bits de données, c'est le maître, cette fois-ci, qui va générer un bit d'acquittement. Si le maître désire lire des octets supplémentaires, il placera le bit d'acquittement à 0. En revanche, si le maître décide que la lecture est terminée, il placera le bit ACK au niveau 1. L'esclave comprendra alors que le transfert est terminé. Cette fois-ci, bien que le bit ACK soit au niveau 1, cela ne correspond pas à une condition d'erreur mais à une fin de transfert.

LectureDonnée.png

Conflits

Problème

  • La conception du bus I²C est destiné à accueillir plusieurs maîtres. Mais le problème c'est ce que tous les réseaux utilisent un canal de transmission unique: Comment arbitrer ?
  • Chaque maître peut prendre possession du bus dès que celui-ci est libre : possibilité que deux maîtres prennent la parole en même temps.
  • Pas de problème électrique -> collecteur ouvert
  • Problème logique - >éviter la corruption des données due à la collision des bits transmis

Principe

Prise de contrôle du bus

  • Vérifier que le bus est libre.
  • Condition d’arrêt envoyée depuis au moins 4,7 µs.
  • Prise de contrôle effectif, mais vérification de l’état des lignes SDA et SCL.

Plusieurs cas :

-Différents maîtres envoient les mêmes données en même temps : aucun conflit, cas rare.

-Un maître impose un ‘0’ : il relit obligatoirement un ‘0’ et continuera à transmettre.

-Un maître cherche à appliquer un ‘1’ sur le bus.

Alors,

S’il lit ‘1’, il continue à transmettre.

S’il lit ‘0’, un autre maître a pris la parole en même temps: Il perd l’arbitrage, arrête d’émettre, mais continue à lire.

Exemple

ExmDePrinc.png


SCLR: Horloge résultante


SDA1: Niveaux de SDA imposés par le maître n°1


SDA2: Niveaux de SDA imposés par le maître n°2


SDAR: Niveaux de SDA réels résultants lus par les deux maîtres



ExmDPrin.png


Analyse:

Le premier octet est transmis normalement car les deux maîtres imposent les même données (Cas n°1). Le bit ACK est mis à '0' par l'esclave.

Lors du deuxième octet, le maître n°2 cherche à imposer un '1' (SDA2) , mais relit un '0' (SDAR), il perd alors le contrôle du bus et devient esclave (Cas n°3). Il reprendra le contrôle du bus, lorsque celui-ci sera de nouveau libre.

Le maître n°1 ne voit pas le conflit et continue à transmettre normalement Cas n°2).

Au total, l'esclave à reçu les données du maître n°1 sans erreurs et le conflit est passé inaperçu.

Spécificité

Les adresses réservées

Les adresses 0000 0xxx ne sont pas utilisées pour l’adressage des composants:

  • L’adresse 0000 0000: Adresse d’appel général. Les circuits ayant la capacité de traiter ce type d’appel émettent un acquittement. Le deuxième octet définit le contenu de l’appel.
  • L’adresse 0000 0110: RESET. Remet tous les registres des circuits connectés dans leur état initial. Les circuits qui le permettent rechargent leur adresse d’esclave.
  • L’adresse 0000 0010: Les circuits qui le permettent rechargent leur adresse d’esclave.
  • L’adresse 0000 0100: Les circuits définissant leur adresse de façon matérielle réinitialisent leur adresse d’esclave.
  • L’adresse 0000 0000: Interdit.
  • L’adresse xxxx xxx1: Joue le rôle d’interruption. xxxx xxx peut être l’adresse du circuit qui a généré l’interruption.
  • L'adresse 0000 0001: Octet de start : utilisé pour synchroniser les périphériques lents avec les périphériques rapide.
  • L'adresse 0000 001x: Permet de rendre sourds tous les circuits I2C présents sur le bus. On peut donc changer le protocole de transmission sans générer d’erreurs au niveau des circuits I2C. Le bus repasse en mode normal lors de la réception d’une condition d’arrêt.
  • L'adresses 0000 0110 à 0000 1111: Non définies et ignorées par les circuits I2C. Elles peuvent être utilisées pour débugger un réseau multimasters par exemple.

I²C étendu

I2C Fast Mode :

  • 400 kbits/s, Adressage sur 10 bits
  • Paramètres physiques inchangés : protocole, niveaux, capacitance identiques : changement uniquement au niveau timing
  • Abandon de la compatibilité CBUS
  • Entrées à trigger de Schmitt
  • Sorties haute impédance lorsque le périphérique n’est pas alimenté
  • La résistance de tirage doit être adaptée

– Jusqu’à 200pF : résistance suffit

– De 200pF à 400pF : source de courant préférable


Adressage étendu:

  • Espace d’adressage trop restreint en mode standard
  • 2 octets d’adressage :


I2c etendu.png








  • Compatibilité assurée avec le mode standard

– R/W et ACK à la même position,

– 11111 permet de faire la différence entre mode standard et mode fast.

La Spartan 3E

Nous utiliserons le microcontrôleur présent sur la carte suivante. Relié sur les pattes GND, VCC, IO8, IO7 à l'aide du bus.

Conclusion

Pour conclure : nous avons vu la constitution de la manette Nunchuck, un accéléromètre 3 axes et un joystick. Puis comment utiliser le bus I2C à l'aide des fils SCA et SCL. Nous devrons créer le bus, puis créer le programme sur la Spartan 3E afin de mouvoir le Pacman et gérer le changement de mode, « stick analogique » / « accéléromètre ».

Réalisation du Projet

Nous avons réalisé le bus permettant la liaison entre la Nunchuk, la carte Spartan 3E et le Pacman. De cette façon il nous a été permis de mouvoir le Pacman avec le stick analogique de la Nunchuk, nous avons ensuite configuré le programme de façon a le bouger avec l’accéléromètre. Nous avons ensuite créer 3 modes de jeux que l'on peut changer avec les deux boutons Z et C présents sur la manette  : - de base, le Pacman bouge latéralement avec l'accéléromètre et verticalement avec le stick analogique -En appuyant sur C, on gère complètement les mouvements avec le joystick -En appuyant sur Z, on gère entièrement les mouvements avec l'accéléromètre.

Nous avons commandé un arrêt du jeu dans le cas où toutes les gommes ont été mangées par le Pacman, et un autre dans le cas où elles ne seraient pas toutes mangées en l'espace de 9 vies.


Le Bus

Nous avons utilisé 4 fils afin de relier la Nunchuck aux entrées de la carte : GND, VCC, IO7 et IO8 ce qui permet les échanges entre la Nunchuk et le microcontrôleur. Il faut ensuite assigner les entrées aux sorties correspondantes, ce qui correspondra à une modification du VHDL.

BusNun carte3.png

Le FIFO

Pour pouvoir utiliser la gestion d'accéléromètre de la manette Nunchuk nous avons du stocker l'ensemble de ses données. Alors pour effectuer cet stockage nous avons mis en place un FIFO(premier arrivé, premier sorti) qui stocke les données systématiquement pour que le processus puisse tout gérer après.

Plus précisément: La méthode FIFO permet de décrire une méthode de gestion des données consistant à traiter la file d'attente(le bus I2C dans notre cas) des actions à effectuer dans l'ordre chronologique, ainsi qu'en logistique, dans la gestion des stocks.


Pour bien comprendre sa logique de fonctionnement; une petite animation est ci-dessous:

Fifoanimation.gif

Le VHDL gérant les échanges Nunchuck-carte

Nous avons fait des modifications dans le fichier vhdl pour pouvoir gérer le Nunchuk.

  • Premièrement:

Nous avons supprimé nunchuk3.vhd en laissant juste avr_fpga_s3e.ucf qui permettait de faire les liaisons des portes.
Par exemple le code qui permet de configurer les liaisons avec l'écran VGA;

# ==== VGA Port (VGA) ====
NET "blue" LOC = "G15" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = FAST ;
NET "green" LOC = "H15" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = FAST ;
NET "hsynch" LOC = "F15" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = FAST ;
NET "red" LOC = "H14" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = FAST ;
NET "vsynch" LOC = "F14" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = FAST ;



  • Deuxièmement:

Par rapport à l'année précédent, cette année nous avons utilisé un FIFO donc il nous fallait faire des changements pour mettre le FIFO dans le code VHDL. Pour ceci, dans le fichier io2.vhdl nous avons supprimé tout ce qui était avec le signal I_SWITCH(ce qui permettait de commander l’interrupteur de l'année précédente) et nous avons remplacé un code lié à un FIFO. Ce qui nous a donné un programme plus efficace et plus aéré.

Pour commencer, nous avons mis en place le FIFO dans Componant nunchukTop:

NunchukTop.jpg


COMPONENT nunchukTop IS
PORT (
  sys_clk : IN std_logic;
  Init : IN std_logic;

  --commande de bus
  readFIFO,i_continue : in std_logic;
  --les états du FIFO
  data_present, full, half_full : out std_logic;
  --les données de FIFO
  O_data_nunchuk : out std_logic_vector(7 downto 0);
  -- pour le bus i2c i/o
  sda        : INOUT  std_logic;
  scl        : INOUT  std_logic);
END COMPONENT;


Après avoir terminé les déclarations, dans cette partie l'ensemble du travail consistait donc à câbler et ajouter des lignes dans les deux "cases" des deux processus de lecture et d'écriture dans port map.

Interfacer le I2C pour lire les données de la Nunchuk


nunchuk: nunchukTop port map (
	        sys_clk => I_CLK,
                Init => I_CLR,
                readFIFO => s_readFIFO,
		i_continue => s_twen_b2,
                O_data_nunchuk => s_data_nunchuk,
		data_present => s_twcr_b7,
		full => s_twcr_b6,
		half_full => s_twcr_b5,
                -- i2c i/o
                sda => sda,
                scl  => scl);


Par exemple le changement fait pour l'adaptation au cœur Nunchuk:

Avant(2013)

 I_SWITCH(7) <= s_data_nunchuk(3);
					 I_SWITCH(6) <= s_data_nunchuk(2);
					 I_SWITCH(5) <= s_data_nunchuk(5);
					 I_SWITCH(4) <= s_data_nunchuk(4);
					 I_SWITCH(3) <= s_data_nunchuk(7);
					 I_SWITCH(2) <= s_data_nunchuk(6);
					 I_SWITCH(1) <= s_data_nunchuk(0);
					 I_SWITCH(0) <= s_data_nunchuk(1);

Après(2014)

s_readFIFO <= I_RD_IO WHEN (I_ADR_IO = x"23") ELSE '0';



Code utilisé pour commander l'accéléromètre

Désormais nous pouvons commander le pacman à l'aide du stick analogique de la nunchuck car le programme précédent gérait déjà un joystick.On constate qu'afin de récupérer les données on utilise nunData[0] et nunData[1].La manette Nunchuk envoie ses informations comme 6 octets de données, lisibles . Les six octets de données sont :


TableauNunData.png


Le byte 0 permet de choisir la direction sur l'axe des x, le byte 1, sur l'axe des y au joystick.De la même façon le byte 2 permet de choisir la direction sur l'axe des X, le byte 3 sur l'axe des Y de accéléromètre et le byte 4 sur l'axe des Z. nous ajouterons un code en C dépendant du paramètre NunData(byte) qui permet de récupérer la valeur du byte ce qui permettra de gérer l’accéléromètre, nous l'expliquerons plus bas.Le byte 5 permet de gérer les deux bits de poids faible de AY et AZ, car comme on peut le constater dans le tableau, AY et AZ ont bien 8 valeurs possibles contenues de 9 à 2, il reste donc les deux bits de poids faible. Nous ne les utiliserons pas car les bits nous permette de mettre une sensibilité plus ou moins importante, or l'influence de ces bits de poids faible est minim. De plus, le byte 5 permet de gérer les deux boutons C et Z, que nous utiliserons pour passer d'un mode de jeu à un autre.


Le paramètre NunData nous permet de récupérer les données du byte entre crochets. Nous avons décidé qu'en appuyant sur C on passe en mode entièrement stick analogique, Sur Z en mode uniquement accéléromètre. Par défaut, on peut se déplacer latéralement avec l'accéléromètre,et verticalement avec le stick. Nous nous servirons des bytes 2 et 3 pour l'accéléromètre nous n'utiliserons pas l'axe Z.


  • En appuyant sur C, uniquement joystick
//BC-joystick		
if((nunData[5]&0x02)==0x00){ // SI on a 0 sur le bit 1 de l'octet 5 c'est-à-dire si C est appuyé 
  if (nunData[0]>0xC0) { dxf = 2; dyf = 0;vPORTB &= 0xFC;}  //déplacement latéral vers la droite
  if (nunData[0]<0x30) {dxf = -2; dyf = 0;vPORTB = (vPORTB&0xFD)|0x01;} //déplacement latéral vers la gauche 
  if (nunData[1]>0xC0) {dyf = -2; dxf = 0;vPORTB = (vPORTB &0xFE)|0x02;} //déplacement vertical vers le bas
  if (nunData[1]<0x30) {dyf = 2; dxf = 0;vPORTB |= 0x03;}	//déplacement vertical vers le haut	       		 	
////nunData[0] et nunData[1] correspondent aux bytes X et Y de l'accéléromètre
}
  • En appuyant sur Z, uniquement accéléromètre
	//BZ-accelerometre
	if((nunData[5]&0x01)==0x00){ // SI on a 0 sur le bit 0 de l'octet 5 c'est-à-dire si Z est appuyé

	   if (nunData[2]>0x80) {dxf = 2; dyf = 0;vPORTB &= 0xFC;} // déplacement latéral vers la droite
           if (nunData[2]<0x70) {dxf = -2; dyf = 0;vPORTB = (vPORTB&0xFD)|0x01;} // déplacement latéral vers la gauche
           if (nunData[3]>0x90) {dyf = -2; dxf = 0;vPORTB = (vPORTB &0xFE)|0x02;} // déplacement vertical vers le bas
           if (nunData[3]<0x60) {dyf = 2; dxf = 0;vPORTB |= 0x03;}// déplacement vertical vers le haut
//nunData[2] et nunData[3] correspondent aux bytes X et Y de l'accéléromètre
	}
  • Configuration par défaut
	//de base, accelerometre x, joystick y
	else
	{
	   if (nunData[2]>0xA0) {dxf = 2; dyf = 0;vPORTB &= 0xFC;}// déplacement latéral vers la droite (accéléromètre)
           if (nunData[2]<0x60) {dxf = -2; dyf = 0;vPORTB = (vPORTB&0xFD)|0x01;}// déplacement latéral vers la gauche (accéléromètre)
           if (nunData[1]>0xC0) {dyf = -2; dxf = 0;vPORTB = (vPORTB &0xFE)|0x02;} //déplacement vertical vers le bas(stick)
           if (nunData[1]<0x30) {dyf = 2; dxf = 0;vPORTB |= 0x03;}	//déplacement vertical vers le haut (stick)
	}
Chaque commande suit le même schéma,
 if  (nunData[2]<0x70) {dxf = -2; dyf = 0;vPORTB = (vPORTB&0xFD)|0x01;

On choisit le byte 2 (axe X de l'accéléromètre) , et si sa valeur est inférieur a 0111 0000 la position en x du pacman (dxf) se déplace de 2 vers la gauche. LA valeur 0x70 correspond à la sensibilité de accéléromètre.

Autres modifications apportées

Affichage de "live"

Le projet fournit par l'enseignant comptait le nombre de fois que l'on perdait une rencontre avec un fantôme. Nous avons décidé de donner un nombre de touches maximum autorisées (au nombre de 9). On décomptera ces "vies" à chaque touche avec un fantôme, une arrivée à 0 stoppera le jeu et affichera un "game over".


  • Afin d'afficher le mot LIVES à l'écran
unsigned char *adr_message;//on se place au bout à droite et on remonte de n lignes (n=2 ici)
adr_message = (unsigned char *)LIVESUNIT; //debut memoire+derniere ligne+offset dans ligne
//affichage de LIVES
*adr_message = lives + '0';
adr_message-=10;*adr_message = 'S';
adr_message-=2;*adr_message = 'E';
adr_message-=2;*adr_message = 'V';
adr_message-=2;*adr_message = 'I';
adr_message-=2;*adr_message = 'L';
  • Afin de déclarer le nombre de vie, et de le décrementer à chaque touche avec le fantôme
// dans la fonction main
unsigned char live=9 ;
[...]
// décrémentation dans la boucle if ((xe==x)&& (ye==y))

if ((xe==x) && (ye==y)) { 
// if enemy catchs pacman
GhostState = ENEMYINHOME;   
 xe = 48; ye = 40; x = 8; y = 16; 
setpacmanXY(x,y);   
setenemyXY(xe,ye);     
// BCD lives management     
 lives--;    
// conversion BCD
if ((lives &0x0F) > 9) lives = lives-6;   
if ((lives &0xF0) > 0x90) lives = lives-0x60;  
putLives(lives);   
//xe=44;ye=16;     
softTimer=0;   
waitStart();  
   }
}

La décrémentation se fait quand (xe==x)&& (ye==y) c'est-à-dire quand la position du pacman est égal à la position du fantôme : quand le pacman se fait manger.

elle se traduit par
 lives--;

On peut remplacer 9 par la valeur que l'on veut, nous avons choisit 9 pour laisser un jeu assez simple.

Livespacman.jpg

You Win et Game Over

Une arrivée à 0 du nombre de vie stoppera le jeu et affichera un "game over". A l'inverse si toutes les gommes sont mangées en moins de 9 vies, le jeu s'arrête et affiche "you win".

void putLives(uint8_t lives){
                            unsigned char *afflives;
                            afflives = (unsigned char *)LIVESUNIT; //debut memoire+derniere ligne+offset dans ligne +25???  
                            *afflives = (lives &0x0F)+'0';
                            afflives--;afflives--;
                            *afflives = ((lives &0xF0)>>4)+'0';  
}
Youwinpacman.jpg


// BCD lives management
lives--; // pour décrémenter les vies
//conversion BCD
if ((lives &0x0F) > 9) lives = lives-6;
if ((lives &0xF0) > 0x90) lives = lives-0x60;
putLives(lives);
Gameoverpacman.jpg

La gomme rouge

L'année précédente la gomme rouge n'avait pas été géré, nous avons décidé de pouvoir l'intégrer au jeu comme les autres gommes blanches sauf qu'elle fera gagner 100 points au lieu d'un.

La gomme rouge

L'année précédente la gomme rouge n'avait pas été gérée, nous avons décidé de pouvoir l'intégrer au jeu comme les autres gommes blanches sauf qu'elle fera gagner 100 points au lieu d'un. Par manque de temps nous n'avons pas pu programmer un retour à la maison du fantôme ou un gobage du fantôme si celui-ci est touché par le pacman après avoir ingéré la gomme rouge.

Nous avons donc rajouté le programme ci-dessous dans la fonction eat_Pac_Gomme :

void eat_Pac_Gomme(unsigned int addr, uint16_t *score, unsigned char *nb_gomme){
	char* ptr;
	ptr = (char *)(addr);	
        if(*ptr==4){
		*ptr=0;
		increaseScore(score,1);
		*nb_gomme+=1;
			}
	else if(*ptr==5){
		*ptr=0;
		increaseScore(score,100);
		*nb_gomme+=1;
	                }
	}
Le premier if était déjà dans le programme initial, si la variable ptr=4, c'est à dire s'il s'agit d'une gomme blanche, on la remplace par 0 dans le tableau ce qui correspond à un fond noir comme le montre le dessin ci-dessous.En reprenant ce modèle, nous avons dit que si l'adresse de ptr était de 5, en le gobant, on met un fond noir, on incrémente le score de 100, et on incrémente le compte de gommes de 1.

Fin

Pacmangif.gif