PIC 16F84A

Remarques et astuces de programmation en assembleur

Equivalence avec le langage C

 

1- Charger une valeur littérale dans un registre

 

movlw B'10001100' ; W = B'10001100'

movwf REGISTRE ; (REGISTRE) = B'10001100' = 0x8C = D'140'

 

REGISTRE = 0x8C ;

 

2- Charger un registre avec le contenu d'un autre registre

 

movf REGISTRE1 , W ; W = (REGISTRE1)

movwf REGISTRE2 ; (REGISTRE2) = (REGISTRE1)

 

 

 

3- Echanger le contenu de deux registres : (REGISTRE1) < - > (REGISTRE2)

 

Il faut utiliser une variable intermédiaire :

REGISTRE_TEMP (registre d'usage général)

 

movf REGISTRE1 , W ; W = (REGISTRE1)

movwf REGISTRE_TEMP ; (REGISTRE_TEMP) = (REGISTRE1)

movf REGISTRE2, W ; W = (REGISTRE2)

movwf REGISTRE1 ; (REGISTRE1) = (REGISTRE2)

movf REGISTRE_TEMP, W ; W = (REGISTRE_TEMP)

movwf REGISTRE2 ; (REGISTRE2) = (REGISTRE_TEMP)

 

REGISTRE_TEMP = REGISTRE1 ;

REGISTRE1 = REGISTRE2 ;

REGISTRE2 = REGISTRE_TEMP ;

 

 

4- Tests de comparaison

4-1- Tests d'égalité

4-1-1- Le contenu du registre est-il nul ?

(REGISTRE) = 0x00 ?

 

movf REGISTRE , f ; (REGISTRE) = (REGISTRE)

btfss STATUS , Z ; test du bit Z

goto non ; Z = 0 c'est-à-dire (REGISTRE) != 0x00

{ bloc d'instructions 1 }

goto suite

non

{ bloc d'instructions 2 }

suite

{ suite du programme }

 

 

4-1-2- Le contenu du registre est-il différent de zéro ?

(REGISTRE) != 0x00 ?

movf REGISTRE , f ; (REGISTRE) = (REGISTRE)

btfsc STATUS , Z ; test du bit Z

goto non ; Z = 1 c'est-à-dire (REGISTRE) = 0x00

{ bloc d'instructions 1 }

goto suite

non

{ bloc d'instructions 2 }

suite

{ suite du programme }

 

 

4-1-3- Le contenu du registre est-il égal à une certaine valeur ?

(REGISTRE) = 0x3F ?

 

movlw 0x3F ; W = 0x3F

subwf REGISTRE, W ; W = (REGISTRE) - 0x3F

btfss STATUS, Z ; test du bit Z

goto non ; Z = 0 c'est-à-dire (REGISTRE) != 0x3F

{ bloc d'instructions 1 }

goto suite

non

{ bloc d'instructions 2 }

suite

{ suite du programme }

 

 

 

4-1-4- Le contenu du registre est-il différent d'une certaine valeur ?

(REGISTRE) != 0x3F ?

 

 

movlw 0x3F ; W = 0x3F

subwf REGISTRE, W ; W = (REGISTRE) - 0x3F

btfsc STATUS, Z ; test du bit Z

goto non ; Z = 1 c'est-à-dire (REGISTRE) = 0x3F

{ bloc d'instructions 1 }

goto suite

non

{ bloc d'instructions 2 }

suite

{ suite du programme }

 

 

 

4-1-5- Le contenu du registre est-il égal au contenu d'un autre registre ?

(REGISTRE1) = (REGISTRE2) ?

 

 

movf REGISTRE2 , W ; W = (REGISTRE2)

subwf REGISTRE1, W ; W = (REGISTRE1) - (REGISTRE2)

btfss STATUS, Z ; test du bit Z

goto non ; Z = 0 c'est-à-dire (REGISTRE1) != (REGISTRE2)

{ bloc d'instructions 1 }

goto suite

non

{ bloc d'instructions 2 }

suite

{ suite du programme }

 

 

 

4-1-6- Le contenu du registre est-il différent du contenu d'un autre registre ?

(REGISTRE1) != (REGISTRE2) ?

 

movf REGISTRE2 , W ; W = (REGISTRE2)

subwf REGISTRE1, W ; W = (REGISTRE1) - (REGISTRE2)

btfsc STATUS, Z ; test du bit Z

goto non ; Z = 1 c'est-à-dire (REGISTRE1) = (REGISTRE2)

{ bloc d'instructions 1 }

goto suite

non

{ bloc d'instructions 2 }

suite

{ suite du programme }

 

 

 

4-2- Tests de supériorité

4-2-1 - Le contenu du registre est-il strictement supérieur à une certaine valeur ?

(REGISTRE) > 0x3F ?

Les valeurs sont supposées en binaire naturel.

 

 

movf REGISTRE , W ; W = (REGISTRE)

sublw 0x3F ; W = 0x3F - (REGISTRE)

btfsc STATUS, C ; test du bit C (Carry)

goto non ; C = 1 c'est-à-dire 0x3F >= (REGISTRE)

{ bloc d'instructions 1 }

goto suite

non

{ bloc d'instructions 2 }

suite

{ suite du programme }

 

 

4-2-2 - Le contenu du registre est-il supérieur ou égal à une certaine valeur ?

(REGISTRE) >= 0x3F ?

Les valeurs sont supposées en binaire naturel.

 

movlw 0x3F ; W = 0x3F

subwf REGISTRE, W ; W = (REGISTRE) - 0x3F

btfss STATUS, C ; test du bit C (Carry)

goto non ; C = 0 c'est-à-dire (REGISTRE) < 0x3F

{ bloc d'instructions 1 }

goto suite

non

{ bloc d'instructions 2 }

suite

{ suite du programme }

 

 

4-2-3 - Le contenu du registre est-il strictement inférieur à une certaine valeur ?

(REGISTRE) < 0x3F ?

Les valeurs sont supposées en binaire naturel.

movlw 0x3F ; W = 0x3F

subwf REGISTRE, W ; W = (REGISTRE) - 0x3F

btfsc STATUS, C ; test du bit C (Carry)

goto non ; C = 1 c'est-à-dire (REGISTRE) >= 0x3F

{ bloc d'instructions 1 }

goto suite

non

{ bloc d'instructions 2 }

suite

{ suite du programme }

 

 

4-2-4 - Le contenu du registre est-il inférieur ou égal à une certaine valeur ?

(REGISTRE) <= 0x3F ?

Les valeurs sont supposées en binaire naturel.

 

movf REGISTRE , W ; W = (REGISTRE)

sublw 0x3F ; W = 0x3F - (REGISTRE)

btfss STATUS, C ; test du bit C (Carry)

goto non ; C = 0 c'est-à-dire 0x3F < (REGISTRE)

{ bloc d'instructions 1 }

goto suite

non

{ bloc d'instructions 2 }

suite

{ suite du programme }

 

 

4-2-5 - Le contenu du registre est-il supérieur ou égal au contenu d'un autre registre ?

(REGISTRE1) >= (REGISTRE2) ?

Les valeurs sont supposées en binaire naturel.

 

movf REGISTRE2 , W ; W = (REGISTRE2)

subwf REGISTRE1, W ; W = (REGISTRE1) - (REGISTRE2)

btfss STATUS, C ; test du bit C (Carry)

goto non ; C = 0 c'est-à-dire (REGISTRE1) < (REGISTRE2)

{ bloc d'instructions 1 }

goto suite

non

{ bloc d'instructions 2 }

suite

{ suite du programme }

 

 

4-2-6 - Le contenu du registre est-il strictement inférieur au contenu d'un autre registre ?

(REGISTRE1) < (REGISTRE2) ?

Les valeurs sont supposées en binaire naturel.

 

movf REGISTRE2 , W ; W = (REGISTRE2)

subwf REGISTRE1, W ; W = (REGISTRE1) - (REGISTRE2)

btfsc STATUS, C ; test du bit C (Carry)

goto non ; C = 1 c'est-à-dire (REGISTRE1) >= (REGISTRE2)

{ bloc d'instructions 1 }

goto suite

non

{ bloc d'instructions 2 }

suite

{ suite du programme }

 

 

 

5- Boucle Do While

Exemple :

 

 

debut

{ bloc d'instructions }

movf REGISTRE , f

btfsc STATUS , Z

goto debut

suite

{ suite du programme }

 

 

6- Boucle While

Exemple :

debut

movlw 0xE8 ; W = 0xE8

subwf REGISTRE, W ; W = (REGISTRE) - 0xE8

btfss STATUS , Z

goto suite

{ bloc d'instructions }

goto debut

suite

{ suite du programme }

 

 

7- Boucle FOR

Une variable (1 octet) sert de compteur.

Exemple :

Pour exécuter le bloc d'instructions 20 fois, la valeur initiale du compteur doit être 21 :

 

movlw D'21' ; W = D'21'

movwf COMPTEUR ; (COMPTEUR) = D'21' pour 20 boucles

debut

decfsz COMPTEUR , f ; (COMPTEUR) = (COMPTEUR) - 1

goto boucle ; (COMPTEUR) != 0

goto suite ; (COMPTEUR) = 0

boucle

{ bloc d'instructions }

goto debut

suite

{ suite du programme }

 

N.B. Avec (COMPTEUR) = 0xFF en valeur initiale, on effectue 254 boucles.

Avec (COMPTEUR) = 0x00 en valeur initiale, on effectue 255 boucles.

Avec (COMPTEUR) = 0x01 en valeur initiale, on effectue 0 boucle.

 

 

 

8- Manipulation de bits. Les masques

 

8-1- Mettre à 0 certains bits d'un registre

 

Exemple : on veut mettre à 0 les bits 1, 2, 4 et 6, les autres bits étant inchangés :

B'u0u0u00u'

movlw B'10101001' ; W = B'10101001' (on appelle ça un masque)

andwf REGISTRE , f ; fonction ET logique

 

Valeur initiale : (REGISTRE) = B'11010101'

Valeur finale : (REGISTRE) = B'10000001'

 

N.B. S'il n'y a qu'un seul bit à mettre à 0, il faut simplement utiliser l'instruction bcf.

S'il faut mettre tous les bits à 0, il faut simplement utiliser l'instruction clrf REGISTRE.

 

 

8-2- Mettre à 1 certains bits d'un registre

Exemple : on veut mettre à 1 les bits 1, 2, 4 et 6, les autres bits étant inchangés :

B'u1u1u11u'

movlw B'01010110' ; W = B'01010110' (masque)

iorwf REGISTRE , f ; fonction OU logique

 

Valeur initiale : (REGISTRE) = B'11010101'

Valeur finale : (REGISTRE) = B'11010111'

 

N.B. s'il n'y a qu'un seul bit à mettre à 1, il faut simplement utiliser l'instruction bcf.

 

8-3- Inverser certains bits d'un registre

Exemple : on veut complémenter les bits 1, 2, 4 et 6, les autres bits étant inchangés.

 

movlw B'01010110' ; W = B'01010110' (masque)

xorwf REGISTRE , f ; fonction logique OU exclusif

 

Valeur initiale : (REGISTRE) = B'11010101'

Valeur finale : (REGISTRE) = B'10000011'

 

N.B. s'il faut inverser tous les bits, il faut simplement utiliser l'instruction comf REGISTRE , f

 

9- Tables de données

On utilise la technique de l'adressage relatif.

On désire effectuer l'opération arithmétique : y = 10x +1

Ainsi, pour x =D'16' : y = D'161'

Cela peut se faire simplement avec un tableau de données.

 

On commence par créer la routine table.

Pour des raisons de simplicité, l'adresse de début de cette routine peut être (pour un microcontrôleur 16F84A) :

; xxxxxxxxxxx

; Routine table

; xxxxxxxxxxx

org 0x0300 ; adresse de début de la table

table

addwf PCL , f ; (PCL) = (PCL) + W

retlw D'1'

retlw D'11'

retlw D'21'

retlw D'31'

retlw D'41'

retlw D'51'

retlw D'61'

retlw D'71'

retlw D'81'

retlw D'91'

retlw D'101'

retlw D'111'

retlw D'121'

retlw D'131'

retlw D'141'

retlw D'151'

retlw D'161'

retlw D'171'

retlw D'181'

retlw D'191'

retlw D'201'

retlw D'211'

retlw D'221'

retlw D'231'

retlw D'241'

retlw D'251'

; Fin de la routine table

; xxxxxxxxxxxxxxxxxx

 

Avec un début de routine à l'adresse 0x300, l'instruction retlw D'1' se trouve à l'adresse 0x301, retlw D'11' à l'adresse 0x302 etc...

La table peut contenir jusqu'à 255 éléments (0x301 à 0x3FF).

Ici, notre table possède 26 éléments donc pas de problème de taille.

 

Dans le programme principal, pour appeler la routine, il faut au préalable charger le registre spécial PCLATH avec la valeur 0x03 (0x02 si l'adresse de début est 0x200 etc ...) :

 

movlw 0x03 ; W = 0x03

movwf PCLATH ; (PCLATH) = 0x03

movlw D'16' ; W = D'16' : 16ème ligne de la table

call table

movwf resultat ; (resultat) = D'161'

 

(C) Fabrice Sincère