Utiliser les PIC 16F et 18F/Les sous-programmes en assembleur
Les sous-programmes
[modifier | modifier le wikicode]Le sous-programme est la brique de base pour la construction de programmes lisibles. Ils servent :
- à regrouper un ensemble d'instructions pour leur donner un nom explicite
- à regrouper des instructions qui font un calcul très souvent utilisé
Les instructions de sous-programmes
[modifier | modifier le wikicode]Les instructions CALL et RETLW et RETURN sont pour l'appel de sous-programme.
Opérations littérales (adressage direct) et de contrôles | |||||
Mnémonique
Opérande |
Description | Cycles | 14 bits Opcode | status affected | notes |
CALL k | appel du sous programme k | 2 | 10 0kkk kkkk kkkk | ||
GOTO k | aller à l'adresse | 2 | 10 1kkk kkkk kkkk | ||
RETLW k | retour avec le littéral dans W | 2 | 11 01xx kkkk kkkk | ||
RETURN | retour de sous-programme | 2 | 00 0000 0000 1000 |
Le rôle de la pile pour les appels imbriqués
[modifier | modifier le wikicode]Une pile désigne une structure de données qui ressemble à une pile d'assiettes. On met les assiettes au fur et à mesure sur la pile (on appellera cette action empiler) et quand on veut en retirer une on retire celle du dessus (on appelle cette action dépiler. C'est ce que l’on appelle aussi une structure LIFO (Last in First Out).
Si l’on veut qu'un sous-programme puisse lui-même appeler un autre sous-programme il faut que les appels successifs utilisent une pile. Chaque appel (de sous-programme) empile l'adresse de retour (ou adresse de l'instruction suivante) tandis que chaque fin de sous-programme dépile cette adresse.
Avec le PIC 16F on ne peut pas abuser des sous-programmes car il n'y a que 8 niveaux d'imbrications. C'est relativement peu pour l’utilisation de compilateurs car les librairies elles-mêmes peuvent déjà en comporter quelques uns.
Il n'y a aucune instruction qui manipule explicitement la pile sur le PIC. Cela interdit aux constructeurs de compilateurs de l’utiliser pour les variables locales et les paramètres des procédures et fonctions.
Les choix multiples
[modifier | modifier le wikicode]La programmation de suivant le cas faire... peut se faire de différentes manières. Nous commençons par en présenter une :
CBLOCK 0x00 ; début de la zone variables en ACCESS RAM
w_temp :1 ; Zone de 1 byte
status_temp : 1 ; zone de 1 byte
Choix : 1 ; je déclare ma variable
ENDC ; Fin de la zone
...
;si Choix=0 faire le sous programme spgm0 si Choix=1 faire spgm1
; Choix contient ici une valeur <=N
movlw 0x0
subwf Choix,w ;Choix - W -> W
btfsc STATUS,Z ;Z=1 si = 0 et on saute
goto spgm0
movlw 0x1
subwf Choix,w ;Choix - W -> W
btfsc STATUS,Z ;Z=1 si = 0 et on saute
goto spgm1
...
movlw 0xN
subwf Choix,w ;Choix - W -> W
btfsc STATUS,Z ;Z=1 si = 0 et on saute
goto spgmN
; erreur ici !!!
suite
....
spgm0 ;code ici
goto suite
....
Les sous-programmes ne sont pas ici de vrais sous-programmes (car appelés avec goto et non avec call, et finissant par goto au lieu de return). D'autre part, cette technique ne traite pas le dépassement de l'index signalé par "; erreur ici". À vous d’être créatifs...
Les tableaux en mémoire programme (lookup table en anglais)
[modifier | modifier le wikicode]Comme aucune instruction ne permet de lire un octet en mémoire programme, l’astuce est d’utiliser l’instruction retlw qui permet de retourner une valeur passée en argument. Écrivons donc notre tableau sous forme de retlw (voir plus haut, cela donne :
retlw 0 ; premier élément = 0
retlw 1 ; deuxième élément = 1
...
retlw 225 ; nième élément = 225
Nous pouvons ensuite utiliser PCL (poids faible du compteur programme) pour accéder à ce tableau. Si l'index d'accès au tableau est dans une variable "index" :
movf index, w ; index -> W
call tableau
...
tableau
addwf PCL , f ; ajouter w à PCL
retlw 0 ; premier élément = 0
retlw 1 ; deuxième élément = 1
...
retlw 225 ; nième élément = 225
Donc, si on charge 1 dans W et qu’on effectue un appel « call tableau ». Le programme se branche sur la bonne ligne, le PCL est incrémenté de 1 et le programme exécute donc alors la ligne « retlw 1 ». Si l'origine du tableau est au-delà des 8 bits, par exemple :
ORG 0x300
tableau
addwf PCL , f ; ajouter w à PCL
retlw 0 ; premier élément = 0
ne pas oublier de positionner PCLATH correctement. Pour l'exemple ci-dessus, cela donne :
movlw 03
movwf PCLATH
L'adressage indirect du 16FXXX
[modifier | modifier le wikicode]Cet adressage fait appel à 2 registres, dont un est particulier, car il n’existe pas vraiment. Examinons-les donc :
Les registres FSR et INDF
INDF signifie INDirect File. C’est le fameux registre de l’adresse 0x00. Ce registre n’existe pas vraiment, ce n’est qu’un procédé d’accès particulier à FSR utilisé par le PIC® pour des raisons de facilité de construction électronique interne.
Le registre FSR est à l’adresse 0x04 dans les 2 banques. Il n’est donc pas nécessaire de changer de banque pour y accéder, quelle que soit la banque en cours d’utilisation.
Le contenu du registre FSR pointe sur une adresse en 8 bits. Or, sur certains PIC®, la zone RAM contient 4 banques (16F876). L’adresse complète est donc une adresse sur 9 bits. Le registre FSR est alors complété alors par le bit IRP du registre Status.
movlw 0x50 ; chargeons une valeur quelconque
movwf mavariable ; et plaçons-la dans la variable « mavariable »
movlw mavariable ; on charge l’ADRESSE de mavariable, par
; exemple, dans les leçons précédentes, c’était
; 0x0E. (W) = 0x0E
movwf FSR ; on place l’adresse de destination dans FSR.
; on dira que FSR POINTE sur mavariable
movf INDF,w ; charger le CONTENU de INDF dans W.
Les puristes peuvent se demander pourquoi ne pas écrire directement
movf FSR,w
au lieu de
movf INDF,w
C'est tout simplement parce que movf FSR,w existe mais a une autre signification, mettre le registre FSR dans w ! On a bien besoin d'un pseudo registre pour l'adressage indirect.
Tableau en RAM
[modifier | modifier le wikicode]On complète l'adressage indexé de la section précédente.
movf INDF,w ; W<-(FSR)
avec
movwf INDF ;(FSR)<-W
Nous pouvons ainsi utiliser l'adressage indexé dans les deux directions.
Architecture complète du 16F84
[modifier | modifier le wikicode]Puisque cette section termine notre description du PIC 16F84 du point de vue de ses instructions, nous allons résumer ce que nous avons appris avec le schéma complet de ce microcontrôleur tel qu'on peut le trouver dans la documentation officielle.
Un certain nombre de fonctions de ce schéma seront détaillées un peu plus loin : les ports d'entrées et sorties ainsi que le timer 0.
L'adressage indirect du 18FXXX
[modifier | modifier le wikicode]Le concept précédent a été étendu dans les PIC 18F pour pouvoir accéder à de plus grandes quantités de mémoires. Il y a maintenant 3 registres FSR. Puisqu’ils doivent permettre d'adresser toute la mémoire ils doivent avoir 12 bits chacun, d'où la présence de FSR2H:FSR2L, FSR1H:FSR1L et FSR0H:FSR0L. Pour compliquer un peu les choses, il y a cinq équivalent à INDF : INDFn, POSTINCn, POSTDECn, PREINCn et PLUSWn. Évidemment cette complexité est faite pour simplifier la construction des compilateurs sur cette architecture.
movlw LOW(mavariable)
movwf FSR0L
movlw HIGH(mavariable)
movwf FSR0H
movf INDF0,w ; charger le CONTENU de INDF0 dans W.
peut être remplacé par :
lfsr FSR0,mavariable
movf INDF0,w ; charger le CONTENU de INDF0 dans W.
Microchip a donc ajouté une instruction pour faciliter ce mode d'adressage.
Faites ces exercices : Les sous-programmes en assembleur. |