Le langage assembleur dicte certaines règles, parmi celles-ci le
respect d'un certain formalisme dans la mise en forme du code source:
- Les déclarations de variables sont cadrées à gauche (tous les
xxx equ xxx)
- Les directives LIST ou
_ _ CONFIG sont
précédées d'un blanc, tabulation ou espaces(s)
- Les étiquettes sont cadrées à gauche
- Les lignes de code sont, comme les directives CONFIG ou LIST,
précédées d'un blanc
- Le cadrage des commentaires, précédés d'un ; est indifférent
J'ai laissé en entête les lignes qui définissent les paramètres
combinés par une fonction ET et qui définissent la configuration
souhaitée. Ces quelques lignes auraient aussi bien pu être remplacées
par une simple ligne __ CONFIG H'3FF1'. La valeur hexa
'3FF1'donne en binaire 0011 1111 1111 0001. Vous vous reporterez
utilement à la documentation existante pour retrouver la signification
des différents bits, par exemple sur http://lea-linux.org/_src/redir.php3?url=http%3a%2f%2fwww.sq-1.com%2Fconfig.html
En résumé, de droite à gauche:
- bits 0 et 1: 01, utilisation d'un oscillateur XT c'est à dire
quartz jusqu'à 4 MHz
- bit 2: 0, Watch dog timer désactivé, le chien de garde qui surveille
le temps de cycle ne sera donc pas activé
- bit 3: 0, Power up timer activé, à la mise sous tension il va
s'écouler une très légère tempo avant que la scrutation du programme
démarre
- bits 4 à 13: suite de 1, Code protect désactivé
Dans le même ordre d'idée j'ai laissé la liste détaillée des variables
et mnémoniques. L'autre technique aurait été de faire appel à une
directive d'inclusion d'un fichier contenant toutes ces nmémoniques
(et bien d'autres) avec leurs valeurs respectives. On aurait ainsi
trouvé à la place de la liste une simple ligne:
#include <p16f84.inc>
C'est évidemment plus sobre, l'inconvénient est toutefois que dans
la suite du code les différents appels à des variables contenues dans
le fichier inclus sont moins 'transparents'. Le débutant aura du mal
à faire le lien entre l'appel à une mnémonique et une de ses fameuses
variables incluses.
Encore une fois il ne saurait être question de faire de ce document
un cours sur l'assembleur appliqué à la programmation des PIC. Vous
pourrez utilement vous reporter à ce sujet à un document de fond
``La programmation des PICs'' de BIGONOFF, par exemple sur http://lea-linux.org/_src/redir.php3?url=http%3a%2f%2fwww.abcelectronique.com%2Fbigonoff.
Le travail réalisé par le code d'entête est assez classique, on
fixe l'origine du code dans la mémoire du PIC (peut-être pas nécessaire
puisque 0 est l'adresse par défaut), puis on fait un reset des sorties
du port A, après quoi on défini les 5 broches du port A comme autant
de sorties (RA0 à RA4). Cette manipulation ne peut se faire qu'en
sélectionnant la page 1 de la mémoire, le registre trisa n'étant
pas accessible depuis la page 0.
Le programme à proprement parler n'est constitué que de 6 lignes,
une étiquette qui servira à boucler, 4 lignes qui affectent successivement
les valeurs 1 et 0 à la pin 2 (RA3) du PIC en laissant passer une
tempo entre chaque changement, après quoi la dernière ligne reboucle
sur l'étiquette définie plus haut. On ne peut plus simple donc.
Vous n'aurez aucun mal à démonter le mécanisme des tempos de 60,
30, 10, 5 sec etc. Elle s'obtiennent par répétition d'une tempo
de base repérée par l'étiquette wait0.
L'analyse de cette dernière est intéressante. Les deux premières
lignes qui suivent l'étiquette ne sont parcourues qu'une seule fois.
Elles initialisent le compteur count1 à 200 (valeur décimale ce
qui explique la notation curieuse .200). Suivent deux boucles imbriquées,
la boucle externe d1 - goto d1 et la boucle interne d2 - goto d2.
Le jeu consiste ici à décrémenter les compteurs et à boucler gentiment
tant que ceux-ci ne sont pas tombés à zéro. Le passage par zéro
du compteur interne (d2) décrémente d1 d'une unité et réinitialise
d2 à 200. La mise à zéro de d1 termine la temporisation. Les deux
mécanismes sont basés sur des opérateurs decfsz, acronyme qui signifie,
en bon français, décrémente la variable et saute si zéro! En clair
la variable nommée, ici count1 ou count2 est décrémentée, la nouvelle
valeur est rangée dans la variable (d'ou le ,1). Si cette nouvelle
variable est différente de zéro on exécute la ligne de code suivante,
sinon on saute une ligne plus loin.
La valeur de cette temporisation est assez facile à déterminer si
on garde présent à l'esprit que les lignes de code s'exécutent à
raison d'une ligne par cycle d'horloge sauf pour les branchements
qui en nécessitent deux. La boucle interne nécessite donc 3 cycles.
Parcourue 200 fois elle consomme 600 cycles. Chaque boucle externe
nécessite 5 cycles, plus les 600 cycles de la boucle interne, le
tout multiplié par les 200 boucles à parcourir. Il vient donc très
en gros 120000 cycles. Sur un pic raccordé à un quartz cadencé à
4 MHz la fréquence interne est de 1 MHz (1/4). La tempo élémentaire
sera achevée après 0.12 sec. Quatre tempos wait0 à suivre dureront
donc environ 1/2 sec (wait1), deux wait1 dureront 1 sec etc...
Deux remarques:
Le calcul effectué ici est taillé à la hache. Si vous souhaitez
déterminer avec précision la durée de la tempo il faudra fignoler
un peu (les boucles sont elles décrites 200 ou 199 fois?). Pour
ma part je garde un mauvais souvenir des problèmes du genre nombre
d'arbres et nombre d'intervals.
La temporisation par boucles successives est une horreur puisqu'on
consomme de la puissance pour faire passer le temps. Il existe d'autres
techniques bien plus judicieuses et qui utilisent, par exemple,
le chien de garde. Vous n'aurez aucun mal à trouver le source d'un
logiciel utilisant cette méthode, cherchez par exemple count.asm
sur Internet.
|