Aller au contenu


Photo
- - - - -

Arduino : interruption sur signal pwm ( recepteur RC)


8 réponses à ce sujet

#1 bypbop

bypbop

    Habitué

  • Membres
  • PipPip
  • 273 messages
  • Gender:Male
  • Location:Lille

Posté 22 octobre 2013 - 08:14

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


#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;
  } 
  
}

Avez vous une idée sur comment je pourrais faire pour avoir un changement de programme net et sans attendre la fin de la boucle ...

Cordialement,
bypbop

#2 bypbop

bypbop

    Habitué

  • Membres
  • PipPip
  • 273 messages
  • Gender:Male
  • Location:Lille

Posté 26 octobre 2013 - 05:58

Bonjour à tous je regarde depuis mon projet les interruption sur arduino mais bon j'avoue je suis trop peu habituer à les utiliser.
Est ce qq'un du forum pourrait m'expiquer piano piano les interruptions.

Cordialement,
bypbop

#3 olivthill

olivthill

    Membre occasionnel

  • Membres
  • Pip
  • 143 messages
  • Gender:Male
  • Location:Normandie

Posté 26 octobre 2013 - 10:32

Tout d'abord, je vais vous démoraliser en vous disant qu'on ne peut pas mettre d'interruption sur la pin 13 d'une Arduino Uno ou d'une Nano.

Ensuite, voici quelques explications.
Mais je crains que vous ne les connaissiez déjà puisque vous dites que vous avez déjà testé une interruption sur un bouton avec la arduino.

Les interruptions sont gérées par le microprocesseur. Atmel les a prévues (Intel aussi, et Motorola, etc.).
Un programme qui tourne ne peut être interrompu par rien, sauf par l'extinction du courant et par une interruption.
Un reset déclenche une interruption. L'appui d'une touche d'un clavier d'un ordinateur déclenche une interruption.
Ces événements physiques font changer le voltage de certaines broches du microprocesseur.
Quand cela arrive, le microprocesseur va interrompre le programme en cours, et va faire un saut à une adresse en mémoire interne. Ces adresses sont habituellement dans le bas de la mémoire à des emplacements fixes, qui dépendent de la broche qui est sollicitée. Par exemple, on va dire à l'adresse 10h pour la pin 2, et 14h pour la pin 3 (je ne sais pas si ce sont les adresses réellement utilisées par Atmel, mais c'est pour donner une idée). Entre deux adresses, il y a habituellement 4 octets. C'est peu pour un programme d'interruption. Alors, il s'y trouve généralement uniquement une instruction pour sauter ailleurs, dans la mémoire vive générale où va se trouver le programme d'interruption, qui a été placé auparavant par le programmeur avec la commande attachInterrupt() ou son équivalent dans d'autres langages.
Ensuite le microprocesseur va parcourir le programme de l'interruption, jusqu'à la fin, ou jusqu'à ce qu'il soit interrompu par une autre interruption dans le cas où l'on se trouve dans une partie de code qui n'est pas protégée contre les interruptions (cas par défaut mais qu'on peut changer avec noInterrupts()).
Puis, le microprocesseur retrouve le programme d'avant l'interruption, et continue son déroulement.
C'est tout.

Sur une Arduino Uno, il n'existe que deux connecteurs auxquels on peut attacher une interruption : le 2 et le 3. Sur une Nano, c'est pareil. Le 13 ne peut pas déclencher une interruption.
J'ai oublié de préciser que je parle là des interruption dites "externes". Ce sont celles qui s'utilisent le plus couramment et le plus facilement.

Mais il existe aussi trois interruptions dites "internes". Pour celles-là on n'utilise pas attachInterrupt(), et elles ne sont pas déclenchées par des événements sur des pins de la Arduino. Elles sont déclenchées par des timers internes.

Un timer est une horloge. La Arduino Uno a trois timers. Il est possible d'associer un tick à une interruption interne. Il faudra créer une fonction qui s'appelle précisément ISR(TIMER...vect), avec plusieurs possibilités pour remplacer les points de suspension. Il faudra coder avec des instructions un peu inhabituelles comme cli() et sei().
Voir les explications http://letsmakerobots.com/node/28278 et http://blog.oscarliang.net/arduino-timer-and-interrupt-tutorial/
Je ne sais pas si les timers vous seront utiles. Si vous les essayez, sachez que la librairie servo utilise déjà l'un des trois timers.

#4 bypbop

bypbop

    Habitué

  • Membres
  • PipPip
  • 273 messages
  • Gender:Male
  • Location:Lille

Posté 27 octobre 2013 - 12:37

Merci bcp pour cette réponse je comprends un peu mieux mais je pense que lorsque j'aurais un peu plus l'habitude de manipuler les interruptions cela rentrera mieux.
Oui j'ai fait une interruption et j'ai vu qu'il y avait que 2 interruptions sur 2 et 3 ... j'ai fait un test avec une simple interrupt sur un bouton en HIGH ...

Ps: Je n'utilise plus la pin 13 maintenant mais la 8 mon signal de mon recepteur entre sur cette pin.

Alors mon projet est conçu de la sorte j'ai 4 led strip cf vidéos ;-) je sors 4 x 3 pwm sur ces pins avec la librairie softpwm ...

Afin d etre precis ds la mesure de mon signal Rc j'aimerais mettre en place un timer qui lui fait basculer mon programme.


En regardant les différents liens ds votre réponse j'ai vu qu'il y avait un timer en capture ... Je suis d'ailleurs retomber sur ces sites en recherchant des infos sur les timers.

Mais aprés grand flou total je ne comprends pas les registers et devient un peu du charabia pour moi.

Pour moi je pense que je dois utiliser ISR(TIMERx_CAPT_vect)

Qu'en pensez vous ? Auriez vou fait la mm chose que moi ?

Cordialement,
bypbop

#5 olivthill

olivthill

    Membre occasionnel

  • Membres
  • Pip
  • 143 messages
  • Gender:Male
  • Location:Normandie

Posté 27 octobre 2013 - 03:07

Je n'utilise plus la pin 13 maintenant mais la 8 mon signal de mon recepteur entre sur cette pin.
...
Afin d etre precis ds la mesure de mon signal Rc j'aimerais mettre en place un timer qui lui fait basculer mon programme.

Comme le signal n'est pas sur la pin 2 ni sur la pin 3, il ne peut pas déclencher une interruption externe.
Mais si je comprends bien l'idée derrière le mot "basculer", ce serait d'avoir une interruption interne qui se déclenche à chaque tic d'un timer interne.
Cette interruption interne ira faire un digitalRead(8) pour voir si le signal est haut ou bas. Puis, en fonction de cet état, il y aura un appel ou pas à une fonction d'éclairage.
C'est une idée intéressante, à laquelle je n'avais pas pensée. Il faut juste que l'intervalle entre deux tics ne soit pas trop court, sinon la Arduino passera beaucoup de temps dans l'interruption et n'aura plus beaucoup de temps pour s'occuper du programme principal.

je pense que je dois utiliser ISR(TIMERx_CAPT_vect)

On a le choix entre OVF (overflow, c'est-à-dire quand le maximum est atteint), COMPA (quand une valeur est atteinte) et CAPT (quand il y a un changement). Les exemples sur la page précitée utilisent OVF ou COMPA, mais pas CAPT. Il doit y avoir des raisons. On voit que CAPT n'est possible qu'avec un timer 16 bit et la Arduino n'a qu'un seul timer comme ça qui est le timer1. Malheureusement la librairie servo utilise ce timer. Donc, comme vous utiliser servo (si je ne me trompe pas), alors vous ne pouvez pas utiliser ce timer1, et donc vous ne pouvez pas utiliser ISR(TIMER1_CAPT_vect). Par ailleurs, je pense que CAPT se déclenchera beaucoup trop souvent pour votre besoin. Je pense qu'il est préférable d'utiliser l'overflow, donc ISR(TIMER0_OVF_vect) ou ISR(TIMER2_OVF_vect). L'horloge va faire 256 tics, et au 257e l'interruption est appelée (les timers 0 et 2 sont codés sur 8 bits, d'où le nombre 256).

grand flou total je ne comprends pas les registers et devient un peu du charabia pour moi.

Je conseillerais d'utiliser la librairie MsTimer2 http://playground.arduino.cc/Main/MsTimer2 . Elle simplifie beaucoup les choses. On a juste à lui passer le nombre de millisecondes entre deux interruptions, et le nom de la fonction à utiliser quand l'interruption est déclenchée. La librairie MsTimer2 serait ce que je choisirais, sauf si le timer2 serait déjà pris que je sois obligé d'en prendre un autre.

Sinon, la documentation officielle est le PDF http://www.atmel.com/Images/doc7810.pdf

Autrement, voici, par exemple une explication de la ligne :

TCCR0B |= (1 << WGM02);

  • TCCR0B est le nom d'un registre. Un registre est un octet dans la mémoire la plus interne de l'ATmega328.
  • Un registre contient plusieurs drapeaux et/ou plusieurs valeurs. En l'occurrence le registre TCCR0B contient les choses qui sont indiquées à la page 100 de la documentation http://www.atmel.com/Images/doc7810.pdf .
  • La barre verticale |, appelée pipe en anglais, est l'opérateur booléen pour faire un OR, un OU. Pour rappel 0|0=0, 1|0=1, 0|1=1, et 1|1=1.
  • Le signe égal = est le signe de l'affectation.
  • La combinaison |= est un raccourci, comme +=. "TCCR0B |= (1 << WGM02);" est équivalent à "TCCR0B = TCCR0B | (1 << WGM02);"
  • Le signe double chevron vers la gauche << est un opérateur pour faire un décalage à gauche, vers les bits forts.
  • WGM02 est l'abréviation de Waveform Generation Mode pour le timer 0 et c'est la 2e partie de cet indicateur de mode (il y a une autre partie située dans un autre registre). Cela correspond au 3e bit dans l'octet. Donc WGM02 est égal à 3. Mais c'est plus lisible dans un programme d'avoir WGM02 plutôt que d'avoir 3.
Bref, la ligne en question va simplement mettre un 1 dans le troisième bit du registre TCCR0B. Pour mettre un zéro dans ce troisième bit, on utiliserait la valeur 0 et l'opérateur AND qui est représenté par le &, donc on ferait : TCCR0B &= (0 << WGM02);

Je n'ai pas expliqué à quoi sert chaque bit de chaque registre parce que mon message est déjà long, et qu'il faudrait cibler un point particulier.

#6 bypbop

bypbop

    Habitué

  • Membres
  • PipPip
  • 273 messages
  • Gender:Male
  • Location:Lille

Posté 27 octobre 2013 - 07:11

Encore merci pour ces explications cela m'aide bcp. Je n'utilise pas la librairie servo juste softPWM (je devrais verifié si elle n'utilise pas le timer concerné)

Je viens de regarder la librairie Mstimer2 mais une question m'interpelle ? comment mesurer une durée dans ce cas.
Dans mon projet je veux faire varier via un interrupteur de ma radio le pwm et le detecter sur l'arduino.

si je fais un tic tt les x secondes il faudrait le faire ttes les 1 msec pour connaitre la durée de la partie haute non ?


Cordialement,
bypbop


Ps : Je viens de verifier la librairie softPWM utilise le timer2 :-(

#7 olivthill

olivthill

    Membre occasionnel

  • Membres
  • Pip
  • 143 messages
  • Gender:Male
  • Location:Normandie

Posté 27 octobre 2013 - 08:51

Dans mon projet je veux faire varier via un interrupteur de ma radio le pwm et le detecter sur l'arduino.

si je fais un tic tt les x secondes il faudrait le faire ttes les 1 msec pour connaitre la durée de la partie haute non ?

Un signal PWM dure entre 1 et 2 millisecondes avec le neutre qui dure 1.5 milliseconde. Puis, il y a entre 19 et 18 millisecondes pendant lesquelles rien ne se passe. Et cela se répète.
C'est prévu pour qu'il soit possible de mixer 10 PWM, chacun occupant une tranche de 2ms dans l'intervalle de 20ms.
Dans le cas présent, la radio n'enverra qu'un seul signal PWM, et donc il faudra bien viser pour lire la bonne tranche, car il y aura neuf chances sur dix de tomber à côté.

Je vais réfléchir, mais pour le moment je ne sais pas comment résoudre le problème.
Ce serait beaucoup plus simple s'il était possible de mettre le signal sur la pin 2 ou sur la pin 3.

#8 bypbop

bypbop

    Habitué

  • Membres
  • PipPip
  • 273 messages
  • Gender:Male
  • Location:Lille

Posté 28 octobre 2013 - 09:06

Bonjour Olivthill

J'ai trouvé ceci : https://www.inkling....-18/recipe-18-8

Qu'en pensez vous ?

Cordialement,
bypbop

#9 olivthill

olivthill

    Membre occasionnel

  • Membres
  • Pip
  • 143 messages
  • Gender:Male
  • Location:Normandie

Posté 28 octobre 2013 - 10:02

Ca marche peut-être. Il faudrait tester.

Je vois aussi un autre code qui se base sur le timer1 et la lecture de la pin 8 : http://diydrones.com/profiles/blogs/705844:BlogPost:39393



Répondre à ce sujet



  


0 utilisateur(s) li(sen)t ce sujet

0 members, 0 guests, 0 anonymous users