Cours:TPS 2103 3

De troyesGEII
Aller à : navigation, rechercher

Pour archives !!!!

se référez aux tps : Cours:TPS_2103_tp2 et Cours:TPS_2103_tp3





Retour à la liste des Tps

Éléments de correction

Lien enseignant


Mesure de temps d'exécution

Commençons par analogie au td à essayer de mesurer le temps d'exécution d'une fonction.

Nous allons en profiter pour 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 Timer 2.

Le principe est toujours le même :

  • Initialiser le timer
  • Répéter plusieurs fois l'instruction souhaitée
  • Observer la valeur du timer
  • Afficher cette valeur

Le timer 2 et ses registres (sans interruption)

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 est mis à un automatiquement par le matériel. Ce ne sera pas la matériel qui le mettra à 0 s'il n'y a pas d'interruptions. C'est à vous programmeur de le faire ! Mais pour le faire il vous faut écrire un 1 dans ce bit b0 !

Les habituels bits de configuration de la division se trouvent dans le registre TCCR2B et fonctionnent exactement comme pour timer 0.

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.

Configuration des entrées/sorties

Nous souhaitons ici évaluer le temps mis par la fonction 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.jpg Compléter le programme suivant en choisissant les bonnes valeurs pour évaluer le temps d'exécution de pinMode()

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);
}


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.jpg Comparer en déclarant une sortie directement en configurant le registre DDRx

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.jpg Évaluer la durée d'exécution du code suivant :

//void setup()
//{
  pinMode(6,OUTPUT);
  for (char i=0;i<10;i++)
  {
    digitalWrite(6,0);
    digitalWrite(6,1);
  }
  
//}

//void loop()
//{
//}

Question.jpg Écrire le même code en utilisant directement les registres ad-hoc et comparer les vitesses d'exécution.

Génération d'un signal en sortie

Nous allons commencer par générer un signal carré simple (rapport cyclique 0,5) sans interruption. La technique consiste à attendre (bêtement ?) que le drapeau de dépordement (TOV2) se positionne à 1. On n'oubliera pas de le remettre à 0 (en évrivant un 1 dedans !).

La comparaison avec le Timer 2 (8 bits)

En scrutant le débordement

En utilisant le principe vu en td et l'exercice précédent, répondez à la question suivante :

Question.jpg Faire un programme qui génère un signal de fréquence 1kHz sur la patte PB3, en utilisant le timer 2

On rappelle que la fréquence du quartz de la carte UNO est de 16MHz.

Remarque : Vous en profiterez pour vous passer de toute fonction arduino :

int main()
{
  // variables

  // e/S 
  DDRx|=1<<Pxx;

  // configuration du timer2
  TCCR2A ??? (1<<WGM20);
  TCCR2A ??? (1<<WGM21);
  TCCR2B ??? (1<<CS22);
  TCCR2B ??? (1<<CS21);
  TCCR2B ??? (1<<CS20);
 
  for (;;) // boucle infinie : ne pas modifier !
  {   
    TIFR2|=1<<TOV2;
    TCNT2=????;
    // Attendre un débordement du timer
    while (???) ;
    // Acquitter le débordement
    ????
    // Changer l'état de la sortie
    PORTx ^= (1<<Pxx);
  }
}

La mesure de la fréquence sera réalisée à l'oscilloscope.

En utilisant une interruption

L'attente passive de la section précédente peut être évitée à l'aide des interruptions. On imagine un programme qui fait des tas de choses mais qui sera interrompu régulièrement par un timer.

La comparaison avec le Timer 2 (8 bits)

Question.jpg En utilisant la documentation ci-dessus, on vous demande de générer le même signal d'un kilo Hertz à l'aide d'une interruption. Servez vous de la structure suivante :

// Fonction de traitement Timer 2 OverFlow
ISR(TIMER2_OVF_vect)
{
}

int main()
{
  // variables

 // e/s

 // configuration du timer2

 // autorisation d'interruption

 // boucle
  for (;;)
  {
    // tout se passe dans l'interruption
  }
}

Sans interruption mais sans attente passive : le matériel fait tout

Documentation

La comparaison avec le Timer 2 (8 bits)

Voici la documentation correspondante sous forme de schéma (ci-contre).

Ce mode de fonctionnement s'appelle la comparaison. L'idée générale est que lorsque le timer 2 (TCNT2) arrive à la même valeur que celle qui est contenue dans un registre (OCR2A ou OCR2B) une logique interne est capable de changer (ou pas) une sortie qui s'appelle OC2A ou OC2B.

Ce mode est essentiellement géré par les deux bits COM2A1 et COM2A0 comme indiqué dans le tableau ci-dessous :

Mode non PWM pour la comparaison
COM2A1 COM2A0 Description
0 0 Opération Normale PORT, OC2A déconnecté
0 1 Bascule OC2A sur la comparaison
1 0 Mise à 0 de OC2A sur la comparaison
1 1 Mise à 1 de OC2A sur la comparaison

Nous avons ajouté les informations correspondant à la carte UNO entre parenthèse. Par exemple la sortie correspondante au bit b3 du PORTD est OC2A et correspond au numéro 11 de la carte UNO. L'autre broche gérée par le comparateur B est la broche 3 et se trouve entre parenthèse avec le registre de comparaison.

Utilisation du timer 2 en mode CTC

Le mode CTC du timer est un mode qui veut dire : Clear Timer on Compare match.

Question.jpg Faire un programme qui génère un signal de fréquence 1kHz sur la patte PB3, en utilisant le timer 2 et la comparaison

Indication : l'idée est de placer le timer en mode CTC (Clear Timer on Compare match) et la génération de signaux en mode basculement de OC2A.

Description des bits pour le mode de fonctionnement du timer 2 CTC
Mode WGM22 WGM21 WGM20 Mode de fonctionnement Bas si Mise à jour de OCRAx si Drapeau TOV2 positionné si
2 0 1 0 CTC OCR2A immédiatement MAX

Retour sur la musique

Nous avons eu l'occasion d'utiliser un buzzer dans un précédent TP. Vous allez l'utiliser de nouveau pour générer de nouveau des notes de musique.

Question.jpg Vous allez maintenant reprendre la génération de notes de musique sur le buzzer. On vous demande de choisir une mode de division adapté à votre problème. Puis de précalculer les 11 valeurs correspondants aux notes ci-dessous. Faire ensuite un programme complet qui génère une musique en utilisant les delay() Arduino.

Génération d'un signal en sortie en MLI

La Modulation de Largeur d'Implulsion ou MLI permet de faire varier des intensités lumineuses ou des vitesses de rotation de moteur.

Génération d'un seul signal

Le mode PWM (comme CTC) est géré par les bits WGM22, WGM21 et WGM20 en suivant le tableau suivant :

Description des bits le mode de fonctionnement du timer 2
Mode WGM22 WGM21 WGM20 Mode de fonctionnement Bas si Mise à jour de OCRAx si Drapeau TOV2 positionné si
0 0 0 0 Normal 0XFF immédiatement MAX
1 0 0 1 PWM à phase correcte OXFF TOP BOTTOM
2 0 1 0 CTC OCR2A immédiatement MAX
3 0 1 1 PWM rapide 0XFF BOTTOM MAX
4 1 0 0 Reservé - - -
5 1 0 1 PWM à phase correcte OCR2A TOP BOTTOM
6 1 1 0 Reservé - - -
7 1 1 1 PWM rapide OCR2A BOTTOM TOP

Attention : ces trois bits n'appartiennent pas au même registre comme le montre le schéma ci-dessous !

La documentation (presque) complète du Timer 2 (8 bits)

Comme la figure ci-dessus ne le documente pas, nous donnons maintenant les modes de générations de signaux en mode PWM rapide.

Mode PWM rapide
COM2A1 COM2A0 Description
0 0 Opération Normale de PORT, OC2A déconnecté
0 1 WGM22 = 0: Opération Normale de PORT, OC2A déconnecté, WGM22 = 1: Bascule OC2A sur la comparaison
1 0 Mise à 0 de OC2A sur la comparaison et à 1 sur overflow (MLI non inversée)
1 1 Mise à 1 de OC2A sur la comparaison et à 0 sur l'overflow (MLI inversée)


Question.jpg En utilisant le mode PWM rapide, il vous est demandé de réaliser un programme complet capable de changer le rapport cyclique du signal généré en fonction d'une valeur envoyée par la liaison série. Pour éviter de gérer la liaison série avec des registres, on vous demande de reprendre le langage Arduino pour réaliser cette partie.

Indications : La conversion d'une chaîne de caractères en une valeur hexadécimale mérite un soin particulier. Vous utiliserez les primitives :

  • if (Serial.available()>0)
  • Serial.readBytesUntil('\n', buffer, 4);

pour cela. Vous transformerez ensuite les deux caractères buffer[0] et buffer[1] en valeur hexadécimale si seulement c'est possible. Autrement un message d'erreur sera envoyé par la liaison série.

Génération de deux signaux PWM

Question.jpg En utilisant le mode PWM rapide, il vous est demandé de réaliser un programme complet capable de changer le rapport cyclique de deux signaux PWM. Les deux valeurs seront envoyées par la liaison série avec un protocole que l'on vous laisse définir.