Atelier du 25 mars 2008
La programmation c'est si simple : atelier 6
Vous remarquerez que j'ai ajouté une étiquette, sur la ligne du centre, cette étiquette sera l'endroit que nous voulons boucler le programme, tel qu'indiqué sur notre ordinogramme. L'interpréteur devra garder cette référence et c'est pour cela que nous devons apposer une étiquette. L'étape suivante (G) nous demande d'effacer le LCD, si ont consulte les documents du fabricant nous trouverons la commande $01, comme étant "home and clear", c'est ce que nous ferons mais en nous assurant que nous préciseront à notre routine SendLCD qu'il s'agit bien d'une commande, en plaçant la variable DATABIT à 0.
Les commandes subséquentes de notre ordinogramme, feront l'affichage de la valeur binaire.
Nous devront donc acheminer du data, vers notre affichage. Le LCD accepte des valeurs ASCII, (American Standard Code for Information Interchange) pour coder les caractères à reproduire. Ces codes sont fournis dans la littérature du fabricant et aussi dans votre manuel d'interpréteur. Dans le cas de MicroCodeStudio ont peut envoyer les caractères entre guillemets et il générera le code approprié, nous nous servirons de cet avantage.
Voila notre affichage binaire est maintenant complété, il nous reste à changer de ligne, pour que
le reste s'affiche au début de la deuxième ligne. Le manufacturier nous indique que la case 1 de
la deuxième ligne porte l'adresse $40. Il nous précise aussi une commande pour déplacer le curseur, nous devont envoyer l'adresse désiré du curseur, en maintenant le bit 7 à 1. Dans notre cas, nous voulons le positionner à la case $40, si nous additionnons la commande $80 (bit 7 =1), nous obtenons $C0. C'est ce que nous devrons acheminer au LCD.
Les deux prochaines étapes, afficher les valeurs décimale et hexadécimale, nous demanderas un peu de réflexion. Nous devrons travailler notre affichage, un caractère à la fois, en commençant par le plus significatif, donc celui de gauche. Voici comment nous procéderons pour isoler ces valeurs. Nous savons déjà que la valeur maximum est 255 et le minimum est 000, donc trois cases d'affichage, une pour les centaines, les dizaines et les unités. Nous pouvons isoler les centaines, en divisant NEWBIN par 100 et en emmagasinant le résultat dans notre variable NEWDEC. Nous nous servirons de notre variable NEWDEC, comme une case de travail, pour éviter de changer la valeur contenue dans NEWBIN. Notre variable temporaire NEWDEC contient une des trois valeurs possibles; 0, 1 ou 2, ce qui représente les centaines, nous pouvons donc l'envoyer à l'afficheur en prenant soin d'ajouter l'offset ASCII ($30).
Pour les phases suivantes, nous aurons besoin d'une variable supplémentaire pour effectuer nos
calculs, j'ai choisi d'ajouter une variable de type BYTE que j'appelle TEMPB. Cette variable sera temporaire et ne sera utilisée que pour faire nos calculs et n'affecte en rien d'autres parties du programme, c'est pour cela que je choisis un nom qui commencent par TEMP, pour me rappeler
que cette variable est locale. Pour trouver le reste de notre division, c.-à-d. les dizaines et les unités, nous soustrayons de NEWBIN, notre valeur initiale intacte, 100 fois la valeur de NEWDEC et nous plaçons le résultat dans notre nouvelle variable TEMPB. Les dizaines et les unités sont maintenant dans TEMPB et il nous faut isoler les dizaines; divisons donc TEMPB par 10 et plaçons le résultat
dans NEWDEC, puisque son contenu (les centaines) ne nous sert plus car il est déjà affiché!
NEWDEC contient maintenant une valeur représentant les dizaines et peut avoir la valeur de 0 à 9. Nous pouvons donc l'afficher sans plus de transformation, en n'oubliant pas l'offset ASCII.
Les unités seront extraites de la même façon que les dizaines. Si nous soustrayons de TEMPB, dix fois la valeur de NEWDEC, nous retrouvons nos unités. Il ne reste qu'à les afficher.
Dans les calculs effectués précédemment, j'ai ajouté des parenthèses pour grouper les calculs. Ces parenthèses sont facultatives pour MicroCodeStudio, car les opérations mathématiques sont effectuées dans un ordre précis, les multiplications et divisions sont exécutés avant les additions et soustraction. Ce principe est très important, car nos résultats peuvent changer réellement, si nous n'en tenons pas compte. Par exemple si je veux calculer un degré Centigrade à partir d'un degré Fahrenheit, je dois soustraire 32, multiplier par 5 et diviser par 9. Si j'écris simplement C = F - 32 *5 /9, l'interpréteur effectueras 32 multiplié par 5 et divisé par 9 et il soustrairas le résultat obtenu de F. Ce résultat sera erroné. Si nous ajoutons des parenthèses, nous précisons à l'interpréteur, ce qui doit être fait en premier. Donc C = (F-32) * 5/9 nous donneras toujours la bonne réponse. Vous pouvez consulter le manuel de votre interpréteur, pour déterminer l'ordre de préséance des opérateurs mathématiques et logique.
Pour le calcul hexadécimal, nous utiliserons la même méthode de division pour séparer nos "digits", sauf que cette fois nous diviserons par 16. L'affichage sera aussi fait différemment car nous avons 16 caractères possibles et qu'ils ne suivent pas dans la table ASCII. Commençons par isoler notre première valeur à afficher. Nous effectuerons cette opération en affectant à notre variable NEWHEX, le quotient de la division de NEWBIN par 16. Cette valeur pourra être entre zéro et quinze (0 à F). Nous savons comment afficher les nombres de 0 à 9, mais nous devrons porter une attention spéciale pour les autres valeurs supérieures à 9.
Nous utiliserons la commande "IF - THEN", cette commande vérifie une condition (test logique) et effectue une opération, si le résultat du test est vrai. Si le résultat du test est faux, cette opération
(qui suit le THEN) sera ignorée. Dans le cas qui nous préoccupe, si la valeur de NEWHEX est supérieur à 9, nous devons effectuer une opération supplémentaire, sinon tout baigne!. Quelle sera cette opération supplémentaire? Eh bien elle consistera essentiellement à l'ajout d'un deuxième "offset", qui représente le saut à effectuer dans la table ASCII. Nous remarquons en consultant le tableau 17, des pages précédentes, que le décalage additionnel est de sept. C'est cette addition supplémentaire qui sera effectué, si notre résultat est supérieur à neuf.
Notre premier digit HEX est maintenant affiché, pour retrouver le reste de notre division, ont pourrait effectuer; TEMPB = NEWBIN - (NEWHEX *16) , ce qui suivrait notre logique utilisée pour les nombres décimaux. Je vous propose ici une autre méthode, l'opération précédente à affiché le premier "nibble" de notre résultat, il nous reste donc à afficher le dernier nibble. Nous nous servirons de l'opération "bitwise" AND. Les opérations appelées "bitwise" effectuent des manipu- lation logique qui travaille directement sur les BITS individuellement. Nous avons précédemment utilisé une opération "bitwise", quand nous avons inversé le résultat de nos commutateurs, NEWBIN = ~NEW. Le tilde ~ représente l'opération NOT dans MicroCodeStudio ( ! est valide aussi) Les principales fonctions sont le AND, OR, Exclusive OR, NOT et leurs dérivés NAND, NOR, NXOR. Regardons les résultats de ces différentes fonctions, en utilisant des diagrammes de Karnaugh. La variable A représente une entrée, anisi que B et le résultat est R. Le NOT est une inversion simple, les 0 deviennent 1 et les 1 deviennent 0.
Donc dans l'expression suivante NEWHEX= NEWBIN & $0F, NEWHEX prendra la valeur des LSB.
Notre travail d'affichage est complété, il nous reste maintenant à effectuer la boucle qui recommence
les opérations. D'après notre ordinogramme, nous devons vérifier si les commutateurs ont été
modifiés, si oui on reprend le processus d'affichage, si non on attends que l'entrée soit changée. Nous effectuons la lecture des commutateurs dans notre variable NEW (elle ne nous sert plus). Nous avions conservé l'état des commutateurs précédents dans OLD, nous pourrons nous en servir pour la comparaison. Si ils sont inégaux, nous effectuerons un saut au début du programme de conversion (DoMore), si ils sont égaux nous retournons lire les commutateurs à nouveau.
Ces sauts dans le programme, s'appelle des "GOTO", ce sont des sauts inconditionnels, qui doivent pointer sur des étiquettes déjà établies dans notre code. Le programme principal est maintenant complété, mais si nous tentons de le programmer ainsi dans notre PIC ™, l'interpréteur nous donneras des messages d'erreurs. Pourquoi? Tout simplement parce que nous n'avons pas écrit le code pour les routines SendLCD, Delay et DoDelay!
Commençons donc par SendLCD, si on se reporte à la page 19, nous voyons notre ordinogramme. La codification ressembleras à ce qui suit:
On conserve la commande initiale dans notre variable COMSAVE et nous décalons les bits MSB pour qu'ils soient alignés avec les LSB ( / 16). Le premier nibble est donc aligné avec les bits correspondants de notre port A. Ensuite on vérifie si notre variable DATABIT est à 1 et nous ajustons le bit RS en conséquence (bit 7du port A). Après l'exécution de la sous-routine Delay, nous manipulons le bit E, pour faire accepter le data au LCD. Nous rechargeons la commande initiale, on masque les MSB et on recommence le processus.
Pour les deux routines suivantes, nous commencions par sauvegarder la valeur de l'accumulateur
dans une variable TEMPA. Dans l'interpréteur choisi il n'existe pas de fonction pour conserver l'accumulateur directement, nous devrons nous servir d'une partie de code assembleur. (ASM) Cette ligne de code sera précédée par @ qui indique à l'interpréteur que la suite de la ligne sera du langage machine. Donc @ MOVWF TEMPA devrait être acceptée pour la sauvegarde de notre accumulateur dans notre variable TEMPA. La commande @ MOVF TEMPA, 0 effectuera le chargement de l'accumulateur avec le contenu de notre variable TEMPA. Dans les faits, il y a peu de chance que cela soit accepté sans erreurs, les lignes de codes écrites en assembleur doivent être très précises. La variable TEMPA n'est pas définie pour le langage assembleur, nous devrons préciser l'endroit exact de l'adresse mémoire à cette fonction pour quelle soit valides. Comment pouvons-nous savoir quelle adresse à été assignée à TEMPA? On pourrait aller voir le fichier avec une extension .asm et découvrir quelle adresse à effectivement été allouée. Il est à noter que ce travail en assembleur est valide pour les registres internes du PIC™ car ils sont définis dans le fichier include M16F62x.inc, dont nous avons déjà parlé. Donc pour cette fois-ci, nous sauterons cette étape, nos variables se chargeront de conserver nos valeurs importantes. Puisque la variable TEMPA ne peut nous servir dans le cas présent, nous nous en servirons pour conserver d'autres valeurs.
Regardons ensemble la routine Delay, nous chargerons TEMPA avec la longueur du délai désiré, contenu dans la variable COUNTER. Ceci nous permettra de conserver COUNTER intacte, pour les appels subséquents de cette routine. Une des premières choses à faire dans cette routine est de décrémenter TEMPA, pour nous indiquer le nombre de fois qu'il reste à exécuter DoDelay. Par la suite nous appelons cette sous-routine, qui produira un délai d'environ 500 microsecondes. Nous vérifions ensuite la valeur de TEMPA pour voir si on à terminé, si oui nous effectuons la commande RETURN. Cette commande fait textuellement ce que son nom exprime, c'est la façon de terminer une sous-routine, le programme reprendra son cours à l'instruction suivante du GOSUB, dans le programme appelant. Je reviendrai plus tard sur le sujet. Supposons que TEMPA n'est pas égal à 0, la commande RETURN ne sera pas exécutée et c'est la commande GOTO DlyLoop qui sera la prochaine. Cette étiquette pointe vers l'endroit de notre routine qui décrémente TEMPA. Cette boucle se répétera donc tant et aussi longtemps que TEMPA ne sera pas égal à zéro.