# Micro contrôleurs AVR/Le Timer 1

Le timer 1 est un timer étendu sur 16 bits. Cette taille de timer, 8 bits pour le timer 0 (du précédent chapitre) et 16 bits pour le timer 1 n’est pas sans rappeler l'architecture des PIC 16F. Rappelons par contre que le timer 0 est passé à 16 bits dans les PIC 18F. Mais revenons-en à notre sujet principal : les AVRs.

## Documentation du timer 1 seul

Le timer 1 est un compteur sur 16 bits avec une horloge calibrée réalisée à partir de l'horloge (quartz externe). Son utilisation est possible en compteur. Dans ce cas c’est un signal externe qui fera avancer le compteur.
Utiliser des registres 16 bits avec un processeur 8 bits nécessite quelques précautions. On peut lire dans la documentation :
* Pour réaliser une écriture 16 bits, l'octet de poids fort doit être écrit en premier
* pour lire un registre 16 bits, l'octet de poids faible doit être lu avant l'octet de poids fort
En principe le compilateur C sait gérer ces situations.

### Timer1 de l'ATMega8

Voici sous forme schématique la documentation du timer 1. Il y a dans ce schéma toute l'information nécessaire pour réaliser la programmation du timer 1 dans n’importe quel langage.
Les registres utilisés par le Timer1 sont donc :
* TCNT1H et TCNT1L, (H pour High = poids fort, L pour LOW = poids faible)
* TCCR1B
* éventuellement le PORTD, et TIFR.
Au risque de se répéter, l'accès d'un registre 16 bits par un processeur 8 bits est toujours un peu complexe puisque cela se fait en deux écriture. En ce qui concerne l'architecture que l’on étudie, il y a un registre temporaire (partagé avec d'autres registres). On retiendra :
* pour une écriture : on écrit d’abord le poids fort puis le poids faible
* pour une lecture : on lit d’abord le poids faible puis le poids fort.
La bonne nouvelle est que notre compilateur C est capable de manipuler directement les 16 bits (TCNT1=0x1FF;) comme le montrent les définitions suivantes :
La mise à zéro du bit TOV1 est un peu particulière. Elle se réalise en mettant un 1 dans le bit correspondant ou en écrivant une valeur dans le timer.
Le bit du PORTD qui sert éventuellement à piloter le compteur 1 s’appelle T1.

### Timer1 de l'ATMega328

Le fonctionnement du Timer 1 est identique à celui de l'ATMega8 mais des registres ont changés légèrement de nom et des fonctionnalités ont été ajoutées. Mais ces nouvelles fonctionnalités ne sont pas présentées ici.
C'est maintenant le registre TIFR1 qui contient le drapeau de débordement TOV1.

#### Exercice 1

1°) L'AVR ATMega8 possède un oscillateur de 4 MHz. Quelle fréquence minimale de l'interruption TOV1 peut-il générer avec son horloge si la documentation du timer 1 de l'ATMega8 est la même que celle de l'ATMega328 ?
Remarquez la présence d'une variable qualifiée de volatile. Il faut mieux déclarer les variables globales utilisées par une interruption comme volatile. Cela évite au compilateur de faire des optimisations qui seraient dommageable au bon fonctionnement. Cette variable est commentée comme non nécessaire car l'interruption pourrait se faire avec la simple instruction :
4 MHz/(1024*65536) = 0,0 596 Hz.
Le bit TOV1 est automatiquement mis à 0 par l'interruption.
2°) Quelle fréquence et sur quel bit est-elle générée dans les mêmes conditions que la question précédente ?
0,0 596 Hz / 2 car basculement avec un ou exclusif (soit 0,0 298 Hz).
3°) Quel bit de quel registre autorise l'interruption ?
Le bit TOIE1 du registre TIMSK.

## La comparaison

La comparaison sert à générer une fréquence calibrée sur une sortie quelconque (ou un bit interne). Elle est aussi utilisée pour générer une MLI (Modulation de Largeur d'Impulsion, PWM en anglais).

### Documentation de la comparaison et de la MLI

Les différents modes de comparaison sont choisis à l'aide des bits WGM13, WGM12, WGM11 et WGM10 (un bit de plus que le timer 0). Ces choix sont conformes au tableau suivant.

#### Description des bits pour la génération de forme d'onde

| Mode | WGM13 | WGM12 | WGM11 | WGM10 | Mode de fonctionnement | Bas si | Mise à jour de OCRAx si | Drapeau TOV1 positionné si |
| 0 | 0 | 0 | 0 | 0 | Normal | 0XFFFF | immédiatement | MAX |
| 1 | 0 | 0 | 0 | 1 | PWM à phase correcte (8 bits) | OXFF | TOP | BOTTOM |
| 2 | 0 | 0 | 1 | 0 | PWM à phase correcte (9 bits) | OX1FF | TOP | BOTTOM |
| 3 | 0 | 0 | 1 | 1 | PWM à phase correcte (10 bits) | OX3FF | TOP | BOTTOM |
| 4 | 0 | 1 | 0 | 0 | CTC (Clear Timer on Compare) | OCR1A | immédiatement | MAX |
| 5 | 0 | 1 | 0 | 1 | PWM rapide (8 bits) | OXFF | BOTTOM | TOP |
| 6 | 0 | 1 | 1 | 0 | PWM rapide (9 bits) | OX1FF | BOTTOM | TOP |
| 7 | 0 | 1 | 1 | 1 | PWM rapide (10 bits) | OX3FF | BOTTOM | TOP |
| 14 | 1 | 1 | 1 | 0 | PWM rapide | ICR1 | BOTTOM | TOP |
| 15 | 1 | 1 | 1 | 1 | PWM rapide | OCR1A | BOTTOM | TOP |
* MAX = 0xFFFF
* BOTTOM = 0x0000
Nous n'avons présenté qu'une partie du tableau mais cela devrait suffire pour une utilisation courante.
Comme le montre ce tableau, le timer1 est un timer 16 bits capable de fonctionner sur 8, 9 et 10 bits (modes 5, 6 et 7). Il est même aussi capable de fonctionner avec une valeur maximale quelconque (modes 14 et 15) où la valeur maximale du comptage est fixée par un registre. Cela ressemble au mode CTC mais il s'agit en fait de fixer la fréquence de la MLI. Le rapport cyclique sera fixé par OCR1A et/ou OCR1B pour le mode 14 et seulement OCR1B pour le mode 15.
Une application classique du mode 14 est la commande d'un servomoteur qui nécessite la réalisation d'un signal MLI à une fréquence de 50 Hz.
Pour chacun des modes de ce tableau ci-dessus, les bits COM1A1 et COM1A0 auront un fonctionnement différent. Ces bits sont destinés à gérer les formes d'onde du signal de sortie.

#### Comparaison simple
##### Mode non PWM pour la comparaison

| COM1A1/COM1B1 | COM1A0/COM1B0 | Description |
| 0 | 0 | Opération Normale PORT, OC1A/OC1B déconnecté |
| 0 | 1 | Bascule OC1A/OC1B sur la comparaison |
| 1 | 0 | Mise à 0 de OC1A/OC1B sur la comparaison |
| 1 | 1 | Mise à 1 de OC1A/OC1B sur la comparaison |
Et voici donc la documentation correspondante :
Il est possible de passer le Timer 1 en mode 8 bits, ce qui n'apparaît pas sur la figure : $(WGM13,WGM12,WGM11,WGM10)_{2}=0001$ mais sera expliqué plus tard.

#### Mode PWM rapide
##### Mode PWM rapide et comparaison

| COM1A1/COM1B1 | COM1A0/COM1B0 | Description |
| 0 | 0 | Opération Normale PORT, OC1A/OC1B déconnecté |
| 0 | 1 | WGM02=0 Opération Normale PORT, OC1A/OC1B déconnecté |
| 0 | 1 | WGM02=1 Basculement de OC1A/OC1B sur la comparaison |
| 1 | 0 | Mise à 0 de OC1A/OC1B sur la comparaison et à 1 à BOTTOM |
| 1 | 1 | Mise à 1 de OC1A/OC1B sur la comparaison et à 0 à BOTTOM |
Ce tableau nous montre clairement que seuls les modes 2 et 3 sont importants pour la MLI. Ces deux modes fonctionnent :
* mode 2 on augmente OCR1A/OCR1B pour augmenter la largeur d'impulsion
* mode 3 on augmente OCR1A/OCR1B pour diminuer la largeur d'impulsion

#### Mode PWM à phase correcte

Ce mode utilise le compteur 0 dans les deux sens : en comptage et décomptage.

##### Mode PWM à phase correcte et comparaison

| COM1A1/COM1B1 | COM1A0/COM1B0 | Description |
| 0 | 0 | Opération Normale PORT, OC1A/OC1B déconnecté |
| 0 | 1 | WGM02=0 Opération Normale PORT, OC1A/OC1B déconnecté |
| 0 | 1 | WGM02=1 Basculement de OC1A/OC1B sur la comparaison |
| 1 | 0 | Mise à 0 de OC0A sur la comparaison quand comptage et mise à 1 de OC1A/OC1B sur la comparaison quand décomptage |
| 1 | 1 | Mise à 1 de OC0A sur la comparaison quand comptage et mise à 0 de OC1A/OC1B sur la comparaison quand décomptage |

### Exemple de programme en C

Nous donnons, pour commencer, le programme suivant destiné à faire clignoter une LED à environ à 1 Hz sur une platine Arduino MEGA2560. Cette platine fonctionnant à 16 MHz, il faut compter jusqu'à 7812 si l’on utilise un prédiviseur par 1024 et un mode de basculement de bit. Attention, 1024 * 7812 ne donne pas 16 MHz mais 8 MHz à cause du basculement !
Il n'y a aucune interruption dans ce programme ! La boucle while(1) peut être remplacée par n’importe quelle activité sans déranger le matériel.

### Interruption de comparaison

La comparaison permet de faire basculer une broche particulière de manière entièrement matérielle. Pour le timer 1 les broches sont appelées OC1A et OC1B.
Et pour l'ATMega328p ces broches sont :
* PB1 broche 15 pour OC1A
* PB2 broche 16 pour OC1B
Mais il suffit que le cahier des charges impose le basculement d'une broche (qui n'est ni OC1A ni OC1B) pour que l’on soit obligé de faire ce travail de basculement à l'aide d'une interruption.
Imaginons donc que l’on désire utiliser une des interruptions de comparaison (il y en a deux). La première chose à faire est de trouver comment elles ont été définies dans "avr/interrupt.h" :
Si l’on désire utiliser la première, il nous faudra donc écrire quelque chose qui ressemble à :
Ce qui reste donc à faire est donc d'autoriser cette interruption. Cela se réalise en deux étapes :
* mise à un du bit OCIE1A du registre TIMSK1
* autorisation générale des interruptions avec un "sei"

#### Exercice 2

Modifier le code donné en exemple dans la section précédente pour remplacer le basculement matériel de la broche OC1A par le basculement de la broche PB3 (toujours à un Herz).

#### Exercice 3

Réaliser une commande simple de servomoteur en C pur (sans la librairie Arduino). Comme le montre la figure ci-contre, il s'agit de réaliser une Modulation de Largeur d'Impulsion de fréquence 50 Hz (période de 20 ms).
Indications
Seul le timer1 permet de réaliser cela en matériel pur, c'est-à-dire sans code spécifique s'exécutant pour le réaliser et donc sans interruption. En effet 16 MHz / 50 *1024 = 312,5 qui est une valeur de plus de 8 bits ! Cette valeur correspond à la valeur TOP de TCNT1 pour réaliser 50 Hz à partir de 16 MHz avec un prescaler de 1024. Il serait donc bon de prendre le mode 14 de la PWM et d'initialiser ICR1 à 313.
Le rapport cyclique doit varier entre 1 ms et 2 ms.
Une question importante est de savoir comment brancher le servomoteur ?
* Pour cela il faut chercher la broche OC1A sur le microcontrôleur. Sur l'ATMega328p c'est la broche PB1 (broche 15 d'un boîtier DIP).
* Chercher ensuite dans google en tapant "pinout arduino uno" et chercher sur une des images proposées soit PB2 soit OC1A.
* La correspondance Arduino est trouvée : c'est la broche -9 qui sera amenée au fil orange du servomoteur.
* Le fil marron foncé est amené à la masse et le rouge à Vcc (de l'Arduino).
Pour information il est possible de trouver des petits servomoteurs autour de 4 €.
La résolution n'est pas terrible puisque l'on doit varier OCR1A de 15 à 31. Il suffit de diviser par 256 au lieu de 1024 pour avoir plus de résolution :
On a maintenant une résolution sur 125 valeurs.
Ce code a été testé sur Tinkercad avec succès.
Il est possible d'utiliser le prescaler à 64. il faudrait alors mettre 5000 dans ICR1.

#### Exercice 4

Reprendre l'exercice 3 pour une commande en panoramique et en inclinaison (pan/tilt touret), c'est-à-dire deux servomoteurs.
On peut naturellement utiliser le timer1 pour les deux commandes si l'on se place dans le mode 14.
| Le Timer 0 | Le Timer 2 |