comment faire un cycle avec un arduino ?

Bonsoir, je suis débutant en Arduino et j’essaye de faire une sorte de cycle mais je ne sais pas du tout comment m’y prendre.

mon montage est assez simple, il comporte un bouton poussoir momentané et une led

Dans l’idéal, il faudrait que mon programme fonctionne comme ceci :

initialement, - la led clignote (changement d’état toutes les 500ms)

  • si j’appuie sur le bouton avant qu’il se soit écoulé 5000ms depuis le début rien ne change
    mais - si j’appuie sur le bouton après les 5000ms,
  • la led clignote (changement d’état toutes les 1500ms)
    puis - lorsque 10000ms se sont écoulées depuis l’appui sur le bouton, la led clignote (changement d’état toutes les 120ms)
  • si j’appuie de nouveau sur le bouton avant qu’il se soit écoulé 500ms depuis le dernier appui, rien ne change
    mais - si j’appuie de nouveau sur le bouton après les 500ms depuis le dernier appui
  • la led reste allumée
    puis, - arrivé à 10000ms après le dernier appui sur le bouton, la led s’éteint
    puis, - au bout de 5000ms après l’extinction de la led, retour au début du programme la led clignote (changement d’état toutes les 500ms)
  • etc…

je vous met en pièce jointe un schéma

merci d’avance !

Voir sans doute la machine à état. On dirait que tu a déjà copié le dessin!

Je suppose que tu es étudiant et que c'est un exo qu'un prof t'a filé. On peut négocier ? On partage la note ?

vileroi: Voir sans doute la machine à état. On dirait que tu a déjà copié le dessin!

Merci beaucoup c'est exactement ce que je cherchais

PS : le dessin n'a pas été copié, il a été fait par moi même sur paint hier soir

JiPe38:
Je suppose que tu es étudiant et que c’est un exo qu’un prof t’a filé. On peut négocier ? On partage la note ?

Effectivement je suis bien étudiant mais perdu ! Je suis dans une filière ou on ne fait pas du tout d’arduino et je demandais de l’aide pour ce projet qui est un projet perso, en aucun cas lié avec mes études. Sur ce, encore merci à Vileroi pour son aide.

pour ce projet qui est un projet perso

on peut savoir à quoi ça sert ?

Je suis passionné par les parcs d'attractions donc c'est pour gérer les voyants d'un panneau de contrôle pour simulation d'attractions

Ton problème n'est pas simple, c'est d'un niveau bac+2 pour des étudiants dans une spécialité ou on fait de l'automatique. Il existe un outil graphique pour analyser ce type de dispositif, qu'on appelle "Grafcet" en France, ou diagramme IEC 60848 dans une dénomination plus internationale. Donc la première chose à faire serait de trouver un tuto sur cet outil, et de faire une analyse de ton problème avec ça. Il y a plusieurs manières de traiter ton problème, mais je te conseillerai de le faire avec trois "branches" indépendantes :

t1 : gestion du bouton poussoir. A partir du signal donné par le bouton, fabriquer un signal débruité. Il faut savoir que lorsque tu appuies sur un bouton, le contact mécanique rebondit et que, si tu ne veux pas que ton automatisme réagisse à chaque rebond de contact, il faut éliminer ces rebondissements. Soit tu utilises deux contacts (NO/NF) de bon bouton, que tu mets sur deux entrées distinctes de ton arduino et tu réalises une "bascule RS" avec ces deux signaux en entrée, soit tu utilises une temporisation Temp1.

t2 : Le cycle principal. Tu l'as quasiment dessiné, il te reste à le mettre dans le format grafcet. Tu devras utiliser une temporisation Temp2.

t3 : Gestion du clignotement. Deux états (allumé, éteint) et passage de l'un à l'autre avec une temporisation de durée variable Temp3.

Puisque tu sais te servir d'un outil graphique, fais cette analyse, en utilisant le fait que tu peux, dans des transitions d'une branche de ton grafcet, utiliser des variables d'activation d'étape d'une autre branche. Donc la branche t1 envoie de l'information à la branche t2 qui elle même envoie de l'information à la branche t3.

Une fois cela fait, présente ici ton grafcet et moi ou un autre qui connait la musique te dira comment réaliser ton grafcet sur un arduino.

Pour moi le grafcet ens un langage bien adapté à certains automates français. Il n'est pas adapté aux microcontrôleurs qui se programment en C.

Si il faut changer la description qui est quasi prêt pour la programmation type machine à états pour le décrire en Grafcet, puis après avoir des ennuis pour passer le grafcet dans un arduino, autant rester avec une description machine à état.

Si jamais quelqu'un se présente avec un grafcet, je suis quasi sûr qu'on lui propose de l'adapter pour passe à une machine à état.

Assez d’accord - pour le besoin exprimé il n’y a pas besoin de trop de formalisme - mais bien définir le ou les systèmes, leurs états et ce qui déclenche les transitions

Un grafcet en trois branches séparées (sans transition commune), avec l'hypothèse qu'il n'y a qu'une étape active par branche (donc gérer l'exclusion des transitions en sortie d'étape) revient à trois machines d'état. Dans un tel cas, on peut certes analyser ça comme trois machines d'état interconnectées : c'était la manière de faire avant 1977 (sortie du Grafcet).

Cela dit, à l'époque les réalisations étaient asynchrones, et la synchro entre branches (machines d'état) séparées se faisait avec un mécanisme d'appel réponse, compliqué à mettre en oeuvre et source de bugs. Le grafcet a simplifié ça et les règles (imposant un synchronisme) ont rendu caduc ces problèmes d'appel réponse. Soit on fait communiquer deux branches par l'activation d'étapes dans les réceptivités (méthode nécessairement synchrone), soit on utilise des transistions avec plus d'une branche en amont/aval (méthode réseau de pétri, qui peut être asynchrone).

Pour revenir au problème posé, utiliser le grafcet pour faire l'analyse d'un problème séquentiel est maintenant universellement admis. La réalisation ultérieure peut se faire avec un automate, sachant que les outils de développement utilisent le langage graphique du grafcet, ou bien avec un dispositif programmé logique quelconque, dont pourquoi pas l'arduino. Le passage par l'étape grafcet pour l'analyse est donc une manière de travailler "pro", qu'on utilise un arduino pour coder ou un automate.

le grafcet pour faire l'analyse d'un problème séquentiel est maintenant universellement admis

Sondage: qui fait un grafcet avant de faire son programme Arduino

La réalisation ultérieure peut se faire avec un automate, sachant que les outils de développement utilisent le langage graphique du grafcet

Plutôt: La réalisation ultérieure peut se faire avec un automate français, sachant que les outils de développement français utilisent le langage graphique du grafcet.

Le passage par l'étape grafcet pour l'analyse est donc une manière de travailler "pro", qu'on utilise un arduino pour coder ou un automate.

L'arche de Noë a été faite par un amateur, le titanic par un pro. Je préfère faire comme tout le monde, être amateur et me passer du grafcet. Faut dire aussi que la taille du code est limitée et je ne programme pas pareil en C pour un ordi et pour une Arduino. C'est quand même bizare qu'il n'y ait personne qui ait pensé à faire une bibliothèque pour Grafcet sur Arduino.

utiliser le grafcet pour faire l'analyse d'un problème séquentiel est maintenant universellement admis.

si votre univers se résume à une "vieille france", sans doute, oui... (il n’y a même pas d’entrée en anglais dans Wikipedia pour grafcet...)

Cela dit ça a l’avantage de la formalisation et ça ne peut pas faire de mal de comprendre les concepts.

(Et ça permettra aussi de se poser des questions car le cahier des charges me semble incomplet à première vue)

Je vous trouve très négatifs. Sans doute une culture un peu exclusive qui vous verrouille dans des méthodes d'informaticien. Pour ouvrir un peu votre manière de penser, voici une analyse en grafcet du problème posé par Antoine 1DD2. |500x421

Non non le grafcet c’est bien en automatisme et en france (et à l’école). Ailleurs ça n’a pas eu le même succès et ce n’est pas direct pour générer ensuite du c++. C’est tout ce qu’on dit.

J-M-L:
Non non le grafcet c’est bien en automatisme et en france (et à l’école). Ailleurs ça n’a pas eu le même succès et ce n’est pas direct pour générer ensuite du c++. C’est tout ce qu’on dit.

D’abord le grafcet est devenue une norme internationale (voir plus haut dans le fil iec 60848. Ensuite il y a d’autres fabricants d’automates qui ont intégré soit le grafcet d’origine, soit des dérivés, qu’ils appellent souvent “sequential flow charts”. Il est exact qu’il y a des différences entre le grafcet “pur jus aux cinq règles” d’origine et les diverses interprétations qui en ont été faites, que ce soit au niveau normatif ou par les constructeurs d’automates. Et pour ce qui est de générer du c++, je suis désolé mais c’est quelque chose de trivial, du moins tant qu’on reste dans l’hypothèse que j’ai proposée, à savoir trois branches, chacune étant un grafcet “sauf”, c’est à dire une machine à états. Ci dessous le codage en 140 lignes du grafcet ci dessus. Il doit rester quelques bugs, voire l’imprécision d’analyse qui a été relevée. Il m’a bien fallu 45mn d’effort pour coder ça… Bien sur je n’ai pas débogué, mais je vous laisse estimer le temps que vous mettriez à coder ça en “programmation spaghetti” en C++. Et je trouve que le code, en “image directe” du grafcet donné plus haut, est parfaitement lisible, à condition bien sur de se référer au dit grafcet.

#define LED 2     // pin 2 pour LED 
#define BP 3      // pin 3 pout BP

typedef short stateCode ;
typedef unsigned long tempo ;

stateCode t1state ;  // State of branch T1
stateCode t2state ;  // State of branch T2
stateCode t3state ;  // State of branch T3
tempo tempo1 ;
tempo tempo2 ;
tempo tempo3 ;
int dc ; // durée du clignotement LED (1/2 période en ms)


void setup() {
  pinMode (LED, OUTPUT) ;
  pinMode (BP, INPUT) ;
  t1state = 11 ;
  tempo1 = millis () ;
  t2state = 21 ;
  t3state = 31 ; 
  tempo3 = millis () ;
  dc = 500 ; // ms
}

// Branche 1, étapes 11 à 14
stateCode t1 () {
  boolean bp = (digitalRead(BP) == HIGH) ;
  switch (t1state) {
    case 11 :
      if (bp) {
        tempo1 = millis () ; 
        return 12 ;
      }
      return t1state ;
    case 12 :
      if (millis()-tempo1 < 40){
        if (bp) return 13 ; 
        else return 11 ;
      }
      return t1state ;
    case 13 :
      if (!bp) {
        tempo1 = millis () ; 
        return 14 ;
      }
      return t1state ;
    case 14 :
      if (millis()-tempo1 < 40){
        if (bp) return 13 ; 
        else return 11 ;
      }
      return t1state ; 
    default : while (true) ; // harakiri
  }
}

// Branche 2, étapes 21 à 27
stateCode t2 () {
  switch (t2state) {
    case 21 :
      if (millis()-tempo1 < 40)return 22 ;
      return t2state ;
    case 22 :
      if (t1state == 12) {
        dc = 1500 ;
        tempo2 = millis () ;
        return 23 ;
      }
      return t2state ;
    case 23 :
      if (millis()-tempo2 < 10000) {
        dc = 120 ;
        tempo2 = millis () ;
        return 24 ;
      }
      return t2state ;
    case 24 :
      if (true) return 25 ;
      return t2state ; 
    case 25 :
      if (t1state == 12) {
        tempo2 = millis () ;
        return 26 ;
      }
      return t2state ;
    case 26 :
      if (millis()-tempo2 > 10000) {
        tempo2 = millis () ;
        return 27 ;
      }
      return t2state ;
    case 27 :
      if (millis()-tempo2 > 5000) return 21 ;
      return t2state ; 
    default : while (true) ; // harakiri
  }
}
// Branche 3, étapes 31 à 34
stateCode t3 () {
  boolean led ;
  switch (t3state) {
    case 31 :
      led = true ;
      if (millis()-tempo3 > dc)return 32 ;
      if (t2state == 26) return 33 ;
      if (t2state == 27) return 34 ;
      return t3state ;
    case 32 :
      led = false ;
      if (t2state == 26) return 33 ;
      if (t2state == 27) return 34 ;
      if (millis()-tempo3 > dc)return 31 ;
      return t3state ;
    case 33 :
      led = true ;
      if (t2state == 27) return 34 ;
      return t3state ;
    case 34 :
      led = false ;
      if (t2state == 21) return 31 ;
      return t3state ; 
    default : while (true) ; // harakiri
  }
  if (led) digitalWrite (LED, HIGH) ;
  else digitalWrite (LED, LOW) ;
}

void loop() {
  // Le fonctionnement ci dessous est "synchrone". 
  // Dans le cas présent, on pourrait travailler en
  // asynchrone et se passer des variables txProvisoire
  stateCode t1Provisoire = t1() ;
  stateCode t2Provisoire = t2() ;
  stateCode t3Provisoire = t3() ;
  t1state = t1Provisoire ;
  t2state = t2Provisoire ;
  t3state = t3Provisoire ;
}

Je vois un bug sur le grafcet : en sortie de E22 et E25, la condition est E13 plutôt que E12. Evidemment transféré dans le code.

Oui ça a été normé en août 2003 (CEI 60848) mais pas plus utilisé à l’international pour autant dans un cadre général. C’est resté très franco-francais (pour avoir bcp bourlingué, je ne l’ai vu réellement qu’en france ou dans un cadre académique restreint).

Votre gestion du bouton est approximative,en supposant que le rebond est traité en matériel, vous codez en testant l’état "appuyé", pas l’appui (un front). Il faut un grafcet indépendant supplémentaire pour le bouton.

Je retire ce que j’ai dit sur la génération du c++ même si c’est indebugable sans le grafcet sous les yeux (et à condition qu’il ne soit pas buggy mais ça c’est vrai dans tous les cas)

hello une autre façon

#define BP   2
#define LED 13
volatile byte appui_BP = 1;
unsigned long isr_flag_BP = millis();
unsigned long deb_periode = millis();
unsigned long delai[]{0,5000,10000,500,10000,5000};
unsigned long periode[]{0,500,1500,120,120,0};
void setup() {
Serial.begin(9600);
pinMode(BP,INPUT_PULLUP);
pinMode(LED,OUTPUT);
attachInterrupt (0, isr_BP,  FALLING); // interruption sur front descendant
Serial.print("appui_BP = ");Serial.print(appui_BP);
Serial.print("  attente ");Serial.print(delai[appui_BP]);
Serial.print("  periode ");Serial.println(periode[appui_BP]);
}

void loop() 
{
 switch(appui_BP)
 {
case 1:
{
  if((millis()-deb_periode)>=periode[appui_BP])
  {digitalWrite(LED,!digitalRead(LED));
  deb_periode=millis();
  }
}
break;
case 2:
{
  if((millis()-deb_periode)>=periode[appui_BP])
  {digitalWrite(LED,!digitalRead(LED));
  deb_periode=millis();
  }
}
break;
case 3:
{
 if((millis()-deb_periode)>=periode[appui_BP])
  {digitalWrite(LED,!digitalRead(LED));
  deb_periode=millis();
  }
}
break;
case 4:
{ 
  digitalWrite(LED,HIGH);
  deb_periode=millis();
}
break;
case 5:
{
  digitalWrite(LED,LOW);
  deb_periode=millis();
}
break;
default:{;}
break;
 }
}

void isr_BP ()
{
  SREG &= 0b01111111;                       //interdit les interruptions reset le bit 7 de sreg
  if ((millis() - isr_flag_BP) > delai[appui_BP])      //anti-rebonds de 200 millis
  {
    appui_BP++;                             //BP est incrémenté
    if (appui_BP >= 6)                      //si BP à dépassé la butée haute
    {
      appui_BP = 1;                         //alors BP repasse à 1
    }
  }
  EIFR  = 0b00000001;                       //acquitte demande d'interruption par rebonds (200ms)
  SREG |= 0b10000000;                       //ré-autorise les interruptions
  isr_flag_BP = millis();
  Serial.print("appui_BP  = ");Serial.print(appui_BP);
  Serial.print("  attente = ");Serial.print(delai[appui_BP]);
  Serial.print("  periode = ");Serial.println(periode[appui_BP]);
}

Si je présente:


a quelqu’un qui n’a pas suivi cette conversation, je ne pense pas qu’il puisse dire de quoi il s’agit.

Et on est passé d’une machine à 5 états à un graphe en 15 états.

Qu’en pense @antoine1DD2?