Auteur Sujet: Ajout fonction à mon programme décodeur d’accessoires universel  (Lu 13316 fois)

Boubou

  • Newbie
  • *
  • Messages: 5
    • Voir le profil
Bonjour,

J'ai débuter mon circuit avec une boite minitrix digital avec une mobile station, mais ne voulant pas utiliser le reste de la digitalisation Minitrix ( commande des aiguillages, détection de passage, etc..), et je me suis dit qu'avec arduino, et quelques shield je devais m'en sortir.
Je suis tombé sur ce magnifique site de connaissance qui est Locoduino, et avec le programme "décodeur d'accessoires universel", j'ai réussi sans trop de souci à faire fonctionner ma détection DCC pour piloter mes aiguillages.

Mon problème c'est posé dès que j'ai voulu ajouter ma détection de passage.

En fait, ma détection se fait avec des LEDs infra-rouge et des phototransistors.
Les Leds : je  les fais clignoter à 1khz
Mes phototransistors : ils sont connectés sur les entrées digitales de Mon arduino Mega.

J'ai voulu ajouter une boucle de lecture dans mon programme décodeur d'accesoires universel, et cà ne marche pas, en fait cà bloque la partie décodeur, et je comprends pas vraiment pourquoi.

Doi-je créer une fonction, mettre ma boucle ailleur ? franchement je suis un peux largué  :'(, Merci pour votre aide

Voici la partie boucle de mon programme :
 
void loop()
{
 
  for (int a=38; a<46 ; a++ ) {
  int duration = pulseIn(a,HIGH);
  int b=duration+8;
     if (duration >450 && duration <1500){
    digitalWrite (b, LOW);
  }else {digitalWrite (b, HIGH;}
  }
 
    // Dcc is run first, and if necessary, lets the accessories work.
  if (dccCommander.Loop())
 
  {
    Serial.println ("accessories.loop");
    accessories.Loop();
  }

Dominique

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 2870
  • 100% Arduino et N
    • Voir le profil
Re : Ajout fonction à mon programme décodeur d’accessoires universel
« Réponse #1 le: juin 16, 2016, 11:35:39 pm »
Bonjour,

En fait, ma détection se fait avec des LEDs infra-rouge et des phototransistors.
Les Leds : je  les fais clignoter à 1khz
Mes phototransistors : ils sont connectés sur les entrées digitales de Mon arduino Mega.

Mais pourquoi faire clignoter les leds IR ? : cela complique le programme en ajoutant des fonctions du temps qui interfèrent avec le décodage DCC. Si en plus il y a du filtrage du 1000 Hz sur les entrées digitales, ça devient inutilement compliqué.

Personnellement je fais de la détection IR avec des diodes IR qui émettent en continu.
Cordialement,
Dominique

Boubou

  • Newbie
  • *
  • Messages: 5
    • Voir le profil
Re : Ajout fonction à mon programme décodeur d’accessoires universel
« Réponse #2 le: juin 17, 2016, 10:08:16 am »
Bonjour Dominique,

Je fais clignoter les leds pour éviter que la lumière extérieur (soleil, lampe halogène) soit détecter par mon phototransistor. Ma détection se fait depuis dessous avec ce composant : ITR20001

Pour info : j'ai reçu deux réponses  sur mon problème et je les remercies

voici leur réponse :

1) De ce que je comprends, pulseIn peut prendre un temps indéterminé, qui peut au pire osciller entre 450 et 1500 millisecondes pour une seule broche, et vous bouclez sur neuf broches de 38 à 46 ! C’est beaucoup trop long et ne permet pas au reste de fonctionner correctement... La première modification pourrait être de ne faire qu’une seule broche à chaque loop(). Mais même dans ce cas, la plus grande des durées possibles est tout de même d’une seconde et demie ! Un traitement par interruption pourrait faire l’affaire, mais il y a trop de broches concernées... La seule solution viable serait de faire faire ce travail à un autre Arduino, et de les faire discuter via I2C, CAN ou liaison série. Il faut réfléchir davantage...
2) La solution consiste à ne pas utiliser pulseIn qui est une fonction bloquante.
Tel que c’est écrit, la boucle bloque longtemps le programme et les messages DCC sont perdus.

La solution que je vais essayer d'appliquer, c'est d'ajouter un arduino et ainsi séparer ma gestion DCC de ma détection.
Le Mega me servira pour la détection et un Uno pour le DCC.

Merci à tous, je vous tiens au courant si cà marche

Jean-Luc

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 1691
    • Voir le profil
Re : Ajout fonction à mon programme décodeur d’accessoires universel
« Réponse #3 le: juin 17, 2016, 10:11:24 am »
Bonjour,

pulsiIn est une fonction bloquante. En aucun cas ça ne peut fonctionner, les messages DCC sont perdus.

Il faut à chaque tour de boucle lire une des entrées et faire fonctionner un automate par entrée de manière non bloquante :

1) Il faut un tableau stockant l'état de scan de chaque entrée. Typiquement on a les états ATTENTE_PULSE et PULSE_EN_COURS. Si on est en ATTENTE_PULSE et que l'on voit un front montant, on passe en PULSE_EN_COURS et on récupère la date du front. Si on est en PULSE_EN_COURS et que l'on voit un front descendant, on passe en ATTENTE_PULSE et on calcule la durée du pulse. Puis on traite la sortie selon la durée calculée

2) il faut un tableau stockant la date du front montant.

3) il faut faire avancer le compteur (de 0 à 9) à chaque exécution de loop.

On va dire qu'il n'y a pas de rebond étant donné que ce sont des diodes IR

Donc

enum { ATTENTE_PULSE, PULSE_EN_COURS };

typedef struct {
  byte etatEntree;
  unsigned long dateFrontMontant;
} EntreePulse;

EntreePulse entrees[9];

byte entreeEnCours = 0;

Ensuite, il faut initialiser ceci à ATTENTE_PULSE dans setup

for (byte i = 0; i < 9; i++) entrees[i].etatEntree = ATTENTE_PULSE;

Ensuite dans loop

void loop()
{
  byte niveauEntreeEnCours = digitalRead(entreeEnCours + 38);
  if (entrees[entreeEnCours] == ATTENTE_PULSE) {
    if (niveauEntreeEnCours == HIGH) {
      // front montant sur l'entree
      entrees[entreeEnCours].etatEntree = PULSE_EN_COURS;
      entrees[entreeEnCours].dateFrontMontant = millis();
    }
  }
  else {
    if (niveauEntreeEnCours == LOW) {
      // front descendant sur l'entree
      unsigned long largeurPulse = millis() - entrees[entreeEnCours].dateFrontMontant;
      digitalWrite(entreeEnCours + 38 + 8, (largeurPulse > 450 && largeurPulse < 1500));
    }
  }
  entreeEnCours++;
  if (entreeEnCours == 9) entreeEnCours = 0;

  if (dccCommander.Loop())
  {
      accessories.Loop();
  }
}

Non testé
« Modifié: juin 17, 2016, 02:19:23 pm par Jean-Luc »
Cordialement

Boubou

  • Newbie
  • *
  • Messages: 5
    • Voir le profil
Re : Ajout fonction à mon programme décodeur d’accessoires universel
« Réponse #4 le: juin 19, 2016, 04:51:07 pm »
Salut Jean-Luc,

Merci pour ton code, je l'ai installé mais j'ai un bug et je trouve pas, peux-tu m'aider ?

message d'error :

no match for 'operator==' (operand types are 'EntreePulse' and '<anonymous enum>')

Je te remercie d'avance pour ton aide

boubou
 

Thierry

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 740
    • Voir le profil
Re : Ajout fonction à mon programme décodeur d’accessoires universel
« Réponse #5 le: juin 19, 2016, 05:54:02 pm »
Salut

Utiliser ici un enum anonyme me parait musclé ! J'aurais plutôt codé:

enum Pulse { ATTENTE_PULSE, PULSE_EN_COURS };

typedef struct {
  Pulse etatEntree;
  unsigned long dateFrontMontant;
} EntreePulse;

Boubou

  • Newbie
  • *
  • Messages: 5
    • Voir le profil
Re : Ajout fonction à mon programme décodeur d’accessoires universel
« Réponse #6 le: juin 19, 2016, 06:53:00 pm »
Salut Thierry,

Merci pour le conseil, mais ça ne résoud pas mon problème.

J'ai beau chercher, je ne trouve pas.

Merci

Boubou
« Modifié: juin 19, 2016, 07:35:04 pm par Dominique »

Jean-Luc

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 1691
    • Voir le profil
Re : Ajout fonction à mon programme décodeur d’accessoires universel
« Réponse #7 le: juin 19, 2016, 07:22:57 pm »
Erreur de ma part. C'est entrees[entreeEnCours].etatEntree == ATTENTE_PULSE qu'il faut écrire.
Cordialement

Boubou

  • Newbie
  • *
  • Messages: 5
    • Voir le profil
Re : Ajout fonction à mon programme décodeur d’accessoires universel
« Réponse #8 le: juin 19, 2016, 11:51:46 pm »
Hello,

Merci à Jean-luc et Thierry , cà marche, plus qu'à régler qq détails.


Boubou