Démarrer en électronique programmable

Toutes les discussions sur l'Arduino !

Modérateur : MOD

Répondre
Avatar du membre
Arduino
Prolixe
Messages : 1699
Enregistré le : mer. 25 sept. 2013, 17:14

Re: Démarrer en électronique programmable

Message par Arduino » sam. 27 févr. 2016, 18:49

Voilà comment tu devrais opérer :

Sur une plaque d'essai, tu branches deux boutons poussoirs sur les entrées 2 et 3. Ce sont les entrées qui permettent les interruptions dont j'ai parlé dans le cours.

Tu peux brancher une (ou deux) DEL rouge(s) sur la sortie 4, ou bien utiliser la DEL du module qui est sur 13 pour la mise au point.

Ainsi, tu as reconstitué ton PN. Le premier poussoir représente l'ILS1 qui annonce le train, l'autre poussoir représente le 2 qui libère le PN. OK comme cela ?

Ton programme fait clignoter la ou les DEL (tu peux prendre Blink pour le modifier) mais vérifie au tout début une variable booléenne qu'on va appeler presence_train qui vaut 0 en temps normal, et 1 si un train arrive donc si poussoir 1 appuyé et qui revaudra 0 si poussoir 2 appuyé.

En fonction de la valeur de presence_train, tu exécutes ou non ton clignotement.

1- dessine ton montage avec fritzing (cela fait partie de l'apprentissage et me permettra de voir si ton montage est bon)
2- écrit le programme en utilisant une interruption sur la broche 2 pour mettre presence-train à 1 et une autre sur la broche 3 pour remettre presence_train à 0.

Pas besoin de boucle for !

Et après, on en rediscute... :wink:

Avatar du membre
tgvdu88
Papotier
Messages : 179
Enregistré le : sam. 25 oct. 2008, 17:45
Site Internet : https://www.facebook.com/tgvdu88/
Contact :

Re: Démarrer en électronique programmable

Message par tgvdu88 » sam. 27 févr. 2016, 19:41

J'en suis là mais pour l'instant ça ne marche pas, il faut que je m'y replonge :)

Code : Tout sélectionner

// définition de la broche 2 de la carte en tant que variable
const int led_rouge = 4;
#define ILS 3 // ILS avant PN
#define ILS1 2 // ILS1 après PN
boolean Inter = 0;

void interruptionILS1 ()
{
  if (digitalRead (ILS1)== LOW){{

  Inter = 0;} // bouton appuyé
{ 
 while(Inter == 0) 
 {digitalWrite (led_rouge, LOW);}}}
}


// fonction d'initialisation de la carte
void setup()
{
    // initialisation de la broche 2 comme étant une sortie
pinMode(led_rouge, OUTPUT);
pinMode (ILS, INPUT_PULLUP);
pinMode (ILS1, INPUT_PULLUP);
digitalWrite (led_rouge, LOW);
attachInterrupt (0,interruptionILS1, CHANGE);
}
void loop()
{

if (digitalRead (ILS)== LOW){{
  Inter = 1;} // bouton appuyé
{ 
 while(Inter == 1) // si BP appuyé
  { digitalWrite (led_rouge, HIGH);
  delay (750);
  digitalWrite (led_rouge,LOW);
  delay (750);
  }}}
}
     
Pour le schéma c'est celui-ci:
Image
Fichiers joints
Feux PN.JPG
Feux PN.JPG (60.38 Kio) Vu 1812 fois

Avatar du membre
jlb
Fécond
Messages : 694
Enregistré le : jeu. 04 oct. 2012, 16:38
Echelle pratiquée : N
Prénom : Jean-Luc
Site Internet : http://modelleisenbahn.triskell.org

Re: Démarrer en électronique programmable

Message par jlb » sam. 27 févr. 2016, 21:52

Bonsoir,
tgvdu88 a écrit :

Code : Tout sélectionner

void loop()
{
  if (digitalRead (ILS)== LOW)
  {
    {
      Inter = 1;
    } // bouton appuyé
    { 
      while(Inter == 1) // si BP appuyé
      {
        digitalWrite (led_rouge, HIGH);
        delay (750);
        digitalWrite (led_rouge,LOW);
        delay (750);
      }
    }
  }
}
Il y a des accolades excédentaires dans ton programme. Ce n'est pas facile à lire. Le formatage le rend également difficile à lire. Je le reformate :

Code : Tout sélectionner

void loop()
{
  if (digitalRead (ILS)== LOW)
  {
    Inter = 1; // bouton appuyé
    while(Inter == 1) // si BP appuyé
    {
      digitalWrite (led_rouge, HIGH);
      delay (750);
      digitalWrite (led_rouge,LOW);
      delay (750);
    }
  }
}
Le programme reste bloqué sur le clignotement et actionner l'ILS de nouveau ne donne rien. J'ai bon ?

Avatar du membre
tgvdu88
Papotier
Messages : 179
Enregistré le : sam. 25 oct. 2008, 17:45
Site Internet : https://www.facebook.com/tgvdu88/
Contact :

Re: Démarrer en électronique programmable

Message par tgvdu88 » sam. 27 févr. 2016, 22:36

Oui tu as tapé dans le mille :P

Avatar du membre
jlb
Fécond
Messages : 694
Enregistré le : jeu. 04 oct. 2012, 16:38
Echelle pratiquée : N
Prénom : Jean-Luc
Site Internet : http://modelleisenbahn.triskell.org

Re: Démarrer en électronique programmable

Message par jlb » dim. 28 févr. 2016, 00:43

Il y a plusieurs problèmes :

Tout d'abord ce n'est pas l'état de l'ILS qui est intéressant. En effet, tu démarres le clignotement sur le fait que l'entrée associée à l'ILS soit LOW. Or quand un train va se présenter, le programme va lire LOW plusieurs fois de suite. Et donc le clignotement va être démarré plusieurs fois. Il faut donc détecter le passage de HIGH à LOW et donc mémoriser la valeur précédente de l'entrée et la comparer à la valeur courante.

Ensuite un ILS ne colle pas franchement. Quand il colle il risque d'y avoir des rebonds. Le programme va donc voir plusieurs passages de HIGH à LOW. Il faut donc faire un antirebond.

Tu ne peux pas utiliser delay car pendant ce temps, le train peut passer devant l'ILS de sortie et le programme ne le verra pas. Il faut gérer le clignotement différemment avec la fonction millis. Voir à ce propos http://www.locoduino.org/spip.php?article6

Enfin, une fois que l'ILS a été vu LOW, le programme reste bloqué dans le while.

Pour régler le problème de l'ILS, le mieux est d'utiliser une bibliothèque ou tout est déjà dispo comme Bounce2 : https://github.com/thomasfredericks/Bou ... master.zip

Pour faire clignoter la LED tu peux faire à la main comme dans l'article dont le pointeur est ci-dessus ou bien utiliser la bibliothèque ScheduleTable : http://www.locoduino.org/spip.php?article116
Modifié en dernier par jlb le dim. 28 févr. 2016, 00:57, modifié 1 fois.

Alain17
Démonstratif
Messages : 1424
Enregistré le : ven. 21 juil. 2006, 16:36
Localisation : Entre Cognac, Ré et Oléron

Re: Démarrer en électronique programmable

Message par Alain17 » dim. 28 févr. 2016, 00:49

tgvdu88 a écrit :J'en suis là mais pour l'instant ça ne marche pas, il faut que je m'y replonge :)...
Je crois que tu devrais relire les conseils d'Arduino dans son cours sur les interruptions :
viewtopic.php?f=63&t=80539&start=225#p1873798

Avatar du membre
Arduino
Prolixe
Messages : 1699
Enregistré le : mer. 25 sept. 2013, 17:14

Re: Démarrer en électronique programmable

Message par Arduino » dim. 28 févr. 2016, 10:58

tgvdu88 a écrit :J'en suis là mais pour l'instant ça ne marche pas, il faut que je m'y replonge :)
.........
Bonjour tgvdu88 et autres élèves,

Je vais reprendre ton programme et y apporter quelques commentaires qui d'ailleurs s'adressent à tous les élèves de façon générale.

La première remarque est que ton programme est difficile à lire car il n'est pas assez indenté (ou formaté) ; jlb l'a d'ailleurs déjà mentionné dans le cours : il faut utiliser l'indentation proposée par l'IDE. Cette indentation aurait pu te permettre de voir que les accolades ne sont pas en nombre pair (9 pour ta fonction d'interruption et 9 dans loop) or il faut autant d'accolades ouvrantes que fermantes. Ceci me fait penser que tu essaies de faire fonctionner ton programme en rajoutant des bouts de code (rustines) par ci par là. Mais pour que cela fonctionne, il faut déjà que le principe de fonctionnement soit bien clair dans ta tête.

Je reprends donc ton programme avec en rouge mes commentaires :

// définition de la broche 2 de la carte en tant que variable
Non, une broche est une broche et une variable booléenne est une valeur du programme qui peut être soit vraie (TRUE ou encore 1), soit fausse (FALSE ou encore 0). Ne pas confondre les deux.
const int led_rouge = 4;
#define ILS 3 // ILS avant PN
#define ILS1 2 // ILS1 après PN
Le site Arduino conseille de plutôt utiliser les const int et non les #define qu'on réservera pour des définitions plus sophistiquées. Prends ce que tu préfères, mais agit toujours de la même façon (bon, ceci est un petit détail).
boolean Inter = 0;
Le nom de cette variable n'est pas assez explicite : que signifie Inter pour un autre programmeur que toi ? Interrupteur, Interruption, Interlude ? Même si le nom est plus long, tu te féliciteras de l'avoir choisi quand tu reprendras le programme dans un an pour l'améliorer (d'ici là, tu auras oublié comment il fonctionne).

void interruptionILS1 ()
{
if (digitalRead (ILS1)== LOW){{

Inter = 0;} // bouton appuyé
{
while(Inter == 0)
{digitalWrite (led_rouge, LOW);}}}
}
Pas besoin de surveiller les ILS puisqu'ils vont déclencher les interruptions ; ce sera le µC qui fera la surveillance et lorsqu'il détectera un déclenchement, il ira faire la routine d'interruption que tu auras définie.

// fonction d'initialisation de la carte
void setup()
{
// initialisation de la broche 2 comme étant une sortie
pinMode(led_rouge, OUTPUT);
pinMode (ILS, INPUT_PULLUP);
Pourquoi cet ILS n'est pas numéroté comme l'autre ?
pinMode (ILS1, INPUT_PULLUP);
digitalWrite (led_rouge, LOW);
attachInterrupt (0,interruptionILS1, CHANGE);
Pas CHANGE car sinon lorsque l'ILS ne sera plus déclenché et qu'il passera de 0 à 5 V, il provoquera une interruption et ce n'est pas ce que tu veux. Utilise plutôt LOW ou FALLING.
}
void loop()
{

if (digitalRead (ILS)== LOW){{
Inter = 1;} // bouton appuyé
{
while(Inter == 1) // si BP appuyé
{ digitalWrite (led_rouge, HIGH);
delay (750);
digitalWrite (led_rouge,LOW);
delay (750);
Il est déconseillé d'utiliser delay avec les interruptions, donc comme l'a dit jlb, on va utiliser le programme BlinkWithoutDelay (ou s'en inspirer).
}}}
}

Voici maintenant comment je verrais le fonctionnement de ce programme. Tout d'abord, j'ai deux ILS :
ILS0 en amont du PN (relié à broche 2)
ILS1 en aval du PN (relié à broche 3)
Cette numérotation 0 et 1 est préférable à 1 et 2, tu le comprendras avec la fonction attachInterrupt... :wink:
led_rouge est sur la sortie 4
la variable booléenne s'appelle presence_train et est initialisée à FALSE.

Programme principal : tu as très bien décrit ce que tu veux qu'il fasse, donc résumons : le programme principal doit faire clignoter la led_rouge uniquement si presence_train est TRUE ! Point final. Donc, voici ce que cela pourrait donner :

void loop () {
if (presence_train == TRUE) {
// Mettre ici le programme de clignotement sans delay
}
}
Mais comment faire pour avoir presence_train à TRUE ou bien FALSE ? Ce sera le rôle des interruptions.
Celle déclenchée par ILS0 :
void interrupt_ILS0 () {
presence_train = TRUE ;
}
Celle déclenchée par ILS1 :
void interrupt_ILS1 () {
presence_train = FALSE ;
}

Désolé, j'avais mis des espaces pour créer une indentation, mais le forum les vire. :oops:
Et bien sûr, dans le setup les attachInterrupt qui vont bien.

Je n'aurais pas le temps de tester ce programme avant ce soir. Pour ce qui concerne les rebonds, je ne crois pas que ce sera un problème car dès qu'un ILS passe à LOW, il change la variable booléenne et peu importe s'il le fait 3 ou 4 fois de suite, ce sera toujours la même valeur...

Dis-moi si tu as bien suivi tout ce que je te dis et ne te décourage pas, cela finira par fonctionner (ceci dit, l'automatisme d'un PN avec des ILS, deux voies, des servos, des feux de St André et peut-être aussi la sonnerie n'est pas un problème simple à résoudre :roll: donc, il faut y aller par palliers successifs).

Avatar du membre
tgvdu88
Papotier
Messages : 179
Enregistré le : sam. 25 oct. 2008, 17:45
Site Internet : https://www.facebook.com/tgvdu88/
Contact :

Re: Démarrer en électronique programmable

Message par tgvdu88 » dim. 28 févr. 2016, 11:38

Merci à tous pour vos analyses et vos conseils.

J'avais modifié mon programme après avoir publié le premier. Je l'ai rendu plus clair mais je vais encore apporter vos modifications.

Pour le programme, la ligne avec l'histoire de la broche 2 c'est une partie d'un copié collé et j'ai oublié de la supprimer :mdr:

J'ai bien compris que Delay ne peux pas être utilisé mais la fonction millis non plus me semble t'il. j'ai vu qu'il y a une fonction qui fonctionne, mais il faut que je retrouve son nom.


Je pense que je commence à comprendre le principe, je vais retravailler dessus.

Merci à tous ;)

Avatar du membre
Arduino
Prolixe
Messages : 1699
Enregistré le : mer. 25 sept. 2013, 17:14

Re: Démarrer en électronique programmable

Message par Arduino » dim. 28 févr. 2016, 12:01

tgvdu88 a écrit :Merci à tous pour vos analyses et vos conseils.
.......
J'ai bien compris que Delay ne peux pas être utilisé mais la fonction millis non plus me semble t'il. j'ai vu qu'il y a une fonction qui fonctionne, mais il faut que je retrouve son nom.
A essayer tout de même ; millis() ne s'incrémente pas, mais cela n'a pas une grande importance car la durée de clignotement n'est pas critique. Si tu perds quelques millisecondes, ce n'est pas grave. Avant de chercher une autre solution, j'essaierai déjà millis() pour voir mais je ne garantis pas le résultat (cela se tente).

J'ai aussi oublié de te dire : il faut déclarer presence_train en volatile (pour que la variable soit dans la mémoire RAM et non dans les registres où elle pourrait être écrasée) :
volatile boolean presence_train = FALSE ;

Avatar du membre
tgvdu88
Papotier
Messages : 179
Enregistré le : sam. 25 oct. 2008, 17:45
Site Internet : https://www.facebook.com/tgvdu88/
Contact :

Re: Démarrer en électronique programmable

Message par tgvdu88 » dim. 28 févr. 2016, 14:41

Bon alors mon programme fonctionne! Il reste encore un détail à régler. Lorsque que l'interruption est activé lorsque les LED sont allumées elles restent dans leur état et inversement.
Je vais revoir mon programme :)

edit: c'est bon problème réglé!
Il fallait juste rajouter une condition.

Avatar du membre
Arduino
Prolixe
Messages : 1699
Enregistré le : mer. 25 sept. 2013, 17:14

Re: Démarrer en électronique programmable

Message par Arduino » dim. 28 févr. 2016, 18:05

Je suis très content pour toi et aussi pour moi car tu es la preuve qu'on arrive toujours à trouver une solution avec Arduino et que ce n'est pas aussi compliqué que ce que certains affirment... Bravo :applause:

Je présenterai l'exercice de la gestion d'un PN un jour, mais je ne le traiterai sans doute pas avec des ILS. Ce sera l'occasion de faire cogiter sur un sujet qui en intéresse plus d'un. :siffle:

Avatar du membre
tgvdu88
Papotier
Messages : 179
Enregistré le : sam. 25 oct. 2008, 17:45
Site Internet : https://www.facebook.com/tgvdu88/
Contact :

Re: Démarrer en électronique programmable

Message par tgvdu88 » dim. 28 févr. 2016, 18:17

Je pense que je finirai par remplacer les ILS par des detecteurs infra rouge mais qui au niveau logiciel ne devrait pas changer grand chose. A voir...

Avatar du membre
Arduino
Prolixe
Messages : 1699
Enregistré le : mer. 25 sept. 2013, 17:14

Re: Démarrer en électronique programmable

Message par Arduino » dim. 28 févr. 2016, 18:40

Personnellement, je pense que ce problème de gestion de PN est plus facile si on dispose de détecteur d'occupation de voies réagissant sur toute la longueur de voie à protéger.

Bon, je t'avais promis un programme pour la soirée : le voici et je l'ai essayé avec le mock-up de gestion des signaux à trois feux, en déplaçant trois câbles et il fonctionne (comme toi, la led_rouge restait allumée si l'ILS1 était déclenché pendant une période d'allumage, mais en rajoutant une ligne dans la fonction d'interruption de l'ILS de sortie, cela a résolu le problème).

Code : Tout sélectionner

/*  Ce programme gere un PN a une seule voie parcourue dans un seul sens.
 *  Deux ILS, un en amont du PN, l autre en aval, provoquent des interruptions,
 *  ce qui modifie une variable indiquant la presence ou non d un train.
 *  La fonction loop est la copie de l exemple BlinkWithoutDelay
 */
 
const int ILS0 = 2; // ILS0 avant PN
const int ILS1 = 3; // ILS1 apres PN
const int led_rouge =  4;
volatile boolean presence_train = false;

// Variables will change :
int ledState = LOW;             // ledState used to set the LED

// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long previousMillis = 0;        // will store last time LED was updated

// constants won't change :
const long interval = 1000;           // interval at which to blink (milliseconds)

void setup() {
  // set the digital pin as output:
  pinMode (led_rouge, OUTPUT);
  pinMode (ILS0, INPUT_PULLUP);
  pinMode (ILS1, INPUT_PULLUP);
  attachInterrupt (0, interrupt_ILS0, LOW);
  attachInterrupt (1, interrupt_ILS1, LOW);
}

void loop() {
  if (presence_train == true) {
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }

    // set the LED with the ledState of the variable:
    digitalWrite(led_rouge, ledState);
  }
  }
}

void interrupt_ILS0 () {
  presence_train = true;
}

void interrupt_ILS1 () {
  presence_train = false;
  digitalWrite (led_rouge, LOW);
}
Tu dois pouvoir le tester si ta maquette respecte bien les E/S que j'ai utilisées (voir plus haut). :wink:

Avatar du membre
tgvdu88
Papotier
Messages : 179
Enregistré le : sam. 25 oct. 2008, 17:45
Site Internet : https://www.facebook.com/tgvdu88/
Contact :

Re: Démarrer en électronique programmable

Message par tgvdu88 » dim. 28 févr. 2016, 20:33

Il va falloir que je remonte le mock up de l'exercice a 3 feux pour tester ;)
Mon programme est le meme que le tien sauf que j'ai rajouter la conditon dans loop.

Avatar du membre
Arduino
Prolixe
Messages : 1699
Enregistré le : mer. 25 sept. 2013, 17:14

Re: Démarrer en électronique programmable

Message par Arduino » dim. 28 févr. 2016, 20:40

Non, il te suffit de refaire le montage que tu as publié un peu plus haut ; il n'y a que trois sorties à câbler.

Note que sur ton schéma, les deux fils rouges ne servent à rien puisque le 5 V n'est pas nécessaire.

Et maintenant, tes projets ? Améliorer le module de gestion PN ou bien transformer le module à signaux 3 feux en véritable B.A.L avec arrêt des trains qui se suivent devant un feu rouge ? :gne:

Répondre