L’utilisation des timers en Arduino est une méthode avancées permettant d’exécuter du code sans perturber le reste du programme. Ils permettent notamment d’activer des fonctions à des intervalles de temps précis. Les timers sont utilisées dans bon nombre de librairie de manière complètement transparente pour l’utilisateur (millis(), Servo.h, PWM, etc.)
Dans certains cas, il est possible d’utiliser des librairies qui configure les timers qui simplifierons l’utilisation.
Matériel
- Arduino UNO
- Câble USB A/ USB B
Description
Les timers sont des registres du microprocesseur qui s’incrémente en fonction des impulsions d’horloge ou d’impulsions extérieures. Il est possible de les configurer pour modifier leur comportement.
Le microprocesseur de l’Arduino UNO (ATmega328P) possède 3 timers:
- timer0 (8 bits) compte de 0 à 256 et commande la PWM des broches 5 et 6. Il est aussi utilisé par les fonctions delay(), millis() et micros().
- timer1 (16 bits) compte de 0 à 65535 et est utilisé pour la commande PWM des broches 9 et 10. Il est utilisé également par la libriaire Servo.h
- timer2 (8 bits) qui est utilisé par la fonction Tone() et la génération de la PWM sur les broches 3 et 11.
Configuration des Timers
La partie la plus compliqué de l’utilisation du capteur est leur configuration. Un timer est configuré à l’aide de son registre de controle. Voici le rappel des registre.
Timer 0 | Timer 1 | Timer 2 | Rôle |
---|---|---|---|
TCNT0 | TCNT1L | TCNT2 | Timer (bit 0 à 7) |
– | TCNT1H | – | Timer (bit 8 à 15) |
TCCR0A | TCCR1A | TCCR2A | Registre de contrôle |
TCCR0B | TCCR1B | TCCR2B | Registre de contrôle |
– | TCCR1C | – | Registre de contrôle |
OCR0A | OCR1AL | OCR2A | Output Compare (bit 0 à 7) |
– | OCR1AH | – | Output Compare (bit 8 à 15) |
OCR0B | OCR1BL | OCR2B | Output Compare (bit 0 à 7) |
– | OCR1BH | – | Output Compare (bit 8 à 15) |
– | ICR1L | – | Input Capture (bit 0 à 7) |
– | ICR1H | – | Input Capture (bit 8 à 15) |
TIMSK0 | TIMSK1 | TIMSK2 | Interrupt Mask |
TIFR0 | TIFR1 | TIFR2 | Interrupt Flag |
Le registre TCNTx contient la valeur du timer/counter, le registre TCCRxA et TCCRxB sont les registres de contrôles. OCRxA rt OCRxB contiennent les valeurs de registre à comparer. TIMSKx contient le masque d’interruption et TIFRx, quant à lui, contient les flags d’activation.
Code utilisant le timer2
Pour cette exemple, nous utilisons le timer2 qui est codé sur 8bits (256). Il nous faut donc introduire un compteur supplémentaire.
unsigned long elapsedTime, previousTime; void onTimer() { static boolean state = HIGH; elapsedTime=millis()-previousTime; Serial.print(F("Set LED 13 : ")); if(state){ Serial.print(F("ON")); }else{ Serial.print(F("OFF")); } Serial.print(F(" - "));Serial.print(elapsedTime);Serial.println(F("ms")); digitalWrite(13, state); state = !state; previousTime=millis(); } void setup(){ Serial.begin(9600); pinMode(13, OUTPUT); cli(); // disable all interrupts TCCR2A = (1<<WGM21)|(0<<WGM20); // Mode CTC TIMSK2 = (1<<OCIE2A); // Local interruption OCIE2A TCCR2B = (0<<WGM22)|(1<<CS22)|(1<<CS21); // Frequency 16Mhz/ 256 = 62500 OCR2A = 250; //250*125 = 31250 = 16Mhz/256/2 sei(); // enable all interrupts } ISR(TIMER2_COMPA_vect){ // timer compare interrupt service routine static int counter=0; if (++counter >= 125) { // 125 * 4 ms = 500 ms counter = 0; onTimer(); } } void loop(){ }
Code utilisant le timer1
Pour cette exemple, nous allons utiliser le timer1
unsigned long elapsedTime, previousTime; void onTimer() { static boolean state = HIGH; elapsedTime=millis()-previousTime; Serial.print(F("Set LED 13 : ")); if(state){ Serial.print(F("ON")); }else{ Serial.print(F("OFF")); } Serial.print(F(" - "));Serial.print(elapsedTime);Serial.println(F("ms")); digitalWrite(13, state); state = !state; previousTime=millis(); } void setup(){ Serial.begin(9600); pinMode(13, OUTPUT); cli(); // disable all interrupts TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; OCR1A = 31250; // compare match register 16MHz/256/2 = 31250 TCCR1B = (1 << WGM12); // CTC mode TCCR1B = (1 << CS12); // // Frequency 16Mhz/ 256 = 62500 TIMSK1 = (1 << OCIE1A); // Local interruption OCIE1A sei(); // enable all interrupts } ISR(TIMER1_COMPA_vect){ // timer compare interrupt service routine onTimer(); } void loop(){ }
N.B. : Nous avons rajouté une mesure du temps écoulé à titre d’illustration mais il faut faire attention lorsqu’on utilise des fonctions basées sur les interruptions dans les fonctions appelées par des interruptions. Il peut y avoir des interférences.
Résultat
Une fois le programme lancé, la LED embarquée s’allume et s’éteint toutes les 500ms
Sources
Retrouvez nos tutoriels et d’autres exemples dans notre générateur automatique de code
La Programmerie