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 PIC16F683 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).
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 PIC16F683. 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 |
#include <xc.h> #define _XTAL_FREQ 4000000 void main(void) { ANSEL = 0b00000000; TRISA = 0b11111110; // RA0 en sortie PORTA = 0; // Config Timer0 : horloge interne, prescaler 1:256 OPTION_REG = 0b00000111; // T0CS=0 (interne), PSA=0 (prescaler→Timer0) // PS2:PS0=111 (1:256) TMR0 = 0; // Initialiser le compteur while(1) { // Timer0 déborde toutes les ~65ms // (256 × 256 / 1MHz = 65.536ms) if(INTCONbits.T0IF) { INTCONbits.T0IF = 0; // Reset flag PORTA ^= 0b00000001; // Toggle LED } } }
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é |
// Timer1 : Fosc/4 = 1MHz, prescaler 1:8 // Fréquence comptage = 125 kHz → période = 8µs // Pour 500ms : 500000/8 = 62500 comptages // Valeur initiale = 65536 - 62500 = 3036 = 0x0BDC T1CON = 0b00110001; // Prescaler 1:8, ON TMR1H = 0x0B; TMR1L = 0xDC; while(!PIR1bits.TMR1IF); // Attendre overflow PIR1bits.TMR1IF = 0; // Reset flag
Timer0 (8 bits) : Simple, idéal pour des délais courts et des tâches de base. Déborde fréquemment (max ~65ms avec prescaler 256).
Timer1 (16 bits) : Plus polyvalent, permet des délais plus longs (jusqu'à ~524ms avec prescaler 8). 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