Cours:XR207 tp digicode : Différence entre versions

De troyesGEII
Aller à : navigation, rechercher
m ({{Bleu|Codez !!}})
Ligne 236 : Ligne 236 :
  
 
{{Question|Vous utiliserez le programme réalisé au tp précédent, et notamment la fonction {{Rouge|playnote(note,duree)}} pour jouer la note associée à chaque appui d'une touche}}
 
{{Question|Vous utiliserez le programme réalisé au tp précédent, et notamment la fonction {{Rouge|playnote(note,duree)}} pour jouer la note associée à chaque appui d'une touche}}
 
 
 
 
 
={{Rouge|Complément au [[Cours:TPS_2103_tp2|TP précédent]] : Mesure de temps d'exécution}}=
 
 
Nous allons dans cette partie mesurer le temps d'exécution de certaines fonctions Arduino, et se rendre compte de l'une de leur principale limite.
 
 
Le temps écoulé sera mesuré à l'aide du {{Rouge|Timer 2}}.
 
 
Le principe est le suivant :
 
*Initialiser le timer
 
*Répéter plusieurs fois l'instruction souhaitée
 
*Observer la valeur du timer
 
*Afficher cette valeur
 
 
=={{Bleu|Le timer 2 et ses registres (sans interruption)}}==
 
[[Fichier:AVR_Timer2.png|thumb|500px|Documentation simple du Timer 2 (8 bits)]]
 
Voici ci-contre, avec les conventions schématiques habituelles, le schéma de fonctionnement du timer 2.
 
 
On distingue ainsi le bit b0 du registre '''TIFR2''' appelé '''TOV2''' qui permet de détecter un débordement du timer. Pour plus de précisions, référez-vous au td sur le sujet !
 
 
Les habituels bits de configuration de la division se trouvent dans le registre '''TCCR2B''' et fonctionnent exactement comme pour les autres timers.
 
 
Le registre '''ASSR''' sert à choisir la source de l'horloge du timer 2. Pour nous, sauf mention contraire, ce sera toujours le quartz. Ce registre doit être configuré dans ce mode de fonctionnement par défaut.
 
 
=={{Bleu|Configuration des entrées/sorties}}==
 
 
Nous souhaitons ici évaluer le temps mis par la fonction [http://arduino.cc/en/Reference/pinMode {{Rouge|pinMode()}}].
 
 
L'affichage du résultat sera tout simplement transmis sur la liaison série en utilisant les fonctions suivantes :
 
*Serial.begin(debit)
 
*Serial.print("valeur = ")
 
*Serial.println(valeur,DEC)
 
 
{{Question|Compléter le programme suivant en choisissant les bonnes valeurs pour évaluer le temps d'exécution de pinMode()}}
 
<source lang=c>
 
void setup()
 
{
 
  // Variables éventuelles
 
 
  // Initialisation du port série
 
  Serial.begin(9600);
 
 
  // Configuration du timer 2 : Attention, chaque bit doit être configuré à '0' ou '1'
 
  TCCR2A ??? (1<<WGM20); // mettre à 0
 
  TCCR2A ??? (1<<WGM21); // mettre à 0
 
 
  TCCR2B ??? (1<<WGM22); // mettre à 0
 
// choix du pré-diviseur :
 
  TCCR2B ??? (1<<CS22);
 
  TCCR2B ??? (1<<CS21);
 
  TCCR2B ??? (1<<CS20);
 
 
  // Initialisation du Timer : acquittement et valeur de départ
 
  TIFR2|=1<<TOV2;
 
 
}
 
 
void loop() {
 
  TCNT2=0; // timer2 mis à zéro
 
 
//********** debut du calcul dont on veut mesurer la durée
 
  for (i=0;i<100;i++) // Le nombre d'itérations peut/doit être adapté !
 
  {
 
    // Fonction à évaluer : il est intéressant de répéter la fonction plusieurs fois
 
    pinMode(6,OUTPUT);
 
  }
 
//********* fin du calcul dont on veut mesurer la durée
 
 
 
  // Récupérer la valeur du timer et l'afficher seulement si le timer n'a pas débordé !!!
 
 
  // envoyer dans liaison série
 
 
  delay(500);
 
}
 
</source>
 
 
 
'''Attention ! ''' Ne prenez pas ce que vous donne le timer pour argent comptant. Cette valeur doit avoir certaines propriétés :
 
* ne pas être accompagnée d'un débordement de '''TCNT2'''. Vous seriez donc très inspiré d'écrire la valeur du flag '''TOV2''' avec la liaison série en plus de la valeur de temps
 
* augmenter lorsqu'on augmente le nombre de boucles exécutées sur l'instruction testée (autre manière de dire les choses, on double le temps si on double le nombre de boucles).
 
 
Ce travail nécessite dons un peu de soin et beaucoup d'essais pour trouver la bonne valeur de la division dans le pré-diviseur à choisir. Il peut être utile de mettre les tests dans loop() pour prendre son temps pour ouvrir la liaison série.
 
 
 
{{Question|Comparer en déclarant une sortie directement en configurant le registre DDRx}}
 
 
=={{Bleu|Valeur de sortie}}==
 
 
Si la fonction pinMode() est d'importance, sa durée d'exécution ne l'est pas forcément puisque la plupart du temps elle n'est exécutée qu'une seule fois.
 
 
Allons donc un peu plus loin dans la manipulation des ports en modifiant l'état d'une sortie (pin 6 arduino ou PD6).
 
 
{{Question|Évaluer la durée d'exécution du code suivant :}}
 
 
<source lang=c>
 
//void setup()
 
//{
 
  pinMode(6,OUTPUT);
 
  for (char i=0;i<10;i++)
 
  {
 
    digitalWrite(6,0);
 
    digitalWrite(6,1);
 
  }
 
 
 
//}
 
 
//void loop()
 
//{
 
//}
 
</source>
 
 
{{Question|Écrire le même code en utilisant directement les registres ad-hoc et comparer les vitesses d'exécution.}}
 

Version du 20 avril 2015 à 10:57

Retour à la liste des Tps

Éléments de correction

ArduinoPinout.png

Vous allez développer un système de digicode architecturé autour d'un atmega328p (le µcontrôleur présent sur les cartes arduino).

Pour ce TP, nous utilisons une carte arduino sans le shieldinfo

Nous utiliserons les fonctions arduino dans ce TP, en essayant de les éviter au maximum afin d'écrire un code le plus réutilisable possible.


Informations lumineuses

Le digicode sera équipé de 2 voyants lumineux (rouge et vert).

On utilisera des résistances de 330Ω, et vous êtes libre de choisir un montage à anodes ou cathodes communes.

Todo.jpg Câbler sur une plaque à essais les leds sur les pin PC0 et PC1

Question.jpg Écrire une fonction pour éteindre ou allumer une led dont le prototype sera le suivant :

void setEtatLed(unsigned char numLed,unsigned char val);
Bluebg.png
Aidesmall.png
À propos de cette image

Astuce


Vous pourrez vous inspirer du programme suivant permettant de faire clignoter la led "13" de la carte Arduino Uno.

#define led PB5

void setup()
{
  DDRB |= 1 << led;
  
}

void loop()
{
  PORTB |= 1 << led;
  delay(100);
  PORTB &= ~(1 << led);
  delay(100);
}


Decodage d'un clavier

Câblage

Le tableau suivant résume la disposition physique du clavier avec la position physique sur le connecteur des lignes (L1 à L4) et colonnes (C1 à C3) en vue de dessus :

B0 B1 B2 B3 D4 D5 D6
L1 L2 L3 L4 C1 C2 C3

ArduinoClavier.png

L/C C1 C2 C3
L1 1 2 3
L2 4 5 6
L3 7 8 9
L4 * 0 #

Todo.jpg Câbler sur une plaque à essais le clavier 12 touches que l'on vous donne. Les colonnes seront reliées sur le port D et les lignes sur le port B (cf indications ci dessus)

Remarque : On ne câblera aucune résistance de tirage, on utilisera les résistances internes au µcontrôleur.

Indice de ligne

Question.jpg Ecrire et tester le programme lecture_ligne() qui renvoie le numéro de ligne sur laquelle un bouton est appuyé

  • Servez-vous bien évidemment du travail en TD !
  • Rappelons qu'il faut écrire un '1' sur une entrée, pour activer la résistance de pull-up associée
  • La validation se fera en utilisant la liaison série, à l'aide des fonctions arduino.
char lecture_ligne()
{
  char ch;
  DDRD ?= .... ;    // commençons par lister les sorties sur le port D
  DDRB ?= .... ;    // puis les entrées sur le port B
  PORTD?=..... ;    // on place les sortie à l'état 0
  PORTB?= .... ;    // on active les résistances de pull-up sur les entrées

  _delay_ms(1);        // un délais est nécessaire pour l'activation des pull-ups

  ch = PINB & 0x??; // on récupère ensuite l'état des entrées
  switch (ch)
  {
     case  : return 0; // aucune touche
     case  : return 1; // L1
     case  : return 2; // L2
     case  : return 3; // L3
     case  : return 4; // L4
     // si autre cas, deux touches ou autre
     default : return -1;
  }
}

Indice de colonne

Question.jpg De la même façon, écrire et tester la fonction lecture_colonne() qui permettra d'obtenir le numéro de colonne sur laquelle un bouton est appuyé.


Touche appuyée

Nous souhaitons maintenant écrire une fonction qui renverra une valeur tel que décrit ci dessous :

char touches[LIGNES][COLONNES] = { // tableau de char à 2 dimensions
  {1,,},
  {...},
  {...},
  {,,11}
};

char getTouche();
La valeur retournée sera :
  • -1 si pas de touches (ou plusieurs) appuyées
  • la valeur correspondant à la touche pour les chiffres
  • 11 pour le #
  • 10 pour l' *

Question.jpg Écrire cette fonction en vous servant bien évidemment des 2 fonctions précédentes et pourquoi pas du tableau "touches" complété.

char getTouche()
{
   ....
}

Assemblons le tout

Nous allons utiliser les 2 fonctions getTouche() et setEtatLed() pour réaliser un programme de digicode.

Cahier des charges

Commençons pour définir les contraintes :

  • On appuie sur la touche ON (touche '*') => la led rouge s'allume
  • L'utilisateur doit alors saisir le code sur 4 chiffres
  • On valide le code par la touche OK (touche '#')
  • Si le code est bon la led verte s'allume pendant 10s, sinon la led rouge clignote pendant 10s

Codez !!

Nous commençons par décrire le programme grâce à l'algorigramme suivant :

  • initialiser i
  • éteindre les leds
  • si la touche apuyé est '*'
    • allumer led rouge
    • répéter
      • attendre plus de touches appuyées ( à l'aide d'un while(getTouche....); )
      • répéter
        • lire clavier => touche ( touche = getTouche(); !!! )
        • tant que touche<0
      • si touche '*'
        • réinitialiser i
      • sinon
        • sauvegarder touche dans un tableau
        • incrémenter i
      • tant que i<4
    • attendre plus de touches appuyés
    • attendre appui sur touche
    • si touche '#'
      • vérifier le code
      • si code valide
        • allumer led verte pendant 10s
      • sinon
        • faire clignoter led rouge pendant 10s


Remarque : Utiliser un tableau pour mémoriser le code, ex :

 const unsigned char code[4]={1,2,3,4};

Question.jpg Écrire le programme correspondant

Améliorations

Todo.jpg Il serait intéressant de proposer une procédure de changement du code.


Todo.jpg Il est également intéressant de régler une durée maximum (4s) de saisie du code, en utilisant un timer.

Buzzer

Objectif

Nous souhaitons utiliser le buzzer afin d'avoir une information sonore sur la touche du clavier appuyée.

Pour ce faire, chaque touche sera associée à une note de musique tel qu'indiqué dans le tableau suivant :

Touche 0 1 2 3 4 5 6 7 8 9 * #
Note Do Do# Ré# Mi Fa Fa# Sol Sol# La La# Si
Fréquence (Hz) 261,63 277,18 293,66 311,13 329,63 349,23 369,99 392 415,3 440 466,16 493,88
Période (µs) 3822 3608 3405 3214 3037 2863 2703 2551 2408 2273 2145 2025


Programmons

Question.jpg Vous utiliserez le programme réalisé au tp précédent, et notamment la fonction playnote(note,duree) pour jouer la note associée à chaque appui d'une touche