Vous êtes sur la page 1sur 27

Le jeu d’instructions

Les instructions sont détaillées à partir de la page 57 du datasheet. Il peut donc sembler inutile de les
reprendre dans ce cours. Mais j’ai finalement opté pour une explication pratique de ces instructions. J’ai
choisi en effet de les expliquer avec des petits exemples concrets, plutôt que de simplement traduire le
datasheet.

Bien entendu, vous pouvez expérimenter ces instructions avec MPLAB et son simulateur, en insérant ces
instructions après l’étiquette " start " de votre programme.

Je vais donc expliquer ces instructions dans un ordre qui me facilite les explications, en commençant par
celles déjà vues, dans le but final d’obtenir toutes les références aux instructions dans le même document.

9.1 L’instruction " GOTO " (aller à)

Cette instruction effectue ce qu’on appelle un saut inconditionnel, encore appelé rupture de séquence
synchrone inconditionnel.

Rappelez-vous que l’instruction goto contient les 11 bits de l’emplacement de destination. Les 2 bits
restants sont chargés depuis le registre PCLATH. Rappelez-vous en effet la manière dont est construit le PC
dans le cas des sauts. On ne peut sauter qu’à l’intérieur d’une même PAGE de 211, soit 2048 Kmots.

Ceci n’a aucune espèce d’importance pour la 16F84, qui ne dispose que de 1Kmots de mémoire
programme, mais devra être considéré pour les pics de plus grande capacité (16F876). Nous en reparlerons
à ce moment.

Voici donc en résumé le fonctionnement du goto :

 L’adresse de saut sur 11 bits est chargée dans le PC.


 Les 2 bits manquants sont chargés depuis PCLATH (b3 et b4), pas pour la 16F84.
 Le résultat donne l’adresse sur 13 bits (10 bits pour la 16F84)
 La suite du programme s’effectue à la nouvelle adresse du PC.

Souvenez-vous, que pour la 16F84 : Adresse de saut = adresse réelle. Vous ne devez donc vous préoccuper
de rien. Pour les autres, en cas de débordement, MPLAB vous le signalera.

Syntaxe

goto etiquette

Exemple :

Start
goto plusloin ; le programme saute à l’instruction qui suit l’étiquette
xxxx xxxx ; plusloin
xxxx xxxx
plusloin
xxxx xxxx ; instruction exécutée après le saut : le programme se poursuit ici
Remarquez que vous pouvez sauter en avant ou en arrière.

goto nécessite 2 cycles d’horloge, comme pour tous les sauts

9.2 L’instruction " INCF " (INCrement File)

Cette instruction provoque l’incrémentation de l’emplacement spécifié (encore appelé File).

Syntaxe

incf f,d

Comme pour toutes les instructions, f représente File, c’est à dire l’emplacement mémoire concerné pour
cette opération. d représente la Destination. Sauf spécification contraire, d vaut toujours, au choix :

 F (la lettre f) : dans ce cas le résultat est stocké dans l’emplacement mémoire.
 W (la lettre w) : dans ce cas, le résultat est laissé dans le registre de travail, et le contenu de
l’emplacement mémoire n’est pas modifié.

La formule est donc (f) + 1 -> (d) : Les parenthèses signifient " le contenu de "

Bit du registre STATUS affecté

Le seul bit affecté par cette opération est le bit Z.

Etant donné que la seule manière, en incrémentant un octet, d’obtenir 0, est de passer de 0xFF à 0x00. Le
report n’est pas nécessaire, puisqu’il va de soi. Si, après une incrémentation, vous obtenez Z=1 , c’est que
vous avez débordé. Z vaudra donc 1 si (f) avant l’exécution valait 0xFF.

Exemples

incf mavariable , f ; le contenu de ma variable est augmenté de 1


; le résultat est stocké dans mavariable.
mavariable ,
incf ; Le contenu de mavariable est chargé dans w et
w
; augmenté de 1. W contient donc le contenu de
; mavariable + 1. mavariable n’est pas modifié

9.3 L’instruction " DECF " (DECRement File)

Decrémente l’emplacement spécifié. Le fonctionnement est strictement identique à l’instruction précédente.

Syntaxe
decf f,d ; (f) – 1 -> (d)

Bit du registre STATUS affecté

Le seul bit affecté par cette opération est le bit Z.

Si avant l’instruction, (f) vaut 1, Z vaudra 1 après l’exécution (1-1 = 0)

Exemples

decf mavariable , f ; décrémente mavariable, résultat dans mavariable


mavariable ,
decf ; prends (mavariable) – 1 et place le résultat dans w
w

9.4 L’instruction " MOVLW " (MOVe Literal to W)

Cette instruction charge la valeur spécifiée (valeur littérale, ou encore valeur immédiate), dans le registre de
travail W.

Syntaxe

movlw k ; k représente une valeur de 0x00 à 0xFF.

Bit du registre STATUS affecté

Aucun ( donc même si vous chargez la valeur ‘0’.)

Exemple

movlw 0x25 ; charge 0x25 dans le registre w

9.5 L’instruction " MOVF " (MOVe File)

Charge le contenu de l’emplacement spécifié dans la destination

Syntaxe

movf f,d ; (f) -> (d)

Bit du registre STATUS affecté

Une fois de plus, seul le bit Z est affecté (si f vaut 0, Z vaut 1).

Exemple 1
Pour cette instruction, je vais me montrer beaucoup plus explicite. Vous allez comprendre pourquoi

movf mavariable,w ; charge le contenu de mavariable dans w.

ATTENTION

Il est impératif ici de bien faire la distinction entre movlw k et movf f,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é. Si nous
nous rappelons, dans la leçon précédente que mavariable représentait l’adresse 0x0E de notre zone de
RAM. Supposons maintenant que mavariable contienne 0x50.

Si nous exécutons l’instruction suivante :

movlw mavariable

L’assembleur va traduire en remplaçant mavariable par sa VALEUR. Attention, la valeur, ce n’est pas le
contenu. L’assembleur va donc réaliser la substitution suivante :

movlw 0x0E

Après l’instruction, nous aurons 0x0E dans le registre W. Nous parlerons dans ce cas d’un ADRESSAGE
IMMEDIAT. Le déroulement est du type f -> (d) (f n’est pas entre parenthèses).

Si nous exécutons par contre l’instruction suivante :

mavariable ,
movf
w

L’assembleur va traduire également en remplaçant mavariable par sa valeur. Nous obtenons donc :

movf 0x0E , w

Ce qui signifie : charger le CONTENU de l’emplacement 0x0E dans w. Nous parlerons ici d’un
ADRESSAGE DIRECT. Je rappelle qu’il est primordial de ne pas confondre, sinon, vous ne comprendrez
plus rien lors de la réalisation des programmes. Après cette instruction, W contient donc 0x50. Le
déroulement est du type (f) -> (d).

Exemple 2

movf mavariable , f

Que fait cette instruction ? Si vous avez tout suivi, elle place le CONTENU de mavariable dans mavariable.
Dire que cela ne sert à rien est tentant mais prématuré.

En effet, si le contenu de mavariable reste bien inchangé, par contre le bit Z est positionné. Cette instruction
permet donc de vérifier si (mavariable) = 0.

9.6 L’instruction " Movwf " (MOVe W to File)


Permet de sauvegarder le contenu du registre de travail W dans un emplacement mémoire.

Syntaxe

movwf f ; (W) -> (f)

Bit du registre STATUS affecté

Aucun

Exemple

movlw 0x50 ; charge 0x50 dans W


movwf mavariable ; ma variable contient maintenant 0x50.

9.7 L’instruction " ADDLW " (ADD Literal and W)

Cette opération permet d’ajouter une valeur littérale (adressage immédiat) au contenu du registre de travail
W.

Syntaxe

addlw k ; (W) + k -> (W)

Bits du registre STATUS affectés

 Z Si le résultat de l’opération vaut 0, Z vaudra 1


 C Si le résultat de l’opération est supérieur à 0xFF (255) , C vaudra 1
 DC Si le résultat de l’opération entraîne en report du bit 3 vers le bit 4, DC vaudra 1
Ne vous inquiétez pas trop pour DC, il n’est utilisé que pour les opérations sur les quartets, par
exemple, les nombres Binary Coded Decimal

Exemple

movlw 253 ; charger 253 en décimal dans W


addlw 4 ; Ajouter 4. W contient 1, Z vaut 0, C vaut 1(déborde)
addlw 255 ; ajouter 255 W vaut 0, C vaut 1, Z vaut 1

9.8 L’instruction " ADDWF " (ADD W and F)

Ne pas confondre avec l’instruction précédente. Une nouvelle fois, il s’agit ici d’un ADRESSAGE
DIRECT. Le CONTENU du registre W est ajouté au CONTENU du registre F

Syntaxe

addwf f , d ; (w) + (f) -> (d)

Bits du registre STATUS affectés

C, DC, et Z

Exemple

movlw 12 ; charger 12 dans W


movwf mavariable ; mavariable vaut maintenant 12
movlw 25 ; charger 25 dans W
addwf mavariable,f ; résultat : (W) + (mavariable), donc 25+12
; résultat = 37 sauvé dans mavariable (,f)

9.9 L’instruction " SUBLW " (SUBtract W from Literal)

Attention, ici il y a un piège. L’instruction aurait du s’appeler SUBWL. En effet, on soustrait W de la


valeur littérale, et pas l’inverse.

Syntaxe

sublw k ; k – (W) -> (W)

Bits du registre STATUS affectés

C, DC, Z

Notez ici que le bit C fonctionne de manière inverse que pour l’addition. Ceci est commun à la plupart des
microprocesseurs du marché.

Si le résultat est positif, donc, pas de débordement : C =1. S’ il y a débordement, C devient 0.

Ceci est logique, et s’explique en faisant une soustraction manuelle. Le bit C représente le 9ème bit ajouté
d’office à la valeur initiale. Si on effectue une soustraction manuelle donnant une valeur <0, on obtient
donc une valeur finale sur 8 bits, le report obtenu venant soustraire le bit C. Si le résultat est >0, il n’y a pas
de report, le résultat final reste donc sur 9 bits. La formule de la soustraction est donc : k précédé d’un
neuvième bit à 1 – contenu de W = résultat sur 8 bits dans W avec 9ème bit dans C.

Exemple 1

movlw 0x01 ; charger 0x01 dans W


sublw 0x02 ; soustraire W de 2
; résultat : 2 – (W) = 2-1 = 1
; Z = 0, C = 1, donc résultat positif

Effectuons cette opération manuellement :

C b7 b6 b5 b4 b3 b2 b1 b0 Dec
1 0 0 0 0 0 0 1 010 2
- 0 0 0 0 0 0 0 01 1 1
= 1 0 0 0 0 0 0 0 1 1

Comment procéder ? Et bien, comme pour une soustraction décimale. On commence par les bits de droite :
0-1, ça ne passe pas, donc on emprunte 10 (noté en exposant vert), et on soustraira évidemment une unité
supplémentaire au bit b1. On a donc :B ‘10’ – B’1’, car souvenez-vous qu’on a emprunter 10 en BINAIRE.
Résultat 1. On soustrait ensuite les b1 : on aura 1 – 0 – l’emprunt, donc 1-0-1 = 0. On continue de droite à
gauche jusqu’au 9ème bit qui est le carry. Résultat final : B’00000001’ et carry à 1, cqfd.

Exemple 2

movlw 0x02 ; charger 0x02 dans W


sublw 0x02 ; soustraire 2 – (w) = 2 –2 = 0
; Z = 1 , C = 1 : résultat nul

C b7 b6 b5 b4 b3 b2 b1 b0 Dec
1 0 0 0 0 0 0 1 0 2
- 0 0 0 0 0 0 0 1 0 2
= 1 0 0 0 0 0 0 0 0 0

On procède toujours de la même manière.

Exemple 3

movlw 0x03 ; charger 0x03 dans W


sublw 0x02 ; soustraire 2 – (W) = 2 – 3 = -1
; Z = 0, C = 0, résultat négatif
C b7 b6 b5 b4 b3 b2 b1 b0 Dec
1 010 010 010 010 010 010 110 010 2
- 01 01 01 01 01 01 01 11 1 3
= 0 1 1 1 1 1 1 1 1 -1

Procédons de la même manière, et nous obtenons B’11111111’, avec le bit C à 0. Et là, me dites-vous,
B’11111111’, c’est FF, pas –1. Et bien, rappelez-vous ceci : Vous DEVEZ lire le bit C pour interpréter le
résultat de votre soustraction.

Comme ce dernier vaut 0, vous êtes AVERTIS que le résultat de l’opération est négatif. Or, comment
savoir la valeur absolue d’un nombre négatif ? En prenant son complément à 2. Rappelez-vous :

Complément à 1 de B’11111111’ = B’00000000’ (on inverse tous les bits)


Complément à 2 = complément à 1 + 1, donc B’00000001’.
Donc, le complément à 2 de 0xFF vaut –0x01. cqfd.

La preuve, si vous ajoutez 1 à –1, vous obtenez B’11111111’ + B’00000001’ = B’00000000’ = 0.

Vous maîtrisez maintenant les soustractions. Certains auront sans doute pensé que j’expliquais trop en
détail, mais mon expérience m’a appris que les soustractions représentaient souvent un écueil dans la
réalisation de trop de programmes.

Encore un dernier détail : Pour effectuer une soustraction de 1, vous pouvez bien entendu effectuer une
addition de –1. Le résultat sera strictement le même, à votre charge d’interpréter les bits Z et C. Je vous
laisse le faire vous-même pour vous convaincre.

9.10 L’instruction " SUBWF " (SUBtract W from F)

Nous restons dans les soustractions, mais, cette fois, au lieu d’un adressage immédiat, nous avons un
ADRESSAGE DIRECT.

Syntaxe

subwf f , d ; (f) – (W) -> (d)

Bits du registre STATUS affectés

C , DC , Z

Exemple
movlw 0x20 ; charger 0x20 dans w
movwf mavariable ; mettre w dans (mavariable) (0x20)
movlw 0x1F ; charger 0x1F dans w
subwf mavariable,w ; (mavariable) - (w) -> (w)
; 0x20 – 0x1F = 0x01
; résultat dans w, C=1, Z=0
movwf autrevariable ; sauver 0x01 dans une autre variable

9.11 L’instruction " ANDLW " (AND Literal with W)

Cette instruction effectue une opération " AND " BIT A BIT entre le contenu de W et la valeur littérale qui
suit.

Syntaxe

andlw k ; avec k = octet : (w) & k -> (w)

Bit du registre STATUS affecté

Exemple

movlw B’11001101’ ; charger w


andlw B’11110000’ ; effectuer un ‘and’ (&)

b7 b6 b5 b4 b3 b2 b1 b0
1 1 0 0 1 1 0 1
And 1 1 1 1 0 0 0 0
= 1 1 0 0 0 0 0 0

Rappelez-vous qu’on effectue un AND entre chaque bit de même rang. Seuls restent donc positionnés à 1
les bits dont les 2 opérandes valent 1. Donc, le fait d’effectuer un AND avec la valeur B’11110000’
MASQUE les bits 0 à 3, et ne laisse subsister que les bits 4 à 7.

Tant que vous ne jonglerez pas avec l’hexadécimal, je vous conseille de toujours traduire les nombres en
binaires pour toutes les instructions concernant les bits.

9.12 L’instruction " ANDWF " (AND W with F)


Maintenant, vous devriez avoir bien compris. De nouveau la même opération, mais en ADRESSAGE
DIRECT. Je vais donc accélérer les explications.

Syntaxe

andwf f , d ; (f) AND (w) -> (d)

Bit du registre STATUS affecté

Exemple

movlw 0xC8 ; charger 0XC8 dans w


movwf mavariable ; sauver dans mavariable
movlw 0xF0 ; charger le masque
andwf mavariable,f ; (mavariable) = 0xC0 (on a éliminé le quartet faible).

9.13 L’instruction " IORLW " (Inclusive OR Literal with W)

Et oui, les mêmes instructions, mais pour le OU inclusif. Inclusif signifie simplement le contraire
d’exclusif, c’est à dire que le bit de résultat vaudra 1 si un des bits, OU LES DEUX BITS, opérandes =1.

Syntaxe

iorlw k ; (w) OR k -> (w)

Bit du registre STATUS affecté

Exemple

movlw 0xC3 ; charger 0xC3 dans W


iorlw 0x0F ; FORCER les bits 0 à 3
; résultat ; (w) = 0xCF

b7 b6 b5 b4 b3 b2 b1 b0
1 1 0 0 0 0 1 1
OR 0 0 0 0 1 1 1 1
= 1 1 0 0 1 1 1 1

Donc, avec un ou inclusif (OR), on peut FORCER n’importe quel bit à 1 (pour rappel, avec AND, on peut
forcer n’importe quel bit à 0).

9.14 L’instruction " IORWF " (Inclusive OR W with File)

Effectue un OR entre (w) et l’emplacement spécifié. C’est donc une instruction en ADRESSAGE DIRECT.
Je ne donnerais pas d’exemple, vous devriez avoir compris.

Syntaxe

iorwf f , d ; (w) OR (f) -> (d)

Bit du registre STATUS affecté

9.15 L’instruction " XORLW " (eXclusive OR Literal with W)

Par opposition au ou inclusif, voici maintenant le OU EXCLUSIF. Sa table de vérité est la même que le ou
inclusif, excepté que lorsque les 2 bits sont à 1, le résultat est 0.

Cette instruction va donc servir à INVERSER n’importe quel bit d’un octet. En effet, si vous effectuez " 1
xor 0 ", vous obtenez 1, si vous effectuez " 0 xor 0 ", vous obtenez 0. Donc, si vous appliquez xor 0, la
valeur de départ est inchangée.

Si par contre vous appliquez " 0 xor 1 " , vous obtenez 1, et avec " 1 xor 1 ", vous obtenez 0. En appliquant
xor 1, vous inversez le bit, quelque soit son état initial.

Maintenant, vous pouvez donc FORCER un bit à 1 avec OR, MASQUER un bit (le mettre à 0) avec AND,
et l’INVERSER avec XOR.

Syntaxe

xorlw k ; (w) xor k -> (w)

Bit du registre STATUS affecté

Exemple

movlw B’11000101’ ; charger W


xorlw B’00001111’ ; xor avec la valeur
; résultat : B ‘11001010’
; les 4 bits de poids faible ont été inversés

b7 b6 b5 b4 b3 b2 b1 b0
1 1 0 0 0 1 0 1
xor 0 0 0 0 1 1 1 1
= 1 1 0 0 1 0 1 0

Remarquez que tous les bits de l’octet initial ont été inversés par chaque bit de la seconde opérande qui
étaient à 1.

9.16 L’instruction " XORWF " (eXclusive OR W with F)

C’est exactement la même opération que XORLW, mais en ADRESSAGE DIRECT.

Syntaxe

xorwf f , d ; (w) xor (f) -> (d)

Bit du registre STATUS affecté

9.17 L’instruction " BSF " (Bit Set F)

C’est une instruction qui permet tout simplement de forcer directement un bit d’un emplacement mémoire à
1

Syntaxe

bsf f,b ; le bit n° b est positionné dans la case mémoire (f)


; b est évidemment compris entre 0 et 7

Bit du registre STATUS affecté

Aucun

Exemples

bsf STATUS , C ; positionne le bit C à 1 dans le registre STATUS


mavariable ,
bsf ; positionne bit 2 de (mavariable) à 1
2
9.18 L’instruction " BCF " (Bit Clear F)

C’est une instruction qui permet tout simplement de forcer directement un bit d’un emplacement mémoire à
0

Syntaxe

bcf f,b ; le bit n° b est mis à 0 dans la case mémoire (f)


; b est évidemment compris entre 0 et 7

Bit du registre STATUS affecté

Aucun

Exemples

bcf STATUS , C ; positionne le bit C à 0 dans le registre STATUS


mavariable ,
bcf ; positionne bit2 de (mavariable) à 0
2

9.19 L’instruction " RLF " ( Rotate Left through Carry)

Rotation vers la gauche en utilisant le carry.

Les opérations de décalage sont des opérations très souvent utilisées. Les PICs ont la particularité de ne
posséder que des opérations de ROTATION. Vous allez voir qu’avec ces opérations, on peut très
facilement réaliser des décalages.

L’opération de rotation effectue l’opération suivante : Le bit de carry C est mémorisé. Ensuite chaque bit de
l’octet est déplacé vers la gauche. L’ancien bit 7 sort de l’octet par la gauche, et devient le nouveau carry.
Le nouveau bit 0 devient l’ancien carry. Il s’agit donc d’une rotation sur 9 bits.

Syntaxe

rlf f, d ; (f) rotation gauche avec carry-> (d)

Bit du registre STATUS affecté

Exemple1

Un petit exemple vaut mieux qu’un long discours.


bsf STATUS,C ; positionne le carry à 1
movlw B’00010111’ ; charge la valeur dans w
movwf mavariable ; initialise mavariable
rlf mavariable,f ; rotation vers la gauche

C b7 b6 b5 b4 b3 b2 b1 b0
f 1 0 0 0 1 0 1 1 1
rlf 0 0 0 1 0 1 1 1 1

Vous voyez que tous les bits ont été décalés vers la gauche. " C " a été réintroduit dans b0. Le résultat reste
sur 9 bits.

Exemple 2

bcf STATUS,C ; positionne le carry à 0


movlw B’00010111’ ; charge la valeur dans w
movwf mavariable ; initialise mavariable
rlf mavariable,f ; rotation vers la gauche

Si vous avez compris, le résultat sera B’00101110’, avec le carry à 0. Si le carry est à 0 au départ, on
effectue un simple décalage vers la gauche. Que se passe-t-il si, en décimal, on effectue ce type
d’opération ?

Prenons le nombre 125 et décalons-le vers la gauche en décimal, nous obtenons 1250. Nous avons multiplié
le nombre par sa base. Et bien c’est la même chose en binaire (une fois de plus).

Prenons B’00010111 ‘, soit 23 en décimal. Décalons-le, nous obtenons B’00101110’, soit 46. Nous avons
donc effectué une multiplication par 2. Retenez ceci, cela vous sera très utile par la suite.

9.20 L’instruction " RRF " ( Rotate Right through Carry)

Rotation vers la droite en utilisant le carry

L’opération de rotation vers la droite effectue l’opération suivante : Le bit de carry " C " est mémorisé.
Ensuite chaque bit de l’octet est déplacé vers la droite. L’ancien bit 0 sort de l’octet par la droite, et devient
le nouveau carry. L’ancien Carry devient le nouveau bit7. Il s’agit donc également d’une rotation sur 9 bits.

Syntaxe

rrf f, d ; (f) rotation droite avec carry-> (d)


Bit du registre STATUS affecté

Exemple1

bsf STATUS,C ; positionne le carry à 1


movlw B’00010111’ ; charge la valeur dans w
movwf mavariable ; initialise mavariable
rrf mavariable,f ; rotation vers la droite

b7 b6 b5 B4 b3 b2 b1 b0 C
f 0 0 0 1 0 1 1 1 1
rrf 1 0 0 0 1 0 1 1 1

Vous voyez que tous les bits ont été décalés vers la droite. C a été réintroduit dans b7. Le résultat reste sur 9
bits.

Exemple 2

bcf STATUS,C ; positionne le carry à 0


movlw B’00010111’ ; charge la valeur dans w
movwf mavariable ; initialise mavariable
rrf mavariable,f ; rotation vers la droite

Si vous avez compris, le résultat sera B’00001011’, avec le carry à 1.

Si le carry est à 0 au départ, on effectue un simple décalage vers la droite.

Que s’est-il passé ? Et bien notre nombre de départ, soit 23 en décimal est devenu 11. Le carry représente le
bit " -1 ", donc, la moitié du bit 0, donc ½. En effet, en décimal, le chiffre derrière les unités a comme
valeur 1/base, donc 1/10. En binaire ce sera donc ½.

Si nous regardons alors les 9 bits, nous obtenons 11 ½ . Nous avons donc effectué une DIVISION PAR 2.
Retenez ceci, cela vous sera également très utile par la suite.

9.21 L’instruction " BTFSC " (Bit Test F, Skip if Clear)

Traduit littéralement, cela donne : Teste le bit de l’emplacement mémoire et saute s’il vaut 0. Il s’agit ici de
votre premier SAUT CONDITIONNEL, ou RUPTURE DE SEQUENCE SYNCHRONE
CONDITIONNELLE .

En effet, il n’y aura saut que si la condition est remplie. Notez que dans ce cas l’instruction prendra 2
cycles, sinon, elle n’utilisera qu’un cycle. De plus, il faut retenir que pour tous ces types de saut, ON NE
SAUTE QUE l’INSTRUCTION SUIVANTE. En effet, la syntaxe ne contient pas d’adresse de saut,
comme nous allons le voir

Syntaxe

btfsc f, b ; on teste le bit b de la mémoire (f).


; si ce bit vaut 0, on saute l’instruction suivante, sinon
; on exécute l’instruction suivante.
Instruction exécutée si faux ; si le bit vaut 0, ne sera pas exécutée (skip)
Poursuite du programme ; le programme continue ici

Bit du registre STATUS affecté

Aucun

Exemple1

Voici un exemple dans lequel on doit exécuter une seule instruction supplémentaire si le bit vaut 1.

btfsc STATUS,C ; tester si le bit C du registre STATUS vaut 0


bsf mavariable,2 ; non (C=1), alors bit 2 de mavariable mis à 1
xxxx ; la suite du programme est ici dans les 2 cas

Exemple 2

Que faire si les traitements différent de plus d’une instruction ? Et bien, on combine les sauts conditionnels
avec les saut inconditionnels (par exemple goto).

movlw 0x12 ; charger 12 dans le registre de travail


subwf mavariable,f ; on soustrait 0x12 de mavariable
btfsc STATUS,C ; on teste si le résultat est négatif (C=0)
goto positif ; non, alors au saute au traitement des positifs
xxxx ; on poursuit ici si le résultat est négatif

Ces procédures sont les mêmes pour tous les sauts inconditionnels, je ne les détaillerai donc pas avec autant
d’explications.

9.22 L’instruction " BTFSS " (Bit Test F, Skip if Set)


Traduit littéralement, cela donne : Teste le bit de l’emplacement mémoire et saute s’il vaut 1. Toutes les
remarques de l’instruction " BTFSC " restent valables.

Syntaxe

btfss f, b ; on teste le bit b de la mémoire (f).


; si ce bit vaut 1, on saute l’instruction suivante, sinon
; on exécute l’instruction suivante.
Instruction exécutée si faux ; si le bit vaut 0, ne sera pas exécutée (skip)
Poursuite du programme ; le programme continue ici

Bit du registre STATUS affecté

Aucun

Exemple

btfss STATUS,C ; tester si le bit C du registre STATUS vaut 1


bsf mavariable,2 ; non (C=0), alors bit 2 de mavariable mis à 1
xxxx ; la suite du programme est ici dans les 2 cas

9.23 L’instruction " DECFSZ " (DECrement F, Skip if Z)

Nous poursuivons les sauts conditionnels avec une instruction très utilisée pour créer des boucles. Cette
instruction décrémente un emplacement mémoire et saute l’instruction suivante si le résultat de la
décrémentation donne une valeur nulle.

Syntaxe

decfsz f, d ; (f) –1 -> (d). Saut si (d) = 0

Bit du registre STATUS affecté

Aucun

Exemple1

movlw 3 ; charger 3 dans w


movwf compteur ; initialiser compteur
movlw 0x5 ; charger 5 dans w
boucle ; étiquette
addwf mavariable , f ; ajouter 5 à ma variable
decfsz compteur , f ; décrémenter compteur et tester sa valeur
goto boucle ; si compteur pas 0, on boucle
mavariable ,
movf ; on charge la valeur obtenue dans w
w

Comment écrit-on ce type de programme ? Et bien tout simplement de la manière suivante :

 on initialise les compteur de boucles.


 on place une étiquette de début de boucle
 on écrit les instructions qui doivent s’exécuter plusieurs fois
 l’instruction decfsz permet de déterminer la fin des boucles
 l’instruction goto permet de localiser le début de la boucle.

ATTENTION

- Si vous aviez mis :

decfsz compteur , w ; décrémenter compteur et tester sa valeur

la boucle n’aurait jamais de fin, car la variable compteur ne serait jamais modifiée.

- Si vous placez 0 dans le compteur de boucles, la boucle sera exécutée 256 fois. Si vous ne désirez pas que
la boucle soit exécutée dans ce cas, vous devez ajouter un test AVANT l’exécution de la première boucle,
comme dans l’exemple suivant :

Exemple 2

movf compteur,f ; permet de positionner Z


btfsc STATUS , Z ; sauter si Z = 0, donc si compteur >0
goto suite ; compteur = 0, ne pas traiter la boucle
boucle ; étiquette de début de boucle
addwf mavariable , f ; ajouter 5 à ma variable
decfsz compteur , f ; décrémenter compteur et tester sa valeur
goto boucle ; si compteur pas 0, on boucle
suite ; on saute directement ici si compteur = 0
mavariable ,
movf ; on charge la valeur obtenue dans w
w

9.24 L’instruction " INCFSZ " (INCrement F, Skip if Zero)

Je ne vais pas détailler cette instruction, car elle est strictement identique à la précédente, hormis le fait
qu’on incrémente la variable au lieu de la décrémenter.

Syntaxe :

incfsz f , d ; (f) + 1 -> (d) : saut si (d) = 0

Bit du registre STATUS affecté

Aucun

9.25 L’instruction " SWAPF " (SWAP nibbles in F)

Nous pouvons traduire cette instruction par "inverser les quartets dans F ". Cette opération inverse
simplement le quartet (demi-octet) de poids faible avec celui de poids fort.

Syntaxe

swapf f , d ; inversion des b0/b3 de (f) avec b4/b7 -> (d)

Bit du registre STATUS affecté

Aucun : cette particularité nous sera très utile lorsque nous verrons les interruptions.

Exemple

movlw 0xC5 ; charger 0xC5 dans w


movwf mavariable ; placer dans mavariable
swapf mavariable , f ; (mavariable) = 0x5C

9.26 L’instruction " CALL " (CALL subroutine)

Cette opération effectue un saut inconditionnel vers un sous-programme. Voyons ce qu’est un sous-
programme. Et bien, il s’agit tout simplement d’une partie de programme qui peut être appelé depuis
plusieurs endroits du programme dit " principal ".

Le point de départ est mémorisé automatiquement, de sorte qu’après l’exécution du sous-programme, le


programme continue depuis l’endroit où il était arrivé. Cela paraît un peu ardu, mais c’est extrêmement
simple. Voyez les exemples dans la description de l’instruction RETURN.

Syntaxe

call etiquette ; appel de la sous-routine à l’adresse etiquette.


Mécanisme

Lors de l’exécution de l’instruction, l’adresse de l’instruction suivante est sauvegardée sur le sommet d’une
pile (exactement comme une pile d’assiettes). Lorsque la sous-routine est terminée, l’adresse sauvegardée
est retirée de la pile et placée dans le PC. Le programme poursuit alors depuis l’endroit d’où il était parti.

Notez que si le sous-programme (ou sous-routine) appelle lui-même un autre sous programme, l’adresse
sera également sauvée au dessus de la pile. Attention, cette pile a une taille limitée à 8 emplacements. Il
n’existe aucun moyen de tester la pile, vous devez donc gérer vos sous-programmes pour ne pas dépasser 8
emplacements, sinon, votre programme se plantera.

Notez que lorsque vous sortez d’un sous-programme, l’emplacement est évidemment libéré. La limite n’est
donc pas dans le nombre de fois que vous appelez votre sous- programme, mais dans le nombre
d’imbrications (sous-programme qui en appelle un autre qui en appelle un autre) etc.

Bit du registre STATUS affecté

Aucun

9.27 L’instruction " RETURN " (RETURN from subroutine)

Retour de sous-routine. Va toujours de pair avec une instruction call. Cette instruction indique la fin de la
portion de programme considérée comme sous-routine (SR). Rappelez-vous que pour chaque instruction
call rencontrée, votre programme devra rencontrer une instruction return.

Syntaxe

Return ; fin de sous-routine. Le PC est rechargé depuis la pile, le


; programme poursuit à l’adresse qui suit la ligne call.

Bit du registre STATUS affecté

Aucun

Exemples

Comme ceci est un concept très important, je vais détailler un peu plus. Imaginons un programme qui a
besoin d’une petite temporisation (comme chaque instruction prend du temps, on peut s’arranger pour en
faire perdre volontairement au programme afin de retarder son fonctionnement. Ecrivons-la :

movlw 0xCA ; valeur du compteur


movwf compteur ; initialiser compteur de boucles
boucle
decfsz compteur,f ; décrémenter compteur, sauter si 0
goto boucle ; boucler si pas 0
xxx ; suite du programme
Imaginons maintenant que cette petite temporisation soit appelée régulièrement par notre programme
principal. Ecrivons à quoi ressemble le programme principal :

xxx ; instruction quelconque


xxx ; instruction quelconque
xxx ; instruction quelconque
xxx ; instruction quelconque
tempo ; ici, on a besoin d’une tempo
xxx ; instruction quelconque
xxx ; instruction quelconque
xxx ; instruction quelconque
tempo ; ici aussi
xxx ; instruction quelconque
xxx ; instruction quelconque
tempo ; et encore ici
xxx ; instruction quelconque

La première chose qui vient à l’esprit, est d’effectuer un copier/coller de notre temporisation. On obtient
donc un programme comme ceci :

xxx ; instruction quelconque


xxx ; instruction quelconque
xxx ; instruction quelconque
xxx ; instruction quelconque
movlw 0xCA ; valeur du compteur
movwf compteur ; initialiser compteur de boucles
boucle
decfsz compteur,f ; décrémenter compteur, sauter si 0
goto boucle ; boucler si pas 0
xxx ; instruction quelconque
xxx ; instruction quelconque
xxx ; instruction quelconque
movlw 0xCA ; valeur du compteur
movwf compteur ; initialiser compteur de boucles
boucle2
decfsz compteur,f ; décrémenter compteur, sauter si 0
goto boucle2 ; boucler si pas 0
xxx ; instruction quelconque
xxx ; instruction quelconque
movlw 0xCA ; valeur du compteur
movwf compteur ; initialiser compteur de boucles
boucle3
decfsz compteur,f ; décrémenter compteur, sauter si 0
goto boucle3 ; boucler si pas 0
xxx ; instruction quelconque

Ceci n’est pas élégant, car, si nous devons changer la valeur de notre tempo, nous devons la changer partout
dans le programme, sans oublier un seul endroit.

On peut également se dire : " utilisons une macro ", qui, rappelez-vous, effectue une substitution au
moment de l’assemblage. C’est vrai, qu’alors, il n’y a plus qu’un endroit à modifier Mais, dans notre PIC,
le code se retrouvera cependant autant de fois qu’on a utilisé la temporisation. Que de place perdue, surtout
si la portion de code est grande et utilisée plusieurs fois.

Pour remédier à ceci, nous utiliserons la technique des sous-programmes.

Première étape, modifions notre temporisation pour en faire une sous-routine :

tempo ; étiquette de début de la sous-routine


movlw 0xCA ; valeur du compteur
movwf compteur ; initialiser compteur de boucles
boucle
decfsz compteur,f ; décrémenter compteur, sauter si 0
goto boucle ; boucler si pas 0
return ; fin de la sous-routine.

Deuxième étape, nous modifions notre programme principal pour que chaque fois que nous avons besoin
d’une tempo, il appelle le sous-programme. Nous obtenons :

xxx ; instruction quelconque


xxx ; instruction quelconque
xxx ; instruction quelconque
xxx ; instruction quelconque
call tempo ; appel du sous programme
xxx ; instruction quelconque, le programme continue ici
xxx ; instruction quelconque
xxx ; instruction quelconque
call tempo ; appel du sous programme
xxx ; instruction quelconque, le programme continue ici
xxx ; instruction quelconque
call tempo ; appel du sous programme
xxx ; instruction quelconque, le programme continue ici

Dans ce cas, la routine tempo n’est présente qu’une seule fois en mémoire.

On peut améliorer : supposons que nous désirons une temporisation à durée variable. On modifie la sous-
routine en supprimant la valeur d’initialisation, et on place celle-ci dans le programme principal. Cela
s’appelle un sous-programme avec passage de paramètre(s).

Exemple, notre sous-programme devient :

tempo ; étiquette de début de la sous-routine


movwf compteur ; initialiser compteur de boucles
boucle
decfsz compteur,f ; décrémenter compteur, sauter si 0
goto boucle ; boucler si pas 0
return ; fin de la sous-routine.

Quand à notre programme principal :

xxx ; instruction quelconque


xxx ; instruction quelconque
xxx ; instruction quelconque
xxx ; instruction quelconque
movlw 0x25 ; charger w avec 0x25
call tempo ; appel du sous programme tempo d'une durée de 0x25
xxx ; instruction quelconque, le programme continue ici
xxx ; instruction quelconque
xxx ; instruction quelconque
movlw 0x50 ; charger w avec 0x50
call tempo ; appel du sous programme tempo d'une durée de 0x50
xxx ; instruction quelconque, le programme continue ici
xxx ; instruction quelconque
movlw 0x10 ; charger w avec 0x10
call tempo ; appel du sous programme tempo d'une durée de 0x10
xxx ; instruction quelconque, le programme continue ici

Voilà, maintenant vous savez ce qu’est un sous-programme. Enfantin, n’est-ce pas ?

9.28 L’instruction " RETLW " (RETurn with Literal in W)

Retour de sous-routine avec valeur littérale dans W. C’est une instruction très simple : elle équivaut à
l’instruction return, mais permet de sortir d’une sous-routine avec une valeur spécifiée dans W.

Syntaxe

retlw k ; (w) = k puis return

Bit du registre STATUS affecté

Aucun

Exemple

test ; étiquette de début de notre sous-programme


btfss mavariable,0 ; teste le bit 0 de mavariable
retlw 0 ; si vaut 0, fin de sous-programme avec (w)=0
retlw 1 ; sinon, on sort avec (w) = 1

9.29 L’instruction " RETFIE " (RETurn From IntErrupt)

Cette instruction indique un retour d’interruption (nous verrons ultérieurement ce que sont les
interruptions). Cette instruction agit d’une manière identique à RETURN, excepté que les interruptions sont
remises automatiquement en service au moment du retour au programme principal.

Syntaxe

retfie ; retour d’interruption

Bit du registre STATUS affecté

Aucun

9.30 L’instruction " CLRF " (CLeaR F)

Cette instruction efface l’emplacement mémoire spécifié

Syntaxe
clrf f ; (f) = 0

Bit du registre STATUS affecté

Z : Vaut donc toujours 1 après cette opération.

Exemple

clrf mavariable ; (mavariable) = 0

9.31 L’instruction " CLRW " (CLeaR W)

Cette instruction efface w

Syntaxe

clrw ; (w) = 0

C’est une instruction qui n’est pas vraiment indispensable, car on pourrait utiliser l’instruction " movlw
0 ". La différence est que dans ce cas, le bit Z n’est pas affecté.

Bit du registre STATUS affecté

Z : Vaut donc toujours 1 après cette opération.

9.32 L’instruction " CLRWDT " (CLeaR WatchDog)

Remet à 0 le chien de garde de votre programme. Nous aborderons le fonctionnement du watchdog


ultérieurement. Sachez cependant que c’est un mécanisme très pratique qui permet de provoquer un reset
automatique de votre PIC en cas de plantage du programme (parasite par exemple).

Le mécanisme est simple à comprendre : il s’agit pour votre programme d’envoyer cette instruction à
intervalles réguliers. Si la commande n’est pas reçue dans le délai imparti, la PIC est redémarrée au début.
C’est exactement le mécanisme utilisé par les conducteurs de train qui doivent presser un bouton à
intervalle régulier. Si le bouton n’est pas pressé, le train s’arrête. On détecte ainsi si le conducteur est
toujours correctement en train de travailler.

Syntaxe

clrwdt ; remet le timer du watchdog à 0

Bit du registre STATUS affecté

Aucun

9.33 L’instruction " COMF " (COMplement F)


Effectue le complément à 1 de l’emplacement mémoire spécifié. Donc, inverse tous les bits de l’octet
désigné

Syntaxe

comf f,d ; NOT (f) -> (d)

Bit du registre STATUS affecté

Exemple

movlw B’11001010’ ; charge valeur dans W


movwf mavariable ; initialise mavariable
comf mavariable,w ; charge l’inverse de mavariable dans W
; (W) = B’00110101’

En utilisant cette instruction, on peut également tester si mavariable vaut 0xFF. En effet, si c’est le cas, W
vaudra 0 et Z vaudra donc 1.

9.34 L’instruction " SLEEP " (Mise en sommeil)

Place la PIC en mode de sommeil. Elle ne se réveillera que sous certaines conditions que nous verrons plus
tard.

Syntaxe

Sleep ; arrêt de la PIC

Bit du registre STATUS affecté

Aucun

9. 35 L’instruction " NOP " (No Operation)

Comme vous devez être fatigués, et moi aussi, je vous présente l’instruction qui ne fait rien, qui ne
positionne rien, et qui ne modifie rien. On pourrait croire qu’elle ne sert à rien. En fait elle est surtout
utilisée pour perdre du temps, par exemple pour attendre une ou deux instructions, le temps qu’une
acquisition ai pu se faire, par exemple. Nous l’utiliserons donc à l’occasion.

Syntaxe

nop ; tout simplement

Ceci termine l’analyse des 35 instructions utilisées normalement dans les PICs mid-range.
9.36 Les instructions obsolètes

Il reste 2 instructions qui étaient utilisées dans les précédentes versions de PICs. Elles sont encore
reconnues par la PIC 16F84 mais leur utilisation est déconseillée par Microchip. En effet, leur compatibilité
future n’est pas garantie.

Il s’agit de l’instruction OPTION, qui place le contenu du registre " W " dans le registre OPTION_REG, et
de l’instruction TRIS, qui place le contenu de " W " dans le registre TRISA ou TRISB suivant qu’on utilise
TRIS PORTA ou TRIS PORTB.

Ces instructions ne sont plus nécessaires actuellement, car ces registres sont désormais accessibles
directement à l’aide des instructions classiques.