Créez des délais précis avec les compteurs matériels du PIC
Un Timer (ou compteur) est un périphérique matériel intégré au microcontrôleur qui compte les impulsions d'horloge de manière autonome, sans intervention constante du processeur. Cela permet de créer des délais précis, de mesurer des durées, ou de générer des événements périodiques.
Le PIC16F877A dispose de trois timers : le Timer0 (8 bits), le Timer1 (16 bits) et le Timer2 (8 bits, très utile avec le PWM). Chaque timer a ses propres registres et usages selon le projet.
L'avantage principal des timers par rapport à __delay_ms() est qu'ils fonctionnent en arrière-plan. Le processeur peut exécuter d'autres tâches pendant que le timer compte, ce qui est essentiel dans les applications temps réel.
Le Timer0 est le timer le plus simple du PIC16F877A. Il utilise un registre 8 bits (TMR0) qui s'incrémente à chaque cycle d'horloge (ou via une source externe).
| Registre | Bit | Fonction |
|---|---|---|
| OPTION_REG | T0CS (bit 5) | Source : 0 = horloge interne, 1 = signal externe (T0CKI) |
| OPTION_REG | PSA (bit 3) | Prescaler : 0 = assigné au Timer0, 1 = assigné au WDT |
| OPTION_REG | PS2:PS0 (bits 2-0) | Valeur du prescaler : 000=1:2, 001=1:4, ... 111=1:256 |
| INTCON | T0IF (bit 2) | Flag d'overflow : passe à 1 quand TMR0 déborde (255→0) |
| INTCON | T0IE (bit 5) | Active l'interruption Timer0 |
Avec Fosc = 4 MHz et un prescaler 1:256, un overflow complet de Timer0 dure environ 65,536 ms. Si tu bascules une LED à chaque overflow, elle va clignoter rapidement : c’est normal.
#include <xc.h> #define _XTAL_FREQ 4000000 // PIC16F877A : LED sur RB0 void main(void) { ADCON1 = 0x06; // Configure les broches analogiques en numérique TRISB = 0b11111110; // RB0 en sortie, le reste en entrée PORTB = 0; // Timer0 : horloge interne (Fosc/4), prescaler 1:256 OPTION_REG = 0b00000111; TMR0 = 0; INTCONbits.T0IF = 0; while(1) { if(INTCONbits.T0IF) { INTCONbits.T0IF = 0; // Reset overflow PORTB ^= 0b00000001; // Toggle RB0 } } }
Le Timer1 offre une plage de comptage beaucoup plus grande (0 à 65535) grâce à ses deux registres 8 bits : TMR1H (octet haut) et TMR1L (octet bas). Il est très utile pour générer des délais plus longs ou plus précis.
| Bit | Nom | Fonction |
|---|---|---|
| 5-4 | T1CKPS | Prescaler : 00=1:1, 01=1:2, 10=1:4, 11=1:8 |
| 3 | T1OSCEN | Oscillateur Timer1 activé |
| 2 | T1SYNC | Synchronisation externe |
| 1 | TMR1CS | Source : 0 = Fosc/4, 1 = externe |
| 0 | TMR1ON | 1 = Timer1 activé |
#include <xc.h> #define _XTAL_FREQ 4000000 // PIC16F877A - Timer1 : Fosc=4MHz => Fosc/4 = 1MHz // Prescaler 1:8 => tick = 8µs // 500ms => 500000/8 = 62500 ticks // Précharge = 65536 - 62500 = 3036 = 0x0BDC void main(void) { ADCON1 = 0x06; TRISB = 0b11111110; PORTB = 0; PIR1bits.TMR1IF = 0; // T1CKPS=11 (1:8), TMR1CS=0 (Fosc/4), TMR1ON=1 T1CON = 0b00110001; TMR1H = 0x0B; TMR1L = 0xDC; while(!PIR1bits.TMR1IF); PIR1bits.TMR1IF = 0; // Exemple : toggle LED RB0 après 500ms PORTB ^= 0b00000001; while(1) { // boucle vide } }
Le Timer2 est un timer 8 bits particulièrement utile pour les signaux périodiques et pour piloter le PWM avec les modules CCP du PIC16F877A.
| Bit | Nom | Fonction |
|---|---|---|
| 6-3 | TOUTPS3:TOUTPS0 | Postscaler (1:1 à 1:16) |
| 2 | TMR2ON | 1 = Timer2 activé |
| 1-0 | T2CKPS1:T2CKPS0 | Prescaler : 00=1:1, 01=1:4, 1x=1:16 |
Le Timer2 est souvent le meilleur choix quand tu veux générer une période stable pour du PWM ou des interruptions régulières rapides.
Formule générale pour calculer le temps de débordement :
// Temps = (Valeur_max - Valeur_initiale) × Prescaler × (4 / Fosc) // // Timer0 (8 bits, Fosc=4MHz, prescaler=256) : // Temps = 256 × 256 × (4/4000000) = 65.536 ms // // Timer1 (16 bits, Fosc=4MHz, prescaler=8) : // Temps max = 65536 × 8 × (4/4000000) = 524.288 ms
Timer0 (8 bits) : Simple, idéal pour des délais courts et des tâches de base.
Timer1 (16 bits) : Plus précis et permet des délais plus longs.
Timer2 (8 bits) : Très pratique pour le PWM et les événements périodiques rapides.