Vous êtes sur la page 1sur 7

Utilisation des interruptions avec le PIC

Claude Barbaud 10 janvier 2011

Principe:
Le fonctionnement par interruptions sur un microcontrôleur permet à celui-ci
d'exécuter une tâche(programme principal) qui peut être interrompue par un
événement. Le processeur doit alors exécuter une tâche(sous-programme)
associée à cette source d'interruption. Quand la tâche est exécutée, le processeur
revient à sa tâche principale.

On peut faire une analogie avec quelqu'un qui fait la cuisine tranquillement: il
peut être interrompu par plusieurs sources: la sonnette de la maison, le téléphone,
la minuterie de ses appareils de cuisson, le détecteur de fumée. Il doit traiter
l'événement avant de revenir à sa tâche principale. Le traitement de ces
évènements peut lui-même être interrompu par un événement jugé plus important.

De la même façon, avec un système ordiné, on doit souvent définir des priorités
dans les interruptions:
 Le traitement d'une interruption peut être interrompu par une interruption
qui lui est prioritaire.
 Le traitement d'une interruption ne doit pas être interrompu par une
interruption de niveau inférieur.
 Le traitement d'une interruption ne peut être interrompu par aucune autre.

Sources d'interruptions
Les interruptions peuvent être causées par des sources externes ou par des sources
internes

Sources externes:
 broches parallèles (Exemples: clavier, alarme)
 ports séries

Sources internes
 Timer
 Convertisseur A-N
 Reset

19-1
Exemple[PIC]: Interruption avec une source externe:
RB0
// Claude Barbaud 24 janvier 2005
//----------------------------------------------------------------
// INT_EXT.C
//
// Exemple d'utilisation de l'interruption externe.
// Chaque fois qu'il y a une interruption on fait
// clignoter le led temoin.
// la source d'interruption est un front descendant sur RB0
//----------------------------------------------------------------
#include "16F876.H"
#fuses HS,NOWDT,PUT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use RS232(Baud=19200,Xmit=PIN_C6,Rcv=PIN_C7, bits=8, errors)

#define LED PIN_A5 // Led temoin


void cligne(int x); // prototype de la fonction cligne()
//------------------------------------------------------//
// Sous programme de traitement de l'interruption //
// externe //
//------------------------------------------------------//
#int_ext // Cette directive indique que la fonction
// suivante est la tache de l'interruption
rb_ext( ) // fonction sans parametres
{
cligne(2);
}

//-------------------- Programme principal -----------------------


void main(void)
{
ext_int_edge(H_TO_L); // Front descendant
enable_interrupts(INT_EXT); // Valide l'interruption sur RB0
enable_interrupts(GLOBAL); // Valide les interruptions
cligne(4);

while(1); // ce programme ne fait rien


}

//---------------------------------------------------//
// void cligne(int x) //
// //
// Clignotement de la led verte x fois a //
// intervalle de 200 ms. //
//-------------------------------------------------- //
void cligne(int x)
{
int i;
for (i=0; i<x; ++i)
{
output_low(led);
delay_ms(80);
output_high(led);

19-2
delay_ms(80);
}
}

Source de l'interruption
La source de l'interruption est indiquée au début du sous-programme d'interruption par la
directive #int_ext . Cette directive identifie RB0 comme source de l'interruption.

Autre directive concernant les sources externes:


#int_rb changement sur B4-B7

Seules les broches définies en entrée peuvent déclencher une interruption. Ces directives
ne discriminent pas quelle entrée est la source, mais on peut utiliser bit_test()

Validation de l'interruption
L'interruption ne peut être active que si elle est validée
enable_interrupts(INT_EXT); // Valide l'interruption sur RB0
enable_interrupts(GLOBAL); // validation globale

L'interruption doit être validée individuellement (INT_EXT) et globalement.

On peut interdire une interruption par l'instruction disable_interrupt() Les paramètres sont
les mêmes:
disable_interrupts(INT_EXT);
disable_interrupts(GLOBAL);

 Gestion des priorités des interruptions

Exemple[PIC]: Interruption externe par B4-B7


// Claude Barbaud 24 janvier 2005
//----------------------------------------------------------------
// INT_RB.C
//
// Exemple d'utilisation de l'interruption externe.
// Chaque fois qu'il y a une interruption on fait
// clignoter le led temoin.
// la source d'interruption est un changement sur B4_B7
//----------------------------------------------------------------
#include "16F876.H"
#fuses HS,NOWDT,PUT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use RS232(Baud=19200,Xmit=PIN_C6,Rcv=PIN_C7, bits=8, errors)

#byte port_b = 6 // adresse du port B

#define LED PIN_A5 // Led temoin


void cligne(int x); // prototype de la fonction cligne()
//------------------------------------------------------//
// Sous programme de traitement de l'interruption //
// externe //
//------------------------------------------------------//

19-3
#int_rb
rb_ext( )
{
int lecture;
disable_interrupts(GLOBAL); // Evite de s'interrompre soi-meme
lecture = port_b & 0xF0; // isole les 4 bits d'en haut
if(bit_test(lecture, 4)) // on peut tester les bits pour
// decider des actions

cligne(4);

if(bit_test(lecture, 7))
cligne(7);
enable_interrupts(GLOBAL);
}

//-------------------- Programme principal -----------------------


void main(void)
{
set_tris_b(0xFF); // port_b en entree
enable_interrupts(INT_RB); // Valide l'interruption sur B4-B7
enable_interrupts(GLOBAL); // Valide les interruptions
cligne(4);

while(1); // ce programme ne fait rien


}

//---------------------------------------------------//
// void cligne(int x) //
// //
// Clignotement de la led verte x fois a //
// intervalle de 200 ms. //
//-------------------------------------------------- //
void cligne(int x)
{
int i;
for (i=0; i<x; ++i)
{
output_low(led);

delay_ms(200);
output_high(led);
delay_ms(200);
}
}

19-4
Exemple[PIC]: Interruption de source interne: Timer 1
// Isidore Lauzier 10/3/02 - CCS C
//----------------------------------------------------------------//
// Timer1.c //
// Démonstration de l'utilisation du timer1 //
// Le timer est programmé en tranches de 100 ms. On affiche //
// l'heure, les minutes et les secondes. //
//----------------------------------------------------------------//
#include <16F876.H>
#device ADC=10
#device PIC16F876 *=16
#fuses HS,NOWDT,PUT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use RS232(Baud=19200,Xmit=PIN_C6,Rcv=PIN_C7, bits=8, errors)

#bit TMR1IF = 0x0C.0 // Indicateur d'int. du timer1


#define TEMOIN PIN_A5

void cligne(int x);

//------------------ Variables globales --------------------------


int ms_100;
short sec;

//----------------------------------------------------------------
// #int_timer1
// Gestion des interruptions pour le chronométrage avec le
// timer1. Il est nécessaire de recharger le compteur à nouveau
// à chaque interruption. Il faut ajouter le temps de latence,
// soit le contenu du timer1 et le délai causé par la lecture
// et le chargement de cette valeur.
//----------------------------------------------------------------
#int_timer1 // Cette fonction est appelée à chaque
clock_isr1() { // 8 débordements du timer1 (65535->0).
long int cycles;
setup_timer_1(T1_DISABLED); // Arrêt pour le chargement
cycles = get_timer1(); // Temps de latence
cycles = cycles + 3038; // (65535-62500)=3035+(25/div8)=3038
set_timer1(cycles);
setup_timer_1( T1_INTERNAL | T1_DIV_BY_8 ); // tranche de 100 ms
--ms_100;
if (!ms_100) {
sec=TRUE;
ms_100=10;
}
}

//---------------------- Programme principal ----------------------

main() {
int i, min;
cligne(1); // Témoin

19-5
ms_100=10;
i=0;
min=0;
sec=FALSE;
set_timer1(3035); // 65535-62500 = 100 ms avec
setup_timer_1( T1_INTERNAL | T1_DIV_BY_8 ); // un cristal de 20
mHz.
TMR1IF=0; // Reset de l'indicateur d'int. du
timer1
enable_interrupts(int_timer1);
enable_interrupts(GLOBAL);
do {
if (sec) {
i++;
if (i==60) {
i=0;
++min;
if (min==60) min=0;
}
printf("\r%2u:%2u",min,i);
sec=FALSE;
}
} while (TRUE);

disable_interrupts(int_timer1); // avec un crystal de 20 mHz.


}

//---------------------------------------------------//
// void cligne(int x) //
// //
// Clignotement de la led témoin x fois à //
// intervalle de 200 ms. //
//-------------------------------------------------- //
void cligne(int x) {
int i;
for (i=0;i<x;i++) {
output_high(TEMOIN);
delay_ms(100);
output_low(TEMOIN);
delay_ms(100);
}
}

19-6
Exemple: utilisation des changements sur RB7-RB5
//------------------------------------------------------//
// Claude Barbaud 25 janvier 2005 //
// Ce programme montre l'utilisation des changements de //
// B5 - B7 comme source d'interruption //
//------------------------------------------------------//

#include <16F876.H>

#fuses HS,NOWDT,NOPROTECT
#use delay(clock=20000000)

#use RS232(Baud=19200,Xmit=PIN_C6,Rcv=PIN_C7, bits=8, errors)

#byte port_b = 6
#define in 0xe0;

int last_b; // memorisation de l'ancienne valeur du port


int cmpt1, cmpt2, cmpt3;

//-------sous-programme de traitement de l'interruption--------//


#int_rb
rb_isr( ) {
byte changes;
output_low(PIN_B0);

delay_ms(100); // anti-rebond
changes = port_b & 0xe0; // RB7, RB6, RB5
if (bit_test(changes,5) != bit_test(last_b,5)) cmpt1= cmpt1+1;
if (bit_test(changes,6) != bit_test(last_b,6)) cmpt2= cmpt2+1;
if (bit_test(changes,7) != bit_test(last_b,7)) cmpt3= cmpt3+1;
last_b = changes;
printf("\n\rB5 = %u B6 = %u B7 = %u",cmpt1, cmpt2,cmpt3);
output_high(PIN_A5);
}

Main() {
set_tris_b(0xe0);
cmpt1=cmpt2=cmpt3=0;
last_b = port_b & 0xe0;
disable_interrupts(GLOBAL);
enable_interrupts(RB_CHANGE); // RB_CHANGE = INT_RB
enable_interrupts(GLOBAL);

for (;;) ;

19-7