SlideShare a Scribd company logo
1 of 34
Download to read offline
Programmation des PIC en C


Microcontrôleur facile pour électronicien amateur

                   PARTIE 2




                      Noxyben
                       2008

                   www.noxyben.fr




                        -1-
Introduction ................................................................................................................................ 3
Le schéma de base...................................................................................................................... 4
Principe de fonctionnement des ports I/O .................................................................................. 7
Utilisation des ports d’entrée/sortie (I/O)................................................................................... 8
   Utilisation d’un PORT en sortie : un chenillard 8 leds .......................................................... 8
     Le matériel : ....................................................................................................................... 8
     Le programme : ................................................................................................................ 10
     Analyse du programme : .................................................................................................. 12
     Compilation du programme et injection dans le PIC : ..................................................... 16
     Tests ................................................................................................................................. 17
     Conclusion :...................................................................................................................... 17
   Utilisation d’un PORT en entrée : un chenillard 8 leds contrôlé par 2 boutons poussoirs. . 18
     Le matériel : ..................................................................................................................... 18
     Le programme : ................................................................................................................ 19
     Analyse du programme : .................................................................................................. 22
     Compilation du programme et injection dans le PIC : ..................................................... 23
     Tests ................................................................................................................................. 24
     Conclusion :...................................................................................................................... 24
   Le PORTB et les interruptions ............................................................................................. 25
     Principe de fonctionnement :............................................................................................ 25
     Le matériel : ..................................................................................................................... 26
     Le programme : ................................................................................................................ 27
     Analyse du programme : .................................................................................................. 29
     Tests ................................................................................................................................. 34
     Conclusion :...................................................................................................................... 34




                                                                    -2-
Introduction
Après avoir vu dans la première partie comment est structuré le PIC, on va enchaîner
directement sur des montages concrets : rien de mieux pour apprendre et mémoriser
que de faire soi-même un montage « en vrai ». Je vous invite chaleureusement à
faire un tour chez votre marchand de composants électroniques et à faire chauffer
votre fer à souder. Vous allez avoir besoin d’un PIC16F877, un programmateur, une
platine d’essai du genre « pastilles pré-percées » au pas de 2,54 mm, et quelques
composants qui traînent certainement dans vos fonds de tiroirs : Led, régulateur
7805, condensateurs, support 40 broches…
Pour la partie logicielle il vous faudra télécharger la version de démonstration de
SourceBoost, qui comprend le compilateur BoostC que nous allons employer, et
éventuellement un logiciel de transfert comme Icprog pour piloter votre
programmateur de PIC. Si vous avez acheté un programmateur en kit comme le
Velleman K8076, le logiciel « PICPROG » est compris. Pensez à télécharger les
mises à jour.




                                        -3-
Le schéma de base
                                    IC2
             D1
      9V =
                                   7805
                       R1

                  C3                      C4
                            Led1
                                                              1                 40
                                                              2                 39        ICSP
                                                              3                 38
                                                              4                 37
                                                              5                 36
                                                              6                 35
                                                              7                 34




                                                                   PIC 16F877
                                                              8                 33
                                                                                     C6
-4-




                                                              9                 32
                                                              10                31
                                                    C5        11                30
                                                              12                29
                                                              13                28
                                                              14                27
                                                              15                26

                                                         C2   16                25
                                          C1
                                                              17                24
                                               Q1
                                                              18                23
                                                              19                22
                                                              20                21

                                                                   IC1
Le schéma ci-dessus est la base sur laquelle on va pouvoir construire des
applications utiles. Il ne fait rien d’autre que de permettre au PIC de fonctionner, c’est
en quelque sorte le « minimum vital ». Bien entendu, d’autres variantes sont
possibles, mais plutôt que d’en dresser la liste exhaustive, je vous propose de
réaliser cette version et de remettre à plus tard l’étude des différents circuits
d’oscillateur, de reset…

L’alimentation : Pour alimenter le circuit, une source continue d’environ 9V fera
parfaitement l’affaire (une pile 9V par exemple). La régulation et l’adaptation à un
niveau de 5V requis par le PIC incombent au régulateur 7805.
Remarque : pour que celui-ci fonctionne correctement, la tension d’alimentation doit
être supérieure d’au moins 2 ou 3 volts à la tension régulée, donc 5 + 2 = 7 Volts.
La diode D1 protège le circuit contre les inversions accidentelles de polarité (diode
type 1N4001 ou 1N4007 par exemple).
Le condensateur C3 sert de « réservoir » au régulateur. La règle habituelle est de
prendre 1000 F / Ampère. Dans notre cas, un condensateur électrochimique
de 470 avec une tension d’au moins 16V convient parfaitement.
Le condensateur C4 nous permet de découpler le régulateur du reste du
circuit : il absorbe les variations de tension parasite qui pourraient remonter
vers le régulateur. 10 ou 100 nF devraient convenir.
Le couple R1 – Led1 sert de témoin de mise sous tension, et accessoirement
décharge le condensateur C3 lorsque l’alimentation est coupée.
Avec une tension d’alimentation de 9V, on prendra pour R1 une valeur de
390 1/4W
Les condensateurs C5 et C6 quant à eux sont des condensateurs de
découplage du PIC. À monter au plus près du 16F877, ils empêchent que
d’éventuels parasites collectés par les lignes d’alimentation ne pénètrent dans
le circuit intégré. Quelques pF ou nF du genre condensateur « tantale goutte »
feront l’affaire. Surtout pas de gros condensateur électrochimique de plusieurs
  F qui aurait un effet néfaste sur le temps de montée de l’alimentation et
pourrait ainsi perturber le PIC au moment du démarrage.

L’oscillateur : Il est constitué de Q1, un quartz « parallèle » dont la fréquence
d’oscillation nominale peut aller jusqu’à 20MHz, et des condensateurs C1 et
C2 pour lequel on prendra une valeur de 20pF, conformément aux indications
de la documentation de Microchip.




                                           -5-
Le connecteur ICSP : Bien que n’étant pas indispensable, on va équiper
notre platine de ce connecteur « In Circuit Serial Programming », qui nous
permettra de programmer le PIC sans le retirer de son support. A vrai dire, le
brochage n’est pas vraiment normalisé. Je vous propose donc la version
suivante, que vous pourrez adapter à votre guise. Le seul impératif est que les
bonnes lignes du programmateur aboutissent sur les bonnes pattes du PIC

   •   patte 1 - 6 : Vpp (tension de programmation)
   •   patte 2 - 7 : VDD (tension d’alimentation 5V)
   •   patte 3 - 8 : PGD (Program Data = ligne de transfert des données)
   •   patte 4 – 9 : Vss (tension de masse = 0V)
   •   patte 5 - 10 : PGC (Program Clock = ligne d’horloge de programmation)

                                  1       6
                                  2       7
                                  3       8
                                  4       9
                                  5      10



En fonctionnement normal, la pin 1 est pontée sur la pin 6, la pin 2 sur la 7, la
3 sur la 8, la 4 sur la 9 et la 5 sur la 10.
Pour programmer le PIC on déconnecte l’alimentation du circuit, on ôte tous
les ponts du connecteur ICSP et on branche à la place le cordon ICSP du
programmateur, en veillant à ce que les signaux correspondent bien. Si ce
n’est pas le cas, il vous faudra confectionner un cordon ad’ hoc en croisant les
bonnes lignes.

Le circuit de RESET : Rien de plus simple pour l’instant : la ligne de reset
 MCLR (la pin 1 du PIC) est simplement reliée à la tension d’alimentation.
Ainsi, pour redémarrer le PIC, on coupe l’alimentation et on réalimente.




                                       -6-
Principe de fonctionnement des ports I/O
 Les ports d’entrée / sortie numériques peuvent être considérés comme les
périphériques les plus simples du microcontrôleur. Pour le PIC, on contrôle leur
fonctionnement à l’aide de registres spéciaux (deux registres par port). Par exemple,
pour le port A, on a le registre PORTA et le registre TRISA.
Les registres « TRISx » contrôlent le mode de fonctionnement des entrées / sorties :
selon la valeur de chaque bit, 0 ou 1, la pin correspondante du port fonctionnera soit
en sortie, soit en entrée. Les registres « PORTx » contiennent les données, lues, ou
à écrire sur le port. Certains ports possèdent en plus des fonctionnalités spécifiques :
le PORTB est équipé de résistances de tirage (pull-up) internes qui peuvent être
activées ou non. La pin RB0 du PORTB sert d’entrée d’interruption externe, et les
pins RB4 à RB7 peuvent générer une interruption lorsqu’un changement d’état est
détecté à leurs bornes. Toutes ces particularités sont bien entendu décrites dans les
documentations Microchip spécifiques à chaque composant.




                                          -7-
Utilisation des ports d’entrée/sortie (I/O)

Utilisation d’un PORT en sortie : un chenillard 8 leds


Le matériel :



                1                 40
                2                 39
                3                 38
                4                 37                                             VCC
                5                 36
                6                 35
                                               R9 R8 R7 R6 R5 R4 R3 R2
                7                 34
                     PIC 16F877




                8                 33
                9                 32
                10                31
                11                30
                                       Rd8
                12                29
                13                28
                                       Rd8
                14                27
                15                26
                                       Rd6
                16                25
                17                24
                                       Rd5
                18                23
                19                22
                                       Rd4
                20                21
                                       Rd3
                                       Rd2
                                       Rd1




On va rajouter les quelques composants du schéma ci-dessus à notre montage de
base. Le but est de pouvoir commander 8 leds à travers les 8 lignes du PORTD.
On pourrait raccorder les leds directement aux pins du PIC à travers des résistances
appropriées, (ça marche aussi) mais au cas où l’idée vous viendrait d’allumer les 8
leds en même temps, le courant débité par le PORTD pourrait dépasser la valeur
limite. En effet, un coup d’œil à la rubrique caractéristiques électriques du datasheet
nous informe que le courant maximal pouvant être débité par un PORT est de 200
mA. Avec des résistances légèrement sous-dimensionnées et 8 leds allumées on
pourrait s’en approcher dangereusement. Bon, c’est vrai, j’exagère un peu, même
avec 8 x 20 mA on n’est encore qu’à 160mA de consommation sur le port. Mais
autant adopter de bons réflexes dès le départ. On choisit donc de passer par des
transistors. On pourra prendre des transistors petit signaux standard. Si vous trouvez
dans vos tiroirs des BC537 ou 2N2222 ou quoi que ce soit d’équivalent, ça
conviendra parfaitement.
Pour les résistances R2 à R9, si on considère que le point de fonctionnement des
leds est à environ 1,8V / 10 mA, et que VCC = 5 V : VRx = 5-1,8 = 3,2V ; donc
R = VRx / I = 3,2 / 0.01 = 320.

                                             -8-
La valeur normalisée la plus proche étant 330, on prendra donc pour les résistances
R2 à R9 des 330 Ohms ¼ de Watt.
Pour les résistances Rd1 à Rd8, afin d’assurer une bonne saturation des transistors,
on prendra des résistances de 4,7 kOhms ¼ de Watt.




                                        -9-
Le programme :

On rentre enfin dans le vif du sujet. Afin de piloter notre montage avec un joli effet
« K2000 », je vous propose le programme ci-dessous :

#include <system.h>

//Cible PIC16F877, bits de configuration
#pragma DATA _CONFIG, _PWRTE_OFF & _BODEN_OFF & _WDT_OFF &
_LVP_OFF & _CPD_OFF & _DEBUG_OFF & _HS_OSC & _CP_OFF

//Configuration de la fréquence d'horloge, ici 20Mhz
#pragma CLOCK_FREQ 20000000



void main( void )
{

       //Initialisation port A
       porta = 0x00;
       //Initialisation port B
       portb = 0x00;
       //Initialisation port C
       portc = 0x00;
       //Initialisation port D
       portd = 0x00;
       //Initialisation port E
       porte = 0x00;



       //Configuration port A
       trisa = 0x00;
       //Configuration port B
       trisb = 0x00;
       //Configuration port C
       trisc = 0x00;
       //Configuration port D
       trisd = 0x00;
       //Configuration port E
       trise = 0x00;

       //Configuration A/D pins
       adcon1 = 0x06;


       //désactivation du mécanisme de gestion des interruptions
       clear_bit( intcon, GIE );


                                          - 10 -
//Validation des résistances de pull-ups du port B
clear_bit( option_reg, NOT_RBPU );

//Boucle sans fin
while( 1 )
{
       portd = 0b00000001;
       delay_ms(100);
       portd = 0b00000011;
       delay_ms(10);
       portd = 0b00000010;
       delay_ms(100);
       portd = 0b00000110;
       delay_ms(10);
       portd = 0b00000100;
       delay_ms(100);
       portd = 0b00001100;
       delay_ms(10);
       portd = 0b00001000;
       delay_ms(100);
       portd = 0b00011000;
       delay_ms(10);
       portd = 0b00010000;
       delay_ms(100);
       portd = 0b00110000;
       delay_ms(10);
       portd = 0b00100000;
       delay_ms(100);
       portd = 0b01100000;
       delay_ms(10);
       portd = 0b01000000;
       delay_ms(100);
       portd = 0b11000000;
       delay_ms(10);
       portd = 0b10000000;
       delay_ms(100);
       portd = 0b11000000;
       delay_ms(10);
       portd = 0b01000000;
       delay_ms(100);
       portd = 0b01100000;
       delay_ms(10);
       portd = 0b00100000;
       delay_ms(100);
       portd = 0b00110000;
       delay_ms(10);
       portd = 0b00010000;
       delay_ms(100);
       portd = 0b00011000;
       delay_ms(10);
       portd = 0b00001000;

                                  - 11 -
delay_ms(100);
             portd = 0b00001100;
             delay_ms(10);
             portd = 0b00000100;
             delay_ms(100);
             portd = 0b00000110;
             delay_ms(10);
             portd = 0b00000010;
             delay_ms(100);
             portd = 0b00000011;
             delay_ms(10);

      }
}




Analyse du programme :

Étudions cela un peu plus en détails :

#include <system.h>

Cette directive indique au précompilateur d’inclure le fichier system.h. Celui-ci
contient à son tour une inclusion pour le fichier spécifique à votre PIC (16F877.h),
dans lequel sont indiquées les associations nom de registre / adresses mémoire.
D’où l’importance de bien indiquer à BoostC la cible (ici 16F877) pour laquelle vous
désirez compiler votre programme.


#pragma DATA _CONFIG, _PWRTE_OFF & _BODEN_OFF & _WDT_OFF &
_LVP_OFF & _CPD_OFF & _DEBUG_OFF & _HS_OSC & _CP_OFF

Une autre directive de précompilation, qui permet de définir les bits de configuration
du PIC. Pour mémoire, ces bits de configuration permettent de configurer un certain
nombre de paramètres de fonctionnement du PIC. Bien heureusement, SourceBoost
reprend à peu de chose près les mêmes désignations que Microchip :
    • PWRTE_OFF : désactive le Power-up Timer Enable bit
    • BODEN_OFF : désactive le Brown-Out reset Enable bit
    • WDT_OFF : désactive le Watch Dog Timer
    • LVP_OFF : désactive le Low Voltage Programming
    • CPD_OFF : désactive la protection de la mémoire de données EEPROM ?
    • DEBUG_OFF : désactive l’In-Circuit Debugger
    • HS_OSC : Configure l’oscillateur en mode HS (High Speed)
    • CP_OFF : désactive la protection du code
Pour l’instant on désactive tout (OFF), à part bien sûr l’oscillateur qu’on configure en
mode « HS », mode recommandé par Microchip pour l’emploi d’un quartz 20 MHz.
Si vous utilisez un quartz 4 MHz, le mode le plus approprié sera « XT ». La différence
réside entre HS et XT réside dans le gain de l’amplificateur inverseur du circuit
d’oscillateur du PIC. Plus la fréquence de travail est élevée, plus le gain doit être
                                         - 12 -
élevé. Mais dans la pratique, en mode « HS » et avec un quartz à 4 MHz, ça marche
aussi. Pour savoir quel mode choisir, regardez dans la documentation Microchip sur
la gamme des PIC « mid-range », ou mieux sur la documentation du 16F877 dans la
section « oscillator ».


#pragma CLOCK_FREQ 20000000

A nouveau une directive de précompilation. On indique ici quelle est la fréquence du
quartz utilisé. Les temporisations générées par la fonction « delay » utilisée plus loin
dans le programme sont basées sur cette valeur.

void main( void )
{


}

La fonction « main » est obligatoire en langage C : c’est le « point d’entrée » du
programme. Le «void» placé avant «main» indique que la fonction ne retourne
aucune valeur, et le «void» entre parenthèses indique qu’on ne prend pas de valeur
en argument. Tout le reste de notre programme viendra se placer entre les
accolades ouvrante et fermante.

      //Initialisation port A
      porta = 0x00;
      //Initialisation port B
      portb = 0x00;
      //Initialisation port C
      portc = 0x00;
      //Initialisation port D
      portd = 0x00;
      //Initialisation port E
      porte = 0x00;

Les variables porta, portb, portc, portd et porte sont affectées aux registres
correspondant à l’état des Entrées/Sortie des ports. (respectivement le PORTA,
PORTB, PORTC, PORTD, PORTE). Ces variables sont déclarées dans le fichier
d’entête spécifique au PIC 16F877 (fichier avec l’extension « .h » ), lui-même inclus
dans le fichier «system.h». Ainsi, vous pouvez accéder à un registre du PIC
simplement en l’appelant par son nom, sans se soucier de son adresse.
Écrire une donnée dans un de ces registres affectera dès-lors les pins
correspondantes du PORT, si celles-ci sont configurées en sortie. Ici, on initialise tout
à 0.




                                          - 13 -
//Configuration port A
       trisa = 0x00;
       //Configuration port B
       trisb = 0x00;
       //Configuration port C
       trisc = 0x00;
       //Configuration port D
       trisd = 0x00;
       //Configuration port E
       trise = 0x00;

Suivant le même principe que pour les registres porta, portb, portc… les variables
trisa, trisb, trisc, trisd, trise sont affectées aux registres de contrôle de direction des
ports (respectivement le PORTA, PORTB, PORTC, PORTD, PORTE). On affecte au
cinq registres «tris» la valeur hexadécimale (d’où le «x» pour heXa) 00. Un coup
d’œil aux fiches détaillées des registres correspondant nous montre que cette valeur
00 passe toutes les lignes d’Entrés/Sortie des ports en mode « sortie ».
Une remarque : Microchip recommande de d’initialiser en premier lieu les registres
« portx », et de configurer la direction avec les registres « trisx » ensuite. Pour éviter
d’avoir un état incertain sur les pins au moment du démarrage.

       //Configuration A/D pins
       adcon1 = 0x06;

Certaines pins des ports sont susceptibles d’être utilisée par le convertisseur
Analogique / Numérique. Par défaut, (voir fiche détaillée du registre adcon1), les pins
en question sont configurées en mode analogique. La valeur hexadécimale 0x06 les
passe en mode numérique.

       //désactivation du mécanisme de gestion des interruptions
       clear_bit( intcon, GIE );

Le registre intcon contrôle le mécanisme d’interruption. «intcon» pour INTerrupt
CONtrol. GIE, Global Interrupt Enable bit, est un des bits du registre intcon, il active
ou désactive de manière globale toutes les interruptions. La fonction «clear_bit()» est
une fonction implémentée par BoostC, permettant de mettre un bit à 0. Son pendant
est la fonction «set_bit()» qui permet, elle de mettre un bit à 1. La syntaxe ci-dessus
signifie donc : « mettre à 0 le bit GIE du registre intcon ».




                                           - 14 -
//Validation des résistances de pull-ups du port B
      clear_bit( option_reg, NOT_RBPU );

Le registre option_reg contrôle certaines options du PIC, parmi lesquelles figure
l’activation ou non des résistances de pull-up du PORTB. Le bit correspondant à
cette option est NOT_RBPU. Celui-ci fonctionne en logique négative (d’où le NOT
devant RBPU). La syntaxe ci-dessus signifie donc « mettre à 0 le bit NOT_RBPU du
registre option_reg ». Or, étant donné que le bit NOT_RBPU fonctionne en logique
négative, le mettre à 0 signifie ACTIVER les résistances de pull-up du PORTB ! Pour
l’instant on ne se sert pas de ces résistances, donc vous pouvez, si vous préférez,
mettre ce bit à 1 pour les désactiver.

      //Boucle sans fin
      while( 1 )
      {

      }

Comme l’indique le commentaire, il s’agit là d’une boucle sans fin. «While» est une
instruction de contrôle de boucle du langage C. La traduction française donnerait :
« tant que 1… ». Or, «1» n’a pas de raison de changer d’état, donc une fois lancée,
on ne sort pas de cette boucle. Tout le code entre les accolades ouvrante et
fermante se répètera dès lors indéfiniment.

             portd = 0b00000001;

La variable «portd» est affectée au registre correspondant à l’état des Entrées/Sortie
du PORTD. Ici, on écrit la donnée binaire (d’où le b de 0bxxxxxxxx) 0b00000001, ce
qui a pour effet de passer la pin RD0 à l’état 1, alors que les pins RD1 à RD7 restent
à l’état 0.

             delay_ms(100);

La fonction «delay_ms()» est une fonction implémentée par BoostC, permettant
d’introduire une temporisation. Ici, delay_ms(100) génère une temporisation de 100
millisecondes. Cette temporisation est calculée en fonction de la valeur de la
fréquence d’horloge qu’on a indiquée plus en amont par la directive PRAGMA
CLOCK_FREQ.




                                        - 15 -
portd = 0b00000011;
              delay_ms(10);

On « allume » une deuxième pin du PORTD, et on attend ensuite 10 millisecondes,
avant de passer à la suite. Le principe utilisé ici est le suivant : on allume une led, on
attend 100 ms, on allume une deuxième led, on attend 10 ms, on éteint la première
led, on attend 100 ms, etc. L’allumage simultané de deux les n’est là que pour
diminuer l’effet de saccade lors du passage d’une led à l’autre.
Vous l’aurez remarqué : cette manière de faire est un peu « rustique », on aurait pu
remplacer la répétition des instructions par des boucles bien construites. Mais d’un
point de vue didactique ça me semble plus simple à comprendre, et comme on est
loin d’avoir saturé la mémoire du PIC…


Compilation du programme et injection dans le PIC :

Après l’étude théorique, il ne reste plus qu’à compiler notre programme et l’injecter
dans le PIC. Pour cela, on va suivre les étapes suivantes :

COMPILATION :

   •   Lancez l’IDE de SourceBoost.
   •   Assurer vous que le compilateur utilisé est bien BoostC (dans le menu
       paramètres).
   •   Créez un nouveau projet (menu Projet : Nouveau).
   •   Dans ce projet, créez un nouveau fichier (menu Fichier : Nouveau) dans
       lequel vous allez copier le code ci-dessus.
   •   Sélectionnez la « cible », autrement dit le composant pour lequel vous voulez
       compiler le projet : PIC 16F877 (menu Paramètres : Cible)
   •   Compilez le programme (menu Construction : Construire)
   •   Si tout s’est bien passé, le compilateur indique « success » et a généré dans
       le répertoire de votre projet plusieurs fichiers. L’un d’entre eux a une extension
       en «.hex».

TRANSFERT (avec un programmateur Velleman K8076) :

   •   Configurez le programmateur pour le 16F877 (il faut que les « ponts »
       aboutissent sur les bonnes pattes du support ZIF, si vous utilisez ce dernier)
   •   A ce stade, soit vous placez le pic sur le support ZIF du programmateur, soit
       vous raccordez le cordon « ICSP » sur la platine sur laquelle est monté le PIC.
   •   Raccordez le programmateur au PC.
   •   Alimentez le programmateur.
   •   Lancez le programme PICPROG (livré avec le programmateur Velleman).
   •   Sélectionnez la cible, ici un PIC 16F877 (si vous ne le trouvez pas dans la
       liste, vérifiez sur le site de Velleman s’il n’y a pas de mise à jour).
   •   Ouvrez le fichier «.hex » généré par le compilateur pour votre projet
   •   Cliquez sur le bouton « write all data », et attendez que le transfert s’effectue.



                                          - 16 -
•    Si à ce stade tout est ok, déconnectez le programmateur, placez le PIC sur
        son circuit ou remettez les ponts à la place du connecteur ICSP de votre
        platine prototype.


Tests

Vous pouvez alimenter votre circuit et… He is alive ! Un magnifique effet de balayage
anime vos 8 led. Elle est pas belle la vie ?


Conclusion :

Ca y est, vous avez créé une application à base de microcontrôleur ! Il est vrai que
pour l’instant, l’interaction de notre montage avec le monde réel est très limitée. Il
peut néanmoins servir à créer de jolis effets lumineux. On pourrait également
envisager de s’en servir comme télécommande rustique (à une seule fonction ?) en
montant une led infrarouge et en programmant la séquence d’allumages/extinctions
adéquate.




                                         - 17 -
Utilisation d’un PORT en entrée : un chenillard 8 leds contrôlé par 2
boutons poussoirs.

Étape suivante : on va utiliser des pins d’un autre port en entrée, pour contrôler le
fonctionnement de notre application.

Le matériel :



                               1                 40
                               2                 39
                               3                 38
                               4                 37
                               5                 36
                               6                 35
                               7                 34
                                                          RB1
                                                          RB0/INT
                                    PIC 16F877


                               8                 33
                               9                 32
                               10                31
                               11                30
                               12                29
                               13                28          switchon   switchoff
                               14                27
                               15                26
                               16                25
                               17                24
                               18                23
                               19                22
                               20                21




On reprend le schéma précédent, et on y ajoute deux boutons poussoirs directement
raccordés aux pins RB0 et RB1, autrement dit les deux bits de poids faible du
PORTB. Vous allez me dire, « Quand on appuie sur les boutons poussoirs, ok, les
pins sont à la masse, mais quand on relâche le potentiel est flottant, non ? »
justement non, puisque qu’on va utiliser les résistances de pull-up interne du PIC.
Une remarque importante : il n’y a que le PORTB qui soit équipé de telles
résistances. Si vous utilisez un autre port, il faudra câbler vous-même ces
résistances de tirage entre VCC et la pin correspondante.




                                                 - 18 -
Le programme :

La structure générale est identique à l’exemple précédent, avec tout de même
quelques modifications :

#include <system.h>

//Cible PIC16F877, bits de configuration
#pragma DATA _CONFIG, _PWRTE_OFF & _BODEN_OFF & _WDT_OFF &
_LVP_OFF & _CPD_OFF & _DEBUG_OFF & _XT_OSC & _CP_OFF

//Configuration de la fréquence d'horloge, ici 4Mhz
#pragma CLOCK_FREQ 4000000


void main( void )
{

      //Initialisation port A
      porta = 0x00;
      //Initialisation port B
      portb = 0x00;
      //Initialisation port C
      portc = 0x00;
      //Initialisation port D
      portd = 0x00;
      //Initialisation port E
      porte = 0x00;


      //Configuration port A
      trisa = 0x00;
      //Configuration port B
      trisb = 0x03; // On configure les deux pins de poids faible en entrée
      //Configuration port C
      trisc = 0x00;
      //Configuration port D
      trisd = 0x00;
      //Configuration port E
      trise = 0x00;

      //Configuration A/D pins
      adcon1 = 0x06;




      //désactivation du mécanisme de gestion des interruptions
      clear_bit( intcon, GIE );


                                        - 19 -
//Validation des résistances de pull-ups du port B
clear_bit( option_reg, NOT_RBPU );


volatile bit switchon@0x06.0;        // 0 pour RB0
volatile bit switchoff@0x06.1;       // 1 pour RB1
bool go =0;      // variable de contrôle



//Boucle sans fin
while( 1 )
{

       if (switchon == 0)
       {
               go = 1;
       }

       if (switchoff == 0)
       {
               go = 0;
               portd = 0b00000000;
       }


       if ( go )
       {
               portd = 0b00000001;
               delay_ms(100);
               portd = 0b00000011;
               delay_ms(10);
               portd = 0b00000010;
               delay_ms(100);
               portd = 0b00000110;
               delay_ms(10);
               portd = 0b00000100;
               delay_ms(100);
               portd = 0b00001100;
               delay_ms(10);
               portd = 0b00001000;
               delay_ms(100);
               portd = 0b00011000;
               delay_ms(10);
               portd = 0b00010000;
               delay_ms(100);
               portd = 0b00110000;
               delay_ms(10);
               portd = 0b00100000;
               delay_ms(100);
               portd = 0b01100000;

                                   - 20 -
delay_ms(10);
            portd = 0b01000000;
            delay_ms(100);
            portd = 0b11000000;
            delay_ms(10);
            portd = 0b10000000;
            delay_ms(100);
            portd = 0b11000000;
            delay_ms(10);
            portd = 0b01000000;
            delay_ms(100);
            portd = 0b01100000;
            delay_ms(10);
            portd = 0b00100000;
            delay_ms(100);
            portd = 0b00110000;
            delay_ms(10);
            portd = 0b00010000;
            delay_ms(100);
            portd = 0b00011000;
            delay_ms(10);
            portd = 0b00001000;
            delay_ms(100);
            portd = 0b00001100;
            delay_ms(10);
            portd = 0b00000100;
            delay_ms(100);
            portd = 0b00000110;
            delay_ms(10);
            portd = 0b00000010;
            delay_ms(100);
            portd = 0b00000011;
            delay_ms(10);
        }
    }
}




                              - 21 -
Analyse du programme :

Le programme ressemble, à quelques détails près, à celui de l’exemple précédent.

/Cible PIC16F877, bits de configuration
#pragma DATA _CONFIG, _PWRTE_OFF & _BODEN_OFF & _WDT_OFF &
_LVP_OFF & _CPD_OFF & _DEBUG_OFF & _XT_OSC & _CP_OFF

//Configuration de la fréquence d'horloge, ici 4Mhz
#pragma CLOCK_FREQ 4000000

Comme vous pouvez le constater, on a changé de quartz. De 20 MHz on est passé à
4 MHz. Pourquoi ? Pas de raison particulière, c’est uniquement dans un but
didactique. Si vous voulez conserver votre quartz 20 MHz, conservez les valeurs de
l’exemple précédent pour cette section.

//Configuration port B
       trisb = 0x03; // On configure les deux pins de poids faible en entrée

Les deux boutons poussoirs (« switchon » et « switchoff » sur le schéma) sont câblés
sur les pins du port B : RB0 et RB1. Dans l’exemple précédent, ces pins étaient
configurées en sortie. Il nous faut maintenant les configurer en entrée. Pour cela, on
met à 1 les bits correspondants du registre trisb, qui contrôle la direction du PORTB.
Ce qui nous donne, en binaire : 0b00000011, et donc, en hexadécimal : 0x03.

      volatile bit switchon@0x06.0;       // .0 pour RB0
      volatile bit switchoff@0x06.1;      // .1 pour RB1

On crée ici deux variables, « switchon » et « switchoff », de type « bit », donc codées
chacune sur 1 bit. Ces variables ne devront pas être placées n’importe où en
mémoire. Ce qu’on veut, c’est les associer aux bits correspondants aux pins RB0 et
RB1 du PORTB. On spécifie donc au compilateur l’adresse de ces variables. Par
exemple, pour switchon, « @0x06.0 », signifie « à l’adresse 0x06, le bit 0 ». 0x06
étant, bien entendu, l’adresse du PORTB. Le « .0 » spécifie le rang du bit, ici le bit de
poids 0, autrement dit RB0. Et pour switchoff, on procède de la même manière mais
en associant le bit « .1 », autrement dit RB1.
L’attribut « volatile » devrait surprendre les familiers du langage C. C’est un ajout de
BoostC au langage C ANSI standard, utilisé pour spécifier au compilateur que la
variable peut être modifiée en dehors du flot normal du programme. Imaginez, vous
venez de lire l’état d’une variable, vous ne l’avez pas modifiée, et voilà qu’elle
change d’état ! Incompréhensible. D’où l’attribut volatile. On avait jusqu’à présent les
variables « const » constantes, les variables standard modifiables par le programme,
et on a maintenant les variables « volatile » dont l’état peut changer en dehors du
programme.




                                          - 22 -
bool go =0;    // variable de contrôle

On crée une autre variable, « go », de type « bool » qui ne peut prendre que deux
états : vrai ou faux (1 ou 0). On ne spécifie pas d’adresse, c’est donc le compilateur
qui lui en attribuera une dans l’un des registre généraux de l’espace RAM. On
initialise cette variable à 0. Celle-ci servira de variable de contrôle, nous permettant
de valider ou non l’allumage des 8 leds.

              if (switchon == 0)
              {
                      go = 1;
              }

On introduit une condition de test. Si switchon est égal à 0, on attribue la valeur 1 à
la variable go. Si vous découvrez le langage C, remarquez ici la différence entre un
« = » qui permet d’attribuer une valeur et un « == » qui permet de tester une égalité.

              if (switchoff == 0)
              {
                      go = 0;
                      portd = 0b00000000;
              }

C’est au tour de switchoff d’être testé. S’il est égal à 0 (le bouton poussoir switchoff
est actionné et ramène le potentiel Vss sur RB1), on exécute la portion de code entre
accolades : on attribue la valeur 0 à la variable go, puis on met toutes les pins du
PORTD à 0 -> toutes les leds sont éteintes.

              if ( go )
              {
                      portd = 0b00000001;
                      delay_ms(100);
                      ...
                      ...
                      ...
              }

On teste enfin la variable « go ». Si elle est « vraie » (état =1), on exécute le code
entre accolades qui allume successivement les leds via le PORTD. Si elle est
« fausse » (état = 0) on recommence la boucle en testant switchon, puis switchoff,
puis à nouveau go, etc.



Compilation du programme et injection dans le PIC :

Rien de particulier ici. Procédez comme pour l’exemple précédent, et tout devrait
bien se passer.



                                          - 23 -
Tests

Vous pouvez alimenter votre circuit et… Rien !
Normal, vous n’avez pas encore appuyé sur switchon. Réparez cet oubli : un
magnifique effet de balayage anime à nouveau vos 8 leds.
Appuyez maintenant sur switchoff. Le balayage s’éteint, mais, pas tout de suite !
Uniquement à la fin du cycle de balayage des leds (eh oui, on doit attendre que le
programme repasse par le test de switchoff).


Conclusion :

Le contrôle du fonctionnement de notre chenillard par deux boutons poussoirs
marque incontestablement un progrès. Vous savez maintenant utiliser les ports I/O
du pic en entrée et en sortie, utiliser les résistances de pull-up du PORTB.
Cependant, le fonctionnement actuel ne nous satisfait pas pleinement. Ce qu’on
voudrait, c’est que le balayage s’éteigne tout de suite, dès qu’on appuie sur
switchoff. Pour remédier à cela, on pourrait introduire des tests de switchoff avant
chaque allumage de la led suivante, plutôt qu’une seule fois avant de dérouler toute
la séquence. On pourrait également remplacer la séquence par une fonction
exécutée en boucle, le test sur switchoff étant alors réalisé avant chaque itération.
Quoi qu’il en soit, nous allons passer à l’étape suivante : l’utilisation du mécanisme
d’interruption sur changement d’état du PORTB.




                                         - 24 -
Le PORTB et les interruptions


Principe de fonctionnement :

Le port B possède une caractéristique particulièrement intéressante : au même titre
que certains autres modules périphériques du PIC, il a la possibilité de générer des
interruptions.
Pour mémoire, le principe de fonctionnement des interruptions est le suivant : à un
moment donné (aléatoire), un événement particulier déclenche une interruption
(débordement d’un compteur, fin de conversion analogique numérique…).
L’exécution normale et linéaire du programme est interrompue, et le PIC se branche
sur une portion de code particulière : la routine d’interruption. Celle-ci exécute alors
un traitement particulier en réponse à l’événement déclencheur de l’interruption.
Puis, on sort de la routine d’interruption et on retourne à l’exécution normale du
programme.
Pour gérer ce mécanisme, il faut : valider dans le programme la ou les sources
d’interruption, et écrire une routine d’interruption appropriée.
Le contrôle des interruptions se fait grâce aux registres INTCON, PIE1, PIR1, PIE2,
PIR2. Le registre INTCON regroupe les bits de validation (= enable bit) et de
signalisation (= flag ou drapeau) des interruptions « de base ». Les interruptions des
modules périphériques sont gérées par les registres PIE et PIR. Sur le PIC 16F877
on a deux PIE et deux PIR, étant donné le nombre important de sources
d’interruptions possibles.
Avec BoostC, la routine d’interruption prend la forme d’une fonction particulière,
intitulée « interrupt ».
Dans l’exemple suivant, on va utiliser une interruption générée par le PORTB pour
contrôler la vitesse de défilement des 8 leds contrôlées par le PORTD. L’interruption
sur changement d’état du PORTB est générée dès qu’un changement d’état est
détecté sur une des pin RB4, RB5, RB6, ou RB7. Dans notre cas, ce sera RB4.




                                          - 25 -
Le matériel :




                        1                 40
                        2                 39
                        3                 38
                        4                 37
                        5                 36
                        6                 35
                        7                 34
                             PIC 16F877


                        8                 33
                        9                 32
                        10                31
                        11                30
                        12                29
                        13                28                   switchint
                        14                27
                        15                26
                        16                25
                        17                24
                        18                23
                        19                22
                        20                21




Pour cet exemple, pas de grand changement : on se contente de câbler un bouton
poussoir supplémentaire sur la pin RB4 (la patte n°37 du PIC 16F877). On appelle ce
poussoir « switchint ».




                                               - 26 -
Le programme :

#include <system.h>

//Cible PIC16F877, bits de configuration
#pragma DATA _CONFIG, _PWRTE_OFF & _BODEN_OFF & _WDT_OFF &
_LVP_OFF & _CPD_OFF & _DEBUG_OFF & _XT_OSC & _CP_OFF

//Configuration de la fréquence d'horloge, ici 4Mhz
#pragma CLOCK_FREQ 4000000

//***********************************************************************************************
        volatile bit switchint@0x06.4;          // 4 pour RB4
        int i;                 // variable utilisée comme compteur dans une boucle "for"
        bool speed=1;                  // variable "mémoire"

//***********************************************************************************************
void interrupt( void )         //routine de gestion des interruptions
{
        if (intcon & 0b00000001)
        {
        delay_ms(10);          // attente de 10 ms, pour éviter les rebonds du contact

               if (switchint == 0)         // on teste si RB4 est maintenu à l'état bas.
               {
                       speed = !speed;     // inverse l'état de la variable speed
               }
               //portb = portb;      //lecture du portb pour supprimer le mismatch.
               clear_bit( intcon, RBIF); //On efface le bit drapeau de l'interruption
        }
}
//***********************************************************************************************
void leds(void)                // fonction allumant successivement les leds
{
                portd = 0b00000001;
                       if (speed == 0)
                       {
                               delay_ms(50);
                       }
                       delay_ms(50);

               for ( i=0; i<8; i++ )
               {
                       portd = portd << 0b00000001;
                       if (speed == 0)
                       {
                               delay_ms(50);
                       }
                       delay_ms(50);

                                              - 27 -
}
}

//***********************************************************************************************
void main( void )
{

       //Initialisation port A
       porta = 0x00;
       //Initialisation port B
       portb = 0x00;
       //Initialisation port C
       portc = 0x00;
       //Initialisation port D
       portd = 0x00;
       //Initialisation port E
       porte = 0x00;


       //Configuration port A
       trisa = 0x00;
       //Configuration port B
       trisb = 0x10; // On configure la pin RB4 en entrée (0x10            0b00010000)
       //Configuration port C
       trisc = 0x00;
       //Configuration port D
       trisd = 0x00;
       //Configuration port E
       trise = 0x00;

       //Configuration A/D pins
       adcon1 = 0x06;

       //Validation des résistances de pull-ups du port B
       clear_bit( option_reg, NOT_RBPU );

       //désactivation (temporaire) du mécanisme de gestion des interruptions
       clear_bit( intcon, GIE );

       //mise à 0 flags + désactivation toutes interruptions sauf interruption sur
       //changement PORTB
       intcon = 0b00001000; // on efface les flags, et on valide le bit RBIE : bit de
                               validation d'interruption sur changement du PORTB

       //validation des interruptions :
       set_bit(intcon, GIE );




                                              - 28 -
//Boucle sans fin
      while( 1 )
      {
             leds();
      }
}




Analyse du programme :

Notre programme nous permet de faire défiler les 8 leds contrôlées par le PORTD :
Contrairement aux exemples précédents où on effectuait un « va et vient » avec un
effet de fondu, les leds sont allumées successivement l’une après l’autre. Puis on
recommence.
Deux vitesses de défilement sont possibles. On passe de l’une à l’autre en
actionnant le bouton poussoir « switchint ».


#include <system.h>

//Cible PIC16F877, bits de configuration
#pragma DATA _CONFIG, _PWRTE_OFF & _BODEN_OFF & _WDT_OFF &
_LVP_OFF & _CPD_OFF & _DEBUG_OFF & _XT_OSC & _CP_OFF

//Configuration de la fréquence d'horloge, ici 4Mhz
#pragma CLOCK_FREQ 4000000

Même séquence d’initialisation qu’à l’exemple précédent : on inclut le fichier
system.h, on configure les bits de configuration, et on indique la fréquence d’horloge.

      volatile bit switchint@0x06.4;         // 4 pour RB4
      int i;                // variable utilisée comme compteur dans une boucle "for"
      bool speed=1;                 // variable "mémoire"

On déclare ensuite les variables utilisées dans le programme :
« switchint » qui est une variable de type « bit », affectée à la pin RB4 du PORTB,
« i » qui est une variable de type « int » qui nous servira à compter les itérations
d’une boucle « for », et « speed », variable booléenne (qui ne peut donc valoir que 0
ou 1) qui nous permettra de contrôler les temporisations entre l’allumage des leds et
donc, la vitesse du défilement.




                                         - 29 -
void interrupt( void )     //routine de gestion des interruptions
{
       if (intcon & 0b00000001)
       {
       delay_ms(10);       // attente de 10 ms, pour éviter les rebonds du contact

              if (switchint == 0)         // on teste si RB4 est maintenu à l'état bas.
              {
                      speed = !speed;     // inverse l'état de la variable speed
              }
              //portb = portb;      //lecture du portb pour supprimer le mismatch.
              clear_bit( intcon, RBIF); //On efface le bit drapeau de l'interruption
       }
}

Voici donc la fameuse routine d’interruption ! Il s’agit d’une fonction spéciale chargée
du traitement des interruptions. Pas besoin de l’appeler dans le corps du programme
(contenu dans la fonction main() ), elle sera exécutée automatiquement lorsqu’une
source d’interruption valide se manifestera. Son nom est figé, donc si vous la
remplacez par une fonction « void interruption( void ) », ça ne marchera pas !
SourceBoost ne reconnaitrait pas qu’il s’agit là de la routine de traitement des
interruptions. Quelle que soit la source d’interruption, la fonction interrupt() sera
appelée. Donc, si vous avez plusieurs sources d’interruptions possibles, il faudra
tester quelle est l’origine, afin d’exécuter le traitement adéquat.
C’est ce qu’on fait ici avec l’instruction « if (intcon & 0b00000001) » : on fait un ET
logique entre le registre INTCON et la valeur binaire 0b00000001. Si le bit de poids 0
du registre INCON est égal à 1, le résultat vaudra 1 et la portion de code suivant le
test « if » sera exécutée. Le bit de poids 0 d’INTCON n’est autre que RBIF, bit
« drapeau » de signalisation de l’interruption sur changement du port PORTB.
On aurait pu ici se passer de ce test, étant donné qu’on a qu’une seule source
d’interruption dans notre exemple.
Vient ensuite une temporisation de 10 millisecondes (delay_ms(10) ) qui nous permet
de nous affranchir des rebonds du contact de switchint. Sans cela, ces rebonds
généreraient une multitude d’interruptions successives.
Puis, on test la valeur de switchint, le traitement effectif n’ayant lieu que s’il est à 0,
autrement dit si le bouton poussoir est appuyé. Je dois vous faire remarquer ici que
contre le PIC, vous n’avez aucune chance : il est beaucoup plus rapide que vous !
Une interruption sera générée lorsque vous appuierez sur switchint, mais aussi
lorsque vous le relâcherez ! Mais dans ce dernier cas, switchint sera égal à 1, et le
traitement sera ignoré : la condition du « if » sera fausse.
Vient ensuite le code utile du traitement de notre interruption : on inverse l’état de la
variable « speed » grâce à l’opérateur « ! » (lire « NOT ») qui complémente
l’opérande située à sa droite. Ainsi, « speed » devient égal à l’inverse de « speed ».
Pour mémoire, j’ai mis en commentaire l’instruction « portb = portb ». Pourquoi ? Il
faut savoir ici que l’interruption est générée lorsque l’état physique d’une pin du
PORTB est différent de l’état mémorisé dans son tampon de réception. On a alors un
« mismatch », autrement dit un décalage. Pour supprimer ce décalage, il faut
effectuer une opération de lecture du PORTB pour « réaligner » l’état théorique et
l’état physique du port. Dans notre cas, une lecture de la variable switchint provoque
la lecture du port, c’est donc déjà fait. Mais dans l’hypothèse ou votre code de

                                          - 30 -
traitement de l’interruption n’accéderait pas au PORTB, il faudrait effectuer cette
lecture. Sans quoi, à peine sorti de la routine d’interruption, on y retournerait, le
« mismatch » étant toujours présent !
On efface enfin le bit de signalisation d’interruption, RBIF (poRt B Interrupt Flag bit)
grâce à l’instruction « clear_bit(intcon, RBIF) ».

void leds(void)             // fonction allumant successivement les leds
{
              portd = 0b00000001;
                     if (speed == 0)
                     {
                            delay_ms(50);
                     }
                     delay_ms(50);

              for ( i=0; i<8; i++ )
              {
                      portd = portd << 0b00000001;
                      if (speed == 0)
                      {
                              delay_ms(50);
                      }
                      delay_ms(50);

              }
}

Contrairement aux exemples précédents, le code chargé d’allumer successivement
les leds est regroupé dans une fonction, appelée « leds ». Le « void » à gauche
signifie qu’on ne retourne aucune valeur, alors que le void entre parenthèses indique
qu’on ne prend aucune valeur en argument.
On allume notre première led sur RD0 grâce à l’instruction « portd = 0b00000001 ;
Puis, on test la variable « speed ». En fonction du résultat, soit on exécute une
première temporisation de 50 millisecondes suivie d’une deuxième temporisation de
50ms, soit on exécute uniquement la deuxième temporisation.
Puis on entre dans la boucle for, qui utilise la variable « i » comme compteur.
Dans cette boucle, exécutée 7 fois, on commence par effectuer un décalage à l’aide
de l’instruction « portd = portd << 0b00000001 ; ». La traduction en français de cette
instruction donne quelque chose du genre « portd est égal à portd décalé d’un bit
vers la gauche ». L’opérateur de décalage étant << .
Puis, on retrouve nos deux temporisations dont la première est conditionnée à la
valeur de « speed ».




                                          - 31 -
void main( void )
{

      //Initialisation port A
      porta = 0x00;
      //Initialisation port B
      portb = 0x00;
      //Initialisation port C
      portc = 0x00;
      //Initialisation port D
      portd = 0x00;
      //Initialisation port E
      porte = 0x00;


      //Configuration port A
      trisa = 0x00;
      //Configuration port B
      trisb = 0x10; // On configure la pin RB4 en entrée (0x10     0b00010000)
      //Configuration port C
      trisc = 0x00;
      //Configuration port D
      trisd = 0x00;
      //Configuration port E
      trise = 0x00;

      //Configuration A/D pins
      adcon1 = 0x06;

      //Validation des résistances de pull-ups du port B
      clear_bit( option_reg, NOT_RBPU );


On entre ensuite dans le corps du programme (la fonction « main »), la seule
différence par rapport à l’exemple précédent étant la valeur affectée au registre
« trisb » : seule la pin RB4 est configurée en entrée.




                                         - 32 -
//désactivation (temporaire) du mécanisme de gestion des interruptions
       clear_bit( intcon, GIE );

       //mise à 0 flags + désactivation toutes interruptions sauf interruption sur
       //changement PORTB
       intcon = 0b00001000; // on efface les flags, et on valide le bit RBIE : bit de
                               validation d'interruption sur changement du PORTB

       //validation des interruptions :
       set_bit(intcon, GIE );


Viens ensuite la partie configuration du mécanisme d’interruption. J’aurais pu faire
plus simple et remplacer les trois instructions par une seule, mais je préfère procéder
comme suis :
1 – désactivation globale des interruptions avec l’instruction « clear_bit( intcon,
GIE) » qui efface le bit GIE du registre INTCON.
2 – effacement des bits « drapeaux » de signalisation d’interruption éventuellement
positionnés, et configuration de la source d’interruption : pour valider l’interruption sur
changement d’état du PORTB, on met à 1 le bit RBIE.
3 – activation globale des interruptions avec l’instruction « set_bit( intcon, GIE) » qui
met à 1 le bit GIE (Global Interrupt Enable) du registre INTCON. A partir de là, c’est
parti : si vous appuyez sur switchint, le PIC exécutera la fonction « interrupt ».

       //Boucle sans fin
       while( 1 )
       {
              leds();
       }

Puis vient enfin, comme dans les exemples précédents, une boucle sans fin qui se
contente d’appeler la fonction « leds() » définie précédemment.




                                           - 33 -
Tests

Après avoir compilé et transféré votre programme comme précédemment, vous
pouvez alimenter le montage : les leds se mettent à défiler l’une après l’autre, sans
fin. Une pression sur le bouton poussoir switchint fait passer la vitesse de défilement
de rapide à lente. Une nouvelle pression sur switchint et la vitesse de défilement
repasse de lente à rapide. Autrement dit, ça marche : une pression sur le bouton
poussoir switchint lance bien la routine d’interruption, et celle-ci inverse effectivement
la variable booléenne « speed ».
Trop fort, non ?


Conclusion :
Vous connaissez maintenant le mécanisme de base de gestion des interruptions.
Les bits de validation (RBIE) et de signalisation (RBIF) de l’interruption sur
changement du PORTB étant présents dans le registre INTCON, nous n’avons pas
eu pour l’instant à nous préoccuper des registres PIE1, PIR1, PIE2, PIR2.
Mine de rien, notre dernier exemple nous a fait passer d’une programmation
« séquentielle », où toutes les actions étaient effectuées dans l’ordre, l’une à la suite
de l’autre, à une programmation « événementielle » capable de prendre en compte
un événement à tout moment du déroulement du programme.
Autrement dit : on devient bons !




                                          - 34 -

More Related Content

What's hot

Micocontroleur16 fxxx (1)
Micocontroleur16 fxxx (1)Micocontroleur16 fxxx (1)
Micocontroleur16 fxxx (1)Karim Touati
 
Microcontroleur Pic16 F84
Microcontroleur Pic16 F84Microcontroleur Pic16 F84
Microcontroleur Pic16 F84guest1e7b02
 
Afficheur 7 segments
Afficheur 7 segmentsAfficheur 7 segments
Afficheur 7 segmentsMaha Achouri
 
Microcontrôleur PIC Microchip part1/2
Microcontrôleur PIC Microchip part1/2Microcontrôleur PIC Microchip part1/2
Microcontrôleur PIC Microchip part1/2Mohammed Lamghari
 
Microcontrôleur PIC Microchip part2/2
Microcontrôleur PIC Microchip part2/2Microcontrôleur PIC Microchip part2/2
Microcontrôleur PIC Microchip part2/2Mohammed Lamghari
 
Catalogues produits 03: électroniques de pesage - transmetteurs de poids & in...
Catalogues produits 03: électroniques de pesage - transmetteurs de poids & in...Catalogues produits 03: électroniques de pesage - transmetteurs de poids & in...
Catalogues produits 03: électroniques de pesage - transmetteurs de poids & in...LAUMAS
 
Généralités sur les périphériques du STM32
Généralités sur les périphériques du STM32Généralités sur les périphériques du STM32
Généralités sur les périphériques du STM32Hajer Dahech
 
Cours reseau ouya
Cours reseau ouyaCours reseau ouya
Cours reseau ouyaYaya Diako
 
Généralités sur les microcontrôleurs et PicBasic
Généralités sur les microcontrôleurs et PicBasicGénéralités sur les microcontrôleurs et PicBasic
Généralités sur les microcontrôleurs et PicBasicmorin moli
 
Rapport Projet ENSMM - programmation sur microcontrôleur
Rapport Projet ENSMM - programmation sur microcontrôleurRapport Projet ENSMM - programmation sur microcontrôleur
Rapport Projet ENSMM - programmation sur microcontrôleurYanis Marchand
 
Lecture sécurisée des données de CAN J1939 et J1708, contrôle de la consommat...
Lecture sécurisée des données de CAN J1939 et J1708, contrôle de la consommat...Lecture sécurisée des données de CAN J1939 et J1708, contrôle de la consommat...
Lecture sécurisée des données de CAN J1939 et J1708, contrôle de la consommat...Technoton
 
Outils d'analyse et d'affichage des données du bus CAN J1939 et FMS. Webinair...
Outils d'analyse et d'affichage des données du bus CAN J1939 et FMS. Webinair...Outils d'analyse et d'affichage des données du bus CAN J1939 et FMS. Webinair...
Outils d'analyse et d'affichage des données du bus CAN J1939 et FMS. Webinair...Technoton
 
Supervision Postes Moyenne Tension
Supervision Postes Moyenne TensionSupervision Postes Moyenne Tension
Supervision Postes Moyenne TensionKarim Hassaouan
 

What's hot (20)

Cours pics16 f877
Cours pics16 f877Cours pics16 f877
Cours pics16 f877
 
Micocontroleur16 fxxx (1)
Micocontroleur16 fxxx (1)Micocontroleur16 fxxx (1)
Micocontroleur16 fxxx (1)
 
Microcontroleurs
MicrocontroleursMicrocontroleurs
Microcontroleurs
 
Microcontroleur Pic16 F84
Microcontroleur Pic16 F84Microcontroleur Pic16 F84
Microcontroleur Pic16 F84
 
Afficheur 7 segments
Afficheur 7 segmentsAfficheur 7 segments
Afficheur 7 segments
 
Microcontrôleur PIC Microchip part1/2
Microcontrôleur PIC Microchip part1/2Microcontrôleur PIC Microchip part1/2
Microcontrôleur PIC Microchip part1/2
 
Microcontrôleur PIC Microchip part2/2
Microcontrôleur PIC Microchip part2/2Microcontrôleur PIC Microchip part2/2
Microcontrôleur PIC Microchip part2/2
 
Catalogues produits 03: électroniques de pesage - transmetteurs de poids & in...
Catalogues produits 03: électroniques de pesage - transmetteurs de poids & in...Catalogues produits 03: électroniques de pesage - transmetteurs de poids & in...
Catalogues produits 03: électroniques de pesage - transmetteurs de poids & in...
 
Généralités sur les périphériques du STM32
Généralités sur les périphériques du STM32Généralités sur les périphériques du STM32
Généralités sur les périphériques du STM32
 
Cours reseau ouya
Cours reseau ouyaCours reseau ouya
Cours reseau ouya
 
T ps dsp
T ps dspT ps dsp
T ps dsp
 
Généralités sur les microcontrôleurs et PicBasic
Généralités sur les microcontrôleurs et PicBasicGénéralités sur les microcontrôleurs et PicBasic
Généralités sur les microcontrôleurs et PicBasic
 
Rapport Projet ENSMM - programmation sur microcontrôleur
Rapport Projet ENSMM - programmation sur microcontrôleurRapport Projet ENSMM - programmation sur microcontrôleur
Rapport Projet ENSMM - programmation sur microcontrôleur
 
Exam IIA5 INSAT 2018
Exam IIA5 INSAT  2018Exam IIA5 INSAT  2018
Exam IIA5 INSAT 2018
 
Le grafcet
Le grafcet Le grafcet
Le grafcet
 
Microcontroleur
MicrocontroleurMicrocontroleur
Microcontroleur
 
Lecture sécurisée des données de CAN J1939 et J1708, contrôle de la consommat...
Lecture sécurisée des données de CAN J1939 et J1708, contrôle de la consommat...Lecture sécurisée des données de CAN J1939 et J1708, contrôle de la consommat...
Lecture sécurisée des données de CAN J1939 et J1708, contrôle de la consommat...
 
Outils d'analyse et d'affichage des données du bus CAN J1939 et FMS. Webinair...
Outils d'analyse et d'affichage des données du bus CAN J1939 et FMS. Webinair...Outils d'analyse et d'affichage des données du bus CAN J1939 et FMS. Webinair...
Outils d'analyse et d'affichage des données du bus CAN J1939 et FMS. Webinair...
 
Supervision Postes Moyenne Tension
Supervision Postes Moyenne TensionSupervision Postes Moyenne Tension
Supervision Postes Moyenne Tension
 
Final
FinalFinal
Final
 

Viewers also liked

Architecture du microprocesseur
Architecture du microprocesseurArchitecture du microprocesseur
Architecture du microprocesseurOndernemersschool
 
Cours microcontroleur 8051 v1.1
Cours microcontroleur 8051 v1.1Cours microcontroleur 8051 v1.1
Cours microcontroleur 8051 v1.1Jack Ilboudo
 
Le Micro Processeur
Le Micro ProcesseurLe Micro Processeur
Le Micro Processeurrazman
 
Logiques sequentielle
Logiques sequentielleLogiques sequentielle
Logiques sequentielleAbdelAm20
 
Cours technologie electrique pneumatique
Cours technologie electrique   pneumatiqueCours technologie electrique   pneumatique
Cours technologie electrique pneumatiqueSalah Hammami
 
Tp transcodage logique combinatoire
Tp transcodage logique combinatoireTp transcodage logique combinatoire
Tp transcodage logique combinatoirebilal001
 
Circuits Base Hydraulique
Circuits Base HydrauliqueCircuits Base Hydraulique
Circuits Base Hydrauliqueyouri59490
 
Café Numérique Bruxelles - Les Makers - Arduino
Café Numérique Bruxelles - Les Makers - ArduinoCafé Numérique Bruxelles - Les Makers - Arduino
Café Numérique Bruxelles - Les Makers - ArduinoQuentin Geluyckens
 
Exos de logique séquentielle
Exos de logique séquentielleExos de logique séquentielle
Exos de logique séquentielleMo Ur Ad Es-se
 
TP Compteurs - logique combinatoire
TP Compteurs - logique combinatoire TP Compteurs - logique combinatoire
TP Compteurs - logique combinatoire bilal001
 
TP Les bascules - logique combinatoire
TP Les bascules - logique combinatoire TP Les bascules - logique combinatoire
TP Les bascules - logique combinatoire bilal001
 
ARDUINO + LABVIEW : CONTRÔLE DE LA TEMPÉRATURE
ARDUINO + LABVIEW : CONTRÔLE DE LA TEMPÉRATUREARDUINO + LABVIEW : CONTRÔLE DE LA TEMPÉRATURE
ARDUINO + LABVIEW : CONTRÔLE DE LA TEMPÉRATUREHajer Dahech
 
Api cours
Api coursApi cours
Api coursBel Ami
 
PFE Réalisation d’un onduleur monophasé autonome commandé par PIC 16F877
PFE Réalisation d’un onduleur monophasé autonome commandé par PIC 16F877PFE Réalisation d’un onduleur monophasé autonome commandé par PIC 16F877
PFE Réalisation d’un onduleur monophasé autonome commandé par PIC 16F877RAMZI EL IDRISSI
 
Architecture of 8051 microcontroller))
Architecture of 8051 microcontroller))Architecture of 8051 microcontroller))
Architecture of 8051 microcontroller))Ganesh Ram
 

Viewers also liked (20)

Architecture du microprocesseur
Architecture du microprocesseurArchitecture du microprocesseur
Architecture du microprocesseur
 
Cours microcontroleur 8051 v1.1
Cours microcontroleur 8051 v1.1Cours microcontroleur 8051 v1.1
Cours microcontroleur 8051 v1.1
 
mourad 2eme
mourad 2ememourad 2eme
mourad 2eme
 
Le Micro Processeur
Le Micro ProcesseurLe Micro Processeur
Le Micro Processeur
 
Cours de c
Cours de cCours de c
Cours de c
 
Logiques sequentielle
Logiques sequentielleLogiques sequentielle
Logiques sequentielle
 
Compteur ARDUINO
Compteur ARDUINOCompteur ARDUINO
Compteur ARDUINO
 
Compteur synchrone
Compteur synchroneCompteur synchrone
Compteur synchrone
 
Pic16f84
Pic16f84Pic16f84
Pic16f84
 
Cours technologie electrique pneumatique
Cours technologie electrique   pneumatiqueCours technologie electrique   pneumatique
Cours technologie electrique pneumatique
 
Tp transcodage logique combinatoire
Tp transcodage logique combinatoireTp transcodage logique combinatoire
Tp transcodage logique combinatoire
 
Circuits Base Hydraulique
Circuits Base HydrauliqueCircuits Base Hydraulique
Circuits Base Hydraulique
 
Café Numérique Bruxelles - Les Makers - Arduino
Café Numérique Bruxelles - Les Makers - ArduinoCafé Numérique Bruxelles - Les Makers - Arduino
Café Numérique Bruxelles - Les Makers - Arduino
 
Exos de logique séquentielle
Exos de logique séquentielleExos de logique séquentielle
Exos de logique séquentielle
 
TP Compteurs - logique combinatoire
TP Compteurs - logique combinatoire TP Compteurs - logique combinatoire
TP Compteurs - logique combinatoire
 
TP Les bascules - logique combinatoire
TP Les bascules - logique combinatoire TP Les bascules - logique combinatoire
TP Les bascules - logique combinatoire
 
ARDUINO + LABVIEW : CONTRÔLE DE LA TEMPÉRATURE
ARDUINO + LABVIEW : CONTRÔLE DE LA TEMPÉRATUREARDUINO + LABVIEW : CONTRÔLE DE LA TEMPÉRATURE
ARDUINO + LABVIEW : CONTRÔLE DE LA TEMPÉRATURE
 
Api cours
Api coursApi cours
Api cours
 
PFE Réalisation d’un onduleur monophasé autonome commandé par PIC 16F877
PFE Réalisation d’un onduleur monophasé autonome commandé par PIC 16F877PFE Réalisation d’un onduleur monophasé autonome commandé par PIC 16F877
PFE Réalisation d’un onduleur monophasé autonome commandé par PIC 16F877
 
Architecture of 8051 microcontroller))
Architecture of 8051 microcontroller))Architecture of 8051 microcontroller))
Architecture of 8051 microcontroller))
 

Similar to Programmation des pic_en_c_part2

1086178403 nights2004 2
1086178403 nights2004 21086178403 nights2004 2
1086178403 nights2004 2hoat6061
 
Rapportpfanidbelkacem 140305043828-phpapp01
Rapportpfanidbelkacem 140305043828-phpapp01Rapportpfanidbelkacem 140305043828-phpapp01
Rapportpfanidbelkacem 140305043828-phpapp01bessem ellili
 
Suivi de cohortes, BPJEPS kite, 2011
Suivi de cohortes, BPJEPS kite, 2011Suivi de cohortes, BPJEPS kite, 2011
Suivi de cohortes, BPJEPS kite, 2011michel_parratte
 
Suivi de cohortes BPJEPS glisses aérotractées, 2011
Suivi de cohortes BPJEPS glisses aérotractées, 2011Suivi de cohortes BPJEPS glisses aérotractées, 2011
Suivi de cohortes BPJEPS glisses aérotractées, 2011michel_parratte
 
Mahdi smida rapport master 2 Calcul Haute performance et simulation
Mahdi smida rapport master 2 Calcul Haute performance et simulationMahdi smida rapport master 2 Calcul Haute performance et simulation
Mahdi smida rapport master 2 Calcul Haute performance et simulationMahdi Smida ✔
 
Schindler (manual del miconic bx)
Schindler (manual del miconic bx)Schindler (manual del miconic bx)
Schindler (manual del miconic bx)JosRodriguez149
 
Gestion de la batterie d'un micro-drone projet fin d'année NIDBELKACEM Mouhci...
Gestion de la batterie d'un micro-drone projet fin d'année NIDBELKACEM Mouhci...Gestion de la batterie d'un micro-drone projet fin d'année NIDBELKACEM Mouhci...
Gestion de la batterie d'un micro-drone projet fin d'année NIDBELKACEM Mouhci...Mouhcine Nid Belkacem
 
ETUDE ET REALISATION D’UN MICROPROCESSEURS RISC
ETUDE ET REALISATION D’UN MICROPROCESSEURS RISCETUDE ET REALISATION D’UN MICROPROCESSEURS RISC
ETUDE ET REALISATION D’UN MICROPROCESSEURS RISCVicheka Phor
 
Devoir+corrigé+de+synthèse+n°3+ +génie+mécanique+système+de+grénaillage+et+de...
Devoir+corrigé+de+synthèse+n°3+ +génie+mécanique+système+de+grénaillage+et+de...Devoir+corrigé+de+synthèse+n°3+ +génie+mécanique+système+de+grénaillage+et+de...
Devoir+corrigé+de+synthèse+n°3+ +génie+mécanique+système+de+grénaillage+et+de...Majda El Aouni
 
Gestion de la batterie d'un micro-drone projet fin d'année NIDBELKACEM Mouhci...
Gestion de la batterie d'un micro-drone projet fin d'année NIDBELKACEM Mouhci...Gestion de la batterie d'un micro-drone projet fin d'année NIDBELKACEM Mouhci...
Gestion de la batterie d'un micro-drone projet fin d'année NIDBELKACEM Mouhci...Mouhcine Nid Belkacem
 
Chapitre ii étude technique.docx
Chapitre ii  étude technique.docxChapitre ii  étude technique.docx
Chapitre ii étude technique.docxZouaouine Mahfoud
 

Similar to Programmation des pic_en_c_part2 (13)

1086178403 nights2004 2
1086178403 nights2004 21086178403 nights2004 2
1086178403 nights2004 2
 
Rapportpfanidbelkacem 140305043828-phpapp01
Rapportpfanidbelkacem 140305043828-phpapp01Rapportpfanidbelkacem 140305043828-phpapp01
Rapportpfanidbelkacem 140305043828-phpapp01
 
Suivi de cohortes, BPJEPS kite, 2011
Suivi de cohortes, BPJEPS kite, 2011Suivi de cohortes, BPJEPS kite, 2011
Suivi de cohortes, BPJEPS kite, 2011
 
Suivi de cohortes BPJEPS glisses aérotractées, 2011
Suivi de cohortes BPJEPS glisses aérotractées, 2011Suivi de cohortes BPJEPS glisses aérotractées, 2011
Suivi de cohortes BPJEPS glisses aérotractées, 2011
 
Mahdi smida rapport master 2 Calcul Haute performance et simulation
Mahdi smida rapport master 2 Calcul Haute performance et simulationMahdi smida rapport master 2 Calcul Haute performance et simulation
Mahdi smida rapport master 2 Calcul Haute performance et simulation
 
Schindler (manual del miconic bx)
Schindler (manual del miconic bx)Schindler (manual del miconic bx)
Schindler (manual del miconic bx)
 
Gestion de la batterie d'un micro-drone projet fin d'année NIDBELKACEM Mouhci...
Gestion de la batterie d'un micro-drone projet fin d'année NIDBELKACEM Mouhci...Gestion de la batterie d'un micro-drone projet fin d'année NIDBELKACEM Mouhci...
Gestion de la batterie d'un micro-drone projet fin d'année NIDBELKACEM Mouhci...
 
Rapport cimat
Rapport cimatRapport cimat
Rapport cimat
 
ETUDE ET REALISATION D’UN MICROPROCESSEURS RISC
ETUDE ET REALISATION D’UN MICROPROCESSEURS RISCETUDE ET REALISATION D’UN MICROPROCESSEURS RISC
ETUDE ET REALISATION D’UN MICROPROCESSEURS RISC
 
Devoir+corrigé+de+synthèse+n°3+ +génie+mécanique+système+de+grénaillage+et+de...
Devoir+corrigé+de+synthèse+n°3+ +génie+mécanique+système+de+grénaillage+et+de...Devoir+corrigé+de+synthèse+n°3+ +génie+mécanique+système+de+grénaillage+et+de...
Devoir+corrigé+de+synthèse+n°3+ +génie+mécanique+système+de+grénaillage+et+de...
 
Matlab for engineer
Matlab for engineer Matlab for engineer
Matlab for engineer
 
Gestion de la batterie d'un micro-drone projet fin d'année NIDBELKACEM Mouhci...
Gestion de la batterie d'un micro-drone projet fin d'année NIDBELKACEM Mouhci...Gestion de la batterie d'un micro-drone projet fin d'année NIDBELKACEM Mouhci...
Gestion de la batterie d'un micro-drone projet fin d'année NIDBELKACEM Mouhci...
 
Chapitre ii étude technique.docx
Chapitre ii  étude technique.docxChapitre ii  étude technique.docx
Chapitre ii étude technique.docx
 

Programmation des pic_en_c_part2

  • 1. Programmation des PIC en C Microcontrôleur facile pour électronicien amateur PARTIE 2 Noxyben 2008 www.noxyben.fr -1-
  • 2. Introduction ................................................................................................................................ 3 Le schéma de base...................................................................................................................... 4 Principe de fonctionnement des ports I/O .................................................................................. 7 Utilisation des ports d’entrée/sortie (I/O)................................................................................... 8 Utilisation d’un PORT en sortie : un chenillard 8 leds .......................................................... 8 Le matériel : ....................................................................................................................... 8 Le programme : ................................................................................................................ 10 Analyse du programme : .................................................................................................. 12 Compilation du programme et injection dans le PIC : ..................................................... 16 Tests ................................................................................................................................. 17 Conclusion :...................................................................................................................... 17 Utilisation d’un PORT en entrée : un chenillard 8 leds contrôlé par 2 boutons poussoirs. . 18 Le matériel : ..................................................................................................................... 18 Le programme : ................................................................................................................ 19 Analyse du programme : .................................................................................................. 22 Compilation du programme et injection dans le PIC : ..................................................... 23 Tests ................................................................................................................................. 24 Conclusion :...................................................................................................................... 24 Le PORTB et les interruptions ............................................................................................. 25 Principe de fonctionnement :............................................................................................ 25 Le matériel : ..................................................................................................................... 26 Le programme : ................................................................................................................ 27 Analyse du programme : .................................................................................................. 29 Tests ................................................................................................................................. 34 Conclusion :...................................................................................................................... 34 -2-
  • 3. Introduction Après avoir vu dans la première partie comment est structuré le PIC, on va enchaîner directement sur des montages concrets : rien de mieux pour apprendre et mémoriser que de faire soi-même un montage « en vrai ». Je vous invite chaleureusement à faire un tour chez votre marchand de composants électroniques et à faire chauffer votre fer à souder. Vous allez avoir besoin d’un PIC16F877, un programmateur, une platine d’essai du genre « pastilles pré-percées » au pas de 2,54 mm, et quelques composants qui traînent certainement dans vos fonds de tiroirs : Led, régulateur 7805, condensateurs, support 40 broches… Pour la partie logicielle il vous faudra télécharger la version de démonstration de SourceBoost, qui comprend le compilateur BoostC que nous allons employer, et éventuellement un logiciel de transfert comme Icprog pour piloter votre programmateur de PIC. Si vous avez acheté un programmateur en kit comme le Velleman K8076, le logiciel « PICPROG » est compris. Pensez à télécharger les mises à jour. -3-
  • 4. Le schéma de base IC2 D1 9V = 7805 R1 C3 C4 Led1 1 40 2 39 ICSP 3 38 4 37 5 36 6 35 7 34 PIC 16F877 8 33 C6 -4- 9 32 10 31 C5 11 30 12 29 13 28 14 27 15 26 C2 16 25 C1 17 24 Q1 18 23 19 22 20 21 IC1
  • 5. Le schéma ci-dessus est la base sur laquelle on va pouvoir construire des applications utiles. Il ne fait rien d’autre que de permettre au PIC de fonctionner, c’est en quelque sorte le « minimum vital ». Bien entendu, d’autres variantes sont possibles, mais plutôt que d’en dresser la liste exhaustive, je vous propose de réaliser cette version et de remettre à plus tard l’étude des différents circuits d’oscillateur, de reset… L’alimentation : Pour alimenter le circuit, une source continue d’environ 9V fera parfaitement l’affaire (une pile 9V par exemple). La régulation et l’adaptation à un niveau de 5V requis par le PIC incombent au régulateur 7805. Remarque : pour que celui-ci fonctionne correctement, la tension d’alimentation doit être supérieure d’au moins 2 ou 3 volts à la tension régulée, donc 5 + 2 = 7 Volts. La diode D1 protège le circuit contre les inversions accidentelles de polarité (diode type 1N4001 ou 1N4007 par exemple). Le condensateur C3 sert de « réservoir » au régulateur. La règle habituelle est de prendre 1000 F / Ampère. Dans notre cas, un condensateur électrochimique de 470 avec une tension d’au moins 16V convient parfaitement. Le condensateur C4 nous permet de découpler le régulateur du reste du circuit : il absorbe les variations de tension parasite qui pourraient remonter vers le régulateur. 10 ou 100 nF devraient convenir. Le couple R1 – Led1 sert de témoin de mise sous tension, et accessoirement décharge le condensateur C3 lorsque l’alimentation est coupée. Avec une tension d’alimentation de 9V, on prendra pour R1 une valeur de 390 1/4W Les condensateurs C5 et C6 quant à eux sont des condensateurs de découplage du PIC. À monter au plus près du 16F877, ils empêchent que d’éventuels parasites collectés par les lignes d’alimentation ne pénètrent dans le circuit intégré. Quelques pF ou nF du genre condensateur « tantale goutte » feront l’affaire. Surtout pas de gros condensateur électrochimique de plusieurs F qui aurait un effet néfaste sur le temps de montée de l’alimentation et pourrait ainsi perturber le PIC au moment du démarrage. L’oscillateur : Il est constitué de Q1, un quartz « parallèle » dont la fréquence d’oscillation nominale peut aller jusqu’à 20MHz, et des condensateurs C1 et C2 pour lequel on prendra une valeur de 20pF, conformément aux indications de la documentation de Microchip. -5-
  • 6. Le connecteur ICSP : Bien que n’étant pas indispensable, on va équiper notre platine de ce connecteur « In Circuit Serial Programming », qui nous permettra de programmer le PIC sans le retirer de son support. A vrai dire, le brochage n’est pas vraiment normalisé. Je vous propose donc la version suivante, que vous pourrez adapter à votre guise. Le seul impératif est que les bonnes lignes du programmateur aboutissent sur les bonnes pattes du PIC • patte 1 - 6 : Vpp (tension de programmation) • patte 2 - 7 : VDD (tension d’alimentation 5V) • patte 3 - 8 : PGD (Program Data = ligne de transfert des données) • patte 4 – 9 : Vss (tension de masse = 0V) • patte 5 - 10 : PGC (Program Clock = ligne d’horloge de programmation) 1 6 2 7 3 8 4 9 5 10 En fonctionnement normal, la pin 1 est pontée sur la pin 6, la pin 2 sur la 7, la 3 sur la 8, la 4 sur la 9 et la 5 sur la 10. Pour programmer le PIC on déconnecte l’alimentation du circuit, on ôte tous les ponts du connecteur ICSP et on branche à la place le cordon ICSP du programmateur, en veillant à ce que les signaux correspondent bien. Si ce n’est pas le cas, il vous faudra confectionner un cordon ad’ hoc en croisant les bonnes lignes. Le circuit de RESET : Rien de plus simple pour l’instant : la ligne de reset MCLR (la pin 1 du PIC) est simplement reliée à la tension d’alimentation. Ainsi, pour redémarrer le PIC, on coupe l’alimentation et on réalimente. -6-
  • 7. Principe de fonctionnement des ports I/O Les ports d’entrée / sortie numériques peuvent être considérés comme les périphériques les plus simples du microcontrôleur. Pour le PIC, on contrôle leur fonctionnement à l’aide de registres spéciaux (deux registres par port). Par exemple, pour le port A, on a le registre PORTA et le registre TRISA. Les registres « TRISx » contrôlent le mode de fonctionnement des entrées / sorties : selon la valeur de chaque bit, 0 ou 1, la pin correspondante du port fonctionnera soit en sortie, soit en entrée. Les registres « PORTx » contiennent les données, lues, ou à écrire sur le port. Certains ports possèdent en plus des fonctionnalités spécifiques : le PORTB est équipé de résistances de tirage (pull-up) internes qui peuvent être activées ou non. La pin RB0 du PORTB sert d’entrée d’interruption externe, et les pins RB4 à RB7 peuvent générer une interruption lorsqu’un changement d’état est détecté à leurs bornes. Toutes ces particularités sont bien entendu décrites dans les documentations Microchip spécifiques à chaque composant. -7-
  • 8. Utilisation des ports d’entrée/sortie (I/O) Utilisation d’un PORT en sortie : un chenillard 8 leds Le matériel : 1 40 2 39 3 38 4 37 VCC 5 36 6 35 R9 R8 R7 R6 R5 R4 R3 R2 7 34 PIC 16F877 8 33 9 32 10 31 11 30 Rd8 12 29 13 28 Rd8 14 27 15 26 Rd6 16 25 17 24 Rd5 18 23 19 22 Rd4 20 21 Rd3 Rd2 Rd1 On va rajouter les quelques composants du schéma ci-dessus à notre montage de base. Le but est de pouvoir commander 8 leds à travers les 8 lignes du PORTD. On pourrait raccorder les leds directement aux pins du PIC à travers des résistances appropriées, (ça marche aussi) mais au cas où l’idée vous viendrait d’allumer les 8 leds en même temps, le courant débité par le PORTD pourrait dépasser la valeur limite. En effet, un coup d’œil à la rubrique caractéristiques électriques du datasheet nous informe que le courant maximal pouvant être débité par un PORT est de 200 mA. Avec des résistances légèrement sous-dimensionnées et 8 leds allumées on pourrait s’en approcher dangereusement. Bon, c’est vrai, j’exagère un peu, même avec 8 x 20 mA on n’est encore qu’à 160mA de consommation sur le port. Mais autant adopter de bons réflexes dès le départ. On choisit donc de passer par des transistors. On pourra prendre des transistors petit signaux standard. Si vous trouvez dans vos tiroirs des BC537 ou 2N2222 ou quoi que ce soit d’équivalent, ça conviendra parfaitement. Pour les résistances R2 à R9, si on considère que le point de fonctionnement des leds est à environ 1,8V / 10 mA, et que VCC = 5 V : VRx = 5-1,8 = 3,2V ; donc R = VRx / I = 3,2 / 0.01 = 320. -8-
  • 9. La valeur normalisée la plus proche étant 330, on prendra donc pour les résistances R2 à R9 des 330 Ohms ¼ de Watt. Pour les résistances Rd1 à Rd8, afin d’assurer une bonne saturation des transistors, on prendra des résistances de 4,7 kOhms ¼ de Watt. -9-
  • 10. Le programme : On rentre enfin dans le vif du sujet. Afin de piloter notre montage avec un joli effet « K2000 », je vous propose le programme ci-dessous : #include <system.h> //Cible PIC16F877, bits de configuration #pragma DATA _CONFIG, _PWRTE_OFF & _BODEN_OFF & _WDT_OFF & _LVP_OFF & _CPD_OFF & _DEBUG_OFF & _HS_OSC & _CP_OFF //Configuration de la fréquence d'horloge, ici 20Mhz #pragma CLOCK_FREQ 20000000 void main( void ) { //Initialisation port A porta = 0x00; //Initialisation port B portb = 0x00; //Initialisation port C portc = 0x00; //Initialisation port D portd = 0x00; //Initialisation port E porte = 0x00; //Configuration port A trisa = 0x00; //Configuration port B trisb = 0x00; //Configuration port C trisc = 0x00; //Configuration port D trisd = 0x00; //Configuration port E trise = 0x00; //Configuration A/D pins adcon1 = 0x06; //désactivation du mécanisme de gestion des interruptions clear_bit( intcon, GIE ); - 10 -
  • 11. //Validation des résistances de pull-ups du port B clear_bit( option_reg, NOT_RBPU ); //Boucle sans fin while( 1 ) { portd = 0b00000001; delay_ms(100); portd = 0b00000011; delay_ms(10); portd = 0b00000010; delay_ms(100); portd = 0b00000110; delay_ms(10); portd = 0b00000100; delay_ms(100); portd = 0b00001100; delay_ms(10); portd = 0b00001000; delay_ms(100); portd = 0b00011000; delay_ms(10); portd = 0b00010000; delay_ms(100); portd = 0b00110000; delay_ms(10); portd = 0b00100000; delay_ms(100); portd = 0b01100000; delay_ms(10); portd = 0b01000000; delay_ms(100); portd = 0b11000000; delay_ms(10); portd = 0b10000000; delay_ms(100); portd = 0b11000000; delay_ms(10); portd = 0b01000000; delay_ms(100); portd = 0b01100000; delay_ms(10); portd = 0b00100000; delay_ms(100); portd = 0b00110000; delay_ms(10); portd = 0b00010000; delay_ms(100); portd = 0b00011000; delay_ms(10); portd = 0b00001000; - 11 -
  • 12. delay_ms(100); portd = 0b00001100; delay_ms(10); portd = 0b00000100; delay_ms(100); portd = 0b00000110; delay_ms(10); portd = 0b00000010; delay_ms(100); portd = 0b00000011; delay_ms(10); } } Analyse du programme : Étudions cela un peu plus en détails : #include <system.h> Cette directive indique au précompilateur d’inclure le fichier system.h. Celui-ci contient à son tour une inclusion pour le fichier spécifique à votre PIC (16F877.h), dans lequel sont indiquées les associations nom de registre / adresses mémoire. D’où l’importance de bien indiquer à BoostC la cible (ici 16F877) pour laquelle vous désirez compiler votre programme. #pragma DATA _CONFIG, _PWRTE_OFF & _BODEN_OFF & _WDT_OFF & _LVP_OFF & _CPD_OFF & _DEBUG_OFF & _HS_OSC & _CP_OFF Une autre directive de précompilation, qui permet de définir les bits de configuration du PIC. Pour mémoire, ces bits de configuration permettent de configurer un certain nombre de paramètres de fonctionnement du PIC. Bien heureusement, SourceBoost reprend à peu de chose près les mêmes désignations que Microchip : • PWRTE_OFF : désactive le Power-up Timer Enable bit • BODEN_OFF : désactive le Brown-Out reset Enable bit • WDT_OFF : désactive le Watch Dog Timer • LVP_OFF : désactive le Low Voltage Programming • CPD_OFF : désactive la protection de la mémoire de données EEPROM ? • DEBUG_OFF : désactive l’In-Circuit Debugger • HS_OSC : Configure l’oscillateur en mode HS (High Speed) • CP_OFF : désactive la protection du code Pour l’instant on désactive tout (OFF), à part bien sûr l’oscillateur qu’on configure en mode « HS », mode recommandé par Microchip pour l’emploi d’un quartz 20 MHz. Si vous utilisez un quartz 4 MHz, le mode le plus approprié sera « XT ». La différence réside entre HS et XT réside dans le gain de l’amplificateur inverseur du circuit d’oscillateur du PIC. Plus la fréquence de travail est élevée, plus le gain doit être - 12 -
  • 13. élevé. Mais dans la pratique, en mode « HS » et avec un quartz à 4 MHz, ça marche aussi. Pour savoir quel mode choisir, regardez dans la documentation Microchip sur la gamme des PIC « mid-range », ou mieux sur la documentation du 16F877 dans la section « oscillator ». #pragma CLOCK_FREQ 20000000 A nouveau une directive de précompilation. On indique ici quelle est la fréquence du quartz utilisé. Les temporisations générées par la fonction « delay » utilisée plus loin dans le programme sont basées sur cette valeur. void main( void ) { } La fonction « main » est obligatoire en langage C : c’est le « point d’entrée » du programme. Le «void» placé avant «main» indique que la fonction ne retourne aucune valeur, et le «void» entre parenthèses indique qu’on ne prend pas de valeur en argument. Tout le reste de notre programme viendra se placer entre les accolades ouvrante et fermante. //Initialisation port A porta = 0x00; //Initialisation port B portb = 0x00; //Initialisation port C portc = 0x00; //Initialisation port D portd = 0x00; //Initialisation port E porte = 0x00; Les variables porta, portb, portc, portd et porte sont affectées aux registres correspondant à l’état des Entrées/Sortie des ports. (respectivement le PORTA, PORTB, PORTC, PORTD, PORTE). Ces variables sont déclarées dans le fichier d’entête spécifique au PIC 16F877 (fichier avec l’extension « .h » ), lui-même inclus dans le fichier «system.h». Ainsi, vous pouvez accéder à un registre du PIC simplement en l’appelant par son nom, sans se soucier de son adresse. Écrire une donnée dans un de ces registres affectera dès-lors les pins correspondantes du PORT, si celles-ci sont configurées en sortie. Ici, on initialise tout à 0. - 13 -
  • 14. //Configuration port A trisa = 0x00; //Configuration port B trisb = 0x00; //Configuration port C trisc = 0x00; //Configuration port D trisd = 0x00; //Configuration port E trise = 0x00; Suivant le même principe que pour les registres porta, portb, portc… les variables trisa, trisb, trisc, trisd, trise sont affectées aux registres de contrôle de direction des ports (respectivement le PORTA, PORTB, PORTC, PORTD, PORTE). On affecte au cinq registres «tris» la valeur hexadécimale (d’où le «x» pour heXa) 00. Un coup d’œil aux fiches détaillées des registres correspondant nous montre que cette valeur 00 passe toutes les lignes d’Entrés/Sortie des ports en mode « sortie ». Une remarque : Microchip recommande de d’initialiser en premier lieu les registres « portx », et de configurer la direction avec les registres « trisx » ensuite. Pour éviter d’avoir un état incertain sur les pins au moment du démarrage. //Configuration A/D pins adcon1 = 0x06; Certaines pins des ports sont susceptibles d’être utilisée par le convertisseur Analogique / Numérique. Par défaut, (voir fiche détaillée du registre adcon1), les pins en question sont configurées en mode analogique. La valeur hexadécimale 0x06 les passe en mode numérique. //désactivation du mécanisme de gestion des interruptions clear_bit( intcon, GIE ); Le registre intcon contrôle le mécanisme d’interruption. «intcon» pour INTerrupt CONtrol. GIE, Global Interrupt Enable bit, est un des bits du registre intcon, il active ou désactive de manière globale toutes les interruptions. La fonction «clear_bit()» est une fonction implémentée par BoostC, permettant de mettre un bit à 0. Son pendant est la fonction «set_bit()» qui permet, elle de mettre un bit à 1. La syntaxe ci-dessus signifie donc : « mettre à 0 le bit GIE du registre intcon ». - 14 -
  • 15. //Validation des résistances de pull-ups du port B clear_bit( option_reg, NOT_RBPU ); Le registre option_reg contrôle certaines options du PIC, parmi lesquelles figure l’activation ou non des résistances de pull-up du PORTB. Le bit correspondant à cette option est NOT_RBPU. Celui-ci fonctionne en logique négative (d’où le NOT devant RBPU). La syntaxe ci-dessus signifie donc « mettre à 0 le bit NOT_RBPU du registre option_reg ». Or, étant donné que le bit NOT_RBPU fonctionne en logique négative, le mettre à 0 signifie ACTIVER les résistances de pull-up du PORTB ! Pour l’instant on ne se sert pas de ces résistances, donc vous pouvez, si vous préférez, mettre ce bit à 1 pour les désactiver. //Boucle sans fin while( 1 ) { } Comme l’indique le commentaire, il s’agit là d’une boucle sans fin. «While» est une instruction de contrôle de boucle du langage C. La traduction française donnerait : « tant que 1… ». Or, «1» n’a pas de raison de changer d’état, donc une fois lancée, on ne sort pas de cette boucle. Tout le code entre les accolades ouvrante et fermante se répètera dès lors indéfiniment. portd = 0b00000001; La variable «portd» est affectée au registre correspondant à l’état des Entrées/Sortie du PORTD. Ici, on écrit la donnée binaire (d’où le b de 0bxxxxxxxx) 0b00000001, ce qui a pour effet de passer la pin RD0 à l’état 1, alors que les pins RD1 à RD7 restent à l’état 0. delay_ms(100); La fonction «delay_ms()» est une fonction implémentée par BoostC, permettant d’introduire une temporisation. Ici, delay_ms(100) génère une temporisation de 100 millisecondes. Cette temporisation est calculée en fonction de la valeur de la fréquence d’horloge qu’on a indiquée plus en amont par la directive PRAGMA CLOCK_FREQ. - 15 -
  • 16. portd = 0b00000011; delay_ms(10); On « allume » une deuxième pin du PORTD, et on attend ensuite 10 millisecondes, avant de passer à la suite. Le principe utilisé ici est le suivant : on allume une led, on attend 100 ms, on allume une deuxième led, on attend 10 ms, on éteint la première led, on attend 100 ms, etc. L’allumage simultané de deux les n’est là que pour diminuer l’effet de saccade lors du passage d’une led à l’autre. Vous l’aurez remarqué : cette manière de faire est un peu « rustique », on aurait pu remplacer la répétition des instructions par des boucles bien construites. Mais d’un point de vue didactique ça me semble plus simple à comprendre, et comme on est loin d’avoir saturé la mémoire du PIC… Compilation du programme et injection dans le PIC : Après l’étude théorique, il ne reste plus qu’à compiler notre programme et l’injecter dans le PIC. Pour cela, on va suivre les étapes suivantes : COMPILATION : • Lancez l’IDE de SourceBoost. • Assurer vous que le compilateur utilisé est bien BoostC (dans le menu paramètres). • Créez un nouveau projet (menu Projet : Nouveau). • Dans ce projet, créez un nouveau fichier (menu Fichier : Nouveau) dans lequel vous allez copier le code ci-dessus. • Sélectionnez la « cible », autrement dit le composant pour lequel vous voulez compiler le projet : PIC 16F877 (menu Paramètres : Cible) • Compilez le programme (menu Construction : Construire) • Si tout s’est bien passé, le compilateur indique « success » et a généré dans le répertoire de votre projet plusieurs fichiers. L’un d’entre eux a une extension en «.hex». TRANSFERT (avec un programmateur Velleman K8076) : • Configurez le programmateur pour le 16F877 (il faut que les « ponts » aboutissent sur les bonnes pattes du support ZIF, si vous utilisez ce dernier) • A ce stade, soit vous placez le pic sur le support ZIF du programmateur, soit vous raccordez le cordon « ICSP » sur la platine sur laquelle est monté le PIC. • Raccordez le programmateur au PC. • Alimentez le programmateur. • Lancez le programme PICPROG (livré avec le programmateur Velleman). • Sélectionnez la cible, ici un PIC 16F877 (si vous ne le trouvez pas dans la liste, vérifiez sur le site de Velleman s’il n’y a pas de mise à jour). • Ouvrez le fichier «.hex » généré par le compilateur pour votre projet • Cliquez sur le bouton « write all data », et attendez que le transfert s’effectue. - 16 -
  • 17. Si à ce stade tout est ok, déconnectez le programmateur, placez le PIC sur son circuit ou remettez les ponts à la place du connecteur ICSP de votre platine prototype. Tests Vous pouvez alimenter votre circuit et… He is alive ! Un magnifique effet de balayage anime vos 8 led. Elle est pas belle la vie ? Conclusion : Ca y est, vous avez créé une application à base de microcontrôleur ! Il est vrai que pour l’instant, l’interaction de notre montage avec le monde réel est très limitée. Il peut néanmoins servir à créer de jolis effets lumineux. On pourrait également envisager de s’en servir comme télécommande rustique (à une seule fonction ?) en montant une led infrarouge et en programmant la séquence d’allumages/extinctions adéquate. - 17 -
  • 18. Utilisation d’un PORT en entrée : un chenillard 8 leds contrôlé par 2 boutons poussoirs. Étape suivante : on va utiliser des pins d’un autre port en entrée, pour contrôler le fonctionnement de notre application. Le matériel : 1 40 2 39 3 38 4 37 5 36 6 35 7 34 RB1 RB0/INT PIC 16F877 8 33 9 32 10 31 11 30 12 29 13 28 switchon switchoff 14 27 15 26 16 25 17 24 18 23 19 22 20 21 On reprend le schéma précédent, et on y ajoute deux boutons poussoirs directement raccordés aux pins RB0 et RB1, autrement dit les deux bits de poids faible du PORTB. Vous allez me dire, « Quand on appuie sur les boutons poussoirs, ok, les pins sont à la masse, mais quand on relâche le potentiel est flottant, non ? » justement non, puisque qu’on va utiliser les résistances de pull-up interne du PIC. Une remarque importante : il n’y a que le PORTB qui soit équipé de telles résistances. Si vous utilisez un autre port, il faudra câbler vous-même ces résistances de tirage entre VCC et la pin correspondante. - 18 -
  • 19. Le programme : La structure générale est identique à l’exemple précédent, avec tout de même quelques modifications : #include <system.h> //Cible PIC16F877, bits de configuration #pragma DATA _CONFIG, _PWRTE_OFF & _BODEN_OFF & _WDT_OFF & _LVP_OFF & _CPD_OFF & _DEBUG_OFF & _XT_OSC & _CP_OFF //Configuration de la fréquence d'horloge, ici 4Mhz #pragma CLOCK_FREQ 4000000 void main( void ) { //Initialisation port A porta = 0x00; //Initialisation port B portb = 0x00; //Initialisation port C portc = 0x00; //Initialisation port D portd = 0x00; //Initialisation port E porte = 0x00; //Configuration port A trisa = 0x00; //Configuration port B trisb = 0x03; // On configure les deux pins de poids faible en entrée //Configuration port C trisc = 0x00; //Configuration port D trisd = 0x00; //Configuration port E trise = 0x00; //Configuration A/D pins adcon1 = 0x06; //désactivation du mécanisme de gestion des interruptions clear_bit( intcon, GIE ); - 19 -
  • 20. //Validation des résistances de pull-ups du port B clear_bit( option_reg, NOT_RBPU ); volatile bit switchon@0x06.0; // 0 pour RB0 volatile bit switchoff@0x06.1; // 1 pour RB1 bool go =0; // variable de contrôle //Boucle sans fin while( 1 ) { if (switchon == 0) { go = 1; } if (switchoff == 0) { go = 0; portd = 0b00000000; } if ( go ) { portd = 0b00000001; delay_ms(100); portd = 0b00000011; delay_ms(10); portd = 0b00000010; delay_ms(100); portd = 0b00000110; delay_ms(10); portd = 0b00000100; delay_ms(100); portd = 0b00001100; delay_ms(10); portd = 0b00001000; delay_ms(100); portd = 0b00011000; delay_ms(10); portd = 0b00010000; delay_ms(100); portd = 0b00110000; delay_ms(10); portd = 0b00100000; delay_ms(100); portd = 0b01100000; - 20 -
  • 21. delay_ms(10); portd = 0b01000000; delay_ms(100); portd = 0b11000000; delay_ms(10); portd = 0b10000000; delay_ms(100); portd = 0b11000000; delay_ms(10); portd = 0b01000000; delay_ms(100); portd = 0b01100000; delay_ms(10); portd = 0b00100000; delay_ms(100); portd = 0b00110000; delay_ms(10); portd = 0b00010000; delay_ms(100); portd = 0b00011000; delay_ms(10); portd = 0b00001000; delay_ms(100); portd = 0b00001100; delay_ms(10); portd = 0b00000100; delay_ms(100); portd = 0b00000110; delay_ms(10); portd = 0b00000010; delay_ms(100); portd = 0b00000011; delay_ms(10); } } } - 21 -
  • 22. Analyse du programme : Le programme ressemble, à quelques détails près, à celui de l’exemple précédent. /Cible PIC16F877, bits de configuration #pragma DATA _CONFIG, _PWRTE_OFF & _BODEN_OFF & _WDT_OFF & _LVP_OFF & _CPD_OFF & _DEBUG_OFF & _XT_OSC & _CP_OFF //Configuration de la fréquence d'horloge, ici 4Mhz #pragma CLOCK_FREQ 4000000 Comme vous pouvez le constater, on a changé de quartz. De 20 MHz on est passé à 4 MHz. Pourquoi ? Pas de raison particulière, c’est uniquement dans un but didactique. Si vous voulez conserver votre quartz 20 MHz, conservez les valeurs de l’exemple précédent pour cette section. //Configuration port B trisb = 0x03; // On configure les deux pins de poids faible en entrée Les deux boutons poussoirs (« switchon » et « switchoff » sur le schéma) sont câblés sur les pins du port B : RB0 et RB1. Dans l’exemple précédent, ces pins étaient configurées en sortie. Il nous faut maintenant les configurer en entrée. Pour cela, on met à 1 les bits correspondants du registre trisb, qui contrôle la direction du PORTB. Ce qui nous donne, en binaire : 0b00000011, et donc, en hexadécimal : 0x03. volatile bit switchon@0x06.0; // .0 pour RB0 volatile bit switchoff@0x06.1; // .1 pour RB1 On crée ici deux variables, « switchon » et « switchoff », de type « bit », donc codées chacune sur 1 bit. Ces variables ne devront pas être placées n’importe où en mémoire. Ce qu’on veut, c’est les associer aux bits correspondants aux pins RB0 et RB1 du PORTB. On spécifie donc au compilateur l’adresse de ces variables. Par exemple, pour switchon, « @0x06.0 », signifie « à l’adresse 0x06, le bit 0 ». 0x06 étant, bien entendu, l’adresse du PORTB. Le « .0 » spécifie le rang du bit, ici le bit de poids 0, autrement dit RB0. Et pour switchoff, on procède de la même manière mais en associant le bit « .1 », autrement dit RB1. L’attribut « volatile » devrait surprendre les familiers du langage C. C’est un ajout de BoostC au langage C ANSI standard, utilisé pour spécifier au compilateur que la variable peut être modifiée en dehors du flot normal du programme. Imaginez, vous venez de lire l’état d’une variable, vous ne l’avez pas modifiée, et voilà qu’elle change d’état ! Incompréhensible. D’où l’attribut volatile. On avait jusqu’à présent les variables « const » constantes, les variables standard modifiables par le programme, et on a maintenant les variables « volatile » dont l’état peut changer en dehors du programme. - 22 -
  • 23. bool go =0; // variable de contrôle On crée une autre variable, « go », de type « bool » qui ne peut prendre que deux états : vrai ou faux (1 ou 0). On ne spécifie pas d’adresse, c’est donc le compilateur qui lui en attribuera une dans l’un des registre généraux de l’espace RAM. On initialise cette variable à 0. Celle-ci servira de variable de contrôle, nous permettant de valider ou non l’allumage des 8 leds. if (switchon == 0) { go = 1; } On introduit une condition de test. Si switchon est égal à 0, on attribue la valeur 1 à la variable go. Si vous découvrez le langage C, remarquez ici la différence entre un « = » qui permet d’attribuer une valeur et un « == » qui permet de tester une égalité. if (switchoff == 0) { go = 0; portd = 0b00000000; } C’est au tour de switchoff d’être testé. S’il est égal à 0 (le bouton poussoir switchoff est actionné et ramène le potentiel Vss sur RB1), on exécute la portion de code entre accolades : on attribue la valeur 0 à la variable go, puis on met toutes les pins du PORTD à 0 -> toutes les leds sont éteintes. if ( go ) { portd = 0b00000001; delay_ms(100); ... ... ... } On teste enfin la variable « go ». Si elle est « vraie » (état =1), on exécute le code entre accolades qui allume successivement les leds via le PORTD. Si elle est « fausse » (état = 0) on recommence la boucle en testant switchon, puis switchoff, puis à nouveau go, etc. Compilation du programme et injection dans le PIC : Rien de particulier ici. Procédez comme pour l’exemple précédent, et tout devrait bien se passer. - 23 -
  • 24. Tests Vous pouvez alimenter votre circuit et… Rien ! Normal, vous n’avez pas encore appuyé sur switchon. Réparez cet oubli : un magnifique effet de balayage anime à nouveau vos 8 leds. Appuyez maintenant sur switchoff. Le balayage s’éteint, mais, pas tout de suite ! Uniquement à la fin du cycle de balayage des leds (eh oui, on doit attendre que le programme repasse par le test de switchoff). Conclusion : Le contrôle du fonctionnement de notre chenillard par deux boutons poussoirs marque incontestablement un progrès. Vous savez maintenant utiliser les ports I/O du pic en entrée et en sortie, utiliser les résistances de pull-up du PORTB. Cependant, le fonctionnement actuel ne nous satisfait pas pleinement. Ce qu’on voudrait, c’est que le balayage s’éteigne tout de suite, dès qu’on appuie sur switchoff. Pour remédier à cela, on pourrait introduire des tests de switchoff avant chaque allumage de la led suivante, plutôt qu’une seule fois avant de dérouler toute la séquence. On pourrait également remplacer la séquence par une fonction exécutée en boucle, le test sur switchoff étant alors réalisé avant chaque itération. Quoi qu’il en soit, nous allons passer à l’étape suivante : l’utilisation du mécanisme d’interruption sur changement d’état du PORTB. - 24 -
  • 25. Le PORTB et les interruptions Principe de fonctionnement : Le port B possède une caractéristique particulièrement intéressante : au même titre que certains autres modules périphériques du PIC, il a la possibilité de générer des interruptions. Pour mémoire, le principe de fonctionnement des interruptions est le suivant : à un moment donné (aléatoire), un événement particulier déclenche une interruption (débordement d’un compteur, fin de conversion analogique numérique…). L’exécution normale et linéaire du programme est interrompue, et le PIC se branche sur une portion de code particulière : la routine d’interruption. Celle-ci exécute alors un traitement particulier en réponse à l’événement déclencheur de l’interruption. Puis, on sort de la routine d’interruption et on retourne à l’exécution normale du programme. Pour gérer ce mécanisme, il faut : valider dans le programme la ou les sources d’interruption, et écrire une routine d’interruption appropriée. Le contrôle des interruptions se fait grâce aux registres INTCON, PIE1, PIR1, PIE2, PIR2. Le registre INTCON regroupe les bits de validation (= enable bit) et de signalisation (= flag ou drapeau) des interruptions « de base ». Les interruptions des modules périphériques sont gérées par les registres PIE et PIR. Sur le PIC 16F877 on a deux PIE et deux PIR, étant donné le nombre important de sources d’interruptions possibles. Avec BoostC, la routine d’interruption prend la forme d’une fonction particulière, intitulée « interrupt ». Dans l’exemple suivant, on va utiliser une interruption générée par le PORTB pour contrôler la vitesse de défilement des 8 leds contrôlées par le PORTD. L’interruption sur changement d’état du PORTB est générée dès qu’un changement d’état est détecté sur une des pin RB4, RB5, RB6, ou RB7. Dans notre cas, ce sera RB4. - 25 -
  • 26. Le matériel : 1 40 2 39 3 38 4 37 5 36 6 35 7 34 PIC 16F877 8 33 9 32 10 31 11 30 12 29 13 28 switchint 14 27 15 26 16 25 17 24 18 23 19 22 20 21 Pour cet exemple, pas de grand changement : on se contente de câbler un bouton poussoir supplémentaire sur la pin RB4 (la patte n°37 du PIC 16F877). On appelle ce poussoir « switchint ». - 26 -
  • 27. Le programme : #include <system.h> //Cible PIC16F877, bits de configuration #pragma DATA _CONFIG, _PWRTE_OFF & _BODEN_OFF & _WDT_OFF & _LVP_OFF & _CPD_OFF & _DEBUG_OFF & _XT_OSC & _CP_OFF //Configuration de la fréquence d'horloge, ici 4Mhz #pragma CLOCK_FREQ 4000000 //*********************************************************************************************** volatile bit switchint@0x06.4; // 4 pour RB4 int i; // variable utilisée comme compteur dans une boucle "for" bool speed=1; // variable "mémoire" //*********************************************************************************************** void interrupt( void ) //routine de gestion des interruptions { if (intcon & 0b00000001) { delay_ms(10); // attente de 10 ms, pour éviter les rebonds du contact if (switchint == 0) // on teste si RB4 est maintenu à l'état bas. { speed = !speed; // inverse l'état de la variable speed } //portb = portb; //lecture du portb pour supprimer le mismatch. clear_bit( intcon, RBIF); //On efface le bit drapeau de l'interruption } } //*********************************************************************************************** void leds(void) // fonction allumant successivement les leds { portd = 0b00000001; if (speed == 0) { delay_ms(50); } delay_ms(50); for ( i=0; i<8; i++ ) { portd = portd << 0b00000001; if (speed == 0) { delay_ms(50); } delay_ms(50); - 27 -
  • 28. } } //*********************************************************************************************** void main( void ) { //Initialisation port A porta = 0x00; //Initialisation port B portb = 0x00; //Initialisation port C portc = 0x00; //Initialisation port D portd = 0x00; //Initialisation port E porte = 0x00; //Configuration port A trisa = 0x00; //Configuration port B trisb = 0x10; // On configure la pin RB4 en entrée (0x10 0b00010000) //Configuration port C trisc = 0x00; //Configuration port D trisd = 0x00; //Configuration port E trise = 0x00; //Configuration A/D pins adcon1 = 0x06; //Validation des résistances de pull-ups du port B clear_bit( option_reg, NOT_RBPU ); //désactivation (temporaire) du mécanisme de gestion des interruptions clear_bit( intcon, GIE ); //mise à 0 flags + désactivation toutes interruptions sauf interruption sur //changement PORTB intcon = 0b00001000; // on efface les flags, et on valide le bit RBIE : bit de validation d'interruption sur changement du PORTB //validation des interruptions : set_bit(intcon, GIE ); - 28 -
  • 29. //Boucle sans fin while( 1 ) { leds(); } } Analyse du programme : Notre programme nous permet de faire défiler les 8 leds contrôlées par le PORTD : Contrairement aux exemples précédents où on effectuait un « va et vient » avec un effet de fondu, les leds sont allumées successivement l’une après l’autre. Puis on recommence. Deux vitesses de défilement sont possibles. On passe de l’une à l’autre en actionnant le bouton poussoir « switchint ». #include <system.h> //Cible PIC16F877, bits de configuration #pragma DATA _CONFIG, _PWRTE_OFF & _BODEN_OFF & _WDT_OFF & _LVP_OFF & _CPD_OFF & _DEBUG_OFF & _XT_OSC & _CP_OFF //Configuration de la fréquence d'horloge, ici 4Mhz #pragma CLOCK_FREQ 4000000 Même séquence d’initialisation qu’à l’exemple précédent : on inclut le fichier system.h, on configure les bits de configuration, et on indique la fréquence d’horloge. volatile bit switchint@0x06.4; // 4 pour RB4 int i; // variable utilisée comme compteur dans une boucle "for" bool speed=1; // variable "mémoire" On déclare ensuite les variables utilisées dans le programme : « switchint » qui est une variable de type « bit », affectée à la pin RB4 du PORTB, « i » qui est une variable de type « int » qui nous servira à compter les itérations d’une boucle « for », et « speed », variable booléenne (qui ne peut donc valoir que 0 ou 1) qui nous permettra de contrôler les temporisations entre l’allumage des leds et donc, la vitesse du défilement. - 29 -
  • 30. void interrupt( void ) //routine de gestion des interruptions { if (intcon & 0b00000001) { delay_ms(10); // attente de 10 ms, pour éviter les rebonds du contact if (switchint == 0) // on teste si RB4 est maintenu à l'état bas. { speed = !speed; // inverse l'état de la variable speed } //portb = portb; //lecture du portb pour supprimer le mismatch. clear_bit( intcon, RBIF); //On efface le bit drapeau de l'interruption } } Voici donc la fameuse routine d’interruption ! Il s’agit d’une fonction spéciale chargée du traitement des interruptions. Pas besoin de l’appeler dans le corps du programme (contenu dans la fonction main() ), elle sera exécutée automatiquement lorsqu’une source d’interruption valide se manifestera. Son nom est figé, donc si vous la remplacez par une fonction « void interruption( void ) », ça ne marchera pas ! SourceBoost ne reconnaitrait pas qu’il s’agit là de la routine de traitement des interruptions. Quelle que soit la source d’interruption, la fonction interrupt() sera appelée. Donc, si vous avez plusieurs sources d’interruptions possibles, il faudra tester quelle est l’origine, afin d’exécuter le traitement adéquat. C’est ce qu’on fait ici avec l’instruction « if (intcon & 0b00000001) » : on fait un ET logique entre le registre INTCON et la valeur binaire 0b00000001. Si le bit de poids 0 du registre INCON est égal à 1, le résultat vaudra 1 et la portion de code suivant le test « if » sera exécutée. Le bit de poids 0 d’INTCON n’est autre que RBIF, bit « drapeau » de signalisation de l’interruption sur changement du port PORTB. On aurait pu ici se passer de ce test, étant donné qu’on a qu’une seule source d’interruption dans notre exemple. Vient ensuite une temporisation de 10 millisecondes (delay_ms(10) ) qui nous permet de nous affranchir des rebonds du contact de switchint. Sans cela, ces rebonds généreraient une multitude d’interruptions successives. Puis, on test la valeur de switchint, le traitement effectif n’ayant lieu que s’il est à 0, autrement dit si le bouton poussoir est appuyé. Je dois vous faire remarquer ici que contre le PIC, vous n’avez aucune chance : il est beaucoup plus rapide que vous ! Une interruption sera générée lorsque vous appuierez sur switchint, mais aussi lorsque vous le relâcherez ! Mais dans ce dernier cas, switchint sera égal à 1, et le traitement sera ignoré : la condition du « if » sera fausse. Vient ensuite le code utile du traitement de notre interruption : on inverse l’état de la variable « speed » grâce à l’opérateur « ! » (lire « NOT ») qui complémente l’opérande située à sa droite. Ainsi, « speed » devient égal à l’inverse de « speed ». Pour mémoire, j’ai mis en commentaire l’instruction « portb = portb ». Pourquoi ? Il faut savoir ici que l’interruption est générée lorsque l’état physique d’une pin du PORTB est différent de l’état mémorisé dans son tampon de réception. On a alors un « mismatch », autrement dit un décalage. Pour supprimer ce décalage, il faut effectuer une opération de lecture du PORTB pour « réaligner » l’état théorique et l’état physique du port. Dans notre cas, une lecture de la variable switchint provoque la lecture du port, c’est donc déjà fait. Mais dans l’hypothèse ou votre code de - 30 -
  • 31. traitement de l’interruption n’accéderait pas au PORTB, il faudrait effectuer cette lecture. Sans quoi, à peine sorti de la routine d’interruption, on y retournerait, le « mismatch » étant toujours présent ! On efface enfin le bit de signalisation d’interruption, RBIF (poRt B Interrupt Flag bit) grâce à l’instruction « clear_bit(intcon, RBIF) ». void leds(void) // fonction allumant successivement les leds { portd = 0b00000001; if (speed == 0) { delay_ms(50); } delay_ms(50); for ( i=0; i<8; i++ ) { portd = portd << 0b00000001; if (speed == 0) { delay_ms(50); } delay_ms(50); } } Contrairement aux exemples précédents, le code chargé d’allumer successivement les leds est regroupé dans une fonction, appelée « leds ». Le « void » à gauche signifie qu’on ne retourne aucune valeur, alors que le void entre parenthèses indique qu’on ne prend aucune valeur en argument. On allume notre première led sur RD0 grâce à l’instruction « portd = 0b00000001 ; Puis, on test la variable « speed ». En fonction du résultat, soit on exécute une première temporisation de 50 millisecondes suivie d’une deuxième temporisation de 50ms, soit on exécute uniquement la deuxième temporisation. Puis on entre dans la boucle for, qui utilise la variable « i » comme compteur. Dans cette boucle, exécutée 7 fois, on commence par effectuer un décalage à l’aide de l’instruction « portd = portd << 0b00000001 ; ». La traduction en français de cette instruction donne quelque chose du genre « portd est égal à portd décalé d’un bit vers la gauche ». L’opérateur de décalage étant << . Puis, on retrouve nos deux temporisations dont la première est conditionnée à la valeur de « speed ». - 31 -
  • 32. void main( void ) { //Initialisation port A porta = 0x00; //Initialisation port B portb = 0x00; //Initialisation port C portc = 0x00; //Initialisation port D portd = 0x00; //Initialisation port E porte = 0x00; //Configuration port A trisa = 0x00; //Configuration port B trisb = 0x10; // On configure la pin RB4 en entrée (0x10 0b00010000) //Configuration port C trisc = 0x00; //Configuration port D trisd = 0x00; //Configuration port E trise = 0x00; //Configuration A/D pins adcon1 = 0x06; //Validation des résistances de pull-ups du port B clear_bit( option_reg, NOT_RBPU ); On entre ensuite dans le corps du programme (la fonction « main »), la seule différence par rapport à l’exemple précédent étant la valeur affectée au registre « trisb » : seule la pin RB4 est configurée en entrée. - 32 -
  • 33. //désactivation (temporaire) du mécanisme de gestion des interruptions clear_bit( intcon, GIE ); //mise à 0 flags + désactivation toutes interruptions sauf interruption sur //changement PORTB intcon = 0b00001000; // on efface les flags, et on valide le bit RBIE : bit de validation d'interruption sur changement du PORTB //validation des interruptions : set_bit(intcon, GIE ); Viens ensuite la partie configuration du mécanisme d’interruption. J’aurais pu faire plus simple et remplacer les trois instructions par une seule, mais je préfère procéder comme suis : 1 – désactivation globale des interruptions avec l’instruction « clear_bit( intcon, GIE) » qui efface le bit GIE du registre INTCON. 2 – effacement des bits « drapeaux » de signalisation d’interruption éventuellement positionnés, et configuration de la source d’interruption : pour valider l’interruption sur changement d’état du PORTB, on met à 1 le bit RBIE. 3 – activation globale des interruptions avec l’instruction « set_bit( intcon, GIE) » qui met à 1 le bit GIE (Global Interrupt Enable) du registre INTCON. A partir de là, c’est parti : si vous appuyez sur switchint, le PIC exécutera la fonction « interrupt ». //Boucle sans fin while( 1 ) { leds(); } Puis vient enfin, comme dans les exemples précédents, une boucle sans fin qui se contente d’appeler la fonction « leds() » définie précédemment. - 33 -
  • 34. Tests Après avoir compilé et transféré votre programme comme précédemment, vous pouvez alimenter le montage : les leds se mettent à défiler l’une après l’autre, sans fin. Une pression sur le bouton poussoir switchint fait passer la vitesse de défilement de rapide à lente. Une nouvelle pression sur switchint et la vitesse de défilement repasse de lente à rapide. Autrement dit, ça marche : une pression sur le bouton poussoir switchint lance bien la routine d’interruption, et celle-ci inverse effectivement la variable booléenne « speed ». Trop fort, non ? Conclusion : Vous connaissez maintenant le mécanisme de base de gestion des interruptions. Les bits de validation (RBIE) et de signalisation (RBIF) de l’interruption sur changement du PORTB étant présents dans le registre INTCON, nous n’avons pas eu pour l’instant à nous préoccuper des registres PIE1, PIR1, PIE2, PIR2. Mine de rien, notre dernier exemple nous a fait passer d’une programmation « séquentielle », où toutes les actions étaient effectuées dans l’ordre, l’une à la suite de l’autre, à une programmation « événementielle » capable de prendre en compte un événement à tout moment du déroulement du programme. Autrement dit : on devient bons ! - 34 -