Go Down

Topic: Arduino : interruption sur signal pwm ( recepteur RC) (Read 4068 times) previous topic - next topic

bypbop

Bonjour à tous ,

Voila j'ai fait ce petit projet visant à équiper mon quadcopter il s'agit de 4 rubans leds (ledstrip). Voila je mesure le signal venant de mon recepteur RC mais j'aimerais plutot faire une interruption lorsque par exemple le signal depasse un certain niveau. J'utilise la pin 13 en input pour mesurer le signal provenant du recepteur rc.

Alors actuellement j'arrive a changer de programme mais je suis obliger d'attendre la fin du programme pour appuyer et des fois je bascule d'un programme en sautant un programme.

Comment je pourrais faire pour utiliser une timer ou une interruption sur ma pin 13. J'ai deja tester une interruption sur un bouton avec arduino et faire ca sur un pwm j'en ai aucune idée.


Ps: sur ce projet il ne me reste plus qu'une pin digital la 13. sachant que le projet final sera sur une nano arduino.

Un petite vidéo de mon projet

http://www.youtube.com/watch?v=z0tVXN7LJkU

Code: [Select]

#include <SoftPWM.h>

int pwmrouge;
int pwmvert;
int pwmbleu;

int PulseRc;
int Prog;


int i;

int ledstrip;
void setup()
{
 
 
  // Initialize
  SoftPWMBegin();

  // Create and set pin 13 to 0 (off)
  SoftPWMSet(12, 0);
  pwmrouge = 0;
  pwmvert = 0;
  pwmbleu = 0;
  pinMode(13, INPUT);
  Prog=1;

}

void LedRGB(int pwmrouge, int pwmvert, int pwmbleu, int ledstrip)
{

if (ledstrip==1){
  SoftPWMSetPercent(3, pwmbleu);
  SoftPWMSetPercent(2, pwmvert);
  SoftPWMSetPercent(1, pwmrouge);
}
if (ledstrip==2){
  SoftPWMSetPercent(6, pwmbleu);
  SoftPWMSetPercent(5, pwmvert);
  SoftPWMSetPercent(4, pwmrouge);
}
if (ledstrip==3){
  SoftPWMSetPercent(9, pwmbleu);
  SoftPWMSetPercent(8, pwmvert);
  SoftPWMSetPercent(7, pwmrouge);
}
if (ledstrip==4){
  SoftPWMSetPercent(12, pwmbleu);
  SoftPWMSetPercent(11, pwmvert);
  SoftPWMSetPercent(10, pwmrouge);

}
if (ledstrip==5){
  SoftPWMSetPercent(12, pwmbleu);
  SoftPWMSetPercent(11, pwmvert);
  SoftPWMSetPercent(10, pwmrouge);
 
  SoftPWMSetPercent(9, pwmbleu);
  SoftPWMSetPercent(8, pwmvert);
  SoftPWMSetPercent(7, pwmrouge);

  SoftPWMSetPercent(6, pwmbleu);
  SoftPWMSetPercent(5, pwmvert);
  SoftPWMSetPercent(4, pwmrouge);
 
  SoftPWMSetPercent(3, pwmbleu);
  SoftPWMSetPercent(2, pwmvert);
  SoftPWMSetPercent(1, pwmrouge);
}
}


void loop()
{
  // Turn on - set to 100%
 
  PulseRc = pulseIn(13, HIGH, 25000);
  if (PulseRc>1200){
  Prog++;
  }
  if (Prog>2){Prog=1;}
 
  if (Prog==1){
  LedRGB(100, 0, 0, 5);
  delay(100);
  LedRGB(0, 0, 0, 5);
  delay(50);
  LedRGB(100, 0, 0, 5);
  delay(100);
  LedRGB(0, 0, 0, 5);
  delay(50);
  LedRGB(100,0, 0, 5);
  delay(100);
  LedRGB(0, 0, 0, 5);
  delay(50);
 
  LedRGB(0, 100, 0, 5);
  delay(100);
  LedRGB(0, 0, 0, 5);
  delay(50);
  LedRGB(0, 100, 0, 5);
  delay(100);
  LedRGB(0, 0, 0, 5);
  delay(50);
  LedRGB(0,100, 0, 5);
  delay(100);
  LedRGB(0, 0, 0, 5);
  delay(50);
 
  LedRGB(0, 0, 100, 5);
  delay(100);
  LedRGB(0, 0, 0, 5);
  delay(50);
  LedRGB(0, 0, 100, 5);
  delay(100);
  LedRGB(0, 0, 0, 5);
  delay(50);
  LedRGB(0,0, 100, 5);
  delay(100);
  LedRGB(0, 0, 0, 5);
  delay(50);
 
 
  LedRGB(0, 100, 100, 5);
  delay(100);
  LedRGB(0, 0, 0, 5);
  delay(50);
  LedRGB(0, 100, 100, 5);
  delay(100);
  LedRGB(0, 0, 0, 5);
  delay(50);
  LedRGB(0, 100, 100, 5);
  delay(100);
  LedRGB(0, 0, 0, 5);
  delay(50);
 
  LedRGB(100, 100, 100, 5);
  delay(100);
  LedRGB(0, 0, 0, 5);
  delay(50);
  LedRGB(100, 100, 100, 5);
  delay(100);
  LedRGB(0, 0, 0, 5);
  delay(50);
  LedRGB(100, 100, 100, 5);
  delay(100);
  LedRGB(0, 0, 0, 5);
  delay(50);
 
  LedRGB(100, 100, 0, 5);
  delay(100);
  LedRGB(0, 0, 0, 5);
  delay(50);
  LedRGB(100, 100, 0, 5);
  delay(100);
  LedRGB(0, 0, 0, 5);
  delay(50);
  LedRGB(100, 100, 0, 5);
  delay(100);
  LedRGB(0, 0, 0, 5);
  delay(50);
 
  LedRGB(100, 0, 100, 5);
  delay(100);
  LedRGB(0, 0, 0, 5);
  delay(50);
  LedRGB(100, 0, 100, 5);
  delay(100);
  LedRGB(0, 0, 0, 5);
  delay(50);
  LedRGB(100, 0, 100, 5);
  delay(100);
  LedRGB(0, 0, 0, 5);
  delay(50);
  }
 
 
 

 
 

  if (Prog==2){
   
  pwmrouge = random(0,100);
  pwmvert = random(0,100);
  pwmbleu = random(0,100);
 
  for(i=4 ; i>=1 ; i--)
  {
  LedRGB(pwmrouge, pwmvert, pwmbleu, i);
  delay(40);
  LedRGB(0, 0, 0, i);
  delay(20);
  LedRGB(pwmrouge, pwmvert, pwmbleu, i);
  delay(40);
  LedRGB(0, 0, 0, i);
  delay(20);
  LedRGB(pwmrouge, pwmvert, pwmbleu, i);
  delay(40);
  LedRGB(0, 0, 0, i);
  delay(20);
  LedRGB(pwmrouge, pwmvert, pwmbleu, i);
  delay(40);
  LedRGB(0, 0, 0, i);
  delay(20);
  } 
  i=4;
  }
 
}

Super_Cinci

Tu as deux solutions :

1 - utiliser une interruption spécialement prévue pour : ICP1 (pin 8 ). cette pin utilisée en input capture associée au timer 1 permet de mesurer des longueurs d'impulsions sans avoir (presque) rien à faire au niveau programme...

2 - utiliser (via la pin 13) l'interruption PCI0 qui appellera l'interruption à chaque fois que l'état sur la pin change. il te suffira de relever millis() en fonction de l'état de la pin.

Pour bien jouer avec tout ça, il faut lire les chapitres correspondants dans le datasheet de l'ATMEGA. Un peu long, mais ça vaut le coup.

fdufnews

Tel que ton programme est construit, une interruption n'y changera rien.
L'interruption te fera effectivement sortir du loop mais en quittant l'interruption tu reviendras d'où tu étais parti donc le changement de programme ne sera pris en compte qu'à la fin du programme en cours.
Il faudrait modifier la forme de tes programmes.
Au lieu d'avoir un bloc avec une suite de :
  LedRGB(100, 0, 0, 5);
  delay(100);
qui se répètent, il faudrait modifier le principe de tes programmes pour avoir une boucle courte non bloquante et ainsi pouvoir changer le programme immédiatement.
La boucle courte dont je parle pourrais aller chercher le contenu des programmes dans un (ou des) tableau(x) et il suffirait de pointer sur un tableau ou un autre lors du changement de programme.

Super_Cinci

Justement, son souci, c'est que ce n'est qu'en début de loop() qu'une commande de changement de prog peut être prise en compte (toute commande intervenant pendant un programme tombe à l'eau). avec une INT, le changement sera pris en compte, et appliqué à la fin de la boucle. c'est déjà une grande avancée!

et encore, avec un timeout de 25ms, faut être synchro pour appuyer sur la commande!

bypbop

Merci de vos réponses,

Alors à la rigeur faire un changement à la fin de programme ce n'est pas trés embetant  ...

Je vais donc tester avec une interruption sur la pin 13 qui termine le programme en cours et qui change ensuite ...

Mais si je comprends bien avec la pin 13 une interruption va se déclencher à chaque changement d'état donc il faudra faire un calcul non ?

Cordialement,
bypbop

bypbop

Re :

Pour créer une interruption sur la pin 13 que dois je faire ?

Code: [Select]
attachInterrupt(0, BtnPrg, FALLING);

mais en regardant le manuel arduino des interruptions j'ai 0 ou 1 qui correnspond à la pin 2 et 3 .

ps : je debute sur les interruptions et les timers ;-)

Cordialement,
bypbop

bypbop

ok en fait j'ai bien compris ce que je pouvais faire avec la pin 13. En fait je viens de liberer la pin 13 et je vais essayer de le faire plutot avec le timer et declencher une interruption pour incrementer mon programme.

Cordialement,
bypbop

B@tto

Attention aux timers  et aux fonctions que tu utilises dans ton programme : un timer ne peut pas servir à plusieurs fonctions.
Blog électronique : battomicro.wordpress.com
Photographie : www.interactive-celebration.fr
Fablab de Montpellier : www.labsud.org

bypbop

Bonjour à tous,

Je patauge depuis sur mon interruption pin 8 pas j'ai bien compris que je devais créer une interruption en mode capture mais mes compétences s'arretent la  je suis trop peu habiter à les utiliser.


Est ce que qq'un pourrait m'expliquer tt doucement  ?

Cordialement,
bypbop

Super_Cinci

Allez, c'est parti mon kiki!

En gros, tu souhaîtes récupérer un signal type servo et en extraire un numéro de programme... si j'ai bien compris, si la "pulse" est > 1200, il faut incrémenter le numéro de programme (Prog)...

(code non testé!)
Code: [Select]

#define Tpulse_min 1200   // valeur en µs à partir de laquelle on change le programme.

#define Tm Tpulse_min*2  // adaptation pour le timer
#define T1_stop TCCR1B=0x00  // arrête le timer

void T1_set(){  // initialisation du timer 1 pour la mesure d'impulsion
  // config timer 1 / ICP
  TIMSK1 = 0;
  TCCR1A = 0;
  TCCR1B = 0;
  TCCR1C = 0;
  Tp = false;
}

void T1_start(){  // démarre le timer1 à 2MHz et les interruptions IPC1 et TOVF1
  T1_stop;  // arrêter le timer
  TCNT1 = 0;  // reset timer
  TIMSK1 = 0x21;  // autoriser les int TOVF et ICP
  TCCR1B = 0x42;  // démarrer le timer
}

ISR(TIMER1_CAPT_vect){
  if (TCCR1B & 0x40){     // on est sur le début de l'impulsion
    TCNT1 = 0;              // reset chrono   
    TCCR1B &= 0xBF;         // on se prépare à mesurer la fin de l'impulsion
  } else {                // on a mesuré la fin de l'impulsion
    if (ICR1 > Tm) {        // la pulse est supérieure à la limite
      Prog++;                 // incrémenter le programme
      if (Prog > 2) Prog = 1;
    }
    TCCR1B |= 0x40;         // on se prépare à attendre la prochaine impulsion.
  }
}

ISR(TIMER1_OVF_vect){  // il n'y a pas eu d'impultion durant les dernières 32768 µs, donc on reprend tout à zéro
    TCCR1B |= 0x40;         // on se prépare à attendre la prochaine impulsion positive.
}


Il faudra donc copier tout ça dans ton code, puis mettre T1_set(); et T1_start(); dans ton setup, c'est tout. les fonctions "ISR" sont des interruptions appelées directement par les impulsions sur la pin 8, tu n'as plus rien à faire, le numéro de prog changera tout seul sans que tu t'en aperçoives...

Par contre, j'ai vu dans la lib softPWM un truc super pas gentil :

Code: [Select]
#ifdef ISR
#undef ISR
#endif


ils virent toutes les ISR histoire de bien pourrir tout le code. donc si ça ne marche pas, il y a des chances que softPWM y soit pour beaucoup... et là, moi, je n'y peu pas grand chose, à part te proposer de virer cette mer*e de lib. ce genre de babiole est digne d'un très mauvais programmeur!

bypbop

;-) Merci bcp cela fonctionne

Comme tu l'avais dit j'ai du virer la librairie softPWM  ;-)

au départ j'avais codé sans mais qd je me suis aperçu qu'il y avait 6 pwm sur l'arduino j'ai fait des recherche sur ca

Mon code de test actuelle j'ai rajouté int Tp;

Par contre je pense que c'est normal mais je zappe plusieurs programme en fonction d'un appui long ou court.
et qques fois cela change tt seul de programme ...

Code: [Select]

#define Tpulse_min 1200   // valeur en µs à partir de laquelle on change le programme.

#define Tm Tpulse_min*2  // adaptation pour le timer
#define T1_stop TCCR1B=0x00  // arrête le timer

int Tp;
int Prog = 1;
void T1_set(){  // initialisation du timer 1 pour la mesure d'impulsion
  // config timer 1 / ICP
  TIMSK1 = 0;
  TCCR1A = 0;
  TCCR1B = 0;
  TCCR1C = 0;
  Tp = false;
}

void T1_start(){  // démarre le timer1 à 2MHz et les interruptions IPC1 et TOVF1
  T1_stop;  // arrêter le timer
  TCNT1 = 0;  // reset timer
  TIMSK1 = 0x21;  // autoriser les int TOVF et ICP
  TCCR1B = 0x42;  // démarrer le timer
}

ISR(TIMER1_CAPT_vect){
  if (TCCR1B & 0x40){     // on est sur le début de l'impulsion
    TCNT1 = 0;              // reset chrono   
    TCCR1B &= 0xBF;         // on se prépare à mesurer la fin de l'impulsion
  } else {                // on a mesuré la fin de l'impulsion
    if (ICR1 > Tm) {        // la pulse est supérieure à la limite
      Prog++;                 // incrémenter le programme
      if (Prog > 3) Prog = 1;
    }
    TCCR1B |= 0x40;         // on se prépare à attendre la prochaine impulsion.
  }
}

ISR(TIMER1_OVF_vect){  // il n'y a pas eu d'impultion durant les dernières 32768 µs, donc on reprend tout à zéro
    TCCR1B |= 0x40;         // on se prépare à attendre la prochaine impulsion positive.
}

int red1 = 1;
int green1 = 2;
int blue1 = 3;
int pwmgreen = 0;
int pwmred =  0;
int pwmblue = 0;


int i = 1;

void setup() {               

  pinMode(blue1, OUTPUT);
  pinMode(red1, OUTPUT);
  pinMode(green1, OUTPUT);
 
  T1_set();
  T1_start();

}


void LedRGBPWM(int pwmred, int pwmgreen, int pwmblue){
  analogWrite(red1, pwmred);
  analogWrite(green1, pwmgreen);   
  analogWrite(blue1, pwmblue); 
  }

void loop() {

           if (Prog==1)
           {
           pwmred = random(0, 255);
           pwmgreen = random(0, 255);
           pwmblue = random(0, 255);
           LedRGBPWM(pwmred,pwmgreen,pwmblue);
           delay(100);
           }
           if (Prog==2)
           {
           pwmred = 255;
           pwmgreen = 255;
           pwmblue = 255;
           LedRGBPWM(pwmred,pwmgreen,pwmblue);
           delay(1000);
           }
           if (Prog==3)
           {
           pwmred = 0;
           pwmgreen = 255;
           pwmblue = 255;
           LedRGBPWM(pwmred,pwmgreen,pwmblue);
           delay(1000);
           }
     
     

}





As tu une idée pour que je puisse utiliser 12 pwm sur mes sorties digital . j'utilise un UL2803 derriere pour avoir un pwm en 12V.

Cordialement,
bypbop

Super_Cinci

Attention, car mon code monopolise le timer 1, donc deux sorties PWM! (les pins 9 et 10). ce qui veut dire que toute tentative de PWM sur ces pins va foutre la bazar sur mon code!

c'est ce qu'il manque chez arduino : le contrôle des ressources. tu peux inclure deux libs dans un sketch, tout compilera mais rien ne marchera parce que ces deux libs utilisent une même ressource, et le conflit ne se verra pas à part un joyeux bordel dans l'exécution...

si ça change de programme tout seul, c'est que quelque part, tu as des interférences, ou que ta zapette envoie des impulsions toute seule... j'ai repris un code que j'avais fait pour la voiture à madame, et ça marche impec. j'ai seulement viré les trucs en trop. Tu peux activer l'antiparasite en remplaçant la ligne "  TCCR1B = 0x42;  // démarrer le timer" dans T1_start() par "  TCCR1B = 0xC2;  // démarrer le timer". mais je ne suis pas sûr que ça suffise.

pour tes 12 PWM, il y a moyen de faire une PWM soft, mais mieux gérée. ça monopolisera un timer et pas mal de temps, mais je crois que ton atmega n'a que ça à foutre ;) . en gros, ton timer (le 2 du coup) déclenche toutes les 130µs, et tu compares 12 valeurs. Par contre, dans ce cas, oublie les pinMode digitalWrite, car va falloir tailler dans le lard pour aller vite! mais c'est faisable.

bypbop

En fait je pense plus que cela fait le tour plusieurs fois du programme car quand j appuie rapidement cela change correctement.
Ok pour les pin 9 et 12. On ne peux pas les utiliser en pwm mais je suppose que peux les mettre a 1 ou 0  quand mm ?
Sinon je vais être ds la muise j aurais pas assez de pin pour mon projet.

Qd tu dis soft pwm avec 1 timer par exemple le 2 on on pourrait generer le signal de 12 pin c est bien
ça ?

De tte facon si tu le permets je vais revenir vers toi pour décortiquer  ton bout de code . Je coprends mais j ai du mal a mis retrouver qd ils faut chercher les registres.

Bonne soiree
Bypbop

Super_Cinci

#13
Oct 29, 2013, 12:41 am Last Edit: Oct 29, 2013, 12:44 am by Super_Cinci Reason: 1

Ok pour les pin 9 et 12.
9 et 10 !

J'ai mis un max de commentaires dans mon code, mais bon, je reconnais que c'est pas évident, ça fait 2 ans que je travaille sur le nono avec mon PC sur deux écrans, un pour l'IDE, l'autre pour la datasheet du 328 (ou 2560 selon le projet). et j'arrive toujours pas à coder les registres sans datacheet...

une ISR, c'est une fonction que l'on ne peut pas appeler, mais qui est appelée dès qu'un événement s'y rapportant se produit. l'avantage, c'est que ces fonctions prennent la main tout de suite, donc on n'est pas pénalisé par le reste du soft.

je t'invite à regarder la page 58 du datasheet de l'AtMEGA328, c'est la liste des interruptions possibles...  ]:D quant on sait jouer avec ça, on arrête de lorgner sur les cartes plus puissantes, car on multiplie par 100 au moins les capacités du processeur...

Go Up