Cours Bigonoff 16F877

  • Published on
    25-Nov-2015

  • View
    181

  • Download
    2

Transcript

LA PROGRAMMATION DES PICSPAR BIGONOFFSECONDE PARTIE Rvision 13LA GAMME MID-RANGE PAR LETUDE DES 16F87X(16F876-16F877)231. INTRODUCTION............................................................................................................................................. 92. LES CARACTRISTIQUES DES 16F87X.................................................................................................. 112.1 CARACTRISTIQUES GNRALES DE LA FAMILLE 16F87X............................................................................ 112.2 ORGANISATION DE LA RAM ........................................................................................................................ 122.3 STRUCTURE DU 16F876 ............................................................................................................................... 123. LES PARTICULARITS DE LA PROGRAMMATION DU 16F87X...................................................... 153.1 LA DIRECTIVE _CONFIG ....................................................................................................................... 153.2 UTILISATION DE LA MMOIRE RAM ............................................................................................................ 163.2.1 Ladressage direct................................................................................................................................ 163.2.2 Ladressage indirect............................................................................................................................. 183.3 LUTILISATION DU REGISTRE PCLATH ....................................................................................................... 183.3.1 PCLATH et les calculs dadresse......................................................................................................... 193.3.2 PCLATH et les sauts directs................................................................................................................. 194. SAUTS DE PAGES ET PREMIER PROJET SUR MPLAB...................................................................... 234.1 STRUCTURE ET UTILISATION DU FICHIER MAQUETTE ............................................................................. 244.2 CRATION DUN PROGRAMME SANS SAUT DE PAGE...................................................................................... 284.3 PREMIRES TENTATIVES DE SAUT INTER-PAGES........................................................................................... 284.4 EVITONS LE PIGE ........................................................................................................................................ 314.5 PREMIRE CORRECTION DE NOTRE EXERCICE............................................................................................... 324.6 EVITONS LES WARNINGS INUTILES ............................................................................................................... 334.7 DMONSTRATION PRATIQUE DE LUTILIT DES MACROS.............................................................................. 344.8 LES SOUS-PROGRAMMES INTER-PAGES ........................................................................................................ 385. LES SOURCES DINTERRUPTIONS......................................................................................................... 435.1 ENUMRATION............................................................................................................................................. 435.2 LE REGISTRE INTCON ET LES INTERRUPTIONS PRIPHRIQUES .................................................................. 445.2.1 Mise en service des interruptions primaires ........................................................................................ 445.2.2 Mise en service des interruptions priphriques.................................................................................. 455.3 LES REGISTRES PIE1, PIE2, PIR1 ET PIR2 .................................................................................................. 455.3 ETUDE DE LA ROUTINE DINTERRUPTION DU FICHIER MAQUETTE ........................................................... 475.4 CAS PARTICULIER DES 873 ET 874 ............................................................................................................... 546. MISE EN UVRE ET CONFIGURATION MINIMALE ......................................................................... 576.1 LE MATRIEL NCESSAIRE ........................................................................................................................... 576.2 LE SCHMA MINIMUM .................................................................................................................................. 586.3 LES PARTICULARITS LECTRIQUES............................................................................................................. 597. MIGRATION DU 16F84 VERS LE 16F876................................................................................................. 637.1 SIMILITUDES ET DIFFRENCES AVEC LE 16F84............................................................................................. 637.2 CONVERSION DUN PROGRAMME CRIT POUR LE 16F84 VERS LE 16F876.................................................... 637.3 CAUSES DE NON FONCTIONNEMENT ............................................................................................................. 647.3 CONVERSION DUN EXEMPLE PRATIQUE....................................................................................................... 657.3.1 Ralisation du montage........................................................................................................................ 657.3.2 Cration du projet ................................................................................................................................ 667.3.3 La mthode conseille .......................................................................................................................... 678. OPTIMISONS UN PEU ................................................................................................................................. 798.1 LES DEUX GRANDS TYPES DOPTIMISATION ................................................................................................. 798.2 TRAVAIL SUR UN EXEMPLE CONCRET........................................................................................................... 798.3 LE CHOIX DU TYPE DOPTIMISATION ............................................................................................................ 828.4 APPLICATION PRATIQUE............................................................................................................................... 828.4 OPTIMISATIONS PARTICULIRES .................................................................................................................. 928.4.1 Optimisation des niveaux de sous-programmes ................................................................................... 938.4.2 Lorganisation des ressources ........................................................................................................... 10049. LES DIFFRENTS TYPES DE RESET .................................................................................................... 1059.1 LES 6 TYPES DE RESET ............................................................................................................................... 1059.2 LE RESET ET LES REGISTRES STATUS ET PCON....................................................................................... 1059.3 DTERMINATION DE LVNEMENT ........................................................................................................... 10610. LES PORTS ENTRE/SORTIE ............................................................................................................... 11110.1 LE PORTA .............................................................................................................................................. 11110.2 LE PORTB............................................................................................................................................... 11210.3 LE PORTC............................................................................................................................................... 11210.4 LE PORTD .............................................................................................................................................. 11210.5 LE PORTE............................................................................................................................................... 11310.5.1 Le registre TRISE............................................................................................................................. 11311. LE PORTD EN MODE PSP ...................................................................................................................... 11711.1 A QUOI SERT LE MODE PSP ? ................................................................................................................... 11711.1 COMMENT PASSER EN MODE PSP ? ....................................................................................................... 11711.2 CONNEXION DES PORTD ET PORTE EN MODE PSP ............................................................................... 11811.3 LE FONCTIONNEMENT LOGICIEL............................................................................................................... 11811.4 LE FONCTIONNEMENT MATRIEL ............................................................................................................. 12012. LES ACCS LA MMOIRE EEPROM .............................................................................................. 12312.1 LE REGISTRE EECON1 ............................................................................................................................ 12312.2 LACCS EN LECTURE .............................................................................................................................. 12412.3 LACCS EN CRITURE ............................................................................................................................. 12512.4 INITIALISATION DUNE ZONE EEPROM ...................................................................................................... 12613. LES ACCS LA MMOIRE PROGRAMME..................................................................................... 12713.1 GNRALITS .......................................................................................................................................... 12713.2 LES ACCS EN LECTURE ........................................................................................................................... 12713.3 LES ACCS EN CRITURE .......................................................................................................................... 12913.4 PARTICULARITS ET MISE EN GARDE........................................................................................................ 13013.5 INITIALISATION DUNE ZONE EN MMOIRE PROGRAMME.......................................................................... 13113.6 LA TECHNIQUE DU BOOTLOADER . ...................................................................................................... 13113.6 APPLICATION PRATIQUE : UN CHENILLARD.............................................................................................. 13114. LE TIMER 0................................................................................................................................................ 14914.1 GNRALITS .......................................................................................................................................... 14914.2 LCRITURE DANS TMR0 ........................................................................................................................ 14914.3 LE TIMING EN MODE COMPTEUR ............................................................................................................... 15014.4 MODIFICATION AU VOL DE LASSIGNATION DU PRDIVISEUR ............................................................ 15214.4.1 Prdiviseur du timer 0 vers le watchdog.......................................................................................... 15214.4.2 Prdiviseur du watchdog vers le timer 0.......................................................................................... 15315. LE TIMER 1................................................................................................................................................ 15515.1 CARACTRISTIQUES DU TIMER 1 .............................................................................................................. 15515.2 LE TIMER 1 ET LES INTERRUPTIONS.......................................................................................................... 15615.3 LES DIFFRENTS MODES DE FONCTIONNEMENT DU TIMER1...................................................................... 15615.4 LE REGISTRE T1CON............................................................................................................................... 15715.5 LE TIMER 1 EN MODE TIMER ............................................................................................................... 15915.6 LE TIMER 1 EN MODE COMPTEUR SYNCHRONE ......................................................................................... 15915.7 LE TIMER 1 EN MODE COMPTEUR ASYNCHRONE....................................................................................... 16115.8 LE TIMER 1 ET TOSCEN.......................................................................................................................... 16215.9 UTILISATION DU DBORDEMENT.............................................................................................................. 16415.10 UTILISATION DUNE LECTURE ................................................................................................................ 16615.11 ECRITURE DU TIMER 1............................................................................................................................ 17015.12 EXERCICE PRATIQUE .............................................................................................................................. 17215.12.1 Un peu de maths............................................................................................................................. 17315.12.2 Le programme ................................................................................................................................ 17615.13 ERRATA : FONCTIONNEMENT NON CONFORME ...................................................................................... 181516. LE DEBUGGAGE PIN-STIMULUS .................................................................................................. 18517. LE TIMER 2................................................................................................................................................ 18917.1 CARACTRISTIQUES DU TIMER 2 .............................................................................................................. 18917.2 LE TIMER 2 ET LES INTERRUPTIONS.......................................................................................................... 19017.2 LE TIMER 2 ET LES REGISTRES PR2 ET T2CON........................................................................................ 19017.3 UTILISATION PRATIQUE DE NOTRE TIMER 2.............................................................................................. 19318. RCAPITULATIF SUR LES TIMERS .................................................................................................. 19918.1 LE CHOIX DU TIMER ................................................................................................................................. 19918.1.1 Vous dsirez mesurer un temps compris entre 256 et 65536 cycles................................................. 19918.1.2 Vous dsirez mesurer des temps allant jusque 524288 .................................................................... 19918.1.3 Vous dsirez mesurer des temps quelconques avec une grande prcision ....................................... 19918.1.4 Vous dsirez compter des vnements.............................................................................................. 20018.2 LES BASES DE TEMPS MULTIPLES ............................................................................................................. 20018.3 POSSIBILITS NON ENCORE ABORDES..................................................................................................... 20119. LE CONVERTISSEUR ANALOGIQUE/NUMRIQUE ....................................................................... 20319.1 PRAMBULE............................................................................................................................................. 20319.2 NOMBRES NUMRIQUES, ANALOGIQUES ET CONVERSIONS....................................................................... 20319.3 PRINCIPES DE CONVERSION SUR LES 16F87X ........................................................................................... 20819.4 LE TEMPS DACQUISITION ........................................................................................................................ 20919.5 LA CONVERSION....................................................................................................................................... 21219.6 COMPROMIS VITESSE/PRCISION.............................................................................................................. 21519.7 LES VALEURS REPRSENTES................................................................................................................... 21719.8 CONCLUSIONS POUR LA PARTIE THORIQUE............................................................................................. 21819.9 LA THORIE APPLIQUE AUX PICS : PINS ET CANAUX UTILISS ............................................................... 21919.10 LES TENSIONS DE RFRENCE ................................................................................................................ 22019.11 MESURE DUNE TENSION ALTERNATIVE................................................................................................. 22419.12 LES REGISTRES ADRESL ET ADRESH................................................................................................. 22719.13 LE REGISTRE ADCON1 ......................................................................................................................... 22719.14 LE REGISTRE ADCON0 ......................................................................................................................... 23019.15 LA CONVERSION ANALOGIQUE/NUMRIQUE ET LES INTERRUPTIONS...................................................... 23219.16 LUTILISATION PRATIQUE DU CONVERTISSEUR ...................................................................................... 23219.17 EXERCICE PRATIQUE SUR LE CONVERTISSEUR A/D ................................................................................ 23419.18 CONCLUSION.......................................................................................................................................... 24820. LES MODULES CCP1 ET CCP2 ............................................................................................................. 25120.1 GNRALITS .......................................................................................................................................... 25120.2 RESSOURCES UTILISES ET INTERACTIONS............................................................................................... 25120.3 LES REGISTRES CCP1CON ET CCP2CON .............................................................................................. 25220.4 LE MODE CAPTURE ............................................................................................................................. 25320.4.1 Principe de fonctionnement.............................................................................................................. 25320.4.2 Champs dapplication ...................................................................................................................... 25520.4.3 Remarques et limites dutilisation.................................................................................................... 25520.4.4 Mode sleep et astuce dutilisation .............................................................................................. 25720.5 LE MODE COMPARE ............................................................................................................................ 25720.5.1 Principe de fonctionnement.............................................................................................................. 25820.5.2 Champs dapplication ...................................................................................................................... 26220.5.3 Remarques et limites dutilisation.................................................................................................... 26320.5.4 Le mode sleep ............................................................................................................................. 26320.5.5 Fonctionnement non conforme......................................................................................................... 26420.6 LE MODE PWM .................................................................................................................................. 26520.6.1 La thorie du PWM .................................................................................................................... 26520.6.2 La thorie applique aux PICs......................................................................................................... 26720.6.3 Les registres utiliss ......................................................................................................................... 27320.6.4 Champs dapplication ...................................................................................................................... 27520.6.5 Remarques et limites dutilisation.................................................................................................... 27520.6.6 Le mode sleep ............................................................................................................................. 27520.7 EXERCICE PRATIQUE : COMMANDE DUN SERVOMOTEUR PAR LE PWM................................................... 276620.8 EXERCICE 2 : UNE MTHODE PLUS ADAPTE ............................................................................................ 29120.9 CONCLUSION............................................................................................................................................ 30621. LE MODULE MSSP EN MODE SPI........................................................................................................ 30921.1 INTRODUCTION SUR LE MODULE MSSP ................................................................................................... 30921.2 LES LIAISONS SRIE DE TYPE SYNCHRONE................................................................................................ 30921.3 LE MODE SPI ........................................................................................................................................... 31121.4 LES REGISTRES UTILISS .......................................................................................................................... 31221.5 LE MODE SPI MASTER............................................................................................................................. 31621.5.1 Mise en uvre .................................................................................................................................. 31621.5.2 Le registre SSPSTAT ........................................................................................................................ 31921.5.3 Le registre SSPCON......................................................................................................................... 32021.5.4 Choix et chronogrammes ................................................................................................................. 32121.5.5 Vitesses de transmission................................................................................................................... 32521.5.6 Initialisation du mode SPI Master.................................................................................................... 32621.5.7 Le mode sleep................................................................................................................................... 32721.6 LE MODE SPI SLAVE.............................................................................................................................. 32721.6.1 Mise en uvre .................................................................................................................................. 32721.6.2 Le registre SSPSTAT ........................................................................................................................ 32821.6.3 Le registre SSPCON......................................................................................................................... 32921.6.4 Les autres registres concerns ......................................................................................................... 33021.6.5 Choix et chronogrammes ................................................................................................................. 33121.6.6 Vitesses de transmission................................................................................................................... 33221.6.7 Initialisation du mode SPI SLAVE ................................................................................................... 33221.6.8 Le mode sleep................................................................................................................................... 33321.6.9 Scurit de la transmission .............................................................................................................. 33321.7 EXERCICE PRATIQUE : COMMUNICATION SYNCHRONE ENTRE 2 PICS........................................................ 33421.8 EXERCICE 2 : ALTERNATIVE DE FONCTIONNEMENT.................................................................................. 34821.9 CONCLUSIONS.......................................................................................................................................... 35422. LE BUS I2C.................................................................................................................................................. 35722.1 INTRODUCTION ........................................................................................................................................ 35722.1 CARACTRISTIQUES FONDAMENTALES .................................................................................................... 35722.2 LES DIFFRENTS TYPES DE SIGNAUX ........................................................................................................ 36122.2.1 Le bit ordinaire .......................................................................................................................... 36122.2.2 Le start-condition ............................................................................................................................. 36222.2.3 Le stop-condition.............................................................................................................................. 36222.2.4 Lacknowledge ................................................................................................................................. 36322.2.5 Le bit read/write............................................................................................................................... 36322.3 La notion dadresse............................................................................................................................. 36422.3 Structure dune trame IC ................................................................................................................... 36422.4 EVNEMENTS SPCIAUX........................................................................................................................... 36922.4.1 La libration du bus ......................................................................................................................... 36922.4.2 Le repeated start-condition .............................................................................................................. 36922.4.3 La pause ........................................................................................................................................... 36922.5 ARBITRAGE DU BUS ................................................................................................................................. 37022.6 LES EEPROM IC....................................................................................................................................... 37322.6.1 Caractristiques gnrales............................................................................................................... 37422.6.2 Octet de contrle et adresse esclave ................................................................................................ 37522.6.3 Slection dune adresse interne........................................................................................................ 37822.6.4 Ecriture dun octet ........................................................................................................................... 37922.6.5 Ecriture par page ............................................................................................................................. 38022.6.6 La lecture alatoire .......................................................................................................................... 38122.6.7 La lecture de ladresse courante ...................................................................................................... 38322.6.8 La lecture squentielle ..................................................................................................................... 38322.6.9 Le cas de la 24C16........................................................................................................................... 38422.6.10 Conclusions .................................................................................................................................... 38523. LE MODULE MSSP EN MODE IC ........................................................................................................ 38723.1 INTRODUCTION ........................................................................................................................................ 387723.2 LE REGISTRE SSPSTAT........................................................................................................................... 38823.3 LE REGISTRE SSPCON ............................................................................................................................ 38923.4 LE REGISTRE SSPADD ............................................................................................................................ 39023.5 LE REGISTRE SSPCON2 .......................................................................................................................... 39323.6 LES COLLISIONS ....................................................................................................................................... 39423.7 LE MODULE MSSP EN MODE IC MATRE ................................................................................................ 39423.7.1 La configuration du module ............................................................................................................. 39423.7.2 La vrification de la fin des oprations............................................................................................ 39523.7.3 La gnration du start-condition...................................................................................................... 39723.7.4 Lenvoi de ladresse de lesclave ..................................................................................................... 39723.7.5 Le test de lACK ............................................................................................................................... 39823.7.6 Lcriture dun octet ........................................................................................................................ 39923.7.7 L envoi du repeated start-condition ................................................................................................ 39923.7.8 Lenvoi de ladresse de lesclave ..................................................................................................... 40123.7.9 La lecture de loctet ......................................................................................................................... 40223.7.10 Lenvoi du NOACK ........................................................................................................................ 40223.7.11 Lenvoi du stop-condition............................................................................................................... 40323.8 LUTILISATION DES INTERRUPTIONS ........................................................................................................ 40423.8 LE MODULE MSSP EN MODE IC MULTI-MATRE ..................................................................................... 40523.8.1 Larbitrage ....................................................................................................................................... 40523.8.2 La prise de contrle du bus .............................................................................................................. 40523.8.3 La dtection de la perte de contle .................................................................................................. 40623.9 LE MODULE MSSP EN MODE IC ESCLAVE 7 BITS.................................................................................... 40623.9.1 Ladressage et linitialisation .......................................................................................................... 40723.9.2 la rception du start-condition......................................................................................................... 40723.9.3 La rception de ladresse en mode criture ..................................................................................... 40823.9.4 La gnration du ACK ............................................................................................................... 40923.9.5 La rception dun octet de donne ................................................................................................... 40923.9.6 La rception de ladresse en mode lecture....................................................................................... 41023.9.6 Lmission dun octet ....................................................................................................................... 41023.9.7 Le mode esclave 7 bits par les interruptions .................................................................................... 41123.10 Le module MSSP en mode IC esclave 10 bits .................................................................................. 41523.11 SYNTHSE.............................................................................................................................................. 41723.12 EXERCICE PRATIQUE : PILOTAGE DUNE 24C64...................................................................................... 41823.13 LE MODULE IC EN MODE SLEEP ............................................................................................................ 43223.14 CONCLUSIONS........................................................................................................................................ 43223.15 ANNEXE : ERRATA SUR LE IC................................................................................................................ 43223.16 BUG EN MODE IC ESCLAVE................................................................................................................... 43324. LE MODULE USART EN MODE SRIE SYNCHRONE..................................................................... 43524.1 INTRODUCTION ........................................................................................................................................ 43524.2 MISE EN UVRE ET PROTOCOLES ............................................................................................................. 43524.3 LE REGISTRE TXSTA ............................................................................................................................... 43724.4 LE REGISTRE RCSTA............................................................................................................................... 43824.5 LE REGISTRE SPBRG............................................................................................................................... 43924.6 LINITIALISATION .................................................................................................................................... 44024.7 LMISSION EN MODE MATRE.................................................................................................................. 44124.8 LMISSION EN MODE ESCLAVE................................................................................................................ 44324.9 LA RCEPTION EN MODE MATRE ............................................................................................................. 44424.9.1 La file FIFO de RCREG................................................................................................................... 44524.9.2 Lerreur doverflow.......................................................................................................................... 44624.10 LA RCEPTION EN MODE ESCLAVE ......................................................................................................... 44724.11 LE MODE SLEEP...................................................................................................................................... 44724.12 DIFFRENCES ENTRE MSSP ET USART ................................................................................................ 44724.13 EXERCICE PRATIQUE .............................................................................................................................. 44824.14 REMARQUE SUR LE MODE SLEEP ............................................................................................................ 46424.15 CONCLUSIONS........................................................................................................................................ 46525. LE MODULE USART EN MODE ASYNCHRONE............................................................................... 46725.1 LE MODE SRIE ASYNCHRONE.................................................................................................................. 467825.1.1 Le start-bit........................................................................................................................................ 46725.1.2 Les bits de donne ............................................................................................................................ 46825.1.3 La parit........................................................................................................................................... 46825.1.4 Le stop-bit ........................................................................................................................................ 46925.1.5 LES MODES COMPATIBLES.................................................................................................................... 47025.1.6 Les erreurs de synchronisation ........................................................................................................ 47325.2 MISE EN UVRE....................................................................................................................................... 47525.3 LE REGISTRE TXSTA ............................................................................................................................... 47725.4 LE REGISTRE RCSTA............................................................................................................................... 47825.5 LE REGISTRE SPBRG............................................................................................................................... 47925.6 LINITIALISATION .................................................................................................................................... 48025.7 EMISSION, RCEPTION, ET ERREUR DOVERFLOW .................................................................................... 48025.8 LERREUR DE FRAME ............................................................................................................................... 48325.9 UTILISATION DU 9ME BIT COMME BIT DE PARIT ...................................................................................... 48325.10 LA GESTION AUTOMATIQUE DES ADRESSES............................................................................................ 48325.11 LE MODE SLEEP...................................................................................................................................... 48625.12 EXEMPLE DE COMMUNICATION SRIE ASYNCHRONE.............................................................................. 48725.12.1 Utilisation de BSCP. ...................................................................................................................... 50525.13 CONCLUSIONS........................................................................................................................................ 50926. NORME ISO7816 ET PIC16F876 ............................................................................................................. 51126.1 AVANT-PROPOS ....................................................................................................................................... 51126.2 LANCTRE WAFER ............................................................................................................................ 51126.3 LA SUCCESSION PICCARD2 . ................................................................................................................ 51326.4 LA BIGCARD 1 ......................................................................................................................................... 51426.5 LA BIGCARD 2 .......................................................................................................................................... 51526.6 CONCLUSIONS.......................................................................................................................................... 51727. LE MODE SLEEP ...................................................................................................................................... 51927.1 GNRALITS .......................................................................................................................................... 51927.2 LES MCANISMES..................................................................................................................................... 51927.3 LES INTERRUPTIONS CONCERNES ........................................................................................................... 52027.4 CONCLUSION.......................................................................................................................................... 52128. LE RESTE DU DATASHEET................................................................................................................... 52328.1 INTRODUCTION ........................................................................................................................................ 52328.2 LE MODE LVP.......................................................................................................................................... 52328.3 PWRTE ET BODEN................................................................................................................................ 52428.4 LES ADRESSES RSERVES 0X01 0X03............................................................................................ 52528.5 LOVERCLOCKAGE................................................................................................................................... 52728.6 CE DONT JE NAI PAS PARL ..................................................................................................................... 528ANNEXE1 : QUESTIONS FRQUEMMENT POSES (F.A.Q.)............................................................... 529A1.1 JE NARRIVE PAS UTILISER MON PORTA ............................................................................................. 529A1.2 LE CHOIX DU PROGRAMMATEUR ............................................................................................................. 529CONTRIBUTION SUR BASE VOLONTAIRE ............................................................................................ 531B. UTILISATION DU PRSENT DOCUMENT........................................................................................... 53391. IntroductionTout dabord, un grand remerciement tous ceux qui ont permis que cette aventure existe.Je parle ici de toutes les personnes qui mont envoy leurs commentaires et corrections, lesdiffrents hbergeurs de la premire partie de ce cours, ainsi que tous ceux qui mont envoyremerciements et encouragements. Je remercie davance tous ceux qui feront de mme pourcette seconde partie.Merci galement mon pouse pour sa patience durant toutes ces soires passes plantderrire mon ordi .Cette seconde partie sadresse aux personnes qui ont dj lu et compris la premirepartie, ddicace la programmation du 16F84. Donc, je ne reviendrai pas sur les explicationsde base concernant la programmation, et je nexpliquerai pas non plus les diffrentesfonctions avec autant de dtail. Cet ouvrage est donc un complment, une volution, et non unouvrage destin tre utilis de manire compltement indpendante.Le document indispensable pour aborder la programmation du processeur 16F87x est ledatasheet 16F87x disponible sur le site http://www.microchip.com. Afin que tout le mondedispose du mme document que lauteur, jai intgr dans le rpertoire fichiers , la versiondu datasheet qui a servi pour laborer ce cours.Ceux qui veulent comprendre tous les dtails du fonctionnement des PICs concernspeuvent galement charger le Pic Micro Mid-Range MCU Family Reference Manual ,disponible la mme adresse. Attention, limpression de cet ouvrage, disponible dailleurs parchapitres spars, requiert plusieurs centaines de feuilles.Cet ouvrage est plus technique que le prcdent. Cette dmarche ma t impose, dunepart par ltendue des possibilits, et dautre part par la ncessit dune certaine part dethorie qui, seule, permettra de sortir le lecteur de toutes les situations non abordes de faonconcrte.En effet, ces composants possdent une multitude de fonctions, elles-mmes parfoisscindes en plusieurs modes de fonctionnement. Dcrire un exemple dtaill pour chacune deses fonctions aurait ncessit un ouvrage trop consquent pour que je puisse en venir boutdans des dlais raisonnables. Vous remarquerez cependant que je nai pas t avaredexercices pratiques.Jai donc conserv le maximum dexemples, mais jai opt principalement pour unedmarche qui vise vous fournir tous les outils et toutes les explications qui vous permettrontdutiliser toutes les fonctions de cette srie dans vos applications particulires.Ce faisant, jai d aborder beaucoup de thorie, ce qui rend cet ouvrage un peu plus dur lire que le prcdent. Ce nest pas une dmarche litiste, au contraire, mais une tentative pourvous ouvrir le maximum de portes pour le futur. De plus, vous tes senss, lors de la lecturede cet ouvrage, matriser parfaitement le 16F84, on ne peut donc plus parler douvrage pourdbutants.Jespre quen procdant de la sorte, je ne me suis pas montr trop rbarbatif.10Je suis toujours lcoute de tous, je rponds toujours au courrier reu, et si lademande se fait sentir concernant certains chapitres, il me sera toujours possible dajouterexplications complmentaires et exemples supplmentaires.Nhsitez donc pas me faire part de vos remarques et suggestions, et jetez de tempsen temps un il sur mon site (http://www.abcelectronique.com/bigonoff ouwww.bigonoff.org ) pour voir si une nouvelle rvision nest pas disponible.A tout ceux qui mont demand ou qui se demandent pourquoi jai mis cet ouvragegratuitement la disposition de tous, je rpondrai ceci : En ces temps o tout se marchande, o la mondialisation du commerce seffectue audtriment du bien-tre le lHomme et de lHumanit, il est primordial de se dresser contrecette mentalit du tout marchand. Je ne suis pas le prcurseur de cette dmarche dans le domaine de la technique et delinformatique. Bien dautres ont compris ceci avant moi, comme par exemple les crateurs delogiciels freeware. Dautres suivront ces exemples, afin que le monde en gnral, et Interneten particulier, devienne ce quil aurait toujours d tre : un lieu dchange de la connaissanceet un partage des dons et des richesses de chacun .Internet est un formidable outil de communication qui peut nous aider atteindre ce but.Veillons attentivement ce quil ne devienne pas un gigantesque lieu de e-business rcuprpar les multinationales. Je vais cependant peut-tre chercher un diteur qui me permettra de distribuer en plus cesdiffrents ouvrages par la voie classique. Ceci permettrait au plus grand nombre davoir accsaux informations, et, de plus, pourrait se rvler rentable pour lutilisateur, le prix delimpression dun tel ouvrage sur une imprimante jet dencre pouvant se rvler aussionreux que lacquisition dun livre. Mais le cours restera disposition sur internet aussilongtemps que jen aurai la possibilit matrielle et financire.La demande de contribution sur base volontaire nest pas une entorse cette philosophie.Le cours reste gratuit, maide qui le veut, et comme il le veut.Jai construit ce livre en pensant son format papier. Il est prvu pour tre imprim enrecto-verso. Comme il est amen tre corrig, et afin de ne pas vous imposer la rimpressioncomplte en cas de modifications, jai laiss un peu de place libre entre chaque chapitre.Ainsi, une insertion ne ncessitera pas la renumrotation des pages.Je vous souhaite beaucoup de plaisir la lecture de ce petit ouvrage sans prtention, et jevous le conseille : exprimentez, exprimentez, et exprimentez encore ! Et vive lInternet libre !BIGONOFF112. Les caractristiques des 16F87x2.1 Caractristiques gnrales de la famille 16F87xLe 16F876 et le 16F877 (et dautres) font partie de la sous-famille des 16F87x. Cettebranche fait partie intgrante de la grande famille des PICs Mid-Range, au mme titre que le16F84 dont je parle dans le prcdent ouvrage. On peut considrer que le 16F84 constitue lecircuit dentre de gamme de cette famille, alors que le 16F877 reprsente la couchesuprieure. De nouveaux circuits ne devraient probablement pas tarder amliorer encore lesperformances.De ce fait, beaucoup de similitudes sont prvoir entre ces 2 composants. Nous verronsdans le chapitre suivant quels sont ces points communs.La famille 16F87x comprend toute une srie de composants, voici les diffrents typesexistant au moment de lcriture de cet ouvrage. Notez que les composants sont en constantevolution. Il vous appartiendra donc de vous tenir au courant de ces volutions.PIC FLASH RAM EEPROM I/O A/D Port // Port srie16F870 2K 128 64 22 5 NON USART16F871 2K 128 64 33 8 PSP USART16F872 2K 128 64 22 5 NON MSSP16F873 4K 192 128 22 5 NON USART/MSSP16F874 4K 192 128 33 8 PSP USART/MSSP16F876 8K 368 256 22 5 NON USART/MSSP16F877 8K 368 256 33 8 PSP USART/MSSPTous ces composants sont identiques, aux exceptions cites dans le tableau prcdent. Lesdiffrences fondamentales entre ces PICs sont donc les quantits de mmoires disponibles, lenombre dentres/sorties, le nombre de convertisseurs de type analogique/digital (dire analogique/numrique , et le nombre et le type des ports intgrs.A lheure actuelle, ces composants existent dans divers types de botiers. Ces types sontreprsents page 1 et 2 du datasheet. Les botiers 40 broches sont utiliss par les composantsqui disposent dun port //, comme le 16F877. Le botier qui nous intresse plusparticulirement est celui dont le brochage est disponible en haut et gauche de la page 2.Ce botier est disponible en version standard (PDIP 28 broches) ou en version composant desurface , ou CMS (SOIC).Comme pour le 16F84, le numro peut tre suivi dun A , et dun -xx qui donne lafrquence dhorloge maximum du composant. A lheure o jcris cet ouvrage, la version laplus courante est la version 20. Donc, la frquence que nous utiliserons en standard dans cetouvrage sera de 20MHz. De mme, les exercices seront raliss sur un PIC16F876, moinscher que le 16F877. Nous nutiliserons ce dernier composant que lorsque ses spcificitsseront indispensables la ralisation de lexercice.12Nous nous intresserons donc dans cet ouvrage principalement au 16F876, qui est le plusutilis lheure actuelle. La transposition vers un autre type ne demande quun minimumdadaptation. Nous parlerons galement du 16F877 lorsque nous aborderons le port parallle.Ainsi, nous aurons vu lintgralit des fonctions de cette famille.2.2 Organisation de la RAMNous voyons donc que la mmoire RAM disponible du 16F876 est de 368 octets. Elle estrpartie de la manire suivante et donne page 13 du datasheet :1) 80 octets en banque 0, adresses 0x20 0x6F2) 80 octets en banque 1, adresses 0xA0 0XEF3) 96 octets en banque 2, adresses 0x110 0x16F4) 96 octets en banque 3, adresses 0x190 0x1EF5) 16 octets communs aux 4 banques, soit 0x70 0x7F = 0xF0 0xFF = 0x170 0x17F =0x1F0 0x1FFQue signifient ces octets communs ? Tout simplement que si vous accdez au registre(adresse mmoire RAM) 0x70 ou au registre 0XF0, et bien vous accdez en ralit au mmeemplacement. Ceci lavantage de permettre dutiliser ces emplacements sans devoirconnatre ltat de RP0,RP1, et IRP.2.3 Structure du 16F876Allons ensemble regarder la structure interne du 16F876, schmatise figure 1.1 page 5 dudatasheet.Que constatons-nous au premier abord ?En premier lieu, les largeurs de bus internes sont les mmes que pour le 16F84, cest dire que nous devrons faire face aux mmes contraintes pour les accs aux diffrentesbanques et registres.Ensuite, nous constatons la prsence de plus de ports, ce qui augmente dautant le nombredentres/sorties disponibles.Viennent ensuite les timers, au nombre de 3 au lieu dun seul pour le 16F84. A ct de cestimers on remarquera la prsence dun convertisseur analogique de 10 bits.Au vu de ce schma-bloc et des indications prcdentes, on peut donc dire, pour dgrossirle sujet de manire approximative, quun 16F876, cest un 16F84 dot en supplment :- De plus de mmoire RAM (rpartie sur 4 banques), Flash, et eeprom- De plus de ports dentre/sortie- De plus de timers- De nouvelles fonctionnalits, comme les gestions de ports srie - Dun convertisseur A/D (analogique/numrique) plusieurs canaux dune rsolution de10 bits.13Nous voyons donc que ltude du 16F876 peut se rsumer lapprentissage desdiffrences par rapport au 16F84. Ces diffrences introduisent cependant une part nonngligeable de thorie, ce qui ma convaincu dcrire cette seconde partie.Il faut dire qucrire un livre de plus de 500 pages rien que sur les diffrences avec laprcdente version, propos de laquelle louvrage comportait 200 pages, indique que les ditesdiffrences justifiaient quon sy attarde.Il existe de plus des fonctions qui ncessitent une tude plus pousse (debuggage surcircuit, techniques du bootloader), mais jaborderai ceci dans le livre suivant (3me partie : Lessecrets des 16F87x). En effet, afin de limiter la taille de cet ouvrage, et dacclrer sa sortie,jai scind la version initialement prvue en plusieurs volumes.En bonne logique, commenons donc par voir ce qui caractrise le 16F87x14Notes : .153. Les particularits de la programmation du 16F87x3.1 La directive _CONFIG Tout comme nous lavons vu dans la premire partie, cette directive dtermine lefonctionnement du PIC. La valeur est inscrite au moment de la programmation dans unregistre spcial, situ en mmoire programme ladresse 0x2007, et ne peut plus tre modifien cours dexcution du programme.Notez que puisque la mmoire programme des PICs vierges contient des 1 , lesniveaux actifs de ces bits sera le niveau 0 .Ce registre de 14 bits (puisquen mmoire programme) dispose dune organisationdiffrente par rapport celui du 16F84. Voici donc ses fonctions, reprises page 122 dudatasheet :- CP1/CP0 : bits 13/12 et 5/4 : Dtermine quelle zone du 16F876 sera protge contre lalecture. Vous pouvez donc choisir de protger la totalit du PIC, ou seulement une partie.Les diffrentes zones pouvant tre protges sont les suivantes :CP1 CP01 1 Aucune protection (_CP_OFF)1 0 Protection de la zone 0x1F00 0x1FFF (_CP_UPPER_256)0 1 Protection de la zone 0x1000 0x1FFF (_CP_HALF)0 0 Protection de lintgralit de la mmoire (_CP_ALL)- DEBUG : bit 11 : Debuggage sur circuit. Permet de ddicacer RB7 et RB6 lacommunication avec un debugger.1 : RB6 et RB7 sont des I/O ordinaires (_DEBUG_OFF)0 : RB6 et RB7 sont utiliss pour le debuggage sur circuit (_DEBUG_ON)- Bit 10 : non utilis- WRT : bit 9 : Autorisation dcriture en flash1 : Le programme peut crire dans les zones non protges par les bits CP1/CP0 (_WRT_ENABLE_ON)0 : Le programme ne peut pas crire en mmoire flash (_WRT_ENABLE_OFF)- CPD : bit 8 : Protection en lecture de la mmoire eeprom.1 : mmoire eeprom non protge (_CPD_OFF)0 : mmoire eeprom protge (_CPD_ON)- LVP : bit 7 : Utilisation de la pin RB3/PGM comme broche de programmation1 : La pin RB3 permet la programmation du circuit sous tension de 5V (_LVP_ON)0 : La pin RB3 est utilise comme I/O standard (_LVP_OFF)- BODE N : bit 6 : provoque le reset du PIC en cas de chute de tension (surveillance de latension dalimentation)1 : En service (_BODEN_ON)160 : hors service (_BODEN_OFF)- PWRTE : bit 3 : Dlai de dmarrage la mise en service. Attention, est automatiquementmis en service si le bit BODEN est positionn.1 : dlai hors service (sauf si BODEN = 1) (_PWRTE_OFF)0 : dlai en service (_PWRTE_ON)- WDTE : bit 2 : Watchdog timer1 : WDT en service (_WDT_ON)0 : WDT hors service (_WDT_OFF)- FOSC1/FOSC0 : bits 1/0 : slection du type doscillateur11 : Oscillateur de type RC (_RC_OSC)10 : Oscillateur haute vitesse (_HS_OSC)01 : Oscillateur basse vitesse (_XT_OSC)00 : Oscillateur faible consommation (_LP_OSC)Noubliez pas dutiliser ces valeurs dans la directive _CONFIG. Les diffrentes valeurs,prdfinies dans le fichier P16F876.INC doivent tre spares par des directives & .Voici un exemple dutilisation :__CONFIG _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_OFF & _CPD_OFF &_LVP_OFF & _BODEN_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSCJe fournis dans les fichiers joints ce cours, une maquette pour le 16F876 et une pour le16F877, dans lesquelles le corps de programme et les explications des directives ont dj tlabors par mes soins. Ces fichiers m16f876.asm et m16F877.asm vous pargnerontsans aucun doute bien du travail peu valorisant.3.2 Utilisation de la mmoire RAMSur ce processeur, nous avons donc 4 banques de mmoire RAM. Nous voyons que lesadresses schelonnent entre 0x00 et 0x1FF.Si vous convertissez 0x1FF en binaire, laide de la calculette de Windows, vousconstaterez quil faut 9 bits pour coder cette valeur. La largeur du bus de donnes tant de 8bits, et la largeur du bus dadressage direct de 7 (voir la premire partie), il va nous falloirtrouver des bits supplmentaires.3.2.1 Ladressage directPour ce type dadressage, il nous manque donc 2 bits. Tout comme dans le cas du 16F84,nous allons trouver ces 2 bits dans le registre STATUS. La combinaison des bits RP0 et RP1de ce registre, permet donc daccder en adressage direct lintgralit de la mmoire RAM.Ladresse finale est donc compose de RP1/RP0 comme bits 8 et 7, complts des 7 bits deladresse directe utilise dans lexpression.17Les 4 possibilits concernant RP1/RP0 donnent donc :00 : Accs la RAM 0x00 0x7F01 : Accs la RAM 0x80 0xFF10 : Accs la RAM 0x100 0x17F11 : Accs la RAM 0x180 0x1FFNotez que la RAM situe de 0x70 0x7F est accessible quel que soit ltat de RP0 et RP1.En effet, les zones correspondantes dans les autres banques sont en fait des images de cettezoneVoici des emplacements de mmoire RAM. Pour rappel, les ( ) dans les commentairessignifient le contenu de :variable1 EQU 0x25 ; adresse de la variable 1variable2 EQU 0x7E ; adresse de la variable 2variable3 EQU 0xA1 ; adresse de la variable 3movlw 0x50 ; charger 0x50 dans Wmovwf variable2 ; dans la case mmoire 0x7E, car indpendant de; RPxmovlw 0x30 ; charger 0x30 dans Wbcf STATUS , RP0 ; passage en banque 0bcf STATUS , RP1movwf variable1 ; placer dans la case mmoire 0x25movwf variable3 ; placer dans 0x21, car seuls 7 bits sont pris en; compte. Pige.bsf STATUS , RP1 ; passer en banque 2movf variable2 , W ; (0x17E) dans W, donc (0x7E), donc 0x50movwf variable1 ; 0x50 dans la case mmoire 0x125bsf STATUS , RP0 ; passage en banque 3movwf variable1 ; 0x50 dans la case mmoire 0x1A5Vous pouvez facilement voir les correspondances des adresses en utilisant le tableau 2.3page 13 du datasheet, ou avec la calculatrice de Windows. Si vous ne comprenez pas bien ouque vous doutez, procdez la mthode suivante pour obtenir ladresse concerne : 1) Convertissez ladresse en binaire avec la calculatrice Windows 2) Entrez en binaire les 2 bits RP0 et RP1 3) Compltez avec les 7 bits gauche de ladresse binaire.Par exemple, pour la dernire ligne du prcdent exemple :1) RP0/RP1 = 112) 25 en hexadcimal donne 100101 en binaire (attention, il ny a que 6 chiffres, jecomplte donc par un 0 gauche : 0100101 3) Ceci donne B110100101, soit 0x1A5183.2.2 Ladressage indirectLadressage indirect utilise le registre FSR/INDF . Hors, ce registre une largeur de 8bits. Donc, tel quel, il lui est impossible dadresser plus de 2 banques. Il va donc falloirtrouver une fois de plus un bit supplmentaire.Ce bit est le bit IRP du registre STATUS. Ce bit est donc utilis comme bit de poids fort(bit 8) complt par les 8 bits contenus dans le registre FSR.En fonction de la valeur de IRP, nous accderons donc :IRP = 0 : Banques 0 et 1, soit registres de 0x00 0xFFIRP = 1 : Banques 2 et 3, soit registres de 0x100 0x1FFDonc, faites attention : les bits RP0 et RP1 ninfluencent en aucune faon ladressageindirect. De mme , IRP ninfluence en aucune faon ladressage direct.Voici un exemple dutilisation de ladressage indirect. On prsume que cet exemple est lasuite du prcdent :bcf STATUS,IRP ; pointer banques 0 et 1 indirectmovlw variable1 ; charger 0x25, donc adresse de variable1movwf FSR ; mettre 0x25 dans le pointeurmovf INDF,w ; charger (0x25), donc 0x30bsf STATUS,IRP ; pointer banque 2 et 3 indirectmovwf INDF ; mettre 0x30 dans le registre 0x125movlw variable3 ; charger adresse variable3movwf FSR ; dans pointeurbcf STATUS,RP0 ; pointer banque0 en adressage directbcf STATUS,RP1movf variable3,w ; charger (0x21) car 0xA1 en 7 bits , donc 0x30movwf INDF ; placer 0x30 en 0x1A1. En effet, 8 bits de ; ladresse 0xA1 + bit8 1 (IRP)Pour rsumer :- Vous devez toujours vrifier RP0 et RP1 avant toute utilisation de ladressage direct.- Vous devez toujours vrifier IRP avant toute utilisation de ladressage indirect.Sachez dj que, suivant mes observations, plus de la moiti des erreurs deprogrammation persistantes sont dues des erreurs de slection de banques.3.3 Lutilisation du registre PCLATHNous avons dj vu ce registre dans ltude du 16F84 : en effet, lors dune oprationmathmatique sur le registre PCL (dans le cadre de lutilisation dun tableau), le rsultatdonnait une valeur sur 8 bits.Notre 16F84 permettant un adressage de plus de 8 bits, les bits manquants taientgalement emprunts PCLATH.193.3.1 PCLATH et les calculs dadresseCette limitation existe ici aussi de la mme manire. Donc, nous devrons donc utilisernotre PCLATH en suivant les recommandations suivantes :- En cas dopration sur PCL, la valeur sur 8 bits obtenue est complte par PCLATH pourformer ladresse de destination effective. Supposons donc que nous fassions une additionde w par rapport PCL. O va pointer alors le pointeur de programme (PC) ? Voici le contenu de PC aprs laddition :b7 b0 seront en fait le contenu effectif de PCLb12 b8 seront les bits b4 b0 de PCLATH.Exemple dopration qui sapplique dans ce cas :movlw B10010 ; charger valeurmovwf PCLATH ; initialiser PCLATHmovlw 0x22 ; charger valeuraddwf PCL , f ; sauter plus loinPCLATH (5 bits) PCL (8 bits)B4 B3 B2 B1 B0 B7 B6 B5 B4 B3 B2 B1 B0PC(13 bits) = adresse de sautB12 B11 B10 B9 B8 B7 B6 B5 B4 B3 B2 B1 B0Ce fonctionnement est strictement identique celui expliqu dans le cadre du 16F84.Si on prend comme exemple concret le rsultat suivant :- PCL vaut B11011010 aprs laddition- PCLATH a t initialis B00010010 par lutilisateur. Notez que b7 b5 sont inutiliss.- Le saut final seffectuera donc ladresse B1001011011010 aprs laddition, soit0x12DA.PCLATH (5 bits) PCL (8 bits)1 0 0 1 0 1 1 0 1 1 0 1 0PC(13 bits) = adresse de saut1 0 0 1 0 1 1 0 1 1 0 1 03.3.2 PCLATH et les sauts directsEt oui, avec ce processeur survient un autre problme, problme que nous navions pasrencontr cette fois avec le 16F84.Si vous examinez le jeu dinstructions du 16F876 dans le dtail, vous allez vousapercevoir quil est strictement identique celui du 16F84, et, de ce fait, prsente les mmeslimitations.20Une de celle-ci, la plus gnante, est le nombre de bits qui accompagne les instructions desaut, comme le goto . Rappelez-vous que les instructions de saut sont de la forme :Op-code + 11 bits de destination.Or, les sauts sur 11 bits ne permettent que des sauts lintrieur dune page de 2KMots. Notre processeur utilise un maximum de 8Kmots de programme, et ncessite donc 2bits supplmentaires pour accder lintgralit de la mmoire programme. Le schma-blocdonnant bien une largeur de bus dadressage de 13 bits.Ces bits, nous allons donc aller les chercher galement dans le registre PCLATH. Commeil ne nous manque que 2 bits, nous nutiliserons donc que les 2 bits b4 et b3 de PCLATH.Pour rsumer, le saut seffectuera ladresse donne en argument complte en poids fortpar les 2 bits b4 et b3 de PCLATH. Les bits 2 0 de PCLATH sont inutiliss ici.PCLATH ARGUMENT DU SAUT (11 bits)B4 B3 B10 B9 B8 B7 B6 B5 B4 B3 B2 B1 B0PC(13 bits) = adresse de sautB12 B11 B10 B9 B8 B7 B6 B5 B4 B3 B2 B1 B0Petit exemple pratique : soit les instructions suivantes :movlw 0x13 ; charger 0x13, soit B10011, donc b4=1, b3=0movwf PCLATH ; dans PCLATHgoto 0x112 ; sauter thoriquement en 0x112 (B00100010010)Voici ce que a donne :PCLATH ARGUMENT DU SAUT (11 bits)1 0 0 0 1 0 0 0 1 0 0 1 0PC(13 bits) = adresse de saut1 0 0 0 1 0 0 0 1 0 0 1 0Donc, vous constaterez que le programme saute en ralit ladresse 0x1112, et non ladresse 0x112.Mais ne vous inquitez pas trop : tout dabord nous allons voir tout a avec un exemplepratique, et ensuite, les sauts dans les espaces suprieurs 2K ne devraient pas vous perturberavant un certain temps.Noubliez pas en effet que vous ne rencontrerez ce problme que si votre programmedpasse les 2Kmots de code. Donc, il faudra que vous ayez crit plus de 2000 lignes de codedans votre programme.Nul doute que quand vous en serez l, vous matriserez parfaitement ce type de limitation.De plus, je vais vous venir en aide, en vous expliquant et en crant des macros pour vousfaciliter le traitement de ce problme le jour o vous le rencontrerez.21Notez quil est rare dcrire un ligne du typegoto 0x112car, en gnral, vous utiliserez plutt un saut vers une tiquette, du style :goto etiquetteDans ce cas, vous devrez raisonner de faon inverse. Il vous faudra savoir dans quellepage de 2Kmots se trouve etiquette et ensuite vous positionnerez PCLATH enconsquence.Rassurez-vous cependant, MPASM ne manquera pas de vous avertir, par un warning,quil y a un risque ce niveau.Mais, pour tre certain que vous compreniez bien tout, nous allons mettre tout ceci enpratique dans le chapitre suivant.22NOTES : ...234. Sauts de pages et premier projet sur MPLABPour clarifier la situation, nous allons donc mettre ceci en pratique. Commencez donc parfaire une copie de votre fichier m16f876.asm et renommez cette copie en pclath.asm .Lancez MPLAB et crez un nouveau projet pclath.pjt .Je nentrerai plus dans les dtails, vu que jai tout expliqu dans la premire partie ducours. Dans la fentre edit project qui souvre alors, slectionnez < change > ct de lafentre development mode , puis choisissez la mise en service du simulateur pour le16F876. Ceci est donn pour lancienne version 5.x de MPLAB. Pour la 6.x, voyez le cours-part1Cliquez ensuite sur la ligne pclath [.hex] , le bouton < Node Properties > devient actif.Cliquez dessus et configurez la fentre qui souvre de manire identique celle de la figuresuivante :24Cliquez OK dans la fentre Node Properties , puis revenez la fentre Editproject . Crez un nouveau nud avec et slectionnez votre fichier pclath.asm . Cliquez ensuite dans la fentre Edit project . Dans le menu file , ouvrez enfin votre fichier pclath .asm . Vous tes enfinprts travailler sur votre premier programme en 16F876.Si vous navez pas tout suivi, retournez jeter un il dans le cours sur le 16F84.4.1 Structure et utilisation du fichier maquette Commencez donc, comme toujours, par remplir votre cadre de commentaires, pourexpliquer ce que contiendra votre nouveau projet. Tout comme dans la premire partie ducours, jinsiste de nouveau pour que vous documentiez au maximum vos programmes. Cestle seul et unique moyen de vous permettre une maintenance aise de vos ralisations dans letemps. Ce qui vous semble vident aujourdhui ne le sera peut-tre plus demain. Sachez quemoi-mme je documente mes programmes exactement de la faon que je dcris dans ce cours,car ce qui est bon pour vous lest forcment pour moi aussi.Jouvre ici une parenthse, pour me fcher un peu (une fois nest pas coutume, vous nemy reprendrez plus).Malgr tous ces avertissements, je reois rgulirement des programmes excuts parcertains dentre-vous, et vierges de tout commentaire. Dune part, je ne lirai plus lesprogrammes sans commentaire, et dautre part, si ces personnes me les envoient, cest quilsne fonctionnent pas. Comment alors admettre que ces personnes nont pas besoin de conseilspour raliser leur programme, mais en ont besoin pour les debugger lorsquils ne fonctionnentpas ?De mme, je reois des programmes de personnes qui ont dcid de nutiliser aucunsymbole. Essayez donc de lire des programmes du style :bsf 03,7movlw 0x3Cmovwf 04movf 0,0Et bien, moi, jy renonce dfinitivement. Et dire que leurs auteurs stonnent quils sontdifficiles debugger. Cest quand mme plus clair comme ceci, non ? (cest le mmeprogramme) :bsf STATUS,IRP ; pointer sur banques 2 et 3movlw mavariable ; charger adresse de ma variablemovwf FSR ; dans pointeur indirectmovf INDF,w ; charger mavariable dans wAutrement dit, si vous vous obstinez utiliser la premire mthode (qui vous refera trsvite perdre le temps gagn), alors cest que vous avez dcid de vous passer de mes conseils.Gardez donc dans ce cas vos problmes de debuggage pour vous.25Ben oui, cette fois je rle un peu, mais il faut me comprendre, non ? Jestime donc que sivous poursuivez, cest que vous tes pleins de bonne volont, et que vous comprenez quecest dans votre propre intrt dutiliser les commentaires et adressages symboliques.Je referme la parenthse.Voici donc un exemple de zone de commentaires pour cet exercice :;************************************************************************; Exercice sur les sauts inter-pages pour montrer l'utilisation de *; PCLATH. *; *;************************************************************************; *; NOM: PCLATH *; Date: 04/07/2001 *; *; Version: 1.0 *; *; Circuit: aucun *; Auteur: Bigonoff *; *; *;************************************************************************; *; Fichier requis: P16F876.inc *; *; *;************************************************************************Viennent ensuite, comme toujours, la dclaration de processeur destine MPASM, et larfrence au fichier dinclusion, qui devra tre prsent dans votre rpertoire des fichiers.LIST p=16F876 ; Dfinition de processeur#include ; fichier includeEnsuite, vous trouvez la fameuse directive _CONFIG qui dfinit le fonctionnement debase du processeur. Rien de spcial ici, vu que ce nest quun exercice statique:__CONFIG _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_OFF & _CPD_OFF & _LVP_OFF &_BODEN_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSCPlus bas se trouvent les assignations systme. Ceci dans le but de vous viter dechercher dans le programme aprs les registres concerns. Il suffit de modifier ici les valeursde certains registres. Ces valeurs seront charges lors de linitialisation par la routine init .;**************************************************************************; ASSIGNATIONS SYSTEME *;**************************************************************************; REGISTRE OPTION_REG (configuration); -----------------------------------OPTIONVAL EQUB'00000000'; RBPU b7 : 1= Rsistance rappel +5V hors service; INTEDG b6 : 1= Interrupt sur flanc montant de RB0; 0= Interrupt sur flanc descend. de RB0; TOCS b5 : 1= source clock = transition sur RA426; 0= horloge interne; TOSE b4 : 1= Slection flanc montant RA4(si B5=1); 0= Slection flanc descendant RA4; PSA b3 : 1= Assignation prdiviseur sur Watchdog; 0= Assignation prdiviseur sur Tmr0; PS2/PS0 b2/b0 : valeur du prdiviseur; 000 = 1/1 (watchdog) ou 1/2 (tmr0); 001 = 1/2 1/4; 010 = 1/4 1/8; 011 = 1/8 1/16; 100 = 1/16 1/32; 101 = 1/32 1/64; 110 = 1/64 1/128; 111 = 1/128 1/256; REGISTRE INTCON (contrle interruptions standard); -------------------------------------------------INTCONVAL EQU B'00000000'; GIE b7 : masque autorisation gnrale interrupt ; ne pas mettre ce bit 1 ici ; sera mis en temps utile; PEIE b6 : masque autorisation gnrale priphriques; T0IE b5 : masque interruption tmr0; INTE b4 : masque interruption RB0/Int; RBIE b3 : masque interruption RB4/RB7; T0IF b2 : flag tmr0; INTF b1 : flag RB0/Int; RBIF b0 : flag interruption RB4/RB7; REGISTRE PIE1 (contrle interruptions priphriques); ----------------------------------------------------PIE1VAL EQU B'00000000'; PSPIE b7 : Toujours 0 sur PIC 16F786; ADIE b6 : masque interrupt convertisseur A/D; RCIE b5 : masque interrupt rception USART; TXIE b4 : masque interrupt transmission USART; SSPIE b3 : masque interrupt port srie synchrone; CCP1IE b2 : masque interrupt CCP1; TMR2IE b1 : masque interrupt TMR2 = PR2; TMR1IE b0 : masque interrupt dbordement tmr1; REGISTRE PIE2 (contrle interruptions particulires); ----------------------------------------------------PIE2VAL EQU B'00000000'; UNUSED b7 : inutilis, laisser 0; RESERVED b6 : rserv, laisser 0; UNUSED b5 : inutilis, laisser 0; EEIE b4 : masque interrupt criture EEPROM; BCLIE b3 : masque interrupt collision bus; UNUSED b2 : inutilis, laisser 0; UNUSED b1 : inutilis, laisser 0; CCP2IE b0 : masque interrupt CCP2Ne vous occupez pas de ces registres ici. Nous verrons ceux que vous ne connaissez pasencore plus tard. Vous trouvez galement deux zones prvues pour placer vos propresdfinitions et assignations, le tout avec chaque fois un exemple.27Il va de soi que lorsque vous matriserez parfaitement les PICs, vous pourrez vous passerdes assignations dont vous navez pas usage. Mais ceci vous permet dtre certains de ne rienoublier.Maintenant, vous vous trouvez dans la zone des macros, o quelques macros existent dj.Par exemple, les macros de passage de banques. Nous naurons pas besoin des autres dans lecadre de cet exercice;**************************************************************************; MACRO;**************************************************************************BANK0 macro ; passer en banque0bcf STATUS,RP0bcf STATUS,RP1endmBANK1 macro ; passer en banque1bsf STATUS,RP0bcf STATUS,RP1endmBANK2 macro ; passer en banque2bcf STATUS,RP0bsf STATUS,RP1endmBANK3 macro ; passer en banque3bsf STATUS,RP0bsf STATUS,RP1endmCes macros permettent de slectionner une banque particulire en positionnant les 2 bitsconcerns. Il est vident que si vous savez dans quelle banque vous vous trouvez, il nest pastoujours ncessaire de repositionner les 2 bits. Il se peut en effet que lun des 2 soit dj dansle bon tat. Nanmoins, lutilisation de cette macro ne vous cotera quune lignesupplmentaire, et limitera fortement les risques derreurs. Vous verrez dautres macros danscette maquette, nen tenez pas compte pour linstant.De plus, certaines macros que je dveloppe dans mes exercices et dans les fichiersmaquettes ont leur quivalent (ou presque) dj intgr dans MPASM. Cependant, dans cecas, leur contenu nest pas visible, cest donc une dmarche moins didactique (noubliez pasquil sagit dun cours). De toute faon, je vous parlerai de ces macros particulires.Ensuite vous trouvez les diffrentes zones demplacement RAM pour chacune desbanques, ainsi que lemplacement des 16 octets de la zone commune. Je rappelle que ces 16octets sont accessibles indpendamment de la valeur de RP0 et RP1.;************************************************************************; VARIABLES ZONE COMMUNE;************************************************************************; Zone de 16 bytes; ----------------CBLOCK 0x70 ; Dbut de la zone (0x70 0x7F)28w_temp : 1 ; Sauvegarde registre Wstatus_temp : 1 ; sauvegarde registre STATUSFSR_temp : 1 ; sauvegarde FSR (si indirect en interrupt)PCLATH_temp : 1 ; sauvegarde PCLATH (si prog>2K)ENDCDans cette zone, vous trouvez les variables de sauvegarde temporaire ncessaires lorsquevous utilisez les interruptions. Les explications concernant ces variables sont donnes dans lechapitre 5 sur les interruptions.Pour notre exemple, supprimez ces variables, nous nutiliserons pas les interruptions.Supprimez enfin tout ce qui suit les lignes suivantes, except la directive END :;***********************************************************************; DEMARRAGE SUR RESET;***********************************************************************org 0x000 ; Adresse de dpart aprs reset4.2 Cration dun programme sans saut de pageNous allons maintenant complter notre petit exercice. Noubliez pas de toujours laisser ladirective END aprs la dernire ligne de votre programme.Ajoutez maintenant les lignes suivantes, puis compilez avec Tout devrait se passersans problme.saut1nop ; ne rien fairenop ; ne rien fairegoto saut1 ; sauterEND Tapez ensuite , le curseur du simulateur vient se placer sur la ligne ladresse 0x00.Pressez ensuite plusieurs fois pour constater que votre boucle fonctionne sans problme.4.3 Premires tentatives de saut inter-pagesNous allons maintenant provoquer un saut entre 2 pages distinctes. Tout dabord, quelleest la longueur dune page ? Et bien, rappelez-vous : elle est de 2Kmots, qui est la limite des 11bits impose parlarchitecture des instructions de saut. Donc, on dbordera de la page en passant deB11111111111 B100000000000, autrement dit quand on a modification du bit 12 ou dubit 13 (bit 12 dans ce cas). Cette nouvelle adresse est ladresse 0x800. Voici donc les zonesdes diffrentes pages :Page 0 : de 0x0000 0x07FF Page 1 : de 0x0800 0x0FFF29Page 2 : de 0x1000 0x17FFPage 3 : de 0x1800 0x1FFFModifions donc notre petit programme de la faon suivante (noubliez pas la directive END , je ne lindiquerai plus) :org 0x000 ; Adresse de dpart aprs resetnop ; ne rien fairesaut1nop ; ne rien fairenop ; ne rien fairegoto saut2 ; sauterorg 0x800 ; adresse de la suite du programmesaut2nop ; ne rien fairenop ; ne rien fairegoto saut1 ; sauterLancez la compilation avec . Dans la fentre des rsultats, vous voyez apparatre 2 warnings . Les numros de lignes peuvent tre diffrents en fonction des espaces entre leslignes :Message[306] D:\DOCUME~1\LESSONS\PICS-P~2\FICHIERS\PCLATH.ASM 214 : Crossingpage boundary -- ensure page bits are set.Message[306] D:\DOCUME~1\LESSONS\PICS-P~2\FICHIERS\PCLATH.ASM 221 : Crossingpage boundary -- ensure page bits are set.Si vous vous reportez aux lignes incrimines (dans mon cas 214 et 221), vous constaterezque ces lignes correspondent aux deux instructions de saut.En fait MPASM attire votre attention sur le point suivant : les sauts incrimins traversentune limite de page, il vous demande de vrifier si les bits correspondants de PCLATH sontbien positionns. Ceci est logique, car la directive org0x800 place le saut2 en page 1,alors que le saut 1 est situ en page 0.Ne tenons pas compte de ces avertissements dans un premier temps. Tapez donc ensuite puis une succession de pour voir le droulement du programme.Que se passe-t-il ? Au lieu que linstruction goto saut2 nous envoie vers saut2 , nousnous retrouvons en fait la premire ligne du programme.Examinons ce qui sest pass :- Linstruction goto saut2 est traduite par lassembleur en goto 0x800 - Or, 0x800 comporte 12 bits, donc est tronque 11 bits, ce qui donne goto 0x00 . Eneffet 0x800 = B100000000000. Si vous enlevez le bit de poids fort, il resteB00000000000- La gestion interne du PIC ajoute ladresse les bits 3 et 4 de PCLATH, qui sont 0 .Ladresse finale est donc 0x00. En effet, ltude des 2 dernires colonnes du tableau 2-130de la page 15 du datasheet nous apprend que ce registre est toujours remis 0 aprs unreset ou une mise sous tension.- Que trouvons-nous ladresse 0x00 ? Tout simplement la ligne qui suit la directive org0x00 .Modifions encore notre programme pour voir si vous avez tout compris :Remplaons pour cela la ligneorg 0x800 ; adresse de la suite du programmeParorg 0x850 ; adresse de la suite du programmeProfitez-en pour ouvrir la fentre Special Fonction Registers du menu Window .Ceci vous permettre de suivre lvolution du registre PCL, titre dinformation.Lancez la compilation , puis faites avancer votre programme lentement en pas pas.Arriv la ligne du saut vers saut2 , pressez encore une fois . Que se passe-t-il ? Unenouvelle fentre souvre alors, intitule Program Memory Window . Cette fentrereprsente le contenu de votre mmoire programme.En effet, o donc avez-vous saut ? Appliquons de nouveau la mme mthode. Le saut adonc du avoir lieu vers ladresse 0x050, au lieu de 0x850 prvue. donc hors de notreprogramme. MPLAB ne peut donc pas pointer dans votre fichier source, il est contraintdouvrir cette nouvelle fentre.Si vous ne pointez pas sur la bonne adresse, pas de panique, MPLAB semble ne pasapprcier ce type de manuvre. Faites dfiler la fentre jusqu ladresse 0x00. Vous verrezalors la premire partie de votre programme. Remarquez que lassembleur a bien traduit le saut en goto 0x050 . Dfilez maintenantjusque ladresse 0x850. vous voyez alors la seconde partie de notre programme.314.4 Evitons le pigeNous allons encore une fois modifier notre programme en remplaant la ligneorg 0x850 ; adresse de la suite du programmeparorg 0x7FF ; adresse de la suite du programmeNous allons donc sauter juste avant la limite de la page, ce qui fait que la premireinstruction suivant ltiquette saut2 sera en page 0, tandis que la suite du programme seraen page 1. Nous nous trouvons donc au lieu de dbordement de page dun programme.Recompilons notre programme et analysons la fentre des rsultats. Nous constatons alorsquil ny a plus quun seul warning, correspondant au second saut. Ceci est logique, carltiquette saut2 est maintenant situe dans la mme page (0) que le premier goto .Faisons donc tourner notre programme en pas--pas. Il semble maintenant fonctionnertout fait correctement. Quel est donc ce mystre ?En fait, comme toujours, ce nest que pure logique. Il y a 3 phases distinguer dans lefonctionnement de ce petit bout de code.- Le premier saut (goto saut1) seffectue sans problme, puisque ladresse de destination(0x7FF) est situe dans la page 0, les bits 3 et 4 de PCLATH tant 0, ladresse dedestination obtenue est bien 0x7FF- Ensuite, en avanant en pas pas, on passe la page2. Notez en passant 2 choses. PCL estremis 0, ce qui est logique, et PCLATH voit son contenu inchang. Cest ici quil ne fautpas tomber dans le pige :32LE REGISTRE PCLATH NEST JAMAIS MODIFIE AUTOMATIQUEMENT PAR LEPROGRAMME.Cest lutilisateur seul de procder sa modification. Mais PCLATH nest utilis quepour les sauts directs, PAS pour le droulement du programme. Si vous regardez en effet leschma-bloc du 16F876, vous constatez que le compteur de programme a une capacit de 13bits, donc ne pose aucun problme pour le droulement squentiel du programme.- Ensuite, vous trouvez le saut goto saut1 . De nouveau on sattend un problme, et ilnen est rien. Pourquoi ? Et bien tout simplement, malgr le warning de MPASM quidemande de vrifier PCLATH, ce dernier est tout simplement bien configur.En effet, nous navons pas jusqu prsent modifi PCLATH, donc il pointe toujours surla page 0. Donc notre saut seffectuera bien en page0. Donc,CE NEST PAS PARCE QUE VOTRE PROGRAMME SEXECUTE DANS UNEPAGE QUE PCLATH POINTE VERS CETTE MEME PAGE. IL VOUS INCOMBE DEGERER VOUS-MEME PCLATH.Si vous avez compris ce qui prcde, vous allez tout comprendre dans le fonctionnementde PCLATH. Rassurez-vous, je vous le rappelle, ceci ne vous sera utile que pour desprogrammes dune taille suprieure 2Kmots, donc vous avez le temps de bien assimiler. Jecommence cependant par cette partie, car je reois normment de courrier de personnes quidsirent modifier un code-source crit pour un 16F876. Ces modifications entranent parfoisun dbordement de page, ce qui empche donc le programme modifi de fonctionner.4.5 Premire correction de notre exerciceRemplaons encore une fois notre ligneorg 0x7FF ; adresse de la suite du programmeparorg 0x850 ; adresse de la suite du programmeMais, cette fois, nous allons tenter deffectuer correctement nos sauts. Pour ce faire,occupons-nous dabord du premier. Nous devrons donc sauter de la page 0 vers la page1.Mais avant tout, voici un petit tableau destin vous viter lusage de la calculatricepour tablir les valeurs des bits 3 et 4 de PCLATH.Adresses de destination Page B4 B30x0000 0x07FF 0 0 00x0800 0x0FFF 1 0 10x1000 0x17FF 2 1 00x1800 0x1FFF 3 1 1Nous voyons daprs ce tableau que nous devrons positionner le bit3 de PCLATH 1pour pouvoir sauter en page1, 0x850 tant bien situ dans cette page.33Donc, avant la ligne de saut, nous devrons ajouter la mise 1 de ce bit. Notez quelanalyse du tableau des registres du datasheet nous montre que PCLATH est prsent danstoutes les banques. Donc, inutile de positionner correctement RP0 et RP1. Et oui, jen vois quiavaient dj purement ignor ce dtail (rappelez-vous, plus de la moiti des erreurs deprogrammation)bsf PCLATH , 3 ; prparer saut en page 1goto saut2 ; sauterMaintenant, occupons-nous de notre second saut. En effet, ladresse de destination vadpendre galement, COMME TOUS LES SAUTS, du contenu de PCLATH. Si nous laissonsPCLATH dans cet tat, le saut2 seffectuera en ralit vers ladresse 0x800. Aussi, avant lesaut, devrons-nous remettre PCLATH en configuration page 0 .bcf PCLATH , 3 ; prparer saut en page 0goto saut1 ; sauterCompilons le programme : toujours les 2 warnings davertissement de franchissement depages. Excutons le programme : il tourne maintenant parfaitement. Vous voyez, rien desorcier, juste de la rflexion.4.6 Evitons les warnings inutilesNous avons vu que les warnings sont bien pratiques dans ce cas prcis pour nous indiquerles sauts inter-page. Le problme, cest quune fois la solution trouve, le warning persiste.Or, dans le cas dun tout gros programme, puisquil sagit ici de programmes dpassant2Kmots, vous risquez de vous retrouver avec des dizaines de warnings de ce type.Une fois que vous aurez rgl chaque cas sparment, si vous modifiez votre programme,et que cette modification, par exemple une insertion, provoque des modifications dans lesemplacements de sauts de pages, vous serez dans lincapacit de le vrifier sans tout reprendredepuis le dbut.Autre inconvnient, si votre correction est mauvaise, vous naurez pour le vrifier aucunautre choix que de tout contrler depuis le dbut. Jai rencontr galement ce problme, et jaitrouv une astuce qui me met labri de ce type dinconvnient, car je transfre alors lecontrle des sauts de page directement MPASM.Je vais vous montrer quelle a t ma dmarche et quelle solution pratique jai trouve (denouveau, certaines macros intgres MPLAB effectuent le mme style doprations).MPASM gnre un warning de saut de page quand la page de destination est diffrente dela page dans laquelle linstruction de saut est excute. Lastuce consiste faire croire MPASM quil se trouve dans la mme page. Comment ? Tout simplement en modifiant lesadresses de destination. Je commence par expliquer directement dans le source duprogramme.Voyons notre premier saut : nous nous trouvons en page0 et nous dsirons sauter ladresse saut2 situe en page1. MPASM remplace saut2 par sa valeur et voit que cettevaleur nest pas en page0. Nous allons donc le bluffer.34Pour lui faire croire que le saut seffectue en page0, il suffit de supprimer le bit 11 deladresse, afin de ne garder que les 11 bits utiliss en ralit. Cette opration naura aucunimpact, puisque lassemblage ne conservera de toute faon que les 11 bits de poids faible. Parcontre, MPASM naura plus aucune raison de gnrer un warning.Modifions donc simplement notre lignegoto saut2 ; sauterengoto (saut2 & 0x7FF) ; sauterCompilez le tout : le premier warning a disparu, occupons-nous du second. Ici, cestexactement le contraire. MPASM constate que nous sommes en page 1 et que nous sautons enpage 0. Il suffit donc de lui faire croire que nous sautons en page1. Comment ? Toutsimplement en forant le bit 11 de ladresse 1. Ceci naura aucune consquence, puisque lassemblage, seuls les 11 bits de poids faibles seront conservs.Modifions donc simplement notre lignegoto (saut1 ) ; sauterengoto (saut1 | 0x800) ; sauterLe symbole | signifie pour lassembleur OR (voir premire partie, oprationsboolennes). Il est obtenu en maintenant la touche de droite enfonce et en tapant latouche pour le clavier belge, et pour le clavier franais (pas sur le pav numrique).Compilons tout a, plus de warning, excutons le programme : tout fonctionne bien.Mais tout ceci nest gure pratique, ni facile mettre en place. De plus le risque derreurdevient trs grand au fur et mesure de laugmentation de taille de notre programme.En effet, si diffrentes insertions dplacent par exemple notre saut2 vers la page2, et bienlinstruction de saut plac en page1 ne gnrera plus aucun warning. Ceci est logique, car onaura dfinitivement fait croire MPASM que notre appel seffectue lintrieur de la page0.Nous navons donc rsolu notre problme que de manire temporaire.Faites lessai si vous ntes pas convaincu. Modifiez org 0x850 en org 1000 , etvous constaterez que vous navez pas de warning pour linstruction goto saut2 , alors quele saut est erron.4.7 Dmonstration pratique de lutilit des macrosPour que ce soit pratique, reste implmenter ceci dans des macros. Je vous ai donc misau point une petit macro qui va faire tout le travail pour vous.GOTOX macro ADRESSE ; saut inter-pagelocal BIT4 = (ADRESSE & 0x1000) ; voir bit 12local BIT3 = (ADRESSE & 0x0800) ; voir bit 11local ICI ; adresse couranteICIlocal PICI = (ICI+2 & 0x1800) ; page du saut35IF BIT3 ; si page 1 ou 3bsf PCLATH , 3 ; b3 de PCLATH = 1ELSE ; sinonbcfPCLATH , 3 ; b3 de PCLATH = 0ENDIFIF BIT4 ; si page 2 ou 3bsfPCLATH , 4 ; b4 de PCLATH = 1ELSE ; sinonbcfPCLATH , 4 ; b4 de PCLATH = 0ENDIFgoto (ADRESSE & 0x7FF | PICI); adresse simuleendmHoul ! Jen vois qui paniquent. Restez cool, jexplique ligne par ligne, cest toutsimple. Vous allez commencer voir le vritable intrt des macros. Plus quun simpletraitement de texte, cest, cette fois, un vritable instrument anti-erreurs.GOTOX macro ADRESSE ; saut inter-pageIci, tout simplement on dclare la macro. Cette macro se nomme donc GOTOX, et ellereoit en argument ADRESSE, qui est ladresse de destination du saut. Donc, pour un sautinter-page vers ladresse saut2 , on utilisera donc : GOTOX saut2 local BIT4 = (ADRESSE & 0x1000) ; voir bit 12Dans cette ligne, nous trouvons dabord la directive LOCAL , qui signifie que la valeursera recalcule chaque appel de la macro. La valeur BIT4 sera donc diffrente chaquefois que vous appelerez GOTOX . Cest logique.Vient derrire le calcul de BIT4 . On pourra dire que BIT4 est gal ladresse dedestination AND 0x1000, soit B1000000000000 . Donc, BIT4 vaudra 0 si ladresse dedestination tient sur 12 bits, donc infrieure 0x1000, donc en page 0 ou 1. Cest dire si lebit 4 de PCLATH devra tre mis 0 pour sauter. Ladresse de destination a dans ce casson bit 12 0 .local BIT3 = (ADRESSE & 0x0800) ; voir bit 11Strictement identique pour une adresse qui comporte son bit 11 0. Donc, ceci nouspermet de savoir si ladresse de destination se situe ou non en page 1 et 3. Reportez-vous autableau chapitre 4.5local ICI ; adresse couranteICIIci, nous dclarons simplement une tiquette locale. Cette dclaration est suivie parltiquette en elle-mme, en premire colonne, comme il se doit. Ceci nous permet de savoiro, et plus prcisment dans quelle page, la macro GOTOX a t appele. La directive local est indispensable, car si on appelle plusieurs fois la macro GOTOX , ICI sera chaque fois un endroit diffrent.local PICI = (ICI+2 & 0x1800) ; page du saut36Bon, ici que va-t-on faire ? Et bien tout simplement dterminer la page dans laquelle setrouve notre macro. En effet, nous avons vu que pour berner les warnings de MPASM, il fautconnatre la page dans laquelle on se trouve au moment de lappel.Donc, on commence par ajouter 2 ladresse courante. Pourquoi ? Tout simplement parceque ce qui importe, cest ladresse du goto . Or, notre macro va soccuper galementautomatiquement des bits 3 et 4 de PCLATH, et ceci, bien videmment, avant le goto enquestion. Donc, ladresse de notre goto est ladresse actuelle incrmente de 2, puisque 2instructions le prcderont.Ensuite, on trouve un AND avec 0x1800, ce qui a pour effet dliminer ladresse encours et de conserver son adresse de page. Donc, lissue de ceci, PICI vaudra 0x000,0x800, 0x1000, ou 0x1800. IF BIT3 ; si page 1 ou 3Ceci signifie tout simplement que la ou les lignes suivantes seront assembles SI la valeurde BIT3 existe, donc si BIT3 est diffrent de 0 , donc si on doit sauter en page 1 ou enpage 3.bsfPCLATH , 3 ; b3 de PCLATH = 1Dans ce cas, MPASM crera automatiquement cette ligne, cest dire que le bit3 dePCLATH sera mis automatiquement 1.ELSE ; sinonbcf PCLATH , 3 ; b3 de PCLATH = 0Tout simplement : sinon (donc si BIT3 = 0), MPASM crira automatiquement cettedernire ligne, donc le bit3 de PCLATH sera mis automatiquement 0.ENDIFCeci indique la fin du test prcdent.IF BIT4 ; si page 2 ou 3bsf PCLATH , 4 ; b4 de PCLATH = 1ELSE ; sinonbcf PCLATH , 4 ; b4 de PCLATH = 0ENDIFEt bien, ici, cest strictement identique, mais concernera le bit4 de PCLATH. Cette macrovous permet donc de sauter automatiquement de et vers nimporte laquelle des 4 pages sansplus vous soucier de rien. Avouez que cest rudement pratique.goto (ADRESSE & 0x7FF | PICI) ; adresse simuleCeci, cest la fameuse ligne, un peu amliore, que vous avez utilise dans lexempleprcdent. Cest cette ligne qui va berner MPASM en lui faisant croire que vous sautezdans la page actuelle.37La premire opration (ADRESSE & 0x7FF) permet de conserver ladresse code sur 11bits, tandis que la seconde ( | PICI ) ajoute en fait ladresse de base de la page courante.Il ne reste plus qu modifier notre programme principal.org 0x000 ; Adresse de dpart aprs resetsaut1nop ; ne rien fairenop ; ne rien faireGOTOX saut2 ; sauterorg 0x850 ; adresse de la suite du programmesaut2nop ; ne rien fairenop ; ne rien faireGOTOX saut1 ; sauter en page 0END ; directive fin de programmeCompilez le tout : plus de warning. Excutez : tout ce passe sans problme. Allez jeter unil sur le code obtenu laide de cette macro dans la fentre window-> program memory .Amusez-vous galement modifier les directives org pour essayer toutes sortes decombinaisons de pages. Vous verrez qu chaque fois MPASM compile correctement votreprogramme. Plus de warning, plus de soucis.Il ne vous reste plus quune chose retenir : en cas de warning concernant les sauts depage, remplacez linstruction goto par la macro GOTOX pour les lignes concernes, etle problme sera automatiquement rsolu. Nest-ce pas utile, les macros ?Attention, ne tombez cependant pas dans le pige grossier suivant. Par exemple, neremplacez pas :btfss STATUS , Zgoto plusloinparbtfss STATUS , ZGOTOX plusloinPourquoi ? Tout simplement parce que btfss permet de sauter linstruction suivante, et queGOTOX est une macro qui contient 3 instructions. Donc, le test ne fonctionnerait pas.En effet, ce ne serait pas goto qui suivrait btfss, mais bsf ou bcf PCLATH,3. Il vous faudradonc, soit excuter votre test dune autre faon, soit placer les modifications de PCLATHavant le test.Je vous ai cris 2 macros spares directement utilisables avec ce genre de configuration. : PCLAX (modifie PCLATH) et GOTSX (saut simple, sans modification de PCLATH).En fait, PCLAX suivi de GOTSX est lquivalent de GOTOX.Lavantage est de sparer le saut de linitialisation de PCLATH.PCLAX macro ADRESSE ; positionne PCLATH pour; les sauts sans le sautlocal BIT4 = (ADRESSE & 0x1000) ; voir bit 12local BIT3 = (ADRESSE & 0x0800) ; voir bit 1138IF BIT3 ; si page 1 ou 3bsf PCLATH , 3 ; b3 de PCLATH = 1ELSE ; sinonbcf PCLATH , 3 ; b3 de PCLATH = 0ENDIFIF BIT4 ; si page 2 ou 3bsf PCLATH , 4 ; b4 de PCLATH = 1ELSE ; sinonbcf PCLATH , 4 ; b4 de PCLATH = 0ENDIFEndmGOTSX macro ADRESSE ; saut inter-page sans; slection de PCLATHlocal ICI ; adresse courantelocal PICI = (ICI & 0x1800) ; page du sautICIgoto (ADRESSE & 0x7FF | PICI) ; adresse simuleendmEn fait, il sagit tout simplement de la macro GOTOX scinde pour pouvoir treutilise facilement avec les tests. Si on reprend notre exemple, on pourra remplacerbtfss STATUS , Zgoto plusloinparPCLAX pluloin ; configure le registre PCLATH pour le sautbtfss STATUS , Z ; effectue le test (nimporte lequel)GOTSX plusloin ; saute avec leurre de warning (une seule ; instruction)Pour information, la macro intgre PAGESEL est quivalente notre macro PCLAX.PAGESEL pluloin ; configure le registre PCLATH pour le sautbtfss STATUS , Z ; effectue le test (nimporte lequel)GOTSX plusloin ; saute avec leurre de warning (une seule ; instruction)4.8 Les sous-programmes inter-pagesMaintenant, vous allez me dire. Les sauts de type goto , cest bien joli, mais que sepasse-t-il pour les sous-routines ?Et bien, identiquement la mme chose, un dtail prs. Une sous-routine se termine parune instruction de retour (return, retlw). Si vous regardez le schma-bloc, vous verrez que latotalit du compteur de programme, cest dire les 13 bits, a t conserve dans la pile.Donc, vous devez positionner PCLATH pour lappel de sous-routine, exactement commepour un saut, par contre, vous ne devez pas vous en proccuper concernant le retour.Ceci est heureux, car sinon il serait difficile dappeler la mme sous-routine depuis 2 pagesdiffrentes.39Par contre, comme votre programme revient sa page dappel aprs le return, vous devrezrepositionner correctement PCLATH pour viter quun saut ordinaire ne prenne encompte votre modification de PCLATH.Le retour seffectuera donc toujours correctement quelles que soient les pages dappel etdemplacement de la sous-routine. Reste seulement tablir pour les call , les macroscorrespondant aux goto . Les voici :CALLX macro ADRESSE ; call inter-pagelocal BIT4 = (ADRESSE & 0x1000) ; voir bit 12local BIT3 = (ADRESSE & 0x0800) ; voir bit 11local ICI ; adresse couranteICIlocal PICI = (ICI+2 & 0x1800) ; page du sautIF BIT3 ; si page 1 ou 3bsf PCLATH , 3 ; b3 de PCLATH = 1ELSE ; sinonbcf PCLATH , 3 ; b3 de PCLATH = 0ENDIFIF BIT4 ; si page 2 ou 3bsf PCLATH , 4 ; b4 de PCLATH = 1ELSE ; sinonbcf PCLATH , 4 ; b4 de PCLATH = 0ENDIFcall (ADRESSE & 0x7FF | PICI) ; adresse simulelocal BIT4 = ((ICI+5)& 0x1000) ; voir bit 12local BIT3 = ((ICI+5) & 0x0800) ; voir bit 11IF BIT3 ; si page 1 ou 3bsf PCLATH , 3 ; b3 de PCLATH = 1ELSE ; sinonbcf PCLATH , 3 ; b3 de PCLATH = 0ENDIFIF BIT4 ; si page 2 ou 3bsf PCLATH , 4 ; b4 de PCLATH = 1ELSE ; sinonbcf PCLATH , 4 ; b4 de PCLATH = 0ENDIFendmCALLSX macro ADRESSE ; sous-routine inter-page sans; slection de PCLATHlocal ICI ; adresse courantelocal PICI = (ICI+2 & 0x1800) ; page du sautICIcall (ADRESSE & 0x7FF | PICI) ; adresse simuleendmLa macro PCLAX tant identique, inutile de lcrire deux fois.Le calcul (ICI+5) se justifie par le raisonnement suivant :Il importe de repositionner PCLATH pour quil pointe dans la page courante, afin dviterquun simple goto ou un call lintrieur de la page ne provoque en ralit un sautdans la page prcdemment pointe par PCLATH modifi par la macro. Tout ceci est ralisautomatiquement par notre macro CALLX40La macro va gnrer 5 lignes de code, et donc aprs son excution, le programmecontinuera ladresse du dbut de la macro (ICI) incrmente de 5.Vous navez donc plus qu placer votre macro la place de votre call habituel.Etiquette_pagex ; on est en page xCALLX etiquette_pagey ; appel de sous-routine en page ySuite du programme principal ; poursuite, avec PCLATH pointant ; automatiquement sur la page xetiquette_pagey ; sous-routine en page yici commence la sous-routine ; traitement normalreturn ; retour normal de sous-routineVous pouvez galement pointer sur la bonne page en utilisant PCLAX, et en indiquantladresse courante comme adresse de destination.PCLAX etiquette_pagey ; pointer sur page yCALLSX etiquette_pagey ; appel de sous-routine en page yici ; tiquette pour dterminer pagecourantePCLAX ici ; repointer sur page couranteSuite du programmeOu, enfin, en utilisant la macro intgre de MPASM.PAGESEL etiquette_pagey ; pointer sur page yCALLSX etiquette_pagey ; appel de sous-routine en page yici ; tiquette pour dterminer pagecourantePAGESEL ici ; repointer sur page couranteSuite du programmeVous voyez que CALLX est tout de mme plus pratique, avec bien moins de risquesdoubli.Jai t particulirement long dans ce chapitre, mais cette notion tait assez dlicate aborder, et il me semblait dommageable de vouloir utiliser un processeur plus puissant et seretrouver bloqu le jour on dsire crer un programme consquent.A la fin de ce chapitre, je place dans le rpertoire fichiers , le programme pclath.asm , qui contient lexercice termin.41Notes : 42Notes : 435. Les sources dinterruptionsJai choisi dnumrer les diffrentes sources dinterruption du 16F876, car nous allons enavoir besoin dans les chapitres suivants. De plus, nous allons pouvoir mettre en vidence quelques diffrences avec le 16F84, ce qui place ce chapitre dans la suite logique duprcdent.5.1 EnumrationVoici un tableau rcapitulatif des 13 interruptions disponibles sur le 16F876. Notez que le16F877/4 dispose dun port parallle supplmentaire qui lui autorise une source dinterruptionen sus. Sur ces composants, nous aurons donc 14 sources dinterruption.Dclencheur Flag Registre Adr PEIE Enable Registre AdrTimer 0 T0IF INTCON 0x0B NON T0IE INTCON 0x0BPin RB0 / INT INTF INTCON 0x0B NON INTE INTCON 0x0BCh. RB4/RB7 RBIF INTCON 0x0B NON RBIE INTCON 0x0BConvert. A/D ADIF PIR1 0x0C OUI ADIE PIE1 0x8CRx USART RCIF PIR1 0x0C OUI RCIE PIE1 0x8CTx USART TXIF PIR1 0x0C OUI TXIE PIE1 0x8CPort srie SSP SSPIF PIR1 0x0C OUI SSPIE PIE1 0x8CModule CCP1 CCP1IF PIR1 0x0C OUI CCP1IE PIE1 0x8CModule CCP2 CCP2IF PIR2 0x0D OUI CCP2IE PIE2 0x8DTimer 1 TMR1IF PIR1 0x0C OUI TMR1IE PIE1 0x8CTimer 2 TMR2IF PIR1 0x0C OUI TMR2IE PIE1 0x8C EEPROM EEIF PIR2 0x0D OUI EEIE PIE2 0x8DSSP mode I2C BCLIF PIR2 0x0D OUI BCLIE PIE2 0x8DPort parallle PSPIF PIR1 0x0C OUI PSPIE PIE1 0x8CQuelques mots sur ce tableau.En jaune vous avez les 3 interruptions dont le traitement est identique celui du 16F84 etque nous avons vues dans la premire partie.En vert, vous voyez linterruption dcriture eeprom dont le traitement a t modifi. Cetteinterruption tait dj prsente sur le 16F84, mais son traitement est ici lgrement diffrent.En bleu ce sont les nouvelles interruptions utilisables sur le 16F876.La ligne grise se rfre linterruption supplmentaire du 16F877 ou 16F874.Lexplication des diffrentes colonnes, de gauche droite :- Dclencheur : Evnement ou fonction qui est la source de linterruption- Flag : Bit qui se trouve positionn lorsque lvnement survient44- Registre : Registre auquel le flag appartient- Adr : Adresse de ce registre (tous en banque0, avec INTCON prsent dans les 4 banques)- PEIE : Indique si le positionnement de PEIE du registre INTCON joue un rle. Cest cause du OUI dans la ligne EEPROM que le traitement de cette interruption est icilgrement diffrente du 16F84.- Enable : nom du bit qui permet dautoriser ou non linterruption- Registre : Registre qui contient ce bit- Adr : adresse de ce registre (tous en banque1, avec INTCON dans les 4 banques)5.2 Le registre INTCON et les interruptions priphriquesCommenons donc par ce que nous connaissons, et pour faire simple, comparons lecontenu de ce registre avec celui du 16F84, histoire davoir une ide des modifications.INTCON pour le 16F84GIE EEIE T0IE INTE RBIE T0IF INTF RBIFINTCON pour le 16F87xGIE PEIE T0IE INTE RBIE T0IF INTF RBIFEn fait, nous constatons que tout est rest identique au 16F84, except EEIE, devenuPEIE. Nous allons expliquer pourquoi.En fait, Microchip a choisi une mthode un peu particulire, et a scind les interruptionsentre ce que nous pourrions appeler les interruptions primaires et les interruptionssecondaires, appeles ici interruptions priphriques.Pour raliser ceci, on a donc ajout au registre INTCON un second bit de validation gnrale des interruptions qui ne concerne que les interruptions priphriques.Comme il ny avait pas la place dans ce registre, le bit EEIE concernant lcriture eneeprom, et considr comme secondaire , a t dplac vers le registre PIR2.5.2.1 Mise en service des interruptions primairesDes constatations prcdentes, nous pouvons dire que nous disposons de 3 interruptionsprimaires. Cest dire utilisables exactement de la mme manire que pour le 16F84. Pourmettre en service une de ces interruptions, vous devez donc :1) Valider le bit concernant cette interruption2) Valider le bit GIE (General interrupt enable) qui met toutes les interruptions choisies enserviceDonc, ce niveau vous ne devriez avoir aucun problme, rien de chang.455.2.2 Mise en service des interruptions priphriques Nous avons vu que les interruptions priphriques sont tributaires du bit de validationgnrale des interruptions priphriques PEIE. Voici donc les 3 tapes ncessaires la miseen service dune telle interruption :1) Validation du bit concernant linterruption dans le registre concern (PIE1 ou PIE2)2) Validation du bit PEIE (PEripheral Interrupt Enable bit) du registre INTCON3) Validation du bit GIE qui met toutes les interruptions en service.Notez donc que la mise en service de PEIE ne vous dispense pas linitialisation du bitGIE, qui reste de toute faon prioritaire.Cette architecture vous permet donc de couper toutes les interruptions dun coup(effacement de GIE) ou de couper toutes les interruptions priphriques en une seuleopration (effacement de PEIE) tout en conservant les interruptions primaires. Ceci vousdonne davantage de souplesse dans le traitement des interruptions, mais complique un petitpeu le traitement.5.3 Les registres PIE1, PIE2, PIR1 et PIR2Vous avez vu que ces composants disposent de plus de sources dinterruptions que ne peuten grer le registre INTCON. Donc, les autorisations dinterruptions vont se trouver dansdautres registres. Ces registres sont PIE1 et PIE2. Les flags correspondants se trouvent quant eux dans les registres PIR1 et PIR2.Voici le nom de chaque bit de ces registresRegistre Adresse B7 B6 B5 B4 B3 B2 B1 B0PIE1 0x8C PSPIE ADIE RCIE TXIE SSPIE CCP1IE TMR2IE TMR1IEPIR1 0x0C PSPIF ADIF RCIF TXIF SSPIF CCP1IF TMR2IF TMR1IFPIE2 0x8D N.I. Rserv N.I. EEIE BCLIE N.I. N.I. CCP2IEPIR2 0x0D N.I. Rserv N.I. EEIF BCLIF N.I. N.I. CCP2IFVous remarquerez que les 2 registres dautorisations (PIE1 et PIE2) se trouvent en banque1, tandis que les registres de flags (PIR1 et PIR2) se trouvent en banque 0.Remarquez aussi quil y a quelques bits non implments, qui donneront toujours 0 sils sont lus, mais aussi 2 bits rservs quil est impratif de maintenir 0 afin deconserver toute compatibilit future.Les bits des registres PIEx permettent dautoriser les interruptions correspondantes, maisrappelez-vous que ces bits ne sont oprationnels que si le bit PEIE du registre INTCON estmis 1. Dans le cas contraire, toutes ces interruptions sont invalides.Pour quune des interruptions dcrites ici soit oprationnelle, je rappelle quil faut donc latriple condition suivante :- Le bit GIE du registre INTCON doit tre mis 146- Le bit PEIE du registre INTCON doit tre mis 1- Le bit correspondant linterruption concerne (registre PIE1 ou PIE2) doit tre mis 1.Voici maintenant le rle de chacun des bits dautorisation dinterruption, sachant quun bit 1 autorise linterruption correspondante :PIE1PSPIE Lecture/criture sur le port PSP // (concerne uniquement les 16F877/16F874)ADIE Conversion analogique/digitaleRCIE Rception dun caractre sur le port srie USARTTXIE Emission dun caractre sur le port srie USARTSSPIE Communication sur le port srie synchrone SSPCCP1IE Evnement sur compare/capture registre 1TMR2IE Correspondance de valeurs pour le timer TMR2TMR1IE Dbordement du timer TMR1PIE2EEIE Ecriture dans lEEPROMBCLIE Collision de bus pour le port srie synchrone I2CCCP2IE Evnement sur compare/capture registre 2Et maintenant, les flags correspondants. Attention, certains flags ncessitent uneexplication assez pousse, explications qui seront reprises dans les chapitres correspondantaux vnements concerns.PIR1PSPIF Lecture ou criture termine sur le port // du 16F877ADIF Fin de la conversion analogique/digitaleRCIF Le buffer de rception de lUSART est plein (lecture seule)TXIF Le buffer dmission de lUSART est vide (lecture seule)SSPIF Fin de lvnement dpendant du mode de fonctionnement comme suit :Mode SPI Un caractre a t envoy ou reuMode I2C esclave Un caractre a t envoy ou reuMode I2C matre Un caractre a t envoy ou reuou fin de la squence start ou fin de la squence stop ou fin de la squence restart ou fin de la squence acknowledge ou start dtect durant IDLE (multimatre)ou stop dtect durant IDLE (multimatre)CCP1IF Evnement compare/capture 1 dtect suivant mode :Mode capture : capture de la valeur TMR1 raliseMode compare : La valeur de TMR1 atteint la valeur programmeTMR2IF La valeur de TMR2 atteint la valeur programmeTMR1IF Dbordement du timer TMR1PIR2EEIF Fin dcriture de la valeur en EEPROMBCLIF Collision de bus, quand le SSP est configur en matre I2CCCP2IF Evnement compare/capture 2 dtect suivant le mode :Mode capture : capture du TMR1 ralise47Mode compare : La valeur de TMR1 atteint la valeur programme5.3 Etude de la routine dinterruption du fichier maquette .Voici le contenu de la routine dinterruption principale contenue dans le fichier m16f876.asm . Cette routine contient tous les tests qui permettent daiguiller lesinterruptions vers la bonne sous-routine. Dans la majorit des cas, vous naurez plus quvous occuper de remplir correctement les sous-routines concernes.Vous pourrez galement supprimer les tests qui ne vous sont pas ncessaires, et,ventuellement inverser leur ordre afin de dfinir des priorits. Soyez dans ce cas attentifs aubon usage du bit PEIE.;**************************************************************************; ROUTINE INTERRUPTION;**************************************************************************;sauvegarder registres;---------------------org 0x004 ; adresse d'interruptionmovwf w_temp ; sauver registre Wswapf STATUS , w ; swap status avec rsultat dans wmovwf status_temp ; sauver status swappmovf FSR , w ; charger FSRmovwf FSR_temp ; sauvegarder FSRmovf PCLATH , w ; charger PCLATHmovwf PCLATH_temp ; le sauverclrf PCLATH ; on est en page 0BANK0 ; passer en banque0Cette premire partie effectue la sauvegarde des diffrents registres. Nous allons dcrireici leur utilit et leurs impratifs. w_temp est la sauvegarde du registre de travail W . Ce registre va tre utilis pourla sauvegarde des autres registres. De fait, cest le premier qui doit tre sauv.Hors, si vous sauvez le registre W avant dtre autoris modifier STATUS , quilui nest pas encore sauv, vous ne pouvez donc pas changer de banque. En effet, lechangement de banque ncessite la modification de RP0 et RP1 du registre STATUS .Donc, si vous suivez toujours, au moment de linterruption, vous ne pouvez pas savoircomment sont configurs RP0 et RP1, donc vous ne savez pas vers quelle banque vouspointez. Il est donc de ce fait impratif de sauvegarder W dans la zone RAM commune.REMARQUE IMPORTANTELes 16F873 et 16F874 ne disposent pas dune zone de banque commune. Comme vous nepouvez pas prvoir dans quelle banque vous allez sauver W, vous devez rserver la mmeadresse relative pour w_temp la fois dans la banque 0 et dans la banque 1. Ensuite, vouseffacerez le registre STATUS pour sauver les autres registres dans la banque 0 (par exemple)movwf w_temp ; Sauver W dans la banque 0 ou dans la 1swapf STATUS,W ; charger STATUS swapp48clrf STATUS ; pointer sur la banque 0movwf status_temp ; sauver STATUS en banque 0La suite tant identique, except quil est inutile dcrire la macro BANK0 La dclaration sera du type :CBLOCK 0x20 ; Dbut de la zone (0x20 0x7F)w_temp : 1 ; sauvegarde de W en banque 0....ENDCCBLOCK 0xA0 ; Dbut de la zone (0xA0 0xFF)w_temp2 : 1 ; sauvegarde de w en banque 1 (mme position imprative; que pour w_temp. Dans ce cas, premire position.. ; ltiquette w_temp2 ne sera pas utilise, mais; lemplacement est rserv en pratiquant de la sorte...ENDCRevenons notre 16F876 : Pour status_temp vous pourriez par contre commencer parcharger status dans w, puis procder un changement de banque avant de le sauver. Sasauvegarde en banque 0 nest donc pas imprative. Vous pouvez donc placer status_tempdans nimporte quelle banque. Ceci est galement vrai pour les registres suivants FSR_temp sauvegarde le registre FSR dadressage indirect. Ce registre ne devratre imprativement sauv que si la routine dinterruption risque de perturber ce niveau leprogramme principal. Il faut donc 2 conditions ceci :- Il faut que le programme principal utilise ladressage indirect, sinon, aucune raison desauvegarder FSR.- ET il faut que la routine dinterruption utilise ladressage indirect, car sinon le registreFSR ne serait pas modifi et il ny aurait donc aucune raison de le sauvegarder.Notez que rien ne vous empche de sauvegarder FSR dans tous les cas pour des raisons defacilit et de prcaution. Il ne vous en cotera que 2 mots de programme et quelquesnanosecondes de temps dexcution. A vous de voir si ces surplus sont nuisibles ou non votre programme. La mme remarque est valable pour la sauvegarde de PCLATH.Pour terminer, voyons donc la sauvegarde du registre PCLATH dans PCLATH_temp :cette sauvegarde na de sens bien entendu que si la routine dinterruption modifie PCLATH. En gnral, cette modification risque dintervenir si votre programme est dune taillesuprieure 2Kmots. Dans ce cas, en effet, le programme principal a de grandes chances demodifier PCLATH pour effectuer des sauts corrects, et vous serez alors contraint de remettreles bits 3 et 4 de PCLATH 0.Ceci pour viter quun saut dans votre routine dinterruption ne sorte de celle-ci. Notezque si vous supprimez la sauvegarde de PCLATH dans votre routine dinterruption et quevous utilisez PCLATH pour un autre usage (tableau), vous devrez alors galement supprimerla ligne clrf PCLATH qui modifie ce registre dans la routine dinterruption. Dans ce cas49particulier, vous ntes pas oblig de sauver PCLATH, mais vous ne pouvez pas le modifiernon plus.On termine ce dbut par la macro BANK0, qui permet de pointer sur la banque 0 en casdadressage direct.Voyons maintenant la suite de notre routine :; Interruption TMR0; -----------------btfsc INTCON , T0IE ; tester si interrupt timer autorisebtfss INTCON , T0IF ; oui, tester si interrupt timer en coursgoto intsw1 ; non test suivantcall inttmr0 ; oui, traiter interrupt tmr0bcf INTCON , T0IF ; effacer flag interrupt tmr0goto restorereg ; et fin d'interruptionIl sagit bien videmment ici de vrifier si cest le timer0 qui a dclenchlinterruption.On commence par tester si linterruption a t autorise, en vrifiant le positionnementde T0IE. Vous allez me dire : drle de procdure, quel est lintrt ?Et bien, vous ne devez jamais perdre de vue que les flags sont positionns quel quesoit ltat du bit de validation correspondant. Vous avez donc 3 cas possibles :1) Vous nutilisez pas les interruptions tmr0 dans votre programme : dans ce cas, vouspouvez tout simplement effacer ces 6 lignes de code.2) Vous utilisez les interruptions tmr0 dans votre programme. Cependant, le bit T0IE reste enservice tout au long de votre programme. Il est donc inutile de le tester. Vous pouvez donceffacer la premire ligne.3) Votre programme utilise les interruptions du timer0, mais pas tout le temps, de plus vousutilisez dautres sources dinterruption. Donc, dans votre programme principal, vouscoupez par moment T0IE afin de ne pas tre interrompu par le dbordement du timer0pendant certaines priodes. Dans ce cas, si votre timer0 dborde, le flag T0IF serapositionn , mais linterruption correspondante ne sera pas gnre. Si par malheur seproduit alors une interruption due un autre vnement que vous aviez autoris, et quevous ne testiez pas T0IE, alors vous seriez induit en erreur lors du test de T0IF. Celui-citant positionn, bien que linterruption ne soit pas due au dbordement de tmr0. Vousdevez donc laisser le test de T0IE.La seconde ligne, qui vrifie si le bit T0IF est positionn, ne sera donc excut que si laligne prcdente a dfini que T0IE est bien positionn. Donc, Si T0IF et T0IE sont tout deuxpositionns, on saute la ligne call inttmr0 . Dans le cas contraire, on saute, via gotointsw1 , au test suivant pour continuer la recherche de la source de linterruption.La ligne call inttmr0 permet dappeler la sous-routine inttmr0 , dans laquelle vouspourrez placer le code de traitement de votre routine dinterruption timer0.50IMPORTANT : la routine dinterruption, telle quelle est crite ici, utilise des sous-routines. Donc, si vous utilisez les interruptions, et sachant que vous disposez de 8 niveauxsur la pile (voir premire partie), il vous restera donc : 8 1 (pour les interruptions) 1 (pourlappel de sous-routine dans la routine dinterruption) = 6 imbrications de sous-routinespossibles.Si vous avez besoin dun niveau supplmentaire, il vous suffira tout simplement deremplacer le call intttmr0 par un goto inttmr0 . Dans lancienne sous-routine inttmr0 , vous devrez donc remplacer le return par un goto restorereg , aprs avoirajout la ligne bcf INTCON , T0IF juste avant. Vous devrez bien entendu procder de lamme faon pour chaque interruption utilise. Ceci vous conomise donc un niveau de pile,par labsence de sous-routines dans la routine dinterruption. Mais il est quant mme peufrquent dans un programme bien structur de dpasser cette limite. Ne vous inquitez doncpas de ceci pour linstant.La ligne jaune, bcf INTCON,T0IF permet deffacer le flag aprs avoir trait laroutine. Noubliez pas que ces flags, pour la plupart (nous verrons les exceptions), neseffacent pas automatiquement. Si vous oubliez de les effacer, ds que le programme sortirade linterruption, il y entrera de nouveau, et ce indfiniment ( moins que le watchdog ne soiten service). Mais gure besoin de vous inquiter, cette routine prend tout ceci en charge pourvous. Ce quil importe, cest davoir compris, nul besoin de rinventer la roue .La ligne verte, goto restorereg , quant elle, permet, une fois le traitement de votreinterruption effectu, de sortir directement de la routine dinterruption, aprs avoir restaur lesdiffrents registres.Notez que la suppression de cette ligne permet de conserver les tests suivants, donc detraiter en une seule fois plusieurs interruptions simultanes . Cest vous que le choixappartient en fonction du cas particulier de votre programme.Il vous est galement possible dinverser lordre des diffrents tests. Ceci vous amne tablir une hirarchie de priorits dans le cas dinterruptions multiples simultanes . Lapremire teste sera dans ce cas la premire traite.Noubliez pas dans ce cas de bien prendre en compte le test de PEIE, ainsi que de grercorrectement les tiquettes.Ensuite, nous trouvons :; Interruption RB0/INT; --------------------intsw1btfsc INTCON , INTE ; tester si interrupt RB0 autorisebtfss INTCON , INTF ; oui, tester si interrupt RB0 en coursgoto intsw2 ; non sauter au test suivantcall intrb0 ; oui, traiter interrupt RB0bcf INTCON , INTF ; effacer flag interupt RB0goto restorereg ; et fin d'interruptionCe test namne aucun commentaire particulier, et fonctionne de faon identique aupremier cas cit.51; interruption RB4/RB7; --------------------intsw2btfsc INTCON , RBIE ; tester si interrupt RB4/7 autorisebtfss INTCON , RBIF ; oui, tester si interrupt RB4/7 en coursgoto intsw3 ; non sautercall intrb4 ; oui, traiter interrupt RB4/7bcf INTCON , RBIF ; effacer flag interupt RB4/7goto restorereg ; et fin d'interruptATTENTION : noubliez pas (cours-part1) que dans la routine intrb4 detraitement de cette interruption, vous devrez imprativement lire le PORTB, afindannuler la condition de positionnement de RBIF, et ainsi permettre son reset lors duretour.Vient ensuite :intsw3btfss INTCON , PEIE ; tester interruption priphrique autorisegoto restorereg ; non, fin d'interruptionCeci amne un petit commentaire. En effet, vous avez deux faons darriver ce point devotre routine dinterruption :1) Vous avez conserv les lignes goto restorereg . Dans ce cas, puisque vous arrivez cepoint du programme, cest que forcment vous ntes pas pass par une des interruptionsprcdentes. En effet, aprs excution dune interruption prcdente, cette partie aurait tsaute via la ligne en question.Donc, dans ce cas, les vnements prcdents nont pas t les dclencheurs delinterruption. Il sagit donc forcment dune interruption priphrique, donc, il est inutile detester PEIE, car il est forcment 1 .2) Vous avez supprim les lignes goto restorereg . Dans ce cas, il est possible quuneinterruption prcdente ait eu lieu. Dans ce cas, il vous reste deux sous-solutions :- Si le bit PEIE reste inchang durant toute lexcution du programme, vous pouvezsupprimer ce test.- Si vous modifiez le bit PEIE durant lexcution de votre programme, vous devez laissercette ligne, pour les mmes raisons que celles voques pour le test de T0IE.Naturellement, si vous nutilisez dans votre programme aucune interruption priphrique,inutile de laisser ces lignes.Notez que si vous ne touchez rien, tout fonctionnera trs bien dans tous les cas (saufcertains programmes spcifiques). Je vous conseille donc, dans le doute, de laisser cetteroutine telle quelle, si vous ntes pas quelques microsecondes prs.Ensuite, nous trouvons les tests des interruptions priphriques52; Interruption convertisseur A/D; ------------------------------bsf STATUS , RP0 ; slectionner banque1btfss PIE1 , ADIE ; tester si interrupt autorisegoto intsw4 ; non sauterbcf STATUS , RP0 ; oui, slectionner banque0btfss PIR1 , ADIF ; tester si interrupt en coursgoto intsw4 ; non sautercall intad ; oui, traiter interruptbcf PIR1 , ADIF ; effacer flag interuptgoto restorereg ; et fin d'interrupt; Interruption rception USART; ----------------------------intsw4bsf STATUS , RP0 ; slectionner banque1btfss PIE1 , RCIE ; tester si interrupt autorisegoto intsw5 ; non sauterbcf STATUS , RP0 ; oui, slectionner banque0btfss PIR1 , RCIF ; oui, tester si interrupt en coursgoto intsw5 ; non sautercall intrc ; oui, traiter interrupt; LE FLAG NE DOIT PAS ETRE REMIS A 0goto restorereg ; et fin d'interrupt; Interruption transmission USART; -------------------------------intsw5bsf STATUS , RP0 ; slectionner banque1btfss PIE1 , TXIE ; tester si interrupt autorisegoto intsw6 ; non sauterbcf STATUS , RP0 ; oui, slectionner banque0btfss PIR1 , TXIF ; oui, tester si interrupt en coursgoto intsw6 ; non sautercall inttx ; oui, traiter interrupt; LE FLAG NE DOIT PAS ETRE REMIS A 0goto restorereg ; et fin d'interrupt; Interruption SSP; ----------------intsw6bsf STATUS , RP0 ; slectionner banque1btfss PIE1 , SSPIE ; tester si interrupt autorisegoto intsw7 ; non sauterbcf STATUS , RP0 ; oui, slectionner banque0btfss PIR1 , SSPIF ; oui, tester si interrupt en coursgoto intsw7 ; non sautercall intssp ; oui, traiter interruptbcf PIR1 , SSPIF ; effacer flag interuptgoto restorereg ; et fin d'interrupt; Interruption CCP1; -----------------intsw7bsf STATUS , RP0 ; slectionner banque1btfss PIE1 , CCP1IE ; tester si interrupt autorisegoto intsw8 ; non sauterbcf STATUS , RP0 ; oui, slectionner banque0btfss PIR1 , CCP1IF ; oui, tester si interrupt en coursgoto intsw8 ; non sautercall intccp1 ; oui, traiter interrupt53bcf PIR1 , CCP1IF ; effacer flag interuptgoto restorereg ; et fin d'interrupt; Interruption TMR2; -----------------intsw8bsf STATUS , RP0 ; slectionner banque1btfss PIE1 , TMR2IE ; tester si interrupt autorisegoto intsw9 ; non sauterbcf STATUS , RP0 ; oui, slectionner banque0btfss PIR1 , TMR2IF ; oui, tester si interrupt en coursgoto intsw9 ; non sautercall inttmr2 ; oui, traiter interruptbcf PIR1 , TMR2IF ; effacer flag interuptgoto restorereg ; et fin d'interrupt; Interruption TMR1; -----------------intsw9bsf STATUS , RP0 ; slectionner banque1btfss PIE1 , TMR1IE ; tester si interrupt autorisegoto intswA ; non sauterbcf STATUS , RP0 ; oui, slectionner banque0btfss PIR1 , TMR1IF ; oui, tester si interrupt en coursgoto intswA ; non sautercall inttmr1 ; oui, traiter interruptbcf PIR1 , TMR1IF ; effacer flag interuptgoto restorereg ; et fin d'interrupt; Interruption EEPROM; -------------------intswAbsf STATUS , RP0 ; slectionner banque1btfss PIE2 , EEIE ; tester si interrupt autorisegoto intswB ; non sauterbcf STATUS , RP0 ; oui, slectionner banque0btfss PIR2 , EEIF ; oui, tester si interrupt en coursgoto intswB ; non sautercall inteprom ; oui, traiter interruptbcf PIR2 , EEIF ; effacer flag interuptgoto restorereg ; et fin d'interrupt; Interruption COLLISION; ----------------------intswBbsf STATUS , RP0 ; slectionner banque1btfss PIE2 , BCLIE ; tester si interrupt autorisegoto intswC ; non sauterbcf STATUS , RP0 ; oui, slectionner banque0btfss PIR2 , BCLIF ; oui, tester si interrupt en coursgoto intswC ; non sautercall intbc ; oui, traiter interruptbcf PIR2 , BCLIF ; effacer flag interuptgoto restorereg ; et fin d'interrupt; interruption CCP2; -----------------intswCbcf STATUS , RP0 ; slectionner banque0call intccp2 ; traiter interruptbcfPIR2 , CCP2IF ; effacer flag interupt54Trois remarques :- Comme cest prcis dans le fichier source, les flags RCIF et TXIF ne doivent pas treeffacs manuellement. Vous ne le pouvez dailleurs pas, il sont en lecture seule. Nousverrons plus tard que ces flags sont en fait remis 0 automatiquement lors de la lecture ducontenu du registre de rception ou de lcriture du registre dmission.- Si vous conservez les lignes goto restorereg dans votre routine dinterruption, alorsvous narriverez votre dernier test dinterruption que si tous les autres ont chou. Dansce cas, inutile donc de tester la dernire interruption, puisque cest forcment elle qui aprovoqu lvnement. Par contre, si vous dcidez de supprimer ces lignes, il vous faudraalors ajouter un test supplmentaire sur la dernire interruption, sans quoi elle seraitexcute chaque fois.- Il est inutile de conserver les tests des interruptions que vous nutilisez pas dans votreprogramme. Donc, de fait, inutile galement de conserver des interruptions qui neconcernent pas votre type de processeur. Cest pour a que cette routine nintgre paslinterruption du port parallle. Si vous utilisez un 16F877, par exemple, libre vous delajouter. Je lai dailleurs fait pour vous dans le fichier m16F877.asm .Pour terminer, nous aurons :;restaurer registres;-------------------restoreregmovf PCLATH_temp , w ; recharger ancien PCLATHmovwf PCLATH ; le restaurermovf FSR_temp , w ; charger FSR sauvmovwf FSR ; restaurer FSRswapf status_temp , w ; swap ancien status, rsultat dans wmovwf STATUS ; restaurer statusswapf w_temp , f ; Inversion L et H de l'ancien W ; sans modifier Zswapf w_temp , w ; Rinversion de L et H dans W; W restaur sans modifier statusretfie ; return from interruptCe bout de code restaure les registres sauvegards prcdemment. Aussi, si vous avezsupprim des sauvegardes, noubliez pas de supprimez galement les restaurations.La dernire ligne sort de la routine dinterruption, et replace le bit GIE 1.5.4 Cas particulier des 873 et 874Si vous tes attentif, vous aurez remarqu une diffrence fondamentale entrelorganisation mmoire dun 16F873 ou 16F874 et celle dun 16F876 ou 16F877. En effet, lesdeux premiers cits ne possdent que deux banques de mmoire RAM utilisateur et surtout nedisposent pas dune zone dite commune .55Ds lors, si vous utilisez la routine dinterruption prcdemment propose, vous nepourrez jamais savoir dans quelle banque se trouveront sauvs les diffrents registres, puisquevous ignorerez dans quel tat se trouve le registre STATUS.La premire astuce consiste donc forcer la slection de banque sur la banque 0 avantde sauvegarder les principaux registres. Nous ajoutons donc simplement un clrf STATUS lendroit appropri, cest--dire APRES, videmment avoir lu lancienne valeur de STATUSafin de pouvoir la restaurer ultrieurement. Ca donne :;sauvegarder registres;---------------------org 0x004 ; adresse d'interruptionmovwf w_temp ; sauver registre Wswapf STATUS,w ; swap status avec rsultat dans wclrf STATUS ; force la banque 0 (pas de commune sur 873/874)movwf status_temp ; sauver status swappmovf FSR , w ; charger FSRmovwf FSR_temp ; sauvegarder FSRmovf PCLATH , w ; charger PCLATHmovwf PCLATH_temp ; le sauverclrf PCLATH ; on est en page 0Moyennant ceci, les registres STATUS, FSR, et PCLATH seront maintenant sauvs enbanque 0, ce qui ne ncessite plus lutilisation de la zone commune (vous pouvez videmmentutiliser cette astuce sur le 16F876/877 pour conomiser de la zone commune.Subsiste cependant la sauvegarde de W, qui ne peut tre faite aprs la lecture deSTATUS, puisque a modifierait videmment le contenu de W. Moralit, il est impossible deprvoir si w_temp se trouvera en banque 0 ou en banque 1. La solution est donc de rserverdeux emplacements au mme offset en banque 0 et en banque 1 pour la sauvegarde de W.Ceci rsoud notre problme, moyennant le sacrifice dun octet en RAM.;banque 0CBLOCK0x20 ; Dbut de la zone (0x20 0x6F)w_temp : 1 ; sauvegarde de W durant interrupt; attention, offset identique en banque 1status_temp : 1 ; sauvegarde de status durant interruptFSR_temp : 1 ; sauvegarde de FSR durant interruptPCLATH_temp : 1 ; sauvegarde de PCLATH durant interruptENDC ; Fin de la zone; banque 1CBLOCK0xA0 ; Dbut de la zone (0xA0 0xEF)w_temp_2 : 1 ; second emplacement de sauvegarde de W; attention, mme offset que w_tempENDC ; Fin de la zoneVous trouverez les fichiers maquettes correspondants dans votre rpertoire fichiers .56Notes : 576. Mise en uvre et configuration minimaleEt oui, la thorie, cest bien beau et indispensable, mais si vous dsirez programmer des16F876, cest bien entendu pour raliser des montages pratiques.Nous allons donc commencer ici la partie pratique de lutilisation de ce nouveau PIC pourvous. Et tout dabord :6.1 Le matriel ncessaireJai tout dabord pens crer une platine dexprimentation universelle, avecprogrammateur intgr. Jai cependant renonc au dernier moment pour les raisons suivantes :- Cette seconde partie sadresse ceux qui ont dj expriment le 16F84, et donc qui nedsirent pas forcment utiliser toutes les possibilits du 16F876, mais dsirent utiliser uneapplication particulire.- Il mest apparu trs difficile de crer une carte qui permette dexploiter lintgralit desfonctions des 16F87x, sauf utiliser jumpers, switches mcaniques et lectroniques, quiauraient rendu la carte trs lourde mettre en uvre, et trs onreuse.- Tous les magasines spcialiss proposent des platines dexprimentation dusage gnral.Chacun pourra donc trouver la solution qui lui convient le mieux.- Tout le monde na pas envie de se lancer dans la ralisation dune carte assez complexe,ncessitant la ralisation dun circuit imprimPour toutes ces raisons, et tant donn que cette seconde partie peut tre utilise commeun manuel de rfrence, jai choisi dutiliser de petites platines dexprimentation simplespouvant tre ralises sur une platine dessais. Ceci permet de disposer de fonctionsautonomes claires, et permet au lecteur de raliser une petite platine centre sur le sujet quilintresse.Le matriel minimum pour raliser la carte de base est donc :- 1 PIC 16F876 20 en botier DIP- 1 alimentation de 5V continus. Une simple pile plate de 4.5V peut faire laffaire.- 2 supports 28 broches, largeur 0.3 tulipe , ou 2 supports 14 pins tulipe - 1 Quartz 20 MHz- 2 condensateurs non polariss 15 pF- 1 platine dexprimentation trous, comme pour la premire partie du coursA ceci viendront sajouter les diffrents composants ncessaires la ralisation desdiffrentes applications.Au sujet des 2 supports, je vous conseille en effet dinsrer votre PIC dans un dessupports, et de le laisser insrer tout au long de vos exprimentations. Il vous suffira58dinsrer ce support dans le support de la platine dexprimentation, comme si PIC +support se comportaient comme un composant unique. Ainsi, vous pargnerez les pins devotre PIC.6.2 Le schma minimumVoici les schmas minimum permettant de faire fonctionner notre 16F876 ou notre16F87759Vous pouvez constater que la mise en uvre du 16F876 (et du 16F877) est similaire celle du 16F84.6.3 Les particularits lectriquesVous constatez que sur le schma concernant le 16F876, vous avez 2 connexions VSS qui sont relies la masse. En fait, en interne, ces pins sont interconnectes. La prsence deces 2 pins sexplique pour une raison dquilibrage des courants et dquipotentialit. Lescourants vhiculs dans le pic sont loin dtre ngligeables du fait des nombreusesentres/sorties disponibles.Le constructeur a donc dcid de rpartir les courants en plaant 2 pins pourlalimentation VSS, bien videmment, pour les mmes raisons, ces pins sont situes de part etdautre du PIC, et en positions relativement centrales.Sur le 16F877, cette procdure a t galement tendue VDD, car encore plusdentres/sorties sont disponibles.Notez que ces PICs fonctionneront si vous dcidez de ne connecter quune seule dechacune des pins, mais dans ce cas vous vous exposerez une destruction des composantslors des fortes charges, suite au non respect de la rpartition des courants internes et/ou desfonctionnements erratiques ds un dfaut dquipotentialit.Pour le reste nous noterons lhabituelle connexion de MCLR au +5V, cette pin tantutilise pour effectuer un reset du composant en cas de connexion la masse.Nous trouvons galement le quartz, qui pourra tre remplac par un rsonateur ou par unsimple rseau RC, de la mme manire que pour le 16F84.Les condensateurs sur le quartz, du fait de la frquence plus importante du quartz utilisici (20MHz) seront de valeur infrieure celle utilise pour le 16F84 ( 4Mhz), soit 15pF.La tolrance sur ces composants permet dutiliser dautres valeurs, mais mon expriencema montr que cest cette valeur qui permet le fonctionnement le plus fiable cettefrquence. Certains composants ont en effet refus de fonctionner avec des valeurs de 27pFavec les quartz qui taient en ma possession. Aucun na refuser de fonctionner avec la valeurde 15pF.Il se peut cependant que vous rencontriez un comportement diffrent (peu probable), dufait de la provenance de votre propre quartz. En cas de doute, demandez la documentation decelui-ci afin dadapter les valeurs, ou essayez dautres valeurs de faon exprimentale.Si vous avez besoin dun reset hardware , le montage suivant est le plus simple et leplus pratique. Le condensateur est facultatif, sauf en environnement perturb.6061Notes : 62Notes : 637. Migration du 16F84 vers le 16F8767.1 Similitudes et diffrences avec le 16F84Nous allons directement prciser quelles sont les similitudes entre le 16F84 et le 16F876,afin de vous montrer quels chapitres de la premire partie vous pouvez vous rapporter sansproblme.En fait, cest trs simple : pratiquement tout ce que vous avez vu sur le 16F84 estidentique pour le 16F876. Ceci inclus :- le jeu dinstructions- les modes dadressage- Lutilisation des sous-programmes- le timer 0- Le mcanisme gnral des interruptions- Les niveaux dimbrication des sous-programmes- Les limitations dues aux largeurs de bus internes (utilisation de RP0 par exemple)- Lutilisation du watchdogEn contrepartie, et en sus des fonctions supplmentaires, vous noterez les diffrencessuivantes :- La sparation des registres en 4 banque implique la modification des adresses de ceux-ci- Lutilisation de 4 banques implique lutilisation du bit RP1 en plus du bit RP0- Lutilisation de 4 banques implique lutilisation du bit IRP pour ladressage indirect- Lutilisation dun programme de plus de 2K implique lutilisation de PCLATH- Laugmentation des possibilits modifie lorganisation des registres dinterruption- Linitialisation pralable du registre ADCON1 est ncessaire pour lutilisation du PORTA- Les variables (zones RAM disponibles) ne se trouvent pas aux mmes emplacements7.2 Conversion dun programme crit pour le 16F84 vers le 16F876En consquence des points prcdents, il vous apparat donc que les programmes critspour 16F84 peuvent tre assez facilement ports vers le 16F876.Mais attention, comme les adresses ne sont plus identiques, vous devrez imprativementrecompiler le fichier source dans MPLAB. Je vais vous expliquer un peu plus loin commentprocder en partant dun exemple pratique.La premire chose importante retenir est donc que :ON NE PEUT PAS PLACER TEL QUEL DANS UN 16F876 UN FICHIER .HEX ASSEMBLE POUR UN 16F84.647.3 Causes de non fonctionnementSi le programme transfr ne fonctionne plus, il faudra lexaminer avec attention. En effet,il se peut que vous rencontriez un des cas suivants, surtout si le programme a t ralis sanstenir compte des recommandations que je fais dans la premire partie.1) Vrifiez si des adresses ne sont pas utilises directement dans le programmeExemple :movf 0x0C , w ; charger W avec la variable adresse 0x0CSolution : il vous faut dclarer la variable dans la zone des variables, et utiliser sontiquette dans le programmemovf mavariable,w ; la variable mavariable est dclare en zone 0x202) Vrifiez les assignations et dfinitions dadressesExemple :mavariable EQU 0x0CSolution : modifiez lassignation ou la dfinition de faon la rendre compatible avec le16F876Exemple :mavariable EQU 0x020Ou mieux, dclarez la variable de faon classique dans la zone des variables.3) Vrifiez si des bits non utiliss dans le 16F84 nont pas t utiliss en tant que bitslibres pour le programmeurExemple :bsf PCLATH , 4 ; mettre flag perso 1Solution : dclarez une variable supplmentaire contenant le flag et utilisez celui-ci dansle programmeExemple :bsf mesflags , 1 ; mettre flag perso 14) Vrifiez si le programme nutilise pas une astuce concernant les adresses .65Exemple :movlw 0x10 ; pointer sur 0x10movwf FSR ; placer adresse dans pointeurmovf INDF , w ; charger une variablebsf FSR , 2 ; pointer sur 0x14movwf INDF ; copier la valeurSolution : ceci est un peu plus dlicat. La procdure utilise ci-dessus utilise une astuce enmanipulant directement les bits du pointeur FSR. Il est vident que si vous changez lesadresses des variables, ceci va entraner un dysfonctionnement du programme.Dans ce cas vous devrez rorganiser vos variables en consquence, ou modifier le corpsdu programme pour tenir compte des nouvelles dispositions.5) Si les entres/sorties sur PORTA fonctionnent sur simulateur mais pas en pratiqueVous avez probablement omis dinitialiser le registre ADCON1. Notez que le fichiermaquette inclus cette gestion. Vous navez donc pas vous en inquiter pour l instant.Evidemment, on considre que les frquences de fonctionnement des 2 PICs sontidentiques.7.3 Conversion dun exemple pratiqueAfin de mettre ceci en pratique, nous allons migrer notre programme led_Tmr1 pour le porter sur 16F876. Afin de vous faciliter la vie, le fichier original, cr pour le16F84, est fourni sous la rfrence Led16f84.asm.Il existe plusieurs mthodes pour raliser cette opration. La premire qui vient lespritest de crer un nouveau projet et de modifier le fichier original. Cette mthode prsentecependant un trs fort taux de probabilit derreur, surtout pour les gros projets.Je vais donc vous prsenter une mthode plus fiable.7.3.1 Ralisation du montageAfin de pouvoir tester notre exercice, nous allons raliser la platine dexprimentationcorrespondante.Il suffit dans ce cas de raliser le schma de base prsent au chapitre 6 et dy connecterune LED sur RA2. Ceci ne devrait vous poser aucun problme.667.3.2 Cration du projetNous allons maintenant crer notre premier vrai projet 16F876. Pour ceci, commencez pardupliquer le fichier m16F876.asm , et renommez-le Led_tmr0.asm .Ensuite excutez les tapes suivantes :- Lancez MPLAB- Cliquez new project - Choisir le nom Led_tmr0.pjt en pointant dans le rpertoire des fichiers dexemple.- Dans la fentre qui souvre, cliquez change ct de development mode - Choisissez PIC16F876 dans le menu droulant processor - Cochez la case MPLAB SIM Simulator - Cliquez OK - Une fentre vous indique quil ny a pas de fichier hex . Cliquez OK - Confirmez par OK les diffrentes fentres davertissement.- Dans la fentre edit project reste ouverte, cliquez sur add node - Choisissez votre fichier Led_tmr0.asm - Cliquez OK , la fentre project edit se ferme, lcran est vide.Nous allons maintenant ouvrir le fichier assembler et lancien fichier.- Cliquez file->open et ouvrez le fichier Led_tmr0.asm - Cliquez file->open et ouvrez le fichier Led16F84.asm .Maintenant, vous disposez des 2 fichiers sur votre cran, mais rappelez-vous :Seul le ou les fichiers qui sont prciss dans les nuds ( node ) du projet sont pris encompte au moment de lassemblage. Egalement ceux prciss comme inclus dans ces mmesfichiers (directive include ).Par consquent, 2 fichiers sont bien affichs lcran, mais le fichier Led_16F84.asm na aucune influence sur lassemblage, car il ne fait pas partie du nud du projet, et nest pasnon plus utilis par une directive dinclusion dans le seul fichier nud de notre projet(Led_tmr0.asm).677.3.3 La mthode conseilleVous laurez dj compris, la mthode que je trouve la plus sre, est deffectuer des copier/coller partir du fichier source vers le fichier cible. Ceci prsente lavantage de nerien oublier durant les modifications de code.Commenons donc par remplir nos zones de commentaires.;**************************************************************************; Ce fichier est la base de dpart pour une programmation avec *; le PIC 16F876. Il contient les informations de base pour *; dmarrer. *; *;**************************************************************************; *; NOM: Led_tmr0 *; Date: 07/04/2002 *; Version: 1.0 *; Circuit: platine d'exprimentation *; Auteur: Bigonoff *; *;**************************************************************************; *; Fichier requis: P16F876.inc *; *; *; *;**************************************************************************; Exercice de migration d'un programme de 16F84 vers le 16F876. *; Clignotement d'une LED une frquence de 1Hz en utilisant les *; interruptions du timer0. *; *;**************************************************************************Ensuite, intressons-nous notre fichier Led_16F84.asm , et regardons dans lordre :Les 2 premires lignes, savoir :LIST p=16F84 ; Dfinition de processeur#include ; Dfinitions des constantesOnt dj leur quivalent dans le fichier Led-tmr0.asm sous la forme de :LIST p=16F876 ; Dfinition de processeur#include ; fichier includeNous navons donc pas nous en occuper. Pour rappel, il sagit de la dclaration du typede processeur, et du nom du fichier contenant les assignations correspondantes inclure.Ensuite, nous trouvons la directive _CONFIG qui dfinit le mode de fonctionnement duprocesseur. Nous devons transcrire cette ligne, et non la copier simplement, tant donn queleur structure est diffrente sur les 2 PICs.Au niveau du fichier pour le 16F84, nous trouvons :__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC68Nous notons alors le mode de fonctionnement choisi, savoir :- Pas de protection programme en lecture- Pas de watchdog- Mise en service du reset retard la mise sous tension- Oscillateur en mode HS.Nous allons ensuite transposer ce mode de fonctionnement au fichier du 16F876, encompltant les nouveaux modes en fonction de nos besoins. Pour vous faciliter la vie, lescommentaires des diffrents modes de fonctionnement font partie du fichier maquette, doncgalement, par consquence, de votre fichier Led_tmr0.asm .Prenons la ligne par dfaut, et voyons ce que nous devons changer :__CONFIG _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_OFF & _CPD_OFF & _LVP_OFF &_BODEN_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSCVoyons donc les bits dans lordre :CP_OFFAbsence de protection du programme en lecture. Cest ce que nous voulions.DEBUG_OFF Pas de mode debug en service : conservons ce paramtre, puisque nous nutilisons pas defonction supplmentaire celles prvues dans le 16F84. WRT_ENABLE_OFFA conserver pour les mmes raisonsCPD_OFFIdemLVP_OFFDe mmeBODEN_OFFNe pas se tracasser de tout ceci pour linstantPWRTE_ONLaissons ce paramtre comme pour le 16F84, cest dire dans sa valeur actuelleWDT_OFFPas de watchdog, tout comme pour lexercice sur le 16F84HS_OSCAvec un quartz 20MHz, le tableau nous donne cette valeur pour loscillateur.Vous constatez donc que la mthode est simple :- Vous appliquez les paramtres du source du 16F84 au fichier du 16F876- Vous laissez les autres bits dans leur configuration par dfaut- Si vous vouliez ajouter des options ou des modifications, vous corrigez alorsventuellement la directive _CONFIG en consquence.Donc, pour notre cas particulier, il ny a rien changer dans notre ligne de directive.Passons donc aux assignations systme.Du ct du 16F84, nous avions :69OPTIONVAL EQUH'0087' ; Valeur registre option ; Rsistance pull-up OFF ; Prscaler timer 256INTERMASK EQUH'00A0' ; Interruptions sur tmr0Vous constaterez en regardant les datasheets, que le registre OPTION a strictement lamme configuration pour les 2 PICs, donc vous pouvez dans un premier temps recopier lesmmes valeurs pour le fichier 16F876 de votre exercice.Par contre, INTERMASK initialisait les interruptions, au niveau du registre INTCON.Nous avons vu quil y a des changements au niveau des interruptions, donc, pour viter touteerreur, nous allons reprendre bit par bit les valeurs en question.Ici, nous avons donc, comme document et vrifi, une mise en service des interruptionsdu timer0. Dans ce cas-ci, vous constaterez que la valeur pour les 2 fichiers sera identique.Dans le fichier 16F876, jai opt pour une valeur sous forme binaire, pour faciliter lacomprhension. Donc, pour mettre les interruptions timer0 en service, il suffit de positionnerle bit 5 1 . Notez quil est inutile de soccuper de GIE, car il sera trait dans la routinedinitialisation.Les 2 lignes correspondantes pour notre fichier Led_tmr0.asm deviennent donc(pensez toujours adapter vos commentaires) :; REGISTRE OPTION_REG (configuration); -----------------------------------OPTIONVAL EQUB'10000111'; RBPU b7 : 1= Rsistance rappel +5V hors service; PSA b3 : 0= Assignation prdiviseur sur Tmr0; PS2/PS0 b2/b0 valeur du prdiviseur; 111 = 1/128 1/256; REGISTRE INTCON (contrle interruptions standard); -------------------------------------------------INTCONVAL EQUB'00100000'; GIE b7 : masque autorisation gnrale interrupt ; ne pas mettre ce bit 1 ici; T0IE b5 : masque interruption tmr0Du ct du fichier 16f876, vous noterez galement les assignations pour les valeurs desregistres PIE1 et PIE2. Comme aucune des interruptions utilises dans ces registres ne sontutilises ici, vous pouvez les laisser tels quels. Nous verrons galement plus loin la fin decette zone.Ensuite, nous trouvons notre zone des dfinitions :;*********************************************************************; DEFINE *;*********************************************************************#DEFINE LED PORTA,2 ; LEDNous supprimons donc lexemple fourni dans le fichier 16F876 :70; exemple; -------#DEFINE LED1 PORTB,1 ; LED de sortie 1et nous le remplaons par la vritable dfinition de notre fichier source :#DEFINE LED PORTA,2 ; LEDNous accderons la led par une fonction xor , nous dfinirons donc la valeur qui vamodifier la led :#DEFINE LEDMASK B00000100 valeur pour le masque de la ledNous arrivons aux zones de macros, zones quil ne faut pas modifier, les macros 16F84 et16F876 tant diffrentes. Seules les macros personnelles peuvent tre ajoutes aprs avoirventuellement t modifies. Nous navons pas de telles macros dans cet exercice.Nous voici la zone des variables. Le 16F876 contient plus de banques que le 16F84. Mais,comme le programme provient dun 16F84, ces banques sont forcment inutilises.Cependant, les adresses des zones sont diffrentes, il ne faudra donc recopier que lecontenu des zones, et non leur dclaration.Du ct 16F84, nous avions :;*********************************************************************; DECLARATIONS DE VARIABLES *;*********************************************************************CBLOCK 0x00C ; dbut de la zone variablesw_temp :1 ; Sauvegarde du registre Wstatus_temp : 1 ; Sauvegarde du registre STATUScmpt : 1 ; compteur de passage ENDC ; Fin de la zoneIci, il nous faut oprer avec une grande attention. En effet, nous disposons de plusieursbanques de variables dans le 16F876. On pourrait tre tent de tout mettre dans la banque0,mais, en cas de modifications ou dajouts ultrieurs, il faut prvoir que certaines variables,principalement celles utilises pour la sauvegarde des registres au niveau des interruptions,doivent tre sauves dans la zone commune.La premire tape consiste donc ne pas tenir compte de ces variables, car elles sont djdclares dans le fichier 16F876. Les autres variables pourront en gnral tre copies dans labanque0.Dans ce cas, nous constatons que les variables w_temp et status_temp sont les variables desauvegarde dj dclares. Nous ne nous en occupons donc pas.La seule variable propre au programme est la variable cmpt. Nous copions donc sa dclarationdans la banque0.Ceci nous donne donc, au niveau de la banque 0, et aprs avoir supprim les lignesdexemples :71;**************************************************************************; VARIABLES BANQUE 0 *;**************************************************************************; Zone de 80 bytes; ----------------CBLOCK 0x20 ; Dbut de la zone (0x20 0x6F)cmpt : 1 ; compteur de passage ENDC ; Fin de la zone Quant la banque commune, elle conserve les dclarations des variables de sauvegarde.Les autres banques tant inutilises dans notre exemple pourront donc tre supprimes desdclarations.;**************************************************************************; VARIABLES ZONE COMMUNE *;**************************************************************************; Zone de 16 bytes; ----------------CBLOCK 0x70 ; Dbut de la zone (0x70 0x7F)w_temp : 1 ; Sauvegarde registre Wstatus_temp : 1 ; sauvegarde registre STATUSFSR_temp : 1 ; sauvegarde FSR (si indirect en interrupt)PCLATH_temp : 1 ; sauvegarde PCLATH (si prog>2K)ENDCNous trouvons maintenant la routine dinterruption principale. Cette routine dpend dutype de PIC utilis, nous ny touchons donc pas pour linstant. Vous allez voir que cettemaquette va donc une nouvelle fois vous simplifier la vie.Vous trouvez ensuite le code correspondant la routine dinterruption du timer0.;**********************************************************************; INTERRUPTION TIMER 0 *;**********************************************************************inttimerdecfsz cmpt , f ; dcrmenter compteur de passagesreturn ; pas 0, on ne fait rienmovlw LEDMASK ; slectionner bit inverserxorwf PORTA , f ; inverser LEDmovlw 7 ; pour 7 nouveaux passagesmovwf cmpt ; dans compteur de passagesreturn ; fin d'interruption timerPuisque la gestion principale et les switches vers les sous-routines dinterruption fontpartie de votre maquette, vous navez donc plus qu copier tout ce qui suit ltiquette inttimer de votre fichier 16F84 dans lemplacement prvu de votre fichier 16F876. Cecinous donne :;**************************************************************************; INTERRUPTION TIMER 0 *;**************************************************************************inttmr0decfsz cmpt , f ; dcrmenter compteur de passagesreturn ; pas 0, on ne fait rienmovlw b'00000100' ; slectionner bit inverserxorwf PORTA , f ; inverser LEDmovlw 7 ; pour 7 nouveaux passages72movwf cmpt ; dans compteur de passagesreturn ; fin d'interruption timerComme il ny a pas dautres interruptions traites, voici donc termine la partieinterruption. Nest-ce pas simple ? Bien sr, il reste plein de code inutile, mais le but de cetexercice nest pas loptimisation, mais la comprhension des mcanismes de conversion. Unefois lexercice termin, il vous sera loisible, titre dexercice personnel, doptimiser le sourceobtenu. En attendant, voyons la suite.Nous en sommes maintenant la routine dinitialisation. Pour notre 16F84, nous avions :;*********************************************************************; INITIALISATIONS *;*********************************************************************initclrf PORTA ; Sorties portA 0clrf PORTB ; sorties portB 0BANK1 ; passer banque1clrf EEADR ; permet de diminuer la consommationmovlw OPTIONVAL ; charger masquemovwf OPTION_REG ; initialiser registre option; Effacer RAM; ------------movlw 0x0c ; initialisation pointeurmovwf FSR ; pointeur d'adressage indirectinit1clrf INDF ; effacer ramincf FSR,f ; pointer sur suivantbtfss FSR,6 ; tester si fin zone atteinte (>=40)goto init1 ; non, bouclerbtfss FSR,4 ; tester si fin zone atteinte (>=50)goto init1 ; non, boucler; initialiser ports; -----------------bcfLED ; passer LED en sortieBANK0 ; passer banque0movlw INTERMASK ; masque interruptionmovwf INTCON ; charger interrupt control; initialisations variables; -------------------------movlw 7 ; charger 7movwf cmpt ; initialiser compteur de passagesgoto start ; sauter programme principalNous devons distinguer les diffrentes parties de cette tape. La premire partie est grede nouveau par notre fichier maquette. Inutile de sen proccuper. Il en va de mme pourleffacement de la zone RAM. Notez que notre fichier maquette nefface que la zone RAM dela banque0. Si vous souhaitez effacer les autres banques, vous dajouter le code ncessaire.Ce ne sera cependant pas ncessaire ici. Les lignes non surlignes reprsentent les tapesprises en charge par la routine dinitialisation standard, celles en vert sont des lignesspcifiques au programme.73Nous voyons donc quil nous suffit dajouter la configuration des entres/sorties etlinitialisation de notre compteur pour terminer notre routine dinitialisation.Vous constatez que notre routine dinitialisation 16F876 inclus les initialisations desentres/sorties, en faisant rfrence des assignations. En effet, nous trouvons :init; initialisation PORTS (banque 0 et 1); ------------------------------------BANK0 ; slectionner banque0clrf PORTA ; Sorties PORTA 0clrf PORTB ; sorties PORTB 0clrf PORTC ; sorties PORTC 0bsf STATUS,RP0 ; passer en banque1movlw B'00000110' ; PORTA en mode digitalmovwf ADCON1 ; criture dans contrle A/Dmovlw DIRPORTA ; Direction PORTAmovwf TRISA ; criture dans registre directionmovlw DIRPORTB ; Direction PORTBmovwf TRISB ; criture dans registre directionmovlw DIRPORTC ; Direction PORTCmovwf TRISC ; criture dans registre directionVous constatez que les directions des PORTS sont inclus dans les assignationsDIRPORTx, assignations qui sont dclares dans la zone des assignations systme :; DIRECTION DES PORTS I/O; -----------------------DIRPORTA EQUB'00111111' ; Direction PORTA (1=entre)DIRPORTB EQUB'11111111' ; Direction PORTBDIRPORTC EQUB'11111111' ; Direction PORTCIl nous suffit donc de transposer notre initialisation bsf LED qui place le RA2 en sortiedirectement dans la zone des assignations systme.Nous modifierons donc la ligne concerne en :DIRPORTA EQUB'00111011' ; RA2 en sortieRestent les lignes :movlw 7 ; charger 7movwf cmpt ; initialiser compteur de passagesPour travailler proprement, nous dclarons la valeur 7 dans une assignation, au niveaude la zone des define par exemple :;**************************************************************************; DEFINE *;**************************************************************************#DEFINE LED PORTA,2 ; LED de sortie#DEFINE CMPTVAL 7 ; valeur de recharge du compteurNotez que nous pouvions galement crire :CMPTVAL EQU 774Qui revient strictement au mme dans ce cas.Nous placerons donc la ligne dinitialisation du compteur dans notre routinedinitialisation, en utilisant notre assignation (ou dfinition). La routine dinitialisation devientdonc :;**************************************************************************; INITIALISATIONS *;**************************************************************************init; initialisation PORTS (banque 0 et 1); ------------------------------------BANK0 ; slectionner banque0clrf PORTA ; Sorties PORTA 0clrf PORTB ; sorties PORTB 0clrf PORTC ; sorties PORTC 0bsf STATUS,RP0 ; passer en banque1movlw ADCONVAL ; PORTA en mode digital/analogiquemovwf ADCON1 ; criture dans contrle A/Dmovlw DIRPORTA ; Direction PORTAmovwf TRISA ; criture dans registre directionmovlw DIRPORTB ; Direction PORTBmovwf TRISB ; criture dans registre directionmovlw DIRPORTC ; Direction PORTCmovwf TRISC ; criture dans registre direction; Registre d'options (banque 1); -----------------------------movlw OPTIONVAL ; charger masquemovwf OPTION_REG ; initialiser registre option; registres interruptions (banque 1); ----------------------------------movlw INTCONVAL ; charger valeur registre interruptionmovwf INTCON ; initialiser interruptionsmovlw PIE1VAL ; Initialiser registremovwf PIE1 ; interruptions priphriques 1movlw PIE2VAL ; initialiser registremovwf PIE2 ; interruptions priphriques 2; Effacer RAM banque 0; ---------------------bcf STATUS,RP0 ; slectionner banque 0movlw 0x20 ; initialisation pointeurmovwf FSR ; d'adressage indirectinit1clrf INDF ; effacer ramincf FSR,f ; pointer sur suivantbtfss FSR,7 ; tester si fin zone atteinte (>7F)goto init1 ; non, boucler; initialiser variable; --------------------movlw CMPTVAL ; charger valeur d'initialisationmovwf cmpt ; initialiser compteur de passages; autoriser interruptions (banque 0); ----------------------------------clrf PIR1 ; effacer flags 1clrf PIR2 ; effacer flags 275bsf INTCON,GIE ; valider interruptionsgoto start ; programme principalLes lignes surlignes en jaune introduisent correspondent notre initialisation du PORTA.Ces lignes sont inchanges, la modification intervenant dans la zone des assignations systme.Les lignes surlignes en vert correspondent linitialisation du compteur suivant le define dclar prcdemment.Cette mthode prsente lavantage de pouvoir changer de valeur sans devoir recherchertoutes les occurrences dans le programme, au risque den oublier une. Comme nous avonsanalys notre programme, nous savons que cette valeur est galement utilise dans la routinedinterruption du timer 0 :movlw 7 ; pour 7 nouveaux passagesDonc, nous modifions galement cette ligne en utilisant notre dfinition :movlw CMPTVAL ; pour CMPTVAL nouveaux passagesAinsi, toute modification de la valeur de recharge du compteur ne ncessitera que lditionde lassignation. Ceci vite doublier des valeurs en chemin.Arrivs ce stade, il ne nous reste plus que notre programme principal :;*********************************************************************; PROGRAMME PRINCIPAL *;*********************************************************************startgoto start ; bouclerENDQuil nous suffit de recopier tel quel vers notre fichier 16F876. Attention cependant ceque la directive END figure bien en fin de programme.Lancez lassemblage en pressant . Si vous ne vous tes pas tromps, lassemblagedevrait se drouler sans problme. Le rapport contenant, comme dhabitude les warnings des registres situs dans des banques diffrentes de 0.A ce stade, vous pouvez alors fermer votre fichier Led_16F84 , vous nen aurez plusbesoin. Reste dans la fentre de MPLAB uniquement votre fichier Led_tmr0.asm .Programmez votre PIC16F876 avec le fichier Led_tmr0.hex obtenu et testez le rsultat survotre platine dexprimentation.Lancez lalimentation, vous constatez, si vous ne vous tes pas tromp que la LEDclignote, mais une frquence bien plus leve quun clignotement par seconde.Si vous examinez le programme, vous constaterez que cest logique, puisque la base detemps est donne par le timer TMR0. Or ce timer compte en synchronisme avec la frquencedu quartz du PIC.Le programme tait conu pour un quartz 4MHz, et maintenant nous utilisons un quartz 20MHz. La vitesse est donc 5 fois trop importante.76Si vous allez dans la routine dinterruption du timer0, vous verrez que cest la variablecmpt qui compte le nombre de passages dans tmr0. Une fois cmpt 0, on inverse la LED et onrinitialise cmpt avec la valeur CMPTVAL.Souvenez-vous que cette valeur tait fixe 7 dans la zones des dfinitions. Il suffit doncpour rsoudre notre problme, de multiplier CMPTVAL par 5.Remplacez donc :#DEFINE CMPTVAL 7 ; valeur de recharge du compteurpar#DEFINE CMPTVAL D35 ; valeur de recharge du compteurAttention, D35, et non 35, qui serait interprt comme 0x35, soit 53 dcimal.Rassemblez avec , reprogrammez le processeur et relancez lalimentation : LaLED clignote une frquence de 1Hz. Vous voyez lintrt davoir utilis une assignation :plus besoin de rechercher les 2 endroits o on initialise cmpt.Ne courez pas montrer votre pouse. Non, a je vous lai dj dit dans la premirepartie.Le fichier assembleur tel quil devrait tre la fin de cet exercice vous est fourni dans lerpertoire fichiers , comme dhabitude, et comme les exercices pratiques de la suite de cetouvrage.77Notes : 78Notes : 798. Optimisons un peuPlusieurs dentre vous, ce niveau, vont trouver que le programme prcdent est un peugros pour les fonctions quil excute. Si vous tes dans ce cas, vous navez pas tort. Cestpourquoi jintercale ce chapitre ici pour commencer vous parler doptimisation.Cependant, toutes les mthodes doptimisation ne peuvent tre dcrites ici, jen reparleraidonc tout au long de cette seconde partie.Et tout dabord : Optmiser , en voici un bien grand mot. Pourquoi faire ?Et bien, dans ce cas prcis, justement, pour rien du tout. Il ne sert strictement riendoptimiser ce programme. En effet, ce programme est suffisamment petit pour entrer dans le16F876 (et mme le 16F873). De plus notre programme passe la plupart de son temps attendre une interruption en excutant sans fin la boucle du programme principal. Quilattende l ou ailleurs, quelle importance ?Je vous propose juste cette petite optimisation pour commencer vous habituer cestechniques pour le cas o elle serait ncessaire, mais tout dabord, un peu de thorieapplique .8.1 Les deux grands types doptimisationOn peut dire quune optimisation est destine rendre plus efficace un programme. Onpeut distinguer, dans la plupart des cas, 2 grands type doptimisations :- La diminution de la taille du programme- Lamlioration de la vitesse de traitement ou de raction un vnement.Il semble au premier regard que ces 2 techniques soient complmentaires. En effet, ladiminution de la taille du programme induit une diminution du nombre de lignes, donc de ladure dexcution. En y regardant de plus prs, vous verrez quil nen est rien.8.2 Travail sur un exemple concretPrenons un exemple concret sous la forme dune portion de programme, parfois appel code . Imaginons un programme qui place la valeur 5 dans 20 emplacement mmoiresconscutifs :Startmovlw D20 ; pour 20 bouclesmovwf compteur ; dans variable de comptagemovlw dest ; adresse de destinationmovwf FSR ; dans pointeur indirectLoopmovlw 0x05 ; valeur mettre dans emplacementsmovwf INDF ; placer valeur 0x05 dans destinationincf FSR,f ; pointer sur emplacement suivantdecfsz compteur,f ; dcrmenter compteur de boucles80goto loop ; pas fini, suivantnop ; instruction suivante dans le programmeQue pouvons-nous dire de ce bout de code ?En fait, nous voyons que nous avons initialis 20 variables (dest,dest+1..dest+D19)avec la valeur 5 tout en nutilisant que 9 instructions.Vous allez me dire quil est impossible doptimiser ce programme fictif ? Dtrompez-vous. Il faut tout dabord vous rappeler quil y a 2 voies doptimisations, loptimisation entaille et loptimisation en vitesse dexcution.Si vous regardez ce programme, vous verrez quil est difficile de faire plus court. Parcontre nous allons voir quon peut facilement faire plus rapide, preuve que les 2 voies ne sontpas toujours lies, et mme peuvent tre opposes.Supposons que cette portion de code intervienne un niveau o la vitesse de raction estcritique.Si vous avez remarqu que le contenu de W ne changeait jamais dans la boucle, bravo,vous commencez alors raisonner en programmeur. Si ce nest pas encore le cas, aucunproblme, cest en travaillant quon devient travailleur, cest donc en PICant quondevient PIColeur (ne me prenez surtout pas au mot, je ne veux pas dennuis avec votrepouse).Donc, pour rester srieux (a change), calculons la vitesse dexcution (en cyclesdinstructions) de notre programme.- Pour les 4 premires lignes, nous aurons donc 4 cycles.- Ensuite, les 3 premires lignes de la boucle (3 cycles) seront excutes 20 fois, car 20boucles. Ceci nous donne 60 cycles.- Ensuite, plus compliqu, la condition du decfsz sera fausse (pas de saut) les 19premires fois, et vraie (saut) la 20me fois. Soit un total de 19+2 = 21 cycles.- Vient enfin le goto qui produira 19 fois un saut, la 20me fois il ne sera pas excutsuite au saut du decfsz . Soit donc un total de 19*2 = 38 cycles.Rappelez-vous en effet que les instructions qui amnent un saut ncessitent 2 cycles (voirpremire partie).Donc, pour rsumer, ce programme prsente les caractristiques suivantes :- Taille : 9 mots de programme- Temps dexcution : 123 cycles Revenons-en notre remarque sur la valeur inchange de W lintrieur de la boucle.Si W ne change pas, inutile de rpter son chargement chaque passage dans la boucle. Ilfaudra cependant linitialiser au moins une fois, donc avant lexcution de cette boucle.Ceci nous donne :Start81movlw D20 ; pour 20 bouclesmovwf compteur ; dans variable de comptagemovlw dest ; adresse de destinationmovwf FSR ; dans pointeur indirectmovlw 0x05 ; valeur mettre dans emplacementsLoopmovwf INDF ; placer valeur 0x05 dans destinationincf FSR,f ; pointer sur emplacement suivantdecfsz compteur,f ; dcrmenter compteur de bouclesgoto loop ; pas fini, suivantnop ; instruction suivante dans le programmeVous voyez donc que la taille du programme est strictement inchange, puisquon na faitque dplacer linstruction movlw 0x05 en dehors de la boucle. Par contre, durantlexcution du programme, cette instruction ne sera plus excute quune seule fois, au lieudes 20 fois de lexemple prcdent.Nous avons donc un gain de 19 cycles, qui nous ramne le temps dexcution 104cycles. Nous avons donc optimis notre programme au niveau temps dexcution. La taillerestant inchange, ces 2 mthodes ne sont pas incompatibles.Maintenant, imaginons que ces 104 cycles soient inacceptables pour notre programme, quincessite de ragir beaucoup plus vite. Ecrivons donc tout btement :Startmovlw 0x05 ; valeur mettre dans les emplacementsmovwf dest ; placer 0x05 dans emplacement 1movwf dest+1 ; placer 0x05 dans emplacement 2movwf dest+2 ; placer 0x05 dans emplacement 3movwf dest+3 ; placer 0x05 dans emplacement 4movwf dest+4 ; placer 0x05 dans emplacement 5movwf dest+5 ; placer 0x05 dans emplacement 6movwf dest+6 ; placer 0x05 dans emplacement 7movwf dest+7 ; placer 0x05 dans emplacement 8movwf dest+8 ; placer 0x05 dans emplacement 9movwf dest+9 ; placer 0x05 dans emplacement 10movwf dest+A ; placer 0x05 dans emplacement 11movwf dest+B ; placer 0x05 dans emplacement 12movwf dest+C ; placer 0x05 dans emplacement 13movwf dest+D ; placer 0x05 dans emplacement 14movwf dest+E ; placer 0x05 dans emplacement 15movwf dest+F ; placer 0x05 dans emplacement 16movwf dest+10 ; placer 0x05 dans emplacement 17movwf dest+11 ; placer 0x05 dans emplacement 18movwf dest+12 ; placer 0x05 dans emplacement 19movwf dest+13 ; placer 0x05 dans emplacement 20Que dire de ce programme ? Et bien, calculons ses caractristiques commeprcdemment :- Taille du programme : 21 mots de programme- Temps dexcution : 21 cycles.Nous constatons donc que nous avons augment la taille du programme (donc perdu en optimisation taille , mais, par contre, nous sommes pass de 104 21 cycles de tempsdexcution. Nous avons donc gagn en optimisation temps .82Nous voyons donc de faon vidente que les 2 types doptimisation peuvent ncessiter dessolutions opposes. En effet, si javais commenc par vous donner ce dernier exemple, laplupart dentre-vous aurait immdiatement dclar : Ce programme nest pas optimis .En fait, il lest, mais au niveau du temps, pas au niveau de la taille. Et il est tellementoptimis au niveau temps quil est impossible de loptimiser encore davantage. Tout cecipour vous dire : mfiez-vous des grands pros pour lesquels votre programme nestjamais assez bien optimis .Si votre programme ralise ce quil a faire dans les temps imparti, alors il estsufisamment optimis. Dans ce cas, mieux vaut privilgier la lisibilit du code, afin denfaciliter la maintenance. Je ne suis pas un fan de loptimisation sans raison.8.3 Le choix du type doptimisationA ce stade, vous allez vous demander comment vous devez procder en pratique, etquelles procdures utiliser . Il ny a pas de rponse passe-partout, il sagit dune question debon sens. Voici ce que je vous conseille, et que je pratique par moi-mme.En premier lieu, donner priorit la clart et l ouverture du programme. Par ouverture , jentends la construction du programme de faon permettre sa modificationultrieure. Par exemple, le programme prcdent, dans sa premire version (et sa premireamlioration) est plus clair, plus agrable lire, et plus simple modifier que la dernireversion. Pour changer le nombre de boucles, il suffit dans le premier cas, de modifier la valeur D20 .En second lieu, et si cest ncessaire, dterminer le type doptimisation. Si par exemple,vous manquez de place pour votre programme, ou si vous ne souhaitez pas utiliser plusieurspages, vous optimiserez la taille de celui-ci. Par contre, si certaines squences sont critiquesen temps dexcution (par exemple pour certaines interruptions), vous tenterez doptimiser auniveau temps dexcution.Dans tous les cas, placez un commentaire dans votre programme lendroit deloptimisation, pour vous rappeler en cas de modification ultrieure la mthode utilise et laraison de cette optimisation. En effet, cest clair que si vous reprenez un jour la dernireversion du programme prcdent, vous allez vous dire mais pourquoi ai-je programm decette faon ? Optimisons donc ceci en diminuant la taille . Et crac, vous allez allonger ladure dexcution, alors quil y avait probablement une bonne raison de lavoir raccourcie.Rappelez-vous quil ne sert rien de vouloir tout prix optimiser un programme si lebesoin ne sen fait pas sentir. Prfrez de loin un programme clair et bien structur.8.4 Application pratiqueNous allons reprendre notre exercice Led_tmr0 et tenter de loptimiser au niveau de laclart et de la taille. Si vous avez compris ce qui prcde vous savez quil est inutiledoptimiser ce programme, si ne nest pour en amliorer la clart.83Je vais effectuer un copier/coller du programme Led_tmr0 en Led_otpi.asm . Ceciafin de conserver dans les exemples les 2 versions du programme. Vous pouvez, en ce quivous concerne, travailler directement dans votre fichier original.La premire chose quil vous vient lesprit, en parcourant le source, est quil y a plein dedfinitions, macros, et autres assignations inutiles. Vous pouvez en effet les supprimer, maisceci ne diminuera en rien la taille du fichier excutable obtenu ni sa vitesse dexcution.Rappelez-vous en effet que ce ne sont que de simples facilits dcritures. Ces directives nesont remplaces par du code que si elles sont utilises effectivement dans le programme.Nanmoins, nous allons les supprimer pour rendre le fichier source plus compact et plusrapide lire. Il ne sagit donc pas ici doptimisation, tout au plus peut-on parler desuppression de textes inutiles.La meilleure faon pour savoir si une assignation, dfinition ou autre directive de traitement de texte est utilise, est de placer un ; devant sa dclaration. On lanceensuite lassemblage. Sil ny a pas de message derreur, cest que cette directive nest pasutilise dans notre programme. Nous allons en profiter galement pour liminer lescommentaires inutiles pour notre application.Prenons donc le dbut du programme :;**************************************************************************; *; Exercice doptimisation en taille d'un programme simple *; Optimisation sur base du fichier "Led_tmr0" *; *;**************************************************************************; *; NOM: Led_opti *; Date: 13/04/2002 *; Version: 1.0 *; Circuit: platine d'exprimentation *; Auteur: Bigonoff *; *;**************************************************************************; *; Fichier requis: P16F876.inc *; *;**************************************************************************; Permet d'liminer le code superflu *; *;**************************************************************************LIST p=16F876 ; Dfinition de processeur#include ; fichier include__CONFIG _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_OFF & _CPD_OFF & _LVP_OFF &_BODEN_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSCIci, nous nous contentons de commenter len-tte, comme affich ci-dessous. Au niveaude la configuration, nous ne changeons rien.84Viennent ensuite tous les commentaires gnraux concernant les configurations possibles.Nous ne conservons que les commentaires lis aux choix que nous avons faits, inutile deconserver les autres. Ceci nous donne :;_CP_OFF Pas de protection;_DEBUG_OFF RB6 et RB7 en utilisation normale;_WRT_ENABLE_OFF Le programme ne peut pas crire dans la flash;_CPD_OFF Mmoire EEprom dprotge;_LVP_OFF RB3 en utilisation normale;_BODEN_OFF Reset sur chute de tension hors service;_PWRTE_ON Dmarrage temporis;_WDT_OFF Watchdog hors service;_HS_OSC Oscillateur haute vitesse (4Mhz85movwf w_temp ; sauver registre Wswapf STATUS,w ; swap status avec rsultat dans wmovwf status_temp ; sauver status swappmovf FSR , w ; charger FSRmovwf FSR_temp ; sauvegarder FSRmovf PCLATH , w ; charger PCLATHmovwf PCLATH_temp ; le sauverclrf PCLATH ; on est en page 0BANK0 ; passer en banque0; Interruption TMR0; -----------------btfsc INTCON,T0IE ; tester si interrupt timer autorisebtfss INTCON,T0IF ; oui, tester si interrupt timer en coursgoto intsw1 ; non test suivantcall inttmr0 ; oui, traiter interrupt tmr0bcf INTCON,T0IF ; effacer flag interrupt tmr0goto restorereg ; et fin d'interruption;restaurer registres;-------------------restoreregmovf PCLATH_temp , w ; recharger ancien PCLATHmovwf PCLATH ; le restaurermovf FSR_temp , w ; charger FSR sauvmovwf FSR ; restaurer FSRswapf status_temp,w ; swap ancien status, rsultat dans wmovwf STATUS ; restaurer statusswapf w_temp,f ; Inversion L et H de l'ancien W ; sans modifier Zswapf w_temp,w ; Rinversion de L et H dans W; W restaur sans modifier statusretfie ; return from interruptSi vous assemblez ceci, vous aurez un message derreur du type :Symbol not previously defined (intsw1)En fait, ceci est logique, car vous avez supprim la ligne o devait seffectuer le saut encas dune interruption non provoque par tmr0 :goto intsw1 ; non test suivantComme il ny a pas de test suivant, vu quil ny a quune seule interruption utilise, ce testdevrait pointeur sur restorereg . Remplacez donc cette ligne par :goto restorereg ; non test suivantA ce moment, cela fonctionne, mais na plus gure de sens, vu que nous aurons unalgorithme du type : Si interruption non provoque par tmr0, sauter en restorereg, sinon,traiter interruption timer0 puis sauter en restorereg. Cest logique, vu que la seule faondaccder cette partie de code, cest quil y ait eu interruption. Or, la seule interruptionautorise est linterruption tmr0. Inutile donc deffectuer un test.86Nous aurons donc :; Interruption TMR0; -----------------call inttmr0 ; traiter interrupt tmr0bcf INTCON,T0IF ; effacer flag interrupt tmr0goto restorereg ; et fin d'interruptionNous pouvons donc aller plus loin, en constatant quil devient inutile pour la lisibilitdinclure un appel vers une sous-routine. Autant crire dans ce cas le code directement dans laroutine principale dinterruption. Dplaons donc le contenu de la routine inttmr0 la placede lappel de cette sous-routine :; Interruption TMR0; -----------------decfsz cmpt , f ; dcrmenter compteur de passagesreturn ; pas 0, on ne fait rienmovlw b'00000100' ; slectionner bit inverserxorwf PORTA , f ; inverser LEDmovlw CMPTVAL ; pour CMPTVAL nouveaux passagesmovwf cmpt ; dans compteur de passagesbcf INTCON,T0IF ; effacer flag interrupt tmr0goto restorereg ; et fin d'interruptionNe pas, bien videmment, dplacer le return (ni ltiquette inttmr0 ) .Nous pouvons maintenant supprimer toutes les structures des diffrentes interruptions,structures qui ne contiennent que des return . Elles ne seront jamais appeles, et, du coup,parfaitement inutiles et consommatrices despace (pas de temps).Continuons examiner notre routine dinterruption en lexaminant depuis le dbut. Nousvoyons que plusieurs registres sont sauvegards. Rappelez-vous quune sauvegarde estindispensable si les 2 conditions suivantes sont simultanment remplies :- Le registre sauvegard doit tre utilis dans le programme principal- Le registre sauvegard doit tre modifi dans la routine dinterruptionSi nous examinons le programme partir du moment o les interruptions sont en service,cest dire partir de la ligne bsf INTCON,GIE , vous voyez que le programme comporteuniquement 2 sauts.Voyons maintenant les registres sauvegarder effectivement :Le premier registre est le registre w . Dans ce cas prcis, et extrmement rare, il nestpas utilis dans le programme principal, il ny a donc pas de raison de le sauvegarder.Ensuite, nous trouvons la sauvegarde du registre STATUS . Comme notre programmeprincipal ne contient aucune utilisation de ce registre, il nest donc pas ncessaire de lesauvegarder. Ce cas prcis est galement extrmement rare, tant donn que STATUS estutilis pour les changements de banques (RP0,RP1), pour les tests (btfsx STATUS,x), pourles oprations de rotation (utilisation du carry) etc.87Nous pouvons dire que pour la presque totalit des programmes, les registres W et STATUS seront systmatiquement sauvegards. Mais, tant donn que le but de ce chapitreest loptimisation, nous optimiserons donc.Continuons avec la sauvegarde de FSR. Notre programme principal nutilise pasladressage indirect, pas plus que notre routine dinterruption. Donc, 2 bonnes raisons desupprimer cette sauvegarde.Maintenant, voyons PCLATH dont la sauvegarde est galement inutile, vu que notreprogramme tient en page0, et nutilise pas de tableaux mettant en uvre PCLATH. Asupprimer donc galement.Il est vident que la suppression de la sauvegarde inclus la suppression de la restaurationde ces registres. Autre consquence, cette suppression inclus galement la suppression desvariables utilises pour cette sauvegarde. Voyons ce quil reste de notre routinedinterruption :org 0x004 ; adresse d'interruptionclrf PCLATH ; on est en page 0BANK0 ; passer en banque0; Interruption TMR0; -----------------decfszcmpt , f ; dcrmenter compteur de passagesreturn ; pas 0, on ne fait rienmovlw b'00000100' ; slectionner bit inverserxorwf PORTA , f ; inverser LEDmovlw CMPTVAL ; pour CMPTVAL nouveaux passagesmovwf cmpt ; dans compteur de passagesbcfINTCON,T0IF ; effacer flag interrupt tmr0goto restorereg ; et fin d'interruption;restaurer registres;-------------------restoreregretfie ; return from interruptOn peut dire quelle a sensiblement maigri. Nanmoins, regardons-la en dtail. Nousconstatons que la premire ligne place PCLATH 0. Or, si on regarde le datasheet deMicrochip, on constate que ce registre est mis 0 lors dun reset. Comme il reste inchangdurant lexcution de notre programme, nous pouvons nous passer de cette ligne. Nouspouvons raisonner de faon identique pour RP0 et RP1, forcs 0 par la macro BANK0 ,qui est de ce fait inutile, et peut tre supprime de la routine dinterruption. En consquence,ntant plus utilise nulle part, nous pouvons nous passer galement de sa dclaration.Regardons attentivement, et nous constatons la prsence de la ligne goto restorereg ,qui na plus aucune utilit, tant donn que ladresse de saut suit ladresse de linstruction.Cest donc un saut qui nen est plus un. Supprimons donc cette ligne. Il nous reste :88;**************************************************************************; ROUTINE INTERRUPTION *;**************************************************************************org 0x004 ; adresse d'interruption; Interruption TMR0; -----------------decfsz cmpt , f ; dcrmenter compteur de passagesreturn ; pas 0, on ne fait rienmovlw b'00000100' ; slectionner bit inverserxorwf PORTA , f ; inverser LEDmovlw CMPTVAL ; pour CMPTVAL nouveaux passagesmovwf cmpt ; dans compteur de passagesbcf INTCON,T0IF ; effacer flag interrupt tmr0retfie ; return from interruptVoici notre programme fortement simplifi. Lancez lassemblage, placez le code dansvotre PIC, et vous constatez que a ne fonctionne plus. Pourquoi ?En fait, si vous simulez en pas pas, vous constaterez que linterruption na lieu quuneseule fois. En effet, linstruction return effectue une sortie de la routine dinterruptionSANS remettre le bit GIE 1. Il ny aura donc pas de nouvelle interruption. De plus, le flagT0IF ne sera pas resett lors de la sortie de la routine dinterruption.Cette instruction se trouvait lorigine dans la sous-routine inttmr0 appele depuis laroutine dinterruption principale. Elle permettait de revenir dans cette routine, qui, elle, seterminait par retfie aprs un reset du flag T0IF. Ce nest plus le cas ici.Il vous faut donc remplacer linstruction return par un saut lendroit voulu, quipermet de rtablir la situation dorigine.Notre routine dinterruption finale est donc :;**************************************************************************; ROUTINE INTERRUPTION *;**************************************************************************org 0x004 ; adresse d'interruption; Interruption TMR0; -----------------decfsz cmpt , f ; dcrmenter compteur de passagesgoto fin ; pas 0, sortir aprs reset du flagmovlw b'00000100' ; slectionner bit inverserxorwf PORTA , f ; inverser LEDmovlw CMPTVAL ; pour CMPTVAL nouveaux passagesmovwf cmpt ; dans compteur de passagesfinbcf INTCON,T0IF ; effacer flag interrupt tmr0retfie ; return from interruptVoici notre routine dinterruption fortement allge. Voyons maintenant notre routinedinitialisation.89La ligne suivante peut tre supprime, comme expliqu prcdemment :BANK0 ; slectionner banque0Ensuite, les effacements prventifs des PORTs peuvent galement tre supprims pourcette application :clrf PORTA ; Sorties PORTA 0clrf PORTB ; sorties PORTB 0clrf PORTC ; sorties PORTC 0Par contre, les lignes suivantes sont absolument indispensables, comme je lai djexpliqu, et comme nous le verrons en dtail dans le chapitre sur les conversionsanalogiques/numriques.movlw ADCON1VAL ; PORTA en mode digital/analogiquemovwf ADCON1 ; criture dans contrle A/DEnsuite les lignes dinitialisation des directions des registres peuvent tre modifies :movlw DIRPORTA ; Direction PORTAmovwf TRISA ; criture dans registre directionmovlw DIRPORTB ; Direction PORTBmovwf TRISB ; criture dans registre directionmovlw DIRPORTC ; Direction PORTCmovwf TRISC ; criture dans registre directionEn effet, les ports sont tous placs en entre lors dun reset, inutile donc de les y forcer,dautant que seul le PORTA est utilis. De plus, comme une seule sortie est utilise, il suffitde forcer le bit correspondant 0 :bcf LED ; placer RA2 en sortieEn effet, LED va tre remplac par PORTA,2 . Comme on pointe sur la banque1, dufait de la premire ligne, ceci sera excut comme TRISA,2 . Si vous doutez, relisez vite lapremire partie.Plus loin, nous trouvons les initialisations des registres dinterruption. une seuleinterruption est utilise ici, qui nutilise pas les interruptions priphriques. Comme INTCONest mis 0 galement lors dun reset, nous pourrons nous limiter placer le bit dautorisationcorrespondant 1. La suppression des valeurs inutilises permet galement de supprimer lesdfinitions correspondantes :; registres interruptions (banque 1); ----------------------------------bsf INTCON,T0IE ; interruptions tmr0 en serviceVient leffacement de la RAM, qui nest pas ncessaire ici, vu que ces emplacements nesont pas utiliss. Supprimons-le.Linitialisation de la variable utilise(cmpt) nest utile que pour la dure du premierallumage de la LED. Comme la valeur linitialisation est alatoire, on pourrait avoir un90premier allumage aprs une dure allant au maximum jusque 8 secondes. Bien que ce ne soitpas gnant, conservons cette initialisation.Les 2 reset de PIRx ne sont pas ncessaires non plus, donc on supprime. Quant au gotostart il est de fait inutile, car ladresse de saut suit directement le saut.Voici donc le programme pur, pour ne pas dire optimis . Assemblez-le et vrifiezson fonctionnement correct.LIST p=16F876 ; Dfinition de processeur#include ; fichier include__CONFIG _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_OFF & _CPD_OFF & _LVP_OFF &_BODEN_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC;_CP_OFF Pas de protection;_DEBUG_OFF RB6 et RB7 en utilisation normale;_WRT_ENABLE_OFF Le programme ne peut pas crire dans la flash;_CPD_OFF Mmoire EEprom dprotge;_LVP_OFF RB3 en utilisation normale;_BODEN_OFF Reset tension hors service;_PWRTE_ON Dmarrage temporis;_WDT_OFF Watchdog hors service;_HS_OSC Oscillateur haute vitesse (4Mhz91; ----------------CBLOCK 0x70 ; Dbut de la zone (0x70 0x7F)ENDC;//////////////////////////////////////////////////////////////////////////; I N T E R R U P T I O N S;//////////////////////////////////////////////////////////////////////////;**************************************************************************; DEMARRAGE SUR RESET *;**************************************************************************org 0x000 ; Adresse de dpart aprs reset goto init ; Initialiser;**************************************************************************; ROUTINE INTERRUPTION *;**************************************************************************org 0x004 ; adresse d'interruption; Interruption TMR0; -----------------decfsz cmpt , f ; dcrmenter compteur de passagesgoto fin ; pas 0, on sort de l'interruptionmovlw b'00000100' ; slectionner bit inverserxorwf PORTA , f ; inverser LEDmovlw CMPTVAL ; pour CMPTVAL nouveaux passagesmovwf cmpt ; dans compteur de passagesfinbcf INTCON,T0IF ; effacer flag interrupt tmr0retfie ; return from interrupt;//////////////////////////////////////////////////////////////////////////; P R O G R A M M E;//////////////////////////////////////////////////////////////////////////;**************************************************************************; INITIALISATIONS *;**************************************************************************init; initialisation PORTS (banque 0 et 1); ------------------------------------bsf STATUS,RP0 ; passer en banque1movlw ADCON1VAL ; PORTA en mode digital/analogiquemovwf ADCON1 ; criture dans contrle A/Dbcf LED ; placer RA2 en sortie; Registre d'options (banque 1); -----------------------------movlw OPTIONVAL ; charger masquemovwf OPTION_REG ; initialiser registre option; registres interruptions (banque 0); ----------------------------------bsf INTCON,T0IE ; interruptions tmr0 en service; initialiser variable; --------------------movlw CMPTVAL ; charger valeur d'initialisationmovwf cmpt ; initialiser compteur de passages; autoriser interruptions (banque 0); ----------------------------------bsf INTCON,GIE ; valider interruptions92;**************************************************************************; PROGRAMME PRINCIPAL *;**************************************************************************startgoto start ; bouclerEND ; directive fin de programmeSi vous regardez attentivement, vous voyez que dans nos suppressions, nous avons effacla ligne qui permettait de repointer sur la banque 0. Replaons donc cette ligne lendroitvoulu :; initialisation PORTS (banque 1); -------------------------------bsf STATUS,RP0 ; passer en banque1movlw ADCON1VAL ; PORTA en mode digital/analogiquemovwf ADCON1 ; criture dans contrle A/Dbcf LED ; placer RA2 en sortie; Registre d'options (banque 1); -----------------------------movlw OPTIONVAL ; charger masquemovwf OPTION_REG ; initialiser registre optionbcf STATUS,RP0 ; repasser en banque 0; registres interruptions (banque 0); ----------------------------------bsf INTCON,T0IE ; interruptions tmr0 en service8.4 Optimisations particuliresNous venons de voir les 2 grands types doptimisation, mais il en existe dautres, lies des cas particuliers. Ces types doptimisation peuvent tre par exemple :- Loptimisation des ressources matrielles externes (par exemple, comment diminuer lenombre dI/O ncessaires pour le fonctionnement du projet). Un cas typique estlutilisation du multiplexage des pins utilises.- Loptimisation des ressources matrielles internes (par exemple, diminution du nombre detimers utiliss).- Loptimisation des niveaux de sous-programme (pour ne pas dpasser les 8 niveauxmaximum autoriss).- Loptimisation permise par un arrangement tudi des ressourcesComme pour le cas prcdent, toutes ces optimisations ne sont pas forcment compatibles.Il est clair que, par exemple, utiliser le multiplexage des pins va ncessiter plus de code etplus de temps dexcution.Il est une fois de plus question de priorit. Retenez donc que :93Il ny a pas une seule optimisation, il y a toujours plusieurs optimisations parfoiscontradictoires. Parler doptimiser un programme est donc incorrect ou incomplet. Il fautprciser de quel type doptimisation on parle.Il y a donc probablement dautres types doptimisation, mais le but de ce chapitre est devous faire comprendre le raisonnement appliquer, et non de tout dtailler de faonexhaustive.8.4.1 Optimisation des niveaux de sous-programmesJe vais vous toucher un mot des mthodes pour diminuer le nombre de niveaux de sous-routines utiliss dans vos programmes. En effet, je reois pas mal de courrier suite lapremire partie du cours concernant les sous-routines, principalement des erreurs de stack .Tout dabord, rappelez-vous quil ne faut pas confondre niveaux de sous-routines etnombre de sous-routines. Les premiers sont limits 8, le second nest limit que par lacapacit mmoire programme de votre pic.Pour dterminer le niveau de sous-routine utilis dans votre programme, il suffit de leparcourir en ajoutant 1 chaque call rencontr, et en soustrayant 1 chaque return rencontr.Le nombre maximal atteint lors de ce comptage dtermine le niveau maximum de sous-programme utilis par votre programme.Noubliez cependant pas dajouter 1 ce nombre maximum, si vous utilisez lesinterruptions, augment du niveau de sous-programme utilis dans la routine dinterruption.Pour rester concrets, imaginons un programme fictif. Ce programme est incomplet,nessayez donc pas de le faire tourner, ou alors ajoutez ce quil manque.goto start ; programme;**************************************************************************; ROUTINE INTERRUPTION *;**************************************************************************;sauvegarder registres;---------------------org 0x004 ; adresse d'interruptionmovwf w_temp ; sauver registre Wswapf STATUS,w ; swap status avec rsultat dans wmovwf status_temp ; sauver status swapp; Interruption TMR0; -----------------btfsc INTCON,T0IE ; tester si interrupt timer autorisebtfss INTCON,T0IF ; oui, tester si interrupt timer en coursgoto intsw1 ; non test suivantcall inttmr0 ; oui, traiter interrupt tmr0bcf INTCON,T0IF ; effacer flag interrupt tmr0goto restorereg ; et fin d'interruption; Interruption RB0/INT; --------------------intsw1call intrb0 ; oui, traiter interrupt RB094bcf INTCON,INTF ; effacer flag interupt RB0;restaurer registres;-------------------restoreregswapf status_temp,w ; swap ancien status, rsultat dans wmovwf STATUS ; restaurer statusswapf w_temp,f ; Inversion L et H de l'ancien W ; sans modifier Zswapf w_temp,w ; Rinversion de L et H dans Wretfie ; return from interrupt;**************************************************************************; INTERRUPTION TIMER 0 *;**************************************************************************inttmr0incf compteur,f ; incrmenter compteurreturn ; fin d'interruption timer;**************************************************************************; INTERRUPTION RB0/INT *;**************************************************************************intrb0movf mavariable ; charger mavariablecall divis ; diviser par 2return ; fin d'interruption RB0/INT;**************************************************************************; TRAITER REGISTRE *;**************************************************************************traitregmovwf mavariable ; mettre w dans mavariablecall multipli ; multiplier par 2return ; retour;**************************************************************************; Diviser par 2 *;**************************************************************************divisbcf STATUS,C ; effacer carryrrf mavariable,f ; diviser mavariable par 2return ; retour;**************************************************************************; Multiplier par 2 *;**************************************************************************multiplibcf STATUS,C ; effacer carryrlf mavariable,f ; multiplier mavariable par 2return ; retour;**************************************************************************; Ajouter 1 *;**************************************************************************ajoutincf mavariable,f ; ajouter 1return ; retour;**************************************************************************; programme principal *;**************************************************************************startmovlw 0x05 ; 5 dans w95call traitreg ; mettre le double dans mavariablecall ajout ; incrmenter mavariablegoto start ; bouclerEND ; directive fin de programmeEtudions donc les niveaux de sous-routines de ce petit programme, du reste parfaitementinutile. Commenons par le programme principal :- On commence par le niveau 0. En premire ligne, on trouve goto start . Il sagit dunsaut, non dun appel de sous-routine, donc on najoute rien- On arrive ltiquette start . On avance dans le programme, et on tombe sur la ligne call traitreg . Il sagit dun call, donc on ajoute 1. On est donc 1 niveau.- On poursuit ltiquette traitreg et on avance dans la sous-routine. On arrive la ligne call multipli . On ajoute donc 1, nous voici 2. Poursuivons donc ladresse multipli .- On droule le programme, et on arrive return . On dcompte donc 1. Nous revoici 1. Retour donc dans la routine traitreg, et plus prcisment la ligne return . Ondcompte de nouveau 1. Nous revoici 0, et dans le programme principal, preuve que toutse passe bien.- On poursuit le programme principal et on arrive la ligne call ajout . On ajoute 1, cequi nous fait 1. On passe ltiquette ajout . On avance dans le programme et ontrouve la ligne return . On soustrait 1, ce qui nous fait 0, et retour au programmeprincipal. On dmarre de 0, on termine 0, tout est correct.Rappelez-vous que si, un moment donn, vous obtenez une valeur suprieure 8 ouinfrieure 0, vous avez forcment fait une erreur dans la construction de votre programme.En gnral il sagit dune mprise entre goto et call , ou un oubli ou ajout dun return .Nous voyons donc que la valeur maximale atteinte lors de lexcution de notre programmeest de 2. Donc, notre programme principal utilise un niveau de sous-programme de 2.Etant donn quune interruption peut avoir lieu nimporte quel moment de notreprogramme (et donc au moment o nous sommes dans la sous-routine multipli, de niveau 2),il convient dajouter ce niveau ceux utiliss dans les routines dinterruption.Imaginons donc quune interruption intervienne au moment o nous nous trouvons dans lecas le plus dfavorable, cest dire au niveau 2 :- Linterruption a lieu, et ncessite une sauvegarde sur la pile (stack), comme expliqu dansla premire partie. Nous tions 2, nous voici 3.- Nous voici dans la routine dinterruption, nous arrivons la ligne call inttmr0 . Nousajoutons donc 1, nous en sommes 4.96- Dans la sous-routine inttmr0 , nous trouvons return , donc nous revoici 3, et dansla routine dinterruption principale.- Nous trouvons ensuite call intrb0), ce qui nous ramne 4, nous voici dans intrb0 .- Nous trouvons ensuite call divis qui nous amne 5 dans la sous-routine divis .- Dans cette routine, nous trouvons return , nous revoici 4 dans la suite de la routine intrb0 .- Nous poursuivons et nous trouvons un return . Nous voici 3 dans la routinedinterruption principale, qui se termine par retfie , qui est un return particulier.- Nous sortons donc de la routine dinterruption et nous faisons 1, ce qui nous ramne auniveau 2 du dpart. De nouveau, preuve que tout sest bien pass.Nous voyons donc que notre programme complet ncessite une profondeur de niveau desous-routines de 5 (valeur maximale rencontre). Nous sommes donc en dessous des 8niveaux permis, tout est bon.Mais tout nest pas toujours si rose, aussi, si votre programme dpasse les 8 niveauxpermis, je vais vous donner quelques astuces pour en diminuer la valeur.La premire chose faire, cest de regarder si toutes les sous-routines sont utiles. En effet,une sous-routine appele une seule fois dans un programme nest pas vraiment indispensable.Mais a, tout le monde peut le faire, il ne sagit pas doptimisation. Tout dabord un prambule : En gnral, loptimisation des niveaux de sous-routinesdiminue la clart du programme, et sont donc rserver aux applications pour lesquelles onna pas le choix. Principalement pour viter le dbordement de la pile, bien entendu (niveaux>8), mais galement parfois pour gagner du temps dexcution.Dans tous les autres cas, ne tentez pas doptimiser les niveaux de sous-programmes.Je ne sais pas si cest vraiment une bonne ide de parler de ce type doptimisation, maiscomme je reois beaucoup de courrier ce sujet, je my suis finalement dcid.Examinons tout dabord la routine dinterruption principale. Si vous regardezattentivement, vous distinguez que les sous-routines inttmr0 et intrb0 ne sont appelesqu partir dun seul endroit dans le programme. Ce sera en gnral vrai pour tous lesprogrammes utilisant la maquette que je vous fournis. Donc, partant de l, il est possible degagner un niveau de sous-routine cet endroit.En effet, si on appelle la sous-routine depuis un seul endroit, on connat donc le point deretour de cette sous-routine, qui sera la ligne suivant son appel. Vous suivez ?Donc, on peut remplacer le call vers cette sous-routine par un goto , et le return de cette sous-routine par un autre goto . Jen vois qui sont en train de fumer des mninges,pour dautres cest clair. Vous allez voir quen pratique avec la routine inttmr0 , ce nestpas trs compliqu.97; Interruption TMR0; -----------------btfsc INTCON,T0IE ; tester si interrupt timer autorisebtfss INTCON,T0IF ; oui, tester si interrupt timer en coursgoto intsw1 ; non test suivantgoto inttmr0 ; oui, traiter interrupt tmr0retourbcfINTCON,T0IF ; effacer flag interrupt tmr0goto restorereg ; et fin d'interruption; suite du traitement interrupt;**************************************************************************; INTERRUPTION TIMER 0 *;**************************************************************************inttmr0incf compteur,f ; incrmenter compteurgoto retour ; fin d'interruption timerVous voyez donc que vous avez limin un call avec le return correspondant.Sachez que vous pouvez faire de mme avec la sous-routine intrb0 , vous gagnez en fait unniveau de sous-routine au total de votre programme. Mais ceci au dpend de la structurationde votre programme, je vous le rappelle.Tant que nous y sommes, nous pouvons constater quil ny a quune seule instruction (bcfINTCON,T0IF) entre le point de retour et un nouveau saut. Nous en profitons donc pouroptimiser en taille et en temps la routine obtenue en dplaant cette instruction et ensupprimant un saut.; Interruption TMR0; -----------------btfsc INTCON,T0IE ; tester si interrupt timer autorisebtfss INTCON,T0IF ; oui, tester si interrupt timer en coursgoto intsw1 ; non test suivantgoto inttmr0 ; oui, traiter interrupt tmr0; suite du traitement interrupt;**************************************************************************; INTERRUPTION TIMER 0 *;**************************************************************************inttmr0incf compteur,f ; incrmenter compteurbcfINTCON,T0IF ; effacer flag interrupt tmr0goto retorereg ; fin d'interruption timerVoici donc un niveau de gagn. Voyons maintenant une autre astuce, pas trsrecommandable, et donc, je le rappelle, nutiliser quen cas dabsolue ncessit. Jelexplique car vous risquez de la rencontrer en analysant des programmes crits par dautres.Bon, accrochez-vous et regardez les 2 lignes suivantes tires de la routine dinterruption :call divis ; diviser par 2return ; fin d'interruption RB0/INTVous ne remarquez rien ? Effectivement, cest loin de sauter aux yeux. En fait, il sagitdun call suivi directement par un return .98Bon, vous allez me dire que vous ntes pas plus avanc. Jy arrive. Je vais raisonner enfranais plutt quun organigramme dans un premier temps.- Au moment de lexcution de cette sous-routine, se trouve sur la pile ladresse de retourdu programme appelant- A lappel de la sous-routine divis jempile ladresse de retour sur la pile et je saute en divis - Au retour de cette routine divis , je dpile ladresse de retour et je reviens sur la ligne return de ma sous-routine affiche.- A lexcution du return , je dpile ladresse du programme appelant et je retourne celui-ci.Je suppose que a sembrouille encore plus dans votre esprit, ce nest pas le but recherch,mais, en me relisant, a semble logique. Je continue donc mon explication.Vous voyez donc, quen fait jempile ladresse de retour au moment de lappel de laroutine divis . Mais cette adresse de retour ne va me servir que pour permettre lexcutionde linstruction return , qui elle-mme va dpiler ladresse du programme appelant. Bon,un petit ordinogramme pour montrer tout a ne sera pas superflu.Que constatons-nous de spcial sur cet ordinogramme ? Et bien, si vous suivez ledroulement chronologique illustr par les flches, vous voyez que vous rencontrez 2 return conscutifs.99Si vous analysez bien, vous remarquez que ceci est d au fait que lappel de la sous-routine2 est suivi directement par le return marquant la fin de la sous-routine1.Vous ne voyez toujours pas ? En fait, si on traduit ces 2 retours conscutifs en franais, onpourrait dire :On dpile ladresse de retour empile afin de pointer sur linstruction qui demande dedpiler ladresse de retour afin dobtenir ladresse de retour vers le programme.On peut donc se dire que si ladresse de retour dpile dans la sous-routine2 ne sert quobtenir ladresse de retour qui sera dpile par la sous-routine1, on pourrait souhaiterretourner directement de la sous-routine2 vers le programme principal. Vous commencez comprendre ?En fait, comme on ne peut pas dpiler 2 adresses la fois, on pourrait tout aussi bien sedire quil suffit de ne pas empiler ladresse de retour vers la sous-routine1, ce qui fait que leretour de la sous-routine2 permettrait le retour direct vers le sous-programme. Comme onnaurait pas empil, on gagnerait un niveau de sous-routine.Or, comment ne pas empiler ? Simple ! Il suffit de remplacer le call par un goto .Ceci vous donne la chronologie suivante :Un petit mot dexplication. En fait, si vous suivez partir du programme, vous voyez quenous rencontrons un call vers la sous-routine1. On empile donc ladresse de retour vers leprogramme principal. Ensuite, on arrive dans la sous-routine1, dans laquelle un goto nousrenvoie la sous-routine2. Dans celle-ci on trouve un return qui dpile ladresseprcdemment empile, soit celle du retour vers le programme principal, sans repasser par lasous-routine1.De cette faon, la sous-routine2 peut tre appele de faon classique par un call , ouappele par un goto , auquel cas le retour seffectue depuis le programme qui a appel lasous-routine qui a appel la sous-routine2100Si vous comptez les niveaux de sous-routine, vous avez gagn un niveau. Ceci se traduiten langage dassemblage par :;**************************************************************************; INTERRUPTION RB0/INT *;**************************************************************************intrb0movf mavariable ; charger mavariablegoto divis ; diviser par 2;**************************************************************************; Diviser par 2 *;**************************************************************************divisbcf STATUS,C ; effacer carryrrfmavariable,f ; diviser mavariable par 2return ; retourATTENTION : ne me faites pas crire ce que je nai pas crit. Je vous rappelle que jedconseille fortement ce type de pratique, ne rserver quaux cas dsesprs. Jexplique ceciafin de vous aider comprendre certaines astuces que vous risquez de rencontrer si vousexaminez des programmes raliss par dautres.Il existe encore dautres mthodes. Vous verrez par exemple dans le chapitre consacr audebugger, comment utiliser une sous-routine sans utiliser un seul niveau sur la pile. Mais lisezdans lordre, quand vous en serez arrivs l, il sera temps de vous casser les mninges.8.4.2 Lorganisation des ressourcesJe vais maintenant vous montrer une astuce trs simple concernant des zones de donnes copier, comparer, etc.Le problme est que vous ne disposez que dun seul pointeur indirect, FSR. Lamanipulation simultane de 2 zones implique une gymnastique permanente au niveau de ceregistre.Imaginons le petit programme suivant (pour tester au simulateur) :LIST p=16F876 ; Dfinition de processeur#include ; fichier include; Zone de 80 bytes; ----------------CBLOCK0x20 ; Dbut de la zone (0x20 0x6F)Zone1 : D'14' ; table de 14 octetsZone2 : D'14' ; table de 14 octetscmpt : 1 ; variable localesav1 : 1 ; sauvegarde pointeur1sav2 : 1 ; sauvegarde pointeur2inter : 1 ; zone intermdiaireENDC ; Fin de la zone101ORG 0x00startmovlw D'14' ; nombre d'octets transfrermovwf cmpt ; dans compteurmovlw Zone1 ; adresse zone1movwf sav1 ; dans pointeur1movlw Zone2 ; adresse zone2movwf sav2 ; dans pointeur2loopmovf sav1,w ; charger pointeur1movwf FSR ; dans pointeur indirectmovf INDF,w ; charger valeur pointemovwf inter ; dans valeur intermdiairemovf sav2,w ; charger pointeur2movwf FSR ; dans pointeur indirectmovf inter,w ; charger valeur intermdiairemovwf INDF ; transfrer valeurincf sav1,f ; incrmenter pointeur1incf sav2,f ; incrmenter pointeur2decfszcmpt,f ; dcrmenter compteur d'lmentsgoto loop ; pas dernier, suivantENDVous constatez que ce nest vraiment pas pratique de modifier et sauver sans arrt FSR.Ceci impose 2 variables de sauvegarde et lutilisation dune variable intermdiaire pourstocker la donne transfrer.La premire chose laquelle vous pouvez penser, cest dconomiser les variables desauvegarde de FSR, puisque la distance entre Zone1 et Zone2 est fixe. Ceci nous donne :startmovlw D'14' ; nombre d'octets transfrermovwf cmpt ; dans compteurmovlw Zone1 ; adresse zone1movwf FSR ; dans pointeur indirectloopmovf INDF,w ; charger valeur pointemovwf inter ; dans valeur intermdiairemovlw Zone2-Zone1 ; cart entre les 2 zonesaddwf FSR,f ; pointer sur zone2movf inter,w ; charger valeur intermdiairemovwf INDF ; transfrer valeurmovlw Zone1-Zone2+1 ; cart entre zone2 et zone1 suivantaddwf FSR,f ; pointer sur suivantdecfszcmpt,f ; dcrmenter compteur d'lmentsgoto loop ; pas dernier, suivantENDCest dj mieux, mais on a toujours besoin dune sauvegarde intermdiaire. La lignecomprenant Zone1-Zone2+1 sexplique par le fait que pour pointer sur la Zone1, on doitajouter la valeur ngative Zone1-Zone2, et, quensuite, on doit incrmenter cette valeur pourpasser la variable suivante, do le +1 qui permet dviter lincrmentation.On peut alors se dire quil serait judicieux de placer les tables pour quun seul bitdiffrencie leur emplacement. Zone1 va de B0010 0000 B 0010 1101102La Zone2 commence ds lors en B0010 1110. On remarque que si on dcale toutsimplement Zone2 de 2 emplacements, elle stendra de B0011 0000 B0011 1101. EntreZone1 et Zone2, seul le bit 4 de lemplacement est modifi.Profitons de cette astuce :; Zone de 80 bytes; ----------------CBLOCK0x20 ; Dbut de la zone (0x20 0x6F)Zone1 : D'14' ; table de 14 octets : NE PAS DEPLACERcmpt : 1 ; variable localelibre : 1 ; emplacement libreZone2 : D'14' ; table de 14 octets : NE PAS DEPLACERENDC ; Fin de la zone ORG 0x00startmovlw D'14' ; nombre d'octets transfrermovwf cmpt ; dans compteurmovlw Zone1 ; adresse zone1movwf FSR ; dans pointeur indirectloopmovf INDF,w ; charger valeur pointebsf FSR,4 ; pointer zone2movwf INDF ; transfrer valeurincf FSR,f ; pointer sur suivantbcf FSR,4 ; repointer Zone1decfszcmpt,f ; dcrmenter compteur d'lmentsgoto loop ; pas dernier, suivantENDDans ce cas, on peut parler doptimisation, aussi bien en place quen vitesse dexcution,et mme en nombre de variables RAM utilises.Notez que nous avons dplac Zone2 en y insrant le cmpt, plus une variable inutilise quipourra servir un autre usage. Noubliez pas de prciser dans votre zone de variables leszones quil ne faudra plus dplacer.Vous pouvez aussi utilisez les assignations (Zone1 EQU 0x20), mais alors faites trsattention aux double-emplois, je vous dconseille cette mthode.Vous pouvez galement utiliser cette technique en plaant vos tables dans des banquesdiffrentes. Si vous placez, par exemple Zone1 en 0x20 (banque0) et Zone2 en 0xA0(banque1), le passage de la source la destination se fera cette fois en modifiant le bit 7 deFSR.Et si vous placez Zone1 en 0x20 (banque0) et Zone2 en 0x120 (banque2), alors le passagede lune lautre ne ncessitera que la modification du bit IRP du registre STATUS.Vous voyez donc que simplement dfinir un emplacement judicieux pour vos variablespeut vous permettre des optimisations intressantes.103Notes : 104Notes : 1059. Les diffrents types de resetNous passons maintenant ltude des diffrentes causes qui peuvent aboutir provoquerun reset de notre PIC. Cest dire un redmarrage depuis ladresse 0x00 et la rinitialisationventuelle de certains registres.Il peut tre en effet parfois utile de pouvoir dtecter, au niveau de la procduredinitialisation, le type de reset qui vient dtre excut. Ceci afin de permettre de raliser desoprations diffrentes.On pourrait avoir, par exemple, un procdure qui initialiserait le systme en cas depremier dmarrage, et une autre qui permettrait de rcuprer un processus plant aprs undbordement de watchdog suite un violent parasite secteur.Nous allons donc voir comment distinguer et reconnatre la cause du reset en cours.9.1 Les 6 types de resetNous pouvons dire que si notre programme est contraint de redmarrer au dbut de sasquence, ladresse 0x00, cest quun des vnements suivant est survenu (on exceptenaturellement un saut volontaire de la part de lutilisateur de type goto 0x00 ) :- Apparition de la tension dalimentation aprs une coupure- Application dun niveau bas sur la pin MCLR durant le droulement du programme- Application dun niveau bas sur la pin MCLR durant le mode sleep - Dbordement du watchdog durant le droulement du programme- Dbordement du watchdog durant le mode sleep - Remonte de la tension dalimentation aprs une chute partielleParmis ces 6 types, le dbordement du watchdog durant le mode de sommeil nest pas proprement parler un reset, puisquil provoque le rveil du PIC, sans provoquer un reset ladresse 0x00, ni mme la modification des registres affects par les resets classiques.Cependant, jintgre ce cas ici, tant donn quil met en uvre les mmes procdures dedtection.Il existe au moins une faon non documente pour provoquer volontairement un reset parle programme. Comme je dconseille vivement ce genre de procds, je nen parlerai pas.9.2 Le reset et les registres STATUS et PCONPour pouvoir dterminer quel vnement a provoqu le reset, il nous faudra plusieurs bits.Etant donn que nous avons 6 causes de reset possible, nous avons besoin dun minimum de 3bits. En ralit, nous allons voir que 4 bits sont utiliss, 2 se trouvent dans le registreSTATUS, et 2 dans un nouveau registre, le registre PCON.Voici la description du registre PCON106b0 : BOR : Brown Out Reset : Reset sur chute de tensionb1 : POR : Power On Reset : Reset par mise sous tensionb2-b7 : N.U. Non utiliss : non implments, lus comme 0 Les bits concerns par le reset dans le registre STATUS sont les suivants :b3 : PD : Power Down bit : passage en mode sleepb4 : TO : Time Out bit : reset par dbordement du watchdogNotez que ces bits, ainsi que les bits qui nous intressent sont actifs ltat bas, cest--dire, pour rappel, que cest lorsquils sont 0 quils indiquent que lvnement a eu lieu.Il vous faut noter que le bit BOR est dans un tat indtermin lors de la mise sous tension.Ce bit est forc 0 lorsquune chute de tension provoque le reset du PIC. Donc, si vousvoulez dtecter ce passage 0, il vous faudra tout dabord placer ce bit 1 dans votre routinedinitialisation.Vous pourrez par exemple utiliser les lignes suivantes :initbsf STATUS,RP0 ; passer en banque 1btfss PCON,POR ; tester si mise sous tensionbsf PCON,BOR ; oui, alors forcer BOR 1bcf STATUS,RP0 ; repasser banque0, suite de linitialisation9.3 Dtermination de lvnementJe vous donne le tableau qui vous permettra de dtecter quel type de reset vous tesconfronts dans votre routine dinitialisation. Vous auriez pu trouver ce tableau uniquementpar dduction des explications prcdentes.POR BOR TO PD Evnement qui a provoqu le reset0 X 1 1 Mise sous tension du PIC0 X 0 X Impossible, puisque TO est mis 1 la mise sous tension0 X X 0 Impossible, puisque PD est mis 1 la mise sous tension1 0 1 1 Retour de la tension dalimentation aprs une chute de tension1 1 0 1 Reset par dbordement du watchdog1 1 0 0 Sortie du mode sleep par dbordement du watchdog1 1 U U Reset provoqu par la broche MCLR1 1 1 0 Reset par MCLR durant le mode sleepJe vais vous commenter un peu ce tableau, afin de vous viter de vous casser lesmninges. Vous allez voir que tout est logique :La premire ligne concerne la mise sous tension du PIC, cest dire le passage de ce quele PIC considre comme une absence dalimentation, vers ce quil considre comme unealimentation correcte. Les valeurs exactes de ces niveaux sont donns, pour ceux que aintresse, dans le datasheet, au niveau des caractristiques lectriques.107Dans votre programme, vous dtecterez cet vnement en examinant le bit POR. Sil vaut0, alors on est dans le cas de la mise sous tension, encore appele Power On Reset.Comme la mise sous tension provoque automatiquement la mise 1 de TO et de PD, leslignes 2 et 3 du tableau sont donc impossibles. Inutile donc de tester ces configurations, ellesne se prsenteront jamais.La quatrime ligne du tableau vous montre que le simple test du bit BOR vous permet dedterminer que le reset a t provoqu par une chute de la tension dalimentation. La faondont le PIC dtermine une chute de tension est galement spcifie dans les caractristiqueslectriques.Notez quune perte de tension totale, provoquera, au moment de la rapparition de latension, un P.O.R. plutt quun B.O.R. On peut donc estimer quun B.O.R. est conscutif une chute de lalimentation qui place le PIC en risque de plantage , alors quun P.O.R. estla consquence dune perte dalimentation qui impose larrt total de llectronique du PIC.Une chose importante vous rappeler, cest que le bit BOR est dans un tat indterminlors dune mise sous tension. Il pourrait tout aussi bien tre 1 qu 0. Cest pour a que sivous dsirez utiliser ce bit, vous devrez le forcer 1 lors du Power On Reset, afin de pouvoirtester son ventuel passage 0.Une seconde chose noter est que le bit BOR, donc le reset de type Brown Out Reset nest utilis QUE si le bit BODEN a t valid au niveau de la directive _CONFIG. Suivantvotre application, vous avez donc 2 possibilits :1) Soit vous nutilisez pas la fonction BOR, donc vous estimez quil est prfrable que votrePIC fonctionne cote que cote, mme si une chute dalimentation risque de provoquer unplantage de son programme2) Soit vous dcidez que le PIC ne peut fonctionner que si la tension permet unfonctionnement sans risque, et donc vous activez le bit BODENPour situer les esprits, vous pouvez considrer, par exemple quun petit gadget qui faitclignoter une LED avec une alimentation par pile doit fonctionner le plus longtemps possible,donc vous ne validez pas BODEN. Par contre, un montage qui pilote une scie circulaireautomatique ne devra fonctionner que sil nexiste aucun risque de plantage du programme,donc vous activerez BODEN.Pour comprendre les lignes suivantes, il vous faut savoir que le bit PD peut tre remis 1par un des 2 vnements suivants :- Mise sous tension- Excution de linstruction clrwdt .La mise 0 est, comme je lai dit plus haut, provoque par linstruction sleep Sachant ceci, si nous examinons la cinquime ligne du tableau, nous voyons que TO nousindique que le reset a t provoqu par le dbordement du watchdog. En examinant en surplusle bit PD 1, nous pouvons en dduire que le programme tait en phase dexcution normale108dune instruction. Donc, dans cette circonstance, nous savons que le watchdog a provoqu unreset de notre programme en cours dexcution.Passons alors la sixime ligne, qui ne se diffrencie que par le bit PD, cette fois 0.Comme je lai dit, ce bit est mis 0 par linstruction sleep . Nous pouvons donc en dduireque le watchdog a rveill le PIC qui tait plac en mode sleep . Il ny a donc pas de resetprovoqu dans ce cas.La septime ligne devrait vous laisser un peu perplexe. En effet, nous voyons 2 fois lamention u pour unchanged ou inchang . Si les bits peuvent tre 1 ou 0, ilspeuvent tre dans un des tats correspondant aux deux lignes prcdentes. Comment dans cecas savoir quel est le type de reset traiter ?En fait, il suffit de rflchir. Nous voyons donc daprs cette ligne quune action surMCLR provoque un reset qui ne modifie ni TO, ni PD.A partir de l, imaginons que TO = PD = 1. Dans ce cas, on peut dire quon a affaire unreset qui nest ni un P.O.R, ni un B.O.R., puisque les bits correspondants sont 1 . Cenest pas non plus un dbordement de watchdog, puisque TO = 1. Ne reste donc que lapossibilit que le reset soit provoqu par une action sur MCLR.Si, par contre, le bit PD tait 0, cela voudrait dire quon a agit sur MCLR pendant que lePIC tait en mode sleep .Vous allez me dire, et si TO valait 0 ? Et bien, dans ce cas, cela voudrait dire que nousvenions davoir affaire un reset de type dbordement de watchdog, juste avant notre actionsur MCLR. Donc, il nous suffisait de remettre TO 1 une fois notre reset de type watchdog intervenu, pour viter de nous trouver confront cette incertitude.Si vous examinez la huitime ligne de notre tableau, vous voyez quelle correspond undes cas que je viens dexpliquer, savoir un reset de type MCLR alors que le PIC tait enmode sleep Au terme de lanalyse de ce tableau, vous devez tre capable, le jour o vous en aurezbesoin, de dterminer quel est le type de reset qui vous amne excuter votre routinedinitialisation.Notez que je nai pas intgr les routines de test de reset dans le fichier maquette, car il estassez peu frquent quon doive les utiliser. Et quand on doit les utiliser, il est rare quon doivediffrencier tous les cas. Il vous suffira donc, le cas chant, de revenir lire ce chapitre et detraiter votre cas particulier en fonction de ce que je vous ai expliqu.Je ne ferai pas dexercices sur ce chapitre, car cela me semble inutile et demanderaitbeaucoup de manipulations pour tester tous les cas possibles. Jestime que ce serait de la pertede temps, dautant que les programmes se rsumeraient tester les diffrents bits dans lordredonn par le prcdent tableau.Par contre, une donne intressante obtenir est ltat des diffrents registres aprschaque type de reset. Je vous conseille donc de regarder le tableau 12-6 du datasheet qui vousdonnera toutes les informations utile ce niveau.109Certains registres sont en effet affects de faon diffrente selon le type de reset intervenu.110Notes : 11110. Les ports entre/sortieNous allons maintenant voir dans ce chapitre les diffrents ports du 16F87x dans leurutilisation en tant que PORT I/O, cest--dire sans utiliser les fonctions spciales des pinsconcernes.Nous tudierons ces fonctions spciales dans les chapitres correspondants au momentvoulu. Les PICs 16F87x disposent en effet dinnombrables possibilits, ce qui ne rend passimple la description exhaustive de toutes les utilisations possibles.Commenons donc par les vieilles connaissances, et en premier lieu par :10.1 Le PORTANous en avons dj parl dans le chapitre sur la conversion des programmes. En fait, lePORTA, dans sa partie PORT I/O est fort semblable celui observ sur le 16F84.Nous trouvons donc ici 6 pins I/O numrotes de RA0 RA5. Nous avons donc 6 bitsutiles dans le registre PORTA et 6 bits dans le registre TRISA. Les bits 6 et 7 de ces registresne sont pas implments. Comme toujours, ils seront lus comme des 0 .La principale diffrence avec le 16F84 provient de ce que le PORTA, au moment du reset,est configur comme un ensemble dentres analogiques. Donc, nous devrons forcer unevaleur dans le registre ADCON1 dans notre routine dinitialisation pour pouvoir utiliser ceport comme port dentre/sortie de type gnral.Je verrai le registre ADCON1 dans le chapitre consacr au convertisseur A/D.Limportant, ici, est de savoir que pour utiliser le PORTA de la mme faon que sur le 16F84,nous devrons placer la valeur Bx000011x, dans lequel x vaut 0 ou 1. Pour les plus curieuxdentre-vous, cette valeur provient du tableau 11-2, mais nous y reviendrons.Donc, pour utiliser le PORTA en mode I/O, nous placerons par exemple la valeurB00000110 dans ADCON1, soit 0x06. Notez que le registre ADCON1 se trouve enbanque1.bsf STATUS,RP0 ; passer en banque 1movlw 0x06 ; valeur pour mode numrique movwf ADCON1 ; dans ADCON1xxxx ; suite des initialisations.Si vous examinez la routine dinitialisation de votre fichier maquette, vous verrez quelinitialisation de ADCON1 a t prvue. De sorte que ceci vous vite cet oubli trs frquent, en croire le courrier que je reois ce sujet.Attention ce que lutilisation de cette valeur influe galement sur le fonctionnement duPORTE, comme vous le verrez plus loin.Le reste du PORTA est strictement identique celui du 16F84, avec la mme remarque auniveau de RA4, qui est toujours en drain ouvert, cest--dire quil ne permet pas dimposer un112niveau +5V sur la pin correspondante. Cest galement une erreur que je constatefrquemment, au niveau lectronique, cette fois.10.2 Le PORTBRien de particulier dire sur ce PORTB, qui est identique celui du 16F84, du moinspour la partie I/O classique.Notez la pin RB0 qui, en configuration dentre, est de type trigger de Schmitt quandelle est utilise en mode interruption INT . La lecture simple de RB0 se fait, elle, de faontout fait classique, en entre de type TTL.Je vous renvoie donc la premire partie pour plus dinformations sur ce PORT.10.3 Le PORTCNous voici dans les nouveauts. Cest un PORT qui nexistait pas sur le 16F84. Voyonsdonc, toujours au niveau de son utilisation classique , quelles sont ses caractristiques.Tout dabord au niveau programmation, cest un PORT tout ce quil y a de plus classique.Nous trouvons donc un registre TRISC localis dans la banque 1, qui permet de dciderquelles sont les entres et quelles sont les sorties. Le fonctionnement est identique celui desautres TRIS, savoir que le positionnement dun bit 1 place la pin en entre, et que lepositionnement de ce bit 0 place la dite pin en sortie.Notez, comme pour tous les autres ports, que la mise sous tension du PIC, et tout autrereset, force tous les bits utiles de TRISx 1, ce qui place toutes les pins en entre. Je nyreviendrai plus.Nous trouvons galement le registre PORTC, qui, comme les autres PORTx, se trouvedans la banque 0. Son fonctionnement est, de nouveau, identique celui des autres PORTxEnsuite, au niveau lectronique, nous noterons que toutes les pins, lorsquelles sontconfigures en entre, sont des entres de type trigger de Schmitt . Je vous rappelle quececi permet dviter (en simplifiant) les incertitudes de niveau sur les niveaux qui ne sont nides 0V, ni des +5V, donc, en gnral, sur les signaux qui varient lentement dun niveau lautre.A la vue de ceci, lutilisation pour vous du PORTC ne devrait poser aucun problme.10.4 Le PORTDTout dabord, il faut noter, mais vous laurez remarqu, que ce port nest prsent que surles 16F877, et non sur les 16F876. Je vous rappelle quafin dviter de traner partout desquivalences, quand je parle 16F877, jinclus le 16F874 et autres PICs compatibles. Il en vade mme pour le 16F876 par rapport au 16F873. Quand il y a une diffrence (comme la taillemmoire), je fais la distinction explicitement.113Une fois de plus, ce PORT fonctionne de faon identique aux autres, dans son mode defonctionnement gnral.Le registre TRISD comportera donc les 8 bits de direction, pendant que le registrePORTD correspond aux pins I/O concernes.Notez quici galement, les 8 pins I/O, en mode entre, sont du type trigger deSchmitt .Prenez garde que le fonctionnement de ce port dpend galement de la valeur que vousplacerez dans TRISE, qui concerne pourtant, premire vue, le PORTE. Mais, au momentdune mise sous tension, la valeur qui est place automatiquement dans TRISE configurevotre PORTD en port I/O de type gnral. Vous ne devez donc pas, priori, vous en occupersi vous voulez rester dans ce mode.10.5 Le PORTEDe nouveau, et fort logiquement, ce port nest prsent que sur les PICs de type 16F877.Il ne comporte que 3 pins, RE0 RE2, mais, contrairement aux autres ports, les bits nonconcerns de TRISE sont, cette fois, implments pour dautres fonctions.Vous remarquerez que les pins REx peuvent galement tre utilises comme pinsdentres analogiques. Cest de nouveau le registre ADCON1 qui dtermine si ce port serautilis comme port I/O ou comme port analogique.Par dfaut, le port est configur comme port analogique, et donc, comme pour le PORTA,vous devrez placer la valeur adquate dans ADCON1 pour pouvoir lutiliser comme port I/Onumrique. Notez cependant que la valeur 0x06 utilise dans lexplication pour le PORTA,place du mme coup votre PORTE en mode numrique.Vous navez donc, une fois de plus, rien ajouter votre fichier maquette pourfonctionner dans ce mode.Au niveau lectronique, les pins REx utilises en entre seront, une fois de plus, du type trigger de Schmitt .10.5.1 Le registre TRISELe registre TRISE dispose de certains bits de configuration qui ne sont pas prsents sur lesautres TRISx. Microchip a voulu probablement faire des conomies de registre en utilisant cesbits pour des fonctions qui ne relvent pas de la dtermination du sens des entres/sorties.Voyons donc le rle de chacun des bits de TRISE :b7 : IBF : Input Buffer Full status bitb6 : OBF : Output Buffer Full status bitb5 : IBOV : Input Buffer OVerflow detect bit114b4 : PSPMODE : Parallel Slave Port MODE select bitb3 : 0 : Non implment (lu comme 0 )b2 : : Direction I/O pour RE2 (1 = entre)b1 : : Direction I/O pour RE1b0 : : Direction I/O pour RE0Nous voyons que les bits 0 2 fonctionnent de faon identique ceux des autres TRISx.Un bit 1 positionne la pin en entre, un bit 0 la positionne en sortie.Les bits 7 5 seront tudis en temps utile, examinons plutt le bit 4 (PSPMODE).Cest ce bit qui dtermine si le PORTD (et non le PORTE) sera utilis en port I/Oclassique. Si vous placez 1 ici, le PORTD sera considr comme un port dinterfaage avec unmicroprocesseur. Nous y reviendrons dans le chapitre suivant.Par chance, si les bits 0 2 sont bien forcs 1 lors dune mise sous tension, plaantRE0 RE2 en entre, par contre, les autres bits sont forcs 0 lors de cette mise soustension. Donc le PORTD fonctionnera alors comme un port I/O classique, vous ne devez rienfaire de spcial.115Notes : 116Notes : 11711. Le PORTD en mode PSP11.1 A quoi sert le mode PSP ?Le mode PSP (pour Parallel Slave Port) permet un microprocesseur, ou tout autresystme extrieur de prendre le contrle du PORTD de votre PIC. Ce systme pourra crire delui-mme des valeurs sur le PORTD, et y lire des valeurs que votre programme PIC y auraprpare son intention.Le PORTD devra donc passer alternativement en entre et en sortie, et sous la seuledcision du systme extrieur. Cest donc celui-ci qui dcide quel moment une lecture ouune criture sopre. Les transferts sont donc raliss de faon asynchrones avec leprogramme de votre PIC.Voici un chapitre qui va intresser les lectroniciens pointus dsireux dinterfacer leurPIC avec un autre processeur, de faon , par exemple, obtenir un super UART.Pour les autres, ne vous inquitez pas si vous ne comprenez pas tout, car vous nutiliserezprobablement jamais cette possibilit, et, du reste, cela ne vous empchera pas de profiter desautres possibilits de votre PIC.La premire chose est de bien se mettre daccord sur les termes. Nous parlons ici duPORD en mode parallle. Il ne sagit pas ici du port parallle de votre imprimante, mais de lamthode de communication entre 2 microprocesseurs.Ensuite, il faut comprendre que ce mode est un mode Slave ( esclave), cest dire sousle contrle du microprocesseur sur lequel vous connectez votre PIC. Cest ce processeur quiva prendre le contrle de votre PORTD.11.1 Comment passer en MODE PSP ?Commencez par regarder la figure 3-9 du datasheet.Ceux qui sont attentifs et qui ont lu le chapitre prcdent ont dj un lment de rponse.La premire chose faire est de forcer le bit PSPMODE du registre TRISE 1 .Ensuite, vous voyez que les 3 pins RE0/RE2 sont utilises dans un de leur mode spcial etportent de fait les dnominations RD/CS/WR. Ces pins sont actives ltat bas. Ces pins sontsous contrle du microprocesseur matre, ce qui fait que vous devez les configurer en entrevia les bits b0/b2 de TRISE.Mais vous remarquez galement, si vous tes toujours attentif, que cest la valeur imposepar une mise sous tension, donc inutile de vous en occuper.Vous notez galement que le PORTD passe sous contrle de ces pins, le registre TRISDnest donc plus daucune utilit : inutile de le configurer.118Notez que dans la plupart des cas, vous utiliserez les interruptions pour grez ce mode defonctionnement, vous devez donc mettre en service linterruption PSP comme indiqu dans lechapitre sur les interruptions.En effet, les changes dinformation se font sur dcision du microprocesseur matre, etdonc de faon asynchrone avec le programme de votre PIC. Les interruptions restent lameilleure faon de traiter rapidement les vnements asynchrones.11.2 Connexion des PORTD et PORTE en mode PSPSi nous reprenons nos 3 pins du PORTE, avec les noms utiliss pour cette fonction, cest dire RD, CS, et WR, nous pourrons dire :La pin CS est la pin Chip Select , que tous les lectroniciens spcialiss dans lesmicroprocesseurs connaissent.Pour les autres, on peut dire que le Chip Select permet de valider la slection du circuitconcern, en loccurrence notre PIC.Sur la carte microprocesseur, un dtecteur dadresse, plac sur le bus dadresse permetde slectionner ladresse laquelle va rpondre notre PIC. Comme dans la plupart dessystmes, ce CS sera actif ltat bas.Je pourrais donner ici un cours complet sur les techniques dinterfaages, mais ce nestpas le but de cet ouvrage. Je part du principe que quelquun qui veut interfacer son PIC avecune carte microprocesseur possde suffisamment de connaissances ce niveau pour sepasser de mes explications.Si ce ntait pas le cas, et si je recevais du courrier prcis concernant ce point, jajouteraiune annexe pour en parler.Ensuite, nous trouvons les signaux RD pour ReaD et WR pour WRite . Denouveau ces signaux sont actifs ltat bas. Notez que sur certains microprocesseurs, ilnexiste quune seule pin RD/WR. A vous donc dans ce cas de gnrer lectroniquement les 2signaux, ce qui nest pas compliqu.Maintenant, concernant le PORD, il sera connect au bus de data de la carte microprocesseur.Notez, une fois de plus, que sur certains microprocesseurs, les bus de data et dadressepeuvent tre multiplexs, ou dune largeur diffrente de 8 bits. Il vous incombe une fois deplus de rendre les signaux et les messages compatibles lectroniquement.11.3 Le fonctionnement logicielMaintenant que tout est configur et que le PIC est interfac, voyons comment fonctionnelensemble au niveau software.119En fait, la procdure est simple, vous voyez donc quil existe 2 cas : soit lemicroprocesseur crit dans le pic, soit il lit.Considrons tout dabord une criture.- Le microprocesseur excute une criture de DATA ladresse du PIC.- La DATA est mmorise dans le tampon (latch) de lecture du PIC.- Le flag dinterruption PSPIF est positionn, ainsi que le bit IBF du registre TRISE- Si linterruption est autorise, une interruption est gnre- Le programme lit le latch pour savoir quelle valeur a t crite par le microprocesseur, cequi provoque galement le reset du bit IBF (Input Buffer Full = buffer dentre plein) Si on regarde ce qui se passe au niveau du PIC, on aura tout simplement :- Le flag PSPIF est positionn, et une interruption a ventuellement lieu- Le programme excute un movf PORTD,w pour rcuprer la donne crite par lemicroprocesseur.- Le test de IBF et OBF permet de savoir si on a eu affaire une lecture ou une criture.Notez que lorsque vous lisez le PORTD, vous obtenez non pas le niveau prsent sur lespins RD0 RD7, mais la valeur que le microprocesseur a crite directement dans letampon dentre.Il se peut bien entendu que le microprocesseur crive une seconde donne dans lePORTD du PIC, avant que celui-ci nait eu le temps de lire la donne prcdente.Dans ce cas, cette prcdente donne est perdue, et le bit IBOV est positionn poursignaler lutilisateur quun crasement a eu lieu et quau moins une des donnestransmises est perdue.Vous voyez donc que tout ceci est extrmement simple. Ce nest pas plus compliqu auniveau dune lecture de donne depuis le microprocesseur : - Le PIC crit sa donne dans le latch dcriture, qui est galement PORTD.- Ceci provoque le positionnement du bit OBF (Ouput Buffer Full = buffer de sortie plein)- Quand le microprocesseur le dcide, il effectue une lecture du PORTD, et rcupre alorsla valeur que vous y avez crite- Le flag OBF passe 0 ds que le cycle de lecture est commenc- Le flag PSPIF est positionn une fois la fin du cycle de lecture termin120- Une interruption est alors ventuellement gnre si elle a t autoriseSi on regarde au niveau du PIC, on aura tout simplement :- On crit la valeur envoyer au processeur dans PORTD- On est prvenu que la valeur a t lue par le positionnement du flag PSPIF, et,ventuellement, par lapparition de linterruption correspondante.- Le test de IBF et OBF permet de savoir si on a eu affaire une lecture ou une criture.Notez que le tampon de lecture possde la mme adresse que le tampon dcriture. Cetteadresse est tout simplement le registre PORTD. Attention, ces tampons sont physiquementdiffrents, donc en crivant dans PORTD vous ne dtruisez pas ce que le microprocesseur acrit. Autrement dit, vous ne lisez pas ce que vous avez crit, mais ce que le microprocesseura crit.Pour faire simple, quand vous crivez dans PORTD, vous crivez dans un registrediffrent de celui que vous accdez en lisant PORTD. Vous avez donc 2 PORTD .Remarquez donc que dans ce mode, lcriture dune valeur dans PORTD ne se traduit parlapparition de cette valeur sur les pins RDx quau moment o le microprocesseur effectueune requte de lecture du PORTD.Le PORTD est donc sous le contrle total du microprocesseur extrieur.11.4 Le fonctionnement matrielLes chronogrammes des figures 3-10 et 3-11 du datasheet vous donnent les droulementschronologiques des diffrentes tapes.Un spcialiste des techniques microprocesseurs naura aucun mal les interprter, jevais cependant vous les rsumer de faon simple, et en clair . Voyons tout dabord lachronologie dune criture.Avant tout, souvenez-vous que dans un change, nous nous plaons du point de vue dumatre, cest--dire du microprocesseur. Il sagit donc dune criture dans le PIC, donc dunelecture au niveau du programme du PIC.Souvenez-vous galement quun cycle dinstruction est compos de 4 clocks dhorloge,nomms Q1 Q4. La frquence de fonctionnement du PIC est en effet gale la frquence delhorloge divise par 4.Voici donc les vnements hardware et leurs implications software du cycle dcriture :- La donne est place sur le PORTD par le microprocesseur (en connexion avec le bus dedonnes) et doit rester stable jusqu la fin de lordre dcriture121- Au minimum 20 25 ns plus tard, les lignes de contrle CS et WR sont places ltatbas (peu importe lordre)- La ligne WR ou CS ou les deux repasse(nt) 1, la data est capture dans le latch dentredu PIC- Le microprocesseur doit maintenir la donne stable encore durant 20 35ns- Au temps Q4 qui suit, IBF et PSPIF passent simultanment 1.Quant au cycle de lecture (on suppose que la donne se trouve dj dans le latch de sortiedu PIC).- Les lignes de contrle RD et CS sont places ltat bas (peu importe lordre)- A ce moment, le bit OBF passe 0- Le PIC place la donne sur les lignes RD0 RD7- Au minimum 80 90ns plus tard, le microprocesseur effectue la lecture de la donne- Il remonte ensuite la ligne RD ou CS, ou les 2.- La donne disparat des lignes RD0 RD7 entre 10 et 30ns plus tard- Au cycle Q4 suivant du PIC, le bit PSPIF est positionn, ce qui provoqueraventuellement une interruptionCe chapitre tait particulirement ardu comprendre, jen suis conscient. Les explicationsrisquent cependant de vous tre utiles un jour, cest pourquoi jai abord le sujet de faonassez dtaille.Vous vous rendez compte quil mest particulirement difficile de vous donner unexercice pratique mettant en uvre ce mode particulier, car cela ncessiterait de construireune seconde carte gre en matre par un microprocesseur.Mais je suis convaincu quune fois cet ouvrage et le prcdent assimils, vous pourrezconstruire le cas chant votre programme de communication inter-processeurs.122Notes :12312. Les accs la mmoire eepromLes accs en mmoire eeprom ne sont pas plus compliqus que pour le 16F84. Il suffit eneffet de respecter la procdure indique par Microchip.Le fichier maquette que je vous fournis contient 2 macros destines lcriture et lalecture en eeprom.Ces macros mettent en jeu 4 registres, savoir EEADR, EEDATA, EECON1, etEECON2. Ces registres ont dj t dcris dans la premire partie consacre au 16F84.Nanmoins, le registre EECON1 subit pour cette version quelques modifications que nousallons dcrire.Le registre EEADR est toujours utilis pour placer ladresse relative en EEPROM, tandisque EEDATA contiendra la donne lue ou crire.Comme pour le 16F84, le registre EECON2 nen est pas vritablement un. Microchiplutilise en tant que registre de commande. Lcriture de valeurs spcifiques dans EECON2provoque lexcution dune commande spcifique dans llectronique interne du PIC.Vous disposez dune zone de 128 octets en mmoire EEPROM pour les modles16F873/4, et dune zone de 256 octets pour les modles 16F876/7.Ladresse relative de laccs EEPROM est donc compris entre 0x00 et 0xFF, ce quipermet de nutiliser quun registre de 8 bits pour dfinir cette adresse, tout comme sur le16F84.12.1 Le registre EECON1b7 : EEPGD : EEprom ProGram/Data select bitb6 : N.U. : Non Utilisb5 : N.U. : Non Utilisb4 : N.U. : Non Utilisb3 : WRERR : WRite ERRor flag bitb2 : WREN : WRite ENableb1 : WR : WRite control bitb0 : RD : ReaD control bitLe bit EEPGD permet de slectionner si on dsire crire en mmoire EEPROM ou enmmoire FLASH. Et oui, cest possible au niveau du 16F87x, nous verrons comment dans lechapitre suivant. Il sagit donc dun nouveau bit, qui nexistait pas sur le EECON1 du 16F84.Par contre, nous constatons la disparition du bit EEIF (le flag dinterruption de findcriture EEPROM). Celui-ci a tout simplement migr vers le registre PIR2, vous vous ensouvenez peut-tre.Les autres bits demeurent inchangs, avec pour rappel :124- WRERR qui indique une interruption anormale du cycle dcriture (par exemple, unreset)- WREN qui permet dautoriser les oprations dcriture (sorte de scurit pour viter lescritures accidentelles)- WR qui permet de lancer le cycle dcriture- RD qui permet de lancer le cycle de lecturePassons maintenant aux applications concrtes :12.2 Laccs en lectureCommenons par examiner la procdure de lecture, via la macro concerne :REEPROM macro ; lire eeprom(adresse & rsultat en w)clrwdt ; reset watchdogbcf STATUS,RP0 ; passer en banque2bsf STATUS,RP1movwf EEADR ; pointer sur adresse eeprombsf STATUS,RP0 ; passer en banque3bcf EECON1,EEPGD ; pointer sur eeprombsf EECON1,RD ; ordre de lecturebcf STATUS,RP0 ; passer en banque2movf EEDATA,w ; charger valeur luebcf STATUS,RP1 ; passer en banque0endmLa procdure est extrmement simple. Elle consiste tout simplement crire ladresserelative EEPROM concerne dans le registre EEADR, de positionner le bit RD, et dercuprer la valeur lue qui se trouve alors dans le registre EEDATA.Pour cette macro, ladresse de lecture est passe dans le registre W , la valeur lue estgalement retourne en W.Nous pouvons donc appeler cette macro par une portion de code comme ceci :movlw adreseeprom ; charger ladresse de lecture dans WREEPROM ; lire EEPROMmovwf madata ; sauver valeur lueRien donc de particulier ou de neuf dans cette procdure. La seule chose se souvenir,cest que lemplacement physique rel de lEEPROM commence ladresse 0x2100, alorsque ladresse relative que nous devons employer dans notre programme commence, elle, lavaleur 0x00. Autrement dit, lorsque vous accdez ladresse EEPROM 0x01 dans votreprogramme, la donne se trouvera physiquement ladresse 0x2101 de votre PIC.Notez que linstruction clrwdt nest pas vraiment ncessaire, mais est utile lors delappel successif de la macro.12512.3 Laccs en critureProcdons comme pour la lecture, en examinons la macro de notre fichier maquette.WEEPROM macro addwrite ; la donne se trouve dans WLOCAL loopbcf STATUS,RP0 ; passer en banque2bsf STATUS,RP1movwf EEDATA ; placer data dans registremovlw addwrite ; charger adresse d'crituremovwf EEADR ; placer dans registrebsf STATUS,RP0 ; passer en banque3bcf EECON1 , EEPGD ; pointer sur mmoire databsf EECON1 , WREN ; autoriser accs criturebcf INTCON , GIE ; interdire interruptionsmovlw 0x55 ; charger 0x55movwf EECON2 ; envoyer commandemovlw 0xAA ; charger 0xAAmovwf EECON2 ; envoyer commandebsf EECON1 , WR ; lancer cycle d'criturebsf INTCON , GIE ; rautoriser interruptionsloopclrwdt ; effacer watchdogbtfsc EECON1 , WR ; tester si criture terminegoto loop ; non, attendrebcf EECON1 , WREN ; verrouiller prochaine criturebcf STATUS , RP0 ; passer en banque0bcf STATUS , RP1endmIci, nous aurons 2 paramtres passer la macro, savoir la donne crire, et ladresse laquelle on doit crire cette donne. Comme nous navons quun seul registre W, nouschoisirons donc dajouter un argument cette macro, argument appel addwrite pouradresse dcriture. La valeur est donc passe dans W, ladresse est donne en argument.La procdure nest gure complique : on commence par mettre la donne crire dansEEDATA et ladresse dcriture dans EEADR. Ensuite, on met en service les critures sur lammoire eeprom.On interdit ensuite les interruptions (recommand par Microchip), et on excute btement la squence de lancement de lcriture. On peut alors rautoriser lesinterruptions.Il nous faut ensuite attendre la fin de lcriture, aprs quoi on peut de nouveau remettrele verrou en interdisant de nouveau les critures.Il faut cependant tre attentif et noter quelques particularits de notre macro.En premier lieu, vous constatez que notre macro replace le bit GIE 1 afin de rautoriserles interruptions prcdemment interdites. Il va de soi que sil nest pas souhaitable que ce bitsoit positionn dans votre programme, il vous faudra alors supprimer les lignes concernantGIE dans la macro.126Ensuite, la boucle dattente deffacement de WR (qui repasse 0 une fois lcrituretermine) peut tre remplace par une mise en sommeil du PIC. Vous savez en effet quil estpossible de rveiller le PIC sur le positionnement dun flag dinterruption. Le flag concern(EEIF) permet donc, en fin dcriture, de rveiller le PIC.Vous pouvez galement vous dire quil est dommage dattendre la fin de lcriture avantde poursuivre votre programme. En effet, si vous navez quune seule valeur crire, rien nevous interdit dexcuter des instructions durant que le PIC effectue lcriture EEPROM eninterne. Ce que vous ne pouvez pas faire, cest procder une nouvelle criture avant que laprcdente ne soit termine.Vous pouvez alors imaginer, condition de laisser en permanence le bit WRENpositionn, de tester WR AVANT de procder lcriture. Ainsi, la premire criture nattendpas, la seconde attendra que la premire soit termine avant dcrire, mais nattendra pas quela seconde soit acheve avant de sortir. Il suffit alors de dplacer la boucle avant la squenceimpose pour lcriture.Enfin, noubliez pas que vous pouvez utiliser les interruptions pour tre prvenu de la finde lcriture, et donc de la possibilit dcrire loctet suivant.Je vous rappelle que la dure de vie minimale garantie de leeprom est de 100.000 cyclesdcriture par adresse.A titre dinformation, lcriture dun octet en mmoire eeprom ncessite une dure delordre de 4ms. Avec un 16F876 cadenc 20MHz, cela reprsente pas moins de 20.000cycles dinstruction. Vous voyez donc que les critures en EEPROM ncessitent normmentde temps lchelle du PIC. La petite boucle qui semble anodine, en place de lutilisation desinterruptions, vous fait donc perdre 20.000 cycles (et tout a en 3 lignes). Notez que le clrwdt nest en ralit pas ncessaire, puisque lcriture ne prend quau maxium 4ms, maisest utile dans le cas dexcutions successives de cette mme macro. Ca ne change du reste rienau temps perdu dans la boucle dattente.12.4 Initialisation dune zone eepromNous lavions dj vu, mais pour complter ce chapitre, je vais le rappeler. La directivepour dclarer des valeurs en EEPROM est DE . Notez que ces valeurs seront alors critesen EEPROM directement au moment de la programmation. Ne pas oubliez dans ce cas deprcder la directive DE de la directive ORG pointant sur un emplacement EEPROMvalide (de 0x2100 0x21FF).Exemple :ORG 0x2100 ; zone eepromDE 2,4,8,2 ; mettre 2 dans 0x2100, 4 dans 0x2101 etc.DE A ; mettre A (0x41) en 0x210412713. Les accs la mmoire programme13.1 GnralitsVoici une possibilit intressante qui nexiste pas sur notre bon vieux 16F84 : lapossibilit dcrire des donnes dans la mmoire de programme, cest--dire en mmoireFLASH.Nous allons voir que les procdures sont fort semblables aux accs en mmoire eeprom.Les registres utiliss pour ces premiers le sont galement ici.Seulement, il faut que vous vous rappeliez que la mmoire de programme est constitue,non pas doctets, mais de mots de 14 bits. Donc, lcriture et la lecture concerne des mots de14 bits.Vous vous rendez bien compte quun mot de 14 bits ne peut pas tenir dans un registre de 8bits. Donc les donnes devront tre passes par le biais de 2 registres.Si, maintenant, nous raisonnons sur ladresse concerne par lopration de lecture oudcriture, nous voyons trs bien galement que cette adresse ne pourra tenir dans un seulregistre. En effet, la zone mmoire se caractrise par une adresse construite sur 13 bits. Cecinous impose donc de nouveau 2 registres pour la dfinition de ladresse.Forts de ce qui prcde, nous pouvons alors en conclure que nous aurons besoin de 2registres supplmentaires, ajouts aux 4 registres utiliss pour les accs EEPROM.Nous aurons donc pour ladressage, les registres EEADR et EEADRH. Vous comprenezimmdiatement (je lespre) que le registre EEADRH contient les bits de poids fort (Hight) deladresse daccs.De mme, nous aurons pour les donnes, les registres EEDATA et EEDATH. Ce dernier,galement, contient les bits de poids fort de la donne lue ou crire.Attention de bien vous souvenir que les donnes en mmoire programme sont des donnesde 14 bits (forcment la mme longueur que les instructions), alors que les adresses sontcodes sur 13 bits.EEADRH contiendra donc au maximum 5 bits utiles, alors que EEDATH en contiendra 6.J espre que jusqu prsent, cest clair. Si a ne ltait pas, relisez calmement ce quiprcde.13.2 Les accs en lectureCommenons par le plus simple, une lecture de donne dans la mmoire programme.Voyons donc le code suivant :128bcf STATUS,RP0 ; passer en banque 2bsf STATUS,RP1movlw high adresse ; charger octet fort adressemovwf EEADRH ; placer dans pointeur adresse hautmovlw low adresse ; charger octet faible adressemovwf EEADR ; placer dans pointeur adresse basbsf STATUS,RP0 ; passer banque 3bsf EECON1,EEPGD ; pointer sur mmoire flashbsf EECON1,RD ; lancer la lecturebcf STATUS,RP0 ; passer banque2nop ; 2 cycles ncessairesmovf EEDATA,w ; charger 8 lsbxxxx ; sauver ou utiliser 8 lsbmovf EEDATH,w ; charger 6 msbxxxx ; sauver ou utiliser 6 msbbcf STATUS,RP1 ; passer banque0Si vous regardez attentivement, vous voyez, dans cette portion de code, 2 directives. Ilsagit de high et de low . Leur utilisation est trs simple : high signale MPASM quil doit prendre loctet de poids fort de la donne sur 16 bitsplace derrire. low , fort logiquement, indique quil faut prendre loctet de poids faible.Prenons un exemple concret avec la portion de code suivante :ORG 0x1F05labelmovlw low label ; on charge donc low 0x1F05, donc on charge 0x05movlw high label ; on charge donc high 0x1F05, donc on charge 0x1FCe nest pas plus compliqu que a. Examinons maintenant la structure de notre lecture enmmoire FLASH.On commence par initialiser les 2 pointeurs dadresse, en utilisant les 2 directivesprcdentes. adresse reprsente dans ce cas une tiquette place dans notre zone dedonnes (nous verrons un exemple concret).Ensuite, on signale quon travaille en mmoire FLASH, et non en mmoire EEPROM, enpositionnant le bit EEPGD, puis on lance la lecture.Le PIC va mettre 2 cycles pour lire la donne en FLASH. Durant ces 2 cycles, Microchipsuggre dutiliser 2 instructions nop . Jai cependant profit du fait que je devais changerde banque pour utiliser utilement un de ces 2 cycles. Ne reste donc quun nop . Notez quedurant ces 2 cycles, certains registres, comme EEADR sont inaccessibles. Prudence donc sivous tentez dutiliser lautre cycle pour raliser une opration. A vous de tester, comme je laifait.Donc, aprs ces 2 cycles, nous pouvons rcuprer les 14 bits de la donne, dans lesregistres EEDATA et EEDATH et en faire lusage que nous voulons. Notez que rien ne vousempche de nutiliser que le registre EEDATA si vous nutilisez que 8 bits.Une fois de plus, la routine ne prsente aucune difficult particulire. Voyons maintenantlcriture.12913.3 Les accs en critureLa procdure dcriture ne prsente pas non plus de difficult particulire, il convientsimplement dtre attentif certains points prcis. Voyons donc cette portion de code :bcf STATUS,RP0 ; passer en banque 2bsf STATUS,RP1movlw high adresse ; charger octet fort adressemovwf EEADRH ; placer dans pointeur adresse hautmovlw low adresse ; charger octet faible adressemovwf EEADR ; placer dans pointeur adresse basmovlw datahaute ; 6 bits hauts de la donne criremovwf EEDATH ; placer dans registre data hautemovlw databasse ; 8 bits bas de la donne criremovwf EEDATA ; dans registre data bassebsf STATUS,RP0 ; passer banque 3bsf EECON1,EEPGD ; pointer sur mmoire programmebsf EECON1,WREN ; autoriser les critures (verrou)bcf INTCON,GIE ; interdire les interruptionsmovlw 0x55 ; charger 0x55movwf EECON2 ; envoyer commandemovlw 0xAA ; charger 0xAAmovwf EECON2 ; envoyer commandebsf EECON1 , WR ; lancer cycle d'criturenop ; 2 cycles inutilisablesnopbsf INTCON,GIE ; rautoriser les interruptionsbcf EECON1,WREN ; rinterdire les critures (verrou).Vous constatez que, tout comme la procdure de lecture en mmoire programme est fortsemblable celle de lecture en EEPROM, celle dcriture en mmoire programme est fortsemblable celle dcriture en EEPROM.Nous commenons, en effet, par placer ladresse dans les 2 pointeurs (souvenez-vous, 13bits).Ensuite, nous plaons la donne dans les 2 registres prvus. Notez que rien ne vous obligedutiliser les 14 bits, si vous souhaitez mmoriser des octets, il vous suffit de ne pas utiliserEEDATH.Il nous faut maintenant indiquer que nous travaillons en mmoire programme, enpositionnant EEPGD.Vient, une fois de plus, la procdure standard dcriture impose par Microchip. Commedans le cas prcdent, cette procdure utilise des valeurs placer dans le registre fictifEECON2.Le Pic va alors sarrter, le temps deffectuer lcriture dans la mmoire programme.Lorsquil se rveillera, entre 4 et 8 ms plus tard, les 2 instructions suivantes ne seront pasexcuts.Celui-ci va continuer avancer dans le droulement du programme, mais ninterprterapas les 2 commandes suivantes. Je vous conseille donc (tout comme Microchip) de mettre 2 nop cet endroit. Ce temps est ncessaire au PIC pour crire les donnes en mmoireprogramme.130Vous pouvez maintenant, si vous le voulez, rautoriser les interruptions, puis remettre leverrou de protection des critures.13.4 Particularits et mise en gardeVous constatez donc que les mthodes daccs sont fort semblables pour les accs enEEPROM et en FLASH. Il importe toutefois de bien cerner quelques diffrences notables.1) Les accs en EEPROM sont limits 256 emplacements, alors quen mmoireprogramme, vous avez accs lintgralit des 2Kmots de la mmoire. Vous pouvez donccrer, par exemple, de plus gros tableaux.2) Les donnes stockes en EEPROM ont une taille limite 8 bits, alors que les donnesstockes en mmoire programme ont une taille maximale de 14 bits.3) Vous ne pouvez crire dans la mmoire programme que si vous avez prcis_WRT_ENABLE_ON dans votre directive de configuration.Forts de tout ceci, vous allez me dire maintenant alors je vais utiliser toujours lescritures en mmoire programme, puisquil ny a que des avantages .Malheureusement, il y a un inconvnient, et il est de taille :La dure de vie garantie de la mmoire FLASH est seulement de 1000 cycles dcriture,contre 100.000 pour la mmoire EEPROM. Donc, vous voyez quune utilisation tropintensive de ce type dcriture peut mener trs rapidement la destruction du PIC.Si vous vous trompez dans la ralisation de votre programme, par exemple, et que votreroutine dcriture en mmoire programme tourne en boucle continue, ceci provoquera ladestruction thorique de votre flash au bout de 1000 boucles.Sachant quune procdure complte prend de lordre de 4ms 8ms, ceci nous donne unedure de vie de lordre de 4000 8000ms . Votre PIC serait donc dtruit aprs 8s maximum.Vous voyez donc quil faut tre extrmement prudent dans lutilisation de cette routine. Vousvoyez donc lintrt du bit de verrou (WREN).Notez que les toutes dernires versions de 16F87xx ont vu la dure de vie de la mmoireflash augmente dun facteur 100. A vous de vrifier le moment venu si ncessaire.Voici, pour ma part comment jutilise ces diffrentes zones :En gnral, jutilise les donnes en mmoire programme pour les donnes fixes, cest--dire crites au moment de la programmation. Jvite donc dutiliser la routine dcriture enmmoire FLASH. Jutilise par contre rgulirement celle de lecture, qui nest pas destructive.Je place les paramtres qui sont susceptibles de modifications ventuelles en mmoireEEPROM, dans la mesure du possible.131Ceci explique que je vais raliser un exercice avec vous qui nutilise que la lecture enmmoire programme. Mais une fois la lecture comprise, lcriture lest aussi, il suffit derecopier la procdure standardise.13.5 Initialisation dune zone en mmoire programmeVous allez me dire quil suffit dutiliser la directive DE . Malheureusement, cettedirective ne permet que dcrire des donnes de la taille dun octet.Mais, en cherchant un peu dans les directives autorises, nous trouvons la directive DA , qui est lorigine prvue pour crire des chanes de caractres en mmoireprogramme. Elle saccommode fort bien de donnes de la taille de 14 bits.Un petit exemple vaut mieux quun long discours :ORG 0x0200DA 0x1FF, 0x155 ; place 1FF en mmoire programme 0x200 et 0x155 en 0x201DA 0xFFFF ; devrait placer 0xFFFF en mmoire 0x202, mais, la taille ; dune case de mmoire programme tant limite 14 bits,; la valeur relle sera de 0x3FFF13.6 La technique du bootloader .Je nentrerai pas ici dans les dtails, puisque jutiliserai cette possibilit dans la troisimepartie du cours. Je vous explique simplement en quoi consiste le raisonnement.On part du principe que le PIC peut crire dans la mmoire programme.On place donc une portion de code en mmoire haute, qui va communiquer avec unpriphrique extrieur afin de recevoir un programme excuter (ce peut tre un PC, uneEPROM externe, etc.).Ce programme sera charg par la routine du PIC, et plac en zone dexcution. Ainsi, lePIC se sera programm tout seul, sans lintervention dun programmateur.La seule limite est quil faut pralablement charger le programme dcriture (Bootloader) laide dun programmateur classique, et lactiver au moment opportun. Jy reviendrai, carcela autorise de nouvelles perspectives.13.6 Application pratique : un chenillardVoici qui clture la thorie sur ce sujet. Mais je ne vais pas vous laisser l. Nous allonsdonc, si vous voulez bien, raliser un exemple pratique. Et, pour faire quelque chosedoriginal, qui diriez-vous dun petit jeu de lumire, style chenillard ?Je vous donne le schma utilis. Notez que ce chenillard ne ncessitera que 8 LEDs enplus de notre PIC. Je vous donnerai cependant un petit schma qui vous permettra, si vous levoulez, de piloter directement des spots 220V.132Voyons dabord le chenillard LEDs :Vous voyez que cest on ne peut plus simple, et ne vous ruinera pas.Pour ceux qui dsirent utiliser des lampes 220V, voici le schma que je leur propose.ATTENTION DANS CE CAS : LES TENSION MISES EN JEU PEUVENTETRE MORTELLES. IL EST DE CE FAIT HORS DE QUESTION DE REALISER CEMONTAGE SUR UNE PLATINE DESSAIS. UN CIRCUIT IMPRIME DEVRA ETREREALISE, MIS EN BOITIER, ET LES MESURES DE SECURITE CORRECTES(TERRES, FUSIBLES, CEM) DEVRONT ETRE PRISES.Donc, si vous ntes pas un habitu des montages lectroniques, ignorez ce schma, il y vade votre scurit. Ralisez la version LEDs.133Afin davoir une ide de ce que nous avons faire, nous allons crer un pseudo-code .Ceci prsente lavantage de pouvoir dfinir les diffrentes fonctions dont nous aurons besoin,et la faon donc elles vont sarticuler.Un pseudo-code nest jamais que la description en franais de ce que notre programme vadevoir raliser. Jaurais pu utiliser un ordinogramme, mais il faut varier les plaisirs, etsatisfaire tout le monde. Jai souvent remarqu que les partisans du pseudo-code taient defarouches adversaires des ordinogrammes, et inversement.Pour ma part, je ne vois pas en quoi lutilisation de lun empche lutilisation de lautre.Tout est histoire de felling et dpend galement de lapplication en elle-mme. Certainsprogrammes se laissant mettre plus volontiers dans une forme que dans une autre.Nous allons devoir lire des valeurs successives dans la mmoire programme, et envoyer cesvaleurs sur le PORTB, afin dallumer les LEDS concernes.Bien entendu, afin de rester une chelle de temps humaine , nous allons devoirtemporiser entre 2 allumages successifs. Dans le cas contraire, nous naurions le temps de rienvoir.Nous allons donc imaginer que nous allumerons les LEDs une vitesse de lordre de 5allumages par seconde. Ceci nous donnera donc un temps dattente de lordre de 200ms.Voyons donc ce que nous donne notre pseudo-code :DbutInitialisation du systmeBoucleJe lis 1 octet en FLASHJe lenvoie sur le PORTBJattends 200msJe recommence la boucleVous voyez, a prsente lavantage dtre clair.Nous voyons donc que nous aurons besoin dune routine pour lire en FLASH, duneroutine de temporisation, quant lenvoi sur le PORTB, il ne ncessite quune instruction.Il nous faut cependant rflchir la routine de lecture dun octet en flash. Nous allonsdevoir pointer sur le dbut de notre zone de donnes, et, une fois toutes les donnes envoyes,nous devrons recommencer. Il nous faut donc dterminer quand nous arrivons au bout de lazone de donnes.On pourrait indiquer la longueur totale, et compter les octets, mais ceci ncessiteradutiliser un compteur de 16 bits, pour le cas o nous dciderions dentrer plus de 256donnes.Il serait ingnieux de penser que nous avons 8 LEDs piloter, et que nos donnescomportent 14 bits. Il nous reste donc 6 bits qui ne sont pas utiliss. Pourquoi dans ce cas nepas dcider quun des bits positionn 1 indique que la dernire valeur est atteinte ? Nouschoisirons par exemple le premier bit libre, savoir le bit 8.134 Notre sous-routine pourra alors tre du type :Lire en FlashLire un mot en flashIncrmenter pointeur FLASH pour prochaine lectureBit 8 = 1 ?Si oui, pointer sur premire donne en flashRetourReste notre routine de temporisation, et, pour savoir si la temporisation est termine, jepropose de se servir de linterruption timer0, qui positionnera un flag pour le signaler.Sachant que nous voulons une valeur approximative de 200ms, nous utiliserons unprdiviseur de 256, ce qui nous donne un temps maxi de (256*256)/5000000, soit 13,1 ms.Pour obtenir nos 200ms, nous devrons donc passer approximativement 15 fois dans notreroutine dinterruption, avant de signaler que le temps est coul.Interruption timer0Dcrmenter compteurCompteur = 0 ?Oui, positionner flag tmpEt recharger compteur avec la valeur 15Retour dinterruptionNotre sous-routine de temporisation devient alors tout simplement :TempoFlag tmp positionn ?Non, boucler sur tempoOui, effacer flag tmpet retourVous voyez donc que nous avons de la sorte ralis notre programme. Il ne reste plusqu remplacer les phrases en franais par des instructions.Nous allons donc maintenant nous intresser au programme en langage dassemblage.Commencez, comme dhabitude, par effectuer un copier/coller de votre fichier m16F876.asm . Renommez la copie en lum1.asm . Crez un projet et chargez ce fichier.Crons tout dabord notre zone de commentaires, comme je vous le rpte sans arrt (oui,je sais, je suis casse-bonbons ce niveau).;*****************************************************************************; Ralisation d'un mini-chenillard 8 LEDs *; *;*****************************************************************************; *; NOM: Lum1 *; Date: 23/04/2002 *; Version: 1.0 *; Circuit: Circuit maquette (ou C.I. si lampes 220V) *; Auteur: Bigonoff *; *;*****************************************************************************; *; Fichier requis: P16F876.inc *135; lumdat.inc *; *;*****************************************************************************; *; Notes: les 8 sorties sont sur le PORTB. Un niveau haut allume la LED *; correspondante. *; Exercice sur les lectures en mmoire FLASH *; La frquence du quartz est de 20MHz *; *;*****************************************************************************Maintenant, intressons-nous la configuration, ainsi qu lhabituel include . Jaidcid de mettre le watchdog en service, le reset de la configuration tant des plus classiques :LIST p=16F876 ; Dfinition de processeur#include ; fichier include__CONFIG _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_OFF & _CPD_OFF & _LVP_OFF &_BODEN_OFF & _PWRTE_ON & _WDT_ON & _HS_OSC;_CP_OFF Pas de protection;_DEBUG_OFF RB6 et RB7 en utilisation normale;_WRT_ENABLE_OFF Le programme ne peut pas crire dans la flash;_CPD_OFF Mmoire EEprom dprotge;_LVP_OFF RB3 en utilisation normale; _BODEN_OFF Reset tension hors service;_PWRTE_ON Dmarrage temporis;_WDT_ON Watchdog en service;_HS_OSC Oscillateur haute vitesse (20Mhz)Ensuite, nous avons les valeurs qui seront places dans les diffrents registres linitialisation. Il suffit de se rappeler que nous allons travailler avec le PORTB en sortie(donc, inutile de mettre les rsistance internes en service), et que nous avons besoin duneinterruption sur le timer0, avec un prdiviseur de 256.Nous neffacerons pas tous les registres inutiliss, car je compte rutiliser ceprogramme plus loin dans le cours, afin de lamliorer avec de nouvelles fonctions. Effacezdonc seulement les assignations pour PIE2, et celle concernant le PORTC.;*****************************************************************************; ASSIGNATIONS SYSTEME *;*****************************************************************************; REGISTRE OPTION_REG (configuration); -----------------------------------OPTIONVAL EQU B'10000111'; RBPU b7 : 1= Rsistance rappel +5V hors service; PSA b3 : 0= Assignation prdiviseur sur Tmr0; PS2/PS0 b2/b0 : valeur du prdiviseur; 111 = 1/256; REGISTRE INTCON (contrle interruptions standard); -------------------------------------------------INTCONVAL EQU B'00100000'; GIE b7 : masque autorisation gnrale interrupt; PEIE b6 : masque autorisation gnrale priphriques; T0IE b5 : masque interruption tmr0; INTE b4 : masque interuption RB0/Int136; RBIE b3 : masque interruption RB4/RB7; T0IF b2 : flag tmr0; INTF b1 : flag RB0/Int; RBIF b0 : flag interruption RB4/RB7; REGISTRE PIE1 (contrle interruptions priphriques); ----------------------------------------------------PIE1VAL EQU B'00000000'; PSPIE b7 : Toujours 0 sur PIC 16F786; ADIE b6 : masque interrupt convertisseur A/D; RCIE b5 : masque interrupt rception USART; TXIE b4 : masque interrupt transmission USART; SSPIE b3 : masque interrupt port srie synchrone; CCP1IE b2 : masque interrupt CCP1; TMR2IE b1 : masque interrupt TMR2 = PR2; TMR1IE b0 : masque interrupt dbordement tmr1; REGISTRE ADCON1 (ANALOGIQUE/DIGITAL); ------------------------------------ADCON1VAL EQU B'00000110' ; PORTA en mode digital; DIRECTION DES PORTS I/O; -----------------------DIRPORTA EQU B'00111111' ; Direction PORTA (1=entre)DIRPORTB EQU B'00000000' ; Direction PORTBEnsuite, les assignations du programme. Pour linstant, nous savons dj que nous avonsune constante, savoir les 15 passages dans linterruption du timer0 pour atteindre nos200ms. Dfinissons donc cette constante qui va servir recharger le compteur (recharge enanglais se dit reload ) . Jutilise souvent des noms de variables ou de fonctions en anglais,car langlais est plus court et ne comporte pas daccents.;*****************************************************************************; ASSIGNATIONS PROGRAMME *;*****************************************************************************RELOADEQU D'15' ; nombre de passages dans tmr0Prenez garde, une fois de plus, de ne pas tomber dans le pige grossier qui consisterait oublier le D . Dans ce cas, vous auriez 0x15 passages, soit D21 passages. Je suis certainque certains taient prts tomber dans le panneau.Je vous rappelle que la meilleure mthode est de toujours indiquer le systme avant lavaleur. Ainsi, on ne se trompe jamais (enfin, quand je dis jamais , joublie peut-tre de direque a mest dj arriv moi aussi).Nous navons pas encore de define pour linstant, laissons la zone vide, quant auxmacros, nous ne conserverons que celles concernant les banques.;*****************************************************************************; DEFINE *;*****************************************************************************;*****************************************************************************; MACRO *;*****************************************************************************137; Changement de banques; ----------------------BANK0 macro ; passer en banque0;bcf STATUS,RP0bcf STATUS,RP1endmBANK1 macro ; passer en banque1bsf STATUS,RP0bcf STATUS,RP1endmBANK2 macro ; passer en banque2bcf STATUS,RP0bsf STATUS,RP1endmBANK3 macro ; passer en banque3bsf STATUS,RP0bsf STATUS,RP1endmCe que nous pouvons dire sur nos zones de variables, aprs avoir effac les exemples,cest que nous avons besoin, priori, dune variable pour compter les passages dans le timer0.Par contre, notre programme aura une taille de moins de 2K, inutile donc de sauvegarderPCLATH. Inutile galement de sauvegarder FSR, nous nutiliserons pas ladressage indirectdans notre routine dinterruption toute simple. Ceci nous donne :;*****************************************************************************; VARIABLES BANQUE 0 *;*****************************************************************************; Zone de 80 bytes; ----------------CBLOCK 0x20 ; Dbut de la zone (0x20 0x6F)cmpt : 1 ; compteur de passages dans tmr0ENDC ; Fin de la zone;*****************************************************************************; VARIABLES ZONE COMMUNE *;*****************************************************************************; Zone de 16 bytes; ----------------CBLOCK 0x70 ; Dbut de la zone (0x70 0x7F)w_temp : 1 ; Sauvegarde registre Wstatus_temp : 1 ; sauvegarde registre STATUSENDCNous naurons nul besoin de la zone RAM en banques 1,2, et 3. Donc, nous effaons cequi les concerne.Si, se stade, nous lanons lassemblage, nous aurons videmment des erreurs relativesaux assignations que nous avons supprimes. Il ne suffit pas deffacer les assignations (ce quine nous fait rien gagner en taille du programme), il faut surtout effacer les instructions qui yfont rfrence.138Donc, tout dabord, dans la routine dinterruption principale, nous allons effacer lasauvegarde et la restauration de PCLATH et de FSR.Profitons-en pour supprimer les tests dinterruptions qui ne nous seront pas utiles. Nousnavons besoin ici que de linterruption tmr0. Cependant, je compte dans un futur exercice,rutiliser ce fichier. Je vous demande donc de conserver galement linterruption concernantle convertisseur A/D.Aprs un minimum de rflexion, et en vous rappelant quil est inutile, comme notreroutine est conue, de tester la dernire interruption (si ce nest aucune autre, cest donc celle-ci), vous devriez arriver au rsultat suivant :;*****************************************************************************; ROUTINE INTERRUPTION *;*****************************************************************************;sauvegarder registres;---------------------org 0x004 ; adresse d'interruptionmovwf w_temp ; sauver registre Wswapf STATUS,w ; swap status avec rsultat dans wmovwf status_temp ; sauver status swappBANK0 ; passer en banque0; Interruption TMR0; -----------------btfsc INTCON,T0IE ; tester si interrupt timer autorisebtfss INTCON,T0IF ; oui, tester si interrupt timer en coursgoto intsw1 ; non test suivantcall inttmr0 ; oui, traiter interrupt tmr0bcf INTCON,T0IF ; effacer flag interrupt tmr0goto restorereg ; et fin d'interruption; Interruption convertisseur A/D; ------------------------------intsw1call intad ; traiter interruptbcf PIR1,ADIF ; effacer flag interupt;restaurer registres;-------------------restoreregswapf status_temp,w ; swap ancien status, rsultat dans wmovwf STATUS ; restaurer statusswapf w_temp,f ; Inversion L et H de l'ancien W ; sans modifier Zswapf w_temp,w ; Rinversion de L et H dans W; W restaur sans modifier statusretfie ; return from interrupt;*****************************************************************************; INTERRUPTION TIMER 0 *;*****************************************************************************inttmr0return ; fin d'interruption timer;*****************************************************************************; INTERRUPTION CONVERTISSEUR A/D *;*****************************************************************************intad139return ; fin d'interruptionPassons linitialisation, et supprimons ce dont nous naurons nul besoin, commelinitialisation du PORTC (conservez le PORTA, nous en aurons besoin ultrieurement) ouencore linitialisation de PIE2.Nous pouvons galement supprimer leffacement de la RAM en banque0, nous nutilisonsdailleurs que peu de variables. Profitons-en pour initialiser notre unique variable actuelleavec la valeur de rechargement. Voici ce que vous devriez obtenir :;*****************************************************************************; INITIALISATIONS *;*****************************************************************************init; initialisation PORTS (banque 0 et 1); ------------------------------------BANK0 ; slectionner banque0clrf PORTA ; Sorties PORTA 0clrf PORTB ; sorties PORTB 0bsf STATUS,RP0 ; passer en banque1movlw ADCON1VAL ; PORTA en mode digital/analogiquemovwf ADCON1 ; criture dans contrle A/Dmovlw DIRPORTA ; Direction PORTAmovwf TRISA ; criture dans registre directionmovlw DIRPORTB ; Direction PORTBmovwf TRISB ; criture dans registre direction; Registre d'options (banque 1); -----------------------------movlw OPTIONVAL ; charger masquemovwf OPTION_REG ; initialiser registre option; registres interruptions (banque 1); ----------------------------------movlw INTCONVAL ; charger valeur registre interruptionmovwf INTCON ; initialiser interruptionsmovlw PIE1VAL ; Initialiser registremovwf PIE1 ; interruptions priphriques 1; initialiser variables; ---------------------movlw RELOAD ; valeur de rechargementmovwf cmpt ; dans compteur de passage tmr0; autoriser interruptions (banque 0); ----------------------------------clrf PIR1 ; effacer flags 1bsf INTCON,GIE ; valider interruptionsgoto start ; programme principalPassons maintenant aux choses srieuses, en commenant par laborer notre programme.Reprenons donc notre pseudo-code, et tout dabord la routine principale. Tout vous semblecorrect ? Nous en reparlerons.BoucleJe lis 1 octet en FLASHJe lenvoie sur le PORTBJattends 200ms140Je retourne en BoucleIl est trs simple de convertir ceci en langage dassemblage.;*****************************************************************************; PROGRAMME PRINCIPAL *;*****************************************************************************startclrwdt ; effacer watch dogcall readflash ; lire un octet en flashmovwf PORTB ; le mettre sur le PORTB (allumage LEDs)call tempo ; attendre 200msgoto start ; bouclerEND ; directive fin de programmeVoyons maintenant notre sous-routine de temporisation, pour cela, reprenons notrepseudo-code :TempoFlag tmp positionn ?Non, boucler sur tempoOui, effacer flaget retourNous avons besoin dun flag, cest--dire dune variable boolenne, ou encore, dun bitdans un octet. Il nous faut donc dfinir cette variable. Nous choisirons donc un octet en tantque flags . Cet octet contient 8 bits, donc 8 variables boolennes potentielles. Nousdfinirons le bit 0 comme notre flag boolen, que nous appellerons flagtempo . Notre zonede variables en banque 0 devient donc :CBLOCK0x20 ; Dbut de la zone (0x20 0x6F)cmpt : 1 ; compteur de passages dans tmr0flags : 1 ; flags divers; b0 : flag de temporisation ENDC ; Fin de la zone#DEFINE flagtempo flags,0 ; flag de temporisationLe define , est, comme dhabitude, destin nous faciliter les critures.Quand nous ajoutons une variable, le premier rflexe doit consister soccuper de sonventuelle initialisation. Au dpart, nous choisissons donc deffacer lensemble des flags.; initialiser variables; ---------------------movlw RELOAD ; valeur de rechargementmovwf cmpt ; dans compteur de passage tmr0clrf flags ; effacer les flagsNous pouvons donc maintenant crire notre routine de temporisation, que nous plaons,suivant notre habitude, entre la routine dintialisation et le programme principal :;*****************************************************************************; TEMPORISATION *;*****************************************************************************;-----------------------------------------------------------------------------141; Attend que le flag soit positionn par la routine d'interruption tmr0;-----------------------------------------------------------------------------tempobtfss flagtempo ; tester si flag tempo positionngoto tempo ; non, attendrebcf flagtempo ; oui, effacer le flagreturn ; et retourBien entendu, pour que le flag puisse tre positionn, il nous faut crire notre routinedinterruption tmr0 partir de notre pseudo-code :Interruption timer0Dcrmenter compteurCompteur = 0 ?Oui, positionner flag tmpEt recharger compteur avec la valeur 15Retour dinterruptionDe nouveau, rien de plus simple, toutes les variables utiles ont dj t dfinies.;*****************************************************************************; INTERRUPTION TIMER 0 *;*****************************************************************************inttmr0decfsz cmpt,f ; dcrmenter compteur de passagereturn ; pas 0, rien d'autre fairebsf flagtempo ; si 0, positionner flag de temporisationmovlw RELOAD ; valeur de rechargementmovwf cmpt ; recharger compteurreturn ; fin d'interruption timerVoici donc notre temporisation oprationnelle. Ne reste plus que la lecture des donnes enmmoire programme.Donnes, vous avez dit ? Mais oui, bien sr, il faut dabord les y mettre, nos donnes.Souvenez-vous que linitialisation des donnes en mmoire programme peut se faire avec ladirective DA .Mais je vais en profiter pour utiliser la technique des include , ainsi, nous ferons dune pierre deux coups .Afin dviter de traner toutes les valeurs dallumage de nos LEDs dans le programmeprincipal, et galement afin de vous viter de devoir tout recopier, nous allons crer un fichierspar contenant nos donnes.Commencez donc par aller dans le menu file -> new . une fentre intitule untitled (a ne sinvente pas) souvre lcran. Allez dans le menu files -> save as et sauvez-la sous ne nom lumdat.inc dans le mme rpertoire que votre projet.Vous auriez pu galement choisir lextension .asm , ou encore .txt , mais prenezlhabitude dutiliser lextension .inc pour vos fichiers INClude , ceci vous permettra demieux vous y retrouver.Ds que cest fait, le nouveau nom et le chemin apparaissent dans lintitul de la fentre.142Vous avez maintenant 2 fentres ouvertes dans lcran de MPLAB. Mais, souvenez-vous,ce nest pas parce que le fichier est ouvert lcran quil fait partie de notre projet.Nous allons donc linclure dans celui-ci en ajoutant tout simplement une directive include . dans notre fichier .asm .LIST p=16F876 ; Dfinition de processeur#include ; fichier include#include ; donnes d'allumageMais bon, ce nest pas tout dinclure le fichier, encore faut-il savoir quelle adresse lesdonnes vont aller se loger. En tout tat de cause, il faut que ce soit aprs notre programme, etnon en plein ladresse de dmarrage 0x00. Le plus simple est donc dimposer ladresse dechargement. Vous vous souvenez sans doute que cela seffectue laide de la directive ORG .Reste choisir ladresse de dpart de nos donnes, donc la valeur placer suite notredirective ORG . Evitons de perdre de la place, crivons-les directement la fin de notreprogramme.Et comment connatre ladresse de fin de notre programme ? Cest simple, il suffit dyplacer une tiquette (attention, AVANT la directive END, sinon cette tiquette ne serait pasprise en compte).startclrwdt ; effacer watch dogcall readflash ; lire un octet en flashmovwf PORTB ; le mettre sur le PORTB (allumage LEDs)call tempo ; attendre 200msgoto start ; bouclermesdata ; emplacement de mes donnes (lumdat.inc)END ; directive fin de programmeMaintenant, nous allons dans notre fentre lumdat.inc , et nous crons un en-tte, suivide la directive ORG complte de ladresse de position de nos donnes, cest--dire mesdata .;*****************************************************************************; DONNNEES D'ALLUMAGE *;*****************************************************************************;-----------------------------------------------------------------------------; un niveau "1" provoque l'allumage de la sortie correspondante;-----------------------------------------------------------------------------ORG mesdata ; dbut des data en fin de programmeA ce stade, nous allons inscrire des donnes dans notre fichier .inc , en nous souvenantque la dernire donne aura son bit numro 8 positionn 1, ce qui indiquera notreprogramme la fin de la zone. Ecrivons donc en nous souvenant quun 1 allume la LEDcorrespondante, et quun 0 lteint.Ajoutons donc quelque donnes, et pourquoi pas :DA B'00000001' ; valeurs d'allumageDA B'00000010'143DA B'00000100'DA B'00001000'DA B'00010000'DA B'00100000'DA B'01000000'DA B'10000000'DA B'01000000'DA B'00100000'DA B'00010000'DA B'00001000'DA B'00000100'DA B'00000010'|B'100000000' ; dernire valeur, on force b8Notez quon aurait pu simplement crire la dernire ligne de la faon suivante :DA B100000010 ; dernire valeur avec b8 1Ce qui tait strictement quivalent. Nous pouvons fermer notre fentre de donnes (ce nestpas parce quelle est ferme quelle nest plus utilise), ou, mieux , la minimiser, ce qui nouspermettra de la rouvrir si nous voulons modifier les valeurs.Noubliez cependant pas auparavant de sauver en pressant ou en utilisant saveall .Revenons-en nos moutons je voulais dire notre lecture des donnes :Lire en FlashLire un mot en flashIncrmenter pointeur FLASH pour prochaine lectureBit 8 = 1 ?Si oui, pointer sur premire donne en flashRetourEn regardant cette sous-routine, nous voyons quon utilise un pointeur. Donc, il devragalement tre initialis.Ce pointeur, si vous vous rappelez, est un pointeur cod sur 2 octets, car laccs latotalit de la zone mmoire programme ncessite 13 bits. Ce pointeur est constitu, pour lesaccs en mmoire programme, des registres EEADR et EEADRH. Nous allons donc lesinitialiser de faon ce que la premire lecture corresponde la premire donne crite dansnotre fichier lumdat.inc .Ajoutons donc nos lignes sur les initialisations des variables. Vous pensez a ?; initialiser variables; ---------------------movlw RELOAD ; valeur de rechargementmovwf cmpt ; dans compteur de passage tmr0clrf flags ; effacer les flagsmovlw low mesdata ; adresse basse des datamovwf EEADR ; dans pointeur bas FLASHmovlw high mesdata ; adresse haute des datamovwf EEADRH ; dans pointeur haut FLASHCest bien davoir pens aux directive low et high que nous avons vuesprcdemment. Rien redire ?144Malheureusement, dans ce cas, vous avez tout faux au niveau du rsultat final. Vous testomb dans le pige classique. Les banques, vous les avez oublies ? Et oui, EEADR etEEADRH sont en banque 2. Si donc, vous avez pensez :; initialiser variables; ---------------------movlw RELOAD ; valeur de rechargementmovwf cmpt ; dans compteur de passage tmr0clrf flags ; effacer les flagsbsf STATUS,RP1 ; passer en banque2movlw low mesdata ; adresse basse des datamovwf EEADR ; dans pointeur bas FLASHmovlw high mesdata ; adresse haute des datamovwf EEADRH ; dans pointeur haut FLASHbcf STATUS,RP1 ; repasser en banque 0alors je vous donne un bon point (passez me voir la rcr ).Mais alors, si rellement vous avez pens :; initialiser variables; ---------------------bcf STATUS,RP0 ; repasser en banque0movlw RELOAD ; valeur de rechargementmovwf cmpt ; dans compteur de passage tmr0clrf flags ; effacer les flagsbsf STATUS,RP1 ; passer en banque2movlw low mesdata ; adresse basse des datamovwf EEADR ; dans pointeur bas FLASHmovlw high mesdata ; adresse haute des datamovwf EEADRH ; dans pointeur haut FLASHbcf STATUS,RP1 ; repasser en banque 0Alors je vous dit BRAVO . En effet, il fallait penser que notre routine dinitialisationdes variables tait fausse, puisque nous avions oubli de repasser en banque 0, lesinitialisations prcdentes concernant la banque 1 (et en plus, ctait not).Donc, rappelez-vous de toujours bien rflchir et de garder lesprit ouvert. Il ne suffit pasde raliser btement tout ce que je vous dis sans rflchir plus loin. Dautant que jestimeque les erreurs sont profitables, je vous en fais donc faire quelques-unes classiques volontairement. Il y en aura dautres, quon se le dise (et dans votre intrt, essayez de lestrouver sans tricher ).Tout est maintenant prt pour lcriture de notre routine de lecture dun octet en mmoireprogramme. Essayez dcrire vous-mme cette routine.;*****************************************************************************; LIRE UN OCTET EN FLASH *;*****************************************************************************;-----------------------------------------------------------------------------; Lit un octet en mmoire programme, puis pointe sur le suivant; retourne l'octet lu dans w; si le bit 8 du mot lu vaut 1, on pointe sur la premire donne;-----------------------------------------------------------------------------readflashBANK3 ; pointer sur banque3145bsf EECON1,EEPGD ; accs la mmoire programmebsf EECON1,RD ; lecturenop ; 2 cycles d'attentenopbcf STATUS,RP0 ; pointer sur banque2incf EEADR,f ; incrmenter pointeur bas sur donnesbtfsc STATUS,Z ; tester si dbordincf EEADRH,f ; oui, incrmenter pointeur hautbtfss EEDATH,0 ; tester bit 0 data haute = bit 8 donnegoto readfsuite ; si 0, sauter instructions suivantesmovlw low mesdata ; si 1, adresse basse des datamovwf EEADR ; dans pointeur bas FLASHmovlw high mesdata ; adresse haute des datamovwf EEADRH ; dans pointeur haut FLASHreadfsuitemovf EEDATA,w ; charger 8 bits donnebcf STATUS,RP1 ; repointer sur banque0return ; et retourQuelques points sont prendre en considration. En premier lieu, lincrmentation dupointeur seffectue bien sur 2 registres, EEADR et EEADRH. Noubliez pas que laccs lammoire programme complte ncessite 13 bits. On incrmentera donc le registre de poidsfort si le registre de poids faible a dbord , cest dire quil est pass de 0xFF 0x00.Si vous aviez pens utiliser pour ce faire linstruction :btfsc STATUS,C ; tester si dbordLide ntait pas mauvaise en soi, malheureusement linstruction incf prcdentenagit pas sur le bit C . Cela naurait donc pas fonctionn.Ensuite, vous voyez que le bit 8 de notre donne correspond fort logiquement au bit 0 deEEDATH. Cest donc ce dernier que nous testons pour constater que nous sommes arrivs enfin de notre zone de donnes.Lancez lassemblage et placez le fichier obtenu dans votre PIC. Alimentez, et regardez : laLED connecte sur RB0 sallume et est la seule sallumer. quelque chose ne nest donc paspass comme prvu. A votre avis, quel niveau ?Il suffit de raisonner. Il y a eu allumage de la premire LED, donc lecture de la premirevaleur en mmoire programme.Si nous vrifions la fin de cette routine (puisque le dbut fonctionne), nous voyons quetout lair correct. On repasse bien en banque 0 avant de sortir, et linstruction return estbien prsente. Le problme provient sans doute dailleurs.En regardant le programme principal, nous voyons que celui-ci appelle la routine detemporisation. Cest probablement dans cette routine que quelque chose cloche .Regardez-la attentivement. Vous ne remarquez rien ? Non ? Et si je vous rappelle quecette routine attend durant 200ms, vous ne pensez toujours rien ? Alors je vous rappelle quenous avons mis le watchdog en service dans notre configuration.146Alors la, a doit faire tilt . En effet, le watchdog va vous provoquer un reset aprs unedure approximative de 18ms. Donc, bien avant que notre routine de temporisation soittermine.Il ny a donc aucune chance darriver jusqu lallumage suivant. Ajoutez donc uneinstruction de reset du watchdog :tempoclrwdt ; effacer watchdogbtfss flagtempo ; tester si flag tempo positionngoto tempo ; non, attendrebcf flagtempo ; oui, effacer le flagreturn ; et retourReprogrammez votre PIC, et contemplez leffet obtenu. Vous pouvez alors votre guisecomplter les squences dallumage en ajoutant des donnes dans votre fichier lumdat.inc .Noubliez pas que le seul bit 8 1 doit tre celui de votre dernire donne.Vous pouvez galement diminuer la valeur de RELOAD dans les assignations, de faon acclrer le dfilement. Une valeur de 4 devrait vous donner le look K2000 , pour lesnostalgiques de la srie.A ce stade, vous pouvez tenter dinterpeller votre pouse. Devant votre air admiratif pource jeu de lumire intelligent , il est possible quelle vous gratifie dun regard compatissant.Nen esprez gure plus, cependant, la bont fminine a ses limites.Par contre, cest le moment de montrer le montage votre jeune fils ou votre petit frre.Pour sr, il va vouloir installer le montage dans votre voiture.147Notes : 148Notes : 14914. Le timer 014.1 GnralitsNous avons dj parl du timer 0 dans le premir livre. Ce timer fonctionne de faonidentique celui du PIC16F84. Inutile donc de revenir sur tout ce que nous avons dj vu,toutes les explications restent dapplication.Je vais seulement vous donner quelques complments dinformation, complments quisappliquent tous les PICs de la gamme MID-RANGE.Remarquez pour commencer que le timer 0 utilise, pour ses incrmentations le registre de8 bits TMR0. Ce registre contient une valeur indtermine la mise sous tension, si vousdsirez compter partir dune valeur prcise (0 ou autre), placer explicitement cette valeurdans votre programme :clrf TMR0 ; commencer le comptage partir de 0Jai test sur quelques 16F876 en ma possession, et jai obtenu une valeur de dmarrageconstante et gale 0xFF. Ceci ne peut cependant pas tre gnralis, il sagit au plus dunpeu de curiosit de ma part.Ceci est valable pour la mise sous tension (reset de type P.O.R) ou pour la rcuprationaprs une chute de tension (reset de type B.O.R). Par contre, pour les autres types de reset, lecontenu de TMR0 restera inchang par rapport sa dernire valeur.Notez galement quil est impossible darrter le fonctionnement du timer. Une astuce quevous pouvez utiliser, si vous dsirez suspendre le comptage du temps (en mode timer), est defaire passer le timer0 en mode compteur. Ceci, bien entendu, condition que la pin RA4 nesoit pas affecte une autre utilisation.14.2 Lcriture dans TMR0Tout dabord, si nous nous trouvons en mode de fonctionnement timer du timer 0,nous pouvons tre amens crire une valeur (ou ajouter une valeur) dans le registre TMR0.Ceci, par exemple, pour raccourcir le temps de dbordement du timer avant ses 256 cyclesclassiques.Voyons donc ce qui se passe au moment de lcriture dune valeur dans TMR0.La premire chose quil va se passer, est que le contenu du prdiviseur, sil tait affect autimer 0 (souvenez-vous quil sert galement pour le watchdog) va tre remis 0. Attention, jeparle du contenu du prdiviseur, pas de la valeur du prdiviseur (je vais expliquer en dtail).Ensuite, les 2 cycles dinstruction suivants seront perdus au niveau du comptage du timer.La mesure de temps reprendra donc partir du 3me cycle suivant.Il importe de comprendre que le prdiviseur fonctionne de la faon suivante :150- Le prdiviseur compte jusque sa valeur programme par PS0/PS2.- Une fois cette valeur atteinte, TMR0 est incrment- Le prdiviseur recommence son comptage limpulsion suivanteSupposons par exemple que TRM0 contienne la valeur 0x15, que le prdiviseur soitslectionn sur une valeur de 8 affecte au timer 0. Supposons galement que nous ensommes 2 cycles dinstruction depuis la dernire incrmentation de TMR0. Il reste doncthoriquement 6 cycles dinstruction avant que TMR0 ne passe 0x16. Nous avons donc lasituation suivante :Prdiviseur configur : 8Contenu du prdiviseur : 2Valeur de TMR0 : 0x15Imaginons qu cet instant nous rencontrions la squence suivante :movlw 0x25 ; prendre la valeur 0x25movwf TMR0 ; dans TMR0Nous obtenons pour la suite de notre programme :Instruction suivante : TMR = 0x25, contenu prdiviseur = 0, prdiviseur 8.Instruction suivante : Pas de comptage, contenu prdiviseur = 0Instruction suivante : redmarrage du comptage : contenu prdiviseur = 1Vous voyez donc que non seulement nous avons perdu 2 cycles, mais quen plus nousavons perdus les instructions qui avaient t comptabilises dans notre prdiviseur.Lorsque vous crivez dans TMR0, il vous appartient, si ncessaire, de prendre en comptecette perte dinformations.14.3 le timing en mode compteurIl y a quelques prcautions prendre lorsquon travaille avec le timer 0 en modecompteur. En effet, les lments compter sont, par dfinition, asynchrones avec lhorloge duPIC.Or la sortie du prdiviseur, et donc lincrmentation du registre TMR0 est, elle,synchronise sur le flanc montant de Q4 (Q4 tant le 4me clock de lhorloge du PIC).Dit plus simplement, on peut dire que la sortie du prdiviseur passe 1 au moment ola valeur de comptage est gale la valeur du prdiviseur choisie (8 dans lexempleprcdent). Une fois cette valeur dpasse, la sortie du prdiviseur repasse 0, jusquaumultiple de 8 suivant (dans notre exemple).Mais lincrmentation de TMR0 se fait sur le test suivant : On a incrmentation si aumoment du flanc montant de Q4, la sortie du prdiviseur est 1.151On voit alors tout de suite que si le signal est trop rapide, nous risquons de rater ledbordement du prdiviseur, celui-ci tant repass 0 avant davoir eu apparition du flancmontant de Q4.On peut donc en dduire que pour tre certain de ne rien rater, la sortie de notreprdiviseur devra tre maintenue au minimum le temps sparant 2 Q4 conscutifs. Donc,lquivalent de 4 Tosc (temps doscillateur), soit la dure dun cycle dinstruction.Nous aurons, de plus quelques limites dues llectronique interne. Ceci nous donneles rgles simples suivantes :Si on nutilise pas de prdiviseur, la sortie du prdiviseur est gale son entre, donc :- La dure totale du clock ne pourra tre infrieure 4 Tosc.- De plus, on ne pourra avoir un tat haut 152Ce temps minimum ne respecte pas le temps minimum absolu impos, qui est de 10 ns.Cest donc ce dernier temps dont nous tiendrons compte. Notre frquence maximale est donc de :F = 1/T = 1/ (20*10-9) = 50 . 106 Hz = 50 MHz.Donc, vous voyez que vos PICs peuvent, condition dutiliser le prdiviseur une valeursuffisante, compter des frquences pouvant atteindre 50 MHz14.4 Modification au vol de lassignation du prdiviseurVous pouvez tre amens, en cours dexcution de votre programme, changerlassignation du prdiviseur entre le watchdog et le timer 0. En effet, il vous suffit de changerle bit PSA du registre pour effectuer cette opration.Il vous faudra cependant respecter les procdures suivantes, sous peine de provoquer unreset non dsir de votre PIC au moment de la modification de PSA.Certains profitent dailleurs de cette anomalie pour provoquer des resets la demandedepuis le logiciel. Je vous le dconseille fermement :- Dune part parcequun programme qui ncessite un reset de ce type est en gnral unprogramme mal structur (vous imaginez un programme sur votre PC qui ncessite unreset ?)- Dautre part, parce que ce fonctionnement est anormal, et donc, bien videmment, non garanti . En passant sur une nouvelle rvision de PICs, vous risquez que votre astuce ne fonctionne plus.Nous avons donc 2 possibilits : soit nous affectons le prdiviseur au watchdog alorsquil tait affect au timer 0, soit le contraire.14.4.1 Prdiviseur du timer 0 vers le watchdogCommenons par ce cas de figure. Nous allons devoir distinguer 2 sous-cas particuliers,en fonction de la valeur finale de notre prdiviseur (bits PS0/PS2).Imaginons tout dabord que la valeur de notre prdiviseur finale soit diffrente de 1. Voicialors la procdure respecter scrupuleusement :Modifpsaclrf TMR0 ; effacer timer0, et donc le contenu du prdiviseurbsf STATUS,RP0 ; passer en banque 1bsf OPTION_REG,PSA ; prdiviseur sur watchdog SANS changer valeurclrwdt ; effacer watchdog et prdiviseurmovlw Bxxxx1abc ; dfinir la nouvelle valeur prdiviseur(selon abc)movwf OPTION_REG ; dans registrebcf STATUS,RP0 ; repasser en banque 0, fin du traitement153Si maintenant, nous dsirons que la valeur finale du prdiviseur soit gale 1, noussommes obligs de passer par une valeur intermdiaire quelconque, mais diffrente de 1.Voici donc la procdure :Modifpsabsf STATUS,RP0 ; passer en banque 1movlw Bxx0x0111 ; prdiviseur quelconque, tmr en compteurmovwf OPTION_REG ; dans registrebcf STATUS,RP0 ; repasser en banque 0clrf TMR0 ; effacer timer0, et donc le contenu du prdiviseurbsf STATUS,RP0 ; passer en banque 1movlw Bxxxx1111 ; passer sur watchdog, mode tmr rel utilismovwf OPTION_REG ; dans registreclrwdt ; effacer watchdog et prdiviseurmovlw Bxxxx1000 ; dfinir la nouvelle valeur prdiviseur(1)movwf OPTION_REG ; dans registrebcf STATUS,RP0 ; repasser en banque 0, fin du traitement14.4.2 Prdiviseur du watchdog vers le timer 0Dans ce cas, la procdure est plus simple :clrwdt ; commencer par effacer le watchdog et le prdiviseurbsf STATUS,RP0 ; passer en banque 1movlw Bxxxx0abc ; passer sur tmr 0 et nouvelle valeur prdiviseur (abc)movwf OPTION_REG ; dans registrebcf STATUS,RP0 ; repasser banque 0, fin du traitementJe vous rappelle que le non respect de ces procdures risque de causer un reset imprvu devotre PIC.Une dernire chose prendre en compte, cest que, puisque le comptage ne se fait quaumoment de la monte de Q4, il y a un dcalage entre lapparition du clock et le moment o ceclock est pris en compte. Ce dcalage est donc au maximum de 1 cycle dinstruction.Voici donc quelques complments dinformation sur le timer 0, tant donn quau stadeo vous en tes, vous avez de plus en plus de chance de raliser des programmes complexes.154Notes : 15515. Le timer 1Voici un sujet qui ma valu bien du courrier lectronique. Jai constat que beaucoup demes correspondants avaient des difficults mettre en uvre ce timer.Nous allons voir, que dans ses fonctions de base, la mise en uvre de ce timer nest pasplus complique que celle du timer 0.Je me limiterai dans ce chapitre au fonctionnement du timer en tant que tel. Je verrai sesmodes de fonctionnement annexes dans les chapitres concerns (CCP).15.1 Caractristiques du timer 1Le timer 1 fonctionne dans son ensemble comme le timer 0. La philosophie est semblable.Il y a cependant de notables diffrences.Tout dabord, ce timer est capable de compter sur 16 bits, comparer aux 8 bits du timer0. Il sera donc capable de compter de D0 D65535. Pour arriver ces valeurs, le timer 0devait recourir ses prdiviseurs, ce qui, nous lavons vu dans la premire partie du cours,limitait de ce fait sa prcision lorsquon tait contraint de recharger son contenu (perte desvnements compts par le prdiviseur).Le timer 1 compte donc sur 16 bits, ce qui va ncessiter 2 registres. Ces registres senomment TMR1L et TMR1H. Je pense quarrivs ce stade, il est inutile de vous prciserlequel contient la valeur de poids faible, et lequel contient celle de poids fort.Souvenez-vous que le contenu de TMR1L et de TMR1H nest pas remis 0 lors dunreset. Donc, si vous voulez compter partir de 0, il vous incombe de remettre 0 ces 2registres vous-mme.Le timer 1 permet galement, tout comme le timer 0, de gnrer une interruption une foisle dbordement effectu.Le timer 1 dispose, lui aussi, de la possibilit de mettre en service un prdiviseur. Mais ceprdiviseur ne permet quune division maximale de 8. Le rsultat final est cependant meilleurque pour le timer 0, qui ne pouvait compter que jusque 256, multipli par un prdiviseur de256, soit 65536.Pour notre nouveau timer, nous arrivons une valeur maximale de 65536 multipli par 8,soit 524288.Vous allez me rtorquer que ceci vous permet datteindre des temps plus longs, mais nevous permet pas dutiliser des temps aussi courts que pour le timer 0, qui peut gnrer uneinterruption tous les 256 clocks dhorloge, notre timer 1 ncessitant 65536 clocks auminimum.156En fait, il suffit que lors de chaque interruption vous placiez la valeur 0xFF dans TMR1H,et vous vous retrouvez avec un compteur sur 8 bits. Vous pouvez naturellement utiliser touteautre valeur qui vous arrange.La souplesse du timer 1 est donc plus importante que celle du timer 0. Et vous allez voirque cest loin dtre termin.Tout comme pour le timer 0, les registres de comptage TMR1L et TMR1H contiennentune valeur indtermine aprs un reset de type P.O.R ou B.O.R. De mme, un autre reset nemodifie pas le contenu prcdent de ces registres, qui demeurent donc inchangs.15.2 Le timer 1 et les interruptionsIl est bien entendu quun des modes privilgis de lutilisation des timers, est la possibilitde les utiliser en tant que gnrateurs dinterruptions.Je vous rappelle donc ici que le timer 1 permet, exactement comme le permet le timer 0,de gnrer une interruption au moment o timer dborde , cest--dire au moment o savaleur passe de 0xFFFF 0x0000 (souvenez-vous que nous travaillons sur 16 bits).Quelles sont les conditions pour que le timer 1 gnre une interruption ? Et bien, toutsimplement que cette interruption soit autorise. Donc :- Il faut que le bit dautorisation dinterruption du timer 1 (TMR1IE) soit mis 1. Ce bit setrouve dans le registre PIE1 (banque 1).- Pour que le registre PIE1 soit actif, il faut que le bit PEIE dautorisation des interruptionspriphriques soit positionn dans le registre INTCON.- Il faut galement, bien entendu, que le bit dautorisation gnrale des interruption (GIE)soit positionn dans le registre INTCON.Moyennant quoi, une interruption sera gnre chaque dbordement du timer1. Cetvnement sera indiqu par le positionnement du flag TMR1IF dans le registre PIR1.Comme dhabitude, il vous incombe de remettre ce flag 0 dans la routine dinterruption,sous peine de rester indfiniment bloqu dans la dite routine. Mais, comme pour les autresinterruptions, le fichier maquette que je vous fournis effectue dj ce travail.Voici une squence qui initialise les interruptions sur le timer 1 :bsf STATUS,RP0 ; passer en banque 1bsf PIE1,TMR1IE ; autoriser interruptions timer 1bcf STATUS,RP0 ; repasser banque 0bsf INTCON,PEIE ; interruptions priphriques en servicebsf INTCON,GIE ; interruptions en service15.3 Les diffrents modes de fonctionnement du timer1157Le timer 1 peut, tout comme le timer 0, fonctionner en mode timer (cest--dire encomptage des cycles dinstruction), ou en mode compteur (cest--dire en comptant desimpulsions sur une pin externe.Cependant, le timer 1 dispose de 2 modes diffrents de mode de comptage : un mode detype synchrone et un mode de type asynchrone.Vous avez dj eu une ide de ce quest un mode synchrone au chapitre traitant du timer0. Rappelez-vous que le comptage ne seffectuait, en sortie du prdiviseur, quau moment dela monte de Q4, donc en synchronisme avec lhorloge interne.En plus, nous avons la possibilit, au niveau du timer 1, dutiliser un quartz sur les pinsT1OSI et T1OSO afin de disposer dune horloge spare de lhorloge principale.En tout tat de cause, souvenez-vous quun timer utilis en mode timer , neffectuejamais quun simple comptage de cycles dinstruction.Pour rsumer, nous pouvons donc dire que le timer peut fonctionner en tant que :- Timer bas sur lhorloge interne (compteur de cycles dinstruction)- Timer bas sur une horloge auxiliaire- Compteur synchrone- Compteur asynchrone.Les modes de fonctionnement sont dfinis en configurant correctement le registreT1CON, que nous allons examiner maintenant. Mais tout dabord, je vous donne leschma-bloc du timer 1 :15.4 Le registre T1CONComme je le disais, cest ce registre, situ en banque 0, qui va permettre de configurer letimer1 en fonction de nos besoins. Voici les bits qui le composent :b7 : Inutilis : lu comme 0 b6 : Inutilis : lu comme 0 b5 : T1CKPS1 : Timer 1 oscillator ClocK Prescale Select bit 1b4 ; T1CKPS0 : Timer 1 oscillator ClocK Prescale Select bit 0158b3 : T1OSCEN : Timer 1 OSCillator ENable control bitb2 : T1SYNC : Timer 1 external clock input SYNChronisation control bitb1 : TMR1CS : TiMeR 1 Clock Source select bitb0 : TMR1ON : TiMeR 1 ON bitJe ne sais pas quel est votre sentiment, mais moi, la premire fois que jai rencontr cesbits, jai trouv leur nom particulirement barbare . Mais bon, leur utilisation estheureusement plus simple retenir que les noms. Voyons donc.Tout dabord, les bits T1CKPS1 et T1CKPS0 dterminent eux deux la valeur duprdiviseur dont nous avons dj parl. Le prdiviseur, comme son nom lindique, et commepour le timer0, permet, je le rappelle, de ne pas compter chaque vnement reu, maisseulement chaque multiple de cet vnement. La valeur de ce multiple est la valeur duprdiviseur.T1CKPS1 T1CKPS0 Valeur du prdiviseur0 0 10 1 21 0 41 1 8Vous pouvez donc vrifier que les choix sont plus limits que pour le timer 0, mais ceciest compens par le fait que le timer 1, je le rappelle encore, compte sur 16 bits au lieu de 8.Nous trouvons ensuite T1OSCEN. Ce bit permet de mettre en service loscillateur interne,et donc permet dutiliser un second quartz pour disposer dun timer prcis travaillant unefrquence distincte de la frquence de fonctionnement du PIC. Mais rassurez-vous, je vaisvous dtailler tout a un peu plus loin.Pour linstant, retenez que si vous placez ce bit 1 , vous mettez en serviceloscillateur interne, ce qui aura, nous le verrons plus loin, toute une srie de consquences.Maintenant, voyons T1SYNC, qui permet de choisir si le comptage des vnements seraeffectue de faon synchrone ou asynchrone avec lhorloge principale du PIC. Il est de faitvident que lorsque TMR1 est utilis en mode timer , T1SYNC na aucune raison dtre, lecomptage tant dtermin par loscillateur principal du PIC, il est automatiquementsynchrone.Le bit TMR1CS permet de dfinir quel est le mode de comptage du timer 1 :- Soit on place TMR1CS 0 , et dans ce cas, il compte les cycles dinstructions du PIC.Dans ce cas, on dira, tout comme pour le timer 0, que TMR1 travaille en mode timer .- Soit, on place ce bit 1 , et TMR1 compte alors les flancs montants du signal appliqusur la pin RC0/T1OSO/T1CKI (la pin porte 3 noms, en fonction de son utilisation).Comme je le disais plus haut, si TMR1CS est 0, alors T1SYNC est ignor.Reste le plus simple, le bit TMR1ON, qui, sil est mis 1 , autorise le timer 1 fonctionner, alors que sil est mis 0 , fige le contenu du timer 1, et donc, le met larrt.15915.5 Le timer 1 en mode timer Nous allons maintenant voir avec plus de dtails les diffrents modes de fonctionnementde ce timer, en les examinant chacun en particulier. Et tout dabord, en commenant par leplus simple, le mode timer .Dans ce mode, nous trouvons un fonctionnement tout ce quil y a de plus simple, puisquenous avons affaire un comptage des cycles dinstructions internes du PIC, exactementcomme nous avions pour le timer 0.Pour choisir ce mode, nous devons configurer T1CON de la faon suivante :T1CON : B00ab0001Si vous avez suivi, vous avez dj compris que ab reprsentent la valeur duprdiviseur choisie, et que TMR1CS devra tre mis 0 . TMR1ON permet de mettre letimer en service. Ceci configure le fonctionnement interne du timer 1 comme illustr ci-dessous :Voici un exemple dinitialisation du timer 1, configur avec un prdiviseur de 4clrf TMR1L ; effacer timer 1, 8 lsbclrf TMR1H ; effacer timer 1, 8 msbmovlw B0010000 ; valeur pour T1CONmovwf T1CON ; prdiviseur = 4, mode timer, timer offbsf T1CON,TMR1ON ; mettre timer 1 en service15.6 Le timer 1 en mode compteur synchronePour travailler dans le mode compteur synchrone , nous devons configurer T1CON dela faon suivante :T1CON : B00ab0011Evidemment, pour pouvoir compter des vnements sur la pin T1CKI, il faut que cette pinsoit configure en entre via le registre TRISC.160Donc, en reprenant le schma, vous voyez que la pin RC1 nest pas utilise, pas plus queloscillateur et la rsistance associe. Donc, vous ignorez la partie situe dans le rectanglepointill.Nous entrons donc sur T1CKI (T1 ClocK In) et nous arrivons sur un trigger de Schmitt(2). Nous arrivons ensuite sur la slection du signal via TMR1CS. Comme nous avons mis 1 pour ce bit, nous validons donc lentre de T1CKI et nous ignorons le comptage desinstructions internes (mode timer).Ensuite, nous arrivons au prdiviseur, dont la valeur est fixe par T1CKPS1 et T1CKPS0.Vous constatez qu ce niveau, le comptage se fait de faon asynchrone. En effet, parsynchrone il faut comprendre : qui est synchronis par lhorloge interne du PIC. .Or, ici, les vnements sont compts dans le prdiviseur indpendamment de lhorloge duPIC.Par contre, la sortie du prdiviseur est envoye galement dans un module desynchronisation. Le bloc de slection T1SYNC permet de dfinir si on utilise la sortie duprdiviseur avant la synchronisation (mode asynchrone) ou aprs la synchronisation (modesynchrone).Nous avons mis notre T1SYNC 0. Comme il est actif ltat bas, ceci nous slectionnele signal synchronis. Le signal est ensuite valid ou non grce TMR1ON, signal qui vaservir incrmenter le mot de 16 bits constitu de TMR1H et TMR1L.Si ce mot de 16 bits passe de 0xFFFF 0x0000 (dbordement), le flag TMR1IF est alorspositionn, et peut gnrer une interruption, si cest le choix de lutilisateur.Voici donc le schma-bloc du mode compteur synchrone :Vous voyez que cest trs simple. Reste expliquer le rle du synchronisateur. En effet,vous allez me dire : A quoi sert de synchroniser ou de ne pas synchroniser la sortie duprdiviseur?En fait, la diffrence principale est que si vous choisissez de synchroniser, alors, fortlogiquement, vous ne comptez pas si le PIC est larrt. Or, quand le PIC est-il larrt ? Etbien quand vous le placez en mode sleep .161Donc, le timer 1 utilis en mode compteur synchrone ne permet pas de rveiller le PICsur une interruption du timer 1. Cest logique, car, puisquil ny a pas de comptage, il ny apas de dbordement.Notez que la prsence du synchronisateur retarde la prise en compte de lvnement,puisquavec ce dernier la sortie du prdiviseur ne sera transmise au bloc incrmenteur que surle flanc montant suivant de lhorloge interne.Il me reste vous prciser que le comptage seffectue uniquement sur un flanc montantde T1CKI, donc sur le passage de T1CKI de 0 vers 1 . Il ne vous est pas possible ici dechoisir le sens de transition, comme le permettait le bit TOSE pour le timer 0.De plus, le flanc montant de T1CKI nest pris en compte que sil a t prcd dau moinsun flanc descendant.Ce dernier point mrite un complment dinformation. Si vous avez un signal connect auPIC qui est au niveau 0, et dont vous devez compter les passages 1 , alors, lorsque votrePIC recevra son alimentation, le premier flanc montant de T1CKI ne sera pas comptabilis,puisque pas prcd dun flanc descendant.Notez que pour viter de perdre un comptage, les temps minimum des signauxappliqus rpondent exactement aux mmes critres que pour le timer 0. Je vous renvoie doncau chapitre prcdent ce sujet.15.7 Le timer 1 en mode compteur asynchronePartant des explications prcdentes, le schma-bloc obtenu ne prsente aucune difficult,il suffit bien entendu de supprimer le bloc de synchronisation :Donc, vous voyez quun vnement est comptabilis immdiatement, sans attendre unequelconque transition de lhorloge interne.Les contraintes temporelles, concernant les caractristiques des signaux appliqus sonttoutefois toujours dapplication (voyez chapitre prcdent).162La plus grosse diffrence, cest que le comptage seffectue mme si le PIC est stopp, etque son horloge interne est arrte. Il est donc possible de rveiller le PIC en utilisant ledbordement du timer1.Par contre, cette facilit se paye au niveau de la facilit de lecture et dcriture desregistres TMR1H et TMR1L, mais je verrai ceci un peu plus loin.La valeur placer dans le registre T1CON pour travailler dans ce mode est bienvidemment :T1CON : B00ab0111Il faut de nouveau ne pas oublier de configurer T1CKI (RC0) en entre, via le bit 0 deTRISC.15.8 Le timer 1 et TOSCENNous avons presque fait le tour des modes de fonctionnement du timer 1. Reste utiliserloscillateur interne.La valeur placer dans T1CON est donc :T1CON : B00ab1x11Remarquez la prsence dun x qui vous permet de choisir si vous dsirez travailler enmode synchrone ou asynchrone. Les remarques que jai faite ce sujet pour lutilisation enmode compteur restent dapplication.Bien quil sagisse dune mesure de temps, donc dun timer, il faut bien videmmentconfigurer T1CON pour quil puisse compter les oscillations reues sur la pin T1OSI. Cecirejoint ce que je vous ai dj signal, savoir quun timer nest rien dautre quun compteurparticulier.Arriv ici, vous vous posez peut-tre quelques questions concernant cet oscillateur. Je vaisdonc tenter danticiper :A quoi sert cet oscillateur ?Et bien, tout simplement utiliser une base de temps diffrente pour le timer et pour lePIC. Ceci permet donc de choisir un quartz multiple exact de la frquence mesurer, tout enconservant une vitesse de traitement maximale du PIC.Souvenez-vous que je vous ai dj parl, dans la premire partie, ddie au 16F84, de lasolution de luxe consistant, pour amliorer la prcision, utiliser un second oscillateurpour raliser des mesures de prcision. Lavantage, ici, cest que loscillateur est prsent eninterne, il ne suffit donc que de lui ajouter un quartz.Voici un schma typique de lutilisation du timer 1 avec un quartz sur OSCEN :163Vous notez donc la prsence de 2 quartz. Le quartz 1 vous permet dutiliser le PIC safrquence de travail maximale (ici, 20MHz). Le second vous donne une base de tempsdiffrente pour lutilisation du timer 1.Se pose donc une seconde question : Quelles sont les valeurs du second quartz que je peuxutiliser ?En fait, loscillateur a t conu pour fonctionner efficacement une valeur centre sur32KHz (attention KHz, pas MHz). Mais vous pouvez augmenter cette frquence jusque 200KHz.Cet oscillateur fonctionne donc une vitesse plus lente que loscillateur principal. La table6-1 du datasheet vous donne les valeurs des condensateurs utiliser pour quelques frquencestypiques.Vous voyez que jai choisi une frquence de 32768 Hz pour mon second quartz. En fait, jenai pas choisi cette valeur par hasard. En effet, si vous vous souvenez que le timer 1 comptesur 16 bits (le contraire serait tonnant, vu le nombre de fois que je vous lai rpt), nousaurons un dbordement du timer 1 au bout du temps : 65536 / frquence. Soit tout juste 2secondes. Voici qui nous donne une base de temps trs prcise (nutilisant pas de prdiviseur),et qui ne provoque quune interruption toutes les 2 secondes.Si vous voulez une interruption toutes les secondes, il vous suffira de positionner le bit 7de TMR1H lors de chaque interruption. Ainsi, le timer 1 comptera de 0x8000 0xFFFF, soit164un comptage de 32678 cycles. Ceci nous donnera un temps de comptage de 32768/32768 = 1seconde pile . Il vous suffit donc dans ce cas dajouter la lignebsf TMR1H,7 ; forcer bit 7 de TMR1H = bit 15 de TMR1 votre routine dinterruption du timer 1.Ce mode constitue donc le mode idal pour crer une mesure de temps rel. Notez de plusque si vous avez configur le mode asynchrone, le timer continuera de compter mme si votrePIC est en mode sleep .La prcision obtenue est fonction du quartz, mais est typiquement de 20 parts par million.Ceci nous donne une erreur maximale, pour le cas de la ralisation dune horloge, de 1,7seconde par jour.Je vous donne le schma-bloc correspondant au mode OSCEN, schma que vous aurezprobablement trouv vous-mme :Il me reste cependant vous signaler que dans ce mode particulier, les pins RC0 (T1OSO)et RC1 (T1OSI) sont automatiquement configures en entre, indpendamment des bitscorrespondants de TRISC. Il est donc inutile de configurer les bits 0 et 1 de ce registre.15.9 Utilisation du dbordementProgrammer le timer1 et comprendre son fonctionnement ne suffit pas. Encore faut-illutiliser pour mesurer ou compter.La premire mthode dutilisation de notre TMR1 est la plus courante. Je ne la rpte quepour pourvoir faire la distinction avec les piges qui se trouvent dans la seconde mthodedutilisation.Cette mthode consiste utiliser le dbordement de la valeur du timer pour positionner leflag TMR1IF, et, ventuellement, pour dclencher une interruption.165La philosophie utilise est donc la suivante :- On initialise le timer avec une valeur de dpart (ventuellement 0)- On attend son dbordement- A ce moment on dtecte que le temps prdfini est coul.Imaginons donc la squence dinitialisation de notre timer 1 utilis en mode timer. Nousdcidons pour cet exemple que nous avons besoin dun prdiviseur dune valeur de 4. Nousdcidons galement dautoriser linterruption du timer1. Si nous nous souvenons quil nousincombe de remettre le timer 0, nous aurons, par exemple, la squence suivante :clrf TMR1L ; effacer timer 1, 8 lsbclrf TMR1H ; effacer timer 1, 8 msbmovlw B00100000 ; valeur pour T1CONmovwf T1CON ; prdiviseur = 4, mode timer, timer offbsf STATUS,RP0 ; passer en banque 1bsf PIE1,TMR1IE ; autoriser interruptions timer 1bcf STATUS,RP0 ; repasser banque 0bsf INTCON,PEIE ; interruptions priphriques en servicebsf INTCON,GIE ; interruptions en servicebsf T1CON,TMR1ON ; mettre timer 1 en serviceLe raisonnement serait identique pour un fonctionnement en mode compteur.Bien entendu, il ne sagit que dun exemple, plusieurs lignes peuvent tre inverses, vouspouvez mettre GIE et PEIE en service en mme temps etc. Certains dentre vous, lilacr, ont peut-tre remarqu que je navais pas remis le flag TMR1IF 0 avant de lancerles interruptions.Cest judicieusement pens, mais ce nest pas utile. En effet, au moment de la mise soustension, PIR1 est automatiquement mis 0. De plus, T1CON est galement mis 0, ce quiimplique que le timer 1 est larrt tant quon ne le met pas en service intentionnellement.Donc, il est impossible que le timer 1 ait provoqu un dbordement de TMR1IF avant samise en service.Si, par contre, on ne dsirait pas compter de 0x0000 0xFFFF, on peut initialiser lesregistres du timer 1 pour diminuer le temps de comptage. Imaginons que nous dsirionscompter 3978 cycles dinstructions :En fait, nous devrons donc initialiser le timer1 pour quil dmarre le comptage 3978cycles avant sa valeur de dbordement. Vous voyez, en raisonnant un peu, quil suffit demettre dans les registres du timer1, la valeur 0x10000 de laquelle on soustrait la valeur compter. Exemple, pour bien visualiser, si vous dsirez compter 1 cycle, vous mettrez0x10000 0x01 = 0xFFFF, ce qui est logique, puisquau cycle suivant, nous auronsdbordement.Dans notre cas, il sagira donc de mettre 0x10000 D3978 dans notre timer1, constitude TMR1H pour le poids fort, et TMR1L pour le poids faible. Plutt que de calculer cettevaleur, autant laisser faire MPASM, il est l pour a (entre autres). Dfinissons notre valeursur 16 bits :166VALUE EQU 0x10000 D3978 ; calcul de la valeur sur 16 bits Il suffit alors de remplacer :clrf TMR1L ; effacer timer 1, 8 lsbclrf TMR1H ; effacer timer 1, 8 msbpar :movlw LOW VALUE ; 8 bits faibles de la valeur calculemovwf TMR1L ; dans TMR1Lmovlw HIGH VALUE ; 8 bits forts de la valeur calculemovwf TMR1H ; dans TMR1HBien entendu, dans notre exemple, vous devrez remettre le prdiviseur 1, sinon nousaurons interruption aprs 4 * 3978, soit 15912 cycles.De la sorte, notre compteur dbordera 3978 cycles aprs avoir t lanc. Vous voyez doncque vous pouvez obtenir une bien meilleure prcision quavec le timer 0, et, de plus,beaucoup plus facilement.15.10 Utilisation dune lectureNous pouvons aussi vouloir dcider dutiliser notre timer dune autre faon. En effet,supposons que nous voulions construire un chronomtre. Nous aurons alors la structure deprogramme suivante :- On presse le bouton dmarrer - On lance le timer 1 en mode timer, partir de 0.- On presse le bouton lecture de temps intermdiaire - On sauve la valeur de TMR1H et TMR1L- On presse le bouton stop - On arrte le timer 1- On lit la valeur dans TMR1H et TMR1LEvidemment, il sagit dun exemple, on considre ici, pour simplifier, que le tempsmesur est compris entre 0 et 0xFFFF cycles. Si le temps tait plus long, nous devrions enplus compter le nombre de fois que le timer1 a dbord. Nous aurions alors le temps total (encycles) = (nombre de dbordements * 0x10000) + valeur actuelle du mot de 16 bits : TMR1HTMR1L.La philosophie utilise dans ce mode est donc la suivante :- On dmarre le timer partir de 0- On dtecte un vnement- On lit la valeur du timer pour calculer le temps coulLe programme serait alors, par exemple (START, STOP et LAP sont des define quipointent sur des pins utilises en entre) :start167clrf TMR1L ; effacer timer 1, 8 lsbclrf TMR1H ; effacer timer 1, 8 msbattendrebtfss START ; tester si le bouton dmarrer est pressgoto attendre ; non, attendrebsf T1CON,TMR1ON ; oui, lancer le timerattendre2btfss LAP ; tester si temps intermdiaire pressgoto attendre2 ; non, attendremovf TMR1L,w ; lire 8 lsbmovwf VALL ; sauver dans variablemovf TMR1H,w ; lire 8 msbmovwf VALH ; sauver dans variableattendre3btfss STOP ; tester si bouton stop est pressgoto attendre3 ; non, attendrebcf T1CON,TMR1ON ; oui, arrter le timer 1movf TMR1L,w ; lire 8 lsbmovwf FINALL ; sauver dans variablemovf TMR1H,w ; lire 8 msbmovwf FINALH ; sauver dans variableExaminons ce programme. Noubliez pas quil sagit dun exemple symbolique, donc, jesais que ce programme impose de presser LAP avant de presser STOP , que les bouclesintroduisent une erreur, quil tait prfrable dutiliser dautres mthodes etc. En fait, ce nestpas ce que je voulais vous monter.Regardez la dernire lecture, celle qui place le timer 1 dans 2 variables, pour obtenir unevaleur sur 16 bits. Le rsultat FINALH FINALL reflte effectivement le temps qui sestcoul depuis la mise en service du timer 1 jusqu son arrt.Imaginez qu la fin de lexcution de cette squence, nous ayons :FINALL = 0x12FINALH = 0xDENous pouvons dire quil sest coul 0xDE12 cycles, soit 56850 cycles entre le dmarrageet larrt du timer 1.Regardez maintenant ce qui se passe au niveau de la mesure du temps intermdiaire.Supposons que nous avons aprs excution de notre programme :VALL = 0xFEVALH = 0x45Vous en concluez donc quil sest coul 0x45FE cycles, soit 17918 cycles entre ledmarrage du timer 1 et la mesure de temps intermdiaire (on nglige les temps de raction destockage des valeurs).Vous tes bien certain de ceci ? Oui ? Alors vrifions ce qui se passe lors de la lecture :movf TMR1L,w ; lire 8 lsb168Comme notre valeur VALL vaut 0xFE, cest donc que notre TMR1L vaut 0xFE. Nous neconnaissons pas encore, ce stade, la valeur de TMR1H. Ensuite :movwf VALL ; sauver dans variableNous sauvons donc bien 0XFE dans VALL, mais un cycle dinstruction sest excut,notre TMR1L continue de compter, et vaut donc maintenant 0xFF. Voyons la suite :movf TMR1H,w ; lire 8 msbA ce moment, une nouvelle instruction est excute, donc TMR1L a de nouveau tincrment, et est pass donc 0x00, entranant lincrmentation de TMR1H. Cest donc cettevaleur incrmente que nous allons lire. En effet, 0x44FF + 1 = 0x4500.movwf VALH ; sauver dans variableDonc, nous sauvons 0x45, puisque cest le rsultat que nous avions obtenu.Donc, nous avons dduit que la valeur du timer au moment de la lecture tait de 0x45FE,alors que nous constatons en ralit que ce compteur valait 0x44FE, soit 17662. Nous noussommes donc tromps de 256 cycles.Vous allez alors me rpondre quil suffit de vrifier que TMR1L soit infrieur 0xFE. Silest suprieur, on soustrait 1 de TMR1H.En fait, votre raisonnement nest valable que dans cet exemple prcis. En effet, lecomptage des cycles comme je viens de le faire ci-dessus inclus plusieurs conditions :- Il faut que le prdiviseur utilis soit gal 1. En effet, dans le cas contraire, si vous avezun TMR1L gal 0xFF, il vous est impossible de savoir sil y a eu incrmentation ou pasde TMR1L. Donc, vous ne pouvez savoir si vous devez ou non rectifier TMR1H.- Ensuite, si les interruptions sont en service, vous ne pouvez pas tre certain quil ny a paseu interruption entre la lecture de TMR1L et celle de TMR1H. Donc, vous ne pouvez passavoir combien de cycles sparent les 2 instructions.- Si nous travaillons en mode compteur, nous ne pouvons pas savoir combien dimpulsionsont t comptabilises entre les lectures.Forts de tout ceci, nous pouvons en dduire quil est prfrable, pour lire les 16 bits dutimer 1 doprer en mettant le dit timer hors-service :bcf T1CON,TMR1ON ; arrter le timer 1movf TMR1L,w ; lire 8 lsbmovwf FINALL ; sauver dans variablemovf TMR1H,w ; lire 8 msbmovwf FINALH ; sauver dans variablebsf T1CON,TMR1ON ; remettre timer en serviceMais, bien entendu, ceci nest pas toujours possible. En effet, dans notre exemple, lamesure du temps intermdiaire impose de ne pas arrter le timer pour lire la valeur. Nousallons donc changer de stratgie.169Nous pouvons utiliser lalgorithme suivant :- On lit le poids fort TMR1H et on le sauve- On lit le poids faible- On relit le poids fort : sil na pas chang, cest OK, sinon, on recommence.Si on se dit que le TMR1L ne peut dborder 2 fois de suite, on peut se passer derecommencer le test. Mais, pour que cette condition soit vraie, il faut que le temps sparant les2 lectures ne soit pas trop grand, donc il faut empcher quune interruption sintercale :- On interdit les interruptions- On lit le poids fort TMR1H et on le sauve- On lit le poids faible TMR1L et on le sauve- On relit le poids fort : sil na pas chang, on va en suite - On relit le poids fort- On relit le poids faibleSuite :- On rautorise les interruptionsCa parat plus long, mais si vous encodez la boucle prcdente, vous verrez que le tempsncessaire est plus long (surtout en cas dinterruption). Voici la squence tire de ce pseudo-code :bcf INTCON,GIE ; interdire les interruptionsmovf TMR1H,w ; charger poids fortmovwf TEMPOH ; sauver valeurmovf TMR1L,w ; lire poids faiblemovwf TEMPOL ; sauver valeurmovf TMR1H ; relire poids fortxorwf TEMPOH,w ; comparer les 2 poids fortsbtfsc STATUS,Z ; tester si identiquesgoto suite ; oui, fin du traitementmovf TMR1H,w ; charger poids fortmovwf TEMPOH ; sauver valeurmovf TMR1L,w ; lire poids faiblemovwf TEMPOL ; sauver valeursuitebsf INTCON,GIE ; rautoriser les interruptionsNotre programme prcdent devient donc :startclrf TMR1L ; effacer timer 1, 8 lsbclrf TMR1H ; effacer timer 1, 8 msbattendrebtfss START ; tester si le bouton dmarrer est pressgoto attendre ; non, attendrebsf T1CON,TMR1ON ; oui, lancer le timerattendre2btfss LAP ; tester si temps intermdiaire pressgoto attendre2 ; non, attendrebcf INTCON,GIE ; interdire les interruptionsmovf TMR1H,w ; charger poids fortmovwf VALH ; sauver valeurmovf TMR1L,w ; lire poids faiblemovwf VALL ; sauver valeur170movf TMR1H ; relire poids fortxorwf VALH,w ; comparer les 2 poids faiblesbtfsc STATUS,Z ; tester si identiquesgoto suite ; oui, fin du traitementmovf TMR1H,w ; charger poids fortmovwf VALH ; sauver valeurmovf TMR1L,w ; lire poids faiblemovwf VALL ; sauver valeursuitebsf INTCON,GIE ; rautoriser les interruptionsattendre3btfss STOP ; tester si bouton stop est pressgoto attendre3 ; non, attendrebcf T1CON,TMR1ON ; oui, arrter le timer 1movf TMR1L,w ; lire 8 lsbmovwf FINALL ; sauver dans variablemovf TMR1H,w ; lire 8 msbmovwf FINALH ; sauver dans variableVous voyez quil faut toujours rester attentif, pour viter de tomber dans toutes sortes depiges. Je vous montre les plus classiques, mais il en existera toujours dans une application oudans une autre.15.11 Ecriture du timer 1Nous venons de parler de lecture des 2 registres du timer 1. Vous vous doutez bien que lescritures comportent galement des piges.La plus simple des solutions est videmment darrter le timer lors dune criture, de lafaon suivante :bcf T1CON,TMR1ON ; stopper le timer 1movlw VALL ; charger valeur bassemovwf TMR1L ; dans registremovlw VALH ; charger valeur hautemovwf TMR1H ; dans registrebsf T1CON,TMR1ON ; remettre timer 1 en serviceMais, vous voudrez peut-tre, pour une application particulire, inscrire une valeur dans letimer sans devoir larrter. Quel problme allez-vous rencontrer ? Voyons donc le cassuivant :- On crit la valeur basse dans TMR1L- On crit la valeur haute dans TMR1HCa a lair tout simple, mais vous devez raisonner de faon identique que pour la lecture, savoir :Il se peut que votre registre TMR1L dborde entre le moment de son criture et le momentde lcriture de TMR1H. Supposons que vous vouliez crire la valeur 0x53FF.- Vous commencez par crire 0xFF dans TMR1L- Vous crivez 0x53 dans TMR1H, mais durant ce temps, TMR1L a dbord- La valeur finale crite est donc : 0x5300171Nous retrouvons donc le mme type derreur que pour la lecture, et les mmes remarques.Vous ne pouvez donc pas savoir partir de quelle valeur vous aurez dbordement, sauf pourle cas particulier du mode timer avec prdiviseur 1.A ce stade, jen vois qui disent : Eh, il suffit dcrire dans lautre sens, TMR1H suivi deTMR1L .Cest bien pens, mais, en fait, alors se pose un autre problme. Etant donn que le timerest en train de tourner, vous ne connaissez pas la valeur qui se trouve dans TMR1L aumoment de lcriture de TMR1H. Il se peut donc que le TMR1L dborde avant que vousnayez termin. Si on reprend lexemple prcdent :- On crit 0x53 dans TMR1H, TMR1L dborde ce moment, et incrmente TMR1H- On crit 0xFF dans TMR1L- Le rsultat final est donc 0x54FF.De nouveau, nous retrouvons notre erreur.En fait, la solution est simple : si on veut viter que le TMR1L dborde, il suffit de luiplacer en premier lieu une valeur suffisamment basse pour tre sr dviter tout dbordement(par exemple 0) . Bien entendu, il faudra galement interdire les interruptions :- On interdit les interruptions- On crit 0x00 dans TMR1L- On crit la valeur haute dans TMR1H- On crit la valeur basse dans TMR1L- On rautorise les interruptions Voici donc la squence rsultante :bcf INTCON,GIE ; interdire les interruptionsclrf TMR1L ; 0 dans TMR1Lmovlw VALH ; charger valeur hautemovwf TMR1H ; dans registremovlw VALL ; charger valeur bassemovwf TMR1L ; dans registrebsf INTCON,GIE ; rautoriser les interruptionsVous voyez que ce nest pas compliqu, condition de prendre garde aux piges qui voussont tendus.Il me reste vous signaler quune criture dans un des registres TMR1L ou TMR1Hprovoque leffacement des lments dj comptabiliss dans le prdiviseur. Une criture dansun de ces registres, si vous utilisez un prdiviseur diffrent de 1, provoquera donc une pertedinformations.Attention, ne confondez pas valeur du prdiviseur et contenu du prdiviseur . Lavaleur est celle que vous avez place via T1CKPS1 et T1CKPS0. Ces valeurs ne sont pasmodifies. Le contenu est le nombre dvnements dj compts par le prdiviseur. Cestdonc ce contenu qui est perdu lors dune criture dans TMR1L ou TMR1H.17215.12 Exercice pratiqueA la lecture de tout ce qui prcde, vous devez tre conscient quil mest trs difficile devous proposer des exercices pour tous les cas de figure possibles. Je vais donc me limiter unseul exemple qui mettra en pratique certains des points que nous avons abords.Puisque nous avons dj pas mal parl du mode timer lorsque nous avons tudi le timer 0dans la premire partie, je vais vous proposer un exercice qui utilise le timer 1 en modecompteur.Nous allons donc construire un programme qui inverse ltat dune LED chaque fois que10 impulsions sont reues sur la pin T1CKI . Ces impulsions seront cres par des pressionssur un bouton-poussoir.Si vous vous souvenez de la premire partie, javais parl que les interrupteurs sontsoumis des rebonds. Il nous faudra donc, pour que notre montage fonctionne liminer cesrebonds.Jutiliserai pour ce faire la charge dun petit condensateur au travers dune rsistance. Cecipermettra de ralentir (intgrer) la monte du niveau en tension, de faon ce que le passage ltat 1 intervienne aprs la fin des rebonds de linterrupteur.Afin de permettre lutilisation de tous les types dinterrupteurs, jai choisi un temps deretard de 20ms.Voici le schma que nous allons utiliser :17315.12.1 Un peu de mathsJe pourrais vous donner les valeurs que jai choisies en vous donnant une formuleapproximative, pourtant largement suffisante. Seulement, jai remarqu quil y a desmticuleux parmi mes lecteurs (je nai pas dit maniaques ). Si je ne donne pas plus deprcision, je vais donc mattirer de nouveau de nombreux courriers. Je prends donc lesdevants Et puis, il faut bien que je montre de temps en temps que je sais calculer, et, de plus, ava mattirer la sympathie des professeurs de mathmatiques (en esprant que je ne fasse pasderreur).Plus srieusement, je profite de cet exemple pour vous montrer comment calculer desmontages particuliers. Ceux que a nintresse pas nont qu excuter le pseudo-codesuivant :Dbut Si je naime pas les maths Alors goto chapitre 15.12.2 Sinon On poursuit :Redevenons srieux (a change) :Voyons donc les donnes :- Le temps de charge : 20 ms- La tension applique : 5V- La tension dtecte comme niveau haut par le PIC : 0,7 VDD (datasheet)Les inconnues :- R1- R2- CEt la formule de charge dun condensateur sous une tension constante, et via unersistance srie :Uc = U1 (1-e-t/rc)Avec Uc = tension aux bornes du condensateur aprs le temps t , U1 = tension decharge, t = temps coul depuis le dbut de la charge, r = rsistance de charge, et c = valeurdu condensateur.Donc, une quation avec 3 inconnues (R1,R2,C), il va falloir avoir de limagination(comme dhabitude en lectronique).Tout dabord, si on regarde le montage, on constate que si on ferme linterrupteur, en finde charge du condensateur, la tension finale est dtermine par le pont diviseur form par R1et R2. Donc, il nous faut choisir R2 fortement suprieur R1, sous peine de ne pouvoir jamais174atteindre notre tension de niveau haut gale 0,7 Vdd. Nous prendrons arbitrairement R2 =10*R1. Vous voyez en effet que si vous choisissez R1 = R2, par exemple, votre tension finalene pourra dpasser Vdd/2.Ensuite, il ne faut pas que le courant consomm par la pin T1CKI soit trop important parrapport au courant de charge, sous peine de ne pas arriver charger le condensateur. Il fautaussi que limpdance dentre de T1CKI soit assez suprieur R2 pour ne pas fausser noscalculs.Le datasheet (15.3) nous donne un courant dentre de T1CKI = 5A.Forts de tout ceci, nous dduisons la rsistance dentre de notre T1CKI :R = U/IR = 5V / (5 * 10-6A) = 106 Ohms = 1 MOhmsNous choisirons donc, pour viter les interfrences entre courant absorb par T1CKI etcharge du condensateur, R2 = Rtocki / 10Donc : R2 = 100 KOhmsDo : R1 = R2 / 10, donc R1 = 10 KohmsNe reste donc plus quune inconnue, C, quil faut tirer de lquation prcdente. Qui sycolle ? Ben oui, les maths, tout compte fait, a ne sert pas qu lcole. Si a vous tente defaire comme moi, prenez un papier et calculez ce condensateur. Sinon, lisez la suite :Bon, essayons de voir notre formule, il nous faut extraire C qui est dnominateur dunexposant de e . Pas vraiment marrant. Posons :-t/rc = xCeci rend la lecture plus claire, car nous avons maintenant :Uc = U1 * (1-ex)Nous ne connaissons pas x , mais nous avons besoin, pour le trouver de connatre U1,qui est la tension relle de charge.5V me direz-vous ? Pas du tout ! La tension de charge est dtermine par le pont diviseurR1/R2. Encore des souvenirs de lcole allez-vous penser. Cest trs simple pourtant, cettefois il suffit dappliquer la loi dOhm (jai horreur de retenir des formules toutes faites, jeprfre les retrouver par raisonnement).En fin de charge du condensateur, et tant donn que nous avons choisi les rsistancespour que le courant absorb par T1CKI soit ngligeable, nous pouvons dire que le courantcirculant dans R1 (IR1) est le mme que celui circulant dans R2(IR2), et, videmment le mmeque celui qui circule dans les deux (IR12R2).175Donc, comme I = U/R,IR2 = Vdd / (R1+R2)Donc, la tension aux bornes de R2, qui est notre tension de charge finale, est gale IR2 *R2, donc :UR2 = U1 = (Vdd / (R1+R2)) * R2U1 = (5V * 105 Ohms) / (105 Ohms + 104 Ohms).U1 = (5V * 105) / (11*104)U1 = 4,54VLe passage au niveau 1 se fait 0,7Vdd, soit 0,7 * 5V = 3,5V. Donc, notre tensionfinale de 4,54V nous permet bien de faire passer T1CKI au niveau 1 .Reprenons notre quation :Uc = U1 * (1-ex)Donc :1- ex = Uc/U1Doex = 1-(Uc/U1)Mais ce foutu x est toujours en exposant ,il faudrait le faire descendre . En grattantdans vos souvenirs, vous vous souviendrez peut-tre que le logarithme nprien dun nombre la puissance n est gal n . Autrement dit : ln(ex)= x.Pour vous en convaincre, ce nest quun cas particulier des logarithmes. Un logarithme enbase x de la base la puissance y est gal y. Simple exemple en base 10 :Log 105 = 5Le logarithme nprien ntant quun logarithme en base e , vous comprenezmaintenant lgalit prcdente.Il suffit donc, pour respecter lgalit, de prendre le logarithme nprien des 2 cts delidentit. Ceci nous donne :ln (ex) = ln(1-(Uc/U1) )Ou encore :x = ln(1-(Uc/U1))176Uc reprsente la tension aux bornes du condensateur aprs le temps que nous avons dfini(20ms). Or, ce temps est le temps du passage au niveau haut de T1CKI. Ce passageseffectuant lorsque la tension est gale 0,7 Vdd, nous avons donc que Uc = 0,7Vdd, soit0,7*5V (la tension dalimentation du PIC) = 3,5V.Donc, nous pouvons tirer x :X = ln (1-(3,5V / 4,54V) = -1,473Ne reste plus qu remplacer de nouveau x par ce quil reprsente :(-t/rc) = -1,473donc,t = 1,473 * r * cAutrement dit (et crit) :C = t / (1,473 * r)C = 20 * 10-3 F / (1,473 * 104 )On peut en effet estimer que la rsistance de charge vaut R1.C = 20 * 10-7 F / 1,473 = 2 * 10-6 F / 1,473 = 1,3 * 10-6FDonc,C = 1,3 F.Nous prendrons donc un condensateur de 1 F.Si, pour vrifier, vous remplacez C par sa valeur dans la formule initiale, :Uc = U1 * (1-e-t/rc) , vous trouverez Uc = 3,56V, ce qui nous rend bien les 3,5V de passage duniveau 0 vers le niveau 1 de notre pin T1CKI. C.Q.F.D.Ca fait plaisir de voir quon nest pas encore tout fait rouill, pas vrai ?15.12.2 Le programmeRevenons nos moutons, je veux dire nos PICs. Nous allons construire le pseudo-codede notre programme :InitialiserInitialiser le timer 1 et le charger avec une valeur de -10 Aller au programme principal177Interruption timer 1Inverser LEDRecharger timer 1 avec -10 Fin dinterruptionProgramme principalRien faire du toutCopiez comme dhabitude votre fichier maquette, et renommez la copie cmpt1.asm .Crez un nouveau projet, et crez len-tte du programme.;*****************************************************************************; Exercice d'utilisation du timer 1 en mode compteur. *; On inverse une LED pour chaque srie de 10 impulsions reues sur T1CKI *; *;*****************************************************************************; *; NOM: Cmpt1 *; Date: 07/05/2002 *; Version: 1.0 *; Circuit: platine d'exprimentation *; Auteur: Bigonoff *; *;*****************************************************************************; *; Fichier requis: P16F876.inc *; *; *; *;*****************************************************************************; *; Notes: Entre des impulsions sur T1CKI (RC0). *; Impulsions gnres par un bouton-poussoir quip d'un systme *; anti-rebond par rseau RC. *; LED de sortie connecte sur RB0 *; *;*****************************************************************************LIST p=16F876 ; Dfinition de processeur#include ; fichier include__CONFIG _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_OFF & _CPD_OFF & _LVP_OFF &_BODEN_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC;_CP_OFF Pas de protection;_DEBUG_OFF RB6 et RB7 en utilisation normale;_WRT_ENABLE_OFF Le programme ne peut pas crire dans la flash;_CPD_OFF Mmoire EEprom dprotge;_LVP_OFF RB3 en utilisation normale; _BODEN_OFF Reset tension hors service;_PWRTE_ON Dmarrage temporis;_WDT_OFF Watchdog hors service;_HS_OSC Oscillateur haute vitesse (20Mhz)Ensuite, les assignations systme, dont on ne conserve que celles utiles. A noter que, vuquon na quun bit positionner pour chacune, et que le niveau est connu au moment de lamise sous tension, on aurait pu se permettre de nutiliser que le positionnement du bit en178question (bsf ou bcf) au niveau de la routine dinitialisation. Cependant, pour ne rien omettre,conservons ces assignations.;*****************************************************************************; ASSIGNATIONS SYSTEME *;*****************************************************************************; REGISTRE OPTION_REG (configuration); -----------------------------------OPTIONVAL EQUB'10000000' ; Rsistance rappel +5V hors service; REGISTRE INTCON (contrle interruptions standard); -------------------------------------------------INTCONVAL EQUB'01000000' ; autorisation gnrale priphriques; REGISTRE PIE1 (contrle interruptions priphriques); ----------------------------------------------------PIE1VAL EQUB'00000001' ; interrupt dbordement tmr1Ensuite, nous avons nos constantes. Ici, nous souhaitons que le timer 1 dborde au bout de10 pressions sur le bouton-poussoir. Nous devrons donc recharger le timer avec une valeurtelle que TMR1H dborde aprs 10 vnements. Donc, comme je vous lai expliqu :;*****************************************************************************; ASSIGNATIONS PROGRAMME *;*****************************************************************************RELOADEQU 0x10000 - D'10' ; valeur de recharge de TMR1Concernant les macros, ne conservez que la macro de passage en banque 0;*****************************************************************************; MACRO *;*****************************************************************************BANK0 macro ; passer en banque0bcfSTATUS,RP0bcfSTATUS,RP1endmNous navons, premire vue, pas besoin de variable, vu que cest notre timer 1 qui vacompter lui-mme les impulsions reues. Profitons-en galement pour supprimer les variablesde sauvegarde dont nous naurons pas besoin. Notre programme principal ne fera rien du tout,il ny a donc rien sauvegarder lors dune interruption.;*****************************************************************************; VARIABLES BANQUE 0 *;*****************************************************************************CBLOCK0x20 ; Dbut de la zone (0x20 0x6F)ENDC;*****************************************************************************; VARIABLES ZONE COMMUNE *;*****************************************************************************CBLOCK 0x70 ; Dbut de la zone (0x70 0x7F)ENDC179;*****************************************************************************; DEMARRAGE SUR RESET *;*****************************************************************************org 0x000 ; Adresse de dpart aprs reset goto init ; InitialiserVoyons notre routine dinterruption, trs simple :- Il ny a quune seule interruption, donc, inutile de tester de quelle interruption il sagit.- Il ny a rien sauvegarder, donc rien restaurer- La routine se contente dinverser la LED et de recharger le timer (compteur)- Il ne faut pas oublier deffacer le flag de linterruption timer 1 (TMR1IF)Nous pouvons donc crire notre routine dinterruption, rduite sa plus simpleexpression :;*****************************************************************************; ROUTINE INTERRUPTION TIMER 1 *;*****************************************************************************ORG 0x04movlw B'00000001' ; pour bit 0xorwf PORTB,f ; inverser LEDclrf TMR1L ; car criture sans stopper compteurmovlw HIGH RELOAD ; octet fort valeur de rechargemovwf TMR1H ; dans timer poids fortmovlw LOW RELOAD ; octet faible valeur de rechargemovwf TMR1L ; dans timer poids faiblebcfPIR1,TMR1IF ; effacer flag interuptretfie ; return from interruptReste maintenant, dans notre routine dinitialisation, initialiser notre timer 1 en modecompteur (nous choisirons asynchrone, mais cela na aucune importance ici), le prchargeravec le valeur RELOAD , de faon ce que le premier allumage de la LED seffectueaprs 10 pressions sur notre bouton-poussoir, et initialiser notre LED en sortie de RB0.;*****************************************************************************; INITIALISATIONS *;*****************************************************************************init; initialisation PORTS (banque 0 et 1); ------------------------------------BANK0 ; slectionner banque0clrf PORTB ; sorties PORTB 0bsf STATUS,RP0 ; passer en banque1bcf TRISB,0 ; RB0 en sortie (LED); Registre d'options (banque 1); -----------------------------movlw OPTIONVAL ; charger masquemovwf OPTION_REG ; initialiser registre option; registres interruptions (banque 1); ----------------------------------movlw INTCONVAL ; charger valeur registre interruption180movwf INTCON ; initialiser interruptionsmovlw PIE1VAL ; Initialiser registremovwf PIE1 ; interruptions priphriques 1; initialiser timer 1; --------------------bcf STATUS,RP0 ; passer banque 0movlw LOW RELOAD ; octet faible de recharge timer 1movwf TMR1L ; dans registre poids faiblemovlw HIGH RELOAD ; octet fort de recharge timer 1movwf TMR1H ; dans registre poids fortmovlw B'000000111' ; timer en service en mode compteur asynchronemovwf T1CON ; dans registre de contrle timer 1bsf INTCON,GIE ; valider interruptionsReste notre programme principal, qui ne fait strictement rien :;*****************************************************************************; PROGRAMME PRINCIPAL *;*****************************************************************************startgoto start ; bouclerEND ; directive fin de programmeProgrammez votre 16F876, placez la sur votre circuit, et lancez lalimentation. Pressez lebouton calmement une trentaine de fois. Votre LED doit sinverser chaque multiple de 10pressions.Si , ce niveau, vous obtenez un comportement erratique (la LED sallume nimportequand, frtille etc.), cest que vous avez travaill avec des fils volants. Or, la rsistance derappel la masse de T1CKI (R2) est de 100 Kohms, ce qui est une grosse valeur. Il faut savoirque lorsque vous travaillez avec des valeurs suprieures 10 Kohms, les interfrences(parasites) sont de plus en plus susceptibles daffecter votre montage.Dans ce cas, le remde est fort simple : vous remplacez R2 par une rsistance de10Kohms. Cependant, alors, pour respecter tous nos calculs, il vous faudra alors remplacer R1par une rsistance de 1Kohms, et C par un condensateur de 10F. Vous voyez quil y atoujours plusieurs paramtres lectroniques prendre en compte pour la ralisation dunmontage. En rgle gnrale, utilisez des rsistances dentre infrieures ou gales 10Kohms.Bon, ce stade, tout le monde est galit, avec un montage oprationnel. Coupezlalimentation, attendez 5 secondes, et relancez lalimentation.Pressez lentement le bouton-poussoir (1 pression par seconde), et comptez les impulsionsavant le premier allumage de la LED. Vous vous attendiez 10 impulsions, mais vous devezen trouver 11.Que voil un curieux phnomne, vous ne trouvez pas ?En fait, lexplication est donne par le fonctionnement interne du timer 1 du PIC.La premire impulsion nest prise en compte que si le signal dentre a subit au moins unflanc descendant. Et oui, vous aviez dj oubli ?181Ceux qui sen sont souvenus sont trs forts et mritent une mention trs bien .Pour rsumer, la mise sous tension de notre montage, le niveau sur T1CKI est bas.Lorsque vous pressez la premire fois sur le bouton, vous avez un flanc montant. Mais ceflanc montant nayant pas t prcd dun flanc descendant, ce flanc nest tout simplementpas pris en compte.Vous relchez ensuite le bouton, ce qui fait passer votre niveau dentre de 1 0 .Ceci constitue votre premier flanc descendant. Donc, le comptage seffectuera partir de laprochaine pression du bouton-poussoir.Vous pouvez vrifier ceci en constatant que si le premier allumage de la LED seffectueaprs 11 pressions, tous les autres allumages et extinctions seffectueront aprs 10 impulsions.Vous pourriez corriger le programme en initialisant la valeur du timer1 dans la routine dedinitialisation -9 au lieu de -10 . La valeur -10 devant demeurer dans la routinedinterruption. Si vous voulez vrifier, il suffit donc dajouter 1 dans TMR1L (pour lesrticents en maths, pour passer de 10 -9 , il faut ajouter 1 et non soustraire .Votre routine dinitialisation du timer devient :; initialiser timer 1; --------------------bcf STATUS,RP0 ; passer banque 0movlw LOW RELOAD+1 ; octet faible de recharge timer 1movwf TMR1L ; dans registre poids faiblemovlw HIGH RELOAD ; octet fort de recharge timer 1movwf TMR1H ; dans registre poids fortmovlw B'000000111' ; timer en service en mode compteur asynchronemovwf T1CON ; dans registre de contrle timer 1bsf INTCON,GIE ; valider interruptions15.13 Errata : Fonctionnement non conformeJe termine sur une remarque importante qui concerne plusieurs versions de 16F87x.,quand le timer 1 est configur en mode compteur , que ce soit synchrone ou asynchrone :La lecture du registre TMR1L peut empcher TMR1H dtre incrment durant le tempsde la lecture. Inversment, la lecture de TMR1H peut empcher TMR1L dtre incrmentdurant le temps de la lecture.Ceci peut tre particulirement gnant, si le passage de TMR1L de 0xFF 0x00 neprovoque pas lincrmentation de TMR1H, donnant de ce fait une erreur non ngligeable.Microchip indique que ce point sera prochainement corrig, mais cela fait plusieursversions de suite que cette correction nest pas effective.A vous, dans le cas o vous utilisez ces possibilits, soit de grer ce phnomne, soitde vous renseigner chez Microchip pour savoir si votre propre version de PIC intgre toujoursce bug.182La solution de Microchip pour contourner le problme est pour le moins radicale : ilrecommande, si vous utilisez le timer 1 avec le bit TMR1CS positionn (mode compteur) etque vous devez lire la valeur 16 bits du compteur, dutiliser tout simplement un autre timer ouune autre mthode pour votre application.Prcisons, pour ceux qui nauraient pas bien compris, que a ne concerne que la lecture oulcriture des registres TMR1L/TMR1H sans arrter le timer.Les solutions que jai proposes pour viter les erreurs ne fonctionneront donc que sur lesversions debugges des PICs.Jai cependant donn ces solutions, car ce sont des grands classiques sur toutes lesfamilles de microcontrleurs utilisant des compteurs sur 16 bits. Connatre ces techniquesvous sera toujours utile. De plus, lorsque vous passesez des PICs plus performants, il faudraesprer que Microchip aura rsolu ce problme.183Notes : 184Notes : 18516. Le debuggage pin-stimulus Et oui, en cas de problme, la premire question qui vient lesprit est : comment puis-jesimuler un programme qui fait intervenir des modifications de niveaux sur les pins ?Jintroduis ce chapitre ici, car vous vous posez peut-tre la question suite vos ventuelsdboires concernant lexercice prcdent.En fait, MPLAB dispose de la possibilit de crer un fichier qui contient les vnements envoyer sur une ou plusieurs pins, en fonction du nombre de cycles couls depuis le dbut duprogramme.Prenez votre projet cmpt1 , que nous allons faire fonctionner en mode simulation.- Allez dans le menu : file -> New . Une fentre souvre alors.- Dans cette fentre, vous commencez par introduire le mot CYCLE qui sert MPLAB(anciennes versions) dterminer quil sagit dun fichier dvnements.- Tapez une tabulation, puis entrez le numro de la pin simuler. Pour notre part, il sagitde T1CKI. Mais comme MPLAB ne reconnat pas ce nom, nous utiliserons son autrenom : RC0 .- Vous pouvez ensuite taper dautres noms spars par des tabulations, chaque nomcorrespondant une pin simuler.- Tapez return - Sous la colonne CYCLE , vous tapez le numro du cycle auquel se rapporte lamodification. Il sagit ici de cycles dinstructions. Pour rappel ,chaque instruction utiliseun cycle, sauf les sauts qui en ncessitent 2.- Ensuite, sous la colonne RC0 , donc aprs avoir tap une nouvelle tabulation, entrezltat que vous dsirez pour la pin en question.- Procdez de mme pour les autres pins, et vous pouvez terminer par un commentairespar par un ; RemarquePour savoir quels sont les noms de pins que vous pouvez utiliser, allez dans Debug>Simulator Stimulus>Asynchronous . Une fois la fentre ouverte, allez sur Stim 1(P) et cliquez avec le bouton de droite. Choisissez assign pin et vous avez la liste desnoms de pins autoriss.Observez que cette fentre vous donne accs MCLR, donc vous permet de simuler desoprations de reset .186Voici le fichier que nous allons crer pour la circonstance :CYCLE RC000 0 ; au dbut, RC0 = 030 1 ; 30 cycles aprs le dbut, mettre RC0 1 40 0 ; puis, tous les 10 cycles, on inverse RC050 160 070 180 090 1100 0110 1120 0130 1140 0150 1160 0170 1180 0190 1200 0210 1220 0230 1240 0250 1260 0270 1280 0A titre dinformation, si vous aviez voulu utiliser 2 pins (RC0 et RC1) , voici ce que vousauriez pu crer :CYCLE RC0 RC100 0 0 ; au temps 0, RC0 et RC1 sont 0 30 1 0 ; aprs 30 cycles, RC0 = 1 et RC1 = 040 0 1 ; 10 cycles plus loin, RC0 = 0 et RC1 = 1Notez que la valeur des cycles reprsente le nombre de cycles couls depuis le dbut duprogramme.Maintenant, sauvez votre fichier (file -> save as) en entrant un nom termin parlextension .sti pour STImulus . Ne tenez donc pas compte des suffixes indiqus pardfaut.Vous sauvez alors votre fichier sous cmpt1.sti . Vrifiez imprativement que la case unix format ne soit pas coche.Nous allons ensuite indiquer MPLAB quil doit utiliser ce fichier :- Allez dans le menu : debug -> simulator stimulus - Choisissez pin-stimulus -> enable 187- Un requester souvre alors, vous demandant de choisir votre fichier. Choisissez cmpt1.sti .A ce stade, allez dans windows -> Stopwatch Une fentre souvre alors, qui vous indique le nombre de cycles que MPLAB estimecoul depuis le dbut de votre simulation. Si la fentre cycles nindique pas 0 , alorspressez Zero .Vous pouvez maintenant lancer la simulation de faon classique. Pressez F6, puis F7 pourchaque pas.Remarquez quau cycle 30, RC0 passe 1 et que TMR1L est incrment. Continuez vosactions sur F7 jusqu ce que une interruption soit gnre.La dernire action de votre fichier sti se termine au cycle 280. Une fois arriv cecycle, il vous suffit de presser zero dans votre fentre stopwatch pour que la lecture devotre fichier sti reprenne au dbut, sans influencer le droulement de votre programme.Vous constaterez galement que MPLAB incrmente votre registre TMR1L aupremier flanc montant de RC0. Le programme ne prsuppose pas des tats prcdents deRC0. Il ne peut donc savoir sil sagit ou non dun premier flanc montant.Ceci doit attirer votre attention sur les limites des simulations. Une simulation reste unesimulation, et ne peut donc prendre toutes les contraintes relles en compte.Un autre exemple est que, en mode simulation, toutes les variables en zone RAM sontinitialises 0, alors que dans la ralit, leur contenu est alatoire. Idem concernant le contenudes timers.Nous verrons dans le livre suivant une mthode de debuggage beaucoup plus puissante.188Notes :18917. Le timer 2Dans ce chapitre, nous allons maintenant tudier le dernier des trois timers de notre PIC.Celui-ci dispose, comme vous pouvez dj vous en douter, de caractristiques diffrentes des2 autres.Cette approche de Microchip permet lutilisateur davoir un panach des modesdutilisations possibles, tout en conservant, pour chaque timer, une facilit dutilisation et unecomplexit, donc un cot, abordables.Votre dmarche, lorsque vous choisirez un timer, sera donc fonction de lutilisationenvisage. Jy reviendrai.17.1 Caractristiques du timer 2Le timer 2 est un compteur sur 8 bits, donc nous ne rencontrerons pas les difficultsinhrentes la lecture et lcriture de ses registres.Le timer 2, comme les prcdents, possde un prdiviseur. Celui-ci peut tre paramtravec une des 3 valeurs suivantes : 1,4, ou 16. Nous sommes donc pauvres ce niveau.Cependant, le timer 2 dispose galement dun postdiviseur, qui effectue une secondedivision aprs lunit de comparaison, que nous allons voir. Ce postdiviseur peut prendrenimporte quelle valeur comprise entre 1 et 16, ce qui donne un grand choix possible ceniveau.La valeur du diviseur total, vue par lutilisateur, est bien entendu obtenue en multipliant lavaleur du prdiviseur par celle du postdiviseur.Moyennant ceci, il est possible, avec le timer 2, dobtenir les valeurs de diviseursuivantes :1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,20,24,28,32,36,40,44,48,52,56,60,64,80,96,112,128,144,160,176,192,208,224,240,256Vous voyez quavec ce timer, vous disposez dun large ventail de diviseurs effectifs.Le timer 2 incrmente pour sa part le registre TMR2, registre unique puisque comptagesur 8 bits.Les valeurs de division minimale et maximale sont donc identiques celles du timer 0, quidisposait galement dun comptage sur 8 bits, avec prdiviseur de 1 256.Le registre TMR2 est remis automatiquement 0 lors dun reset, contrairement au timer 1,pour lequel vous deviez vous en charger. Ceci peut tre un avantage ou un inconvnient,suivant le type de raction que vous attendez du timer. Cest clair quun reset inopin et nondsir du pic remettra dans ce cas votre timer 2 dans son tat initial.190Il faut galement tenir compte que ce timer ne dispose daucune entre extrieure via unepin du PIC. Il ne peut donc fonctionner quen mode timer pur.17.2 Le timer 2 et les interruptionsLe timer 2 fonctionne, ce niveau, comme le timer1. Le flag dinterruption se nommeTMR2IF, en toute logique, tandis que le bit dautorisation sappelle TMR2IE.La principale diffrence provient de lvnement qui cause le positionnement de TMR2IF,donc qui cause linterruption. Je vais en parler un peu plus loin.Tout comme pour le timer 1, il sagit dune interruption priphrique, donc, la procdurepour autoriser les interruptions du timer 2 se fera en 3 tapes :- Autorisation des interruptions priphriques via le bit PEIE du registre INTCON- Autorisation de linterruption timer 2 via TMR2IE du registre PIE1- Autorisation gnrale des interruptions via le bit GIE du registre INTCONJe vous renvoie donc aux chapitres prcdents pour des renseignements plus prcis.17.2 Le timer 2 et les registres PR2 et T2CONLe principe de fonctionnement des 2 prcdents timers tait le suivant :- On incrmente le contenu du TMR (sur 1 ou 2 octets) suivant lvnement choisi et lavaleur du prdiviseur.- Une fois que le timer dborde , ceci dclenche le positionnement du flag associLe principe du timer 2 est diffrent, dans le sens que lvnement dtect nest pas ledbordement ordinaire du timer (cest--dire le passage de 0xFF 0x00), mais ledbordement par rapport une valeur prdfinie.Cette valeur tant mmorise dans le registre PR2 (banque 1). Nous pouvons donc avoir,par exemple, dbordement de 0x56 0x00, en plaant la valeur 0x56 comme valeur maximaledans le registre PR2.On peut donc dire que le fonctionnement du timer est le suivant :- On incrmente le contenu du prdiviseur chaque cycle dinstruction- Chaque fois que ce contenu correspond un multiple de la valeur du prdiviseur, onincrmente TMR2 (contenu du timer 2)- Chaque fois que le contenu de TMR2 dpasse le contenu de PR2, on remet TMR2 0, eton incrmente le contenu du postdiviseur.191- Chaque fois que le contenu du postdiviseur correspond un multiple de la valeur dupostdiviseur, on positionne le flag TMR2IF.Pour clarifier la comprhension, je vous donne le schma-bloc du timer 2.Vous constatez quil ny a pour ce timer quune seule source de comptage, savoirlhorloge principale du PIC divise par 4, autrement dit le compteur dinstructions. Noussommes donc bien en prsence dun timer pur .Une prdivision est paramtre par T2CKPS0 et T2CKPS1. La sortie du prdiviseurincrmente le registre TMR2. Cette valeur est compare avec la valeur contenue dans PR2.Chaque fois que les contenus de TMR2 dpasse celle de PR2, la sortie du comparateurincrmente la valeur contenue dans le postdiviseur. Cette sortie effectue galement un reset deTMR2, qui redmarre donc 0.En fait ce schma est trompeur, bien que dorigine Microchip, car il risque dinduire enerreur. En effet, la sortie du comparateur sera prise en compte le cycle suivant lgalit desdeux registres, donc lors du dbordement du timer par rapport la valeur de PR2.Donc, le nombre de cycles rellement compts est, abstraction faite des diviseurs, lavaleur de PR2 incrmente de 1.En effet, tout comme pour le timer0, vous aviez une impulsion chaque dbordement de0xFF vers 0x00, pour le cas du timer2, vous aurez dbordement de la valeur de PR2 vers0x00. Le timer 0 donnait bien, pour une valeur maximale de 0xFF, un nombre dimpulsionscomptes de 0x100 (D256), donc valeur maximale + 1. Il sagit donc ici du mmephnomne et du mme calcul.Chaque fois que le contenu du postdiviseur est gal un multiple de la valeur de ce celui-ci, paramtre par TOUTPS0 TOUTPS3, le flag TMR2IF est forc 1, et une interruptionest ventuellement gnre.192Ne vous proccupez pas de la flche sortie de TMR2 , le timer2 est utilis en internepour dautres fonctions que nous tudierons plus tard.Une criture dans le registre TMR2 efface le contenu du prdiviseur et du postdiviseur.Pour rappel, ne pas confondre contenu (nombre dvnements compts) et valeur (dterminepar les bits de configuration).Forts de tout ceci, vous avez maintenant compris que la spcificit du timer 2, et donc sonprincipal avantage, est quil permet de configurer le dbordement sur nimporte quellevaleur de TMR2, associ un large ventail de valeurs de diviseur.Inutile donc dattendre le passage de 0xFF 0x00, quoique cela reste possible,simplement en plaant 0xFF dans PR2.Cet avantage, combin la grande flexibilit de lensemble prdiviseur/postdiviseur,permet dobtenir trs facilement des dures dinterruption prcises sans complicationslogicielles.Voici prsent le contenu du registre T2CON, qui permet de paramtrer prdiviseur etpostdiviseur, ainsi que dautoriser ou non le fonctionnement du timer2.T2CON (en banque 0)- b7 : non utilis, laisser 0- b6 : TOUTPS3 : Timer2 OUTput PostScale bit 3- b5 : TOUTPS2 : Timer2 OUTput PostScale bit 2- b4 : TOUTPS1 : Timer2 OUTput PostScale bit 1- b3 : TOUTPS0 : Timer2 OUTput PostScale bit 0- b2 : TMR2ON : TiMeR 2 ON- b1 : T2CKPS1 : Timer 2 ClocK PreScale bit 1- b0 : T2CKPS0 : Timer 2 ClocK PreScale bit 0Vous constatez que les bits TOUTPSx permettent de configurer la valeur du postdiviseur.Il y a 16 valeurs possibles (0 15). Comme une valeur de diviseur de 0 na aucun sens, lenombre form par les 4 bits de TOUTPSx est incrment de 1 pour obtenir la valeur effectivedu postdiviseur.Voici donc les valeurs utilisables :193b6 b5 b4 b3 Postdiviseur0 0 0 0 10 0 0 1 20 0 1 0 30 0 1 1 40 1 0 0 50 1 0 1 60 1 1 0 70 1 1 1 81 0 0 0 91 0 0 1 101 0 1 0 111 0 1 1 121 1 0 0 131 1 0 1 141 1 1 0 151 1 1 1 16Quant au prdiviseur, on na le choix quentre 3 valeurs :b1 b0 Prdiviseur0 0 10 1 41 0 161 1 16Il me reste vous donner la formule de la dure sparant 2 positionnements conscutifs duflag TMR2IF. Vous pourriez retrouver cette formule vous-mme, en suivant les explicationsprcdentes :Dure totale = temps dune instruction * prdiviseur * postdiviseur * (PR2 +1)La valeur maximale est donc bien, comme pour le timer 0 de 16*16*256 = 65536.17.3 Utilisation pratique de notre timer 2Supposons que nous dsirions raliser une interruption toutes les secondes. Nous avionsvu quavec nos autres timers, ceci nous posait problme, car nous navions aucune valeurmultiple exacte possible, do une erreur au final (sauf utiliser un second quartz sur letimer1 ou diminuer la frquence de fonctionnement du PIC).Nous calculons quavec notre quartz de 20MHz, nous avons 5.000.000 de cyclesdinstruction par seconde. Nous allons donc devoir compter le plus prcisment possiblejusque 5.000.000.194Vous vous rendez bien compte que compter jusque 5.000.000 ne peut tre ralis en unseul passage dans la routine dinterruption, le maximum tant de 65536. Nous allons doncpasser un certain nombre de fois dans la routine dinterruption.Cherchons tout dabord le plus grand nombre de 8 bits permettant une division exacte de5.000.000. Sans tre expert en mathmatiques, le nombre D250 convient trs bien.Nous pouvons donc dcider quaprs 250 passages dans notre routine dinterruption, nousaurons atteint une seconde. Ceci implique que nous devions compter jusque 5.000.000/250 =20.000 entre 2 passages.La valeur maximale pouvant tre compte par notre timer 2, je le rappelle, est de 256 (siPR2 = 0xFF) multipli par 256 (prdiviseur * postdiviseur), soit 65536. Nous sommes doncen dessous, cela reste donc possible.Nous allons maintenant essayer de trouver une combinaison prdiviseur/postdiviseur qui nous donne un rsultat entier, en commenant par la plus forte valeur, soit 256. Souvenez-vous que les valeurs possibles de toutes les combinaisons sont :1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,20,24,28,32,36,40,44,48,52,56,60,64,80,96,112,128,144,160,176,192,208,224,240,256- Une valeur de division de 256 nous donne 20.000 / 256 = 78,125- Une valeur de division de 240 nous donne 20.000/240 = 83,33- Nous continuons de la sorte, toujours des rsultats fractionns- Une valeur de division de 160 nous donne 20.000/160 = 125Nous voici donc avec une valeur entire. Nous devons donc configurer PR2 avec une valeurde (125 1), soit 124, ce qui est tout fait dans nos possibilits.Pour raliser notre programme, nous devrons donc :- Configurer le prdiviseur 16- Configurer le postdiviseur 10 (10*16 = 160)- Plaer D124 dans PR2Moyennant quoi, pour chaque 250me passage dans la routine dinterruption, nous auronsune dure exacte dune seconde.Ceci nous donne donc une prcision gale celle de notre quartz, sans utiliser de secondehorloge, qui aurait t ncessaire avec le timer1. Vous voyez quavec ce timer2, vous pouvezobtenir des temps configurables de faon trs prcise, et dans un grand ventail. Cest l lapuissance du timer 2.Mais bon, je ne vais pas vous laisser tomber ici, nous allons donc raliser rellement unprogramme qui permet une fois de plus de faire clignoter notre LED une frquence de 1 Hz.1 Hz, vous avez dit ? Alors ne tombons pas dans le pige, 1Hz cest 0.5 seconde allumeet 0.5 seconde teinte, donc nous devons compter non pas 1 seconde, mais 0.5 seconde.195Qu cela ne tienne, il nous suffit de passer 125 fois dans notre routine dinterruption aulieu de 250 fois. Simple, non ? Vous auriez besoin du dixime de seconde ? Et bien, comptezjusque 25.Effectuez une copie de votre fichier maquette, et nommez-la led_tmr2.asm .Commenons par crire len-tte et la directive config.;*****************************************************************************; Exercice d'utilisation du timer2 : ralisation d'une LED qui clignote *; une frquence exacte de 1Hz. *; *;*****************************************************************************; *; NOM: Led_Tmr2 *; Date: 21/05/2002 *; Version: 1.0 *; Circuit: platine d'exprimentation *; Auteur: Bigonoff *; *;*****************************************************************************; *; Fichier requis: P16F876.inc *; *;*****************************************************************************; *; Notes: La LED est connecte sur RB0 *; On utilise les interruptions timer2 *; 1 interruption toutes les 4 ms *; *;*****************************************************************************LIST p=16F876 ; Dfinition de processeur#include ; fichier include__CONFIG _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_OFF & _CPD_OFF & _LVP_OFF &_BODEN_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC;_CP_OFF Pas de protection;_DEBUG_OFF RB6 et RB7 en utilisation normale;_WRT_ENABLE_OFF Le programme ne peut pas crire dans la flash;_CPD_OFF Mmoire EEprom dprotge;_LVP_OFF RB3 en utilisation normale; _BODEN_OFF Reset tension hors service;_PWRTE_ON Dmarrage temporis;_WDT_OFF Watchdog hors service;_HS_OSC Oscillateur haute vitesse (4Mhz196; REGISTRE INTCON (contrle interruptions standard); -------------------------------------------------INTCONVAL EQUB'01000000' ; autorisation gnrale priphriques; REGISTRE PIE1 (contrle interruptions priphriques); ----------------------------------------------------PIE1VAL EQUB'00000010' ; interrupt TMR2Maintenant, les assignations du programme, soit la valeur utiliser pour le compteur depassages dans la routine dinterruption, et la valeur utiliser pour le registre PR2.;*****************************************************************************; ASSIGNATIONS PROGRAMME *;*****************************************************************************PRVAL EQU D'124' ; le tmr2 compte jusque (124+1) * 160 * 0,2s = 4msCOMPTVAL EQU D'125' ; pour 125 passages dans tmr2 = 125 * 4ms = 500msUn petit define pour la position de la LED sur RB0 :;*****************************************************************************; DEFINE *;*****************************************************************************#DEFINE LED PORTB,0 ; LED de sortieLa zone des variables se rduit sa plus simple expression : une seule variable estncessaire pour compter les passages dans la routine dinterruption. Aucune sauvegarde deregistre ncessaire, puisque notre programme principal nexcute rien.;*****************************************************************************; VARIABLES BANQUE 0 *;*****************************************************************************; Zone de 80 bytes; ----------------CBLOCK0x20 ; Dbut de la zone (0x20 0x6F)compteur : 1 ; compteur de passages dans tmr2 ENDC ; Fin de la zoneOn arrive sur ladresse de dmarrage aprs reset :;*****************************************************************************; DEMARRAGE SUR RESET *;*****************************************************************************org 0x000 ; Adresse de dpart aprs reset goto init ; InitialiserLa routine dinterruption na nul besoin des sauvegardes, ni de la gestion des interruptionsmultiples. Donc, elle ne comportera que la routine dinterruption timer2 en elle-mme.*****************************************************************************; ROUTINE INTERRUPTION TMR2 *;*****************************************************************************;-----------------------------------------------------------------------------; Un passage dans cette routine tous les 160*125*0,2s = 4ms.; Pas de programme principal, donc pas de sauvegarde effectuer; Dure d'allumage de la LED = dure d'un cycle * prdiviseur * postdiviser *; valeur de comparaison du timer * nombre de passages dans cette routine =197; 0,2s * 16 * 10 * 125 * 125 = 500.000 s = 500ms = 0.5s;-----------------------------------------------------------------------------org 0x004 ; adresse d'interruptiondecfsz compteur,f ; dcrmenter compteurgoto intend ; pas 0, fin interruptionmovlw COMPTVAL ; valeur de rechargemovwf compteur ; dans compteur de passagemovlw B'00000001' ; valeur pour inverser LEDxorwf PORTB,f ; inverser LEDintendbcf PIR1,TMR2IF ; effacer flag interupt tmr2retfie ; retour d'interruptionVous voyez que cette routine dcrmente le compteur de passages, et, lorsque ce dernieratteint 0, il inverse ltat de la LED.Nous trouvons ensuite la routine dinitialisation, qui commence par initialiser le PORTBet les registres dinterruption.;*****************************************************************************; INITIALISATIONS *;*****************************************************************************init; Initialiser portB; -----------------bsf STATUS,RP0 ; passer banque1bcf LED ; passer RB0 en sortie; Registre d'options (banque 1); -----------------------------movlw OPTIONVAL ; charger masquemovwf OPTION_REG ; initialiser registre option; registres interruptions (banque 1); ----------------------------------movlw INTCONVAL ; charger valeur registre interruptionmovwf INTCON ; initialiser interruptionsmovlw PIE1VAL ; Initialiser registremovwf PIE1 ; interruptions priphriques 1Il est temps maintenant dinitialiser notre timer 2, ce qui consiste placer les valeurs depr et de postdiviseur, et de le mettre en service, aprs avoir initialis le registre PR2 avec lavaleur de dbordement . Notez que jutilise dessin la notion de dbordement, car celle decomparaison induit en erreur, comme je vous lai dj expliqu.; initialiser Timer 2; -------------------movlw PRVAL ; valeur de "dbordement" de tmr2movwf PR2 ; dans PR2bcf STATUS,RP0 ; repasser banque 0movlw B'01001110' ; postdiviseur 10,prdiviseur 16,timer ONmovwf T2CON ; dans registre de contrleNe reste donc plus qu initialiser notre variable, puis autoriser les interruptions.198; initialiser variable; --------------------movlw COMPTVAL ; valeur de rechargemovwf compteur ; dans compteur de passage interruption; autoriser interruptions (banque 0); ----------------------------------bsf INTCON,GIE ; valider interruptionsQuant notre programme principal, il ne fait rien, et donc se contente de boucler sur lui-mme.;*****************************************************************************; PROGRAMME PRINCIPAL *;*****************************************************************************startgoto start ; bouclerEND ; directive fin de programmeVoici notre programme termin, lancez lassemblage, placez le fichier .hex dans votrePIC, et observez la LED. Elle clignote la frquence de 1Hz, avec la prcision du quartz.Voici donc une solution de base pour raliser une horloge ou dautres applications basessur la mesure du temps en secondes. Nul besoin de quartz spcial avec notre timer2.Si vous dcidez de simuler ce programme, vous pouvez, dans la fentre des registresspciaux, remarquer les registres t2pre et t2post (tout en bas) qui indiquent le contenudu pr et du post diviseur du timer. Ces registres ne sont pas accessibles par votre programme,ils sont simuls par MPLAB pour vous montrer le droulement de votre programme.Remarquez en mode pas pas que la valeur D124 dans TMR2 ne provoque ni lereset de TMR2, ni le positionnement du flag TMR2IF. Cest au moment ou TMR2 devraitpasser D125 que ces oprations seffectueront.19918. Rcapitulatif sur les timers18.1 Le choix du timerVous vous demandez peut-tre comment choisir votre timer dans une applicationparticulire. En fait, il sagit de rester logique. Prenons quelques cas concrets :18.1.1 Vous dsirez mesurer un temps compris entre 256 et 65536 cycles. Dans ce cas, tout dpend de la prcision demande, et de la valeur mesurer.Sil sagit dune valeur multiple de 256 (par exemple 512), vous pouvez utiliser le timer0, 1,ou 2 sans aucun problme et avec une prcision maximale.Si, par contre, vous devez mesurer des nombres de cycles non divisibles par despuissances de 2, et quune grande prcision est demande, vous avez 3 options :- Soit vous utilisez le timer2, en utilisant la technique prcdemment dcrite.- Soit vous utilisez le timer1, qui dispose de la possibilit de comptage jusque 65536 sansutiliser de prdiviseur- Soit vous utilisez le timer0, mais au prix dune perte de prcision ou dune programmationplus dlicate.18.1.2 Vous dsirez mesurer des temps allant jusque 524288Vous pouvez alors utiliser le timer 1, avec un prdiviseur. Naturellement, si la valeur atteindre nest pas un multiple exact du prdiviseur, votre prcision en sera altre.18.1.3 Vous dsirez mesurer des temps quelconques avec une grande prcisionDans ce cas, si on admet que le nombre de cycles mesurer nest pas un multiple exactdune valeur de diviseur, vous disposez de 2 mthodes principales et simples pour obtenir cesmesures de temps :- Soit vous utilisez le timer1 avec un second quartz calcul de faon obtenir des multiplesexacts. Ceci prsente lavantage de moins utiliser de temps de PIC, puisque la secondehorloge aura une frquence maximale de 200KHz, ce qui permet despacer lesinterruptions. Par contre, ceci ncessite de sacrifier 2 pins et dutiliser plus de matriel.- Soit vous utilisez le timer2, en calculant des valeurs multiples de pr et postdiviseur et enplaant le rsultat dans PR2. Une longue dure sera prise en compte en comptant lespassages dans la routine dinterruption. Cette mthode est plus simple et plus conomique,mais ncessite plus de temps dexcution, surtout pour les longues dures pour lesquellesdes interruptions seront sacrifies dans le seul but de les compter. Le temps doit bienentendu tre multiple de la dure dune instruction.20018.1.4 Vous dsirez compter des vnementsDans ce cas le timer2 est inutilisable, reste donc :- Soit le timer 0 qui permet de choisir entre dtection des flancs montants ou descendants,mais limite le comptage 256 (multipli par le prdiviseur)- Soit le timer 1 qui permet de compter jusque 65536 sans prdiviseur, mais qui impose dedtecter uniquement les flancs montants de votre signal.Je pourrais multiplier les exemples, mais le but tait simplement de vous montrer quechaque timer est plus ou moins bien adapt au but recherch. Dans la grande majorit desapplications, le choix du timer ncessitera une petite rflexion.Prenez garde que llectronique est lie au logiciel, les deux devront donc tre tudis enparallle. En effet, pour simple exemple, si vous avez besoin des caractristiques du timer1pour compter des vnements, vous serez alors dans lobligation de connecter le signal surT1CKI et non sur T0CKI. De plus, si vous dsiriez compter des flancs descendants, vousdevrez ajouter un montage qui inverse votre signal dentre.18.2 Les bases de temps multiplesIl vous arrivera probablement de devoir utiliser plusieurs bases de temps dans le mmeprogramme.La premire solution qui vient lesprit est dutiliser plusieurs timers. Ceci peut se rvlerla bonne solution, mais ce nest pas toujours ncessaire. En effet, si vos bases de tempsdisposent dun dnominateur commun, vous pouvez utiliser ce dnominateur comme base detemps gnrale, et compter les passages dans la routine dinterruption.Imaginons par exemple que vous ayez besoin de grer une impulsion sur une brochetoutes les 200ms, et que vous dsirez faire clignoter une LED une frquence de 1Hz. Vouspouvez alors dcider dutiliser un timer pour la LED, un autre pour les impulsions.Mais vous pouvez aussi vous dire : jai besoin dune dure de 500ms pour ma LED, etdune autre de 200ms pour les impulsions. Je dcide de crer une dure dinterruption de100ms.Ma routine dinterruption sera donc du type :- Je dcompte compteur 1- Compteur 1 = 0 ?- Non, je ne fais rien- Oui, je gre mon impulsion, et je recharge compteur 1 avec 2 (200ms)- Je dcrmente compteur 2- Compteur 2 = 0 ?- Non, fin dinterruption- Oui, je gre ma LED et je recharge compteur 2 avec 5 (500ms)- Fin dinterruption201Vous voyez donc quavec cette mthode, je gre 2 temps diffrents avec le mme timer.Dans la pratique, cest une mthode que vous utiliserez probablement souvent.18.3 Possibilits non encore abordesArriv ce stade, vous ne disposez pas encore de toutes les possibilits des performanceset des utilisations possibles des timers.Pour complter vos connaissances, et pour apprhender toutes les remarquablesdiversits dapplication, il vous reste encore tudier les modules CCPx abords dans unchapitre ultrieur.Vous verrez alors que vous pouvez disposer de fonctions supplmentaires, et mmevaincre ce que vous pensiez tre les limites des timers concerns.202Notes : 20319. Le convertisseur analogique/numrique19.1 PrambuleTout dabord, je vais vous demander de ne pas paniquer. En effet, je vais dtailler lefonctionnement du convertisseur analogique/numrique, afin de permettre de lexploiter dansses moindres ressources.Ce faisant, vous allez trouver ici des formules mathmatiques pour le moins barbares.Mais, rassurez-vous, dans limmense majorit des cas vous naurez pas besoin de cesformules. En effet, je vous donnerai les valeurs sres employer pour les viter, au prix dunelgre perte de performance au niveau du temps de conversion, perte qui na gnralement pasla moindre importance.Beaucoup de personnes me demandent comment effectuer une conversionanalogique/numrique, mais je maperois que peu savent ce que cette conversion reprsenterellement et quelle sont ses limites. Je crains donc quil ne faille commencer par un peu dethorie.De plus, cette approche prsente lavantage de vous permettre de vous sortir de toutes lessituations futures quil mest impossible de prvoir lheure actuelle, par exemple, sortiedune nouvelle version de 16F87x avec des caractristiques temporelles diffrentes de cellesdu PIC tudi ici.Bien entendu, si tout ceci ne vous intresse pas, ou que vous jugez que cela ne peut rienvous apporter, vous tes libres de tourner les pages votre convenance.19.2 Nombres numriques, analogiques et conversionsMais commenons donc par le commencement. Quest-ce quun ConvertisseurAnalogique/Digital (CAD), de prfrence nomm Convertisseur Analogique/Numrique(CAN), ou Analogic to Digital Converter (ADC) ?Bien quon utilise souvent la notion de convertisseur analogique/digital , la bonneexpression franaise serait plutt convertisseur analogique/numrique . Mais bon, je nesuis pas ici pour vous donner une leon de franais, jen suis du reste incapable.En fait, nous avons vu jusqu prsent que nous pouvions entrer un signal sur les pins duPIC, qui dterminait, en fonction du niveau de tension prsente, si ce signal tait considrcomme un 1 ou un 0 logique. Ceci est suffisant pour tout signal binaire, cest--dire neprsentant que 2 valeurs possibles.Supposons que vous dsiriez, avec votre PIC, mesurer une valeur analogique, cest--dire,en fait, connatre la valeur de la tension prsente sur une pin de votre PIC. Il est des tasdapplications o vous aurez besoin dune telle possibilit, par exemple si vous voulezmesurer la tension de votre batterie laide dun PIC.204Comme llectronique interne du PIC ne comprend que les valeurs binaires, il vous faudradonc transformer cette valeur analogique en une reprsentation numrique. Ce procdsappelle numrisation, et, pour leffectuer, vous avez besoin dun convertisseuranalogique/numrique.Il importe ce niveau de rappeler ce quest un signal analogique. Commenons parexaminer une tension, par exemple la tension de votre alimentation. Cette tension peutsexprimer par une infinit de valeur, et vous pouvez faire varier cette tension de faoncontinue, sans quil y ait un trou entre 2 valeurs.Un nombre numrique, au contraire, dispose dun nombre fini de valeurs, on parlera devaleurs discrtes . Par exemple, dans un octet, vous pouvez coder 0x01 ou 0x02, mais ilny a pas de valeur intermdiaire, au contraire de votre valeur analogique, pour laquelle vouspouvez toujours insrer une telle valeur.Le problme est donc en premier lieu de savoir comment passer mathmatiquement dunereprsentation lautre, donc comment convertir du numrique vers lanalogique etrciproquement.Vous effectuez couramment, et sans le savoir, des conversions analogiques/numriques.En effet, lorsque vous dcidez darrondir des valeurs, vous transformez une valeuranalogique (qui peut donc prendre une infinit de valeur) en une valeur numrique (quicontient un nombre fini dlments).En effet, prenons le nombre 128,135132. Si vous dcidez darrondir ce nombre enconservant 4 digits, vous direz que ce nombre numris devient 128,1. Vous voyez doncquen numrisant vous perdez de la prcision, puisque vous liminez de fait les valeursintermdiaires. Avec cet exemple, vous pouvez reprsenter les valeurs 128,1 et 128,2, maistoute autre valeur intermdiaire sera transforme en un de ces deux nombres discrets.La prcision obtenue dpend donc du nombre de digits que vous souhaitez conserver pourle rsultat, lequel sera entach dune erreur.Que vaut cette erreur (ne me dites pas 0,1) ? En fait, si vous rflchissez un peu, vousvoyez que 128,13 sera converti en 128,1, tandis que 128,16 sera converti en 128,2. Lerreurmaximal obtenue est donc de la moiti du plus faible digit. Comme notre digit vaut 0,1,lerreur finale maximale sera donc dans notre exemple de 0,05.Si vous convertissez maintenant dans lautre sens, vous pouvez dire que votre nombrenumris de 128,1 reprsente en ralit une grandeur analogique relle comprise entre 128,05et 128,15. La valeur moyenne tant de 128,1, ce qui est logique.La constatation est qu une seule valeur numrique correspond une infinit de valeursanalogiques dans un intervalle bien dfini.Supposons que nous voulions numriser une valeur analogique comprise entre 0 et 90 enune valeur numrique code sur 1 digit dcimal. Nous voyons tout de suite que la valeuranalogique 0 sera traduite en D0, la valeur analogique 10 sera traduite en D1, etc. jusque lavaleur 90 qui sera convertie en D9.205Si maintenant notre valeur analogique varie entre 10 et 100, la valeur analogique 10 seraconvertie en D0, la valeur analogique 20 sera convertie en D1, etc. jusque la valeuranalogique 100 qui sera convertie en D9.Donc, puisque nous ne disposons ici que dun digit, qui peut prendre 10 valeurs, de 0 9pour traduire une valeur qui peut varier dun minimum un maximum, on peut tirer despetites formules.On peut dire que chaque digit numrique reprsente la plage de valeurs de la grandeuranalogique divise par la plus grande valeur reprsente par notre nombre numris.Ceci, bien entendu, en partant du principe que nos nombres numriques commencent 0 . Dans le cas contraire, la plus grande valeur sera remplace par la diffrence entrela plus grande et la plus petite valeur possible .Donc, pour prendre notre premier exemple, 1 digit numris reprsente la valeurmaximale analogique moins la valeur minimale analogique divis par la valeur maximalenumrique. Donc : (90-00)/9 = 10.Vous voyez que 1 en numrique reprsente la valeur analogique 10. Notre grandeurnumrique mesure donc les dizaines. Le pas de notre conversion est de 10.Si nous prenons notre second exemple, nous aurons : (100-10)/9 = 10 galement. Jaichoisi ces exemples car ils taient simples.Si maintenant, nous dsirons effectuer lopration inverse, cest--dire savoir quellevaleur analogique correspond une valeur numrique, nous pourrons dire que :La valeur analogique typique est gale la valeur analogique minimale reprsente laquelle on ajoute le pas multipli par la valeur numrique correspondante.Cest trs simple comprendre. Supposons que nous ayons la valeur numrique 5. Quereprsente-t-elle comme grandeur analogique relle dans notre premier exemple ? Et bien,tout simplement 0 + (5*10) = 50. Ca semble logique, non ?Quand notre second exemple, cette mme valeur reprsente une grandeur analogiquede : 10 + (5*10) = 60. Cest tout aussi logique.Voici un graphique correspondant notre premier exemple, pour vous permettre dy voirclair. Noubliez pas que nous arrondissons (convertissons) toujours au niveau du demi digit.En rouge vous avez toutes les valeurs analogiques possibles de 0 90, tandis quen bleu, vousavez les seules 10 valeurs numriques correspondantes possibles.206Vous constatez que la courbe analogique peut prendre nimporte quelle valeur, tandis quela courbe numrique ne peut prendre quune des 10 valeurs qui lui sont permises.Par exemple, la valeur 16 existe sur la courbe analogique, mais la valeur 1,6 nexiste passur la courbe numrique. Chaque palier de cette courbe reprsente 1 digit (chelle bleue) et unpas de 10 sur lchelle rouge analogique.Nous voyons galement que pour certains valeurs analogiques (par exemple 15), nousavons 2 valeurs numriques possibles. La mme situation se retrouve dans la vie relle. Sivous donnez 10 euros un commerant pour payer un montant de 7,565 euros, libre lui deconsidrer que vous lui devez 7,57 plutt que 7,56 euros. Je pense quun juriste aura grandmal vous dpartager, et dailleurs je doute que vous portiez laffaire en justice.Nous venons de voir que nous avons effectu une conversion dune grandeur analogiqueen grandeur numrique et rciproquement pour une grandeur que nous avons suppose fixedans le temps.Mais que se passerait-il pour une grandeur qui varie, comme par exemple un signalaudio ?En fait, de nouveau, ce signal va varier dans le temps de faon continue. Le PIC, lui (outout autre convertisseur existant), va effectuer intervalles rguliers des mesures du signalpour le convertir en valeurs numriques successives. Donc, de nouveau, notre chelle detemps ne sera plus continue, mais constitue de bonds.Cest comme si, par exemple, vous preniez une srie de photos successives avec unappareil rapide. Lorsque vous visualisez lanimation, vous aurez une succession dimagesfixes qui restitueront lanimation.207Plus les photos sont rapproches dans le temps, plus vous vous rapprochez de la ralit, etmoins vous perdez dvnements. Vous passez progressivement de lappareil photo lacamra, mais cette dernire travaille galement sur le mme principe.Corollaire :Plus les vnements filmer sont rapides, et plus vos photos devront tre rapprochespour ne pas perdre des vnements.Cest exactement le mme principe pour la numrisation de signaux variables. En fait,vous ralisez une double numrisation. La premire consiste, comme nous lavons vu plushaut, dcouper la valeur en une succession de tranches, la seconde consiste dcouper letemps en une autre succession de tranches. Voici ce que a donne pour un signal quelconque.Vous voyez que vous perdez 2 fois en prcision. Dune part votre valeur est arrondie enfonction du nombre de digits utiliss pour la conversion, et dautre part, tous les vnementssurvenus entre 2 conversions (chantillonnages) sont perdus.Vous pouvez en dduire que :1) Plus vous dsirez de prcision, plus vous devez augmenter le nombre de digits utilisspour le rsultat2082) Plus votre signal volue rapidement, plus vous devez diminuer le temps sparant 2chantillonnages, autrement dit, augmenter votre vitesse dchantillonnage.Je vous passerai les thories de Fourrier et autres, pour simplement vous dire que pour unsignal sinusodal, on admet que la frquence dchantillonnage doit tre suprieure au doublede la frquence du signal mesurer.Pour vous donner un exemple, lorsquon convertit un signal audio pour en faire un signalnumrique destin tre plac sur un disque CD, les caractristiques de la conversion sont lessuivantes :1) Echantillonnage sur 16 bits, soit 65536 valeurs numriques diffrentes : on serapproche donc normment du signal analogique original.2) Frquence dchantillonnage de 44100 Hz, ce qui nous donne, suite au thormeprcdent, une frquence maximale sinusodale digitalise 22 KHz sil ny avait pas defiltrage qui rduit un peu cette frquence (loreille humaine parvient en gnral capter des frquences maximales de 16KHz, 20Khz pour certaines personnes).Anecdote en passant, ceci vous dmontre linutilit des enceintes qui sont annonces avecdes frquences maximales de plus de 50 KHz. Dune part, votre CD na pas enregistr detelles frquences, dautre part votre oreille est incapable de les interprter. Quand on voit unchiffre, il faut toujours se demander quelle est la ralit qui se cache derrire (autre quecommerciale).19.3 Principes de conversion sur les 16F87xJusqu prsent, nous venons de raisonner en dcimal. Les pics, eux travaillent en binaire.Mais, rassurez-vous, ceci reste strictement identique. Souvenez-vous que lorsquon change debase de numrotation, les formules restent toutes dapplication (cours-part1).Notre 16F87x travaille avec un convertisseur analogique / numrique qui permet unchantillonnage sur 10 bits. Le signal numrique peut donc prendre 1024 valeurs possibles.Vous avez vu que pour pouvoir convertir une grandeur, nous devons connatre la valeurminimale quelle peut prendre, ainsi que sa valeur maximale. Les pics considrent par dfautque la valeur minimale correspond leur Vss dalimentation, tandis que la valeur maximalecorrespond la tension positive dalimentation Vdd. Nous verrons cependant quil estpossible dutiliser dautres valeurs.Nous navons toujours pas parl des mthodes utilises pour convertir physiquement lagrandeur analogique en grandeur numrique au cur du PIC. Il est inutile dentrer ici dans uncours dlectronique applique, mais il est bon de connatre le principe utilis, car cela vavous aider comprendre la suite. La squence est la suivante :- Le pic connecte la pin sur laquelle se trouve la tension numriser un condensateurinterne, qui va se charger via une rsistance interne jusque la tension applique.209- La pin est dconnecte du condensateur, et ce dernier est connect sur le convertisseuranalogique/numrique interne.- Le pic procde la conversion.Plusieurs remarques et questions sont souleves par cette procdure. En tout premier lieu,le condensateur va mettre un certain temps se charger, il nous faut donc connatre ce temps.Ensuite, il nous faut comprendre comment fonctionne la conversion, pour valuer le tempsmis pour cette conversion.Ceci nous donnera le temps total ncessaire, afin de savoir quelle est la frquencemaximale dchantillonnage pour notre PIC.Remarquez que si le signal varie aprs le temps de charge du condensateur interne, cettevariation ne sera pas prise en compte, puisque la pin sera dconnecte du dit condensateur.19.4 Le temps dacquisitionCest le temps quil faut pour que le condensateur interne atteigne une tension proche dela tension convertir. Cette charge seffectue travers une rsistance interne et la rsistancede la source connecte la pin, les formules sont donc drives de celles que nous avonscalcules lors de la ralisation de notre circuit anti-rebond du chapitre sur le timer 1.Ce temps est incrment du temps de raction des circuits internes, et dun temps quidpend de la temprature (coefficient de temprature). Il faut savoir en effet que lesrsistances augmentent avec la temprature, donc les temps de raction des circuitsgalement.Donc, si on pose :Tacq = temps dacquisition totalTamp = temps de raction des circuitsTc = temps de charge du condensateurTcoff = temps qui dpend du coefficient de temprature.La formule est donc :Tacq = Tamp + Tc + TcoffLe temps de raction Tamp est typiquement de 2s, pas donc de problme ce niveau :Tamp = 2sPour le coefficient de temprature, il nest ncessaire que pour les tempraturessuprieures 25C. Dans les autres cas, il nentre pas en compte. Ce coefficient esttypiquement de 0,05 s par C qui est suprieur 25C. Il sagit bien entendu de la t du PIC,et non de la temprature ambiante.210Donc, ce temps Tcoff sera au minimum de 0 ( moins de 25C) et au maximum de (50-25)*0.05, soit 1,25 s. La t du pic ne pouvant pas, en effet, excder 50C.0 Tcoff 1,25sPremire constatation, si vous voulez bnficier dune frquence maximale, vous devezmaintenir le PIC sous 25C.Reste le temps de charge. Ce temps de charge dpend de la rsistance place en srie avecle condensateur. En fait, il y a 2 rsistances, celle de votre source de signal, et celle lintrieur du PIC.Il est recommand que la rsistance de votre source reste infrieure 10KOhms.Celle interne au PIC est directement lie la tension dalimentation. Plus la tensionbaisse, plus la rsistance est leve, donc plus le temps de chargement est long.Donc, de nouveau, pour obtenir de hautes vitesses, il vous faudra alimenter le PIC avec latension maximale supporte, soit 6V lheure actuelle pour le 16F876.La rsistance interne totale (compose de 2 rsistances internes) varie de 6Kohms 6Vpour arriver 12Kohms sous 3V, en passant par 8Kohms sous 5V.De plus, comme la charge du condensateur dpend galement de la rsistance de la sourcedu signal, pour augmenter votre vitesse, vous devez galement utiliser une source de signalprsentant la plus faible impdance (rsistance) possible.Sachant que le condensateur interne une valeur de 120pF pour les versions actuelles dePIC (16F876), les formules que je vous ai donnes pour le calcul du temps de chargementdun condensateur restant valables, la formule du temps de charge du condensateur est :Tc = -C * (Rinterne + Rsource) * ln (1/2047)Le 2047 provient de ce que pour numriser avec une prcision de bit, la numrisationutilisant une valeur maximale de 1023, la charge du condensateur doit tre au minimum de2046/2047me de la tension mesurer.Comme C est fixe et ln(1/2047) galement, je vais vous calculer la constante unefois pour toutes (nest-ce pas que je suis bon avec vous ?) :-C * ln(1/2047) = 0,914895 * 10-9La formule devient donc :Tc = 0,914895 * 10-9 * (Rinterne + Rsource)Si on se place dans le cas le plus dfavorable (tension de 3V, et rsistance source =10Kohms), notre temps de chargement est de =Tc = 0,914895 * 10-9 * (10 * 10 + 12 * 10)211Tc maximal = 20,12 sMaintenant le cas le plus favorable (tension de 6V, et rsistance source ngligeable) :Tc = 0,914895 * 10-9 * (0 * 10 + 6 * 10)Tc minimal : 5,48 s.Vrifiez dans le datasheet actuel les tensions maximales autorises pour les PICs. Cesdernires sont sujettes fraquentes modifications. A lheure actuelle, la tension maximaleautorise est de 7,5V. CONSULTEZ LES DATASHEETS LES PLUS RECENTS SILENTRE DANS VOS INTENTIONS DUTILISER CETTE TENSION MAXIMALE.Si, maintenant, nous prenons un cas typique, savoir une tension dalimentation de 5V etune rsistance de source de 10 Kohms, nous aurons :Tc = 0,914895 * 10-9 * (10 * 10 + 8 * 10)Tc typique = 16,46 s.Nous allons maintenant calculez les temps minimum, maximum, et typique du temps totaldacquisition Tacq.Le cas le plus dfavorable est : une temprature de 50C et un Tc maximal, ce qui nousdonne :Tacq = Tamp + Tac + TcoffTacq maximum = 2s + 20,12s + 1,25s = 23,37 sLe cas le plus favorable, une temprature infrieure ou gale 25C et un Tc minimal,nous donne :Tacq minimum = 2s + 5,48s = 7,48 s.Maintenant, pour nos utilisations classiques, sous 5V, nous aurons dans le pire des cas :Tacq sous 5V = 2s + 16,46s + 1,25s = 19,71s.Donc, nous prendrons un Tacq de 20s pour notre PIC alimente sous 5V. Mais vousdevez vous souvenir que si vous travaillez sous une tension diffrente, il vous faudra adapterces valeurs.De mme, si vous avez besoin de la plus grande vitesse possible dans votre cas particulier,vous possdez maintenant la mthode vous permettant de calculer votre propre Tacq. Pour mapart, dans la suite de ce cours, je travaillerai avec la valeur standard de 20 s.Remarquez que ces valeurs sont donnes telles quelles dans les datasheets. Je vous aidmontr mathmatiquement do provenaient ces valeurs. Ceci vous permettra de connatreles temps ncessaires pour votre application particulire, et ainsi, vous autorisera la plusgrande vitesse possible.21219.5 La conversionArriv ce stade, aprs le temps Tacq, on peut considrer que le condensateur est charget prt tre connect sur lentre du convertisseur analogique/digital. Cette connexion prendde lordre de 100ns.Une fois le condensateur connect, et donc, la tension numriser prsente sur lentre duconvertisseur, ce dernier va devoir procder la conversion. Je ne vais pas entrer ici dans lesdtails lectroniques de cette conversion, mais sachez que le principe utilis est celui delapproximation successive.Cest une mthode de type dichotomique, cest un bien grand mot pour exprimer unemthode somme toutes assez intuitive. Il sagit tout simplement de couper lintervalle danslequel se trouve la grandeur analogique en 2 parties gales, et de dterminer dans laquelle deces 2 parties se situe la valeur numriser. Une fois cet intervalle dtermin, on le coupe denouveau en 2, et ainsi de suite jusqu obtenir la prcision demande.Prenons un exemple pratique : vous avez un livre de 15 pages, vous en choisissez une auhasard, supposons la numro13. Voici comment vous allez procder pour trouver de quellepage il sagit.- On coupe lintervalle en 2, arrondi lunit suprieure, soit 8.- Le numro de page est-il suprieur, infrieur ou gal 8 ?- Le numro est suprieur, donc dans lintervalle 8-15- On coupe cet intervalle en 2, soit 12- Le numro est-il suprieur, infrieur, ou gal 8 ?- Le numro est suprieur, donc dans lintervalle 12-15- On coupe lintervalle en 2, soit 14- Le numro est-il suprieur, infrieur, ou gal 14 ?- Le numro est infrieur, donc dans lintervalle 12-14- Le numro est donc 13, puisquil ntait gal ni 14, ni 12Cette mthode peut paratre curieuse, mais elle est dune grande efficacit en terme detemps. Chaque question se traduisant par une opration effectuer au niveau lectronique, onpeut dire que moins de question il y a, moins de temps lopration de conversion prendra. Sivous choisissez une page au hasard parmi un livre norme de 65535 pages, vous verrez quevous pouvez trouver le bon numro de page en moins de 16 questions.Appliqu la numrotation binaire, cette mthode est de plus particulirement bienadapte, puisque couper un intervalle en 2 revient dire quon force simplement un bit 1.Reprenons notre exemple prcdent, mais en raisonnant en binaire.Notre nombre de pages maximum est de B1111, soit D15, la page choisie est B1101,soit D13. Effectuons notre conversion.- On coupe lintervalle en 2, soit B1000.- Le numro de page est-il infrieur ?- Non, donc compris entre B1000 et B1111- On coupe lintervalle en 2, soit B1100213- Le numro de page est-il infrieur?- Non, donc compris entre B1100 et B1111- On coupe lintervalle en 2, soit B1110- Le numro de page est-il infrieur?- Oui, donc compris entre B1100 et B1101- On coupe lintervalle en 2, soit B1101- Le numro de page est infrieur ?- Non, donc le numro de page est B1101Vous voyez quen fait vous avez une question (approximation) par bit du rsultat.Autrement dit, en raisonnant en terme de bits :- On place le bit 3 1, donc B1000- Le rsultat est-il infrieur?- Non, alors le bit 3 vaut effectivement 1 - On place le bit 2 1, donc B1100- Le rsultat est infrieur?- Non, alors le bit 2 vaut effectivement 1 - On place le bit 1 1, donc B1110- Le rsultat est-il infrieur ?- Oui, alors le bit 1 ne valait pas 1 , mais 0 - On place le bit 0 1, donc B1101- Le rsultat est infrieur ?- Non, alors le bit 0 valait bien 1 , le rsultat est donc B1101Pour rsumer, le temps ncessaire la conversion est gal au temps ncessaire laconversion dun bit multipli par le nombre de bits dsirs pour le rsultat.Concernant notre PIC, il faut savoir quil ncessite, pour la conversion dun bit, un tempsquon va nommer Tad. Ce temps est driv par division de lhorloge principale. Le diviseurpeut prendre une valeur de 2, 8 ou 32.Attention, on divise ici lhorloge principale, et non le compteur dinstructions. Donc, unedivision par 2 signifie un temps 2 fois plus court que celui ncessaire pour excuter uneinstruction, puisque ce temps dexcution est de Tosc/4.Il est galement possible dutiliser une horloge constitue dun oscillateur interne de typeRC. Cet oscillateur donne un temps de conversion compris entre 2 et 6s, avec une valeurtypique de 4s. Pour les versions LC du 16F876, ce temps passe entre 3 et 9s. Si la frquence du PIC est suprieure 1Mhz, vous ne pourrez cependant lutiliser quencas de mise en sommeil du PIC dans lattente du temps de conversion.En effet, durant le mode sleep , lhorloge principale est stoppe, donc seul cetoscillateur permettra de poursuivre la conversion. Cependant, je le rappelle encore une fois,pour votre PIC tournant plus de 1Mhz, vous tes contraints en utilisant cette horloge deplacer votre PIC en mode sleep jusque la fin de la conversion. Dans le cas contraire, le rsultatserait erron. Je vous conseille donc de nutiliser cette mthode que si vous dsirez placervotre PIC en mode sleep durant la conversion, ou si vous utilisez une frquence de PIC trsbasse, et de toute faon sous les 1MHz.214Le temps de conversion Tad ne peut descendre, pour des raisons lectroniques, en dessousde 1,6s pour les versions classiques de 16F87x, et en dessous de 6s pour les versions LC.Donc, en fonction des frquences utilises pour le quartz du PIC, il vous faudra choisir lediviseur le plus appropri. Voici un tableau qui reprend les valeurs de diviseur utiliser pourquelques frquences courantes du quartz et pour les PICs de type classique. La formuledobtention des temps Tad est simple, puisquil sagit tout simplement, comme expliqu ci-dessus, du temps dinstruction (Tosc) divis par le diviseur donn. Exemple, 20Mz, le tempsdinstruction est de 1/20.000.000, soit 50ns. Donc, avec un diviseur de 2, on aura 100ns.Diviseur 20Mhz 5Mhz 4Mhz 2Mhz 1,25Mhz 333,3Khz2 100ns 400ns 500ns 1s 1,6s 6s8 400ns 1,6s 2s 4s 6,4s 24s32 1,6s 6,4s 8s 16s 25,6s 96sOsc RC 2-6s 2-6s 2-6s 2-6s 2-6s 2-6sLes valeurs en vert sont celles qui correspondent au meilleur diviseur en fonction de lafrquence choisie. Les valeurs en bleu sont inutilisables, car le temps Tad serait infrieur 1,6s. Quand aux valeurs en jaune, je rappelle que pour lutilisation de loscillateur interneRC ces frquences, la mise en sommeil du PIC est impratif durant le temps de conversion.Vous remarquez que, du ces diviseurs, il est possible, par exemple de numriser plusvite avec un PIC tournant 1,25 Mhz quavec le mme PIC muni dun quartz 4 Mhz.Il faut prsent prciser que le PIC ncessite un temps Tad avant le dmarrage effectif dela conversion, et un temps supplmentaire Tad la fin de la conversion. Donc, le temps totalde conversion est de :- Tad : avant le dbut de conversion (le temps de connexion du condensateur est inclus)- 10 * Tad pour la conversion des 10 bits du rsultat- Tad supplmentaire pour la fin de la conversion de b0Soit, au total, un temps de 12 Tad, soit dans le meilleur des cas, un temps de 12 * 1,6s =19,2 s.Notez quun temps quivalent 2 * Tad est ncessaire avant de pouvoir effectuer unenouvelle conversion.Rsumons donc le temps ncessaire pour effectuer lensemble des oprations :- On charge le condensateur interne (ncessite le temps Tacq)- On effectue la conversion (ncessite le temps 12 * Tad)- On doit attendre 2 * Tad avant de pouvoir recommencer une autre conversion215Nous voici donc arriv la question principale. A quelle frquence maximale pouvons-nous chantillonner notre signal ?En fait, nous avons vu que cela dpendait des conditions, puisque Tacq dpend de latension dalimentation et dautres paramtres. Calculons le cas le plus dfavorable sur unetension dalimentation de 5V avec un PIC tournant une vitesse permettant un Tad de 1,6 s(attention, je ne travaille que sur les PICs 16F87x standards, pour les modles diffrents, jevous ai donn toutes les mthodes de calcul) :T entre 2 chantillonnages = Tacq + 12 Tad + 2 Tad = Tacq + 14 Tad, donc : T = 19,71s + 14 * 1,6s = 42,11 s.Ceci correspond donc une frquence de :F = 1/T = 1 / 42,11 * 10-6 = 23747 Hz.Cette frquence vous permet donc dchantillonner des signaux sinusodaux dunefrquence maximale de 11874 Hz (la moiti de la frquence dchantillonnage).Si vous vous placez dans le meilleur des cas, vous ramenez Tacq 7,5s, ce qui vousdonne :T = 7,5s + 14 * 1,6s = 29,9s, soit une frquence de F = 33445 Hz.Soit la possibilit de numriser des signaux sinusodaux dune frquence maximale de16722 Hz (si ce ntait la rsolution sur 10 bits au lieu de 16, on serait dans le domaine de lahi-fi.19.6 Compromis vitesse/prcisionNous avons vu que la conversion seffectue sur 10 bits, avec une frquence maximalepossible de 33445 Hz. Si vous avez besoin dune vitesse plus grande, il est possible dutiliserquelques trucs.La premire chose savoir, cest que laugmentation de vitesse au del ce ces limites nepeut se faire quau dtriment de la prcision en terme de nombre de bits significatifs dursultat. Cette augmentation se paye galement par une plus grande difficult au niveau de laprogrammation.Voici le raisonnement employ. Si on accepte de limiter la prcision un nombre infrieur 10 bits, et en constatant que la numrisation seffectue en commenant par les bits les plussignificatifs, on peut se dire : N bits me suffisent, donc en regardant notre figure prcdente,on dcide de stopper la conversion aprs que les bits en question aient t numriss.Donc, on se dit que pour conserver N bits significatifs, on aurait :216- Tacq pour charger le condensateur- Tad pour le dmarrage- N * Tad pour la conversionSoit, pour une conversion en conservant 4 bits au lieu de 12, cela ramnerait notre tempstotal Tacq + Tad + 4 Tad, soit Tacq + 5 Tad. Nous conomisons donc 7 Tad.Malheureusement, larrt de la numrisation nest pas possible, car le rsultat ne serait pasenregistr dans les registres concerns. Il faut donc amliorer cette astuce. En fait, on ne peutarrter la numrisation, mais on peut changer la valeur du diviseur en cours de digitalisation.Les bits numriss aprs la diminution du diviseur ne seront pas valides, mais ce nest pasimportant, puisque nous avons dcid de ne pas les utiliser.Supposons donc que nous travaillions avec un PIC 20MHz. Nous utilisons donc lediviseur par 32. Chaque Tad vaut donc 32 Tosc.Notre temps de conversion effectif prend donc normalement 12 Tad, soit 12 * 32 Tosc,soit 19,2s. Si nous avons besoin de 4 bits valides, nous pouvons donc dcider de raliser lesoprations suivantes :- Tacq pour charger le condensateur- Tad pour le dmarrage = 32 Tosc- N * Tad pour la conversion = N * 32 Tosc- Modification du diviseur pour passer 2- (11 N) Tad restants pour le reste de la conversion (qui sera errone), donc(11-N) * 2ToscDonc, nous pargnons en ralit (11-N) * (32-2)Tosc, soit pour notre numrisation sur 4bits :(11-4) * 30 Tosc = 210 Tosc, soit 210 * 50ns = 10,5s.La formule gnrale du temps de conversion pour numriser sur N bits est donc :Temps de conversion sur N bits = Tad + N * Tad + (11-N) (2Tosc)Autrement dit :Temps de conversion = (N+1) Tad + (11-N) (2Tosc).Ce qui nous donnera, pour notre conversion sur 4 bits pour un PIC 20Mhz:Temps de conversion = (4+1) * 1,6s + (11-4) * 100ns = 8s + 0,7s = 8,7s.Donc le temps total de numrisation sera :Temps numrisation = Tacq + Temps de conversion = 7,48s + 8,7s = 16,18s.217A ceci nous ajoutons 2Tad, soit 200ns, ce qui nous donne un temps sparant 2chantillonnages de 16,38sCeci nous donnera une frquence dchantillonnage de :Frquence dchantillonnage = 1/16,38s = 61050 Hz. avec 16 valeurs diffrentes possibles.La seconde astuce utilisable, est de constater que si on ne dsire pas utiliser tous les bits, ilest galement inutile de charger le condensateur au maximum. On peut donc reprendre lescalculs de charge du condensateur, afin de diminuer galement Tacq, ce qui permet encoredaugmenter lgrement la frquence dchantillonnage.Remarquez que lutilisation de ces techniques vous donnera toujours un rsultat sur 10bits, mais dont seuls les N premiers reprsenteront encore une valeur utilisable. Les autres bitsdevront donc tre ignors.Bien entendu, il vous incombera de dterminer le temps qui spare le dbut du processusde conversion de celui de modification du diviseur. Cette modification interviendralogiquement un temps Tad (N+1) aprs lancement de la conversion. Tad tant un multipleexact (gnralement 32) de loscillateur principal, une simple petite boucle, ou lutilisationdun timer pourra faire laffaire.Par exemple, pour digitaliser sur 6 bits avec un PIC 20MHz :- Vous lancez lacquisition- Aprs le temps Tacq, vous lancez la conversion- Aprs le temps (6+1) * Tad vous modifiez le diviseur- Vous attendez la fin de la conversionLe temps dattente (6+1) Tad vaut 7 * Tad, donc, 7 * 32 Tosc. Sachant que le tempsdexcution dune instruction est de Tosc/4, le temps dattente sera de 7 * 32 / 4 = 56 cyclesdinstruction.19.7 Les valeurs reprsentesNous avons vu toutes les formules concernant les temps de numrisation. Ne restent plusque les formules qui nous donnent les relations entre valeurs analogiques et reprsentationsnumriques.Nous en avons dj parl au moment de lvocation des techniques darrondissement. Sinous dfinissons :VREF- : Tension minimale analogique (rfrence ngative)VREF+ : Tension maximale analogique (rfrence positive)VIN : Tension dentre numriserVal : valeur numrique obtenue sur 10 bitsNous pouvons dire que pour une numrisation sur 10 bits, on obtiendra la valeurnumrique :218Val = ((VIN - VREF-) / (VREF+ - VREF-)) * 1023)Et rciproquement, la valeur typique qui a t numrise correspond une tension de : VIN = ((Val/1023) * (VREF+ - VREF-)) + VREF- Si nous utilisons une tension de rfrence ngative de 0V, cest--dire que la rfrence detension ngative est en ralit Vss, nous obtenons 2 formules simplifies :Val = (VIN / VREF+ ) * 1023)VIN = (Val/1023) * VREF+En donnant un exemple concret, si nous dcidons que la tension de rfrence positive estde 5V, et que la tension de rfrence ngative est de 0V, nous avons :Val = (VIN / 5) * 1023)VIN = (Val/1023) * 5Dernire remarque : La tension dentre ne peut tre suprieure la tension dalimentationVdd du PIC, ni infrieure sa tension Vss.Si vous voulez mesurer une tension suprieure, par exemple une tension de 15Vmaximum, il vous faudra raliser un diviseur de tension partir de 2 rsistances pour que latension applique reste dans les limites prvues. Les formules sont tires de la loi dohm, etont dj t utiliss dans le calcul du circuit anti-rebond dont nous nous sommes servis dans lecadre du circuit de comptage de notre timer1.19.8 Conclusions pour la partie thoriquePour rsumer, vous disposez des prescriptions suivantes pour utiliser en pratique leconvertisseur A/D avec un PIC standard :- Si une frquence dchantillonnage de lordre de 23KHz vous suffit, vous utilisez untemps Tacq de 20s et vous digitalisez sur 10 bits. Aucun besoin de calculs.- Si vous avez besoin dune frquence comprise entre 23 et 33Khz avec une rsolution de10 bits, vous pouvez optimiser votre montage en rduisant limpdance de la source (parexemple en utilisant un amplificateur oprationnel), et en utilisant la tension maximalesupporte par le PIC.- Si vous avez besoin dune frquence suprieure, vous devrez rduire le nombre de bits denumrisation, comme expliqu plus haut.- Si aucune de ces solutions ne vous convient, vous devrez renoncer numriser avec votrePIC, et utiliser un convertisseur externe.Pour plus de facilit, je vous rassemble ici toutes les formules :219Val numrise = ((VIN - VREF-) / (VREF+ - VREF-)) * 1023)VIN analogique = ((Val/1023) * (VREF+ - VREF-)) + VREF- Temps de conversion sur N bits = Tad + N * Tad + (11-N) (2Tosc)Tad = Tosc * diviseur 1,6 sTemps de conversion sur 10 bits = 12 TadTacq = 2s + Tc = 0,914895 * 10-9 * (Rinterne + Rsource) + 0,05(T - 25C) avec T 25CEt galement, les valeurs que vous pouvez utiliser dans la majorit des cas :Tacq courant : 19,7sTemps de conversion courant : 19,2s.Temps entre 2 numrisation successives : 3,2s19.9 La thorie applique aux PICs : pins et canaux utilissMaintenant vous savez ce quest une conversion analogique/numrique, et commentcalculer les diffrentes valeurs utiles, moins que vous nayez saut les paragraphesprcdents.Reste savoir comment connecter notre ou nos signal (signaux) analogique(s) sur notrePIC.La premire chose comprendre, cest que notre PIC ne contient quun seul convertisseur,mais plusieurs pins sur lesquelles connecter nos signaux analogiques. Un circuit decommutation slectionnera donc laquelle des pins sera relie au condensateur de maintieninterne durant le temps Tacq. Ces diffrentes entres seront donc des canaux diffrents dunseul et mme convertisseur.Corollaire : si vous avez plusieurs canaux chantillonner, vous devrez les chantillonner tour de rle, et donc le temps total ncessaire sera la somme des temps de chaqueconversion. Donc, plus vous avez de signaux chantillonner, moins la frquencedchantillonnage pour chaque canal pourra tre leve.Le 16F876 dispose de 5 canaux dentre analogique. Vous pouvez donc chantillonnersuccessivement jusque 5 signaux diffrents avec ce composant. Les pins utilises sont les pinsAN0 AN4 (qui sont en fait les dnominations analogiques des pins RA0 RA3 + RA5).Le 16F877, quant lui, dispose de 8 canaux dentre analogique. Vous pourrez doncchantillonner jusque 8 signaux diffrents sur les pins AN0 AN7. Les pins AN0 AN4 sontles dnominations analogiques des pins RA0 RA3 + RA5, tandis que les pins AN5 AN7sont les dnominations analogiques des pins RE0 RE2.22019.10 Les tensions de rfrenceNous avons vu dans ltude thorique gnrale de la conversion analogique/digitale, quecette conversion ncessitait une tension de rfrence minimale (Vref-) et une tension derfrence maximale (Vref+).Au niveau de notre PIC, nous avons 3 modes de fonctionnement possibles :- Utilisation de Vss (masse du PIC) comme tension Vref- et de Vdd (alimentation positivedu PIC) comme tension Vref+. Dans ce mode, les tensions de rfrences sont tires eninterne de la tension dalimentation. Il ny a donc pas besoin de les fournir.- Utilisation de la pin Vref+ pour fixer la tension de rfrence maximale Vref+, etutilisation de Vss comme tension de rfrence Vref-. Dans ce cas, la tension Vref+ doitdonc tre fournie au PIC via la pin RA3.- Utilisation de la pin Vref+ pour fixer la tension de rfrence maximale Vref+, etutilisation de la pin Vref- pour fixer la tension de rfrence minimale Vref-. Dans ce cas,les 2 tensions de rfrences devront tre fournies au PIC via RA3 et RA2.Notez que la broche Vref+ est une dnomination alternative de la broche RA3/AN3,tandis que la broche Vref- est une dnomination alternative de la broche RA2/AN2.Donc, lutilisation dune pins comme entre analogique interdit son utilisation commeentre numrique (pin entre/sortie normale ). De mme, lutilisation des rfrences Vref+et Vref- interdit leur utilisation comme pin entre/sortie ou comme pin dentre analogique.Notez galement que les pins ANx sont des pins dentre. Il nest donc pas questiondesprer leur faire sortir une tension analogique. Ceci ncessiterait un convertisseurnumrique/analogique dont nest pas pourvu notre PIC.Nous pouvons maintenant dessiner le schma symbolique des entres de notreconvertisseur analogique/numrique. Ce schma correspond un 16F877, pour le 16F876, lescanaux AN5 AN7 nexistent bien entendu pas.221On voit trs bien sur ce schma que les pins AN2 et AN3 servent selon la position duslecteur dentre analogique ou de tension de rfrence. Le slecteur de canal permet deslectionner lequel des 8 canaux va tre appliqu au convertisseur analogique/digital.Remarquez que la slection de la source des tensions de rfrence dpend de bits duregistre ADCON1, tandis que le canal slectionn pour tre numris dpend de ADCON0.Nous allons en parler.Le convertisseur en lui-mme, en toute bonne logique, na besoin que de la tensiondentre (la pin ANx slectionne), et des 2 tensions de rfrence. Il sort un nombrenumrique de 10 bits, dont nous verrons la destination.Donc, notre procdure de numrisation, pour le cas o on utilise plusieurs canaux, devientla suivante (aprs paramtrage) :222- On choisit le canal numriser, et on met en route le convertisseur- On attend Tacq- On lance la numrisation- On attend la fin de la numrisation- On attend 2 Tad- On recommence avec le canal suivant.Je vais prsent vous donner un exemple de schma mettant en uvre ces tensions derfrence.Imaginons que vous vouliez chantillonner une tension qui varie de 2V 4V enconservant une prcision maximale. Vous avez 2 solutions :La premire qui vient lesprit est dutiliser une entre analogique sans tension derfrence externe, comme pour lexercice prcdent.Dans ce cas votre valeur numrique ne pourra varier, en appliquant la formule Val = (VIN /VREF+ ) * 1023) , que de :(2/5) * 1023 = 409 pour une tension de 2V (4/5) * 1023 = 818 pour une tension de 4V.Votre prcision sera donc de 409 pas sur les 1023 possibles, les autres valeurs tantinutiliss. Vous avez donc une perte de prcision. Pour faire une quivalence avec le mondede la photo, vous ralisez ici un zoom numrique sur la plage 2/4V.Par contre, si vous utilisez une tension de rfrence de 2V comme Vref- et une de 4Vcomme Vref+, vous aurez une valeur numrique de 0 pour la tension 2V, et une valeur de1023 pour la tension de 4V. Vous conservez donc un maximum de prcision, puisque votreintervalle de mesure correspond 1024 paliers.Dans notre analogie avec les appareils photographiques, nous avons ralis par cettemthode, un zoom optique sur la plage de tension 2/4V. Comme avec le zoom optique, lereste du clich (le reste des tensions) nest pas captur par le PIC, mais, en contrepartie, laprcision reste maximale dans la zone cadre.Voici le schma que vous devrez utiliser, aprs avoir paramtr ADCON1 enconsquence :223Les rsistances seront calcules en fonction des diodes zener et de la loi dohm : larsistance est gale la tension au borne de la rsistance (5V tension de la zener) divise parle courant qui doit traverser la zener (gnralement quelques mA.).Vous constatez que ceci vous permet davoir des tensions de rfrence qui ne varient pasen fonction de la tension dalimentation. Il peut donc tre pratique, si votre alimentation nestpas stable, dutiliser des tensions de rfrences fortement stabilises.Ceci est un schma thorique. Mais la bonne pratique lectronique recommande de :- Placer un condensateur en parallle avec chaque diode zener, ceci afin dliminer le bruit des jonctions de ces diodes (pour ce montage particulier)- Placer une rsistance et un condensateur sur la pin MCLR (pour tous vos montages rels)- Placer un condensateur de dcouplage sur chaque pin dalimentation Vdd (pour tous vosmontages rels).Bien entendu, ces accessoires ne sont absolument pas ncessaires pour vos platinesdexprimentation. Ils sont ncessaires pour une utilisation sur un circuit imprim comportantdautres circuits perturbateurs ou pouvant tre perturbs, et dans un circuit dapplication rel,pour lesquels un plantage est toujours gnant.224Je vous donne, titre dinformation, le circuit prcdent modifi pour une applicationrelle :Notez que si vous dsirez mesurer, par exemple, la position dun potentiomtre, lerreursannulera delle-mme si vous nutilisez pas les tensions de rfrence externes. En effet, si latension dalimentation varie, la rfrence interne +Vdd variera galement. Comme lepotentiomtre pourra tre aliment par la mme tension dalimentation, la tension quilfournira variera dans les mmes proportions, donc lerreur sannulera.Il nest donc pas toujours prfrable dimposer une tension de rfrence distincte de votrealimentation. Tout dpend de lapplication.Nous allons poursuivre ltude de notre convertisseur par ltude des registres dont nousvenons de dvoiler le nom. Mais, auparavant :19.11 Mesure dune tension alternativeNous avons vu que notre tension pouvait varier entre Vss et Vdd. Nous ne pouvons doncpas chantillonner directement une tension alternative, comme un signal audio, par exemple.Celui-ci est en effet de la forme :225Nous allons donc devoir nous arranger pour que la tension reste en permanence positive.Ceci seffectue en forant la tension dentre vide une tension Vdd/2, et en amenant latension alternative via un condensateur, de faon effectuer une addition des 2 tensions.Regardez le schma suivant : 226Ceci ramnera la tension mesurer vue par le PIC :Vous voyez que maintenant, lintgralit de la tension mesurer est positive et peut donctre mesure. A vous dinterprter que la valeur centrale correspond une tension alternativedentre de 0, et quune tension de Vdd ou de 0V correspond un maximum de tension.Reste calculer la valeur du condensateur. Cest assez simple. Vous considrez que larsistance dentre vaut approximativement la moiti de la valeur des rsistances utilises (jevous passe la thorie), soit dans ce cas 5 Kohms.Pour que le condensateur ninfluence pas sur la mesure, son impdance doit trengligeable vis--vis de la rsistance dentre. Le terme ngligeable dpend bien entendude la prcision de la conversion souhaite.La valeur de limpdance diminue avec laugmentation de frquence suivant la formule :Zc = 1 / (2 * * f * C), doncC = 1 / (2 * * f * Zc)Avec :Zc = impdance = 3,1415f = frquence en HzC = capacit en faradsDonc, on se place dans le cas le plus dfavorable, cest--dire la frquence la plus basse.Prenons un cas concret :On doit numriser une frquence audio, de 50 Hz 10 Khz.On dcide que Zc doit tre 10 fois plus petite que 5 KohmsOn aura donc un condensateur au moins gal :227C = 1 / (2 * * 50Hz * 500Ohms) = 6,37 F * 10-6 = 6,37 F.Notez que dans ce cas, limpdance de la source de votre signal devra galement tre pluspetite que 5Kohms, sous peine dune forte attnuation.19.12 Les registres ADRESL et ADRESHJattire votre attention sur le fait que le convertisseur donne un rsultat sur 10 bits, et doncque ce rsultat devra donc obligatoirement tre sauvegard dans 2 registres. Ces registres sonttout simplement les registres ADRESL et ADRESH.Comme 2 registres contiennent 16 bits, et que nous nen utilisons que 10, Microchip vousa laiss le choix sur la faon dont est sauvegard le rsultat. Vous pouvez soit justifier lersultat gauche, soit droite.La justification droite complte la partie gauche du rsultat par des 0 . Le rsultat seradonc de la forme :ADRESH ADRESL0 0 0 0 0 0 b9 b8 b7 b6 b5 b4 b3 b2 b1 b0La justification gauche procde bien videmment de la mthode inverse :ADRESH ADRESLb9 b8 b7 b6 b5 b4 b3 b2 b1 b0 0 0 0 0 0 0La justification droite sera principalement utilise lorsque vous avez besoin delintgralit des 10 bits de rsultat, tandis que la justification gauche est trs pratique lorsque8 bits vous suffisent. Dans ce cas, les 2 bits de poids faibles se trouvent isols dans ADRESL,il suffit donc de ne pas en tenir compte. Cette approche est destine vous pargner desdcalages de rsultats. Merci qui ? Merci Microchip.Le choix de la mthode seffectue laide du bit 7 de ADCON1, registre dont je vaismaintenant vous parler.ATTENTION : Le registre ADRESH se situe en banque 0, alors que ADRESL se trouveen banque 1.19.13 Le registre ADCON1Je vais parler maintenant, pour des raisons de commodit, de ce registre. Il permet dedterminer le rle de chacune des pins AN0 AN7. Il permet donc de choisir si une pin serautilise comme entre analogique, comme entre/sortie standard, ou comme tension derfrence. Il permet galement de dcider de la justification du rsultat.228 Notez dj que pour pouvoir utiliser une pin en mode analogique, il faudra que cette pinsoit configure galement en entre par TRISA et ventuellement par TRISE pour le 16F877.Le registre ADCON1 dispose, comme tout registre accessible de notre PIC, de 8 bits, dontseulement 5 sont utiliss :ADCON1- b7 : ADFM : A/D result ForMat select- b6 : Inutilis : lu comme 0 - b5 : Inutilis : lu comme 0 - b4 : Inutilis : lu comme 0 - b3 : PCFG3 : Port ConFiGuration control bit 3- b2 : PCFG2 : Port ConFiGuration control bit 2- b1 : PCFG1 : Port ConFiGuration control bit 1- b0 : PCFG0 : Port ConFiGuration control bit 0Le bit ADFM permet de dterminer si le rsultat de la conversion sera justifi droite (1)ou gauche (0).Nous trouvons dans ce registre les 4 bits de configuration des pins lies au convertisseuranalogique/numrique. Ces bits nous permettent donc de dterminer le rle de chaque pin.Comme nous avons 16 combinaisons possibles, nous aurons autant de possibilits deconfiguration (en fait, vous verrez que nous nen avons que 15).Je vous donne le tableau correspondant ces combinaisons pour le 16F877:PCFG3 0AN7RE2AN6RE1AN5RE0AN4RA5AN3RA3AN2RA2AN1RA1AN0RA0Vref- Vref+A/D/R0000 A A A A A A A A Vss Vdd 8/0/00001 A A A A Vref+ A A A Vss RA3 7/0/10010 D D D A A A A A Vss Vdd 5/3/00011 D D D A Vref+ A A A Vss RA3 4/3/10100 D D D D A D A A Vss Vdd 3/5/00101 D D D D Vref+ D A A Vss RA3 2/5/10110 D D D D D D D D - - 0/8/00111 D D D D D D D D - - 0/8/01000 A A A A Vref+ Vref- A A RA2 RA3 6/0/21001 D D A A A A A A Vss Vdd 6/2/01010 D D A A Vref+ A A A Vss RA3 5/2/11011 D D A A Vref+ Vref- A A RA2 RA3 4/2/21100 D D D A Vref+ Vref- A A RA2 RA3 3/3/21101 D D D D Vref+ Vref- A A RA2 RA3 2/4/21110 D D D D D D D A Vss Vdd 1/7/01111 D D D D Vref+ Vref- D A RA2 RA3 1/5/2Avant de vous donner le tableau concernant le 16F876, et qui est le mme sans les 3 pinsAN7/AN5, je vais vous donner un petit mot dexplication sur linterprtation de celui que jeviens de vous donner.229La premire colonne contient les 16 combinaisons possibles des bits de configurationPCFG3 PCFG0. Remarquez dj que les valeurs 0110 et 0111 donnent les mmes rsultats.Vous avez donc en ralit le choix entre 15 et non 16 combinaisons.Les colonnes AN7 AN0 indiquent le rle qui sera attribu chacune des pinsconcerne. Un A dans une ce ces colonnes indique que la pin correspondante estconfigure comme entre analogique (ne pas oublier TRISx), un D indiquera que la pin esten mode Digital, cest--dire quelle se comportera comme une pin dentre/sortie classique .La colonne AN3/RA3 peut contenir galement la valeur Vref+ qui indiquera quecette pin devra recevoir la tension de rfrence maximale. Il en va de mme pour AN2/RA2qui pourra contenir Vref- , qui indiquera que cette pin doit recevoir la tension de rfrenceminimale.La colonne Vref- indique quelle tension de rfrence minimale sera utilise par leconvertisseur. Il ne pourra sagir que de la tension dalimentation Vss ou de la pin RA2. Cettecolonne est donc lie au contenu de la colonne RA2 .Raisonnement identique pour la colonne Vref+ , lie RA3 . Cette colonne indiquequelle sera la tension de rfrence maximale. De nouveau, il ne pourra sagir que de la tensiondalimentation Vdd ou de la tension prsente sur la pin RA3.La dernire colonne A/D/R rsume les colonnes prcdentes. Le premier chiffrereprsente le nombre de pins configures en tant quentres analogiques, le second en tantquentres/sorties numriques, et le dernier le nombre de pins servant lapplication destensions de rfrence.Comme il y a 8 pins concernes pour le 16F877, la somme des 3 chiffres pour chaqueligne sera bien entendu gale 8.Vous voyez que si vous avez le choix du nombre de pins configures en entresanalogiques, vous navez cependant pas le choix de leur attribution. Par exemple, si vous avez besoin de configurer ces ports pour disposer de 3 entresanalogiques et de 5 entres/sorties numriques, vous devez chercher dans la dernire colonnela ligne 3/5/0 . Cette ligne vous indique que vous devez configurer les bits PCFGx 0100,et que les pins utilises comme entres analogiques seront les pins RA0,RA1, et RA3. Vousdevez donc en tenir compte au moment de concevoir votre schma. Une fois de plus, logicielet matriel sont troitement lis.Vous voyez galement que lors dune mise sous tension, les bits PCFGx contiennent0000. Le PORTA et le PORTE seront donc configurs par dfaut comme ports compltementanalogiques. Ceci vous explique pourquoi lutilisation de ces ports comme portsdentres/sorties classiques implique dinitialiser ADCON1, avec une des valeurs des 2 lignescompltement en bleu dans le tableau.Je vous donne maintenant le tableau quivalent pour le 16F876 :230PCFG3 0AN4RA5AN3RA3AN2RA2AN1RA1AN0RA0Vref- Vref+A/D/R0000 A A A A A Vss Vdd 5/0/00001 A Vref+ A A A Vss RA3 4/0/10010 A A A A A Vss Vdd 5/0/00011 A Vref+ A A A Vss RA3 4/0/10100 D A D A A Vss Vdd 3/2/00101 D Vref+ D A A Vss RA3 2/2/10110 D D D D D - - 0/5/00111 D D D D D - - 0/5/01000 A Vref+ Vref- A A RA2 RA3 3/0/21001 A A A A A Vss Vdd 5/0/01010 A Vref+ A A A Vss RA3 4/0/11011 A Vref+ Vref- A A RA2 RA3 3/0/21100 A Vref+ Vref- A A RA2 RA3 3/0/21101 D Vref+ Vref- A A RA2 RA3 2/1/21110 D D D D A Vss Vdd 1/4/01111 D Vref+ Vref- D A RA2 RA3 1/2/2Ce tableau est identique celui du 16F877, except la disparition du PORTE. Du fait de cettedisparition, vous trouverez plusieurs configuration de PCFGx qui donneront le mme rsultat.Dans ce cas, choisissez celle que vous voulez.Bien videmment, la somme des chiffres de la dernire colonne donnera la valeur 5 pourchacune des lignes, et non 8, comme ctait le cas sur le 16F877.19.14 Le registre ADCON0Ce registre est le dernier utilis par le convertisseur analogique/numrique. Il contient lesbits que nous allons manipuler lors de notre conversion. Sur les 8 bits de notre registre, 7seront utiliss.- b7 : ADCS1 : A/D conversion Clock Select bit 1- b6 : ADCS0 : A/D conversion Clock Select bit 0- b5 : CHS2 : analog Channel Select bit 2- b4 : CHS1 : analog Channel Select bit 1- b3 : CHS0 : analog Channel Select bit 0- b2 : GO/DONE : A/D conversion status bit- b1 : Inutilis : lu comme 0 - b0 : ADON : A/D ON bitNous avons parl maintes reprises de diviseur, afin de dterminer lhorloge duconvertisseur en fonction de la frquence du quartz utilis. Vous pouvez choisir ce diviseur laide des bits ADCSx.231ADCS1 ADCS0 Diviseur Frquence maximale du quartz0 0 Fosc/2 1,25Mhz0 1 Fosc/8 5Mhz1 0 Fosc/32 20 Mhz1 1 Osc RC Si > 1MHz, uniquement en mode sleep Souvenez-vous que:- La conversion durant le mode sleep ncessite de configurer ces bits sur Osc RC ,car loscillateur principal du PIC est larrt durant ce mode- Par contre, lemploi de loscillateur RC pour les PICs connectes un quartz de plus de1MHz vous impose de placer le PIC en mode sleep durant la conversion.- La mise en sommeil du PIC durant une conversion, alors que loscillateur nest pasconfigur comme oscillateur RC entranera un arrt de la conversion en cours, et uneabsence de rsultat, mme au rveil du PIC.Vous avez vu que vous pouvez configurer, via ADCON1, plusieurs pins comme entresanalogiques. Vous avez vu galement que vous ne pouvez effectuer la conversion que sur unepin la fois (on parlera de canal). Vous devez donc tre en mesure de slectionner la canalvoulu. Ceci seffectue via les bits CHSx.CHS2 CHS1 CHS0 Canal Pin0 0 0 0 AN0/RA00 0 1 1 AN1/RA10 1 0 2 AN2/RA20 1 1 3 AN3/RA31 0 0 4 AN4/RA51 0 1 5 AN5/RE0 (Uniquement pour 16F877)1 1 0 6 AN6/RE1 (Uniquement pour 16F877)1 1 1 7 AN7/RE2 (Uniquement pour 16F877)Le bit ADON permet de mettre en service le convertisseur. Si le canal a t correctementchoisi, le positionnement de ce bit permet de dmarrer la charge du condensateur interne, etdonc dtermine le dbut du temps dacquisition.Quant au bit Go/DONE, il sera plac 1 par lutilisateur la fin du tempsdacquisition. Cette action dtermine le dbut de la conversion en elle-mme, qui, je lerappelle, dure 12 Tad.Une fois la conversion termine, ce bit est remis 0 ( Done = Fait ) parllectronique du convertisseur. Cette remise 0 est accompagne du positionnement du flagADIF du registre PIR1. Ce bit permettra ventuellement de gnrer une interruption.Vous disposez donc de 2 faons pratiques de connatre la fin de la dure de conversion :232- Si votre programme na rien dautre faire durant lattente de la conversion, vous bouclezdans lattente du passage 0 du bit GO/Done.- Si votre programme continue son traitement, vous pouvez utiliser linterruption gnrepar le positionnement du flag ADIF.Attention : Si vous arrtez manuellement la conversion en cours, le rsultat ne sera pastransfr dans les registres ADRESL et ADRESH. Vous nobtenez donc aucun rsultat, mmepartiel. De plus, vous devrez quand mme respecter un temps dattente de 2Tad avant que neredmarre automatiquement lacquisition suivante.19.15 La conversion analogique/numrique et les interruptionsCette partie ne comporte aucune difficult particulire. En effet, linterruption gnre parle convertisseur est une interruption priphrique, et doit donc tre traite comme telle. Lesdiffrentes tapes de sa mise en service sont donc :- Positionnement du bit ADIE du registre PIE1- Positionnement du bit PEIE du registre INTCON- Positionnement du bit GIE du registre INTCONMoyennant quoi, toute fin de conversion analogique entranera une interruption. Il voussuffira de remettre 0 le flag ADIF aprs traitement de cette interruption.19.16 Lutilisation pratique du convertisseurArriv ce stade, vous disposez de toutes les informations pour effectuer votre mesure degrandeur analogique.Voici un rsum des oprations concrtes effectuer pour chantillonner votre signal :1) Configurez ADCON1 en fonction des pins utilises en mode analogique, ainsi que lesregistres TRISA et TRISE si ncessaire.2) Validez, si souhaite, linterruption du convertisseur3) Paramtrez sur ADCON0 le diviseur utilis4) Choisissez le canal en cours de digitalisation sur ADCON05) Positionnez, si ce nest pas dj fait, le bit ADON du registre ADCON06) Attendez le temps Tacq (typiquement 19,7s sous 5V)7) Dmarrez la conversion en positionnant le bit GO du registre ADCON08) Attendez la fin de la conversion2339) Lisez les registres ADRESH et si ncessaire ADRESL10) Attendez un temps quivalent 2Tad (typiquement 3,2s)11) Recommencez au point 4Notez que puisque lacquisition redmarre automatiquement aprs le temps 2 Tad ,vous pouvez relancer lacquisition directement, votre charge dattendre non pas le tempsTacq pour la fin de lacquisition, mais le temps Tacq + 2Tad. Ceci vous pargne unetemporisation. En effet, 2 temporisations qui se suivent peuvent tre remplaces par unetemporisation unique de temps cumul.Si donc, nous prenons notre PIC cadence 20Mhz, sous une tension dalimentation de5V, nous aurons :1) Configurez ADCON1 en fonction des pins utilises en mode analogique, ainsi que lesregistres TRISA et TRISE si ncessaire.2) Validez, si souhait, linterruption du convertisseur (PEIE, ADIE, GIE)3) Paramtrez le diviseur 32 sur ADCON0 (B10000000)4) Choisissez le canal en cours de digitalisation sur ADCON0 et lancez le convertisseur(B10xxx001)5) Attendez le temps (Tacq+2Tad), soit 19,7s + 3,2s = 22,9s6) Dmarrez la conversion en positionnant le bit GO du registre ADCON07) Attendez la fin de la conversion8) Lisez les registres ADRESH et si ncessaire ADRESL9) Recommencez au point 4Notez que vous pouvez, comme montr, raliser plusieurs oprations en mme temps.Cependant, fort logiquement, vous ne pouvez pas positionner les bits ADON etGO/DONE en mme temps, puisque le temps Tacq doit imprativement les sparer.Remarque :Lorsque vous disposez de beaucoup de temps entre 2 lectures de la valeur analogique, jevous conseille deffectuer plusieurs mesures intermdiaires, et deffectuer la moyenne de cesmesures. Ainsi, un parasite ventuel, ou une lgre fluctuation de votre tension sera fortementattnue.Il est pratique dans ce cas deffectuer un nombre de mesures qui est une puissance de 2 (2mesures, 4,8,16). Ainsi, pour effectuer votre moyenne, il suffira deffectuer la somme detoutes les valeurs, la division seffectuant par simple dcalage.234Exemple : vous faites 4 mesures successives.Le rsultat moyen sera donc (somme des 4 valeurs) / 4, donc, au niveau programmation,somme des 4 valeurs, suivie de 2 dcalages vers la droite (division par 4).Seconde remarque, vous verrez, dans le chapitre concernant les modules CCP, que desmcanismes sont prvus pour vous faciliter la vie au niveau de lautomatisation dessquences. Jy reviendrai ce moment, mais je vous conseille de suivre dans lordre, pour nepas tre submerg dinformations parfois assez lourdes digrer.19.17 Exercice pratique sur le convertisseur A/DOui, oui, je sais. Vous devez vous dire : ce nest pas trop tt . En effet, je vous ai unpeu assomm de thorie durant toute cette partie. Cependant, ce nest pas de linformationperdue, elle vous sera ncessaire si vous dcidez dutiliser le convertisseur la limite de sespossibilits.Certes, ce ne sera pas toujours le cas, mais qui peut le plus peut le moins, et, de toutesfaons, je vous ai donn des valeurs standard qui vous permettent dignorer toute la partiecalcul si cela ne vous est pas utile.Vous allez donc voir que paradoxalement, la mise en application est plus simple que lathorie relative la conversion. Mais assez de discours, commenons notre exercice parllectronique associe.Nous allons nous servir de notre petit chenillard lum1 , et lamliorer en y ajoutant 2potentiomtres destins rgler, dune part le temps dallumage de chaque LED, et dautrepart, le temps dextinction entre 2 allumages successifs.Le matriel ncessaire supplmentaire consistera donc en 2 potentiomtres de type linaire , et dune valeur peu critique, comprise entre 1Kohms (recommand), et 10Kohms. Etant donn que nous avons effectu nos calculs de temps sur la base dunealimentation de 5V et dune rsistance de source gale 10Kohms, ces valeurs permettrontune numrisation suffisamment rapide de notre tension dentre. Lachat ne vous ruinera pas,le prix dun potentiomtre avoisinant 1 Euro. Vous pouvez mme utiliser des rsistancesajustables pour circuit imprim, qui vous fera encore baisser le prix de faon significative.Nous allons monter nos potentiomtres en mode diviseur de tension , ce qui fait que latension prsente sur le curseur sera proportionnelle la position du bouton sur son axe derotation. En clair, plus vous tournerez le bouton du potentiomtre vers la droite, plus latension sur le curseur augmentera.Comme nous alimentons ces potentiomtres partir de Vdd et de Vss, la tension minimaleprsente sur le curseur sera de Vss, tandis que la tension maximale sera de Vdd. Nous devonsdonc choisir un mode de fonctionnement comportant 2 pins configures en entresanalogiques, et aucune tension de rfrence externe (2/x/0).Ceci, en consultant notre tableau ADCON1, nous indique que cette possibilit nexistepas. Par contre, nous avons la possibilit dutiliser 3 entres analogiques sans tension de235rfrence externe. Nous choisirons donc cette possibilit, quitte ne pas utiliser un des canauxanalogiques alors disponibles.PCFG3 0AN4RA5AN3RA3AN2RA2AN1RA1AN0RA0Vref- Vref+A/D/R0100 D A D A A Vss Vdd 3/2/0Nous devons de ce fait connecter nos 2 potentiomtres sur 2 des 3 pins suivantes : RA3,RA1,RA0. Pour rester logiques, nous choisissons RA0 pour le potentiomtre 1, et RA1 pourle potentiomtre 2.Voici donc notre schma (remarquez que nous avons t oblig de consulter les optionspossibles au niveau du logiciel avant de pouvoir le dessiner ) :Il me reste vous donner le brochage des potentiomtres. En fait, si vous placez celui-cibouton face vous, et les 3 pins de connexion diriges vers le bas, la pin 1 se trouve votredroite, la 2 au centre, et la 3 votre gauche. Linversion des broches 1 et 3 inversera le sens236de fonctionnement du potentiomtre, linversion de la broche 2 avec une des 2 autres setraduira par. un joli petit nuage de fume.Maintenant, nous allons calculer les temporisations. Le potentiomtre 1 va nous servirpour tablir la dure dallumage des LEDs de sortie, le potentiomtre 2 va rgler la dure delextinction. Nous allons dcider que la dure minimale dclairage sera de 1/10me deseconde, la dure maximale de 2,5S. La dure dextinction variera dans le mme registre.Nous aurons donc un algorithme du type :Allumage des LEDsAttente suivant position potentiomtre 1 de 0,1 2,5s.Extinction des LEDsAttente suivant position du potentiomtre 2 de 0,1 2,5SAllumage suivant : on recommence.On va dcider, pour des raisons de facilit, dutiliser 256 valeurs intermdiaires pour nospotentiomtres. Ceci nous permet de coder la valeur sur 1 octet. Un pas de variation vaudradonc plus ou moins : 2500ms / 256 = 9,77 ms.Notre timer 0 nous donne un temps de dbordement, sans prdiviseur, de 0,2 * 256 =51,2s.Pour obtenir 9,77ms, nous avons besoin dun prdiviseur de 9770 / 51,2 = 190,8.Cette valeur nexiste pas, mais comme notre application ne requiert pas de tempscritiques, et que nous avons choisi ces valeurs au pif , nous allons prendre un prdiviseurde 256.De ceci, nous tirons :- Le temps sparant 2 passages successifs dans notre routine dinterruption sera de : 0,2s *256 * 256 = 13,1072 ms- Pour attendre la dure minimale de 100ms, nous devrons passer 100 / 13,1072 =approximativement 8 fois dans notre routine dinterruption.- Pour attendre la dure maximale de 2500ms, nous devrons passer 2500 / 13,1072 = 190fois dans cette mme routine.237Donc, notre potentiomtre devra faire varier notre compteur de passage entre 8 et 190selon sa position. Notre potentiomtre devra donc pouvoir prendre 191 8 = 183 valeurs, cequi nest pas pratique. Nous utiliserons donc 256 valeurs, pour rester dans les puissances de 2.Nous pourrons donc faire varier le nombre de passages entre 8 (potentiomtre auminimum) et (8 + 255), soit 263 (potentiomtre au maximum).Ceci nous donne un temps minimum de 104 ms et un temps maximum de 3,45 secondes.Ceci est tout fait valable pour notre petit chenillard. Dautant que nous pourrons rgler lavitesse avec des pas de 10 ms.Nous allons commencer par crire notre pseudo-code sans nous proccuper de laconversion analogique/numrique. Nous avons dj tudi notre programme principal. Nousvoyons que nous avons besoin dune routine dinterruption.Nous pouvons nous dire que pendant que nous attendons, nous navons rien dautre faire, inutile donc dutiliser une interruption, une simple boucle fera laffaire. Nous utiliseronscependant notre timer 0 pour faciliter le calcul de la dure.On attend 8 fois le dbordement du timer0 ( 8 * 13,10ms)Tant que le compteur est suprieur 0, On attend 13,10ms supplmentaires On dcrmente le compteurOn doit alors intercaler la lecture des diffrents potentiomtres. Comme nous nutilisonsquun potentiomtre la fois (on allume, on attend en fonction du potentiomtre 1, on teint,on attend en fonction du potentiomtre 2), et que le temps dattente minimum est de 8 *13,10ms, on remarque quon a largement le temps deffectuer plusieurs lectures de chaquevaleur.En effet, pour lire un potentiomtre, il nous faut approximativement 20s de tempsdacquisition, et peu prs le mme temps (19,2s) pour effectuer la conversion. Ceci nousprend donc de lordre de 40s, comparer aux 13,10ms (13100 s) de chacun desdbordements de notre timer 0.Comme nous avons au minimum 8 temps dattente, pourquoi donc ne pas en profiter pourraliser 8 lectures du potentiomtre concern ? Notre routine de temporisation devient donc :Pour chacun des 8 premires boucles On lance une conversion A/D On attend que le timer 0 dborde (13,10ms)Dlai supplmentaireOn calcule la moyenne des 8 conversions effectuesTant que le rsultat est > 0 On attend que le timer 0 dborde On dcrmente le rsultatIl nous faut maintenant crire la routine de conversion A/D. Pour bien appliquer ce quenous avons appris, nous allons effectuer les oprations suivantes :238- On choisit le canal numriser (canal 0 = potentiomtre 1, canal1 = pot2)- On lance lacquisition (charge du condensateur) en mettant ON le convertisseur- On attend 20s- On lance la conversion en mettant GO 1 dans ADCON0Bien entendu, nous avons besoin de mesurer nos 20s. Ceci correspond 100 cyclesdinstructions. Nous pouvons donc utiliser notre timer 2, sans diviseur, et avec une valeur de100-1 dans PR2. Il nous suffira donc dattendre le positionnement du flag TRM2IF dans leregistre PIR1.Le temps dattente se ralisera donc comme suit, PR2 tant initialis D99 dans laroutine dinitialisation.- On efface TMR2- On efface TMR2IF- On lance le timer 2- On attend le positionnement de TMR2IF- On arrte le timer 2Ne reste donc plus qu sauvegarder notre rsultat (sur 10 bits) dans 2 variables. Cecipourra se faire, par exemple, dans notre routine dinterruption AD, qui sera dclencheautomatiquement la fin de la conversion. Cette routine se bornera crire les 2 registres dursultat dans les variables pointes.Donc, pour rsumer, voici comment les vnements vont se succderchronologiquement pour chacune des 8 premires dures de 13,10ms.- On met en service le convertisseur- On attend 20s- On lance la conversion- 19,2s plus tard, linterruption A/D est gnre- On sauve le rsultat et on arrte le convertisseur- On attend le temps qui reste de nos 13,10ms du dpart- On recommenceLarrt du convertisseur et du timer 2 ne sont pas obligatoires, mais diminuent laconsommation(et donc lchauffement) du PIC. Cest donc une bonne habitude de procderde la sorte.Donc, le temps qui spare 2 conversions est dapproximativement 13,10ms 20s 19,2s, soit bien plus que les 2Tad ncessaires (3,2s). Donc, aucun soucis de ce ct.Voyons maintenant la ralisation pratique de notre programme. Commencez par copier lefichier lum1.asm , et renommez la copie en lum2.asm . Editez len-tte du programme :239;*****************************************************************************; Ralisation d'un mini-chenillard 8 LEDs avec 2 potentiomtres de *; rglage. *; *;*****************************************************************************; *; NOM: Lum2 *; Date: 31/05/2002 *; Version: 1.0 *; Circuit: Circuit maquette *; Auteur: Bigonoff *; *;*****************************************************************************; *; Fichier requis: P16F876.inc *; lumdat.inc *; *; *; *;*****************************************************************************; *; Notes: les 8 sorties sont sur le PORTB. Un niveau haut allume la LED *; correspondante. *; Exercice sur les conversions A/D, l'aide de 2 potentiomtres *; Le potentiomtre 1 est sur RA0 *; Le potentiomtre 2 est sur RA1 *; Le potentiomtre 1 rgle le temps d'allumage *; Le potentiomtre 2 rgle le temps d'extinction *; La frquence du quartz est de 20MHz *; *;*****************************************************************************Ensuite, la configuration, qui ne pose aucun problme :LIST p=16F876 ; Dfinition de processeur#include ; fichier include#include ; donnes d'allumage__CONFIG _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_OFF & _CPD_OFF & _LVP_OFF &_BODEN_OFF & _PWRTE_ON & _WDT_ON & _HS_OSC;_CP_OFF Pas de protection;_DEBUG_OFF RB6 et RB7 en utilisation normale;_WRT_ENABLE_OFF Le programme ne peut pas crire dans la flash;_CPD_OFF Mmoire EEprom dprotge;_LVP_OFF RB3 en utilisation normale; _BODEN_OFF Reset tension hors service;_PWRTE_ON Dmarrage temporis;_WDT_ON Watchdog en service;_HS_OSC Oscillateur haute vitesse (20Mhz)On trouve ensuite la valeur pour le registre OPTION;*****************************************************************************; ASSIGNATIONS SYSTEME *;*****************************************************************************; REGISTRE OPTION_REG (configuration); -----------------------------------OPTIONVAL EQUB'10000111' ; RBPU b7 : 1= Rsistance rappel +5V hors service; PSA b3 : 0= Assignation prdiviseur sur Tmr0240; PS2/PS0 b2/b0 valeur du prdiviseur = 256Nous naurons quune seule source dinterruption, le convertisseur A/D, qui est uneinterruption priphrique. Ceci nous impose donc de programmer INTCON et PIE1 :; REGISTRE INTCON (contrle interruptions standard); -------------------------------------------------INTCONVAL EQU B'01000000' ; PEIE b6 : masque autorisation gnrale priphriques; REGISTRE PIE1 (contrle interruptions priphriques); ----------------------------------------------------PIE1VAL EQU B'01000000' ; ADIE b6 : masque interrupt convertisseur A/DComme il nexiste pas de mode 2 canaux analogiques sans tension de rfrenceexterne , nous utiliserons le mode 3 canaux . Nous choisissons une justification droite,pour conserver, avant calcul de la moyenne, lintgralit des 10 bits de rsultat. Ce nestquaprs avoir calcul la moyenne, que nous ne conserverons que les 8 bits les plussignificatifs.; REGISTRE ADCON1 (ANALOGIQUE/DIGITAL); ------------------------------------ADCON1VAL EQUB'10000100' ; 3 Entres analogiques, rsultat justifi ; droiteLe PORTA sera configur en entre, le PORTB en sortie. Nous aurions pu nous abstenirde configurer TRISA, celui-ci tant positionn en entre au moment de la mise sous tension.Cependant, je laisse cette configuration pour vous rappeler que TRISA intervient danslinitialisation du convertisseur.; DIRECTION DES PORTS I/O; -----------------------DIRPORTA EQUB'00111111' ; Direction PORTA (1=entre)DIRPORTB EQUB'00000000' ; Direction PORTBLes macros ne posent aucun problme. Jen profite pour rappeler que les macros nonutilises ne consomment aucune place dans la mmoire du PIC, puisquelles ne sont toutsimplement pas traduites.*****************************************************************************; MACRO *;*****************************************************************************; Changement de banques; ----------------------BANK0 macro ; passer en banque0;bcf STATUS,RP0bcf STATUS,RP1endmBANK1 macro ; passer en banque1bsf STATUS,RP0bcf STATUS,RP1endm241BANK2 macro ; passer en banque2bcf STATUS,RP0bsf STATUS,RP1endmBANK3 macro ; passer en banque3bsf STATUS,RP0bsf STATUS,RP1endmNous arrivons notre zone de variables. Nous avons besoin dune variable sur 8 bits pourcompter les boucles de notre routine de temporisation. Les 8 lectures successives dupotentiomtre concern ncessitera 16 emplacements (8 * 2 octets).Pour pouvoir calculer la moyenne de ces valeurs, nous devrons en faire laddition, cecincessitera donc une variable de 2 octets.Ne reste plus que le flag qui va nous informer si nous sommes en train de nous occuper denotre potentiomtre 1 ou de notre potentiomtre 2. Tout ceci nous donne :;*****************************************************************************; VARIABLES BANQUE 0 *;*****************************************************************************; Zone de 80 bytes; ----------------CBLOCK0x20 ; Dbut de la zone (0x20 0x6F)cmpt : 1 ; compteur de bouclesflags : 1 ; flags divers; b0 : 0 = potar1, 1=potar2potar : 16 ; valeurs du potentiomtre lu(msb,lsb)result : 2 ; rsultat de la somme des valeurs ENDC ; Fin de la zone#DEFINE numpotar flags,0 ; flag de temporisationNotre zone commune se borne aux registres sauvegarder :*****************************************************************************; VARIABLES ZONE COMMUNE *;*****************************************************************************; Zone de 16 bytes; ----------------CBLOCK 0x70 ; Dbut de la zone (0x70 0x7F)w_temp : 1 ; Sauvegarde registre Wstatus_temp : 1 ; sauvegarde registre STATUSENDCLe dmarrage du programme, comme toujours en adresse 0x00 :; ////////////////////////////////////////////////////////////////////////////; I N T E R R U P T I O N S; ////////////////////////////////////////////////////////////////////////////242;*****************************************************************************; DEMARRAGE SUR RESET *;*****************************************************************************org 0x000 ; Adresse de dpart aprs reset goto init ; InitialiserPuis notre routine dinterruption, qui ne contient que linterruption du convertisseur. Letest de linterruption est donc inutile :;*****************************************************************************; ROUTINE INTERRUPTION *;*****************************************************************************;sauvegarder registres;---------------------org 0x004 ; adresse d'interruptionmovwf w_temp ; sauver registre Wswapf STATUS,w ; swap status avec rsultat dans wmovwf status_temp ; sauver status swappBANK0 ; passer en banque0; Interruption AD; ---------------bcf ADCON0,ADON ; teindre convertisseurmovf ADRESH,w ; charger poids fort conversionmovwf INDF ; sauver dans zone de sauvegardeincf FSR,f ; pointer sur poids faiblebsf STATUS,RP0 ; passer banque 1movf ADRESL,w ; charger poids faible conversionbcf STATUS,RP0 ; passer banque 0movwf INDF ; sauver dans zone de sauvegardeincf FSR,f ; pointer sur poids fort suivantbcf PIR1,ADIF ; effacer flag interupt;restaurer registres;-------------------restoreregswapf status_temp,w ; swap ancien status, rsultat dans wmovwf STATUS ; restaurer statusswapf w_temp,f ; Inversion L et H de l'ancien W ; sans modifier Zswapf w_temp,w ; Rinversion de L et H dans W; W restaur sans modifier statusretfie ; return from interruptUne petite remarque, ce sujet. Nous utilisons FSR dans le programme principal et dansla routine dinterruption, pourtant nous ne le sauvons pas. Ceci est d au fait que lamodification de FSR effectue dans la routine dinterruption est utilise dans le programmeprincipal.Ceci est possible uniquement parce que la routine dinterruption intervient un endroitconnu de notre programme, et nest donc pas rellement asynchrone. Cest le signe que letraitement de ce morceau de code pouvait tre effectu dans le programme principal, uneroutine dinterruption ntait donc pas indispensable.Nanmoins, jai utilis une interruption dessin pour montrer son utilisation de faondidactique. Je rappelle quil nest nullement question doptimisation ici, bien quon pouvait243simplifier facilement le programme, mais plutt de vous montrer la faon gnrale deprocder. Vous aurez plus facile de supprimer ce qui est inutile plutt que dajouter ce que jene vous aurai pas montr.La routine dinitialisation est semblable celle de lum1 , ceci prs quil a falluinitialiser le timer 2 et son registre PR2.; ////////////////////////////////////////////////////////////////////////////; P R O G R A M M E; ////////////////////////////////////////////////////////////////////////////;*****************************************************************************; INITIALISATIONS *;*****************************************************************************init; initialisation PORTS (banque 0 et 1); ------------------------------------BANK0 ; slectionner banque0clrf PORTA ; Sorties PORTA 0clrf PORTB ; sorties PORTB 0bsf STATUS,RP0 ; passer en banque1movlw ADCON1VAL ; PORTA en mode digital/analogiquemovwf ADCON1 ; criture dans contrle A/Dmovlw DIRPORTA ; Direction PORTAmovwf TRISA ; criture dans registre directionmovlw DIRPORTB ; Direction PORTBmovwf TRISB ; criture dans registre direction; Registre d'options (banque 1); -----------------------------movlw OPTIONVAL ; charger masquemovwf OPTION_REG ; initialiser registre option; registres interruptions (banque 1); ----------------------------------movlw INTCONVAL ; charger valeur registre interruptionmovwf INTCON ; initialiser interruptionsmovlw PIE1VAL ; Initialiser registremovwf PIE1 ; interruptions priphriques 1; timer 2 (banque 1); ------------------movlw D'99' ; 99 + 1 passages = 20smovwf PR2 ; dans comparateur; initialiser variables; ---------------------BANK2 ; passer en banque 2movlw low mesdata ; adresse basse des datamovwf EEADR ; dans pointeur bas FLASHmovlw high mesdata ; adresse haute des datamovwf EEADRH ; dans pointeur haut FLASHbcf STATUS,RP1 ; repasser en banque 0movlw potar ; adresse de la zone de stockagemovwf FSR ; dans pointeurclrf T2CON ; pr = postdiviseur = 1; autoriser interruptions (banque 0); ----------------------------------clrf PIR1 ; effacer flags 1244bsf INTCON,GIE ; valider interruptionsgoto start ; programme principalRien de chang pour la routine de lecture dun octet en mmoire programme :;*****************************************************************************; LIRE UN OCTET EN FLASH *;*****************************************************************************;-----------------------------------------------------------------------------; Lit un octet en mmoire programme, puis pointe sur le suivant; retourne l'octet lu dans w; si le bit 8 du mot lu vaut 1, on pointe sur la premire donne;-----------------------------------------------------------------------------readflashBANK3 ; pointer sur banque3bsf EECON1,EEPGD ; accs la mmoire programmebsf EECON1,RD ; lecturenop ; 2 cycles d'attentenopbcf STATUS,RP0 ; pointer sur banque2incf EEADR,f ; incrmenter pointeur bas sur donnesbtfsc STATUS,Z ; tester si dbordincf EEADRH,f ; oui, incrmenter pointeur hautbtfss EEDATH,0 ; tester bit 0 data haute = bit 8 donnegoto readfsuite ; si 0, sauter instructions suivantesmovlw low mesdata ; si 1, adresse basse des datamovwf EEADR ; dans pointeur bas FLASHmovlw high mesdata ; adresse haute des datamovwf EEADRH ; dans pointeur haut FLASHreadfsuitemovf EEDATA,w ; charger 8 bits donnebcfSTATUS,RP1 ; repointer sur banque0return ; et retourLa routine de temporisation est conforme ce que nous avons dfini, avec dans lordre,les 8 premiers passages, avec lancement de la numrisation;*****************************************************************************; Temporisation *;*****************************************************************************;-----------------------------------------------------------------------------; Base de temps de 13,1072ms.; On attend d'office 8 * 13,10 ms. Durant cette attente, on lance 8; numrisations du potentiomtre concern.; Ensuite, on calcule la moyenne des 8 conversions, et on garde le rsultat; sur 8 bits. Cette valeur indique le nombre de multiples de 13,10ms; supplmentaires attendre.;-----------------------------------------------------------------------------tempo; gestion des 8 premiers passages; -------------------------------movlw 0x08 ; pour 8 * 13,10msmovwf cmpt ; dans compteurtempo1call acquire ; lancer acquisitioncall wait ; attendre 13,1072msdecfszcmpt,f ; dcrmenter compteur de bouclesgoto tempo1 ; boucle suivante245Ensuite, la somme des 8 valeurs obtenues :; calcul de la somme des valeurs; ------------------------------movlw 0x08 ; pour 8 bouclesmovwf cmpt ; dans compteur de bouclesclrf result ; effacer rsultatclrf result+1 ; idem pour poids faibletempo2decf FSR,f ; pointer sur poids faiblemovf INDF,w ; charger poids faibleaddwf result+1,f ; ajouter au poids faible rsultatbtfsc STATUS,C ; tester si dbordementincf result,f ; oui, poids fort +1decf FSR,f ; pointer sur poids fortmovf INDF,w ; charger poids fortaddwf result,f ; ajouter au poids fort rsultatdecfszcmpt,f ; dcrmenter compteur de bouclesgoto tempo2 ; pas dernire, suivanteRemarquez lastuce utilise : la routine dinterruption du convertisseur incrmente FSRdepuis le premier octet de poids fort des valeurs numrises, jusqu loctet qui suit le dernieroctet de poids faible. Il suffit donc de dcrmenter successivement FSR pour additionnertoutes les valeurs en commenant par le dernier poids faible.La mthode est celle de laddition classique sur 2 octets : on additionne les 2 poids faibles,sil y a dbordement, on incrmente le poids fort. On additionne ensuite les 2 poids forts.Comme nous avons 8 valeurs additionner, et que chaque valeur ne comporte que 10 bitsvalides, le rsultat tiendra sur 13 bits. Donc, il ny aura pas dbordement en additionnant lespoids forts.Nous procdons ensuite au calcul de la moyenne. Comme nous voulons un rsultat sur 8bits, et que nous en avons 13, on pourrait se dire quon doit dcaler le rsultat 5 fois vers ladroite. Le rsultat final se trouvant dans le poids faible du rsultat.En fait, il est plus simple de tout dcaler de 3 rangs vers la gauche, le rsultat se trouvantalors dans le poids fort du rsultat. Faites le test sur papier pour vous en convaincre.; calcul de la moyenne sur 8 bits; -------------------------------rlf result+1,f ; dcaler poids faible vers la gaucherlf result,f ; idem poids fort avec b7 poids faiblerlf result+1,f ; dcaler poids faible vers la gaucherlf result,f ; idem poids fort avec b7 poids faiblerlf result+1,f ; dcaler poids faible vers la gaucherlf result,f ; idem poids fort avec b7 poids faible; on avait 5 + 8 bits, on a 8 + 5 bitsDe nouveau, la mthode est classique : on dcale le poids faible vers la gauche, le bit 7tombe dans le carry. On dcale ensuite le poids fort, le carry devient le bit0. On a donc dcalles 16 bits vers la gauche. Notez que nous aurions du mettre le carry 0 avant le dcalage dupoids faible, mais ceci est inutile ici, car nous nutiliserons pas le poids faible du rsultat,seuls comptent les 8 bits finaux du poids fort. Donc peut importe si nous avons fait entrer un 1 indsirable dans le poids faible.246Il reste attendre (result * 13,10ms). Nous devons tester result avant la boucle, de faon ce quune valeur de 0 ne provoque pas 256 boucles, ce qui aurait t le cas en utilisant uneboucle de type decfsz .; attendre result * 13,10ms; -------------------------tempo3movf result,f ; tester rsultatbtfsc STATUS,Z ; tester si 0return ; oui, fin de l'attentecall wait ; attendredecfszresult,f ; dcrmenter dure restantegoto tempo3 ; boucle suivanteIl faut crire maintenant la petite sous-routine dattente du dbordement du timer 0 :;*****************************************************************************; Attendre fin timer 0 *;*****************************************************************************waitclrf TMR0 ; effacer timer0bcf INTCON,T0IF ; effacer flag dbordementwait1btfss INTCON,T0IF ; tester si timer a dbordgoto wait1 ; non, attendrereturn ; fin d'attentePassons maintenant la routine de dmarrage de la numrisation. Cette dernire, commeprvu, se compose de 3 parties : Lancement de lacquisition, attente du temps Tacq,dmarrage du convertisseur :;*****************************************************************************; Acquisition de la valeur analogique *;*****************************************************************************;-----------------------------------------------------------------------------; Si numpotar vaut 0, on travaille sur le potar1, sinon, c'est le potar2; On slectionne le canal, et on lance l'acquisition; on attend 20 s (Tacq), puis on lance la numrisation; la fin de numrisation sera dtecte par interruption;-----------------------------------------------------------------------------acquire; lancer l'acquisition; --------------------movlw B'10000001' ; diviseur 32, canal 0, convertisseur ONbtfsc numpotar ; tester si c'est potentiomtre 2movlw B'10001001' ; oui, alors canal 1movwf ADCON0 ; paramtrer convertisseur, lancer acquisition; attendre 20 s; --------------clrf TMR2 ; effacer timer2bcf PIR1,TMR2IF ; effacer flag dbordementbsf T2CON,TMR2ON ; lancer timer 2acquire1btfss PIR1,TMR2IF ; tester si temps coulgoto acquire1 ; non, attendrebcf T2CON,TMR2ON ; oui, arrt du timer 2247; dmarrage du convertisseur; --------------------------bsf ADCON0,GO ; lancer conversion A/Dreturn ; fin de l'acquisitionLe programme principal est tout simple :;*****************************************************************************; PROGRAMME PRINCIPAL *;*****************************************************************************startclrwdt ; effacer watch dogcall readflash ; lire un octet en flashmovwf PORTB ; le mettre sur le PORTB (allumage LEDs)bcfnumpotar ; pour potentiomtre 1call tempo ; attendre en fonction du potentiomtreclrf PORTB ; teindre LEDsbsfnumpotar ; pour potentiomtre 2call tempo ; attendre en fonction du potentiomtregoto start ; bouclermesdata ; emplacement des donnes (lumdat.inc)END ; directive fin de programmeLancez lassemblage, chargez le programme, et lancez lalimentation. Votre chenillard estmaintenant rglable avec les 2 potentiomtres.Tiens, le vtre reste obstinment bloqu sur la premire LED ? Que se passe-t-il donc ?Jattribue 10 points avec mention du jury ceux qui ont dj compris, les autres, je vousconseille de rflchir un peu avant de poursuivre la lecture.Pour rechercher la cause, passons dans MPLAB en mode simulation en pas pas. Aprslassemblage, pressez , puis des pressions successives de jusqu la ligne :call readflash ; lire un octet en flashdu programme principal. Continuez ensuite les pressions successives de jusqu ce quevous arriviez la ligne suivant ltiquette tempo de votre routine de temporisation.Pressez alors successivement jusque la ligne :call acquire ; lancer acquisitionPressez alors sur . Ceci vous permet dexcuter la sous-routine en une seule fois,sans devoir entrer manuellement lintrieur. Vous tes maintenant sur la ligne :callwait ; attendre 13,1072msPressez de nouveau . La barre infrieure passe en jaune, preuve que le simulateurtravaille. En effet, cette routine dure trs longtemps du point de vue du PIC. En effet, 13,10msreprsentent plus de 65000 instructions excuter.Au bout dun moment, votre programme devrait se retrouver la ligne suivante, savoir :248decfszcmpt,f ; dcrmenter compteur de bouclesEn fait, vous vous retrouvez de faon incomprhensible :org 0x000 ; Adresse de dpart aprs reset goto init ; InitialiserPour ceux qui disent mais bon sang, cest normal , je donne 8 points. Pour les autres, jedonne un indice pour 5 points :Ladresse 0x00 est ladresse de reset, notre PIC a donc effectu un reset durant notreroutine de temporisation.Vous avez trouv ? Sinon, reste savoir quel reset, parmi les types possibles. Enprocdant par limination, on trouve assez facilement quil sagit dun reset provoqu par lewatchdog. En effet, on va attendre au minimum 8 * 13,10ms dans la routine de temporisation,alors que le temps minimal de reset par watchdog sans prdiviseur se situe sous cette valeur.Donc, ne tombez pas dans le pige, pensez que vous devez intercaler des instructions clrwdt avant que ne soit provoqu un reset par le mcanisme du watchdog. Le meilleuremplacement pour le faire est bien entendu dans la boucle dattente du dbordement du timer0, dans la sous-routine wait .waitclrf TMR0 ; effacer timer0bcf INTCON,T0IF ; effacer flag dbordementwait1clrwdt ; effacer watchdogbtfss INTCON,T0IF ; tester si timer a dbordgoto wait1 ; non, attendrereturn ; fin d'attenteVous pouvez maintenant relancer lassemblage et reprogrammer votre PIC. Notez alorsque le potentiomtre 1 vous permet de rgler le temps durant lequel les LEDs restentallumes, alors que le potentiomtre 2 permet de rgler le temps durant lequel elles restentteintes.19.18 ConclusionNous en avons maintenant termin avec notre convertisseur A/D. Tout ceci a du vousparatre compliqu et laborieux , mais vous avez vu dans notre application pratique quonpouvait en gnral se passer des calculs.Ces calculs vous seront par contre utiles pour les applications qui ncessitent dexploiterle convertisseur au maximum de ses possibilits, ce qui rendait impratif les explicationsthoriques.Grce ce convertisseur, vous allez pouvoir mesurer des rsistances, des tensionscontinues ou alternatives, des tempratures, et toute autre grandeur analogique. Ceci ouvredonc les portes de lanalogique votre composant numrique.249Notes : 250Notes : 25120. Les modules CCP1 et CCP220.1 GnralitsLes 16F87x disposent de 2 modules CCP. CCP signifie Capture, Compare, and PWM.Ceci vous indique dj que nous pourrons diviser ce chapitre entre 3 parties distinctes,correspondant autant de modes de fonctionnement.Ces modules CCP sont fortement lis et dpendant des timers 1 et 2, aussi jaurais puplacer ce chapitre directement aprs ltude des timers. Cependant, ils sont galement lis auconvertisseur A/D, et, de plus, jaurai besoin de ce dernier pour pouvoir vous proposer unexercice pratique en fin dtude thorique. Ceci explique pourquoi jen parle maintenant.Cependant, sachez dj que ces modules augmentent les capacits des timers, et doncpondrent la conclusion les concernant quand leurs utilisations classiquesIl faut savoir que les 2 modules CCP1 et CCP2 sont strictement identiques, except lapossibilit, pour le module CCP2, de dmarrer automatiquement la conversion A/D. Jenreparlerai.20.2 Ressources utilises et interactionsAu niveau ressources utilises, nous pouvons simplement dire que les modules CCPxutiliss en mode compare et en mode capture font appel au timer 1, alors que le mode PWMncessite lutilisation du timer 2.Vous comprenez dj que vous allez vous heurter 2 types de contraintes :- Dune part, lutilisation des timers dans les modes tudis prcdemment et dun moduleCCPx va tre soumise des contraintes inhrentes aux registres utiliss. Vous comprenezen effet quil va tre impossible, par exemple, de charger TMR1L et TMR1Hsimultanment avec une valeur qui vous arrange pour lutilisation en mode timer, et uneautre pour lutilisation du CCP1 en mode compare.- Dautre part, lutilisation de 2 modules CCP simultanment va entraner galement descontraintes, dans la mesure o ils devront utiliser les mmes ressources. Tout sera doncquestion dtude et de compromis.Nous allons principalement nous intresser aux interactions lors de lutilisation de 2modules simultanment. Les contraintes lies lutilisation classique des timers serontabordes dans chaque cas particulier.Puisque chacun des modules dispose de 3 modes de fonctionnement, nous aurons 9possibilits dinteraction. Mais, comme les 2 modules sont en fait identiques, les interactionsse rsument 6 cas possibles. En effet, les contraintes lies par exemple CCP1 en modecapture et CCP2 en mode compare sont strictement identiques aux contraintes pour CCP1 enmode compare et CCP2 en mode capture.252Pour notre tableau des contraintes, CCPx concerne CCP1 ou CCP2 au choix, alors queCCPy concerne forcment lautre CCP.Mode de CCPx Mode de CCPy InteractionCapture Capture Les modules doivent utiliser la mme base de temps dutimer 1Capture Compare Si le module compare est utilis en mode trigger, le resetpeut perturber les mesures du module capture.Capture PWM Aucune interaction, les modules utilisent un timerdiffrent.Compare Compare En mode trigger, le premier reset survenu empche lautrecomparateur datteindre sa valeurCompare PWM Aucune interaction, les modules utilisent un timerdiffrent.PWM PWM La frquence sera identique, ainsi que les mises jour vialinterruption TMR2En somme, rien que du logique, ne vous tracassez pas pour les termes que vous necomprenez pas, nous allons parler de tout a en dtail.20.3 Les registres CCP1CON et CCP2CONTout dabord, ne confondez pas, ces registres ont la mme fonction, simplementCCP1CON concerne le module CCP1, tandis que CCP2CON concerne le module CCP2.Ce registre CCPxCON permet donc, en toute logique, de dterminer le mode defonctionnement du module. Voici son contenu, x remplace 1 ou 2 suivant lemodule utilis dans tout le reste du chapitre.CCPxCONb7 : Inutilis : Lu comme 0 b6 : Inutilis : Lu comme 0 b5 : CCPxX : module Capture Compare and Pwm x bit Xb4 : CCPxY : module Capture Compare and Pwm x bit Yb3 : CCPxM3 : module Capture Compare and Pwm x Mode select bit 3b2 : CCPxM2 : module Capture Compare and Pwm x Mode select bit 2b1 : CCPxM1 : module Capture Compare and Pwm x Mode select bit 1b0 : CCPxM0 : module Capture Compare and Pwm x Mode select bit 0Tout dabord, voyons les bits CCPxX et CCPxY. Ces bits sont en fait les 2 bits de poidsfaible qui compltent le nombre de 10 bits utilis pour le mode de fonctionnement PWM. Jenparlerai donc au moment de ltude de ce mode de fonctionnement. Dans les autres modes,ces bits sont donc inutiliss.Les bits CCPxM3 CCPxM0 servent dterminer quel sera le mode de fonctionnementdu module concern. Les possibilits sont les suivantes :253CCPM Fonctionnement0000 Module CCPx larrt0100 Mode capture valid sur chaque flanc descendant0101 Mode capture valid sur chaque flanc montant0110 Mode capture valid sur chaque multiple de 4 flancs montants0111 Mode capture valid sur chaque multiple de 16 flancs montants1000 Mode compare, place la sortie 1 sur dbordement (+ bit CCPxIF = 1)1001 Mode compare, place la sortie 0 sur dbordement (+ bit CCPxIF = 1)1010 Mode compare, positionne CCPxIF sans affecter la sortie1011 Mode compare, positionne CCPxIF sans affecter la sortie, et gnre le trigger11xx Mode PWMAu niveau du mode compare gnrant le trigger, il faut distinguer laction du moduleCCP1 de celle du module CCP2 :- Pour CCP1, lvnement trigger remet TMR1 0 (reset)- Pour CCP2, lvnement trigger remet TMR1 0 (reset) et lance automatiquement laconversion A/D (si le module A/D est en service).Notez quun reset provoque larrt des modules CCP, le contenu du prdiviseur est de plusremis 0.Noubliez pas que pour pouvoir utiliser les modules CCP, il faut que le timer utilis soitcorrectement configur, et, bien entendu, mis en service.20.4 Le mode capture Nous allons commencer par tudier le plus simple des 3 modes, savoir le mode capture.La premire chose remarquer est que ce mode fait intervenir une pin comme vnementdclencheur. Il sagit donc dune entre.Il est donc impratif de configurer la pin CCPx en entre via le registre TRISC avant depouvoir utiliser le module CCPx en mode capture . Comme cest le cas par dfaut aprsune mise sous tension, on a cependant peu de chance de loublier.20.4.1 Principe de fonctionnementLe mode capture est simple comprendre. Il est en troite liaison avec les pins RC1/CCP2et RC2/CCP1 du PIC. Attention linversion des chiffres, la logique ne coule pas de source.En fait, le principe est le suivant :- Au moment de lapparition de lvnement dclencheur sur la pin concerne, la valeur (16bits) du timer 1 contenue dans les registres TMR1H et TMR1L est copie dans lesregistres CCPR1H et CCPR1L. (Ah, tiens, voici un moyen dannuler le bug concernant lalecture au vol de TMR1).254- Simultanment, le bit CCP1IF du registre PIR1 est valid, et une interruption intervient sielle est configure.Lvnement dclencheur est une variation du signal sur la pin CCP1/RC2 pour le moduleCCP1, et sur la pin CCP2/RC1 pour le module CCP2. Lvnement qui provoque la capturedpend des bits CCPxM3 CCPxM0.Vous avez plusieurs possibilits :- Soit, la capture seffectue chaque fois que la tension sur la pin CCPx passe de Vdd Vss(CCPM = 0100)- Soit la capture seffectue chaque fois que la tension sur la pin CCPx passe de Vss Vdd(CCPM = 0101)- Ou alors, la capture seffectue au bout de 4 transitions niveau bas/niveau haut de la pinCCPx, on comprend quil sagit dun prdiviseur de signal par 4 (CCPM = 0110)- Ou enfin, la capture seffectue de faon identique, mais aprs chaque multiple de 16transitions niveau bas/niveau haut, il sagit donc dun prdiviseur de signal par 16 (CCPM= 0111).Si vous avez bien compris ce qui prcde, vous pouvez vous imaginer le schma-bloccorrespondant. Je vous le donne cependant explicitement, remplacez les termes x par 1 ou 2 en fonction du numro de module utilisVous constatez, propos des contraintes, que vous avez bien un flag CCPxIF parmodule, une pin CCPx, un registre de configuration CCPxCON, et un registre 16 bits desauvegarde de la valeur capture. Par contre, vous navez quun seul timer, savoir TMR1,utilis pour les 2 modules.Remarquez que le prdiviseur ne sapplique que pour la dtection des signaux flancsmontants.25520.4.2 Champs dapplicationVous voyez probablement dj plusieurs applications typiques de ce mode defonctionnement. Sachant que le timer 1 peut fonctionner en mode timer ou en mode compteur,vous pouvez :- Dterminer le temps sparant 2 ou plusieurs vnements. Ceci vous permet par exemplede raliser un chronomtre de haute prcision. Si le temps est suprieur au temps decomptage sur 16 bits de TMR1, celui-ci peut gnrer une interruption, et donc incrmenterune variable qui comptera les multiples de 65536 vnements.- Compter un nombre dvnements compts par le timer 1 survenus entre 2 ou plusieursflancs prsents sur la pin CCPx.Je vous donne un pseudo-code pour la ralisation dun chronomtre. Le bouton-poussoir(sans rebond, bien sr) est connect sur CCPx- On lance le timer1, on autorise interruptions TMR1 et CCPx- Dans linterruption TMR1, on incrmente une variable- On presse sur le bouton (start)- Linterruption CCPx sauve les registres CCPRxH et CCPRxL ainsi que la variable(variable1)- On presse sur le bouton (stop)- Lors de linterruption CCPx on sauve la variable (variable2)- Le temps exact coul entre les 2 vnements en nombre de cycles sera : ((variable2-variable1) * 65536 + (CCPRxH CCPRxH sauv) *256 + (CCPRxL CCPRxL sauv)) *prdiviseur.Lavantage, cest que la capture se fait au moment prcis de lvnement, et donc le tempsde raction du programme nintervient plus dans le calcul du temps. De mme, plus aucunproblme, ni de bug, pour la lecture des 2 octets de TMR1. Et dire que Microchiprecommandait de changer de timer pour ce genre dapplicationsAttention, il sagit dun pseudo-code simplifi, il vous faudra, pour en faire un programmeoprationnel, grer les risques de dbordements de la variable, pour ne citer quun exemple.Mais cela vous montre les avantages de cette mthode.20.4.3 Remarques et limites dutilisationLutilisation de ce mode de fonctionnement impose lapplication de certaines rgles etconseils de prudence. Il importe dtre attentif. Certaines de ces rgles sont dailleursdapplication pour le mode compare . Voici ces rgles :256-Le timer 1 doit imprativement tre configur en mode timer ou en mode compteursynchrone . En mode compteur asynchrone, la capture ne fonctionne pas.Je vous renvoie au chapitre sur le timer 1 pour plus de renseignements.- Tout changement de configuration du mode capture peut provoquer un positionnementindsirable du bit CCPxIF. Avant tout changement, vous devez donc interdire lesinterruptions CCPx, et forcer CCPxIF 0 avant de rautoriser les interruptions.Pour le CCP1 :bsf STATUS,RP0 ; passer en banque 1bcf PIE1,CCP1IE ; interdire interruptions CCP1bcf STATUS,RP0 ; repasser en banque 0movlw nouveau_mode ; nouveau mode pour CCP1movwf CCP1CON ; dans registre de commandebcf PIR1,CCP1IF ; effacer flag dinterruptionbsf STATUS,RP0 ; passer en banque 1bsf PIE1,CCP1IE ; rautoriser interruptions CCP1bcf STATUS,RP0 ; repasser en banque 0Pour le CCP2 :bsf STATUS,RP0 ; passer en banque 1bcf PIE2,CCP2IE ; interdire interruptions CCP2bcf STATUS,RP0 ; repasser en banque 0movlw nouveau_mode ; nouveau mode pour CCP2movwf CCP2CON ; dans registre de commandebcf PIR2,CCP2IF ; effacer flag dinterruptionbsf STATUS,RP0 ; passer en banque 1bsf PIE2,CCP2IE ; rautoriser interruptions CCP2bcf STATUS,RP0 ; repasser en banque 0Ceci, bien entendu, ne concerne que le cas o vous utilisez les interruptions des modulesconcerns.Attention, CCP1IE se trouve dans PIE1, alors que CCP2IE se trouve dans PIE2. Mmeremarque pour CCP1IF qui se situe dans PIR1, alors que CCP2IF est dans PIR2.- Tout arrt du mode capture (changement de mode, ou arrt du module CCPx) provoqueleffacement du contenu du prdiviseur (les vnements dj compts sont perdus).- La modification du prdiviseur en cours de fonctionnement peut positionner le bit CCPxIFde faon non souhaite. Autrement dit, vous devez commencer par interdire lesinterruptions CCPx, comme expliqu ci-dessus.- Le contenu du prdiviseur nest pas effac lors de cette modification. Il est donc conseilldeffacer dabord CCPxCON avant de choisir le nouveau prdiviseur. Ainsi, le contenu decelui-ci sera effectivement effac.clrf CCPxCON ; arrt du module CCPxmovlw nouvelle_valeur ; nouveau prdiviseur et CCPx en servicemovwf CCPxCON ; modifier prdiviseur257- Dans le cas o la pin CCPx serait configure en sortie, ltablissement dun niveau surcette pin par logiciel serait interprt comme un niveau entrant, et pourrait donc gnrer laprise en compte dun vnement de capture, exactement comme si la modification deniveau sur la pin tait due un vnement extrieur. Ceci vous permet donc de crer descaptures pilotes par soft.20.4.4 Mode sleep et astuce dutilisationSi vous placez votre PIC en sommeil (sleep), votre timer 1 ne pourra plus compter,puisque le mode asynchrone nest pas autoris dans lutilisation des modules CCP. Cependantle prdiviseur fonctionne, lui, de faon asynchrone, et est donc dans la possibilit depositionner le flag CCPxIF.De ce fait, une interruption provoque par CCPx pourra rveiller votre PIC, bien que lamise jour des registres CCPRxH et CCPRxL ne se ralise pas dans ce cas.Vous pouvez penser que ceci ne sert donc rien, et vous avez en partie raison. Cependant,en rflchissant un peu, vous constatez que cette astuce vous permet en ralit de disposer de2 pins supplmentaires (CCP1 et CCP2) capables de vous gnrer des interruptions.Donc, si vous ne vous servez pas dun module CCP, mais que vous avez besoin duneentre dinterruption supplmentaire, rien ne vous interdit de configurer le module CCP devotre choix en mode capture pour disposer automatiquement de lentre dinterruptionCCPx correspondante. Il suffit alors dignorer le contenu des registres CCPRxH et CCPRxL.Bien videmment, vous pouvez galement utiliser simultanment les 2 entresdinterruption CCP1 et CCP2.Voici donc une astuce qui peut se rvler trs pratique, dautant que ces pins peuvent treconfigures en tenant compte dun prdiviseur ou du choix du sens de transition. Elles secomportent donc comme une RB0/INT amliore.20.5 Le mode compare Ce mode de fonctionnement est bas sur la correspondance de la valeur du timer 1(TMR1H/TMR1L) avec la valeur contenue dans CCPRxH/CCPRxL. Lgalit de ces valeursentranera les ractions souhaites.ATTENTION : Le rsultat dune galit ne crera leffet quau moment de lexcution ducycle suivant. Il y a donc toujours un retard de 1 cycle dinstruction entre la vrification delgalit, et laction qui en dcoule.Ceci explique toutes les expressions +1 dans les formules de calcul des diffrentstemps.Souvenez-vous quil en tait de mme pour le timer 2, pour lequel nous avionspositionnement du flag TMR2IF au moment o TMR2 passait de la valeur de PR2 0x00. Lereset de TMR2 intervenait donc bien le cycle suivant son galit avec PR2.258Les temps calculs de gnration dinterruption taient donc : contenu de PR2 + 1. Il ensera de mme pour le mode compare de nos modules CCPx. Tous ces retards sont dusau mode de fonctionnement synchrone des PICs.Certaines configurations de ce mode font intervenir la pin CCPx en tant que sortie. Vousdevrez donc dans ce cas configurer cette pin en sortie en effaant le bit de TRISCcorrespondant.20.5.1 Principe de fonctionnementComme je viens de lexpliquer, lgalit entre les registres du timer 1 (TMR1H/TMR1L)et la valeur de consigne fixe par les registres CCPRxH/CCPRxL entrane une ou plusieursactions en fonction du mode choisi.Si nous prenons le mode dfinit par les bits CCPxM3 CCPxM0 configurs 1010 ,nous aurons le fonctionnement suivant :- Quand le contenu du mot de 16 bits form par TMR1H/TMR1L atteint celui form parCCPRxH/CCPRxL, le flag CCPxIF est positionn ds le cycle suivant. Une interruption aventuellement lieu si elle a t pralablement configureAttention, le timer 1 ne dborde pas (ne repasse pas 0x0000), il continue de compternormalement. La prochaine correspondance entranera donc une nouvelle interruption 65536cycles plus tard (si on na pas modifi les registres concerns entre-temps).Nous ne sommes donc pas en prsence dun fonctionnement semblable celui du timer 2,pour lequel le dpassement de la valeur entranait automatiquement la remise 0 de celui-ci.Voici un graphique qui prsente lvolution du contenu de TMR1 (TMR1H/TMR1L) enfonction du temps, et le positionnement de CCPxIF en fonction de CCPRx(CCPRxH/CCPxL). Attention, vu lchelle utilise, le temps dun cycle nest pasreprsentable. Noubliez pas que les actions seffectuent toujours le cycle suivant lacomparaison.259Autour de ce fonctionnement de base, encore appel mode software , nous avons 3variantes.La combinaison 1000 des bits CCPxM3 CCPxM0, condition que la pin CCPxcorrespondante soit place en sortie via TRISC, induit le fonctionnement THEORIQUEsuivant :- Au moment de la configuration de CCPxCON, la sortie CCPx est force automatiquement 0 , indpendamment du contenu prcdemment plac dans PORTC par le programme- Le timer 1 compte. Au cycle suivant la correspondance des valeurs du TMR1 et deconsigne, le flag CCPRxIF est positionn, une interruption a ventuellement lieu.- La pin CCPx passe 1 automatiquement, et y reste jusqu sa modification par leprogramme, ou par une modification de CCPxCONLa courbe CCPx commence linstant de la programmation de CCPxCON. Avant cetinstant, son niveau peut tre quelconque (1 ou 0).La dure du signal utile (ici, la dure de ltat bas) de notre pin CCPx sera :T = (CCPRx + 1) * 4 * Tosc * prdiviseurLa combinaison 1001 des bits CCPxM3 CCPxM0 induit un fonctionnementsemblable, except que les niveaux sur CCPx sont inverss :- Au moment de la configuration de CCPxCON, la sortie CCPx est force automatiquement 1 , indpendamment du contenu prcdemment plac dans PORTC par le programme- Le timer 1 compte. Au cycle suivant la correspondance des valeurs du TMR1 et deconsigne, le flag CCPRxIF est positionn, une interruption a ventuellement lieu.- La pin CCPx passe 0 automatiquement, et y reste jusqu sa modification par leprogramme, ou par une modification de CCPxCON260ATTENTION : le fonctionnement rellement observ est le suivant : la pin CCPx NESTPAS positionne automatiquement sur la valeur inverse de celle obtenue au moment de lacomparaison. En fait, nous devrons trouver une astuce pour forcer cette pin manuellement son niveau de dpart. Je vous encourage donc lire la mthode que jai imagine et utilisedans le second exercice. Jai interrog Microchip au sujet de cette discordance entre datasheet mid-range et fonctionnement rel. La rponse que les responsables techniques montdonne est que les datasheets ont t crits avant la sortie du 16F876, et que ce dernier necorrespond pas, ce niveau, aux caractristiques annonces. Comprenez : Il sagit dunbug .Jen profite pour un apart : Ce nest pas parce que quelquun sens reprsenter larfrence dit ou crit quelque chose, que ceci doit faire office de vrit toute puissante et nonvrifie. Tout le monde peut faire des erreurs (de bonne ou de mauvaise foi), vous detoujours vous interroger sur la validit des messages reus et prmchs (je penseprincipalement aux informations souvent orientes reues via les media).Reste une dernire variante notre option de base, lorsquon configure nos bits decontrle CCPxM3 CCPxM0 avec la valeur 1011 . Dans ce mode, la pin CCPx resteinchange, mais nous gnrons un signal trigger qui permet de commanderautomatiquement un ou deux vnements supplmentaires.Le trigger en question provoque, sur les 2 modules CCP, le reset automatique du timer 1.Donc, ceci nous ramne exactement au fonctionnement du timer 2, mais sur 16 bits :- Le cycle suivant lgalit des registres TMR1H/TMR1L avec la valeur de consigneCCPRxH/CCPRxL, le timer 1 est remis 0 (il dborde sur la valeur fixe parCCPRxH/CCPRxL)- Au moment du dbordement, le flag CCPxIF est positionn, et une interruption a lieu sielle a t configure.Notez dj que le dbordement provoqu par le module CCP ninduit pas lepositionnement du flag TMR1IF, SAUF si la valeur place dans CCPRxH/CCPRxL tait2610xFFFF. Dans ce dernier cas, le positionnement des 2 flags CCPxIF et TMR1IF serasimultan.Mais le trigger provoque une seconde action, uniquement pour le module CCP2. Pour cemodule, en mme temps que les vnements prcdemment cits, le bit GO du registreADCON0 sera automatiquement positionn, lanant la conversion (si le convertisseur A/Dtait en service, bien entendu).Donc, si vous avez compris, et que vous voulez utiliser votre timer 1 avec une valeur decomparaison (comme pour le timer 2), vous utiliserez le module CCP1 ou CCP2 en modecompare avec trigger, et vous serez prvenu (avec interruption ventuelle) de la fin de ladure par le positionnement de CCP1IF ou CCP2IF, et non par TMR1IF.Le temps de cycle induit par ce mode de fonctionnement, sera donc, en toute logique :T = (CCPRxHL + 1) * Tcy * prdiviseurOu encore :T = (CCPRxHL + 1) * 4 * Tosc * prdiviseurAvec CCPRxHL le nombre de 16 bits form par la combinaison de CCPRxH et CCPRxLPour rsumer les diffrentes possibilits du mode compare , on peut dire :- Ce mode est bas sur la comparaison du contenu du timer 1 avec une valeur de consigne.- Le cycle suivant lgalit de ces registres, le flag CCPxIF est positionn- De plus il est possible simultanment (mais non obligatoire), :- Soit de forcer la sortie CCPx 0 ou 1- Soit de remettre 0 le timer 1, de faon provoquer un phnomne de dbordementpour le module CCP1262- Soit, pour le module CCP2, de resetter le timer 1 ET de lancer la conversion A/D si leconvertisseur tait en service. Nous verrons lutilisation pratique de cette fonction dansnos exercices de fin de chapitre.Vous voyez donc que vous disposez de toute une panoplie de nouvelles fonctions lies autimers 1.Voici le schma-bloc du module CCP2 :Le module CCP1 est identique, except quil ne dispose pas de la possibilit depositionner le bit GO du registre ADCON020.5.2 Champs dapplicationDe nouveau, toutes ces possibilits nous ouvrent la voie de nouvelles mises en uvre denos applications.Le mode software pourra tre utilis pour signaler quun temps tabli de faon prcise(comptage sur 16 bits) a t atteint, ou quune quantit dvnements comptabilise par letimer 1 a galement t atteint. Donc, en gnral, pour toute occurrence unique dun comptageparticulier.La modification de la sortie CCPx permet de fournir un signal qui intervient un tempsprcis aprs le dmarrage du timer, ou qui dure un temps prcis, ou encore de fournir unsignal de sortie aprs comptabilisation dun nombre dtermin dvnements reus par letimer 1. Lavantage de cette mthode est quelle nintroduit pas de retard de raction d autraitement logiciel de loccurrence constate. Nous verrons un exemple pratique de cettepossibilit.Le trigger permet bien videmment de transformer le timer 1 en un timer grandeflexibilit. Ce mode permet de fait de disposer de lavantage de la flexibilit du timer 2, enconservant un comptage sur 16 bits. Ce mode devrait pouvoir vous tirer de toutes lessituations de mesure de temps et dvnements que vous rencontrerez.Le trigger du module CCP2, appliqu au convertisseur analogique/numrique permet defaciliter grandement la mthode de numrisation.263Je dveloppe un peu ce dernier point. La mthode dchantillonnage utilise sur les PICsimplique les oprations suivantes :- On dmarre le convertisseur et on slectionne le canal- On attends le temps Tacq de charge du condensateur- On lance la conversion.Ces tapes peuvent tre transformes, en utilisant le mode trigger du module comparateur :- On dmarre le convertisseur et on slectionne le canal- On programme le temps Tacq dans le module CCP2.Une fois le temps Tacq termin, le module CCP2 se chargera lui-mme de dmarrer laconversion. Vous navez donc plus vous charger de dtecter, par interruption ou par pooling,la fin de la dure Tacq.20.5.3 Remarques et limites dutilisationDe nouveau, jattire votre attention sur certains points de ce mode de fonctionnement :- Le module CCPx en mode compare ne peut fonctionner que si le timer 1 fonctionne enmode timer ou en mode compteur synchrone . Le fonctionnement en mode compteur asynchrone ne permet pas le fonctionnement de ce module.- Lutilisation de la pin CCPx dans ce mode nest possible quaprs avoir configur la pinconcerne en sortie, en effaant le bit du registre TRISC correspondant- Il nest pas possible de mlanger les modes de fonctionnement du mode compare . Parexemple, il est impossible dobtenir le positionnement de la pin CCPx et dutilisersimultanment le trigger.20.5.4 Le mode sleep Le timer 1 configur en timer ou en compteur synchrone ne peut compter si le PICest plac en mode sommeil. Donc, il ny a aucune chance dans ces conditions que lacorrespondance de valeurs entre TMR1H/TMR1L et CCPRxH/CCPRxL intervienne.Comme la suite des vnements dpend de cette occurrence, le mode compare estdonc inutilisable durant la mise en sommeil du PIC.Lorsque le PIC se rveille, suite un autre vnement, le fonctionnement se poursuit o ilavait t arrt.Si une pin CCPx est utilise comme sortie du module, le mode sleep maintient cettepin dans ltat actuel.26420.5.5 Fonctionnement non conformeJe rappelle ici la remarque que jai prcdemment faite lors de ltude thorique du modecompare avec pilotage de la pin CCPx :Attention, ce qui suit concerne exclusivement les modles de 16F87x disponibles aumoment de la ralisation de cet ouvrage. Il vous appartiendra, si vous voulez vous assurerdune ventuelle correction, de vous renseigner sur le site de Microchip, ou de tenter vous-mme lexprience avec les PICs en votre possession.Le datasheet des pics mid-range de Microchip est trs clair : si on inscrit la valeur B00001001 dans le registre CCP1CON, la sortie CCP1 (si elle est configure en sortie)doit passer instantanment 1 .En fait, il nen nest rien. Si le module CCP force effectivement cette pin 0 une foisla comparaison entre CCPR1HL et TMRHL ralise, par contre lcriture dune valeur dansCCP1CON ne permet pas sa remise 1 instantane.Il est possible que Microchip corrige ce problme dans les futures versions du 16F876.Dans le cas contraire, voyez lexercice 2 de pilotage de servomoteur dans lequel je donne unemthode maison pour corriger ce phnomne.Autre remarque : Microchip indique que lutilisation dun module CCP utilis en mode compare en mme temps quun module utilis en mode capture , ou de 2 modules CCPutiliss en mode compare , est soumis la contrainte suivante :Chacun des modules compare prcdemment impliqus devra tre utilis exclusivementen mode compare avec trigger . Non seulement jai trouv ceci illogique (car le premierreset empche le second dtre excut), mais, de plus, les essais que jai raliss dmontrentque ce nest pas du tout le cas. Je nai donc pas retenu cette contrainte, preuve en est que lesecond exercice utilise 2 modules CCP en mode compare, dont un seul est utilis avec trigger.De nouveau, en cas de nouvelle version de 16F87x , vous de vrifier si cefonctionnement reste constant (pour ma part, je pense que oui)Mes propres conclusions (qui nengagent donc que moi) sont les suivantes :- La premire erreur est un bug prsent dans les 16F87x, preuve en est le nombre decorrections sur le mme sujet prsentes sur le site Microchip pour toute une srie dautresPICs.- La seconde erreur est une erreur dans les datasheets, le fonctionnement des PICs semblebeaucoup plus logique que la contrainte impose par les datasheets. En effet, lutilisation,par exemple, de 2 modules CCP en mode compare avec trigger na pas le moindresens (un reset du timer1 empche lautre module CCP datteindre sa valeur decomparaison).26520.6 Le mode PWM Nous voici dans la partie la plus dlicate des possibilits des modules CCP. Non que lesprincipes soient compliqus, mais plutt quil nest pas simple de les expliquer de faon claireet concise quel que soit le niveau du lecteur.Je vais donc tenter de faire de mon mieux, mais cela ncessitera un peu de thorie (commedhabitude, allez-vous me dire). Et oui, les 16F87x sont des PICs de pros qui ncessitentplus de cette thorie indispensable pour exploiter correctement toutes les fonctions que le petit16F84.Notez que si vous tes dj un vrai pro , ceci doit vous embter, mais il faut bienpenser tout le monde, non ? Et puis, un peu de lecture, a ne fait de tort personne.20.6.1 La thorie du PWM PWM signifie Pulse Width Modulation , ce quon pourrait traduire par modulation delargeur dimpulsion.En somme, il sagit dun signal binaire de frquence fixe dont le rapport cyclique peut tremodul par logiciel.Etant donn quun signal binaire na plus de secret pour vous, vous savez donc quil sagitdun signal qui peut prendre 2 tats. Notre module PWM utilisera une pin de notre PICconfigure en sortie.Il me faut aborder la notion de rapport cyclique, la modulation tant simplementlexpression du fait que celui-ci peut tre modifi en permanence.Le rapport cyclique dun signal binaire frquence fixe peut tre dfini comme tant lerapport entre le temps o il se trouve ltat 1 par rapport au temps total dun cycle. Uncycle ntant constitu, par dfinition, que dun tat 1 suivi dun tat 0 , la somme destemps des 2 tats tant constante.Notez donc quil y a 2 paramtres qui dfinissent un signal PWM :- La dure dun cycle complet (ou, par dduction, sa frquence de rptition)- Le rapport cycliqueDonc, si on pose :- Tc = Dure dun cycle- Rc le rapport cyclique- Th = dure de ltat haut- Tb = dure de ltat bas, on peut dire :266- Tc = Th + Tb (Dure dun cycle en secondes = dure de ltat haut + dure de ltat bas)- Frquence du signal (en hertz) = 1/Tc- Rc = Th / Tc (rapport cyclique en % = temps ltat haut divis par le temps de cycle)Je vais donc commencer par illustrer, de faon claire, quelques exemples de signaux de cetype.Exemple dun signal PWM avec un rapport cyclique de 50% :Vous voyez que ce signal est effectivement de frquence fixe, puisque chaque temps Tcest identique.Le temps Th est identique au temps Tb, ce qui donne bien un rapport cyclique de 50%,puisque Rc = Th / Tc = Th / (Tb + Th) = Th / (2 Th) = = 50%Un tel signal sappelle signal carr. Cest un cas particulier dun signal PWM.Exemple dun signal PWM avec un rapport cyclique de 10% :Vous pouvez constater que ce signal possde strictement le mme temps de cycle Tc quele prcdent. Sa frquence est donc identique.Cependant, son rapport cyclique a t modifi. Th reprsente maintenant 10% du temps decycle total, alors que Tb reprsente 90%267Voyons maintenant un rapport cyclique de 90% :De nouveau, le temps Tc est inchang, seul le rapport cyclique a t modifi. Le temps Thdure maintenant 90% du temps Tc, Tb occupant fort logiquement les 10% restants.Reste maintenant voir les 2 cas particuliers restants, savoir le rapport cyclique de 0%,et celui de 100%.Fort logiquement, un signal avec un rapport cyclique de 0% est un signal dont le temps ltat haut occupe 0% du temps total. Cest donc un signal qui est constamment ltat bas.De mme, un signal avec un rapport cyclique de 100% est un signal qui est constamment ltat haut.Cependant, si vous dessinez de temps signaux, vous constatez quil vous est impossibledindiquer le temps Tc, donc sa frquence. Et, de fait, ce signal ne variant plus, nest plus unsignal priodique au sens lectronique du terme (les mathmaticiens vont me sortir des tempsinfinis, mais cela ne correspond pas la ralit lectronique).Le rapport cyclique dun signal PWM doit donc tre suprieur 0% et infrieur 100%.Voici une partie de la thorie aborde, vous avez maintenant compris que le module PWMde notre PIC permet de crer un signal priodique dont il est possible de faire varier (moduler)le rapport cyclique.20.6.2 La thorie applique aux PICsNous avons vu que nous avons besoin de 2 choses pour crer notre signal. Dune part, letemps TC, qui dtermine la frquence (fixe) de notre signal, et dautre part le rapport cyclique(variable) de ce dernier.Concernant le rapport cyclique, les PICs influencent plutt un autre paramtre, cest--direle temps Th.Les 2 valeurs utilises dans la programmation seront donc Tc et Th. Si vous avez besoindune autre valeur (Rc), il vous suffit de la tirer des formules simples prcdentes.268Nous allons maintenant tudier la faon de grer le premier paramtre, savoir le tempsTc.Ce temps est dfini tout simplement par le timer 2. Vous programmez ventuellement leprdiviseur, vous chargez la valeur adquate dans PR2, et le temps mis par votre TMR2 pourdborder vous donne votre temps TC.Dj une remarque trs importante :Le postdiviseur nest pas utilis dans le module PWM. Donc nintervient pas dans lecalcul de Tc.Ceci implique galement que vous pouvez utiliser votre timer 2 en tant que gnrateurpour le module PWM, et, grce au postdiviseur, travailler avec un autre temps (multiple dupremier) dans le reste de votre programme.Pour faire simple, avec le mme timer TMR2, avec Tcy = dure dun cycle dinstruction,et en vous souvenant de la formule donne au moment de ltude du timer 2 :- Temps du cycle utilis pour le module PWM : Tc = (Tcy * prdiviseur) (PR2 + 1)- Temps du timer2 utilis classiquement dans le programme =Tc = (Tcy * prdiviseur * postdiviseur) (PR2 + 1)Inconvnient : il ne sera pas possible dobtenir des temps longs avec notre module PWM.Celui-ci est donc prvu pour travailler avec des frquences relativement importantes.Nous avons dj parl du timer 2 dans son emploi classique, ce qui nous intresse donc iciest la premire formule utilise dans le module PWM.Le module PWM travaille avec le timer 2, et au niveau de Tcy de la faon suivante :- Vous entrez votre valeur de dbordement dans PR2- A chaque fois que TMR2 dborde de PR2 0x00, la pin CCPx passe au niveau 1.Donc, si nous reprenons un signal PWM quelconque, nous avons dj :269Comme vous constatez, nous avons dtermin lemplacement de monte du signal de 0 1 . Or, comme le temps Tc est le temps sparant 2 montes successives du signal(ou 2 descentes), nous avons dfini Tc. Pour rappel :TC = (PR2 + 1) * Tcy * prdiviseurOu encoreTc = (PR2 + 1) * 4 * Tosc * prdiviseurEn effet, un cycle dinstruction vaut 4 cycles doscillateur.Reste donc dfinir lemplacement de redescente de notre signal pour obtenir notre signalcomplet.Ce quil nous faudrait, cest un deuxime registre PR2 , qui nous indiquerait, aumoment o TMR2 atteindrait cette valeur, que le signal doit retomber 0 . Et bien, cest cequi est implment, en gros, dans notre PIC.Je vais commencer par le principe gnral, et je vais me rapprocher au fur et mesure delexpos de la situation relle. Le principe va donc tre le suivant :Le Timer 2 compte : on imagine que le signal CCP vaut actuellement 0 :- TMR2 arrive la valeur de PR2- Au cycle suivant, TMR2 repasse 0 , CCPx passe 1 - TMR2 arrive la seconde valeur de consigne, CCPx passe 0 - TMR2 arrive la valeur de PR2- Au cycle suivant, TMR2 = 0, CCPx vaut 1 - TMR2 arrive la seconde valeur de consigne, CCPx passe 0 - Et ainsi de suiteCeci vous donne la reprsentation suivante :Vous pouvez immdiatement faire la constatation suivante :270Pour que le systme fonctionne, la valeur inscrite en tant que seconde rfrence doit treinfrieure celle de (PR2+1), sans quoi TMR2 natteindrait jamais cette valeur. De plus, cettevaleur, contrairement PR2 ne doit pas provoquer le reset du timer, sans quoi il lui seraitimpossible datteindre la valeur de PR2.Quelle sera donc notre marge de manuvre, et de ce fait la prcision obtenue ?Et bien, elle dpendra de la valeur inscrite dans le registre PR2. Plus cette valeur estfaible, moins nous avons le choix des valeurs inscrire en tant que seconde rfrence, cettedernire devant rester infrieure PR2 et suprieure 0.Or PR2 dpend du calcul de notre temps Tc. Nous ne pouvons donc pas y mettre ce quenous voulons pour notre application pratique, moins de dcider de choisir le quartz le mieuxadapt notre application.Supposons donc que notre PR2 contienne la valeur dcimale D50. Pour faire varier notrerapport cyclique de 0 100%, nous ne pouvons mettre que des valeurs de D0 D50. Donc,nous ne pouvons rgler notre rapport cyclique quavec une prcision de 1/50me, soit 2%.Dans la plupart des applications, cette prcision risque dtre insuffisante. Cest pourquoiMicrochip vient une fois de plus notre secours.Comme nous ne pouvons pas augmenter la valeur de rfrence, nous allons simplement yajouter des dcimales , ceci affinera notre possibilit de rglage, et donc la prcision finaleobtenue dans les mmes proportions.Notez que le terme dcimal est impropre dans ce cas puisque nous sommes en systmebinaire, et non dcimal. Mais jai trouv limage plus parlante . Par la suite, je parlerai denombres fractionnaires.Il a t dcid, pour nos PICs, dajouter 2 dcimales binaires notre compteur TMR2.Ce compteur se prsentera donc comme tant de la forme :b7 b6 b5 b4 b3 b2 b1 b0 ,b-1 b-2Ceci formant un nombre de 10 bits effectifs, et donc multiplie la prcision par 4. Bienentendu, pour que a serve quelque chose, notre seconde valeur de comparaison disposeragalement de ces 2 digits supplmentaires.Maintenant, que reprsentent ces digits aprs la virgule ? Cest simple. Tout comme lepremier chiffre aprs la virgule dun nombre dcimal reprsente des multiples de 1/10 (10-1),le second des multiples de 1/100(10-2), le premier bit aprs la virgule reprsente des multiplesde (2-1), le second des multiples de (2-2)Nos chiffres b-1 b-2 reprsentent donc le nombre de du temps dincrmentation de notreTMR2. Donc, en toute bonne logique :- Avec un prdiviseur de 1, la prcision est de Tcy / 4, soit Tosc- Avec un prdiviseur de 4, la prcision est de Tcy, soit 4 Tosc- Avec un prdiviseur de 16, la prcision est de 4 * Tcy, soit 16 Tosc271Comme notre PR2, et donc le temps Tc continue de fonctionner, lui, sur 8 bits, notre cyclese droule donc de la faon suivante :Le Timer 2 compte : on imagine que le signal CCP vaut actuellement 0 - TMR2 (8 bits) arrive la valeur de PR2 (8 bits)- Au cycle suivant, TMR2 repasse 0 , CCPx passe 1 - TMR2 + 2 dcimales atteint la seconde valeur de consigne (8 bits + 2 dcimales ),CCPx passe 0 , le timer 2 continue de compter.- TMR2 (8 bits) arrive la valeur de PR2 (8 bits)- Au cycle suivant, TMR2 = 0, CCPx vaut 1 , et ainsi de suiteJe sais que a peut paratre ardu, mais si vous avez compris ce qui prcde, alors vousnaurez aucun problme pour la suite.Voici dailleurs reprsent sous forme dun graphique, la chronologie des vnements enfonction du contenu du registre TMR2 du timer 2 :Faites attention aux datasheets de Microchip, ils ne parlent pas de nombres fractionnaires,ils parlent de nombres de type b9 b8 .. b0. Noubliez pas quen fait, exprims de la sorte,ces valeurs sur 10 bits concernant le module PWM reprsentent des quarts de valeurs entires.La prcision obtenue pour le rglage du rapport cyclique dpend de la valeur inscrite dansPR2, complte par les 2 digits fractionnaires ajouts.Un exemple :272Avec un PIC cadenc 20MHz, et une frquence de votre signal PWM de 78,125Khz :Le temps Tc vaut : 1/78,125 Khz = 12,8 sTc = (PR2 + 1) * Prdiviseur * 4 * ToscTosc = 1/20MHz = 50 nsPR2 = (TC / (prdiviseur * 4 * Tosc) 1PR2 = (12,8s / 200ns) 1 = 64 1 = 63 (avec prdiviseur = 1)Donc, on placera 63 dans notre registre PR2Il sera alors possible dajuster notre rapport cyclique sur des valeurs comprises entreB00000000,00 et B 00111111,11 , soit 256 valeurs diffrentes, donc une prcision sur 8bits, ou encore une marge derreur de 0,4%.En somme, la prcision vaut 1 / ((PR2+1) * 4), et est donc en toute logique multiplie par4 par rapport une comparaison sans utiliser de fractions (sur 8 bits).Il reste prciser un point. Les signaux PWM sont en gnral utiliss, comme leur nomlindique, pour moduler le rapport cyclique dun signal, et donc pour faire variercontinuellement celui-ci en fonction des rsultats obtenir.Comme il faut intervenir sur des valeurs de consigne de 10 bits, lcriture ne pourra pas sefaire en une seule fois, et donc pourra provoquer une valeur temporaire indsirable. Cephnomne est appel glitch .Mais, de nouveau, Microchip nous fourni une solution, en utilisant un registreintermdiaire qui servira de valeur de comparaison, et qui sera charg au moment dudbordement de TMR2.La procdure exacte est donc la suivante :- Le Timer 2 compte : on imagine que le signal CCP vaut actuellement 0 - TMR2 arrive la valeur de PR2- Au cycle suivant, TMR2 repasse 0 , CCPx passe 1 - En mme temps, la valeur programme comme consigne par lutilisateur est copie dansle registre final de comparaison.- TMR2 arrive la valeur de la copie de la seconde valeur de consigne, CCPx passe 0 - TMR2 arrive la valeur de PR2- Au cycle suivant, TMR2 = 0, CCPx vaut 1 , et ainsi de suiteDonc, vous en dduirez que toute modification de la valeur de comparaison, et donc de ladure de Th ne sera effective qu partir du cycle suivant celui actuellement en cours.On conclut cette partie fortement thorique en rsumant les formules qui seront utiles.Tout dabord le calcul de PR2, qui fixe le temps total de cycle Tc :273PR2 = (TC / (prdiviseur * 4 * Tosc) 1Ensuite, la formule qui lie les 10 bits de notre second comparateur, sachant que ces 10 bits(COMPAR) expriment un multiple de quarts de cycles dinstructions, donc un multiple detemps doscillateur, avec le temps du signal ltat haut (Th).Th = COMPAR * prdiviseur * Tosc.Donc,COMPAR = Th / (prdiviseur * Tosc)On peut galement dire, en fonction du rapport cyclique (Rc), queTh = Tc * RcIl faut encore rappeler que pour comparer TMR2 avec COMPAR cod sur 10 bits, il fautque TMR2 soit galement cod sur 10 bits. Il faut donc complter TMR2 avec 2 bits quireprsentent les quarts de cycle dinstruction.En fait, tout se passe trs simplement. Si vous choisissez un prdiviseur de 1, TMR2 seracomplt, en interne, par le numro (de 0 3) du temps Tosc en cours.Si, vous utilisez un prdiviseur de 4, ce nombre sera complt par le nombredvnements dj comptabiliss par le prdiviseur (de 0 3).Si, par contre, vous utilisez un prdiviseur de 16, ce nombre sera complt par le nombrede multiples de 4 vnements dj comptabiliss par le prdiviseur.De cette faon, TMR2 sera bien complt avec 2 bits qui reprsentent des quarts devaleur. Inutile donc de vous en proccuper, cest llectronique interne qui sen charge, mais,au moins, comme a, vous le savez.20.6.3 Les registres utilissNous voici dbarrass de la thorie pure, passons maintenant un peu de concret.Nous avons besoin de plusieurs registres pour programmer toutes ces valeurs. En fait,nous les avons dj tous rencontrs, ne reste donc qu expliquer leur rle dans ce modeparticulier.Nous avons besoin dune valeur de dbordement pour notre timer 2, cette valeur se trouve,comme je lai dj dit dans le registre PR2. Cest donc une valeur sur 8 bits.La valeur de la seconde comparaison (celle qui fait passer la sortie de 1 0) est une valeurde 8 bits complte de 2 bits fractionnaires.Le nombre entier sera inscrit dans le registre CCPRxL. Les 2 bits fractionnaires quicompltent ce nombre sont les bits DCxB1 et DCxB0 du registre CCPxCON.274Comme nous lavons vu, ce nombre de 10 bits sera copi en interne par le PIC vers unautre registre, qui sera le registre CCPRxH complt de 2 bits internes non accessibles. Notezquen mode PWM , il vous est impossible dcrire dans ce registre. Vous navez donc pas,en fait, vous en proccuper, le PIC sen charge.Pour lancer le mode PWM , nous devons donc procder aux initialisationssuivantes :1) On initialise PR2 en fonction de la dure totale du cycle (Tc):PR2 = (TC / (prdiviseur * 4 * Tosc) 12) On calcule la valeur de comparaison DCB en valeur fractionnaire suivant la formule :DCB = Th / (prdiviseur * Tosc)On place les bits 9 2 dans CCPRxL (valeur entire), les bits 1 et 0 (fraction) tantpositionns dans DCxB1 et DCxB0 du registre CCPxCON3) On place la pin CCPx en sortie en configurant TRISC4) On lance le timer 2 en programmant son prdiviseur5) On configure CCPxCON pour travailler en mode PWM .Vous voyez quaprs avoir ingurgit toute la thorie, la mthode vous semble simple, etcest le cas. Je vous donne le schma-bloc simplifi du module PWM :275Je commente un peu. Vous voyez en dessous le fonctionnement normal de notre timer 2,qui dborde sur PR2 grce au comparateur 8 bits. Ceci entrane en mme temps la recopie des10 bits de CCPRxL/DCxB1/DCxB0 vers CCPRxH/2 bits internes.Au mme moment, la sortie est force 1 via la bascule et ltage de sortie, valid parle registre TRISC. Pour information, le fonctionnement de la bascule est simple : uneimpulsion sur lentre set , force la sortie 1 , tandis quune impulsion sur lentre reset force cette mme sortie 0 . Entre les 2 impulsions, la sortie ne change pas dtat.Quand la valeur TMR2, complte par 2 dcimales devient identique la valeur qui at copie dans CCPRxH, la sortie est force 0 . Vous voyez, rien de magique, celadevrait commencer devenir clair.20.6.4 Champs dapplicationEn fait, vous utiliserez ce module chaque fois que vous aurez besoin dun signal defrquence fixe, mais de rapport cyclique variable.Citons par exemple lexemple typique du pilotage dun servomoteur utilis en modlisme(jy reviendrai pour lexercice pratique), ou la variation de vitesse dun moteur courantcontinu (modlisme), et bien dautres applications.20.6.5 Remarques et limites dutilisationPour que tout fonctionne comme prvu, il faut veiller respecter certaines contraintes,auxquelles jai dj fait allusion. Un rappel ne fait cependant pas de tort :La valeur de rfrence encode dans CCPRxL ne peut tre suprieure la valeur contenuedans PR incrmente de 1. Dans le cas contraire, le signal ne pourrait jamais atteindre cetteconsigne, et la pin CCPx resterait bloque au niveau haut (rapport cyclique > 100%)Il est possible dutiliser le timer 2 la fois comme timer classique et comme gnrateurpour le module PWM. Dans ce cas, prdiviseur et valeur de PR2 seront forcment identiques.Par contre, comme le postdiviseur nest pas utilis dans le module PWM, il reste possibledobtenir des temps de timer multiples du temps utilis dans le module PWM.Le registre CCPRxH nest pas accessible en criture lors du fonctionnement en modePWM.La prise en compte du changement de valeur du rapport cyclique ne se fera quaprs la findu cycle en cours.20.6.6 Le mode sleep La mise en sommeil du PIC provoque larrt du timer 2. Le module PWM ne pourradonc pas continuer de fonctionner dans ces conditions.276La pin CCPx maintiendra la tension quelle dlivrait au moment du passage en sommeildu PIC.Au rveil de celui-ci par un vnement dclencheur, le cycle se poursuivra lendroit o ilavait t arrt.20.7 Exercice pratique : commande dun servomoteur par le PWMEnfin, une application concrte. Jai choisi de vous faire raliser le pilotage dunservomoteur de modlisme, dont la position sera tributaire de la position dun potentiomtrede rglage.De cette faon, sous allons mettre en uvre dans un premier temps :- Le fonctionnement PWM du module CCP- Lutilisation du mode compare avec trigger du module CCP pour lancer la conversionA/D- La mthode efficace dutilisation du convertisseur A/DVoyons tout dabord les contraintes. Un module en mode PWM et un autre en mode compare ne pose aucun problme de contrainte. Mais le seul module capable de dmarrerle convertisseur A/D est le CCP2. Ceci nous impose donc dutiliser CCP1 pour le mode PWM , et donc, de fait, de piloter ce servomoteur via la pin CCP1/RC2Une fois de plus, programmation et lectronique devront tre tudis ensemble.Le potentiomtre nous envoie une valeur analogique. Nous navons pas besoin de tensionde rfrence externe. Le tableau de paramtrage de PCFG nous donne, pour une entreanalogique sans tension de rfrence :PCFG3 0AN4RA5AN3RA3AN2RA2AN1RA1AN0RA0Vref- Vref+A/D/R1110 D D D D A Vss Vdd 1/4/0Ceci nous impose lutilisation de AN0/RA0 comme pin dentre analogique.Vous voyez de nouveau que notre logiciel nous impose 2 contraintes matrielles. Plusvous utilisez les fonctions ddicaces des PICs, plus vous devez vous proccuper de votrelogiciel avant de pouvoir dessiner votre schma.Le schma, donc, sera du type :277Remarquez que votre servo dispose de 3 pins, dont 2 destines lalimentation, et unerecevant un signal de type PWM destin indiquer la position de consigne souhaite.Ce servo est sens fonctionner sous 5V, et avec un courant de commande IN infrieur 20mA. Dans le cas contraire, adaptez votre schma en consquence.Remarquez pour ceux qui ne disposent pas dun servo et qui dsirent raliser ce montage moindre cot, quils disposent dautres mthodes pour vrifier le fonctionnement correct dumontage :- Ceux qui ont un voltmtre aiguille peuvent placer ce dernier sur la pin RC2. La tensionmoyenne indique sera fonction du rapport cyclique fourni.- Ceux qui disposent dun oscilloscope peuvent placer celui-ci sur la pin RC2, ils pourrontvoir directement la forme des signaux obtenus.Reste maintenant tablir quels sont les signaux ncessaires notre servomoteur.278La commande dun servomoteur ncessite la fourniture dimpulsions sur sa broche decommande. Ces impulsions devront tre rptes un intervalle de temps infrieur 20ms. Lalargeur dimpulsion fournit langle de rotation du servomoteur par rapport sa positioncentrale (0) :Une impulsion de 1,5 ms gnre un angle de 0Une impulsion de 1ms gnre un angle de 90Une impulsion de 2ms gnre un angle de +90Nous voyons donc quen faisant varier la largeur dimpulsion entre 1 et 2 ms, nouspouvons obtenir nimporte quel angle de notre servomoteur sur une plage de 180.Faire varier une largeur dimpulsion, cest exactement dans les possibilits de notremodule PWM.Souvenez-vous quil nous faudra fixer le temps de cycle, la largeur du niveau haut tantdfinie par le servomoteur :Ce temps de cycle devra tre infrieur 20ms (impos par la norme utilise par lesservomoteurs) et suprieur 2ms (temps ltat haut maximum).Le temps entre 2 incrmentations de notre Timer 2 vaut : prdiviseur * Tcy. Ouprdiviseur * 4 * ToscAvec un prdiviseur de 1, nous pouvons obtenir une dure maximale de :Tc = 1 * 4 * Tosc * 256 (PR2 maxi + 1)= 51,2 s, ce qui est trop court.Avec un prdiviseur de 4, la dure maximale est de :Tc = 4 * 4 * 50ns * 256 = 204 s, ce qui est encore trop courtAvec un prdiviseur de 16, la dure maximale est de :Tc = 16 * 4 * 50ns * 256 = 819 s, ce qui reste trop court.279Et bien zut, a ne marche pas. Cest d au fait que notre postdiviseur est inactif pour letimer 2. Pourtant on voudrait bien pouvoir utiliser notre module PWM pour cette application.Reprenons donc notre formule :Tc = prdiviseur * 4 * Tosc * (PR2+1).Comme nous avons dj un prdiviseur et un PR2 leur valeur maximale, commentencore allonger TC maximum ? Tout simplement en augmentant Tosc.Tosc, le temps de loscillateur, dpend du quartz utilis pour cadencer notre PIC. Pourrappel : Tosc = 1/Fquartz.Donc, en remplaant, pour faire simple, notre quartz de 20Mhz, par celui de 4MHz quenous avons utilis pour notre PIC 16F84, et que vous devez donc, en bonne logique, possder,nous aurons :Tosc = 1 / 4Mhz = 0,25s.Dans ces conditions, notre Tc maximum devient :Tc maxi = 16 * 4 * 0,25s * 256 = 4096 s. = 4,096 msCette fois cest bon. Notez que je vous informe dj quavec ce type de signal, et lesdures trs longues mises en jeu, la mthode consistant utiliser le PWM est loin dtre lameilleure. Cest pourquoi je vous proposerai une mthode bien plus efficace. Mais le but decet exercice est de comprendre et de mettre en uvre les CCP en mode PWM et en mode compare avec trigger .Remplaons donc dans notre montage le quartz de 20 Mhz par celui de 4Mhz.Dans ce cas, nous mettrons la valeur 0xFF dans PR2, pour obtenir un temps TC gal 2,176ms.Notre valeur Th devra varier de 1 2 ms, ce qui correspondra des valeurs de : Th minimum = 1000s, donc CCPR1H minimum = 1000 / (16*4*0,25) = 62,5Th maximum = 2000s, donc CCPR1H maximum = 2000 / (16*4*0,25) = 125Donc, nous devrons transformer notre valeur de potentiomtre, qui varie de 0 1023, enune valeur qui varie de 0 62,5 (donc, 250 valeurs diffrentes). Ceci nous permettre de placerdans CCPR1L la valeur rsultant de :CCPR1L = 62,5 + valeur variable de 0 62,5 par pas de 1/4Notre potentiomtre permet, grce ses 10 bits, de gnrer 1024 valeurs diffrentes. Enconservant la plus proche puissance de 2 disponible de ce dont nous avons besoin (250valeurs), nous voyons que nous pouvons retenir 256 valeurs diffrentes.280Donc, nous conserverons 8 bits (256 valeurs) pour la valeur de notre potentiomtre, alorsque nous avons besoin de 250 valeurs. Nous rpartirons approximativement le surplus de partet dautre des limites, ce qui nous donnera :CCPR1L = 61,75 + (valeur potentiomtre sur 8 bits / 4)Soit une valeur minimale de 61,75 et une valeur maximale de 61,75 + (255/4) = 125,5Notre temps Th pourra donc varier de :Th min = 61,75 * 16 * 4 * 0,25s = 0,998 msThmax = 125,5 * 16 * 4 * 0,25s = 2,008 msNous avons donc bien gnr notre signal qui varie de 1 2 ms.Il faut maintenant se poser la question de la rsolution (prcision) obtenue. Cest trssimple :Dans lintervalle utile, nous avons 250 valeurs intermdiaires, donc notre prcision sera de180 degrs de rotation / 250 = 0,72 degrs. Nous pourrons donc positionner notreservomoteur avec une prcision de 0,72 degrs.Ceci correspond une variation minimale du temps de 1ms pour 180, soit (1ms / 180) *0,72 = 4s.Cette mme prcision, exprime en %, nous donne : 1/250 = 0,4 %Donc, pour rsumer tout ceci, on peut dire :- Nous mettrons 0xFF dans notre PR2, ce qui nous donne un temps Tc de 4,096ms- Nous chargerons la valeur de notre potentiomtre, de 0 1023- Nous conservons les 8 bits de poids fort (soit 6 bits entiers + 2 dcimales )- Nous ajoutons (en quarts de valeurs) (61,75 * 4), soit 247- Le rsultat tient alors sur 10 bits (en ralit le bit 9 vaudra toujours 0 dans ce cas)- Nous mettrons les 8 bits de poids fort comme partie entire dans CCPR1L- Nous mettrons les 2 bits de poids faible (quarts) dans CCP1X et CCP1YPour exemple, si notre potentiomtre vaut 0, on aura :- Valeur sur 10 bits = 00- On conserve les 8 bits de poids fort, soit B00000000- On ajoute 247, on obtient donc D247, soit B0011110111 sur 10 bits- On place B00111101 dans CCPR1L- On place B11 dans CCP1X/CCP1YDe la sorte, notre valeur minimale est de :281Partie entire = B00111101 = 61Partie fractionnaire (quarts) = B11 quarts = = 0,75Valeur complte = 61,75Si notre potentiomtre vaut 1023, on aura :- Valeur sur 10 bits = D1023 = B1111111111- On conserve les 8 bits de poids fort, soit B11111111, soit D255- On ajoute D247, on obtient donc D502, soit B0111110110 sur 10 bits- On place B01111101 dans CCPR1L- On place B10 dans CCP1X/CCP1YDe la sorte, notre valeur maximale est de :Partie entire = B01111101 = 125Partie fractionnaire = B10 = 2/4 = 0,5Valeur complte = 125,5Je sais que jai insist assez lourdement, et que jai effectu de nombreuses rptitions,mais jai prfr passer pour un radoteur plutt que de vous laisser dans lhsitationconcernant certaines procdures. Que ceux qui ont compris du premier coup veuillent bienmexcuser.Nous avons parfaitement rgl le problme de notre module CCP1, configur en PWM , occupons-nous maintenant de notre module CCP2, configur en compare avectrigger .Aprs le temps Tacq, la conversion A/D dmarrera automatiquement (du fait du trigger),et gnrera une interruption aprs un temps de 12 Tad.Grce au tableau que je vous ai fourni dans le chapitre sur le convertisseur A/D, vousconstatez que, pour un PIC 4Mhz, vous devez choisir un prdiviseur du convertisseur = 8,ce qui vous donne un temps Tad = 2s. Le temps d chantillonnage prendra donc 12 * 2s =24 s.Le temps Tacq est de minimum 20s, si on ne veut pas se casser la tte calculer.Donc, une conversion complte, avec son acquisition, durera donc 20s + 24s = 44 s.Nous avons besoin de la valeur du potentiomtre au maximum une fois par cycle PWM . Inutile en effet de remettre jour plusieurs fois CCPR1L durant le mme cycle, ilnest de toute faon transfr dans CCPR1H qu la fin du cycle en cours.A cela il faut ajouter 2 TAD avant lacquisition suivante, soit 44s + 4s = 48 s sparantau minimum 2 acquisitions.Ce cycle PWM dure 4096s, ce qui nous laisse le temps deffectuer :4096 / 48 = 85 mesures dans lintervalle.282Nous allons profiter de cette opportunit, tout en nous montrant plus modeste, eneffectuant 16 mesures dans cet intervalle. De cette faon, nous pourrons limiter linfluencedun parasite. Ceci nous donne un temps sparant 2 chantillonnages de 4096 s/ 16 = 256 s.Comme notre temps dchantillonnage est fixe (12 TAD), nous allons allonger le tempssparant le dbut de lacquisition du dbut de la conversion. Ceci revient en fait allonger letemps dacquisition.Ce nouveau temps sera donc de : 256s 24s = 232s. Le temps sparant 2 dmarragesdchantillonnage successifs sera lui de 256s, puisque durant le temps de conversion, letimer1 continue de compter.Je vous donne la chronologie des vnements avec ce petit graphique :Vous voyez quune fois lanc, vous ne vous occupez plus de rien, vous serez prvenu parune interruption chaque fois quune nouvelle valeur du potentiomtre sera disponible.Nous allons donc configurer notre timer 1 avec un temps de dbordement de 256s.Nous allons utiliser le temps de charge de notre condensateur (temps dacquisition) Tacqde 220s.Nous placerons donc dans CCPR1H/CCPR1L la valeur 16 bits tire de la formule : Temps de cycle du timer 1 = (CCPR2HL + 1) * 4 * Tosc * prdiviseur = 256sSoit, avec un prdiviseur de 1 :CCPR2HL = (256 / (4 * Tosc) 1 = 255 (ne pas oublier que notre quartz est maintenant 4Mhz).283Donc, D255 = B 0000000011111111 sur 16 bits. Nous placerons donc :CCPR2H = B00000000 = 0x00CCPR2L = B11111111 = 0xFFPour ceux qui nont pas suivi lastuce, la mthode normale aurait t de dire :- Je configure CCP1 pour une dure de Tacq de 2Tad + 20 s- La conversion est termine, jattends 256s 48 s- Je reconfigure CCP1 pour une dure de Tacq de 2Tad + 20s- La conversion est termine, jattends 256s 48 s- Etc.Ceci ncessitait 2 mesures de temps distinctes. Jai donc simplifi en :- Je configure CCP1 avec 256 s. On aura donc une conversion toutes les 256s- La conversion est termine en 12Tad, ce qui nous laisse 256s-12Tad = 232s commeTacq. Ce temps est suprieur aux (20s + 2Tad) minimum requis, donc aucun problme.Le temps total est donc identique (256s), la frquence dchantillonnage galement, quiest suffisante pour obtenir 16 mesures du potentiomtre entre 2 modifications du PWM .Mais on na plus besoin de la boucle de temporisation supplmentaire.Une fois tout configur, notre module CCP1 fonctionnera donc de la faon suivante, dansla routine dinterruption du convertisseur A/D :- On sauve la valeur lueBen oui, cest tout. En effet, intervalle de 256 s, une nouvelle conversion seraautomatiquement lance, nous navons plus nous occuper que de sauver les valeurs. Noussommes prvenu de la fin dune conversion par une interruption ADIF.Nous obtenons donc, entre 2 mises jour de PWM , 16 valeurs dont il nous suffira detirer la moyenne. Cette moyenne devra donc tre crite dans nos paramtres du module PWM comme expliqu plus haut. Quand allons-nous crire cette valeur ?En fait, nous avons 2 possibilits ;- Soit nous mettons PWM jour toutes les 16 mesures du potentiomtre (dans ce cas,cette mise jour se fera dans la routine dinterruption A/D- Soit nous mettons PWM jour une fois par cycle Tc, et donc chaque interruption dedbordement du timer 2.Nous navons que lembarra du choix. Je choisis la seconde solution, qui est la bonne. Eneffet, comme nous modifierons les valeurs au dbut du cycle, nous sommes certains de ne pasobtenir de fonctionnement alatoire puisque la copie de notre valeur de consigne sur 10 bitsseffectuera au dbut de linterruption suivante. Nous sommes donc certains que cette copieninterviendra pas entre le moment o nous modifions nos 2 bits fractionnaires et le momento nous modifions nos 8 autres bits.284Notre routine dinterruption du timer 2 va donc :- Calculer la moyenne des 16 mesures du potentiomtre sauves- Entrer cette moyenne comme paramtre du module PWM .Jen profite pour faire une petite remarque. Jen vois dici qui se disent : On est dans unexercice pratique, et Bigonoff fait toujours de la thorie et des mathmatiques, il ny a pasmoyen de sen passer ? .La rponse est malheureusement non. En effet, je nai pas donn toutes ces formulesuniquement pour faire joli, et pour ne les utiliser que dans la thorie. Tout ce qui concerne lesmesures de temps, conversion etc. ncessitent de pralablement calculer toutes les valeurs deconsignes dont vous aurez besoin.Il ny a malheureusement pas de miracle. En lectronique traditionnelle, il fallaitcalculer des constantes de temps avec des condensateurs, des rsistances, et autrescomposants. En lectronique programmable, on calcule galement, mais simplement enemployant des formules diffrentes. Les contraintes restent identiques.Mais vous allez voir que toute cette thorie, qui semble ne plus finir, se traduit finalementpar un programme ultra-simple.Faites un copier/coller de votre fichier m16f876.asm et renommez la copie en servo1.asm . Crez un nouveau projet qui utilise ce fichier.Commenons, comme toujours, par diter len-tte :;*****************************************************************************; Exercice sur l'utilisation des modules CCP. *; Pilotage d'un servomoteur en utilisant le module CCP1 en mode PWM *; et le module CCP2 en mode compare avec trigger *; *;*****************************************************************************; *; NOM: Servo1 *; Date: 06/06/2002 *; Version: 1.0 *; Circuit: Platine d'exprimentation *; Auteur: Bigonoff *; *;*****************************************************************************; *; Fichier requis: P16F876.inc *; *;*****************************************************************************; *; Le PIC DOIT tre cadenc avec un quartz de 4Mhz *; L'entre de commande du servo est connecte sur CCP1/RC2 *; Le potentiomtre de rglage de position du servo est connect sur AN0 *; *;*****************************************************************************LIST p=16F876 ; Dfinition de processeur#include ; fichier include285__CONFIG _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_OFF & _CPD_OFF & _LVP_OFF &_BODEN_ON & _PWRTE_ON & _WDT_ON & _HS_OSC;_CP_OFF Pas de protection;_DEBUG_OFF RB6 et RB7 en utilisation normale;_WRT_ENABLE_OFF Le programme ne peut pas crire dans la flash;_CPD_OFF Mmoire EEprom dprotge;_LVP_OFF RB3 en utilisation normale; _BODEN_ON Reset tension en service;_PWRTE_OFF Dmarrage rapide;_PWRTE_ON Dmarrage temporis;_WDT_ON Watchdog en service;_HS_OSC Oscillateur haute vitesse (4Mhz286;*****************************************************************************; MACRO *;*****************************************************************************; Changement de banques; ---------------------BANK0 macro ; passer en banque0bcf STATUS,RP0bcf STATUS,RP1endmBANK1 macro ; passer en banque1bsf STATUS,RP0bcf STATUS,RP1endmNos variables en banque 1 se limitent la zone de stockage des 16 valeurs analogiqueslues, un compteur qui indique lemplacement, parmi les 16 disponibles utiliser pour laprochaine lecture, et une variable sur 16 bits destine recevoir les calculs concernant lesconsignes PWM;*****************************************************************************; VARIABLES BANQUE 0 *;*****************************************************************************; Zone de 80 bytes; ----------------CBLOCK0x20 ; Dbut de la zone (0x20 0x6F)zoneval : 0x10 ; 16 emplacements de sauvegardenumval : 1 ; numro de l'emplacement de sauvegardeconsigne : 2 ; calcul de la consigne ENDC ; Fin de la zoneEn zone commune, nous avons nos habituelles variables de sauvegarde pour les routinesdinterruption. Notez que notre programme principal ne fait rien. Mais jai conserv quelquessauvegardes pour que vous puissiez amliorer cet exemple pour en faire un programmeoprationnel.;*****************************************************************************; VARIABLES ZONE COMMUNE *;*****************************************************************************; Zone de 16 bytes; ----------------CBLOCK 0x70 ; Dbut de la zone (0x70 0x7F)w_temp : 1 ; Sauvegarde registre Wstatus_temp : 1 ; sauvegarde registre STATUSENDCLa routine dinterruption principale contient les tests pour les 2 interruptions utilises.Notez que, cette fois, pour varier les plaisirs, jai enlev les instructions goto restoreg , cequi induit que si 2 interruptions simultanes se produisent, elles seront traites en mmetemps. Ceci pour vous montrer quil y a plusieurs faons de procder.287;*****************************************************************************; DEMARRAGE SUR RESET *;*****************************************************************************org 0x000 ; Adresse de dpart aprs reset goto init ; Initialiser; ////////////////////////////////////////////////////////////////////////////; I N T E R R U P T I O N S; ////////////////////////////////////////////////////////////////////////////;*****************************************************************************; ROUTINE INTERRUPTION *;*****************************************************************************;sauvegarder registres;---------------------org 0x004 ; adresse d'interruptionmovwf w_temp ; sauver registre Wswapf STATUS,w ; swap status avec rsultat dans wmovwf status_temp ; sauver status swappBANK0 ; passer en banque0; Interruption convertisseur A/D; ------------------------------btfss PIR1,ADIF ; tester si interrupt en coursgoto intsw1 ; non sautercall intad ; oui, traiter interruptbcf PIR1,ADIF ; effacer flag interupt; Interruption TMR2; -----------------intsw1btfss PIR1,TMR2IF ; tester si interrupt en coursgoto restorereg ; non, fin d'interruptcall inttmr2 ; oui, traiter interruptbcf PIR1,TMR2IF ; effacer flag interupt;restaurer registres;-------------------restoreregswapf status_temp,w ; swap ancien status, rsultat dans wmovwf STATUS ; restaurer statusswapf w_temp,f ; Inversion L et H de l'ancien Wswapf w_temp,w ; Rinversion de L et H dans Wretfie ; return from interruptLa routine dinterruption du convertisseur A/D est toute simple, puisquelle se contente desauvegarder la valeur lue dans lemplacement dsign, et dincrmenter ce pointeurdemplacement.;*****************************************************************************; INTERRUPTION CONVERTISSEUR A/D *;*****************************************************************************;-----------------------------------------------------------------------------; Sauvegarde la valeur du potentiomtre sur 8 bits dans un des 16 emplacements; prvus. numval contient le numro de l'emplacement; Relance une nouvelle conversion, avec Tacq = 232s, ce qui permet au moins; 16 mesures durant le temps de cycle du module PWM (4096 s); ----------------------------------------------------------------------------288intadmovf numval,w ; numro de l'emplacement de sauvegardeandlw 0x0F ; garder valeurs de 0 15addlw zoneval ; ajouter emplacement dbut zonemovwf FSR ; dans pointeurmovf ADRESH,w ; charger 8 bits forts du convertisseur A/Dmovwf INDF ; sauvegarder valeurincf numval,f ; incrmenter numro de valeurreturn ; fin d'interruptionLa routine dinterruption du timer 2 permet le calcul de la moyenne des 16 valeursprcdemment sauvegardes, et la dduction de la nouvelle valeur de rglage du PWM.;*****************************************************************************; INTERRUPTION TIMER 2 *;*****************************************************************************;-----------------------------------------------------------------------------; Calcule la moyenne des 16 valeurs du potentiomtre, ajoute l'offset, et; rgle le module PWM en consquence; 1) on ajoute les 16 valeurs, on obtient donc 16 * valeur moyenne, donc; rsultat sur 12 bits; 2) On divise rsultat par 16, donc on obtient la valeur moyenne sur 8 bits; 3) On ajoute l'offset exprim en 1/4 de valeurs, le rsultat tient sur 9 bits; 4) On sauve les 2 bits faibles dans CCP1X et CCP1Y; 5) on divise les 9 bits par 4 pour obtenir la valeur entire et on sauve les; 8 bits 0xxxxxxx obtenus dans CCPR1L;-----------------------------------------------------------------------------inttmr2; faire la somme des 16 valeurs; -----------------------------movlw zoneval ; adresse de dbut de la zonemovwf FSR ; dans pointeurclrf consigne ; efface poids fort du rsultatclrf consigne+1 ; idem poids faibleinttmr2lmovf INDF,w ; charger valeur pointeaddwf consigne+1,f ; ajouter poids faible rsultatbtfsc STATUS,C ; tester si dbordementincf consigne,f ; oui, incrmenter poids fortincf FSR,f ; incrmenter pointeurbtfss FSR,4 ; tester si termin (FSR = 0x30)goto inttmr2l ; non, valeur suivante; division du rsultat par 16; --------------------------rrf consigne,f ; poids fort / 2, inutile d'effacer carry; car b7/b4 seront inutilissrrf consigne+1,f ; poids faible divis par 2 avec b7=carryrrf consigne,f ; poids fort / 2, inutile d'effacer carryrrf consigne+1,f ; poids faible divis par 2 avec b7=carryrrf consigne,f ; poids fort / 2, inutile d'effacer carryrrf consigne+1,f ; poids faible divis par 2 avec b7=carryrrf consigne,f ; poids fort / 2, inutile d'effacer carryrrf consigne+1,f ; poids faible divis par 2 avec b7=carry; ajouter la valeur minimale (offset); -----------------------------------movlw OFFSET ; charger offset (ici, il tient sur 8 bits)addwf consigne+1,f ; ajouter poids faiblebtfsc STATUS,C ; tester si dbordementincf consigne,f ; oui, incrmenter poids fort289; sauver les 2 bits fractionnaires; --------------------------------bcf CCP1CON,CCP1X ; effacer bit 1bcf CCP1CON,CCP1Y ; effacer bit 0btfsc consigne+1,1 ; tester si futur bit "-1" = 1bsf CCP1CON,CCP1X ; oui, mettre bit 1 1btfsc consigne+1,0 ; tester si futur bit "-2" = 1bsf CCP1CON,CCP1Y ; oui, mettre bit 0 1; placer valeur entire sur 8 bits; --------------------------------rrf consigne,f ; rcuprer futur b6 dans carryrrf consigne+1,f ; diviser par 2 avec entre de b6 dans b7rrf consigne,f ; rcuprer futur b7 dans carryrrf consigne+1,w ; diviser par 2, b6 et b7 en placemovwf CCPR1L ; placer nouvelle valeur de consignereturn ; fin d'interruptionRien de bien compliqu, donc, il sagit tout simplement de lapplication des formulesprcdemment expliques.Vient le tour de notre routine dinitialisation. Cest ici que tout se passe, en fait, puisquetout sera automatique par la suite.Jai volontairement spar nettement les diffrentes tapes, afin que vous puissiez voirdun coup dil les diffrentes fonctions initialises.; ////////////////////////////////////////////////////////////////////////////; P R O G R A M M E; ////////////////////////////////////////////////////////////////////////////;*****************************************************************************; INITIALISATIONS *;*****************************************************************************init; initialisation PORTS (banque 0 et 1); ------------------------------------BANK1 ; slectionner banque1Bcf TRISC,2 ; CCP1/RC2 en sortie; Registre d'options (banque 1); -----------------------------movlw OPTIONVAL ; charger masquemovwf OPTION_REG ; initialiser registre option; registres interruptions (banque 1); ----------------------------------movlw INTCONVAL ; charger valeur registre interruptionmovwf INTCON ; initialiser interruptionsmovlw PIE1VAL ; Initialiser registremovwf PIE1 ; interruptions priphriques 1; configurer le module CCP1; -------------------------bcf STATUS,RP0 ; passer banque 0movlw B'00001100' ; pour mode PWMmovwf CCP1CON ; dans registre de commande CCPmovlw PR2VAL ; valeur de dbordement290bsf STATUS,RP0 ; passer en banque 1movwf PR2 ; dans registre de comparaisonbcf STATUS,RP0 ; repasser en banque 0movlw B'00000110' ; timer 2 on, prdiviseur = 16movwf T2CON ; dans registre de contrle; configurer le convertisseur A/D; -------------------------------movlw ADCON1VAL ; 1 entre analogiquebsf STATUS,RP0 ; passer banque 1movwf ADCON1 ; criture dans contrle1 A/Dbcf STATUS,RP0 ; repasser banque 0movlw B'01000001' ; convertisseur ON, prdiviseur 8movwf ADCON0 ; dans registre de contrle0; configurer le module CCP2; -------------------------movlw B'00001011' ; pour mode compare avec triggermovwf CCP2CON ; dans registre commande CCP2movlw high CCPR2VAL ; charger poids fort valeur de comparaisonmovwf CCPR2H ; dans registre poids fortmovlw low CCPR2VAL ; charger poids faible valeur de comparaisonmovwf CCPR2L ; dans registre poids faiblebsf T1CON,TMR1ON ; lancer le timer 1; autoriser interruptions (banque 0); ----------------------------------clrf PIR1 ; effacer flags 1clrf PIR2 ; effacer flags 2bsf INTCON,GIE ; valider interruptionsRemarquez que nous navons pas dintialisation de variables. Ceci peut se comprendre. Eneffet :Concernant le pointeur demplacement, on garde dans la routine dinterruption, les 4 bitsde poids faible. Donc, inutile dinitialiser, car, commencer sauvegarder un emplacementou un autre na aucune importance, puisquon aura sauvegard de toute faon dans les 16emplacements avant leur utilisation.La zone des valeurs sauvegardes sera remplie par la routine dinterruption AD avantquon nutilise ces valeurs dans la routine dinterruption TMR2. Donc, inutile non plusdinitialiser.Le rsultat consigne est initialis avant chaque utilisation, et donc, une fois de plus,inutile de le configurer.Ne reste que notre programme principal, qui, le pauvre, na rien dautre faire qu setourner les pouces.Ceci pour vous dire que la gnration de notre signal PWM vous laisse normment detemps pour grer autre chose. Imaginez que vous utilisez une lecture de potentiomtre et lagnration dun signal PWM, et que tout ceci se ralise de faon pratiquement transparentepour votre programme principal.291Lancez lassemblage, placez le fichier servo1.hex dans votre PIC, noubliez pas dechanger le quartz, et lancez lapplication. Votre potentiomtre vous permet maintenant dergler un beau signal PWM avec un tat haut dune dure de 1 2 ms.Votre servomoteur, pour peu quil soit compatible avec la norme et quil fonctionne sous5V, sera positionn en suivant les volutions de votre potentiomtre. Attention cependant laconsommation de la pin dentre de votre servomoteur (cela ne devrait cependant pas poser deproblme).20.8 Exercice 2 : une mthode plus adapteNous avons vu que des temps trs longs comme ceux requis par la commande dunservomoteur ntaient pas trs appropris lchelle de temps du module PWM . Cedernier est en effet prvu pour tourner bien plus vite. Il permet de plus de disposer de temps haut et bas de dure trs prcise.Si nous regardons les chronogrammes ncessaires pour le pilotage de notre servomoteur,nous voyons que nous avons besoin de 2 temps diffrents :- Le temps de maintien ltat haut du signal, entre 1 et 2 ms. Ce temps est critique etdemande une grande prcision, car cest lui qui dtermine la position de notreservomoteur- Le temps total de cycle, qui lui nintervient en aucune faon sur cette position, il rclameseulement dtre infrieur 20ms. Ce temps nest donc absolument pas critique.Donc, on peut dire que pour piloter notre servo, on doit :- Placer un signal ltat haut durant une priode trs prcise- Attendre un temps non critique avant de recommencer.Ceci nous amne tout naturellement utiliser pour cette application le module CCP1 enmode compare avec gestion de la pin CCP1 Souvenez-vous en effet, que la combinaison 1001 des bits CCPxM3 CCPxM0 induitle fonctionnement suivant :292La largeur de ltat haut dpend trs prcisment du timer 1 et de CCPR. Aucun retard ouperturbation logiciel nintervient. Il nous suffit donc de reprogrammer CCP1CON intervallede moins de 20ms pour gnrer notre signal de faon parfaite.Par contre, nous ne devons pas oublier que notre timer 1 est galement utilis dans notremodule CCP2, utilis, lui, en mode trigger . Nous avons donc des contraintes dutilisationdu fait de lutilisation des 2 modules CCP.Il nous suffit de rflchir pour constater que, dans ce cas, le reset de notre timer 1 nepourra intervenir avant que la valeur CCPR1HL ne soit atteinte. Dans le cas contraire, notreligne CCP1 ne pourrait jamais repasser 0 .Ceci implique que notre temps sparant 2 chantillonnages ne pourra tre infrieur , dansle pire des cas, 2ms. Sachant que 20ms sparent au maximum 2 impulsions, cela nous permetde raliser 10 mesures de notre potentiomtre. Le chronogramme vous est donn plus bas.Nous aurions pu galement dcider deffectuer les conversions A/D au rythme dterminpar un autre timer (tmr0 ou tmr2). Ceci nous dlivrait de cette contrainte, sous condition delancer nous-mmes la conversion A/D (pas dutilisation du module CCP2 en mode trigger).La mthode de conversion tant alors celle utilise dans notre exercice lum2 .Bien entendu, il sagit ici dun exercice dapplication des modules CCP. Je vais doncchoisir la premire solution.Pour rsumer, nous choisirons donc une valeur de comparaison CCPR1HL variable, quinous donnera, en fonction de la valeur de notre potentiomtre, un temps variable entre 1 et 2ms.Nous choisirons de fait une valeur de CCPR2HL fixe, qui nous fixera le temps sparant 2conversions, en tant conscient que cette valeur CCPR2HL devra tre imprativement plusgrande que la valeur CCPR1HL.Ceci nous donnera donc un temps au minimum de 2 ms. Nous allons choisir 2,4ms, et 8mesures de conversion A/D intermdiaires ce qui nous donnera un temps approximatifsparant 2 impulsions de 2,4 * 8 = 19,2ms.293Nous utiliserons pour cet exercice notre quartz habituel de 20Mhz.Notre timer1, utilis avec un prdiviseur de 1, nous permet des mesures de temps de 0,2s(1 cycle) 13,1072 ms (65536 cycles). Nous aurons besoin de temps compris entre 1 2,4ms, ce qui est parfaitement dans les possibilits de notre timer 1. Vous voyez que les duresmises en uvre et le type de signal sont plus adaptes cette faon de procder.La dure de limpulsion rpond la formule suivante (Jappelle CCPR1HL la valeur 16bits forme par CCPR1H/CCPR1L, de mme TMR1HL la valeur forme par la concatnationde TMR1H et de TMR1L):T = (CCPR1HL + 1) * Tcy * prdiviseurAutrement dit :CCPR1HL = ( T / (Tcy * prdiviseur) ) 1Une dure de 1ms se traduira donc par une valeur de :CCPR1HL minimum = ( 1ms / 0,2s) 1 = 4999Une dure de 2 ms rclamera une valeur de :CCPR1HL maximum = (2ms / 0,2s) 1 = 9999La dure sparant 2 conversions A/D rpond la mme formule, mais relative CCPR2HL :CCPR2HL = (2,4ms / 0,2s) 1 = 11999Nous allons donc excuter les procdures suivantes (aprs initialisation) :- On lance le timer 1 et on lance le module CCP1 (dbut de limpulsion)- Aprs le temps dpendant de CCPR1HL, on obtient la fin de limpulsion- On aura ensuite 8 interruptions A/D durant lesquelles on mesure le potentiomtre- Lors de la 8me interruption, on mesure la moyenne, on calcule une nouvelle valeur deconsigne CCPR1HL, on arrte et on remet 0 le timer 1.- On recommence les oprationsNotez que linterruption intervient la fin de la conversion A/D, alors que le reset dutimer 1 (trigger) annonce la fin du temps dacquisition Tacq et donc le dbut de la conversion.Comme cette conversion dure 12 Tad, soit 19,2s avec notre quartz de 20Mhz, le dbut delimpulsion suivante se fera donc 12 Tad aprs le dbut de la 8me conversion. Donc un tempstotal sparant 2 impulsions de (8 * 2,4ms) + 19,2s = 19,2192 ms.294Si on veut tre prcis, on doit encore ajouter le temps entre le dbut de linterruption, et leredmarrage par logiciel du timer 1. Le chronogramme suivant nen tient pas compte.Limportant dans cette application est que nous restions sous le temps total de 20ms.Nous aurons donc le chronogramme simplifi suivant :Juste un petit mot dexplications. sur notre chronogramme, chaque flche pointe vers lebas indique un des dbuts de conversion A/D comprise entre chaque impulsion. Le dernierdbut de conversion seffectue aprs 19,2ms.12 * Tad plus tard (19,2s), la fin de cette conversion a lieu. A ce moment, on resettetmr1, et on relance une nouvelle impulsion (qui intervient donc un encore un peu plus tard, letemps dexcuter les quelques instructions ncessaires).Reste un petit dtail mettre au point. En effet, on doit simultanment mettre CCP1 etTMR1 en service pour lancer limpulsion, ce qui est impossible. On va donc devoir, soit :- Mettre TMR1 en service, puis CCP1, ce qui implique que lorsque CCP1 passe 1 ,TMR1 a dj compt un cycle- Soit mettre CCP1, puis TMR1 en service, ce qui implique que quand TMR1 commencera compter, il y aura dj un cycle que CCP1 sera 1 .En fait, cela na aucune importance pour cette application, mais il est bon que vouspreniez garde ce phnomne, pour le cas o votre application ncessiterait un crneau fixedune grande prcision.De toute faon, lanomalie de fonctionnement explique dans la partie thorique va nousimposer une faon pratique de faire lgrement diffrente.Voyons maintenant ce qui se passe au niveau du potentiomtre. Nous avons une valeurcomprise entre 0 et 1023.Or, nous avons besoin dune valeur comprise, pour CCPR1HL entre 4999 et 9999. Cecinous donne une plage de variation de 5000.295Nous allons donc dcider de multiplier la valeur de notre potentiomtre par 5, ce qui nousdonnera des valeurs comprises entre 0 et 5115. Nous rpartirons le surplus de part etdautre des valeurs limites, ce qui nous donne :Valeur minimale de CCPR1HL = 4999 ((5115-5000)/2) = 4942Valeur maximale de CCPR1HL = 4942 + 5515 = 10057.Ceci nous donnera un temps compris entre :T = (CCPR1HL+1) * Tcy * prdiviseurT minimum = 4943 * 0,2s = 988,6s = 0,9886 msT maximum = 10058 * 0,2 = 2011,6s = 2,0116msNous avons donc bien ralis nos objectifs. La valeur placer dans CCPR1HL sera donc :CCPR1HL = (potentiomtre * 5 ) + 4942Nous constatons que nous conservons lintgralit des 10 bits de la conversion A/D. Cecinous donne dans ce cas 1000 valeurs utiles intermdiaires, soit une prcision de :Prcision relative = 1/1000 = 0,1%Ceci nous permet de rgler notre angle avec une prcision de :Prcision angulaire = 0,1% * 180 degrs = 0,18 degr.Voyez la prcision obtenue. Et encore, il faut savoir que, si vous avez suivi, cetteprcision est celle de notre convertisseur A/D, donc de notre potentiomtre. Vous pourrieztrs bien rgler le servomoteur daprs une autre rfrence (consigne externe,), ce qui vouspermettrait davoir une prcision de 1 cycle dinstruction (1Tcy), soit 0,2s. La prcisionserait alors de :1/5000 = 0,02%Vous pourriez donc positionner votre servomoteur avec une prcision thorique de 0,036degr. Ceci vous montre les possibilits de votre PIC.Il nous reste dterminer comment effectuer la multiplication par 5. Lidal est de seservir de puissances de 2, afin dviter de se servir de programmes de multiplication (longs).Rien de plus simple : Multiplier un nombre par 5 revient le multiplier par 4, puis ajouter le rsultat au nombre initial. Les multiplications par 4 sont constitues de dcalages,quant aux additions, elles sont gres par le PIC.Si on se souvient que nous avons effectu 8 mesures intermdiaires de notrepotentiomtre, la somme de ces 8 valeurs nous donne 8 fois la valeur moyenne de notrepotentiomtre.296Donc, pour obtenir 4 fois la valeur de notre potentiomtre, nous diviserons cette sommepar 2. Reste ajouter la valeur unitaire, valeur obtenue en divisant de nouveau la somme par 4(division totale par 8) Ceci nous donne lalgorithme suivant (avec pot = valeur dupotentiomtre):- On additionne les 8 valeurs de mesure (on obtient 8 * pot)- On dcale le rsultat vers la droite (division par 2), et on sauve le rsultat (4 * pot)- On dcale encore de 2 rangs vers la droite (division par 8). Rsultat = pot- On ajoute la valeur obtenue la valeur prcdemment sauvegarde (4 * pot + pot = 5 *pot).Il est temps, maintenant, de passer la ralisation de notre programme. Faites uncopier/coller de votre fichier m16F876.asm et renommez cette copie servo2.asm .Commenons par diter len-tte et la configuration :;*****************************************************************************; Exercice sur l'utilisation des modules CCP. *; Pilotage d'un servomoteur en utilisant le module CCP1 en mode *; "compare avec sortie sur CCP1" et le module CCP2 en mode *; "compare avec trigger" *; *;*****************************************************************************; *; NOM: servo2 *; Date: 10/06/2002 *; Version: 1.0 *; Circuit: Platine d'exprimentation *; Auteur: Bigonoff *; *;*****************************************************************************; *; Fichier requis: P16F876.inc *; *;*****************************************************************************; *; Le PIC est cadenc 20 Mhz *; L'entre de commande du servo est connecte sur CCP1/RC2 *; Le potentiomtre de rglage de position du servo est connect sur AN0 *; *;*****************************************************************************LIST p=16F876 ; Dfinition de processeur#include ; fichier include__CONFIG _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_OFF & _CPD_OFF & _LVP_OFF &_BODEN_ON & _PWRTE_ON & _WDT_ON & _HS_OSC;_CP_OFF Pas de protection;_DEBUG_OFF RB6 et RB7 en utilisation normale;_WRT_ENABLE_OFF Le programme ne peut pas crire dans la flash;_CPD_OFF Mmoire EEprom dprotge;_LVP_OFF RB3 en utilisation normale; _BODEN_ON Reset tension en service;_PWRTE_ON Dmarrage temporis;_WDT_ON Watchdog en service297;_HS_OSC Oscillateur haute vitesse (4Mhz298bsf STATUS,RP0bcf STATUS,RP1endmConcernant les variables en banque 0, nous avons besoin de 8 emplacements pour sauverles 8 lectures du potentiomtre, une pour sauver le rsultat, et une autre pour indiquerlemplacement de sauvegarde. En fait, comme vous commencez devenir des pros , onpeut commencer tout doucement utiliser de temps en temps des astuces.Les 8 valeurs vont devoir tre additionnes, pour pouvoir calculer la moyenne. On peutdonc, au lieu de sauvegarder la dernire valeur lue, ladditionner directement une des 7autres. Cela nous vite une sauvegarde, et un emplacement de sauvegarde. Donc, ceux-cipassent de 8 7.Et puisque nous avons dj commenc additionner dans un des emplacements, autantconserver celui-ci pour le rsultat, ce qui nous conomise la variable de rsultat.Noubliez pas que les emplacements des valeurs du potentiomtre doivent pouvoircontenir 10 bits, donc utilisent 2 octets. Le rsultat, qui sera au maximum de 8 fois la valeurmaximale dun potentiomtre tiendra donc sur 10 + 3 = 13 bits.Ceci nous pargne donc 2 octets de RAM pour le rsultat, et 2 autres pour lemplacementde sauvegarde conomis. Dans notre application, cela importe peu, mais il nen sera pastoujours ainsi. Jai des applications qui utilisent lintgralit des emplacements RAM. Il estdailleurs possible en sus dutiliser des registres non utiliss matriellement dans lapplicationconcerne (ADRESL, EEDATA,etc.) pour y sauver des variables.Voici donc notre zone RAM en banque 0 :;*****************************************************************************; VARIABLES BANQUE 0 *;*****************************************************************************; Zone de 80 bytes; ----------------CBLOCK0x20 ; Dbut de la zone (0x20 0x6F)zoneval : D'14' ; 7 emplacements de 2 octets pour potnumval : 1 ; numro de l'emplacement de sauvegardeENDC ; Fin de la zoneDans notre zone RAM commune, jai laiss toutes les sauvegardes, pour le cas o vousdsireriez complmenter ce programme pour raliser une application pratique :;*****************************************************************************; VARIABLES ZONE COMMUNE *;*****************************************************************************; Zone de 16 bytes; ----------------CBLOCK 0x70 ; Dbut de la zone (0x70 0x7F)w_temp : 1 ; Sauvegarde registre Wstatus_temp : 1 ; sauvegarde registre STATUSFSR_temp : 1 ; sauvegarde FSR (si indirect en interrupt)299PCLATH_temp : 1 ; sauvegarde PCLATH (si prog>2K)ENDCVoyons maintenant notre routine dinterruption. Comme nous navons quune seulesource dinterruption, inutile de tester de laquelle il sagit. Commenons donc par sauvegardernos registres :;*****************************************************************************; DEMARRAGE SUR RESET *;*****************************************************************************org 0x000 ; Adresse de dpart aprs reset goto init ; Initialiser; ////////////////////////////////////////////////////////////////////////////; I N T E R R U P T I O N S; ////////////////////////////////////////////////////////////////////////////;*****************************************************************************; ROUTINE INTERRUPTION *;*****************************************************************************;-----------------------------------------------------------------------------; Sauvegarde la valeur du potentiomtre sur 10 bits dans un des 8 emplacements; prvus. numval contient le numro de l'emplacement (! 2 octets); Si emplacement = 0, en plus on lance une nouvelle impulsion; ----------------------------------------------------------------------------;sauvegarder registres;---------------------org 0x004 ; adresse d'interruptionmovwf w_temp ; sauver registre Wswapf STATUS,w ; swap status avec rsultat dans wmovwf status_temp ; sauver status swappmovf FSR , w ; charger FSRmovwf FSR_temp ; sauvegarder FSRmovf PCLATH , w ; charger PCLATHmovwf PCLATH_temp ; le sauverclrf PCLATH ; on est en page 0BANK0 ; passer en banque0Ensuite, on dtermine si on est en train de raliser la 8me mesure de la valeur dupotentiomtre, auquel cas, on devra en plus calculer la moyenne et lancer une nouvelleimpulsion.; Interruption convertisseur A/D; ------------------------------; tester si 8me interruption; ---------------------------incf numval,f ; incrmenter pointeur emplacementbtfsc numval,3 ; tester si numval = 8goto intpulse ; oui, dmarrer impulsionSi ce nest pas le cas, on sauve la valeur lue dans lemplacement prvu (attention, 2octets) :; pointer sur emplacement de sauvegarde; -------------------------------------300movlw zoneval-2 ; premier emplacement de sauvegarde -1movwf FSR ; zone emplacement dans pointeurbcf STATUS,C ; effacer carryrlf numval,w ; charger numro interrupt * 2addwf FSR,f ; FSR = emplacement concern (de 0 6); sauver valeur potentiomtre; ---------------------------movf ADRESH,w ; charger 8 bits forts du convertisseur A/Dmovwf INDF ; sauver le poids fortincf FSR,f ; pointer sur emplacement poids faiblebsf STATUS,RP0 ; passer en banque 1movf ADRESL,w ; charger poids faible convertisseur A/Dbcf STATUS,RP0 ; repasser banque 0movwf INDF ; sauver le poids faiblegoto restorereg ; fin du traitementSi, par contre, nous sommes en train de lire la 8me valeur du potentiomtre, nouscommenons par stopper et resetter notre timer 1.; arrt et reset du timer1; ------------------------intpulsebcf T1CON,TMR1ON ; arrt timer 1clrf TMR1L ; effacer timer 1 poids faibleclrf TMR1H ; idem poids fortEnsuite, on ajoute la valeur lue la valeur sauve dans le premier emplacement (quidevient le futur rsultat). Attention, nous travaillons toujours avec des grandeurs codes sur 2octets. Noubliez pas quil faudra donc grer le dbordement de loctet faible vers loctet fort(CARRY) :; ajouter valeur potentiomtre au rsultat; le rsultat sera zoneval et zoneval+1; ----------------------------------------movf ADRESH,w ; charger 8 bits forts du convertisseur A/Daddwf zoneval,f ; ajouter au poids fort emplacement 0 (lecture 1)bsf STATUS,RP0 ; passer banque1movf ADRESL,w ; charger poids faiblebcf STATUS,RP0 ; repasser banque 0addwf zoneval+1,f ; ajouter au poids faible emplacement 0btfsc STATUS,C ; tester si dbordementincf zoneval,f ; oui, incrmenter poids fortNous avons donc dans le rsultat, la somme de la lecture 1 et de la lecture 8. Il nous restedonc additionner les 6 valeurs intermdiaires.Nous commencerons par le dernier octet, car ceci nous permet de raliser en premierladdition des poids faibles, ce qui est plus simple au niveau algorithme (si vous ntes pasconvaincus, crivez le code correspondant au sens inverse).On profite den avoir termin avec le compteur demplacements pour lutiliser commecompteur de boucles. Non seulement a nous conomise une variable, mais, de plus, lasortie de cette boucle, numval se retrouve automatiquement 0 . Ceci pour vous montrerles rflexes qui seront les vtres lorsque vous programmerez depuis un certain temps lesmicrocontrleurs aux ressources limites.; ajouter les 6 valeurs restantes301; -------------------------------movlw zoneval+D'13' ; pointer sur dernier poids faiblemovwf FSR ; dans pointeurmovlw 0x06 ; 6 additions effectuermovwf numval ; numval = compteur de bouclesintplmovf INDF,w ; charger poids faibleaddwf zoneval+1,f ; ajouter poids faible rsultatbtfsc STATUS,C ; tester si dbordementincf zoneval,f ; oui, incrmenter poids fortdecf FSR,f ; pointer sur poids fortmovf INDF,w ; charger poids fortaddwf zoneval,f ; ajouter poids fort rsultatdecf FSR,f ; pointer sur poids faible prcdentdecfsznumval,f ; dcrmenter compteur de bouclesgoto intpl ; pas 0, addition suivanteMaintenant nous avons besoin de calculer notre valeur moyenne. Comme nous disposonspour le moment de 8 fois cette valeur, il nous faut donc diviser par 8. Cependant, comme nousaurons besoin de 4 fois la valeur pour la multiplication par 5, nous profiterons de cettedivision pour sauvegarder la premire division par 2 (8 fois la valeur divis par 2 gal 4 fois lavaleur).; calculer 4* valeur moyenne (zoneval); et valeur moyenne (zoneval+2); ------------------------------------bcf STATUS,C ; effacer carryrrf zoneval,f ; diviser poids fort par 2rrf zoneval+1,f ; idem poids faible, avec carrybcf STATUS,C ; effacer carryrrf zoneval,w ; charger poids fort / 4movwf zoneval+2 ; sauverrrf zoneval+1,w ; charger poids faible avec carrymovwf zoneval+3 ; sauverbcf STATUS,C ; effacer carryrrf zoneval+2,f ; calculer poids fort / 8rrf zoneval+3,w ; charger poids faible / 8Suite ceci, la multiplication finale de la valeur moyenne par 5 se rsume additionner lavaleur moyenne avec la valeur moyenne multiplie par 4.; calculer 5 fois valeur moyenne; ------------------------------addwf zoneval+1,f ; ajouter poids faiblesbtfsc STATUS,C ; tester si carryincf zoneval,f ; oui, incrmenter poids fortmovf zoneval+2,w ; charger poids fortaddwf zoneval,w ; ajouter poids fortReste ajouter notre offset (galement sur 2 octets) pour obtenir notre plage de consignedsire, le rsultat sera stock dans zoneval et zoneval+1; calculer nouveau temps de pulse; -------------------------------addlw HIGH OFFSET ; ajouter poids fort offsetmovwf zoneval ; dans poids fort rsultatmovf zoneval+1,w ; charger poids faible rsultat302addlw LOW OFFSET ; ajouter poids faible offsetbtfsc STATUS,C ; tester si dbordementincf zoneval,f ; oui, incrmenter poids fort rsultatmovwf zoneval+1 ; sauver poids fort rsultatReste lancer limpulsion pour une dure lie la valeur prcdemment calcule :; lancer l'impulsion durant CCPR1HL; ---------------------------------movf zoneval,w ; charger poids fort rsultatmovwf CCPR1H ; dans poids fort consignemovf zoneval+1,w ; charger poids faible rsultatmovwf CCPR1L ; dans poids faible consignemovlw B'00001001' ; comparateur, CCP1 = 0 sur galitbsf T1CON,TMR1ON ; lancer timer 1movwf CCP1CON ; dans registre de contrleEn fait, si vous faites ceci, votre pin CCP1 doit passer 1 au moment de lcrituredans CCP1CON.Sur les PICs qui sont en ma possession (16F876SP-20), cela ne fonctionne pas, comme jelai expliqu dans la partie thorique. Si cela fonctionne chez vous, avec les PICs en votrepossession au moment de la lecture de cet ouvrage, utilisez cette mthode, cest la plus simpleet la plus logique.Dailleurs, si vous passez ceci dans MPLAB 5.5, ceci ne fonctionne pas non plus.Microchip a donc intgr cette anomalie dans son mulateur.En fait, si on la force 1 , la pin CCP1 passe bien 0 la fin du temps coul(CCPR1HL = TMR1HL), mais, par contre la pin CCP1 ne passe jamais 1 au moment delcriture du registre CCP1CON.Qu cela ne tienne, il nous suffira donc de forcer notre pin 1 avant de lancer lecomparateur. On pourrait penser :; lancer l'impulsion durant CCPR1HL; ---------------------------------movf zoneval,w ; charger poids fort rsultatmovwf CCPR1H ; dans poids fort consignemovf zoneval+1,w ; charger poids faible rsultatmovwf CCPR1L ; dans poids faible consignemovlw B'00001001' ; comparateur, CCP1 = 0 sur galitbsf T1CON,TMR1ON ; lancer timer 1bsf PORTC,2 ; forcer pin CCP1 1movwf CCP1CON ; dans registre de contrleCela fonctionne effectivement dans MPLAB en mode simulateur (passage 1 de RC2(CCP1), puis passage 0 le cycle suivant lidentit : CCPR1HL = TMR1HL). Leproblme, cest que la pin reste dsesprment 0 sur notre PIC relle place sur soncircuit. Pourquoi ?En fait, cest trs simple et trs logique. Une fois le mode compare avec gestion CCP lanc, la pin RC2 nest plus commande par le PORTC, mais par le comparateur du moduleCCP.303Donc, MPLAB a beau vous indiquer que PORTC,2 vaut 1 , la pin RC2 reste en ralit 0 . Ce nest pas le PORTC qui commande RC2 (encore les limites de la simulation).Il nous faut donc trouver une autre astuce. Jai trouv la suivante (aprs avoir crit,comme indiqu, Microchip, leur technicien ma rpondu votre mthode pour forcer la pinCCP semble la mieux indique ). Si vous trouvez une meilleure astuce, nhsitez pas vousen servir (et men faire part, bien entendu).Cest le module CCP1 qui doit placer la pin CCP1 1 . Il suffit donc de le mettre enmode B00001000 et de forcer manuellement lgalit entre TMR1HL et CCPR1HL.Ainsi, la pin CCP1 passe immdiatement 1 , puisque ce nest que linitialisation deCCPxCON qui pose problme, et non son fonctionnement sur lgalit.Il suffit ensuite de rebasculer sur notre mode normal, qui remettra la pin CCP1 0 au boutdu temps dfini.Notez que pour crer un pulse 0 , nous aurions du agir de faon strictement inverse(dabord B00001001, puis B00001000 dans CCPxCON).Pour crer une galit immdiate, il suffit de mettre dans CCPR1HL la mme valeur quedans TMR1HL. Comme nous avons remis notre timer 0, nous ferons de mme avec lavaleur de consigne.; forcer CCP1 "1"; -----------------clrf CCPR1L ; effacer comparateur consigne poids faibleclrf CCPR1H ; idem poids fort (galit force avec TMR1HL)movlw B'00001000' ; comparateur, passe CCP1 1 sur galitmovwf CCP1CON ; lancer comparateur sur galit force (pin = 1 sur ; cycle suivantbsf T1CON,TMR1ON ; lancer timer 1 (donc ici, CCP1 passe 1)Vous voyez que cest trs simple : on efface CCPR1LH, puis on force le mode compareavec passage de CCP1 1 sur galit. Comme lgalit est prsente (le timer est stopp), lapin CCP1 passe 1 au cycle suivant, soit juste au moment o on lance notre timer (quicommence compter le temps de mise 1 de CCP1). Nous navons donc aucun dcalageentre valeur de consigne et dure de limpulsion.Il nous faut ensuite lancer le module dans son mode normal , cest--dire en modecompare avec remise 0 de CCP1, le cycle suivant lgalit entre TMR1HL etCCPR1HL.Jespre que cest clair, et que vous ntes pas en train de fumer .Si cest le cas, je vous accorde une pause. Prenez une collation, prsentez vos excuses lapersonne (pouse, enfant) qui a eu la malencontreuse ide de vous distraire durant la lecturede ce chapitre (et qui vous navez pas manqu de faire un commentaire peu courtois) etrevenez relire le tout dans quelques minutes.304; lancer l'impulsion durant CCPR1HL; ---------------------------------movf zoneval,w ; charger poids fort rsultatmovwf CCPR1H ; dans poids fort consignemovf zoneval+1,w ; charger poids faible rsultatmovwf CCPR1L ; dans poids faible consignemovlw B'00001001' ; comparateur, CCP1 = 0 sur galitmovwf CCP1CON ; dans registre de contrleNotez que le timer 1 a dj t redmarr, inutile donc de le faire une seconde fois.Nous navons plus qu restaurer les registres sauvegards :; restaurer registres; -------------------restoreregbcf PIR1,ADIF ; effacer flag interuptmovf PCLATH_temp,w ; recharger ancien PCLATHmovwf PCLATH ; le restaurermovf FSR_temp,w ; charger FSR sauvmovwf FSR ; restaurer FSRswapf status_temp,w ; swap ancien status, rsultat dans wmovwf STATUS ; restaurer statusswapf w_temp,f ; Inversion L et H de l'ancien W ; sans modifier Zswapf w_temp,w ; Rinversion de L et H dans W; W restaur sans modifier statusretfie ; return from interruptBon, le plus dur est fait. Passons maintenant notre routine dinitialisation. RC2 en sortie,registres dinterruption et doption ne posant pas de problme :; ////////////////////////////////////////////////////////////////////////////; P R O G R A M M E; ////////////////////////////////////////////////////////////////////////////;*****************************************************************************; INITIALISATIONS *;*****************************************************************************init; initialisation PORTS (banque 0 et 1); ------------------------------------BANK1 ; slectionner banque1bcf TRISC,2 ; CCP1/RC2 en sortie; Registre d'options (banque 1); -----------------------------movlw OPTIONVAL ; charger masquemovwf OPTION_REG ; initialiser registre option; registres interruptions (banque 1); ----------------------------------movlw INTCONVAL ; charger valeur registre interruptionmovwf INTCON ; initialiser interruptionsmovlw PIE1VAL ; Initialiser registremovwf PIE1 ; interruptions priphriques 1305Ensuite, on configure notre convertisseur A/D, avec un prdiviseur de 32, puisque nousavons remis notre quartz de 20MHz :; configurer le convertisseur A/D; -------------------------------movlw ADCON1VAL ; 1 entre analogiquebsf STATUS,RP0 ; passer banque 1movwf ADCON1 ; criture dans contrle1 A/Dbcf STATUS,RP0 ; repasser banque 0movlw B'10000001' ; convertisseur ON, prdiviseur 32movwf ADCON0 ; dans registre de contrle0Puis notre module CCP2, qui va lancer nos conversions A/D. Le module CCP1 na pas tre lanc, puisquil le sera dans la routine dinterruption A/D.; configurer le module CCP2; -------------------------movlw B'00001011' ; pour mode compare avec triggermovwf CCP2CON ; dans registre commande CCP2movlw high CCPR2VAL ; charger poids fort valeur de comparaisonmovwf CCPR2H ; dans registre poids fortmovlw low CCPR2VAL ; charger poids faible valeur de comparaisonmovwf CCPR2L ; dans registre poids faiblebsf T1CON,TMR1ON ; lancer le timer 1, synchrone, prdiv = 1Ne reste plus qu initialiser notre compteur 0 , et lancer les interruptions. On auraitpu se passer deffacer PIR1, mais au diable lavarice.; initialiser variable; --------------------clrf numval ; on commence par la premire interruption; autoriser interruptions (banque 0); ----------------------------------clrf PIR1 ; effacer flags 1bsf INTCON,GIE ; valider interruptionsgoto start ; programme principalReste notre programme principal, qui ne fait rien, une fois de plus. Libre vous dutilisercette ossature pour crer un vrai programme de pilotage de modle rduit. Et en plus de passer son temps derrire son ordi, Madame, il joue avec des petitesvoitures (ou des petits avions ) . Vraiment, vous cumulez, vos oreilles doivent souventsiffler, ou alors vous avez une pouse comprhensive (comme la mienne quoi que,parfois).Mais bon, moi je ne fais pas de modlisme (jai essay, mais mon avion tait plus souvent latelier quen lair H oui, pas dou, il parat).Fin du break, on retourne aux choses srieuses :;*****************************************************************************; PROGRAMME PRINCIPAL *;*****************************************************************************startclrwdt ; effacer watch dog306 goto start ; bouclerEND ; directive fin de programmeLancez lassemblage, placez servo2.hex dans votre pic, alimentez, et vous voici enprsence dun signal de pilotage de servomoteur parfaitement standard.Notez que si vous avez besoin de 2 servomoteurs, rien ne vous interdit dutiliser CCP2,quitte lancer alors manuellement la conversion A/D. Vous avez besoin de plus deservomoteurs ? Pas de problme, vous activez les entres de commande des servomoteurs lesuns aprs les autres en vous servant dautres pins du PIC. Ces sorties attaquent des porteslogiques qui laissent passer les pins CCP1 et CCP2 successivement sur les entres concernesdes servomoteurs.Ne reste qu diminuer dans les mmes proportions le temps de cycle total. Petit exemplethorique :- On configure CCP1 et CCP2 chacun pour piloter une sortie.- On affecte un temps Tc identique aux 2 modules de 10ms- La pin RB0 sert slectionner servo1/servo2 ou servo3/servo4- Aprs 10ms, on gnre les 2 pulses destins aux servos 1 et 2- Aprs 10 ms, on change ltat de RB0- On gnre les 2 pulses destins aux servos 2 et 3- On modifie RB0, et on recommenceVous voyez que chaque servo aura bien reu son impulsion dans lintervalle de 20ms.Avec cette mthode simple, vous pouvez pilotez (20ms/2ms) * 2 = 20 servomoteurssimultans, tout en nutilisant que trs peu de temps CPU, et en conservant une prcisionimbattable. Le timer 2 peut servir dterminer votre temps de cycle total.20.9 ConclusionCeci termine le chapitre consacr aux modules CCP. Vous voyez que ces modulesajoutent en fait des fonctions trs puissantes aux timers 1 et 2.Lorsque vous avez des signaux calibrs gnrer, des mesures dvnements raliser,des temps prcis mesurer, votre premier rflexe doit consister regarder si un des modes defonctionnement des modules CCP ne serait pas adapt votre problme.Jai donn un exemple dutilisation, mais il y en a bien dautres. Par exemple, au niveaude certaines transmissions srie qui ncessitent des bits de largeur variable, bits qui sontparticulirement simples grer avec la procdure prcdente.307Notes : 308Notes : 30921. Le module MSSP en mode SPI21.1 Introduction sur le module MSSPLe module MSSP, pour Master Synchronous Serial Port, permet lchange de donnes duPIC avec le mode extrieur, en utilisant des transmissions srie synchrones.Il nest pas le seul proposer des communications, nous avons dj vu la liaison parallledans le module PSP, et nous verrons dautres communications srie avec le module USART.Vous verrez que lensemble de ces modules vous ouvre toutes les voies royales de lacommunication, que ce soit avec votre PC, avec des afficheurs, des mmoires de typeeeprom, des dtecteurs de temprature, des horloges en temps rel, etc.Une fois matrises ces possibilits, et je vais vous y aider, vous pourrez raliser desapplications mettant en uvre dautres circuits que votre simple PIC. Nous sommes donc enprsence dun chapitre trs important. Ceci explique les nombreuses redondancesdexplications que je vais vous fournir. Je prfre en effet rpter plusieurs fois la mmechose avec des termes diffrents, que de laisser des lecteurs en chemin, cause dune erreurdinterprtation ou dune incomprhension.Notez que nous avons dj rencontr des communications srie dans le chapitre consacr la norme ISO 7816 dans la premire partie du cours (16F84). Il nous fallait alors grer chaquebit reu. Nous verrons quavec ces modules, nous navons plus nous occuper de latransmission des bits en eux-mmes, mais nous les recevrons et mettrons directement sousforme doctet, toute la procdure de srialisation tant alors automatique.Outre le gain en taille programme qui en dcoulera, vous vous rendez compte que lesvitesses de transmission pourront tre amliores de faon notable. Au lieu que votreprogramme ne soit interrompu lors de la rception ou de lmission de chaque bit, il ne le seraplus que pour chaque octet. Ceci multiplie allgrement la vitesse maximale possible dans unfacteur de plus de 10.Il y a tellement de modes possibles de fonctionnement, quil ne me sera pas possible dedonner systmatiquement des exemples. Je me limiterai donc des situations courantes.Nous verrons que le module MSSP peut travailler selon 2 mthodes. Soit en mode SPI,soit en mode I2C. Jai dcid de sparer ces fonctions en 2 chapitres distincts, car, bienquelles utilisent le mme module, et donc les mmes registres, elles ncessitent desexplications assez diffrentes.Mais commenons par le commencement21.2 Les liaisons srie de type synchroneJe viens de vous parler de liaisons srie synchrones, encore convient-il de vous donner unminimum dexplications sur ce que cela signifie :310Une liaison srie est une liaison qui transfre les donnes bit aprs bit (en srie), aucontraire dune liaison parallle, qui transmet un mot la fois (mot de 8 bits, 16 bits, ou plussuivant le processeur).La notion de synchrone est bien entendu de la mme famille que synchronis . Cecisignifie simplement que lmetteur/rcepteur fournira un signal de synchronisation quidterminera non seulement le dbut et la fin de chaque octet, mais galement la position dechaque tat stable des bits.Nous voyons donc que ce fonctionnement ncessite en plus des lignes de communication(entre et sortie de donnes), une ligne qui vhicule le signal de synchronisation (on parleradhorloge).Cette mthode prsente donc lavantage de permettre la lecture des bits toujours aumoment le plus favorable, et vite les problmes dus aux imprcisions de la vitesse. Il nencessite pas non plus dans le cas du SPI de bit de dpart (start-bit), ni de fin (stop-bit).Par contre, elle prsente linconvnient de ncessiter une ligne supplmentaire pourvhiculer lhorloge. Cette ligne, parcourue par dfinition par un signal haute frquence,raccourcira en gnral la longueur maximale utilisable pour la liaison.Vous avez bien entendu 2 faons denvoyer les bits la suite les uns des autres :- Soit vous commencez par le bit 7, et vous poursuivez jusquau bit 0. Cest la mthodeutilise par le module MSSP.- Soit vous procdez de faon inverse, dabord le bit 0 jusquau bit de poids le plus fort.Cest de cette faon que fonctionnera notre module USART, que nous tudierons plustard.Voici un exemple tout fait gnral de rception dun mot de 8 bits en mode sriesynchrone. Cest un exemple, les synchronisations et les niveaux varient dun circuit lautre,ainsi que nous allons le voir plus loin. Dans cet exemple, la lecture seffectue sur le frontdescendant du signal dhorloge :311Vous constatez que :- La lecture seffectue un endroit stable du bit concern (vers le milieu de sa dure)- Il y a 2 lignes rouges, car le bit peut prendre 2 valeurs (0 ou 1).- Le passage dun niveau lautre nest pas instantan, ce qui explique les lignes rougesobliques, et la zone de transition est le temps durant laquelle une lecture ne donnerait pasune valeur fiable (la transition entre les niveaux nest pas encore compltement termine).Plus la vitesse est lente, plus cette priode de transition est petite par rapport la dure deltat stable du bit. A une vitesse plus faible, les transitions apparaissent donc de faonpratiquement verticale.Voici un second exemple, qui donne une lecture concrte de loctet B10011010Cet exemple concret vous permet dassimiler la diffrence de reprsentation entre le casgnral (premire figure avec double ligne rouge) et un cas particulier (seconde figure avecligne rouge simple dfinissant loctet). Les habitus des chronogrammes de ce type voudrontbien mexcuser pour cette prcision.21.3 Le mode SPISPI signifie Serial Peripheral Interface. Ce mode correspond donc un fonctionnement standard du port srie synchrone. Il permet dinterconnecter de faon flexible etparamtrable diffrents composants avec les 16F87x.Le mode SPI ncessite sur notre PIC :- Une entre de donnes srie (SDI pour Serial Data Input)- Une sortie de donnes srie (SDO pour Serial Data Output)- Une entre/sortie horloge (SCK pour Serial ClocK)- Une entre optionnelle de slection du PIC (SS pour Slave Select)Vous pouvez retrouver ces pins sur le brochage de nos PICs. Comme dhabitude, cesfonctions sont multiplexes avec les ports classiques.312- SDI est multiplex avec RC4- SDO est multiplex avec RC5- SCK est multiplex avec RC3- SS est multiplex avec RA5.Dans ce mode, le module peut videmment mettre et recevoir. Il peut grer lui-mmelhorloge (mode master ) ou subir lhorloge gre par un autre microprocesseur (mode slave ). Dans ce dernier cas, il peut galement y avoir dautres esclaves (mode multi-slave ).Vous constaterez donc, que, si on excepte le fil de masse, une liaison de ce type ncessiteau minimum 2 fils (lignes) reliant les 2 composants. Le nombre de lignes peut cependantcrotre suivant les besoins de lutilisateur.La ligne dhorloge est toujours ncessaire, du fait mme de la dfinition de synchrone .On peut donc avoir les modes de liaisons suivants :- Liaison 2 fils : Permet de vhiculer linformation dans un seul sens un moment donn.On pourra distinguer la liaison unidirectionnelle (cest toujours le mme composant quimet, et toujours le mme qui reoit) et la liaison bidirectionnelle half-duplex (chacunmet et reoit tour de rle et sur le mme fil).- Liaison 3 fils : Permet de vhiculer linformation dans les 2 sens (bidirectionnelle), unfil diffrent tant dvolu chaque sens de transfert dinformation. Comme ceci permet lacommunication simultane dans les 2 sens de transmission, on parlera de liaison full-duplex.Nous verrons plus loin quen ralit le PIC met et reoit toujours simultanmentlorsquon utilise le module SPI. Loctet qui nest ventuellement pas utilis sera un octetfictif.- Lajout dun fil supplmentaire ddicac (SS) par esclave, ces 2 modes prcdents,permet de connecter plusieurs esclaves sur la mme ligne dhorloge. Le signal de slectionpermet de choisir quel esclave ragira sur la gnration de lhorloge.Prenez garde que tous ces signaux ncessitent forcment une rfrence de tension (masse).Donc, si votre metteur et votre rcepteur ne partagent pas la mme alimentation, il vousfaudra interconnecter les 2 tensions Vss de vos circuits. Ceci ncessitera donc un filsupplmentaire.Tout ceci nous donne une plthore de modes de fonctionnement, que nous allons tudieren squence.21.4 Les registres utilissTout au long de ltude de notre module MSSP, nous allons retrouver 2 registres deconfiguration et de status, savoir SSPSTAT , SSPCON , plus un registre SSPCON2 utilis uniquement pour le mode I2C, et dont nous ne parlerons donc pas dansce chapitre.313Ces registres contiennent des bits de contrle et des indicateurs dont le rle dpend dumode utilis actuellement par le module.Ceci implique que la description gnrale de ces registres ncessite de nombreusesconditions (telle fonction si tel mode, telle autre pour tel autre mode etc.). Ceci risque derendre les explications confuses. De plus, lutilisateur se sert en gnral du module, au seindun programme, pour une seule fonction. Peut donc lui importe davoir une vue absolumentgnrale de toutes les fonctions.Jai donc choisi de dcrire ces registres et les bits qui les composent pour chaque modedutilisation particulier. Le lecteur pourra se reporter au datasheet de Microchip sil souhaiteune vue densemble.A ces registres sajoutent le SSPSR (Synchronous Serial Port Shift Register), qui contientla donne en cours de transfert, et le registre SSPBUF (Synchronous Serial Port BUFfer) quicontient loctet envoyer, ou loctet reu, suivant linstant de la communication.Les autres registres utiliss sont des registres dont nous avons dj tudi lefonctionnement.Le mcanisme gnral nest pas trs compliqu comprendre. Voyons tout dabord duct de lmetteur.Loctet envoyer est plac dans le registre SSPBUF. La donne est recopieautomatiquement par le PIC dans le registre SSPSR, qui est un registre destin srialiser ladonne (la transformer en bits successifs).Ce second registre, non accessible par le programme, est tout simplement un registre quieffectue des dcalages.Comme le premier bit envoyer est le bit 7, le registre devra dcaler vers la gauche. Toutfonctionne donc un peu comme linstruction rlf , except que le bit sortant nest pasenvoy vers le carry, mais directement sur la ligne SDO. Le mcanisme se poursuit jusqu ceque les 8 bits soient envoys.Ct rcepteur, cest videmment le mme genre de mcanisme. Le bit reu sur la ligneSDI est entr par le ct droit du mme registre SSPSR, donc par le bit 0. Ce registre subitalors un dcalage vers la gauche qui fait passer ce bit en position b1. Le bit suivant sera alorsreu en position b0, et ainsi de suite. Le dernier bit reu entrane automatiquement la copie dela donne contenue dans SSPSR vers le registre SSPBUF.Donc, on rsume la squence de la faon suivante :- Lmetteur copie sa donne de SSPBUF vers SSPSR- Pour chacun des 8 bits- Au premier clock, lmetteur dcale SSPSR vers la gauche, le bit sortant (ex b7) est envoy sur SDO- Au second clock, le rcepteur fait entrer le bit prsent sur SDI et le fait entrer dans SSPSR en dcalant ce registre vers la gauche. Ce bit se trouve maintenant en b0.- On recommence pour le bit suivant314- Le rcepteur copie SSPSR dans SSPBUFA la fin de la transmission, loctet envoyer qui avait t plac dans SSPBUF aura tremplac par loctet reu.Ce quil faut retenir, cest quil faut 2 synchronisations diffrentes. La premire pourplacer le bit envoyer sur la ligne de transmission, et la seconde pour dire au rcepteur quonpeut lire ce bit, qui est maintenant stable. Comme le signal dhorloge prsente 2 flancs (unflanc montant et un flanc descendant), nous avons donc nos 2 repres avec une seule horloge.Vous avez bien entendu compris qumission et rception sont simultanes.Vous pouvez parfaitement illustrer ce fonctionnement en crant un petit programme passer au simulateur de MPLAB. Vous allez faire passer le contenu de lmetteur dans lercepteur. On cre 2 variables, une sappelle emis , et lautre recu . Vous imaginerez lecarry comme tant la ligne de transmission.movlw 0x08 ; Pour 8 octetsmovwf cmpt ; dans compteur de bouclesbouclerlf emis,f ; on dcale lmetteur, le bit envoyer est dans le carryrlf recu,f ; on fait entrer le carry par la droite dans le rcepteurdecfszcmpt,f ; 8 bits traits ?goto boucle ; non, suivantnop ; oui, les 8 bits de lmetteur sont dans le rcepteurRemarquez bien que le transfert seffectue en 2 tapes non simultanes (les 2 lignes rlfsuccessives, chacune excute sur un cycle dhorloge diffrent). Si vous avez compris ceci,alors vous avez compris ce quest une liaison srie synchrone.Remarquez quil ny a quun seul registre SSPSR, et un seul SSPBUF, ce qui vous indiquequmission et rception se font simultanment au sein dun mme PIC de la faon suivante :- On transfre la donne mettre dans SSPBUF- Le PIC copie cette donne dans SSPSR- On opre 8 dcalages vers la gauche, chaque bit sortant est envoy vers SDO, chaque bitentrant provient de SDI- Le PIC copie la donne vers SSPBUF, donc remplace la donne mettre par la donnereue.- A ce moment, le bit BF est positionn, indiquant que SSPBUF contient une donne lire,et le flag SSPIF est positionn galement pour indiquer la fin du cycle.Donc, toute mission saccompagne automatiquement dune rception, et rciproquement,toute rception ncessite une mission. Loctet ventuellement non ncessaire (reu ou mis)sera un octet factice, sans signification, souvent appel dummy .Pour bien comprendre, mme si, par exemple, vous nutilisez pas votre pin SDI,lmission dun octet sur SDO saccompagnera automatiquement de la rception dun octetfictif (dummy) sur la ligne SDI. A vous de ne pas en tenir compte.315A linverse, pour obtenir la rception dun octet sur la ligne SDI, le matre est contraintdenvoyer un octet sur sa ligne SDO, mme si celle-ci nest pas connecte. Il enverra doncgalement un octet fictif.Voici le tout sous forme de dessins. En rouge les bits reus, en bleu les bits envoys :316Une dernire petite remarque, avant de passer aux tudes dtailles : La pin SDOconservera ltat quelle avait lors de la fin de la transmission.Etant donn que le bit 0 est transmis en dernier, si loctet envoy est un octet pair (b0 = 0),la ligne SDO restera fige ltat bas jusquau prochain envoi dun octet. Par contre, si loctetest impair (b0 = 1), cette ligne restera fige ltat haut dans les mmes conditions.Ceci na aucune importance concernant la transmission, mais les amateurs doscilloscopespourront se poser des questions sils examinent les signaux prsents sur cette pin.21.5 Le mode SPI MasterJe poursuis mes descriptions par lutilisation du module MSSP en mode SPI, utilis danssa fonction de Master ou matre . Vous commencez vous rendre compte du nombrede combinaisons, qui va rendre les exercices systmatiques impossibles (ou alors vousrisquiez davoir votre cours aprs la cessation de fabrication des composants). Rassurez-vous,vous en aurez cependant suffisamment pour pouvoir passer de la thorie la pratique.21.5.1 Mise en uvreRien ne vaut une petite figure pour vous montrer linterconnexion de votre PIC configuredans ces conditions. Le schma de principe suivant illustre une connexion bidirectionnelle sur3 fils. Pour rappel, ce mode permet la rception et lmission simultane (mais nonobligatoire) de loctet utile:Remarquez quil y a bien une ligne par sens de transfert de linformation, et que cest lematre qui envoie lhorloge. Cest le matre qui gre lhorloge, et cest lui qui dcide delinstant de la transmission.Le circuit esclave peut tre aussi bien un autre PIC quun circuit ou un ensemble decircuits quelconque.Pour le cas o vous navez besoin que dun seul sens de transfert, il suffit de ne pasconnecter la ligne non dsire. Souvenez-vous cependant que, malgr que vous nutilisez pas317la ligne en question, au niveau interne au PIC, il y aura toujours mission et rceptionsimultanes.Si vous dcidez dinterconnecter 2 PICs, un tant le matre et lautre lesclave, toutetransmission se traduit par lchange du contenu du registre SSPBUF du matre avec celui delesclave.Il se peut galement que vous dsiriez transfrer vos donnes de faon bidirectionnelle,mais en nutilisant quune seule ligne. La solution sera alors de connecter ensemble SDI etSDO, et de placer SDO en entre (haute impdance) au moment de la rception dun octet.Ainsi, SDO ninfluencera pas la ligne en mode rception. Voici le schma de principecorrespondant :Concernant la mthode de programmation du module, ces 2 modes ninduisent aucunediffrence. Il suffit simplement ici dajouter la gestion de la validation ou non de la pin SDO,suivant que lon se trouve en mission ou en rception. Il faut videmment que lesclave fassede mme de son ct, dune faon ou dune autre.En pratique, cela seffectuera de la faon suivante :Routine de rceptionbsf STATUS,RP0 ; passage en banque 1bsf TRISC,5 ; mettre SDO en entre (haute-impdance)bcf STATUS,RP0 ; repasser banque 0 (ventuellement)suite ; traitement normal de la rceptionFin de la routine de rceptionRoutine dmissionbsf STATUS,RP0 ; passage en banque 1bcf TRISC,5 ; on met SDO en sortiebcf STATUS,RP0 ; repasser banque 0 (ventuellement)suite ; traitement normal de lmissionFin de la routine dmissionCe mode particulier ne diffre donc des traitements normaux de rception etdmission que nous allons voir que par la gestion du mode entre/sortie de RC5 (SDO). Jenen parlerai donc plus.318Bien entendu, il va de soi que lmission et la rception dun octet utile ne pourra dans cecas tre simultane (mode half-duplex).De nouveau, de faon interne au PIC, la rception et lmission seront toujourssimultanes. Ce mode implique donc que lorsquon met dans cette configuration, on reoitun octet qui ne provient pas en ralit de lesclave.Je termine ces schmas de principe, en indiquant comment notre PIC peut, par exemple,tre connecte plusieurs esclaves diffrents :Les pins Rxx et Ryy sont des pins quelconques du PIC configures en sortie. Elles sontconnectes sur les pins de slection de la transmission sur chacun des esclaves. Les 3 autresconnexions (entre/sortie/horloge) sont communes tous les circuits et constituent un bus.Notez quil est impossible quun esclave communique avec un autre esclave. Toutes lestransmissions sont gres par le matre. Cest le cas des communications full-duplex, quincessitent des lignes croises. Evidemment, si on croise les lignes entre A et B et entre A etC, elles ne seront pas croises entre B et C qui ne pourront donc communiquer (sauf ajoutdlectronique de slection).319Pour communiquer, le PIC matre slectionne un esclave via la pin Rxx ou Ryy (nimportequelle pin du PIC), puis lance la communication de faon classique. Au niveau du PIC matre,seule la gestion de ces pins de slection (par exemple bsf PORTx,y) est supplmentaire parrapport aux transmissions classiques. Jutiliserai cette possibilit dans lexercice propos enfin de chapitre.21.5.2 Le registre SSPSTATCommenons maintenant ltude de nos registres pour ce mode particulier. Attention, jene parlerai que des bits utiliss dans le fonctionnement dcrit actuellement (SPI en modemaster). Un bit non dcrit ne veut pas dire quil nest pas utilis dans un autre mode defonctionnement. En cas de doute, consultez le datasheet.Ce registre, Synchronous Serial Port STATus register, situ en banque 1, dispose de 2 bitsde configuration (b7 et b6), et de 6 bits dindication de status (b5 b0), do son nom. Les 2premiers cits sont accessibles en lecture et en criture, les suivants sont accessibles en lectureseule. Le positionnement de ces derniers est automatique en fonction de ltat de latransmission.SSPSTAT en mode SPI MASTERb7 : SMP : SaMPle bit (0 = milieu, 1 = fin)b6 : CKE : ClocK Edge select (0 = repos vers actif, 1 = actif vers repos)b5 : nonb4 : nonb3 : nonb2 : nonb1 : nonb0 : BF : Buffer Full (0 = buffer vide,1 = octet reu)Le bit SMP permet de dfinir quel moment du cycle dhorloge on effectue la capture dubit prsent sur SDI. Si SMP vaut 0, la capture a lieu au milieu du cycle dhorloge en cours.Sil vaut 1, la capture a lieu la fin de ce cycle. Bien entendu vous choisirez le mode le plusappropri en fonction du chronogramme de fonctionnement de lesclave connect. Vousdterminerez alors quel moment la donne prsente par celui-ci sera stable. On peut direque si lesclave place sa donne au dbut du cycle, le matre devra lire au milieu de ce cycle.Par contre, sil place sa donne au milieu, le matre lira celle-ci en fin de cycle.Le bit CKE dtermine quel sens de transition de lhorloge accompagne le placement du bitsur la ligne SDO. SI CKE vaut 0, la ligne dhorloge SCK sera force vers son tat actif, tandisque si CKE vaut 1, lhorloge passera ltat de repos au moment de lapparition de notre bitsur SDO. En milieu de cycle, lhorloge prendra ltat oppos.Le bit BF est un indicateur (lecture seule) qui, sil vaut 1 , indique que le buffer derception (SSPBUF) contient un octet complet reu via SDI.Ce bit est lecture seule, pour leffacer, vous devez lire le registre SSPBUF, et ce mmesi vous navez aucun usage de loctet quil contient.32021.5.3 Le registre SSPCONSecond et dernier registre utilis pour commander notre mode SPI, le registre SSPCONnous livre maintenant ses secrets.SSPCON en mode SPI MASTERb7 : nonb6 : nonb5 : SSPEN : SSP ENable (1 = module SSP en service)b4 : CKP : ClocK Polarity select bit (donne le niveau de ltat de repos)b3 : SSPM3 : SSP Mode bit 3b2 : SSPM2 : SSP Mode bit 2b1 : SSPM1 : SSP Mode bit 1b0 : SSPM0 : SSP Mode bit 0Le bit SSPEN permet tout simplement de mettre le module SSP en service (quel que soitle mode). Les pins SCK, SDO et SDI sont, une fois ce bit valid, dconnectes du PORTC, etprises en charge par le module SSP.ATTENTION : il vous est toujours, cependant, ncessaire de configurer ces lignes enentre et en sortie via TRISC.SCK (RC3) est la pin dhorloge, donc dfinie en sortie sur notre PIC matreSDI (RC4) est lentre des donnes, donc dfinie en entreSDO (RC5) est la sortie des donnes, donc dfinie en sortie.Donc TRISC devra contenir, pour le mode SPI master :TRISC = Bxx010xxx Souvenez-vous cependant que, si vous utilisez une ligne commune pour lmission et larception, vous devrez placer SDO en entre durant la rception, afin de ne pas bloquer lesignal reu du fait de limposition dun niveau (0 ou 1) sur la ligne par SDO.CKP dtermine ce quon appelle la polarit du signal dhorloge. En fait, il dtermine si, aurepos, la ligne dhorloge se trouve ltat bas (CKP = 0) ou ltat haut (CKP = 1). Ltatactif tant loppos de ltat de repos. Vous trouverez couramment dans les datasheets lanotion de idle qui prcise ltat de repos ( opposer donc ltat actif).Les bits SSPMx sont les bits de slection du mode de fonctionnement. Je vous donnenaturellement dans ce chapitre les seules configurations qui concernent le mode SPIMASTER.b3 b2 b1 b0 Mode0 0 0 0 SPI master, priode dhorloge : Tcy = 4 * Tosc0 0 0 1 SPI master, priode dhorloge : Tcy * 4 = Tosc * 160 0 1 0 SPI master, priode dhorloge : Tcy * 16 = Tosc * 640 0 1 1 SPI master, priode = sortie du timer 2 * 2321Vous constatez que la slection dun de ces modes influence uniquement la frquencedhorloge. Les 3 premiers modes vous donnent des horloges lies la frquence de votrequartz, alors que le dernier de ces modes vous permet de rgler votre frquence dhorloge enfonction de votre timer 2. Dans ce cas, chaque dbordement de ce timer2 inverse ltat dusignal dhorloge, ce qui explique que le temps dun cycle complet (2 flancs) ncessite 2dbordements du timer 2.Bien entendu, vous navez quun seul timer 2, donc, si vous dcidiez dutiliser ce mode,cela induirait des contraintes dans la mesure o votre timer 2 serait dj dvolu un autreusage au sein de votre programme. A vous de grer ces contraintes.Si vous utilisez le timer2 comme source dhorloge, le prdiviseur sera actif, mais pas lepostdiviseur, qui ninterviendra pas dans le calcul de la frquence de lhorloge SPI.Nous avons parl du dbut de la transmission, il nous reste savoir quel vnementannonce la fin de la communication.En fait, nous disposons de 2 bits pour indiquer cet tat notre programme :- Le bit SSPIF du registre PIR1 est positionn ds que lchange dinformations est termin.Ce bit pourra gnrer une interruption, si celle-ci est correctement initialise.- Le bit BF du registre SSPSTAT sera positionn ds quune donne reue est inscrite dansle registre SSPBUF. Ce bit ne sera effac que si on lit la donne contenue dans ce registre.21.5.4 Choix et chronogrammesNous avons vu que nous avons plusieurs bits qui influent sur la chronologie desvnements. Je vais tenter de vous montrer en quoi ces choix influent sur la faon dont sontlus et envoys les octets.Vous savez maintenant quune transmission dmarre toujours automatiquement parlcriture de loctet envoyer dans SSPBUF par le matre (pour autant que le module SSP soiten service) et se termine par le positionnement du flag SSPIF du registre PIR1 et par lepositionnement du flag BF.Remarquez que lmission et la rception commencent, du point de vue des chronologies,par lapparition des clocks dhorloge.Ceci induit automatiquement lmission et la rception simultane des donnes. Donc, auniveau de votre PIC matre, vous placerez une donne dans SSPBUF pour dmarrer aussi bienune rception quune mission. Si vous navez rien envoyer, il suffira de placer nimportequoi dans SSPBUF. De mme, si lesclave na rien vous renvoyer en retour, il suffira de nepas traiter la valeur automatiquement reue.Donc, du point de vue de votre programme, une mission / rception simultanes doctetsutiles (full-duplex) se traduira par la squence suivante :- On place la donne envoyer dans SSPBUF322- Une fois SSPIF positionn, on lit dans SSPBUF la valeur reue simultanmentSi nous scindons mission et rception dun octet utile en 2 tapes (half-duplex), nousobtiendrons dans le cas o lesclave rpond linterrogation du matre :- On place la donne envoyer dans SSPBUF- Une fois SSPIF positionn, on ignore la valeur reue (octet inutile)- On place une donne fictive envoyer (octet inutile)- Une fois SSPIF positionn, on lit la valeur reue dans SSPBUFOu le contraire, si le matre rceptionne un octet de lesclave et doit lui rpondre :- On place une donne fictive dans SSPBUF- Une fois SSPIF positionn, on traite la valeur lue- On rpond en plaant la rponse dans SSPBUF- Une fois SSPIF positionn, on ignore la valeur fictive reue dans SSPBUFJe vais maintenant vous montrer les chronogrammes. Vous avez dj compris quil y a 4combinaisons dhorloge possibles en fonction de CKE et de CKP :CKP CKE horloge0 0 SCK 0 au repos,le placement de la donne induit un flanc montant de SCK0 1 SCK 0 au repos,le placement de la donne induit un flanc descendant de SCK1 0 SCK 1 au repos,le placement de la donne induit un flanc descendant de SCK1 1 SCK 1 au repos,le placement de la donne induit un flanc montant de SCKDonc, ceci implique quil y a 4 mthodes pour le dbut de lmission. Il y a par contre 2faons de dterminer le moment de la lecture pour la rception, en fonction de SMP. Soit aumilieu du cycle, soit la fin du cycle. Ceci nous donne 8 modes de fonctionnement possiblesau total.Afin de vous permettre de mieux comprendre, je vous spare ce chronogramme en 3parties. Dabord la chronologie de lmission dun octet par le matre, et ensuite celles de larception par le mme matre. Noubliez pas quen ralit mission et rception sontsimultanes, et donc superposables.Donc, voyons le chronogramme dmission :323Vous constatez que lmission des bits sur SDO est synchronise avec lhorloge SCK, quipeut prendre 4 volutions diffrentes. Vous choisirez le mode suivant le fonctionnement delesclave connect. Sur le datasheet de ce dernier, le constructeur vous indiquera quelle formele signal dhorloge doit prendre au moment de la lecture du bit que votre PIC aura envoy.Un cycle est la distance sparant 2 flches rouges. Vous remarquerez que, quelle que soitla configuration, lesclave devra toujours lire la donne du matre au milieu du cycle (flchebleue)La lecture du bit que vous envoyez, sera imprativement synchronise par votre horloge(comme toutes les actions en mode synchrone), et doit se faire dans la zone stable du bit. Sivous prenez par exemple le mode CKP = 0 et CKE = 0, vous voyez que le bit est plac par lematre sur le flanc montant de SCK. La lecture par lesclave devra se faire imprativement surle flanc redescendant de SCK, qui est le seul signal prsent durant ltat stable du bit.Voyons maintenant la rception dun octet plac par lesclave sur la ligne SDI. Nousavons 2 modes possibles, dpendants de SMP. De nouveau, ce choix dcoule directement dela chronologie de votre composant esclave. Le moment o son fonctionnement provoque leplacement de la donne induit le moment o vous devrez procder sa lecture.Je vais de nouveau scinder les 2 cas. Imaginons tout dabord que llectronique delesclave soit conue pour que le bit destin au matre soit plac en dbut de cycle (donc enmme temps que le matre place son propre bit sur SDO). Nous aurons :324Vous voyez dans ce cas que le choix de linstant de lecture nest pas possible. Vous devezlire le bit au milieu du cycle. Ceci vous impose de placer le bit SMP du registre SSPSTAT 0.Examinons maintenant le cas o lesclave choisit de placer son bit au milieu du cycle(donc au moment o il procde la lecture du bit reu du matre) :Vous constatez cette fois que, puisque lesclave place son bit au milieu du cycle, il vousfaudra attendre la fin de celui-ci (qui concide au dbut du cycle suivant) pour procder la325capture du bit concern. Ceci imposera donc de configurer SMP 1 . Dans ce dessin, eneffet, un cycle est dlimit par 2 flches bleues.Remarquez que bien que vous travailliez en mode matre , ce mot ne concerne que lagnration de lhorloge. Pour la programmation, vous ntes en fait matre de rien du tout.Comme cest vous qui disposez du composant programmable, cest vous de vous plier auxexigences du composant esclave connect.Cest donc ce dernier qui va dcider de votre faon de travailler, et non linverse. Quandvous travaillerez en mode esclave, vous serez de nouveaux soumis aux exigences du matreconnect. Cest donc toujours vous qui devrez vous soumettre aux exigences matrielles(except si vous dveloppez la fois le logiciel du matre et de lesclave).Vous vous souviendrez donc que :- Le matre place toujours sa donne en dbut de cycle- On en dduit que lesclave lira toujours la donne en milieu de cycle- Lesclave peut placer sa donne, soit en dbut, soit en milieu de cycle- Ceci implique que le matre lira la donne reue, soit en milieu, soit en fin de cycle.Ces implications sont dues au fait quon ne peut lire que lorsque le bit est stable, cest--dire aprs le moment o le bit est plac, et avant quil ne disparaisse au profit du suivant.Comme nous sommes synchroniss lhorloge, le seul moment possible de lecture sesitue donc un demi cycle aprs le positionnement du bit.21.5.5 Vitesses de transmissionVoyons maintenant, mais jen ai dj parl, des vitesses de transmission disponibles. Laslection de ces vitesses est dtermine par les bits SSPM3 SSPM0 du registre SSPCON.Vous avez le choix entre une vitesse fixe en fonction de lhorloge principale de votre PICet une vitesse fixe en fonction de votre timer2 Sachant que F = 1/T, avec un quartz de 20Mhz, vous disposerez alors des options suivantes :0000 donnera une vitesse de Fcy (frquence de cycle), soit 5 MHz0001 donnera une vitesse de Fcy / 4, soit 1,25 MHz0010 donnera une vitesse de Fcy / 16, soit 312,5 KHz0011 donnera une vitesse dpendant de votre timer 2, suivant la formule suivante :T = (PR2 + 1) * Tcy * prdiviseur * 2Ou encoreF = Fcy / ((PR2 + 1) * prdiviseur * 2)326Je rappelle que le postdiviseur nest pas utilis dans ce cas.La vitesse maximale permise pour la liaison srie synchrone est donc de Fosc/4, soit, pourun PIC cadenc 20MHz, de 5MHz, 5.000.000 de bits par seconde, ou encore 5.000.000bauds (5MBauds). Vous constatez quil sagit dune vitesse assez importante, qui ncessitedes prcautions de mise en uvre (qualit et longueur des liaisons par exemple).La vitesse minimale est celle utilisant le timer 2 avec prdiviseur 16. Nous aurons, pourun quartz de 20MHz, une vitesse minimale de Fcy / (2 * prdiviseur * (PR2+1)), soit 5Mhz /(2 * 16 * 256) = 610,3 bauds.Ceci vous donne une grande flexibilit dans le choix de la frquence de lhorloge,frquence qui dpend une fois de plus des caractristiques de lesclave connect.21.5.6 Initialisation du mode SPI MasterSi vous avez compris tout ce qui prcde, alors vous navez mme pas besoin de cetteredondance dinformation. Pour le cas o un petit rsum ne serait pas superflu, voici lesprocdures dinitialisation de notre module :- On initialise SMP en fonction du moment de capture de la donne reue (milieu ou fin ducycle)- On initialise CKP en fonction de ltat de repos de la ligne dhorloge (polarit)- On slectionne CKE suivant le flanc dhorloge souhait au moment de lcriture dun bitsur SDO- On choisit la vitesse de lhorloge suivant SSPMx- On met le module en service via SSPEN- On configure SCK et SDO en sortie, SDI en entre, via TRISC.Rien donc de bien compliqu, une fois assimil ce qui prcde. Le dmarrage dunemission (et donc de la rception simultane) seffectue simplement en plaant un octet dansSSPBUF.La fin de lmission (et donc de la rception) seffectuera en vrifiant le positionnementde SSPIF, en grant linterruption SSP correspondante (si configure) ou en vrifiant lepositionnement du bit BF, mthode moins souvent utilise.Pour raliser un exercice pratique, il nous faut bien entendu un matre et un esclave.Comme je ne sais pas quels circuits vous avez sous la main, je vous proposerai un exercicemettant en uvre 2 PICs, un configur en matre, et lautre en esclave. Il nous faudra ds lorstudier ce second mode avant de pouvoir raliser notre exercice pratique.32721.5.7 Le mode sleepLe passage en mode sleep induit larrt la fois de lhorloge principale du PIC, et dutimer 2. Vous navez donc plus aucune possibilit de gnrer lhorloge.La transmission sera donc suspendue, et reprendra do elle se trouvait arrte, une fois lePIC rveill par un autre vnement externe (except un reset, bien sr).21.6 Le mode SPI SLAVEComme vous laurez dj compris depuis longtemps, ce mode (slave ou esclave) prsentela particularit de subir lhorloge de synchronisation au lieu de limposer. Ceci va induire descontraintes diffrentes, contraintes paramtres de nouveau par les mmes registres que pourle mode master .21.6.1 Mise en uvreJe vais maintenant vous donner les 2 configurations possibles de votre PIC connecte enmode SPI esclave. Le premier cas est donn si le PIC est le seul esclave du systme. Nulbesoin, alors, priori, de le slectionner en particulier. Nous verrons cependant que cela nestpas toujours vrai.Bien entendu, on trouve aussi le cas pour lequel votre PIC nest pas le seul esclave dusystme. Dans ce cas, il faut bien que votre PIC sache quand cest lui que le matresadresse :328Vous remarquez la prsence de la pin SS, configure en entre. Cette pin, lorsquelle estplace au niveau bas, indique au PIC que la communication en cours lui est destine. Il prendalors en compte les fluctuations de lhorloge.Si le PIC a t configur pour tenir compte de la pin SS, et que celle-ci se trouve ltathaut, le PIC ignorera tout signal en cours sur la ligne dhorloge, et donc ne rceptionnera ninenverra aucun bit.Notez que vous disposez galement, comme pour le mode matre , de la possibilitdinterconnecter SDO et SDI pour tablir une liaison half-duplex. Les mthodes de gestion etles limitations seront donc les mmes.21.6.2 Le registre SSPSTATDe nouveau, peu de bits utiliss pour ce mode dans ce registre. Le bit SMP doit tre forc 0. Cest logique, tant donn que nous avons prcis dans ltude du fonctionnement enmatre que lesclave est oblig de lire sa donne au milieu du cycle.329SSPSTAT en mode SPI SLAVEb7 : doit tre positionn 0 (lecture en milieu de cycle)b6 : CKE : ClocK Edge select (0 = repos vers actif, 1 = actif vers repos)b5 : nonb4 : nonb3 : nonb2 : nonb1 : nonb0 : BF : Buffer Full (0 = buffer vide,1 = octet reu)CKE a strictement la mme fonction que pour le mode master, je ne mattarderai doncpas. Si CKE vaut 0, la transition vers ltat actif dtermine le dbut du cycle (instant o lematre place sa donne). Si CKE vaut 1, la transition vers ltat de repos dtermine le dbutdu cycle.BF indique que le registre SSPBUF contient une donne reue en provenance du matre.La seule faon deffacer ce bit est de lire le registre SSPBUF (mme si vous navez aucunbesoin de la donnes quil contient).Si vous ne lisez pas SSPBUF, la prochaine rception dun octet donnera lieu une erreur overflow , et loctet qui sera alors reu ne sera pas transfr dans SSPBUF. Il sera doncperdu. En mode esclave, il est donc impratif de lire chaque octet reu, sous peine darrt dela rception des octets.21.6.3 Le registre SSPCONCe registre utilise, pour le mode esclave, deux bits de plus que pour le mode matre .SSPCON en mode SPI SLAVEb7 : WCOL : Write COLlision detect bitb6 : SSPOV : SSP receive Overflow indicator bit (1 = perte de loctet reu)b5 : SSPEN : SSP ENable (1 = module SSP en service)b4 : CKP : ClocK Polarity select bit (donne le niveau de ltat de repos)b3 : SSPM3 : SSP Mode bit 3b2 : SSPM2 : SSP Mode bit 2b1 : SSPM1 : SSP Mode bit 1b0 : SSPM0 : SSP Mode bit 0Le bit SSPOV permet de dtecter une erreur de type overflow . Cette erreur intervient(SSPOV = 1) si la rception termine dun octet induit la tentative de transfert de cette donnedepuis SSPSR vers SSPBUF, alors que votre programme na pas encore t lire la donneprcdente contenue dans SSPBUF (bit BF toujours positionn)Cette situation intervient en gnral lors de la dtection par pooling de la rception dunoctet. La mthode dinterruption tant moins sujette ce type derreur (raction immdiate la rception dun octet). Ce bit reste 1 jusqu ce quil soit remis 0 par votre programme.330Il vous incombera galement de lire le registre SSPBUF, afin deffacer le bit BF qui avaitprovoqu lerreur, sans cela, la prochaine rception dun octet donnerait de nouveau lieu lamme erreur.En cas derreur de ce type, loctet contenu dans SSPSR nest pas copi dans SSPBUF.Cest donc le dernier octet reu (contenu dans SSPSR) qui est perdu, celui contenu dansSSPBUF ne sera pas cras .Le positionnement de lindicateur WCOL vous informe que vous avez crit un nouveloctet envoyer dans SSPBUF, alors mme que lmission de loctet prcdemment crit esttoujours en cours. Il vous appartient deffacer cet indicateur une fois lerreur traite.Concernant les bits SSPMx, ils vont de nouveau dterminer les modes de fonctionnementpossibles du SPI en mode esclave. Plus question de vitesse, cette fois, puisquelle estdtermine par le matre.SSPMx Mode0100 SPI esclave, la pin SS permet de slectionner le port SPI0101 SPI esclave, la pin SS est gre comme une pin I/O ordinaireSouvenez-vous que la pin SS (optionnelle) peut servir dans le cas des esclaves multiples.Dans ce cas, cette entre valide le signal dhorloge reu. Elle permet donc de ne ragir quelorsque le PIC est rellement concern. Le registre TRISC devra tre correctement configur.Nous allons voir quen fait lutilisation de la pin SS est souvent moins facultative quellene le semble au premier abord.21.6.4 Les autres registres concernsDe nouveau, nous allons retrouver nos registres SSPSR et SSPBUF, sur lesquels je nereviendrai pas. Concernant le registre TRISC, qui dfinit entres et sorties, nous pouvons djdire que les pins SDO et SDI conservent leur fonction, alors que SCK subit maintenantlhorloge impose par le matre, et donc devient une entre. TRISA,5 permet de dfinir SS enentre, pour le cas o vous souhaitez utiliser cette possibilitSCK (RC3) est la pin dhorloge, donc dfinie en entre sur notre PIC esclaveSDI (RC4) est lentre des donnes, donc dfinie en entreSDO (RC5) est la sortie des donnes, donc dfinie en sortie.SS (RA5) est lentre de slection du module SPI (optionnelle)Donc TRISC devra contenir, pour le mode SPI slave :TRISC = Bxx011xxx Si vous dsirez utiliser SS, vous devrez placer TRISA,5 1 .Notez, de plus, que dans ce cas vous devrez aussi dfinir RA5 comme entre numriqueen configurant correctement le registre ADCON1 (comme expliqu dans le chapitre sur leconvertisseur A/D).33121.6.5 Choix et chronogrammesNous pouvons distinguer ici 2 chronogrammes diffrents, dpendant de ltat de CKE.Pour chacun des niveaux de CKE, nous avons 2 signaux dhorloge possibles. Voyons toutdabord le cas le plus simple, celui pour lequel CKE = 0.Souvenez-vous que vous disposez de la possibilit dutiliser la pin SS. Dans ce cas, elledevra tre place 0 au dbut de la transmission, faute de quoi, le PIC esclave ne ragirait pas lhorloge envoye par le matre.Cette fois, ce nest plus le placement dune valeur dans SSPBUF qui dclenche letransfert. Cest en effet le PIC matre qui dcide du dbut de cette transmission. Si SCK vaut0, le PIC esclave dtecte le dbut de la transmission au moment de la dtection du premierflanc actif de SCK.Le PIC esclave placera sa donne sur sa ligne SDO au moment de la premire transitionentre tat de repos et tat actif de SCK (si lentre SS optionnelle est utilise, il faudra de plusquelle se trouve au niveau bas). Le matre est sens faire de mme sur la ligne SDI de notrepic esclave.Donc, la lecture de la ligne SDI seffectuera lors de la transition entre tat actif et tat derepos de SCK. Tous les instants de transition sont parfaitement dtermins par lhorloge. Laligne SS, qui valide la communication est optionnelle, et dpend du mode choisi (avec ou sansgestion de SS). Si le mode sans gestion de SS est choisi, ltat de la ligne SS naura aucuneimportance. Si, par contre, le mode avec gestion de SS est programm, alors les transferts neseffectueront que si cette ligne est place au niveau bas par le matre.Voyons maintenant ce qui se passe si nous choisissons de travailler avec CKE = 1332Dans ce cas, le placement de la valeur seffectue sur la transition entre le niveau actif et leniveau de repos de SCK. Malheureusement, il va de soi que la premire transition, concernantle bit 7, est impossible dtecter. En effet, la ligne tant au repos, la premire transitionmodifierait la ligne SCK depuis son niveau actuel (repos) vers le niveau repos. Il ny a doncpas de transition. Rien ne permet donc lesclave de savoir que la transmission a commenc.Il lui est donc impossible de placer son bit b7 sur la ligne.La solution trouve est de se servir de la ligne de slection SS, dont le passage ltat basremplace la premire transition manquante de SCK.Le premier bit sera donc plac par lesclave au moment de la slection de celui-ci via lapin SS. Il va donc de soi que dans cette configuration, la ligne SS devient indispensable aufonctionnement de lensemble.Donc, pour rsumer, si vous utilisez la communication en mode SPI esclave et que vouschoisissez CKE = 1, alors vous devrez choisir le mode SSPMX = 0100, qui met la pin SS enservice.21.6.6 Vitesses de transmissionJe ne vais pas entrer ici dans trop de dtails. Si vous dcidez dinterfacer 2 PICs identiquesensemble, vous pouvez estimer que la vitesse maximale en mode master est gale lafrquence maximale en mode slave.Si vous utilisez un autre composant externe comme matre, il faudra vous assurer que sessignaux prsentent certaines caractristiques compatibles avec le datasheet du PIC (parexemple, le temps de maintien de la ligne SDI aprs le moment de la lecture). Ceci vouspermettra de calculer avec prcision la vitesse maximale commune entre les 2 composants.21.6.7 Initialisation du mode SPI SLAVEVoici les procdures dinitialisation de notre module :333- On initialise CKP en fonction de ltat de repos de la ligne dhorloge (polarit).- On slectionne CKE suivant le flanc dhorloge correspondant au moment de lcriture parle matre dun bit sur SDI- On choisit la mise en service ou non de SS, via SSPMx- On met le module en service via SSPEN- On configure SDO en sortie, SDI et SCK en entre, via TRISC.- On configure ventuellement SS (RA5) en entre via TRISA et ADCON1Le dmarrage dun transfert seffectue simplement lors de la premire transition de SCK(si CKE = 0) ou lors du flanc descendant de SS (si CKE = 1)La fin du transfert seffectuera en vrifiant le positionnement de SSPIF, en grantlinterruption SSP correspondante (si configure) ou en vrifiant le positionnement du bit BF.21.6.8 Le mode sleepLe passage en mode sleep narrte pas lhorloge SCK, puisque cette dernire est gnrepar le matre. Le PIC en mode esclave est ds lors parfaitement capable de recevoir etdmettre des donnes dans ce mode.Chaque fin dmission/rception pourra alors rveiller le PIC, qui pourra lire loctet reuet prparer le suivant mettre lors du prochain transfert.21.6.9 Scurit de la transmissionAu niveau du PIC en esclave risque de se poser un problme. En effet, supposons quonperde une impulsion de lhorloge SCK, ou, au contraire quun parasite ajoute une fausseimpulsion lors du transfert dun octet.Pour prendre exemple du premier cas, voici ce qui va se passer :- Le matre envoie son octet et 8 impulsions dhorloge.- Lesclave ne reoit que 7 impulsions, et donc dlivre (du point de vue du matre) 2 fois lemme bit. Il lui reste donc le bit 0 envoyer. Notez que le matre ne peut savoir quelesclave na envoy que 7 bits utiles, de mme lesclave ne peut savoir que le matre aprocd la rception de 8 bits.- Le matre envoie loctet suivant et 8 nouvelles impulsions dhorloge.- Lesclave croit alors que la premire impulsion concerne le bit 0 du transfert prcdent, etinterprte les 7 suivantes comme les 7 premires du transfert courant.Dans cette seconde transaction, le matre aura donc reu un octet compos du bit 0 deloctet prcdent, complt par les bits 7 1 de loctet courant.334Toutes les communications seront donc dcales. Il importe donc de permettre lesclavede se resynchroniser afin quune erreur de rception de lhorloge nait dinfluence que sur unseul octet. Ceci peut seffectuer de diverses faons, mais la plus simple est le recourssystmatique lutilisation de la pin SS.En effet, chaque fois que cette pin va repasser ltat haut, le module SPI va se remettre 0, et, ds lors, saura que la prochaine impulsion dhorloge concerne un nouvel octet.Je conseille de ce fait de toujours utiliser en mode SPI esclave, si cest possible, le modequi met en service la gestion de la pin SS.21.7 Exercice pratique : communication synchrone entre 2 picsNous voici arriv au moment tant attendu de mettre toute cette thorie en application. Lapremire chose comprendre, cest que pour tablir une communication, il faut 2interlocuteurs (le mono-dialogue est trs peu enrichissant).Donc, pour permettre tous de raliser cet exercice, je vais devoir choisir 2 composantsque vous connaissez. Je choisis donc sans hsiter 2 PICs 16F876. Oui, je sais, il vous faudraen acheter un second, mais il vous servira sans aucun doute un jour ou lautre, puisque vouslisez ce cours.Voici donc ce que je vous propose. Nous allons programmer un PIC matre qui vacompter des positions depuis 0 jusque 255. Ce PIC va envoyer ce numro intervalles de 1seconde un PIC esclave, qui lui renverra alors un octet contenu dans sa mmoire eeprom laposition demande. Le matre recevra cet octet et sen servira pour lenvoyer sur son PORTB,et provoquer ainsi lallumage des LEDs correspondantes qui y seront connectes.Ainsi, nous aurons ralis une rception et une mission par un SPI matre, ainsi quunemission et une rception par un SPI esclave. Nous aurons vu de la sorte la plupart desmcanismes dans un seul exercice.Un bouton-poussoir plac sur la pin RB0 de notre PIC esclave, permettra dinverserloctet envoyer au PIC matre.Voyons le schma de notre montage :335Ce montage nest gure compliqu. Le PIC matre reoit les 8 leds, et le PIC esclave lebouton-poussoir. Ils sont interconnects via les lignes de communication du module SPI. Lesdonnes dallumage sont videmment contenues dans leeprom du PIC esclave.Il est important de travailler proprement, si vous emmlez des longs fils, vous aurez toutesles chances, vu les vitesses mises en jeu, dobtenir un comportement erratique. Les 2condensateurs de 0.1f permettent un dcouplage des 2 PICs.Par scurit, la pin SS de lesclave est mise en service, et commande par une pinquelconque du PIC matre (jai choisi alatoirement RC6).Si vous dcidez dutiliser ce montage en affectant chaque PIC une source dalimentationdiffrente, noubliez pas quil vous faudra alors ajouter un fil de liaison entre les 2 masses(tension Vss). Il faut toujours, en effet, avoir une tension de rfrence (essayez de mesurerune tension avec un voltmtre en nutilisant quun seul fil). Le terme diffrence depotentiel en lieu et place de tension prend alors tout son sens.Nous allons tout dabord utiliser un protocole full-duplex. Si vous avez tout suivi, voussavez que nous allons envoyer et recevoir simultanment loctet utile de notrecommunication.En imaginant n reprsentant le numro de loctet envoy, ceci peut se traduire par :- Le matre slectionne lesclave en mettant la pin RC6 0 .- Le matre place son octet n dans SSPBUF, la transmission commence- Le matre reoit la rponse loctet n-1 qui se trouvait dans SSPSR de lesclave- Lesclave reoit en mme temps loctet n envoy par le matre- Le matre stoppe la communication en replaant la pin RC6 1 336- Lesclave lit loctet n en provenance du matre, interprte, et place le rsultat dansSSPBUF pour quil soit envoy lors du prochain transfert.- On recommence le tout avec loctet n+1 pour le matre, et rponse loctet n pourlesclaveRemarquez quil est trs important de comprendre que loctet reu par le matre nest pasla rponse loctet quil vient denvoyer, mais la rponse sa question prcdente. En effet,mission et rception tant simultane, il est impossible pour lesclave de prparer sa rponseavant davoir reu la question dans son intgralit. Nous verrons comment rsoudre ceproblme par la suite.Bon, passons la pratique. Nous allons tablir une communication entre 2 PICs, il importedonc que ces 2 PICs parlent le mme langage. Nous devons donc dfinir les paramtres denotre communication. Jai choisi arbitrairement :- Liaison 312,5 Kbauds, donc Fosc/64 avec un quartz 20MHz- Parit de lhorloge : 0V au repos- Le matre place son bit sur la transition : tat de repos vers tat actif.- Lesclave renvoie son propre bit en mme temps que le matre (dbut du cycle).- Le matre lit donc ce bit un demi cycle plus tard, en milieu de cycle.Qui dit 2 PICs dit 2 logiciels. Commenons par crer celui de notre PIC matre. Effectuezun copier/coller de votre fichier maquette, et renommez cette copie SPIMast1.asm . Crezun nouveau projet du mme nom, et ditez len-tte.;*****************************************************************************; Programme de communication srie synchrone entre 2 PICs 16F876. *; Logiciel pour le master. *; *; Le matre envoie le numro de l'affichage dsir *; L'esclave renvoie l'octet correspondant de sa mmoire eeprom *; Le matre rcupre l'octet et l'envoie sur son PORTB (8 LEDs) *; *; Liaison full-duplex. L'esclave renvoie donc l'octet correspondant la *; demande prcdente. *; *;*****************************************************************************; *; NOM: SPIMast1 *; Date: 21/06/2002 *; Version: 1.0 *; Circuit: platine d'exprimentation *; Auteur: Bigonoff *; *;*****************************************************************************; *; Fichier requis: P16F876.inc *; *;*****************************************************************************; *; Notes: Les 8 LEDS sont connectes sur le PORTB *; Les 2 PICs sont interconnects via SDO,SDI, et SCK *; La frquence des quartz est de 20 MHz *; La vitesse de communication est de Fosc/64, soit 312,5 KHz *; *;*****************************************************************************337LIST p=16F876 ; Dfinition de processeur#include ; fichier include__CONFIG _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_OFF & _CPD_OFF & _LVP_OFF &_BODEN_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSCJai choisi denvoyer un numro toutes les secondes. Jai choisi dutiliser le timer 2.Ltude dj ralise dans le chapitre qui lui est consacr, nous donne :- Prdiviseur : 16- Postdiviseur : 10- Valeur de comparaison : 249- Nombre de passages dans la routine : 125Le temps total sera en effet donn par la formule :T = (PR2+1) * prdiviseur * postdiviseur * Tcy * nombre de passagesT = (249+1) * 16 * 10 * 0,2s * 125 = 1.000.000s = 1s.La ligne de slection de lesclave (SS) tant connecte la pin RC6 de notre matre, voicinos dfinitions et assignations :;*****************************************************************************; DEFINITIONS ET ASSIGNATIONS *;*****************************************************************************#DEFINE SELECTPORTC,6 ; slection de l'esclavePR2VAL EQUD'249' ; Valeur de comparaison timer 2CMPTVAL EQUD'125' ; 125 passages dans la routine d'interruptionNos variables seront peu nombreuses, nous avons besoin dun compteur de passages dansla routine dinterruption du timer2, de loctet que lon va incrmenter et envoyer lesclave,et dun flag qui va nous servir savoir quand les 125 passages dans la routine dinterruptionauront t excuts.;*****************************************************************************; VARIABLES BANQUE 0 *;*****************************************************************************; Zone de 80 bytes; ----------------CBLOCK0x20 ; Dbut de la zone (0x20 0x6F)num : 1 ; numro envoyer l'esclavecmpt : 1 ; compteur de passages d'interruptionflags : 1 ; 8 flags d'usage gnral; b0 : une seconde s'est couleENDC ; Fin de la zoneLes variables de sauvegarde ne concernent que les registres STATUS et W .338;*****************************************************************************; VARIABLES ZONE COMMUNE *;*****************************************************************************; Zone de 16 bytes; ----------------CBLOCK 0x70 ; Dbut de la zone (0x70 0x7F)w_temp : 1 ; Sauvegarde registre Wstatus_temp : 1 ; sauvegarde registre STATUSENDCLa routine dinterruption est toute simple. Jai choisi de grer le module SPI par pooling,afin de varier les plaisirs. Nous naurons donc quune seule source dinterruption, le timer2.Celui-ci dcrmente une variable initialise 125. Ds que cette variable atteint 0, le flagest positionn, ce qui signale au programme principal que la dure est coule.La routine dinterruption recharge elle-mme le compteur, et le timer nest pas stopp.Cette mthode permet dobtenir 1 seconde dintervalle entre 2 positionnements du flag. Si onavait choisi de lancer le timer et le compteur dans la routine dattente (wait), on aurait obtenuun temps de 1 seconde partir de ce moment. Cest un peu compliqu expliquer, mais plussimple comprendre avec un petit graphique :Le positionnement du flag signale la sortie de la routine de temporisation. La premiremthode permet donc de grer des vnements intervalles rguliers (notre cas). Le tempssparant 2 positionnements du flag est constant et ne dpend pas de linstant o on entre dansnotre routine de temporisation.La seconde mthode permet dattendre un temps prcis dans une routine de temporisation.Elle ne comptabilise pas le temps coul entre le positionnement prcdent du flag et linstanto on entre dans la routine dinterruption.339;*****************************************************************************; DEMARRAGE SUR RESET *;*****************************************************************************org 0x000 ; Adresse de dpart aprs reset goto init ; Initialiser; ////////////////////////////////////////////////////////////////////////////; I N T E R R U P T I O N S; ////////////////////////////////////////////////////////////////////////////;*****************************************************************************; ROUTINE INTERRUPTION *;*****************************************************************************;-----------------------------------------------------------------------------; La routine d'interruption timer 2 est appele toutes les; (0,2s * 160 * 250) = 8ms.; au bout de 125 passages, une seconde s'est coule, on positionne; le flag;-----------------------------------------------------------------------------;sauvegarder registres;---------------------org 0x004 ; adresse d'interruptionmovwf w_temp ; sauver registre Wswapf STATUS,w ; swap status avec rsultat dans wmovwf status_temp ; sauver status swappbcf STATUS,RP0 ; passer banque0bcf STATUS,RP1; interruption timer 2; --------------------bcf PIR1,TMR2IF ; effacer le flag d'interruptiondecfszcmpt,f ; dcrmenter compteur de passagesgoto restorereg ; pas 0, fin de l'interruptionmovlw CMPTVAL ; valeur de recharge du compteurmovwf cmpt ; recharger compteurbsf flags,0 ; positionner flag;restaurer registres;-------------------restoreregswapf status_temp,w ; swap ancien status, rsultat dans wmovwf STATUS ; restaurer statusswapf w_temp,f ; Inversion L et H de l'ancien W ; sans modifier Zswapf w_temp,w ; Rinversion de L et H dans W; W restaur sans modifier statusretfie ; return from interruptNous arrivons maintenant dans notre routine dinitialisation. Commenons par lesPORTs :;*****************************************************************************; INITIALISATIONS *;*****************************************************************************init; initialisation PORTS; --------------------340BANKSEL PORTB ; slectionner banque 0clrf PORTB ; sorties PORTB 0clrf PORTC ; sorties PORTC 0bsf SELECT ; dslectionner esclaveBANKSEL TRISB ; slectionner banque 1clrf TRISB ; PORTB en sortiemovlw B'10010111' ; SDO et SCK, et select en sortiemovwf TRISC ; direction PORTCVous remarquez la prsence dune nouvelle macro, BANKSEL . Celle-ci place RP0 etRP1 de faon similaire nos macro BANKx . Cependant, on prcise comme argument unnom de registre ou un emplacement mmoire. BANKSEL effectue le changement en fonctionde la banque de ladresse spcifie. BANKSEL est une macro intgre MPASM. Il ne sagitpas proprement parler dune directive, puisquelle sera remplace par des instructions aumoment de lassemblage du programmeDans notre exemple, BANKSEL PORTB dtecte que PORTB se trouve en banque 0.La macro va donc crer les 2 lignes suivantes :bcf STATUS,RP0bcf STATUS,RP1Plus loin, nous trouvons BANKSEL TRISB . TRISB se trouvant en banque 1, la macrova induire :bsf STATUS,RP0bcf STATUS,RP1Lavantage apparent est que vous navez pas besoin de connatre la banque du registre quevous utilisez, vous ne risquez donc pas de vous tromper. Linconvnient est que si vous neconnaissez pas cette banque, vous ne pouvez pas non plus savoir si le registre suivant quevous utiliserez fait partie ou non de la mme banque, vous tes donc contraint dutiliser denouveau BANKSEL mme si ce registre ne ncessitait pas un nouveau changement debanques. A vous de voir.Notez que BANKSEL positionne toujours les 2 bits, RP0 et RP1, mme si un seulncessitait dtre modifi. Elle sera donc toujours traduite en 2 instructions, et ncessiteradonc 2 cycles dexcution.Le reste ne pose pas de problme, on prpare lextinction des LEDs (ds que TRISBsera configur), et on prpare la dslection de lesclave en prparant le positionnement de laligne RC6 1 .Ensuite, on initialise et on lance notre timer 2. Le premier intervalle de 1 secondecommence donc ce moment.; initialiser timer 2; -------------------movlw PR2VAL ; charger valeur de comparaisonBANKSEL PR2 ; passer banque 1movwf PR2 ; initialiser comparateurmovlw B'01001110' ; timer2 on, prdiv = 16, post = 10BANKSEL T2CON ; passer banque 0341movwf T2CON ; lancer timer 2Viennent ensuite les initialisations des variables :; initialiser variables; ---------------------clrf num ; on commence par l'lment 0movlw CMPTVAL ; pour dure initiale d'une secondemovwf cmpt ; dans compteur de passagesclrf flags ; effacer flagsDe nouveau, rien de particulier, on initialise le compteur de passages dans timer2, quina pu encore se produire, tant donn que linterruption timer2 nest pas encore en service. Ilnest de ce fait pas grave de linitialiser directement aprs avoir lanc le timer. Le flag esteffac, et le premier octet envoy lesclave sera 0x00.Nous allons maintenant initialiser le module SPI. Une fois de plus, toute cette thorieamne une initialisation ultra-simple.; initialiser SPI; ---------------movlw B'00100010' ; SPI matre, Tosc/64, repos = 0movwf SSPCON ; dans registre de contrleNous avons dcid que le matre lirait le bit reu au milieu du cycle, donc le bit SMP duregistre SSPSTAT vaudra 0 .La donne est transmise sur le flanc repos vers actif de lhorloge, donc CKE duregistre SSPSTAT = 0. Nous devrons donc initialiser SSPSTAT avec B00000000, ce qui estjustement sa valeur au moment dun reset. Inutile donc de linitialiser. Cest la raison pourlaquelle il napparat mme pas dans notre programme.Concernant SSPCON, il faut juste mettre le SPI en service (SSPEN), et choisir la fonctionmatre avec Fosc/64, ce qui nous donne SSPMx = 0010. Enfantin, nest-ce pas ?Ne reste plus qu mettre notre interruption du timer 2 en service :; lancer interruption timer 2; ---------------------------bsf STATUS,RP0 ; passer banque 1bsf PIE1,TMR2IE ; interruption timer 2 en servicebcf STATUS,RP0 ; repasser banque 0bsf INTCON,PEIE ; interruptions priphriques en servicebsf INTCON,GIE ; lancer les interruptionsCeci termine notre initialisation. Le programme principal va effectuer lenvoi dun octettoutes les secondes, rceptionner la rponse lenvoi prcdent, puis envoyer loctet reu surle PORTB. Une premire temporisation supplmentaire dune seconde permet de sassurerque lesclave a bien termin son initialisation et est prt recevoir (inutile dans ce cas-ci, carnotre esclave mettra moins dune seconde pour tre prt, mais prendre en considration lorsde lutilisation dun priphrique quelconque).342;*****************************************************************************; PROGRAMME PRINCIPAL *;*****************************************************************************;-----------------------------------------------------------------------------; Attend qu'une seconde soit coule depuis l'mission prcdente; Envoie l'octet num, et rceptionne en mme temps la rponse l'octet; envoy lors du prcdent transfert.; Envoie l'octet reu sur les LEDs, et incrmente l'octet num pour le; prochain envoi;-----------------------------------------------------------------------------call wait ; attendre 1 seconde supplmentaire pour; tre sr que l'esclave soit prtloopcall wait ; attendre 1 secondecall send ; envoyer l'octet nummovf SSPBUF,w ; charger l'octet reu de l'esclavemovwf PORTB ; l'envoyer sur les 8 LEDsincf num,f ; incrmenter numro envoyergoto loop ; bouclerLa routine dattente wait est toute simple, puisquelle se borne attendre lepositionnement du flag par la routine dinterruption, puis effacer ce flag.;*****************************************************************************; Attendre 1 seconde *;*****************************************************************************;-----------------------------------------------------------------------------; attendre qu'une seconde se soit coule depuis le prcdent passage dans; cette routine;-----------------------------------------------------------------------------waitbtfss flags,0 ; flag positionn?goto wait ; non, attendre flagbcf flags,0 ; reset du flagreturn ; et retourNous arrivons maintenant au cur de notre exercice, lmission et la rception dun octet.De nouveau, vous allez voir que la complexit de ltude thorique se traduit par unenorme facilit de lapplication dans un programme. Cest dailleurs le but des modulesintgrs que de vous donner accs de faon simple des fonctions puissantes. Essayez doncde raliser ce transfert synchrone en pilotant vous-mme SDI, SDO, et SCK. Bon courage.De plus, vous verrez que les vitesses que vous pourrez atteindre seront nettementinfrieures celles possibles par lutilisation du module SPI, et en monopolisant votreprogramme pour cette unique tche.;*****************************************************************************; Envoyer l'octet num *;*****************************************************************************;-----------------------------------------------------------------------------; Slectionne l'esclave, envoie l'octet sur la liaison srie et reoit; l'octet prpar par l'esclave.; Attend la fin de l'change avant de sortir, aprs avoir dslectionn; lesclave;-----------------------------------------------------------------------------sendbcf SELECT ; slectionner l'esclave343bcf PIR1,SSPIF ; effacer flagmovf num,w ; charger octet envoyermovwf SSPBUF ; lancer le transfertsendloopbtfss PIR1,SSPIF ; tester si transfert termingoto sendloop ; non, attendrebsf SELECT ; dslectionner l'esclavereturn ; et retourEND ; directive fin de programmeAttention, jai plac cette fois les sous-routines aprs le programme principal, noubliezpas la directive END .Cette sous-routine est trs simple : on place loctet envoyer dans SSPBUF, et on attendsimplement que le bit SSPIF soit positionn, signalant que le transfert est termin. A cemoment, loctet reu a remplac celui envoy dans SSPBUF, il ne restera plus qu lire ceregistre dans le programme principal.Lancez lassemblage, et placez le fichier .hex obtenu dans votre PIC matre.Pour terminer ce programme, et avant de voir le programme destin lesclave, je vousdonne un petit chronogramme de lchange dinformations, afin de bien vous fairecomprendre ce que vous envoyez et ce que vous recevez.Vous constatez que le matre reoit la rponse sa question prcdente, et non laquestion en cours. Vous visualisez bien le fait quun transfert synchrone quivaut lchangeentre le contenu de SSPBUF du matre et celui de lesclave. Lchelle de temps nest pascorrecte, en ralit le temps de calcul de lesclave est trs trs petit par rapport la secondequi spare 2 transferts, la double et la simple flche bleues sont donc pratiquementsuperposes.Bon, passons ltude du programme de notre esclave. Les contraintes ont dj ttablies, effectuez un copier/coller de votre fichier maquette, et nommez cette copie SPISlav.asm . Crez un nouveau projet ce nom, puis ditez len-tte.344;*****************************************************************************; Programme de communication srie synchrone entre 2 PICs 16F876. *; Logiciel pour l'esclave. *; *; Le matre envoie le numro de l'affichage dsir *; L'esclave renvoie l'octet correspondant de sa mmoire eeprom *; Si le bouton-poussoir est activ, l'octet est invers avant renvoi *; Le matre rcupre l'octet et l'envoie sur son PORTB (8 LEDs) *; *; Liaison full-duplex. L'esclave renvoie donc l'octet correspondant la *; demande prcdente. *; *;*****************************************************************************; *; NOM: SPISlav *; Date: 22/06/2002 *; Version: 1.0 *; Circuit: platine d'exprimentation *; Auteur: Bigonoff *; *;*****************************************************************************; *; Fichiers requis: P16F876.inc *; *;*****************************************************************************; *; Notes: Le bouton-poussoir est connect sur RB0 *; Les 2 PICs sont interconnects via SDO,SDI, et SCK *; La frquence des quartz est de 20 MHz *; La vitesse de communication est de Fosc/64, soit 312,5 KHz *; *;*****************************************************************************LIST p=16F876 ; Dfinition de processeur#include ; fichier include__CONFIG _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_OFF & _CPD_OFF & _LVP_OFF &_BODEN_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC;*****************************************************************************; DEFINE *;*****************************************************************************#DEFINE BP PORTB,0 ; bouton-poussoirOn conservera la macro de lecture en eeprom, tant donn que nous allons y placerquelques donnes.;*****************************************************************************; MACRO *;*****************************************************************************; oprations en mmoire eeprom; -----------------------------REEPROM macro ; lire eeprom(adresse & rsultat en w)clrwdt ; reset watchdogbcf STATUS,RP0 ; passer en banque2345bsf STATUS,RP1movwf EEADR ; pointer sur adresse eeprombsf STATUS,RP0 ; passer en banque3bcf EECON1,EEPGD ; pointer sur eeprombsf EECON1,RD ; ordre de lecturebcf STATUS,RP0 ; passer en banque2movf EEDATA,w ; charger valeur luebcf STATUS,RP1 ; passer en banque0endmAussi curieux que cela paraisse, et ce qui vous dmontre la simplicit de mise en uvre dela communication, nous naurons besoin daucune variable, exceptes celles ncessaires lasauvegarde des registres pour la routine dinterruption.Jai choisi en effet de travailler par interruptions sur SPI, comme cela, vous avez unexemple avec interruptions et un exemple avec pooling.;*****************************************************************************; VARIABLES BANQUE 0 *;*****************************************************************************; Zone de 80 bytes; ----------------CBLOCK0x20 ; Dbut de la zone (0x20 0x6F)ENDC ; Fin de la zone;*****************************************************************************; VARIABLES ZONE COMMUNE *;*****************************************************************************; Zone de 16 bytes; ----------------CBLOCK 0x70 ; Dbut de la zone (0x70 0x7F)w_temp : 1 ; Sauvegarde registre Wstatus_temp : 1 ; sauvegarde registre STATUSENDCJe vous ai laiss la dclaration de la zone banque 0, pour le cas o vous dsireriez utiliserce programme comme base pour une application particulire.Nous allons ensuite programmer quelques donnes dans la zone eeprom. Ces donnesconstituent les donnes renvoyes au matre. Celui-ci envoie le numro (ladresse) de loctetsouhait, lesclave renvoie loctet prsent cet emplacement. Je me suis limit 16emplacements, le but tant de montrer les transferts, et non de crer une application pratique.;*****************************************************************************; DONNEES EEPROM *;*****************************************************************************ORG0x2100 ; adresse zone dataDE B'00000001' ; data d'allumageDE B'00000010'DE B'00000100'DE B'00001000'DE B'00010000'DE B'00100000'DE B'01000000'DE B'10000000'346DE B'00000001'DE B'00000100'DE B'00010000'DE B'01000000'DE B'00000010'DE B'00001000'DE B'00100000'DE B'10000000'Souvenez-vous que ladresse absolue de la zone eeprom est 0x2100, et que la directivepermettant dinitialiser une zone data est DE . Je vous mets les 1 en vert, vous voyezainsi quel allumage de LED correspond le mot dclar.Nous voici notre routine dinterruption, qui ne comprend que linterruption SPI. NotrePIC entre dans cette interruption quand le transfert est termin. Il lit en eeprom loctet dont lenumro est maintenant dans SSPBUF (reu du matre), et place cet octet dans son SSPBUF,qui sera transmis lors du prochain transfert au matre.Lorsque le bouton-poussoir est press, loctet est invers avant dtre envoy. Les LEDsteintes seront donc allumes et vice et versa. Ceci va savrer pratique pour dmontrer par lapratique le dcalage entre interrogation et rponse.;*****************************************************************************; DEMARRAGE SUR RESET *;*****************************************************************************org 0x000 ; Adresse de dpart aprs reset goto init ; Initialiser; ////////////////////////////////////////////////////////////////////////////; I N T E R R U P T I O N S; ////////////////////////////////////////////////////////////////////////////;*****************************************************************************; ROUTINE INTERRUPTION *;*****************************************************************************;-----------------------------------------------------------------------------; A chaque rception d'un octet en provenance du matre, l'octet est trait; et la rponse replace dans SSPBUF;-----------------------------------------------------------------------------;sauvegarder registres;---------------------org 0x004 ; adresse d'interruptionmovwf w_temp ; sauver registre Wswapf STATUS,w ; swap status avec rsultat dans wmovwf status_temp ; sauver status swapp; Interruption SSP; ----------------BANKSEL PIR1 ; passer banque 0bcf PIR1,SSPIF ; effacer flag interuptmovf SSPBUF,w ; charger numro reu du matreandlw 0x0F ; on n'a que 16 positions validesREEPROM ; lire l'octet correspondant en eeprombtfss BP ; tester si bouton pressxorlw 0xFF ; oui, inverser l'octet reumovwf SSPBUF ; placer rponse dans SSPBUF qui sera; envoye en mme temps que la rception347; de l'octet suivant;restaurer registres;-------------------restoreregswapf status_temp,w ; swap ancien status, rsultat dans wmovwf STATUS ; restaurer statusswapf w_temp,f ; Inversion L et H de l'ancien W swapf w_temp,w ; Rinversion de L et H dans Wretfie ; return from interruptNotre routine dinitialisation commence par soccuper des PORTs.; ////////////////////////////////////////////////////////////////////////////; P R O G R A M M E; ////////////////////////////////////////////////////////////////////////////;*****************************************************************************; INITIALISATIONS *;*****************************************************************************init; initialisation PORTS; --------------------BANKSEL TRISC ; passer banque 1bcf TRISC,5 ; SDO en sortiemovlw 0x06 ; pour PORTA en numriquemovwf ADCON1 ; dans registre de contrleNotez que, bien que la pin SS soit prise en charge par le module SPI, le fait doublier deconfigurer ADCON1 pour limposer comme pin numrique, la ferait dtecter en prioritcomme une entre analogique.A propos, en me relisant, je tiens prciser que SS est en italique puisquil sagitdune pin active ltat bas, non pour voquer une idologie que par ailleurs je rprouve. Jetenais cette prcision pour viter un dangereux amalgame quant mes intentions. Je sais quecertains sont trs forts pour dcouvrir des messages cachs dans les livres, tableaux et autresuvres, mais je tiens rassurer tout le monde : il sagit dun cours, non dune uvre , et ilny a aucun message cach. Tous mes messages sont en clair dans le texte .Le mode SPI esclave ne requiert quune seule sortie, savoir la pin SDO (RC5).Linitialisation du module SPI est aussi simple que pour le matre, on choisira le modeesclave avec gestion de la pin SS. On initialise SSPBUF 0, de faon que le premier transfertenvoie cette valeur au matre.; initialiser SPI; ---------------bcf STATUS,RP0 ; repasser banque 0movlw B'00100100' ; esclave avec SS activemovwf SSPCON ; dans registreclrf SSPBUF ; premier octet envoy = 0Il nous faut maintenant mettre linterruption SPI en service :; autoriser interruptions; -----------------------348bsf STATUS,RP0 ; passer banque 1bsf PIE1,SSPIE ; autoriser interrupts SPIbcf STATUS,RP0 ; repasser banque 0bsf INTCON,PEIE ; autoriser interruptions priphriquesbsf INTCON,GIE ; valider interruptionsEt le reste de notre programme ? Vous allez rire :;*****************************************************************************; PROGRAMME PRINCIPAL *;*****************************************************************************startgoto start ; bouclerEND ; directive fin de programmeDifficile, de nouveau, de faire plus simple.Lesclave pouvant tre mis en mode sommeil durant la rception, vous pouvez ajouter :startsleep ; mise en sommeilgoto start ; bouclerEND ; directive fin de programmeAttention, dans ce cas. Le rveil du PIC provoque la remise en service de loscillateur, quiest un signal fortement perturbateur. Si votre PIC est incorrectement dcouple, si vos filssont longs ou sujets aux perturbations, vous risquez dobtenir un fonctionnement alatoire.Je vous dconseille donc dutiliser cette instruction sleep sur une platinedexprimentation, comportant, de surcrot, 2 PICs disposant de leur propre oscillateur.Noubliez pas que les vitesses de transmission sont assez importantes, et donc facilementsensibles aux perturbations.Lancez lassemblage, placez les 2 PICs sur le circuit et lancez lalimentation. Au bout dequelques secondes, les LEDs commencent clignoter sur le matre, preuve que les transfertsfonctionnent.Si vous maintenez press le bouton-poussoir, vous constatez que lallumage suivant esttoujours non invers. Ce nest que 2 allumages plus tard que les LEDs seront inverses. Cecivous dmontre que la rponse concerne toujours loctet prcdent.21.8 Exercice 2 : alternative de fonctionnementSi ce fonctionnement ne nous convient pas, cest--dire si nous voulons que lallumagedes LEDs corresponde ladresse envoye, nous navons dautre alternative que de travailleren half-duplex, cest--dire, mettre loctet, puis recevoir la rponse par une autretransmission. Comme la transmission comporte automatiquement une mission et unerception simultanes, nous ignorerons simplement le premier octet reu.Une transmission se fera donc de la faon suivante :- On envoie le numro de loctet349- On rceptionne loctet correspondant la requte prcdente, on lignore (octet dummy)- On attend que lesclave ait eu le temps de placer loctet dans SSPBUF- On envoie nimporte quoi (octet dummy)- On rceptionne loctet correspondant la requte prcdente (octet courant)- On place cet octet sur le PORTB.Vous voyez que de la sorte, on procde en 2 tapes : lmission dun octet utile avecrception dun octet ne servant rien, suivie par mission dun octet ne servant rien avecrception dun octet utileEntre les 2 transmissions, il est impratif dattendre que lesclave ait eu le temps de traiterlinformation. Nous allons nous servir de nouveau de notre routine dinterruption timer 2,pour positionner un autre flag. Le temps sparant 2 passages dans cette routine est de 8ms, cequi est largement suprieur au temps de raction de lesclave.Pour calculer ce dernier, il suffit de compter les cycles dinstructions survenus entre lemoment o le matre est interrompu par sa routine dinterruption timer2, et le moment olesclave a plac sa rponse dans SSPBUF. 8ms correspondent 40.000 cycles dinstruction,vous voyez que lesclave a eu tout le temps ncessaire pour placer sa rponse.Voici ce que a donne sur un petit dessin (attention, de nouveau pas lchelle) :On voit trs nettement que chaque change dinformation utile ncessite prsent 2transmissions conscutives. Par contre, lavantage est que loctet reu est bien loctet derponse la requte actuelle, et non plus la prcdente.Le programme de lesclave reste inchang, puisquil se contente de rpondre auxinterrogations. Il lui importe peu que linterrogation soit un dummy (pour rappel, octetinutile) ou un octet rellement important. En modifiant le programme de lesclave, on aurait350pu se passer de calculer la rponse au dummy reu, et placer directement nimporte quoi dansSSPBUF. Cela na cependant aucune importance pour cette application.Par contre, le matre devra grer cette double transmission. Effectuez un copier/coller devotre programme SPIMast1.asm et renommez la copie en SPIMast2.asm . Crez unnouveau projet ce nom.Le dbut ne pose pas problme :;*****************************************************************************; Programme de communication srie synchrone entre 2 PICs 16F876. *; Logiciel pour le master. *; *; Le matre envoie le numro de l'affichage dsir *; L'esclave renvoie l'octet correspondant de sa mmoire eeprom *; Le matre rcupre l'octet et l'envoie sur son PORTB (8 LEDs) *; *; Liaison half-duplex. L'esclave renvoie donc l'octet correspondant la *; demande actuelle. L'change d'informations ncessite cependant 2 *; cycles d'mission/rception *; *;*****************************************************************************; *; NOM: SPIMast2 *; Date: 23/06/2002 *; Version: 1.0 *; Circuit: platine d'exprimentation *; Auteur: Bigonoff *; *;*****************************************************************************; *; Fichier requis: P16F876.inc *; *;*****************************************************************************; *; Notes: Les 8 LEDS sont connectes sur le PORTB *; Les 2 PICs sont interconnects via SDO,SDI, et SCK *; La frquence des quartz est de 20 MHz *; La vitesse de communication est de Fosc/64, soit 312,5 KHz *; *;*****************************************************************************LIST p=16F876 ; Dfinition de processeur#include ; fichier include__CONFIG _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_OFF & _CPD_OFF & _LVP_OFF &_BODEN_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC;*****************************************************************************; DEFINITIONS ET ASSIGNATIONS *;*****************************************************************************#DEFINE SELECTPORTC,6 ; slection de l'esclavePR2VAL EQU D'249' ; Valeur de comparaison timer 2CMPTVAL EQU D'125' ; 125 passages dans la routine d'interruption; dure = Tcy*(PR2+1)*prdiv*postdiv*cmptval; = 0,2s * 250 * 16 * 10 * 125 = 1s.351Ensuite, les variables. Il suffit pour nous dutiliser un second bit comme flag dans lavariable flags , nous choisirons arbitrairement le bit 1.;*****************************************************************************; VARIABLES BANQUE 0 *;*****************************************************************************; Zone de 80 bytes; ----------------CBLOCK0x20 ; Dbut de la zone (0x20 0x6F)num : 1 ; numro envoyer l'esclavecmpt : 1 ; compteur de passages d'interruptionflags : 1 ; 8 flags d'usage gnral; b0 : une seconde s'est coule; b1 : 8 ms se sont coulesENDC ; Fin de la zoneRien dire non plus sur les variables en zone commune :;*****************************************************************************; VARIABLES ZONE COMMUNE *;*****************************************************************************; Zone de 16 bytes; ----------------CBLOCK 0x70 ; Dbut de la zone (0x70 0x7F)w_temp : 1 ; Sauvegarde registre Wstatus_temp : 1 ; sauvegarde registre STATUSENDCLa routine dintialisation est strictement identique, except le positionnement du flag 1 chaque passage dans la routine dinterruption.;*****************************************************************************; DEMARRAGE SUR RESET *;*****************************************************************************org 0x000 ; Adresse de dpart aprs reset goto init ; Initialiser; ////////////////////////////////////////////////////////////////////////////; I N T E R R U P T I O N S; ////////////////////////////////////////////////////////////////////////////;*****************************************************************************; ROUTINE INTERRUPTION *;*****************************************************************************;-----------------------------------------------------------------------------; La routine d'interruption timer 2 est appele toutes les; (0,2s * 160 * 250) = 8ms.; au bout de 125 passages, une seconde s'est coule, on positionne; le flag;-----------------------------------------------------------------------------;sauvegarder registres;---------------------org 0x004 ; adresse d'interruption352movwf w_temp ; sauver registre Wswapf STATUS,w ; swap status avec rsultat dans wmovwf status_temp ; sauver status swappbcf STATUS,RP0 ; passer banque0bcf STATUS,RP1; interruption timer 2; --------------------bcf PIR1,TMR2IF ; effacer le flag d'interruptionbsf flags,1 ; 8 ms coulesdecfszcmpt,f ; dcrmenter compteur de passagesgoto restorereg ; pas 0, fin de l'interruptionmovlw CMPTVAL ; valeur de recharge du compteurmovwf cmpt ; recharger compteurbsf flags,0 ; positionner flag;restaurer registres;-------------------restoreregswapf status_temp,w ; swap ancien status, rsultat dans wmovwf STATUS ; restaurer statusswapf w_temp,f ; Inversion L et H de l'ancien W ; sans modifier Zswapf w_temp,w ; Rinversion de L et H dans W; W restaur sans modifier statusretfie ; return from interruptRien ne change pour linitialisation;*****************************************************************************; INITIALISATIONS *;*****************************************************************************init; initialisation PORTS; --------------------BANKSEL PORTB ; slectionner banque 0clrf PORTB ; sorties PORTB 0clrf PORTC ; sorties PORTC 0bsf SELECT ; dslectionner esclaveBANKSEL TRISB ; slectionner banque 1clrf TRISB ; PORTB en sortiemovlw B'10010111' ; SDO et SCK, et select en sortiemovwf TRISC ; direction PORTC; initialiser timer 2; -------------------movlw PR2VAL ; charger valeur de comparaisonBANKSEL PR2 ; passer banque 1movwf PR2 ; initialiser comparateurmovlw B'01001110' ; timer2 on, prdiv = 16, post = 10BANKSEL T2CON ; passer banque 0movwf T2CON ; lancer timer 2; initialiser variables; ---------------------clrf num ; on commence par l'lment 0movlw CMPTVAL ; pour dure initiale d'une secondemovwf cmpt ; dans compteur de passagesclrf flags ; effacer flags353; initialiser SPI; ---------------movlw B'00100010' ; SPI matre, Tosc/64, repos = 0movwf SSPCON ; dans registre de contrle; lancer interruption timer 2; ---------------------------bsf STATUS,RP0 ; passer banque 1bsf PIE1,TMR2IE ; interruption timer 2 en servicebcf STATUS,RP0 ; repasser banque 0bsf INTCON,PEIE ; interruptions priphriques en servicebsf INTCON,GIE ; lancer les interruptionsCest dans le programme principal que se situe la diffrence de fonctionnement. Vousnoterez la prsence de la temporisation des 8ms, et la double mission/rception. Afin dviterdutiliser une sous-routine spcifique, loctet dummy envoy sera de nouveau loctet num . Ceci na aucune importance, loctet dummy pouvant, par dfinition, trenimporte quoi, donc pourquoi pas loctet num ?;*****************************************************************************; PROGRAMME PRINCIPAL *;*****************************************************************************;-----------------------------------------------------------------------------; Attend qu'une seconde soit coule depuis l'mission prcdente; Envoie l'octet num et rception un dummy; 8 ms aprs le dbut de la premire transmission, envoie un dummy (ici,; pour des raisons de facilit, envoie l'octet num comme dummy, cela; vite d'utiliser une seconde sous-routine) et rceptionne la rponse; l'octet num.; Envoie l'octet reu sur les LEDs, et incrmente l'octet num pour le; prochain envoi;-----------------------------------------------------------------------------call wait ; attendre 1 seconde supplmentaire pour; tre sr que l'esclave soit prtloopcall wait ; attendre 1 secondecall send ; envoyer l'octet num, recevoir dummybcf flags,1 ; effacer flag 1loop2btfss flags,1 ; tester si 8 ms coulesgoto loop2 ; non, attendrecall send ; envoyer l'octet dummy, recevoir rponse; l'octet nummovf SSPBUF,w ; charger l'octet reu de l'esclavemovwf PORTB ; l'envoyer sur les 8 LEDsincf num,f ; incrmenter numro envoyergoto loop ; bouclerLancez lassemblage, placez votre PIC matre sur le circuit, et envoyez lalimentation.Vous ne constatez aucune diffrence. Cest normal, tant donn que vous ne voyez pas lescorrespondances entre octet envoy et octet reu.Ceci explique pourquoi jai ajout un bouton-poussoir. Pressez-le et vous constatez queles LEDs seront inverss ds le clignotement suivant. Ceci dmontre que loctet reu est bienla rponse loctet en cours de traitement, et non plus la rponse au prcdent.35421.9 ConclusionsVoil, vous tes maintenant devenus des spcialistes du module SPI. Une corde de plusest donc ajoute votre arc de programmeur es-PICs. Noubliez pas que les transmissionssrie synchrones sont utilises, en gnral, pour les cas suivants :- Liaisons hauts dbits- Liaisons courtes distances (le plus souvent entre 2 composants de la mme carte).- Communications avec des circuits spcifiques ncessitant des liaisons synchronesElles sont souvent sensibles aux perturbations, et il convient dtre soigneux dans laralisation dapplications pratiques.Les exercices prsents navaient nul besoin de grer les conditions derreur. Il nensera pas toujours de mme pour vos applications pratiques. Pensez donc vrifier lesindicateurs concerns dcrits dans la partie thorique, si vous avez des raisons de penser quilpeut arriver quun des indicateurs derreur se retrouve positionn.De nouveau, cest vous de savoir sil y a risque ou non de collision ou de dbordement,daprs la structure de votre programme, et du priphrique connect.355Notes : 356Notes : 35722. Le bus I2C22.1 IntroductionJai dcid, plutt que de passer directement ltude du module MSSP en mode IC, decommencer par vous expliquer en quoi consiste ce bus.En effet, bien que le module prenne en charge tous les aspects de gestion de ce bus, il masembl important de comprendre ce qui se passait effectivement au niveau des lignes qui leconstituent.De plus, labsence de ces informations vous poserait problme au moment dtablir unecommunication avec un composant IC. En effet, lorsque vous rencontrerez un nouveaucomposant, tout ce dont vous disposerez son sujet sera, en gnral, son datasheet. Sans uneconnaissance assez prcise du bus IC, vous vous retrouveriez confront quelque chose quirisquerait bien de vous paratre incomprhensible.Et puis, mieux vaut avoir une information quon nutilisera ventuellement pas quuneabsence dinformation au moment o on en a besoin. Vous ne pensez pas ?22.1 Caractristiques fondamentalesLe bus IC permet dtablir une liaison srie synchrone entre 2 ou plusieurs composants.Il a t cr dans le but dtablir des changes dinformations entre circuits intgrs setrouvant sur une mme carte. Son nom, dailleurs, traduit son origine : Inter Integrate Circuit,ou I.I.C., ou plus communment IC (I carr C). Ce bus est le descendant du CBUS, qui est demoins en moins utilis.Son domaine dapplication actuel est cependant bien plus vaste, il est mme, par exemple,utilis en domotique.Il comporte des tas de similitudes avec le SMBUS dIntel (System Management BUS),mais je ne parlerai pas de ce bus ici. Si cela vous intresse, vous trouverez des informationssur Internet. Sachez simplement que nos 16F87x peuvent crer des signaux compatibles aveccette norme.L IC permettait, ses dbuts, de travailler des frquences maximales de 100Kbits/seconde, vitesses assez rapidement portes 400 Kbits/seconde. Il existe maintenantdes familles de circuits pouvant atteindre des vitesses de 3.4 Mbits/seconde. Il nest pas dansmon propos dtudier ces modles hi-speed particuliers. De toute faon, le fonctionnementthorique reste identique.Le bus IC est constitu de 2 uniques lignes bidirectionnelles :- La ligne SCL (Serial Clock Line), qui, comme son nom lindique, vhicule lhorloge desynchronisation- La ligne SDA (Serial DAta line), qui vhicule les bits transmis.358Il est important de vous souvenir que :- la ligne SCL est gre par le matre (nous verrons que par moment, lesclave peut prendreprovisoirement le contrle de la ligne).- la ligne SDA, un moment donn, est pilote par celui qui envoie une information (matreou esclave).Tous les circuits sont connects sur ces 2 lignes. Il existe 2 sortes de circuits pouvant treconnects :- Les circuits matres, qui dirigent le transfert et pilotent lhorloge SCL.- Les circuits esclaves, qui subissent lhorloge et rpondent aux ordres du matre.Chacun de ces 2 types peut mettre et recevoir des informations.Une particularit est quon peut placer plusieurs matres sur le mme bus IC. Ceciimplique que, sans prcautions, si 2 matres dsirent prendre le contrle du bus en mmetemps, on encourrait, sans prcautions particulires, 2 risques :- La destruction de llectronique des circuits, pour le cas o lun dentre eux impose unniveau haut et lautre un niveau bas (court-circuit).- La corruption des donnes destines ou en provenance de lesclave.Fort heureusement, vous vous doutez bien que Philips (linventeur de lIC) a trouv dessolutions pour parer ces ventualits. Je commence par les contraintes lectroniques. Jeparlerai des corruptions de donnes plus loin dans ce chapitre.Pour la partie lectronique, la parade est simple. On travaille avec des tages de sortie quine peuvent imposer quun niveau 0, ou relcher la ligne, qui remonte delle-mme au niveau 1via des rsistances de rappel.De cette faon, on naura jamais de court-circuit, puisque personne ne peut placer latension dalimentation sur la ligne. Ces tages sont des montages que vous trouverez dans lalittrature sous la dnomination de collecteur ouvert ou de drain ouvert suivant latechnologie utilise. La pin RA4 de votre PIC utilise dailleurs la mme technique.Notez que vous pouvez faire de mme, si un jour vous dcidez de piloter une ligne partirde 2 pics, par exemple. Imaginons le montage suivant :359Imaginons que vous dsiriez allumer la LED depuis nimporte lequel des 2 PICs. Si vouscrez les sous-routines suivantes dans chaque PIC :Allumagebcf PORTB,1returnextinctionbsf PORTB,1returnSi maintenant, votre PIC1 tente dteindre la LED, il placera +5V sur la ligne RB1. Si aumme instant votre PIC2 dsire allumer la LED, il placera 0V sur la ligne RB1. Et nous voicien prsence dun beau court-circuit, avec risque de destruction des 2 PICs. Si on regarde defaon schmatique ce qui se passe au niveau des 2 PICs, on voit : Le courant passe directement depuis le +5V du PIC1 vers le 0V du PIC2, ce qui provoqueun court-circuit. Il va de soi que si on avait utilis la pin RA4 (prvue pour cet usage) onnaurait pas rencontr ce problme.Mais il existe une solution simple permettant dutiliser nimporte quelle pin, et quiconsiste ne jamais autoriser le PIC envoyer un niveau haut. On modifie donc leprogramme comme suit :Initialisationbcf PORTB,1 ; Si RB1 en sortie, alors RB1 = 0AllumageBANK1 ; passer banque 1bcf TRISB,1 ; RB1 en sortie, donc allumage de la LEDBANK0 ; repasser banque 0360returnextinctionBANK1 ; passer banque 1bsf TRISB,1 ; RB1 en entre, donc non connecte -> Led teinteBANK0 ; repasser banque 0returnOn obtient alors un schma quivalant thorique du type :Si on enclenche un ou lautre interrupteur, on allume la LED (on force la ligne RB1 ltat bas). Si on tente dteindre la LED, il faut que les 2 PICs librent la ligne.Cest exactement ce qui se passe pour le bus I2C. Chaque circuit peut forcer la ligne SCLou SDA 0, mais aucun circuit ne peut la forcer ltat haut. Elle repassera ltat haut viales rsistances de rappel (pull-up) si tous les circuits connects ont libr la ligne.Le schma dinterconnexion des circuits sur un bus IC est donc le suivant :361ATTENTION : souvenez-vous que la masse de tous ces circuits, qui sert de rfrence, doitvidemment tre commune. De ce fait, si ces circuits se situent sur des cartes diffrentes, oune partagent pas la mme rfrence, il vous faudra une ligne supplmentaire dans votreconnexion, afin de transmettre la tension de rfrence. On parle donc couramment de liaison 2 lignes, mais en ralit 3 lignes sont ncessaires pour communiquer.22.2 Les diffrents types de signauxNous allons voir que cette norme joue intelligemment avec les niveaux prsents sur les 2lignes, afin de raliser diverses oprations. Plutt que de vous donner directement unchronogramme de transmission, je vais scinder les diffrentes tapes. De cette faon je penseque ce sera beaucoup plus simple comprendre.22.2.1 Le bit ordinaire Tout dabord, la mthode utilise pour crire et recevoir des bits est diffrente de celleutilise dans ltude de notre module SPI. En effet, pour ce dernier, un bit tait mis sur unflanc de lhorloge, et tait lu sur le flanc oppos suivant de la dite horloge.Au niveau du bus IC, le bit est dabord plac sur la ligne SDA, puis la ligne SCL estplace 1 (donc libre) durant un moment puis force de nouveau 0. Lmission du bitseffectue donc sans aucune correspondance dun flanc dhorloge. Il est lu lors du flancmontant de cette horloge.Notez quil est interdit de modifier la ligne SDA durant un niveau haut de SCL. La drogation cette rgle nest valable que pour les squences dites de condition que vous allons voirplus loin.Voici quoi ressemble lmission et la lecture dun bit :Vous constatez que le bit prsent sur la ligne SDA doit tre prsent avant la monte dusignal SCL, et continuer un certain temps avant sa redescente.36222.2.2 Le start-conditionComme pour tout signal synchrone, le protocole ne dfinit pas de start et de stop-bit. Maisil intgre toutefois les notions de start-condition et de stop-condition . Ces squencesparticulires, obtenues en modifiant la ligne SDA alors que la ligne SCL est positionne ltat haut permettent de dfinir dbut et fin des messages. Nous verrons que ceci estindispensable pour reprer le premier octet du message, qui a un rle particulier.Si on se souvient quau repos, SCL et SDA se trouvent relchs, et donc ltat haut, lestart-condition (symbole conventionnel : S) est ralis simplement en forant la ligne SDA 0, tout en laissant la ligne SCL 1.Il existe un driv de cette condition, appel repeated start condition , qui est utilislorsquun message en suit directement un autre. Il sagit donc en fait dun second start-condition au sein dun mme message. Nous verrons son intrt plus tard. Sachez ce niveauquun repeated start-condition peut tre considr comme identique un start-condition .22.2.3 Le stop-conditionNous venons dy faire allusion. Cette condition indique la fin du message en cours. Elleremet les lignes SDA et SCL au repos, mais en respectant la chronologie suivante :La ligne SDA est ramene 1, alors que la ligne SCL se trouve dj 1. Voici ce que celadonne :36322.2.4 LacknowledgeVoici de nouveau un nom barbare. Lacknowledge (ACK) est en fait laccus de rceptionde loctet envoy. Cest donc le rcepteur qui met ce bit pour signaler quil a bien lu loctetenvoy par lmetteur. Cet accus de rception est lu comme un bit classique. Il vaudra 0 silaccus de rception signifie OK , et 1 pour toute autre raison (rcepteur danslimpossibilit de rpondre, par exemple).Voici un ACK (OK) :Et voici une absence daccus de rception, encore dnomme NOACK. En effet, unNOACK quivaut une absence de raction, puisque seul le niveau bas est impos, le niveauhaut tant li la libration de la ligne (ou sa non appropriation).22.2.5 Le bit read/writeIl nous faut encore voir un bit particulier. Le bit R/W indique lesclave si les bits dedonnes contenus dans la trame sont destins tre cris (R/W = 0) ou lus (R/W = 1) par lematre. Dans le cas dune criture, le matre enverra les donnes lesclave, dans le cas dunelecture, cest lesclave qui enverra ses donnes au matre.Etant donn que ce bit ne prsente aucune particularit, je ne vous donne pas lechronogramme (identique celui dcrit pour le bit ordinaire ).36422.3 La notion dadresseNous avons vu que nous pouvions connecter un grand nombre de composants IC sur lemme bus. Cest dailleurs le but recherch.Mais nous ne disposons daucune ligne de slection, comme nous lavions pour le moduleSPI (ligne SS). Cest donc de faon logicielle que le destinataire va tre slectionn. Ceci faitnaturellement appel la notion dadresse.La premire norme IC limitait la taille des adresses 7 bits. Cependant, au fil de sonvolution, on a vu apparatre la possibilit dutiliser des adresses codes sur 10 bits. Nousverrons comment cela est possible.Nous pouvons donc dire que seul lesclave dont ladresse correspond celle envoye parle matre va rpondre.Toutes les adresses ne sont pas autorises, certaines sont rserves pour des commandesspcifiques. Parmi celles-ci, nous trouvons :- B0000000 : utilise pour adresser simultanment tous les priphriques (general calladdress). Les octets complmentaires prcisent le type daction souhait (par exemple,reset).- B0000001 : utilise pour accder aux composants CBUS (anctre de l IC)- B0000010 : rserve pour dautres systmes de bus- B0000011 : rserve pour des utilisations futures- B00001xx : pour les composants haute-vitesse- B11111xx : rserve pour des utilisations futures- B11110xy : permet de prciser une adresse sur 10 bits.Concernant cette dernire adresse, cette squence permet de complter les 2 bits de poidsforts xy reus par un octet complmentaire contenant les 8 octets de poids faible. Nousobtenons donc une adresse comprenant 10 bits utiles. Nous verrons ceci en dtails.Souvenez-vous que si vous devez attribuer une adresse votre PIC configur en esclave, ilvous faudra viter les adresses prcdentes, sous peine de problmes lors de lutilisation aveccertains composants spcifiques.Corollaires de tout ce qui prcde :- Seuls les esclaves disposent dadresses- Ce sont toujours les matres qui pilotent le transfert- Un matre ne peut parler qu un esclave (ou tous les esclaves), jamais un autre matre.Rien ninterdit cependant quun composant passe du status de matre celui desclave etrciproquement. Le bus IC est donc dune complte souplesse ce niveau.22.3 Structure dune trame IC365Nous avons vu tous les signaux possibles, il nous faut maintenant tudier le protocole decommunication des intervenants en IC.Nous savons dj que la transmission commence par un start-condition (S).Vient ensuite ladresse, code sur 7 ou 10 bits, complte par le bit R/W qui prcise si lesdonnes qui vont suivre seront crites ou lues par le matre. Notez que certains considrentque ce bit fait partie de ladresse, ce qui implique alors que ladresse relle se retrouvemultiplie par deux, et que les adresses parires sont destines des critures, et les adressesimpaires des lectures.Chaque octet envoy est toujours accompagn dun accus de rception de la part de celuiqui reoit. Un octet ncessite donc 8 + 1 = 9 impulsions dhorloge sur la pin SCL.On distingue ds lors 2 cas : soit ladresse est code sur 7, soit sur 10 bits. Voici commentse prsente le dbut dune trame ( partir ce cet instant, dans les chronogrammes concernantlIC, je note en rouge ce qui est transmis par le matre et en bleu ce qui est transmis parlesclave) :Notez donc, et cest logique, que cest toujours le matre qui envoie ladresse, quil soitrcepteur ou metteur pour le reste du message.Pour coder une adresse sur 10 bits, on utilisera comme premier octet ladresse rserveB11110xy0 qui prcise quun second octet est ncessaire. Voici ce que donne lenvoi duneadresse sur 10 bits :Remarquez que si vous codez ladresse sur 2 octets, le bit R/W doit toujoursimprativement tre gal 0. Vous prcisez donc toujours une criture. Nous verrons plusloin ce que nous devons faire si nous avons besoin dune lecture. De plus, le bit R/W ne sesitue que dans le premier octet de ladresse, cela explique pourquoi vous pouvez caser 8 bitsdans loctet 2, alors que vous tes limits 7 bits dans le cas dune adresse sur 1 octet.Notez enfin que si vous utilisez une adresse sur 7 bits, elle ne pourra jamais, videmment,commencer par B 11110366Afin dtre certain que vous avez tout compris, je vous donne le chronogrammecorrespondant (jai considr que les flancs des signaux taient verticaux, cest plus simple dessiner cette chelle) :Vous constaterez en lisant les chronogrammes prsents dans les documentationstechniques des composants, quon ne vous donne que la ligne SDA rsultante. Celle-ci dfinitle niveau prsent sur la ligne, mais il ne faut jamais oublier que le matre et lesclave placentdes bits tour de rle sur la mme ligne.Vous voyez ici, par exemple, que durant lacknowledge, le matre libre la ligne SDA(niveau 1). A ce moment, cest lesclave qui impose le niveau bas de confirmation. Vous endduirez ce moment que lorsque le matre crit (en rouge), lesclave lit, lorsque lesclavecrit (en bleu), le matre lit.Ceci explique que pour un nophyte, ces chronogrammes ne sont pas toujours aiss comprendre. Nul doute quaprs avoir lu ce chapitre, vous trouverez la norme IC commesimple comprendre.Nous venons de crer le dbut de notre trame, savoir le start-condition (S) envoy par lematre, le premier octet dadresse galement envoy par le matre, suivi par laccus derception de lesclave (ACK) envoy par lesclave. Suit ventuellement un second octetdadresse (adresse sur 10 bits), complt de nouveau par laccus de rception.Remarquez que, si vous vous tes poss la question, aprs lenvoi du premier octet, dansle cas dune adresse code sur 10 bits, il pourrait trs bien y avoir plusieurs esclavesconcerns par ce premier octet (plusieurs esclaves dont ladresse tient sur 10 bits). Il se peutdonc quil y ait plusieurs esclaves diffrents qui envoient en mme temps leur accus derception. Ceci na aucune importance, lors de lenvoi du second octet, il ny aura plus quunseul esclave concern.Si on ne reoit pas un ACK , cest soit que lesclave slectionn nexiste pas, soit quilnest pas prt.367A ce stade, nous avons choisi notre esclave, reste savoir ce quon attend de lui. Nousavons ce stade, 2 possibilits :- Soit nous allons lui envoyer un ou plusieurs octets de donne- Soit nous allons recevoir de lui un ou plusieurs octets de donneLa slection de lun ou lautre cas dpend de la valeur que vous avez attribu votre bitR/W.- Si R/W = 0, les octets suivants sont envoys par le matre et lus par lesclave (criture)- Si R/W = 1, les octets suivants sont envoys par lesclave et lus par le matre (lecture)Corollaire : il nest pas possible, en IC, dcrire et de lire en mme temps. Si vous dsirezeffectuer une lecture et une criture, ceci ncessitera 2 oprations, donc 2 envois du start-sequence.Maintenant, si vous avez suivi, vous devez vous dire : mais alors, puisque le bit R/W dupremier octet dadresse dans le cas dune adresse sur 10 bits vaut toujours 0, comment donceffectuer une lecture en mode 10 bits ? .En fait, ceci est un peu plus compliqu. Il faut comprendre que limposition du bit R/W 0 se justifie pour llectronique des circuits concerns. Les esclaves devront en effet lire lesecond octet dadresse, il sagit donc dune criture (vu du ct du matre). La solution pour lalecture dans les adresses 10 bits est la suivante :- Le matre envoie le start-condition- Le matre envoie le premier octet dadresse, avec R/W 0 - Le matre envoie le second octet dadresse- Le matre envoie un repeated start-condition- Le matre envoie le premier octet dadresse, avec R/W 1 - Le matre commence la rception des donnes.Vous remarquez que le matre doit reprciser le bit R/W 1 . Comme ce bit est contenudans le premier octet dadresse, il doit donc renvoyer ce dernier. Et comme il conserve ledialogue (il na pas envoy de stop-condition), il sadresse donc toujours en fait au mmeesclave, et na pas besoin de rpter le second octet dadresse.Voici ce que donne lenvoi dune adresse 10 bits pour une lecture :368Voyons tout dabord le cas de lcriture. Je parlerai pour faire simple dadresses codessur 7 bits, pour les adresses sur 10 bits, il suffira dajouter un ou deux octet, vous avezcompris la manuvre. La procdure est la suivante :- Le matre envoie le start-condition (S)- Le matre envoie loctet dadresse, avec le bit R/W 0 (criture)- Lesclave rpond par ACK - Le matre envoie le premier octet de donne- Lesclave rpond par ACK - - Le matre envoie le dernier octet de donne- Lesclave rpond par ACK ou par NOACK - Le matre envoie le stop-condition (P)Notez quil est possible, pour lesclave denvoyer un NOACK (cest--dire un bit ACK 1 ) pour signaler quil dsire que le matre arrte de lui envoyer des donnes(par exemple si sa mmoire est pleine, ou si les octets reus sont incorrects etc.).Le matre dispose de la possibilit de mettre fin au transfert en envoyant le stop-sequence(P).Voici ce que a donne dans le cas o le matre envoie une adresse code sur 7 bits et 2octets de donnes destination de lesclave.Le cas de la lecture nest pas plus compliqu. Voici la squence, toujours pour une adressecode sur 7 bits :- Le matre envoie le start-condition- Le matre envoie le premier octet dadresse, avec le bit R/W 1 (lecture)- Lesclave rpond par ACK - L esclave envoie son premier octet de donne- Le matre rpond par ACK - - Lesclave envoie le xme octet de donne- Le matre rpond NOACK pour signaler la fin du transfert- Le matre envoie le stop-sequence (P).Notez que cest le matre seul qui dcide de mettre fin la rception. Il doit alorscommencer par envoyer un NOACK , ce qui signale lesclave quil na plus besoin detransmettre, suivi par un stop-sequence qui met fin la transmission.Comme cest le matre qui envoie le ACK chaque fin de lecture, lesclave na aucunmoyen de faire savoir quil dsire que la lecture sarrte.Voici ce que cela donne :369Vous voyez que de nouveau, tout est logique. Le dbut de la squence est toujoursidentique, le matre envoie toujours le start, ladresse, et le bit R/W. Lesclave donne toujoursle premier acknowledge.A partir de loctet qui suit lenvoi de ladresse, cest lesclave qui place les donnes surSDA, et donc le matre qui rpond par lacknowledge. La dernire requte se termine parlenvoi, par le matre, dun NOACK prcdent le stop-condition.Notez cependant que cest toujours le matre qui pilote la ligne SCL.22.4 Evnements spciauxIl nous reste voir quelques squences particulires qui compltent cette gestion du busIC.22.4.1 La libration du busNous avons vu que le matre prend le contrle du bus avec le start-condition. A partir dece moment, les autres matres ventuels doivent attendre que le matre ait termin sestransactions avant de tenter de prendre leur tour le contrle du bus.La libration du bus est effective une fois que 4,7 s se sont coules depuis lenvoi dustop-sequence, aucun nouveau start-sequence nayant t reu.22.4.2 Le repeated start-conditionSi le matre dsire envoyer une seconde trame, au lieu de terminer la trame en cours parun stop-condition, il la terminera par un nouveau start-condition. Ce dernier porte dans ce casle nom de SR pour repeated start-condition . Sa fonction est strictement identique au start-condition, mais ne libre pas le bus comme risquerait de le faire la combinaison stop-sequence/start-sequence. Le matre actuel empche donc un autre matre de saccaparer lebus.Le repeated start-condition marque en mme temps la fin dune transaction, et le dbutdune suivante.22.4.3 La pauseUn autre cas particulier est celui ou, lors dune criture, lesclave demande au matre depatienter durant un certain temps (par exemple le temps mis pour traiter loctet prcdent).370La mthode est simple, lesclave bloque la ligne dhorloge SCL ltat bas durant lapause demande. Lorsque le matre essaye denvoyer limpulsion dhorloge, il ny arrive pas,puisquelle est force ltat bas par lesclave. Le matre dispose dune lectronique internequi lui permet de vrifier ltat de SCL.Lorsquil est de nouveau prt, lesclave libre la ligne SCL, qui prend alors ltat haut. Lematre peut alors poursuivre.Tant que la ligne SCL est bloque, le matre resette son gnrateur de temps interne.Autrement dit, la libration de la ligne SCL, les chronogrammes de gnration dhorlogeseront respects. Vous voyez que limpulsion de SCL qui suit la fin de la pause a strictementla mme dure que toutes les autres impulsions.22.5 Arbitrage du busVous trouverez partout, dans les datasheets concernant les composants IC, la notiond arbitration , pour arbitrage.Cest dans cette capacit quont ces composants de grer les conflits que rside toute lapuissance du bus IC. Ces mthodes permettent de disposer dun bus comportant plusieursmatres, et permettent des systmes totalement dcentraliss, dans lesquels chacun peutlibrement prendre la parole.Il faut pour comprendre ce qui suit, avoir bien compris que le niveau 0 est prioritairesur le niveau 1 . Si un circuit quelconque passe une ligne 0, cette ligne sera force 0. Sipar contre le circuit demande que la ligne passe 1 (libration de la ligne), celle-ci nepassera 1 que si aucun autre circuit ne la force 0 .Bien entendu, les circuits ne peuvent pas prendre la parole nimporte quand ni nimportecomment. Il importe, comme lors dune discussion entre humains, de respecter les rgles decourtoisie lmentaires (quoi que certains, au vu de certains forums, semblent sen passer sansproblme).371La premire question qui se pose est : quand un matre peut-il prendre la parole ?La rponse est simple : quand le bus est libre. Il nous faut alors tablir quelles sont lesconditions dans lesquelles le bus peut tre considr comme tel.Tout matre est capable de dtecter automatiquement les start et stop-conditions .Ds lors, ds quun start-condition est dtect, le bus est considr occup jusqu ladtection du stop-condition correspondant. A partir de ce moment, si le matre prcdentne reprend pas la parole avant 4,7 s, le bus est considr comme libre.Si le nouveau matre vient de se connecter au rseau, il lui suffit de sassurer que la ligneSCL soit ltat haut depuis au moins 4,7s pour vrifier quun autre matre ne dirige pas lebus. Dans la pratique, certains matres nattendent mme pas cette limite de 4,7s poursassurer que le bus soit libre, a ne pose pas de problme de fonctionnement particulier.Vous allez me dire : cest bien beau, tout a, mais si 2 nouveaux matres prennent lecontrle en mme temps ? Et bien, rassurez-vous, cest galement prvu, et gr de faon automatique. Imaginonsque le bus soit libre, et que les matres 1 et 2 saccaparent le bus en mme temps.Chaque matre dispose dune lectronique qui vrifie en permanence la correspondanceentre les niveaux appliqus sur SDA et SCL, et les niveaux lus en ralit sur ces lignes. Sil ya discordance, cest quun tiers prend le contrle de cette ligne. Nous en avons dj vu unexemple lorsque lesclave imposait une pause via la ligne SCL.Nous savons donc que les 2 matres vont placer leurs donnes sur la ligne SDA et quelesclave lira la donne place sur le flanc montant de SCL.Mais les matres galement vont lire automatiquement la ligne SDA. Si un matre place unniveau 0, le niveau lu sera obligatoirement 0. Si, par contre, le matre place un niveau 1, etquun autre matre a plac la valeur 0, le premier va constater quil y a un autre matre,puisque la ligne SDA vaudra 0 alors quil a plac 1 . Le second matre ne vasapercevoir de rien du tout, puisque la ligne SDA est bien 0.Dans ce cas, le matre qui na pas pu imposer son niveau 1 perd le contrle du bus, etse retire au profit du matre prioritaire .Voici ce que a donne :372Dans cet exemple, le matre 2 dsire placer ladresse B0010011, soit D19. Le matre 2tente de placer ladresse B0010100, soit D20. Vous voyez que le premier matre quienvoie un bit 1 en mme temps que le matre 2 place un 0 est mis hors-jeu. On peutdj en dduire les rgles suivantes :- Les adresses les plus faibles sont prioritaires par rapport aux adresses plus leves. Dansla construction dun systme, les esclaves les plus prioritaires se verront donc affecter lesadresses les plus basses- En cas dadresses identiques, lcriture a priorit sur la lecture (car le bit R/W vaut 0 pourlcriture).- Les collisions sont dites non destructives , puisque la donne prioritaire arriveintacte au destinataire.Corollaire : ce ne sont pas les matres qui sont prioritaires les uns par rapport aux autres,les priorits sont fonctions des trames envoyes.Donc, si vous avez tout compris, si, au mme moment, un matre tente de slectionnerlesclave xx, et quun autre matre tente de slectionner lesclave yy, celui qui envoieladresse la plus leve devra se retirer du bus.Vous allez me rtorquer quil se peut trs bien que les 2 matres accdent au mmeesclave. Fort bien, mais cela ne pose de nouveau aucun problme. Nous avons 2 possibilits :Tout dabord, les 2 matres effectuent une lecture. Dans ce cas, il ny a absolument aucunproblme. Les 2 matres envoient tous les deux une requte de lecture de lesclave, qui va leurrpondre tous les deux en mme temps. La requte tant la mme, la rponse est doncidentique et valide.Si, par contre, les 2 matres effectuent une criture, ladresse va tre complte par lesoctets de donne. Dans ce cas, si les 2 matres crivent la mme chose, tous les intervenantsny verront que du feu. Lesclave crira la donne, valide puisquelle est identique pour les 2matres.Si les 2 matres ncrivent pas la mme chose, nous allons nous retrouver avec un conflitdu mme type que celui concernant ladresse. A un moment donn, un des matres va tenter373dcrire un 1 , et lira 0 sur la ligne SDA. Il se retirera donc de la communication. Lapriorit sera une fois de plus affecte loctet de donne de valeur la plus faible.Vous voyez qu partir de ce moment, tous les problmes de conflits de bus sont rsolus.Bien entendu, tout ceci est automatique dans les circuits intgrs. Le programmeur reoit doncsimplement des indicateurs qui linforment de ltat actuel de la transmission.Et si 2 esclaves diffrents tentent dcrire en mme temps ? Et bien, cest tout simplementimpossible, chaque esclave doit, par dfinition, avoir une adresse diffrente, et ne peutrpondre que sil est slectionn.Si vous avez besoin de rendre un matre prioritaire, il suffit que le dlai qui spare ladtection du stop-condition de la prise de contrle du bus soit plus court que pour les autresmatres. Autrement dit, vous introduirez un dlai plus ou moins long entre la dtection dustop-condition et le fait de considrer que le bus est libre. Ainsi, le matre qui disposera dudlai le plus court pourra simposer en premier.De cette faon, vous pouvez choisir entre donner priorit un matre donn, ou priorit ladresse de destination la plus petite.Si vous tes attentifs, vous pouvez encore protester, en dmontrant que les 2 matrespeuvent tenter de prendre le contrle du bus, mais dune faon lgrement dcale (un desdeux ragit un peu plus vite que lautre). Dans ce cas, il faut en revenir au start-condition,dans lequel le matre fait descendre la ligne SDA 0 . Le matre le plus lent verra donc laligne SDA descendre avant mme quil ne lai positionne. Il se retirera donc du bus avantmme davoir tent la moindre action.Dernire petite question : un matre peut-il parler un autre matre ? En fait, non. Dunepart, seuls les esclaves ont une adresse, et seuls les esclaves subissent lhorloge. Par contre,rien ninterdit un matre, lorsquil na rien dire, de se configurer en esclave. Alors il peutchanger des informations avec un matre.Jen reste l pour la thorie gnrale, je pourrais vous parler de l IC high-speed , maissi vous avez compris ce qui prcde, et que vous avez besoin dun tel composant, il vous seraais de le mettre en uvre.Ce que je prfre faire, par contre, cest vous donner un exemple concret de circuitcourant utilisant LIC. Jai choisi de vous expliquer la faon dont fonctionne une eeprom detype 24C32, 24C64 ou autre (attention, la 24C16 fait exception).Lisez ceci, car jutiliserai cette eeprom dans le cadre de notre exercice pratique sur LIC.22.6 Les eeprom ICAvec ce chapitre, je vais vous montrer comment interprter un datasheet de composantIC. Jai reu normment de courrier concernant ces composants et le mode IC, ce quijustifie, ce cours tant destin rendre service au plus grand nombre, que je my attarde.374De plus, je suis persuad que si vous devenez un adepte des microcontrleurs, vous aurezun jour ou lautre besoin dun composant de ce type.22.6.1 Caractristiques gnralesPour que tout le monde parte sur les mmes bases, je vous fournis le datasheet du 24C64en format pdf, et en direct de chez Microchip.Tout dabord, un il sur le tableau de la premire page nous montre quil sagit duncircuit qui accepte une frquence dhorloge de maximum 400KHz. Nous sommes donc enplein dans la norme IC seconde gnration.Les tensions sont compatibles avec notre PIC. Notez que la norme IC nimpose pas lavaleur de la tension de rappel au niveau haut. Suivant les technologies, vous pourriez vousretrouver avec des composants ncessitant des tensions diffrentes (12V). Dans ce cas, desimples rsistances de protection vous permettraient dinterfacer facilement ces composantsavec votre PIC.Un coup dil aux caractristiques vous informe que vos donnes sont labris pour unedure minimale garantie de 200 ans. Si vous perdez vos sauvegardes au bout de 100 ou 150ans, courez donc vite vous plaindre chez Microchip.1.000.000 de cycles deffacement/criture sont de plus garantis (vous avez le temps deprocder des exprimentations).Microchip vous informe galement sur cette premire page, que la 24C64 (ou 24LC64, ou24AA64) dispose de 64Kbits de mmoire. Attention, Kbits et non Kbytes. Ceci nousdonne en fait 8Kbytes de donnes mmorises.On vous parle galement de random access et de sequential access . La notion de random pour alatoire , signifie que vous pouvez accder nimporte quelle casemmoire, sans avoir parcourir lensemble. Si vous imaginez un livre, cela signifie que vouspouvez ouvrir ce livre nimporte quelle page. Sequential , pour squentiel signifie exactement linverse. Vous pouvez crire oulire adresse aprs adresse, dans lordre croissant, sans avoir vous proccuper de dfinir chaque fois ladresse.Ceci vous indique donc que les accs offrent beaucoup de souplesse. On vous parle deplus de page-write . Nous verrons que cela permet dcrire toute une srie doctets (sur lamme page de 32) en une seule opration dcriture.Page 2, vous trouvez les contraintes lies aux signaux, contraintes qui restent bien entenduconformes la norme IC. Rien dinquitant pour nous.Le petit tableau 1-1 en haut droite, nous donne la fonction des pins de cette eeprom. Ony voit que 3 pins, A0, A1, et A2 sont des pins qui sont utilises par lutilisateur pour dfinir laslection du circuit. Nous y reviendrons. Nous trouvons en plus les 2 lignes dalimentation, cequi est logique, et les 2 lignes du bus, SCL et SDA, obligatoires pour tous les circuits IC.375On notera une dernire pin, WP, qui permet, lorsquelle est place au niveau haut,dinterdire les critures dans la mmoire, tout en autorisant les lectures. Si cette pin estconnecte la masse, ou nest pas connecte du tout, les oprations dcritures sontautorises.Nous arrivons au tableau 1-3 de la page 3. Ce tableau poursuit les caractristiquesprcdentes. Jetez un il sur la ligne bus free time . Vous voyez quil est indiqu que lebus doit tre libre depuis 4700 ns avant quune nouvelle transmission puisse avoir lieu. Nousretrouvons donc bien nos fameuses 4,7s entre le stop-condition et le moment o lescomposants considrent que le bus est libre.Encore plus bas dans le tableau, vous voyez input filter . Sachez que tous lescomposants IC sont munis dun filtre destin liminer les parasites. Notre PIC en estgalement pourvu, jen reparlerai au moment voulu.Lavant-dernire ligne nous indique quune opration dcriture ncessite 5ms maximum,ce qui est norme par rapport aux vitesses mises en jeu. Une opration dcriture est lcrituredun seul octet, ou dun groupe doctets (maximum une page). Vous avez donc intrt utiliser les procdures dcriture par page lorsque vous avez plusieurs octets conscutifs crire. Jexpliquerai plus loin comment savoir que lcriture est termine.Dailleurs, le plus loin ne lest pas tant que a. Si vous tournez la page, vous voyez ladescription des pins dont jai dj parl, et les caractristiques du bus, qui sont bien entenducelles du bus IC. Un encadr est important, il signale que leeprom nenvoie pas son accusde rception (donc le matre lira un NOACK ) si un cycle prcdent dcriture nest pastermin. Voici donc comment savoir si le cycle est oui ou non termin.La page 5 montre comment se passe le transfert, cest--dire de faon strictementconforme au protocole IC (heureusement).22.6.2 Octet de contrle et adresse esclaveOn arrive aux choses srieuses avec la page 6. La figure 5-1 vous montre le format deloctet de contrle. Octet de contrle ? Quest-ce que cest que cette nouveaut ? Pas de panique, Il sagit tout simplement de loctet dadressage, donc le premier octetmis par le matre et le premier reu par lesclave, cest--dire leeprom.Vous allez me dire que je nai dit nulle part que leeprom est un composant esclave. Cestvrai, mais il faut faire de temps en temps fonctionner sa tte. En fait, ce nest pas leeprom quidcide si on la lit ou on lcrit. Ce nest pas non plus leeprom qui dcide quel momentenvoyer ou recevoir des donne. De plus, la figure 5-1 nous montre que leeprom a uneadresse, et cest le composant esclave qui dispose dune adresse. Tout ceci nous dmontre queleeprom est un circuit IC esclave.Voyons loctet dnomm de contrle par Microchip. Bien entendu, nous, nous savonsquil sagit tout simplement de loctet dadresse, envoy directement aprs le start-condition :376Microchip a utilis le terme contrle probablement pour ne pas que lutilisateurconfonde ladresse de leeprom (contrle) et ladresse de loctet concern dans leeprom.Nous constatons immdiatement quon nous impose les 4 premiers bits de ladresse deleeprom, les 3 bits restants tant notre convenance. Comme toujours, cette adresse setermine par le bit R/W. Nous pouvons en dduire que :- Notre eeprom sera adresse obligatoirement dans la plage : B1010000 B1010111.- Cest une adresse assez leve, les eeproms ntant pas considrs comme des composantsprioritaires- Nous avons 8 possibilits de choix de ladresse, fonctions de A2,A1, et A0.- Nous pouvons de ce fait placer, sans artifice, un maximum de 8 eeproms sur notre bus.- Nous avons besoin dune possibilit de choisir ces 3 bits.- Nous avons affaire un adressage sur 7 bits.Arrivs ce stade, vous devez savoir que les bus IC sont destins recevoir une foule decomposants diffrents. Or, chaque composant doit avoir une adresse distincte. Lesconstructeurs de circuits intgrs se sont donc mis daccord pour rserver certaines plagesdadresses des composants particuliers. Ceci permet dviter les conflits malheureux quirendraient impossibles certaines cohabitations.Les adresses commenant par 1010 sont en gnral rserves aux eeproms. Il nousreste dfinir les 3 bits dadressage pour notre ou nos eeproms.En fait, cest tout simple, nous avons vu que notre eeprom dispose de 3 broches A0, A1, etA2. Cest le niveau plac sur ces pins qui dfinira ladresse.Par exemple, si vous placez du +5V ( 1 ) sur la pin A1, alors le bit A1 de ladressevaudra 1 . Si vous reliez cette mme pin la masse ( 0 ), alors le bit A1 de ladressevaudra 0 . Vous choisissez donc ladresse finale de votre eeprom au moment de laconnexion physique de celle-ci sur son circuit.Ladresse est donc configurable au moment de la cration du circuit, et ne peut pas tremodifie par logiciel.La plus petite adresse possible sera : B1010000, soit D80 ou 0x50. La plus grande seraB1010111, soit D87 ou 0x57. Voyons donc comment interfacer nos 8 eeproms sur uncircuit, et quelles seront leurs adresses respectives.377Je nai reprsent que les lignes +5V et 0V. Les lignes SDA et SCL respectives de chaquecircuit devront bien videmment tre relies entre elles et au bus IC.La pin WP sera laisse non connecte, ou relie la masse pour une utilisation normale, etconnecte au +5V pour protger leeprom. Bien entendu, il nest pas interdit de connecter cespins WP une pin de votre PIC, de faon commander la protection en criture par logiciel.Si vous avez besoin de plus de 8 eeproms, vous pouvez galement utiliser desmcanismes de slection de groupes deeprom partir de votre PIC, en laissant ou non passerlhorloge SCL, mais ceci dborde du cadre de ces explications, et du bus IC dans son sensstrict.Vous voyez que dans cet exemple, chacune des 8 eeproms rpondra une adresse unique,comprise entre 0x50 et 0x57. Je nai pas reprsent les interconnexions des lignes SCL etSDA, mais je vous en ai dj parl tout au dbut du chapitre.37822.6.3 Slection dune adresse interneNous venons de dfinir ladresse IC, cest--dire ladresse physique sur le bus de chaquecircuit eeprom. Mais, lorsquon opre dans une mmoire, il nous faut encore savoir quelleadresse on lit ou on crit parmi les 8Koctets possibles quelle contient.Il ne faut pas, ce niveau, confondre ladresse du circuit, et ladresse de la donne lireou crire.Pour slectionner une adresse dans une eeprom, il suffit, directement aprs le premieroctet dadressage du circuit, dcrire dans leeprom slectionne ladresse, code sur 2 octets, laquelle devra sinitialiser son pointeur interne.Donc, mme si on doit lire un emplacement mmoire, on doit crire ladresse (R/W = 0).Jinsiste donc une nouvelle fois : ladresse sur laquelle on travaille dans leeprom doit trecrite par le matre.Toutes les oprations sur les eeprom se ralisent en effet sur lemplacement dsign parun pointeur interne. Ceci fonctionne exactement comme pour ladressage indirect des PICs.Avant de pouvoir utiliser la case pointe par INDF , vous deviez en effet initialiser lepointeur FSR , il en est de mme ici.La slection dune adresse seffectue donc fort logiquement de la faon suivante :- Le matre envoie le start-condition- Le matre envoie le premier octet avec ladresse de leeprom et le bit R/W 0 (criture)- Leeprom envoie laccus de rception (ACK)- Le matre envoie les 2 octets de ladresse de loctet concern.Notez que ladresse de loctet doit tenir dans la plage des 8Koctets disponibles, ce quidonne une adresse code sur 13 bits (de B0000000000000 B1111111111111, soit de0x00 0x1FFF). Comme on envoie 2 octets, cela nous donne 16 bits.Ladresse sera aligne vers la droite, ce qui implique que les 3 bits gauche du premieroctet (poids fort) seront inutiliss. On les placera de prfrence 0, pour toute compatibilitfuture avec une eeprom de capacit suprieure.Autrement dit :Jai not ladresse de lesclave en majuscules (Ax) et la valeur dinitialisation du pointeurde leeprom (adresse de loctet) en minuscules (ax). Ceci afin de ne pas vous embrouiller avecces diffrentes notions dadressage.A ce niveau, il faut se souvenir que le premier ACK envoy par lesclave signale sicelui-ci est prt. Si lesclave rpond ce moment NOACK (donc ne rpond pas), cest379quil na pas termin lopration prcdente, il faut donc recommencer la tentative jusqu ceque la rponse soit ACK .Evidemment, si vous adressez un esclave qui nexiste pas, vous obtiendrez galement un NOACK , puisque personne naura plac la ligne SDA 0 . Dans ce cas, vous risquezdattendre longtemps.22.6.4 Ecriture dun octetNous savons maintenant choisir une eeprom, et slectionner une adresse dans cetteeeprom. Nous allons voir comment crire une donne lemplacement choisi.La procdure est trs simple, elle consiste initialiser le pointeur dadresse, puis envoyer directement aprs loctet de donne. Leeprom sait parfaitement que loctet suivantdevra tre crit lemplacement spcifi. Cest bien entendu le bit R/W qui indique leeprom quil sagit dune criture.Donc, dans lordre :- Le matre envoie le start-sequence- Le matre envoie ladresse de leeprom avec le bit R/W 0 (criture)- Leeprom, si elle est prte, rpond ACK - Le matre envoie le poids fort de ladresse concerne- Leeprom rpond ACK - Le matre envoie le poids faible de ladresse concerne- Leeprom rpond ACK - Le matre envoie la donne crire en eeprom- Leeprom rpond ACK - Le matre envoie le stop-sequence.Sous forme de chronogramme simplifi :Pour faire un peu plus concret, imaginons que nous voulions crire la valeur 0x3D ladresse 0x1A58 de notre EEPROM, sur laquelle les pins A2 et A0 sont connectes lamasse et A1 au +5V. Voici ce que nous devons envoyer :Et voil, rien de plus simple. Vous savez maintenant comment crire un octet dans uneeeprom 24c64 ou assimile.38022.6.5 Ecriture par page Nous avons vu que nous pouvions crire un octet nimporte quelle adresse de notreeeprom. Mais cette opration dcriture ncessite leeprom un temps de traitement internede 5ms. Durant ces 5ms, leeprom rpondra NOACK toute nouvelle tentative dcriture.Pour crire nos 8*1024 octets, il nous faudrait, en pratiquant de la sorte, 8 * 1024 * 5ms,soit plus de 40 secondes. Cette mthode nest donc gure pratique pour les critures multiplesdoctets.Heureusement, nous avons la possibilit dcrire des srie doctets en une seule oprationdcriture. Nous parlerons ici du cas de la 24C64, dont chaque page fait 32 octets. Cette taillevarie en fonction du type deeprom, une 24C512 dispose de pages de 128 octets, par exemple.Ceci est rendu possible par un mcanisme interne leeprom, qui incrmenteautomatiquement les 5 bits de poids faible du pointeur dadresse (b0 b4). Attention, il ny apas de report sur le bit b5 pour la 24C64. (en fait, leeprom utilise un buffer interne, maiscest transparent pour lutilisateur).Il suffit donc de placer les octets de donne les uns la suite des autres, ils seront critsautomatiquement dans les adresses successives de leeprom.Donc, nous aurons des trames du style :Supposons que ladresse dfinie soit 0x1180 :Loctet 0 sera crit : 0x1180 + 0x00 = 0x1180Loctet 1 sera crit : 0x1180 + 0x01 = 0x1181....L octet 31 sera crit : 0x1180 + 0x1F = 0x119FAttention cependant au pige. Si vous dfinissez une adresse de base de 0x115E, parexemple :0x115E = B0001 0001 0101 1110Loctet 0 sera crit ladresse 0x115ELoctet 1 sera crit ladresse 0x115FA quelle adresse sera crit loctet 2 ? Si vous me rpondez : 0x1160 , vous tes tombsdans le pige. Voyons en binaire :Loctet 2 sera crit ladresse : B0001 0001 0101 1110381+ B0000 0000 0000 0010-----------------------------------= B0001 0001 0100 0000En effet, je vous ai dit que lincrmentation ne concernait que les 5 bits de poids faible (b4 b0), le bit b5 nest donc pas affect par lincrmentation.Ceci vous prcise que loctet 2 sera crit ladresse 0x1140.Donc, lincrmentation ne seffectue correctement que si lensemble des adresses desoctets crits se trouvent dans la mme page de 32. Le cas optimal est obtenu si ladressepasse comme second et troisime octet de la trame est une adresse dont les 5 bits de poidsfaible sont gaux 0. Dans ce cas, on se trouve en dbut de page, et on peut donc crire 32octets simultanment.Comme lcriture de ces 32 octets ne ncessite pas plus de temps que lcriture dunseul, le temps ncessaire pour remplir toute notre eeprom sera divise par un facteur de 32,soit moins de 2 secondes.Partant de la, il vous est trs simple de dcouvrir quelle mthode utilise votreprogrammateur deeprom.Je rsume les 2 mthodes dcriture :- Soit vous envoyez ladresse dcriture suivie par loctet crire- Soit vous envoyez ladresse de dpart suivie par un maximum de 32 octets, qui serontcris squentiellement dans la mmoire.Tout ce qui prcde est valable pour la 24C64. Sur une 24C512, par exemple, vouspourrez envoyer 128 octets de data, le bit 7 du pointeur dadresse interne ntant pas affectpar lcriture. Renseignez-vous selon le type deeprom que vous utiliserez.22.6.6 La lecture alatoireAlatoire (random) est prendre ici dans le sens de nimporte o , et non en commesignifiant au hasard . Cette dernire dfinition naurait dailleurs aucun intrt.Pour lire un octet une adresse spcifique, il faut raliser les oprations suivantes :- Initialiser le pointeur dadresse de leeprom- Lire loctet concern- Envoyer un NOACK pour signifier la fin de la transaction.Donc, vous voyez que ceci ncessite une opration dcriture (le pointeur dadresse),suivie par une opration de lecture (loctet lire).382Comme le bit R/W dfinissant le sens de transfert nexiste que dans le premier octetsuivant le start-condition, vous voyez dj quil vous faudra envoyer 2 fois ce premier octet,donc 2 fois le start-condition.Vous pouvez procder en une seule tape, ou en 2 tapes successives. Si vous utilisez 2tapes, vous aurez :- Le matre envoie le start-condition (S)- Le matre envoie ladresse de leeprom avec le bit R/W 0 (criture)- Leeprom envoie laccus de rception (ACK)- Le matre envoie loctet fort de ladresse lire- Leeprom envoie laccus de rception (ACK)- Le matre envoie loctet faible de ladresse lire- Leeprom envoie laccus de rception (ACK)- Le matre envoie le stop-condition (P)- Le matre envoie le start-condition (S)- Le matre envoie ladresse de leeprom avec le bit R/W 1 (lecture)- Leeprom envoie laccus de rception (ACK)- Leeprom envoie loctet lire- Le matre envoie un NOACK - Le matre envoie le stop-condition (P)Autrement dit :Si vous utilisez la mthode conseille, cest--dire en une seule tape, vous remplacezsimplement le stop-condition suivi du start-condition par un repeated start-condition (SR),ce qui nous donne :- Le matre envoie le start-condition (S)- Le matre envoie ladresse de leeprom avec le bit R/W 0 (criture)- Leeprom envoie laccus de rception (ACK)- Le matre envoie loctet fort de ladresse lire- Leeprom envoie laccus de rception (ACK)- Le matre envoie loctet faible de ladresse lire- Leeprom envoie laccus de rception (ACK)- Le matre envoie le repeated start-condition (SR)- Le matre envoie ladresse de leeprom avec le bit R/W 1 (lecture)- Leeprom envoie laccus de rception (ACK)- Leeprom envoie loctet lire- Le matre envoie un NOACK - Le matre envoie le stop-condition (P)383Ou, sous forme de chronogramme simplifi :Donc, pour rsumer, vous crivez ladresse, puis vous lisez la donne. Le passage entrelecture et criture ncessite de devoir renvoyer le start-condition (SR).22.6.7 La lecture de ladresse couranteVous avez vu que si nous dcidons deffectuer une lecture alatoire en 2 tapes, nouscommenons par envoyer ladresse de lecture, puis nous procdons la lecture en elle-mme.En fait, si vous rflchissez, ceci quivaut dire :- Jinitialise le pointeur dadresse de leeprom- Je lis ladresse courante.En effet, le pointeur dadresse reste mmoris dans leeprom. A tout moment, vousdisposez donc de la possibilit de lire ladresse qui est actuellement pointe par le pointeurdadresse.REMARQUE : La lecture dun octet provoque automatiquement lincrmentation dupointeur dadresse. Donc, la prochaine lecture renverra loctet suivant, et ainsi de suite. Si lepointeur dpasse la capacit de la mmoire, il recommence 0.22.6.8 La lecture squentielleEt bien, de nouveau, cest tout simple. Cette procdure permet de lire plusieurs octetsconscutifs. Ceci fonctionne exactement comme pour lcriture par page, except que nousretrouvons pas ici les contraintes de page. Nous pouvons donc lire lintgralit de la mmoireeeprom en une seule opration, nous ne sommes pas limits 32 octets.Nous procdons comme pour la lecture alatoire, mais au lieu que le matre envoie un NOACK aprs avoir lu loctet, il envoie un ACK , qui signale leeprom quil souhaitelire loctet suivant. Ce nest quau dernier octet que le matre enverra un NOACK .384La procdure est la suivante :- Le matre envoie le start-condition (S)- Le matre envoie ladresse de leeprom avec le bit R/W 0 (criture)- Leeprom envoie laccus de rception (ACK)- Le matre envoie loctet fort de ladresse lire- Leeprom envoie laccus de rception (ACK)- Le matre envoie loctet faible de ladresse lire- Leeprom envoie laccus de rception (ACK)- Le matre envoie le repeated start-condition (SR)- Le matre envoie ladresse de leeprom avec R/W 1 (lecture)- Leeprom envoie laccus de rception (ACK)- Leeprom envoie loctet lire- Le matre envoie un ACK - Leeprom envoie loctet suivant lire- Le matre envoie un ACK - Leeprom envoie loctet suivant lire- ..- ..- Leeprom envoie loctet suivant lire- Le matre envoie un NOACK - Le matre envoie le stop-condition (P)Ce qui nous donne :22.6.9 Le cas de la 24C16Bon, juste un mot sur leeprom 24C16, dont je vous ai dit quelle ntait pas compatible.Jen parle pour mviter du courrier, car jai comme une intuition ce sujet.Sur la 24C16, les pins A0, A1, et A2 existent, mais ne sont pas connectes lintrieur deleeprom. Elles ne peuvent donc pas servir pour slectionner ladresse.Premire dduction : on ne peut mettre quune et une seule eeprom 24C16 par bus.Nos bits A2,A1, et A0 du premier octet sont donc libres. Ils sont en fait utiliss commebits de poids fort de ladresse de loctet concern. Leeprom 2416 contient 16Kbits demmoire, donc 2Koctets. Ladresse dun octet se code de ce fait sur 11 bits. Donc, si vous mesuivez toujours :385Sur une 24C64, on a :- start-condition- premier octet = 1010 A2 A1 A0, avec A2/A0 adresse physique de leeprom- second octet = MSB adresse = x x x a12 a11 a10 a9 a8- troisime octet = LSB adresse = a7 a6 a5 a4 a3 a2 a1 a0Sur une 24C16, on aura- start-condition- premier octet = 1010 a10 a9 a8, avec a10/a8 = 3 bits de poids fort de ladresse de loctet- second octet = a7 a6 a5 a4 a3 a2 a1 a0Autrement dit, leeprom 24C16 rpond en fait 8 adresses diffrentes pour un seul circuit.Cest une astuce qui permet de gagner un octet en mission, mais se paye par loccupation de8 adresses pour un seul circuit. Cest pour a que vous lisez souvent que la 24C16 nest pascompatible avec les autres eeprom (24c32, 24c64).Vous pouvez donc remplacer sans problme dans un montage une 24C32 par une 24C64,mais vous ne pouvez remplacer une 24c16 par une autre 24cxx que si vous modifiez lelogiciel du matre en consquence.22.6.10 ConclusionsNous venons dtudier tout le datasheet de leeprom 24C64. Vu le nombre important dequestions que jai reues ce sujet, il ma paru ncessaire deffectuer cette analyse. Ceci vousouvrira de plus les portes des nombreux autres priphriques IC.Ceci clture notre tude thorique du bus IC. Nous allons maintenant tudier commentces options sont disponibles sur nos 16F87x.386Notes : 38723. Le module MSSP en mode IC23.1 IntroductionNous avons vu que le bus IC permettait plusieurs configurations diffrentes, ncessitait lagestion de larbitrage du bus, des diffrents vnements etc.Notre 16F87x est capable de grer tout ceci de faon automatique. Nous allons donctrouver :- La gestion des modes esclave, matre, et multi-matre- La gnration et la dtection de start et stop-condition- La gnration et la reconnaissance des signaux ACK - La gnration automatique des NOACK en cas de problme logiciel- Les modes dadressage sur 7 et 10 bits- Lutilisation de toutes les vitesses de transfert compatiblesDe plus, les pins SDA et SCL, lorsque le module est utilis en mode IC, adaptent lesflancs des signaux en suivant les spcifications IC. Ceci est rendu possible par lintgrationde filtres spcifiques sur les pins concernes. Je ne parlerai pas du fonctionnement de cesfiltres, car cela sort du cadre de cet ouvrage et ne vous apporterait rien de plus. Limportanttant que les PICs sont compatibles IC. Pour rester simple, disons quen sortie, ceci permetde respecter les chronologies, et quen entre cela rduit les risques de prise en compte desparasites.En effet, comme le signal SDA, en mission, doit rester prsent un certain temps aprs leretour 0 de la ligne SCL, ce temps tant dpendant de la vitesse du bus IC, il faudra prciserce paramtre.Les 16F87x sont prvus pour travailler avec des frquences dhorloge SCL de 100 KHz,400 KHz, et 1MHz. Vous configurerez les filtres en fonction des frquences choisies.Dans le mme esprit, les pins disposent dentres de type trigger de Schmitt , dont nousavons dj parl plusieurs reprises, et qui permettent une dtection plus scurise dessignaux parasits.Les pins SDA et SCL sont naturellement multiplexes avec dautres pins, en loccurrenceRC4 et RC3.Nous utiliserons dans ce chapitre les registres tudis dans le mode SPI, mais le mode ICncessite lutilisation de registres supplmentaires. En tout, nous aurons besoin de 6 registres.Sachant que le registre SSPSR contient la donne en cours de transfert et que SSPBUFcontient la donne reue ou mettre (voir mode SPI), il nous reste 4 registres examiner.38823.2 Le registre SSPSTATTout comme pour ltude du mode SPI, je dcris les fonctions des bits des registrestudis uniquement pour le mode IC. Certains bits ont une autre signification suivant lemode, en cas de doute, consultez le datasheet, ou ltude du mode SPI dans cet ouvrage.Il faut noter que les noms de plusieurs bits ont t choisis en fonction de leur rle dans lemode SPI. Comme le mode IC peut utiliser ces bits dans un but compltement diffrent, leurnom na parfois plus aucun rapport avec leur fonction. Dans ce cas, je ne rappellerai pas cenom, jutiliserai un nom plus appropri.Un exemple est donn par le bit SMP (SaMple bit). Ce bit permettait de choisir linstantdchantillonnage (sample) dans le mode SPI. Dans le mode IC, il sert mettre en service lefiltre adquat. Son nom dans ce mode na donc plus aucun rapport avec sa fonction.Le registre SSPSTAT en mode ICb7 : SMP : Slew rate control set bit (1 pour 100 KHz et 1MHz, 0 pour 400 KHz)b6 : CKE : Input levels set bit (0 = bus IC, 1 = bus SMBUS)b5 : D_A : Data / Address bit (0 = adresse, 1 = data)b4 : P : stoP bitb3 : S : Start bitb2 : R_W : Read/Write bit information (0 = write, 1 = read)b1 : UA : Update adressb0 : BF : Buffer Full / data transmit in progressVous constatez que, dans ce mode, tous les bits sont maintenant utiliss. Nous avonsbeaucoup plus dindicateurs que dans le mode SPI. Voyons tout ceci en dtail.Le bit SMP prend ici une nouvelle signification. Il dtermine si le filtre doit tre ou nonmis en service. Il vous suffit de savoir que si vous travaillez avec une frquence de 100 KHzou de 1 MHz, vous devez mettre ce bit 1 (hors-service). Par contre, pour une vitesse de400 KHz, vous le laisserez 0 (en service).Le bit CKE prend galement une signification diffrente. Si vous mettez ce bit 1 ,vous travaillerez avec des niveaux dentre compatibles avec le bus SMBUS. Par contre, en lelaissant 0 , vous travaillerez avec des signaux compatibles IC (ce qui est notre objectifici).D_A vous indique si le dernier octet reu ou transmis tait un octet de donne (1) ou unoctet dadresse (0). Ceci vous permet de savoir o vous en tes dans le transfertdinformations.Le bit P est galement un indicateur. Il vous informe si le dernier vnement dtect taitun stop-condition (P = 1). Il sefface automatiquement ds quun autre vnement est reu. Ilsefface galement lors dun reset, ou si vous mettez le module MSSP hors-service.Le bit S est un indicateur qui procde exactement de la mme faon, mais pour un start-condition.R_W a 2 fonctions distinctes selon quon travaille en IC matre ou en IC esclave :389- En IC esclave, il vous indique ltat du bit R/W (bit 0 du premier octet qui suit le start-condition). Si R/W vaut 0 , une criture est donc en cours, sil vaut 1 , il sagit dunelecture. Ce bit est valide entre la dtection de la correspondance dadresse (Si cest votrePIC qui est slectionne par le matre) et la fin de la trame en cours, donc jusquauprochain stop-sequence, repeated start-sequence, ou bit NOACK.- En IC matre, il vous informe si un transfert est en cours (1) ou non (0).Le bit UA est un indicateur utilis uniquement en esclave sur adresses 10 bits. Il vousprvient quand vous devez mettre votre adresse jour en mode IC.En effet, vous ne disposez que dun seul registre de 8 bits pour inscrire votre adresseesclave. Comme le mode 10 bits ncessite 2 octets, le positionnement automatique de ce bitUA vous signale que le premier octet dadresse a t trait, et quil est temps pour vous deplacer votre second octet dadresse dans le registre concern (et inversment).Nous verrons en temps utile comment cela se passe. Le bit UA force la ligne SCL 0(pause), et est effac automatiquement par une criture dans SSPADD.Reste maintenant le bit BF, qui indique si le registre SSPBUF est plein (1) ou vide (0).Evidemment, positionn, en rception, il signifie que loctet a t reu, alors quen missionil signale que la transmission de loctet nest pas encore termine.23.3 Le registre SSPCON De nouveau, nous allons voir que tous les bits de ce registre sont utiliss.SSPCON en mode ICb7 : WCOL : Write COLlision detect bitb6 : SSPOV : SSP OVerflow indicator bitb5 : SSPEN : SSP ENable select bitb4 : CKP : Pause (si 0)b3 : SSPM3 : SSP select bit M3b2 : SSPM2 : SSP select bit M2b1 : SSPM1 : SSP select bit M1b0 : SSPM0 : SSP select bit M0Voyons ces bits en dtailWCOL est, comme son nom lindique, un indicateur qui signale que nous rencontrons unecollision dcriture (WCOL = 1). Il y a 2 cas possibles :- En mode master, cette collision arrive si vous tentez dcrire dans le registre SSPBUFalors que ce nest pas le bon moment (bus pas libre, start-condition pas encoreenvoye). Cette collision a pour consquence que la donne nest pas crite dans leregistre SSPBUF (bloqu en criture).390- En mode slave, ce bit sera positionn si vous tentez dcrire dans le registre SSPBUF alorsque le mot prcdent est toujours en cours de transmission. Vous devrez remettre ce flag 0 par logicielLindicateur SSPOV vous informe dune erreur de type overflow . Cest--dire quevous venez de recevoir un octet, alors que vous navez pas encore lu le registre SSPBUF quicontient toujours loctet prcdemment reu. Le registre SSPBUF ne sera pas cras par lanouvelle donne, qui sera donc perdue. Vous devez remettre ce flag 0 par logiciel. Ce bitna donc de signification quen rception.SSPEN permet de mettre tout simplement le module en service. Les pins SCL et SDApassent sous le contrle du module MSSP. Les pins SCL et SDA devront cependant treconfigures en entre via TRISC.CKP joue dans ce mode IC un rle particulier. Il permet de mettre lhorloge SCL enservice (1), ou de la bloquer ltat bas, afin de gnrer une pause (0). De fait, CKP ne serautilis que dans le cas de lIC esclave, qui est le seul mode o la pause peut savrerncessaire.SSPMx sont les bits qui dterminent de quelle faon va fonctionner le module IC. Je vousdonne donc seulement les modes relatifs lICb3 b2 b1 b0 Fonctionnement0 1 1 0 mode IC esclave avec adresse sur 7 bits0 1 1 1 mode IC esclave avec adresse sur 10 bits1 0 0 0 mode IC matre : frquence dtermine par le registre SSPADD1 0 0 1 rserv1 0 1 0 rserv1 0 1 1 Mode esclave forc ltat de repos1 1 0 0 rserv1 1 0 1 rserv1 1 1 0 Mode matre avec adresses 7 bits, interruptions sur vnements S et P1 1 1 1 Mode matre avec adresses 10 bits, interruptions sur vnements S et PNous ne parlerons que des 3 premiers modes, les autres ntant pas ncessaires. De plus,je ne sais pas ce que signifie mode matre avec adresse , tant donn quun matre na pasdadresse, et que rien nempche le mme matre dadresser des esclaves sur 7 et 10 bitsdadresse.Jai pos la question Microchip, leur rponse a t que les modes IC firmwarecontrolled permettent de prendre la gestion IC en charge par le logiciel. Avouez que,comme prcision, a nous avance beaucoup. Ma question tait pourtant prcise. A mon avis,le technicien nen savait pas plus que moi ce sujet.23.4 Le registre SSPADDPuisque je viens den parler, autant continuer par celui-ci. Son nom signifie SynchronousSerial Port ADDress register. Il a deux fonctions compltement distinctes, selon que lontravaille en IC matre ou en IC esclave.391Commenons par le mode esclave. Cest dans ce registre que vous placerez ladresse laquelle devra rpondre votre PIC. Si vous dcidez de travailler en mode 10 bits, vousplacerez les bits de poids fort dans SSPADD. Vous serez alors prvenus par le bit UA duregistre SSPSTAT quil est temps dy placer les bits de poids faible afin de complterladresse, et inversment.En mode matre, ce registre permet de dterminer la frquence de travail du signaldhorloge. Tous les signaux sont synchroniss sur base dune dure unitaire qui dpend de lavaleur place dans ce registre.Le pic utilise un registre spcial, quivalant un timer, et quon dnomme BRG pourBaud Rate Generator. Ce dernier se charge avec la valeur contenue dans SSPADD (en fait lesseuls 7 bits de poids faible), et dcrmente 2 fois par cycle dinstruction. Une fois arriv 0, ilse recharge si ncessaire pour produire un nouvel vnement.Par exemple, pour la lecture dun octet, on aura un temps TBRG durant lequel la ligne SDAest positionne, SCL tant 0, ensuite la ligne SCL est mise 1 durant un temps TBRG. A lafin de ce temps, la ligne SCL redescend et le nouveau bit SDA est positionn.Ce qui nous donne une lecture de bit de la forme :Remarquez que le positionnement de SDA intervient peu aprs la descente de SCL. Ceciest impratif pour la norme IC, qui impose que SDA ne peut varier tant que SCL se trouve ltat haut. Ce retard est provoqu par les filtres de sortie (flew rate control), ce qui expliqueleur importance.Nous constatons que la dure dun cycle dhorloge SCL est de 2 fois TBRG. Comme BRGdcrmente 2 fois par cycle dinstructions (donc tous les 2 Tosc), et quil met 2 Toscsupplmentaires pour se recharger, on peut dire que le temps de dure dun bit est de :Dure dun bit = Tosc * 2 * 2 * (SSPADD + 1)La frquence de lhorloge est donc dtermine par la formule :392FSCL = Fosc / (4 * (SSPADD + 1))En gnral, vous connaissez la frquence (100KHz, 400KHz, 1MHz), et vous cherchez dterminer SSPADD. Do :SSPADD = (Fosc / (FSCL * 4)) 1Avec, bien entendu, Fosc la frquence de votre oscillateur principal.Pour rappel, seuls 7 bits tant transfrs vers BRG, SSPADD ne poura tre suprieur 127.Examinons maintenant quoi sert SSPADD en mode esclave. En ralit, il prend ici lerle que lui confre son nom, autrement dit il contient ladresse laquelle va rpondre le PICaux requtes du matre. Dans le cas des adresses codes sur 7 bits, il contiendra les 7 bits enquestion.Mais attention, ladresse en question sera crite dans les bits 7 1 de SSPADD. Le bit 0devra TOUJOURS tre laiss 0.En fait, tout se passe comme si le PIC comparait le premier octet reu avec loctetmmoris dans SSPADD. Si on a identit, il sagit dune criture dans le PIC. Le pic compareensuite loctet reu avec SSPADD+1, si on a identit, il sagit dune lecture du PIC.Autrement dit, si ladresse que vous avez choisie pour votre PIC est 0x03, vous devezplacer cette adresse dans les bits 7 1, autrement dit dcaler ladresse vers la gauche, etpositionner b0 0.Vous inscrirez donc dans SSPADD la valeur 0x06.Adresse : 0 0 0 0 0 1 1 : 0x03 (sur 7 bits)SSPADD : 0 0 0 0 0 1 1 0 : 0x06Si ladresse est code sur 10 bits, vous commencez par crire le premier octet dansSSPADD (prcd bien entendu par B11110). Vous attendez le positionnement du bit UA,puis vous placez dans SSPADD votre second octet.En dautres termes :- Vous placez : 1 1 1 1 0 A9 A8 0 dans SSPADD- Vous attendez le bit UA- Vous placez : A7 A6 A5 A4 A3 A2 A1 A0 dans SSPADDUne fois la transaction termine, le bit UA est de nouveau positionn, vous replacez B1 11 1 0 A9 A8 0 dans SSPADD pour tre prt pour le transfert suivant.Tant que le bit UA reste positionn, le bus IC est maintenu en pause automatiquement parvotre PIC esclave. Quand vous mettez SSPADD jour, le bit UA est automatiquement effac,et le bus est libr.39323.5 Le registre SSPCON2Voici un registre que nous navons pas encore examin. Voyons donc ce quil contient, lebit 7 ne concerne que le mode esclave, tandis que les autres bits ne concernent que le modematre :SSPCON2b7 : GCEN : General Call ENable bit (rponse appel gnral)b6 : ACKSTAT : ACKnowledge STATus bit (tat du bit ACK reu)b5 : ACKDT : ACKnowledge DaTa bit (valeur transmise)b4 : ACKEN : ACKnowledge ENable bit (placer lacknowledge)b3 : RCEN : ReCeive ENable bit (lance la rception)b2 : PEN : stoP-condition ENable bit (gnrer stop-condition)b1 : RSEN : Repeated Start-condition ENable bit (gnrer SR)b0 : SEN : Start-condition ENable bit (gnrer S)Examinons maintenant ces bits en dtail :GCEN est le seul bit qui concerne le mode esclave. Si vous validez ce bit, le PIC rpondranon seulement ladresse que vous avez place dans SSPADD, mais galement ladresserserve dappel gnral (0x00). Les octets qui suivront dans ce cas auront des fonctionsparticulires et rserves (reset par exemple). Si vous dcidez que votre PIC doit rpondre ladresse dappel gnral, il vous appartiendra de grer ces commandes.ACKSTAT vous donne ltat du bit dacknowledge envoy par lesclave lorsque vouscrivez des donnes. Si ACKSTAT vaut 0 , cest que lesclave vous a envoy un ACK ,sil vaut 1 , cest quil ny a pas eu dacknowledge (NOACK).ACKDT est la valeur de lacknowledge envoyer lesclave lorsque vous procdez unelecture. Ce bit sera envoy lorsque vous positionnerez le bit ACKEN. De nouveau, une valeur 0 signifie que vous envoyez un ACK , une valeur 1 sera place pour un NOACK.ACKEN lance la gnration de lacknowledge. La valeur de ce bit (ACK ou NOACK) estdtermine par la valeur que vous avez place dans ACKDT. Ces 2 bits sont donc lis.RCEN : Lance la rception dun octet en provenance de lesclave. Pour lancer unecriture, on place la valeur crire dans SSPBUF, pour lancer une lecture, on met RCEN 1 .PEN : Lance la gnration automatique du stop-conditionRSEN : Lance la gnration du repeated start-conditionSEN : Lance la gnration du start-condition.Attention de ne pas confondre, au niveau des noms, les bits CREN, RCEN, SREN. Uneerreur ce niveau est trs difficile dtecter par relecture du code.39423.6 Les collisionsIl nous reste voir ce qui se passe en cas de collision sur le bus, si le PIC configur enmatre se voit ravir le bus IC durant une opration (mode multi-matre).La rponse est simple : le bit BCIF (Bus Collision Interrupt Flag) du registre PIR2 estpositionn, lopration courante est abandonne, et une interruption est ventuellementgnre si elle est configure.23.7 Le module MSSP en mode IC matreNous voici maintenant dans lutilisation concrte de notre PIC configure en IC matre.Je ne traite pour linstant que le cas o votre PIC est le seul matre du bus (mode mono-matre), cest le cas que vous rencontrerez probablement le plus souvent.Je vais partir dun cas thorique, dans lequel on ralise les oprations suivantes :- On crit un octet dans lesclave- Puis, sans perdre le contrle du bus, on lit un octet de rponse en provenance de lesclaveCeci se traduira par la squence dvnements suivante :- On configure le module MSSP- On envoie le start-condition- On envoie ladresse de lesclave concern avec b0 = 0 (criture)- On envoie la donne crire- On envoie le repeated start-condition (SR)- On envoie ladresse de lesclave concern avec b0 = 1 (lecture)- On lance la lecture- On envoie un NOACK pour indiquer la fin de la rception- On envoie un stop-conditionJe vais maintenant vous expliquer comment tout ceci sorganise en pratique dans notrePIC.23.7.1 La configuration du moduleAvant de pouvoir utiliser notre module, il importe de le configurer. Nous allons imaginerque nous travaillons avec une frquence dhorloge principale de 20MHz (le quartz de notrePIC), et avec une frquence dhorloge IC de 400 KHz.Les tapes seront les suivantes :1) On configure TRISC pour avoir les pins SCL (RC3) et SDA (RC4) en entre2) On configure SSPSTAT comme ceci :395- On positionne SMP (slew rate control) suivant la frquence du bus IC. Dans le cas de400KHz, ce bit sera mis 0, ce qui met le slew rate en service.- On place CKE 0 pour la compatibilit IC3) On calcule la valeur de recharge du Baud Rate Generator, et on place la valeur obtenuedans SSPADD SSPADD = (Fosc / (FSCL * 4)) 1Dans notre cas :SSPADD = (20 MHz / (400KHz * 4)) 1SSPADD = (20.000 / (400 * 4))-1SSPADD = 11,5. On prendra la valeur 12 (dcimal, faites attention)Pourquoi 12 et pas 11 ? Tout simplement parce que plus SSPADD est petit, plus lafrquence est grande. Il vaut donc mieux arrondir en utilisant une frquence infrieure lalimite acceptable que suprieure.4) On configure SSPCON, comme suit :- On positionne le bit SSPEN pour mettre le module en service- On choisit SSMPx = 1000 pour le mode IC matreTout ceci nous donne un code du style :InitBANKSEL TRISC ; slectionner banque 1bsf TRISC,3 ; SCL en entre (mis par dfaut sur un reset)bsf TRISC,4 ; SDA en entre (idem)movlw B00000000 ; slew rate control en service, mode ICmovwf SSPSTAT ; dans SSPSTATmovlw D12 ; valeur de recharge du BRGmovwf SSPADD ; dans registre de rechargebcf STATUS,RP0 ; passer banque 0movlw B00101000 ; module MSSP en service en mode IC mastermovwf SSPCON ; dans registre de contrle23.7.2 La vrification de la fin des oprationsA ce stade, il faut que vous sachiez quil nest pas autoris, ni dailleurs possible, degnrer une action si la prcdente nest pas termine.Par exemple, vous ne pouvez pas lancer un start-condition si le prcdent stop-conditionnest pas termin, de mme vous ne pouvez pas envoyer un ACK si la rception de loctetnest pas acheve, et ainsi de suite.Vous avez donc 3 solutions pour raliser une squence doprations sur le port IC.396- Soit vous lancez votre commande et vous attendez quelle soit termine avant de sortir dela sous-routineCeci se traduit par la squence suivante :CommandeLancer la commandeCommande termine ?Non, attendre la fin de la commandeOui, fin- Soit vous sortez de votre sous-routine sans attendre, mais vous devrez tester si loprationprcdente est termine avant le pouvoir la lancer (puisque vous tes galement dans cecas sorti de la commande prcdente sans attendre).Ceci se traduit par la squence suivante :CommandeY a-t-il toujours une commande en cours ?oui, attendre quelle soit terminenon, alors lancer la nouvelle commandeet fin- Soit vous utilisez les interruptions, mais je verrai ce cas sparment, car la gestion desinterruptions dans ce mode nest pas vraiment simpleDans le premier cas, on connat lvnement dont on dtecte la fin (la commande quonexcute), dans le second, on doit tester toutes les possibilits, afin de conserver une sous-routine unique.Il faut de plus savoir que lorsque vous lancez une commande (par exemple unacknowledge), le bit dexcution est effac automatiquement une fois laction termine. Donc,pour lacknowledge, vous placez ACKEN pour lancer la commande, ACKEN estautomatiquement effac lorsque laction est termine.Je vous prsente tout dabord la faon de dtecter si une commande quelconque est encours dexcution.Il faut dterminer tous les cas possibles, les commandes peuvent tre :- Transmission en cours (signale par le bit R/W du registre SSPSTAT)- Start-condition en cours (signal par le bit SEN du registre SSPCON2)- Repeated start-condition en cours (signal par le bit RSEN de SSPCON2)- Stop-condition en cours (signal par le bit PEN de SSPCON2)- Rception en cours (signal par le bit RCEN de SSPCON2)- Acknowledge en cours (signal par le bit ACKEN de SSPCON2)Voici donc un exemple de sous-routine qui attend que lopration prcdente soittermine :I2C_idleBANKSEL SSPSTAT ; passer en banque 1I2C_idle2397clrwdt ; effacer watchdogbtfsc SSPSTAT,R_W ; tester si mission en coursgoto I2C_idle2 ; oui, attendrei2C_idle3clrwdt ; effacer watchdogmovf SSPCON2,w ; charger registre SSPCON2andlw 0x1F ; conserver ACKEN,RCEN,PEN,RSEN,et SENbtfss STATUS,Z ; tester si tous 0 (aucune opration en cours)goto I2C_idle3 ; non, attendrebcf STATUS,RP0 ; repasser en banque 0return ; rien en cours, on peut sortirBien videmment, si vous navez pas activ le watchdog, vous pouvez vous passer desinstructions clrwdt .23.7.3 La gnration du start-conditionCommenons donc par le commencement, savoir la gnration du start-condition. Lestapes ncessaires sont les suivantes :- On vrifie si lopration prcdente est termine- On lance le start-conditionVoici le code correspondant :I2C_startcall I2C_idle ; attendre fin de lopration prcdente(voir plus haut)BANKSEL SSPCON2 ; passer en banque 1bsf SSPCON2,SEN ; lancer start-conditionbcf STATUS,RP0 ; repasser en banque 0return ; retourEt son alternative, comme expliqu prcdemment :- On lance le start-condition- On attend que le start-condition soit terminI2C_startBANKSEL SSPCON2 ; passer en banque 1bsf SSPCON2,SEN ; lancer le start-conditionI2C_start2clrwdt ; effacer watchdogbtfsc SSPCON2,SEN ; start-condition termin ?goto I2C_start2 ; non, attendrebcf STATUS,RP0 ; oui, repasser en banque 0return ; et retour23.7.4 Lenvoi de ladresse de lesclaveNous allons maintenant devoir envoyer ladresse de lesclave. Nous allons construirenotre sous-routine en imaginant que ladresse de lesclave est SLAVE . Cette adresse estcode sur 7 bits.398Nous allons donc raliser les oprations suivantes ;- On vrifie si lopration prcdente est termine- On place ladresse de lesclave dcale vers la gauche et complte par le bit 0 (R/W) 0 (criture) dans SSPBUF, ce qui lance lmissionI2C_adresscall I2C_idle ; attendre fin de lopration prcdentemovlw SLAVE*2 ; charger adresse esclave (b7 b1) avec b0 = 0movwf SSPBUF ; lancer lmission de ladresse en mode criturereturn ; et retouret son alternative :- On place ladresse de lesclave comme prcdemment- On attend la fin de lmissionI2C_adressmovlw SLAVE*2 ; charger adresse esclave (b7 b1) avec b0 = 0movwf SSPBUF ; lancer lmission de ladresse en mode critureBANKSEL SSPSTAT ; passer en banque 1I2C_adress2clrwdt ; effacer watchdogbtfsc SSPSTAT,R_W ; tester si mission terminegoto I2C_adress2 ; non, attendrebcf STATUS,RP0 ; oui, repasser banque 0return ; et retour23.7.5 Le test de lACKNous aurons souvent besoin, aprs avoir envoy ladresse de lesclave, de savoir si cedernier est prt, et donc a bien envoy laccus de rception ACK . Avant de pouvoir testerce bit, il faut que lmission soit termine, ce qui est automatiquement le cas si vous avezutilis la seconde mthode, mais nest pas vrai si vous avez prfr la premire.Voici donc le cas correspondant la premire mthode :- On vrifie si lopration prcdente est termine- On teste le bit ACK et on dcide en consquenceI2C_checkcall I2C_idle ; attendre fin de lopration prcdenteBANKSEL SSPCON2 ; passer en banque 1btfsc SSPCON2,ACKSTAT ; tester ACK reugoto error ; pas reu, traiter erreur.. .. .. ; poursuivre ici si OK.. .. ..error.. .. .. ; continuer ici si lesclave nest pas prt... .. ..Pour la seconde mthode, cest strictement identique, si ce nest que lappel de la sous-routine I2C_idle nest pas ncessaire (lopration prcdente est forcment termine,puisquon attend quelle soit finie avant de sortir de la sous-routine).399Cette procdure ne lance aucune commande, elle ne ncessite donc pas dattendre avant le return .23.7.6 Lcriture dun octetNous en sommes arriv lcriture de loctet dans lesclave. Cette procdure eststrictement identique lenvoi de ladresse de lesclave.Nous allons donc raliser les oprations suivantes ;- On vrifie si lopration prcdente est termine- On place loctet envoyer dans SSPBUF, ce qui lance lmissionI2C_sendcall I2C_idle ; attendre fin de lopration prcdentemovlw OCTET ; charger octet envoyermovwf SSPBUF ; lancer lcriture de loctetreturn ; et retouret son alternative :- On place loctet envoyer dans SSPBUF- On attend la fin de lmissionI2C_sendmovlw OCTET ; charger octet envoyermovwf SSPBUF ; lancer lcritureBANKSEL SSPSTAT ; passer en banque 1I2C_send2clrwdt ; effacer watchdogbtfsc SSPSTAT,R_W ; tester si mission terminegoto I2C_send2 ; non, attendrebcf STATUS,RP0 ; oui, repasser banque 0return ; et retour23.7.7 L envoi du repeated start-conditionNous allons devoir procder une lecture. Comme nous tions en mode criture, nousdevons renvoyer un nouveau start-condition. Comme nous ne dsirons pas perdre le bus, nousnallons pas terminer lopration prcdente par un stop-condition, nous enverrons doncdirectement un second start-condition, autrement dit un repeated start-condition.- On vrifie si lopration prcdente est termine- On lance le repeated start-conditionVoici le code correspondant :I2C_startcall I2C_idle ; attendre fin de lopration prcdenteBANKSEL SSPCON2 ; passer en banque 1bsf SSPCON2,RSEN ; lancer le repeated start-conditionbcf STATUS,RP0 ; repasser en banque 0400return ; retourEt son alternative, toujours sur le mme principe :- On lance le repeated start-condition- On attend que le repeated start-condition soit terminI2C_startBANKSEL SSPCON2 ; passer en banque 1bsf SSPCON2,RSEN ; lancer le repeated start-conditionI2C_start2clrwdt ; effacer watchdogbtfsc SSPCON2,RSEN ; start-condition termin ?goto I2C_start2 ; non, attendrebcf STATUS,RP0 ; oui, repasser en banque 0return ; et retourMaintenant, vous allez me dire mais quest-ce qui diffrencie un repeated start-conditiondun start-condition ordinaire ? En fait, vous devez vous souvenir quun start-condition part de la ligne au repos (SCL =SDA = 1) et place SDA 0 alors que SCL reste son tat de repos (1).Le stop-condition, lui, remet les lignes dans leur tat de repos en suivant la logique inverse(remonte de SDA alors que SCL est dj remont 1).Vous avez besoin du repeated start-condition lorsque les lignes ne sont pas dans leur tatde repos, puisque SCL est 0, et SDA peut ltre galement (ACK). Donc, avant de pouvoirrgnrer un nouveau start-condition, il faut remettre ces lignes dans leur tat de repos. Cestce que fait le repeated start-condition.La squence gnre par ce dernier est donc la suivante :- Ds le positionnement de SREN, la ligne SDA est place ltat haut- Aprs un temps gal TBRG, la ligne SCL est amene galement ltat haut- Aprs une nouvelle dure gale TBRG, on repasse SDA 0, ce qui quivaut alors unstart-condition- TBRG plus tard, le bit SREN est effac, et le bit SSPIF positionn.Ds lors, il vous suffira de placer votre adresse dans SSPBUF.Vous voyez que les 2 premires lignes sont supplmentaires par rapport un start-condition simple. Elles permettent de ramener les 2 lignes ltat haut sans gnrer de stop-condition . Elles ncessitent 2 temps TBRG supplmentaires.Les 2 dernires lignes correspondent videmment au cycle normal dun start-condition .Et hop, un petit chronogramme (mais si, je sais que vous aimez a) :401Si vous avez tout compris, vous constatez que rien ne vous empche dutiliser un SR au lieu dun S , mais vous ne pouvez pas utiliser un S en lieu et place dun SR .Dans ce dernier cas, les lignes ntant pas au repos, le start-condition ne serait toutsimplement pas gnr.23.7.8 Lenvoi de ladresse de lesclaveNous allons maintenant devoir envoyer encore une fois ladresse de lesclave. Nousdevrons cette fois positionner le bit 0 1 pour indiquer une lecture.Nous allons donc raliser les oprations suivantes ;- On vrifie si lopration prcdente est termine- On place ladresse de lesclave dcale vers la gauche et complte par le bit 0 (R/W) 1 (lecture) dans SSPBUF, ce qui lance lmissionI2C_adresscall I2C_idle ; attendre fin de lopration prcdentemovlw (SLAVE*2) |1 ; charger adresse esclave (b7 b1) avec b0 = 1; on pouvait crire galement (SLAVE*2)+1movwf SSPBUF ; lancer lmission de ladresse en mode criturereturn ; et retouret son alternative :- On place ladresse de lesclave comme prcdemment- On attend la fin de lmissionI2C_adressmovlw (SLAVE*2)|1 ; charger adresse esclave (b7 b1) avec b0 = 1; SLAVE*2 = adresse dcale, |1 = OR 1 402movwf SSPBUF ; lancer lmission de ladresse en mode critureBANKSEL SSPSTAT ; passer en banque 1I2C_adress2clrwdt ; effacer watchdogbtfsc SSPSTAT,R_W ; tester si mission terminegoto I2C_adress2 ; non, attendrebcf STATUS,RP0 ; oui, repasser banque 0return ; et retour23.7.9 La lecture de loctetNous devons maintenant lire loctet en provenance de lesclave. De nouveau 2 mthodes.Tout dabord :- On vrifie si lopration prcdente est termine- On lance la lectureI2C_readcall I2C_idle ; attendre fin de lopration prcdenteBANKSEL SSPCON2 ; passer banque 1bsf SSPCON2,RCEN ; lancer la rceptionbcf STATUS,RP0 ; repasser banque 0return ; et retouret lalternative :- On lance la lecture- On attend la fin de lopration pour sortirI2C_readBANKSEL SSPCON2 ; passer banque 1bsf SSPCON2,RCEN ; lancer la rceptionI2C_read2btfsc SSPCON2,RCEN ; rception termine ?goto I2C_read2 ; non, attendrebcf STATUS,RP0 ; repasser banque 0return ; et sortir23.7.10 Lenvoi du NOACKPour clturer une lecture, le matre doit envoyer un NOACK, voici comment oprer :- On vrifie si lopration prcdente est termine- On lance le NOACKI2C_NOACKcall I2C_idle ; attendre fin de lopration prcdenteBANKSEL SSPCON2 ; passer banque 1bsf SSPCON2,ACKDT ; le bit qui sera envoy vaudra 1 bsf SSPCON2,ACKEN ; lancer lacknowledge (= ACKDT = 1 = NOACK)bcf STATUS,RP0 ; repasser banque 0return ; et retouret lalternative :403- On envoie NOACK- On attend que lenvoi soit terminI2C_NOACKBANKSEL SSPCON2 ; passer banque 1bsf SSPCON2,ACKDT ; le bit qui sera envoy vaudra 1 bsf SSPCON2,ACKEN ; lancer lacknowledge (= ACKDT = 1 = NOACK)I2C_NOACK2btfsc SSPCON2,ACKEN ; tester si NOACK termingoto I2C_NOACK2 ; non, attendrebcf STATUS,RP0 ; repasser banque 0return ; et retour23.7.11 Lenvoi du stop-conditionIl ne reste plus qu envoyer notre stop-condition pour voir si tout sest bien pass.- On vrifie si lopration prcdente est termine- On lance le stop-conditionVoici le code correspondant :I2C_stopcall I2C_idle ; attendre fin de lopration prcdenteBANKSEL SSPCON2 ; passer en banque 1bsf SSPCON2,PEN ; lancer le stop-conditionbcf STATUS,RP0 ; repasser en banque 0return ; retourEt son alternative, comme expliqu plus haut :- On lance le stop-condition- On attend que le repeated start-condition soit terminI2C_stopBANKSEL SSPCON2 ; passer en banque 1bsf SSPCON2,PEN ; lancer le stop-conditionI2C_start2clrwdt ; effacer watchdogbtfsc SSPCON2,PEN ; stop-condition termin ?goto I2C_start2 ; non, attendrebcf STATUS,RP0 ; oui, repasser en banque 0return ; et retourNous avons maintenant termin nos oprations. Remarquez cependant que si vous avezutilis la seconde mthode, le transfert est termin. Par contre, si vous avez prfr lapremire, il vous faudra encore attendre la fin du stop-condition avant que le bus ne soiteffectivement libr.Remarquez galement que le flag SSPIF est positionn pour chaque opration termine.Vous pouvez donc remplacer le test de fin dexcution par un simple test sur ce flag :404Waitbcf STATUS,RP0 ; passer banque 0bcf PIR1,SSPIF ; reset du flagWait2btfss PIR1,SSPIF ; flag positionn ?goto Wait2 ; non, attendrereturn ;return23.8 Lutilisation des interruptionsIl se peut que vous dsiriez utiliser les interruptions pour traiter tous ces vnements, enparticulier si vous dsirez que votre pic continue effectuer dautres tches durant les tempsdes oprations sur le bus eeprom.Il existe cependant une certaine difficult pour mettre en uvre les interruptions ceniveau. En effet, vous avez un seul flag (SSPIF), alors que linterruption sera gnre pourchacune des oprations.Afin de savoir o vous en tes au moment o vous arrivez dans votre routinedinterruption, il vous faudra utiliser un compteur que vous incrmenterez chaque opration.Vous aurez alors dans votre routine dinterruption SSP, un slecteur dans le style (cmpt est uncompteur) :incf cmpt,f ; incrmenter compteur de positionmovlw HIGH tablesaut ; poids fort adresse de la table de sautmovwf PCLATH ; dans PCLATHmovf cmpt,w ; charger compteur de positionaddlw LOWtablesaut ; ajouter poids faible adresse table de sautbtfsc STATUS,C ; tester si on dbordeincf PCLATH,f ; oui, incrmenter PCLATHtablesautmovwf PCL ; provoquer un saut dans la table qui suit :goto I2C_start ; envoyer start-condition (cmpt valait 0 en entrant ; dans la routine, et vaut 1 maintenant)goto I2C_sendadress ; envoyer adresse esclave (cmpt = 2)goto I2C_testAck ; tester acknowledgegoto I2C_sendByte ; envoyer octetgoto I2C_testAck ; tester acknowledgegoto I2C_stop ; envoyer stop-conditionVous voyez que suivant ltat de cmpt, vous allez sauter des routines diffrentes enfonction de lavance de votre squence. Jai illustr une squence pour lcriture. Celle-cicommencera en initialisant cmpt 0. Il sera incrment chaque appel. Ainsi, la premireadresse de saut sera etiquettesaut + 1 , donc le premier goto . Vous crirez bien entendugalement, si vous en avez besoin, une seconde suite de goto correspondant la lecture.Si la premire adresse du goto concernant la lecture vaut, par exemple, 22, vousinitialiserez cmpt 21 pour une lecture.Ensuite, vous remarquez ici une astuce de programmation. Je vous avais dit que lorsquevous criez un tableau de saut, vous ne pouviez pas dborder sur 2 pages de 256 octets.Votre tableau tait donc de fait limit.405Lastuce utilise ici permet de dpasser cette limite. En effet, au lieu dajouter w PCL directement, on opre laddition dans le registre W . Si on dtecte que le rsultatdbordera sur lautre page, on incrmente tout simplement PCLATH. Ne reste plus quplacer le rsultat dans PCL.De cette faon, non seulement vous pouvez placer votre tableau nimporte quel endroit,mais, en plus, vous pouvez utiliser un compteur de plus de 8 bits, ce qui vous permet de crerdes tableaux de sauts de plus de 256 lments.La mme technique est videmment autorise pour les tableaux de retlw . Vous voyezque vous commencez devenir des pros .23.8 Le module MSSP en mode IC multi-matreLe passage en mode multi-matre signifie tout simplement que votre PIC nest pas le seulmatre du bus IC. Il doit donc sassurer de ne pas entrer en conflit avec un autre matre durantles diverses utilisations du bus.23.8.1 LarbitrageIl y a plusieurs choses prendre en considration lorsque vous travaillez avec plusieursmatres. Tout dabord, vous ne pouvez prendre la parole que si le bus est libre, ce quiimplique de vrifier si le bus est libre avant denvoyer le start-condition.En second lieu, lorsque vous prenez la parole, vous devez vous assurer quun autre matrequi aurait pris la parole en mme temps que vous na pas pris la priorit. Auquel cas, vousdevez vous retirer du bus.Il y a donc 5 moments durant lesquels vous pouvez perdre le contrle du bus :- Durant le start-condition- Durant lenvoi de ladresse de lesclave- Durant lmission dun NOACK- Durant lmission dun octet- Durant un repeated start-condition.23.8.2 La prise de contrle du busUne fois de plus, Microchip nous a facilit la vie ce niveau. Votre PIC surveille le busIC en permanence, et vous informe de ltat du bus. En effet, chaque fois quil voit passer un start-condition , il positionne le bit S du registre SSPSTAT 1 et efface le bit P .Chaque fois quun stop-condition est mis, il positionne le bit P du mme registre, etefface le bit S .406Il vous suffira alors de tester si le bit S est effac pour vous assurer que le bus est libre.Microchip recommence cependant de tester les bits S et P simultanment poursassurer de la libration du bus.Quoi que je ne comprenne pas bien lintrt de cette technique, je vous la dcritcependant. En effet, si P est positionn, alors S est effac. Donc, il est inutile de tester P , cest de la logique combinatoire.Jai interrog Microchip ce sujet, la rponse a t que javais effectivement raison, maisquil tait plus sr de tester comme indiqu. Je souponne donc fortement que cette rponsequi ne veut rien dire ne cache un bug de fonctionnement concernant le fonctionnement de cesbits. Je vous encourage donc procder comme recommand.- Si le bit P est positionn, alors le bus est libre- Si P et S sont effacs, alors le bus est libre.Ceci nous donne :I2C_freeBANKSEL SSPSTAT ; passer en banque 1btfsc SSPSTAT,P ; tester P positionngoto busfree ; oui, traiter bus librebtfsc SSPSTAT,S ; Tester si P et S libresgoto I2C_free ; S positionn, on recommence les testsbusfreesuite ; suite du traitement, le bus est libre23.8.3 La dtection de la perte de contleDe nouveau, la dtection de la perte de contrle, quel que soit le cas, ncessite de ne testerquun seul bit. Le bit BCIF (Bus Collision Interrupt Flag) du registre PIR2. La dtection de laperte de contrle est en effet automatique et cbl de faon hardware dans le PIC. Cest donclui qui soccupe de tout grer ce niveau.Il vous suffit donc, aprs ou avant chaque opration, suivant la mthode retenue, de testerltat du bit BCIF. Sil est positionn, alors vous avez perdu le contrle du bus et vous devezabandonner le traitement en cours. Vous le reprendrez ds que le bus sera nouveau libre.Si vous utilisez les interruptions, vous pourrez galement gnrer une interruption sur basede BCIF. Il vous suffira alors, par exemple, si une interruption de ce type est gnre, deremettre votre variable cmpt 0, afin de reprendre les oprations au dbut.23.9 Le module MSSP en mode IC esclave 7 bitsJe vais maintenant vous expliquer comment utiliser votre PIC en IC esclave. Vousrencontrerez ce cas lorsque vous voudrez que votre PIC communique avec un autre matre,qui peut tre un circuit programmable spcialis, un microcontrleur, un autre PIC etc.La premire chose comprendre, cest que, dans ce mode, vous pouvez mettre etrecevoir, mais ce nest pas vous qui dcidez quand le transfert lieu.407Donc, puisque la transmission peut avoir lieu nimporte quel moment, la meilleuremthode dexploitation sera dutiliser les interruptions. Je vous donnerai donc des exemplesde routines dans le chapitre correspondant.Nanmoins, en mode esclave, vous tes dchargs de toute une srie dopration, commela gnration des start et stop-conditions, lenvoi de ladresse etc.Vous disposez de 2 possibilits dutilisation du mode esclave, selon que vous utiliserezune adresse code sur 7 ou sur 10 bits. Nous verrons les diffrences que cela implique. Pourlinstant, je me contente dun adressage sur 7 bits.Ce mode correspond une valeur de SSPMx de B011023.9.1 Ladressage et linitialisationNous allons cette fois utiliser notre registre SSPADD pour mmoriser ladresse laquellerpondra notre PIC. En effet, en mode esclave, nul besoin de gnrer lhorloge, ce quiexplique le double rle de ce registre.Ladresse sera mmorise, bien entendu, dans les bits 7 1 du registre SSPADD. Le bit 0devra tre laiss 0 .I2C_initBANKSEL SSPADD ; passer en banque 1movlw ADRESSE*2 ; charger valeur adresse (bits 7 1)movwf SSPADD ; dans registre dadresseclrf SSPSTAT ; slew rate ON, compatible I2Cmovlw B10000000 ; appel gnral en service (facultatif)movwf SSPCON2 ; dans registre SSPCON2bcf STATUS,RP0 ; repasser banque 0movlw B00110110 ; MSSP en service, mode I2C 7 esclave 7 bits, SCL OKmovwf SSPCON ; dans registre de contrleVous allez voir que bon nombre doprations sont maintenant prises automatiquement encharge par votre PIC.Nous allons imaginer la squence suivante pour traiter tous les cas particuliers :- Le matre crit un octet dans votre PIC- Ensuite le matre lit un octet de rponseVoici, chronologiquement, tous les vnements qui vont intervenir :23.9.2 la rception du start-conditionLe matre va commencer par envoyer le start-condition. Votre PIC esclave, qui surveille lebus, va positionner le bit S du registre SSPSTAT. Cependant, vous navez mme pas vous en proccuper, le PIC va poursuivre lexamen du bus et sait maintenant que suitladresse de lesclave concern.40823.9.3 La rception de ladresse en mode critureDeux cas peuvent maintenant se produire. Soit ladresse qui vient dtre mise par lematre est celle de votre PIC, soit elle concerne un autre esclave. Dans le second cas, vous neverrez rien du tout, le PIC naura aucune raction suite une adresse qui ne le concerne pas. Ilattend alors le prochain stop-condition pour poursuivre lanalyse du bus.Par contre, si le message est bien destin votre PIC, et si votre PIC est en conditionvalable pour le recevoir (je vais en parler), les vnements suivants vont se produire :- Ladresse sera transfre dans le registre SSPBUF- En consquence, le bit BF sera positionn, pour indiquer que le buffer est plein- Le bit SSPIF sera positionn, et une interruption aura ventuellement lieu- Le bit D_A du registre SSPSTAT sera mis 0 (adresse prsente)- Le bit R_W sera mis 0 (criture)- Laccus de rception ACK va tre gnrLa premire chose dont il faut se souvenir, cest quil faut toujours lire une donneprsente dans SSPBUF, sinon la donne suivante ne pourra pas tre traite. Ceci, mme sivous navez pas besoin de cette donne.En effet, un octet prsent dans SSPBUF est signal par le positionnement 1 du bit BF(Buffer Full). La lecture du registre SSPBUF provoque leffacement automatique du bit BF.Si vous recevez votre adresse alors que loctet BF tait toujours positionn (vous naviezpas lu la donne prcdente), alors :- Ladresse ne sera pas transfre dans SSPBUF- Le bit SSPOV sera positionn- Laccus de rception ne sera pas transmis (NOACK) indiquant au matre que vous ntespas prt recevoir.- Le bit SSPIF sera positionn.Le bit SSPOV devra imprativement tre effac par votre programme. Autrement dit, sivous avez des raisons de penser quil est possible que votre programme ne ragisse pas assezvite un vnement, vous devez toujours tester SSPOV. Sil vaut 1 , alors, vous devezleffacer, vous devez lire SSPBUF, et vous savez que vous avez perdu loctet reu.Rassurez-vous, comme vous avez envoy un NOACK , le matre le sait aussi, il peutdonc rpter linformation.Lexception tant que sil sagit de ladresse gnrale (0x00), et quun autre esclave quirpond galement cette adresse gnre le ACK , le matre ne pourra pas savoir que vousnavez pas rpondu.Vous savez maintenant que vous devez lire ladresse afin deffacer le bit BF. Mais vousallez me dire que cela ne sert rien, puisque ladresse lue doit forcment tre ladresse devotre esclave, que vous connaissez.409En ralit, pas tout fait. Si vous avez positionn le bit CGEN , votre PIC ragira, soit ladresse contenue dans SSPADD, soit ladresse gnrale 0x00. Le test de cette valeurvous indiquera de quelle adresse il est question.I2C_adressmovf SSPBUF,w ; charger adresse reue (efface BF)btfsc STATUS,Z ; tester si 0 (adresse gnrale)goto adressGen ; oui, traiter adresse gnrale (toujours en criture)suite.. ; non, traiter une commande via ladresse de SSPADDI2C_adressGenSuite.. ; ici, il sagit de ladresse gnrale.23.9.4 La gnration du ACK Comme je viens de vous le dire, elle est automatique. On distingue 2 cas :- Soit le buffer tait vide (BF = 0) et le bit SSPOV tait galement 0 lors de la rceptionde ladresse : dans ce cas, le bit BF sera positionn et un ACK sera automatiquementgnr.- Soit le bit BF ou le bit SSPOV ou les deux tait 1 au moment du transfert, et dans cecas SSPOV et BF seront positionns 1, et un NOACK sera gnr.En ralit, gnrer un NOACK , je vous le rappelle, quivaut tout simplement ne riengnrer du tout.Si le bit SSPOV tait positionn et pas le bit BF, alors cest que votre programme nestpas bien crit (vous avez rat un octet et vous ne vous en tes pas aperu, puisque vous avezlu SSPBUF sans effacer SSPOV). Ce cas ne devrait donc jamais arriver.Le bit SSPIF sera positionn dans tous les cas. Une interruption pourra donc toujoursavoir lieu mme si la transaction ne sest pas correctement effectue, ce qui vous permettra detraiter lerreur.23.9.5 La rception dun octet de donneEt bien, la rception dun octet de donne est strictement similaire la rception deladresse. La seule diffrence est que le bit D_A sera positionn pour indiquer que loctet reuest un octet de donne. Les cas derreurs sur BF et SSPOV fonctionneront de faon identique,je nai donc pas grand-chose dire ici.De nouveau, un ACK sera gnr si tout sest bien pass, et un NOACK dans lecas contraire, mettant fin au transfert.41023.9.6 La rception de ladresse en mode lectureVous allez maintenant recevoir le repeated start-condition, gr en interne par votre PIC.Suit directement aprs ladresse de votre PIC, mais avec le bit R/W mis 1 (lecture).Voici ce qui va en rsulter :- Ladresse sera transfre dans le registre SSPBUF, avec R/W 1 - DANS CE CAS PARTICULIER, BF NE SERA PAS POSITIONNE- Le bit SSPIF sera positionn, et une interruption aura ventuellement lieu- Le bit D_A du registre SSPSTAT sera mis 0 (adresse prsente)- Le bit R_W sera mis 1 (lecture)- Laccus de rception ACK va tre gnrIl est important de constater que lorsquon reoit une adresse en mode esclave et enlecture, bien que SSPBUF contienne ladresse reue, BF nest pas positionn.Ceci est logique, car SSPBUF contient forcment ladresse mmorise dans SSPADD, nulbesoin de la lire, vous connaissez son contenu. En effet, les commandes gnrales sont pardfinition des commandes dcriture.Votre PIC va maintenant gnrer un ACK automatiquement, vous navez donc pas vous en proccuper.23.9.6 Lmission dun octetUne fois que votre PIC a dtect que le matre avait besoin de recevoir un octet, il forceautomatiquement le bit CKP 0 , ce qui place la ligne SCL 0 , et donc gnre unepause. Ceci est bien entendu ncessaire pour viter que le matre ne lise votre PIC avant quevous nayez eu le temps dcrire votre octet de donne dans SSPBUF. Ne tranez cependantpas, n oubliez pas que vous bloquez lintgralit du bus IC.Il vous reste donc placer votre octet envoyer dans SSPBUF, puis placer le bit CKP 1, ce qui va librer la ligne SCL et va permettre au matre de recevoir votre donne.Lcriture de SSPBUF provoque le positionnement de BF, qui sera effac une fois locteteffectivement envoy.I2C_Sendmovlw DATA ; charger la donne envoyermovwf SSPBUF ; dans le bufferbsf SSPCON,CKP ; met fin la pause, permet le transfertou, en alternative, si vous dsirez tester toutes les conditions derreur :I2C_Sendbsf STATUS,RP0 ; passer en banque 1btfsc SSPSTAT,BF ; envoi prcdent envoy ?goto $-1 ; non, attendrebcf STATUS,RP0 ; repasser banque 0I2C_send2bcf SSPCON,WCOL ; effacer bit de collisionmovlw DATA ; charger donne envoyer411movwf SSPBUF ; dans le bufferbtfsc SSPCON,WCOL ; collision ?goto I2C_send2 ; oui, on recommence lcriturebsf SSPCON,CKP ; met fin la pause, permet le transfertJai utilis volontairement lexpression goto $-1 , car vous la rencontrerez parfois danscertains programmes. Lexplication est la suivante :$ est une directive qui reprsente ladresse courante. Donc, $-1 ladresseprcdente. Comme dans les PICs 16Fxxx, chaque instruction ncessite un mot deprogramme, goto $-1 veut simplement dire sauter la ligne prcdente , tout comme goto $-3 signifiera sauter 3 lignes plus haut . De mme goto $+4 indiquera quilfaut sauter 4 lignes plus bas.Si vous dcidez dutiliser cette directive, limitez-vous 2 ou 3 lignes au maximum. Evitezles goto 35 qui rendraient votre programme parfaitement illisible. Cest pourquoi jaiattendu longtemps avant dintroduire cette notion, afin de vous habituer utiliser destiquettes.Cette fois, cest le matre qui enverra le ACK sil dsire lire un autre octet, ou un NOACK sil a dcid de terminer. Vous ne disposez daucun moyen direct pour lire ltatdu ACK envoy. Votre PIC gre automatiquement ce bit pour savoir sil doit attendre unnouveau start-condition, ou sil doit se prparer lenvoi dune nouvelle donne.Cependant, une astuce vous permet de savoir si un NOACK a t gnr par le matre. Eneffet, la rception du NOACK provoque le reset du bit R_W. Comme je vais vous lindiquerplus bas, ceci se traduit, en fin de lecture, par la configuration suivante :R_W = 0 (donc on peut croire quon est en criture)SSPIF = 1 (donc loctet a t reu)BF = 0 (et le buffer est vide).Il est vident que si lopration est termine et que le buffer est vide, cest quil sagissaitdune lecture, et non dune criture (auquel cas SSPBUF sera plein et BF vaudrait 1 ).Cette anomalie vous permet donc de dtecter la prsence du NOACK si besoin tait.23.9.7 Le mode esclave 7 bits par les interruptionsJe vous ai dit quen mode esclave, le traitement par interruptions tait le plus appropri. Ilest temps maintenant de vous expliquer comment procder.De nouveau, vous navez quune seule interruption, savoir SSPIF . Le bit BCIF naaucune raison dtre ici, car seul un matre peut gnrer et dtecter une collision de bus. Or,vous avez plusieurs vnements susceptibles de provoquer cette interruption. Il vous faudradonc une mthode pour distinguer quel vnement vous avez traiter.Tout se base sur ltat des bits suivants, contenus dans le registre SSPSTAT :S : sil vaut 1 , une opration est en cours412R_W : 1 indique une lecture en cours, 0 une critureD_A : 1 signale que loctet qui vient darriver est une donne, 0 une adresseBF : 1 signale que SSPBUF est pleinNous allons, en toute logique, rencontrer les cas suivants :Premier casS = 1 ; transfert en coursR_W = 0 ; il sagit dune critureBF = 1 ; la donne a t reueD_A = 0 ; et il sagit de ladresseNous voyons donc que le matre dsire crire (nous envoyer des octets). Ladresse denotre PIC ou ladresse gnrale est maintenant dans notre SSPBUF. Nous devons le lire afindeffacer BF.Second casS = 1 ; transfert en cours.R_W = 0 ; il sagit dune critureBF = 1 ; la donne a t reueD_A = 1 ; et il sagit dune donneNous venons ici de recevoir une donne, quil nous incombe de ranger danslemplacement de notre choix.ATTENTION : Si votre bus IC travaille grande vitesse, ou que le traitement de votreinterruption est retard (autre interruption), vous pourriez avoir le bit S=0 et le bit P(stop-condition) = 1. Ceci signifie simplement que le stop-condition a dj t reu avantque vous nayez eu le temps de traiter la rception de loctet.Troisime casS = 1 ; transfert en coursR_W = 1 ; il sagit dune lectureBF = 0 ; Le buffer est vide (ladresse en lecture ninfluence pas BF)D_A = 0 ; ladresse a t reueVotre PIC vient de recevoir son adresse. Comme il sagit de requte de lecture, le bus estmaintenu en pause par votre PIC qui a plac le bit CKP automatiquement 0 . Une foisque vous avez plac la premire donne crire dans votre registre SSPBUF (BF passe 1 ), vous remettez CKP 1, ce qui va permettre lmission.Remarquez que, bien que ladresse soit charge dans SSPBUF, le bit BF na pas tpositionn automatiquement. Il est donc inutile de lire SSPBUF.Quatrime casS = 1 ; transfert en cours413R_W = 1 ; il sagit dune lectureBF = 0 ; loctet a t envoy (le buffer est vide)D_A = 1 ; et il sagissait dune donneCeci indique que vous devez maintenant placer un octet de donne qui nest pas lepremier. Le matre vous en rclame donc dautres.Vous devez donc placer un nouvel octet dans SSPBUF, puis remettre CKP 1 pour librerla ligne SCL. Si, suite une erreur du matre, il vous demandait un octet, alors que vousnavez plus rien envoyer, vous naurez dautre solution que de lui envoyer nimporte quoi.Une absence de raction de votre part entranerait le blocage du bus IC.Cinquime casS = 1 ; transfert en coursR_W = 0 ; il sagit dune critureBF = 0 ; Le buffer est videD_A = 1 ; Le dernier octet envoy tait une donne.En fait, nous avons ici une impossibilit apparente dont jai dj parl. En effet, si noussommes dans notre routine dinterruption, cest que lopration a t termine, puisque SSPIFa t positionn. De quelle opration sagit-il ? Et bien, dune criture. Donc, puisquelcriture est termine, la donne se trouve dans SSPBUF. Or le bit BF nest pas positionn,cest donc une situation paradoxale.Lexplication est quun NOACK a t reu lors dune lecture, indiquant que letransfert est termin. Ce NOACK a comme effet de resetter le bit R_W, ce qui nous donnecette configuration paradoxale.Ce cas est donc tout simplement la concrtisation de la rception dun NOACK. Vous savez partir de ce moment que le matre ne vous demandera plus de nouvel octet, vous de traiter ceci ventuellement dans votre programme.La routine dinterruptionNous pouvons maintenant en venir la faon de traiter les interruptions. Nous allonsimaginer que nous compltons la sous-routine dinterruption int_ssp. Nous allons considrerque la zone des variables contient les lments suivants :- La zone de stockage des octets reus dmarre en bufin- La zone de stockage des octets mettre dmarre en bufout- ptrin contient un pointeur sur le prochain emplacement libre de bufin- ptrout contient un pointeur sur le prochain emplacement libre de bufout- flagout est un flag qui est positionn lorsque tous les octets ont t envoys- flaggen est un flag qui indique sil sagit dune commande gnraleLe traitement des flags est du ressort du programme principal.414Je ne gre pas les conditions derreur (ex : dbordement des buffers) afin de ne pasalourdir les routines, limportant est de comprendre la faon de procder.;*****************************************************************************; INTERRUPTION SSP *;*****************************************************************************;-----------------------------------------------------------------------------; Gestion de linterruption en mode esclave.; cas 1 : rception de ladresse en mode criture; cas 2 : rception dune donne; cas 3 : rception de ladresse en mode lecture; cas 4 : envoi dune donne en mode lecture; cas 5 : rception du NOACK de fin de lecture; erreur : tout autre cas est incorrect, on provoque le reset du PIC par; dbordement du watchdog ( vous de traiter de faon approprie);-----------------------------------------------------------------------------intssp; conserver les bits utiles; --------------------------BANKSEL SSPSTAT ; passer en banque 1movf SSPSTAT,w ; charger valeur SSPSTATandlw B00101101 ; garder D_A, S, R_W, et BFbcf STATUS,RP0 ; repasser en banque 0movwf ssptemp ; sauvegarder dans variable temporaire; cas 1 : rception adresse criture; ----------------------------------xorlw B00001001 ; buffer plein, contient une adressebtfss STATUS,Z ; condition ralise ?goto intssp2 ; non, examiner cas 2movlw bufin ; charger adresse du buffer de rceptionmovwf ptrin ; le prochain octet sera le premier du buffer inbcf flaggen ; par dfaut, pas une commande gnralemovf SSPBUF,w ; efface BF, teste ladressebtfsc STATUS,Z ; adresse gnrale reue ?bsf flaggen ; oui, positionner le flagreturn ; fin du traitement; cas 2 : rception dune donne; -------------------------------intssp2movf ssptemp,w ; charger bits utiles de SSPSTATxorlw B00101001 ; buffer plein, contient une donneandlw B11110111 ; liminer le bit S (stop-condition dj reu)btfss STATUS,Z ; condition ralise ?goto intssp3 ; non, examiner cas 3movf ptrin,w ; charger pointeur dentremovwf FSR ; dans pointeur dadressemovf SSPBUF,w ; charger donne reuemovwf INDF ; la placer dans le buffer dentreincf ptrin,f ; incrmenter le pointeur dentrereturn ; fin du traitement; cas 3 : mission de la premire donne; ---------------------------------------intssp3movf ssptemp,w ; charger bits utiles de SSPSTAT415xorlw B00001100 ; demande denvoi, on vient de recevoir ladressebtfss STATUS,Z ; condition ralise ?goto intssp4 ; non, examiner cas 4movlw bufout+1 ; charger adresse du buffer dmission + 1movwf ptrout ; le prochain octet sera le second du buffer outmovf bufout,w ; charger le premier octet du buffer dmissionmovwf SSPBUF ; dans le buffer I2Cbsf SSPCON,CKP ; met fin la pause, permet le transfertreturn ; fin du traitement; cas 4 : mission dune donne quelconque; ----------------------------------------intssp4movf ssptemp,w ; charger bits utiles de SSPSTATxorlw B00101100 ; demande denvoi qui suit un autre envoibtfss STATUS,Z ; condition ralise ?goto intssp5 ; non, examiner cas 5movf ptrout,w ; charger pointeur buffer de sortiemovwf FSR ; dans pointeur dadressemovf INDF,w ; charger octet envoyermovwf SSPBUF ; le mettre dans le buffer de sortiebsf SSPCON,CKP ; libre lhorloge, permet le transfertincf ptrout,f ; incrmenter pointeur de sortiereturn ; fin du traitement; cas 5 : rception du NOACK; ---------------------------intssp5movf ssptemp,w ; charger bits utiles de SSPSTATxorlw B00101000 ; NOCAK reubtfss STATUS,Z ; condition ralise ?goto $ ; non, reset PIC par dbordement watchdogbsf flagout ; signaler fin de lecturereturn ; et retourVous voyez que tout est logique. Vous allez peut-tre penser que cette routine de slectionest un peu longue. Mais, de toute faon, je viens de lcrire pour vous, pas vrai? Je vousconseille un excellent exercice si vous comptez utiliser lIC en mode esclave : essayez dercrire cette routine vous-mme, vous saurez vite si vous avez tout compris ou pas.23.10 Le module MSSP en mode IC esclave 10 bitsJe ne vais pas reprendre lintgralit des fonctions pour ce cas, je vais me contenter devous expliquer ce qui diffre lorsque vous dcidez de travailler avec des adresses codes sur10 bits.Nous allons distinguer 2 cas, celui de la lecture et celui de lcriture. Commenons par lesecond. Les oprations raliser sont les suivantes (pour le cas o on a correspondancedadresse) :- Le PIC reoit le start-condition- On reoit le premier octet dadresse, avec R/W 0 .- On gnre le ACK- On reoit le second octet dadresse416- On gnre le ACK- On reoit le premier octet.- .Tout ceci est dj connu, il ne reste quune question : comment savoir que lon doit placerle second octet dadresse ?Et bien, tout simplement parce que le bit UA (Update Adress) est automatiquementpositionn lorsque vous devez changer loctet qui se trouve dans SSPADD. Cepositionnement de UA saccompagne de la mise en pause automatique du bus, lhorloge tantbloque ltat bas par le PIC esclave.Ds que vous crivez votre autre octet dans SSPADD, le bit UA est automatiquementeffac, et la ligne SCL est libre afin de mettre fin la pause. Les tapes sont donc lessuivantes :- On reoit le premier octet dadresse : Le ACK est gnr automatiquement, le bit UA estpositionn ainsi que le bit SSPIF. Lhorloge SCL est maintenue ltat bas, plaant le busen mode pause- On crit le second octet dadresse dans SSPADD : le bit UA est resett, la ligne SCL estlibre- On reoit le second octet dadresse : Le ACK est gnr automatiquement, le bit UA estpositionn ainsi que le bit SSPIF. Le bus est plac en pause.- On crit le premier octet dadresse dans SSPADD : on est alors prt pour une prochainerception, le bit UA est resett automatiquement et la pause prend finNous avons donc reu 2 fois une interruption avec le bit UA positionn. Il suffit donc, endbut de notre routine dinterruption, de tester UA. Sil est mis 1 , on met jourSSPADD. Sil contenait loctet 1 dadresse, on y place loctet 2, et rciproquement.Voyons maintenant le cas de lcriture :- Le PIC reoit le start-condition- On reoit le premier octet dadresse, avec R/W 0 .- On gnre le ACK- On reoit le second octet dadresse- On gnre le ACK- On reoit le repeated start-condition- On reoit le premier octet dadresse, avec R/W 1 - On gnre le ACK- On envoie le premier octet demandCeci se traduit, au niveau du PIC :- On reoit le premier octet dadresse : Le ACK est gnr automatiquement, le bit UA estpositionn ainsi que le bit SSPIF. Lhorloge SCL est maintenue ltat bas, plaant le busen mode pause417- On crit le second octet dadresse dans SSPADD : le bit UA est resett, la ligne SCL estlibre- On reoit le second octet dadresse : Le ACK est gnr automatiquement, le bit UA estpositionn ainsi que le bit SSPIF. Le bus est plac en pause.- On crit le premier octet dadresse dans SSPADD : on est alors prt pour une prochainerception, le bit UA est resett automatiquement et la pause prend fin- On reoit de nouveau le premier octet dadresse, MAIS UA nest pas positionn (cest unefonction automatique du PIC). On se retrouve donc maintenant dans le cas dune lectureavec des adresses de 7 bits (mmes conditions).Donc, notre algorithme reste valable : on ne met jour SSPADD que si UA est positionn.Sinon, on poursuit le traitement ordinaire de notre interruption.23.11 SynthseNous avons maintenant tudi tous les cas possibles, savoir :- Lmission et la rception en IC matre- Lmission et la rception en IC multi-matre- Lmission et la rception en mode esclave sur adresses 7 bits- Lmission et la rception en mode esclave sur adresses 10 bits- La gestion des interruptions.Vous voici devenu des spcialistes de lIC, moins que vous ne ressentiez brutalementun important mal de tte. Rassurez-vous, en prenant une pause et en relisant quelques fois,vous allez voir que cest plus simple comprendre qu expliquer (heureusement pour vous,malheureusement pour moi).Vous constatez par vous-mme quil ne mest gure possible de donner un exempleconcret pour chaque mode, cest pourquoi je vous ai donn dans la thorie des exemples detraitement des vnements IC. Je ne raliserai donc quun exercice, que jai choisivolontairement comme un cas des plus courants.Je vous rappelle que vous disposez de plusieurs faons de traiter les vnements (pooling,interruptions). Je vous donne ici les mthodes que je vous prconise :Pour le mode matre ou multimatre:- Si vous avez le temps dattendre, je vous conseille dexcuter les commandes et dattendrela fin de leur excution pour sortir de la sous-routine correspondante.- Si vous voulez gagner un peu de temps, vous sortez de suite, et vous testez lors de laprochaine sous-routine si la prcdente est termine. Cette mthode est galement pluspratique pour le mode multimatre, car le test du bus libre peut tre intgr dans la routineI2C_free418- Si vous avez absolument besoin de librer le PIC le plus rapidement possible, vous devrezutiliser les interruptions.Pour le mode esclave :- Je vous conseille dans tous les cas le traitement par interruption, puisque les vnementsarrivent de faon asynchrone au droulement de votre programme, sans oublier quunretard de raction provoque le blocage du bus.- Si vous ne souhaitez absolument pas utiliser les interruptions, alors noubliez pas de testertoutes les conditions derreurs possibles (SSPOV, BF ) afin dviter un blocage dfinitifdu bus IC.23.12 Exercice pratique : pilotage dune 24c64Enfin, nous arrivons la pratique. Pour raliser cet exercice, nous allons ajouter uneeeprom 24C32 ou 24C64 notre PIC. Nous aurons galement besoin de 8 LEDs, afin devisualiser ce que contient leeprom.Voici le montage :419Notez sur ce schma la prsence des 2 rsistances de rappel au +5V indispensables sur leslignes SCL et SDA.Nous allons raliser un programme qui crit 40 valeurs dans leeprom. Ces valeurs vontensuite tre lues pour provoquer les allumages des LEDs. En somme, le programme vafonctionner comme notre programme lum , mais les donnes seront crites et lues dansnotre eeprom, ce qui est bien entendu le but de cet exercice.Commencez par effectuer un copier/coller de votre fichier m16F876.asm et renommezcette copie lum_eep.asm . Construisez un nouveau projet sur base de ce fichier.Comme toujours, on commence par len-tte et la configuration. Jai choisi de mettre lewatchdog en service :;*****************************************************************************; Exercice sur les accs I2C concrtiss par les changes avec une 24C64. *; Le programme crit 40 octets dans l'eeprom, puis les lit en boucle et *; envoie les octets lus intervalle de 0,5 seconde sur le PORTB (LEDs) *; *;*****************************************************************************; *; NOM: lum_eep *; Date: 06/07/2002 *; Version: 1.0 *; Circuit: Platine d'exprimentation *; Auteur: Bigonoff *; *;*****************************************************************************; *; Fichier requis: P16F876.inc *; *;*****************************************************************************; *; Notes: L'eeprom est connecte sur le bus I2C (SCL + SDA) *; A2, A1, et A0 de l'eeprom sont connectes la masse *; 8 LEDs sont connectes sur le PORTB *; LE quartz travaille 20MHz. *; *;*****************************************************************************LIST p=16F876 ; Dfinition de processeur#include ; fichier include__CONFIG _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_OFF & _CPD_OFF & _LVP_OFF &_BODEN_OFF & _PWRTE_ON & _WDT_ON & _HS_OSC;_CP_OFF Pas de protection;_DEBUG_OFF RB6 et RB7 en utilisation normale;_WRT_ENABLE_OFF Le programme ne peut pas crire dans la flash;_CPD_OFF Mmoire EEprom dprotge;_LVP_OFF RB3 en utilisation normale; _BODEN_OFF Reset tension hors service;_PWRTE_ON Dmarrage temporis;_WDT_ON Watchdog en service;_HS_OSC Oscillateur haute vitesse (4Mhz420; ASSIGNATIONS SYSTEME *;*****************************************************************************; REGISTRE OPTION_REG (configuration); -----------------------------------OPTIONVAL EQUB'10000000' ; RBPU b7 : 1= Rsistance rappel +5V hors serviceEnsuite, nos assignations. Nous allons avoir besoin de la valeur de recharge du timer2,calcule comme dans notre programme spimast1.asm . On prendra une valeur de rechargede PR2 de 249, ce qui, associ un nombre de passages de 125 et une combinaison pr etpostdiviseurs donnant une division totale de 80, nous donnera un temps total de 0.5S.Comme nous avons cbl notre eeprom avec ses lignes A2,A1, et A0 la masse, sonadresse : 1010 A2 A1 A0 R/W nous donnera en pratique : B10100000 (0xA0). Vue souscette forme, ladresse est dj prte placer dans SSPADD, donc nous naurons pas besoin dela dcaler vers la gauche.;*****************************************************************************; ASSIGNATIONS PROGRAMME *;*****************************************************************************ADRESSEQU B'10100000' ; adresse eeprom = 1010 A2 A1 A0 R/W(0); l'adresse est dj dcale (0xA0)PR2VALEQU D'249' ; Valeur de comparaison timer 2CMPTVAL EQU D'125' ; 125 passages dans la routine d'interruption; dure = Tcy*(PR2+1)*prdiv*postdiv*cmptval; = 0,2s * 250 * 16 * 5 * 125 = 0.5s.Nous allons devoir crire 40 valeurs dans notre mmoire RAM. Afin de rduire un peunotre fichier source (mais pas lexcutable), nous allons crer une petite macro, qui placeloctet pass en paramtre dans le buffer, la position prcise comme second paramtre.;*****************************************************************************; MACRO *;*****************************************************************************WBUF macro octet,offset ; place l'octet "octet" dans buffer+offsetmovlw octet ; charger octetmovwf buffer+offset ; placer dans le bufferendmMaintenant, notre zone de variables, qui contiendra notre buffer de 32 octets, une variablecontenant le nombre doctets envoyer, une variable sur 16 bits qui contiendra ladresse envoyer dans le pointeur dadresse de leeprom (ladresse de lecture ou dcriture), et, enfin,notre flag et notre compteur pour linterruption du timer2.;*****************************************************************************; VARIABLES BANQUE 0 *;*****************************************************************************; Zone de 80 bytes; ----------------CBLOCK0x20 ; Dbut de la zone (0x20 0x6F)buffer : 0x20 ; 32 octets de buffer421buflen : 1 ; longueur utilise du buffercmpt : 1 ; compteur de passages d'interruptionflags : 1 ; 8 flags d'usage gnral; b0 : 0.5s s'est couleeepa : 2 ; valeur pour le pointeur d'adresse eepromENDC ; Fin de la zoneLa zone de variables communes ne contient que les variables de sauvegarde ncessaires :;*****************************************************************************; VARIABLES ZONE COMMUNE *;*****************************************************************************; Zone de 16 bytes; ----------------CBLOCK 0x70 ; Dbut de la zone (0x70 0x7F)w_temp : 1 ; Sauvegarde registre Wstatus_temp : 1 ; sauvegarde registre STATUSENDCLa routine dinterruption, tout droit tire de notre programme lum , se contente depositionner le flag au bout de 125 passages correspondants 0.5 s.;*****************************************************************************; DEMARRAGE SUR RESET *;*****************************************************************************org 0x000 ; Adresse de dpart aprs reset goto init ; Initialiser; ////////////////////////////////////////////////////////////////////////////; I N T E R R U P T I O N S; ////////////////////////////////////////////////////////////////////////////;*****************************************************************************; ROUTINE INTERRUPTION *;*****************************************************************************;*****************************************************************************; ROUTINE INTERRUPTION *;*****************************************************************************;-----------------------------------------------------------------------------; La routine d'interruption timer 2 est appele toutes les; (0,2s * 80 * 250) = 4ms.; au bout de 125 passages, une demi-seconde s'est coule, on positionne; le flag;-----------------------------------------------------------------------------;sauvegarder registres;---------------------org 0x004 ; adresse d'interruptionmovwf w_temp ; sauver registre Wswapf STATUS,w ; swap status avec rsultat dans wmovwf status_temp ; sauver status swappbcf STATUS,RP0 ; passer banque0bcf STATUS,RP1422; interruption timer 2; --------------------bcf PIR1,TMR2IF ; effacer le flag d'interruptionbsf flags,1 ; 8 ms coulesdecfszcmpt,f ; dcrmenter compteur de passagesgoto restorereg ; pas 0, fin de l'interruptionmovlw CMPTVAL ; valeur de recharge du compteurmovwf cmpt ; recharger compteurbsf flags,0 ; positionner flag;restaurer registres;-------------------restoreregswapf status_temp,w ; swap ancien status, rsultat dans wmovwf STATUS ; restaurer statusswapf w_temp,f ; Inversion L et H de l'ancien W ; sans modifier Zswapf w_temp,w ; Rinversion de L et H dans W; W restaur sans modifier statusretfie ; return from interruptOn en arrive aux initialisations. En premier lieu, les PORTs. Comme au moment de lamise sous tension, les ports sont tous en entre, on ne forcera que les pins qui devront treconfigures en sortie. Dans notre cas, le PORTB, qui, pilotera les LEDs.On en profite pour couper les rsistances de rappel au +5V (pullup) du PORTB, qui serontici inutiles, via le registre doption.; ////////////////////////////////////////////////////////////////////////////; P R O G R A M M E; ////////////////////////////////////////////////////////////////////////////;*****************************************************************************; INITIALISATIONS *;*****************************************************************************init; initialisation PORTS; --------------------BANKSEL PORTB ; passer banque 0clrf PORTB ; sorties PORTB 0bsf STATUS,RP0 ; passer en banque1clrf TRISB ; PORTB en sortie, les autres en entremovlw OPTIONVAL ; charger masquemovwf OPTION_REG ; initialiser registre optionVient maintenant notre module IC. Nous allons indiquer que nous mettons le slew-ratecontrol en service et que nous travaillons avec des niveaux compatibles IC. Ceci nousamne ncrire que des 0 dans SSPSTAT. La frquence est dtermine par la valeur place dans SSPSTAT. Nous avons dj calculcette valeur pour une frquence de quartz de 20MHz et un dbit de 400KBauds. Cette valeurvaut 12.Il ne reste plus qu mettre le module en service et choisir le mode IC matre (tout cecivia SSPCON)423; initialiser I2C; ---------------clrf SSPSTAT ; slew rate control en service, mode ICmovlw D'12' ; valeur de recharge du BRG (400 Kbauds)movwf SSPADD ; dans registre de rechargebcf STATUS,RP0 ; passer banque 0movlw B'00101000' ; module MSSP en service en mode IC mastermovwf SSPCON ; dans registre de contrleOn initialise ensuite nos variables, ce qui se limite ici resetter le flag et initialiser lecompteur de passage pour la premire dure de 0.5 s.; initialiser variables; ---------------------clrf flags ; reset flagsmovlw CMPTVAL ; pour 125 passagesmovwf cmpt ; dans compteur de passagesReste initialiser notre timer2 (avec pr et postdiviseurs) et de mettre linterruptioncorrespondante en service. Cest du dj-vu.; initialiser timer 2; -------------------movlw PR2VAL ; charger valeur de comparaisonBANKSEL PR2 ; passer banque 1movwf PR2 ; initialiser comparateurmovlw B'00100110' ; timer2 on, prdiv = 16, post = 5bcf STATUS,RP0 ; passer banque 0movwf T2CON ;lancer timer 2; lancer interruption timer 2; ---------------------------bsf STATUS,RP0 ; passer banque 1bsf PIE1,TMR2IE ; interruption timer 2 en servicebcf STATUS,RP0 ; repasser banque 0bsf INTCON,PEIE ; interruptions priphriques en servicebsf INTCON,GIE ; lancer les interruptionsgoto start ; programme principalNotre sous-routine dinterruption se contente de tester le positionnement du flag,positionnement effectu par la routine dinterruption. Bien entendu, il ne faudra pas oublier deresetter ce flag avant de sortir :;*****************************************************************************; Attendre 0.5 seconde *;*****************************************************************************;-----------------------------------------------------------------------------; attendre que 0.5s se soit coule depuis le prcdent passage dans; cette routine;-----------------------------------------------------------------------------waitclrwdt ; effacer watchdogbtfss flags,0 ; flag positionn?goto wait ; non, attendre flagbcf flags,0 ; reset du flagreturn ; et retour424Maintenant, nous arrivons notre programme principal, qui commence par remplir lebuffer avec des donnes mmoriser en eeprom.Bien entendu, cest idiot de procder au remplissage dune eeprom de cette faon, puisquenous allons placer en eeprom des donnes qui se trouvent dj dans notre PIC. Mais il sagitdun exercice. Comme jai limit les composants au maximum, je nai pas dchange aveclextrieur, et donc, je nai pas dautre moyen de vous proposer la fois lecture et criture.Dans le chapitre sur les communications asynchrones, je modifierai ce programme pour lerendre utile. En attendant, revenons-en nos moutons (pardon, nos eeproms).Nous allons utiliser notre macro pour crire 32 valeurs dans le buffer :;*****************************************************************************; PROGRAMME PRINCIPAL *;*****************************************************************************start; remplir le buffer d'mission; ----------------------------WBUF 0x01,0x00 ; placer l'octet dans bufferWBUF 0x02,0x01 ; placer l'octet dans buffer + 1WBUF 0x04,0x02 ; placer l'octet dans buffer + 2WBUF 0x08,0x03 ; placer l'octet dans buffer + 3WBUF 0x10,0x04 ; placer l'octet dans buffer + 4WBUF 0x20,0x05 ; placer l'octet dans buffer + 5WBUF 0x40,0x06 ; placer l'octet dans buffer + 6WBUF 0x80,0x07 ; placer l'octet dans buffer + 7WBUF 0x40,0x08 ; placer l'octet dans buffer + 8WBUF 0x20,0x09 ; placer l'octet dans buffer + 9WBUF 0x10,0x0A ; placer l'octet dans buffer + 10WBUF 0x08,0x0B ; placer l'octet dans buffer + 11WBUF 0x04,0x0C ; placer l'octet dans buffer + 12WBUF 0x02,0x0D ; placer l'octet dans buffer + 13WBUF 0x01,0x0E ; placer l'octet dans buffer + 14WBUF 0x00,0x0F ; placer l'octet dans buffer + 15WBUF 0x01,0x10 ; placer l'octet dans buffer + 16WBUF 0x03,0x11 ; placer l'octet dans buffer + 17WBUF 0x07,0x12 ; placer l'octet dans buffer + 18WBUF 0x0F,0x13 ; placer l'octet dans buffer + 19WBUF 0x1F,0x14 ; placer l'octet dans buffer + 20WBUF 0x3F,0x15 ; placer l'octet dans buffer + 21WBUF 0x7F,0x16 ; placer l'octet dans buffer + 22WBUF 0xFF,0x17 ; placer l'octet dans buffer + 23WBUF 0xFE,0x18 ; placer l'octet dans buffer + 24WBUF 0xFC,0x19 ; placer l'octet dans buffer + 25WBUF 0xF8,0x1A ; placer l'octet dans buffer + 26WBUF 0xF0,0x1B ; placer l'octet dans buffer + 27WBUF 0xE0,0x1C ; placer l'octet dans buffer + 28WBUF 0xC0,0x1D ; placer l'octet dans buffer + 29WBUF 0x80,0x1E ; placer l'octet dans buffer + 30WBUF 0x00,0x1F ; placer l'octet dans buffer + 31Ensuite, nous allons envoyer ce buffer dans leeprom, via le bus IC. Nous allons imaginerque la routine eep_sendbuf se charge denvoyer le buffer. Nous crirons cette routine plusloin.425; envoyer buffer dans eeprom; --------------------------clrf eepa ; adresse d'criture = 00clrf eepa+1 ; idem poids faiblemovlw 0x20 ; 32 octets prsentsmovwf buflen ; placer dans le compteur d'octetscall eep_sendbuf ; envoyer le buffer dans l'eepromOn avait convenu quon crirait 40 octets. Comme on a dj crit 32 octets (limiteautorise en une seule criture, souvenez-vous), il nous reste 8 octets placer dans le buffer et envoyer. Naturellement, on va crire ces donnes dans leeprom la suite des prcdents,soit partir de ladresse 0x0020, ceci nous impose donc dcrire la nouvelle adresse dupointeur dans notre variable eepa (qui sera utilise dans notre sous-routine).; placer 8 nouveaux octets dans le buffer; ---------------------------------------WBUF 0x55,0x00 ; placer l'octet dans bufferWBUF 0xAA,0x01 ; placer l'octet dans buffer + 1WBUF 0x55,0x02 ; placer l'octet dans buffer + 2WBUF 0xAA,0x03 ; placer l'octet dans buffer + 3WBUF 0xF0,0x04 ; placer l'octet dans buffer + 4WBUF 0x0F,0x05 ; placer l'octet dans buffer + 5WBUF 0xF0,0x06 ; placer l'octet dans buffer + 6WBUF 0x0F,0x07 ; placer l'octet dans buffer + 7; envoyer buffer dans eeprom; --------------------------clrf eepa ; adresse d'criture = 0x0020movlw 0x20 ; adresse poids faiblemovwf eepa+1 ; initialisermovlw 8 ; 8 octets prsentsmovwf buflen ; placer dans le compteur d'octetscall eep_sendbuf ; envoyer le buffer dans l'eepromMaintenant, nos 40 octets sont cris dans leeprom, reste les lire et les envoyer dans lePORTB.Nous commenons donc par initialiser eepa avec ladresse du premier octet lire eneeprom, soit 0x00. Comme cette variable ne sera pas modifie par les sous-routines, on nelinitialisera quune fois :; traitement des lectures; -----------------------clrf eepa ; adresse de lecture = 00clrf eepa+1 ; idem poids faibleMaintenant, il nous reste procder aux lectures suivies par des envois sur PORTB. On a40 octets envoyer, donc :- Pour chaque octet- On lit loctet en eeprom- On lenvoie sur le PORTB- On attend 0.5 seconde- Si pas dernier octet, suivant.426Bien entendu, on doit rpter cette squence linfini, do une seconde boucleextrieure :- On positionne le pointeur dadresse de leeprom sur 0x0000 (premier octet)- On initialise le compteur doctets- Pour chaque octet- On lit loctet en eeprom- On lenvoie sur le PORTB- On attend 0.5 seconde- Si pas dernier octet, suivant.- Si dernier, on reprend le tout au dbutNous avons besoin dun compteur doctets. Comme nous ne nous servons plus de notrebuffer (on lit un octet la fois), on rcuprera notre variable buflen .Nous aurons besoin de quelques sous-routines. Nous allons les nommer, nous lesconstruirons plus loin :eep_adress : Initialise le pointeur dadresse de leepromi2c_stop : envoie le stop-condition sur le bus IC.eep_readc : lit loctet courant sur leeprom (lecture courante).Souvenez-vous que la lecture de loctet courant incrmente automatiquement le pointeurdadresse interne de leeprom. Voici ce que a nous donne :loop1call eep_adress ; initialiser pointeur d'adressecall i2c_stop ; fin transactionmovlw D'40' ; 40 octets liremovwf buflen ; dans compteur d'octetsloop2call eep_readc ; lire l'octet courantmovwf PORTB ; envoyer sur PORTBcall wait ; attendre 0.5sdecfszbuflen,f ; dcrmenter compteur d'octetsgoto loop2 ; pas dernier, suivantgoto loop1 ; dernier, on recommenceNotre programme principal est termin. Voyez quil est trs simple. Bien entendu, il reste crire les sous-routines, mais ces sous-routines peuvent tre rcupres dun programme lautre.En gnral, dans un programme de ce type, on aura :- Un programme principal qui utilise des sous-routines de gestion du priphriques I2C.- Des sous-routines de gestion du priphrique qui utilisent des sous-routines du bus I2C.- Des sous-routines du bus I2C qui grent lhardware.En sommes, un fonctionnement par couche. En travaillant ainsi (et cest valable pour despriphriques autres que les IC), vous avez des avantages non ngligeables :427- Vous pouvez ajouter un nouveau priphrique sans devoir rcrire les routines de gestionhardware- Si vous changez de PIC ou de processeur, vous ne devez modifier que les routines degestion hardware.- Vous ne faites donc quune seule fois le travail pour le hardware, et une seule fois parpriphrique ajout.Donc, notre programme principal peut tre considr comme un programme de hautniveau (il se rapproche du pseudo-code), nos routines de gestion du priphrique comme unpilote de priphrique, et nos routines de gestion du bus comme les routines de plus basniveau (hardware ou bios).Ceci pour vous dmontrer une fois de plus quon peut programmer en assembleur et resterstructur.Voyons donc comment cela se passe en pratique. Nous commencerons donc par nosroutines de gestion de leeprom. Et tout dabord, la routine de lecture de loctet courant. Onsupposera que le pointeur dadresse est positionn par une autre sous-routine. Les tapesncessaires sont les suivantes :- On envoie le start-condition- On crit ladresse du circuit (attention, pas ladresse du pointeur dadresse) avec le bitR/W 1 (lecture). Ladresse du circuit, pour une eeprom, est 1010 A2 A1 A0 R/W.- On procde la lecture de loctet courant- On envoie un stop-conditionSi vous avez tout compris, le start, stop, etc. seront traites par les sous-routines du busIC. On dcide que loctet sera retourn au programme principal via le registre w .;*****************************************************************************;*****************************************************************************; ROUTINES EEPROM *;*****************************************************************************;*****************************************************************************;*****************************************************************************; LIRE L'OCTET COURANT *;*****************************************************************************;-----------------------------------------------------------------------------; Lit l'octet point par le pointeur eeprom et le retourne dans w; ensuite, clture la communication;-----------------------------------------------------------------------------eep_readccall i2c_start ; envoyer start-conditionmovlw ADRESS+1 ; charger adresse eeprom en lecturecall i2c_write ; envoyer adresse eepromcall i2c_read ; lire l'octetcall i2c_stop ; fin du transfertreturn ; et retour428Vous voyez, cest tout simple : en procdant de la sorte, il vous suffit du datasheet deleeprom pour crire votre routine.Une autre routine ncessaire, est notre routine qui va crire le contenu du buffer dansleeprom. Nous aurons besoin du nombre doctets envoyer (pass dans buflen), de ladressedcriture en eeprom (passe dans eepa), et des donnes crire (contenues dans buffer). Laroutine devra effectuer les oprations suivantes :- Initialiser le pointeur dadresse (routine dj appele par notre programme principal)- Pour chaque octet- Ecrire loctet sur le bus I2C- Octet suivant- Envoyer le stop-condition (on ne peut plus rien ajouter);*****************************************************************************; ENVOYER LE BUFFER DANS L'EEPROM *;*****************************************************************************;-----------------------------------------------------------------------------; Envoie le buffer dans l'eeprom; buffer contient les donnes envoyer; buflen contient le nombre d'octets envoyer (dtruit aprs l'excution); eepa contient l'adresse d'criture;-----------------------------------------------------------------------------eep_sendbufcall eep_adress ; initialiser pointeur adressemovlw buffer ; charger adresse buffermovwf FSR ; dans pointeureep_sendb1movf INDF,w ; charger un octetcall i2c_write ; l'envoyerincf FSR,f ; incrmenter pointeur bufferdecfszbuflen,f ; dcrmenter nbre d'octets restantsgoto eep_sendb1 ; pas fini, suivantcall i2c_stop ; fin du transfertreturn ; et retourCest toujours aussi simple, on ne soccupe nullement de llectronique. Il nous restemaintenant notre procdure dinitialisation du pointeur dadresse. Ladresse placer dans lepointeur se trouve dans eepa Les oprations sont un peu plus longues :- On envoie un start-conditionLabel 1- On envoie ladresse du circuit en criture (criture de 1010 A2 A1 A0 0 )- On lit lack reu.- Si NOACK, on envoie un repeated start-condition et on recommence Label 1- Si ACK :- On crit loctet dadresse de poids fort (eepa)- On crit loctet dadresse de poids faible (eepa+1).Une fois de plus (jinsiste), ne confondez pas ladresse de leeprom (1010 A2 A1 A0R/W), avec ladresse de lecture ou dcriture de loctet dans leeprom (2 octets eepa).;*****************************************************************************; INITIALISER LE POINTEUR D'ADRESSE;*****************************************************************************429;-----------------------------------------------------------------------------; envoie le start-condition, puis l'adresse de l'eeprom; ensuite, teste le ACK; Si NOACK, on envoie le repeated start-condition, puis de nouveau l'adresse; si toujours NOACK, on recommence; Si ACK, on envoie les 2 octets d'adresse contenus dans eepa;-----------------------------------------------------------------------------eep_adress; envoyer adresse circuit tant que pas ACK; ----------------------------------------call i2c_start ; envoyer start-conditioneep_adress1movlw ADRESS ; charger adresse eeprom + criturecall i2c_write ; crire adresse eeprombsf STATUS,RP0 ; passer en banque1btfss SSPCON2,ACKSTAT ; tester ACK reugoto eep_adressok ; oui, poursuivre OKcall i2c_rstart ; non, envoyer repeated start-conditiongoto eep_adress1 ; recommencer test; placer 2 octets d'adresse dans pointeur; ---------------------------------------eep_adressokbcf STATUS,RP0 ; repasser banque 0movf eepa,w ; charger poids fort adressecall i2c_write ; crire poids fortmovf eepa+1,w ; charger poids faible adressecall i2c_write ; crire poids faiblereturn ; et retourEt voil : concernant notre eeprom, nous savons maintenant la slectionner et initialiser lepointeur dadresse, lire loctet point, et crire un buffer. A vous de complter si vous avezbesoin dautres sous-routines.Maintenant, il nous faut grer notre hardware, cest--dire piloter rellement notre bus IC.Jai choisi ici la mthode qui consiste envoyer une commande, et attendre la fin de sonexcution pour sortir. Il sagit donc simplement ici de recopier ce que nous avons vu dans lathorie.Afin de faciliter la lecture, jai cr une petite macro qui attend leffacement du bit passen second paramtre dans le registre pass en premier paramtre.;*****************************************************************************;*****************************************************************************; ROUTINES I2C *;*****************************************************************************;*****************************************************************************;-----------------------------------------------------------------------------; On attend que chaque commande soit termine avant de sortir de la; sous-routine correspondante;-----------------------------------------------------------------------------IWAIT macro REGISTRE,BIT ; attendre effacement du bit du registreclrwdt ; effacer watchdogbtfsc REGISTRE,BIT ; bit effac?goto $-2 ; non, attendrebcf STATUS,RP0 ; repasser en banque 0endm ; fin de macro430Il suffit donc dinscrire IWAIT registre ,bit pour attendre que le bit soit effac avant decontinuer. Le watchdog est gr, et on repasse en banque 0 avant de poursuivre(en effet,jentre et je termine toujours une routine en tant en banque 0 (convention personnelle que jevous conseille). Comme ce test prcdera la sortie de la sous-routine, autant linclure.Remarquez le $ -2 dont je vous ai dj parl, et qui signifie simplement 2 lignes plushaut .Maintenant, on entre dans le vif de notre sujet, la gestion de LIC. On commence parlenvoi du start-condition :;*****************************************************************************; ENVOYER LE START-CONDITION *;*****************************************************************************i2c_startbsf STATUS,RP0 ; passer en banque 1bsf SSPCON2,SEN ; lancer le start-conditionIWAIT SSPCON2,SEN ; attendre fin start-conditionreturn ; et retourPlus simple me parat impossible, pas vrai ?Les repeated start-condition et stop-condition sont strictement similaires :;*****************************************************************************; ENVOYER LE REPEATED START-CONDITION *;*****************************************************************************i2c_rstartbsf STATUS,RP0 ; passer en banque 1bsf SSPCON2,RSEN ; lancer le repeated start-conditionIWAIT SSPCON2,RSEN ; attendre fin repeated start-conditionreturn ; et retour;*****************************************************************************; ENVOYER LE STOP-CONDITION *;*****************************************************************************i2c_stopbsf STATUS,RP0 ; passer en banque 1bsf SSPCON2,PEN ; lancer le stop-conditionIWAIT SSPCON2,PEN ; attendre fin stop-conditionreturn ; et retourLenvoi dun ACK ou dun NOACK ne diffrent que par la valeur place dansACKDT.;*****************************************************************************; ENVOYER LE ACK *;*****************************************************************************i2c_ackbsf STATUS,RP0 ; passer en banque 1bcf SSPCON2,ACKDT ; le bit qui sera envoy vaudra " 0 "bsf SSPCON2,ACKEN ; lancer l'acknowledge (= ACKDT = 0 = ACK)IWAIT SSPCON2,ACKEN ; attendre fin ACKreturn ; et retour;*****************************************************************************; ENVOYER LE NOACK *431;*****************************************************************************i2c_noackbsf STATUS,RP0 ; passer en banque 1bsf SSPCON2,ACKDT ; le bit qui sera envoy vaudra " 1 "bsf SSPCON2,ACKEN ; lancer l'acknowledge (= ACKDT = 1 = NOACK)IWAIT SSPCON2,ACKEN ; attendre fin NOACKreturn ; et retourVous pouviez combiner les 2 sous-routines pour gagner de la place, avec 2 points dentreet un goto (optimisatoin en taille, mais pas en temps dexcution), mais le but ici tait derester explicite.i2c_noackbsf STATUS,RP0 ; passer en banque 1bsf SSPCON2,ACKDT ; le bit qui sera envoy vaudra " 1 "goto ic2_acknoack ; poursuivre le traitementi2c_ackbsf STATUS,RP0 ; passer en banque 1bcf SSPCON2,ACKDT ; le bit qui sera envoy vaudra " 0 "ic2_acknoackbsf SSPCON2,ACKEN ; lancer l'acknowledge (= ACKDT = 0 = ACK)IWAIT SSPCON2,ACKEN ; attendre fin ACKreturn ; et retourNous avons besoin galement de pouvoir crire un octet. De nouveau, cest trs simple,loctet sera pass par lintermdiaire du registre w :;*****************************************************************************; ENVOYER UN OCTET *;*****************************************************************************;-----------------------------------------------------------------------------; L'octet est pass dans W;-----------------------------------------------------------------------------i2c_writemovwf SSPBUF ; lancer l'mission de l'adresse en mode criturebsf STATUS,RP0 ; passer en banque 1IWAIT SSPSTAT,R_W ; attendre mission terminereturn ; et retourIl ne nous reste plus qu pouvoir lire un octet, tant entendu que lcriture de ladresse ducircuit est strictement identique lcriture dun octet de donne :;*****************************************************************************; LIRE UN OCTET *;*****************************************************************************;-----------------------------------------------------------------------------; L'octet est retourn dans W;-----------------------------------------------------------------------------i2c_readbsf STATUS,RP0 ; passer en banque 1bsf SSPCON2,RCEN ; lancer la lectureIWAIT SSPCON2,RCEN ; attendre rception terminemovf SSPBUF,w ; charger octet reureturn ; et retourEND ; directive fin de programme432Vous voyez la directive end de fin de programme, ce qui vous confirme que cesttermin. Vous constatez que bien que cela semble un peu long, tout ceci est extrmementsimple. De plus, je vous le rappelle, vous ncrirez jamais ces routines quune seule fois.Lancez lassemblage, placez votre fichier lum_eep.hex dans votre eeprom, et lancezlalimentation. Vos LEDs clignotent suivant les donnes inscrites en eeprom.23.13 Le module IC en mode sleepSi votre PIC est plac en mode de sommeil, il sera capable dans tous les cas de recevoirdes octets de donne ou dadresse. Si linterruption SSPIF est active, le PIC sera rveill partoute correspondance dadresse ou toute fin dopration.23.14 ConclusionsCeci termine ce trs long chapitre consacr au bus I2C. Jai beaucoup dvelopp, effectuplusieurs rptitions, mais ce bus est un bus trs frquemment utilis, et il est plus queprobable que si vous continuez laventure des PICs, vous serez amens lutiliser de faonrpte.23.15 Annexe : errata sur le ICAvant de pouvoir terminer cet ouvrage, Microchip vient de publier un errata, dat du07/2002, concernant le fonctionnement du module IC. Cet errata concerne les versionsactuellement disponibles des PICs. A vous de vrifier le cas chant si cet errata a t corrigau moment o vous utiliserez cet ouvrage dans les PICs qui seront ce moment en votrepossession. Ce bug est drangeant si vous utilisez votre PIC dans un environnement multi-matre. Voici de quoi il sagit :Lorsquun start-condition est plac sur la ligne, le bit S est positionn dans le registreSSPSTAT. Tant que ce bit est positionn, le module narrive plus dtecter un nouveau start-condition qui interviendrait par erreur. Le bit S reste positionn jusque :- La rception dun stop-condition- Le reset du module MSSP- Laccus de rception du second octet dune adresse sur 10 bits.Autrement dit :Si, PAR ERREUR, un start-condition est rencontr au milieu dune trame, il ne sera pasdtect comme une erreur, et sera interprt comme tant un bit de donne.De plus, un NOACK gnr par lesclave ne provoquera pas non plus le reset du module.433Malheureusement, ce bug affecte actuellement toutes les versions de PICs, y comprisles tout nouveaux PIC 18xxx. Microchip annonce quil va tenter de corriger ce bug sur lesnouvelles versions.Dans lattente, la solution propose est la suivante :- lancer un timer lors de la rception dun start-condition. Le temps de dbordement seracalcul en fonction du temps maximum sparant la rception dun start-condition deleffacement normal du bit S .- Si le timer dborde (temps tablir par lutilisateur), cest que le stop-condition na past reu dans le dlai correct. Lutilisateur devra alors resetter le module, ce qui peut trefait en changeant provisoirement la valeur des bits SSPMx, puis les remettre la valeurcorrecte pour lapplication.23.16 Bug en mode IC esclaveMicrochip a remplac le prcdent document concernant le bug en mode multimatre parun nouveau document qui indique cette fois un bug en mode IC esclave.Ce bug intervient quand :- Lorsque par erreur un repeated start-condition (SR) est reu lintrieur dun bit dedonne ou dadresse. Dans ce cas, ce SR indsirable pourrait tre interprt comme un bitde donne.- Lorsque un SR est reu par lesclave, en mode lecture, alors que la trame prcdentesadressait au mme esclave et galement en mode lecture. Ceci est beaucoup plus gnant,car correspond un fonctionnement possible normal du mode IC. Vous tes ds lorscontraints de prendre les prcautions indiques. Sans les dites prcautions, vous risquez devoir votre PIC bloquer dfinitivement votre bus IC.La mthode de protection contre ce bug est identique celle dcrite prcdemment, cest--dire lancement dun timer ds rception du start-condition, le dbordement du timerindiquant que le stop-condition na pas t reu dans les dlais prvus. Ce dlai dpend de lalongueur des trames changes, et donc de lapplication.Une fois lerreur dtecte, le module IC devra tre resett. Ceci peut se faire de 2 faons :- En changeant provisoirement la valeur des bits SSPM3 SSPM0 du registre SSPCON.- En effaant puis repositionnant le bit SSPEN du registre SSPCON.Noubliez pas, si vous utilisez le module IC, de vrifier toute ventuelle volution de ce(ces ?) bug directement chez Microchip.434Notes : 43524. Le module USART en mode srie synchrone24.1 IntroductionEt oui, nous avons un second module de communication srie. Selon lhabitude deMicrochip, celui-ci fonctionne de faon diffrente par rapport au module MSSP, afin de vousoffrir un maximum de possibilits. Son tude est donc loin dtre inutile, je dirai mmequelle est indispensable.USART signifie Universal Synchronous Asynchronous Receiver Transmitter . Cestdonc un module qui permet denvoyer et de recevoir des donnes en mode srie, soit de faonsynchrone, soit asynchrone. Dans certaines littratures, vous retrouverez galement le termegnrique de SCI pour Serial Communications Interface .Le module USART de notre PIC gre uniquement 2 pins, savoir RC6/TX/CK etRC7/RX/DT. Comme vous savez quune liaison srie synchrone ncessite une ligneddicace lhorloge, il ne vous reste donc quune seule ligne pour transmettre les donnes.On en dduit que le PIC ne pourra mettre et recevoir en mme temps en utilisantlUSART en mode synchrone. On parlera donc de liaison half-duplex . Par contre, le modeasynchrone na pas besoin de ligne dhorloge (voir cours sur les 16F84, chapitre sur la norme7816), il nous restera alors 2 lignes pour communiquer, chacune tant ddicace un sens detransfert. Nous pourrons donc envoyer et recevoir des donnes en mme temps. On parlera deliaison full-duplex .Comme, de plus, vous savez maintenant que lhorloge, en mode synchrone, est sous lecontrle du matre, notre USART pourra fonctionner dans les modes suivants :- Mode asynchrone full duplex : mission sur TX et rception sur RX- Mode asynchrone half-duplex sur 2 lignes (TX et RX) ou sur une ligne (TX/RX relies)- Mode synchrone matre : mission horloge sur CK et mission/rception donnes sur DT- Mode synchrone esclave : rception horloge sur CK et mission/rception donnes sur DTJe vais donc, pour votre facilit, scinder de nouveau les explications en 2 chapitres. Ceschapitres auront pas mal de points communs, comme, par exemple, les registres utiliss. Jecommence, pour rester dans la logique de ce que nous venons de voir, par le fonctionnementen mode synchrone.24.2 Mise en uvre et protocoles436Vous constatez que tous les intervenants peuvent tre matres ou esclaves. Bien entendu, ilne peut y avoir quun matre en mme temps, de mme quil ne peut y avoir quun seulmetteur en mme temps.Cest donc vous de grer ceci. Il existe diffrentes mthodes, par exemple :- Vous dcidez que cest toujours le mme lment qui est le matre. Cest donc lui quiadministre le bus. Il dcide qui peut mettre, et quand. Ceci peut tre ralis, par exemple,en envoyant un octet particulier qui prcise qui va rpondre. Le matre interroge chaqueesclave tour de rle en prcisant dans son message le numro de lesclave interrog.Celui-ci rpond sous le contrle du matre. Cette mthode est couramment appele spooling .- Le tocken-ring , ou anneau jeton fonctionne de la faon suivante : Le matreactuel parle un esclave (il prcise par un octet qui il sadresse). Il passe alors la parole lesclave, qui devient le nouveau matre du bus. Le matre actuel redevient esclavejusqu ce quun matre lui rende le droit de gestion (jeton).- Le spooling avec request mlange plusieurs techniques. Les esclaves et le matre sontinterconnects avec une ou plusieurs lignes de slections supplmentaires (gres parlogiciel). Quand un esclave a quelque chose dire, il force une ligne de request . Lematre sait alors que quelquun a quelque chose dire, il va interroger les intervenants tour de rle pour savoir qui a positionn la ligne. Une fois lesclave interrog, celui-cilibre la ligne. Notez que cette mthode ressemble celle utilise en interne pour grer lesinterruptions. On peut amliorer en ajoutant plusieurs lignes de request de prioritsdiffrentes, et vous en arrivez la mthode utilise par le processeur de votre PC pourcommuniquer avec certains priphriques (Interrupt-ReQuest ou IRQ).- Toute autre mthode par laquelle vous vous assurez quun seul et unique matre gre lebus un instant donn, et quun seul et unique composant est en train dmettre. Ceciinclus lajout de lignes spcifiques gres comme des lignes de slection.437Je vous donne un petit exemple de tocken-ring . Supposons qu la mise sous tension,le matre est le PIC1. Vous dcidez dattribuer ladresse 1 au PIC1, 2 au PIC2, et 3 autroisime composant. Vous devez ensuite vous fabriquer un protocole de communication.Vous dcidez que les trames envoyes (suite doctets) seront de la forme :Loctet 1 contient ladresse du destinataire code sur 5 bits, le bit 6 indiquant que ledestinataire peut rpondre, le bit 7 tant le jeton (tocken). Il sera suivi par 2 octets de donnes.Voici ce que pourrait donner un change :- Le PIC1 (qui est le matre) envoie : B00000010, Baaaaaaaa, Bbbbbbbbb- Le PIC 2 (adresse = 2) sait que les octets lui sont destins, il na pas droit de rponse- Le PIC1 envoie : B01000010, Bcccccccc,Bdddddddd- Le PIC2 sait que les octets lui sont destins, le bit 6 du premier octet 1 lautorise rpondre. Il place sa rponse dans son registre dmission, mais il reste en esclave- Le PIC1 provoque la lecture, il rcupre la rponse du PIC2 : B00000001, Beeeeeeee,Bffffffff- Le PIC1 envoie : B10000011, Bgggggggg,Bhhhhhhhh- Le PIC1 a donn le jeton (bit7 1) au PIC3 tout en lui transmettant 2 octets.- Le PIC1 devient esclave- Le PIC3 devient le matre : il peut continuer les transactions comme il lentend.Voici un exemple de ce que pourrait donner un tocken-ring , comme a vous pouvezimaginer des exemples pratiques dapplication. Ceci pour vous dire que cest vousdimaginer un protocole de communication (ou de vous conformer un protocole existant sivous avez besoin dinsrer votre PIC dans un rseau spcifique).24.3 le registre TXSTAle registre TRANSMITT STAtus and control register , comme son nom lindique,contient des bits de status et de contrle, la plupart concernant lmission de donnes. Voiciles bits utiliss en mode synchrone :TXSTA en mode synchroneb7 : CSRC : Clock SouRCe select bit (1 = master, 0 = slave)b6 : TX9 : TRANSMITT 9 bits enable bit (1 = 9 bits, 0 = 8 bits)b5 : TXEN : TRANSMITT ENable bitb4 : SYNC : SYNChronous mode select bit (1 = synchrone, 0 = asynchrone)b3 : N.U. : Non Utilis : lu comme 0 b2 : non : non utilis en mode synchroneb1 : TRMT : TRansMiT shift register status bit (1 = TSR vide)b0 : TX9D : TRANSMIT 9th bit DataVoyons ce que signifie tout ceci :CSRC dtermine si votre PIC va travailler en tant que matre ou en tant quesclave. Dansle premier cas, cest lui qui dcide du moment des transferts de donnes, et qui pilotelhorloge. Dans le second cas, il subira les vnements.438TX9 indique si vous voulez envoyer des donnes codes sur 8 ou sur 9 bits. Un bit plac 1 ici conduira mettre des donnes codes sur 9 bits. Ceci peut vous permettre, parexemple, denvoyer et de recevoir un bit de parit, mais peut galement servir un tout autreusage.Notez que le PIC ne gre pas automatiquement le calcul de la parit. Si vous dcidez delutiliser en tant que tel, il vous appartiendra de la calculer (nous en verrons un exemple dansla partie ddicace la communication asynchrone).TXEN permet de lancer lmission. Comme vous ne pouvez travailler quen mode half-duplex, vous mettrez lmission ou la rception en service, votre USART tant incapabledeffectuer les 2 oprations en mme temps (au contraire de votre module MSSP en mode SPIpour qui ce mode tait impos).SYNC indique si vous travaillez en mode synchrone (1) ou asynchrone (0). Dans cechapitre, nous traitons le mode synchrone, donc ce bit devra tre positionn 1 .TRMT indique quand le registre TSR est vide, cest--dire quand lmission de la dernirevaleur prsente est termine.TX9D contient la valeur du 9me bit envoyer, quand vous avez dcid, via lepositionnement de TX9, de raliser des missions de mots de 9 bits. Comme les registres nepeuvent en contenir que 8, il fallait bien caser ce dernier bit quelque part.24.4 Le registre RCSTARCSTA, pour ReCeive STAtus and control register , contient dautres bits de contrleet de status, axs principalement sur la rception des donnes. Voici les bits qui le composent.RCSTA en mode synchroneb7 : SPEN : Serial Port ENable bitb6 : RX9 : RECEIVE 9 bits enable bit (1 = 9 bits, 0 = 8 bits)b5 : SREN : Single Receive ENAble bitb4 : CREN : Continuous Receive ENable bitb3 : non : non utilis en mode synchroneb2 : non : non utilis en mode synchroneb1 : OERR : Overflow ERRor bitb0 : RX9D : RECEIVE 9th Data bitQuant au rle de chacun de ces bits :SPEN met le module USART en service, permettant son utilisation.RX9 permet de choisir une rception sur 8 ou sur 9 bits, exactement comme pourlmission.SREN lance la rception dun seul octet. La communication se terminera delle-mme lafin de la rception de loctet.439CREN lance la rception continue. Les octets seront reus sans interruption jusqu ce quece bit soit effac par vos soins.OERR indique une erreur de type overflow. Jexpliquerai comment survient cette erreur.Sachez dj quelle survient si vous navez pas trait de faon assez rapide les octetsprcdemment reus.RX9D contient le 9me bit de votre donne reue, pour autant, bien entendu, que vous ayezactiv le bit RX9.Vous voyez que vous avez le choix entre mission (bit TXEN), rception dun octet(SREN), ou rception continue (CREN). Or, vous ne pouvez mettre et recevoir en mmetemps. Que se passe-t-il donc si vous activez plusieurs de ces bits en mme temps ?En fait, Microchip a dtermin une priorit dans lordre de ces bits, de faon ce quunseul soit actif un moment donn. Les priorits sont les suivantes :- Si CREN est activ, on aura rception continue, quel que soit ltat de SREN et TXEN- Si CREN nest pas activ, et que SREN est activ, on aura rception simple, quel que soitltat de TXEN- On naura donc mission que si TXEN est activ, alors que CREN et SREN sontdsactivs.24.5 Le registre SPBRGCe registre Serial Port Baud Rate Generator permet de dfinir la frquence delhorloge utilise pour la transmission, et donc de fixer son dbit. Le terme BRG doitmaintenant vous tre familier. Bien entendu, il ne sagit pas du mme BRG utilis dans lemodule MSSP. Ces 2 modules sont compltement indpendants.Il est vident que SPBRG ne sert, dans le cas de la liaison synchrone, que pour le matre,puisque lesclave reoit son horloge de ce dernier, et na donc aucune raison de la calculer.Attention, je traite ici le cas de la liaison synchrone. Les formules sont diffrentes entremode synchrone et mode asynchrone.La formule qui donne le dbit pour le mode synchrone est :D = Fosc / (4 * (SPBRG + 1))Comme vous aurez souvent besoin de calculer SPBRG en fonction du dbit souhait,voici la formule transforme :SPBRG = (Fosc / (4 * D)) 1Prenons un cas concret. Imaginons que vous vouliez raliser une transmission 19200bauds avec un PIC cadenc 20MHz. Quelle valeur devons-nous placer dans SPBRG ?440SPBRG = (20.000.000 / (4 * 19200)-1 = 259,4.Il va de soi que non seulement on doit arrondir, mais en plus, la valeur maximale pouvanttre place dans SPBRG est de 255 (dcimal). Donc, nous prendrons SPBRG = 255, ce quinous donne un dbit rel de :D = 20.000.000 / (4 * (255+1)) = 19531 bauds.Lerreur sera de :Erreur = (19531 19200) / 19200 = 1,72%Cest une erreur tout fait acceptable. Noubliez pas quen mode synchrone, vousenvoyez lhorloge en mme temps que le signal, votre esclave va donc suivre lerreur sansproblme, condition de rester dans ses possibilits lectroniques.Remarquez que plus on augmente SPBRG, plus on diminue le dbit. Nous venons sans levouloir de calculer que le dbit minimum de notre PIC matre cadenc 20MHz sera de19531 bauds. Si vous avez besoin dun dbit plus faible, il ne vous restera comme possibilitque de diminuer la frquence de votre Quartz.De la mme faon, si vous avez besoin dun dbit particulirement prcis, il vousappartiendra de choisir un quartz qui vous permettra dobtenir une valeur entire de SPBRGdans votre calcul.Calculons maintenant le dbit maximum possible avec notre PIC cadence 20MHz. Cedbit sera obtenu, en bonne logique, avec une valeur de SPBRG de 0 .Dmax = 20000000 / (4 * (0+1)) = 5.000.000 = 5 MBauds.Vous constatez une fois de plus que les liaisons synchrones sont prvues pour travailleravec de trs grandes vitesses.24.6 LinitialisationPour initialiser votre module en mode synchrone, il vous faudra- Choisir si vous travaillez en mode matre ou esclave- Dcider si vous utilisez des missions sur 8 ou sur 9 bits- Positionner votre bit SYNC pour le travail en mode synchrone- Dcider si vous communiquez en 8 ou en 9 bits- Si vous travaillez en matre, initialiser la valeur de SPBRG- Mettre le module en servicePar dfaut, la mise sous tension, les pins CK et DT sont configures en entre, il nestdonc pas ncessaire dinitialiser leur bit respectif dans TRISC, sauf si vous avez entre-tempsmodifi ce registre.Exemple dinitialisation en mode matre :441Initbsf STATUS,RP0 ; passer en banque 1movlw B10010000 ; mode matre synchrone, mission 8 bitsmovwf TXSTA ; dans registre TXSTAmovlw BRGVAL ; valeur calcule de SPBRGmovwf SPBRG ; dans baud rate generatorbcf STATUS,RP0 ; repasser banque 0movlw B10000000' ; module en service, rception 8 bitsmovwf RCSTA ; dans registre RCSTAExemple dintialisation en mode esclave :bsf STATUS,RP0 ; passer en banque 1movlw B00010000 ; mode esclave synchrone, mission 8 bitsmovwf TXSTA ; dans registre TXSTAbcf STATUS,RP0 ; repasser banque 0movlw B10000000' ; module en service, rception 8 bitsmovwf RCSTA ; dans registre RCSTA24.7 Lmission en mode matreJe vais vous expliquer ici comment se passe une mission du point de vue du matre. Lemodule est considr comme configur par la prcdente routine.Vous validez la mise en service de lmission en positionnant le bit TXEN.Si vous utilisez le format de donne sur 9 bits, vous devez commencer par placer la valeurdu 9me bit dans le bit TX9D.Ensuite, vous placez la donne mettre dans le registre TXREG (TRANSMITTREGister).Cette donne est transfre ds le cycle dinstruction suivant, ainsi que le bit TX9D, dansson registre TSR (Transmitt Shift Register). Ce registre nest pas accessible directement parvotre programme. Il va effectuer lenvoi de vos bits de donnes sur la ligne DT en effectuantdes dcalages vers la droite.Cest donc le bit de poids faible (b0) qui sera envoy en premier, au contraire du moduleMSSP qui effectuait ce dcalage vers la gauche, et donc commenait l le bit de poids fort(b7).Ds que loctet est transfr dans TSR (et donc avant quil ne soit compltementtransmis), le registre TXREG se retrouve donc vide. Ceci vous est signal par lepositionnement du flag dinterruption TXIF.Comme le transfert entre TXREG ne seffectue que si la transmission du mot contenudans TSR est termine, ceci vous laisse la possibilit, sans craser le contenu actuel de TSR,dcrire une nouvelle valeur dans TXREG. Le chargement dune valeur dans TXREGsaccompagne de leffacement automatique du flag TXIF. Cest dailleurs la seule faon deleffacer.442Si TXREG ne contient plus aucun octet envoyer, lorsque TSR aura termin lenvoi deson dernier octet, le bit TRMT passera 1 , indiquant la fin effective de lmission.Lcriture dune nouvelle valeur dans TXREG effacera de nouveau TRMT.Donc, en rsum, imaginons lenvoi de 2 octets :- Vous placez le 9eme bit dans TX9D, puis loctet envoyer dans TXREG- Le bit TRMT passe 0 (mission en cours)- Le bit TXIF passe 0 (registre TXREG plein)- Loctet est transfr dans TSR, lmission commence- Le registre TXREG est maintenant vide, le flag TXIF passe 1- Vous chargez TX9D et le second octet envoyer (le PIC est toujours en train dmettreloctet prcdent)- Le bit TRMT est toujours 0- Le bit TXIF passe 0 (registre TXREG plein).- A ce stade, TSR continue lmission de loctet 1, TXREG contient loctet 2.- TSR termine lmission de loctet 1, transfert de loctet 2 de TXREG vers TSR- Le flag TXIF passe 1 (TXREG vide)- Lmission de loctet 2 se poursuit- Lmission de loctet 2 se termine, TRMT passe 1 (mission termine).Bien videmment, si vous travaillez avec des mots de 8 bits, vous navez pas vousoccuper du bit TX9D.Si vous avez tout compris, dans le cas o vous avez plusieurs octets envoyer :- Vous avez toujours un octet en cours de transmission dans TSR, le suivant tant dj prtdans TXREG.- Si on a besoin de 9 bits, on place toujours TX9D avant de charger TXREG.- Chaque fois que TXIF passe 1 (avec interruption ventuelle), vous pouvez rechargerTXREG avec loctet suivant (tant que vous en avez).- Quand la communication est termine, TRMT passe 1.Notez que si vous utilisez les interruptions, le bit TXIF ne peut tre effac manuellement,il ne lest que lorsque votre registre TXREG est recharg. Ceci implique que lorsque vous443placez votre dernier octet envoyer, vous devez effacer TXIE avant de sortir pour interdiretoute nouvelle interruption, le flag TXIF tant automatiquement repositionn chaque foisque TXREG sera vide.Pour quil y ait une mission, il faut donc que, le module tant initialis et lanc :- SREN et CREN soient dsactivs- TXEN soit positionn- Le registre TXREG soit chargLa seconde et la troisime ligne peuvent tre inverse, ce qui vous laisse 2 possibilits dedmarrer une criture.- Soit vous validez TXEN, et vous chargez TXREG au moment o vous dsirez lancerlmission. Ceci est la procdure normale - Soit vous prparez TXREG avec la valeur mettre, et vous positionnez TXEN.Cette dernire procdure permet, si vous examinez les chronogrammes des figures 10-9 et10-10 page 106 du datasheet, de gagner un peu de temps, surtout sur les communications faibles dbits.Vous remarquerez en effet que la transmission commence, sur la figure 10-10,directement aprs positionnement du bit TXEN, alors quil y a un dlai sur la figure 10-9concernant la premire solution, entre le chargement de TXREG et le dbut effectif de latransmission.Un petit mot concernant cette diffrence. Elle est due au fait que le Baud Rate Generatorcommence compter ds quun des bits TXEN, CREN ou SREN est positionn. Par contre, ilest forc 0 dans le cas contraire.Si on adopte la premire mthode, vous voyez tout de suite que lorsque vous chargezTXREG, le BRG peut contenir nimporte quelle valeur. La transmission ne commencera doncque lors du prochain dbordement du BRG. Ceci explique le dlai.Par contre, sur la seconde mthode, le BRG tant forc 0 , ds quon positionneTXEN, il est prt envoyer la premire donne.Ne vous tracassez pas outre mesure pour ceci, cela ne vous concernera principalementquen cas de temps de rponse critique avec des dbits faibles, ce qui est relativement peufrquent.24.8 Lmission en mode esclaveEn fait, cest extrmement simple. Vous travaillez en mode esclave exactement comme enmode matre, except que vous navez pas vous proccuper du registre SPBRG.444Vous placerez donc vos donnes de la mme faon, et vous serez prvenu que votreregistre TXREG est vide par le positionnement de lindicateur TXIF. La fin de lmission seconclura galement par le positionnement du bit TRMT.Cest bien le matre qui dcide quand a effectivement lieu votre mission, mais vous aurez grer strictement les mmes vnements. Nous verrons une autre diffrence quand nousparlerons du mode sleep un peu plus loin.24.9 La rception en mode matreComme il fallait sy attendre, la rception des donnes met en uvre 2 autres registres.RSR (Receive Shift Register) est le pendant pour la rception de TSR pour lmission, ilralise la rception des bits en effectuant un dcalage vers la droite (souvenez-vous que pourlUSART, b0 est transmis en premier lieu).Ds que RSR est plein, son contenu est transfr dans RCREG, qui est le seul des 2registres accessible par votre programme. Il contient la donne effectivement reue,complte ventuellement (si vous travaillez sur 9 bits) par le bit RX9D.La procdure est la suivante :- Vous positionnez SREN ou CREN, ce qui a pour effet que votre PIC commence envoyerlhorloge. Lesclave qui a la parole sest entre-temps occup de prparer son mission.- Quand les 8 impulsions dhorloge (ou 9 pour le mode 9 bits) ont t envoys, loctet a treu.- Loctet est transfr dans le registre RCREG (le 9me bit ventuel est transfr versRX9D), et le flag RCIF est positionn- Vous lisez alors le bit RX9D ventuel PUIS le registre RCREG, ce qui provoqueleffacement du bit RCIF.Si vous aviez choisi de positionner SREN, le cycle est termin, lhorloge est stopp. Parcontre, si vous aviez prfr CREN, lhorloge continue denvoyer ses impulsions, provoquantles lectures continues des autres mots recevoir, jusqu ce que vous resettiez CREN.Notez que la lecture dun bit seffectue sur le flanc descendant de lhorloge.445Le fonctionnement est donc relativement simple, mais il importe de tenir compte deplusieurs points importants :24.9.1 La file FIFO de RCREGFIFO, FIFO ? Quest-ce donc ceci ? En fait, FIFO est labrviation de First In FirstOut , ou, en franais, Premier Entr, Premier Sorti . Il sagit dune file, interprtercomme la file dattente dun magasin (pas celle de la poste, notre PIC ne dispose pas dassezde place).Dans une file de ce type, les nouveaux vnements (clients pour le magasin, donnes pournotre PIC), arrivent en bout de file. Le premier vnement traiter sera bien entendu lepremier arriv (sauf si vous aimez les agitations muscles).Tout ce que lagent (La caissire, ou notre programme) aura savoir, cest sil reste aumoins un vnement (client ou donne) traiter.Et bien, notre registre RCREG dispose dune file FIFO de 2 emplacements. Cest un petitcadeau de Microchip, qui vous permet de prendre un peu de retard dans la raction auxvnements entrants. La signalisation quil y a au moins un lment traiter tant dvolu RCIF.Comment cela fonctionne-t-il ? En fait, de faon totalement transparente pour lutilisateur.Imaginons que les octets arrivent, et que vous ragissiez avec retard :- Le premier octet est en cours de rception dans RSR, RCREG est vide, donc RCIF est 0 - Le premier octet est reu et transfr dans la file de RCREG, RCIF est positionn, lesecond octet est en cours de rception dans RSR- Le second octet est reu et transfr dans la file de RCREG, RCIF reste positionn, letroisime octet est en cours de rception dans RSR.446Comme on na que 2 emplacements, vous devrez ragir avant la fin de la rception dutroisime octet, mais vous voyez que votre temps de raction peut tre allong. Voici alors ceque vous allez faire :- Vous lisez, si vous travaillez sur 9 bits, le 9me bit, RX9D.- Vous lisez RCREG, donc le premier octet reu. Cette lecture ne provoque pasleffacement de RCIF, puisque RCREG nest pas vide. Par contre, le 9me bit du secondoctet est transfr ce moment dans RX9D, ce qui explique que vous deviez le lire enpremier.- Vous lisez alors, si vous travaillez sur 9 bits, le bit RX9D qui est le 9me bit de votresecond octet.- Vous lisez donc encore RCREG, donc le second octet reu. Le flag RCIF est effac, leregistre RCREG est vide.Vous voyez que vous navez pas vous occuper de ce FIFO. Tant que RCIF estpositionn, vous lisez, cest tout. Il faut seulement se souvenir quil faut imprativement lireRX9D AVANT de lire RCREG.24.9.2 Lerreur doverflowNous avons vu que le registre RCREG pouvait contenir 2 emplacements. Imaginonsmaintenant que vous ragissiez avec tellement de retard quun troisime octet soit reu avantque vous ayez lu les 2 prcdents mmoriss dans la file dattente.Comme il ny a plus de place dans la file, le mot reu dans RSR sera tout simplementperdu. Pour vous signaler ce fait, le bit OERR (Overflow ERRor) sera automatiquementpositionn.Il vous appartiendra de remettre OERR 0 . Cette remise 0 se fait de faon unpeu particulire, en effaant le bit CREN pour mettre fin la rception continue. Le bit OERRest en effet lecture seule.Attention, il est impratif de couper CREN (puis de le remettre le cas chant). Dans lecas contraire, OERR ne serait pas remis 0 , ce qui bloquerait la rception des octetssuivants.Votre raction devrait donc tre du style :- Tant que RCIF est positionn- Je lis RX9D puis RCREG- RCIF nest plus positionn, OERR est positionn ?- Non, pas de problme- Oui, je sais que jai perdu un octet et je coupe CRENEvidemment, vous avez beaucoup moins de chance davoir une erreur doverflow si voustravaillez via les interruptions, ce que je vous conseille fortement dans ce mode.44724.10 La rception en mode esclaveTout comme pour lmission, trs peu de diffrences entre le matre et lesclave. Lesvnements grer sont identiques et se traitent de la mme faon.Notez cependant que le mode dmission simple nest pas utilisable dans le cas delesclave. Le bit SREN nest donc pas gr si le PIC est dans ce mode (CSRC = 0). Vousdevrez alors utiliser uniquement CREN.24.11 Le mode sleepUne fois de plus, un simple raisonnement vous permettra de dduire le fonctionnement duPIC en mode de sommeil.Lhorloge CK est drive de lhorloge principale du PIC. Comme cette horloge principaleest stoppe durant le sommeil, il est clair que le PIC configur en matre ne peut ni mettre nirecevoir en mode sleep .Par contre, pour lesclave, cette contrainte nexiste pas. Aussi, si une mission ou unerception est lance avant la mise en sommeil, le PIC sera rveill si le bit de validationcorrespondant (RXIE et/ou TXIE) est positionn.24.12 Diffrences entre MSSP et USARTVous disposez maintenant de 2 modules capables de grer une liaison srie synchrone, savoir le module MSSP en mode SPI, et le module USART en mode synchrone. Quanddevez-vous utiliser un ou lautre de ces modules ?Peut-tre tes-vous dj capables de rpondre tout ou partie de cette question daprs ceque je vous ai expliqu. Le fonctionnement de ces modules est assez dissemblable, et doncinduit des contraintes et des possibilits diffrentes.- Le module MSSP met les bits en commenant par le bit 7 jusquau bit 0 , alors quelUSART procde de faon inverse. Il va de soi que si vous interfacez 2 PICs dont vouscrivez vous-mme le programme, cela ne posera pas de problme (comme pour plusieursdes autres diffrences). Par contre, si vous vous connectez dans un circuit existant, cettediffrence prendra tout son sens.- Une liaison SPI est toujours une liaison full-duplex, qui ncessite donc 3 fils de liaison.Ceci exclut le fonctionnement multi-matre (sans artifice), puisque vous devez croiser lesfils dmission et de rception. Par contre, lUSART travaille sur 2 fils et en mode half-duplex, linconvnient de la transmission unidirectionnelle tant compense par labsencede croisement des fils, donc de la possibilit de travailler en multi-matres.- Le MSSP dispose dune pin de validation SS qui nest pas prsente dans le moduleUSART. Cette pin nest dailleurs pas vraiment ncessaire dans ce module, puisque lemode half-duplex, qui nimplique pas une rponse simultane, permet de recevoir et detraiter une adresse du destinataire.448- Le module MSSP, frquence de quartz gale du PIC, permet de travailler avec desvitesses plus basses que pour le module USART.Voici dj quelques diffrences flagrantes entre ces 2 modules, qui ne devraient pas vouslaisser dans lexpectative au moment du choix dans une application spcifique.24.13 Exercice pratiqueNous voici arriv au stade de notre exercice pratique. Je vous propose un exemple qui meten uvre les 4 modes dcrits, afin de vous permettre de voir comment utiliser votre PIC danstoutes les situations.Nous allons donc connecter ensemble 2 PICs en utilisant leur module USART. Le premiersera le matre permanent, le second lesclave. Le fonctionnement sera le suivant :- Le PIC matre envoie lesclave un mot de 9 bits , dont les 8 bits principaux reprsententune adresse relative, le 9me bit indiquant quelle zone de donnes a t choisie .- Lesclave lit loctet dans son buffer dont ladresse est donne par les 8 bits reus. Le 9emebit prcise si le buffer utilis est celui de la banque 0 ou de la banque 1.- Lesclave envoie loctet lu au matre sur 8 bits. Le 9eme bit est utilis pour dire au matresi la fin de la zone est atteinte ou non (dernier lment).- Le matre rceptionne loctet, et place la donne sur les LEDs connectes sur le PORTB.Bien entendu, cet exercice nest gure utile, mais il prsente lavantage de mettre enuvre rception et mission, en mode esclave et matre, et en plus sur 9 bits. Aprs tout, cestce quon lui demande, non ?Voici le schma retenu :449Vous remarquez que cest par logiciel que nous avons dcid que lun serait le matre etlautre lesclave. Rien ne nous empche donc de rendre la ligne dhorloge bidirectionnelle enassignant le rle de matre lun puis lautre PIC. Ce ne sera pas le cas dans notre exercice.Nous allons commencer par raliser le programme du matre. Effectuez un copier/collerde votre fichier m16F876.asm et renommez la copie en UsartM.asm . Crez un projetdu mme nom.Tout dabord, pour travailler proprement, en-tte et configurations sont indispensables :;*****************************************************************************; Exercice de communication srie synchrone sur base du module USART *; Ce programme est le programme du matre *; Utilisation d'une liaison sur 9 bits 38400 bauds *; *;*****************************************************************************; *; NOM: USARTM *; Date: 17/07/2002 *; Version: 1.0 *; Circuit: Platine d'exprimentation *; Auteur: Bigonoff *; *;*****************************************************************************; *; Fichier requis: P16F876.inc *; *;*****************************************************************************; *; Les 8 LEDS sont connectes sur le PORTB. *; Liaison half-duplex 38400 bauds thoriques (38461 rels) *; Le PIC tourne avec une frquence de 20MHz *; Envoi du pointeur d'adresse sur 8 bits *; Slection du buffer 0 ou 1 de l'esclave sur 9eme bit *; Rception de l'octet correspondant sur 8 bits. Le 9eme bit reu, si *450; positionn, indique que l'adresse envoye est la dernire du buffer *; *;*****************************************************************************LIST p=16F876 ; Dfinition de processeur#include ; fichier include__CONFIG _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_OFF & _CPD_OFF & _LVP_OFF &_BODEN_OFF & _PWRTE_ON & _WDT_ON & _HS_OSCNous allons avoir besoin de 3 valeurs. Les deux premires seront utilises pour tablir ledlai de 0.5 seconde, exactement comme dans lexercice prcdent. Je ny reviendrai pas. Latroisime valeur est celle que nous devrons entrer dans SPREG, afin dtablir la vitesse detransmission. Comme jai choisi 38400 bauds, ceci donnera :SPBRG = (Fosc / (4 * D)) 1 Soit, avec notre quartz de 20 MHz :SPBRG = (20.000.000 / (4 * 38400)) 1 = 129,2Nous choisirons de mettre la valeur 129, ce qui nous donnera un dbit rel de :D = Fosc / (4 * (SPBRG + 1))Soit :D = 20.000.000 / (4 * (129+1)) = 38461 bauds.Lerreur na ici pas la moindre importance, vu que nous travaillons en synchrone, et que,de plus, les 2 interlocuteurs sont des PICs. Souvenez-vous que lesclave na mme pas besoinde savoir quel dbit on travaille. Il se contente de ragir aux signaux dhorloge reus. Cecinous donnera les assignations suivantes :;*****************************************************************************; ASSIGNATIONS PROGRAMME *;*****************************************************************************PR2VAL EQU D'249' ; Valeur de comparaison timer 2CMPTVAL EQU D'125' ; 125 passages dans la routine d'interruption; dure = Tcy*(PR2+1)*prdiv*postdiv*cmptval; = 0,2s * 250 * 16 * 5 * 125 = 0.5s.BRGVAL EQU D'129' ; pour un dbit de 38461 baudsDans notre zone de variables en banque 1, nous allons retrouver notre compteur depassages dans la routine dinterruption du timer 2 :;*****************************************************************************; VARIABLES BANQUE 0 *;*****************************************************************************; Zone de 80 bytes; ----------------451CBLOCK0x20 ; Dbut de la zone (0x20 0x6F)cmpt : 1 ; compteur de passages d'interruption ENDC ; Fin de la zoneDans la zone commune, on retrouve nos variables de sauvegarde, mais galement dautresvariables utilises dans notre programme, comme :- Des flags- Loctet envoyer lesclave- Un compteur de boucles.Jai choisi de placer ces variables en zone commune, car cela diminuera le nombre dechangements de banques dans le programme. En effet, plusieurs registres utilisscontinuellement (TXSTA) se trouvent en banque 1, et se retrouvent impliqus dans desboucles. Comme nos variables se retrouvent dans certaines de ces boucles, le fait de pouvoir yaccder depuis nimporte quelle banque se rvlera pratique. Nous obtenons donc :;*****************************************************************************; VARIABLES ZONE COMMUNE *;*****************************************************************************; Zone de 16 bytes; ----------------CBLOCK 0x70 ; Dbut de la zone (0x70 0x7F)w_temp : 1 ; Sauvegarde registre Wstatus_temp : 1 ; sauvegarde registre STATUSFSR_temp : 1 ; sauvegarde FSR (si indirect en interrupt)flags : 1 ; 8 flags d'usage gnral; b0 : une demi-seconde s'est coule; b1 : 4ms se sont coules; b2 : tat du 9eme bit envoyer; b3 : tat du 9eme bit reunumoctet : 1 ; numro d'octet envoy l'esclavenumloop : 1 ; nombre de boucles effectuerENDC#DEFINE TIME05S flags,0 ; 0.5 secondes coules#DEFINE TIME4MS flags,1 ; 4ms coules#DEFINE EMI9 flags,2 ; valeur du 9eme bit envoyer#DEFINE REC9 flags,3 ; valeur du 9eme bit reuRemarquez les dfinitions de bits, qui nous viteront de traner des flags,x dans leprogramme. Cest du reste plus parlant.Le dmarrage sur reset se passe de commentaires (except le prsent commentaire quiindique quon se passe de commentaires) :;*****************************************************************************; DEMARRAGE SUR RESET *;*****************************************************************************org 0x000 ; Adresse de dpart aprs reset goto init ; InitialiserNotre routine dinterruption ne va grer que linterruption du timer 2. Jai suffisammentparl de cette interruption dans plusieurs exercices prcdents, je ny reviens donc pas :452; ////////////////////////////////////////////////////////////////////////////; I N T E R R U P T I O N S; ////////////////////////////////////////////////////////////////////////////;*****************************************************************************; ROUTINE INTERRUPTION *;*****************************************************************************;-----------------------------------------------------------------------------; La routine d'interruption timer 2 est appele toutes les; (0,2s * 80 * 250) = 4ms.; au bout de 125 passages, une demi-seconde s'est coule, on positionne; le flag;-----------------------------------------------------------------------------;sauvegarder registres;---------------------org 0x004 ; adresse d'interruptionmovwf w_temp ; sauver registre Wswapf STATUS,w ; swap status avec rsultat dans wmovwf status_temp ; sauver status swappmovf FSR , w ; charger FSRmovwf FSR_temp ; sauvegarder FSR; interruption timer 2; --------------------BANKSEL PIR1 ; passer banque 0bcf PIR1,TMR2IF ; effacer le flag d'interruptionbsf TIME4MS ; positionner flag pour 4msdecfszcmpt,f ; dcrmenter compteur de passagesgoto restorereg ; pas 0, fin de l'interruptionmovlw CMPTVAL ; valeur de recharge du compteurmovwf cmpt ; recharger compteurbsf TIME05S ; positionner flag pour 0.5 seconde;restaurer registres;-------------------restoreregmovf FSR_temp,w ; charger FSR sauvmovwf FSR ; restaurer FSRswapf status_temp,w ; swap ancien status, rsultat dans wmovwf STATUS ; restaurer statusswapf w_temp,f ; Inversion L et H de l'ancien Wswapf w_temp,w ; Rinversion de L et H dans Wretfie ; return from interruptNous arrivons aux initialisations, en commenant par les PORTs. Comme nous nutilisonsen tant que tel que le PORTB, et que les bits utiliss pour la transmission sont dans le bon tatpar dfaut (en entre), cette partie est trs courte. Notez la bonne pratique qui consiste couper les rsistances de rappel au +5V lorsquon ne sen sert pas, cela diminue laconsommation gnrale.; ////////////////////////////////////////////////////////////////////////////; P R O G R A M M E; ////////////////////////////////////////////////////////////////////////////;*****************************************************************************; INITIALISATIONS *;*****************************************************************************init; initialisation PORTS (banque 0 et 1); ------------------------------------453BANKSEL PORTA ; slectionner banque0clrf PORTB ; sorties PORTB 0bsf STATUS,RP0 ; passer en banque1clrf PORTB ; PORTB en sortie (LEDs)bsf OPTION_REG,7 ; couper rsistances de rappelNous en sommes la partie qui nous intresse, savoir linitialisation de notre USART .Ceci seffectue sans problme, en suivant la thorie explique. Nous choisirons dutiliser cePIC en matre, mission et rception sous 9 bits, module USART en service, et BRGcorrespondant 38400 bauds (D129).; initialiser USART; -----------------movlw B'11010000' ; mode matre synchrone, mission 9 bitsmovwf TXSTA ; dans registre TXSTAmovlw BRGVAL ; valeur calcule de SPBRGmovwf SPBRG ; dans baud rate generatorbcf STATUS,RP0 ; repasser banque 0movlw B'11000000' ; module en service, rception 9 bitsmovwf RCSTA ; dans registre RCSTALe reste concerne linitialisation du timer 2, des variables, et la mise en service delinterruption timer 2.; initialiser timer 2; -------------------movlw PR2VAL ; charger valeur de comparaisonBANKSEL PR2 ; passer banque 1movwf PR2 ; initialiser comparateurmovlw B'00100110' ; timer2 on, prdiv = 16, post = 5BANKSEL T2CON ; passer banque 0movwf T2CON ; lancer timer 2; initialiser variables; ---------------------movlw CMPTVAL ; pour dure initiale de 0.5s.movwf cmpt ; dans compteur de passagesclrf flags ; effacer flagsclrf numoctet ; on commence par l'lment 0; lancer interruption timer2; --------------------------bsf INTCON,PEIE ; interruptions priphriques en servicebsf STATUS,RP0 ; passer banque 1bsf PIE1,TMR2IE ; lancer interruptions timer2bcf STATUS,RP0 ; repasser banque 0bsf INTCON,GIE ; lancer les interruptionsgoto start ; dmarrer programme principalAu tour de nos diffrentes fonctions (jai voulu dire sous-routines ). Tout dabord uneattente de 0.5 seconde :;*****************************************************************************; Attendre 0.5 seconde *;*****************************************************************************;-----------------------------------------------------------------------------; attendre qu'une seconde se soit coule depuis le prcdent passage dans; cette routine;-----------------------------------------------------------------------------454waitclrwdt ; effacer watchdogbtfss flags,0 ; flag positionn?goto wait ; non, attendre flagbcf TIME05S ; reset du flag pour 0.5 secondebcf TIME4MS ; et reset du flag de 4msreturn ; et retourTrs simple, comme vous voyez. Le flag TIME4S, remis 0 ici, et positionn chaquepassage dans la routine dinterruption timer 2 (toutes les 4ms), est destin nous donner untemps intermdiaire de 4ms. Si vous comprenez le mcanisme :- On attend la fin des 0.5 secondes : les 2 flags sont effacs- 4ms plus tard, le flag TIME4MS est positionn- 0.5 seconde aprs lattente des 0.5 prcdente, le flag TIME05S est positionn.Donc, en toute logique, voici notre routine qui attend le positionnement du flagTIME4MS :;*****************************************************************************; Attendre 4 ms *;*****************************************************************************;-----------------------------------------------------------------------------; attendre que 4ms se soient coules depuis le prcdent passage dans; la routine wait;-----------------------------------------------------------------------------wait4msclrwdt ; effacer watchdogbtfss TIME4MS ; flag positionn?goto wait4ms ; non, attendre flagreturn ; et retourInutile ici de resetter notre flag TIME4MS, il serait repositionn 4ms plus tard, et nousnen avons plus besoin quaprs la prochaine attente de 0.5 seconde.Voici maintenant une routine plus intressante. Elle envoie la valeur contenue dans lavariable numoctet sur le port srie.;*****************************************************************************; ENVOYER UN OCTET *;*****************************************************************************;-----------------------------------------------------------------------------; Envoie l'octet numoctet vers l'esclave.; attend la fin de la transmission pour sortir; le 9eme bit du mot envoyer est dans EMI9;-----------------------------------------------------------------------------sendusartbsf STATUS,RP0 ; passer en banque 1bcf TXSTA,TX9D ; par dfaut, 9eme bit = 0btfsc EMI9 ; 9eme bit doit valoir 1?bsf TXSTA,TX9D ; oui, alors le positionnermovf numoctet,w ; charger octet envoyerbcf STATUS,RP0 ; passer banque 0movwf TXREG ; octet dans registre de transmissionbsf STATUS,RP0 ; repasser banque 1bsf TXSTA,TXEN ; envoyer l'octet455clrwdt ; effacer watchdogbtfss TXSTA,TRMT ; transmission termine?goto $-2 ; non, attendrebcf TXSTA,TXEN ; oui, fin de transmissionbcf STATUS,RP0 ; repasser banque 0return ; et retourVous notez que le 9eme bit envoy sera le reflet du flag EMI9, positionn par notreprogramme principal. Jai choisi dattendre la fin de lmission avant de sortir de cetteroutine. Comme notre watchdog est en service, nous le resettons dans la boucle dattente.On envoie, et on doit recevoir, voici la sous-routine qui le permet :;*****************************************************************************; RECEVOIR UN OCTET *;*****************************************************************************;-----------------------------------------------------------------------------; Reoit un octet de l'esclave.; l'octet reu sera retourn dans W; le 9eme bit du mot reu sera retourn dans REC9; Comme on effectue une lecture simple (SREN), le bit SREN est resett; automatiquement en fin d'mission. On se sert de cette particularit pour; tester si la transmission, est termine. On pouvait aussi tester le passage; "1" du bit RCIF.; En ralit, vu que l'mission suivante a lieu 0.5s plus tard, on pouvait; fort bien se passer d'attendre la fin de la rception. J'ai inclus le test; titre d'exemple.;-----------------------------------------------------------------------------recusartbsf RCSTA,SREN ; un seul octet recevoirclrwdt ; effacer watchdogbtfsc RCSTA,SREN ; rception termine?goto $-2 ; non, attendrebcf REC9 ; par dfaut, 9eme bit reu = 0btfsc RCSTA,RX9D ; 9eme bit reu = 1?bsf REC9 ; oui, signalermovf RCREG,w ; lire octet reureturn ; et retourComme il est indiqu dans les commentaires, 2 remarques ici :- La dtection de la fin de transmission peut se faire soit sur le relchement du bit SREN , vu quil sagit ici dune mission unique, soit sur le positionnement du bitRCIF qui intervient une fois que loctet reu se trouve dans RCREG.- Il ntait pas ncessaire dattendre la fin de la rception avant de continuer, vu que, detoute faon, notre mission suivante seffectuera pratiquement 0.5 seconde plus tard,lmission sera donc termine ce moment.Voici maintenant la sous-routine qui appelle les prcdentes, elle ralise les oprationssuivantes :- On attend la fin de la demi-seconde courante- On envoie le numro de loctet souhait lesclave- On attend que lesclave ait eu le temps de lire et de prparer sa rponse.- On lance la lecture de loctet renvoy par lesclave456- On place loctet lu (bits 0 7) sur le PORTB qui allume les LEDs- On incrmente le numro de loctet souhait pour la prochaine boucle- On examine le bit 8 (9me bit) reu de lesclave.- Sil vaut 0, on recommence au dbut- Sil vaut 1, ctait le dernier, dans ce cas :- On remet le numro de bit 0- On regarde si on doit encore boucler- Si oui, on recommence une srie de boucles, si non, on sortNous allons devoir estimer le temps que met notre esclave prparer sa rponse :- Si on part du principe que nous traiterons la rception sur notre esclave en modeinterruption- Si on pose que le PIC esclave tait en mode sleep au moment de la rception- Si on se souvient que le temps commence compter partir de la sortie de la routine wait , on peut estimer :Temps de raction = temps de lmission vers lesclave + temps de rveil de lesclave + tempsncessaire lesclave pour entrer dans la routine dinterruption, lire loctet reu, chercher ladonne demande et la placer dans le registre dmission.On va donc compter la louche , faute de ne pas avoir encore le logiciel de lesclave :Temps dmission = dure dun bit * nombre de bits misTemps dmission = (1s / 38400 bauds) * 9 bits = 234 sTemps de rveil de lesclave = 1024 Tosc = 1024 * (1/20 MHz) = 51,2 s.Si on estime grossirement que 200 cycles dinstructions seront suffisants pour traiterlinformation, nous aurons encore besoin de 200 * 4 / 20MHz = 40 s.Le temps total de raction sera de : 234 + 51,2 + 40 = 325 s.Nous passons dans notre routine timer 2 toutes les 4ms. Comme nous ne sommes passpcialement press dans cette application, nous en profitons donc pour attendre 4ms au lieudes 325 s minimales requises. Nous voyons que notre PIC esclave dispose de tout son tempspour rpondre. Ceci explique la sous-routine wait4ms .Dans une application PIC, il faut toujours pouvoir tablir des ordres de grandeurconcernant les temps mis en jeu, a facilite la ralisation des programmes.Il faut toujours galement se poser la question de lutilit ou non des calculs prcis etsavoir si cela vaut la peine de compliquer le programme pour optimiser certains dlais.Dans ce cas, si nous avions opt pour fabriquer un dlai de 325 s, notre programmeaurait fonctionn exactement de la mme faon, les octets dfilant toutes les 0.5 seconde. Ilnest donc pas utile de compliquer le programme pour fabriquer ce dlai prcis. Autant utiliserune ressource dj implmente, savoir un dlai de 4ms.Tout ceci nous donne :457;*****************************************************************************; CHENILLARD SUR UNE SERIE DE DATA *;*****************************************************************************;-----------------------------------------------------------------------------; le numro du buffer de l'esclave est dans BIT8 (9me bit); le numro de l'octet demand est dans numoctet; Le 9eme bit positionn de l'octet reu indique que le buffer de l'esclave; ne contient plus de donnes; Le nombre de boucles raliser est dans w;-----------------------------------------------------------------------------chenillmovwf numloop ; sauver dans compteur de boucleschenloopcall wait ; attendre 0.5 secondecall sendusart ; envoyer le numro de l'octetcall wait4ms ; attendre que l'esclave soit prtcall recusart ; rceptionner octetmovwf PORTB ; placer octet reu sur les LEDsincf numoctet,f ; incrmenter numro de l'octetbtfss REC9 ; reu 9eme bit = 1? (fin de data)goto chenloop ; non, octet suivantclrf numoctet ; oui, reprendre depuis le dbutdecfsznumloop,f ; dcrmenter compteur de bouclesgoto chenloop ; pas dernire, suivantereturn ; fini, retourA ce stade, il ne reste plus qu construire notre programme principal. Celui-ci va secontenter, afin quon puisse voir si tout fonctionne bien, de lancer 3 fois la prcdente routineavec le 9eme bit 0 , suivi de 4 fois la mme routine, mais avec le 9eme bit 1 .Ceci se traduira par 3 squences dallumage des LEDs correspondant la premire zonede donnes stockes dans lesclave, suivies par 4 squences correspondant la seconde zonede donnes. On reprendra ensuite le tout au dbut.;*****************************************************************************; PROGRAMME PRINCIPAL *;*****************************************************************************startclrwdt ; effacer watch dogbcf EMI9 ; signaler 9eme bit = 0 (premire srie de data)movlw 0x03 ; 3 boucles effectuercall chenill ; excuter les 3 bouclesbsf EMI9 ; signaler 9eme bit = 1 (seconde srie de data)movlw 0x04 ; 4 boucles effectuercall chenill ; excuter les 4 bouclesgoto start ; bouclerEND ; directive fin de programmeToujours la mthode habituelle de travailler en programmation dite structure , avecdes routines courtes et hirarchises et un programme principal rduit lappel de fonctionsralises sous forme de sous-routines.Nous en avons termin avec le programme placer dans le PIC matre. Nous allons nousattaquer celui de lesclave, encore plus simple. Commencez par effectuer un copier/collerde votre fichier m16F876.asm , renommez cette copie UsartS.asm , et crez un nouveauprojet du mme nom.458Selon notre habitude, commenons par len-tte et les bits de configuration. Comme jailintention cette fois dutiliser le mode sleep , nous ne validerons pas notre watchdog, quirveillerait la PIC trop tt, et donc un moment inopportun.;*****************************************************************************; Exercice de communication srie synchrone sur base du module USART *; Ce programme est le programme de l'esclave *; Utilisation d'une liaison sur 9 bits 38400 bauds *; *;*****************************************************************************; *; NOM: USARTS *; Date: 17/07/2002 *; Version: 1.0 *; Circuit: Platine d'exprimentation *; Auteur: Bigonoff *; *;*****************************************************************************; *; Fichier requis: P16F876.inc *; *;*****************************************************************************; *; Le PIC reoit une adresse en provenance du matre. *; Le 9eme bit contient la zone de data concerne (0 ou 1). *; Le PIC renvoie l'octet correspondant l'adresse reue. *; Ce cet octet est le dernier de la zone, le 9eme bit sera positionn. *; *;*****************************************************************************LIST p=16F876 ; Dfinition de processeur#include ; fichier include__CONFIG _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_OFF & _CPD_OFF & _LVP_OFF &_BODEN_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSCPour les mmes raisons que dans le programme du matre, jai choisi de placer mesvariables dans la zone RAM commune. Si vous voulez, titre dexercice, ralisez ceprogramme en plaant les variables en banque 1, vous verrez alors lavantage de procdercomme je lai fait dans ce cas.Les variables sont dailleurs rduites leur plus simple expression. En effet, pourlesclave, nul besoin de temps dattente puisquil doit rpondre ds linterrogation du matre.Jutiliserai donc seulement 2 flags ou indicateurs, pour signaler ltat du 9me bit reu etcelui du 9me bit mettre.Etant donn quon nenvoie et quon ne reoit quun seul octet la fois, les donnesprsentes dans RX9D et dans TX9D ne seront pas crases entre 2 changes. Jaurais donc puutiliser directement les valeurs de ces bits. Mais ce ne sera pas toujours le cas dans vosprogrammes, aussi ai-je prfr vous montrer une mthode plus gnrale.;*****************************************************************************; VARIABLES ZONE COMMUNE *;*****************************************************************************; Zone de 16 bytes; ----------------459CBLOCK 0x70 ; Dbut de la zone (0x70 0x7F)w_temp : 1 ; Sauvegarde registre Wstatus_temp : 1 ; sauvegarde registre STATUSFSR_temp : 1 ; sauvegarde FSR (si indirect en interrupt)flags : 1 ; 8 flags d'usage gnral; b0 : tat du 9eme bit envoyer; b1 : tat du 9eme bit reuoctet : 1 ; octet reu ou envoyerENDC#DEFINE EMI9 flags,0 ; valeur du 9eme bit envoyer#DEFINE REC9 flags,1 ; valeur du 9eme bit reuLe dmarrage sur le reset, toujours identique :;*****************************************************************************; DEMARRAGE SUR RESET *;*****************************************************************************org 0x000 ; Adresse de dpart aprs reset goto init ; InitialiserNous voici aux interruptions. Jai choisi de traiter la rception dun octet par interruption.En effet, le temps sparant 2 rceptions conscutives est trs long (0,5 seconde). Jenprofiterai donc pour placer le PIC en mode sleep dans lattente de loctet en provenancedu matre. Il sera rveill par linterruption. Bien entendu, je pouvais intgrer le traitementdans le programme principal (il me suffisait de ne pas activer le bit GIE). Mais, ce traitementest plus gnral, et donc plus didactique.La routine dinterruption de rception sur USART se contente de lire et de sauver loctetreu (ce qui efface le flag RCIF), et de positionner le flag REC9 en fonction de la valeur du9me bit reu. On en profite pour mettre fin au mode de rception.; ////////////////////////////////////////////////////////////////////////////; I N T E R R U P T I O N S; ////////////////////////////////////////////////////////////////////////////;*****************************************************************************; ROUTINE INTERRUPTION *;*****************************************************************************;sauvegarder registres;---------------------org 0x004 ; adresse d'interruptionmovwf w_temp ; sauver registre Wswapf STATUS,w ; swap status avec rsultat dans wmovwf status_temp ; sauver status swappmovf FSR , w ; charger FSRmovwf FSR_temp ; sauvegarder FSR; Interruption rception USART; ----------------------------BANKSEL RCSTA ; passer banque 0bcf REC9 ; par dfaut, 9eme bit reu = 0btfsc RCSTA,RX9D ; tester si 9eme bit reu = 1bsf REC9 ; oui, signaler 9eme bit = 1460movf RCREG,w ; charger octet reumovwf octet ; le sauverbcf RCSTA,CREN ; fin de rception;restaurer registres;-------------------restoreregmovf FSR_temp,w ; charger FSR sauvmovwf FSR ; restaurer FSRswapf status_temp,w ; swap ancien status, rsultat dans wmovwf STATUS ; restaurer statusswapf w_temp,f ; Inversion L et H de l'ancien W ; sans modifier Zswapf w_temp,w ; Rinversion de L et H dans W; W restaur sans modifier statusretfie ; return from interruptLa routine dintialisation se contente dinitialiser et de mettre en service le moduleUSART en mode esclave asynchrone, et de valider les interruptions de la rception USART.; ////////////////////////////////////////////////////////////////////////////; P R O G R A M M E; ////////////////////////////////////////////////////////////////////////////;*****************************************************************************; INITIALISATIONS *;*****************************************************************************init; Registre d'options; ------------------BANKSEL OPTION_REG ; passer banque 1bsf OPTION_REG,7 ; couper rsistances de rappel; initialiser USART; -----------------movlw B'01010000' ; mode esclave synchrone, mission 9 bitsmovwf TXSTA ; dans registre TXSTAbcf STATUS,RP0 ; repasser banque 0movlw B'11000000' ; module en service, rception 9 bitsmovwf RCSTA ; dans registre RCSTA; lancer interruption USART; -------------------------bsf INTCON,PEIE ; interruptions priphriques en servicebsf STATUS,RP0 ; passer banque 1bsf PIE1,RCIE ; autoriser interrupts RX USARTbcf STATUS,RP0 ; repasser banque 0bsf INTCON,GIE ; lancer les interruptionsgoto start ; dmarrer programme principalIl fallait bien mettre les donnes envoyer quelque part. Jai choisi de les ranger enmmoire programme. Il nous faut donc une routine qui puisse lire ces donnes en mmoireflash. De plus, nous aurons 2 zones, la zone concerne sera dsigne par le matre, notreroutine devra donc effectuer la slection.Il faudra de plus indiquer au matre si loctet demand est le dernier de la zone. Commeles donnes ranges en mmoire programme sont des mots de 14 bits, et que nous nen461utiliserons que 8, jai choisi dutiliser le bit 8 (b0 du poids fort de la donne) pour indiquerque nous nous trouvons en prsence du dernier mot de la zone. Il nous suffira alors derenvoyer ce bit comme 9me bit du mot destination du matre.;*****************************************************************************; LIRE UN OCTET EN MEMOIRE PROGRAMME *;*****************************************************************************;-----------------------------------------------------------------------------; Lit l'octet l'adresse "octet" en mmoire programme.; Positionne EMI9 suivant le 9eme bit du mot de 14 bits correspondant;-----------------------------------------------------------------------------readflash; pointer sur dbut de la zone de donnes; ---------------------------------------BANKSEL EEADRH ; positionner banque 2movlw HIGH zonedat1 ; par dfaut, MSB zone de donnes 1btfsc REC9 ; zone 2 demande?movlw HIGH zonedat2 ; oui, MSB zone de donnes 2movwf EEADRH ; positionner pointeur adresse MSBmovlw LOW zonedat1 ; par dfaut, LSB zone de donnes 1btfsc REC9 ; zone 2 demande?movlw LOW zonedat2 ; oui, LSB zone de donnes 2movwf EEADR ; positionner pointeur adresse MSB; Ajouter offset demand; ----------------------movf octet,w ; charger octet reu = numro de l'octetaddwf EEADR,f ; ajouter au pointeur d'adresse LSBbtfsc STATUS,C ; dbordement?incf EEADRH,f ; oui, incrmenter pointeur poids fort; Lire l'octet point; -------------------bsf STATUS,RP0 ; passer banque 3bsf EECON1,EEPGD ; pointer sur zone flashbsf EECON1,RD ; lire l'octet pointnop ; attendrenop ; attendrebcf STATUS,RP0 ; passer banque 2movf EEDATA,w ; charger 8 bits de donnesmovwf octet ; sauver l'octet lubcf EMI9 ; par dfaut, pas dernier octetbtfsc EEDATH,0 ; 9eme bit de donne = 1?bsf EMI9 ; oui, le signalerbcf STATUS,RP1 ; repasser banque 0return ; et retourNous en arrivons dj notre programme principal. Ce dernier va devoir raliser lesoprations suivantes :- Lancer la lecture dun octet- Attendre que le matre dcide denvoyer un octet, et que ce dernier soit reu- Lire loctet et stopper la rception- Slectionner la zone de donnes concerne, et lire loctet demand en mmoire flash- Prparer lmission de loctet concern- Attendre que le matre se dcide lire loctet prpar ( approximativement 4ms plus tard)- Stopper le mode dmission et reprendre au dbut462Voyons tout ceci en dtail, et tout dabord :- Lancer la lecture dun octet- Attendre que le matre dcide denvoyer un octet, et que ce dernier soit reu;*****************************************************************************; PROGRAMME PRINCIPAL *;*****************************************************************************start; lecture sur port srie; ----------------------bsf RCSTA,CREN ; lancer la rceptionsleep ; attendre un octet reuJai choisi dans lattente (trs longue) de la rception dun octet, de placer le PIC en mode sleep . Ceci prsente lavantage de ne pas devoir spooler en permanence ltat dunflag. Si nous avions utilis le watchdog, nous aurions du insrer une boucle supplmentaire,notre watchdog rveillant le PIC intervalles rguliers. Rien de bien dramatique, donc.Pour rappel, puisque RCIE est positionn, une fois RCIF positionn (ce qui intervientlorsquun octet a t reu et plac dans RCREG, le PIC sera rveill. Comme les bit GIE etPEIE sont positionns, linstruction suivante sera excute, puis le PIC se connectera sur notreroutine dinterruption.Ensuite, nous avons :- Lire loctet et stopper la rceptionComme nous lavons vu, ceci est entirement gr par notre routine dinterruption.Puis nous trouvons :- Slectionner la zone de donnes concerne, et lire loctet demand en mmoire flashCeci est gr par notre routine readflash , quil nous suffit donc dappeler.; lecture de l'octet demand en flash; -----------------------------------call readflash ; lire l'octet demand dans la mmoire flashMaintenant, prparer lmission de loctet concern est du ressort de la portion de codesuivante, qui positionne dabord le bit 9 envoyer, puis place loctet dans le registre TXREG,et ensuite lance lmission. Noubliez pas que lmission naura effectivement lieu quelorsque le matre dcidera denvoyer ses 9 impulsions dhorloge.; envoyer l'octet demand; -----------------------bsf STATUS,RP0 ; passer en banque1bcf TXSTA,TX9D ; par dfaut, 9eme bit envoyer = 0btfsc EMI9 ; tester si 9eme bit doit valoir 1463bsf TXSTA,TX9D ; oui, positionner 9eme bitmovf octet,w ; charger octet envoyerbcf STATUS,RP0 ; repasser banque 0movwf TXREG ; placer octet envoyer dans registre d'envoibsf STATUS,RP0 ; repasser banque 1bsf TXSTA,TXEN ; lancer l'missionIl nous faut maintenant attendre la fin de lmission, caractrise par le positionnement duflag TRMT. Ensuite, nous stoppons lmission, afin de repasser en rception en sautant audbut de notre programme principal :; attendre la fin de l'mission; -----------------------------btfss TXSTA,TRMT ; mission termine?goto $-1 ; non, attendre; clture de l'mission; ---------------------bcf TXSTA,TXEN ; fin de l'missionbcf STATUS,RP0 ; repasser banque 0goto start ; bouclerIl reste crire quelques donnes en mmoire flash, rparties en 2 zones distinctes :;*****************************************************************************; DATA *;*****************************************************************************;-----------------------------------------------------------------------------; 2 zones contenant les donnes envoyer, codes sur 9 bits; le bit8 indique le dernier octet de la zone;-----------------------------------------------------------------------------zonedat1DA B'000000001'DA B'000000010'DA B'000000100'DA B'000001000'DA B'000010000'DA B'000100000'DA B'001000000'DA B'010000000'DA B'001000000'DA B'000100000'DA B'000010000'DA B'000001000'DA B'000000100'DA B'100000010' ; le 9me bit vaut 1, donc fin de zonezonedat2DA B'000000001'DA B'000000011'DA B'000000111'DA B'000001111'DA B'000011111'DA B'000111111'DA B'001111111'DA B'011111111'DA B'001111111'DA B'000111111'DA B'000011111'464DA B'000001111'DA B'000000111'DA B'000000011'DA B'000000001'DA B'100000000' ; le 9me bit vaut 1, donc fin de zoneEND ; directive fin de programmeNotez que la directive END doit se trouver en fin de la zone des donnes, et non en findu programme principal.Programmez les 2 PICs laide des fichiers obtenus, et lancer lalimentation. Vos LEDseffectuent 3 squences daller-retour suivies par 4 squences de remplissage. Vous avez russivotre communication srie synchrone base sur lUSART.24.14 Remarque sur le mode sleepLes lecteurs particulirement attentifs, et surtout ceux qui cherchent anticiper ce quilsvont lire, nauront pas manqu de faire la rflexion suivante :Pourquoi diable place-t-il le PIC en mode sommeil durant lattente de la rception du mot,et ne le fait-il pas dans lattente de lmission ?Si vous tes dans ce cas, bravo. Si en plus, vous avez la solution, alors vous tes devenuun expert. Je mexplique donc :Pour rveiller le PIC, il faut imprativement le positionnement dun flag dinterruption.Or, quavons-nous notre disposition concernant lUSART ? Tout dabord le flag RCIF que nous avons utilis. Il permet de signaler que la rceptiondun mot est termine, et que loctet reu a t charg dans le registre RCREG (avecpositionnement ventuel de RX9D). Cest exactement ce quil nous fallait attendre. Aucunproblme, donc, pour la rception.Au niveau de lmission, nous avons lindicateur TXIF. Malheureusement pour notreexercice, ce flag est positionn, non pas quand la transmission est termine, mais quand leregistre TXREG est vide. Ce flag est prvu pour oprer une mission continue de plusieursoctet, et donc rveillerait le PIC dans ce cas chaque fois quune place est libre dans leregistre dmission. Larrt de la transmission au moment du positionnement de TXIFempcherait donc la transmission du dernier octet. Or, nous nen avons quun transmettre.On pourrait donc penser quil ny a pas de solution notre problme si on voulaitabsolument forcer notre PIC entrer en sommeil durant lattente de la fin de lmission. Etbien si, il y a une astuce possible.- Vous crivez loctet envoyer dans TXREG.- Au cycle suivant, TXREG est transfr dans TSR, TXREG est vide, donc TXIF estpositionn465- Vous crivez une seconde fois loctet dans TXREG. Comme TSR nest pas encore vide(lmission nest pas termine, et peut-tre mme pas commence), TXREG nest pastransfr, donc TXIF nest pas positionn.- Vous validez les interruptions dmission par TXIE.- Vous placez votre PIC en mode sommeil.- Le premier octet a t transmis, TXREG est transfr dans TSR, TXREG est vide, doncTXIF est positionn- Votre PIC se rveille, il vous suffit de couper TXEN pour mettre fin lmission .Lmission du second octet naura donc pas lieu. La coupure de TXEN provoque le resetde lUSART. Vous en profitez pour effacer le bit TXIE.Vous voyez donc quen rflchissant, on trouve des solutions simples pour tous les cas defigure. Dans le cas prsent, il suffisait simplement dcrire 2 valeurs au lieu dune dansTXREG.24.15 ConclusionsNous venons dtudier lUSART dans son fonctionnement synchrone, nul doute que vousne trouviez nombre dapplications le concernant. En effet, lUSART est non seulementpuissant et rapide, mais galement trs simple demploi.Je termine avec une petite remarque. Faites attention de ne pas confondre, dans lcriturede vos programmes, CREN avec RCEN. Comme ce dernier existe, MPASM ne voussignalerait pas derreur, mais votre programme ne pourrait pas fonctionner correctement.Cest le genre derreurs de distraction difficiles dtecter du premier coup dil. Vouspensez bien que si je vous en parle, cest que cela mest dj arriv.466Notes : 46725. Le module USART en mode asynchrone25.1 Le mode srie asynchroneJai dj parl de ce mode dans la premire partie du cours, au chapitre concernant lanorme ISO 7816. Vous pouvez commencer par aller relire ce chapitre.Cependant, je vais reprendre ici les caractristiques de ce mode, agrmentes de quelquesexplications complmentaires. Ceci vous vitera de sauter dun livre lautre.Nous savons maintenant ce quest une liaison srie synchrone. Une liaison srieasynchrone, comme son nom lindique, fonctionne de la mme faon, en mettant les bits lesuns la suite des autres, mais sans fournir le signal dhorloge qui a permis de les gnrer.Ceci a forcment plusieurs consquences, dont les suivantes :- Comme le rcepteur dune donne ne reoit pas le signal dhorloge, il doit savoir quellevitesse lmetteur a gnr son transfert. Cest en effet la seule faon pour lui de savoirquand commence et quand fini un bit.- Comme metteur et rcepteurs se mettent daccord pour adopter une vitesse commune, ettant donn que chacun travaille avec sa propre horloge, de lgres diffrences peuventapparatre sur les 2 horloges, introduisant des drives. Il faudra grer ceci.- Il faut un mcanisme qui permette de dtecter le dbut dune donne. En effet, imaginonsque la ligne soit niveau 1 et que lmetteur dcide denvoyer un 1 . Commentsavoir que la transmission a commenc, puisque rien ne bouge sur la ligne concerne ?- De la mme faon, il faut tablir un mcanisme pour ramener la ligne son tat de reposen fin de transmission. Ceci tant indispensable pour permettre la dtection de la donnesuivante.- Notez enfin que dans les transmissions asynchrones, la grande majorit des liaisonsprocdent en commenant par lenvoi du bit 0. Ce sera notre cas.La liaison utilisera les 2 mmes pins que pour la liaison synchrone, savoir RC6/TX/CKet RC7/RX/DT. Les dnominations qui conviendront dans ce cas seront bien entendu TX pourlmission et RX pour la rception.Ces pins devront tre configures en entre via TRISC pour fonctionner en mode USART.25.1.1 Le start-bitAu repos, nous allons imaginer que notre ligne soit au niveau 1 . Je choisis ce niveauparce que cest celui prsent sur la ligne dmission de votre PIC. Rien nempche detravailler avec une lectronique qui modifie ces niveaux, comme par exemple lutilisationdun driver RS485 (par exemple le MAX485), ou un pilote RS232 (comme le MAX232) qui468permettra a votre liaison srie de devenir compatible lectriquement avec le port RS232 devotre PC (jy reviendrai).Donc, notre ligne se trouve 1 . Or, nous navons quune seule ligne ddicace unsens de transfert, donc nous disposons dun seul et unique moyen de faire savoir audestinataire que la transmission a commenc, cest de faire passer cette ligne 0 (start-bit).On peut donc simplement dire que le start-bit est :- Le premier bit mis- Un bit de niveau toujours oppos au niveau de repos (donc 0 dans notre cas).- Un bit dune dure, par convention, la mme que celle dun bit de donne.25.1.2 Les bits de donneNous avons envoy notre start-bit, il est temps de commencer envoyer nos bits dedonne. En gnral, les bits de donne seront au nombre de 7 ou de 8 (cas les plus courants).La dure dun bit est directement lie au dbit choisi pour la connexion. En effet, le dbitest exprim en bauds, autrement dit en bits par seconde. Donc, pour connatre la dure dunbit, il suffit de prendre linverse du dbit.Tb = 1 / Dbit.Par exemple, si on a affaire une connexion 9600 bauds, nous aurons :Tb = 1 / 9600 bauds = 104,16 s.25.1.3 La paritDirectement aprs avoir envoy nos 7 ou 8 bits de donnes, nous pouvons dciderdenvoyer ou non un bit de parit. Ce bit permet dimposer le nombre de bits 1 mis(donne + parit), soit comme tant pair (parit paire), soit comme tant impair (paritimpaire).Le rcepteur procde la vrification de ce bit, et, si le nombre de bits 1 necorrespond pas la parit choisie, celui-ci saura que la rception ne sest pas effectuecorrectement. La parit permet de dtecter les erreurs simples, elle ne permet ni de les rparer,ni de dtecter les erreurs doubles. Par contre, la dtection frquente derreurs de parit indiqueun problme dans lchange des donnes.Voici par exemple, un cas de parit paire :La donne vaut : B00110100 Nous avons 3 bits 1 . Donc, pour avoir notre parit paire, notre bit de parit devra doncvaloir 1 , ce qui forcera le nombre total de bits 1 valoir 4 , ce qui est bien pair.469On enverra donc : B001101001 : 4 bits 1 = parit paire25.1.4 Le stop-bitNous avons maintenant mis tous nos bits de donne et notre parit ventuelle. Reste permettre notre ligne de transmission de revenir ltat de repos. Ce passage est dnomm stop-bit .On peut dire son sujet que :- Il sera le dernier bit mis de loctet- Son niveau est toujours celui du niveau de repos (donc 1 dans notre cas).- Sa dure sera par convention la mme que celle dun bit de donne.Le stop-bit nest pas comptabilis (pas plus que le start-bit) pour le calcul du bit de parit.Notez quil est permis dimposer lutilisation de 2 stop-bits . Ceci est le cas, parexemple, de la norme ISO 7816. Ceci revient simplement dire quil sagit dun stop-bit quidure une dure quivalante celle de 2 bits.Une autre faon de voir les choses, est de dire quon ne pourra envoyer loctet suivantquaprs une dure Tb aprs lmission du premier stop-bit. Ou, dit encore autrement, on doitmnager une pause dune dure de 1 bit, entre lmission de 2 octets conscutifs.Un mot concernant la lecture dun bit par le rcepteur. Il est vident que la lecture dechaque bit doit seffectuer dans la zone prsentant la plus grande probabilit de stabilit dubit. En gnral, les lectroniques sont construites pour mesurer le bit au milieu de sa dure.Voici, pour illustrer tout ceci, lmission dune donne code sur 8 bits, avec parit paireet un stop-bit. Les lectures sont indiques par les flches infrieures :Notez, pour votre information, que la lecture dun bit par le PIC ne seffectue pas en uneseule fois. En ralit, votre PIC effectuera 3 mesures conscutives centres sur le milieuprsum du bit. Ces 3 mesures sont entres dans une porte majoritaire, qui dfinit quel sera leniveau considr comme exact. Ceci vite quun parasite nengendre une erreur de lecture.470Une porte majoritaire, est un circuit qui fournit sur sa sortie ltat majoritairement prsentsur sa ou ses entres.Autrement dit, si votre PIC a lu, pour un bit donn, 2 fois la valeur 1 et une fois lavaleur 0 , le bit sera considr comme valant 1 , puisque 1 est prsentmajoritairement (2 contre 1). Ceci est cependant transparent pour vous, vous navez pas vous en proccuper.25.1.5 Les modes compatiblesNous avons vu que le transfert dune donne sera compose de :- 1 Start-bit- 7 ou 8 bits de donne- 0 ou 1 bit de parit- 1 ou 2 stop-bits.Ceci nous donne des longueurs totales comprises entre 9 et 12 bits.Notre PIC nous permet, lui, de grer 8 ou 9 bits de donnes, la parit doit tre gremanuellement et intgre dans les bits de donnes. Un seul stop-bit est mis. Ceci nousdonne :- 1 Start-bit- 8 ou 9 bits de donne- 1 stop-bitLes longueurs possibles seront comprises entre 10 et 11 bits. Je vais maintenant vousmontrer comment exploiter les diffrentes possibilits avec votre PIC en fonction de sespossibilits.Cas 1 : 1 start-bit, 7 bits de donne, 0 bit de parit, 1 stop-bitDans ce cas, la transmission seffectue sur 9 bits, ce que ne permet pas le PIC.Pour lmission, on peut raliser lastuce suivante :On ralise une mission avec 8 bits de donne, et on placera :- Les 7 bits de donne dans les bits 0 6- Le stop-bit dans le bit 7 (donc bit 7 toujours 1 ).Ceci se traduira par la rception, vue par linterlocuteur de votre PIC, par la rceptiondune donne comportant 1 start-bit, 7 bits de donne, 0 bit de parit, et 2 stop-bits (le faux,plac dans le bit 7 de la donne, et le vrai, envoy automatiquement par le module USART).Comme second stop-bit ou pause entre 2 missions sont identiques (la ligne reste ltathaut), le rcepteur ny verra que du feu.471La rception est par contre impossible. En effet, si linterlocuteur envoie ses donnes defaon jointive, le start-bit de la donne suivant sera reu au moment o le PIC sattend recevoir le stop-bit de la donne en cours. Donc, ceci gnrera une erreur de rception.Par chance, ce mode est extrmement rare. En fait, je ne lai jamais rencontr.Cas 2 : 1 start-bit, 7 bits de donne, 0 bit de parit, 2 stop-bitsNous voici avec une transmission sur 10 bits, ce qui ne devrait pas poser de problme.Forts de ce qui prcde, nous en concluons que nous raliserons une transmission avec 8bits de donnes, pour laquelle :- Les 7 bits de donne seront places dans les bits 0 6- Le premier stop-bit sera plac dans le bit 7 (donc toujours 1 )Emission et rception ne posent donc aucun problme.Cas 3 : 1 start-bit, 7 bits de donne, 1 bit de parit, 1 stop-bitDe nouveau, transmission sur 10 bits, donc sans problme avec une donne code sur 8bits :- Les 7 bits de donne seront placs dans les bits 0 6- La parit sera place dans le bit 7Cas 4 : 1 start-bit, 7 bits de donne, 1 bit de parit, 2 stop-bitsNous voici avec une liaison sur 11 bits, donc nous choisirons une longueur de donne de 9bits pour notre PIC. Ceci nous donne :- Les 7 bits de donne dans les bits 0 6- Le bit de parit dans le bit 7- Le premier bit de stop dans le bit 8 (9me bit)Cas 5 : 1 start-bit, 8 bits de donne, 0 bit de parit, 1 stop-bitUn cas classique, nous choisirons une longueur de donne de 8 bits. La donne nencessite aucun traitement. Cest le cas le plus simple.- Les 8 bits de donnes sont placs dans les bits 0 7Cas 6 : 1 start-bit, 8 bits de donne, 0 bit de parit, 2 stop-bits472Revoici une liaison sur 11 bits, donc nous choisirons une longueur de donn de 9 bits, cequi nous donne :- Les 8 bits de donne dans les bits 0 7- Le premier stop-bit dans le bit 8 (9me bit toujours 1 )De nouveau, cest un cas trs simple.Cas 7 : 1 start-bit, 8 bits de donne, 1 bit de parit, 1 stop-bitEncore une liaison sur 11 bits, donc toujours une longueur de donne de 9 bits. Ici, le bitde parit sera dans le 9me bit, soit :- Les 8 bits de donne dans les bits 0 7- Le bit de parit dans le bit 8 (9me bit)Cest un grand classique que vous rencontrerez souvent (et que nous traiterons dans notreexemple).Cas 8 : 1 start-bit, 8 bits de donne, 1 bit de parit, 2 stop-bitsCette fois, nous avons une liaison sur 12 bits, soit hors possibilits de notre PIC. Nousnous en sortons par une pirouette en mode donne sur 9 bits:En rception :- Les 8 bits de donnes se retrouvent dans les bits 0 7- Le bit de parit se retrouve dans le bit 8 (9me bit)- Le second stop-bit est tout simplement considr comme un temps mort, et est toutsimplement ignor par notre USART.En rsum, en rception, vous navez pas vous proccuper du second stop-bit.En mission- On place les 8 bits de donnes dans les bits 0 7- On place la parit dans le bit 8- A la fin de lmission, on attend un temps supplmentaire correspondant 1 bit avantdenvoyer la donne suivante.Vous rencontrerez ce cas si vous ralisez des programmes pour la norme ISO 7816, parexemple.En rsum, en mission, vous crez le second stop-bit en introduisant un dlai entrelmission de 2 donnes.47325.1.6 Les erreurs de synchronisationJe vous en ai dj touch un mot, vous savez donc que metteur et rcepteur adoptent unevitesse dhorloge qui est sense tre identique sur les 2 composants. Seulement, ces horlogesne sont jamais exactement identiques, ce qui entrane une erreur qui se cumule au fur et mesure de la rception des bits. Bien entendu, la transmission sera resynchronise au star-bitsuivant.La drive maximale est donc obtenue lors de la rception du dernier bit (stop-bit).Prenons tout dabord un cas idal : Soit Tb1 le temps dmission dun bit par lmetteur,et Tb2 le temps sparant 2 lectures par le rcepteur. Dans ce cas idal, les 2 horloges sontparfaite