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 :

ARDUINO UNO - Prendre en compte les entrées console à tout moment


Sujet :

Arduino

  1. #1
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2014
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Octobre 2014
    Messages : 7
    Points : 5
    Points
    5
    Par défaut ARDUINO UNO - Prendre en compte les entrées console à tout moment
    Bonjour,

    Avant tout il faut que je vous explique quel est le but de mon programme : je souhaite automatiser les commandes d'une table motorisé pour un écran tactile.

    Nom : 191ee38db6e8508c86e0b9a50313c5f3.jpeg
Affichages : 861
Taille : 6,0 Ko

    La table se commande avec 4 boutons : 1 - monte le pied, 2 - descend le pied, 3 - incline le plateau (sens horaire) et 4 - incline le plateau (sens anti-horaire)
    Ces quatres boutons sont situées sur la partie amovible de la table (Délire de concepteur ?...) ce qui n'est pas très pratique, ces donc pour cela que je souhaite l'automatisé en commandant le système avec une télécommande IR tout en laissant un accès au boutons de commandes.
    J'entend par automatiser : modifier le positionnement de la table dans un mode préenregistré, enregistrer de nouveau positionnent ou tout simplement actionner les commandes directs.

    Après avoir fais l'étude du circuit de commande de la table, j'ai isolé quatres files qui me permettent d'actionner les quatres commandes citées ci-dessus.
    J'ai donc écrit un programme (ci-dessous) permettant d'activer une sortie numérique durant un temps donné puis une autre sortie durant un temps donnés différent en fonction du positionnement souhaité. Ces signaux seront ensuite envoyé sur un circuit composé de mosfet et de relais qui permettent de lier deux des quatres fils pour activer l'une des commandes.

    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
     
    #include <IRremote.h>
     
    #define TEMPS_UP_DOWN 18500
    #define TEMPS_VERT_HORIZ 12200
    #define TEMPS_TEMPO 1000
     
    int pinTURNH = 2, pinTURNAH = 4;          //TURNH : Rotation du plateau sens horaire - TURNAH : Rotation du plateau sens anti-horaire
    int pinUP = 7, pinDOWN = 8;   //UP : Monte le plateau - DOWN : descend le plateau
     
     
    int RECV_PIN = 11;
    IRrecv irrecv(RECV_PIN);
    decode_results results;
     
    /* Les modes
    Mode 1 : Table -> Présentation
    Mode 2 : Présentation -> Table
     
     
    Les Actions
    Action 1 : UP
    Action 2 : DOWN
    Action 3 : TURNH
    Action 4 : TURNAH
    */
     
     
    void setup()
    {
      Serial.begin(9600);
      irrecv.enableIRIn(); // Initialise le recepteur IR
     
      pinMode(pinTURNH, OUTPUT); 
      pinMode(pinTURNAH, OUTPUT); 
      pinMode(pinUP, OUTPUT); 
      pinMode(pinDOWN, OUTPUT); 
     
      digitalWrite(pinTURNH, LOW);
      digitalWrite(pinTURNAH, LOW);
      digitalWrite(pinUP, LOW);
      digitalWrite(pinDOWN, LOW);
    }
     
    void loop() {
     
     
     
         Serial.println("Dans quelle position souhaitez-vous regler la table ? :");
          Serial.println("- Mode 1 : Mode presentation");
          Serial.println("- Mode 2 : Mode Table");
         digitalWrite(pinTURNH, LOW);digitalWrite(pinTURNAH, LOW);digitalWrite(pinUP, LOW);digitalWrite(pinDOWN, LOW);
     
     
       if (irrecv.decode(&results))
      {
        Serial.println(results.value);   //affiche la valeur envoyer par la telecommande
        irrecv.resume();   // Recoit la valeur suivante
      }
     
     
       if (results.value  == 16724175)     //16724175 est la valeur entière reçu par la console lors de l'appui sur le bouton 1 de la télécommande
       { // Mode 1 : Table -> Présentation
            digitalWrite(pinUP, HIGH);
            delay(TEMPS_UP_DOWN);
            digitalWrite(pinUP, LOW);
            delay(TEMPS_TEMPO);
            digitalWrite(pinTURNH, HIGH);
            delay(TEMPS_VERT_HORIZ);
            digitalWrite(pinTURNH, LOW);
            Serial.println("Position Presentation");
            results.value =0;
       }
     
     
           if (results.value == 16718055)
        { // Mode 2 : Présentation -> Table
              digitalWrite(pinTURNAH, HIGH);
              delay(TEMPS_VERT_HORIZ);
              digitalWrite(pinTURNAH, LOW);
              delay(TEMPS_TEMPO);
              digitalWrite(pinDOWN, HIGH);
              delay(TEMPS_UP_DOWN);
              digitalWrite(pinDOWN, LOW);
              Serial.println("Position Table");
              results.value =0;
         }
     
     
     
    ////////////////////////////commandes direct/////////////////////////////////////////
     
        if (results.value == 16712445){
            digitalWrite(pinUP, HIGH);
            delay(TEMPS_UP_DOWN);
          results.value =0;}
     
       if (results.value == 16720605){
            digitalWrite(pinDOWN, HIGH);
            delay(TEMPS_UP_DOWN);
          results.value =0;}
     
        if (results.value == 16754775){
            digitalWrite(pinTURNH, HIGH);
            delay(TEMPS_VERT_HORIZ);
           results.value =0;}
     
        if (results.value == 16769055){
           digitalWrite(pinTURNAH, HIGH);
           delay(TEMPS_VERT_HORIZ);
          results.value =0;}
     
     
       delay(500);
    }

    Mon problème est le suivant, j'aimerai stopper l’exécution d'un mode ou d'une commande a tout moment par l'appui sur un bouton de la télécommande.
    Dit autrement, comment faire en sorte que la prise en compte des commandes transmisent par la télécommande se fasse a tout moment dans le programme ?

    j'ai essayé avec la commande millis() pour remplacer les tempo ou encore l'utilisation de la bibliothèque #include <TimerOne.h> mais sans jamais aboutir à un semblant de résultat.

    Merci d'avance à ceux qui pourront m'apporter leur aide.

  2. #2
    Modérateur

    Avatar de Vincent PETIT
    Homme Profil pro
    Consultant en Systèmes Embarqués
    Inscrit en
    Avril 2002
    Messages
    3 187
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Consultant en Systèmes Embarqués
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Avril 2002
    Messages : 3 187
    Points : 11 568
    Points
    11 568
    Par défaut
    Salut,
    Tourne toi vers les "interruptions" de ton microcontrôleur.
    Ton Atmega328P, sur ton UNO, a tout ce qui faut en interne pour déclencher une interruption (sous entendu du programme principal) une fois que des données arrivent sur son UART (son port série.)

    Si tu continues dans l'expérimentation des microcontrôleurs, tu verras que la technique du polling, donc ce que tu fais en faisant une tempo dans ton programme principal, est toujours LA mauvaise solution puisque tu mets en attente tout le micro. Les interruptions sont là pour faire ce que tu souhaites, c'est a dire arrêter ce que le micro est entrain de faire pour traiter l'événement de l'interruption puis revenir au programme principal et un microcontrôleur a souvent un sacré paquet d'interruption !

    L'algorithme de ton soft sera a revoir en prenant en compte ce mécanisme pour savoir ce que tu mets dans le programme d'interruption (traitement prioritaire) et ce que tu mets dans ton programme principal (traitement secondaire qui ne craint pas d'être interrompu).

    A+
    La science ne nous apprend rien : c'est l'expérience qui nous apprend quelque chose.
    Richard Feynman

  3. #3
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2014
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Octobre 2014
    Messages : 7
    Points : 5
    Points
    5
    Par défaut
    Merci pour cette réponse très rapide ! Et merci pour ces infos.

    J'ai effectivement lu sur plusieurs forum que l'utilisation de la commande delay() n'était pas une bonne solution. J'ai donc essayé de gérer mes tempo avec la commande millis() mais je n'ai jamais réussi a obtenir ce que je souhaite.

    Pour l’interruption, elle peut intervenir a tout moment (pour l’instant car je n'ai pas encore codé la partie permettant d'enregistrer de nouveau mode). cela veut dire que je ne doit rien mettre dans le loop() et tout gérer en fonction ?

  4. #4
    Modérateur

    Avatar de Vincent PETIT
    Homme Profil pro
    Consultant en Systèmes Embarqués
    Inscrit en
    Avril 2002
    Messages
    3 187
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Consultant en Systèmes Embarqués
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Avril 2002
    Messages : 3 187
    Points : 11 568
    Points
    11 568
    Par défaut
    Citation Envoyé par Roms95
    cela veut dire que je ne doit rien mettre dans le loop() et tout gérer en fonction ?
    Surtout pas !
    La fonction d'interruption doit être rapide, bien souvent elle consiste a mettre à jour un "tableau global" ou "une/des variables globales". Une fois fini, hop, tu retournes au programme principal qui lui se sert du même tableau mais pour faire ce que tu veux toi (traitement, calcul, affichage, positionnement de moteur, ....)

    Imagine cette exemple simple :
    1 - Tu as un tableau en global
    2 - La fonction d'interruption est exécuter et rempli le tableau avec ce qui arrive depuis le port série
    3 - Le programme principal est une boucle infini qui le lit le tableau global est l'envoi sur un afficheur graphique par exemple.

    Si tu regardes ce mécanisme, il est tout simple. L'étape 3 ne fait que de l'affichage par rapport a des données contenues dans un tableau global de manière bouclé à l'infini ! Si jamais une donnée arrive sur le port série alors l'étape 2 arrête tout pour se lancer, elle met a jour le tableau puis redonne la main a l'étape 3 précisément où elle a été interrompu. L'étape 3 reprend sa boucle infini sauf que la tableau global (ou partagé) a changé et l'afficheur graphique affiche autre chose. Il n'y a aucune tempo dans ce que je viens d'écrire ! Juste de la gestion d'interruption.

    Parfois il se peut que tu aies besoin de faire quelques choses de très spécial dans la fonction d'interruption, genre arrêt d'urgence, alors dans ce cas la fonction d'interruption peut contenir beaucoup plus de lignes et être beaucoup plus conséquente (réinitialisation de position de moteur, coupure de certain système, démarrage d'une alarme ou envoi d'un e-mail etc...) Ceci est un autre cas de figure que l'exemple du dessus qui concernait un afficheur.

    Les points a faire attention sont :
    Qu'est ce que je mets dans ma fonction d'interruption ? Beaucoup de code ? Ce qui doit être rapide dans l'interruption et le reste est donné au programme principal ?
    Qu'est ce qui est critique et que ne doit absolument pas être interrompu dans le programme principal ?
    Y a t-il plusieurs sources d'interruptions et comment je gère les priorités ?
    Tu vois le raisonnement ?

    Autre exemple concernant de l'échantillonnage de signal analogique (regarde la subtilité, tu verra où il faut se méfier).
    La fonction d'interruption est très simple : Un timer est lancé et une fois qu'il déborde toutes les 5ms (ça se calcul à l'aide de la doc du micro) une fonction d'interruption se lance (sur overflow du timer bien sur) ! Dedans, tu viens lire le convertisseur analogique numérique, tu places la valeur dans un tableau, tu incrémentes le tableau de 1 pour la fois prochaine et tu redonnes la main au programme principal. Le programme principal attend que le tableau soit rempli pour par exemple calculer la moyenne. Une fois le tableau rempli, on est content car on a des échantillons a intervalle de 5ms précisément (ce qui aide pour calculer des intégrales et dérivés) et on calcul la moyenne des échantillons ! Là il faudra être vigilent car durant ce calcul il faudra être sur que le tableau de change plus et pourtant la fonction d'interruption va se lancer quand même 5ms plus tard sans se préoccuper que tu aies fini ou pas ta moyenne. Une solution peut être de créer 2 tableaux dont l'un est un buffer d'attente pour ne pas perdre non plus des informations lors du calcul de la moyenne.


    Désolé pour les fautes d'orthographe, je fais deux choses à la fois à cet instant.
    Je mélange volontairement "programme et fonction" d'interruption car pour moi c'est la même chose. Je trouve même le terme fonction moins bien adapté dans la mesure où c'est le hard qui le lance et ce n'est pas le programme principal.
    La science ne nous apprend rien : c'est l'expérience qui nous apprend quelque chose.
    Richard Feynman

  5. #5
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Je mélange volontairement "programme et fonction" d'interruption car pour moi c'est la même chose. Je trouve même le terme fonction moins bien adapté dans la mesure où c'est le hard qui le lance et ce n'est pas le programme principal.
    Le terme consacré est "routine"

  6. #6
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2014
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Octobre 2014
    Messages : 7
    Points : 5
    Points
    5
    Par défaut
    Merci, je comprend mieux l'utilisation des interruptions maintenant.

    Effectivement cette interruption correspond a un arrêt d'urgence dans mon système, elle va me permettre de remettre les quartes commandes au niveau bas et de mettre a jour la variable associée aux données reçuent sur la console.

    Dans mon cas, les données transmisent par la télécommande IR sont des entiers donc une variable suffira. Mais le problème est que je n'arrive pas à faire en sorte que mon interruption se lance lors de la réception d'une nouvelle données sur la console.

    Cette partie du code me permet de récuperer et d'afficher les données sur la console puis d'effacer le tampon pour préparer l'arriver de la nouvelle commande.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    if (irrecv.decode(&results))
      {
        Serial.println(results.value);
        irrecv.resume(); // Recoit la valeur suivante
      }

    J'ai ensuite lu sur un forum que la pin de réception s'activait lors d'une entrée sur la console j'ai donc cherché comment s'appellait la pin et j'ai trouvé l'info suivante :

    Port série (USART) = émission/réception série via les broches TXD(PD1)/RXD(PD0)

    j'ai don essayer de lancer mon interruption de la manière suivante:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    attachInterrupt(PD0, interrupt, CHANGE);
    Mais rien à faire, sa ne marche pas. J'ai essayer plusieurs tournures mais je n'aboutis pas.

    Pour ce qui est de l'échantillonnage, j'ai bien compris la subtilité; il faut faire attention que le temps d’exécution du programme principale ne soit pas supérieur a la fréquence d'échantillonnage aux risque de fausser les données. Pour éviter cela il faut utiliser des variables/tableaux tampons.

    Encore merci pour toutes ces explications.

  7. #7
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2014
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Octobre 2014
    Messages : 7
    Points : 5
    Points
    5
    Par défaut
    J'ai résolu mon problème.

    Pour l'interruption : je souhaitais lancer mon interruption lors de la réception d'une données sur le port série se qui représentait un arret d'urgence.
    Malheureusement les interruption peuvent être lancées uniquement par une action (chgmt d'état, front montant,...) sur une pin.
    J'ai donc revu mon système en ajoutant un bouton poussoir, représentant mon bouton d'arret d'urgence, qui agit sur la pin 3 digital par exemple.

    Pour les temporisations: les delay stoppaient l’exécution de mon programme (ce qui était gênant pour la prise en compte d'un arrêt d'urgence). j'ai donc créer la fonction suivante :

    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
      void tempo(int temps)
        {  
         if (arret == 0){ 
          tempoActive = 1;
          tempoDepart = millis();
     
          while (tempoActive == 1){
              if ( ( millis() - tempoDepart ) >= temps )
              {
                   tempoActive = 0;
               }
     
          }
        }
      }
    il suffit d'envoyer la constante de temps en argument à la fonction pour que la tempo se lance.

    J’espère que sa pourra aider.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Prendre en compte les changements dans le registre
    Par kenny49 dans le forum Windows XP
    Réponses: 1
    Dernier message: 13/10/2006, 12h02
  2. [XSLT] prendre en compte les retours à la ligne
    Par mathieux dans le forum XSL/XSLT/XPATH
    Réponses: 1
    Dernier message: 19/07/2006, 21h05
  3. [.NET] ne pas prendre en compte les "0"
    Par californialove dans le forum MFC
    Réponses: 16
    Dernier message: 05/06/2006, 10h05
  4. [XHTML] Ne pas prendre en compte les balises XHTML
    Par simnitch dans le forum Balisage (X)HTML et validation W3C
    Réponses: 8
    Dernier message: 18/08/2005, 15h58
  5. [plugin][tomcat] Comment prendre en compte les jar ?
    Par djodjo dans le forum Eclipse Java
    Réponses: 6
    Dernier message: 08/04/2004, 19h47

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