Initiation au micro-contrôleur PIC

FIXME Recherche des images en cours…

FIXME Liens originels cassés

Cet article est dédié à l’apprentissage des fonctions de base d’un PIC.

Il traitera de la structure interne d’un PIC, de son implantation dans un circuit électronique, de sa programmation. Le tout illustré par quelques exemples pratiques.

Initiation au PIC

  1. Les bases
  2. Utilisation et Fonctionnalités
  3. Les outils de développement
  4. La programmation d’un PIC
  5. Exemple 1 : Faire clignoter une LED
  6. Exemple 2 : Faire clignoter une LED en utilisant les timers et interruptions

Les Bases

Généralités

Un microcontrôleur est un composant programmable. Il regroupe dans un seul boîtier compact un processeur de calcul, de la mémoire vive (RAM), de la mémoire permanente (FLASH, EEPROM), des périphériques. Il existe des dizaines de modèles. Quelques exemples courants : les 8051 de Intel, les 68HC11 de Motorola… et les PIC de Microchip.

Microchip propose plusieurs familles de PIC :

8bits pic10f.jpg pic18f.jpg

10F et 12F: ce sont des PIC minuscules (environ 6 pattes) qui possèdent quelques fonctions essentielles (timer, comparateur ou convertisseur analogique/numérique).

16F : ce sont les PIC les plus répandus. Parmi leurs caractéristiques principales, nous pouvons citer : architecture 8 bits, timers, compteurs, modules PWM, convertisseur analogique/numérique, modules de communication, nombreux ports d’E/S…
18F : Ces PIC sont assez semblables aux 16F.Ils sont optimisés pour la programmation en langage C, grâce à un plus grand nombre d’instructions assembleur. Ils tendent de plus en plus à remplacer les 16F.

16bits pic24.jpg

PIC24 : Tout en restant dans le même type d’application que les 18F, les PIC24 offrent de bien meilleures performances grâce à leur architecture 16 bits, tout en conservant un grand nombre de périphériques.

dsPIC : En combinant architecture 16 bits, coeur de calcul DSP et périphériques plus performants et plus variés, les dsPIC sont le choix idéal pour le contrôle moteur complexe, le traitement du signal… 32bits pic32.jpg

PIC32 : Ce sont aujourd’hui les produits les plus évolués de la gamme Microchip. Leur utilisation est réservée à des applications complexes et gourmandes. |

La première chose à faire pour utiliser un microcontrôleur est de se procurer sa documentation. Les sites internet des constructeurs fournissent l’indispensable « datasheet » (contenant toutes les spécifications du composant), plus des « application notes » (diverses solutions clé en main).

carte_pic_pdip_small

carte_pic_tqfp_small

Exemple de carte avec un PIC boitier PDIP

Exemple de carte avec un PIC boitier TQFP

Architecture interne

Le schéma ci-dessous présente les principaux blocs fonctionnels présents à l’intérieur d’un PIC ainsi qu’une courte description. Pour un schéma plus précis, se référer à la datasheet de votre PIC.

archi_pic_small Description des blocs fonctionnels:

  • Mémoire flash : C’est une mémoire réinscriptible qui conserve ses données lorsque le PIC n’est pas alimenté. Elle est utilisée pour stocker le programme. A chaque ligne du programme est attribuée une adresse qui permettra à l’unité de calcul de se repérer.
  • Mémoire RAM : C’est une mémoire volatile (qui s’efface quand le PIC n’est plus alimenté). Les variables utilisées au cours du programme sont stockées à cet endroit.
  • Unité de Calcul: C’est le cœur du microcontrôleur. Ici se déroulent toutes les opérations à une vitesse définie par la fréquence d’horloge (fréquence d’oscillation divisée par 4).
  • Registre temporaire W : C’est ici qu’est stockée la valeur nécessaire pour une opération de l’unité de calcul.
  • Ports E/S ( Entrées/Sorties ) : Ce sont les unités qui font le lien entre ce qui se passe a l’intérieur du PIC et l’extérieur.
  • Modules annexes : Toutes les fonction annexes (timers, comparateurs, convertisseurs analogiques/numériques …)

Utilisation et Fonctionnalités

Le PIC qui sera détaillé par la suite est le 18F2680. C’est, à l’heure actuelle, l’un des PIC18F les plus polyvalents pour un encombrement réduit. Tous les détails concernant le fonctionnement des différents modules sera identique pour la gamme des 18F.

Montage minimum

D’un point de vue électronique, la mise en oeuvre d’un PIC18F est très simple. En effet, la plupart contiennent un oscillateur intégré ainsi qu’une désactivation possible de la patte de reset.

La partie en fond bleu sur le schéma n’est donc pas obligatoire.

L’oscillateur est un montage de composants qui, une fois alimenté, se met à osciller naturellement à une fréquence constante. Il permet au microcontrôleur de se générer une horloge pour cadencer les mécanismes d’exécution du programme. Plus cette fréquence est rapide, plus le programme s’exécute rapidement. L’oscillateur interne du PIC n’est pas très précis. Pour les applications qui nécessitent une grande précision, il faudra installer un oscillateur externe composé d’un quartz et de condensateurs comme proposé ci-contre.Le reset est une action qui redémarre l’exécution du programme au début. Nous n’utilisons pas la patte de reset (MCLR) au ClubElek puisque nous redémarrons les programmes à distance (par un bus de communication) ou en coupant l’alimentation. Pour les débutants, l’utilisation d’un bouton de reset est recommandée (voir le schéma ci-contre)

cablage_minimum_pic_18F.png

L’alimentation est l’apport d’énergie au microcontrôleur. Il est indispensable qu’elle soit de très bonne qualité pour éviter des redémarrages intempestifs du programme.

Si vous possédez déjà une alimentation continue 5V de bonne qualité, il suffit de la connecter aux pattes VCC (+5V) et GND (0V) du microcontrôler en ajoutant un condensateur de 100nF pour atténuer les parasites (voir schéma ci-contre). Vous pouvez aussi créer une alimentation 5V à partir d’une tension plus élevée en utilisant un composant de type 7805 disponible chez tous les détaillants d’électronique.

Le connecteur de programmation devra être ajouté au montage pour pouvoir écrire le programme dans le PIC. La forme du connecteur devra être choisie en fonction du programmateur que vous utilisez. Les pattes utilisées pour la programmation sont toujours les mêmes : PGC,PGD,VCC,GND,MCLR

Résumé de quelques fonctionnalités d’un PIC

Vous trouverez ici un résumé des fonctionnalités d’un PIC. Pour des informations complémentaires plus poussées, je vous conseille de consulter la datasheet de votre PIC disponible sur le site de Microchip ainsi que un cours très bien fait par Bigonoff. Ce cours est pour les PIC16F et le langage utilisé est l’assembleur, mais le principe des fonctionnalités est toujours le même.

Les ports d’entrée/sortie

Il y a plusieurs ports disponibles sur un PIC. Un port est une association de pattes qui pourra être utilisé soit en entrée (lecture d’une valeur binaire) soit en sortie (écriture d’une valeur binaire). Il est possible de lire et d’écrie une seule patte à la fois ou toutes les pattes d’un port à la fois.

Il est nécessaire de spécifier, pour chaque pin utilisée d’un port, si ce sera une entrée ou une sortie. Cette configuration est accessible par les registres TRISX (où X représente le nom du port : A, B, C, D, E…) et doit être configuré avant toute utilisation du port. Un 1correspond à une entrée (ressemble au I de Input) et un 0 à une sortie (ressemble au O de Output).

Exemple : Je veux utiliser le PORTB qui est composé de 8 pins, les 4 premières en entrée et les 4 autres en sortie, le PORTC en sortie, et le PORTD en entrée. Il faut donc, en début de programme écrire les lignes:

En Assembleur:

movlw 0b00001111
movwf TRISB
movlw 0b00000000
movwf TRISC
movlw 0b11111111
movwf TRISD

En C:

TRISB=0b00001111;
TRISC=0b00000000;
TRISD=0b11111111;

Maintenant que les ports sont configurés, on peut lire ou écrire des valeurs sur ces entrées/sorties.

En Assembleur:

;ecriture bit à bit
bsf PORTB,7
bcf PORTB,6
;ecriture sur tout le port
movlw 0b10101010
movwf PORTC
;lecture sur tout le port
movf PORTD,w

En C:

//ecriture bit à bit
PORTBbits.RB7=1;
PORTBbits. RB6=0;
//ecriture sur tout le port
PORTC=0b10101010;
//lecture sur tout le port
variable=PORTC;
Les interruptions

Une interruption est une action, déclenchée par un événement précis, qui va arrêter le programme principal, s’exécuter, puis reprendre le programme principal à l’endroit où il s’était arrêté. Les interruptions peuvent être déclenchées par:

  • Les timers
  • Les pins interruptibles (ex : RB0)
  • Les interfaces de communication
  • Le convertisseur analogique-numérique

Pour utiliser les interruptions, il faut tout d’abord les activer. Il faut pour cela fixer les valeurs des registres suivant :

INTCON qui contient :

  • GIE (bit 7) : activation générale des interruptions
  • PEIE (bit 6) : activation des interruption des périphériques
  • bit5-bit3 (RBIE,TMR0IE..): activation individuelle de interruptions principales
  • bit2-bit0 (RBIF,TMR0IF..): Lorsqu’un événement déclencheur se produit, il est notifié dans un « flag » (drapeau) qui permettra par la suite d’identifier la cause de l’interruption

INTCON2,INTCON3 contiennent des options supplémentaires

  • PIR1,PIR2,PIR3 contiennent les flags des différentes sources d’interruptions des périphériques
  • PIE1,PIE2,PIE3 contiennent l’activation des différentes sources d’interruptions des périphériques

L’exécution des interruptions se fait à partir de l’adresse programme 0x08. En effet, lorsqu’une interruption se produit, le programme principal s’arrête et exécute l’instruction à l’adresse 0x08. La routine d’interruption est structurée de la façon suivante:

  • Sauvegarder les registres
  • Identifier la source de l’interruption
  • Effectuer l’action associée à cette interruption
  • Restaurer les registres
  • Revenir au programme principal

Matériel nécessaire : Outils de développement

Le Programmateur

Le moyen le plus économique pour programmer un PIC est de fabriquer soi même sa carte programmateur avec des sockets pour différents PIC. De nombreux schémas sont disponibles en ligne. Il est aussi possible d’acheter ces cartes, mais pour un prix bien plus onéreux.Le moyen le plus pratique est sans aucun doute le programmateur Pickit2 de Microchip que l’on peut trouver pour environ 30€. Avec celui-ci, pas besoin de retirer à chaque fois le PIC de la carte pour le programmer, il suffit juste de prévoir un accès facile aux broches VDD,VSS,PGC,PGD,MCLR. pickit2

Le Débuggeur

icd2 Cet élément n’est pas indispensable. Il permet de débugger le programme, c’est à dire de permettre à l’utilisateur de voir l’état des différentes parties du PIC pendant l’exécution un programme. Cependant le PIC ne peut pas être sur la carte finale pour procéder à ces tests, il doit être sur la carte de développement fournie avec le débuggeur.Ce débugger s’appelle MPLAB ICD 2 de Microchip et coûte environ 150-200€. Il est aussi possible de fabriquer un clone bien moins cher mais sûrement un peu moins performant.Dans la plupart des cas, ce débugger n’est pas utile étant donné que MPLAB possède un outil de simulation très performant.Il est à noter que le Pickt2 sait maintenant débugguer un grand nombre de PIC.

Le Logiciel : MPLAB

L’environnement de développement MPLAB est disponible gratuitement sur le site de Microchip. C’est un environnement très complet et très pratique à utiliser. Il propose une interface de saisie du programme puis une vérification des erreurs au moment de la compilation ainsi qu’un simulateur avancé afin de vérifier si le programme fonctionne bien avant de l’envoyer dans le microcontrôleur. Parmi les nombreuses possibilités du simulateur, on peut citer : affichage de l’état de tous les registres et variables en temps réels, simulation d’entrées, exécution en mode pas à pas, points d’arrêts…Le langage de base de programmation est l’assembleur. Il est cependant possible d’ajouter des modules (non microchip) à MPLAB afin de pouvoir programmer en langage C. mplab

Créer un projet dans MPLAB

Choisir « Project » dans la barre de menu principale puis « Project wizard » et laissez vous guider par l’assistant. Au moment de choisir le compilateur, laissez les options par défaut pour programmer en assembleur. Si un composant pour programmer le langage C a été installé auparavant, il est aussi possible de choisir ce compilateur pour le langage C. Il suffit ensuite d’ajouter un nouveau fichier et commencer à entrer le programme.

La programmation d’un PIC

La programmation C en quelques ligne s

Les quelques lignes qui suivent devraient vous permettre de comprendre un programme de base en C, sans aucune connaissance préalable. Si vous connaissez déjà le C vous pouvez donc passer directement au paragraphe suivant. Si vous voulez plus d’infos sur le C en général, je vous conseille les liens de l’excellent site developpez.com.

Les commentaires s’écrivent entre un /* (slash-étoile) et un */ (étoile-slash) : tout ce qui sera écrit entre ces deux symboles ne sera donc pas analysés par le compilateur, on trouve aussi parfois le double slash qui permet d’ignorer toute la fin d’une ligne, elle est théoriquement spécifique au C++ mais est très souvent acceptée par les compilateurs récents.
Pour stocker une valeur dans un programme, il faut utiliser une variable. Pour créer et utiliser une variable, vous devez d’abord la déclarer. La déclaration des variables se fait en début de bloc, avant la première ligne de code. Pour déclarer une variable, il faut d’abord donner son type (qu’est ce que va stocker la variable : entier, réel, caractère, etc…) puis son nom.

int i ;   // Déclaration d’un entier appelé i

Une fonction est un segment de programme exécutant un certain nombre d’opération dans un but précis. De la même façon que les variables, il faut les déclarer en indiquant le type de retour, le nom de la fonction et la liste des paramètres entre parenthèses. Les paramètres sont des valeurs que l’on communique à la fonction.

//Retourne la valeur la plus grande entre a et b
int max(int a, int b)
{
    if(a>b)        //si ‘a’ est supérieur à ‘b’
        return a;  //on retourne ‘a’
    else           //sinon
        return b;  //on retourne ‘b’
}

La directive #include <pic.h> indique au compilateur d’analyser le fichier ‘pic.h’, qui contient des déclarations de fonctions, de variables et de constantes propres au pic. En gros, cela indique au compilateur quoi faire lorsqu’il rencontre une fonction spécifique au pic. Un programme commence toujours dans une fonction qui s’appelle ‘main‘ et qui retourne un entier.

int main()
{
    //Début du programme…
}

Structure d’un programme en C pour le PIC avec le compilateur MCC18

//Les includes:
#include <p18f2680.h>        //Définitions des registres du PIC//La configuration du PIC (syntaxe propre au compilateur):
#pragma config OSC = IRCIO67    //Oscillateur interne, RA6 et RA7 sont des ports normaux//La déclaration des variables globales et entêtes des fonctions:
unsigned char     fin;
void            test();
//La fonction principale:
int main(void)
{
….
}

Les configurations du PIC

Ce sont les configurations les plus importantes du PIC. Elles sont indépendantes du déroulement du programme. C’est par exemple par ce moyen que la source de l’oscillateur du PIC est réglée.

L’explication de ces paramètres est accessible dans MPLAB par le menu Help→Topics→PicC18 config settings. Voici un exemple de configuration pour une utilisation avec oscillateur interne et pin de reset désactivée. Les 5 premières configurations sont indispensables pour éviter les surprises.

#pragma config OSC = IRCIO67        //Oscillateur interne, RA6 et RA7 sont des ports normaux
#pragma config MCLRE = OFF        //désactiver la pin de Reset
#pragma config LVP = OFF        //Low Voltage Programming désactivé => RB5 I/O normale
#pragma config PBADEN = OFF        //PORTB<4> and PORTB<1:0> Configured as Digital I/O Pins on Reset
#pragma config DEBUG = OFF        //débug désactivé => RB6 et RB7 normal I/O
 
#pragma config FCMEN = OFF        //Fail-Safe Clock désactivée
#pragma config IESO = OFF        //Oscillator Switchover mode désactivé
#pragma config PWRT = OFF        //Power-up Timer désactivé
#pragma config BOREN = OFF        //Reset dû a une tension trop basse désactivé
#pragma config BORV = 2            //Brown-out Reset Voltage
#pragma config WDT = OFF        //Watchdog désactivé
#pragma config WDTPS = 1024        //prédiviseur du watchdog
#pragma config LPT1OSC = OFF         //Low-Power Timer 1 Oscillator Disable ==> high power
#pragma config XINST = OFF        //Instruction set extension and Indexed Addressing mode disabled (Legacy mode)
#pragma config BBSIZ = 1024        //1K words (2K bytes) Boot Block
#pragma config STVREN = OFF        //pas de reset dû à la pile

Exemple 1 : Faire clignoter une LED

Comme la théorie n’est rien sans la pratique, voici quelques exemples pour illustrer tout ce qui a été vu précédemment.

Utilisons le simple montage ci contre. Ce n’est que le montage que nous avons déjà vu précédemment auquel a été ajouté un bouton poussoir au niveau de la pin RA0 et une association LED/résistance sur la patte RA1.

led_clignote.png Il va donc falloir par la suite définir la patte RA0 comme une entrée, qui sera vue comme un 1 logique quand le bouton sera au repos et comme un zéro logique quand le bouton sera appuyé.La patte RA1 sera définie comme une sortie. Lorsque la sortie sera définie comme un zéro logique, la LED sera éteinte. Dans le cas contraire, le potentiel au niveau de la broche RA1 sera de 5V et la LED s’allumera.

Choix de la résistance en série avec la LED :
Sachant que la tension de seuil d’une LED rouge est généralement 1,5V (environ 2,2V pour les vertes et jaunes), le courant dans la branche sera, dans le cas d’un fonctionnement nominal : I = (Vcc-Vseuil) / R

On trouve pour Vcc=5V , Vseuil=1,5V et R=220 Ohm :I=16mA

Ce courant est suffisant pour que la LED soit éclairée de façon très visible et il est en dessous du courant limite que le PIC peut fournir (25mA). La résistance est donc bien choisie.

Passons maintenant à la programmation :

#include <p18cxxx.h>        //Définitions des registres du PIC
//bits de configuration, indépendant du programme voir « Help->Topics->PicC18 config settings »
#pragma config OSC = IRCIO67        //Oscillateur interne, RA6 et RA7 sont des ports normaux
#pragma config MCLRE = OFF        //désactiver la pin de Reset
#pragma config LVP = OFF        //Low Voltage Programming désactivé => RB5 I/O normale
#pragma config PBADEN = OFF        //PORTB<4> and PORTB<1:0> Configured as Digital I/O Pins on Reset
#pragma config DEBUG = OFF        //débug désactivé => RB6 et RB7 normal I/O#pragma config FCMEN = OFF        //Fail-Safe Clock désactivée
#pragma config IESO = OFF        //Oscillator Switchover mode désactivé
#pragma config PWRT = OFF        //Power-up Timer désactivé
#pragma config BOREN = OFF        //Reset dû a une tension trop basse désactivé
#pragma config BORV = 2            //Brown-out Reset Voltage
#pragma config WDT = OFF        //Watchdog désactivé
#pragma config WDTPS = 1024        //prédiviseur du watchdog
#pragma config LPT1OSC = OFF         //Low-Power Timer 1 Oscillator Disable ==> high power
#pragma config XINST = OFF        //Instruction set extension and Indexed Addressing mode disabled (Legacy mode)
#pragma config BBSIZ = 1024        //1K words (2K bytes) Boot Block
#pragma config STVREN = OFF        //pas de reset du à la pile
void initialisation(void)
{
    //configuration horloge interne du pic à 32 MHz
    OSCCON = 0x70;        //pas de prédiviseur => 8MHz
    OSCTUNE = 0x40;        //activer la PLL *4 => 32MHz//direction des ports 0=Output, 1= Input par     défaut tous à 1
    TRISAbits.TRISA1 = 0;    //patte 1 du port A en sortie
    TRISAbits.TRISA0 = 1;    //patte 0 du port A en entrée//réinitialisation du port
    PORTB=0x00;            //mise à zéro car état indeterminé au démarrage
    //désactiver le module CCP
    CCP1CON=0;
 
    //désactiver le convertisseur analogique numerique
    ADCON1=0x0F;
}
 
void tempo(void)
{
    unsigned long i;
    for( i=0 ; i<168000 ; i++ );
}
void main ()
{
    initialisation();        //initialisation du PIC
    while(PORTAbits.RA0);    //attente de l’appui du bouton
    for( ; ; )                //boucle infinie
   {
      PORTAbits.RA1 ^=1;    //changer l’état du bit 6 de PORTB
      tempo();            //tempo d’environ 500ms
    }
}

vous trouverez le fichier main.c ici

Exemple 2 : Faire clignoter une LED en utilisant les timers et interruptions

Reprenons le schéma précédent en plaçant le bouton poussoir sur la pin RB0 à la place de la pin RA0. L’avantage de la pin RB0 sur la pin RA0, c’est que c’est une pin interruptible c’est a dire que lors d’un changement d’état, le programme sautera à un endroit précis, ce qui permettra de gérer l’événement.

led_clignoteIT.png

Quelle est l’utilité des timers et des interruptions?Les interruptions permettent de gérer des événements qui peuvent avoir lieu n’importe quand, sans avoir à monopoliser le programme. Dans l’exemple précédent, au début du programme, il faut attendre l’appui sur le bouton. Cela a été réalisé par une boucle monopolisant totalement le programme. Avec cette nouvelle solution, de nombreuses opérations peuvent être effectuées en attendant l’appui du bouton. Cet événement déclenche un saut vers une autre portion du programme qui va traiter l’événement et revenir à l’endroit précis ou le programme s’était arrêté.Les timers ont pour but de remplacer les temporisations sous formes de boucles monopolisant elles aussi le programme. Les temps des timers sont calculés directement en fonction de la fréquence de calcul du microcontrôleur. Cela permet de régler des temporisations très précises et indépendantes de ce qui ce passe dans le programme. Lorsqu’un timer est terminé, il déclenche une interruption qui sera géré comme décrit précédemment.

Exemple de calcul du temps pour un timer:

Nous voulons faire clignoter la LED à une fréquence de 1Hz, c’est a dire qu’elle change d’état (allumée ou éteinte) tout les 500 millisecondes.

Il faut quatre périodes d’horloge pour exécuter une instruction dans un PIC. Pour les 32MHz configurés précédemment, on aura 8 millions d’instructions par secondes et donc 4 millions toutes les 500 millisecondes.

Nous allons pour cela utiliser le module timer 1 du pic. C’est un timer 16 bits, c’est à dire qu’il peut compter de 0 à 65536 puis il génère une interruption. Nous allons l’utiliser à sa configuration d’origine, c’est à dire qu’il sera incrémenté à chaque instruction du pic. A 8 millions d’instructions par secondes, c’est à dire 1 instruction toutes les 0,125 microsecondes, il faut 0,125*65536 = 8192 microsecondes pour compter de 0 à 65536. Même avec ses 16 bits, le timer 1 ne nous permet pas de compter directement jusqu’à 500 millisecondes. Il faudra donc rajouter un compteur, c’est à dire que l’action associée au timer 1 ne s’exécutera qu’une fois sur 500/8,192 = 61 occurrences du timer (pour la mise en oeuvre d’un compteur, se référer au programme ci-après).

En simulant le programme ci-après avec les valeurs calculées ci dessus, on a 499.71ms entre chaque changement d’état de la LED. Il est cependant possible d’être plus précis en jouant avec le prédiviseur ou en choisissant un autre timer.

Le programme

#include <p18cxxx.h>        //Définitions des registres du PIC
//bits de configuration, indépendant du programme voir « Help->Topics->PicC18 config settings »
#pragma config OSC = IRCIO67        //Oscillateur interne, RA6 et RA7 sont des ports normaux
#pragma config MCLRE = OFF        //désactiver la pin de Reset
#pragma config LVP = OFF        //Low Voltage Programming désactivé => RB5 I/O normale
#pragma config PBADEN = OFF        //PORTB<4> and PORTB<1:0> Configured as Digital I/O Pins on Reset
#pragma config DEBUG = OFF        //débug désactivé => RB6 et RB7 normal I/O#pragma config FCMEN = OFF        //Fail-Safe Clock désactivée
#pragma config IESO = OFF        //Oscillator Switchover mode désactivé
#pragma config PWRT = OFF        //Power-up Timer désactivé
#pragma config BOREN = OFF        //Reset dû a une tension trop basse désactivé
#pragma config BORV = 2            //Brown-out Reset Voltage
#pragma config WDT = OFF        //Watchdog désactivé
#pragma config WDTPS = 1024        //prédiviseur du watchdog
#pragma config LPT1OSC = OFF         //Low-Power Timer 1 Oscillator Disable ==> high power
#pragma config XINST = OFF        //Instruction set extension and Indexed Addressing mode disabled (Legacy mode)
#pragma config BBSIZ = 1024        //1K words (2K bytes) Boot Block
#pragma config STVREN = OFF        //pas de reset du à la pile
void initialisation(void)
{
    //configuration horloge interne du pic à 32 MHz
    OSCCON = 0x70;        //pas de prédiviseur => 8MHz
    OSCTUNE = 0x40;        //activer la PLL *4 => 32MHz//direction des ports 0=Output, 1= Input par 
    défaut tous à 1
    TRISAbits.TRISA1 = 0;    //patte 1 du port A en sortie
    TRISBbits.TRISB0 = 1;    //patte 0 du port B en entrée//réinitialisation du port
    PORTB=0x00;            //mise à zéro car état indeterminé au démarrage
    //désactiver le module CCP
    CCP1CON=0;
 
    //désactiver le convertisseur analogique numerique
    ADCON1=0x0F;
 
    //configuration du timer 1
    T1CON=0b10000000;    // pas de préscaler et timer pas mis en route
 
    //activation des interruptions
    INTCONbits.GIE = 1 ;    //activation generales des interruptions
    INTCONbits.PEIE = 1 ;     //activation des interruption des péripheriques (comme le timer)
 
    //activation de l’interruption du timer 1
    PIE1bits.TMR1IE = 1 ;    //activation de l’interruption du timer 1
 
    //activation de l’interruption de la patte RB0
    INTCONbits.INT0IE = 1 ;
}
 
void main ()
{
    initialisation();        //initialisation du PIC
    for( ; ; )                //boucle infinie
    {
        //mettre ici le programme principal
    }
}
 
#pragma interrupt InterruptHandler
void InterruptHandler (void)
{
    unsigned short i;    //compteur pour l’antirebond du bouton//variable dont la valeur est conservée entre chaque appel à la fonction et initialisée la première fois à 61
    static unsigned char cpt = 61;
    if(PIR1bits.TMR1IF && PIE1bits.TMR1IE) // si flag d’interruption du timer 1
    {
        cpt–;                //décrementation du compteur
        if(cpt == 0)        //si le compteur est terminé
        {
            PORTAbits.RA1 ^=1;        //changer l’état du bit 1 de PORTA
            cpt=61;            //réinitialisation du compteur
        }
    PIR1bits.TMR1IF = 0;     //réinitialisation du flag d’interruption
    }
 
    if(INTCONbits.INT0IF && INTCONbits.INT0IE)
    {
        T1CONbits.TMR1ON ^= 1;    //active ou desactive le timer 1
        for(i=0;i<30000;i++);    //environ 50ms
        INTCONbits.INT0IF = 0;    //réinitialisation du flag
    }
}
 
#pragma code InterruptVectorHigh = 0x08        //placer le code suivant à l’adresse 0x08
void InterruptVectorHigh (void)
{
    _asm
    goto InterruptHandler //jump to interrupt routine
   _endasm
}

Vous trouverez le fichier main.c ici

Article écrit par AUQUE Martin

6 novembre 2006