IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Arduino Discussion :

Cherche expert arduino et écran 4D system pour projet mémoire d'ingénieur


Sujet :

Arduino

  1. #61
    Futur Membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Février 2017
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Meuse (Lorraine)

    Informations professionnelles :
    Activité : Technicien maintenance

    Informations forums :
    Inscription : Février 2017
    Messages : 77
    Points : 8
    Points
    8
    Par défaut
    Citation Envoyé par Jay M Voir le message
    Si vous devez insister c'est que le code ne revient pas assez souvent au test des boutons, il doit y avoir trop de parties du code qui sont "lentes" et ralentissent trop la loop.
    Je ne sais pas trop c'est vraiment variable des fois ca se fait sur un appuie très court, des fois il faut un peu insister…

    Citation Envoyé par Jay M Voir le message
    Le sifflement pourrait venir d'un basculement continu d'un truc mécanique entre deux positions -> vanne, relais, etc...
    Ca siffle pour ceux que pour les 4 premiers ce qui parait cohérent du coup car je dois les maintenir appuyé pour qu'ils restent basculés…

    Citation Envoyé par Jay M Voir le message
    vous ne testez que les 4 derniers, non?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
      //utilisation cde EV déportée:
      for (int i = 4; i < 8; i++) {...
    Ce code est pour tester les 4 derniers mais pour les 4 premiers:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    }else if (FEV[i]==0 && digitalRead(CEV[i]) == LOW) {     //si on appuie sur une commande déportée
          etatCev[i] = !etatCev[i];           // on inverse l'état de la commande de l'EV correspondante
          digitalWrite(EV[i], etatCev[i]);
    Ce qui ne fonctionne de toute façon pas.

  2. #62
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 715
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 715
    Points : 5 403
    Points
    5 403
    Par défaut
    pourquoi faut-il "inverser"
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    etatCev[i] = !etatCev[i];           // on inverse l'état de la commande de l'EV correspondante
          digitalWrite(EV[i], etatCev[i]);
    pourquoi ne faut il pas forcer à une certaine valeur ? le sifflement viendrait du basculement constant (entre les 2 états)

  3. #63
    Futur Membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Février 2017
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Meuse (Lorraine)

    Informations professionnelles :
    Activité : Technicien maintenance

    Informations forums :
    Inscription : Février 2017
    Messages : 77
    Points : 8
    Points
    8
    Par défaut
    Citation Envoyé par Jay M Voir le message
    pourquoi faut-il "inverser"
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    etatCev[i] = !etatCev[i];           // on inverse l'état de la commande de l'EV correspondante
          digitalWrite(EV[i], etatCev[i]);
    pourquoi ne faut il pas forcer à une certaine valeur ? le sifflement viendrait du basculement constant (entre les 2 états)
    Parce que je veux commander l'ouverture et la fermeture avec le même bouton j'appui une fois, ca s'ouvre, et une autre fois ca se referme.

  4. #64
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 715
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 715
    Points : 5 403
    Points
    5 403
    Par défaut
    je ne me suis pas plongé dans tout le code, mais attendez vous le relâchement du bouton quelque part ?

    appui --> inversion
    tant que pas relâchement --> rien
    relâchement
    appui --> inversion

  5. #65
    Futur Membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Février 2017
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Meuse (Lorraine)

    Informations professionnelles :
    Activité : Technicien maintenance

    Informations forums :
    Inscription : Février 2017
    Messages : 77
    Points : 8
    Points
    8
    Par défaut
    Citation Envoyé par Jay M Voir le message
    je ne me suis pas plongé dans tout le code, mais attendez vous le relâchement du bouton quelque part ?

    appui --> inversion
    tant que pas relâchement --> rien
    relâchement
    appui --> inversion
    Non de plus le code est le même pour les 8 commandes et seules celles qui sont commandées également avec le cycle mise en froid/pause/ maintien ne restent pas en position quand je lache le bouton…
    Les 4 premières ne commutent que si je reste appuyé sur le bouton alors que les 4 dernières commutent bien lors de l'appui sur le bouton sans que je doive rester appuyé.

    Les 4 premières font partie de la boucle if (FEV[i]==1) et les 4 dernières non. Il y a une commande déportée (un bouton momentané) pour chacune des 8 électrovannes.
    Je pense que ca vient de l'architecture de ma boucle if mais j'ai essayé à peu près toutes les possibilités sans que le fonctionnement soit conforme a ce que je souhaite… ou alors le fait de couper le fonctionnement du cycle (FEV[i]==0) ne coupe pas les EV et les laisse dans la position dans laquelle elles sont.

  6. #66
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 715
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 715
    Points : 5 403
    Points
    5 403
    Par défaut
    pour me clarifier les idées

    Vous avez dit:

    - 8 relais pilotés depuis des pins de votre Arduino
    - 8 boutons dessinés sur votre écran qui pilotent les relais
    - 8 boutons momentanés "physiques" qui sont censés faire la même chose que ceux de l'écran

    - 4 relais sont commandés "manuellement"
    - 4 relais sont sous contrôle du programme

    les relais commandés manuellement fonctionnent toujours
    les relais sous contrôle du programme fonctionnent depuis les boutons de l'écran mais pas depuis les boutons physiques

    --> c'est cela ?
    --> Pouvez vous clarifier ce que "Manuellement" veut dire ?

  7. #67
    Futur Membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Février 2017
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Meuse (Lorraine)

    Informations professionnelles :
    Activité : Technicien maintenance

    Informations forums :
    Inscription : Février 2017
    Messages : 77
    Points : 8
    Points
    8
    Par défaut
    C'est cela. Chaque circuit comporte un corps avec 2 électrovannes. L'une des 2 sert a acheminer l'azote vers le matériel, l'autre sert à mettre le circuit à l'air libre pour retirer la pression afin de déconnecter le tout en toute sécurité. Il y a 4 circuits de 2 électrovannes ce qui en fait bien 8 commandées chacune par un relais.
    Les 4 relais qui commandent les 4 électrovannes qui servent à acheminer l'azote sont commandées par le programme selon un cycle de mise en froid, pause et maintien froid selon 2 modes:
    - Automatique : les temps de mise en froid, pause et maintien froid sont calculés par le programme selon la température ambiante et la pression du circuit auxquels on peut rajouter des "offset" que j'appelle talon.
    - Manuel : les temps de mise en froid, pause et maintien froid sont définis par l'utilisateur.
    Les 4 boutons de l'écran servent à mettre en marche les 2 types de cycles.

    A côté, nous avons des interrupteurs momentanés pour pouvoir les commander en dehors de ces 2 cycles. Ce sont ces commandes qui ne fonctionnent pas comme je le souhaite. Je dois rester appuyé pour que l'électrovanne reste ouverte.

    Les 4 autres électrovannes de "mise à l'air libre" fonctionnent manuellement, soit par appui sur le bouton correspondant sur l'écran, soit par des interrupteurs momentanés qui eux fonctionnent correctement, j'appuie une fois ils s'ouvrent, j'appuie une autre fois, ils se ferment.

  8. #68
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 715
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 715
    Points : 5 403
    Points
    5 403
    Par défaut
    Citation Envoyé par harkilius Voir le message
    Ce sont ces commandes qui ne fonctionnent pas comme je le souhaite. Je dois rester appuyé pour que l'électrovanne reste ouverte.
    et dès que vous lâchez l'électrovanne se ferme ou c'est aléatoire ?
    et j'imagine que ça marche parfaitement si vous appuyez sur le bouton équivalent virtuel sur l'écran, c'est ça ?

    la grosse différence entre le bouton virtuel et le réel c'est que le virtuel ne va vous envoyer une commande qu'une seule fois par appui alors que le bouton momentané vous dira "LOW"' tant que vous le tenez appuyé, c'est à dire que vous captez sa position, pas son changement de position (en supposant que les rebonds sont bien enlevés). Pour se ramener au même cas il faut qu'une fois le passage HIGH -> LOW détecté et l'opération effectuée, vous notiez cet information et ne fassiez plus rien tant que vous n'avez pas vu la transition LOW -> HIGH qui est le relâchement du bouton par l'opérateur. Il ne faut pas que la prochaine fois que la boucle passe par là et voit à nouveau le LOW qu'elle se dise "ah, l'opérateur a appuyé à nouveau, je bascule l'état".

  9. #69
    Futur Membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Février 2017
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Meuse (Lorraine)

    Informations professionnelles :
    Activité : Technicien maintenance

    Informations forums :
    Inscription : Février 2017
    Messages : 77
    Points : 8
    Points
    8
    Par défaut
    Citation Envoyé par Jay M Voir le message
    et dès que vous lâchez l'électrovanne se ferme ou c'est aléatoire ?
    Pour les 4 premières électrovannes dés que je relâche le bouton effectivement l'électrovanne se referme.

    Citation Envoyé par Jay M Voir le message
    et j'imagine que ça marche parfaitement si vous appuyez sur le bouton équivalent virtuel sur l'écran, c'est ça ?
    Les boutons pour les 4 premières électrovannes n'ont pas du tout les mêmes fonctions. Ceux de l'écran servent à mettre en marche un cycle qu'il soit automatique (entièrement calculé par la machine) ou manuel (d'après les infos entrées par l'utilisateur). Par exemple le cycle va ouvrir l'électrovanne pendant 10s pour la mise en froid, puis faire une pause de 5s pour pas faire givrer le matériel puis reouvrir pour 5s pour remettre en froid.
    Les boutons "réels" eux doivent ouvrir l'électrovanne au premier appui et la refermer à l'appui suivant…

    Citation Envoyé par Jay M Voir le message
    la grosse différence entre le bouton virtuel et le réel c'est que le virtuel ne va vous envoyer une commande qu'une seule fois par appui alors que le bouton momentané vous dira "LOW"' tant que vous le tenez appuyé, c'est à dire que vous captez sa position, pas son changement de position (en supposant que les rebonds sont bien enlevés). Pour se ramener au même cas il faut qu'une fois le passage HIGH -> LOW détecté et l'opération effectuée, vous notiez cet information et ne fassiez plus rien tant que vous n'avez pas vu la transition LOW -> HIGH qui est le relâchement du bouton par l'opérateur. Il ne faut pas que la prochaine fois que la boucle passe par là et voit à nouveau le LOW qu'elle se dise "ah, l'opérateur a appuyé à nouveau, je bascule l'état".
    Les 8 boutons "réels" sont identiques pour les 8 électrovannes, alimentés en 5V avec une résistance de 10kOhms suivi d'un interrupteur momentané avec un condo de 10nF en parallèle jusqu'à la masse, le signal est prit entre la résistance et l'interrupteur et ce pour les 8 boutons. 4 d'entre eux servent aux 4 premières électrovannes qui peuvent être également commandé selon les différents cycles.
    Les 4 autres sont toujours commandés manuellement que ce soit par leurs boutons sur l'écran ou leur boutons "réels". Dés que j'appuie, ils s'ouvrent, dés que je réappuie ils se referment.
    Le câblage des boutons n'est pas en cause car ils fonctionnent parfaitement pour les électrovannes qui doivent être commandés "manuellement".
    Pour les 4 électrovannes qui sont aussi commandés par les cycles, je dois rester appuyé sur le bouton "réel" pour qu'elles restent ouverte alors que pour les 4 autres non…

    Je pense vraiment que le problème vient de ma boucle:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
     
    //fonctionnement EV:
        if (FEV[i] == 1 ) { //si EV 1 à 4 à démarré
          if (((Mode[i] == 1) && (pression1[i] >= 135) && (Dem[i] != 0)) || ((Mode[i] == 0) && (Dem[i] != 0))) { //si mode auto ET pression >=135 bars ET profile sélectionné OU mode manu et profil sélectionné
            if (D[i] == 0) { //si la mise en froid n'est pas réalisée
              tpsUP[i] = tpsMeF[i] * 1000; // on utilise le temps de mise en froid
            } else {
              tpsUP[i] = tpsMaint[i] * 1000; //sinon on utilise le temps de maintien froid
            }
            tpsDN[i] = tpsStop[i] * 1000;
            etatCev[i] = HIGH;
            digitalWrite(EV[i], etatCev[i]); //on ouvre l'EV
            if (millis() - T[i] > tpsUP[i]) { //si le temps d'ouverture est atteint
              etatCev[i] = LOW;               // on ferme l'EV
              digitalWrite(EV[i], etatCev[i]);
              D[i] = 1;                       // on dit au systeme que la mise en froid est faite
            }
            if (millis() - T[i] > tpsUP[i] + tpsDN[i]) { // si le temps de pause est atteint
              etatCev[i] = HIGH;
              digitalWrite(EV[i], etatCev[i]);          //on reouvre l'EV
              T[i] = millis();                          //on remet le timer a 0 pour le prochain cycle
            }
          }
        } else {
          etatCev[i] = LOW;                             // sinon on referme les EV
          digitalWrite(EV[i], etatCev[i]);
        }
      }
     
      //utilisation cde EV déportée:
      for (int i = 0; i < 8; i++) {
        if (digitalRead(CEV[i]) == LOW) {     //si on appuie sur une commande déportée
          etatCev[i] = !etatCev[i];           // on inverse l'état de la commande de l'EV correspondante
          digitalWrite(EV[i], etatCev[i]);
        } else {
          digitalWrite(EV[i], etatCev[i]);    // sinon on la laisse telle quelle.
        }
      }
    }
    Pour les commandes de 0 à 3 (CEV[I]) si j'ai LOW, je demande a basculer l'etatCev, variable qui commande l'etat de relais, dans l'autre position ( si c'est HIGH, je bascule sur LOW et vice versa) mais il me semble que cette commande est annulée par la partie de la boucle:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
     } else {
          etatCev[i] = LOW;                             // sinon on referme les EV
          digitalWrite(EV[i], etatCev[i]);
        }
    car j'impose l'étatCev à LOW. Si je retire cette condition, quand j'éteins mon cycle (FEV[i]==0), l'électrovanne reste ouverte au lieu de se refermer.
    J'ai essayé toutes les possibilités de code auxquelles j'ai pensé et je n'obtiens pas le bon fonctionnement des 2 parties.

    Ce code fonctionne très bien pour les électrovannes de 4 à 7 en revanche car elles ne dépendent que du code:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
       //utilisation cde EV déportée:
      for (int i = 0; i < 8; i++) {
        if (digitalRead(CEV[i]) == LOW) {     //si on appuie sur une commande déportée
          etatCev[i] = !etatCev[i];           // on inverse l'état de la commande de l'EV correspondante
          digitalWrite(EV[i], etatCev[i]);
        } else {
          digitalWrite(EV[i], etatCev[i]);    // sinon on la laisse telle quelle.
        }
      }
    }

  10. #70
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 715
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 715
    Points : 5 403
    Points
    5 403
    Par défaut
    vous pouvez reposter le code actuel ?

    je vais essayer de suivre le cheminement

  11. #71
    Futur Membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Février 2017
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Meuse (Lorraine)

    Informations professionnelles :
    Activité : Technicien maintenance

    Informations forums :
    Inscription : Février 2017
    Messages : 77
    Points : 8
    Points
    8
    Par défaut
    Voici la boucle:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
     
    void loop() {
      if (millis() - temps >= 30000) { // on mesure la température, l'humidité et la pression toutes les 30s
        //mesure pressions:
        for (int i = 0; i < 4; i++) {
          pression1[i] = ((analogRead(PEV[i]) * 5) / 1023) * 0.0125;// 5V / 400 Bars =0.0125 données du capteur de pression.
          PressionCalcul[i] = 0.097085 * pression1[i];
          if (pression1[i] != pression1Mem[i]) {
            genie.WriteStr(affPression[i], pression1[i]);
            genie.WriteObject(GENIE_OBJ_COOL_GAUGE, i, pression1[i]);
          }
          pression1Mem[i] = pression1[i];
        }
        //mesure température:
        temperature = getTemp();
        if (temperature != tempMem) {
          genie.WriteObject(GENIE_OBJ_THERMOMETER, 0, temperature + 30); //affichage t°sur thermomètre avec offset de 30
          tempCalcul = 196 + temperature + 10;// la température à atteindre pour refroidir les AD a -196°C avec un offset de 10.
        }
        tempMem = temperature;
     //mesure humidité:
        Hr = getHr();
        if (Hr != HrMem ) {
          genie.WriteObject(GENIE_OBJ_LED_DIGITS, 6, Hr);
        }
        HrMem = Hr;
        temps = millis();
      }
      genie.DoEvents();  // on vérifie ce qu'il se passe sur l'écran
     
     
      //demarrage de l'autotest de la BMO:
      if (AT == 1) {
        Autotest();//déclenchement de l'autotest de la BMO
        if (resultatAT >= 34) {
          genie.WriteStr(28, "OK");
        } else {
          genie.WriteStr(28, "NOK");
        }
      }
      //memorisation des talons et temps dans le paramétrage:
      if (Param != 0) {
        if (Val == 1) {
          if (neg1 == 1) {
            parametres.talMeF[Param] = -slider0_val;
          } else {
            parametres.talMeF[Param] = slider0_val;
          }
          if (neg2 == 1) {
            parametres.talStop[Param] = -slider1_val;
          } else {
            parametres.talStop[Param] = slider1_val;
          }
          if (neg3 == 1) {
            parametres.talMaint[Param] = -slider2_val;
          } else {
            parametres.talMaint[Param] = slider2_val;
          }
          parametres.tpsMeFM[Param] = slider3_val;
          parametres.tpsStopM[Param] = slider4_val;
          parametres.tpsMaintM[Param] = slider5_val;
          saveParametres();
        }
        //si les parametres ont changés on les affiches sinon on conserve les anciens:
        if (parametres.talMeF[Param] != talMeFMem) {
          if (parametres.talMeF[Param] < 0) {
            genie.WriteObject(GENIE_OBJ_LED, 12, 1);
            genie.WriteObject(GENIE_OBJ_LED_DIGITS, 7, -parametres.talMeF[Param]);
          } else {
            genie.WriteObject(GENIE_OBJ_LED, 12, 0);
            genie.WriteObject(GENIE_OBJ_LED_DIGITS, 7, parametres.talMeF[Param]);
          }
        }
        if (parametres.talStop[Param] != talStopMem) {
          if (parametres.talStop[Param] < 0) {
            genie.WriteObject(GENIE_OBJ_LED, 13, 1);
            genie.WriteObject(GENIE_OBJ_LED_DIGITS, 8, -parametres.talStop[Param]);
          } else {
            genie.WriteObject(GENIE_OBJ_LED, 13, 0);
            genie.WriteObject(GENIE_OBJ_LED_DIGITS, 8, parametres.talStop[Param]);
          }
        }
        if (parametres.talMaint[Param] != talMaintMem) {
          if (parametres.talMaint[Param] < 0) {
            genie.WriteObject(GENIE_OBJ_LED, 14, 1);
            genie.WriteObject(GENIE_OBJ_LED_DIGITS, 9, -parametres.talMaint[Param]);
          } else {
            genie.WriteObject(GENIE_OBJ_LED, 14, 0);
            genie.WriteObject(GENIE_OBJ_LED_DIGITS, 9, parametres.talMaint[Param]);
          }
        }
     
        if (parametres.tpsMeFM[Param] != tpsMeFMMem) {
          genie.WriteObject(GENIE_OBJ_LED_DIGITS, 10, parametres.tpsMeFM[Param]);
        }
        if (parametres.tpsStopM[Param] != tpsStopMMem) {
          genie.WriteObject(GENIE_OBJ_LED_DIGITS, 11, parametres.tpsStopM[Param]);
        }
        if (parametres.tpsMaintM[Param] != tpsMaintMMem) {
          genie.WriteObject(GENIE_OBJ_LED_DIGITS, 12, parametres.tpsMaintM[Param]);
        }
        if (parametres.nomAD[Param] != nomADMem) {
          genie.WriteStr(1, parametres.nomAD[Param]);
        }
        //on met les valeurs en mémoire pour comparaison avec le cycle suivant
        talMeFMem = parametres.talMeF[Param];
        talStopMem = parametres.talStop[Param];
        talMaintMem = parametres.talMaint[Param];
        tpsMeFMMem = parametres.tpsMeFM[Param];
        tpsStopMMem = parametres.tpsStopM[Param];
        tpsMaintMMem = parametres.tpsMaintM[Param];
        nomADMem = parametres.nomAD[Param];
        Val = 0;
      }
     
      //définition des temps de travail des EV:
      for (int i = 0; i < 4; i++) {
        if (Mode[i] == 1) { //si le mode auto est sélectionné pour les 4 EV.
          if (Dem[i] < 6) { // si le profil correspond au circuit 1, on fait les calculs avec la pression 1
            tpsMeF[i] = (-tempCalcul / (-PressionCalcul[0] + 12.59815)) + parametres.talMeF[Dem[i]];
            tpsStop[i] = ((-tempCalcul + chauffeCapteur) / (-PressionCalcul[0] + 12.59815)) + parametres.talStop[Dem[i]];
            tpsMaint[i] = ((-tempCalcul + chauffeCapteur) / (-PressionCalcul[0] + 12.59815)) + parametres.talMaint[Dem[i]];
          } else if (Dem[i] > 5 && Dem[i] < 11) { // si le profil correspond au circuit 2 , on fait les calculs avec la pression 2
            tpsMeF[i] = (-tempCalcul / (-PressionCalcul[1] + 12.59815)) + parametres.talMeF[Dem[i]];
            tpsStop[i] = ((-tempCalcul + chauffeCapteur) / (-PressionCalcul[1] + 12.59815)) + parametres.talStop[Dem[i]];
            tpsMaint[i] = ((-tempCalcul + chauffeCapteur) / (-PressionCalcul[1] + 12.59815)) + parametres.talMaint[Dem[i]];
          } else if (Dem[i] > 10 && Dem[i] < 16) { // si le profil correspond au circuit 3 , on fait les calculs avec la pression 3
            tpsMeF[i] = (-tempCalcul / (-PressionCalcul[2] + 12.59815)) + parametres.talMeF[Dem[i]];
            tpsStop[i] = ((-tempCalcul + chauffeCapteur) / (-PressionCalcul[2] + 12.59815)) + parametres.talStop[Dem[i]];
            tpsMaint[i] = ((-tempCalcul + chauffeCapteur) / (-PressionCalcul[2] + 12.59815)) + parametres.talMaint[Dem[i]];
          } else if (Dem[i] > 15 && Dem[i] < 21) { // si le profil correspond au circuit 4, on fait les calculs avec la pression 4
            tpsMeF[i] = (-tempCalcul / (-PressionCalcul[3] + 12.59815)) + parametres.talMeF[Dem[i]];
            tpsStop[i] = ((-tempCalcul + chauffeCapteur) / (-PressionCalcul[3] + 12.59815)) + parametres.talStop[Dem[i]];
            tpsMaint[i] = ((-tempCalcul + chauffeCapteur) / (-PressionCalcul[3] + 12.59815)) + parametres.talMaint[Dem[i]];
          }
        } else {
          tpsMeF[i] = parametres.tpsMeFM[Dem[i]];
          tpsStop[i] = parametres.tpsStopM[Dem[i]];
          tpsMaint[i] = parametres.tpsMaintM[Dem[i]];
        }
        //fonctionnement EV:
        if (FEV[i] == 1 ) { //si EV 1 à 4 à démarré
          if (((Mode[i] == 1) && (pression1[i] >= 135) && (Dem[i] != 0)) || ((Mode[i] == 0) && (Dem[i] != 0))) { //si mode auto ET pression >=135 bars ET profile sélectionné OU mode manu et profil sélectionné
            if (D[i] == 0) { //si la mise en froid n'est pas réalisée
              tpsUP[i] = tpsMeF[i] * 1000; // on utilise le temps de mise en froid
            } else {
              tpsUP[i] = tpsMaint[i] * 1000; //sinon on utilise le temps de maintien froid
            }
            tpsDN[i] = tpsStop[i] * 1000;
            etatCev[i] = HIGH;
            digitalWrite(EV[i], etatCev[i]); //on ouvre l'EV
            if (millis() - T[i] > tpsUP[i]) { //si le temps d'ouverture est atteint
              etatCev[i] = LOW;               // on ferme l'EV
              digitalWrite(EV[i], etatCev[i]);
              D[i] = 1;                       // on dit au systeme que la mise en froid est faite
            }
            if (millis() - T[i] > tpsUP[i] + tpsDN[i]) { // si le temps de pause est atteint
              etatCev[i] = HIGH;
              digitalWrite(EV[i], etatCev[i]);          //on reouvre l'EV
              T[i] = millis();                          //on remet le timer a 0 pour le prochain cycle
            }
          }
        } else {
          etatCev[i] = LOW;                             // sinon on referme les EV
          digitalWrite(EV[i], etatCev[i]);
        }
      }
     
      //utilisation cde EV déportée:
      for (int i = 0; i < 8; i++) {
        if (digitalRead(CEV[i]) == LOW) {     //si on appuie sur une commande déportée
          etatCev[i] = !etatCev[i];           // on inverse l'état de la commande de l'EV correspondante
          digitalWrite(EV[i], etatCev[i]);
        } else {
          digitalWrite(EV[i], etatCev[i]);    // sinon on la laisse telle quelle.
        }
      }
    }

  12. #72
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 715
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 715
    Points : 5 403
    Points
    5 403
    Par défaut
    Salut

    donc j'ai regardé la loop et pour simplifier mon analyse fait comme s'il n'y avait qu'une seule unité.
    Outre un peu d'intendance d'affichage et de gestion des événements, Le coeur du traitement ressemble à cela

    Nom : processflow.png
Affichages : 121
Taille : 129,9 Ko

    D'une part je ne vois pas pourquoi si l'EV a démarré vous forcez à nouveau l'ouverture de l'EV. ça aurait dû se faire quand on change d'état et que FEV passe à 1

    D'autre part Ne devez vous pas aussi mémoriser un changement du statut de l’EV -> (FEV = 0 ou 1) quand vous fermez l'EV ? ou est-ce un passage simple d'un morceau du cycle à un autre ? (cette notion n'est pas capturée dans votre code)

    Il me semble que vous vous mélangez un peu les pinceaux sur les états et les transitions: quand on gère une machine à état et qu'on détecte un évènement pertinent, on effectue les actions associées à ce changement d'état puis on change l'état. On n'a pas de raison de recommencer les actions pendant l'exécution de l'état.

    Le bon niveau de concept est sans doute celui du cycle comme vous le décrivez ci dessous ==> Faites un dessin de cette machine à état pour vos cycles et à chaque étape définissez les évènements possibles qui déclenchent des transitions. écoutez ces évènements, appliquez les actions sur les vannes et passez dans le nouvel état.

    voilà comment j'ai compris ce que vous dites:

    Nom : lesEtats.png
Affichages : 87
Taille : 80,5 Ko

    Avec l'aide de boutons sur l'interface 4D, vous démarrez un cycle. Le cycle progresse entre une pré-étape de mise à froid, suivie d'un temps de pause, puis de maintient au froid. on boucle sur ces deux derniers états tant qu'on ne demande pas via l'interface Nextion d'arrêter le processus.

    les ∆t sont calculés en permanence ou pré-définis et peuvent changer pendant le cycle. le squelette du code ressemblerait à cela:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    enum : uint8_t {etatStop, etatMiseFroid, etatPauseFroide, etatMaintienFroid} etat;
    uint32_t chrono;
     
    void setup()
    {
      etat = etatStop;
    }
     
    void loop()
    {
     
      gestionInterface(); // gestion de l'écran et affichage 
     
      switch (etat) {
     
        case etatStop:
          if (appui boutonStart) { // à définir comment on sait si le bouton est appuyé
            actions1();
            chrono = millis();
            etat = etatMiseFroid;
          }
          break;
     
        case etatMiseFroid:
          if (appui boutonStop) {// à définir comment on sait si le bouton est appuyé
            actions5();
            etat = etatStop;
          } else {
            deltaT1 = calculDeltaT1();
            if (millis() - chrono  >= deltaT1) {
              actions2();
              chrono = millis();
              etat = etatPauseFroide;
            }
          }
          break;
     
        case etatPauseFroide:
          if (appui boutonStop) {
            actions5();
            etat = etatStop;
          } else {
            deltaT2 = calculDeltaT2();
            if (millis() - chrono  >= deltaT2) {
              actions3();
              chrono = millis();
              etat = etatMaintienFroid;
            }
          }
          break;
     
        case etatMaintienFroid:
          if (appui boutonStop) {
            actions5();
            etat = etatStop;
          } else {
            deltaT3 = calculDeltaT3();
            if (millis() - chrono  >= deltaT3) {
              actions4();
              chrono = millis();
              etat = etatPauseFroide;
            }
          }
          break;
      }
    }
    La question qui se pose est la suivante: à quoi servent les boutons physiques --> doivent-ils arrêter la machine ou simplement faire basculer d'un état à un autre.

    --> dessinez les transitions associées à un appui du bouton ainsi que toutes les actions à effectuer lors de chaque événement (les flèches) et ce sera simple à coder.

  13. #73
    Futur Membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Février 2017
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Meuse (Lorraine)

    Informations professionnelles :
    Activité : Technicien maintenance

    Informations forums :
    Inscription : Février 2017
    Messages : 77
    Points : 8
    Points
    8
    Par défaut
    Citation Envoyé par Jay M Voir le message

    D'une part je ne vois pas pourquoi si l'EV a démarré vous forcez à nouveau l'ouverture de l'EV. ça aurait dû se faire quand on change d'état et que FEV passe à 1
    Mes boutons sur l'écran qui commande l'arrivée d'azote (une électrovanne sur les deux dans le corps de chaque circuit) agissent sur l'état de FEV. Si j'appuie dessus le bouton passe vert et FEV passe à 1 et si je rappuie dessus le vert s'éteint et FEV passe a 0.
    Lorsque je fais passer FEV à 1 je lance mon cycle qui va commencer par une période à HIGH, puis quand le temps est écoulé je repasse à LOW puis quand le temps de pause est écoulé je repasse à HIGH. FEV à 1 ne commande pas juste l'ouverture de l'EV, elle commande le cycle Mise en froid, pause et maintien froid. Les interrupteurs déportés servent de mise en marche manuelle. Ils ne lancent pas de cycle. Donc sont utilisables essentiellement lorsque FEV =0. Je n'ai pas ajouté cette condition car FEV n'est utilisé que pour les CEV 0 à 3 et pas les 4 autres et si je rajoute cette condition dans la boucle, pour une raison qui m'échappe, lorsque je coupe mon cycle (FEV passe de 1 à 0), les électrovannes ne se coupent pas.

    Citation Envoyé par Jay M Voir le message
    D'autre part Ne devez vous pas aussi mémoriser un changement du statut de l’EV -> (FEV = 0 ou 1) quand vous fermez l'EV ?
    c'est ce qui est fait avec l'etatCev.

    Citation Envoyé par Jay M Voir le message
    Il me semble que vous êtes un peu confus sur les états et les transitions: quand on gère une machine à état et qu'on détecte un évènement pertinent, on effectue les actions associées à ce changement d'état puis on change l'état. On n'a pas de raison de recommencer les actions pendant l'exécution de l'état.
    Je pense que vous ne saisissez pas le fonctionnement de ma machine en fait… Je ne suis peut-être pas assez clair…
    Lorsque j'appuie sur les 4 boutons ("virtuelle") de débit d'azote sur mon écran:

    Je bascule FEV = 1: je lance mon cycle composé d'un temps de mise en froid, temps de pause, temps de maintien froid, pause, maintien froid, pause, maintien froid, pause... jusqu'à l'infini sauf si je coupe le cycle (FEV=0) en rappuyant sur ce même bouton.

    A coté de ça, les opérateurs veulent pouvoir mettre en marche le débit d'azote comme bon leur semble, d'où les commandes déportées qui inversent l'état de l'électrovanne lorsqu'on appuie sur la commande "réelle" pour reprendre vos termes. Quand l'électrovanne (EV pour raccourcir) est fermée ca l'ouvre, et quand elle est ouverte ça la referme...

    Si vous voulez même, ils veulent un direct 5V pour actionner les relais pour bypasser l'Arduino en cas de plantage de celle-ci.

    Citation Envoyé par Jay M Voir le message
    La question qui se pose est la suivante: à quoi servent les boutons physiques --> doivent-ils arrêter la machine ou simplement faire basculer d'un état à un autre.
    du coup la réponse est donnée, ils doivent juste inverser l'état de l'électrovanne correspondante. Les cycles sont un fonctionnement à part.

  14. #74
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 715
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 715
    Points : 5 403
    Points
    5 403
    Par défaut
    OK en fait j'ai bien compris pour la machine et mon diagramme d'état est correct.

    -> On déclenche un cycle depuis l'écran
    -> On arrête un cycle depuis l'écran
    -> si on en touche rien ça fonctionne en continu en alternant sur les 2 états de droite sur mon dessin

    Mon point ci dessous est toujours valide, je ne vois aucune raison de constamment forcer à nouveau l'ouverture de l'EV si FEV vaut 1. Dans l'absolu au moment ou FEV passe à 1 vous activez l'EV et ensuite vous laissez vos tests gérer l'EV.

    En adoptant l'approche par machine à état ce serait bcp plus clair...

    Ce qui n'était pas clair pour moi c'était le rôle des boutons physiques et s'ils étaient simplement un déport de l'interface écran pour être au plus proche de la machine.
    Je comprends donc que les boutons physique sont "hors cycle".

    Et je reviens sur ce que je disais précédemment aussi, la lecture de ces boutons se faisant constamment dans la loop (et elle tourne plus ou moins vite) vous allez évaluer X fois par seconde ce code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    if (digitalRead(CEV) == LOW) {     //si on appuie sur une commande déportée
          etatCev = !etatCev;           // on inverse l'état de la commande de l'EV correspondante
          digitalWrite(EV, etatCev);
        }
    tant que vous voyez LOW vous inversez, donc tant que vous tenez le bouton enfoncé votre EV va alterner d'état... d'où le cliquetis et un état plus ou moins aléatoire qui dépend de la dernière bascule retenue quand vous relâchez. comme la boucle peut être assez lente, ça peut donner l'impression que ça fonctionne si vous appuyez et relâchez vite (plus vite que le temps d'une loop) mais si vous êtes un peu 'lent' par rapport à la loop, ça va faire n'importe quoi.

    --> Il faut attendre le relâchement du bouton avant de valider une inversion de commande pour le prochain appui.

    Il faudra un bout de code qui ressemble à cela
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    const uint8_t pinBouton = 2;
    uint8_t etatPrecedent;
    
    void setup() {
      Serial.begin(115200);
      pinMode(pinBouton, INPUT_PULLUP);
      pinMode(LED_BUILTIN, OUTPUT);
      etatPrecedent = digitalRead(pinBouton);
    }
    
    void loop() {
      uint8_t etatCourant = digitalRead(pinBouton);
      if (etatPrecedent != etatCourant) { // si changement d'état
        if (etatCourant == LOW) { // et qu'on est appuyé
          Serial.println(F("APPUI !"));  // --> pour vous c'est là qu'il faut inverser l'état
        } else {
          Serial.println(F("RELACHE !"));// --> mais ne rien faire ici
        }
        etatPrecedent = etatCourant;
        delay(20); // debounce, pas besoin pour vous puisque vous avez un condensateur :)
      } // rien à faire si pas de changement d'état
    }

  15. #75
    Futur Membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Février 2017
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Meuse (Lorraine)

    Informations professionnelles :
    Activité : Technicien maintenance

    Informations forums :
    Inscription : Février 2017
    Messages : 77
    Points : 8
    Points
    8
    Par défaut
    Citation Envoyé par Jay M Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    const uint8_t pinBouton = 2;
    uint8_t etatPrecedent;
    
    void setup() {
      Serial.begin(115200);
      pinMode(pinBouton, INPUT_PULLUP);
      pinMode(LED_BUILTIN, OUTPUT); // ne sert a rien dans le code visiblement
      etatPrecedent = digitalRead(pinBouton);
    }
    
    void loop() {
      uint8_t etatCourant = digitalRead(pinBouton); 
      if (etatPrecedent != etatCourant) { // si changement d'état
        if (etatCourant == LOW) { // et qu'on est appuyé
          Serial.println(F("APPUI !"));  // --> pour vous c'est là qu'il faut inverser l'état 
        } else {
          Serial.println(F("RELACHE !"));// --> mais ne rien faire ici
        }
        etatPrecedent = etatCourant;
        delay(20); // debounce, pas besoin pour vous puisque vous avez un condensateur :)
      } // rien à faire si pas de changement d'état
    }
    Le built_in led ne sert a rien pour le coup et en fait ce que vous me conseillez de faire c'est de mémoriser l'état précédent du bouton et d'ajouter une tempo pour être sur de capter correctement l'état du bouton.
    Du coup pour moi je dois remplacer dans mon setup:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    for (int i = 0; i < 8; i++) {
        pinMode(CEV[i], INPUT);
        pinMode(EV[i], OUTPUT);  digitalWrite(EV[i], LOW);
      }
    par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    for (int i = 0; i < 8; i++) {
        pinMode(CEV[i], INPUT_PULLUP);
        pinMode(EV[i], OUTPUT);  digitalWrite(EV[i], LOW);
      }
    et ajouter un etatCevPrecedent…

    Puis remplacer dans mon code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    //utilisation cde EV déportée:
      for (int i = 0; i < 8; i++) {
        if (digitalRead(CEV[i]) == LOW) {     //si on appuie sur une commande déportée
          etatCev[i] = !etatCev[i];           // on inverse l'état de la commande de l'EV correspondante
          digitalWrite(EV[i], etatCev[i]);
        } else {
          digitalWrite(EV[i], etatCev[i]);    // sinon on la laisse telle quelle.
        }
      }
    }
    Par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    //utilisation cde EV déportée:
      for (int i = 0; i < 8; i++) {
        etatCev[i]=digitalRead(CEV[i]);
         if(etatCevPrecedent[i]!=etatCev[i]){   
             if (etatCev[i] == LOW) {     //si on appuie sur une commande déportée
                etatCev[i] = !etatCev[i];           // on inverse l'état de la commande de l'EV correspondante
                digitalWrite(EV[i], etatCev[i]);
             } else {
                digitalWrite(EV[i], etatCev[i]);    // sinon on la laisse telle quelle.
             }
             etatCevPrecedent[i]=etatCev[i];
             delay(20);
           }
        }
    J'ai bien compris?

  16. #76
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 715
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 715
    Points : 5 403
    Points
    5 403
    Par défaut
    Citation Envoyé par harkilius Voir le message
    Le built_in led ne sert a rien pour le coup
    euh oui j'étais parti dans l'idée d'inverser la LED puis j'ai affiché sur la console série

    Citation Envoyé par harkilius Voir le message
    en fait ce que vous me conseillez de faire c'est de mémoriser l'état précédent du bouton et d'ajouter une tempo pour être sur de capter correctement l'état du bouton.
    Mémoriser l'état = oui

    La tempo pas besoin car vous avez un condensateur qui enlève les rebonds. (la tempo sert à cela)

    il me semble me souvenir que vous avez câblé déjà en externe vos boutons sous forme de PULLUP donc dans ce cas pas besoin de changer votre setup()


    Citation Envoyé par harkilius Voir le message
    et ajouter un etatCevPrecedent…
    Oui, un tableau avec une entrée pour chaque bouton, et oui pour le code mais sans le délai nécessairement comme dit plus haut

  17. #77
    Futur Membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Février 2017
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Meuse (Lorraine)

    Informations professionnelles :
    Activité : Technicien maintenance

    Informations forums :
    Inscription : Février 2017
    Messages : 77
    Points : 8
    Points
    8
    Par défaut
    Du coup j'ai fait des modifs:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    //init variable état cde EV:
    uint8_t etatCev[8] = {0};
    uint8_t cdev[8]={0};
    uint8_t cdevPrecedent[8]={0};
    etatCev[i] me permet de conserver l'état de la commande de l'EV et cdev[i] l'état des boutons car j'ai essayé avec le code donnée précédemment ca ne marche pas mieux.

    Dans la partie setup:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    for (int i = 0; i < 8; i++) {
        pinMode(CEV[i], INPUT_PULLUP);
        cdevPrecedent[i]=digitalRead(CEV[i]);
        pinMode(EV[i], OUTPUT);  digitalWrite(EV[i], LOW);
      }
    Ce n'était pas en pullup et j'avais zappé de mettre en mémoire l'état des boutons dans le setup.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     
    //utilisation cde EV déportée:
      for (int i = 0; i < 8; i++) {
        cdev[i]=digitalRead(CEV[i]);
          if(cdev[i]!= cdevPrecedent[i]){
            if (cdev[i] == LOW) {     //si on appuie sur une commande déportée
              etatCev[i] = !etatCev[i];           // on inverse l'état de la commande de l'EV correspondante
              digitalWrite(EV[i], etatCev[i]);
            } else {
              digitalWrite(EV[i], etatCev[i]);    // sinon on la laisse telle quelle.
            }
            cdevPrecedent[i]= cdev[i];
            delay(20);
            }
          }
    }
    Il y a de l'amélioration dans le sens où l'appuie sur les boutons sont plus fiable comparé à avant et la commutation est plus rapide mais ca ne fonctionne toujours pas pour les 4 premiers interrupteurs, ils basculent à l'état HIGH puis LOW directement après.
    Le code à améliorer la réactivité mais j'ai toujours le problème de fonctionnement que j'avais avant.
    Les 4 premiers relais restent ouvert que si je reste appuyé, alors que les 4 autres changes bien d'état à chaque appuie.

    Je pense toujours que ca vient de ma boucle FEV...

  18. #78
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 715
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 715
    Points : 5 403
    Points
    5 403
    Par défaut
    Vous avez dit ne pas démarrer de cycle quand vous testez les boutons, juste l’appui des commandes manuelles c’est cela ?

    Sinon Il se peut que vous ayez un débordement mémoire ailleurs qui mette le souk dans vos variables. Sans voir tout le code difficile à dire et même avec le code faudrait mettre des traces de debug

    Je regarderai demain ce que vous avez modifié, repostez le setup et la loop et les définitions de pins et tableaux (il n’y a pas besoin de cdev[i], juste la valeur courante suffit pendant le test et on l’affecte ensuite dans le tableau des valeurs précédentes) et au mieux ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     else {
              digitalWrite(EV[i], etatCev[i]);    // sinon on la laisse telle quelle.
            }
    ne sert à rien, au pire si etatCev a bougé pour une raison ou pour une autre ça change la valeur. Virez le, si ça n’a pas changé c’est pas la peine de dire à la pin de rester à la même valeur.

  19. #79
    Futur Membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Février 2017
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Meuse (Lorraine)

    Informations professionnelles :
    Activité : Technicien maintenance

    Informations forums :
    Inscription : Février 2017
    Messages : 77
    Points : 8
    Points
    8
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
     
    #include <genieArduino.h>
    #include <OneWire.h>
    #include <EEPROM.h>
    //initialisation sliders:
    int slider0_val = 0;
    int slider1_val = 0;
    int slider2_val = 0;
    int slider3_val = 0;
    int slider4_val = 0;
    int slider5_val = 0;
    uint8_t neg1 = 0;
    uint8_t neg2 = 0;
    uint8_t neg3 = 0;
     
    //initialisation des variables temps et talons:
    const uint8_t nombreDeNoms = 20;
    const uint8_t longeurMaxDuNom = 4;
     
    struct __attribute__((packed)) _paramS {
      char nomAD[nombreDeNoms][longeurMaxDuNom + 1]; //nom des AD
      unsigned long talMeF[20]; //talon mise en froid auto
      unsigned long talStop[20]; //talon pause auto
      unsigned long talMaint[20]; //talon maintien froid auto
      unsigned long tpsMeFM[20]; //tps de mise en froid manu
      unsigned long tpsStopM[20]; //tps pause manu
      unsigned long tpsMaintM[20]; //tps maintien
    } parametres;
     
    const uint32_t keyword = 0xDEADBEEF;
    const uint16_t keywordAddress = 0x00;
    const uint16_t paramAddress = keywordAddress + sizeof(keyword);
     
    unsigned long tpsUP[4] = {0}; //tps d'ouverture EV1 à 4
    unsigned long tpsDN[4] = {0};
    unsigned long tpsMeF[4] = {0};
    unsigned long tpsStop[4] = {0};
    unsigned long tpsMaint[4] = {0};
    //initialisation variable de travail programme:
    int Param = 0; //récupération du numéro de profil.
    int Dem[4] = {0}; // variable de sélection profil circuit 1 à 4
    uint8_t Mode[4] = {0}; //variable pour le circuit 1 à 4
    uint8_t FEV[4] = {0}; //récupère la demande de mise en marche des 4 circuits
     
    //variable calcul pression:
    int pression2[4] = {0}; //2eme pression pour les 4 circuits
    int resultat[4] = {0}; //resultat du calcul pression4 - pression42 pour le circuit 4
    int resultatAT = 0; //resultat de l'autotest BMO
     
    //init pin commande EV:
    const char EV[8] = {5, 12, 6, 11, 7, 10, 8, 9}; //pin cde EV8
     
    //variables de mesure:
    const byte temp = 13; //capteur de temperature branché sur pin 13
    OneWire Capt_temp(temp);
    int pression1[4] = {0}; //première pression azote 4 circuits
    const uint8_t pinHr = A0; //pin mesure humidité
     
    //init capteur pression:
    const uint8_t PEV[4] = {A1, A2, A3, A4}; //pin mesure pression circuit 4
     
    //init commande déportée EV:
    const uint8_t CEV[8] = {48, 50, 52, 38, 40, 42, 44, 46}; //pin cde déportée EV8
     
    //init variable état cde EV:
    uint8_t etatCev[8] = {0};
    uint8_t cdev[8]={0};
    uint8_t cdevPrecedent[8]={0};
    //variable calcul tps mise en froid auto:
    float tempCalcul = 0; //variable de température
    float PressionCalcul[4] = {0}; //variable de pression 4
     
    //init pin mesure tension LED 1à4:
    const uint8_t led[4] = {A5, A6, A7, A8};
    uint8_t etatLed[4] = {0};
     
    //init pin mesure tension des alim de la BMO:
    const uint8_t pinMesureAlim = A15;
     
    //init multiplexeur mesure alim:
    const uint8_t MultiplexeurA = 47;
    const uint8_t MultiplexeurB = 49;
    const uint8_t MultiplexeurC = 51;
    const uint8_t INH = 53;
     
    //init variable de travail:
    int i = 0;
    int j = 0;
    unsigned long temps = 0; //variable de cadencement de loop
    uint8_t D[4] = {0}; //idem circuit 4
    long T[4] = {0}; //idem circuit 4
    uint8_t Val = 0; //variable autorisant la mémorisation des valeurs entrée pour les temps de fonctionnement
    uint8_t AT = 0; //compteur servant à l'autotest.
    int tempMem = 0; //mémoire température
    unsigned long talMeFMem = 0; //mémoire talon mise en froid
    unsigned long talStopMem = 0; //mémoire talon stop
    unsigned long talMaintMem = 0; //mémoire talon maintien froid
    unsigned long tpsMeFMMem = 0; //mémoire mise en froid manuelle
    unsigned long tpsStopMMem = 0; //mémoire stop manuel
    unsigned long tpsMaintMMem = 0; //mémoire maintien froid manuel
    char nomADMem = 0;
    int pression1Mem[4] = {0}; //mémoire pression1
    int affPression[4] = {9, 14, 19, 24};
    int affCr[24] = {31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54};
    int HrMem = 0; //mémoire taux d'humidité
    int Hr = 0;
    int temperature = 0;
    int nombreCarac = 5;
    int KeyboardValue;
    int chauffeCapteur = 190;
    Genie genie;
     
    void setup() {
      //Serial.begin(9600);
      Serial1.begin(200000);
      genie.Begin(Serial1);//écran sur le Serial 1
      genie.AttachEventHandler(myGenieEventHandler);//cde vérifiant ce qui se passe sur l'écran
      genie.WriteContrast(15);
     
      for (int i = 0; i < 8; i++) {
        pinMode(CEV[i], INPUT_PULLUP);
        pinMode(EV[i], OUTPUT);  digitalWrite(EV[i], LOW);
      }
     
      for (int i = 0; i < 4; i++) {
        pinMode(PEV[i], INPUT);
        pinMode(led[i], INPUT);
      }
      pinMode(temp, INPUT);
      pinMode(pinHr, INPUT);
      pinMode(pinMesureAlim, INPUT);
      pinMode(MultiplexeurA, OUTPUT);  digitalWrite(MultiplexeurA, LOW);
      pinMode(MultiplexeurB, OUTPUT);  digitalWrite(MultiplexeurB, LOW);
      pinMode(MultiplexeurC, OUTPUT);  digitalWrite(MultiplexeurC, LOW);
      pinMode(INH, OUTPUT);  digitalWrite(INH, HIGH);
     
     
    void loop() {
      if (millis() - temps >= 30000) { // on mesure la température, l'humidité et la pression toutes les 30s
        //mesure pressions:
        for (int i = 0; i < 4; i++) {
          pression1[i] = ((analogRead(PEV[i]) * 5) / 1023) * 0.0125;// 5V / 400 Bars =0.0125 données du capteur de pression.
          PressionCalcul[i] = 0.097085 * pression1[i];
          if (pression1[i] != pression1Mem[i]) {
            genie.WriteStr(affPression[i], pression1[i]);
            genie.WriteObject(GENIE_OBJ_COOL_GAUGE, i, pression1[i]);
          }
          pression1Mem[i] = pression1[i];
        }
        //mesure température:
        temperature = getTemp();
        if (temperature != tempMem) {
          genie.WriteObject(GENIE_OBJ_THERMOMETER, 0, temperature + 30); //affichage t°sur thermomètre avec offset de 30
          tempCalcul = 196 + temperature + 10;// la température à atteindre pour refroidir les AD a -196°C avec un offset de 10.
        }
        tempMem = temperature;
        //Serial.print("température=");
        //Serial.println(temp+10);
        //mesure humidité:
        Hr = getHr();
        if (Hr != HrMem ) {
          genie.WriteObject(GENIE_OBJ_LED_DIGITS, 6, Hr);
        }
        HrMem = Hr;
        temps = millis();
      }
      genie.DoEvents();  // on vérifie ce qu'il se passe sur l'écran
     
     
      //demarrage de l'autotest de la BMO:
      if (AT == 1) {
        Autotest();//déclenchement de l'autotest de la BMO
        if (resultatAT >= 34) {
          genie.WriteStr(28, "OK");
        } else {
          genie.WriteStr(28, "NOK");
        }
      }
      //memorisation des talons et temps dans le paramétrage:
      if (Param != 0) {
        if (Val == 1) {
          if (neg1 == 1) {
            parametres.talMeF[Param] = -slider0_val;
          } else {
            parametres.talMeF[Param] = slider0_val;
          }
          if (neg2 == 1) {
            parametres.talStop[Param] = -slider1_val;
          } else {
            parametres.talStop[Param] = slider1_val;
          }
          if (neg3 == 1) {
            parametres.talMaint[Param] = -slider2_val;
          } else {
            parametres.talMaint[Param] = slider2_val;
          }
          parametres.tpsMeFM[Param] = slider3_val;
          parametres.tpsStopM[Param] = slider4_val;
          parametres.tpsMaintM[Param] = slider5_val;
          saveParametres();
        }
        //si les parametres ont changés on les affiches sinon on conserve les anciens:
        if (parametres.talMeF[Param] != talMeFMem) {
          if (parametres.talMeF[Param] < 0) {
            genie.WriteObject(GENIE_OBJ_LED, 12, 1);
            genie.WriteObject(GENIE_OBJ_LED_DIGITS, 7, -parametres.talMeF[Param]);
          } else {
            genie.WriteObject(GENIE_OBJ_LED, 12, 0);
            genie.WriteObject(GENIE_OBJ_LED_DIGITS, 7, parametres.talMeF[Param]);
          }
        }
        if (parametres.talStop[Param] != talStopMem) {
          if (parametres.talStop[Param] < 0) {
            genie.WriteObject(GENIE_OBJ_LED, 13, 1);
            genie.WriteObject(GENIE_OBJ_LED_DIGITS, 8, -parametres.talStop[Param]);
          } else {
            genie.WriteObject(GENIE_OBJ_LED, 13, 0);
            genie.WriteObject(GENIE_OBJ_LED_DIGITS, 8, parametres.talStop[Param]);
          }
        }
        if (parametres.talMaint[Param] != talMaintMem) {
          if (parametres.talMaint[Param] < 0) {
            genie.WriteObject(GENIE_OBJ_LED, 14, 1);
            genie.WriteObject(GENIE_OBJ_LED_DIGITS, 9, -parametres.talMaint[Param]);
          } else {
            genie.WriteObject(GENIE_OBJ_LED, 14, 0);
            genie.WriteObject(GENIE_OBJ_LED_DIGITS, 9, parametres.talMaint[Param]);
          }
        }
     
        if (parametres.tpsMeFM[Param] != tpsMeFMMem) {
          genie.WriteObject(GENIE_OBJ_LED_DIGITS, 10, parametres.tpsMeFM[Param]);
        }
        if (parametres.tpsStopM[Param] != tpsStopMMem) {
          genie.WriteObject(GENIE_OBJ_LED_DIGITS, 11, parametres.tpsStopM[Param]);
        }
        if (parametres.tpsMaintM[Param] != tpsMaintMMem) {
          genie.WriteObject(GENIE_OBJ_LED_DIGITS, 12, parametres.tpsMaintM[Param]);
        }
        if (parametres.nomAD[Param] != nomADMem) {
          genie.WriteStr(1, parametres.nomAD[Param]);
        }
        //on met les valeurs en mémoire pour comparaison avec le cycle suivant
        talMeFMem = parametres.talMeF[Param];
        talStopMem = parametres.talStop[Param];
        talMaintMem = parametres.talMaint[Param];
        tpsMeFMMem = parametres.tpsMeFM[Param];
        tpsStopMMem = parametres.tpsStopM[Param];
        tpsMaintMMem = parametres.tpsMaintM[Param];
        nomADMem = parametres.nomAD[Param];
        Val = 0;
      }
     
      //définition des temps de travail des EV:
      for (int i = 0; i < 4; i++) {
        if (Mode[i] == 1) { //si le mode auto est sélectionné pour les 4 EV.
          if (Dem[i] < 6) { // si le profil correspond au circuit 1, on fait les calculs avec la pression 1
            tpsMeF[i] = (-tempCalcul / (-PressionCalcul[0] + 12.59815)) + parametres.talMeF[Dem[i]];
            tpsStop[i] = ((-tempCalcul + chauffeCapteur) / (-PressionCalcul[0] + 12.59815)) + parametres.talStop[Dem[i]];
            tpsMaint[i] = ((-tempCalcul + chauffeCapteur) / (-PressionCalcul[0] + 12.59815)) + parametres.talMaint[Dem[i]];
          } else if (Dem[i] > 5 && Dem[i] < 11) { // si le profil correspond au circuit 2 , on fait les calculs avec la pression 2
            tpsMeF[i] = (-tempCalcul / (-PressionCalcul[1] + 12.59815)) + parametres.talMeF[Dem[i]];
            tpsStop[i] = ((-tempCalcul + chauffeCapteur) / (-PressionCalcul[1] + 12.59815)) + parametres.talStop[Dem[i]];
            tpsMaint[i] = ((-tempCalcul + chauffeCapteur) / (-PressionCalcul[1] + 12.59815)) + parametres.talMaint[Dem[i]];
          } else if (Dem[i] > 10 && Dem[i] < 16) { // si le profil correspond au circuit 3 , on fait les calculs avec la pression 3
            tpsMeF[i] = (-tempCalcul / (-PressionCalcul[2] + 12.59815)) + parametres.talMeF[Dem[i]];
            tpsStop[i] = ((-tempCalcul + chauffeCapteur) / (-PressionCalcul[2] + 12.59815)) + parametres.talStop[Dem[i]];
            tpsMaint[i] = ((-tempCalcul + chauffeCapteur) / (-PressionCalcul[2] + 12.59815)) + parametres.talMaint[Dem[i]];
          } else if (Dem[i] > 15 && Dem[i] < 21) { // si le profil correspond au circuit 4, on fait les calculs avec la pression 4
            tpsMeF[i] = (-tempCalcul / (-PressionCalcul[3] + 12.59815)) + parametres.talMeF[Dem[i]];
            tpsStop[i] = ((-tempCalcul + chauffeCapteur) / (-PressionCalcul[3] + 12.59815)) + parametres.talStop[Dem[i]];
            tpsMaint[i] = ((-tempCalcul + chauffeCapteur) / (-PressionCalcul[3] + 12.59815)) + parametres.talMaint[Dem[i]];
          }
        } else {
          tpsMeF[i] = parametres.tpsMeFM[Dem[i]];
          tpsStop[i] = parametres.tpsStopM[Dem[i]];
          tpsMaint[i] = parametres.tpsMaintM[Dem[i]];
        }
        //fonctionnement EV:
        if (FEV[i] == 1 ) { //si EV 1 à 4 à démarré
          if (((Mode[i] == 1) && (pression1[i] >= 135) && (Dem[i] != 0)) || ((Mode[i] == 0) && (Dem[i] != 0))) { //si mode auto ET pression >=135 bars ET profile sélectionné OU mode manu et profil sélectionné
            if (D[i] == 0) { //si la mise en froid n'est pas réalisée
              tpsUP[i] = tpsMeF[i] * 1000; // on utilise le temps de mise en froid
            } else {
              tpsUP[i] = tpsMaint[i] * 1000; //sinon on utilise le temps de maintien froid
            }
            tpsDN[i] = tpsStop[i] * 1000;
            etatCev[i] = HIGH;
            digitalWrite(EV[i], etatCev[i]); //on ouvre l'EV
            if (millis() - T[i] > tpsUP[i]) { //si le temps d'ouverture est atteint
              etatCev[i] = LOW;               // on ferme l'EV
              digitalWrite(EV[i], etatCev[i]);
              D[i] = 1;                       // on dit au systeme que la mise en froid est faite
            }
            if (millis() - T[i] > tpsUP[i] + tpsDN[i]) { // si le temps de pause est atteint
              etatCev[i] = HIGH;
              digitalWrite(EV[i], etatCev[i]);          //on reouvre l'EV
              T[i] = millis();                          //on remet le timer a 0 pour le prochain cycle
            }
          }
        } else {
          etatCev[i] = LOW;                             // sinon on referme les EV
          digitalWrite(EV[i], etatCev[i]);
        }
      }
     
      //utilisation cde EV déportée:
     for (int i = 0; i < 8; i++) {
        cdev[i] = digitalRead(CEV[i]);
        if (cdev[i] != cdevPrecedent[i]) {
          if (cdev[i] == LOW) {     //si on appuie sur une commande déportée
            etatCev[i] = !etatCev[i];           // on inverse l'état de la commande de l'EV correspondante
            digitalWrite(EV[i], etatCev[i]);
          }
          cdevPrecedent[i] = cdev[i];
          delay(20);
        }
      }
    }
    J'ai essayé de modifier la deuxième partie de ma boucle if(FEV[i]==1) et soit j'arrive a faire commuter les relais lors de chaque appuie de bouton "réel" mais dés que je lance un cycle et que je l'arrête avec le bouton virtuel, les relais restent dans la position dans laquelle ils étaient, soit je n'arrive pas à les faire commuter et en plus ils s'ouvrent et se referme directement… alors que je n'ai même pas relaché le bouton.
    En tout cas les boutons sont plus fiable, lorsque j'appuie ca réagit directement.

    Sans votre bout de code, la bascule des relais était plus aléatoire il fallait soit appuyer court soit insister un peu. Les relais 0 à 3 restaient ouvert tant que je restais appuyé ce qui m'irais très bien à défaut d'avoir mieux du coup...
    Ca fonctionne parfaitement pour les relais 4 à 7 en tout cas...

  20. #80
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 715
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 715
    Points : 5 403
    Points
    5 403
    Par défaut
    Il y a un bug dans votre gestion des noms

    vous déclarez un seul caractère et vous pensez sans doute comparer deux chaînes en faisant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    if (parametres.nomAD[Param] != nomADMem) {
          genie.WriteStr(1, parametres.nomAD[Param]);
        }
    ou encore affecter une chaîne à une autre en faisant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
        nomADMem = parametres.nomAD[Param];
    ça ne fonctionne pas comme cela. D'une part nomADMem devrait être un tableau
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    char nomADMem[longeurMaxDuNom + 1];
    et pour comparer il faut utiliser la fonction strcmp() et pour affecter il faut utiliser la fonction strcpy()

    ça donnerait
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    if (strcmp(parametres.nomAD[Param], nomADMem) != 0) { // strcmp() retourne 0 si les chaînes sont identiques
          genie.WriteStr(1, parametres.nomAD[Param]);
        }
    et
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
        strcpy(nomADMem, parametres.nomAD[Param]);
    Si vous avez des bugs dans l'affectation mémoire des noms, ça peut conduire à des débordement de tableau qui vont ensuite écraser les autres variables et créer une instabilité mais je ne vois pas où sont ces initialisations. --> Vous avez viré des trucs ? le setup() n'a pas son accolade fermante (il manque le gestionnaire myGenieEventHandler() ou des fonctions comme getTemp() ou getHr() ...)

Discussions similaires

  1. Cherche un document management system pour s'inspirer
    Par randriano dans le forum Autres Solutions d'entreprise
    Réponses: 0
    Dernier message: 03/12/2014, 10h08
  2. Réponses: 0
    Dernier message: 05/11/2014, 21h11
  3. Trouver un poste pour un mémoire d'ingénieur CNAM
    Par AntoineGael dans le forum Emploi
    Réponses: 2
    Dernier message: 13/01/2014, 14h22
  4. disquette systéme pour windows xp
    Par gilleski2010 dans le forum Windows XP
    Réponses: 1
    Dernier message: 14/10/2005, 22h13

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo