11.07.2015 Views

Apprendre à programmer avec le 16F877A Introduction - Didel.com

Apprendre à programmer avec le 16F877A Introduction - Didel.com

Apprendre à programmer avec le 16F877A Introduction - Didel.com

SHOW MORE
SHOW LESS
  • No tags were found...

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

http://www.didel.<strong>com</strong>/info@didel.<strong>com</strong><strong>Apprendre</strong> à <strong>programmer</strong> <strong>avec</strong> <strong>le</strong> <strong>16F877A</strong>Exemp<strong>le</strong>s et exercices sous www.didel.<strong>com</strong>/pic/Cours877-1.zipwww.didel.<strong>com</strong>/pic/Cours877-1.pdfLe but est d’apprendre à écrire des programmes en assemb<strong>le</strong>ur pour des applications utilisantun code efficace sur des microcontrô<strong>le</strong>urs en général plus petits. Notre démarche est de tester<strong>le</strong>s programmes sur un 16F877 qui a 4 ports d’entrée-sortie, ce qui facilite la <strong>com</strong>préhension dufonctionnement. Le Microdu<strong>le</strong> 16F877 est aussi idéal pour mettre au point des applicationsutilisant des processeurs en boîtier 6, 8, 14 pattes (voir www.didel.<strong>com</strong>/pic/Deverminage.pdf).En plus de la carte 877, 4 cartes Microdu<strong>le</strong>s et des <strong>com</strong>posants aident pour <strong>le</strong>s tests.La grande idée des Microdu<strong>le</strong>s est que vous ne <strong>le</strong>s utilisez pas dans votre application. Ilsrestent toujours prêts pour tester des routines et préparer des nouveaux projets.Notons encore que pour éviter d’allonger ce document <strong>avec</strong> des informations essentiel<strong>le</strong>s pourmaîtriser tous <strong>le</strong>s aspects d’un PIC, mais pas indispensab<strong>le</strong>s quand on n’a pas encore <strong>le</strong> besoinpour son application, plusieurs renvois sont faits à des documents plus spécialisés, dont uneliste exhaustive est faite dans www.didel.<strong>com</strong>/pic/ToutSurLesPics.pdfMatériel nécessairePickit2 65.-Kit Microdu<strong>le</strong> M2840Eval 140.-<strong>16F877A</strong> 10.-Doc souswww.didel.<strong>com</strong>/08micro/M2840Eval.pdfLa doc généra<strong>le</strong> sur <strong>le</strong>s Microdu<strong>le</strong>s est souswww.didel.<strong>com</strong>/pic/Microdu<strong>le</strong>s.pdfTab<strong>le</strong> des matières1ere partie (ce fichier)<strong>Introduction</strong>Entrées-sorties et délaisCompteurs et décalages2e partie www.didel.<strong>com</strong>/pic/Cours877-2.pdfEntrées et poussoirsArithmétique et <strong>com</strong>paraisons3e partie www.didel.<strong>com</strong>/pic/Cours877-3.pdfToutes <strong>le</strong>s instructions4e partie www.didel.<strong>com</strong>/pic/Cours877-4.pdfPériphériques internes (timer, USART, ..)InterruptionsProgrammes de test5e partie www.didel.<strong>com</strong>/pic/Cours877-5.pdfSéquencement et multitâcheStructure et mise en pageApplications<strong>Introduction</strong>Avant de pouvoir faire <strong>le</strong>s exercices de ce document, il faut instal<strong>le</strong>rSmi<strong>le</strong>NG www.didel.<strong>com</strong>/pic/Smi<strong>le</strong>NG.zip extraire dans c: ce quicrée <strong>le</strong> dossier c:Smi<strong>le</strong>NG Ouvrir et faire un raccourci àSmi<strong>le</strong>NG.exePickit2 : Chercher sous goog<strong>le</strong> ‘’Pickit2 install’’ et choisir sur <strong>le</strong> sitede Microchip Pickit2 install, 3.9 MB).Les exemp<strong>le</strong>s de programmes associés à cette partie se trouvent souswww.didel.<strong>com</strong>/pic/Cours877.zip. Mettre ces fichiers dans un dossier Cours877.


Connectez <strong>le</strong> M2840 au Pickit2 relié au PC via USB. Exécutez Smi<strong>le</strong>NG et Pickit2. LePickit2 doit avoir reconnu <strong>le</strong> 16F877.Lire <strong>le</strong> 16F877Cliquez sur ‘’Read’’. Le contenus’affiche.Vérifiez que la tension est 5V etcliquez sur la case On. La LEDdu. M2840 s’allume et <strong>le</strong>programme T877 s’exécute. Ilalterne toutes <strong>le</strong>s lignes.Déplacer l’afficheur sur <strong>le</strong>s ports pour vérifier que celaclignote partout où cela a un sens (sauf RA7, 6, 4).Le programme de test T877 est très uti<strong>le</strong> pour vérifieren tout temps que <strong>le</strong> 16F877 est en ordre. On <strong>le</strong>recharge dans <strong>le</strong> Pickit2 en cliquant sous Fi<strong>le</strong> –Import Hex – chercher <strong>le</strong> dossier Cours877 et chargerT877.hex.Cliquer ensuite sur WriteCharger sous Smi<strong>le</strong>NG <strong>le</strong> programme T877.asm.On voit qu’il initialise <strong>le</strong>s ports en sortie et envoiedes va<strong>le</strong>urs <strong>com</strong>plémentaires <strong>avec</strong> une attenteentre deux.Assemb<strong>le</strong>r en cliquant à l’endroit indiqué ou <strong>avec</strong>la touche F5. Ceci recrée <strong>le</strong> fichier T877.hexque l’on peut recharger dans <strong>le</strong> Pickit2.Ne vous inquiétez pas si vous ne <strong>com</strong>prenez pas tout ce programme, il sera expliqué par petitesétapes plus loin.Exercice : modifier la va<strong>le</strong>ur Motif, ré-assemb<strong>le</strong>r et <strong>programmer</strong>.Note : Pour chaque modification, une fois que l’on a vu ‘’Assembly successful’’ on clique dansWrite et <strong>le</strong> Pickit2 confirme ’’Reloading Hex fi<strong>le</strong>‘’. Ceci est très efficace pour tester des variantesde programmes.(Explications plus détaillées <strong>avec</strong> copies d’écran sous www.didel.<strong>com</strong>/kits/KiCalm1.pdf page 4)


Notions de base : bits, octets, constantes, variab<strong>le</strong>s, registres, …Si <strong>le</strong> programme T877.asm ci-dessus est du charabia <strong>com</strong>p<strong>le</strong>t, <strong>le</strong> mieux est de lire la brochureDauphin et de faire quelques exercices. http://www.epsitec.ch/Dauphin.zip Cette brochure vousapprend à <strong>programmer</strong> un processeur inventé, à la fois plus simp<strong>le</strong> et plus riche que <strong>le</strong>s PICs.Le notions de nombre, constantes, variab<strong>le</strong>s, etc. sont expliquées <strong>avec</strong> plus de détails dans <strong>le</strong>fichier www.didel.<strong>com</strong>/pic/Bases.pdf dont la <strong>le</strong>cture est re<strong>com</strong>mandée maintenant ou plus tard,quand vous aurez fait quelques exercices.Architecture des PICsLes PICs ont une architecture simp<strong>le</strong>, <strong>avec</strong> une mémoire d’instructions 12 ou 14 bits, desvariab<strong>le</strong>s 8 bits et des périphériques 8 bits dans <strong>le</strong> même espace que <strong>le</strong>s variab<strong>le</strong>s. Cet espacedes variab<strong>le</strong>s est coupé en 4 banques, ce qui <strong>com</strong>plique la sé<strong>le</strong>ction : on travail<strong>le</strong> principa<strong>le</strong>menten banque 0 en passant brièvement dans d’autres banques lorsque c’est nécessaire.Comprendre l’architecture interne n’est pas essentiel. La doc de Microchip est naturel<strong>le</strong>ment laréférence. ww1.microchip.<strong>com</strong>/downloads/en/DeviceDoc/39582b.pdf. Le documentwww.didel.<strong>com</strong>/pic/Architecture.pdf présente une vue simplifiée <strong>avec</strong> mise en évidence desnotions importantes.Les périphériques ont plusieurs fonctions et il faut initialiser la bonne selon l’application. Cetterichesse sera vue dans la partie 4, et <strong>le</strong>s programmes PicTests www.didel.<strong>com</strong>/pic/PicTests.pdfévitent de se perdre dans la doc détaillée de Microchip pour <strong>le</strong>s utilisations standard. Si vousvou<strong>le</strong>z en savoir plus sur des bits qui définissent <strong>le</strong> <strong>com</strong>portement des périphériques, il fautchercher dans la documentation du fabricant ou utiliser une traduction en français, parfois unpeu améliorée, par Bigonoff ou Oumnad. Les livres de Tavernier ont la même approche.L’assemb<strong>le</strong>ur CALMLes règ<strong>le</strong>s de l’assemb<strong>le</strong>ur et <strong>le</strong>s pseudo-instructions apparaîtront petit à petit, pafois sansexplications. Si une présentation systématique vous est nécessaire avant de voir des exemp<strong>le</strong>sde programme, lisez www.didel.<strong>com</strong>/pic/Calm.pdfEntrées et sortiesL’intérêt des microcontrô<strong>le</strong>urs est qu’il ont des sorties sur <strong>le</strong>squel<strong>le</strong>s on peut brancher desdiodes lumineuses, dans amplis pour <strong>com</strong>mander des moteurs, un haut-par<strong>le</strong>ur. Ils ont desentrées pour connecter des poussoirs et interrupteurs, pour lire des signaux analogiques, pourmesurer des durées d’impulsions. Ces fonctions sont programmab<strong>le</strong>s et c’est notre premiersouci : configurer <strong>le</strong> microcontrô<strong>le</strong>ur dans <strong>le</strong> mode <strong>com</strong>patib<strong>le</strong> <strong>avec</strong> l’exercice.Registre de directionPour décider si une broche du processeur est une entrée ou sortie, il faut que <strong>le</strong> contrô<strong>le</strong>ur aitdes aiguillages <strong>com</strong>mandés par un registre de direction appelé Tris. Si <strong>le</strong> bit Tris est à 1 (input)la broche du circuit est connectée au bus et amène l’information dans <strong>le</strong> registre W, sil’instructionMove Port,W est exécutée. Si <strong>le</strong> bit Tris vaut 0 (output), c’est l’information qui vientdu bus qui est mémorisée dans <strong>le</strong> registre et activée en sortie.L’adresse du registre Tris est la même que pour <strong>le</strong> port correspondant, mais dans la banque 1,sé<strong>le</strong>ctionnée en activant <strong>le</strong> bit RP0 du registre Status.


Un premier exercice : copier <strong>le</strong> portA sur <strong>le</strong> PortCLe 16F877 a cinq ports, A et E sont in<strong>com</strong>p<strong>le</strong>ts. Leprogramme <strong>le</strong> plus simp<strong>le</strong> que l’on puisse écrirecopie l’état des lignes d’entrées du PortA sur <strong>le</strong>ssorties du PortC. Le microdu<strong>le</strong>s Sw8 impose ses 0 et1 sur <strong>le</strong> portA et transfère l’informations sur <strong>le</strong>sdiodes du modu<strong>le</strong> Lb8 : rouge pour l’état 0 et vertpour l’état 1.Le cœur du programme Ex877-101.asm estLoop:Move PortA,WMove W,PortCJump LoopChargez <strong>le</strong> programme et observez.RA6 RA7 nesont pas disponib<strong>le</strong>s sur <strong>le</strong> 877.Peut-on imaginer plus simp<strong>le</strong> ? Move est en fait une copie, on nedéplace pas l’information, on en fait une copie. On ne peut pas copierdirectement du portA vers <strong>le</strong> portB, il faut passer par <strong>le</strong> registre W, quijoue un rô<strong>le</strong> de plaque tournante.Loop est un nom inventé (une étiquette pour dire où est la prochaineinstruction) ; on aurait pu mettre Bouc<strong>le</strong>, Toto, mais pas Jump ou PortAqui sont des noms réservés. Il faut mettre <strong>le</strong> : sans espace devant.Pour copier C dans D, il faut adapter l’initialisation, et<strong>com</strong>prendre que <strong>le</strong> concepteur du Pic en 1975 n’apas vu assez loin : il a réservé trois instructions Tris AB C et c’est tout. Pout agir sur TrisD et E, il fautpasser par la banque 1, et utiliser <strong>le</strong>s mêmesnuméros d’adresse que ceuxdes ports D et E.On pourrait écrire pour l’initialisationSet Status:#RP0Move #16'06,W ; DésactiveMove W,AdCon1 ; <strong>le</strong> A/DClr Status:#RP0Move #-1,W ; PortC en entréeMove W,TrisCSet Status:#RP0Move #0,W ; PortD en sortieMove W,PortD ; TrisDClr Status:#RP0C’est plus simp<strong>le</strong> <strong>com</strong>me c’est fait dans Ex877-102.asmProfitez de jouer <strong>avec</strong> <strong>le</strong> modu<strong>le</strong> PoToD8, doc sous www.didel.<strong>com</strong>/08micro/PoToD8.pdf , pourmieux <strong>com</strong>prendre <strong>le</strong>s nombres positifs et négatifs (relire www.didel.<strong>com</strong>/pic/Bases.pdf).Note Il peut y avoir problème pour lire sur <strong>le</strong> PortB. car <strong>le</strong> programmateur utilise RB6 et RB7pour écrire dans <strong>le</strong> 16F877. Un interrupteur fermé peut perturber, malgré la résistance série.Va<strong>le</strong>ur fixe dans <strong>le</strong> portDSi on regarde <strong>le</strong>s affichages de la photo précédente, on lit 14 (hexa) et 00010100 (binaire).Tous <strong>le</strong>s processeurs travai<strong>le</strong>nt en binaire (base 2) que nous noterons 2’00010100. On préfèresouvent l’hexa plus <strong>com</strong>pact 16’14.Assignons une va<strong>le</strong>ur fixe, une constante dans <strong>le</strong> portD, qui sera en général utilisé pour afficherdes va<strong>le</strong>urs. Le cœur du programme Ex877-103.asm estLoop: Move #16’6A,W ; ou Move #2’01101010Move W,PortDJump LoopFaire <strong>le</strong>s exercices proposés au bas du programme (ce qui suit <strong>le</strong> .end n’est pas assemblé).N’oubliez-pas que c’est très rapide : modifier la va<strong>le</strong>ur, assemb<strong>le</strong>r, déplacer la souris, write,cliquer assemblage correct pendant que cela programme, observer <strong>le</strong>s microdu<strong>le</strong>s. Ce n’est quelorsque <strong>le</strong> nom du .hex change qu’il faut al<strong>le</strong>r chercher sur <strong>le</strong> disque.


Question : ce programme copie sans arrêt sur <strong>le</strong> portD ; une fois suffit. Oui, mais il faut toujoursdire au processeur ce qu’il doit faire. On pourrait écrireMove #16’6A,WMove W,PortDIci: Jump Ici ; tourne-toi <strong>le</strong>s pouces !Encore une modif au programme, en<strong>le</strong>vons <strong>le</strong> # qui veut dire constante, va<strong>le</strong>urimmédiate :Move 16’6A,WMove W,PortDIci: Jump IciQuel<strong>le</strong> est la va<strong>le</strong>ur affichée ? Peut-on la prévoir ?Non car c’est une variab<strong>le</strong> qui résulte d’un état imprévisib<strong>le</strong> des bascu<strong>le</strong>s àla mise sous tension (ce n’est pas toujours la même chose si vous coupez).Essayez Move 16’7,WMove W,PortDTiens, c’est la copie <strong>le</strong> portC ! Effectivement <strong>le</strong>s ports sont <strong>com</strong>me desvariab<strong>le</strong>s. Le portC est à l’adresse 7 s’il est initialisé en entrée on <strong>le</strong> lit.Essayez Move 16’85,WMove W,PortDL’assemb<strong>le</strong>ur signa<strong>le</strong> une erreur ! bien sûr, il n’y a que 7 bits pour adresser<strong>le</strong>s variab<strong>le</strong>s, l’adresse doit être inférieure à 16’7F.Oscil<strong>le</strong>r <strong>le</strong> port DActiver-désactiver <strong>le</strong> portD, donc créer une impulsion positive sur tous ses bits, s’écrit deplusieurs façons. La première et la 3 e solution sont identiques (<strong>le</strong>s mêmes instructions sontgénérées).Move #2’11111111,WMove W,PortDMove #2’00000000,WMove W,PortDMove #2’11111111,WMove W,PortDClr PortDMove #-1,WMove W,PortDMove #0,WMove W,PortDPour répéter ces instructions d’activation/désactivation, on crée une bouc<strong>le</strong> en mettant uneétiquette au début de la bouc<strong>le</strong> et en ajoutant une instruction qui saute à cette étiquette, c’est àdire à l’adresse correspondante dans la mémoire du processeur, <strong>com</strong>me dans <strong>le</strong> programme detest.Loop: Move #2’11111111,W ; 1 µsMove W,PortDMove #2’00000000,WMove W,PortDJump LoopLes PICs à 4 MHz exécutent une instruction par microseconde (mais 2 µs pour <strong>le</strong>s sauts). Ceprogramme va activer <strong>le</strong> port D pour 2 micro secondes seu<strong>le</strong>ment, et désactiver pour 3 microsecondes. On ne verra rien sans utiliser un oscilloscope.Bouc<strong>le</strong>s d’attentePour que <strong>le</strong> processeur modifie <strong>le</strong>s sorties à une vitesse ‘’humaine’’, il faut insérer des bouc<strong>le</strong>sd’attente. On initialise un <strong>com</strong>pteur et on dé<strong>com</strong>pte jusqu’à la va<strong>le</strong>ur zéro, que <strong>le</strong> processeur saitbien reconnaître.Move #250,WMove W,Cx1Att: Dec Cx1 ; 1 µsSkip,EQ ; 1 µsJump Att ; 2 µsL’instruction Dec diminue de 1 la variab<strong>le</strong> Cx1. Cx1 est un nom inventé, et il faut dire où cettevariab<strong>le</strong> se trouve en mémoire. C’est libre à partir de l’adresse 16’20, donc il faut déclarer avant<strong>le</strong> début du programmeCx1 = 16’20L’instruction Skip,EQ se prononce Skip If Equal, saute si c’est égal, si l’opération précédente aun résultat égal à zéro. Si ce n’est pas égal à zéro, on passe à l’instruction suivante, dé<strong>com</strong>pteà nouveau. A noter que <strong>le</strong> Skip,EQ, <strong>com</strong>me <strong>le</strong> Jump, s’exécute en 2 microsecondes.Ce bout de programme va faire 250 fois la bouc<strong>le</strong> qui dure 4 microsecondes, donc la duréetota<strong>le</strong> est de 1 milliseconde (plus <strong>le</strong>s 2 microsecondes d’initialisation du dé<strong>com</strong>pteur).


A noter <strong>le</strong>s trois nouvel<strong>le</strong>s instructions. Dec Cx1 dé<strong>com</strong>pte la variab<strong>le</strong> mentionnée. L’instructionSkip,EQ permet de savoir si <strong>le</strong> <strong>com</strong>pteur est à zéro (EQ equal). Si oui, <strong>le</strong> processeur sautel’instruction suivante. Si non, il exécute <strong>le</strong> saut qui lui fait attendre encore un tour.Ce nouveau cœur de programme s’écrit (programme <strong>com</strong>p<strong>le</strong>t Ex877-104.asm)Loop: Move #2’11111111,W ; on allumeMove W,PortD; attente de 1msMove #250,WMove W,Cx1At1: Dec Cx1 ; 1 µsSkip,EQ ; 1 µsJump At1 ; 2 µsMove #2’00000000,W ; on éteintMove W,PortD; attente de 1msMove #250,WMove W,Cx1At2: Dec Cx1 ; 1 µsSkip,EQ ; 1 µsJump At2 ; 2 µsJump LoopC’est encore trop rapide pour notre oeil. On ne peut pas augmenter la va<strong>le</strong>ur 250 au delà de255, car la variab<strong>le</strong> Cx1 est un mot de 8 bits et <strong>le</strong>s PICs n’ont pas d’instructions pour des<strong>com</strong>pteurs ou dé<strong>com</strong>pteurs plus grands que 8 bits.On fait alors une 2 e bouc<strong>le</strong> qui appel<strong>le</strong> la première et utilise une 2 e variab<strong>le</strong>. Vous vou<strong>le</strong>z undixième de secondes ? Il suffit de répéter 100 fois la bouc<strong>le</strong> de 1ms .; Bouc<strong>le</strong> 100 millisecondes = 0.1sMove #100,WMove W,Cx2At12: Move #250,WMove W,Cx1At11: Dec Cx1 ; Bouc<strong>le</strong> 1msSkip,EQJump At11Dec Cx2Skip,EQJump At12On pourrait naturel<strong>le</strong>ment <strong>com</strong>pter et <strong>com</strong>parer quand on atteint la va<strong>le</strong>ur 100 ou 250. C’estmoins efficace <strong>avec</strong> <strong>le</strong> PIC.Relisez plusieurs fois si ce n’est pas bien <strong>com</strong>pris. Ces deux bouc<strong>le</strong>s imbriquées doivent êtrebien assimilées. On <strong>le</strong>s teste dans la section suivante.Programme <strong>com</strong>p<strong>le</strong>tIl faut donc insérer nos bouc<strong>le</strong>s d’attente de 100ms après avoir écrit et après avoir modifié <strong>le</strong>motif sur <strong>le</strong> PortD. Le programme doit aussi initialiser <strong>le</strong> PortD en sortie, et déclarer l’adressedes variab<strong>le</strong>s Cx1 et Cx2.\prog;Ex877-105|Clignote portD.Proc 16F877.Ref 16F877.Loc 16'2007.16 16'3F39CX1 = 16'20 ; Début des varCX2 = 16'21Motif1 = 16'55 ; 2'01010101Motif2 = 16'AA ; 2'10101010Deb: Clr PortASet Status:#RP0Move #16'06,WMove W,AdCon1Move #0,W ; PortDMove W,PortD ; sortieClr Status:#RP0Loop:Move #Motif1,WMove W,PortC; attente 200msMove #200,WMove W,Cx2At12:Move #250,WMove W,Cx1At11: Dec Cx1Skip,EQJump At11Dec Cx2Skip,EQJump At12Move #Motif2,WMove W,PortC; attente 200msMove #200,WMove W,Cx2Att22:Move #250,WMove W,Cx1At21: Dec Cx1Skip,EQJump At21Dec Cx2Skip,EQJump Att22Optimisation et simplificationsL’instruction DecSkip,EQ remplace <strong>le</strong>s deux instructions de la bouc<strong>le</strong> d’attente..EndJumpLoop


Si on n’a pas besoin d’une durée précise, on peut ne pas recharger <strong>le</strong>s <strong>com</strong>pteurs. Après êtrearrivés à zéro, ils re<strong>com</strong>mencent un tour de 256 pas. La façon la plus simp<strong>le</strong> de faire uneattente de 256x256x3 µs =~ 0.2 secondes est d’écrireA$: DecSkip,EQ Cx1Jump A$; A$ est une étiquette dite loca<strong>le</strong>DecSkip,EQ Cx2Jump A$Le programme T877.asm utilise cette attente simplifiée et clignote tous <strong>le</strong>s ports en inversant <strong>le</strong>motif <strong>avec</strong> un ou-exclusif (partie 2). Le programme est nettement plus court.T877.hex est un programme de test que l’on recharge toutes <strong>le</strong>s fois que l’on veut vérifier que <strong>le</strong>processeur fonctionne et que toutes <strong>le</strong>s sorties sont connectées. S’il ne tourne pas, c’est quel’oscillateur interne n’est pas initialisé.RoutinesCe n’est pas très élégant, ni très efficace, de devoir écrire deux fois la même bouc<strong>le</strong> d’attente,<strong>com</strong>me dans <strong>le</strong> programme Ex877-105.asm. On écrit une seu<strong>le</strong> fois <strong>le</strong> modu<strong>le</strong>, appelé routine,et on peut l’appe<strong>le</strong>r autant de fois que l’on veut. L’instruction Call fait l’appel et à la fin de laroutine, l’instruction Ret (return) retourne à l’instruction qui suit <strong>le</strong> Call.Ecrivons une routine DelWx1ms <strong>avec</strong> un paramètre en entrée qui est <strong>le</strong> contenu de W.DelWx1ms signifie ‘’Delai de contenu de W fois 1 milliseconde’’. C’est la grande difficulté detous <strong>le</strong>s programmes informatiques : définir des noms qui expriment au mieux la fonction, et quel’on utilise ensuite sans hésitation.\rout:DelWx1ms|Attente de (W) fois 1ms\in:W nombre de ms\mod:W Cx1 Cx2DelWx1ms: Move W,Cx2A$: Move #250,WMove W,CX1B$: NopDecSkip,EQ CX1 ; bouc<strong>le</strong> 1msJump B$DecSkip,EQ Cx2 ; bouc<strong>le</strong> (W) fois 1msJump A$RetCette routine est <strong>le</strong> premier élément d’une bibiothèque de routines que chaque programmeur seconstitue. Les 3 premières lignes contiennent toute l’information nécessaire pour l’utiliser.CompteurCompter ou dé<strong>com</strong>pter en 8 bits est trivial. Comment <strong>com</strong>pter plus loin que 256 ?Comptons sur <strong>le</strong> portD, toutes <strong>le</strong>s quelques ms. Toute <strong>le</strong>s fois que <strong>le</strong> <strong>com</strong>pteur D passe parzéro, <strong>le</strong> bit Z du registre Status s’active (<strong>le</strong> Carry dont on par<strong>le</strong>ra plus tard n’est pas activé). Onteste ce bit pour décider si on incrémente <strong>le</strong> portC.Les microdu<strong>le</strong>s visualisent ce <strong>com</strong>pteur, charger et exécuter <strong>le</strong> programme Ex877-106.asm.Loop: (attente)Inc PortDSkip,EQJump LoopInc PortCJump Loopdurée 5 ou 4 usLoop: (attente)IncSkip,EQ PortDDec PortCInc PortCJump Loopdurée 4 usOn voit que la 2 e solution est astucieuse. Cela ne semb<strong>le</strong> pas rationnel de dé<strong>com</strong>pter et<strong>com</strong>pter la même variab<strong>le</strong> à chaque cyc<strong>le</strong>, mais <strong>le</strong> résultat est que <strong>le</strong> programme est plus court,plus rapide et sa durée est toujours la même.La décrémentation, à faire en exercice, a aussi une jolie solution.SaturationComme un <strong>com</strong>pteur de voiture, un <strong>com</strong>pteur binaire re<strong>com</strong>mence à zéro après la va<strong>le</strong>urmaximum. Si on veut bloquer un <strong>com</strong>pteur 8 bits à 16’FF, on écritInc CntSkip,NE ; saute si différent de zéroDec Cnt ; on revient en arrière à 16’FF si =0


Pour bloquer à zéro un dé<strong>com</strong>pteur, on refuse de dé<strong>com</strong>pter s’il est à zéro. L’instruction Test nefait rien d’autre que d’activer Z si <strong>le</strong> contenu de la variab<strong>le</strong> est zéro.Test CntSkip,EQ ; saute si égal à zéroDec CntExercice : bloquer un <strong>com</strong>pteur ou dé<strong>com</strong>pteur 16 bits.DécalagesIl n’y a que deux instructions de décalage dans <strong>le</strong>s PICs, qui sont en fait des rotations à travers<strong>le</strong> Carry. Le Carry est un bit dans un registre de fanions, d’état (status) que nous retrouverons àpropos d’arithmétique. Pour <strong>le</strong> moment, c’est un bit dans <strong>le</strong> processeur, que l’on peut mettre àun ou à zéro <strong>avec</strong> <strong>le</strong>s instructions SetC et ClrC.RRC VarRotate Right through CarryRLC VarRotate Left through CarryPour retrouver l’information, il faut donc 9 décalages.On peut tester faci<strong>le</strong>ment <strong>avec</strong> <strong>le</strong> portD et <strong>le</strong>s instructions du programmeEx877-108.asm. On remarque que pour avoir une délai d’observation suffisant, il a fallu définirune attente multip<strong>le</strong> de 0.1 seconde, donc un délai maximum de 25.5 secondesLoop: MoveCallRRCJump#10,WDelWx01s ; 10x0.1s = 1 secondePortDLoopRegardons <strong>le</strong>s programmes faits. Il contiennent beaucoup d’instructions qui reviennent chaquefois. Créons un modu<strong>le</strong> qui ne change plus, et est importé depuis <strong>le</strong> disque à chaqueassemblage. Ce modu<strong>le</strong> contient en plus des deux routines de délai une routine d’initialisationqui met <strong>le</strong> portA en entrée, et <strong>le</strong>s ports B, C, D, E en sortie. Ce fichier Ex877Init1.asi est appelépar <strong>le</strong> programme Ex877-109.asm qui fait la même chose que <strong>le</strong> Ex877-108.asm précédent.Les fichiers <strong>avec</strong> l’extension .asi ne peuvent pas être assemblés, il sont toujours appelés(insérés) dans des fichies exécutab<strong>le</strong>s <strong>avec</strong> l’extension .asmJouons encore <strong>avec</strong> <strong>le</strong>s décalagesPour se faire la main, <strong>com</strong>mençons à déca<strong>le</strong>r sur 16 bits, en observant <strong>le</strong>s LEDs sur <strong>le</strong>s ports Cet D. Initialisons ces deus registres (ports) et décalons à droite en vidant, c’est-à-dire eninjectant des zéros, en mettant <strong>le</strong> carry à zéro avant chaque décalage.MoveMoveMoveMoveLoop: MoveCallClrCRRCRRCJump#2'10110111,WW,PortC#2'10101101,WW,PortD#10,WDelWx01sPortCPortDLoopOn voit dans ce programme Ex877-110.asm que <strong>le</strong> Carry transporte <strong>le</strong> bit ‘’poussé dehors’’ duPortC vers <strong>le</strong> portD.On veut maintenant faire l’équiva<strong>le</strong>nt de Move PortC,PortD par décalage. Il faut 8 décalages, eton va utiliser un dé<strong>com</strong>pteur, <strong>com</strong>me dans <strong>le</strong>s bouc<strong>le</strong>s d’attente. Voir Ex877-111.asmOn peut tester <strong>le</strong> Carry <strong>avec</strong> l’instruction Skip,CC qui saute l’instruction suivante si <strong>le</strong> Carry estC<strong>le</strong>ar (à zéro). On a aussi l’instruction Skip,CS.Comme exercice, <strong>com</strong>ptons <strong>le</strong>s bits à un. L’algorithme est simp<strong>le</strong> : on déca<strong>le</strong>. et toutes <strong>le</strong>s foisque <strong>le</strong> carry est à un, on <strong>com</strong>pte. En parallè<strong>le</strong>, on affiche <strong>le</strong> résultat en binaire sur <strong>le</strong> portB.; initialisationMove #2'10110111,WMove W,PortCMove #2'10101101,WMove W,PortDClr PortB ; servira de <strong>com</strong>pteurLoop: Move #10,WCall DelWx01sClrCRRC PortCRRC PortDSkip,CC


Inc PortBJump LoopCe programme Ex877-112.asm n’arrête pas de déca<strong>le</strong>r, mais <strong>com</strong>me <strong>le</strong> registre est vide et quecela ne <strong>com</strong>pte plus, on ne s’en rend pas <strong>com</strong>pte. Dans un programme réel, il faudrait ajouterun dé<strong>com</strong>pteur pour s’arrêter après 16 cyc<strong>le</strong>s.Ping-pong – à vous d’inventerOn veut que la <strong>le</strong>d Verte s’allume à guche, se déca<strong>le</strong> seu<strong>le</strong> et rebondisse à droite. Commentfaire ? On part <strong>avec</strong> <strong>le</strong>s ports C et D à zéro. On injecte la Led verte <strong>avec</strong> <strong>le</strong> Carry. On déca<strong>le</strong> entestant si <strong>le</strong> carry. Quand il passe à un on continue dans une 2 e partie de programme. Envoyezvotre programme pour correction à info@didel.<strong>com</strong>.Résumé du chapitreOn a montré la différence entre constante (va<strong>le</strong>ur immédiate) et variab<strong>le</strong>.Les variab<strong>le</strong>s sont numérotées de 0 à 16’7F ; de 0 à 16’20, on a des ports <strong>avec</strong> des nomsréservés (PortA, etc). On a utilisé <strong>le</strong>s ports B, C, D <strong>com</strong>me variab<strong>le</strong>s <strong>avec</strong> des bouc<strong>le</strong>s d’attentepour avoir <strong>le</strong> temps d’observer. On déclare l’emplacement des variab<strong>le</strong>s en donnant <strong>le</strong>uradresse. Cx1 = 16’20. On verra plus tard une meil<strong>le</strong>ure façon pour ces déclarations.Les variab<strong>le</strong>s ont 8 bits de large, mais des ports peuvent être in<strong>com</strong>p<strong>le</strong>ts. On initialise unevariab<strong>le</strong> en passant la va<strong>le</strong>ur par W d’abord. L’instruction Move #Va<strong>le</strong>ur,Variab<strong>le</strong> n’existe pas,el<strong>le</strong> nécessiterait plus des 14 bits des instructions.La plupart des instructions agissent sur <strong>le</strong>s fanions (flags) Z et C, qui sont deux bits du registreStatus. Dans ce registre on trouve aussi un bit RP0 qui sé<strong>le</strong>ctionne un 2 e groupe de variab<strong>le</strong>s,qui contient en particulier <strong>le</strong>s registres de direction. Les regitres de direction TrisA, TrisB, TrisCpeuvent être modifiés directement <strong>avec</strong> <strong>le</strong>s instructions Move W,TrisA, etc. C’est plus<strong>com</strong>pliqué pour <strong>le</strong>s registres D et E.Les instructions Inc Var et Dec Var activent <strong>le</strong> fanion Z quand <strong>le</strong> résultat est nul.Les instructions IncSkip,EQ Var et DecSkip.EQ Var économisent une instruction. El<strong>le</strong>s nemodifient pas Z ! IncSkip,NE et DecSkip,EQ n’existent pas.Les instructions RRC Var et RLC Var font tourner <strong>le</strong>s 8 bits à travers <strong>le</strong> carry.Enfin, on a <strong>com</strong>pris l’intérêt des routines dont on peut oublier <strong>le</strong> contenu, il suffit de savoir cequ’el<strong>le</strong>s font et <strong>le</strong>ur passer un ou plusieurs paramètres. Dans <strong>le</strong>s cas simp<strong>le</strong>s, ce paramètre estun mot de 8 bits dans W. Pour varier un délai, 8 bits est insuffisant et on a deux routinesdifférentes pour <strong>le</strong>s délais courts DelWx1ms et <strong>le</strong>s délais longs DelWx01s.Ces routines ‘’de librairie’’ sont dans un fichier <strong>avec</strong> l’extension .asi. Le fichier Ex877Init1.asicontient aussi la routine Init qui initialise <strong>le</strong> Ports A en entrée et <strong>le</strong>s ports B, C, D, E en sortie.Chaque application a des entrées-sorties spécifiques, donc une routine Init: spécifique.A quoi servent ces .Ascii ‘’T e x t e ‘’ à la fin des programmes ? A rien, mais ils laissent unetrace dans <strong>le</strong> fichier hex, que l’on peut lire dans <strong>le</strong> Pickit2.Vos autres questions à info@didel.<strong>com</strong>La 2 e section va continuer <strong>le</strong> petit jeu d’observation de l’effet de nouvel<strong>le</strong>s instructions sur desvariab<strong>le</strong>s et ports et que l’on peut visualiser.La section i inventoriera toutes <strong>le</strong>s instructions et est une annexe sans exercices que l’on lit unepremière fois et consulte quand on n’est plus sûr de sa mémoire.La 3 e section présente <strong>le</strong>s périphériques internes du 877, indispensab<strong>le</strong>s pour beaucoupd’applications.La 4 e section montre <strong>com</strong>ment on gère <strong>le</strong>s périphériques externes <strong>le</strong>s plus courants <strong>avec</strong> desexemp<strong>le</strong>s un peu plus corsés. El<strong>le</strong> donne quelques conseils pour <strong>le</strong> développement desprogrammes.jdn 100928

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!