Pages: [1]   Go Down
Author Topic: Détection interruption.  (Read 436 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Jr. Member
**
Karma: 1
Posts: 72
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Bonjour à tous,

Je cherche à détecter le passage au niveau et au niveau bas d'un signal sortant d'un récepteur de modélisme. Ceci a été faite de nombreuses fois notamment sur MULTIWII et l'ont peut trouver le code sur le net sans difficulté.

Comme je débute dans le domaine de l'électronique et de l'informatique embarqué, je réalise pour l'instant de petits bouts de sketch pour tester certaines fonctionnalités.

Voici un extrait du code que j'ai inséré dans mon sketch :

Code:
// Configure each rc pin for PCINT
void configureReceiver() {
  for (uint8_t chan = 0; chan < 8; chan++)
    for (uint8_t a = 0; a < 4; a++)
      rcData4Values[chan][a] = 1500; //we initiate the default value of each channel. If there is no RC receiver connected, we will see those values
  // PCINT activated only for specific pin inside [D0-D7]  , [D2 D4 D5 D6 D7] for this logger
  DDRD = B11111100;
  PORTD   = (1<<2) | (1<<3) | (1<<4) | (1<<5) | (1<<6) | (1<<7); //enable internal pull ups on the PINs of PORTD (no high impedence PINs)
  PCMSK2 |= (1<<2) | (1<<3) | (1<<4) | (1<<5) | (1<<6) | (1<<7);
  PCICR   = 1<<2; // PCINT activated only for the port dealing with [D0-D7] PINs
}


ISR(PCINT2_vect) { //this ISR is common to every receiver channel, it is call everytime a change state occurs on a digital pin [D2-D7]
  uint8_t mask;
  uint8_t pin;
  uint16_t cTime,dTime;
  static uint16_t edgeTime[8];
  static uint8_t PCintLast;

  pin = PIND;             // PIND indicates the state of each PIN for the arduino port dealing with [D0-D7] digital pins (8 bits variable)

  mask = pin ^ PCintLast;   // doing a ^ between the current interruption and the last one indicates wich pin changed
  sei();                    // re enable other interrupts at this point, the rest of this interrupt is not so time critical and can be interr  pted safely
  PCintLast = pin;          // we memorize the current state of all PINs [D0-D7]

  cTime = micros();         // micros() return a uint32_t, but it is not usefull to keep the whole bits => we keep only 16 bits

  // mask is pins [D0-D7] that have changed
  // chan = pin sequence of the port. chan begins at D0 and ends at D7
  if (mask & 1<<0)           //indicates the bit 0 of the arduino port [D0-D7], that is to say digital pin 2, if 1 => this pin has just changed
    if (!(pin & 1<<0)) {     //indicates if the bit 0 of the arduino port [D0-D7] is not at a high state (so that we match here only descending PPM pulse)
      dTime = cTime-edgeTime[0];
      if (900<dTime && dTime<2200) rcPinValue[0] = dTime; // just a verification: the value must be in the range [1000;2000] + some margin
    }
    else edgeTime[0] = cTime;    // if the bit 0 of the arduino port [D0-D7] is at a high state (ascending PPM pulse), we memorize the time
  if (mask & 1<<1)
    if (!(pin & 1<<1)) {
      dTime = cTime-edgeTime[1];
      if (900<dTime && dTime<2200) rcPinValue[1] = dTime;
    }
    else edgeTime[1] = cTime;
  if (mask & 1<<2)
    if (!(pin & 1<<2)) {
      dTime = cTime-edgeTime[2];
      if (900<dTime && dTime<2200) rcPinValue[2] = dTime;
    }
    else edgeTime[2] = cTime;
  if (mask & 1<<3)
      if (!(pin & 1<<3)) {
      dTime = cTime-edgeTime[3];
      if (900<dTime && dTime<2200) rcPinValue[3] = dTime;
    }
    else edgeTime[3] = cTime;
  if (mask & 1<<4)
      if (!(pin & 1<<4)) {
      dTime = cTime-edgeTime[4];
      if (900<dTime && dTime<2200) rcPinValue[4] = dTime;
    }
    else edgeTime[4] = cTime;
  if (mask & 1<<5)
    if (!(pin & 1<<5)) {
      dTime = cTime-edgeTime[5];
      if (900<dTime && dTime<2200) rcPinValue[5] = dTime;
    }
    else edgeTime[5] = cTime;
  if (mask & 1<<6)
    if (!(pin & 1<<6)) {
      dTime = cTime-edgeTime[6];
      if (900<dTime && dTime<2200) rcPinValue[6] = dTime;
    }
    else edgeTime[6] = cTime;
  if (mask & 1<<7)
    if (!(pin & 1<<7)) {
      dTime = cTime-edgeTime[7];
      if (900<dTime && dTime<2200) rcPinValue[7] = dTime;
    }
    else edgeTime[7] = cTime;

}


uint16_t readRawRC(uint8_t chan) {
  uint16_t data;
  uint8_t oldSREG;
  oldSREG = SREG;
  cli(); // Let's disable interrupts
  data = rcPinValue[pinRcChannel[chan]]; // Let's copy the data Atomically
  SREG = oldSREG;
  sei();// Let's enable the interrupts
  return data; // We return the value correctly copied when the IRQ's where disabled
}


void computeRC() {
  static uint8_t rc4ValuesIndex = 0;
  uint8_t chan,a;

  rc4ValuesIndex++;
  for (chan = 0; chan < 8; chan++) {
    rcData4Values[chan][rc4ValuesIndex%4] = readRawRC(chan);
    rcData[chan] = 0;
    for (a = 0; a < 4; a++)
      rcData[chan] += rcData4Values[chan][a];
    rcData[chan]= (rcData[chan]+2)/4;
    if ( rcData[chan] < rcHysteresis[chan] -3)  rcHysteresis[chan] = rcData[chan]+2;
    if ( rcData[chan] > rcHysteresis[chan] +3)  rcHysteresis[chan] = rcData[chan]-2;
  }
}


La carte sur laquelle je programme est une ARDUINO Duemilanove.

Mon problème est le suivant :

Ce code fonctionne correctement avec un testeur de servo. Mais lorsque je connecte un vrai récepteur (FUTABA R617FS), les interruptions ne se déclenchent plus!
Je me suis alors intéressé aux signaux en sortie du testeur de servo et du RX :
 * Le testeur de servo génère un signal dont la hauteur correspond à la tension de la batterie (5v)
 * Le RX génère un signal dont la hauteur est de 3V!!! Je précise que ce récepteur fonctionne correctement, lorsqu'on lui met un servo, celui bouge.


J'ai modifié ce sketch en remplaçant le port D (pins D2 à D7) par le port C (pins A0 à A5) :

Code:
// Configure each rc pin for PCINT
void configureReceiver() {
  for (uint8_t chan = 0; chan < 6; chan++)
    for (uint8_t a = 0; a < 4; a++)
      rcData4Values[chan][a] = 1500; //we initiate the default value of each channel. If there is no RC receiver connected, we will see those values
#if defined(PROMINI)
  // PCINT activated only for specific pin inside [A0 .. A5] for this logger
  DDRC = B11100000;    // [A0 .. A5] input
  PORTC   = (1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<4) | (1<<5); //enable internal pull ups on the PINs of PORTC (no high impedence PINs)
  PCMSK1 |= (1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<4) | (1<<5);
  PCICR   = 1<<1; // PCINT activated only for the port dealing with [A0-A5] PINs
#endif
}


ISR(PCINT1_vect) { //this ISR is common to every receiver channel, it is call everytime a change state occurs on a digital pin [A0-A5]
  uint8_t mask;
  uint8_t pin;
  uint16_t cTime,dTime;
  static uint16_t edgeTime[6];
  static uint8_t PCintLast;

#if defined(PROMINI)
  pin = PINC;             // PIND indicates the state of each PIN for the arduino port dealing with [A0-A6] digital pins (8 bits variable)
#endif
  mask = pin ^ PCintLast;   // doing a ^ between the current interruption and the last one indicates wich pin changed
  sei();                    // re enable other interrupts at this point, the rest of this interrupt is not so time critical and can be interr  pted safely
    PCintLast = pin;          // we memorize the current state of all PINs [D0-D7]

  cTime = micros();         // micros() return a uint32_t, but it is not usefull to keep the whole bits => we keep only 16 bits

  // mask is pins [A0-A7] that have changed
  // chan = pin sequence of the port. chan begins at D2 and ends at D7
  if (mask & 1<<0)           //indicates the bit 2 of the arduino port [D0-D7], that is to say digital pin 2, if 1 => this pin has just changed
    if (!(pin & 1<<0)) {     //indicates if the bit 2 of the arduino port [D0-D7] is not at a high state (so that we match here only descending PPM pulse)
      dTime = cTime-edgeTime[0];
      if (900<dTime && dTime<2200) rcPinValue[0] = dTime; // just a verification: the value must be in the range [1000;2000] + some margin
    }
    else edgeTime[0] = cTime;

     Etc......

Et celui-ci fonctionne correctement!

Dans le projet que je souhaite réaliser, j'ai besoin des pins analogique (A4 et A5 pour l'I2C, tension batterie, ...), donc il faut que je puisse brancher mon RX sur les pins digitals...

Mes questions :
 * Est-ce que j'ai loupé quelque chose dans le code du MULTIWII qu'il faut reporter dans mon sketch
 * Comment la détection des signaux RX est-elle faite sur MULTIWII, est-ce qu'il y a de l'électronique sur la carte MULTIWII pour adapter le niveau du signal RX

Voilà ma première question sur ce forum en ce dimanche matin. Vos réflections sont les biens venues...

A+
Olivier





Logged

Paris
Offline Offline
Sr. Member
****
Karma: 2
Posts: 366
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Apparement tu as vu juste :
http://www.modelisme.com/forum/aero-radio-electronique/159707-incompatibilite-futaba-t10-servo-hitec.html#post1719722

Quel modèle de carte MultiWii utilise-tu ? peut-être intègre-t-elle un "signal booster" en ligne sur les entrées.

Pour le MultiWii, j'utilise l'entrée PPM, c'est moins gourmand pour le micro contrôleur, et tu est certain de ne pas avoir 2 interruptions simultanées  smiley-cool

A voir ici pour récupérer le PPM Futaba (à tester sur ton Rx) :
http://diydrones.com/profiles/blogs/705844:BlogPost:38393
Peut-être que cette méthode fonctionne sur ton Rx (attention son code n'est pas optimisé, il utilise des pulseIn)

Pour la partie code, tu trouveras dans ce sujet :
http://arduino.cc/forum/index.php/topic,116024.0.html
La dernière version de mes travaux à ce niveau (récupération PPM par CapturePin), j'ai aussi des versions plus anciennes ou je récupérais les signaux des sorties servo, l'historique est ici en Anglais :
http://www.rcgroups.com/forums/showthread.php?t=1648040&page=2
« Last Edit: February 10, 2013, 06:56:00 am by UniseV » Logged

EN: Libraries are my Gurus, they make me believe anything they want !
FR: Les librairies sont mes gourous, elles me font croire ce qu'elles veulent !

0
Offline Offline
Jr. Member
**
Karma: 1
Posts: 72
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

J'ai trouvé  smiley-lol :

La variable DDRD était mal configurée :

Code:
void configureReceiver() {
  for (uint8_t chan = 0; chan < 8; chan++)
    for (uint8_t a = 0; a < 4; a++)
      rcData4Values[chan][a] = 1500; //we initiate the default value of each channel. If there is no RC receiver connected, we will see those values
  // PCINT activated only for specific pin inside [D0-D7]  , [D2 D4 D5 D6 D7] for this logger
  DDRD = B00000000;    // Toutes les pins configurées en entrée
  PORTD   = (1<<2) | (1<<3) | (1<<4) | (1<<5) | (1<<6) | (1<<7); //enable internal pull ups on the PINs of PORTD (no high impedence PINs)
  PCMSK2 |= (1<<2) | (1<<3) | (1<<4) | (1<<5) | (1<<6) | (1<<7);
  PCICR   = 1<<2; // PCINT activated only for the port dealing with [D0-D7] PINs
}

Ce qui était bizarre, c'est que ça marchait quand même dans certaines circonstances...

UniseV : Merci pour ta réponse.
Logged

Pages: [1]   Go Up
Jump to: