Guide Débutant
Timers Hardware Arduino
Guide Progressif pour Maîtriser les PWM
5 octobre 2025
Table des matières
1 C’est quoi un Timer ? 3
1.1 Analogie simple : Le Timer = Un chronomètre automatique . . . . . . . . . . . . 3
2 Les 3 registres à connaître 3
2.1 TCCRx (Timer Counter Control Register) . . . . . . . . . . . . . . . . . . . . . . 3
2.2 TCNTx (Timer Counter) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2.3 OCRx (Output Compare Register) . . . . . . . . . . . . . . . . . . . . . . . . . . 3
3 Les modes PWM expliqués simplement 4
3.1 Mode Fast PWM (le plus simple) . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
4 Décoder les bits (simplifié) 4
4.1 Exemple concret : TCCR1A . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
4.2 Les bits importants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
5 Ta première configuration pas à pas 5
5.1 Objectif : PWM sur pin 9 à 1 kHz, 50% duty cycle . . . . . . . . . . . . . . . . . 5
6 Comprendre ton code de TP 5
6.1 Timer1 (8 kHz, signaux inversés) . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
6.2 Timer2 (4 kHz, variable) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
7 Exercices de base pour comprendre les Timers 6
7.1 Exercice Base 1 : Clignotement LED sans delay() . . . . . . . . . . . . . . . . . . 6
7.2 Exercice Base 2 : Comprendre le prescaler . . . . . . . . . . . . . . . . . . . . . . 7
7.3 Exercice Base 3 : Mode CTC - Compare Match . . . . . . . . . . . . . . . . . . . 9
7.4 Exercice Base 4 : Lire le compteur en temps réel . . . . . . . . . . . . . . . . . . 9
7.5 Exercice Base 5 : PWM manuel (sans mode automatique) . . . . . . . . . . . . . 10
7.6 Exercice Base 6 : Mesurer une durée précise . . . . . . . . . . . . . . . . . . . . . 11
8 Exercices pratiques avancés 12
8.1 Exercice 1 : Change la fréquence . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
8.2 Exercice 2 : Change le duty cycle . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
8.3 Exercice 3 : PWM avec prescaler . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
8.4 Exercice 4 : Servomoteur avec Timer1 . . . . . . . . . . . . . . . . . . . . . . . . 14
8.5 Exercice 5 : Génération de tonalité musicale . . . . . . . . . . . . . . . . . . . . . 15
1
9 Antisèche (Cheat Sheet) 18
9.1 Formules essentielles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
9.2 Prescalers disponibles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
9.3 Pins PWM par Timer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
10 Stratégie d’apprentissage 18
10.1 Pour bien comprendre, suis cette méthode . . . . . . . . . . . . . . . . . . . . . . 18
11 Ressources supplémentaires 19
11.1 Documentation officielle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
11.2 Outils utiles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
12 En résumé : Les 5 étapes clés 19
2
1 C’est quoi un Timer ?
1.1 Analogie simple : Le Timer = Un chronomètre automatique
Imagine un chronomètre qui compte tout seul pendant que tu fais autre chose :
— Tu le règles une fois au départ
— Il compte automatiquement (0, 1, 2, 3...)
— Quand il atteint un certain nombre, il fait une action (allumer/éteindre une pin)
L’Arduino Uno a 3 Timers
— Timer0 : 8 bits (compte de 0 à 255) - Utilisé par millis()
— Timer1 : 16 bits (compte de 0 à 65535) - Le plus puissant
— Timer2 : 8 bits (compte de 0 à 255) - Indépendant
2 Les 3 registres à connaître
Chaque Timer a 3 registres principaux (comme des boutons de réglage) :
2.1 TCCRx (Timer Counter Control Register)
C’est le panneau de contrôle : tu choisis le MODE de fonctionnement
1 TCCR1A = 0; // Reset complet
2 TCCR1B = 0; // Reset complet
Listing 1 – Reset des registres
2.2 TCNTx (Timer Counter)
C’est le compteur : la valeur actuelle qui augmente automatiquement
1 TCNT1 = 0; // Remet le compteur z ro
Listing 2 – Remise à zéro du compteur
2.3 OCRx (Output Compare Register)
C’est la valeur cible : quand TCNT atteint OCR, une action se produit
1 OCR1A = 1000; // Quand le compteur atteint 1000 action !
Listing 3 – Définition de la valeur cible
3
3 Les modes PWM expliqués simplement
3.1 Mode Fast PWM (le plus simple)
Fonctionnement
1. Le compteur monte de 0 → TOP (valeur max)
2. Quand il atteint TOP, il redémarre à 0
3. Pendant ce temps :
— Si compteur < OCR → Pin = HIGH
— Si compteur ≥ OCR → Pin = LOW
Schéma mental :
Compteur: 0 → 100 → 200 → 255 → 0 (recommence)
OCR = 100
Pin: HIGH→LOW (PWM créé!)
Formule de fréquence
Horloge CPU
Fréquence PWM =
Prescaler × TOP
4 Décoder les bits (simplifié)
Les registres utilisent des bits pour activer des fonctions.
4.1 Exemple concret : TCCR1A
1 TCCR1A = (1 << COM1A1 ) | (1 << WGM11 ) ;
Listing 4 – Configuration de TCCR1A
Traduction en français :
— (1 « COM1A1) → "Active le mode PWM sur la pin OC1A (pin 11)"
— (1 « WGM11) → "Partie 1 du réglage du mode Fast PWM"
— Le | signifie "ET aussi" (comme additionner les fonctions)
4.2 Les bits importants
Bit Fonction Effet
COM1A1 Compare Output Mode Active PWM sur pin 11 (OC1A)
COM1B1 Compare Output Mode Active PWM sur pin 12 (OC1B)
COM1B0 Inversion Inverse le signal (30% → 70%)
WGM1x Waveform Generation Mode Choisit Fast PWM, Phase Correct,
etc.
CS1x Clock Select Choisit le prescaler (vitesse)
Table 1 – Bits de configuration des Timers
4
5 Ta première configuration pas à pas
5.1 Objectif : PWM sur pin 9 à 1 kHz, 50% duty cycle
1 void setup () {
2 pinMode (9 , OUTPUT ) ; // Pin 9 = OC1A du Timer1
3
4 // TAPE 1 : Reset complet
5 TCCR1A = 0;
6 TCCR1B = 0;
7 TCNT1 = 0;
8
9 // TAPE 2 : Choisir le mode Fast PWM ( mode 14)
10 // WGM13 =1 , WGM12 =1 , WGM11 =1 , WGM10 =0
11 TCCR1A = (1 << COM1A1 ) | (1 << WGM11 ) ;
12 // ^ ^
13 // Active PWM Mode Fast PWM ( partie 1)
14
15 TCCR1B = (1 << WGM13 ) | (1 << WGM12 ) | (1 << CS10 ) ;
16 // ^ ^ ^
17 // Fast PWM p .2 Fast PWM p .3 Pas de prescaler
18
19 // TAPE 3 : R g l e r la f r q u e n c e
20 // F r q u e n c e = 16 MHz / (1 ( ICR1 + 1) )
21 // Pour 1 kHz : ICR1 = 16000 - 1 = 15999
22 ICR1 = 15999; // TOP = 15999 1 kHz
23
24 // TAPE 4 : R g l e r le duty cycle
25 // 50% de 16000 = 8000
26 OCR1A = 8000; // Pin 9 50%
27 }
28
29 void loop () {
30 // Le PWM fonctionne automatiquement !
31 // Tu peux faire autre chose ici
32 }
Listing 5 – Configuration complète d’un Timer
6 Comprendre ton code de TP
Reprenons ton code ligne par ligne.
6.1 Timer1 (8 kHz, signaux inversés)
1 // 1. Calcul du TOP pour 8 kHz
2 const uint16_t TIMER1_TOP = 1999;
3 // 16 MHz / (1 2000) = 8000 Hz
4
5 // 2. Calcul du duty cycle 30%
6 const uint16_t TIMER1_DUTY_30 = 600;
7 // 600 / 2000 = 0.30 = 30%
8
9 // 3. Configuration
10 TCCR1A = (1 << COM1A1 ) | (1 << COM1B1 ) | (1 << COM1B0 ) | (1 << WGM11 ) ;
11 // ^ ^ ^ ^
12 // PWM pin 11 PWM pin 12 INVERSE pin 12 Mode PWM
13
14 TCCR1B = (1 << WGM13 ) | (1 << WGM12 ) | (1 << CS10 ) ;
15 // ^ ^ ^
5
16 // Mode PWM Mode PWM Prescaler =1
17
18 ICR1 = 1999; // F r q u e n c e = 8 kHz
19 OCR1A = 600; // Pin 11 = 30%
20 OCR1B = 600; // Pin 12 = 70% ( i n v e r s par COM1B0 )
Listing 6 – Configuration Timer1 pour signaux inversés
6.2 Timer2 (4 kHz, variable)
1 // 1. Calcul du TOP pour 4 kHz
2 const uint8_t TIMER2_TOP = 499;
3 // 16 MHz / (8 500) = 4000 Hz
4
5 // 2. Configuration
6 TCCR2A = (1 << COM2B1 ) | (1 << WGM21 ) | (1 << WGM20 ) ;
7 // ^ ^ ^
8 // PWM pin 9 Mode PWM Mode PWM
9
10 TCCR2B = (1 << WGM22 ) | (1 << CS21 ) ;
11 // ^ ^
12 // Mode PWM Prescaler =8
13
14 OCR2A = 499; // TOP = 499 4 kHz
15 OCR2B = newDuty ; // Duty cycle variable (0 -499)
Listing 7 – Configuration Timer2 pour PWM variable
7 Exercices de base pour comprendre les Timers
7.1 Exercice Base 1 : Clignotement LED sans delay()
Objectif : Comprendre le comptage automatique d’un Timer en faisant clignoter une LED
toutes les secondes sans bloquer le programme.
Concept clé : Un Timer compte automatiquement. Quand il atteint une valeur (overflow),
il déclenche une interruption.
Niveau : Très débutant
6
Solution expliquée
1 const int LED_PIN = 13;
2 volatile bool ledState = false ;
3
4 void setup () {
5 pinMode ( LED_PIN , OUTPUT ) ;
6
7 // Configuration Timer1 pour overflow toutes les 1 seconde
8 // Mode normal ( compteur monte de 0 65535)
9 TCCR1A = 0; // Mode normal
10 TCCR1B = 0;
11 TCNT1 = 0; // Reset compteur
12
13 // Prescaler = 256
14 // Temps overflow = (65536 256) / 16 MHz = 1.05 sec
15 TCCR1B = (1 << CS12 ) ; // Prescaler 256
16
17 // Active l ’ interruption overflow
18 TIMSK1 = (1 << TOIE1 ) ;
19
20 sei () ; // Active les interruptions globales
21 }
22
23 void loop () {
24 // Le programme peut faire autre chose ici !
25 // La LED clignote automatiquement g r c e l ’ interruption
26 }
27
28 // Fonction a p p e l e automatiquement chaque overflow
29 ISR ( TIMER1_OVF_vect ) {
30 ledState = ! ledState ;
31 digitalWrite ( LED_PIN , ledState ) ;
32 }
Listing 8 – Clignotement avec Timer1 overflow
Ce que tu apprends :
— Le Timer compte tout seul en arrière-plan
— L’overflow déclenche une interruption automatique
— Le programme principal reste libre
7.2 Exercice Base 2 : Comprendre le prescaler
Objectif : Visualiser l’effet du prescaler sur la vitesse de comptage.
Concept clé : Le prescaler divise l’horloge pour ralentir le comptage.
Niveau : Débutant
7
Solution
1 const int LED_PIN = 13;
2
3 void setup () {
4 Serial . begin (9600) ;
5 pinMode ( LED_PIN , OUTPUT ) ;
6
7 // Configure Timer1 en mode normal
8 TCCR1A = 0;
9 TCCR1B = 0;
10 TCNT1 = 0;
11
12 // Test avec prescaler = 1 ( t r s rapide )
13 testPrescaler (1 , " Prescaler 1 " ) ;
14 delay (2000) ;
15
16 // Test avec prescaler = 8
17 testPrescaler (8 , " Prescaler 8 " ) ;
18 delay (2000) ;
19
20 // Test avec prescaler = 256 ( lent )
21 testPrescaler (256 , " Prescaler 256 " ) ;
22 }
23
24 void testPrescaler ( int prescaler , String nom ) {
25 TCNT1 = 0; // Reset compteur
26
27 // Configure le prescaler
28 if ( prescaler == 1) TCCR1B = (1 << CS10 ) ;
29 else if ( prescaler == 8) TCCR1B = (1 << CS11 ) ;
30 else if ( prescaler == 256) TCCR1B = (1 << CS12 ) ;
31
32 unsigned long debut = millis () ;
33
34 // Attendre que le compteur atteigne 10000
35 while ( TCNT1 < 10000) ;
36
37 unsigned long duree = millis () - debut ;
38
39 Serial . print ( nom ) ;
40 Serial . print ( " : " ) ;
41 Serial . print ( duree ) ;
42 Serial . println ( " ms pour atteindre 10000 " ) ;
43
44 // Calcul t h o r i q u e
45 float theorique = (10000.0 * prescaler ) / 16000.0;
46 Serial . print ( " T h o r i q u e : " ) ;
47 Serial . print ( theorique ) ;
48 Serial . println ( " ms " ) ;
49 Serial . println () ;
50 }
51
52 void loop () {
53 // Vide
54 }
Listing 9 – Test des différents prescalers
Résultats attendus :
— Prescaler 1 : 0.6 ms
— Prescaler 8 : 5 ms
— Prescaler 256 : 160 ms
Ce que tu apprends : 8
— Plus le prescaler est grand, plus le comptage est lent
— Le prescaler permet d’adapter la vitesse à ton besoin
7.3 Exercice Base 3 : Mode CTC - Compare Match
Objectif : Comprendre le mode CTC (Clear Timer on Compare) qui réinitialise automati-
quement le compteur.
Concept clé : Au lieu d’attendre l’overflow (65535), on peut définir notre propre TOP.
Niveau : Débutant
Solution
1 const int LED_PIN = 13;
2 volatile bool ledState = false ;
3
4 void setup () {
5 pinMode ( LED_PIN , OUTPUT ) ;
6
7 // Configuration Timer1 en mode CTC
8 TCCR1A = 0;
9 TCCR1B = 0;
10 TCNT1 = 0;
11
12 // Mode CTC : le compteur va de 0 OCR1A puis reset
13 TCCR1B = (1 << WGM12 ) ; // Mode CTC
14
15 // Prescaler 256
16 TCCR1B |= (1 << CS12 ) ;
17
18 // Pour 500 ms : (16 MHz / 256) 0.5 s = 31250
19 OCR1A = 31249; // Compare Match 31250
20
21 // Active l ’ interruption Compare Match
22 TIMSK1 = (1 << OCIE1A ) ;
23
24 sei () ;
25 }
26
27 void loop () {
28 // Programme libre
29 }
30
31 // Interruption a p p e l e quand TCNT1 == OCR1A
32 ISR ( T IMER1_CO MPA_vect ) {
33 ledState = ! ledState ;
34 digitalWrite ( LED_PIN , ledState ) ;
35 }
Listing 10 – LED qui clignote exactement toutes les 500ms
Différence avec l’overflow :
— Overflow : toujours à 65535 (fixe)
— CTC : tu choisis la valeur (flexible)
Ce que tu apprends :
— Le mode CTC permet un contrôle précis du timing
— OCR1A définit quand l’interruption se déclenche
— Le compteur reset automatiquement à OCR1A
7.4 Exercice Base 4 : Lire le compteur en temps réel
Objectif : Observer comment le compteur augmente en temps réel.
9
Concept clé : TCNT est un registre qu’on peut lire à tout moment.
Niveau : Très débutant
Solution
1 void setup () {
2 Serial . begin (9600) ;
3
4 // Configure Timer1 en mode normal
5 TCCR1A = 0;
6 TCCR1B = 0;
7 TCNT1 = 0;
8
9 // Prescaler = 256 ( pour voir le comptage )
10 TCCR1B = (1 << CS12 ) ;
11
12 Serial . println ( " Observation du compteur Timer1 " ) ;
13 Serial . println ( " Prescaler = 256 " ) ;
14 Serial . println () ;
15 }
16
17 void loop () {
18 // Lit la valeur actuelle du compteur
19 uint16_t valeur = TCNT1 ;
20
21 Serial . print ( " TCNT1 = " ) ;
22 Serial . print ( valeur ) ;
23
24 // Calcul du temps coul
25 float temps_ms = ( valeur * 256.0) / 16000.0;
26 Serial . print ( " | Temps : " ) ;
27 Serial . print ( temps_ms , 2) ;
28 Serial . println ( " ms " ) ;
29
30 delay (100) ;
31 }
Listing 11 – Affichage du compteur
Ce que tu observes :
— Le compteur augmente automatiquement
— Il reset à 0 après 65535 (overflow)
— Le comptage continue même pendant delay()
Ce que tu apprends :
— TCNT est accessible en lecture à tout moment
— Le Timer fonctionne indépendamment du programme
— On peut convertir TCNT en temps réel
7.5 Exercice Base 5 : PWM manuel (sans mode automatique)
Objectif : Créer un PWM "à la main" pour comprendre ce que le Timer fait automatique-
ment.
Concept clé : Le PWM n’est qu’une comparaison : si compteur < seuil → HIGH, sinon →
LOW.
Niveau : Intermédiaire
10
Solution
1 const int LED_PIN = 9;
2 const uint16_t TOP = 1999; // F r q u e n c e : 16 MHz /(1 2000 ) = 8 kHz
3 const uint16_t DUTY = 600; // 30% de 2000
4
5 void setup () {
6 pinMode ( LED_PIN , OUTPUT ) ;
7
8 // Timer1 en mode normal ( pas de PWM auto )
9 TCCR1A = 0;
10 TCCR1B = 0;
11 TCNT1 = 0;
12
13 // Prescaler = 1
14 TCCR1B = (1 << CS10 ) ;
15
16 // Active interruption Compare Match A
17 OCR1A = DUTY ;
18 TIMSK1 = (1 << OCIE1A ) ;
19
20 sei () ;
21 }
22
23 void loop () {
24 // V r i f i e si overflow ( atteint TOP )
25 if ( TCNT1 >= TOP ) {
26 TCNT1 = 0; // Reset manuel
27 digitalWrite ( LED_PIN , HIGH ) ; // D b u t du cycle
28 }
29 }
30
31 // Quand compteur atteint DUTY
32 ISR ( T IMER1_CO MPA_vect ) {
33 digitalWrite ( LED_PIN , LOW ) ; // Fin de l ’ impulsion
34 }
Listing 12 – PWM manuel avec interruption
Comparaison avec PWM automatique :
1 // Ce que fait automatiquement le mode Fast PWM :
2 TCCR1A = (1 << COM1A1 ) | (1 << WGM11 ) ;
3 TCCR1B = (1 << WGM13 ) | (1 << WGM12 ) | (1 << CS10 ) ;
4 ICR1 = TOP ;
5 OCR1A = DUTY ;
6 // Et c ’ est tout ! Le hardware g r e le reste
Listing 13 – Version automatique équivalente
Ce que tu apprends :
— Le PWM est une comparaison répétée
— Le mode Fast PWM fait automatiquement ce que tu codes manuellement
— Apprécier la simplicité du mode automatique !
7.6 Exercice Base 6 : Mesurer une durée précise
Objectif : Utiliser un Timer comme chronomètre de haute précision.
Concept clé : Les Timers sont plus précis que millis() pour des mesures courtes.
Niveau : Débutant
11
Solution
1 void setup () {
2 Serial . begin (9600) ;
3
4 // Configure Timer1 : prescaler = 1
5 TCCR1A = 0;
6 TCCR1B = 0;
7 TCCR1B = (1 << CS10 ) ; // Chaque tick = 0.0625 s
8
9 Serial . println ( " Mesure du temps d ’ e x c u t i o n " ) ;
10 Serial . println () ;
11 }
12
13 void loop () {
14 // Reset le compteur
15 TCNT1 = 0;
16
17 // CODE MESURER
18 int resultat = 0;
19 for ( int i = 0; i < 1000; i ++) {
20 resultat += i ;
21 }
22
23 // Lit le compteur
24 uint16_t ticks = TCNT1 ;
25
26 // Conversion en microsecondes
27 // 1 tick = 1 / 16 MHz = 0.0625 s
28 float microsecondes = ticks * 0.0625;
29
30 Serial . print ( " Temps d ’ e x c u t i o n : " ) ;
31 Serial . print ( microsecondes , 2) ;
32 Serial . println ( " s " ) ;
33
34 Serial . print ( " Nombre de ticks : " ) ;
35 Serial . println ( ticks ) ;
36
37 delay (1000) ;
38 }
Listing 14 – Chronomètre précis
Applications :
— Optimisation de code
— Mesure de temps de réponse
— Debug de performances
Ce que tu apprends :
— Un Timer peut servir de chronomètre ultra-précis
— Résolution : 62.5 nanosecondes (avec prescaler=1) !
— Bien meilleur que millis() (résolution 1 ms)
8 Exercices pratiques avancés
8.1 Exercice 1 : Change la fréquence
Objectif : Passer de 8 kHz à 10 kHz sur Timer1
12
Indice : Utilise la formule : TOP = 16000000
Prescaler×Fréquence −1
Solution
1 // Formule : F r q u e n c e = 16 MHz / ( Prescaler ( TOP + 1) )
2 // 10 kHz = 16000000 / (1 ( TOP + 1) )
3 // TOP = 1600 - 1 = 1599
4
5 ICR1 = 1599; // Nouvelle f r q u e n c e = 10 kHz
6 // Ajuste aussi le duty cycle :
7 OCR1A = 480; // 30% de 1600
Listing 15 – Modification de la fréquence
8.2 Exercice 2 : Change le duty cycle
Objectif : Passer de 30% à 25%
Indice : OCR = TOP × Duty100Cycle
Solution
1 // 25% de 2000 = 500
2 OCR1A = 500; // Pin 11 = 25%
3 OCR1B = 500; // Pin 12 = 75% ( i n v e r s )
Listing 16 – Modification du duty cycle
8.3 Exercice 3 : PWM avec prescaler
Objectif : Génère un signal PWM de 500 Hz avec un duty cycle de 40% sur la pin 9 (Timer1)
en utilisant un prescaler de 8.
Données :
— Fréquence souhaitée : 500 Hz
— Duty cycle : 40%
— Prescaler : 8
— Horloge CPU : 16 MHz
Questions :
1. Calcule la valeur de TOP (ICR1)
2. Calcule la valeur de OCR1A pour 40%
3. Écris le code complet
13
Solution
Calculs :
16000000 16000000
TOP = −1= − 1 = 3999
8 × 500 4000
OCR1A = 4000 × 0.40 = 1600
1 void setup () {
2 pinMode (9 , OUTPUT ) ;
3
4 // Reset
5 TCCR1A = 0;
6 TCCR1B = 0;
7 TCNT1 = 0;
8
9 // Mode Fast PWM , mode 14
10 TCCR1A = (1 << COM1A1 ) | (1 << WGM11 ) ;
11 TCCR1B = (1 << WGM13 ) | (1 << WGM12 ) | (1 << CS11 ) ;
12 // ^
13 // Prescaler = 8
14
15 ICR1 = 3999; // TOP pour 500 Hz
16 OCR1A = 1600; // 40% duty cycle
17 }
18
19 void loop () {
20 // PWM automatique
21 }
Listing 17 – Configuration 500 Hz avec prescaler 8
8.4 Exercice 4 : Servomoteur avec Timer1
Objectif : Configure un signal PWM pour contrôler un servomoteur. Les servos utilisent
généralement :
— Fréquence : 50 Hz (période de 20 ms)
— Impulsion : 1 ms (0°) à 2 ms (180°)
Étapes :
1. Configure Timer1 pour générer 50 Hz sur la pin 9
2. Fais varier le duty cycle entre 1 ms et 2 ms avec un potentiomètre
3. Affiche l’angle correspondant sur le port série
14
Solution
Calculs :
16000000
TOP = − 1 = 39999
8 × 50
1 × 10−3 × 16 × 106
OCR pour 1 ms = = 2000
8
2 × 10−3 × 16 × 106
OCR pour 2 ms = = 4000
8
1 const int POT_PIN = A0 ;
2 const int SERVO_PIN = 9;
3 const uint16_t SERVO_MIN = 2000; // 1 ms 0
4 const uint16_t SERVO_MAX = 4000; // 2 ms 180
5
6 void setup () {
7 Serial . begin (9600) ;
8 pinMode ( SERVO_PIN , OUTPUT ) ;
9
10 // Configuration Timer1 pour 50 Hz
11 TCCR1A = 0;
12 TCCR1B = 0;
13 TCNT1 = 0;
14
15 TCCR1A = (1 << COM1A1 ) | (1 << WGM11 ) ;
16 TCCR1B = (1 << WGM13 ) | (1 << WGM12 ) | (1 << CS11 ) ;
17
18 ICR1 = 39999; // 50 Hz
19 }
20
21 void loop () {
22 int potValue = analogRead ( POT_PIN ) ;
23
24 // Convertir 0 -1023 en 2000 -4000 (1 ms -2 ms )
25 uint16_t pulseWidth = map ( potValue , 0 , 1023 ,
26 SERVO_MIN , SERVO_MAX ) ;
27 OCR1A = pulseWidth ;
28
29 // Convertir en angle (0 -180 )
30 int angle = map ( potValue , 0 , 1023 , 0 , 180) ;
31
32 Serial . print ( " Angle : " ) ;
33 Serial . print ( angle ) ;
34 Serial . println ( " " ) ;
35
36 delay (50) ;
37 }
Listing 18 – Contrôle de servomoteur
8.5 Exercice 5 : Génération de tonalité musicale
Objectif : Utilise Timer2 pour générer des notes musicales sur un buzzer piezo connecté à
la pin 11.
Fréquences des notes (en Hz) :
— Do (C4) : 262 Hz
— Ré (D4) : 294 Hz
— Mi (E4) : 330 Hz
15
— Fa (F4) : 349 Hz
— Sol (G4) : 392 Hz
Questions :
1. Écris une fonction jouerNote(int frequence) qui configure Timer2
2. Crée une mélodie simple (Do-Ré-Mi-Fa-Sol)
3. Chaque note dure 500 ms
16
Solution
1 const int BUZZER_PIN = 11;
2
3 // F r q u e n c e s des notes
4 const int NOTE_C4 = 262;
5 const int NOTE_D4 = 294;
6 const int NOTE_E4 = 330;
7 const int NOTE_F4 = 349;
8 const int NOTE_G4 = 392;
9
10 void setup () {
11 pinMode ( BUZZER_PIN , OUTPUT ) ;
12 }
13
14 void jouerNote ( int frequence ) {
15 // Calcul de TOP pour Timer2 ( prescaler = 8)
16 // TOP = 16000000 / (8 2 frequence ) - 1
17 int top = (16000000 / (8 * 2 * frequence ) ) - 1;
18
19 // Limite 8 bits (0 -255)
20 if ( top > 255) top = 255;
21 if ( top < 0) top = 0;
22
23 // Configuration Timer2
24 TCCR2A = 0;
25 TCCR2B = 0;
26 TCNT2 = 0;
27
28 // Mode CTC avec toggle sur OC2A
29 TCCR2A = (1 << COM2A0 ) | (1 << WGM21 ) ;
30 TCCR2B = (1 << CS21 ) ; // Prescaler = 8
31
32 OCR2A = top ;
33 }
34
35 void arreterNote () {
36 TCCR2A = 0;
37 TCCR2B = 0;
38 }
39
40 void loop () {
41 // Joue Do - R - Mi - Fa - Sol
42 jouerNote ( NOTE_C4 ) ;
43 delay (500) ;
44
45 jouerNote ( NOTE_D4 ) ;
46 delay (500) ;
47
48 jouerNote ( NOTE_E4 ) ;
49 delay (500) ;
50
51 jouerNote ( NOTE_F4 ) ;
52 delay (500) ;
53
54 jouerNote ( NOTE_G4 ) ;
55 delay (500) ;
56
57 arreterNote () ;
58 delay (1000) ; // Pause avant de recommencer
59 }
Listing 19 – Générateur de tonalités
Défi bonus : Modifie le code pour jouer "Au clair de la lune" !
17
9 Antisèche (Cheat Sheet)
9.1 Formules essentielles
Formules clés
Horloge CPU
Fréquence PWM =
Prescaler × (TOP + 1)
OCRx
Duty Cycle (%) = × 100
TOP
Horloge CPU
TOP = −1
Prescaler × Fréquence
9.2 Prescalers disponibles
Timer Prescaler disponibles
Timer0 1, 8, 64, 256, 1024
Timer1 1, 8, 64, 256, 1024
Timer2 1, 8, 32, 64, 128, 256, 1024
Table 2 – Prescalers par Timer
9.3 Pins PWM par Timer
Timer Pins Arduino Registres OCR
Timer0 5, 6 OCR0A, OCR0B
Timer1 9, 10 OCR1A, OCR1B
Timer2 3, 11 OCR2A, OCR2B
Table 3 – Correspondance Timers-Pins
Attention
Pin 11 peut être Timer1 OU Timer2 selon la carte !
10 Stratégie d’apprentissage
10.1 Pour bien comprendre, suis cette méthode
1. Commence simple :
1 // PWM basique sur pin 9
2 analogWrite (9 , 128) ; // 50% duty cycle
3
Listing 20 – PWM basique
2. Passe aux Timers :
— Utilise l’exemple de la section 5
18
— Change UNE valeur à la fois (fréquence, duty cycle)
— Observe les résultats avec un oscilloscope ou Proteus
3. Expérimente :
— Fais les exercices de la section 7
— Compare Timer1 (16 bits) vs Timer2 (8 bits)
— Essaie différents prescalers
4. Comprends TON code :
— Reprends ton code de TP
— Explique chaque ligne à voix haute
— Dessine le schéma temporel sur papier
11 Ressources supplémentaires
11.1 Documentation officielle
— Arduino Timer Reference : https://www.arduino.cc/en/Tutorial/SecretsOfArduinoPWM
— ATmega328P Datasheet (Chapitres 14-16)
11.2 Outils utiles
— Calculateur en ligne : AVR Timer Calculator
— Proteus : Pour visualiser les signaux PWM
— Oscilloscope (ou virtuel) : Pour mesurer la fréquence réelle
Mon conseil perso
Ne cherche PAS à tout comprendre d’un coup !
— Jour 1 : Lis les sections 1-3
— Jour 2 : Teste l’exemple de la section 5
— Jour 3 : Fais les exercices de la section 7
— Jour 4 : Décortique ton code de TP
12 En résumé : Les 5 étapes clés
1. Reset les registres : TCCRxA = 0; TCCRxB = 0;
2. Choisis le mode : Fast PWM, Phase Correct, etc.
3. Règle le prescaler : Pour ajuster la fréquence
4. Définis TOP : Pour fixer la fréquence exacte
5. Ajuste OCR : Pour le duty cycle
Et c’est tout ! Le Timer fait le reste automatiquement.
19