Ce Tutoriel est la suite du tuto N°7 avec un peu plus de précision.
Dans le précédent Tuto, nous avons créer une temporisation d'environ une seconde. Cette imprécision n'est pas forcement acceptable dans toutes les circonstances . Pour corriger ce problème , il va falloir peaufiner notre initialisation de Timer.
Objectif :
- faire une temporisation de 1 seconde précise avec le Timer0 , en jouant sur la valeur d’initialisation.
Pour bien comprendre :
Reprenons notre exemple , comme quoi, notre µC fonctionne à 1Hz . donc 1 instruction/seconde.
Imaginons que nous souhaitions une temporisation de 10 secondes . Plusieurs solutions s'offre à nous :
1/ la première que nous utiliserons jamais et vous allez comprendre pourquoi. Il s'agirait de regarder à chaque instructions la valeur de notre compteur. ça donnerai :
- instruction
- lire notre timer (timer=1): si égale à 10 on fait une tâche
- instruction
- lire notre timer (timer=2) : si égale à 10 on fait une tâche
|
|
|
|
- instruction
- lire notre timer (timer=10) : si égale à 10 on fait une tâche
On voit bien que lire en permanence la valeur de notre Timer serait complétement idiot et pas du tout fonctionnel.
2/ La deuxième , que vous utiliserez je n'en doute pas.
On va utiliser ce fameux Flag. Plutôt que de scruter le Timer en permanence, nous allons utilisez l'interruption de débordement et son drapeau. Mais!, me direz vous le drapeau ne se lève que quand le compteur atteint 255 et repasse à 0 . Donc il ne se lève que toutes les 255 secondes Et oui vous avez raison et compris c'est un bon point !
Pour ce faire nous allons initialiser notre TMR avec une valeur de départ . C'est ici ou se trouve toute la subtilité qu'il faut bien comprendre.
Comme on peut écrire sur notre Timer, on peut donc l’initialiser à 245 . alors quand il arrivera a 255 et lèvera son drapeau il se sera écoulé nos 10 secondes.
255-10 = 245 .
Sans vouloir vous découragez , et j’espère que vous l'aurez compris , je viens de réduire à sa plus simple expression l'utilisation d'un Timer. Ainsi j’espère que vous aurez compris le principe de fonctionnement général .
revenons à nos moutons et à notre compteur de 1seconde.
Pour RAPPEL :
Avec la configuration précédente nous obtenions 1.015 s . c'est à dire 15ms de trop.
Nous avions :
- une instruction toutes les 128µs.
- 1 débordement tous les = 128*256=32,768 ms
En toute logique il va donc falloir retrancher ces 15ms . Commençons par ne pas dépasser les 1 seconde .
Donc au lieu de multiplié par 31 nous allons multiplié par 30.
30 x 32.768 = 983.04 ms
il nous manque donc 16.96 ms pile poil.
en sachant qu'une instruction dure 128µs il nous faut donc combler ces 16.96ms avec autant d’instructions .
16,96ms = 16960µs
16960/128 = 132.5
Comme rien n'est simple, le fait de modifier notre Timer en initialisant une valeur au départ celui-ci nous prends 2 instructions . Donc c'est 130.5 instructions qu'il faut pour bien combler.
Il nous faudra donc compter 130 instructions dans la première boucle au lieu de 255 quand on partait de zéro.
Comme dans notre exemple nous allons retrancher ces 130 instructions à notre compteur . donc 255 - 130 =125
Il faudra que notre compteur au départ soit initialisé à 125 au lieu de 0. Ainsi sa première boucle durera de 125 à 255 soit 130 instructions soit 130*128=16640 µs= 16.640ms
sans oublié de rajouter nos 2 instructions pour initialiser le TMR0 16640+128+128 = 16896µS
Pour résume une première boucle de comptage de 16.8960ms et 30 boucles de 32.768ms = 999.936 ms = 0.999936s .
On remarque que ça ne tombe pas pile poil. pour ne pas vous embrouiller, je ne recommencerai pas les Tuto, mais par contre vous pouvez vous entrainez en faisant un exercice pour tomber pile poil . soit en jouant sur le PRE-SCALER , soit en passant le compteur en 16bit .
Pour vérifier : 1s - 0.999936 = 0.000064 s soit 64µs de moins , cela correspond à une demi instruction ( 128/2=64) qu'on retrouve quand on a arrondi 130.5 à 130 .
Pour un bon programme il faudra bien sur tomber parfaitement sur le bon nombre d'instruction, sinon votre tempo se décale dans le temps. Si j'ai le temps je ferais la correction avec un exemple !
Code : Tout sélectionner
//################################# DECLARATION #########################################
char compteur = 0; // Déclaration de la variable compteur en char ( 0 à 255) et on l'initialise à 0 en même temps
//################################# FONCTION #########################################
void interrupt() { // Ici c'est notre fonction d'interruption
// On regarde quel drapeau a été mis à 1, pour connaitre la source de l'interutpion
if (INTCON.TMR0IF == 1) // Ici le bit TMR0IF (bit2) du registre INTCON est testé
{
++compteur; // On incremente notre compteur sur une interrutpion
INTCON.TMR0IF = 0; // IMPORTANT !!! On ré-arme notre drapeau en le remettant à 0
}
}
//######################### FONCTION PRINCIPALE ET CONFIGURATION #################################
void main() { // ceci contiendra notre programme, c'est la fonction principale(main) et elle est obligatoire.
ANSELC = 0; // Met le PORT C en numérique
PORTC = 0; // Affecte 0 au PORT C
TRISC = 0b00000000; // Place le PORT C en sortie pour afficher les leds
T0CON = 0b11000111 ; // Configuration du TIMER0
TMR0L = 125; // chargement de la valeur 125 dans le TIMER du bas
TMR0H = 0; // chargement de la valeur 0 dans le TIMER du haut
INTCON = 0b10100000; // Configuration de l'interruption
//################################# Boucle infinie #########################################
while(1) // Ici c'est notre boucle sans fin.
{
if (compteur == 31) // Si notre compteur d'interruption à atteint la valeur calculée de 31
{
PORTC = ~PORTC; // alors on inverse nos sorties
compteur = 0; // On remet à 0 notre compteur pour une nouvelle tempo
TMR0L = 125; // On re-initialisenotre compteur à la bonne valeur seulement pour la premiere boucle
}
}
} // Fin de notre fonction principale, la boucle est bouclée
Attention La temporisation parfaite :