Il
est fréquent d´avoir à “attendre” durant le fonctionnement
d´un programme un certain “délai”, c´est-à-dire
d´effectuer une pause avant de continuer les traitements.
Ce délai
est en général définit comme un minimum, par
exemple “attendre au moins 5 mS”
On présentera
dans ce premier chapitre de la logithèque PicTrain comment
obtenir ces délais d´une manière simple et standardisée
par l´introduction de boucles mettant un temps déterminé pour
s´exécuter.
Remarque :
ce que nous appelons “délai” est souvent appelé dans
la littérature “tempo” pour temporisation, mais on parle de
la même chose.
Remarque importante :
il s´agit ici de “délai”, c´est-à-dire
de la possibilité d´interrompre occasionnellement le
programme durant un temps déterminé. Il n´est
pas question de génération de signal périodique
de fréquence donnée, comme abordé dans PicTrain2,
et qui s´obtient en utilisant les Timer0 et Timer1 avec
prédiviseur.
|
B1.1.1.
Horloge et cycle |
Dans nos montages PicTrain,
nous utilisons toujours l´horloge interne du PIC, qui fonctionne à la
vitesse de 4 MHz (Fosc =
fréquence oscillateur).
Ces PIC peuvent
tourner jusqu´à 20 MHz, mais avec un oscillateur
externe. Petite curiosité, ils peuvent aussi tourner plus
lentement, sans limite, on pourrait faire tourner un PIC avec une
horloge à 1 Hz, même si cela ne présente
pas beaucoup d´intérêt.
Un cycle de programme
est toujours égal à Fosc/4, c´est-à-dire
que dans notre cas d´horloge à 4 MHz, le programme
s´exécute à 1 MHz, c´est-à-dire
que les instructions de notre programme s´exécutent
toujours à la vitesse de :
  1 cycle
(1 microseconde, écrit µS en abrégé ou
uS sur le web) pour toutes les instructions, sauf
  Les
instructions incluant un débranchement : call,
goto, return, retlw, retfie, qui utilisent toujours 2 cycles,
  Et
les instructions de test qui utilisent un cycle si le résultat
du test est négatif (faux) et deux cycles s´il est positif
(vrai) : decfsz, incfsz, btfsc,
btfss
En d´autres
termes, une instruction coûte toujours un cycle, plus un cycle
supplémentaire s´il y a débranchement dans le
programme.
En appliquant
ces règles, on voit donc que l´on peut calculer très
précisément la durée d´un morceau de programme,
et on va utiliser cette possibilité pour calculer nos délais.
|
B1.1.2.
Instruction NOP |
L´instruction NOP est
une instruction qui ne fait rien (NOP = no operation).
Cela peut paraître
idiot, une instruction qui ne fait rien, mais l´important est
qu´elle “consomme” un cycle d´horloge. On va donc souvent
s´en servir dans la programmation de nos délais.
Cas simple, si
vous voulez obtenir un délai de 5 microsecondes entre
deux instructions, vous mettez 5 instructions NOP entre
les deux instructions.
|
B1.1.3.
ATTENTION : Interruptions |
Tous les calculs
sur les délais présentés ci-après ne
sont valables que si aucune interruption n´est utilisée
dans votre programme. Par exemple, dans le programme PicTrain2 on
utilise l´interruption Timer0 pour
générer un signal de sortie à 240 Hz.
Si par hasard
une interruption se déclenche pendant l´exécution
de la boucle de délai, la durée de la boucle sera augmentée
du temps de traitement de l´interruption.
En bref, si vous
voulez obtenir un délai précis et sans surprises, il
faut suspendre les interruptions pendant ce temps.
|
B1.2.1.
Délai de base : 100 micro secondes |
La brique de base
pour obtenir les délais est un délai de 100 microsecondes,
c´est-à-dire de 100 cycles d´horloge :

Remarque :
l´expression “$-1” est une
facilité d´écriture de MPLAB qui permet, lors
d´un débranchement, d´aller à une adresse
de programme proche (ici la précédente) sans utiliser
d´étiquette.
Remarque :
le registre VA_CPT_delai1 doit être
défini dans les registres généraux.
Instruc-
tion |
Nb de cycles |
|
Détail |
Total |
call |
2 |
2 |
Appel du délai dans le programme principal |
movlw |
1
 |
11
 |
|
movwf |
1 |
1 |
|
 |
Les deux instructions suivantes sont exécutées
30 fois |
decfsz |
1 |
30 |
|
goto |
2 |
60 |
|
|
Au 31 passage,
il y a débranchement |
decfsz |
1 |
2 |
decfsz consomme 2 cycles (débranchement), mais le
goto n´est pas exécuté |
nop |
1 |
1 |
Ne font rien, mais consomment deux cycles supplémentaires
pour obtenir 100 |
nop |
1 |
1 |
return |
2 |
2 |
|
Entre le call initial
et le retour à l´instruction après le call le
PIC a exécuté exactement 100 cycles, soit 100 microsecondes.
|
B1.2.2.
Délai d´une milliseconde |
Ce délai
peut être obtenu de deux manières différentes :
  Au
moins une milliseconde : on appelle 10 fois de délai
de 100 µS, mais avec les instructions de commande, on
obtiendra un tout petit peu plus que une milliseconde,
  Exactement
une milliseconde.
|
B1.2.2.1.
Au moins 1 mS |
Dans ce cas, nous
allons réutiliser le sous-programme de 100 µS défini
précédemment :


Instruc-
tion |
Nb de cycles |
|
Détail |
Total |
call |
2 |
2 |
Appel du délai dans le programme principal |
movlw |
1
 |
1
 |
|
movwf |
1 |
1 |
|
 |
Les trois instructions suivantes sont exécutées
9 fois |
call |
100 |
900 |
|
decfsz |
1 |
9 |
|
goto |
2 |
18 |
|
|
Au 10 cycle |
call |
100 |
100 |
|
decfsz |
2 |
2 |
Au 10 passage,
decfsz consomme 2 cycles (débranchement), mais le goto
n'est pas exécuté |
return |
2 |
2 |
|
Le total est
de 1035 cycles, soit 1,035 milliseconde, ce qui est en
général suffisant comme approximation pour la plupart
des applications.
|
B1.2.2.2.
Exactement 1 mS |
Notre boucle de
base durant 3 µS, il nous faut l´exécuter
approximativement 1000/3 = 333 fois. En tenant compte des
instructions d´appel et de chargement, on obtient le sous-programme
suivant, avec 331 exécutions :

Comme nos compteurs
ne vont que jusqu´à 256, il faut faire une première
boucle avec 256 passages, puis une deuxième avec 75.
Instruc-
tion |
Nb de cycles |
|
Détail |
Total |
call |
2 |
2 |
Appel du délai dans le programme principal |
clrf |
1
 |
1
 |
|
 |
Les deux instructions suivantes sont exécutées
255 fois |
decfsz |
1 |
255 |
|
goto |
2 |
510 |
|
|
Au 256 cycle,
il y a débranchement |
decfsz |
1 |
2 |
decfz consomme 2 cycles (débranchement) mais le goto
n'est pas exécuté |
movlw |
1 |
1 |
|
movwf |
1 |
1 |
|
 |
Les deux instructions suivantes sont exécutées
74 fois |
decfsz |
1 |
74 |
|
goto |
2 |
148 |
|
 |
Au 75 passage,
il y a débranchement |
decfsz |
1 |
2 |
decfz consomme 2 cycles (débtranchement) mais le goto
n'est pas exécuté |
nop
nop |
1
1 |
1
1
|
ne font rien mais consomment deux cycles supplémentaires
pour obtenir 1000 |
return |
2 |
2 |
|
|
B1.2.3.
Délai : 1 seconde |
Une seconde représentant
1 000 000 cycles, il est nécessaire d´utiliser
d´autres tailles de boucle pour “consommer” ce temps. Même
une “méga boucle” de 256 x 256 x 3 ne
fait que 196 608 cycles, il faudra donc l´exécuter
au moins cinq fois.

En appliquant
les règles sur chacune des boucles, on obtient les résultats
suivants :
  boucle
1 : 3 * 256 — 1 = 767
  boucle
2 : 256 * boucle 1 + 3 * 256 — 1 = 197 119
  boucle
3 : 5 * boucle 2 + 3 * 5 — 1 = 985 609
Avec les autres
instructions le total est de 985 617, soit pratiquement 0,98 seconde,
ce qui est une très bonne approximation. Si vous voulez obtenir
une seconde exactement, il vous faudra ajouter une boucle supplémentaire
pour consommer les 15 000 cycles qui manquent (je vous
laisse le faire !).
 |
PTI+ HORLOGE !
Ce n´est pas comme cela que l´on construit
une montre ! Pour ce faire, il faut générer
un signal d´une fréquence donnée,
et donc utiliser les timers. Par ailleurs, pour
simplifier les calculs ont utilise généralement
dans ce cas un oscillateur externe avec un quartz
adaptés, par exemple de 3,670016 MHz,
qui nous donne exactement 256*256*14*4. |
|
|
|
B1.2.4.
Délai variable |
En partant des
sous-programmes ci-dessus, on peut aussi obtenir des délais
variables, par exemple de N fois 100 microsecondes.
Si nous déplaçons
la chargement initial du compteur dans l´appel du sous-programme
comme suit :

 
le délai
résultant (en microsecondes) est de 6 + N * (100 + 3) — 1,
par exemple :
  N=3 :
315
  N=10 :
1 035 (heureusement identique à notre sous-programme
précédent)
  N=97 :
9 996 soit pratiquement 10 ms
  N=194 :
19 987 soit pratiquement 20 ms
On peut donc choisir
au moment de l´appel la valeur du délai entre 108 et
26 373 microsecondes (N =1 à N =0, c´est-à-dire
256).
|
B1.2.5.
Durée d´exécution |
Dans tout ce que
nous avons vu ci-dessus, nous n´avons tenu compte dans nos
calculs que du temps d´exécution du sous-programme “délai” lui-même.
Si vous voulez
exécuter une action à un intervalle régulier,
par exemple allumer/éteindre une led toutes les secondes,
il faut ajouter au délai le temps d´exécution
du programme d´allumage/extinction lui-même. Dans ce
cas, il ne s´agit que de quelques µS, et cela ne change
pas fondamentalement le résultat.
Si par contre
vous voulez exécuter toutes les millisecondes un morceau de
programme qui lui-même prend 500 microsecondes, le total
sera de 1 500 microsecondes, soir une durée supérieure
de 50 %.
Même si
je me répète, pour obtenir une périodicité (fréquence),
il ne faut pas utiliser cette méthode, mais utiliser les interruptions.
Les délais
sont à réserver vraiment aux “pauses”, c´est-à-dire
aux interruptions ponctuelles. C´est pour cela aussi qu´en
général on parle de délai “d´au moins
NµS”, car seul le minimum est garanti, le délai maximum
peut varier.
Nous verrons les
utilisations plus concrètes avec d´autres briques de
la Briquothèque, comme le
traitement des entrées (traitement
des rebonds) ou l´écriture
en mémoire EEPROM.
Tous les sous-programmes
ci-dessus ont été regroupés dans un fichier
.inc que vous devez intégrer
dans votre projet, pour ainsi utiliser directement tous les “briques”
contenues.
Pour utiliser
ces sous-programmes, il vous faut :
  copier
ce fichier “SP_delai_V1_1.inc” (disponible
ici) dans le répertoire de votre projet MPLAB (voir l´encadré
ci-dessous) ;
  placer
dans la partie “DÉCLARATIONS DE VARIABLES SPÉCIFIQUES” de
votre programme les réservations suivantes :
VA_CPT_delai1
VA_CPT_delai2
VA_CPT_delai3
  placer
en fin de votre programme, juste avant la commande END la
ligne suivante : #include <SP_delai_V1_1.inc>
Remarque :
fonctionnement de la commande #INCLUDE :
cette commande permet simplement d´insérer
dans votre programme les lignes de code contenues
dans le fichier “.inc”, à l´endroit
de cette commande. En d´autres termes, c´est
comme si vous faisiez un copier/coller du contenu
de ce fichier inc.
Cela veut dire
aussi que la taille de votre programme se trouve augmentée
du nombre d´instructions contenues dans le fichier.
Normalement, on
n´indique pas de chemin (répertoire) dans cette commande,
MPLAB va d´abord chercher dans le répertoire du projet,
ensuite dans le répertoire du programme MPLAB.
Donc pour être
plus élégant, au lieu de copier le fichier “SP_delai_V1_1.inc” dans
votre répertoire de projet, je vous recommande de le copier
dans le répertoire “MPASM Suite” du logiciel MPASM (dans les
programmes), il sera à ce moment disponible dans tous vos
projets, et vous n´aurez plus à vous en occuper. |
|
|
|
|