http://www.didel.com/ [email protected] www.didel.com/pic/Cours877-2.pdf Apprendre à programmer avec le 16F877A - 2e partie Exemples et exercices sous www.didel.com/pic/Cours877-2.zip 1ere partie sous www.didel.com/pic/Cours877.pdf Gérons des entrées Câblons le microdule P4S4 sur le portA. Il a 4 poussoirs sur les 4 bits de poids faibles, et 4 interrupteurs. Copions le portA sur le portD Ex877-201.asm On voit que les poussoirs sont actifs à zéro (quand on presse, on a un zéro, affiché en rouge) et que les interrupteurs ont leur état ‘’1’’ en haut, ce qui est logique. Le portA n’a que 6 bits connectés. On voit que les 2 interrupteurs à droite n’ont pas d’effet, et que le processeur met ces bits à zéro. Masquage – instruction ET Pour n’observer qu’un seul bit ou un groupe de bits, on fait un ET logique avec une valeur que l’on appelle masque, et que l’on écrit naturellement en binaire. Par exemple, si on veut surveiller le poussoir tout à droite, câblé sur le bit 0, on écrit Move And Move PortA,W #2'00000001,W W,PortD ; pour voir l’effet Le résultat est qu’un seul bit passe, et la valeur est nulle ou non, ce qui permet d’aiguiller le programme dans deux directions selon la valeur du bit. Le programme Ex877-202.asm allume tous les bits du port C si le poussoir est pressé. Ce programme est bien écrit avec une étiquette inutile (Allume:) qui met en évidence la structure du programme avec 2 branches. En assembleur, l’efficacité du code compte plus et on fait une jolie astuce : on se prépare à écrire des zéros dans le portC, et si le poussoir est pressé, on change d’avis. On économise 4 instructions, et aussi quelques microsecondes. Move PortA,W And #2'00000001,W Move W,PortD Move #2'00000000,W ; Si la touche est relâchée Skip,NE ; NE si relâché Move #2'11111111,W ; On passe ici si la touche est pressée Move W,PortC Jump Loop Créez vous-même le programme Ex877-203.asm avec ces instructions, et retenez bien ce truc, c’est efficace. Instruction OU Le OU logique superpose les 2 opérandes, chaque bit étant le OU des bits correspondants. Cela permet de forcer les bits du masque à un (le ET force les bits à 0. Par exemple, si on veut masquer les bits de poids forts et les mettre tous à un pour ne voir que les poussoirs du microdule P4S4, on écrit Move Or Move PortA,W #2'11110000,W W,PortD Une application fréquente est de décider si une variable 16 bits (un compteur, un long registre à décalage) ne contient que des zéros. Le OU des deux mots est nul que si chaque mot est nul. Le programme Ex877-204.asm améliore le programme Ex877-110 vu précédemment . Il arrête le décalage dès que les deux registres sont vides. Instruction XOR Le OU-Exclusif XOR met un 1 si les 2 bits correspondants sont différents. Si l’un des deux mots (masque) est à zéro ne change rien ; un masque à un change tout. Si le masque est égal à l’autre mot, le résultat est nul, et il est nul seulement dans ce cas. Par exemple, on veut savoir si les interrupteurs sont en haut et le poussoir de droite activé, donc si le processeur lit 2’00111110 sur le portA. On écrit Move PortA,W XOR #2’00111110,W Skip,EQ Jump Mauvais Jump BonneCombinaison Inversion logique – Instruction NOT On a vu comment inverser tous les bits : Xor #2’11111111,W en plus court Xor #-1,W L’instruction NOT fait la même chose sur une variable. Vous voulez savoir si tous les bits d’une variable ou d’un port sont à 1 ? 1ere solution 2e solution Not Var Skip,EQ Jump Pas à un ; tout est à un Inc Var Skip,EQ Jump Pas à un ; tout est à un Test d’un bit – Instruction TestSkip,BS L’instruction TestSkip,BS Var:#bit est longue à écrire, mais elle dit bien ce qu’elle fait : on teste un bit de la variable ; si ce bit est à 1 (set) on saute l’instruction suivante. Pour nos poussoirs, c’est donc facile. On veut afficher différents motifs selon le poussoir : TestSkip,BS PortA :#0 Jump Poussoir0Actif TestSkip,BS PortA :#1 Jump Poussoir1Actif etc. Ecrire #0 #1 n’est pas recommandé, il faut toujours donner des noms aux signaux. Une bonne habitude est de distinguer les noms donnés aux bits en ajoutant au début un b minuscule (pour les masques un m minuscule). C’est ce qui est fait dans le programme Ex877-205.asm. Cela devient plus intéressant, mais étudiez bien ce qui permet le clignotement. L’instruction TestSkip,BC Var:#bit saute si le bit testé est clear (à zéro). Compter des impulsions Si on veut compter les actions d’un poussoir, le programme ne doit compter qu’une fois par action, et ne pas compter quand on presse, ni quand on relâche. Il faut donc deux boucles d’attente. On peut décider d’agir quand on presse ou quand on relâche. Loop: AtPous: TestSkip,BC PortA:#bPousD Jump AtPous ; on vient de presser, que faut-il faire AtRel: TestSkip,BS PortA:#bPousD Jump AtRel ; on vient de relâcher, que faut-il faire Jump Loop Le programme Ex877-206.asm compte sur le PortC quand on presse, et sur le portD quand on relâche. Que remarque-t’on ? Les contacts mécaniques ont des rebonds, pendant 0.1 à 5 millisecondes (selon la mécanique interne) et le processeur peut les voir comme des actions séparées si on échantillonne trop souvent. On échantillonne donc à plus de 1ms pour des poussoirs miniatures, et moins de 0.1s pour ne pas rater les actions humaines les plus rapides. Modifiez le programme Ex877-206.asm pour vérifier. Evidemment, il ne faut pas écrire AtPous: TestSkip,BC PortA:#bPousD Call Del1ms Jump AtPous 2.16 Testeur de réflexes On veut savoir combien de temps, ou quand on a pressé sur un poussoir. Il faut dans la boucle d’attente, surveiller le signal du poussoir, toutes les 10 millisecondes par exemple si on veut être assez précis, et presser moins de 10ms * 255 = 2.55 secondes si on ne veut pas de débordement. Pour un détecteur de réflexes, on met un compteur à zéro, on attend quelques secondes avant d’allumer une LED et on compte à partir de cet instant. Le cœur du programme Ex877-207.asm est donc : TestReflexe: Clr PortC Move #20,W Call DelWx01s ; attente 2 secondes Dec PortC ; PortC à 1 Clr PortD AtPous: Move #10,W Call DelWx1ms Inc PortD ; Durée en multiple de 10ms TestSkip,BC PortA:#bPousD Jump AtPous Fini: Jump Fini ; ou Jump TestReflexe On se pose naturellement quelques questions avec ce programme. Comment compter en décimal et pas en binaire, comment faire une attente initiale aléatoire, comment recommencer Agir sur une seule ligne de sortie Si on sait observer une seule entrée, on doit aussi pouvoir agir sur une seule sortie. Ce sont les instructions Set Var:#bit et Clr Var:#bit (Clr Var existe, on l’a utilisé pour mettre des ports à 0, mais pas Set Var). Ces instructions très utiles agissent aussi sur les fanions et ont une notation abbrégée SetC Force le carry à 1 ClrC Force le carry à 0 Par exemple, comment simuler l’instruction RR Var, qui fait un rotate 8 bits sans passer par le carry ? On teste le carry et on le copie dans le bit de poids fort. ClrC RRC Var ; le bit 7 (poids fort) et à 0 Skip,CC Set Var :#7 ; à 1 si carry à 1 Imaginons une application qui demande de permuter les paires de bits. Les bits 76543210 doivent devenir 67452301. Avec 8 TestSkip et 8 Set bits et quelques instructins supplémentaires, ou peut résoudre le problème. Une autre solution utilise des masquages (un bit sur deux) et un décalage. Joli exercice de style pour se faire la main. Instruction Swap Les mots de 8 bits représentent souvent deux chiffres hexa ou décimaux (code BCD). L’instruction Swap Var permute ces deux moitiés. Swap Var,W copie dans W les bits permutés, sans modifier Var. 76543210 32107654. Arithmétique L’arithmétique binaire ou hexadécimale ne nous est pas naturelle, et la limitation des opérations à 8 bits ne facilite pas les choses. En assembleur, on ne fait pas des applications qui nécessitent des calculs. Les applications pour des petits microcontrôleurs se limitent à corriger des paramètres et comparer des valeurs, on ne va donc chercher à comprendre que l’essentiel. Les PICs ne savent qu’ajouter et soustraire des nombres binaires de 8 bits. en hexa, cela fait des nombres entre 16’00 et 16’FF. On a vu que si on compte, après FF on a 00. La représentation sur un cercle, le cercle des nombres arithmétiques, va nous être utille. Mais raisonnons avec un cercle décimal, de 0 à 99, ce qui permettra de prendre des exemples numériques. Dans chaque base, les problèmes de dépassement de capacité de nombres négatifs, de comparaison, sont les mêmes. Seul le diamètre du cercle change ! Additionnons deux nombres de 2 chiffres. Si le résultat dépasse la capacité. 100 dans toutes les bases, un report (carry) est généré. Ce carry peut vouloir dire qu’il y quelque chose d’anormal dans l’application, ou qu’il faut en tenir compte pour calculer avec des chiffres supplémentaires, comme on verra plus loin. S’il y a dépassement de capacité, le bit C (Carry) est mis à un. Si le résultat est nul, le bit Z (Zero) est activé. Pour les tests, on va utiliser le microdule PotToD8 en série avec un affichage sur le portA, en se limitant à des valeurs inférieures à 16’3F, puisqu’il n’y a que 6 bits sur le portA. Vérifions avec le programme qui copie A sur D, le Ex877-201.asm déjà vu. L’interrupteur sur le PoToD8 doit être en bas. Additionnons le portA avec une valeur constante affichée sur le portC. Le résultat est copié sur le portD. Ex877-210.asm Comment visualiser le Carry ? Le programme Ex877-211.asm.affiche sur le port C le registre Status, qui contient ces deux bits, carry C en position 0 et Z en position 2. Oubliez le bit 1 qui va changer parfois et qui aide les calculs en décimal. Observez quand on tourne le potentiomètre et que le total passe de FF à 00 puis 01. Double précision Calculer en 16 bits nécessite, comme à la main, d’additionner les poids faibles, de mémoriser le report et l’ajouter à la somme des poids forts. L’exemple Ex877-212.asm montre de plus que l’assembleur sait aussi calculer et masquer. Les opérations dans l’assembleur CALM facile à mémoriser : + - * / .And. .Or. etc (on retrouve le nom des instructions). Exercice : Fibonacci La suite de Fibonacci est 1 1 2 3 5 8 13 21 … chaque nouveau nombre est la somme des deux précédents. Afficher cette suite sur le portD (en hexa .. 8 D 15 …) en s’arrêtant dès qu’il y a dépassement de capacité. Solution Ex877-220.asm Complément à 1 et à 2 Le complément à 1 inverse tous les bits, c’est ce que fait l’instruction Not. vue précédemment. Il ne faut pas confondre avec le complément à 2, ou complément vrai, résultat de l’opération zéro moins le nombre. Le figure ci-contre justifie ce terme : 20 est le complément de 80 (en format 2 digits décimal), et ceux qui ont étudié les logarithmes vont comprendre la suite sans peine : au lieu de soustraire, on peut additionner le complément. La figure ci-contre montre qu’au lieu de calculer 40-20, on peut calculer 40 + (100-20) = 40 + 80. Cette addition du complément génère un Carry, alors que la soustraction ne génère pas d’emprunt (borrow). Contrairement à la majorité des micro-contrôleurs, les PICs ne soustraient pas, ils ajoutent le complément, et le carry a la valeur inverse du borrow. C’est tout ce dont il faut se souvenir si on veut savoir si la soustraction est possible (a donné un résultat positif). Le programme Ex877-213.asm effectue les soustractions 16’10 – (valeur du potentiomètre=0..3F). Observez C et Z. Donc, au lieu de soustraire, on peut ajouter le complément. Pour les constantes, l’assembleur sait calculer les compléments, on a déjà utilisé des Move #-1,W au lieu de Move #16’FF,W. On écrit donc souvent pour soustraire une valeur immédiate Move #-Valeur,W Move #Valeur,W calcule Var - #Valeur Var Add W,Var Sub W,Var L’instruction Sub des PICs est inhabituelle. Heureusement CALM (inspiré de Motorola et pas d’Intel) dit exactement ce que font les instructions arithmétiques. Le 1e opérande est soustrait du 2e, et le résultat est mis dans le 3e opérande, s’il y en a un, autrement dans le 2e. Les instructions arithmétiques sont les suivantes : Add #Val,W ; #Val + W W ; pas sur 10F 12F Add Var,W ; Var + W W Add W,Var ; W + Var Var Sub W,#Val,W ; #Val - W W ; pas sur 10F 12F Sub W,Var,W ; Var - W W Sub W,Var ; Var - W Var Nombres négatifs Encore une complexité à mentionner, mais que nous n’allons pas analyser. On a placé des nonbres négatifs sur notre cercle des nombres. Où s’arrêter, comment savoir si un point sur le cercle est –10 ou F0? Le processeur ne connaît que des groupes de 8 bits, et son électronique transforme ces mots sans savoir ce qu’ils représentent. C’est le programmeur qui décide s’il travaille avec des nombres positifs de 0 à 16’FF = 255, ou avec des nombres positifs et négatifs, usuellement les positifs vont de 0 à 16’7F et les négatifs de - 1 (= 16’FF) à -16’80 (= 16’80). La soustraction de deux nombres positifs peut donner un résultat négatif, représenté en complément à 2. Pour avoir sa valeur absolue, positive, on doit soustraire le résultat de zéro (prendre son complément à 2) Clr Sub Temp ; variable temporaire W,Temp,W ; W 0-W = -W ou –W W Quand on parlera de vitesse positive et négative d’un moteur, il faudra choisir une représentation adaptée. L’arithmétique des nombres négatifs est délicate, des explications, des routines et des macros sont données sous www.didel.com/pic/Arith.pdf. En C, il faut déclarer des types de données (8 bits, 16 bits, positifs, signés, etc) et le compilateur choisit les routines de calcul correspondantes. On choisit une taille suffisante pour les nombres, pour ne pas avoir de dépassement de capacité, et on achète un processeur plus rapide avec une mémoire plus grande. Comparaison On a souvent besoin de comparer deux nombres positifs ou négatifs et on utilise la soustraction pour cela. En positifs Move Sub Nb1,W W,Nb2,W Si C est à 1, Nb1 > Nb2 Si Z est à 1, Nb1 = Nb2 En négatifs, c’est compliqué (www.didel.com/pic/Compare.pdf ) L’exercice Ex877-214.asm dit si le nombre lu sur le portA est entre 16’10 et 16’20. On affiche sur le port D des motifs différents. Saturation Souvent, un compteur doit avoir une butée et cela s’implémente avec quelques instructions. Une addition peut aussi devoir être saturée ; c’est un peu plus délicat puisque le résultat d’une addition peut être petit, s’il y a dépassement de capacité. Avant d’accéder dans une table, il peut être important de saturer la valeur pour éviter de lire en dehors des valeurs prévues. Le document www.didel.com/pic/Satu.pdf traite les cas les plus fréquents. Multiprécision Ne parlons pas de la multiprécision et des nombres négatifs difficiles à maîtriser. Les PICs ne sont pas faits pour calculer, mais pour manipuler des bits. Des routines et macros très utiles sont décrites sous www.didel.com/pic/Arith.pdf BCD (Décimal codé binaire) Le code BCD représente 2 chiffres décimaux (0 à 9) sur les deux moitiés d’un octet. On peut additionner, soustraire, des nombres BCD, des exemples de routines sont donnés sous www.didel.com/pic/BCD.pdf . Compter et décompter en BCD est souvent utile, si le résultat doit être présenté sur un affichage 7 segments. Convertir de binaire en décimal est souvent nécessaire si on interagit avec un clavier écran. Voir www.didel.com/picg/doc/DopiBinD.pdf Moyennes Calculer la moyenne de nombres consécutifs, par exemple pour filtrer un capteur, n’est pas évident. Le document www.didel.com/pic/Moyennes.pdf montre comment faire. Résumé du chapitre On a vu comment lire des entrées et supprimer les rebonds de contact. Les opérations logiques permettent de masquer des bits, ou modifier leur valeur. On teste et modifie des bits isolés avec les instructions TestSkip,BS (ou ,BC), Set Clr Les bits sont numérotés de 0 (poids faible) à 7 (poids fort). Le bit n a un poids 2n, noté 2**n dans l’assembleur. Le cercle des nombres aide à comprendre le rôle des fanions C (Carry) et Z (Zero bit, qui vaut 1 si le résultat est nul) dans les opérations de comptage/décomptage et d’addition ou soustraction. Le PIC soustrait en additionnant le complément, ce qui a pour effet que le carry est inversé par rapport à notre habitude scolaire du borrow. La 3e partie liste les instructions, sans exemples. Il faut parcourir cette partie, et y revenir en cas d’incertitude, ou d’erreur d’assemblage due à une mauvaise syntaxe. jdn 101001
© Copyright 2025 ExpyDoc