User Tools

Site Tools


electronique:msp430:interruptions

Les interruptions sur le MSP430

Voila un bon bout assez intéressant qui est vraiment super pratique.
Reprenons notre deuxième hello-world d'avant, et modifions-le un petit peu:

#include <msp430.h>
#include <legacymsp430.h>
 
#define VERT BIT6
#define ROUGE BIT0
#define BOUTON BIT3
 
void main(void)
{
 
  WDTCTL = WDTPW + WDTHOLD;
 
  P1SEL = 0x00; //tout en GPIO
 
  P1DIR = 0x00; //tout en entrée
  P1DIR = (ROUGE | VERT); // sauf les deux LEDs en sortie
  P1OUT = 0x00; //On éteint toutes les sorties
 
  P1REN = BOUTON; //res de pull sur le bouton
  P1OUT |= BOUTON; //on choisit une pull-up
 
 
  while(1) //notre boucle principale
  {
    //on prend que le bit correspondant au bouton
    //de notre registre P1IN, et on regarde si il est on
    if(P1IN & BOUTON)
    {   
      P1OUT |= VERT; //On fait un and, donc on allume VERT
      __delay_cycles(2500000); //on attemt 250000 cylces
      P1OUT ^= VERT; //et on change le bit VERT (donc off)
    }   
    else
    {   
      P1OUT |= ROUGE;
      __delay_cycles(25000); //et on attend un peu moins, plus sympa
      P1OUT ^= ROUGE;
    }   
 
    __delay_cycles(250000); //on réattent, et on recommence tout :p
  }
}

Ici, j'ai mis un délai assez conséquent pour notre LED verte. Le truc c'est que j'aimerais que quand j'appuye sur mon bouton P1.3, que la LED rouge se mette tout de suite à clignotter
Il y a plusieurs facons de faire ca. Une, toute conne, serait de faire un truc du style:

allumer(led_verte);
while(1)
{
 si(presssé(bouton))
 {
  eteindre(verte); allumer(rouge);
  attendre(x);
  eteindre(rouge)
 }
 allumer(verte);
 attendre(x);
 
}

Ou du genre..

Mais ca, ca peut-être simple dans ce cas, mais c'est vraiment pas du tout optimal. On voudrait aussi bien metrre le µC en veille au lieu de le faire boucle infiniment et de regarder si le bouton a été pressé.
Et les interruptions, c'est cool, par ce que ca permet de:

  • Avoir un code plus “simple”
  • Économiser de l'énergie
  • Commencer à faire un “multitache”
  • Faire des codes plus compliqués tout en étant plus simples
  • Et plein d'autres choses ;)

Déjà, qu'est ce qu'une interruption ?
Ben une interruption, c'est un changement de quelque chose: I/O, compteur, conversion ADC terminée, début de transaction SPI (qui est en fait un changement d'I/O), une attente de disque-dur ou de changement de la position de la souris pour les ordis, etc.. Et le µC va voir se changement, va regarder sa table de correspondance interruption-programme, et va lancer le programme que vous avez codé correspondant à l'interruption donnée.
Une interruption peut survenir n'importe ou dans le code. Et les programmes d'interruption peuvent modifier des variables de votre code. Une fois le programme d'interruption terminé, le code d'avant va continuer. Donc si vous faites un code critique ou rien ne doit changer, vous devez spécifier au µC de désactiver (puis ensuite de réactiver) les interruptions !
Voici le déroulement d'une interruption:

  • Le µC arette ce qu'il était en train de faire
  • Il sauvegarde tout son état d'avant (registres et cie)
  • Il regarde quel programme lancer, correspondant à quelle interruption
  • Éxécute notre programme d'interruption (ISR)
  • Il remet son état initial précédément sauvegardé
  • Et il résume son fil d'éxécution initial

Et à quoi ca sert ?
Ben dans notre cas, si vous attendez quelque-chose (qu'un bouton soit pressé), pas besoin de faire un truc spécial dans votre boucle principale. Il suffit de créer une “fonction d'interruption” qui se chargera de faire ca que quand l'évenement arrivera.
Dans les ordinateur de nos jours, les interruptions “s'activent” plusieurs miliers de fois par seconde (souris, clavier, son, réseau, etc…). Pour cela, un programme d'interruption doit être court* et rapide à éxécuter ! Dans un µC, c'est la même chose, quand vous commencerez à faire des trucs sympa ou le µC fait presque du “temps-réel” avec plein de choses à la fois (un jeu, par exemple), vous ne voulez-pas que vos interruptions soient lentes..
Si votre code à juste besoin de s'aciver quand vous appuyez sur un bouton, vous pouvez mettre le µC en veille. Dans le cas des µC M430G
*, nous pouvons passer d'une consommation de ~250µA (fréquence du µC au max, timers et cie) à une conso de 0.1µA (CPU éteint, que la sauvegarde de la RAM est active) !

Voici le code final supportant les interruptions

#include <msp430.h>
#include <legacymsp430.h>
 
#define VERT BIT6
#define ROUGE BIT0
#define BOUTON BIT3
 
void main(void)
{
  WDTCTL = WDTPW + WDTHOLD;
 
  P1SEL = 0x00; //tout GPIO
  P1DIR = 0x00; //tout entrée
  P1DIR |= (ROUGE | VERT);
 
  P1REN = BOUTON; //Resistor ENable de pull sur bouton
  P1OUT = 0x00; //toute les sorties en off
  P1OUT |= BOUTON; //Mais on pull-up bouton
 
  P1IFG &= ~BOUTON; //On enlève l'interruption de BOUTON
  P1IE |= BOUTON;    //Et on active l'interruption de BOUTON 
 
  eint(); //et on active les interruptions en général
 
  while(1) //Notre boucle générale
  {
    P1OUT &= ~VERT; //on éteint vert
    __delay_cycles(250000);
    P1OUT |= VERT;
    __delay_cycles(2500000);
  }
}
 
interrupt (PORT1_VECTOR) Port_1(void)
{
  //tant qu'il est appuyé
  while(!(P1IN & BOUTON))
  {
    P1OUT &= ~VERT; //on éteint VERT;
    P1OUT |= ROUGE;
    __delay_cycles(25000);
    P1OUT ^= ROUGE; //on éteint (toogle) rouge
    __delay_cycles(25000);
    P1IFG &= ~BOUTON; //on enlève l'interrupt
  }
    P1OUT |= VERT; //on rallume VERT
}

Discussion

Enter your comment. Wiki syntax is allowed:
MMVSG
 
electronique/msp430/interruptions.txt · Last modified: 2012/07/14 17:16 by frank