<< The Fribotte Homepage >>
Un club de passionnés en robotique participant à la coupe de France E=M6.
[Accueil] [Qui sommes-nous ?] [Robots] [Coupe e=m6] [BD Technique] [Forum] [Reportages] [Liens] [WiKiFri]

Fribotte

 

La Programmation des pics
par Bigonoff
Premiere partie - pic 16f84 - Révision 4

Téléchargement des fichiers originels ici
Publié le 26/10/2001

18. Astuces de programmation

Index coursIndex du cours
Chapitre précédent17. Le reste du datasheet
Chapitre suivant18. Astuces de programmation (Suite)

 

18. Astuces de programmation

Dans ce chapitre, nous allons examiner quelques méthodes simples pour se tirer de situations classiques.

18.1 Les comparaisons

Quoi de plus simple que d’effectuer une comparaison entre 2 nombres. Il suffit d’effectuer une soustraction. Soit par exemple comparer mem1 avec mem2 :

  movf mem1 , w ; charger mem1
  subwf mem2 , w ; soustraire mem2 – mem1

Il vous suffit ensuite de tester les bits C et Z du registre STATUS pour connaître le résultat :

  • Si Z = 1 , les 2 emplacements mémoires contiennent la même valeur
  • Si Z = 0 et C = 1, le résultat est positif, donc mem2 est supérieur à mem1
  • Si Z = 0 et C = 0, le résultat est négatif, donc mem2 est inférieur à mem1

Si vous désirez simplement comparer l’identité entre 2 valeurs, sans modifier C, vous pouvez également utiliser l’instruction " xor "

  movf mem1 , w ; charger mem1
  xorwf mem2 , w ; Si égalité, tous les bits sont à 0 et Z est à 1


18.2 Soustraire une valeur de w

Supposons que vous avez une valeur dans W et que vous désirez soustraire 5 de cette valeur. Le premier réflexe est le suivant :

  sublw 5  

C’est une erreur classique, car vous avez en réalité effectué (5-w) au lieu de (w-5). Il vous faudra donc effectuer le complément à 2 de cette valeur pour obtenir le bon résultat. Effectuez plutôt ceci :

  addlw -5  

Et oui, ajouter –5 correspond à soustraire 5. Faites-le par écrit si vous n’êtes pas convaincu.

18.3 Les multiplications

Comment effectuer une multiplication ? Et bien tout simplement de la même manière que nous l’effectuons manuellement.

Nous allons créer une routine qui multiplie ensemble 2 nombres de 8 bits. Le résultat nécessitera donc 16 bits, donc 2 octets. En effet, pour obtenir le nombre de digits maximal du résultat d’une multiplication, il suffit d’additionner le nombre de digits des différentes opérandes.

Réalisons donc une multiplication manuelle. Nous allons multiplier 12 par 13. Nous allons travailler avec 4 bits multipliés par 4 bits, avec résultat sur 8 bits. Ceci afin de réduire notre explication. Exécutons donc notre multiplication manuellement.

       

1

1

0

0

12

     

X

1

1

0

1

13

       

1

1

0

0

12

     

0

0

0

0

0

0

   

1

1

0

0

0

0

48

 

1

1

0

0

0

0

0

96

1

0

0

1

1

1

0

0

156

 

Qu’avons-nous effectué ? Et bien nous avons multiplié 12 par chaque " chiffre " de 13 en commençant par la droite . Nous avons décalé d’une rangée vers la gauche chaque résultat intermédiaire avant sont addition finale.

La particularité en binaire, c’est qu’il n’y a que 2 chiffres : 0 et 1. Donc on multiplie soit par 0 (ce qui revient à ne rien faire) soit par 1 (ce qui revient à simplement recopier le chiffre).

Voici donc ce que nous obtenons en binaire :

  • On multiplie 1100 par 1 . On obtient donc 1100 (D’12’)
  • On multiplie 1100 par 0 et on décale le résultat vers la gauche. On obtient donc 0000
  • On multiplie 1100 par 1 et on décale le résultat vers la gauche. On obtient 1100 complété par 00, soit 110000, donc D ‘48’
  • On multiplie 1100 par 1 et on décale le résultat vers la gauche. On obtient 1100 complété par 000, soit 1100000, donc D’96’.
  • On additionne le tout et on obtient 10011100, soit D’156’.

Si on réalisait ce programme, il nous faudrait 4 variables supplémentaires pour stocker les résultats intermédiaires. 8 dans le cas d’une multiplication de 8 bits par 8 bits. On peut alors imaginer de se passer de ces résultats intermédiaires en procédant à l’addition au fur et à mesure du résultat intermédiaire avec le résultat final.

On obtient alors l’algorithme suivant :

  • On multiplie 1100 par 1. On place le résultat dans résultat final
  • On multiplie 1100 par 0. On décale une fois. On ajoute au résultat final
  • On multiplie 1100 par 1. On décale 2 fois. On ajoute au résultat final
  • On multiplie 1100 par 1. On décale 3 fois. On ajoute au résultat final.

Vous pouvez tenter d’écrire ce programme. Ceci reste pratique pour des multiplications de 4 par 4 bits. Pour des multiplications de 8 bits par 8 bits, vous allez devoir réaliser des tas d’additions de nombres de 16 bits avec des nombres de 16 bits. De plus vous devrez décaler le multiplicateur, ce qui impliquera, soit de le modifier (ce qui n’est peut-être pas toujours souhaitable), soit de le sauvegarder, ce qui consomme 1 octet supplémentaire.

En réfléchissant un peu, on peut se dire que plutôt que de décaler le multiplicateur vers la gauche, nous pouvons décaler le résultat vers la droite. Ceci revient au même, mais vous n’avez plus que des additions de 8 bits, toujours dans le poids fort du résultat

Voici comment cela fonctionne avec notre exemple, pour ne pas faire trop long :

  • On multiplie 1100 par 1. On place le résultat à fond à gauche du résultat. Dans résultat on a : 11000000
  • On décale le résultat vers la droite : résultat = 01100000
  • On multiplie 1100 par 0 . On ajoute au résultat : résultat = 01100000
  • On décale le résultat vers la droite : résultat = 00110000
  • On multiplie 1100 par 1. On ajoute au résultat à gauche : résultat :11000000 + 00110000 = 11110000
  • On décale le résultat vers la droite : résultat = 01111000
  • On multiplie 1100 par 1. On ajoute au résultat à gauche : résultat : 11000000 + 01111000 = 100111000 (9 bits). Le bit8 (en vert) est dans le carry.
  • On décale le résultat vers la droite : résultat = 10011100 = D’156’

Notez qu’on ajoute toujours au quartet de poids fort (centrage à gauche). Dans le cas d’une multiplication de 8 bits par 8 bits, on ajoutera donc à l’octet de poids fort. Par moment, nous aurons débordement de l’addition sur 9 bits. Souvenez-vous que le report se trouve dans le carry. Or, dans un décalage, le carry est amené dans le résultat, donc on récupère automatiquement notre 9ème bit, qui deviendra le 8ème après décalage vers la droite.

Cette procédure est très simple à mettre en programme : la preuve, voici le pseudo-code pour une multiplication 8 bits par 8 bits.

  • Effacer le résultat
  • Pour chacun des 8 bits du multiplicateur
    • Si bit de droite du multiplicateur = 1
      • Ajouter multiplicande au poids fort du résultat
    • Décaler 16 bits du résultat vers la droite
    • Décaler multiplicateur vers la droite
  • Bit suivant

Si nous plaçons de plus le décalage du multiplicateur en-tête, avant le test de bit, nous récupérons le bit à tester dans le carry. Le programme devient :

  • Effacer le résultat
  • Pour chacun des 8 bits du multiplicateur
    • Décaler multiplicateur vers la droite
    • Si carry = 1
      • Ajouter multiplicande au poids fort du résultat
    • Décaler 16 bits du résultat vers la droite
  • Bit suivant

Remarquez que ceci est très simple. Nous allons mettre ce pseudo-code sous forme de programme. Nous utiliserons la variable multi comme multiplicateur, multan comme multiplicande, resulH comme résultat poids fort et resulL comme poids faible. multemp est le multiplicateur temporaire qui sera modifié. cmpt est le compteur de boucles Voici donc le programme :

  clrf resulH ; effacer résultat poids fort
  clrf resulL ; idem poids faible
  movlw 0x08 ; pour 8 bits
  movwf cmpt ; initialiser compteur de boucles
  movf multi , w ; charger multiplicateur
  movwf multemp ; sauver dans multemp
  movf multan , w ; multiplicande dans w
loop      
  rrf multemp , f ; décaler multiplicateur vers la droite
  btfsc STATUS , C ; tester si bit sorti = 1
  addwf resulH , f ; oui, ajouter au résultat poids fort
  rrf resulH , f ; décaler résultat poids fort
  rrf resulL , f ; décaler résultat poids faible
  decfsz cmpt , f ; décrémenter compteur de boucles
  goto loop ; pas fini, bit suivant

Vous pouvez créer un petit projet et tester ce programme dans le simulateur. Vous verrez qu’il fonctionne parfaitement. Vous pouvez en faire une sous-routine ou une macro à ajouter dans votre propre fichier include.

Les 2 lignes en gris effectuent un décalage du résultat sur 16 bits. Le bit perdu dans resulH est récupéré dans le carry et remis comme bit7 dans resulL. Astuce de programmation : si l’addition précédente à eu lieu (ligne bleue), le 9ème bit résultant de l’addition est dans le carry, et se retrouve donc comme b7 dans resulH. Par contre, s’il n’y a pas eu l’addition, le carry est forcément à 0 du fait du test (en vert). Vous voyez maintenant l’intérêt d’avoir testé le bit faible du multiplicateur en se servant du carry.

Rassurez-vous, c’est avec l’expérience que vous arriverez à ce genre de résultat. Ce petit programme est disponible sous la dénominations : " multi.asm " [ NDLR : Fichiers exemples ici ]

18.4 Multiplication par une constante

Dans le cas précédent, nous avons effectuer une multiplication entre 2 variables qui peuvent prendre n’importe quelle valeur. Dans le cas où vous utilisez une constante, c’est à dire que vous connaissez le multiplicateur au moment de la conception de votre programme, vous devez essayer, pour des raisons d’optimisation de raisonner en multiplications par 2.

En effet, pour effectuer une multiplication par 2 il suffit de décaler la valeur vers la gauche. C’est très rapide à mettre en œuvre. Ne pas oublier cependant de mette C à 0 avant le décalage, pour ne pas entrer un bit non désiré dans le mot décalé.

Supposons donc que vous devez, dans votre programme, effectuer des multiplications par 10 (décimal). Et bien nous allons essayer de ramener ceci en multiplications par 2. C’est tout simple :

Pour multiplier par 10, il faut :

  • multiplier par 2 (donc décaler l’opérande vers la gauche)
  • multiplier encore par 2 (= multiplier par 4, donc décaler encore une fois).
  • Ajouter l’opérande originale (donc opérande + opérande*4 = opérande *5)
  • Multiplier le résultat par 2 (donc décalage vers la gauche).

Voici donc une multiplication par 10 très rapide. On a fait "fois deux fois deux plus un fois deux". Donc 3 décalages et une simple addition.

En général, on peut s’arranger pour obtenir les résultats des multiplications par des constantes en utilisant cette méthode.

Ceci vous fera gagner un précieux temps programme.

Voici un petit programme qui multiplie un nombre de 4 bits contenu dans mem1 par 10. Résultat dans resul. Vous pouvez adapter pour un nombre de 8 bits très facilement :

  movf mem1 , w ; charger opérande sur 4 bits
  movwf resul ; sauver dans résultat
  bcf STATUS , C ; effacer carry
  rlf resul , f ; multiplier par 2
  rlf resul , f ; multiplier par 4
  addwf resul , f ; ajouter mem1, donc multiplier par 5
  rlf resul , f ; multiplier par 10

 

 

Index cours
Index du cours
Chapitre précédent
17. Le reste du datasheet
Chapitre suivant
18. Astuces de programmation (Suite)

 


Complétez cette page, posez vos questions et remarques ici : WiKiFri

Page http://fribotte.free.fr/bdtech/cours/pic16f84/PART1_cours18a.html modifiée le 14/10/2002.
Copyright fribotte@free.fr, libre de droit pour toute utilisation non commerciale.
Reproduction autorisée par simple mail