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

Langage C++ Discussion :

Comment gérer l'IHM d'un programme embarqué?


Sujet :

Langage C++

  1. #1
    Membre averti Avatar de megamario
    Homme Profil pro
    VB6/VB.net/C/C++/C#
    Inscrit en
    Septembre 2008
    Messages
    929
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : VB6/VB.net/C/C++/C#
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2008
    Messages : 929
    Points : 312
    Points
    312
    Par défaut Comment gérer l'IHM d'un programme embarqué?
    Bonjour,

    Mon programme pour mon aquarium récifal commence à prendre forme, toutes les fonctions sont quasiment terminées. Le contrôleur est un Arduino MEGA 1250, Donc psedo C/C++ puisque toutes les fonctions ne sont pas disponible.

    Il me reste une grosse parti c'est la fonction IHM.
    Mon afficheur est constituer d'un afficheur 2 * 16 caractères, de 3 boutons et de 2 voyants LED.

    Je dialogue avec l'afficheur par l'I2C. Mes fonctions sont définies et fonctionne pour envoyer:
    La ligne 1
    La ligne 2
    Le voyant rouge
    Le voyant vert
    La récupération des 3 boutons.
    Cela fonctionne bien.

    Actuellement j'envoie uniquement l'affichage de base c'est à dire que j'envoie les différentes mesure sur la ligne 2:
    Température
    PH
    Heure

    Sur la ligne 1 j'envoie un titre lorsqu'il n'y a pas de défaut si non j'envoie le ou les défauts les un a la suite des autres:
    Temp trop haute
    PH trop bas RAC
    Temp trop basse
    PH trop Haut RAC
    etc...

    Ce que je souhaite:

    Savoir de quelle façon en général on gère l'affichage.

    Par exemple lorsque j'appuie sur la 1ere touche je doit pouvoir avoir une liste d'option puis des sous menu.
    par exemple:
    Visualisation de Base
    ---Étalonnage
    -------Température
    ------------ Temp = 25C sur la 1ere ligne
    ------------ + - Valide sur la 2eme ligne
    -------PH RAC
    ------------ Étalonnage PH 7
    ------------------ PH RAC = 6.95 sur la 1ere ligne la mesure en court
    ------------------ Valid PH = 7 sur la 2eme ligne
    -------------Etalonnage PH 4
    ------------------ PH RAC = 4.01
    ------------------ Valid PH = 4
    -------------Etalonnage PH 10
    ------------------ PH RAC = 10.02
    ------------------ Valid PH = 10
    -------PH BAC
    ------------ Étalonnage PH 7
    ------------------ PH BAC = 6.95 sur la 1ere ligne la mesure en court
    ------------------ Valid PH = 7 sur la 2eme ligne
    -------------Etalonnage PH 4
    ------------------ PH BAC = 4.01
    ------------------ Valid PH = 4
    -------------Etalonnage PH 10
    ------------------ PH BAC = 10.02
    ------------------ Valid PH = 10
    ---ECLAIRAGE
    -------Eclairage 1
    -------------Allumage
    ------------------ Heure : 09:00 sur la 1ere ligne
    ------------------ HH MM VAL sur la 2eme
    -------------Extinction

    etc...
    etc...

    Donc j'ai une idée assez précise de ce que je doit faire avec l'IHM mais pour la gestion dans le programme je ne sais pas exactement comment je doit faire.
    Il faut par exemple que le restes des fonctions continues à tourner.

    Pour ceux qui connaisse pas l'arduino. mon programme se déroule dans une boucle: Loop

    Actuellement je récupère le timer interne afin de me faire des compteurs de 100ms. Ensuite je lance chaque méthode (capture PH, Capture temp, Capture heures etc..) toutes X 100ene de millisecondes.

    Pareil pour l'affichage actuel
    Toutes les 300 millisecondes j'envoie la ligne 1 puis la ligne 2 puis je vérifie l’état des boutons. Et met à jour éventuellement les voyants.

    Les bouton ne sont pas gérés pour le moment mais juste renvoyer sur le Port Serie pour debug.

    Voici ma fonction Loop, elle ne va pas être simple à comprendre car j'ai énormément de variables externe à la méthode. Si vous voyer quelques choses qui n'est pas plaisant, bien sur dites le moi car je débute.
    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
    void loop()
    {
      int top;
      unsigned char dt[16];
      boolean ScanOsci = true; 
      String Ligne;
      String st;
     
     
      if (millis() >= ancien_millis) { // Vérifie que le temps millis() est bien supérieur à l'ancienne valeur mémorisée
    						   // >> risque à l'init et au retour à zéro de l'horloge interne.
        if (millis() - ancien_millis >= 100){ top = 1;  // création d'un top toutes les 100ms
          ancien_millis = millis();		   // réinitialisation ancien_millis
          compteur_top = compteur_top + 1;	    // Incrémente le compteur de tops 
          compteur_Heure = compteur_Heure +1;
          compteur_I2C = compteur_I2C + 1;
          compteur_InCom = compteur_InCom + 1;
          compteur_Temperature = compteur_Temperature + 1;
          compteur_DigitEntree += 1;
          compteur_Nourissage += 1;
          compteur_PH1 += 1;
          compteur_Alarme += 1;
          for (int i = 0 ; i<= 3 ; i ++)
          {
            compteur_Osci[i] += 1;
            compteur_PauseOsci[i] += 1;
          }
        }  
      }
      //Recherche de l'heure DS1307
      if (compteur_Heure * 10 >= 1000) { //en milliseconde
        DateHeure();
        compteur_Heure = 0;
      }
     
     //Oscilateur
     
        GestionOscilateur();
     
        //Verification des entrées;
        if(compteur_DigitEntree >= 5){
          DetectEntree();
          compteur_DigitEntree = 0;
        }
     
        //Temperature
     
      //affichage de la temperature
        MesBrut += analogRead(analogTempPin);  
        NbTourTemp +=1; 
        //affichage de la temperature
        if (compteur_Temperature >= cmpMesureTemp)
        {
          Temperature(NbTourTemp);
          compteur_Temperature = 0;
          MesBrut = 0;
          NbTourTemp = 0;
        }
     
       //Gestion de l'I2C Vitesse
        if (compteur_I2C  >= 3){
           GestionAffichage();
           compteur_I2C = 0;
        }
        //Compteur Input COM
         if (compteur_InCom >= 3){
           InputCOM();
            compteur_InCom = 0;
         }
         //Compteur PH
         if (compteur_PH1 >= 10){
             MyPH1Mesure();
             compteur_PH1 = 0;
         }
         //Bip Alarme
         if (compteur_Alarme >= 10){
            unsigned char dt[1];
           if (Alarme){
     
                dt[0] = 0x01;//Voyant rouge
                CommandeVoyant(dt);
                if (bipAlarme){
                 digitalWrite( Buzzer, LOW);
                 bipAlarme = false;
                }else{
                  digitalWrite( Buzzer, HIGH);
                 bipAlarme = true;
                } 
     
             }else{
               dt[0] = 0x00;//Arret des voyants
               CommandeVoyant(dt);
               digitalWrite( Buzzer, LOW);
             }
     
             compteur_Alarme = 0;
         }
    }
    Voici la partie de gestion afficheur, voyant et bouton:
    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
    void CommandeVoyant(unsigned char * dt)
    {
       if (dt[0] == 0x00)
       {
        VOYANT[0] = dt[0];
       }else{
         VOYANT[0] = VOYANT[0] | dt[0];
       }
       LCD.I2C_WriteCommand(LCD_SLAVE_ADRR, I2C_CMD_LEDSCONTROL, 1, VOYANT);
    }
    //******************************************************
    //                 AFFICHAGE
    //******************************************************
    void GestionAffichage()
    {
        boolean DefautTemp = false;
        boolean DefautCO2 = false;
        unsigned char Button;
     
         //Affichage de la 1ere ligne
           if (!Alarme){ //pas d'alarme
               LCD.Write_Line("Aquarius  37    ",1);
           }else{ //Presence d'alarme
               if (MSGAlerteCO2 != "") DefautCO2 = true;
               if (MSGAlerteTemp != "") DefautTemp = true;
               if (AffichageHaut >= 10){
                 AffichageHaut = 0;
                 if (DefautCO2 && Def == 0){
                  LCD.Write_Line(MSGAlerteCO2,1);
                  Def = 1; 
                 }else{
                   Def = 0;
                   if (DefautTemp && Def == 0){
                     LCD.Write_Line(MSGAlerteTemp,1);
                     Def = 0;
                   }
                 }
               }else AffichageHaut ++;
           }
     
           //Affichage de la 2eme lignes
           LCD.Write_Line(L2,2);
           // Serial.println("debug affichage 1");
           switch (affichageBas){
             case 0:
               L2 = " ";
               L2 = AffichageHeure();
               affichageBas ++;
               LCD.Write_Line(L2,2);
               break;
             case 10:
               L2 = " ";
               L2 = CNV.LigneMesure("Temp= %s", Temp , "C");
               LCD.Write_Line(L2,2);
               affichageBas ++;
               break;
             case 20:
               L2 = " ";
               L2 = CNV.LigneMesure("PH Rac = %s", MesurePH1, "");
               LCD.Write_Line(L2,2);
               affichageBas ++;
               break;
             case 30:
               affichageBas = 0;
               break;
             default:
               affichageBas ++;
           }
           if(affichageBas >= 30)affichageBas = 0;     
           Button = LCD.I2CXD_ReadCommand(LCD_SLAVE_ADRR, I2C_CMD_BUTTON_STATUS_REGISTER ,1);
           int NbBt = AnaliseButton(Button);
     
    }
    int AnaliseButton(unsigned char Bt)
    {
        int NbBt = 0;
        Bt1court = false;
        Bt2court = false;
        Bt3court = false;
        Bt1long = false;
        Bt2long = false;
        Bt3long = false;
        if ((Bt & 0x01) == 0x01) Bt1court = true;//court
        if ((Bt & 0x02) == 0x02) Bt1long = true;//long
        if ((Bt & 0x04) == 0x04) Bt2court = true;//court
        if ((Bt & 0x08) == 0x08) Bt2long = true;//long
        if ((Bt & 0x10) == 0x10) Bt3court = true;//court
        if ((Bt & 0x20) == 0x20) Bt3long = true;//long
        if (Bt1court || Bt1long ) NbBt ++;
        if (Bt2court || Bt2long) NbBt ++;
        if (Bt3court || Bt3long) NbBt ++;
     
        if (Bt1court) Serial.println("bouton 1 court");
        if (Bt1long) Serial.println("bouton 1 long");
        if (Bt2court) Serial.println("bouton 2 court");
        if (Bt2long) Serial.println("bouton 2 long");
        if (Bt3court) Serial.println("bouton 3 court");
        if (Bt3long) Serial.println("bouton 3 long");
            return NbBt;
    }

  2. #2
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    => Peux-tu faire du C++ ? Veux tu développer en C ou en C++ ?
    => Ta boucle, quelque soit le langage mérite quand même un peu de ménage. On y trouve beaucoup trop de chose. (revoir ses bases de programmation modulaire )
    => J'imagine que dans ce système tu n'as pas accès aux IRQ. Tu accèdes aux périphériques par polling uniquement, c'est à dire en allant lire régulièrement leur état.

    La boucle doit alors ressembler à quelque chose comme ça :
    loop
    ---- lire les entrées
    ---- calculer le nouvel état du système en fonction des entrées
    ---- ecrire les sorties

    Typiquement, pour ton affichage, la lecture des entrées va consister à récupérer l'état des boutons. Le calcul du nouvel état serait probablement coupé en trois : la transformation de l'état des boutons en évènements (DOWN, UP, CLICK, DLB_CLICK, PRESSED, etc...), puis le traitement de cet évènement dans ton 'moteur' d'affichage. Le moteur d'affichage va traiter l'évènement puis déterminer quelles LED éclairer ou éteindre, que mettre dans les lignes, etc. Ensuite, l'écriture des sorties envoie concrètement les commandes I2C.

    Sur le moteur d'affichage à proprement parler, on se base souvent sur une machine à état. Ton affichage possède un état. Chaque évènement le fait changer (ou pas d'état), ce qui permet de dérouler les différents menus. Puis en fonction de l'état courant, l'affichage est construit.

    C'est une vision rapide et simple du principe. Les évènements peuvent venir des boutons mais aussi de timers, de seuil de tes capteurs etc...

    Pour un dev OO en C++, je te conseille de t'intéresser au DP Etat : tutoriels ici et ici.

  3. #3
    Membre averti Avatar de megamario
    Homme Profil pro
    VB6/VB.net/C/C++/C#
    Inscrit en
    Septembre 2008
    Messages
    929
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : VB6/VB.net/C/C++/C#
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2008
    Messages : 929
    Points : 312
    Points
    312
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Salut,
    => Peux-tu faire du C++ ? Veux tu développer en C ou en C++ ?
    => Ta boucle, quelque soit le langage mérite quand même un peu de ménage. On y trouve beaucoup trop de chose. (revoir ses bases de programmation modulaire )
    => J'imagine que dans ce système tu n'as pas accès aux IRQ. Tu accèdes aux périphériques par polling uniquement, c'est à dire en allant lire régulièrement leur état.

    La boucle doit alors ressembler à quelque chose comme ça :
    loop
    ---- lire les entrées
    ---- calculer le nouvel état du système en fonction des entrées
    ---- ecrire les sorties

    Typiquement, pour ton affichage, la lecture des entrées va consister à récupérer l'état des boutons. Le calcul du nouvel état serait probablement coupé en trois : la transformation de l'état des boutons en évènements (DOWN, UP, CLICK, DLB_CLICK, PRESSED, etc...), puis le traitement de cet évènement dans ton 'moteur' d'affichage. Le moteur d'affichage va traiter l'évènement puis déterminer quelles LED éclairer ou éteindre, que mettre dans les lignes, etc. Ensuite, l'écriture des sorties envoie concrètement les commandes I2C.

    Sur le moteur d'affichage à proprement parler, on se base souvent sur une machine à état. Ton affichage possède un état. Chaque évènement le fait changer (ou pas d'état), ce qui permet de dérouler les différents menus. Puis en fonction de l'état courant, l'affichage est construit.

    C'est une vision rapide et simple du principe. Les évènements peuvent venir des boutons mais aussi de timers, de seuil de tes capteurs etc...

    Pour un dev OO en C++, je te conseille de t'intéresser au DP Etat : tutoriels ici et ici.
    Merci beaucoup,

    Effectivement je comptais mieux organiser un peu l'ordre des actions à réaliser. Pour le moment c'est vraiment brouillon.
    Par contre faut que j'envoie en permanence les lignes à l'afficheur.
    Si je suis dans un menu avec l'IHM il faut quand même que j'envoie les lignes, même si j'ai rien changé, car si non l'afficheur se plante.

    Je vais regarder les tutos pour la suite, merci.

    Mais vu que je dois donc envoyer les lignes en permanences et continuer à effectuer les traitements classic. Je pense qu'il me faut donc détecter l’état des boutons. Mettre à jour une variable qui me positionnera ensuite.
    Dans une autre méthode je traite l'affichage en fonction de la ou les variables.
    Puis dans une autre méthode je traite la ou les actions à réaliser.

  4. #4
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par megamario Voir le message
    Mais vu que je dois donc envoyer les lignes en permanences et continuer à effectuer les traitements classic. Je pense qu'il me faut donc détecter l’état des boutons. Mettre à jour une variable qui me positionnera ensuite.
    Dans une autre méthode je traite l'affichage en fonction de la ou les variables.
    Puis dans une autre méthode je traite la ou les actions à réaliser.
    C'est vraiment un principe répandu : une boucle qui fait en permanence les acquisitions (non bloquantes), puis leurs traitements (non bloquants) et les écritures sur les périphériques de sorties (non bloquantes bien sûr). Ta boucle devrait vraiment se 'lire' comme ça.

  5. #5
    Membre averti Avatar de megamario
    Homme Profil pro
    VB6/VB.net/C/C++/C#
    Inscrit en
    Septembre 2008
    Messages
    929
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : VB6/VB.net/C/C++/C#
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2008
    Messages : 929
    Points : 312
    Points
    312
    Par défaut
    Merci je vais regarder sa demain, faut que j'avance pour le mettre en service j'ai la gestion de mon réacteur à calcium a mettre en route.

Discussions similaires

  1. Réponses: 137
    Dernier message: 27/09/2022, 08h54
  2. Réponses: 4
    Dernier message: 26/08/2009, 21h55
  3. Programme de gestion commerciale - Comment gérer les commandes ?
    Par telodo dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 31/12/2008, 15h10
  4. Comment gérer les interruptions des programmes ?
    Par Olivier Regnier dans le forum Langage
    Réponses: 6
    Dernier message: 10/04/2007, 01h27
  5. Comment gérer des services par programmation avec Delphi ?
    Par isachat666 dans le forum API, COM et SDKs
    Réponses: 4
    Dernier message: 18/12/2005, 18h54

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