Atelier du 26 février 2008
La programmation c'est si simple : atelier 4
J'avais mentionné un peu plutôt, qu'un module bien conçu devrait conserver les valeurs des registres. Donc notre module SendLCD, devrait lui aussi conserver les registres et la valeur contenu dans l'accumulateur, avant d'effectuer sa fonction. A la fin juste avant le retour, il devrait les replacer à leurs états initiaux. Toutefois dans certains cas, on peut omettre cette étape si le changement ne pose aucun problème au déroulement normal du programme. Regardons maintenant le nouveau module DoDelay. Celui-ci utilisera l'accumulateur pour faire son travail, donc quand le module DoDelay termineras et qu'il redonne le contrôle au module "appelant", la valeur de l'accu- mulateur sera changé. Dans notre module SendLCD, à chaque fois que le délai est appelé, la valeur contenue dans l'accumulateur sera modifié, nous perdrons donc la valeur de notre commande ou la position des bits de contrôle RS et E! Ce n'est pas très intéressant en soi, mais comment peut-on donc sauvegarder notre valeur? Deux méthodes s'offrent à nous, la première sauvegarder la valeur de l'accumulateur avant d'appeler DoDelay et la recharger après DoDelay. Cette méthode nous demandera douze lignes de code, six sauvegardes et six rappels. La deuxième méthode sera incluse dans DoDelay, ce qui nous demandera seulement 2 lignes de code, une sauvegarde et un rappel. Voyons comment s'effectue cette opération.

Tableau 14

Quel sera la longueur de ce délai? Pour répondre à cette question il faudra savoir, quel est la vitesse du CPU et le nombre de cycles utilisés pour chaque instruction. Supposons un PIC qui utilise une horloge interne de un mégahertz, chaque impulsion d'horloge dureras donc une microseconde. La plupart des instructions d'un pic, s'effectue en un seul coup d'horloge, donc ce CPU à une capacité de un million d'opérations par seconde (1 MIPS). Si nous effectuons un calcul sommaire, nous obtiendrons, la longueur de notre module DoDelay. Premièrement sauvegarder l'accumulateur (1), Charger l'accumulateur avec 248 (1), décrémenter l'accumulateur (247), vérifier sa valeur (247), rétablir l'accumulateur (1), et le retour (2), pour un total de 499 coups d'horloge. Cette routine prendra donc environ 499 microsecondes pour s'effectuer. Elle sera donc très courte et dans
certains cas, elle ne sera pas suffisante.
Supposons que nous ayons besoin d'un délai plus important, comme cent millisecondes. Comment pouvons-nous améliorer cette routine pour avoir un délai plus important?
On pourrait imaginer appeler cette routine environ 200 fois pour créer notre délai requis.
On pourrait aussi faire une autre routine qui accepterais une valeur dans une variable et qui répéterait DoDelay 200 fois!!!

Tableau 15

Ce mécanisme de modules intercalés, peut-être utilisé un certain nombre de fois. La grandeur de la pile ("stack") nous limiteras, quand à la quantité de boucles intercalées. Les CPU modernes nous offrent aussi, d'autres possibilités pour générer des délais, il s'agit des "timers". En effet plusieurs CPU possèdent des registres internes capables de compter au-delà de 256, car il utilisent des registres doubles et des modules diviseurs pour l'horloge ("pre-scaler"). Si vous posséder un tel registre, je vous recommande de vous en servir, votre programme sera plus léger, car l'utilisation de ces "timers" est très simple. De façon générale, vous choisissez une valeur pour le diviseur, vous précharger une valeur dans le timer en question et il ne vous reste qu'à vérifier un "flag" qui indique que l'opération est terminée! Il peut même vous l'indiquer en générant une interruption (IRQ), pendant que vous effectuer d'autre tâche.
Nous regarderons en détails, les mécanismes de ces registres, les méthodes d'interruptions et le fonctionnement interne du microcontrôleur, dans les chapitres qui suivent.
8-Écrire le code, en suivant la syntaxe de l'interpréteur.
Une des dernières étapes consiste à transformer nos ordinogrammes, en un code acceptable pour le CPU que nous utiliserons. Pour ce faire nous nous servirons d'un interpréteur. Cet outil agit comme un traducteur, et génère normalement du code machine dans un fichier de type "HEX". Pour nommer quelques-uns de ces outils, il y a l'assembleur, le langage "C" et le basic. Chacun de ces traducteurs peuvent produire du code machine pour une multitude de CPU. Ils feront usage de librairies, contenant la traduction elle-même, propre à chaque CPU. Ces interpréteurs, en plus de traduire nos lignes de codes, réserverons des cases mémoires pour nos variables déclarées et s'occuperons des directives données au CPU dans ses registres de configuration. Ces directives contrôleront la structure interne du CPU, comme la source d'horloge interne ou externe, utilisation des comparateurs, du voltage de référence, l'utilisation des "timers" et
la programmation des ports d'entrée / sorties pour ne nommer que ceux-là. Dans le cas d'un PIC ™ il s'agit, entre autre, du "config word" (fuses).
Comme la plupart d'entre vous on suivi les présentations de Daniel VA2HDD, sur le PicBasic Pro de microEngineering Labs Inc, nous nous serviront de cet interpréteur pour poursuivre nos exercices. Le choix du PBP© est purement académique, tout autre interpréteur aurais été valide, mais vu sa simplicité, il devient donc le meilleur choix pour le groupe.
Le défi de la page blanche quand on commence un programme en PBP© est similaire à l'expérience que j'ai vécue en écrivant ce document, 22 pages plus tard, je dois avouer que le plus dur est passé. Par où commencer? Commencez donc par un commentaire, qui décriras le nom de votre programme, une description brève de ce qu'il effectue comme travail et votre nom, c'est comme le générique qui apparait au début d'un film, les noms les plus importants y sont présents! Ces commentaires doivent être précédés par une apostrophe ' pour être interprétés comme un tel. L'apostrophe indique le début du commentaire, jusqu'à la fin de la ligne, on doit donc en placer une au début de chaque ligne de commentaires. Dans d'autre interpréteur le caractère qui détermine le début d'un commentaire est différent, il faut consulter le manuel, ou la section d'aide du programme. Une des premières lignes indiquera à l'interpréteur, la configuration matérielle que nous utiliserons.
Cette ligne ressemblera à ceci:
@ DEVICE PIC16F628, INTRC_OSC_NOCLKOUT, WDT_OFF, MCLR_ON, PWRT_ON, BOD_ON, LVP_OFF, CPD_OFF, PROTECT_OFF
Qu'est ce que c'est que ce charabia, me direz-vous? C'est la façon que nous devons utiliser pour que l'interpréteur génère le config word, ou fuses, si vous préférez et la syntaxe est définie dans un fichier "include" dans le programme de l'interpréteur. Regardons une partie du contenu de ce fichier, appelé M16F62X.inc (page suivante). Vous remarquerez que chacune des commandes de notre ligne de code sont clairement définies dans ce fichier. Voici leur signification:
@ DEVICE PIC16F628 Indique à l'interpréteur que nous avons choisis un PIC 16F628
INTRC_OSC_NOCLKOUT Un des 11 choix disponibles; Oscillateur interne et on utilise la pin RA6 comme un I/O régulier, donc on prend l'option "no clock output"
WDT_OFF Le Watch Dog Timer est inactif, cela nous permettra d'utiliser le timer 0.
MCLR_ON La broche RA5 nous servira de Master Clear.
PWRT_ON Le Powerup Timer est on, retarde le début des opérations du CPU
BOD_ON Détecte une baisse dans l'alimentation VCC et génère un Reset.
LVP_OFF La fonction de programmation à bas voltage en désactivée
CPD_OFF La protection du data est off, le data peut donc être lu du PIC™
PROTECT_OFF La protection du code est off, il peut donc être lu du PIC™
ER_OSC_CLKOUT equ 3FEC0013h XX XXXX XXX1 XX11
ER_OSC_NOCLKOUT equ 3FEC0012h XX XXXX XXX1 XX10
ER_OSC equ 3FEC0012h XX XXXX XXX1 XX10
INTRC_OSC_CLKOUT equ 3FEC0011h XX XXXX XXX1 XX01
INTRC_OSC_NOCLKOUT equ 3FEC0010h XX XXXX XXX1 XX00
INTRC_OSC equ 3FEC0010h XX XXXX XXX1 XX00
EXTCLK_OSC equ 3FEC0003h XX XXXX XXX0 XX11
EC_OSC equ 3FEC0003h XX XXXX XXX0 XX11
HS_OSC equ 3FEC0002h XX XXXX XXX0 XX10
XT_OSC equ 3FEC0001h XX XXXX XXX0 XX01
LP_OSC equ 3FEC0000h XX XXXX XXX0 XX00
WDT_ON equ 3FFB0004h XX XXXX XXXX X1XX
WDT_OFF equ 3FFB0000h XX XXXX XXXX X0XX
PWRT_ON equ 3FF70000h XX XXXX XXXX 0XXX
PWRT_OFF equ 3FF70008h XX XXXX XXXX 1XXX
MCLR_ON equ 3FDF0020h XX XXXX XX1X XXXX
MCLR_OFF equ 3FDF0000h XX XXXX XX0X XXXX
BOD_ON equ 3FBF0040h XX XXXX X1XX XXXX
BOD_OFF equ 3FBF0000h XX XXXX X0XX XXXX
LVP_ON equ 3F7F0080h XX XXXX 1XXX XXXX
LVP_OFF equ 3F7F0000h XX XXXX 0XXX XXXX
CPD_ON equ 3EFF0000h XX XXX0 XXXX XXXX
CPD_OFF equ 3EFF0100h XX XXX1 XXXX XXXX
PROTECT_ON equ 03FF0000h 00 00XX XXXX XXXX
PROTECT_OFF equ 03FF3C00h 11 11XX XXXX XXXX

Tableau 16

Grâce à cette seule ligne nous venons de faire plusieurs choix importants. Cette ligne sera pratique- ment toujours la même, pour tout les programmes que nous écrirons, dans cet environnement. Il est très important que les commandes soient écrites de la même façon qu'a l'intérieur du document INC, sinon quand l'interpréteur essaieras de compiler notre programme, il nous donnera un message d'erreur. Je vous conseille d'utiliser la commande Copier-coller pour prévenir les erreurs de frappe!
A l'intérieur du même fichier, nous retrouverons aussi, le nom déjà associé aux registres internes du PIC™, comme TMR0, PCL, STATUS, PORTA, PORTB, PCLATH et INTCON pour n'en nommer que quelques un. Donc si nous voulons faire référence au port d'entrée / sorties A, nous pouvons déjà l'appeler PORTA, car il est défini dans le fichier include. Quand nous décidons notre CPU il est préférable de voir les noms déjà attribués, dans le fichier include et d'utiliser les mêmes. Nous verrons comment on peut changer ces noms, quand nous regarderons les variables.
À la suite de cette ligne, nous activerons ou désactiverons les modules internes du PIC ™ en fonction de nos besoins. Dans le cas du 16F628, pour le programme qui nous concerne, nous ne nous servirons pas des comparateurs, du voltage de référence et du Pulse Width Modulation.
Nous les désactiverons ces modules en ajoutant trois lignes de code:
CMCON = 7 ' désactive les comparateurs.
VRCON=0 ' désactive le voltage de référence
CCP1CON=0 ' désactive PWM