Cours:TPS 2103 3
Sommaire
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)
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)
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é !!!
}
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.
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).
É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()
//{
//}
É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 !).
En scrutant le débordement
En utilisant le principe vu en td et l'exercice précédent, répondez à la question suivante :
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.
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
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.
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.
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 !
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) |
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
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.