Vous êtes sur la page 1sur 96

LA PROGRAMMATION DES PICS

PAR BIGONOFF

Cinquième PARTIE

Migration vers les 18Fxx8

Révision alpha 2 (en cours de réalisation)


2
1. INTRODUCTION............................................................................................................................................. 5

2. PRÉSENTATION GÉNÉRALE...................................................................................................................... 7
2.1 RAPPEL .......................................................................................................................................................... 7
2.2 DESCRIPTION ................................................................................................................................................. 7
2.3 ORGANISATION DES INSTRUCTIONS ............................................................................................................... 7
2.4 ORGANISATION DE LA MÉMOIRE PROGRAMME ............................................................................................... 8
2.4.1 SAUTS RELATIFS ET ABSOLUS...................................................................................................................... 8
2.5 ORGANISATION DE LA MÉMOIRE DE DONNÉES ............................................................................................. 10
2.6 LE REGISTRE WREG.................................................................................................................................... 10
3. LES MODES D’ADRESSAGE ...................................................................................................................... 13
3.1 L’ADRESSAGE LITTÉRAL OU IMMÉDIAT ........................................................................................................ 13
3.2 L’ADRESSAGE DIRECT DE TYPE « BANKED » ................................................................................................ 13
3.3 L’ADRESSAGE DIRECT EN ACCESS BANK ...................................................................................................... 14
3.4 L’ACCÈS DIRECT LONG................................................................................................................................. 16
3.5 L’ADRESSAGE INDIRECT SIMPLE .................................................................................................................. 17
3.6 L’ADRESSAGE INDIRECT POST-DÉCRÉMENTÉ ............................................................................................... 19
3.7 L’ADRESSAGE INDIRECT POST-INCRÉMENTÉ ................................................................................................ 19
3.8 L’ADRESSAGE INDIRECT PRÉ-INCRÉMENTÉ .................................................................................................. 21
3.9 L’ADRESSAGE INDIRECT PRÉ-INDEXÉ ........................................................................................................... 21
4. REGISTRES PARTICULIERS ET PARTICULARITÉS .......................................................................... 23
4.1 LE PC .......................................................................................................................................................... 23
4.2 LES REGISTRES PCL,PCLATH, ET PCLATU .............................................................................................. 24
4.3 LES SAUTS CALCULÉS .................................................................................................................................. 25
4.4 LE REGISTRE « STATUS »........................................................................................................................... 26
4.5 LE CAS DES INSTRUCTIONS 32 BITS .............................................................................................................. 28
4.6 LA PROCÉDURE « READ/MODIFY/WRITE » .................................................................................................... 29
4.7 MANIPULATIONS DE LA PILE ........................................................................................................................ 32
4.8 LES RETOURS RAPIDES « FAST »................................................................................................................... 35
5. LE JEU D’INSTRUCTIONS ......................................................................................................................... 38
5.1 CONVENTIONS ............................................................................................................................................. 38
5.2 L’INSTRUCTION « ADDLW » ...................................................................................................................... 38
5.3 L’INSTRUCTION «ADDWF »........................................................................................................................ 39
5.4 L’INSTRUCTION « ADDWFC ».................................................................................................................... 40
5.5 L’INSTRUCTION «ANDLW » ....................................................................................................................... 41
5.6 L’INSTRUCTION «ANDWF »........................................................................................................................ 42
5.7 L’INSTRUCTION «BC »................................................................................................................................. 42
5.8 L’INSTRUCTION «BCF » .............................................................................................................................. 43
5.9 L’INSTRUCTION «BN » ................................................................................................................................ 44
5.10 L’INSTRUCTION «BNC »............................................................................................................................ 44
5.11 L’INSTRUCTION «BNN »............................................................................................................................ 45
5.12 L’INSTRUCTION «BNOV »......................................................................................................................... 45
5.13 L’INSTRUCTION «BNZ » ............................................................................................................................ 46
5.14 L’INSTRUCTION «BRA »............................................................................................................................ 46
5.15 L’INSTRUCTION «BSF »............................................................................................................................. 47
5.16 L’INSTRUCTION «BTFSC »........................................................................................................................ 48
5.17 L’INSTRUCTION «BTFSS » ........................................................................................................................ 48
5.18 L’INSTRUCTION «BTG »............................................................................................................................ 49
5.19 L’INSTRUCTION «BOV »............................................................................................................................ 50
5.20 L’INSTRUCTION «BZ »............................................................................................................................... 50
5.21 L’INSTRUCTION «CALL ».......................................................................................................................... 51
5.22 L’INSTRUCTION «CLRF ............................................................................................................................. 52
5.23 L’INSTRUCTION «CLRWDT » ................................................................................................................... 52
5.24 L’INSTRUCTION «COMF »......................................................................................................................... 53
5.25 L’INSTRUCTION «CPFSEQ »...................................................................................................................... 54

3
5.26 L’INSTRUCTION «CPFSGT » ..................................................................................................................... 54
5.27 L’INSTRUCTION «CPFSLT »...................................................................................................................... 55
5.28 L’INSTRUCTION «DAW »........................................................................................................................... 56
5.29 L’INSTRUCTION «DECF ».......................................................................................................................... 57
5.30 L’INSTRUCTION «DECFSZ » ..................................................................................................................... 57
5.31 L’INSTRUCTION «DCFSNZ »..................................................................................................................... 58
5.32 L’INSTRUCTION «GOTO »......................................................................................................................... 59
5.33 L’INSTRUCTION «INCF »........................................................................................................................... 59
5.34 L’INSTRUCTION «INCFSZ » ...................................................................................................................... 60
5.35 L’INSTRUCTION «INFSNZ » ...................................................................................................................... 61
5.36 L’INSTRUCTION «IORLW »....................................................................................................................... 61
5.37 L’INSTRUCTION «IORWF » ....................................................................................................................... 62
5.38 L’INSTRUCTION «LFSR »........................................................................................................................... 63
5.39 L’INSTRUCTION «MOVF »......................................................................................................................... 63
5.40 L’INSTRUCTION «MOVFF » ...................................................................................................................... 64
5.41 L’INSTRUCTION «MOVLB »...................................................................................................................... 65
5.42 L’INSTRUCTION «MOVLW »..................................................................................................................... 65
5.43 L’INSTRUCTION «MOVWF »..................................................................................................................... 66
5.44 L’INSTRUCTION «MULLW » ..................................................................................................................... 66
5.45 L’INSTRUCTION «MULWF » ..................................................................................................................... 67
5.46 L’INSTRUCTION «NEGF ».......................................................................................................................... 68
5.47 L’INSTRUCTION «NOP »............................................................................................................................ 69
5.48 L’INSTRUCTION «POP »............................................................................................................................. 69
5.49 L’INSTRUCTION «PUSH ».......................................................................................................................... 70
5.50 L’INSTRUCTION «RCALL » ....................................................................................................................... 71
5.51 L’INSTRUCTION «RESET »........................................................................................................................ 72
5.52 L’INSTRUCTION «RETFIE » ...................................................................................................................... 72
5.53 L’INSTRUCTION «RETLW » ...................................................................................................................... 73
5.54 L’INSTRUCTION «RETURN » .................................................................................................................... 74
5.55 L’INSTRUCTION «RLCF » .......................................................................................................................... 74
5.56 L’INSTRUCTION «RLNCF » ....................................................................................................................... 75
5.57 L’INSTRUCTION «RRCF ».......................................................................................................................... 76
5.58 L’INSTRUCTION «RRNCF » ....................................................................................................................... 77
5.59 L’INSTRUCTION «SETF »........................................................................................................................... 77
5.60 L’INSTRUCTION «SLEEP » ........................................................................................................................ 78
5.61 L’INSTRUCTION «SUBFWB ».................................................................................................................... 79
5.62 L’INSTRUCTION «SUBLW » ...................................................................................................................... 79
5.63 L’INSTRUCTION «SUBWF » ...................................................................................................................... 80
5.64 L’INSTRUCTION «SUBWFB ».................................................................................................................... 81
5.65 L’INSTRUCTION «SWAPF »....................................................................................................................... 82
5.66 L’INSTRUCTION «TBLRD » ....................................................................................................................... 83
5.67 L’INSTRUCTION «TBLWT » ...................................................................................................................... 83
5.68 L’INSTRUCTION «TSTFSZ » ...................................................................................................................... 84
5.69 L’INSTRUCTION «XORLW »...................................................................................................................... 85
5.70 L’INSTRUCTION «XORWF »...................................................................................................................... 85
6. LECTURES ET ÉCRITURES EN MÉMOIRE PROGRAMME............................................................... 87
6.1 LES NOUVEAUX MÉCANISMES ...................................................................................................................... 87
6.2 LA LECTURE ................................................................................................................................................. 87
6.2.1 Le registre « TBLPTR » ....................................................................................................................... 87
6.2.2 L’instruction « TBLRD »...................................................................................................................... 88
6.2.3 Le registre TABLAT ............................................................................................................................. 89
6.3 PROCÉDURE D’EFFACEMENT ........................................................................................................................ 89
6.4 L’ÉCRITURE ................................................................................................................................................. 91
6.4.1 L’instruction « TBLWT »...................................................................................................................... 91

4
1. Introduction
Et bien, nous nous retrouvons de nouveau, suite à l’intérêt croissant que portent fort
logiquement les utilisateurs à cette nouvelle famille.

J’ai choisi d’illustrer plus spécifiquement les modèles 18Fxx8, qui couvrent à l’heure où
j’écris ces lignes les 18F248, 18F258, 18F448, et 18F458. Ce choix n’est pas innocent, j’ai
décidé d’écrire ce nouveau cours alors que j’étais en train d’écrire le descriptif de mon
système domotique sur bus CAN.

En effet, je me suis rendu compte qu’il m’était très difficile de vous expliquer le
fonctionnement de ce système si vous ne disposiez pas des informations de base à cet effet.

Je vais devoir, je le crains, être moins pratique pour cet ouvrage, car je dispose de peu de
temps pour l’écrire. Aussi, si vous commencez à zéro, je vous conseille fortement de
commencer avec les cours part1 et part2, qui regorgent d’exemples pratiques et vous
permettront de vous familiariser avec le monde des microcontrôleurs. L’expérience acquise
sera loin d’être inutile, ce ne sera donc pas du temps perdu.

J’ai longtemps hésité entre deux possibilités qui s’ouvraient à moi, soit tout reprendre
depuis le début, soit partir du principe que vous aviez lu et appliqué les précédents ouvrages.

Finalement, je viens de décider de faire un compromis. Je pars du principe que le lecteur a


lu les cours part1 et part2. Cependant, je replace dans ce cours les notions principales afin
d’éviter au maximum les aller-retour dans un des cours concernés. Ceci raccourcit le travail
que j’ai à faire pour rédiger ce cours, ce qui, sans ça, aurait reporté sa sortie de plusieurs mois,
par contre, cela implique certaines redondances, que ceux qui ont imprimé les précédents
cours voudront bien me pardonner.

J’évite en fait la réalisation de tous les exemples pratiques qui me prennent énormément
de temps, le lecteur étant déjà suffisamment familiarisé avec les pics, de par la réalisation des
exercices des cours précédents. Cet ouvrage est donc plus théorique, mais permettra à tout un
chacun de faire la migration entre les deux familles.

Cependant, vous aurez des exemples pratiques de réalisation si vous suivez en même
temps la mise en ligne de la réalisation de mon système domotique, à base de 18Fxx8 sur bus
CAN. Ceci constituera donc la partie pratique indispensable à la bonne compréhension de
l’ensemble.

N’hésitez jamais à me faire part de vos remarques, ni à me signaler les erreurs qui
m’auraient échappées (www.abcelectronique.com/bigonoff). Faites du copier/coller,
répercutez les infos que vous trouverez ici, traduisez le document dans une autre langue ou un
autre format. Simplement, dans ce cas, veuillez respecter les désirs de l’auteur en fin
d’ouvrage et faites moi parvenir un exemplaire de votre travail. Ceci pour permettre d’en faire
profiter le plus grand nombre.

Pour l’apprentissage de MPLAB, qui est l’outil nécessaire, je vous renvoie au cours part 1,
dans lequel vous apprendrez à maîtriser l’éditeur, l’assembleur, et le simulateur.

5
6
2. Présentation générale
2.1 Rappel

Je rappelle à ceux qui ne prennent pas la peine de lire les introductions, que ce cours est
destiné à ceux qui ont une bonne connaissance des microcontrôleurs PIC de la famille mid-
range (16Fxxx). Pour les autres, veuillez lire au minimum le cours-part1, et, si possible, le
cours-part2. Sans ça, vous risquez bien de ne rien comprendre et de vous lasser.

2.2 Description

Nous traiterons ici des pics 18Fxx8. Un pic est un microcontrôleur fabriqué par
Microchip, et qui fait partie de la gamme high-end de ce constructeur.

Cette famille comporte plusieurs types de pics, les 18xx8 sont très représentatifs de cette
famille.

Lorsque vous aurez étudié ce pic, il vous sera très simple de passer à une autre version, les
adaptations étant mineures.

Je fournis un fichier maquette, m18F258.asm, qui contient le squelette d’un programme de


départ d’une application réelle. Un copier/coller de ce fichier accélérera la réalisation de vos
propres programmes.

2.3 Organisation des instructions

Cette famille se caractérise par des mots d’instruction d’une largeur de 16 bits, chaque
mot étant composé de deux octets.

Les octets sont stockés dans l’ordre poids faible / poids fort. Lorsque vous lisez un fichier
hexadécimal, il vous faudra donc inverser les deux octets lus afin de former le mot intégral.

Notez ici une grosse différence par rapport aux pics de la gamme mid-range, comme les
16Fxxx. Dans cette gamme, les instructions sont codées sur 14 bits, mais en un seul mot d’une
largeur de 14 bits. Une instruction est donc mémorisée dans une et une seule adresse mémoire
d’une largeur de 14 bits.

Sur les 18Fxx8, au contraire, une instruction sera codée au minimum sur deux
emplacements mémoire, chaque emplacement contenant donc un seul octet.

Les instructions sont toujours alignées sur une valeur paire, c’est à dire que le début d’une
instruction doit toujours se trouver à l’adresse paire, alors que le second octet, qui contient
l’octet de poids fort, se trouvera toujours à une adresse impaire.

Il faudra y penser si vous réalisez des sauts calculés : sautez toujours à une adresse paire.

7
2.4 Organisation de la mémoire programme

Bonne nouvelle pour les habitués des 16F, vous pouvez maintenant accéder à l’intégralité
de la mémoire programme sans avoir à gérer des modifications de PCLATH. L’espace
adressable total d’un pic 18F est de 2Mbytes (2 Moctets, ou Mo).

Les 18F248 et 18F448 (18Fx48) disposent de 16Ko de mémoire programme, tandis que
les 18F258 et 18F458 (18Fx58) disposent de 32Ko de mémoire programme.

Attention, soyez vigilants : il s’agit de Kilo-octets, donc de « demi-instructions ». Dans le


meilleur des cas, ceci vous autorise donc respectivement 8192 et 16384 instructions d’un mot
de 16 bits, sachant de plus que certaines instructions sont codées sur 32 bits.

2.4.1 Sauts relatifs et absolus

Une instruction de saut pourra prendre, sur les 18F, trois formes :

- Soit un saut relatif long


- Soit un saut relatif court
- Soit un saut absolu

Le saut absolu, vous le connaissez déjà, sous la forme du « goto », par exemple, utilisé sur
les 16F. Ce goto est suivi de l’adresse directe à laquelle on désire sauter.

goto adresse_absolue

On était du reste limité à un saut dans une page, l’adresse de destination effective était
alors complétée par la valeur contenue dans le registre PCLATH.

Rien de tout ceci sur les 18F, vous pouvez préciser l’adresse directement dans tout
l’espace d’adressage, sans aucun recours à PCLATH. Terminées donc, les limites de pages.

Bien entendu, étant donné que l’instruction est codée sur 16 bits, il n’y a pas suffisamment
de place pour coder l’adresse de destination, puisque coder 2Mo nécessite déjà 20 bits.

La solution a donc été de coder les instructions de sauts absolus sur 32 bits. Lorsque vous
écrivez « goto destination », cette instruction est donc codée sur 2 mots de 16 bits, et nécessite
2 cycles pour son exécution.

Le saut relatif long compense cet encombrement, en limitant le saut à une distance de –
2048 à +2046. Pour ce faire, l’équivalant du « goto » s’appellera « bra » pour « branch
always » ou saut inconditionnel.

L’instruction est donc codée en donnant la distance du saut par rapport à l’emplacement
de l’instruction suivante (en effet, souvenez-vous, au moment de l’exécution d’une
instruction, le PC, ou compteur ordinal, pointe déjà sur l’instruction suivante).

La syntaxe sera donc :

bra distance

8
La distance sera exprimée par un nombre de 11 bits codé en complément à 2. Ceci donne
une valeur comprise entre –1024 et + 1023 (voir cours-part1).

Or, puisqu’on ne peut sauter qu’à une adresse paire, le PIC multiplie cette valeur de lui-
même par 2, ce qui donne la formule :

Nouvel emplacement = emplacement actuel + 2 + (2 * distance)

L’emplacement actuel + 2 s’explique par le fait qu’au moment d’exécuter l’instruction, le


compteur de programme pointe déjà sur l’instruction suivante, et contient donc déjà
l’emplacement actuel + 2.

Pour l’utilisateur, tout ceci est transparent, l’assembleur se charge de convertir l’étiquette
en une valeur de déplacement.

Autrement dit, pour sauter à l’étiquette « label », vous aurez le choix entre :

goto label
Et
bra label

Ces deux instructions donneront le même résultat à condition que le bra saute à un
emplacement compris dans les limites expliquées ci-dessus. Dans le cas contraire, MPASM
vous donnera simplement un warning pour vous avertir, il vous suffira alors de remplacer le
« bra » par un « goto ».

Remarquez que sauter de plus de 1000 instructions en avant et en arrière couvre déjà les
99% des sauts rencontrés dans un programme.

Vous allez me dire : « alors, autant utiliser le goto ». Et bien non, car le goto utilise 32 bits
pour être codé, et le bra n’en utilise que 16.

Autrement dit : utilisez systématiquement des sauts relatifs (nous verrons qu’il y en a
d’autres), et ne remplacez par des sauts absolus que si vous obtenez des warnings lors de
l’assemblage.

Pour terminer, certaines instructions utilisent un saut relatif court, c’est à dire dont la
destination relative est codée sur 8 bits. Ceci permet alors un déplacement de (-128 à +127)
*2 octets à partir de l’emplacement suivant l’instruction. De nouveau, les mécanismes sont les
mêmes, et vous vous ne préoccupez de cette limite que si MPASM vous avertit à l’aide d’un
warning.

Un exemple typique est l’instruction « bc » qui permet de sauter (brancher) si le carry vaut
1.

bc n ; saut relatif, avec n compris entre –128 et +127

Les sauts relatifs courts sont utilisés dans les instructions de sauts conditionnels.

9
2.5 Organisation de la mémoire de données

Si je commence par vous dire que la zone de données est divisée en 15 banques, vous
allez hurler en me disant que c’est encore pire que sur les 16F, sur lesquels les changements
de banques se révèlent souvent pénibles.

En fait, il n’en est rien. Une série de mécanisme, d’instructions, et une organisation
intelligente permet d’écrire de gros programmes sans nécessiter un seul changement de
banque.

En somme, pour la plupart de vos applications, vous n’aurez pas besoin de faire de
changement de banques. Je vais expliquer pourquoi.
La mémoire RAM utilisateur d’un 18Fx48 comporte 768 octets, tandis que celle d’un
18Fx58 en contient 1536. Vous voyez déjà qu’on se trouve dans un autre ordre de grandeur
que la mémoire RAM des 16F. Sachant qu’on place 256 adresses dans une seule banque, ça
fait déjà pas mal de possibilités, mais c’est encore mieux que ça.

La première chose à savoir, c’est que tous les SFR (registres spéciaux) sont situés dans la
même banque, à savoir la banque 15. Donc, c’est déjà fini les changements de banques pour
passer de TRISB à PORTB, par exemple. Tout les registres dans la même banque équivaut
déjà à une simplification, et non des moindres, puisqu’il s’agit d’une des principales causes
d’erreur chez le débutant.

A ce stade, je vous conseille de télécharger le datasheet du 18Fxx8. Je place sur mon site
la version qui a servi à écrire ce cours, comme ça tout le monde aura les mêmes numéros de
page. Par contre, une fois le cours terminé, je vous conseille de charger la dernière version
disponible chez Microchip.

Vous verrez page 47 et 48, table 4-1, les 256 emplacements de la banque 15, avec les
noms des registres correspondants.

2.6 Le registre WREG

Il s’agit de notre registre de travail, dénommé « W » dans les instructions. Lorsque vous
exécutez :

movf variable,w ; charger le contenu de variable dans W

Vous retrouvez la valeur de W dans le registre WREG. Ceci est une grande nouveauté par
rapport à la famille 16F. Ceci peut sembler inutile, mais il n’en est rien. En fait, ça donne tout
simplement accès au registre W pour l’intégralité des instructions, ce qui n’était pas le cas
auparavant. Pas convaincu ? Prenons l’énoncé suivant :

Vous avez une valeur dans W, et vous désirez la décaler vers la gauche. En 16F, vous
devriez écrire :

movwf temporaire ; sauver W dans une variable temporaire


bcf STATUS,C ; effacer le carry
rlf temporaire,w ; charger la valeur décalée vers la gauche

10
Pourquoi avons-nous du sauver W ? Tout simplement parce que l’instruction rlw (rotation
dans W) n’existe pas, on ne peut effectuer un décalage que sur un emplacement mémoire.

C’est toujours identique pour le 18F, mais comme WREG est un registre à part entière, il
est accessible en tant que tel. Vous pouvez donc écrire :

bcf STATUS,C ; effacer carry


rlcf WREG ; décalage direct de W

Vous voyez ici que le décalage s’effectue directement dans W, ce qui ouvre pas mal de
nouvelles possibilités et de facilités d’écriture. Ne vous inquiétez pas pour la syntaxe de
l’instruction « rlcf », nous allons en reparler en étudiant le jeu d’instructions.
Remarquez que ceci rend inutile certaines instructions spécifiques au registre W. Par
exemple, on notera la disparition de l’instruction « clrw »:

clrw ; effacement du registre W

En effet, étant donné que le registre W est accessible comme un registre ordinaire,
l’instruction générale « clrf » fonctionne également pour ce registre :

clrf WREG ; effacer le registre WREG = effacer W

Mais vous constaterez que si vous écrivez « clrw », vous ne serez pas gratifiés d’une
erreur. Simplement, MPASM fait la conversion automatiquement pour vous. Il n’empêche
que cette instruction a bel et bien disparu.

Notez un point que je soulève régulièrement, à savoir que le nombre d’instructions donné
sur papier ne caractérise pas la puissance d’un microcontrôleur, il faut analyser
l’environnement en intégralité.

Vous voyez très bien dans ce cas que la suppression de cette instruction ne diminue en
rien ni la facilité d’utilisation, ni la puissance du microcontrôleur. Au contraire, dans ce cas,
cette diminution est le résultat d’une augmentation de l’efficacité générale, puisque le registre
W est maintenant accessible pour l’intégralité des instructions.

Autrement dit, rien qu’en plaçant le registre W dans la zone des registres accessibles, vous
avez en fait une multitude d’instructions supplémentaires non répertoriées, et non
comptabilisées dans le nombre d’instructions. Dans l’exemple que nous avons vu concernant
le décalage, ceci équivaut par exemple à avoir ajouté l’instruction « rlw », soit « rotation du
registre w ».

Certaines familles de microcontrôleurs travaillent avec des instructions spécifiques, et


donc leur jeu d’instructions est plus étendu. Méfiez-vous des comparaisons directes.

11
12
3. Les modes d’adressage

3.1 L’adressage littéral ou immédiat

Cet adressage précise que la valeur est immédiatement comprise dans l’instruction elle-
même. Aucune autre donnée n’est nécessaire à son exécution.

movlw 0x55 ; charger la valeur 0x55 dans W

Aucune variable n’est précisée, tout est dit dans l’instruction. C’est le mode le plus
simple.

3.2 L’adressage direct de type « banked »

La mémoire RAM est en fait accessible de plusieurs façons :

- Soit par accès « banked »


- Soit par « access bank », ce qui est une nouvelle possibilité.
- Soit par accès direct long
- Soit par accès indirect

Nous allons voir ou revoir ces différentes possibilités, en commençant par l’adressage
« banked »

Cette méthode est semblable dans son principe à celle utilisée par les 16F. Vous précisez
une adresse, et l’adresse accédée est complétée par la banque actuellement sélectionnée.

Sur un 16F, on écrivait :

bsf STATUS,RP0 ; passer en banque 1


movf variable,w ; charger variable en banque 1 dans w
bcf STATUS,RP0 ; revenir éventuellement en banque 0

La syntaxe pour le 18F, si on veut être complet, est un peu différente. Vous précisez que
vous désirez utiliser un adressage de type « banked » en ajoutant « ,banked » à l’instruction.

La ligne concernant la variable devient donc, avec un adressage « banked » :

movf variable,w,banked ; placer B1 dans variable en banque 1


ou
movf variable,w,1 ; placer B1 dans variable en banque 1

Ah là là, allez-vous me dire, un paramètre en plus. Rassurez-vous, MPASM prend ce


paramètre en charge automatiquement. Si vous accédez à une variable qui n’est accessible
qu’en mode « banked », alors le suffixe « ,banked » est ajouté automatiquement.

Bref, vous pouvez continuer à écrire :

movf variable,w ; charger variable en banque 1 dans w

13
Il vous suffit simplement de vous rappeler que puisque votre variable est en banque1,
MPASM ajoutera automatiquement le suffixe.

Il nous reste à savoir comment préciser la banque. Puisque nous avons 15 banques, plus
question ici de RP0 et de RP1, il nous faut plus de bits.

En fait, nous disposons d’un registre spécial, BSR, dont les 4 bits de poids faibles donnent
le numéro de la banque concernée.

On pourrait donc se dire qu’on va exécuter :

movlw 0x01 ; pour banque 1


movwf BSR ; dans BSR
movf variable,w ; charger variable en banque 1 dans w

Mais c’est plus simple que ça, vous disposez d’une instruction spéciale, movlb, qui vous
permet de charger en une seule opération la banque désirée.

Le programme final sera donc :

movlb 0x01 ; pointer en banque 1


movf variable,w ; charger variable en banque 1 dans w

Vous voyez que c’est simple, mais vous allez me dire qu’on en est toujours avec ces
maudites banques. Un peu de patience, que diable.

3.3 L’adressage direct en access bank

Si vous regardez page 46 du datasheet, figure 4-6, vous voyez un petit cadre à droite,
intitulé «access bank ». Ce petit cadre est en fait une clé de la simplification de la gestion des
banques sur les 18F.

En fait, vous imaginez que vous pouvez à tout instant, et quel que soit la banque
actuellement pointée, avoir accès en direct à 256 emplacements.

Ces 256 emplacements sont en fait les adresses 0 à 0x5F des variables en banque 0,
complétés par les registres SFR 0x60 à 0xFF de la banque 15.

Autrement dit, vous obtenez une sorte de banque spéciale, nommée « access bank », qui
vous donne accès aux 96 premiers emplacements RAM de la banque 0 et aux 160 derniers
emplacements de la banque 15.

Autrement dit, vous avez accès en access bank à 160 sur 256 registres FSR possibles.
Vous allez penser que c’est dommage de ne pas avoir accès à tout, mais en fait, nous allons
voir que c’est faux.

Si vous jetez un œil à la table 4-1 page 47 et 48 (attention, ce tableau est inversé, il
commence par les adresses les plus hautes), vous voyez que les 96 premières adresses non
accessibles (donc les dernières dans le tableau) sont représentées en grisé.

14
Ce sont tous des registres concernant le module CAN, mais l’accès à ces registres dispose
également d’un mécanisme qui évite les changement de banque, nous en parlerons dans
l’étude du module CAN. Considérez donc pour l’instant que ces registres n’existent pas.

Notez dans la note dans le cadre du dessous que les registres en grisé sont accessibles en
banque 15, alors que les autres sont accessibles en « access bank », comme je viens de vous le
dire.

Ne vous préoccupez pas de la note numéro 3, j’en parlerai également dans le chapitre
consacré au bus CAN (ce sera un gros chapitre).

Revenons à nos moutons. Il nous faut maintenant savoir comment préciser que nous
désirons un accès à l’ « access bank ». Comme pour le mode « banked », nous ajoutons un
suffixe, qui sera cette fois « ,ACCESS », ou « ,A », ou « ,0 »

Imaginons un programme fictif qui charge le contenu de la variable1, située à l’adresse


0x10 de la banque 0, et place cette valeur dans le registre TRISB situé en banque 15.

Nous pourrons écrire :

movf variable1,w,A ; charger variable1 de l’access bank dans W


movwf TRISB,A ; mettre la valeur dans TRISB en access bank

De nouveau, nous avons des termes supplémentaires, mais de nouveau MPASM nous
simplifie la vie.

En effet, il connaît l’adresse de variable1 et il sait qu’elle est accessible en access bank.
Dans ce cas, il place automatiquement le suffixe « ,A » à la fin de votre instruction. Pratique,
non ?

Votre programme devient donc :

movf variable1,w ; charger variable1 de l’access bank dans W


movwf TRISB ; mettre la valeur dans TRISB en access bank

MPASM s’occupe de tout. Tout ce que vous devez vérifier, c’est que soit votre variable se
trouve en access bank, soit si elle ne s’y trouve pas, que BSR est correctement configuré.

Vous vous dites à présent : « Super, j’ai 96 variables accessibles directement en plus de
mes registres ». Mais, en fait, c’est mieux que ça.

En effet, durant ce temps, votre registre BSR contient une valeur, et donc toutes les
variables contenues dans la banque sont également directement accessibles.

Si BSR contient la valeur 0, alors vous avez accès aux 256 emplacements de la banque 0,
et aux 160 registres FSR de la banque 15.

En imaginant variable1 située à l’adresse 0x10 de la banque 0, et variable2 située à


l’adresse 0x80 de la banque 0, si vous écrivez :

15
movf variable1,w ; charger variable1
movwf TRISB ; sauver dans TRISB
movf variable2 ; charger variable2
movwf PORTB ; mettre dans PORTB

En fait, MPASM convertira en :

movf variable1,w,A ; la variable1 est accessible en access bank


movwf TRISB,W ; TRISB est accessible en access bank
movf variable2,BANKED ; la variable2 n’est PAS accessible en access bank
movwf PORTB,A ; PORTB est accessible en access bank

Il vous faut donc être attentif au fait que l’accès à la variable2 nécessite que BSR soit
correctement configuré à l’aide d’une instruction « movlb ».

Vous devez déjà vous dire que vous avez accès maintenant à 256 variables sans
changement de banque, mais vous pouvez faire mieux.

En effet, si vous décidez de faire pointer BSR sur la banque1, par exemple, vous avez
maintenant accès sans aucun changement :

- Aux 96 variables de la banque 0 situées en access bank


- Aux 256 variables de la banque 1 pointées par BSR.

Autrement dit, vous voici maintenant en possession de 352 variables accessibles sans
changement de banques, en plus de tous vos registres SFR. C’est pas beau, ça, madame ?

Mais ce n’est de nouveau pas fini.

3.4 L’accès direct long

Les 18F disposent d’instructions supplémentaires, et non des moindres, qui permettent
d’accéder à l’intégralité de l’espace RAM sans avoir besoin ni de l’access ram, ni des
banques. Ces instructions sont codées sur 32 bits, et contiennent l’adresse complète de la
variable de façon explicite. Nul besoin donc de recourir à un changement de banque, même si
BSR ne pointe pas sur la banque concernée.

Examinons une instruction qui permet cette manipulation.

movff source,destination

Permet de copier le contenu de l’emplacement source vers l’emplacement destination,


sans nécessiter de recourir aux banques. Les emplacements visés sont donc toujours justes, et
peuvent se trouver dans des banques différentes.

Imaginons par exemple que votre variable1 se trouve en banque2, que votre variable2 se
trouve en banque3, et que votre BSR pointe sur la banque1

Vous pouvez parfaitement écrire :


movff variable1,TRISB ; mettre le contenu de variable1 dans TRISB

16
movff variable2,PORTB ; mettre le contenu de variable2 dans PORTB
movff variable2,variable1 ; copier variable2 dans variable1

Vous voyez que ça commence à devenir sérieusement intéressant. Donc, intelligents


comme vous êtes, vous vous dites que :

- Votre access bank peut contenir 96 variables accessibles en permanence


- Votre registre BSR pointe sur 256 autres variables
- Vous avez accès à toutes les autres variables par accès direct long.

Autrement dit, vous placez dans l’access bank et dans la banque pointée par BSR vos
variables générales, et vous placez dans les autres banques les variables de sauvegarde, par
exemple, et toutes les variables que vous n’accéderez que par accès direct long.

En effet, une sauvegarde d’un registre, lors d’une interruption, par exemple, peut
s’effectuer à l’aide d’une instruction movff registre, variable. Vous n’accédez donc à ces
variables qu’à l’aide d’accès directs longs, ce qui vous permet d’économiser de la place dans
les banques accessibles de façon traditionnelle.

Mais, de nouveau, ce n’est pas encore tout.

3.5 L’adressage indirect simple

La première chose à dire, comparé aux 16F, c’est que les registres d’accès indirect
accèdent maintenant à l’intégralité de la zone RAM, sans aucun changement de banque
nécessaire.

Donc, si vous avez des tableaux et autres zones que vous accédez en accès indirect,
placez-les dans une banque non pointée par BSR, ce qui vous donne encore plus de
possibilités de variables. Vous commencez à comprendre que dans un programme bien conçu,
vous aurez peu, voire pas d’instructions de changement de banque.

L’adressage indirect, comme son nom l’indique, vous permet d’accéder à une adresse
pointée par un registre. Si vous ne connaissez pas le mécanisme, je vous renvoie au cours-
part1.

Les PIC18Fxx8 disposent de 3 registres d’accès indirect, contre 1 pour les 16F. De plus,
comme je l’ai indiqué, ces registres pointent vers l’adresse complète de la variable, et donc ne
sont pas limités à 256 valeurs, comme sur les 16F.

Pour qui réfléchit un peu, cela veut dire que ces registres contiennent plus de 8 bits, la
mémoire du PIC étant organisée sur des registres de 8 bits, chaque registre d’indirection
contient donc en réalité deux registres.
Les registres d’indirection sont dénommés FSR0, FSR1, et FSR2

Imaginons que nous voulions faire pointer FSR0 sur la variable1, dans la banque 3. Vu
que le registre FSR0 est constitué de 2 registres FSR0L (poids faible) et FSR0H (poids fort),
on pourrait se dire que la méthode est la suivante :

movlw LOW(variable1) ; charger poids faible de l’adresse de variable1

17
movwf FSR0L ; dans pointeur poids faible
movlw HIGH(variable1) ; charger poids fort (donc la banque)
movwf FSR0H ; dans pointeur poids fort.

Cette méthode semble logique, mais peu pratique, et une fois de plus, Microchip vient à
notre secours avec une nouvelle instruction spéciale, « lfsr ».

lfsr FSR0,variable1 ; faire pointer FSR0 sur la variable1

Et voilà, tout s’effectue en une seule ligne. Notez que vous ne précisez plus FSR0L ou H,
mais uniquement le nom générique.

Bien évidemment, cette instruction est codée sur 32 bits (2 mots). De nouveau, beaucoup
de simplifications par rapport aux 16F. Les spécialistes savent bien que plus un
microcontrôleur est complexe à étudier, plus il est simple à utiliser. De nouveau, vous en avez
la preuve.

Les PICs disposent d’une méthode particulière pour faire de l’adressage indirect. Au lieu
d’utiliser une syntaxe spéciale, ils définissent un registre virtuel, qui sera interprété par le PIC
comme étant un adressage indirect. Le registre est INDFx, avec « x » représentant un chiffre
de 0 à 2, en rapport avec FSR0 à 2.

Un exemple de syntaxe est le suivant :


lfsr FSR1,variable1 ; pointer sur variable1
movf INDF1,w ; charger la variable1 dans W

Il est très important de savoir qu’une opération réalisée sur un registre FSRxL induit une
opération sur l’intégralité du registre FSR. Autrement dit, le report s’effectue sur FSRxH en
cas de débordement.

Si vous écrivez :

lfsr FSR1,0x1FE ; FSR1H = 0x01 , FSR1L = 0xFE


incf FSR1L,f ; FSR1H = 0x01 , FSR1L = 0xFF
incf FSR1L,f ; FSR1H = 0x02 , FSR1L = 0x00
decf FSR1L,f ; FSR1H = 0x01 , FSR1L = 0xFF

Vous constatez donc que les opérations mathématiques sur FSRxL concernent également
FSRxH. Ceci vaut également, bien entendu, pour les opérations d’addition et de soustraction.

Ceci constitue l’adressage indirect simple. Mais les pics 18F disposent d’autres
possibilités d’adressage indirect. Ces possibilités sont :

- L’adressage indirect simple


- L’adressage indirect post-décrémenté
- L’adressage indirect post-incrémenté
- L’adressage indirect pré-incrémenté
- L’adressage indirect avec offset

Ceci vous ouvre toute une série de nouvelles possibilités, que je vais décrire. Sachez que
le PIC est un processeur orthogonal, c’est à dire que tous les modes d’adressage s’appliquent

18
à toutes les instructions et à tous les registres. C’est très pratique et très puissant. La méthode
utilisée par Microchip pour gérer ses modes d’adressage et ses instructions est très puissant,
mais peu commercial. En effet, lorsqu’on compare avec d’autres familles, on dénombre
beaucoup plus d’instructions et de modes d’adressage, mais c’est principalement parce que
Microchip a choisi d’ouvrir le champ d’application de ses instructions en utilisant des
registres.

Lorsque vous comparez des processeurs, ne vous fiez pas uniquement aux
caractéristiques annoncées, regardez plutôt comment le processeur est mis en œuvre.

Ceci étant dit, nous venons de voir l’adressage indirect simple, voyons les autres modes
d’adressage indirect

3.6 L’adressage indirect post-décrémenté

Cet adressage fonctionne exactement comme l’adressage indirect simple, mais le contenu
du FSR utilisé est décrémenté après l’instruction.

La syntaxe est : POSTDECx, avec « x » numéro du registre FSR de 0 à 2.

POSTDECx s’utilise comme un registre fictif, exactement comme pour INDFx.


Imaginons deux variables : var1 située à l’adresse 0x10, et var2 située à l’adresse 0x11. Nous
pouvons écrire :

lfsr FSR2,var2 ; FSR2 pointe sur 0x11


movff POSTDEC2,PORTB ; envoyer le contenu de var2 dans PORTB, FSR2
; est ENSUITE décrémenté
movff INDF2,PORTC ; on envoie le contenu de var1 sur PORTC

Vous constatez que l’instruction contenant POSTDEC2 a réalisé deux opérations en une
seule instruction :

- Elle a transféré la variable pointée par FSR2


- ENSUITE (post), elle a décrémenté FSR, qui pointe alors sur l’adresse précédente (0x10,
soit var1)

Vous voyez que ce genre d’instructions permet de gérer facilement des tableaux, d’autant
que vous disposez de 3 registres d’indirection.

3.7 L’adressage indirect post-incrémenté

Ici, c’est exactement identique, à part qu’après l’accès, on incrémente le registre FSR
concerné au lieu de le décrémenter.

La syntaxe est : POSTINCx, avec « x » numéro du registre FSR de 0 à 2.

Je ne résiste pas à vous donner un simple exemple de la puissance de ce que nous avons
vu jusqu’à présent.

19
Imaginez d’écrire pour un 16F un programme qui copie un certain nombre de variables
consécutives d’une banque à l’autre. Vous allez voir que vous aller devoir faire des
sauvegardes de FSR, des changements de banque avec IRP, des sauvegardes de l’octet en
cours de transfert, etc. Bref, une belle routine en perspective.

Voyons ce que donnerait un programme qui copie toute les variables de la banque 1 vers
la banque 2 sur un 18F :

lfsr FSR0,0x100 ; FSR0 pointe sur le début de la banque 1


lfsr FSR1,0x200 ; FSR1 pointe sur le début de la banque 2
boucle
movff POSTINC0,POSTINC1 ; transférer un octet, pointer sur suivant
btfss FSR0H,1 ; tester si terminé
bra boucle ; non, octet suivant

Simple, pas vrai ? On ne peut rêver plus court. Quelques mots d’explication pour ne pas
vous tracasser :

Les initialisations se font avec les adresses 0x100 et 0x200. En effet, souvenez-vous que
pour les initialisations de pointeurs indirects, le pointeur accède à l’intégralité de la mémoire,
et n’est pas limité à une banque de 256.

Si vous regardez la figure 4-6 page 46, vous voyez que les adresses relatives à l’intérieur
de la banque sont données à gauche du tableau, et varient chaque fois dans l’intervalle 0x00 à
0xFF, alors que les adresses complètes sont données à droite, et varient de 0x00 à 0xFFF.

Imaginons que vous vouliez accéder à la variable située à l’emplacement 5 de la banque 2.


Si vous utilisez une instruction de type « banked », l’adresse est précisée sur 1 octet. Vous
aurez donc, par exemple :

movb 0x02 ; pointer sur la banque 2


movf 0x05,w ; accéder à la variable 5 de la banque 2

Par contre, si vous utilisez une instruction de type direct long, vous aurez :

movff 0x205, variable ; copier la variable de l’adresse 205 autre part.

En fait, tant que vous utilisez des symboles, l’assembleur fait la distinction pour vous.
Mais comme dans notre exemple, nous pointons en début de banque, il nous faut bien préciser
l’adresse complète.

Si vous avez compris ça, alors, vu qu’un registre FSR est composé en réalité de 2 registres
FSRxH et FSRxL, vous comprendrez que la ligne suivante :

lfsr FSR0,0x100 ; FSR0 pointe sur le début de la banque 1

a placé en réalité la valeur 0x01 dans FSR0H, et la valeur 0x00 dans FSR0L. Partant de là,
le teste de fin de boucle :

btfss FSR0H,1 ; tester si terminé

20
se contente de tester si le bit 1 du poids fort est passé à 1, autrement dit, si FSR0 est passé
de la valeur 0x100 à la valeur 0x200, ce qui signifie qu’on a atteint la fin de la banque 1.
Notez donc que les incrémentations et décrémentations se moquent des limites de banques,
vous pouvez donc manipuler des zones de plus de 256 octets sans aucun problème.

Notez pour finir l’utilisation systématique du « bra » au lieu du « goto » pour les sauts,
chaque fois que c’est possible.

3.8 L’adressage indirect pré-incrémenté

Fonctionne de façon strictement identique aux précédents, si ce n’est que la valeur de


FSRx est incrémentée AVANT de réaliser l’opération précisée par l’instruction.

La syntaxe est : PREINCx, avec « x » numéro du registre FSR de 0 à 2.

Pour mieux comprendre, regardez l’exemple suivant :

lfsr FSR0,0x208 ; FSR0 pointe sur la variable 0x208 (banque 2)


movf PREINC0,w ; charge la variable 0x209 dans W

Notez donc qu’après l’opération, FSR0 pointe sur l’adresse 0x209, comme pour
POSTINC0, mais à la différence que l’incrémentation a été faite avant de réaliser le
chargement de la variable concernée.

Pour information, il n’existe pas de mode indirect pré-décrémenté.

3.9 L’adressage indirect pré-indexé

Ce mode d’adressage est appelé « adressage PlusW » par Microchip. La valeur pointée est
celle dont l’adresse est contenue dans le registre FSR concerné, augmentée de la valeur
contenue dans W (en complément à 2), et qui constitue un déplacement.

La syntaxe est : PLUSWx , avec « x » numéro du registre FSR de 0 à 2

Ceci permet d’exécuter des déplacements calculés avec une grande facilité. Si vous
regardez cet exemple, vous verrez que sa mise en œuvre est très simple. Imaginons que la
variable à l’adresse 0x215 contienne 0x50, et que la variable 0x255 contienne 0x10 :

lfsr FSR0,0x205 ; pointer sur l’adresse 0x205


movlw 0x10 ; déplacement = 0x10
movf PLUSW0,w ; W contient maintenant le contenu de l’adresse 0x215,
; soit 0x50
movf PLUSW0,w ; W contient maintenant le contenu de l’adresse 0x255,
; soit 0x10

Ceci permet des opérations complexes. N’oubliez pas non plus qu’une opération de type
« movff » ne modifie pas le contenu de « W », ce qui permet d’autres types d’opérations.

Vous voyez pour conclure que les modes d’adressage se sont nettement enrichis avec cette
nouvelle famille.

21
ATTENTION : le registre W est considéré comme un registre signé. C’est-à-dire que
si sa valeur est supérieure à 0x7F, elle sera considérée comme un déplacement négatif.

lfsr FSR0,0x205 ; pointer sur l’adresse 0x205


movlw 0x85 ; déplacement = 0x85 = -0x7B
movf PLUSW0,w ; W contient maintenant le contenu de l’adresse 0x18A

22
4. Registres particuliers et particularités
Nous allons examiner ici quelques registres spécifiques importants pour le fonctionnement
des PICs de cette famille

4.1 Le PC

Le PC est le compteur ordinal de notre PIC. C’est lui qui cadence le déroulement des
instructions. A chaque chargement d’une instruction, le PC est incrémenté pour pointer sur
l’instruction suivante.

Etant donné que nos instructions sont codée sur 16 bits, et que la mémoire est organisée en
octets, le PC sera donc incrémenté de 2 lors de chaque chargement d’instructions.

En outre, le premier octet de chaque instruction doit impérativement être placé à une
adresse paire. On dira que le processeur aligne ses instructions sur les adresses paires. Vous
retrouverez cette procédure sur pas mal de processeurs 16 bits, c’est un grand classique.

Si, maintenant, vous êtes un adepte de l’utilisation de la directive « $ », qui précise, je


vous le rappelle, l’adresse du début de la ligne actuelle, vous utilisiez pour les 16F une
syntaxe du style :

nop
goto $-1

Dans ce petit bout de code, le « goto » renvoie sur l’instruction « nop » qui se situe un mot
de programme (-1) avant la ligne « goto ».

Si vous faites ça pour un 18F, ça ne fonctionnera pas. Pourquoi ?

Si vous avez trouvé, bravo. En fait, vous devez vous rappeler que les instructions sont
alignées sur des octets pairs, et que chaque instruction est composée au moins de 2 octets.
Comme l’instruction « nop » est constituée d’un mot de 2 octets, remonter du début de la
ligne « goto » au début de la ligne « nop » nécessite de décrémenter PC de 2 unités.

La syntaxe correcte sera donc :

nop
goto $-2

De même, faites attention dans ce cas-ci par exemple

Label
nop
goto test
bra $- ?

Quelle valeur faut-il placer derrière « $- » pour sauter à l’étiquette label ?


Et bien, remonter au début de l’instruction « goto » nécessite de remonter de 4 octets,
puisqu’un goto est codé sur 32 bits, plus 2 octets pour l’instruction « nop ». Ceci nous donne
donc :

23
Label
nop
goto test
bra $- 6

Retenez donc déjà que si vous utilisez « $ », la valeur ajoutée ou soustraite devra toujours
être multiple de 2. De plus, vous devrez prendre en compte le fait que certaines instructions
comportent 2 mots et non 1, et vous devrez calculer en conséquence.

Franchement, n’est-ce pas plus simple d’écrire :

Label
nop
goto label

ou mieux :
Label
nop
bralabel

Si vous n’êtes pas convaincu, tant pis, on ne pourra pas dire que je ne vous ai pas prévenu.

4.2 Les registres PCL,PCLATH, et PCLATU

Le compteur ordinal, PC, est subdivisé en 3 registres :

- PCL : contient les 8 octets de poids faible de l’adresse. Comme les adresses sont toujours
paires, le bit 0 de ce registre vaudra toujours 0. Ce registre est accessible en lecture et en
écriture.
- PCH : contient les bits 8 à 15 de l’adresse. Ce registre n’est ni accessible en lecture, ni en
écriture.
- PCU : contient les bits 16 à 21 de l’adresse. Ce registre n’est ni accessible en lecture, ni en
écriture.

Lorsque vous réalisez des sauts, branchements, retours, etc., vous n’avez pas à vous
préoccuper de ces registres, ils sont gérés de façon transparente. Par contre, si vous réalisez
des opérations sur PCL, comme des lectures de table, ou des sauts calculés, alors il vous
faudra en tenir compte.

Lors d’une écriture (movwf, addwf etc) d’une valeur dans le registre PCL, le contenu du
registre PCLATH est transféré dans le registre PCH, et le contenu du registre PCLATU est
transféré dans le registre PCU. Autrement dit, comme sur les 16F, vous devez initialiser
correctement PCLATH avant tout opération sur PCL.

Vous n’aurez pas à vous préoccuper de PCLATU sur les 18Fxx8. En effet, l’espace
d’adressage de 16Ko permet des adresses codées sur 15 bits. PCLATU et PCU vaudront donc
toujours 0.

24
A l’inverse, une lecture de PCL transfère automatiquement la valeur de PCH dans
PCLATH, et celle de PCU dans PCLATHU. C’est donc une façon de pouvoir lire l’adresse en
intégralité, et, accessoirement d’initialiser PCLATH.

Attention, j’ai trouvé plusieurs exemples dans la documentation de Microchip qui


« oublient » la gestion de PCLATH. Si vous appliquez ces exemples, vous courrez un grand
risque qu’ils ne fonctionnent pas.

Le déroulement normal du programme, ainsi que les sauts, ne mettent pas à jour
automatiquement PCLATH et PCLATU. Vous devrez soit les mettre à jour manuellement,
soit en lisant PCL.

Remarque : il est interdit d’utiliser une opération codée sur 32 bits pour transférer une
valeur dans PCL. Vous ne pouvez donc pas écrire : « movff variable,PCL »

Autre remarque : n’oubliez pas que chaque instruction compte au minimum 2 octets,
n’oubliez pas ça dans vos calculs.

4.3 Les sauts calculés

A titre d’exemple, je vous donne une routine qui exécute une routine dont le numéro, de 0
à 255, est contenue dans la variable numroutine.

main
. . . . ; programme principal
rcall traiter ; traiter la sous-routine dont le N° se trouve dans
; numroutine
. . . . ; suite du programme après traitement

traiter
movlw HIGH (tablesaut) ; poids fort adresse de la table de saut
movwf PCLATH ; dans PCLATH
rlcf numroutine,w ; charger numéro routine * 2
btfsc STATUS,C ; tester si numéro > 127
incf PCLATH,f ; oui, incrémenter PCLATH
addlw LOW(tablesaut) ; ajouter poids faible adresse table de saut
btfsc STATUS,C ; tester si on déborde
incf PCLATH,f ; oui, incrémenter PCLATH
movwf PCL ; provoquer un saut dans la table qui suit :

tablesaut
bra routine0 ; sauter à la routine 0
bra routine1 ; sauter à la routine 3
bra routine2 ; sauter à la routine 3
bra routine3 ; sauter à la routine 3
. . . . ; et ainsi de suite pour les 256 routines

routine0
. . . .
return ; retour au main

routine1
. . . .

25
return ; retour au main

etc.

Les routines peuvent se trouver n’importe où en mémoire programme, chaque bloc se


trouvant à un emplacement différent.

Si les routines sont trop éloignées de la table de sauts, alors il faudra remplacer les « bra »
par des « goto ». Cependant, comme les « goto » sont des instructions à 4 octets, vous devrez
multiplier numroutine par 4 au lieu de 2. Nul doute que vous ferez sans problème les
modifications nécessaires.

La ligne « rlcf » (rotation avec carry, équivalente de rlf sous 16F) n’est pas précédée d’un
« bcf STATUS,C ». On fait donc entrer n’importe quelle valeur dans le bit b0, qui sera par la
suite écrit dans PCL. Cela n’a aucune importance, le bit 0 de PCL est figé à 0, il est
impossible d’y écrire une autre valeur.

Si vous désirez effectuer des sauts, et non des sous-routines, il vous suffit d’appeler la
routine « traiter » à l’aide d’un « bra » ou d’un « goto » dans le programme principal, et de,
bien entendu, ne pas terminer vos routines par un « return ».

Vous pouvez utiliser la même méthode pour la création de tables de « retlw », sachant que
vous sacrifiez deux octets (l’instruction) pour un seul octet retourné. Nous verrons que le PIC
dispose de fonctions spécifiques à cette intention, plus performantes, et plus simples à mettre
en œuvre.

Une nouvelle fois, méfiez-vous des exemples « simplifiés » donnés dans le datasheet du
PIC, comme par exemple l’exemple 19-1 de la page 201. Si vous appliquez tel quel, vous
risquez de gros problèmes.

Si vous avez un tableau comportant moins de 128 instructions, vous pouvez supprimer les
deux lignes suivantes :

btfsc STATUS,C ; tester si numéro > 127


incf PCLATH,f ; oui, incrémenter PCLATH

Notez qu’il exite une méthode puissante pour effectuer des sauts calculés sur les 18Fxxx,
c’est l’utilisation de la pile via l’instruction PUSH. Je vais parler de cette méthode dans le
chapitre consacré aux manipulations de la pile.

4.4 Le registre « STATUS »

C’est un registre dont chaque bit a une signification particulière. Il est principalement
utilisé pour tout ce qui concerne les tests. Il est donc également d’une importance
fondamentale.

Ce registre comporte 5 bits utiles :

b7 : Non utilisé
b6 : Non utilisé

26
b5 : Non utilisé
b4 :N
b3 : OV
b2 :Z
b1 : DC
b0 :C

Commençons par le bit le moins significatif :

C Carry (report)

Ce bit est en fait le 9ème bit d’une opération. Par exemple, si une addition de 2 octets
donne une valeur >255 (0xFF), ce bit sera positionné.

DC Digit Carry (report de quartet)

Ce bit est utilisé principalement lorsque l’on travaille avec des nombres BCD. Il indique
un report du bit 3 vers le bit 4. Pour information, un nombre BCD est un nombre dont chaque
quartet représente un chiffre décimal.

Z Zéro

Ce bit est positionné à 1 si le résultat la dernière engendre un résultat nul.

Limite d’utilisation : Ces flags ne sont positionnés que pour certaines instructions. Dans
l’étude du jeu d’instructions, les bits susceptibles d’être modifiés seront indiqués pour
chacune des instructions.

OV Overflow (débordement).

Ce bit est utilisé principalement pour les opérations sur les nombres signés. Le
positionnement de ce bit indique qu’un débordement du bit 6 du nombre vers le bit 7 a
entraîné de ce fait un changement de signe du résultat. En effet, dans un nombre signé en
complément à deux (voir part1), le bit 7 représente le signe.

Dans ce cas, l’addition de deux nombres signés positifs pourrait entraîner un résultat
comportant le bit 7 positionné à 1, ce qui serait interprété comme un nombre négatif par
erreur, si on ne tenait pas compte du bit OV.

N Negative (résultat négatif)

Indique que le résultat de la dernière opération concernée a produit un résultat qui doit être
considéré comme négatif si on travaille en complément à 2.

Comme en complément à deux, un nombre est négatif si son bit 7 vaut 1, le bit N indique
en fait que le résultat de l’opération concernée a produit un résultat dont le bit 7 vaut 1.

27
4.5 Le cas des instructions 32 bits

Nous avons vu que certaines instructions demandaient d’être encodées sur 2 mots de 16
bits, soit 32 bits.
Nous avons également vu que ceci nécessitait d’être pris en compte dans certains cas
particuliers. Il reste un cas dont nous n’avons pas parlé.

Imaginons la portion de code suivante :

btfss STATUS,Z ; tester si bit Z = 1


bra routine1 ; non, sauter à la routine 1
bsf variable,4 ; oui, mettre le bit 4 de variable à 1

Cet exemple est purement imaginaire, mais va nous permettre de regarder en détails ce qui
se passe.

Imaginons que Z = 0. Dans ce cas, nous exécutons l’instruction de test (btfss), le PC a été
à ce moment incrémenté de 2, et pointe donc sur le début de l’instruction « bra ». Au cycle
suivant, cette instruction sera exécutée.

Le temps consommé par l’instruction « btfss » est donc de 1 cycle, ce qui est normal pour
une instruction sur un mot sans rupture de séquence.

Imaginons que Z = 1. Dans ce cas, nous chargeons l’instruction de test (btfss). A ce


moment, PC a été incrémenté de 2, et pointe donc sur l’instruction « bra ». On exécute
l’instruction, qui, vu que le test est vrai, va incrémenter de nouveau le PC de 2. On pointe
donc sur l’instruction « bsf ». Comme il y a rupture de séquence, le traitement prendra 2
cycles. Tout est conforme à nos habitudes.

Imaginons maintenant que la routine1 se trouve à plus de 2048 octets de distance de notre
test. Nous allons être contraints d’utiliser un « goto » au lieu d’un « bra ».

btfss STATUS,Z ; tester si bit Z = 1


goto routine1 ; non, sauter à la routine 1
bsf variable,4 ; oui, mettre le bit 4 de variable à 1

L’instruction « goto » étant constituée de 2 octets, la mémoire programme est donc


remplie de la façon suivante :

Instruction btfss
Premier mot de l’instruction goto
Second mot de l’instruction goto
Instruction bsf

Vous voyez tout de suite que si Z vaut 1, nous allons sauter tout droit sur le second mot de
l’instruction goto, au lieu de sauter à l’instruction bsf.

Que va-t-il se passer si on tente d’exécuter une demi-instruction ?

Et bien, ce cas a été prévu : toute instruction non « comprise » par le pic sera interprété
comme un « nop » (no operation ) particulier.

28
Somme toutes, pour le cas où Z vaut 1, le pic va « voir » la séquence suivante en mémoire
programme :

Instruction btfss
Premier mot de l’instruction goto
Nop (reste de l’instruction goto, non interprétable)
Instruction bsf

Autrement dit, votre pic va sauter à cet octet particulier, « exécuter » le « nop », puis
continuer et exécuter l’instruction « bsf ».

L’instruction « btfss » avec saut a donc bien duré 2 cycles, mais l’exécution du « nop »
supplémentaire en a duré un également.

Au niveau de votre programme, tout se passe donc comme si le « btfss » avait nécessité 3
cycles.

Prenez donc garde au fait que si une instruction conditionnelle de type « passer si
condition » est suivie par une instruction de 2 mots, l’exécution du saut nécessitera un cycle
supplémentaire. Ce peut être important si vous devez calculer des temps d’exécutions précis.

4.6 La procédure « read/modify/write »

Il importe de savoir que toute opération sur un bit particulier est traité en plusieurs
séquences dans le PIC. Ceci peut avoir des répercussions importantes sur le fonctionnement
d’un programme, principalement si vous travaillez avec les PORTs d’entrées/sorties.

La séquence est la suivante (en interne, je le rappelle) :

- Le pic lit l’intégralité du registre précisé


- Il modifie le bit concerné
- Il réécrit l’intégralité du registre précisé

Vous allez me dire : oui, mais, puisque c’est exécuté en interne, nous on voit que le bit a
été modifié, et c’est suffisant. Et bien, détrompez-vous.

Imaginons le programme suivant, on imagine que le niveau sur chaque RB0 est amené au
+5V par une résistance :

movlw B’11111110’ ; préparer valeur


movwf TRISB ; RB0 en sortie, les autres en entrée
bcf PORTB,7 ; préparer RB7 à 0
bcf TRISB,7 ; passer RB7 en sortie.

Que constaterez-vous lors de l’exécution de ce programme ? En réalité, en écrivant dans


PORTB,7, vous avez écrit dans le buffer du port. Or, comme ce port est en entrée, rien ne se
répercute au niveau des pins.

Par contre, une fois que vous allez passer la pin en sortie (TRISB,7), le niveau placé dans
le buffer va être transféré vers la sortie, et donc la pin RB7 va passer à l’état bas.

29
Tout est donc logique, et sans problème.

Modifions donc de façon qui semble anodine notre programme, en ajoutant une ligne :

movlw B’11111110’ ; préparer valeur


movwf TRISB ; RB0 en sortie, les autres en entrée
bcf PORTB,7 ; préparer RB7 à 0
bcf PORTB,0 ; passer RB0 à 0.
bcf TRISB,7 ; passer RB7 en sortie.

Qu’avons-nous sur nos sorties ? Réfléchissez avant de poursuivre :

Ceux qui ont dit : RB7 et RB0 = 0 ont tout faux. Pour ceux qui ont trouvé la bonne
réponse : bravo !

Si vous appliquez la façon dont le PIC exécute les opérations sur les bits, le pic a en réalité
exécuté en interne la séquence suivante :

movlw B’11111110’ ; préparer valeur


movwf TRISB ; RB0 en sortie, les autres en entrée
bcf PORTB,7 ; préparer RB7 à 0
; lecture du PORTB = B’11111111’(par exemple)
; modification du bit7 du PORTB, bit 7 : B’01111111’
; écriture du PORTB : B’01111111’
bcf PORTB,0 ; passer RB0 à 0.
; lecture du PORTB = B’11111111’ ( ! ! ! ! !)
; modification du bit 0 = B’11111110’
; écriture du PORTB = B’11111110’
bcf TRISB,7 ; passer RB7 en sortie.
; le buffer est placé sur la sortie
; PORTB : B’11111110’

Et bien, vous constatez que cette fois, RB7 ne vaut pas 0, mais bel et bien 1.
Ceci a été provoqué par la lecture du PORTB provoquée par l’ajout de la ligne qui modifie
RB0. Ceci a provoqué la copie de l’état de RB7 (qui est toujours en entrée, donc vaut 1 dans
notre exemple) dans le buffer, ce qui a écrasé le niveau « 0 » que nous y avions
précédemment placé.

Faites très attention à ceci, car dans le cas contraire, vous risquez bien de ne pas
comprendre ce qui vous arrive. Ce cas intervient lorsque vous inscrivez des valeurs dans une
pin de port placée en sortie, ou, également, lorsque vous utilisez RA4, qui est en collecteur
ouvert.

Pour RA4, en effet, si vous écrivez « 1 », vous risquez que le niveau en sortie soit « 0 »,
suivant l’électronique qui se trouve derrière le PIC.

Imaginons que vous placiez un niveau « 1 » sur RA4. Imaginons que cette ligne soit
utilisée, par exemple, pour gérer une ligne I²C de façon software. Une résistance de rappel au
+5V est présente sur la ligne. Imaginons enfin que plusieurs périphériques utilisent la ligne
I²C en question :

Un moment donné dans votre programme, vous décidez de piloter RA0 pour allumer une
led.

30
Vous avez :

bsf PORTA,0 ; allumer la LED


. . . .
. . . .
bcf PORTA,0 ; éteindre la LED
. . . .
. . . .
bsf PORTA,0 ; allumer la LED
. . . .
. . . .
bcf PORTA,0 ; éteindre la LED

Imaginons ce qui va se passer au niveau de la pin RA4, en fonction d’éléments extérieurs


imaginaires sur la ligne concernée :

Ici, aucun périphérique n’accède à la ligne I²C


bsf PORTA,0 ; allumer la LED
. . . .
. . . .
bcf PORTA,0 ; éteindre la LED
. . . .
Ici, un périphérique impose un niveau bas sur la ligne
. . . .
bsf PORTA,0 ; allumer la LED
. . . .
Ici, le périphérique libère la ligne
. . . .
bcf PORTA,0 ; éteindre la LED

Voyons ce qui se passe au niveau de RA4 dans notre PIC.

Ici, aucun périphérique n’accède à la ligne I²C


bsf PORTA,0 ; allumer la LED
. . . . ; on lit PORTA, on modifie RA0,
; RA0 = 1, RA4 = 1
. . . .
bcf PORTA,0 ; éteindre la LED
; on lit PORTA, on modifie RA0
; RA0 = 0, RA4 = 1
. . . .
Ici, un périphérique impose un niveau bas sur la ligne
. . . .
bsf PORTA,0 ; allumer la LED
; on lit PORTA, on modifie RA0
; RA0 = 1, RA4 = 0 (car RA4 est lu comme 0)
. . . .
Ici, le périphérique libère la ligne
. . . .
bcf PORTA,0 ; éteindre la LED
; on lit PORTA, on modifie RA0
; RA0 = 0, RA4 = 0

31
Vous constaterez que le fait d’avoir modifié RA0 a bloqué la ligne RA4 à 0
définitivement. En effet, lors de la lecture/modification/écriture, la ligne RA4 a été lue comme
étant à 0 (imposée par un périphérique extérieur) bien que dans votre programme vous ayez
placé RA4 à 1 et ne l’avez plus modifié.

Une fois que le périphérique libérera la ligne, RA4 restera bloqué à 0, car le niveau 0
présent maintenant dans le PORTA de votre PIC bloque cette ligne à ce niveau.

Donc, simplement en ajoutant la gestion d’une led, vous avez bloqué une application qui
tournait auparavant.

Pensez à tout ceci si un comportement sur une sortie vous semble curieux. Mettez-vous à
la place du pic, et scindez vos opérations sur les bits en 3 opérations :
lecture/modification/écriture. Comprenez donc bien que toute modification d’un bit sur un
port entraîne une opération sur tous les bits de ce port.

4.7 Manipulations de la pile

Comme dans la famille 16F, le 18Fxx8 dispose d’une pile, destinée principalement à
mémoriser l’adresse de retour d’une sous-routine ou d’une interruption. Cependant, la pile
passe maintenant à 31 emplacements, ce qui permet une plus grande souplesse dans la gestion
des sous-routines.

Accompagnant cette augmentation de capacité, il est maintenant possible de manipuler


directement la pile.

Tout d’abord, il est possible de modifier le sommet de la pile, c’est-à-dire le contenu du


PC sauvegardé en dernier lieu, et donc qui contient en principe l’adresse de prochain retour.

Le sommet de la pile est dénommé « TOS » pour (Top Of Stack), et, bien entendu,
comme le PIC peut adresser un maximum théorique de 2Mo, le PC (compteur ordinal) qui
sera sauvé occupera 21 bits. Le TOS contient donc également 21 bits.

Le TOS est ainsi accessible au travers de 3 registres :

- TOSU : contient les bits 20 à 16 du TOS, ses bits 7 à 5 sont inutilisés


- TOSH : contient les bits 15 à 8 du TOS
- TOSL : contient les bits 7 à 0 du TOS

Lorsque nous avons des registres codant des valeurs sur plus de 8 bits, nous retrouverons
souvent cette terminologie :
U : représente « Upper », soit l’octet qui contient les bits de poids les plus forts (16 à 23)
H : représente « High », soit l’octet qui contient les bits de poids fort (8 à 15)
L : représente « Lower », soit l’octet qui contient les bits de poids faible (7 à 0)

Ainsi, la première chose qu’il vous est possible de faire, c’est de modifier le TOS, et ainsi
de changer l’adresse de retour lors du prochain retour de sous-routine ou d’interruption. Soyez
très prudent lorsque vous agissez ainsi, et posez-vous la question de savoir si votre

32
programme est correctement structuré pour devoir recourir à des méthodes aussi peu
élégantes.

Bien entendu, ce qui va surtout vous intéresser, c’est de pouvoir placer une valeur sur la
pile, et de pouvoir l’en retirer. Ceci s’effectue à l’aide de deux instructions, POP et PUSH.

PUSH permet tout simplement de copier le contenu du PC sur le TOS. Cette valeur sera
ensuite accessible via TOSU, TOSH, TOSL.

Autrement dit, si vous voulez ajouter une valeur sur la pile, vous utilisez PUSH, qui va :

- Incrémenter le pointeur de pile


- Placer le contenu du PC sur la pile

Libre à vous ensuite de manipuler cette valeur comme vous l’entendez, et pour l’usage
que vous voulez.

Maintenant, n’oubliez pas que dans tous les cas, ce sera cette valeur qui sera utilisée lors
du prochain retour. Autrement dit, si vous ne comptez pas utiliser cette nouvelle valeur dans
ce but, n’oubliez surtout pas de la retirer de la pile, à l’aide de l’instruction POP, qui va :

- Décrémenter le pointeur de pile.

Vous êtes donc revenu dans la position d’avant l’instruction PUSH.

Attention, les programmateurs habituées des langages de haut-niveau vont dire : « Super,
je peux passer mes paramètres de fonctions sur la pile ». C’est ce que je me suis dit également
à la première lecture. Malheureusement, ça ne marchera pas. Pourquoi ?

- Dans votre « main », vous écrivez une instruction PUSH


- Vous modifiez TOSU, TOSH, et TOSL pour y placer des paramètres
- Vous appelez votre sous-routine (rcall, ou call)

Si vous faites ça, votre sous-routine, lorsqu’elle voudra lire le TOS, lira en fait l’adresse
de retour placée par votre appel de sous-routine. Vos paramètres, eux, ils sont dans
l’emplacement juste inférieur, qui lui, n’est pas accessible. Si vous voulez y accéder, il faudra
dépiler l’adresse de retour, la sauver, lire les paramètres, refaire un POP, et restaurer l’adresse
de retour, le tout en interdisant les interruptions. Je ne vois guère l’intérêt.

Cette manipulation de pile est une bonne idée, mais malheureusement, son exploitation
souffre du grave défaut de n’avoir pas accès à l’avant-dernière valeur de la pile.

Il existe cependant une solution, par exemple d’utiliser deux emplacements de pile. Tout
d’abord, vous empilez l’adresse de retour de votre programme, puis les variables passées sur
la pile, et ensuite vous sautez à votre sous-routine par un « goto ». La sous-routine dépile les
variables sur la pile, exécute son travail, puis revient au programme principal par un return.

Une utilisation plus intelligente de la pile, est d’utiliser l’instruction PUSH pour effectuer
des sauts calculés.

33
En effet, plutôt que d’effectuer une série de lignes « goto » avec sélection suivant une
opération sur PCL, il est beaucoup plus simple maintenant de procéder de la façon suivante :

- Vous créez une entrée sur la pile avec PUSH


- Vous calculez l’adresse du « goto » en fonction de ce que vous désirez
- Vous modifiez TOSH et TOSL en fonction de l’adresse du saut
- Vous lancez une instruction « return »

Au moment du return, le programme va sauter à l’adresse désignée par celle que vous
avez placée sur la pile, donc à l’adresse de votre saut calculé. La pile est décrémentée de 1 et
revient donc à son niveau d’origine.

sautparpile
push ; placer PC sur la pile
movlw LOW(adresse) ; adresse basse du saut
movwf TOSL ; dans TOSL
movlw HIGH(adresse) ; adresse haute du saut
movwf TOSH ; dans TOSH (TOSU reste à 0x00 pour les 18Fxx8)
return ; « goto » à l’adresse placée sur la pile

Maintenant, il vous faudra veiller à ne pas déborder de la pile, comme d’habitude. Si vous
faites déborder la pile, vous aurez tout d’abord les conséquences suivante :

- Si vous empilez trop, la valeur ne sera pas sauvée, et le bit STKFUL du registre RCON
sera positionné
- Si vous dépilez trop, la valeur dépilée sera « 0 », et donc votre programme reviendra à
l’adresse de départ. Le bit STKUNF du registre RCON sera positionné.

Attention, retour à l’adresse 0x00 ne veut pas dire « reset ». En effet, dans ce cas, aucun
registre n’est affecté, il s’agit d’un simple saut.

En plus de ces actions, vous disposez d’une sécurité supplémentaire. En effet, il faut
comprendre qu’une erreur de débordement de pile n’est jamais normale, il s’agit donc soit
d’une erreur de programmation, soit d’un plantage du PIC.

Dans ce dernier cas, il est alors utile de provoquer un reset général, tout comme le
watchdog effectue un reset s’il n’est pas rechargé périodiquement.

Ceci peut être mis en place en activant le bit STVREN dans les bits de configuration. Une
fois fait, tout débordement dans un sens ou dans un autre provoquera un reset complet du pic.

Notez que les bits STKFUL et STKUNF sont dans un état indéterminé lors de la mise
sous tension. Si votre but est de les utiliser, placez-les vous-même à 0 lors d’une mise sous
tension. Une fois positionnés, il vous faudra également les remettre à 0 par software.

34
4.8 Les retours rapides « fast »

Lorsque vous traitez une interruption, ou parfois pour certaines sous-routines, vous devez
souvent sauvegarder certains registres particuliers, afin de les replacer dans l’état où ils se
trouvaient au moment de revenir au programme principal.

Les 18F disposent d’un mécanisme particulier, qui permet d’effectuer cette sauvegarde
automatiquement dans certaines conditions.

Les registre concernés sont :

- STATUS : contient les indicateurs principaux


- WREG : est le registre de travail (W)
- BSR : est le pointeur de banques pour l’adressage direct banked

Dans le cas de l’utilisation de cette possibilité, les registres sont sauvés automatiquement
dans des registres se sauvegarde, dénommés respectivement : STATUSS, WS, et BSRS. Ces
registres ne sont accessibles ni en lecture, ni en écriture. Vous ne pouvez les utiliser que par le
biais des instructions spécifiques.

Ces registres sont uniques, et donc vous n’avez qu’un niveau utilisable pour employer
cette procédure. Si par exemple, une sous-routine est appelée avec le paramètre « FAST »,
elle ne pourra pas elle-même utiliser un appel de type FAST, sous peine d’écraser le contenu
mémorisé actuellement dans ces registres.

Le premier cas d’utilisation est l’appel de sous-routine, « CALL ». La première chose à


savoir, c’est que cette possibilité existe pour l’appel en adressage direct long (CALL), mais
pas pour l'adressage relatif (RCALL).

La syntaxe est la suivante :

call adresse,FAST ; appel de la sous-routine avec mémorisation.

Si vous faites ça, en plus de sauver l’adresse de retour sur la pile, le pic va
automatiquement, et sans nécessiter de cycle supplémentaire effectuer une sauvegarde de
STATUS, WREG, et BSR.

Bien évidemment, et vous l’aurez deviné, il faudra préciser lors du retour que l’on
souhaite restaurer ces registres, ce qui se fait également avec le paramètre « FAST » placé en
paramètre de l’instruction « RETURN »

Voici un exemple typique :

main
. . . .
call label,FAST ; appel de sous-routine avec sauvegarde
. . . . ; ici, on continue avec BSR,W, et STATUS tels qu’ils
; étaient à l’instruction précédent le call

label

35
. . . . ; traitement de la sous-routine, les registres sont
; éventuellement modifiés
return FAST ; retour au main avec restauration de BSR,W, et STATUS

Le second cas d’utilisation, c’est l’emploi dans cette procédure dans les mécanismes
d’interruption. Lors d’une interruption, les 3 registres concernés saut automatiquement et
toujours sauvegardés.

Corollaire : si vous employez les interruptions dans votre programme, vous ne pouvez pas
utiliser le « return fast » dans un bloc d’instructions pour lequel les interruptions sont activées.
A défaut de cette précaution, une interruption écraserait la sauvegarde créé par l’appel « call
label,FAST ». N’oubliez surtout pas cette remarque.

Dans ce cas, il n’y a rien à préciser lors de l’appel (par définition, puisqu’une interruption
intervient sans appel software). Vous aurez simplement à préciser au retour si vous désirez ou
pas utiliser la restauration automatique. De nouveau, ceci s’effectue en précisant l’option
« FAST » dans la commande de retour, en l’occurrence « RETFIE »

interrupt
. . . . ; traitement de l’interruption, inutile de sauvegarder
; les 3 registres STATUS,W, et BSR
retfie FAST ; retour avec restauration automatique.

Cependant, les interruptions sur le 18F sont structurées en deux niveaux possibles, les
interruptions hautes et basses priorités. Une interruption haute priorité étant susceptible
d’interrompre le traitement d’une interruption basse priorité, vous ne pouvez donc plus utiliser
« retfie FAST » pour l’interruption basse priorité, mais uniquement pour l’interruption haute
priorité.

Tout ceci nous donne une série de possibilités. Imaginons que nous avons une sous-
routine pour laquelle nous souhaitons sauvegarder ces registres. Nous avons trois cas
possibles :

Si on n’utilise pas les interruptions :


- On appelle la sous-routine avec « call FAST » et on en sort avec « return FAST »

Si on utilise les interruptions sur un seul niveau (sans priorité) :

- On sauve manuellement les registres dans des variables (movff) avant l’appel de la sous-
routine, on les restaure avant le retour (movff)
- On ne sauvegarde pas les registres dans la routine d’interruption, on sort de l’interruption
avec « retfie FAST »

Si on utilise les interruptions prioritaires :

- On sauve manuellement les registres dans des variables (movff) avant l’appel de la sous-
routine, on les restaure avant le retour (movff)
- On sauvegarde manuellement les registres dans la routine d’interruption basse priorité
avant le traitement de l’interruption, on restaure manuellement avant le « retfie »
- On ne sauvegarde pas les registres dans la routine d’interruption haute priorité, on sort de
l’interruption avec « retfie FAST »

36
Comprenez bien que vous disposez d’un seul endroit utilisable pour votre retour rapide, et
c’est celui de priorité la plus élevée. C’est du reste logique, c’est l’endroit où vous voudrez en
général traiter vos informations le plus rapidement possible.

37
5. Le jeu d’instructions

5.1 Conventions

Le jeu d’instructions de cette famille comporte pas moins de 75 instructions, qu’on


pourrait classer par famille. Le résumé de ces instructions est donné dans le datasheet, table
25-2 pages 280 et 281 du datasheet.

Je vais voir ces instructions une par une par ordre alphabétique, vous verrez que certaines
existaient déjà sur le 16F, d’autres sont nouvelles, et d’autres, enfin, voient leur syntaxe
légèrement modifiée.

Par convention, je représenterai une valeur par une lettre, et le contenu d’un emplacement
par son nom entouré de parenthèses. Par exemple : « k » exprime une valeur, tandis que
« (var) » Signifie la « valeur contenue à l’adresse var »

« d » (destination) exprime l’endroit où le résultat de l’opération sera placé. Ce résultat


pourra être soit « f », soit « w ». Ce paramètre est facultatif, dans ce cas, MPASM considérera
que le résultat doit être placé dans le registre « f ». Ne rien mettre équivaut donc à inscrire
«,f »

« f » indique que la destination est un « file », ce qui, en terme de dénomination


Microchip, signifie simplement que la destination est le registre précisé dans l’instruction.

« w » précise que le résultat de l’opération se trouve dans le registre W (= WREG). Dans


ce cas, l’opération ne modifie pas le registre éventuellement précisé dans l’instruction.

« a » représente le type d’adressage direct utilisé, soit en access bank, soit en banked. Le
type d’adressage est toujours facultatif, et donc est représenté entre « [] ».

5.2 L’instruction « ADDLW »

Signification

ADD Litteral to W (ajouter valeur littérale au registre W)

Bits de STATUS affectés

N, OV, C, DC, Z

Description

Effectue une addition sur 8 bits entre le registre W (= WREG) et une valeur littérale
précisée dans l’instruction. Le résultat se trouve toujours dans le registre W.

Syntaxe

addlw k ; (W) + k Æ (W) avec k compris entre 0 et 0xFF

38
Taille et durée

1 mot (16 bits)


1 cycle

Exemple

W contient 0x10

addlw 0x05

W contient 0x15

5.3 L’instruction «ADDWF »

Signification

ADD W to File (Ajouter le registre W à la destination)

Bits de STATUS affectés

N, OV, C, DC, Z

Description

Effectue une addition sur 8 bits entre le registre désigné (f) et le registre W. Le résultat
sera placé soit dans W, soit dans f, selon le paramètre précisé comme destination.

Syntaxe

addwf f[,d,[a]] ; (W) + (f) Æ (d)

Taille et durée

1 mot (16 bits)


1 cycle

Notez que cette syntaxe précise que le paramètre « ,d » est facultatif, ainsi que le
paramètre « ,a ». Par contre, vous voyez que pour pouvoir préciser le paramètre « ,a », vous
êtes contraints également de préciser le paramètre de destination.

Vous pouvez donc écrire :

addwf variable ; résultat dans f


ou
addwf variable,f ; résultat dans f
ou
addwf variable,f,A ; résultat dans f, f est en access bank
mais pas
addwf variable,A ; interdit, car a est précisé et pas d

39
Exemple

W contient 0x50
variable contient 0x12

addwf variable,w ; 0x50 + 0x12, résultat dans W

W contient 0x62
var contient 0x12

5.4 L’instruction « ADDWFC »

Signification

ADD W to File with Carry (Ajout de W au registre avec carry)

Bits de STATUS affectés

N, OV, C, DC, Z

Description

Ajoute le contenu de W avec le contenu de F, ajoute également la valeur du carry (0 ou 1)


et place le résultat dans la destination. Cette instruction est très pratique lorsqu’on réalise des
opérations sur plus de 8 bits.

Syntaxe

addwfc f[,d[,a]] ; (f) + (c) + (w) Æ (d)

Taille et durée

1 mot (16 bits)


1 cycle

Exemple

On désire réaliser une addition sur 16 bits entre deux variables 16 bits : Soit var1 =
0x9580 et var2 = 0xF290. Le résultat sera placé la variable2, le report sera dans report.

L’organisation mémoire est la suivante, déclarée en zone CBLOCK :

var1 : 2 ; poids fort / poids faible de la variable1


var2 : 2 ; poids fort / poids faible de la variable2
report : 1 ; bit 16 du résultat

clrf report ; effacer le report


movf var1+1,w ; charger poids faible de var1 = 0x80
addwf var2+1,f ; ajouter au poids faible de var2, résultat dans var2

40
; attention, on utilise addwf et non addwfc
; 0x80 + 0x90 = 0x10 avec carry = 1
movf var1,w ; charger poids fort de var1 = 0x95
addwfc var2,f ; ajouter au poids fort de var2, avec le carry.
; cette fois, on utilise addwfc
; 0x95 + 0xF2 + 1 = 0x88 et carry = 1
clrf WREG ; effacer W
addwfc report ; ajouter 0 + C au report, donc ajouter carry en fait
; report = 0 + 0 + 1 = 1

Résultat final, nous avons dans

Report : 0x01
Var2 : 0x88
Var2+1 : 0x10

Si vous effectuez l’opération 0x9580 + 0xF290, vous trouvez bien : 0x18810

Vous pouvez maintenant effectuer des opérations sur des nombres plus grands qu’un octet
sans devoir faire sans arrêt des tests sur le bit C, comme c’était le cas avec les 16F.

5.5 L’instruction «ANDLW »

Signification

AND Litteral with W (Et logique d’une valeur littérale avec W)

Bits de STATUS affectés

N, Z

Description

Réalise un « et » logique entre le contenu du registre W et le nombre littéral précisé dans


l’instruction. L’opération réalise un « et » bit par bit. En général, cette instruction est utilisée
pour masquer des bits qu’on ne désire pas utiliser. Dans ce cas, les bits à masquer sont mis à 0
dans le littéral précisé.

Syntaxe

andlw k ; (w) and k Æ (w)

Taille et durée

1 mot (16 bits)


1 cycle

Exemple

W vaut 0x87

41
andlw 0x0F ; 0x87 and 0x0F

W vaut maintenant 0x07.

5.6 L’instruction «ANDWF »

Signification

AND W with File (ET logique du registre W avec un autre registre)

Bits de STATUS affectés

N, Z

Description

Réalise un « et » logique entre le registre W et le registre F précisé.

Syntaxe

andwf f[,d[,a]] ; (f) and (w) Æ (d)

Exemple

W contient 0x56
var contient 0xF0

andwf var,w ; 0x56 and 0xF0 Æ W

W contient 0x50
var contient 0xF0

5.7 L’instruction «BC »

Signification

Branch if Carry (brancher si carry est positionné)

Bit de STATUS affecté

Aucun

Description

Branchement (saut relatif court) si carry est positionné. Dans les 16F, si on désirait sauter
plus loin lorsque C était positionné, on devait utiliser un « btfsc STATUS,C » suivi d’un
« goto plusloin ». C’est désormais inutile.

Syntaxe

42
bc n ; Si C = 1, PC = PC + 2n
; avec n compris entre –128 et +127

Taille et durée

1 mot (16 bits)


2 cycles si on saute, 1 cycle si on ne saute pas.

Exemple

bc label ; sauter à l’étiquette label si C = 1


. . . . ; on continue ici si C = 0
. . . .
. . . .
label
. . . . ; on continue ici si C = 1

Label doit être à une distance de –128 à +127 mots à partir de l’instruction qui suit
l’instruction « bc ». Dans le cas contraire, vous aurez un warning de la part de MPASM. Si
c’était le cas, il vous reste à appliquer la méthode habituelle du « btfsc STAUTS,C », suivie
par un « bra » ou par un « goto » selon la distance.

Attention que la distance n’est pas PC + 2n à partir de la ligne courante, mais à partir de
l’instruction suivante : PC pointe toujours sur l’instruction suivante dans le déroulement d’un
programme.

5.8 L’instruction «BCF »

Signification

Bit Clear in File (placer le bit à 0 dans le registre)

Bit de STATUS affecté

Aucun

Description

Force le bit indiqué du registre précisé à « 0 »

Syntaxe

bsf f,b,[a] ; positionne le bit « b » du registre « f » à « 0 »


; b est compris entre 0 et 7

Taille et durée

1 mot
1 cycle

43
Exemple

bsf var,2 ; positionne le bit 2 de la variable var à 0.

5.9 L’instruction «BN »

Signification

Branch if Negative (brancher si résultat négatif)

Bit de STATUS affecté

Aucun

Description

Branchement (saut relatif court) si le bit N du registre STATUS est positionné

Syntaxe

bn n ; Si N = 1, (PC) = (PC) + 2n
; n est compris entre –128 et +127

Taille et durée

1 mot (16 bits)


2 cycles si on saute, 1 cycle si on ne saute pas.

Exemple

bn label ; sauter à l’étiquette label si N = 1

5.10 L’instruction «BNC »

Signification

Branch if Not Carry (brancher si carry pas positionné)

Bit de STATUS affecté

Aucun

Description

Branchement (saut relatif court) si le bit carry n’est pas positionné

Syntaxe

bnc n ; Si C = 0, (PC) = (PC) + 2n

44
; n est compris entre –128 et +127

Taille et durée

1 mot (16 bits)


2 cycles si on saute, 1 cycle si on ne saute pas.

Exemple

bnclabel ; sauter à l’étiquette label si C = 0

5.11 L’instruction «BNN »

Signification

Branch if Not Negative (brancher si résultat pas négatif)

Bit de STATUS affecté

Aucun

Description

Branchement (saut relatif court) si le bit N du registre STATUS n’est pas positionné

Syntaxe

bnn n ; Si N = 0, (PC) = (PC) + 2n


; n est compris entre –128 et +127

Taille et durée

1 mot (16 bits)


2 cycles si on saute, 1 cycle si on ne saute pas.

Exemple

bnn label ; sauter à l’étiquette label si N = 0

5.12 L’instruction «BNOV »

Signification

Branch if Not OVerflow (brancher si pas de débordement)

Bit de STATUS affecté

Aucun

45
Description

Branchement (saut relatif court) si le bit OV du registre STATUS n’est pas positionné.

Syntaxe

bnov n ; Si OV = 0, (PC) = (PC) + 2n


; n est compris entre –128 et +127

Taille et durée

1 mot
2 cycles si on saute, 1 cycle si on ne saute pas.

Exemple

bnov label ; sauter à l’étiquette label si OV = 0

5.13 L’instruction «BNZ »

Signification

Branch if Not Zero (brancher si résultat non nul)

Bit de STATUS affecté

Aucun

Description

Branchement (saut relatif court) si le bit Z du registre STATUS n’est pas positionné.

Syntaxe

bnz n ; Si Z = 0, (PC) = (PC) + 2n


; n est compris entre –128 et +127

Taille et durée

1 mot
2 cycles si on saute, 1 cycle si on ne saute pas.

Exemple

bnz label ; sauter à l’étiquette label si OV = 0

5.14 L’instruction «BRA »

Signification

46
BRanch Always (branchement inconditionnel)

Bit de STATUS affecté

Aucun

Description

Branchement inconditionnel long

Syntaxe

bra n ; (PC) = (PC) + 2n, avec n compris entre –1024 et +1023

Taille et durée

1 mot
2 cycles si on saute, 1 cycle si on ne saute pas.

Exemple

bra label ; sauter toujours à l’étiquette label

Attention, dans le cas de bra, la distance du saut est codée sur 11 bits, et non sur 8. De ce
fait, on peut sauter de –1024 à +1023 mots à partir de l’instruction qui suit le « bra »

Le « bra » est donc un « goto » en adressage relatif long.

5.15 L’instruction «BSF »

Signification

Bit Set in File (placer le bit à 1 dans le registre)

Bit de STATUS affecté

Aucun

Description

Force le bit indiqué du registre précisé à « 1 »

Syntaxe

bsf f,b,[a] ; positionne le bit « b » du registre « f » à « 1 »


; b est compris entre 0 et 7

Taille et durée

47
1 mot
1 cycle

Exemple

bsf WREG,2 ; positionne le bit 2 du registre W à 1.

Remarquez de nouveau que le registre W est maintenant accessible à toutes les


instructions, en précisant « WREG » comme nom de registre.

5.16 L’instruction «BTFSC »

Signification

Bit Test in File, Skip if Clear (tester le bit du registre, passer s’il vaut 0)

Bit de STATUS affecté

Aucun

Description

Vérifie dans le registre précisé le bit dont on précise le numéro. Si le bit vaut 0, on saute
l’instruction suivante.

Syntaxe

btfsc f,b[,a] ; Si le bit b de f = 0, PC = PC+2


; b est compris entre 0 et 7

Taille et durée

1 mot
2 cycles si on saute (voir chapitre sur les instructions 32 bits), 1 cycle si on ne saute pas .

Exemple

btfsc var,3 ; saute l’instruction suivante si le bit 3 de var = 0


. . . . ; on traite cette instruction si b3 = 1
. . . . ; on saute directement ici si b3 = 0

Attention, lisez attentivement le chapitre consacré aux instructions 32 bits. En effet, vu par
l’utilisateur, si l’instruction de test est suivie d’une instruction 32 bits, 1 cycle supplémentaire
sera perdu.

5.17 L’instruction «BTFSS »

Signification

48
Bit Test in File, Skip if Set (tester le bit du registre, passer s’il vaut 1)

Bit de STATUS affecté

Aucun

Description

Vérifie dans le registre précisé le bit dont on précise le numéro. Si le bit vaut 1, on saute
l’instruction suivante.

Syntaxe

btfss f,b[,a] ; Si le bit b de f = 1, (PC) = (PC) + 2


; b est compris entre 0 et 7

Taille et durée

1 mot
2 cycles si on saute (voir chapitre sur les instructions 32 bits), 1 cycle si on ne saute pas .

Exemple

btfss var,3 ; saute l’instruction suivante si le bit 3 de var = 1


movff var1,var2 ; on traite cette instruction si b3 = 0
. . . . ; on saute directement ici si b3 = 1

Attention, lisez attentivement le chapitre consacré aux instructions 32 bits. En effet, vu par
l’utilisateur, si l’instruction de test est suivie d’une instruction 32 bits, 1 cycle supplémentaire
sera perdu. C’est le cas dans cet exemple

5.18 L’instruction «BTG »

Signification

Bit ToGgle in file (inverser le bit du registre)

Bit de STATUS affecté

Aucun

Description

Inverse le bit désigné.

Syntaxe

btg f,b[,a] ; inverse le bit b du registre f.


; b est compris entre 0 et 7

49
Taille et durée

1 mot
1 cycle

Exemple

btg var1,3 ; inverse le bit 3 de la variable var1

Si le bit valait « 1 », il vaut maintenant 0, s’il valait « 0 », il vaut maintenant « 1 ». Voici


une instruction qui nous manquait cruellement dans la famille des mid-range.

5.19 L’instruction «BOV »

Signification

Branch if OVerflow (brancher si débordement)

Bit de STATUS affecté

Aucun

Description

Branchement si le bit OV du registre STATUS vaut 1.

Syntaxe

bov n ; Si OV = 1, (PC) = (PC)+ 2n


; n est compris entre –128 et +127

Taille et durée

1 mot
2 cycles si on saute, 1 cycle si on ne saute pas.

Exemple

bov label ; Si OV = 1, sauter à l’étiquette label

5.20 L’instruction «BZ »

Signification

Branch if Zero (brancher si résultat nul)

Bit de STATUS affecté

Aucun

50
Description

Branchement si le bit Z du registre STATUS vaut 1.

Syntaxe

bz n ; Si Z = 1, (PC) = (PC)+ 2n
; n est compris entre –128 et +127

Taille et durée

1 mot
2 cycles si on saute, 1 cycle si on ne saute pas.

Exemple

bz label ; Si Z = 1, sauter à l’étiquette label

N’oubliez pas que si le bit Z vaut 1, c’est que le résultat de la précédente opération
concernée donnait un résultat nul.

5.21 L’instruction «CALL »

Signification

CALL (appel)

Bit de STATUS affecté


Aucun

Description

Effectue un appel de sous-routine avec un adressage direct long.

Syntaxe

Call k[,FAST] ; appel de sous-routine à l’adresse k


; k représente n’importe quelle adresse de la zone mémoire
; programme
; le paramètre « ,FAST » précise si on utilise le mode
; de restauration automatique de W,STATUS, et BSR
Taille et durée

2 mots
2 cycles

Exemple

call label,FAST ; traite la sous-routine à l’adresse label avec retour rapide

51
Le paramètre « ,FAST » permet de générer une sauvegarde automatique des registres W,
BSR, et STATUS dans des registres internes au PIC : WS, BSRS, et STATUSS. Ces registres
pourront être restaurés automatiquement lors du retour de la sous-routine. Voyez le chapitre
consacré aux retours de type « fast ».

5.22 L’instruction «CLRF

Signification

CLeaR File (effacer registre)

Bit de STATUS affecté

Description

Place tous les bits du registre concerné à 0. N’agit évidemment pas sur les bits en lecture
seule.

Syntaxe

clrf f[,a] ; 0x00 Æ (f)

Taille et durée

1 mot
1 cycle

Exemple

clrf PORTA ; met tous les bits du buffer du PORTA à 0

Le bit Z sera automatiquement positionné après cette instruction

5.23 L’instruction «CLRWDT »

Signification

CLeaR WatchDog Timer (effacer timer du chien de garde)

Bits de RCON affectés

TO, PD

Description

52
Resette le timer du watchdog, afin d’éviter un reset par débordement.

Syntaxe

clrwdt ; resette le watchdog

Taille et durée

1 mot
1 cycle

Exemple

clrwdt ; resette le watchdog

Après l’exécution, le watchdog et son diviseur (le contenu, pas la valeur) sont remis à 0, et
les bits TO et PD du registre RCON sont positionnés.

5.24 L’instruction «COMF »

Signification

COMplement File (complémenter le registre)

Bits de STATUS affectés

N, Z

Description

Effectue l’inversion de tous les bits du registre précisé, ce qui équivaut à effectuer un
« complément à 1 ».

Syntaxe

comf f[,d[,a]] ; effectue le complément de f

Taille et durée

1 mot
1 cycle

Exemple

Si variable = 0x35

comf variable ; complément de variable

Variable = 0xCA

53
5.25 L’instruction «CPFSEQ »

Signification

ComPare File with w register, Skip if EQual (comparer le registre avec W, sauter s’ils
sont égaux)

Bit de STATUS affecté

Aucun

Description

Compare la valeur contenue dans W avec la valeur contenue dans le registre précisé. Si les
valeurs sont identiques, on passe l’instruction suivante.

Syntaxe

cpfseq f[,a] ; si (f) = (w), alors (PC) = (PC) + 2

Taille et durée

1 mot
2 cycles si on saute, 1 cycle si on ne saute pas.

Exemple

movlw 0x05 ; charger valeur de comparaison


cpfseq variable ; tester si variable = 0
bra traiterno ; non, traiter différent
. . . . ; oui, poursuivre ici
Notez qu’aucun bit de STATUS n’est positionné lors de cette comparaison. Cette méthode
permet de faire facilement des tests en cascade, sans devoir utiliser la technique des xorlw. Ni
le contenu de f, ni celui de W ne sont modifiés par cette opération.

5.26 L’instruction «CPFSGT »

Signification

ComPare File with w register, Skip if Greater Than (Comparer le registre avec W, sauter
s’il est supérieur)

Bit de STATUS affecté

Aucun

Description

54
Compare la valeur contenue dans W avec la valeur contenue dans le registre précisé. La
comparaison est faite avec des valeurs non signées (de 0 à 255). Si la valeur contenue dans le
registre F est strictement supérieure à celle contenue dans le registre W, alors on saute
l’instruction suivante.

Syntaxe

cpfsgt f[,a] ; si (f) > (w), alors (PC) = (PC) + 2

Taille et durée

1 mot
2 cycles si on saute, 1 cycle si on ne saute pas.

Exemple

movlw 0x05 ; charger valeur de comparaison


cpfsgt variable ; tester si variable > 5
bra traiterno ; non, traiter inférieure ou égale
. . . . ; oui, poursuivre ici

La comparaison s’effectue sur des nombres non signés. En cas d’égalité le saut n’aura pas
lieu.

5.27 L’instruction «CPFSLT »

Signification

ComPare File with w register, Skip if Less Than (comparer le registre avec W, sauter s’il
est inférieur)

Bit de STATUS affecté

Aucun

Description

Compare la valeur contenue dans W avec la valeur contenue dans le registre précisé. La
comparaison est faite avec des valeurs non signées (de 0 à 255). Si la valeur contenue dans le
registre F est strictement inférieure à celle contenue dans le registre W, alors on saute
l’instruction suivante.

Syntaxe

cpfslt f[,a] ; si (f) < (w), alors (PC) = (PC) + 2

Taille et durée

1 mot
2 cycles si on saute, 1 cycle si on ne saute pas.

55
Exemple

movlw 0x05 ; charger valeur de comparaison


cpfslt variable ; tester si variable < 5
bra traiterno ; non, traiter supérieure ou égale
. . . . ; oui, poursuivre ici

La comparaison s’effectue sur des nombres non signés. En cas d’égalité le saut n’aura pas
lieu.

5.28 L’instruction «DAW »

Signification

Decimal Adjust in W register (ajustement décimal dans W)

Bit de STATUS affecté

Description

Ajuste la valeur contenue dans le registre W pour la rendre conforme à un format BCD.

Syntaxe

daw ; (w) corrigé Æ (w)

Taille et durée

1 mot
1 cycle

Exemple

L’instruction n’est efficace que si vous avez précédemment effectué une addition de deux
variables, chacune étant déjà correctement formatée en mode BCD.

Lors de cette addition, vous pouvez obtenir une valeur qui n’est plus conforme à la norme
BCD, l’instruction DAW résout ce problème. Si la valeur obtenue ne tient pas sur 2 digits
BCD, le report se retrouvera dans le carry

Imaginons après une addition, le résultat incorrect suivant :

W = 0xC5
daw ; effectuer la correction

W = 0x35

56
C=1

Le résultat sera donc en réalité, au format BCD : 135

5.29 L’instruction «DECF »

Signification

DECrement File (décrémenter le registre)

Bits de STATUS affectés

C, DC, N, OV, Z

Description

Décrémente le registre f d’une unité sur 8 bits non signés. Si le registre valait 0, sa valeur
passe à 0xFF

Syntaxe

decf f[,f[,a]] ; (f)-1 Æ (d)

Taille et durée

1 mot
1 cycle

Exemple

decf variable,w ; on place le contenu de la variable décrémentée dans W

Attention, si vous précisez « ,w » comme destination, le contenu de la variable ne sera


évidemment pas modifié. Par contre, w contiendra la valeur de la variable décrémentée de 1.

ATTENTION : contrairement aux pics de la famille 16F, cette instruction modifie plusieurs
flags en plus du flag Z. Soyez prudents sur la récupération d’anciennes routines.

5.30 L’instruction «DECFSZ »

Signification

DECrement File, Skip if Zero (décrémenter le registre, sauter si le résultat est nul)

Bit de STATUS affecté

Aucun

Description

57
Décrémente le registre f d’une unité sur 8 bits non signés. Si le registre valait 0, sa valeur
passe à 0xFF. Si le résultat de cette décrémentation induit un résultat nul, l’instruction
suivante est passée

Syntaxe

decfsz f[,f[,a]] ; (f)-1 Æ (d). Si (d) = 0 Æ (PC) = (PC) + 2

Taille et durée

1 mot
2 cycles si on saute, 1 cycle si on ne saute pas.

Exemple

decfsz variable ; décrémenter variable


bra nozero ; si résultat > 0, alors on traite
. . . . ; suite ici si résultat = 0

Attention, si vous précisez « ,w » comme destination, le contenu de la variable ne sera


évidemment pas modifié. Par contre, w contiendra la valeur de la variable décrémentée de 1.
Le test fonctionnera toujours cependant correctement.

Attention, pour cette instruction, contrairement à l’instruction « decf », aucun bit du


registre STATUS n’est modifié.

5.31 L’instruction «DCFSNZ »

Signification

DeCrement File, Skip if Not Zero (décrémenter le registre, sauter si le résultat n’est pas
nul)

Bit de STATUS affecté

Aucun

Description

Décrémente le registre f d’une unité sur 8 bits non signés. Si le registre valait 0, sa valeur
passe à 0xFF. Si le résultat de cette décrémentation induit un résultat non nul, l’instruction
suivante est passée

Syntaxe

dcfsnz f[,f[,a]] ; (f)-1 Æ (d). Si (d) > 0 Æ (PC) = (PC) + 2

Taille et durée

58
1 mot
2 cycles si on saute, 1 cycle si on ne saute pas.

Exemple

dcfsnz variable ; décrémenter variable


bra zero ; si résultat = 0, alors on traite
. . . . ; suite ici si résultat > 0

Attention, si vous précisez « ,w » comme destination, le contenu de la variable ne sera


évidemment pas modifié. Par contre, w contiendra la valeur de la variable décrémentée de 1.
Le test fonctionnera toujours cependant correctement

5.32 L’instruction «GOTO »

Signification

GO TO (aller à)

Bit de STATUS affecté

Aucun

Description

Saut inconditionnel long à l’adresse spécifiée

Syntaxe

goto k ; k peut être n’importe quelle adresse valide de la mémoire


; programme

Taille et durée

2 mots
2 cycles

Exemple

goto label ; sauter à l’étiquette label

Attention, pour des raisons d’élégance de programmation et de compacité du code, utilisez


de préférence l’instruction « bra » chaque fois que c’est possible.

5.33 L’instruction «INCF »

Signification

INCrement File (incrémenter le registre)

59
Bits de STATUS affectés

C, DC, N, OV, Z

Description

Incrémente le registre f d’une unité sur 8 bits non signés. Si le registre valait 0xFF, sa
valeur passe à 0x00

Syntaxe

incf f[,f[,a]] ; (f)+1 Æ (d)

Taille et durée

1 mot
1 cycle

ATTENTION : contrairement aux pics de la famille 16F, cette instruction modifie plusieurs
flags en plus du flag Z. Soyez prudents sur la récupération d’anciennes routines.

Exemple

incf variable,w ; on place le contenu de la variable décrémentée dans W

5.34 L’instruction «INCFSZ »

Signification

INCrement File, Skip if Zero (incrémenter le registre, sauter si le résultat est nul)

Bit de STATUS affecté

Aucun

Description

Incrémente le registre f d’une unité sur 8 bits non signés. Si le registre valait 0xFF, sa
valeur passe à 0x00. Si le résultat de cette décrémentation induit un résultat nul, l’instruction
suivante est passée

Syntaxe

incfsz f[,f[,a]] ; (f)+1 Æ (d). Si (d) = 0 Æ (PC) = (PC) + 2

Taille et durée

1 mot
2 cycles si on saute, 1 cycle si on ne saute pas.

60
Exemple

incfsz variable ; incrémenter variable


bra nozero ; si résultat > 0, alors on traite
. . . . ; suite ici si résultat = 0

5.35 L’instruction «INFSNZ »

Signification

INcrement File, Skip if Not Zero (incrémenter le registre, sauter si le résultat n’est pas
nul)

Bit de STATUS affecté

Aucun

Description

Incrémente le registre f d’une unité sur 8 bits non signés. Si le registre valait 0xFF, sa
valeur passe à 0x00. Si le résultat de cette décrémentation induit un résultat non nul,
l’instruction suivante est passée

Syntaxe

infsnz f[,f[,a]] ; (f)+1 Æ (d). Si (d) > 0 Æ (PC) = (PC) + 2

Taille et durée

1 mot
2 cycles si on saute, 1 cycle si on ne saute pas.

Exemple

infsnz variable ; incrémenter variable


bra zero ; si résultat = 0, alors on traite
. . . . ; suite ici si résultat > 0

5.36 L’instruction «IORLW »

Signification

Inclusive OR Litteral with W (OU logique entre la valeur littérale et W)

Bits de STATUS affectés

N, Z

61
Description

Effectue un « ou inclusif » bit à bit entre la valeur précisée et le registre W. Le résultat est
placé dans W.

Syntaxe

iorlw k ; k or (W) Æ (W). K est compris entre 0 et 255

Taille et durée

1 mot
1 cycle

Exemple

W = 0x37

iorlw 0x0F ; (W) or 0x0F

W = 0x3F

Cette instruction sert typiquement pour forcer des bits à 1.

5.37 L’instruction «IORWF »

Signification

Inclusive OR W with File (OU logique entre le registre et W)

Bits de STATUS affectés

N, Z

Description

Effectue un « ou inclusif » entre le registre W et la valeur contenue dans le fichier précisé

Syntaxe

iorwf f[,d[,a]] ; (f) or (W) Æ (d)

Taille et durée

1 mot
1 cycle

Exemple

iorwf variable,w ; mettre dans W le résultat de (W) or (variable)

62
5.38 L’instruction «LFSR »

Signification

Load adress to FSR register (charger adresse dans registre FSR)

Bit de STATUS affecté

Aucun

Description

Charge l’adresse de la variable précisée dans le registre FSR concerné

Syntaxe

lfsr f,k ; f est compris entre 0 et 2 et représente le numéro du


; registre FSR concerné
; k représente l’adresse de la variable, dans toute la
; zone RAM possible

Taille et durée

2 mots
2 cycles

Exemple

lfsr FSR0,variable ; place l’adresse de la variable dans FSR0

N ‘oubliez pas qu’un registre FSR est constitué en réalité de deux registres de 8 bits. Cette
instruction effectue donc l’initialisation de deux registres en une seule instruction.

5.39 L’instruction «MOVF »

Signification

MOVe File to destination (copier le registre dans la destination)

Bits de STATUS affectés

N, Z

Description

Copie la valeur contenue dans le registre précisé vers la destination précisée.

Syntaxe

63
movf f[,d[,a]] ; (f) Æ (d)

Taille et durée

1 mot
1 cycle

Exemple

movf variable,w ; charger (variable) dans W

Notez que l’instruction « movf variable,f » copie le contenu de variable dans variable, ce
qui semble n’avoir aucun intérêt. Ce serait le cas si cette instruction ne positionnait pas en
même temps le bit Z, ce qui peut être utile pour un test éventuel, quoi que moins nécessaire
que pour la famille 16F.

Il est impératif ici de bien faire la distinction entre


movlw k ; charge la valeur k dans le registre W
et
movf f,w ; charge le contenu de la variable f dans le registre W

Dans le premier cas, c’est la valeur qui est chargée dans w, dans le second c’est le contenu
de l’emplacement spécifié.

5.40 L’instruction «MOVFF »

Signification

MOVe File to File (copier le registre dans un autre registre)

Bit de STATUS affecté

Aucun

Description

Copie un registre dans un autre registre, à travers toute la mémoire RAM, et sans
restriction de banque

Syntaxe

movff f1, f2 ; (f1) Æ (f2)


; f1 et f2 sont compris entre 0 et 4095

Taille et durée

2 mots
2 cycles

64
Exemple

movff variable,PORTB ; envoyer variable sur le PORTB

Il y a quelques restrictions à l’utilisation de cette puissance instruction :

- Vous ne pouvez pas l’utiliser pour modifier les paramètres d’interruption si les
interruptions sont en service
- Vous ne pouvez pas l’utiliser pour modifier PCL, TOSU, TOSH, ni TOSL

Notez que cette instruction ne modifie aucun flag ce qui la rend précieuse pour
sauvegarder les registres lors des interruptions (terminé les doubles swaps du 16F).

5.41 L’instruction «MOVLB »

Signification

MOVe Litteral to Bsr register (copier la valeur dans le registre BSR)

Bit de STATUS affecté

Aucun

Description

Copie la valeur contenue dans le registre précisé vers la destination précisée.

Syntaxe

movlb k ; k Æ (BSR). k est compris entre 0 et 15

Taille et durée

1 mot
1 cycle

Exemple

movlb 0x2 ; BSR pointe sur la banque 2

5.42 L’instruction «MOVLW »

Signification

MOVe Litteral to W (charger la valeur littérale dans W)

Bit de STATUS affecté

Aucun

65
Description

Charge la valeur précisée dans le registre W.

Syntaxe

movlw k ; k Æ (W)

Taille et durée

1 mot
1 cycle

Exemple

movlw 0x25 ; charger la valeur 0x25 dans le registre W.

5.43 L’instruction «MOVWF »

Signification

MOVe W to File (copier le contenu de W dans un registre)

Bit de STATUS affecté

Aucun

Description

Copie la valeur contenue dans le registre W vers le registre précisé.

Syntaxe

movwf f[,a] ; (W) Æ (f)

Taille et durée

1 mot
1 cycle

Exemple

movwf variable ; sauve le contenu de W dans variable

Prenez garde au fait que cette instruction ne modifie pas les bits de STATUS.

5.44 L’instruction «MULLW »

66
Signification

MULtiply Litteral with W (multiplication de W par une valeur littérale)

Bit de STATUS affecté

Aucun

Description

Multiplie la valeur précisée avec le contenu de W. Le résultat sera placé dans deux
registres spécifiques, PRODH et PRODL contenant respectivement le poids fort et le poids
faible du résultat de la multiplication.

Il s’agit d’une multiplication non signée. L’utilisateur prendra en charge les modifications
nécessaires à la réalisation d’une multiplication signée.

Le registre W ne sera pas modifié par l’opération.

Syntaxe

mullw k ; (w) * k Æ (PRODH)(PRODL)


; avec k compris entre 0 et 255

Taille et durée

1 mot
1 cycle

Exemple

mullw 0x12 ; multiplier W par 0x12, résultat dans PRODH PRODL

5.45 L’instruction «MULWF »

Signification

MULtiply W with File (multiplier W avec le registre)

Bit de STATUS affecté

Aucun

Description

Multiplie le registre W avec le registre F. Le résultat sera placé dans deux registres
spécifiques, PRODH et PRODL contenant respectivement le poids fort et le poids faible du
résultat de la multiplication.

67
Il s’agit d’une multiplication non signée. L’utilisateur prendra en charge les modifications
nécessaires à la réalisation d’une multiplication signée.

Aucun autre registre n’est modifié par l’opération

Syntaxe

mulwf f[,a] ; (w) * (f) Æ (PRODH)(PRODL)

Taille et durée

1 mot
1 cycle

Exemple

mulwf variable ; multiplier W par le contenu de variable


; résultat dans PRODH PRODL

5.46 L’instruction «NEGF »

Signification

Negate File (Inverser le signe du registre)

Bits de STATUS affectés

N, OV, C, DC, Z

Description

Réalise un complément à deux du registre désigné. Le complément à deux consiste à


inverser tous les bits de l’octet, puis à ajouter 1. Le nombre représenté en signé devient alors
le négatif du nombre précédemment représenté en notation signée.

Syntaxe

negf f[,a] ; -(f) Æ (f)

Taille et durée

1 mot
1 cycle

Exemple

W = 0x3A

negf WREG ; complément W à 2

68
W = 0xC6

5.47 L’instruction «NOP »

Signification

No OPeration (pas d’opération)

Bit de STATUS affecté

Aucun

Description

N’effectue aucune opération.

Syntaxe

nop ; pas d’opération

Taille et durée

1 mot
1 cycle

Exemple

nop ; pas d’opération

Cette instruction qui semble ne servir à rien, est utilisée la plupart du temps, soit pour
perdre un cycle, soit dans certaines conditions spéciales qui sont traitées dans ce document.
Vous retrouverez donc de temps en temps cette instruction.

5.48 L’instruction «POP »

Signification

POP top of stack (dépiler le dessus de la pile)

Bit de STATUS affecté

Aucun

Description

Retire les 21 bits sauvegardés au sommet de la pile. En réalité, se contente de décrémenter


le pointeur de pile

Syntaxe

69
pop ; (pointeur de pile) –1 Æ (pointeur de pile)

Taille et durée

1 mot
1 cycle

Exemple

PILE :
0x001234 (TOS)
0x123456 (sommet – 1)
0x165432 (sommet – 2)

PC : 0x02468A

pop ; retrait d’une valeur de la pile

PILE :
0x123456 (TOS)
0x165432 (sommet – 1)

PC : 0x2468C

5.49 L’instruction «PUSH »

Signification

PUSH pc on top of stack (empiler sur le sommet de la pile)

Bit de STATUS affecté

Aucun

Description

Incrémente le pointeur de pile, et place le contenu du PC sur le sommet de la pile

Syntaxe

push ; (pointeur de pile) +1 Æ (pointeur de pile). (PC) Æ (TOS)

Taille et durée

1 mot
1 cycle

Exemple

70
PILE :
0x001234 (TOS)
0x123456 (sommet – 1)

PC : 0x02468A

push ; placer le PC sur la pile

PILE :
0x02468C
0x001234 (sommet – 1)
0x123456 (sommet – 2)

Prenez garde au fait qu’après avoir chargé l’instruction « push », le PC est alors
incrémenté de 2. Autrement dit, le PC contient à ce moment la valeur qu’il avait avant le
chargement de l’instruction + 2. Vous placez donc sur la pile l’adresse de l’instruction qui suit
l’instruction « push ».

5.50 L’instruction «RCALL »

Signification

Relative CALL to subroutine (appel de sous-routine en adressage relatif)

Bit de STATUS affecté

Aucun

Description

Génère un saut relatif de type long vers une sous-routine. L’adresse de retour est
mémorisée sur le sommet de la pile.

Syntaxe

rcall n ; (PC)Æ TOS. (PC) + 2n Æ (PC)


; n est compris entre –1024 et +1023

Taille et durée

1 mot
2 cycles

Exemple

rcall label ; saute à la sous-routine label


. . . . ; après le retour, le déroulement se poursuit ici

71
Utilisez l’instruction « RCALL » en place de l’instruction « CALL » chaque fois que c’est
possible. Si vous tentez d’effectuer un « RCALL » à une adresse trop lointaine, vous serez de
toutes façons prévenus par un warning de MPASM.

5.51 L’instruction «RESET »

Signification

RESET software

Bits affectés

Voir tableau des registres pour connaître tous les registres affectés par un reset software.

Description

Effectue un reset du PIC. Ceci n’est utile réellement qu’en de rares circonstances.
Normalement, un reset software peut toujours être évité avec une programmation structurée
correcte. Cependant, pour certaines applications, il peut s’avérer pratique de disposer de cette
instruction.

Syntaxe

reset ; reset du pic et de tous les registres concernés

Taille et durée

1 mot
1 cycle

Exemple

reset ; reset du pic et de tous les registres concernés

Notez que le datasheet de Microchip indique un seul cycle nécessaire pour effectuer le
reset. Il est assez compliqué de vérifier ceci en pratique, je vous donne donc l’information
« comme telle ».

5.52 L’instruction «RETFIE »

Signification

RETurn From Interrupt Execution (retour d’interruption)

Bits de INTCON affectés

GIE/GIEH, PEIE/GIEL

Description

72
Effectue un retour de sous-routine

Syntaxe

retfie [FAST] ; (TOS) Æ (PC)


; 1 Æ GIE/GIEH ou dans PEIE/GIEL
; si FAST : (BSRS) Æ (BSR), (WS) Æ (W)
; (STATUSS) Æ (STATUS)

Taille et durée

1 mot
2 cycles

Exemple

retfie FAST ; retour avec restauration rapide

Voyez le chapitre consacré aux retours rapides et celui sur les interruptions pour plus de
détails.

5.53 L’instruction «RETLW »

Signification

RETurn from subroutine with Litteral in W (retour de sous-routine avec valeur littérale
dans W

Bit de STATUS affecté

Aucun

Description

Effectue un retour de sous-routine, avec la valeur précisée dans le registre W.

Syntaxe

retlw k ; (TOS) Æ (PC). k Æ (W)


; k est compris entre 0 et 255

Taille et durée

1 mot
2 cycles

Exemple

retlw 0x25 ; effectue un retour avec 0x25 dans le registre W.

73
Permet facilement de retourner une valeur représentant un état de l’exécution de la sous-
routine (code d’erreur par exemple)

5.54 L’instruction «RETURN »

Signification

RETURN from subroutine (retour de sous-routine)

Bit de STATUS affecté

Aucun

Description

Effectue le retour de la sous-routine à l’adresse mémorisée dans le TOS.

Syntaxe

return [FAST] ; (TOS) Æ (PC)


; 1 Æ GIE/GIEH ou dans PEIE/GIEL
; si FAST : (BSRS) Æ (BSR), (WS) Æ (W)
; (STATUSS) Æ (STATUS)

Taille et durée

1 mot
2 cycles

Exemple

return ; retour de sous-routine

Pour plus de détails sur les retours rapides, voyez le chapitre consacré à ce sujet.

5.55 L’instruction «RLCF »

Signification

Rotate Left through Carry on File (rotation à gauche du registre à travers le carry)

Bits de STATUS affectés

C, N, Z

Description

74
Effectue une rotation à gauche sur 9 bits du registre précisé. Le bit 7 passe dans le carry,
l’ancien carry passe dans le bit 0.

Syntaxe

rlcf f[,d[,a]] ; Tous les bits sont décalés à gauche. (C) Æ b0, b7 Æ (C)

Taille et durée

1 mot
1 cycle

Exemple

var = B’01101101’
C=1

rlcf var,f ; rotation de var sur 9 bits

var = B’11011011’
C=0

rlcf var,f ; rotation de var sur 9 bits

var = B ‘10110110’
C=1

5.56 L’instruction «RLNCF »

Signification

Rotate Left, No Carry, on File (rotation à gauche du registre sans utilisation du carry)

Bits de STATUS affectés

N, Z

Description

Effectue une rotation à gauche sur 8 bits du registre précisé. L’ancien bit 7 devient le
nouveau bit 0

Syntaxe

rlncf f[,d[,a]] ; Tous les bits sont décalés à gauche. (b7) Æ b0

Taille et durée

75
1 mot
1 cycle

Exemple

var = B’01101101’

rlncf var,f ; rotation de var sur 8 bits

var = B’11011010’

rlncf var,f ; rotation de var sur 8 bits

var = B ‘10110101’

5.57 L’instruction «RRCF »

Signification

Rotate Right through Carry on File (rotation à droite du registre à travers le carry)

Bits de STATUS affectés

C, N, Z

Description

Effectue une rotation à droite sur 9 bits du registre précisé. Le bit 0 passe dans le carry,
l’ancien carry passe dans le bit 7.

Syntaxe

rrcf f[,d[,a]] ; Tous les bits sont décalés à droite. (C) Æ b7, b0 Æ (C)

Taille et durée

1 mot
1 cycle

Exemple

var = B’01101110’
C=1

rrcf var,f ; rotation de var sur 9 bits

var = B’10110111’
C=0

76
rrcf var,f ; rotation de var sur 9 bits

var = B ‘01011011’
C=1

5.58 L’instruction «RRNCF »

Signification

Rotate Right, No Carry, on File (rotation à droite du registre sans utilisation du carry)

Bits de STATUS affectés

N, Z

Description

Effectue une rotation à droite sur 8 bits du registre précisé. L’ancien bit 0 devient le
nouveau bit 7

Syntaxe

rrncf f[,d[,a]] ; Tous les bits sont décalés à droite. (b0) Æ (b7)

Taille et durée

1 mot
1 cycle

Exemple

var = B’01101101’

rrncf var,f ; rotation de var sur 8 bits

var = B’10110110’

rrncf var,f ; rotation de var sur 8 bits

var = B ’01011011’

5.59 L’instruction «SETF »

Signification

SET File (place tous les bits du registre à 1)

Bit de STATUS affecté

77
Aucun

Description

Place tous les bits possibles du registre concerné à 1. N’agit évidemment pas sur les bits
en lecture seule.

Syntaxe

setf f[,a] ; 0xFF Æ (f)

Taille et durée

1 mot
1 cycle

Exemple

setf TRISB ; place toutes les lignes du PORTB en entrée

5.60 L’instruction «SLEEP »

Signification

enter pic in SLEEP mode (passer le pic en mode sommeil)

Bits de RCON affectés

TO, PD

Description

Place le pic en mode sommeil, resette le watchdog et le contenu de son diviseur.

Syntaxe

sleep ; 0x00 Æ (WDT), 1 Æ TO, 0 Æ PD

Taille et durée

1 mot
1 cycle

Exemple

sleep ; passer en mode sommeil

Le pic restera en sommeil jusqu’à survenance d’un événement prévu (voir chapitre sur le
mode sleep)

78
5.61 L’instruction «SUBFWB »

Signification

SUBstract File from W with Borrow (soustraire le registre de W en utilisant l’emprunt)

Bits de STATUS affectés

N, OV, C, DC, Z

Description

Effectue une soustraction du registre hors de W, avec emprunt. L’emprunt est en réalité
l’inverse du bit carry

Syntaxe

subfwb f[,d[,a]] ; (w) – (f) - !(C) Æ (d)

Taille et durée

1 mot
1 cycle

Exemple

var = 0x50
W = 0x02
C=1

subfwb ; 0x02 – 0x50 – 0x00 (complément de 1)

var = 0xB2
W = 0x02
C = 0 : un emprunt a du être effectué, le résultat doit être interprété en conséquence

Le carry à 0 indique qu’il y aura un report sur la soustraction suivante, si la soustraction


porte sur 16 bits ou plus.

movlw 0xD4 ; charger D4


subfwb,w ; 0xD4 – 0xB2 – 0x01 (complément de 0)

var = 0xB2
W = 0x21
C=1 : aucun emprunt n’a été nécessaire

5.62 L’instruction «SUBLW »

79
Signification

SUBstract W from Litteral (soustraire W de la valeur littérale)

Bits de STATUS affectés

N, OV, C, DC, Z

Description

Soustrait (sans utilisation du report) la valeur du registre W de la valeur littérale

Syntaxe

sublw k ; k – (W) Æ (W)


; avec k compris entre 0 et 255

Taille et durée

1 mot
1 cycle

Exemple

W = 0x5

sublw 0x25 ; effectue 0x25 – 0x05

W = 0x20
C=1

ATTENTION, vous n’effectuez pas une soustraction de la valeur précisée hors de W,


mais exactement le contraire. C’est W qui est soustrait de la valeur. C’est un peu curieux,
d’autant que la syntaxe de l’instruction laisserait sous-entendre le contraire (SUBLW =
substract L from W ?), ce qui n’est pas le cas.

Si le bit C est positionné, alors l’opération n’a pas nécessité d’emprunt.

5.63 L’instruction «SUBWF »

Signification

SUBstract W from File (soustraire W du registre)

Bits de STATUS affectés

N, OV, C, DC, Z

Description

80
Soustrait la valeur contenue dans W de celle contenue dans le registre sans utiliser le carry

Syntaxe

subwf f[,d[,a]] ; (f) – (W) Æ (d)

Taille et durée

1 mot
1 cycle

Exemple

var = 0x53

movlw 0x20 ; valeur à soustraire


subwf var,f ; 0x53 – 0x20

var = 0x33
C = 1 : aucun emprunt nécessaire

5.64 L’instruction «SUBWFB »

Signification

SUBstract W from File with Borrow (soustraire W du registre en utilisant l’emprunt)

Bits de STATUS affectés

N, OV, C, DC, Z

Description

Effectue une soustraction de W hors du registre, avec emprunt. L’emprunt est en réalité
l’inverse du bit carry. Cette opération est l’inverse de SUBFWB.

Syntaxe

subwfb f[,d[,a]] ; (f) – (W) - !(C) Æ (d)

Taille et durée

1 mot
1 cycle

Exemple

var = 0x02
W = 0x50
C=1

81
subwfb ; 0x02 – 0x50 – 0x00 (complément de 1)

var = 0xB2
W = 0x02
C = 0 : un emprunt a du être effectué, le résultat doit être interprété en conséquence

Le carry à 0 indique qu’il y aura un report sur la soustraction suivante, si la soustraction


porte sur 16 bits ou plus.

movlw 0x54 ; charger D4


subwfb,w ; 0xB2 – 0x54 – 0x01 (complément de 0)

var = 0xB2
W = 0x5D
C=1 : aucun emprunt n’a été nécessaire

Attention, veillez à ne pas confondre « SUBWFB » avec « SUBFWB ».

5.65 L’instruction «SWAPF »

Signification

SWAP File (inverser les quartets du registre)

Bit de STATUS affecté

Aucun

Description

Effectue une permutation des deux quartets qui composent l’octet contenu dans le registre
désigné.

Syntaxe

swapf f[,a] ; les bits 7 à 4 sont permutés avec les bits 3 à 0

Taille et durée

1 mot
1 cycle

Exemple

var = 0x35

swapf var,f ; « swapper » var

var = 0x53

82
5.66 L’instruction «TBLRD »

Signification

TaBLe ReaD (lecture de table)

Bit de STATUS affecté

Aucun

Description

Effectue une lecture de l’octet en mémoire flash pointé par le registre TBLPTR et le copie
dans le registre TABLAT.

Syntaxes possibles

tblrd* ; octet pointé par TBLPTR Æ (TABLAT)


tblrd*+ ; octet pointé par TBLPTR Æ (TABLAT), (TBLPTR)+1 Æ (TBLPTR)
tblrd*- ; octet pointé par TBLPTR Æ (TABLAT), (TBLPTR)-1 Æ (TBLPTR)
tblrd+* ; (TBLPTR)+1 Æ (TBLPTR), octet pointé par TBLPTR Æ (TABLAT)

Taille et durée

1 mot
2 cycles

Exemple

Je vous renvoie au chapitre concernant les accès en mémoire programme

5.67 L’instruction «TBLWT »

Signification

TaBLe WriTe (écriture dans la table)

Bit de STATUS affecté

Aucun

Description

Effectue une écriture de l’octet contenu dans TABLAT vers le buffer d’écriture flash, à
l’emplacement pointé par les 3 bits de poids faible de TBLPTR.

Syntaxes possibles

83
tblwt* ; (TABLAT) -> buffer
tblwt*+ ; (TABLAT) -> buffer, (TBLPTR)+1 Æ (TBLPTR)
tblwt*- ; (TABLAT) -> buffer (TBLPTR)-1 Æ (TBLPTR)
tblwt+* ; (TBLPTR)+1 Æ (TBLPTR), (TABLAT) -> buffer

Taille et durée

1 mot
2 cycles

Exemple

Je vous renvoie au chapitre concernant les accès en mémoire programme

5.68 L’instruction «TSTFSZ »

Signification

TeST File, Skip if Zero (teste le registre, passe l’instruction suivante si nul)

Bit de STATUS affecté

Aucun

Description

Teste le registre précisé. Si ce registre vaut 0, alors l’instruction suivante n’est pas
exécutée.

Syntaxe

tstfsz f[,a] ; if (f) = 0 Æ (PC)+2 Æ (PC)

Taille et durée

1 mot
2 cycles si on saute, 1 cycle si on ne saute pas.

Exemple

tstfsz WREG ; teste si W = 0


bra nozero ; traiter W > 0
. . . . ; traiter W = 0

Je rappelle de temps en temps que toutes les instructions s’appliquent également au


registre W.

84
5.69 L’instruction «XORLW »

Signification

eXclusive OR Litteral with W (OU exclusif logique entre la valeur littérale et W)

Bits de STATUS affectés

N, Z

Description

Effectue un « ou exclusif » bit à bit entre la valeur précisée et le registre W. Le résultat est
placé dans W.

Syntaxe

xorlw k ; k xor (W) Æ (W). K est compris entre 0 et 255

Taille et durée

1 mot
1 cycle

Exemple

W = 0xB5

iorlw 0x0F ; (W) xor 0x0F

W = 0xBA

Cette instruction sert typiquement pour inverser des bits ou effectuer des comparaisons. Je
rappelle que :

0 xor 0 = 0
0 xor 1 = 1
1 xor 0 = 1
1 xor 1 = 0

Donc, effectuer un xor avec un bit à 1 inverse le bit, et réciproquement, un bit de résultat
vaut 0 si les deux bits étaient identiques

5.70 L’instruction «XORWF »

Signification

eXclusive OR W with File (OU exclusif logique entre le registre et W)

Bits de STATUS affectés

85
N, Z

Description

Effectue un « ou exclusif » entre le registre W et la valeur contenue dans le fichier précisé

Syntaxe

xorwf f[,d[,a]] ; (f) xor (W) Æ (d)

Taille et durée

1 mot
1 cycle

Exemple

xorwf variable,w ; mettre dans W le résultat de (W) xor (variable)

Ceci clôture l’analyse de nos 75 instructions. Mais, allez-vous me dire, il n’y en a pas 75 ?
En fait si, tout dépend de la façon dont on calcule.

Vous en avez ici 69. Si vous vous souvenez que l’instruction tlbrd comporte en réalité 4
instructions différentes au lieu d’une, et que c’est le cas également pour tblwt, ça nous fait
bien : 69 + 6 = 75 instructions.

86
6. Lectures et écritures en mémoire programme

6.1 Les nouveaux mécanismes

Plutôt que les tableaux de « retlw » peu pratiques, et que les opérations de lecture en
mémoire flash longues et contraignantes comme sur les 16F, nous avons maintenant une
méthode puissante pour lire les données directement dans la mémoire flash.

Pour l’écriture, cette même méthode va nous simplifier la vie, car elle permet l’écriture de
8 octets simultanément, et raccourci les temps nécessaires. Par contre l’obligation d’écriture
par paquet nous compliquera un peu la vie si nous ne désirons écrire qu’un seul et unique
octet.

Quoi qu’il en soit, nous effectuerons probablement beaucoup plus de lectures en mémoire
flash que d’écritures, ces mécanismes vont donc nous être précieux.

6.2 La lecture

La lecture d’un ou plusieurs octets en mémoire flash va dorénavant s’effectuer au travers


de 2 registres particuliers, et d’une instruction, déclinable en plusieurs modes de
fonctionnement.

Le principe général est le suivant :

- On initialise un pointeur sur la mémoire flash


- On lance une instruction de lecture
- On récupère l’octet lu dans un registre spécifique.

6.2.1 Le registre « TBLPTR »

Voici donc le premier de ces registres, à savoir le pointeur. Puisqu’il permet de pointer sur
l’intégralité de la mémoire programme, ce registre contient 21 bits, répartis dans 3 sous-
registres :

TBLPTRU : contient les bits 20 à 16


TBLPTRH : contient les bits 15 à 8
TBLPTRL : contient les bits 7 à 0

Etant donné que nos 18Fxx8 actuels n’adressent qu’un maximum de 32Ko de mémoire
programme, TBLPTRU vaudra toujours 0, et pourra être ignoré dans tous nos programmes. Je
vous l’indique cependant pour le cas où vous utiliseriez un jour un pic de cette famille
disposant de plus de 64K de mémoire programme.

Comme nous l’avons vu, la première étape consiste donc à initialiser notre pointeur. Petite
remarque en passant, pour la lecture dans la mémoire flash, vous n’êtes plus contraints
d’utiliser des adresses multiples de 2. Autrement dit, vous pouvez lire 2 octets par mot
d’instruction, vous ne perdez donc pas de place en utilisant cette méthode, au contraire des

87
tableaux de « retlw » qui vous renvoient un octet par instruction (donc par mot écrit en
mémoire programme).

Voici une routine pour initialiser notre pointeur, en imaginant que l’octet à lire se trouve à
l’adresse « add ».

movlw UPPER(add) ; charger bits 16 à 21 de l’adresse


movwf TBLPTRU ; dans pointeur UPPER
movlw HIGH(add) ; charger bits 8 à 15 de l’adresse
movwf TBLPTRH ; dans pointeur HIGH
movlw LOW(add) ; charger bits 0 à 7 de l’adresse
movwf TBLPTRL ; dans pointeur LOW

Bien entendu, rien ne vous empêche de vous créer une petite macro pour effectuer cette
opération.

Pour les 4 sortes de 18Fxx8 disponibles actuellement, la zone mémoire étant limitée à
32Ko, vous pouvez raccourcir cette procédure en :

movlw HIGH(add) ; charger bits 8 à 14 de l’adresse


movwf TBLPTRH ; dans pointeur HIGH
movlw LOW(add) ; charger bits 0 à 7 de l’adresse
movwf TBLPTRL ; dans pointeur LOW

Vous allez penser que c’est bien contraignant d’effectuer toutes ces opérations pour lire un
octet, surtout si vous avez toute une série d’octets à lire. Rassurez-vous, dans ce cas,
Microchip a prévu des options pour le moins intéressantes.

6.2.2 L’instruction « TBLRD »

C’est cette instruction qui va permettre de lire l’octet qu’on a précédemment pointé avec
notre registre TBLPTR.

Le simple fait d’écrire :

tblrd* ; lire un octet en mémoire flash

provoque la lecture de l’octet. Notez le symbole « * » situé dans l’instruction. Cette étoile
représente l’instant de la lecture, vous allez comprendre.

En réalité, l’instruction TBLRD n’est pas unique, elle se répartit en 4 instructions qui
exécutent la même fonction de base, mais avec des répercussions différentes. En fait, on
pourrait dire qu’il s’agit d’une forme d’adressage dans le même style que celles concernant
les registres FSR.

Vous avez donc 4 possibilités d’écriture :

tblrd* ; effectue la lecture de l’octet pointé par TBLPTR


tblrd*+ ; effectue la lecture, et ensuite incrémente TBLPTR
tblrd*- ; effectue la lecture, et ensuite décrémente TBLPTR
tblrd+* ; incrémente TBLPTR, et ensuite effectue la lecture

88
Vous comprenez immédiatement les avantages de ces instructions. En effet, après ou
avant avoir lu un octet, le pointeur TBLPTR est mis à jour pour pointer sur l’octet suivant,
dans l’ordre où vous décidez de parcourir la table. Comme il s’agit d’une incrémentation ou
d’une décrémentation sur 3 octets, ceci vous évite bien des instructions.

6.2.3 Le registre TABLAT

Nous avons initialisé le pointeur, puis effectué une lecture. Il faut maintenant récupérer
l’octet lu. Où se trouve-t-il ? Tout simplement dans un registre spécialisé, TABLAT.

Nous avons maintenant tout ce qu’il nous faut pour réaliser une lecture d’une table dans la
mémoire flash.

Imaginons un exemple simple : on veut transférer 30 octets contenus à partir de l’adresse


flash 0x0A5213 dans un tableau qui commence à l’adresse 0x20 de la banque 2.

; initialisations
; ---------------
movlw HIGH(add) ; charger bits 8 à 14 de l’adresse
movwf TBLPTRH ; dans pointeur HIGH
movlw LOW(add) ; charger bits 0 à 7 de l’adresse
movwf TBLPTRL ; dans pointeur LOW
movlw .30 ; 30 octets à lire
movwf cmpt ; dans la variable cmpt en access bank
lfsr FSR0,0x220 ; pointer sur variable 0x20 en banque 2

; lectures
; --------
loop
tblrd*+ ; lire un octet, pointer sur le suivant
movff TABLAT,POSTINC0 ; transférer en RAM, pointer sur emplacement suivant
decfsz cmpt ; décrémenter compteur d’octets
bra loop ; pas dernier, suivant

Vous avez vu la taille de la boucle ? Vous voulez essayer de faire la même chose avec un
16F ?

6.3 Procédure d’effacement

Nous avons vu comment lire en mémoire programme, lecture qui s’effectue à n’importe
quelle adresse, et qui concerne un seul octet à la fois.

Avant d’examiner comment écrire dans cette mémoire, nous allons apprendre comment
l’effacer.

En effet, malheureusement, il est impossible d’écrire dans la mémoire programme si


l’emplacement dans lequel nous écrivons n’a pas été préalablement effacé. En fait, on peut
forcer un bit à 0, mais pas le ramener à 1, ce qui explique cette procédure, l’effacement d’un
octet en mémoire consistant à ramener tous ses bits à 1.

89
Nous nous trouvons à ce niveau devant une contrainte, à savoir qu’on ne peut pas effacer
un octet précis, mais uniquement un bloc constitué de 64 octets.

La zone a effacer est pointée de nouveau par notre pointeur flash TBLPTR.

Le début de ce bloc a une adresse alignée sur un multiple de 64, et donc, les 6 bits de
poids faible de TBLPTR seront ignorés (considérés comme étant à 0). Le bloc effacé sera
composé des octets compris entre :

Octet à l’adresse : B’000xxxxx xxxxxxxx xx000000’


Et
Octet à l’adresse : B’000xxxxx xxxxxxxx xx111111’

Autrement dit, vous comprenez déjà la grosse contrainte qui vous attend si vous souhaitez
écrire un seul octet en mémoire flash :

- Vous commencez par lire les 64 octets qui composent le bloc dans une zone RAM
- Vous effacez le bloc complet
- Vous modifier en RAM l’octet à écrire
- Vous réécrivez les 64 octets en flash

Je sais, c’est pénible, mais il n’y a pas moyen d’y couper. L’écriture en mémoire flash
n’est pas du tout facilitée, au contraire de la lecture. De toutes façons, il faut toujours
éviter au maximum d’écrire en mémoire programme, car ça diminue la durée de vie du
PIC, et en plus ça le place à l’arrêt durant l’écriture.

Mais bon, revenons à l’effacement. Après avoir initialiser votre TBLPTR exactement
comme pour la routine de lecture, vous devez utiliser une séquence imposée par Microchip
pour provoquer l’ordre d’effacement :

; initialisations
; ---------------
movlw HIGH(add) ; charger bits 8 à 14 de l’adresse
movwf TBLPTRH ; dans pointeur HIGH
movlw LOW(add) ; charger bits 0 à 7 de l’adresse
movwf TBLPTRL ; dans pointeur LOW

; séquence d’effacement
; ---------------------
bsf EECON1,EEPGD ; pointer sur la mémoire flash
bcf EECON1,CFGS ; accès autorisé à la mémoire flash
bsf EECON1,WREN ; écritures autorisées
bsf EECON1,FREE ; indique une procédure d’effacement
bcf INTCON,GIE ; interdire les interruptions
movlw 0x55 ; séquence imposée
movwf EECON2
movlw 0xAA
movwf EECON2
bsf EECON1,WR ; lancer l’effacement (arrêt du pic)
nop ; instruction ignorée à la remise en marche
bsf INTCON,GIE ; remettre les interruptions si nécessaire

La procédure d’effacement dure à peu près 2ms, ce qui signifie qu’entre l’exécution de la
ligne bsf EECON1,WR et la remise en service de vos interruptions, 2ms se seront écoulées.

90
L’instruction « nop » est obligatoire pour une exécution correcte.

6.4 L’écriture

La première chose à savoir, c’est que vous ne pouvez pas écrire un seul octet en mémoire
flash. Toute écriture doit se faire au minimum sur 8 octets.

La seconde chose à savoir, c’est que l’écriture s’effectue sur des adresses dont la première
doit être un multiple de 8. Autrement dit, pour une écriture, vous configurez impérativement
TBLPTR pour que les bits 0 à 2 de TBLPTRL soient égaux à 0.

La troisième chose, c’est que vous ne pouvez écrire que sur un bloc mémoire effacé.
Donc, voyez la procédure précédente.

Ensuite, l’écriture s’effectue en deux parties : d’une part l’écriture des 8 octets dans un
buffer interne. D’autre part, une fois le buffer chargé, l’écriture réelle s’effectuera via une
séquence imposée. Il est impératif de savoir que l’écriture s’effectuera dans le bloc de 8 octets
pointé par le registre TBLTR, le bloc commençant à une adresse multiple de 8.

Les 8 octets placés dans le buffer seront écrits à l’adresse précisée par TBLPTR entre
l’adresse :

Adresse de début : B « 000xxxxx xxxxxxxx xxxxx000 »


Et
Adresse de fin : B « 000xxxxx xxxxxxxx xxxxx111 »

Les 3 bits de poids faible de TBLPTR seront donc ignorés.

6.4.1 L’instruction « TBLWT »

De nouveau, l’instruction TBLWT s’utilise en 4 syntaxes différentes :

tblwt* ; effectue l’écriture de l’octet pointé par TBLPTR


tblwt*+ ; effectue l’écriture, et ensuite incrémente TBLPTR
tblwt*- ; effectue l’écriture, et ensuite décrémente TBLPTR
tblwt+* ; incrémente TBLPTR, et ensuite effectue l’écriture

Donc, si vous avez tout suivi jusqu’à présent, pour écrire en mémoire flash effacée,
vous devez effectuer les opérations suivantes :

- Initialiser TBLPTR à une adresse multiple de 8


- Ecrire 8 octets dans le buffer à l’aide de l’instruction TBLWT
- Envoyer la séquence d’écriture réelle en mémoire flash

La séquence d’écriture réelle est la suivante :

bsf EECON1,EEPGD ; pointer sur la mémoire flash


bcf EECON1,CFGS ; accès autorisé à la mémoire flashbsf

91
EECON1,WREN ; écritures autorisées
bcf INTCON,GIE ; interdire les interruptions
movlw 0x55 ; séquence imposée
movwf EECON2
movlw 0xAA
movwf EECON2
bsf EECON1,WR ; lancer l’effacement (arrêt du pic)
nop ; instruction ignorée à la remise en marche

Vous constatez que c’est strictement la même séquence que pour l’effacement, excepté
que nous ne positionnons pas le bit FREE

Voyons maintenant ce que probablement vous auriez fait de façon intuitive pour écrire 8
octets en mémoire flash. Il y a un piège. Si vraiment vous n’êtes pas tombé dedans, vous êtes
très fort. On suppose la mémoire déjà effacée. On présume que l’adresse de début d’écriture
est « add » et est bien un multiple de 8. Les 8 octets à écrire se trouvent en RAM à partir de
l’adresse 0x205

; initialisations
; ---------------
movlw HIGH(add) ; charger bits 8 à 14 de l’adresse
movwf TBLPTRH ; dans pointeur HIGH
movlw LOW(add) ; charger bits 0 à 7 de l’adresse
movwf TBLPTRL ; dans pointeur LOW
movlw .8 ; 8 octets à écrire
movwf cmpt ; dans compteur
lfsr FSR0,0x205 ; adresse des octets en RAM

; écriture dans le buffer


; -----------------------
loop
movff POSTINC0,TABLAT ; copier octet dans registre de transfert
tblwt*+ ; écrire l’octet dans le buffer, pointer sur suivant
decfsz cmpt ; décrémenter compteur d’octets
bra loop ; pas dernier, suivant

; séquence d’écriture
; --------------------
bsf EECON1,EEPGD ; pointer sur la mémoire flash
bcf EECON1,CFGS ; accès autorisé à la mémoire flashbsf
EECON1,WREN ; écritures autorisées
bcf INTCON,GIE ; interdire les interruptions
movlw 0x55 ; séquence imposée
movwf EECON2
movlw 0xAA
movwf EECON2
bsf EECON1,WR ; lancer l’effacement (arrêt du pic)
nop ; instruction ignorée à la remise en marche
bsf INTCON,GIE ; remettre les interruptions si nécessaire

Si vous avez imaginer votre routine de la sorte, ce n’est pas mal pensé, mais ça ne
marchera pas. Le piège est subtil, mais il est bien présent.

Souvenez-vous que je vous ai dit que la séquence d’écriture concernait les adresses
pointées par TBLPTR, pour lequel les 3 bits de poids faible sont mis à 0. Or, si vous regardez
ce qui se passe, lors du premier passage dans la boucle, TBLPTR pointe sur « add ». A la fin
de l’exécution de la première boucle, TBLPTR pointe sur add+1, étant donné l’utilisation de

92
« tblwt*+ ». Or, si vous continuez de la sorte, au sortir de la dernière boucle, TBLPTR va
pointer sur « add+8 ». Or, cela veut dire que la séquence d’écriture va concerner les adresses
« add+8 » à « add+15 », et non les adresses « add » à « add+7 ».

Vous avez donc écrit les 8 octets aux mauvaises adresses. Si c’est votre première
expérience des 18F, et si vous avez trouvé tout seul, vous êtes un crack dans le maniement des
microcontrôleurs, ou vous êtes particulièrement doué.

La solution ? Il y en a plusieurs. La plus simple est de décrémenter TBLPTR avant


d’effectuer la séquence d’écriture. Ceci s’effectue simplement en utilisant par exemple une
instruction : tblrd*-, qui effectue une lecture (dont on se moque), puis décrémente TBLPTR.
; séquence d’écriture
; --------------------
tbldr*- ; repointer dans la bonne page
bsf EECON1,EEPGD ; pointer sur la mémoire flash
bcf EECON1,CFGS ; accès autorisé à la mémoire flashbsf
EECON1,WREN ; écritures autorisées
bcf INTCON,GIE ; interdire les interruptions
movlw 0x55 ; séquence imposée
movwf EECON2
movlw 0xAA
movwf EECON2
bsf EECON1,WR ; lancer l’effacement (arrêt du pic)
nop ; instruction ignorée à la remise en marche

Il y a une méthode plus élégante, qui consiste à pointer dès le départ sur l’adresse
précédente, et de faire un accès pré-incrémenté au lieu de post-incrémenté. Je vous écris le
programme.

; initialisations
; ---------------
movlw HIGH(add-1) ; charger bits 8 à 14 de l’adresse - 1
movwf TBLPTRH ; dans pointeur HIGH
movlw LOW(add-1) ; charger bits 0 à 7 de l’adresse - 1
movwf TBLPTRL ; dans pointeur LOW
movlw .8 ; 8 octets à écrire
movwf cmpt ; dans compteur
lfsr FSR0,0x205 ; adresse des octets en RAM

; écriture dans le buffer


; -----------------------
loop
movff POSTINC0,TABLAT ; copier octet dans registre de transfert
tblwt+* ; pointer sur suivant, puis écrire l’octet dans buffer
decfsz cmpt ; décrémenter compteur d’octets
bra loop ; pas dernier, suivant

; séquence d’écriture
; --------------------
bsf EECON1,EEPGD ; pointer sur la mémoire flash
bcf EECON1,CFGS ; accès autorisé à la mémoire flashbsf
EECON1,WREN ; écritures autorisées
bcf INTCON,GIE ; interdire les interruptions
movlw 0x55 ; séquence imposée
movwf EECON2
movlw 0xAA
movwf EECON2

93
bsf EECON1,WR ; lancer l’effacement (arrêt du pic)
nop ; instruction ignorée à la remise en marche
bsf INTCON,GIE ; remettre les interruptions si nécessaire

Maintenant, si vous regardez la boucle, vous entrez dans la boucle en pointant sur add –1.
La première écriture commence par incrémenter TBLPTR, puis écrit dans add, et ainsi de
suite. Lors de la dernière sortie de la boucle, TBLPTR pointera cette fois sur add+7, donc sur
la bonne page.

Si vous êtes attentif, vous avez du vous poser la question suivante : puisqu’on écrit dans le
buffer de sortie avec tblwt, et non directement en mémoire flash, et puisqu’on l’emplacement
d’écriture se fait avec la valeur contenue à ce moment dans TBLPTR, à quoi sert d’utiliser
TBLPRT lors des écritures avec tblwt ?

En fait, vous avez raison. Il faut vous souvenir que TBLPTR comporte 21 bits, et que vous
écrivez obligatoirement à partir d’une adresse multiple de 8.

En fait, dans la boucle de la routine, seuls les bits 0 à 3 de TBLPTR sont utilisés, le
numéro de 0 à 7 obtenu précise l’adresse dans le buffer à laquelle sera rangée l’octet.

Ensuite, lors de la séquence d’écriture, ces 3 bits seront ignorés, et les octets seront écrits
tous les 8 à partir de l’adresse obtenue.

Si vous avez tout suivi, vous auriez pu écrire la routine comme ceci :

; initialisations
; ---------------
clrf TBLPTRL ; on commence l’écriture dans le buffer 0
movlw .8 ; 8 octets à écrire
movwf cmpt ; dans compteur
lfsr FSR0,0x205 ; adresse des octets en RAM

; écriture dans le buffer


; -----------------------
loop
movff POSTINC0,TABLAT ; copier octet dans registre de transfert
tblwt*+ ; écrire l’octet dans le buffer, pointer sur suivant
decfsz cmpt ; décrémenter compteur d’octets
bra loop ; pas dernier, suivant

; séquence d’écriture
; --------------------
movlw HIGH(add) ; charger bits 8 à 14 de l’adresse
movwf TBLPTRH ; dans pointeur HIGH
movlw LOW(add) ; charger bits 0 à 7 de l’adresse
movwf TBLPTRL ; dans pointeur LOW
bsf EECON1,EEPGD ; pointer sur la mémoire flash
bcf EECON1,CFGS ; accès autorisé à la mémoire flashbsf
EECON1,WREN ; écritures autorisées
bcf INTCON,GIE ; interdire les interruptions
movlw 0x55 ; séquence imposée
movwf EECON2
movlw 0xAA
movwf EECON2
bsf EECON1,WR ; lancer l’effacement (arrêt du pic)
nop ; instruction ignorée à la remise en marche

94
bsf INTCON,GIE ; remettre les interruptions si nécessaire

Ceci ne présente pas un grand intérêt, si ce n’est de vous permettre de vérifier si vous avez
tout compris.

Maintenant, comment écrire un seul octet dans la mémoire flash ? Simple, du moins en
théorie.

- Vous copiez le bloc entier de 64 octets qui contient l’adresse concernée en RAM
- Vous modifiez l’octet concerné en RAM
- Vous effacez le bloc de 64 octets (Microchip le désigne comme « rangée » (Row)
- Pour chaque groupe de 8 octets :
- Vous écrivez 8 octets dans le buffer
- Vous lancez une séquence d’écriture

Pas vraiment simple, pour écrire un seul octet. Si vous voulez savoir à quoi ressemble une
telle routine, Microchip l’a écrite pour vous pages 72 et 73, exemple 6-3.

Il nous reste à savoir comment placer des valeurs en mémoire flash directement à partir de
notre fichier source. Ceci s’effectue par la directive DB

ORG 0x100
DB 0x23 , 0x35
DB 0x22 , 0x16

Si vous regardez ce que ceci donne dans la mémoire programme après assemblage, vous
verrez le résultat suivant :

0x100 : 0x23
0x101 : 0x35
0x102 : 0x22
0x103 : 0x16

Vos octets sont donc bien rangés aux endroits que vous aviez prévu.

Attention, MPASM semble travailler par mots de 16 bits. Aussi, si vous écrivez ceci :

DB 0x23
DB 0x35
DB 0x22
DB 0x16

Cela semble strictement identique, et pourtant un examen de la mémoire programme vous


montrera l’organisation suivante :

0x100 : 0x23
0x101 : 0x00
0x102 : 0x35
0x103 : 0x00
0x104 : 0x22
0x105 : 0x00
0x106 : 0x16
0x107 : 0x00

95
MPASM a donc complété votre ligne en considérant que vous vouliez mettre 2 octets par
ligne (ou un multiple de 2), et a complété de lui-même par un « ,0x00 ». Méfiez-vous.

PARLER DE LATA

EN COURS DE REALISATION. TOUS DROITS RESERVES : BIGONOFF


ATTENTION : NON RELU, NON CORRIGE, NON TERMINE, CONTIENT
FORCEMENT UN TAS D’ERREURS.

96

Vous aimerez peut-être aussi