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 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 PIC12F683 dispose de deux timers : le Timer0 (8 bits, compte de 0 à 255) et le Timer1 (16 bits, compte de 0 à 65535). Chaque timer peut fonctionner en mode timer (horloge interne) ou en mode compteur (signal externe), selon la configuration.
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 pour les applications temps réel.
Le Timer0 est le timer le plus simple du PIC12F683. Il utilise un registre 8 bits (TMR0) qui s'incrémente à chaque cycle d'horloge (ou chaque front du signal 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. Donc si tu “toggle” une LED à chaque overflow, elle va clignoter assez vite : c’est normal.
#include <xc.h> #define _XTAL_FREQ 4000000 // PIC12F683 : LED sur GP0 void main(void) { ANSEL = 0b00000000; // Tout en numérique (important) CMCON0 = 0b00000111; // Désactive comparateurs TRISIO = 0b00001000; // GP3 entrée (souvent), le reste en sortie GPIO = 0; // Timer0 : horloge interne (Fosc/4), prescaler 1:256 // 0b00000111 -> T0CS=0, PSA=0, PS=111 OPTION_REG = 0b00000111; TMR0 = 0; INTCONbits.T0IF = 0; while(1) { if(INTCONbits.T0IF) { INTCONbits.T0IF = 0; // Reset overflow GPIO ^= 0b00000001; // Toggle GP0 } } }
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 peut aussi utiliser un cristal externe 32.768 kHz pour un comptage très précis.
| Bit | Nom | Fonction |
|---|---|---|
| 7 | T1GINV | Inversion du gate |
| 6 | TMR1GE | Gate enable |
| 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 // PIC12F683 - 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) { ANSEL = 0; CMCON0 = 0b00000111; TRISIO = 0b00001000; GPIO = 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 GP0 après 500ms GPIO ^= 0b00000001; while(1) { // boucle vide } }
Timer0 (8 bits) : Simple, idéal pour des délais courts et des tâches de base. Déborde fréquemment (max ~65,536ms avec prescaler 256).
Timer1 (16 bits) : Plus polyvalent, permet des délais plus longs (jusqu'à ~524,288ms avec prescaler 8 à 4MHz). Peut utiliser un cristal externe pour une précision maximale.
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