Projet Led haute puissance avec recepteur de modelisme

Bonjour à tous, je réalise un petit projet en vue d'equiper un avion de modelisme. Je pilote 2 leds haute puissance 10w
Je réalise un strobe. Voila j'utilise une arduino nano et je mesure via l'entrée D4 la valeur renvoyé par mon recepteur RC pour changer de programme.

Mon probleme est que le changement de programme est assez aléatoire vu que la boucle de mon programme doit se terminer.
Parfois je saute un programme aussi ...
Comment je pourrais faire pour que le changement de programme soit instantanée ?
Mon programme.

int ledGreen = 11;
int ledBlue = 9;
int ledRed = 10;
int ledWhite = 5;
int rcreceiver;
int Prog;




void setup() {
  Serial.begin(9600);
  pinMode(ledGreen, OUTPUT);     
  pinMode(ledBlue, OUTPUT); 
  pinMode(ledRed, OUTPUT);
  
  pinMode(ledWhite, OUTPUT);
  
  pinMode(4, INPUT);
  
  Prog=1;

}

int strobe(int fadeRed, int fadeGreen, int fadeBlue)
{
  analogWrite(ledWhite, 255); 
  delay(50);
  analogWrite(ledWhite, 0); 
  delay(100);
  analogWrite(ledWhite, 255); 
  delay(50);
  analogWrite(ledWhite, 0); 
  delay(100);
  analogWrite(ledWhite, 255); 
  delay(50);
  analogWrite(ledWhite, 0); 
  delay(100);
  analogWrite(ledWhite, 255); 
  delay(50);
  analogWrite(ledWhite, 0);
  analogWrite(ledRed, fadeRed);
  analogWrite(ledGreen, fadeGreen);
  analogWrite(ledBlue, fadeBlue);
  
  delay(600);
  analogWrite(ledRed, 0);
  analogWrite(ledGreen, 0);
  analogWrite(ledBlue, 0);

}


void loop() {

if (Prog==1)
{
strobe(127,0,0);
  strobe(127,255,0);
  strobe(0,255,0);
  strobe(0,255,255);
  strobe(0,0,255);
  strobe(127,0,255);
  strobe(127,255,255);
}
    

if (Prog==2)
{
  strobe(0,255,0);   
    
    
}
if (Prog==3)
{
strobe(127,0,0);

}
if (Prog==4)
{
analogWrite(ledWhite, 0);
  analogWrite(ledRed, 0);
  analogWrite(ledGreen, 0);
  analogWrite(ledBlue, 0);

}
rcreceiver = pulseIn(4, HIGH, 25000);
if (rcreceiver <=1200)
{
Prog++;
delay(100);
if (Prog >4) Prog=1;
}
if (rcreceiver <=800)
{
Prog=4;
}
}

Cordialement,
bypbop

Bonjour,

Si je comprend bien tu veux pouvoir changer de programme pendant qu'un autre est en cours ?
Si oui il va falloir revoir tout ton programme en non-bloquant (sans delay, ni pulseIn), ou utiliser une RTOS pour avoir deux taches en pseudo-parallèle.

Salut,

Je te conseille de zieuter du côté des interruptions : laboelectronique.be - laboelectronique Resources and Information.
Ca te permettra de te passer de pulseIn.

Sinon pour la" lenteur" c'est parce que tu utilise des delay() forcement bloquant. Il faut utiliser millis() pour faire quelque chose de réactif [Tutorial] Les interruptions temporelles avec Arduino | B@ttoMicro - Microcontrôleurs et compagnie !

Il suffit de scruter millis() et de gérer des étapes. Ta première partie de strobe() pourrais se résumer par :

#define ledWhite 5

unsigned long top,delai;

void setup() {

pinMode(ledWhite, OUTPUT);
top = millis();
analogWrite(ledWhite, 255); 
delai=50

}

void loop() {

if((top+delai)<=millis()) {

top=millis();

if (delai==50) {
delai=100;
analogWrite(ledWhite,0); 
}
else {
analogWrite(ledWhite, 255); 
delai=50;
}

}

B@tto : tu remplaces pas pulseIn par une interruption :wink:
Ou alors ça veut dire que tu vas utiliser millis()/micros() derrière pour traiter le signal ce qui est ... ultra chiant (cf code de réception pour les modules blyss d'il y a quelques temps) et peu précis si le signal de contrôle est court.

Pour remplacer le pulseIn bloquant par un équivalent non bloquant il faut détourner un timer (Timer2 par exemple) pour le faire fonctionner en compteur avec la broche ICP (input capture pin) correspondante.
Voir http://www.atmel.com/images/doc8014.pdf pour les détails d'implémentation.

Ainsi à chaque front du signal de contrôle, une interruption avec la longueur du front est générée. Dans l'interruption il faudra refaire le filtrage du code d'origine pour changer le n° de programme.
Dans le code de loop() il faudra refaire la gestion des programmes en non bloquant avec millis() et des tests en fonction de chaque programme possible (c'est long mais c'est plus simple que d'utiliser un RTOS ou de faire un planificateur).

skywodd:
B@tto : tu remplaces pas pulseIn par une interruption :wink:
Ou alors ça veut dire que tu vas utiliser millis()/micros() derrière pour traiter le signal ce qui est ... ultra chiant (cf code de réception pour les modules blyss d'il y a quelques temps) et peu précis si le signal de contrôle est court.

Faire deux relevé de micros() = ultra chiant ?! On m'avait dit que les programmeur était des fainéants mais la :smiley:

La on parle de remplacer un pulseIn(), pas de décoder une trame. Et le signal sera de l'ordre de la ms, largement compatible avec micros().

volatile byte flag=0;
volatile unsigned long time,result;

void setup() {
attachInterrupt(4,pulse,RISING);
}

void pulse() {

detachInterrupt(4);

if(flag) {

result=micros()-time;
faitCeQueTuVeuxAvecResult();
attachInterrupt(4,pulse,RISING);

}else {

time=micros();
attachInterrupt(4,pulse,FALLING);
}

flag=!flag;

}

void loop() {}

Je pense que tu devrais aller jeter un œil ici:

http://johnlenfr.1s.fr/index.php?option=com_rokdownloads&view=folder&Itemid=122&id=1002:pwmled
http://johnlenfr.1s.fr/index.php?option=com_content&view=article&id=470:telemetrie-graupner-lipometre11&catid=59:lipometre-hott&Itemid=110

Là:

et là:
http://johnlenfr.1s.fr/index.php?option=com_content&view=article&id=507:dji-f550-flame-wheel-montage-leds-mod&catid=67:dji-f550-flame-wheel-quadcopter&Itemid=117

:wink:

J'ai oublié ici:

Tu peux demander le code à Unisev, je sais qu'il traine par ici aussi. A voir avec lui s'il serait d'accord pour t’envoyer un code.
Et après faut être capable de le comprendre...

Merci pour vos messages je regarde tout j'avais essayé avec une interruption aussi et j 'avais le mm probleme.
Donc je vais regarder dans un premier tps m occuper des programmes dans la boucle loop.

je reviens vers vous ...

Cordialement,
bypbop

Re bonjour à tous cela fait drole de penser sequentiel et ensuite penser pseudo multitache ...

J essaye depuis debut d aprés midi a faire une petite sequence allumer une led et puis l autre en utilisant millis() et je n arrive pas ...
Enfin avec une oui je comprends mais deux .... no comment ... Mais c est normal faut que cela rentre !!!

Alors j'ai fait ceci ... d'aprés le post de b@tto

Je verrais par la suite l'interruption ...

int ledWhite = 5;
int ledGreen = 11;
int ledRed = 10;


int led = 1;

unsigned long top,delai;
 
 
void setup() {
    Serial.begin(9600);
    pinMode(ledRed, OUTPUT);
    pinMode(ledGreen, OUTPUT);  
    pinMode(ledWhite,OUTPUT);
 
    top = millis(); // Enregistrement de mon point de départ
 
   delai=100;
 
}
 
 
void loop() {

if((top+delai)<=millis()) {
top=millis();
  if (led==1){

    if (delai==50) {
    delai=100;
     
    analogWrite(ledWhite,0);
    analogWrite(ledGreen,0);
    }
    else {
    analogWrite(ledWhite, 255);
    analogWrite(ledGreen,0);
    delai=50;
    }

  led=2;
  }
  if (led==2){


    
    if (delai==50) {
    delai=100;
    analogWrite(ledGreen,0);
    analogWrite(ledWhite,0);
    }
    else {
    analogWrite(ledGreen, 255);
    analogWrite(ledWhite,0);
    delai=50;
    }
  led=1;
  }
} 
}

et le resultat est catastrophique lol je n'arrive pas trop a comprendre pourquoi !!!

Cordialement;
bypbop

dans
if (led==1)
tu passe
led=2
et ensuite tu test si led==2, ce qui est forcement vrai.

ce que tu cherche a faire, c'est un genre de sequenceur?
tu peut t'inspirer de ca, le code est non-bloquant:

int ledWhite = 5;
int ledGreen = 11;
int ledRed = 10;


int led = 1;

int tache=0;  // equivalent de ta variable led
boolean tacheDone=false;  // indique si la tache a été executé ou pas encore

unsigned long top,delai;
 
 
void setup() {
    Serial.begin(9600);
    pinMode(ledRed, OUTPUT);
    pinMode(ledGreen, OUTPUT);  
    pinMode(ledWhite,OUTPUT);
 
    top = millis(); // Enregistrement de mon point de départ
 
   delai=100;
 
}
 
void loop() {

// gestionnaire du sequenceur de taches
  if((top+delai)<=millis()) {
    tache +=1;
    if (tache>3){tache=0;}
    // a chaque chagement du sequenceur, on met reinit tacheDone et le temps de la tache
    // c'est dans la tache qu'on defini son timing (bof, c'est ce que tu veux, donc ca ira)
    tacheDone == false;
    top=millis();
  }
  
// sequenceur de taches
  if (tacheDone == false){
    if (tache == 0) {
      analogWrite(ledWhite,0);
      analogWrite(ledGreen,0);
      delai=100;
      tacheDone =true;
    }
    if (tache == 1) {
      analogWrite(ledWhite, 255);
      analogWrite(ledGreen,0);
      delai=50;
      tacheDone =true;
    }
    if (tache == 2) {
      analogWrite(ledGreen,0);
      analogWrite(ledWhite,0);
      delai=50;
      tacheDone =true;
    }
    if (tache == 3) {
      analogWrite(ledGreen, 255);
      analogWrite(ledWhite,0);
      delai=50;
      tacheDone =true;
      }

  }
}

Merci jean-l, je comprends mieux maintenant !!

Dans le void set up il y a avait juste une petite erreur dans ton code : j'ai remplacé tacheDone == false par tacheDone = false; surement une faute de frappe :wink:

Le code marche parfaitement mais je me pose une petite question maintenant ! Comme je vais coder plusier programme vu que j'ai une led blanche et une autre RGB !! le codage des sequence va etre surement trés long en ligne ....

Est ce que je pourrais faire la mm chose en codant un tableau du genre :

LEDBLANCHEPWM 0
LEDRGBBLEU 0
LEDRGBROUGE 0
LEDRGBVERT 0
DELAI 50

et boucler dessus avec le delai dans le millis ?? comme cela je pourais definir mes programmes séparément du loop()

Cordialement,
bypbop

faute de frappe, je l'ai fait a l'aveugle.

non, tu n'as pas la bonne methode.
ce qu'il te faut (par exemple) c'est un tableau qui definisse tes sequences/durées.

//struct = delai, LEDBLANCHEPWM, LEDRGBBLEU, LEDRGBROUGE, LEDRGBVERT
int sequences[10][5]={
{5000, 100, 10, 20, 0,}, //seq0
{4000, 255, 255, 80, 70,}, //seq1
{3000, 0, 100, 20, 30,}, //seq2
{2000, 0, 0, 0, 0,}, //seq3
{1000, 0, 0, 0, 0,}, //seq4
{500, 0, 0, 0, 0,}, //seq5
{5000, 0, 0, 0, 0,}, //seq6
{2000, 0, 0, 0, 0,}, //seq7
{2000, 0, 0, 0, 0,}, //seq8
{5000, 0, 0, 0, 0,}, //seq9
};

ensuite tu parcours tes 10 sequences

// gestionnaire du sequenceur de taches
  if((top+delai)<=millis()) {
    tache +=1;
    if (tache>9){tache=0;}
    // a chaque chagement du sequenceur, on met reinit tacheDone et le temps de la tache
    // c'est dans la tache qu'on defini son timing (bof, c'est ce que tu veux, donc ca ira)
    tacheDone == false;
    top=millis();
    delai=sequences[tache][0];  // delai peut etre geré ici ou dans tache
  }

// sequenceur de taches
  if (tacheDone == false){
      analogWrite(ledWhite,sequences[tache][1]);
      analogWrite(ledRed,sequences[tache][2]);
      analogWrite(ledBlue,sequences[tache][3]);
      analogWrite(ledGreen,sequences[tache][4]);
      //delai=sequences[[tache][0];
      tacheDone =true;
    }

c'est tout

Magnifique !!! cela fonctionne parfaitement demain je planche sur l'interruption et le changement de programme :wink:

Encore Merci Jean-l

int ledWhite = 5;
int ledGreen = 11;
int ledRed = 10;
int ledBlue= 9;

int Sequence[10][5] = {
{255, 0  , 0 , 0  , 50},
{0, 0  , 0 , 0  , 200},
{255, 0  , 0 , 0  , 50},
{0, 0  , 0 , 0  , 200},
{255, 0  , 0 , 0  , 50},
{0, 0  , 0 , 0  , 200},
{255, 0  , 0 , 0  , 50},
{0, 0  , 0 , 0  , 200},
{255, 0  , 0 , 0  , 50},
{0, 128  , 0 , 0  , 100},
};


int tache=0;  // equivalent de ta variable led
boolean tacheDone=false;  // indique si la tache a été executé ou pas encore

unsigned long top,delai;
 
 
void setup() {
    Serial.begin(9600);
    pinMode(ledRed, OUTPUT);
    pinMode(ledGreen, OUTPUT);  
    pinMode(ledWhite,OUTPUT);
 
    top = millis(); // Enregistrement de mon point de départ

 
}
 
void loop() {

// gestionnaire du sequenceur de taches
  if((top+delai)<=millis()) {
    tache +=1;
    if (tache > 9){tache=0;}
    // a chaque chagement du sequenceur, on met reinit tacheDone et le temps de la tache
    // c'est dans la tache qu'on defini son timing (bof, c'est ce que tu veux, donc ca ira)
    tacheDone = false;
    top=millis();
  }
  
// sequenceur de taches
  if (tacheDone == false){
      analogWrite(ledWhite,Sequence[tache][0]);
      analogWrite(ledRed,Sequence[tache][1]);
      analogWrite(ledGreen,Sequence[tache][2]);
      analogWrite(ledBlue,Sequence[tache][3]);
      delai=Sequence[tache][4];
      tacheDone =true;

}
}

Cordialement,
bypbop

Par contre j'ai essayé de faire une petite modif pour ajouter des sequences et connaitre la taille du tableau en faisant ceci

int Sequence[][5] = {
{255, 0  , 0 , 0  , 50},
{0, 0  , 0 , 0  , 200},
{255, 0  , 0 , 0  , 50},
{0, 0  , 0 , 0  , 200},
{255, 0  , 0 , 0  , 50},
{0, 0  , 0 , 0  , 200},
{255, 0  , 0 , 0  , 50},
{0, 0  , 0 , 0  , 200},
{255, 0  , 0, 0  , 50},
{0, 0  , 255, 0  , 300},
{0, 128  , 0 , 0  , 300},
{0, 0  , 0 , 255  , 300},
};

et ceci : if (tache > siseof(Sequence)){tache=0;}

et cela ne fonctionne pas ??

en memoire, ta sequence est une suite de int.
un int prend 2 octet.
sizeof renvoi l'occupation memoire du tableau en octet.
1052=100.

donc
if (tache > (siseof(Sequence)/10)-1){tache=0;} // /10 parce que 5*2=10, et -1 parce qu'on part de zero

Merci bien cela fonctionne parfaitement ! ok pour l 'explication !!

Cordialement,
bypbop

Voila j'ai testé l'interruption sur le post de b@tto et je n'ai aucun resultat dans result

j'ai fait volontairement un Serial.println(result); pour voir si il y avait des varations de result mais aucun ...
J'utilise sur ma nano la pin D2 qui correspond à l interruption avec le timer1.

En fait j'aimerais avoir la variation du signal de mon recepteur RC pour enclencher le changement de programme par la suite

int ledWhite = 5;
int ledGreen = 11;
int ledRed = 10;
int ledBlue= 9;

int tache=0;  // tache en cours
boolean tacheDone=false;  // indique si la tache a été executé ou pas encore

unsigned long top,delai;

volatile byte flag=0;
volatile unsigned long time,result;

int prog=0;


//int Sequence[][5] = {
//{255, 0  , 0 , 0  , 50},
//{0, 0  , 0 , 0  , 300},
//{255, 0  , 0 , 0  , 50},
//{0, 0  , 0 , 0  , 300},
//{255, 0  , 0 , 0  , 50},
//{0, 0  , 0 , 0  , 300},
//{0, 128  , 0 , 0 , 1000},
//{0, 0  , 255 , 0 , 1000},
//{0, 0  , 0 , 255 , 1000},
//{0, 0  , 255 , 255 , 1000},
//{0, 128  , 255 , 0 , 1000},
//{0, 128  , 0 , 255 , 1000},
//{0, 128  , 255 , 255 , 1000},
//};


int Sequence[][5] = {
{255, 0  , 0 , 0  , 50},
{0, 0  , 0 , 0  , 200},
{255, 0  , 0 , 0  , 50},
{0, 0  , 0 , 0  , 200},
{255, 0  , 0 , 0  , 50},
{0, 0  , 0 , 0  , 200},
{0, 128  , 0 , 0 , 50},
{0, 0 , 0 , 0 , 500},
};

//int Sequence[][5] = {
//
//{0, 128  , 0 , 0 , 100},
//{0, 0  , 255 , 0 , 100},
//{0, 0  , 0 , 255 , 100},
//{0, 0  , 255 , 255 , 100},
//{0, 128  , 255 , 0 , 100},
//{0, 128  , 0 , 255 , 100},
//{0, 128  , 255 , 255 , 100},
//
//};


 
 
void setup() {
    Serial.begin(9600);
    pinMode(ledRed, OUTPUT);
    pinMode(ledGreen, OUTPUT);  
    pinMode(ledWhite,OUTPUT);
 
    top = millis(); // Enregistrement de mon point de départ
   attachInterrupt(4,pulse,RISING);
 
}

void Prog() {
prog++;
Serial.println(result);  
}


void pulse() {

detachInterrupt(4);

if(flag) {

result=micros()-time;
Prog();
attachInterrupt(4,pulse,RISING);

}else {

time=micros();
attachInterrupt(4,pulse,FALLING);
}

flag=!flag;

}


void loop() {

// gestionnaire du sequenceur de taches
  if((top+delai)<=millis()) {
    tache +=1;
    if (tache > (sizeof(Sequence)/10)-1){tache=0;}
    // a chaque chagement du sequenceur, on met reinit tacheDone et le temps de la tache
    // c'est dans la tache qu'on defini son timing (bof, c'est ce que tu veux, donc ca ira)
    tacheDone = false;
    top=millis();
  }
  
// sequenceur de taches
  if (tacheDone == false){
      analogWrite(ledWhite,Sequence[tache][0]);
      analogWrite(ledRed,Sequence[tache][1]);
      analogWrite(ledGreen,Sequence[tache][2]);
      analogWrite(ledBlue,Sequence[tache][3]);
      delai=Sequence[tache][4];
      tacheDone =true;

}

pulse();
}

Cordialement,
bypbop

je n'ai pas de nano pour essais.
c'est la version 2 (168) ou 3 (328) du nano que tu as?
t'as deja joué avec les interruptions seules?

puls() va etre executé a chaque tour de loop() ET puls peut etre interrompue par l'interruption elle meme malgré ton detachInterrupt.

tu t'y prend mal:
admettons que tu veut calculer la duré d'appuy sur la broche:

unsigned long dureeAppuiStart = 0;
unsigned long dureeAppui = 0;

dans setup:
attachInterrupt(4,pulse,CHANGE);

dans puls():
puls() { //cette IT a lieu a chaque changement LOW/HIGH
if (digitalRead(D2)==HIGH) { // front montant, on memorise l'instant
dureeAppuiStart = millis();
}
if (digitalRead(D2)==LOW) { // front descendant, on calcule la durée
dureeAppui = millis() - dureeAppuiStart;
}
}
(et c'est tout)

dans loop:
vire puls()
rajoute:
if (dureeAppui>0) {
dureeAppui=0;
prog++;
Serial.println(result);
}

voila, j'ai pas testé mais ca dervai marcher, au moins avec un fil sud D2, et le code est non bloquant.
tu devrai pouvoir adapter de la meme maniere un delai entre 2 appuy consécutif.

Bonjour Jean-l,

Alors je suis debutant et les interruptions je comprends le principe mais je ne maitrise pas encore trés bien cette notion ca vient ...
alors j'ai fait les petites modifs mais le code ne fonctionne pas j'ai fais un petit test pour voir si on rentre bien dans l int !! mais apparement non ...

int ledWhite = 5;
int ledGreen = 11;
int ledRed = 10;
int ledBlue= 9;

int tache=0;  // tache en cours
boolean tacheDone=false;  // indique si la tache a été executé ou pas encore

unsigned long top,delai;

unsigned long dureeAppuiStart = 0;
unsigned long dureeAppui = 0;

int prog=0;


//int Sequence[][5] = {
//{255, 0  , 0 , 0  , 50},
//{0, 0  , 0 , 0  , 300},
//{255, 0  , 0 , 0  , 50},
//{0, 0  , 0 , 0  , 300},
//{255, 0  , 0 , 0  , 50},
//{0, 0  , 0 , 0  , 300},
//{0, 128  , 0 , 0 , 1000},
//{0, 0  , 255 , 0 , 1000},
//{0, 0  , 0 , 255 , 1000},
//{0, 0  , 255 , 255 , 1000},
//{0, 128  , 255 , 0 , 1000},
//{0, 128  , 0 , 255 , 1000},
//{0, 128  , 255 , 255 , 1000},
//};


int Sequence[][5] = {
{255, 0  , 0 , 0  , 50},
{0, 0  , 0 , 0  , 200},
{255, 0  , 0 , 0  , 50},
{0, 0  , 0 , 0  , 200},
{255, 0  , 0 , 0  , 50},
{0, 0  , 0 , 0  , 200},
{0, 128  , 0 , 0 , 50},
{0, 0 , 0 , 0 , 500},
};

//int Sequence[][5] = {
//
//{0, 128  , 0 , 0 , 100},
//{0, 0  , 255 , 0 , 100},
//{0, 0  , 0 , 255 , 100},
//{0, 0  , 255 , 255 , 100},
//{0, 128  , 255 , 0 , 100},
//{0, 128  , 0 , 255 , 100},
//{0, 128  , 255 , 255 , 100},
//
//};

void pulse() {

 if (digitalRead(2)==HIGH) {  // front montant, on memorise l'instant
    dureeAppuiStart = millis();
  }
  if (digitalRead(2)==LOW) {  // front descendant, on calcule la durée
    dureeAppui = millis() - dureeAppuiStart;
  }


Serial.println("Int");
}
 
 
void setup() {
    Serial.begin(9600);
    pinMode(ledRed, OUTPUT);
    pinMode(ledGreen, OUTPUT);  
    pinMode(ledWhite,OUTPUT);
 
    pinMode(2,INPUT);
    
    
    top = millis(); // Enregistrement de mon point de départ
   attachInterrupt(4,pulse,RISING);
 
}

void Prog() {
prog++;

}


void loop() {

// gestionnaire du sequenceur de taches
  if((top+delai)<=millis()) {
    tache +=1;
    if (tache > (sizeof(Sequence)/10)-1){tache=0;}
    // a chaque chagement du sequenceur, on met reinit tacheDone et le temps de la tache
    // c'est dans la tache qu'on defini son timing (bof, c'est ce que tu veux, donc ca ira)
    tacheDone = false;
    top=millis();
  }
  
// sequenceur de taches
  if (tacheDone == false){
      analogWrite(ledWhite,Sequence[tache][0]);
      analogWrite(ledRed,Sequence[tache][1]);
      analogWrite(ledGreen,Sequence[tache][2]);
      analogWrite(ledBlue,Sequence[tache][3]);
      delai=Sequence[tache][4];
      tacheDone =true;

}

if (dureeAppui>0) {
  
  Serial.println(dureeAppui);
  dureeAppui=0;
  prog++;
}
}

Cordialement,
bypbop

si tu veux comprendre le IT, alors concentre toi sur les IT, pas sur le fait de jouer une sequence, ni de comuniquer en IR.
tu peut entre autre tester un exemple simple:
http://arduino.cc/en/Reference/AttachInterrupt

je n'ai pas de nano, tu ne m'a pas dit lequel tu avais.
j'ai supposé que l'IT 4 correspondai a la pin D2 du nano, puisque tu l'avais ecrit. j'ai pas été vérifier.
d'ou
attachInterrupt(4,pulse,CHANGE);
et
if (digitalRead(D2)==LOW ... ou HIGH

d'apres http://arduino.cc/en/Reference/AttachInterrupt
la nano se comporte comme sur UNO (au moins le model en 328), les interruptions de pins (celles du genre que l'on souhaite) ne sont possible que les pin 2 et 3, et sont respectivement les interruption 0 et 1.
il aurai donc fallu ecrire
attachInterrupt(0,pulse,CHANGE);
et
if (digitalRead(2)==LOW ... ou HIGH