Cours:TPS XR207 tpTimer

De troyesGEII
Révision datée du 3 avril 2015 à 14:04 par Bjacquot (discussion | contributions) ({{Vert|Sans interruption mais sans attente passive : le matériel fait tout}})
Aller à : navigation, rechercher
Retour à la liste des Tps

Éléments de correction

Nous allons dans ce TP nous pencher sur l'utilisation des timers, notamment pour générer un signal, ceci en utilisant le moins possible les ressources du µcontrôleur.

ArduinoPinout.png

Comment générer un signal périodique

Nous allons dans cette partie comparer les 2 principales méthodes pour générer un signal périodique.

Dans toute cette partie, nous considérerons une sortie périodique telle que :

  • le signal est carré (2 états '0' ou '1')
  • de fréquence 1kHz
  • de rapport cyclique 1/2
  • sortie sur la patte PB3

avec une attente .... méthode basique !

Commençons tout simplement par utiliser une attente, comme nous l'avons fait dans le tp précédent.

Il suffit tout bonnement de configurer correctement la valeur d'attente.

Remarquons que pour plus de précision, il est possible d'utiliser la fonction _delay_us(xxx), dont le nom est suffisamment explicite pour se passer d'une description !

Question.jpg Écrire un programme générant le signal souhaité, et le visualiser avec un oscilloscope.


#include <util/delay.h>

int main()
{
   // configuration e/s

   while(1)                // boucle
   {
      // modification de la sortie

      // attente
      _dela.....
   }
}

Remarque : Comme expliqué en TD, cette méthode fonctionne mais entraîne une occupation à 100% du processeur, qui ne peut donc réaliser que cette action !


l'outil adapté : le timer !

Passons aux choses sérieuses en utilisant un timer (en l’occurrence le timer2 d'un atmega328p), et donnons tout d'abord les 2 figures qui nous permettront de le configurer facilement :

Documentation simple du Timer 2 (8 bits)
La comparaison avec le Timer 2 (8 bits)

Remarquons tout de suite qu'il s'agit d'un compteur 8 bits, c'est à dire qu'il générera un débordement (overflow) lors du passage de 255 à 0.


Paramètres du timer

Comme pour toute utilisation du timer, il est nécessaire de choisir :

  • la valeur du prédiviseur, et donc la fréquence de comptage : fcpt=fq/p
  • le nombre de fois que le compteur s'incrémentera, n, avant d'être réinitialisé

On rappelle que sur les cartes arduino UNO, fq=16MHz

La figure ci après doit vous permettre de trouver facilement la relation entre les différentes valeurs et ainsi déterminer les valeurs n et p adaptées à notre problème.

ChronogrammeTimer.png

Question.jpg Faire un choix pour n et p


Mode comparaison avec interruption

Nous pouvons désormais écrire le programme utilisant le timer2, qui devra utiliser le mode comparaison.

Autrement dit, on configure le timer pour que sa valeur soit réinitialisée à 0 lorsqu'il atteint la valeur OCR2A (ou si vous préférez la valeur n que vous avez calculé juste avant).

Comme indiqué sur la figure un peu plus haut, il s'agit de configurer les bits WGM2[2..0] dans le mode adéquat.

Il conviendra également de générer une interruption à chaque remise à zéro (ou plus exactement lors de chaque comparaison), et pour ce faire il suffit :

  • autoriser l'interruption de comparaison : TIMSK2|=1<<OCIE2A
  • autoriser globalement les interruptions : sei()
  • la fonction d'interruption sera définie par : ISR(TIMER2_COMPA_vect)

La valeur de sortie sera alors modifiée à chaque interruption, et le µcontrôleur pourra vaquer à d'autres activités dans le programme principal.

Question.jpg Écrire le programme utilisant le Timer2, en vous servant du squelette suivant :

// Fonction de traitement Timer 2 Comparaison
ISR(TIMER2_COMPA_vect)
{
 // il suffit de changer l'état de la sortie
}

int main()
{
 // variables

 // e/s

 // configuration du timer2 (prédiviseur)

 // autorisation d'interruption (cf ci dessus)

 // boucle
  while(1)
  {
    // tout se passe dans l'interruption, rien à faire ici
  }
}



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

La comparaison avec le Timer 2 (8 bits)

Par commodité, nous remettons (ci-contre) la documentation correspondante sous forme de schéma.

Ce mode de fonctionnement utilise le mode comparaison, et pilote également directement une sortie bien particulière.

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.

Question.jpg Modifier le programme précédent en supprimant la fonction d'interruption, et en pilotant directement la sortie depuis le timer, en vous servant du tableau précédent.

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.

int main()
{
 // variables

 // e/s

 // configuration du timer2 (prédiviseur)

 // mode de génération de signaux (COM2A1 COM2A0)

 // boucle
  while(1)
  {
    // Plus aucune utilisation processeur
  }
}



Allons un peu plus loin ...

Il vous reste moins d'1h pour terminer le TP, passez à la partie suivante !

Complétons quelque peu notre programme en donnant la possibilité de modifier la fréquence du signal de sortie.

Nous ajoutons 2 boutons (A et B sur notre carte shieldInfo).
  • 1 bouton permettra d'augmenter la fréquence
  • 1 bouton permettra de diminuer la fréquence
  • il suffit de modifier la valeur de comparaison du timer
  • il convient de détecter l'appui sur le bouton (cf tp1)
  • on utilisera les interruptions associées aux boutons
Bouton Position Arduino Pin Port Interruption Niveau logique si bouton appuyé
A Bas Gauche 2 PD2 int0 1
D Haut Gauche 3 PD3 int1 1
B Bas Droite A0 PC0 0
C Haut Droite A1 PC1 0

Question.jpg Écrire un programme répondant au cahier des charges


ISR(INT0_vect)
{
}


ISR(INT1_vect)
{
}


int main()
{
 // variables

 // e/s

 // configuration du timer2 (prédiviseur)

 // mode de génération de signaux (COM2A1 COM2A0)

 // configuration des interruptions INT1 et INT2  (EIMSK et EICRA)

 sei(); // autorisation des interruptions
 // boucle
  while(1)
  {
    // Plus aucune utilisation processeur
  }
}


=> buzzer

=> mélodie

=> changer les notes avec 2ème timer