Catégories
Arduino Interruption Arduino pwm

Arduino #36: les interruptions -Générateur PWM avec INT0

Interruption INT0 arduino

Objectifs

  1. Savoir implémenter les interruptions externes INT0, INT1,…, INTn
  2. Exemple 1: Diviseur de fréquence PWM par 2 (8 sorties synchrones)
  3. Exemple 2: Synthèse de 8/16/32 sorties PWM synchrones

On va aborder à travers deux exemple les aspects pratiques des interruptions externes, en particulier les interruptions INT (INT0, INT1, etc.). La carte Arduino Mega dispose de 8 sources d’interruptions INT : INT0-INT7. Ces derniers sont câblés dans les deux port D et E pour la carte Arduiono Mega.

INT0-INT3 : PORTD0- PORTD3

INTERRUPTION INT PORT D

INT4-INT7 : PORTE4- PORTE7

INTERRUPTION INT PORT E

 

Vecteurs & routines d’interruptions

Nous avons abordé dans l’introduction aux interruption la notion du vecteur d’une interruption. En effet, chaque interruption est caractérisée par un vecteur, un numéro, indiquant sa priorité. L’interruption RESET dispose d’un vecteur égal à 1 (2 pour INT0, 3 pour INT1, etc.), elle la plus prioritaire.

vecteur interruption

Le vecteur permet également d’exécuter la routine ISR(). L’IDE Arduino dispose par défaut des variables prédéfinies pour spécifier un vecteur quelconque. Le nombres d’interruption (disponibilité d’un vecteur) va dépendre de la carte Arduino utilisée. En pratique, on consulte le tableau des sources d’interruptions pour connaitre le nombre et les nom s de sources d’interruptions. La syntaxe préfinie pour spécifier un vecteur est la suivante : NOM_vect.

ISR(INT0_vect){…}           // Interruption INT0
ISR(INT1_vect){…}           // Interruption INT1
ISR(INT2_vect){…}           // Interruption INT2

Donc, il faut connaitre les variables prédéfinies (INT0_vect, INT1_vect, …) pour les différentes interruptions. Il se peut que vous ne savez pas le nom exact pour déclencher votre routine ISR. Par exemple, pour les périphériques ayant des noms composes. Dans ce cas, il faut utiliser la syntaxe originale pour déclencher ISR de la façon suivante : _VECTOR(numéro du vecteur).

ISR(_VECTOR(1)){…}       // Interruption RESET
ISR(_VECTOR(2)){…}       // Interruption INT0
ISR(_VECTOR(3)){…}       // Interruption INT1
#define INT0_vect _VECTOR(1) /* External Interrupt Request 0 */
#define INT1_vect _VECTOR(2) /* External Interrupt Request 1 */
#define PCINT0_vect _VECTOR(3) /* Pin Change Interrupt Request 0 */
#define PCINT1_vect _VECTOR(4) /* Pin Change Interrupt Request 1 */
#define PCINT2_vect _VECTOR(5) /* Pin Change Interrupt Request 2 */
#define WDT_vect _VECTOR(6) /* Watchdog Time-out Interrupt */
#define TIMER2_COMPA_vect _VECTOR(7) /* Timer/Counter2 Compare Match A */
#define TIMER2_COMPB_vect _VECTOR(8) /* Timer/Counter2 Compare Match A */
#define TIMER2_OVF_vect _VECTOR(9) /* Timer/Counter2 Overflow */
#define TIMER1_CAPT_vect _VECTOR(10) /* Timer/Counter1 Capture Event */
#define TIMER1_COMPA_vect _VECTOR(11) /* Timer/Counter1 Compare Match A */
#define TIMER1_COMPB_vect _VECTOR(12) /* Timer/Counter1 Compare Match B */
#define TIMER1_OVF_vect _VECTOR(13) /* Timer/Counter1 Overflow */
#define TIMER0_COMPA_vect _VECTOR(14) /* TimerCounter0 Compare Match A */
#define TIMER0_COMPB_vect _VECTOR(15) /* TimerCounter0 Compare Match B */
#define TIMER0_OVF_vect _VECTOR(16) /* Timer/Couner0 Overflow */
#define SPI_STC_vect _VECTOR(17) /* SPI Serial Transfer Complete */
#define USART_RX_vect _VECTOR(18) /* USART Rx Complete */
#define USART_UDRE_vect _VECTOR(19) /* USART, Data Register Empty */
#define USART_TX_vect _VECTOR(20) /* USART Tx Complete */
#define ADC_vect _VECTOR(21) /* ADC Conversion Complete */
#define EE_READY_vect _VECTOR(22) /* EEPROM Ready */
#define ANALOG_COMP_vect _VECTOR(23) /* Analog Comparator */
#define TWI_vect _VECTOR(24) /* Two-wire Serial Interface */

Attention: _VECTOR(1) pour INT0, _VECTOR(2) pour INT1, etc.

Exemple 1: Diviseur de la fréquence par 2

L’objectif de l’exemple sera de diviseur la fréquence d’un signal PWM par 2 en utilisant l’interruption externe INT0. Ensuite, générer 8 sorties PWM synchrones ayant ½ la fréquence du signal PWM. On va utiliser le pin 2 de la carte Arduino pour générer le signal PWM de référence. Ce dernier sera ensuite câblé avec le pin 21 de la même carte. Sachant que l’interruptions INT0 est câblée avec le même pin, par conséquence, la routine de l’interruption sera exécutée à la présence d’un évènement dans le pin 21 de la carte Arduino. Dans cet exemple, on utilisera la détection par front montant.  Dès la présente d’un front montant sur le pin, on inverse l’état du port A (sur 8 bits). Ayant comme conséquence la génération de 8 sorties PWM avec une fréquence égale à la moitié du signal PWM de référence (voir la vidéo pour plus de détails).

Interruption int0 exemple 1

#define PWMout  2   // Signal PWM de référence 

bool State=false;

void setup()
{
// Initialisation de la sortie PWM (signal carré, rapport cyclique 50%)
analogWrite(PWMout, 128);

// Câblage du pin et configuration en entrée: INT0 => PD0 (pin 38 de la carte)
DDRD =0x00; // Port D en entrée

// Activation de l'interruption globale (registre SREG)
SREG|=0x80;
//SREG|=0x80 // Activation
//SREG&=0x7f // Désactivation
//Ou bien
//sei(): Set interrupt - Activation
//cli(): clear interrup - Désactivation (masquer)

// Validation de l'interruption INT0 (Registre EIMSK)
EIMSK|=0x01; // INT0
//EIMSK|=0x02; // INT1
//EIMSK|=0x04; // INT0
//...
// Choix du mode de détection: Front montant dans INT0
EICRA|=0x03;
//EICRA|=0x00; //niveau bas '0' dans INTn
//EICRA|=0x01; //front montant ou descendant dans INTn
//EICRA|=0x02; //Front descendant dans INTn
//EICRA|=0x03; //Front montant dans INTn

// Initialisation du port A en sortie
DDRA =0xff;
PORTA=0x00;
}

void loop()
{
// Au chaumage
}

// Routine d'interruptions : Pour chaque front montant on inverse l'état
// du port A (8 sorties synchrones)

ISR(INT0_vect){
State=not(State);
PORTA=State*0xff; //State&0xff;
}

Exemple2: Générateur PWM 1 VERS 8

Même code de l’exemple 1 avec une détection par front montant & descendant. La technique va nous permettre des signaux PWM synchrones ayant la même fréquence de celui du signal de référence. Dans cet exemple, le registre EICRA sera chargé avec le mot 0x01.

Interruption int0 exemple 2

#define PWMout  2

bool State=false;

void setup()
{
// Initialisation de la sortie PWM (signal carré)
analogWrite(PWMout, 128);

// Câblage du pin et configuration en entrée: INT0 => PD0 (pin 21 de la carte)
DDRD =0x00; // Port D en entrée

// Activation de l'interruption globale (registre SREG)
SREG|=0x80; // Ou bien sei();

// Validation de l'interruption INT0 (Registre EIMSK)
EIMSK|=0x01;

// Choix du mode de détection: Front montant & descendant dans INT0
EICRA|=0x01;

// Initialisation du port A en sortie
DDRA =0xff;
PORTA=0x00;
}

void loop()
{
// Au chaumage
}


// Routine de l’interruption: Pour chaque front montant & descendant on inverse l'état
// du port A (8 sorties synchrones)

ISR(INT0_vect){
State=not(State);
PORTA=State*0xff; //State&0xff;
}

Détection par niveau bas (Modulation d’amplitudes, voir la vidéo)

Interruption int0 niveau bas

Rapport cyclique non égal à 50% (convertisseur PWM => Signal carré, voir la vidéo)

Laisser un commentaire