Configuration du minuteur T0 sur microcontrôleur STC15 : Temporisation précise de 1 ms avec un oscillateur à 11,0592 MHz

Architecture de l'horloge et principes du minuteur

Le microcontrôleur STC15, basé sur une architecture 8051 améliorée, introduit le mode 1T où un cycle machine correspond à un seul cycle d'horloge. Cette architecture accélère l'exécution par rapport aux modèles 12T traditionnels, mais nécessite une recalibration des paramètres de temporisation. L'utilisation d'un oscillateur externe de 11,0592 MHz est privilégiée car elle permet de générer des vitesses de transmission (baud rates) sans erreur pour les communications UART, tout en offrant une base de temps stable pour les minuteurs.

Le fonctionnement du Timer 0 (T0) repose sur la manipulation de trois registres principaux :

  • TMOD : Définit le mode de fonctionnement (GATE, C/T, M1, M0).
  • AUXR : Registre auxiliaire contrôlant le prédiviseur (bit T0x12 pour le choix 1T/12T).
  • TCON : Registre de contrôle gérant le démarrage (TR0) et le drapeau de débordement (TF0).

Le mode 0 (rechargement automatique 16 bits) est optimal pour des interruptions périodiques. La valeur initiale à charger dans les registres TH0 et TL0 se calcule selon la formule suivante :

Valeur_Initiale = 65536 - (Fréquence_Oscillateur / (Prédiviseur * Fréquence_Cible))

Pour une interruption de 1 ms (1000 Hz) avec un cristal de 11,0592 MHz en mode 1T (prédiviseur = 1), le calcul exact donne : 65536 - (11059200 / 1000) = 54477.

Implémentation de la configuration

L'initialisation du minuteur nécessite la configuration séquentielle des registres, le chargement de la valeur de rechargement et l'activation de la chaîne d'interruptions.

#include <reg51.h>
#include <stdint.h>

#define SYS_CLK 11059200UL
#define TIMER_RELOAD_VAL (65536UL - (SYS_CLK / 1000))

void init_timer0_1ms(void) {
    // Configuration du mode 0 (16 bits avec rechargement automatique)
    TMOD = (TMOD & 0xF0) | 0x00; 
    
    // Activation du mode 1T pour le Timer 0 via le bit T0x12
    AUXR |= 0x80; 
    
    // Chargement de la valeur initiale calculée
    TH0 = (uint8_t)(TIMER_RELOAD_VAL >> 8);
    TL0 = (uint8_t)(TIMER_RELOAD_VAL & 0xFF);
    
    // Activation des interruptions
    ET0 = 1;  // Autorisation de l'interruption T0
    EA = 1;   // Autorisation globale des interruptions
    TR0 = 1;  // Démarrage du compteur
}

La routine de service d'interruption (ISR) doit être concise pour éviter de bloquer l'exécution du programme principal. Voici une implémentation gérant une base de temps d'une seconde :

volatile uint16_t tick_counter = 0;
sbit LED_STATUS = P5^5;

void isr_timer0_handler(void) interrupt 1 {
    tick_counter++;
    
    if (tick_counter >= 1000) {
        tick_counter = 0;
        LED_STATUS = ~LED_STATUS; // Basculement de l'état de la LED
    }
}

Ordonnancement multi-tâches et optimisations

Pour gérer plusieurs événements périodiques sans multiplier les minuteurs matériels, un ordonnanceur logiciel basé sur le tick de 1 ms peut être implémenté à l'aide de structures de données.

typedef struct {
    uint16_t interval_ms;
    uint16_t current_tick;
    void (*callback)(void);
} SoftTimer;

void task_sensor_read(void);
void task_comms_update(void);

SoftTimer scheduler[] = {
    {100, 0, task_sensor_read},   // Exécution toutes les 100 ms
    {250, 0, task_comms_update}   // Exécution toutes les 250 ms
};

#define NUM_TASKS (sizeof(scheduler) / sizeof(scheduler[0]))

void isr_timer0_handler(void) interrupt 1 {
    uint8_t i;
    for (i = 0; i < NUM_TASKS; i++) {
        scheduler[i].current_tick++;
        if (scheduler[i].current_tick >= scheduler[i].interval_ms) {
            scheduler[i].current_tick = 0;
            scheduler[i].callback();
        }
    }
}

Dans les applications sur batterie, la gestion de l'énergie est cruciale. Le minuteur peut être utilisé pour réveiller le microcontrôleur du modeIdle (veille) :

TR0 = 0;       // Suspension du minuteur
PCON |= 0x01;  // Entrée en mode Idle (le CPU s'arrête, les périphériques tournent)
// Le réveil s'effectuera automatiquement lors du prochain débordement de T0

Applications avancées et dépannage

Le Timer 0 peut également être reconfiguré en compteur d'événements externes. En définissant le bit C/T dans TMOD, le minuteur incrémente sur chaque front descendant détecté sur la broche T0 (P3.4). La largeur de l'impulsion doit impérativement dépasser deux cycles machine pour être enregistrée de manière fiable.

// Configuration en compteur d'impulsions 16 bits
TMOD = (TMOD & 0xF0) | 0x05; 
TH0 = 0x00;
TL0 = 0x00;
TR0 = 1;

Lors de l'intégration avec d'autres périphériques, le Timer 0 sert souvent de base de temps pour la génération de signaux PWM logiciels ou pour déclencher des conversions ADC périodiques. Pour éviter les erreurs de calcul de débordement liées aux types de données lors de la définition des constantes, l'utilisation de macros avec le suffixe UL (Unsigned Long) est fortement recommandée :

#define T0_1MS_RELOAD (65536UL - (SYS_CLK / 1000UL))

// Assignation sécurisée évitant les troncatures 8 bits
TH0 = (uint8_t)((T0_1MS_RELOAD >> 8) & 0xFF);
TL0 = (uint8_t)(T0_1MS_RELOAD & 0xFF);

Étiquettes: STC15 8051 Microcontrôleurs Timers EmbarquéC

Publié le 5 juillet à 21h15