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 :

Problème "while" et "do while"


Sujet :

Arduino

  1. #1
    Futur Membre du Club
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2019
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 71
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Septembre 2019
    Messages : 4
    Par défaut Problème "while" et "do while"
    Bonjour,
    je programme depuis 1976 dans divers langages et sur divers microprocesseurs ou micro contrôleurs.
    j'ai commencé avec les cartes ARDUINO il 5 ou 6 ans et je n'ai jamais pu exploiter les instructions "while" ou "do while" que se soit sur UNO, MEGA ou DUE,
    via 5 versions d'IDE (la dernière 2.0.1) et 3 PC différents avec différents OS, VISTA, ..........., WINDOWS10.
    j'ai bien sûr consulté les forums et bien que me conformant aux exemples, ça ne marche pas, ecxepté pour le DUE ou je rajoute une instruction d'un cycle (inTerrups()) avant la boucle, ce qui n'est pas très satisfaisant, à croire que l'addresse de retour de boucle est décalée d'un cycle.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    inTerrupts();
    while(condition)
      {
         // do something
     
      }
    un exemple type sur UNO:
    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
    void setup()
    {
    #include <arduino.h>
    //  timeout = 15000;
    //  b_timeout = false;
      interrupts();
    }
     
    void loop()
      {
      timeout = 15000;
      b_timeout = false;
     
      while(!b_timeout)
       {
          cmpt++;  
       }
    //  if(b_timeout)
    //    {
        noInterrupts();
    //    }
      }
     
    // interrupt routine basée sur un timer cadensé à 1ms
     
    // ********************************
    // timer_interrupts
    // ********************************
    ISR(TIMER1_COMPA_vect)
      {
      // 1ms
     
      // 1s
      if(tim_1s > 1)
        {
        tim_1s--;
        }
      else
        {
        b_1s = true;  
        digitalWrite (LED_BUILTIN, !digitalRead(LED_BUILTIN)); 
        tim_1s = 500;
        }
     
      // 15s
      if(timeout > 1)
        {
        timeout--;  
        }
      else
        {
        b_timeout = true;  
        }
      }
    On peut vérifier que le flag (boolean) b_timeout ainsi que la variable (unsigned int) timeout sont bien mis à jour en supprimant la boucle "while" et en validant le "if".
    La LED clignotte 15 fois puis s'eteind avec le "if", clignotte indéfiniment avec le "while", boucle infinie.

    Quelqun peut-il m'éclairer?
    Grand merci d'avance

  2. #2
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 884
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 884
    Par défaut
    le while fonctionne très bien

    Comme vous utilisez des interruptions, les variables doivent être déclarées volatile et les lecture (si plus d'un octet) ou modification dans la loop (hors ISR si les interruptions restent bloquées) doivent se faire en section critique

    postez un code qui compile avec les déclarations des variables (et c'est mieux pour lire si le code est indenté et que vous utilisez les balises de code)

  3. #3
    Membre Expert

    Homme Profil pro
    Directeur de projet
    Inscrit en
    Mai 2013
    Messages
    1 582
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Service public

    Informations forums :
    Inscription : Mai 2013
    Messages : 1 582
    Par défaut
    Bonjour,

    Hormis ce que Jay a écrit et qui doit être pris en compte, il y a plein de choses à corriger :
    • tel quel le programme ne compile pas. Il ne semble pas complet, les variables globales ne sont mêmes pas déclarées.
    • pourquoi #include <arduino> et pourquoi à cet endroit ?
    • à quoi sert cmpt ?
    • à quoi sert b_1s ?
    • où est le paramétrage du timer ?
    • loop désactive les interruptions donc c'est une seule fois. Alors autant mettre le traitement dans le setup() et laisser loop() vide.
    • le test sur timeout pourrait être mis dans le else du test précédent en divisant les 15000 par 500 soit 30 car 15 s = 30 1/2 s


    Salutations

  4. #4
    Modérateur

    Avatar de Vincent PETIT
    Homme Profil pro
    Consultant en Systèmes Embarqués
    Inscrit en
    Avril 2002
    Messages
    3 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    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 245
    Par défaut
    Bonjour,
    Comme le dit Jay M le problème vient probablement des variables globales qui doivent être déclarées en volatile si elles interviennent dans une interruption. Ce mot clé force la mise à jour de la variable dans son emplacement mémoire, sinon elle se met à jour dans le registre de travail et disparaît au moment où on dépile.

  5. #5
    Futur Membre du Club
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2019
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 71
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Septembre 2019
    Messages : 4
    Par défaut
    Citation Envoyé par Vincent PETIT Voir le message
    Bonjour,
    Comme le dit Jay M le problème vient probablement des variables globales qui doivent être déclarées en volatile si elles interviennent dans une interruption. Ce mot clé force la mise à jour de la variable dans son emplacement mémoire, sinon elle se met à jour dans le registre de travail et disparaît au moment où on dépile.
    Bonjour et merci à tous, le problème est réglé par l'ajout de "volatile" à mes déclaration de variables, néanmoins une chose m'échappe:
    Pourquoi ces variables sont elles correctement interprétées dans le programme principal (loop) par l'instruction "if" et non pas par l'instruction "while" ?
    Particularité de l'IDE ?
    Encore merci à vous.
    Cordialement

  6. #6
    Modérateur

    Avatar de Vincent PETIT
    Homme Profil pro
    Consultant en Systèmes Embarqués
    Inscrit en
    Avril 2002
    Messages
    3 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    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 245
    Par défaut
    Citation Envoyé par pvisage Voir le message
    Bonjour et merci à tous,
    C'est Jay M qui a trouvé la solution


    Citation Envoyé par pvisage Voir le message
    Pourquoi ces variables sont elles correctement interprétées dans le programme principal (loop) par l'instruction "if" et non pas par l'instruction "while" ?
    Je ne vois pas de if dans ton loop() Du moins ils sont en commentaires.

  7. #7
    Futur Membre du Club
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2019
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 71
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Septembre 2019
    Messages : 4
    Par défaut
    Citation Envoyé par Vincent PETIT Voir le message
    C'est Jay M qui a trouvé la solution



    Je ne vois pas de if dans ton loop() Du moins ils sont en commentaires.
    Re bonjour,
    effectivement, pour comparer les deux modes (if ou while) je place la séquence concernée en commentaire, idem dans le setup pour l'initialisation des variables.
    Merci donc à Jay M et à toi.
    Cordialement

  8. #8
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 884
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 884
    Par défaut
    Citation Envoyé par pvisage Voir le message
    Pourquoi ces variables sont elles correctement interprétées dans le programme principal (loop) par l'instruction "if" et non pas par l'instruction "while" ?
    Particularité de l'IDE ?
    Non l'IDE n'a absolument rien à voir avec tout cela, ce n'est grosso modo qu'un éditeur de texte.

    Le comportement que vous voyez dépend des optimisations que le compilateur fait et vous pouvez avoir des comportements différents en ne modifiant qu'une instruction.

    par exemple pour un if il faut aller lire la valeur une fois en mémoire et donc elle sera donc juste, mais pour un while, une fois la variable lue —*si elle n'est pas déclarée volatile —*il va continuer à utiliser le registre puisque c'est plus rapide.

    avec volatile vous dites au compilateur "la variable peut changer pendant que que tu effectues cette boucle, donc ne fait pas confiance au registre, va lire et écrire toujours en mémoire".

    Comme dit aussi précédemment, si l'accès à la variable n'est pas atomique, il faut soit faire le test ou la boucle en section critique (interruptions suspendues) mais c'est dommageable de suspendre les interruptions trop longtemps, donc le mieux c'est de faire juste une copie de la variable en section critique, rétablir les interruptions et travailler avec la copie

  9. #9
    Membre prolifique Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 786
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 786
    Par défaut
    Salut à tous.

    Pourquoi se casser la tête à faire des choses compliquées ?
    Il est nul besoin d'utiliser une boucle while pour faire clignoter une led toutes les 15 secondes.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include	<arduino.h>
    #define		LED	9
    void setup()
    {
    	Serial.begin(115200);
    	pinMode(LED, OUTPUT);
    	digitalWrite(LED, HIGH); 
    }
     
    void loop()
    {
    	delay(15000);
    	digitalWrite(LED, !digitalRead(LED)); 
    }
    Cordialement.
    Artemus24.
    @+

  10. #10
    Membre Expert

    Homme Profil pro
    Directeur de projet
    Inscrit en
    Mai 2013
    Messages
    1 582
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Service public

    Informations forums :
    Inscription : Mai 2013
    Messages : 1 582
    Par défaut
    Bonjour Artemus,

    Citation Envoyé par Artemus24 Voir le message
    ...Pourquoi se casser la tête à faire des choses compliquées ? Il est nul besoin d'utiliser une boucle while pour faire clignoter une led toutes les 15 secondes...
    En fait, sauf erreur de lecture, la led clignote avec une période d'une seconde pendant 15 secondes puis s'arrête de clignoter restant allumée ou éteinte selon son état initial. Ceci étant, il est vrai qu'il y a plus simple mais je pense que le but était plus de maîtriser une interruption sur timer que maltraiter une led qui n'a rien demandée .

    Salut

  11. #11
    Membre prolifique Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 786
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 786
    Par défaut
    Salut à tous.

    Je n'ai pas d'Arduino mais des Modules NodeMCU ESP32.
    Si vous désirez utiliser la minuterie (timer) pour faire clignoter une led disons toutes les 1 seconde, voici un exemple :
    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
    /*****************/
    /*               */
    /*     Timer     */
    /*               */
    /*****************/
     
    /*************************************/
    /*                                   */
    /*     Déclaration des Variables     */
    /*                                   */
    /*************************************/
     
    const	unsigned short			_Led   = 2;
    		volatile int				_Cptr  = 0;
     
    		hw_timer_t 			*_Timer = NULL;
    		portMUX_TYPE			_Mux = portMUX_INITIALIZER_UNLOCKED;
     
    /************************************/
    /*                                  */
    /*     Appel Fonction Minuterie     */
    /*                                  */
    /************************************/
     
    void IRAM_ATTR onTimer()
    {
    	portENTER_CRITICAL_ISR(&_Mux);
     
    	digitalWrite (_Led, !digitalRead(_Led));
    	Serial.print("Compteur : ");
    	Serial.println(++_Cptr);
     
    	portEXIT_CRITICAL_ISR(&_Mux);
    }
     
    /*********************/
    /*                   */
    /*     Démarrage     */
    /*                   */
    /*********************/
     
    void setup()
    {
    	pinMode(_Led, OUTPUT);
    	digitalWrite(_Led, LOW);
     
    	Serial.begin(115200);
    	Serial.println("Début");
     
    	_Cptr = 0;
     
    	_Timer = timerBegin(0, 80, true);					// Diviseur 80 (Prescaler)
    	timerAttachInterrupt(_Timer, &onTimer, true);
    	timerAlarmWrite(_Timer, 1000000, true);				// 1 seconde
    	timerAlarmEnable(_Timer);
    }
     
    /****************************/
    /*                          */
    /*     Boucle Itérative     */
    /*                          */
    /****************************/
     
    void loop()
    {
    }
    La fonction onTimer se déclenche toutes les 1 seconde et change l'état de la led interne du ESP32 et affiche un message dans la console.
    Pas besoin d'utiliser une boucle while et ça fonctionne parfaitement.

    Cordialement.
    Artemus24.
    @+

  12. #12
    Modérateur

    Avatar de Vincent PETIT
    Homme Profil pro
    Consultant en Systèmes Embarqués
    Inscrit en
    Avril 2002
    Messages
    3 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    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 245
    Par défaut
    Bonjour tout le monde,
    Tiens ! Faisons un essai ; Artemus24 tu peux retirer le volatile de la variable _Cptr et nous dire si ça fonctionne toujours ?

    Merci.

  13. #13
    Futur Membre du Club
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2019
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 71
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Septembre 2019
    Messages : 4
    Par défaut
    Citation Envoyé par Jay M Voir le message
    Non l'IDE n'a absolument rien à voir avec tout cela, ce n'est grosso modo qu'un éditeur de texte.

    Le comportement que vous voyez dépend des optimisations que le compilateur fait et vous pouvez avoir des comportements différents en ne modifiant qu'une instruction.

    par exemple pour un if il faut aller lire la valeur une fois en mémoire et donc elle sera donc juste, mais pour un while, une fois la variable lue —*si elle n'est pas déclarée volatile —*il va continuer à utiliser le registre puisque c'est plus rapide.

    avec volatile vous dites au compilateur "la variable peut changer pendant que que tu effectues cette boucle, donc ne fait pas confiance au registre, va lire et écrire toujours en mémoire".

    Comme dit aussi précédemment, si l'accès à la variable n'est pas atomique, il faut soit faire le test ou la boucle en section critique (interruptions suspendues) mais c'est dommageable de suspendre les interruptions trop longtemps, donc le mieux c'est de faire juste une copie de la variable en section critique, rétablir les interruptions et travailler avec la copie
    Bonjour et merci encore pour ces explications claires et précises!
    J'ai fais une confusion en mentionnant l'IDE, je pensais compilateur.
    Le pire est que j'ai régulièrement utilisé des déclaration "volatile" dans des programmes que j'ai développé en c++ pour Intel 80C196 mais dans un autre contexte.
    Cordialement

  14. #14
    Membre prolifique Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 786
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 786
    Par défaut
    Salut à tous.

    Vincent Petit : j'ai supprimé "volatile" mais ça n'a rien changé. Mon exemple fonctionne toujours.

    Cordialement.
    Artemus24.
    @+

  15. #15
    Modérateur

    Avatar de Vincent PETIT
    Homme Profil pro
    Consultant en Systèmes Embarqués
    Inscrit en
    Avril 2002
    Messages
    3 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    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 245
    Par défaut
    Citation Envoyé par Artemus24 Voir le message
    Vincent Petit : j'ai supprimé "volatile" mais ça n'a rien changé. Mon exemple fonctionne toujours.
    Mince je t'ai demandé de faire un mauvais test.

    Il devrait être possible de mettre en évidence l'utilité de volatile si dans le loop() on testait la variable _Cptr pour faire je ne sais quoi.

  16. #16
    Membre Expert

    Homme Profil pro
    Directeur de projet
    Inscrit en
    Mai 2013
    Messages
    1 582
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Service public

    Informations forums :
    Inscription : Mai 2013
    Messages : 1 582
    Par défaut Le canard était toujours vivant...
    Bonjour Artemus,

    Citation Envoyé par Artemus24 Voir le message
    j'ai supprimé "volatile" mais ça n'a rien changé. Mon exemple fonctionne toujours...
    Comme _Cptr n'est pas utilisée en dehors de l'interruption qui en modifie la valeur, il ne peut y avoir de problème (enfin pas de ce type, mettre des Serial.print dans l'interruption est jouable ici car l'interruption est déclenchée seulement toutes les secondes sinon c'est assez risqué car lent) . Les difficultés arrivent quand une partie d'un programme ne "voit" pas qu'une ou plusieurs autres parties peuvent modifier la valeur dans son dos (interruption, multitâche s'il existe).

    Il n'y aurait pas non plus de problème si elle était utilisée une seule fois dans une partie du programme (entre autres pas dans une boucle) en dehors de l'interruption nonobstant la précaution de s'assurer que l'accès reste atomique ou la copier en section critique (ce qui fait disparaître de facto le problème impliquant la déclaration en volatile).

    volatile empêche le compilateur d'utiliser les optimisations de réutilisation des valeurs en registres. Ici le gain devrait être nul sauf si, après l'incrémentation et enregistrement en mémoire de la nouvelle valeur, il recharge la valeur qu'il vient de calculer avant de la passer comme argument au println. Il pourrait y avoir 10 ns de différence (estimation d'expert appelée également "au doigts mouillé"). Gain nettement perceptible n'est-ce pas ?

    Salut

  17. #17
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 884
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 884
    Par défaut
    Citation Envoyé par Guesset Voir le message
    ou la copier en section critique (ce qui fait disparaître de facto le problème impliquant la déclaration en volatile)
    à mon avis ça ne fait rien disparaître. il faudra quand même le mot clé volatile pour éviter toute optimisation qui conduirait à lire une mauvaise valeur (imaginez deux variables 16 bits, l'une normale, l'autre qui doit être volatile et on a besoin des deux dans la loop. imaginez qu'on utilise la normale en début de loop et la volatile en fin de boucle beaucoup plus tard.

    Si on ne met pas volatile, l'optimiseur pourrait faire le choix de lire les 2 variables d'un coup avec un registre 32 bits (il aura pris soin de les ranger côte à côte en mémoire et c'est pas plus cher sur une architecture 32 bits de lire 32 bits d'un coup) et va conserver la valeur pour plus tard pour la valeur volatile. Quand il sera temps de l'utiliser, ce sera une donnée périmée que vous accèderez pour la copie en zone critique. Si par contre vous l'avez déclarée volatile, il sait qu'il n'a pas le droit de faire cette optimisation et lira la variable au bon moment lors de la copie.

    2 règles a retenir pour tranquillité d'esprit:
    - une variable accédée à la fois dans une interruption et le code principal doit être volatile
    - dans le code principal, on n'accède pas la donnée volatile directement (sauf garantie que l'accès est atomique), on effectue une copie de la variable en section critique et on travaille sur la copie

  18. #18
    Membre prolifique Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 786
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 786
    Par défaut
    Salut à tous.

    Je n'ai pas pu mettre en évidence la différence entre la présence et l'absence de "volatile" avec mon ESP32.
    Si quelqu'un a un exemple concret, je veux bien le tester. Merci.

    Cordialement.
    Artemus24.
    @+

  19. #19
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 884
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 884
    Par défaut
    essayez cela sur votre ESP32

    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
     
    hw_timer_t *leTimer = NULL;
     
    unsigned long long valeur = 0; 
     
    void IRAM_ATTR declenchement() {
      valeur = ~valeur; // alterne 0xFFFFFFFFFFFFFFFF et 0x0
    }
     
     
    void setup() {
      Serial.begin(115200);
      leTimer = timerBegin(0, 80, true);                    // timer 0, prescaler, increment
      timerAttachInterrupt(leTimer, &declenchement, true);  // on attache l'interruption
      timerAlarmWrite(leTimer, 100, true);                  // déclenche toutes les 100µs avec réarmement
      timerAlarmEnable(leTimer);                            // activation
    }
     
    void loop() {
      if ((valeur != 0xFFFFFFFFFFFFFFFF) && (valeur != 0x0)) {
        Serial.println("C'est louche !");
      }
    }
    puis testez 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
     
    hw_timer_t *leTimer = NULL;
     
    volatile unsigned long long valeur = 0;
     
    void IRAM_ATTR declenchement() {
      valeur = ~valeur; // alterne 0xFFFFFFFFFFFFFFFF et 0x0
    }
     
     
    void setup() {
      Serial.begin(115200);
      leTimer = timerBegin(0, 80, true);                    // timer 0, prescaler, increment
      timerAttachInterrupt(leTimer, &declenchement, true);  // on attache l'interruption
      timerAlarmWrite(leTimer, 100, true);                  // déclenche toutes les 100µs avec réarmement
      timerAlarmEnable(leTimer);                            // activation
    }
     
    void loop() {
      noInterrupts();
      unsigned long long copie = valeur;
      interrupts();
      if ((copie != 0xFFFFFFFFFFFFFFFF) && (copie != 0x0)) {
        Serial.println("C'est louche !");
      }
    }

    Ce code déclare une variable de 64 bits qui va alterner entre 0x0 et 0xFFFFFFFFFFFFFFFF toutes les 100µs

    l'ESP32 est une architecture 32 bits et il ne sait pas comparer deux valeurs de 64 bits de manière atomique et le && n'est pas atomique non plus. il ne sait pas non plus stocker 64 bits dans un registre.

    Comme je bascule la valeur toutes les 100µs, il y a de forte chance pour que l'interruption se produise de temps en temps pendant une des deux comparaisons et conduise au fait que le if ne voit ni 0 ni 0xFFFFFFFFFFFFFFFF pour diverses raisons (par exemple c'était 0 quand il comparait avec 0xFFFFFFFFFFFFFFFF et c'était passé à 0xFFFFFFFFFFFFFFFF quand il compare à 0, ou alors comme la comparaison se fait en deux temps (partie basse sur 32 bits et partie haute ensuite de manière non atomique) il se peut que le premier test voit les 4 octets bas à 0 et les 4 octets haut à 0xFFFFFFFF, ....)

    Dans le second code on fait les choses correctement, valeur est volatile et sa lecture (pour faire une une copie) se fait en section critique ce qui rend le test de facto atomique

    je n'ai pas essayé mais je suis pratiquement sûr que le premier code vous affichera de temps en temps "C'est louche !" alors que le second code ne le fera jamais.

    En jouant sur la fréquence on peut sans doute minimiser (par exemple essayer 1ms au lieu de 1100µs) ou augmenter les cas où "C'est louche !" apparait mais la loi de Murphy vous garantit que si un problème peut arriver, il arrivera (au pire moment bien sûr)


    je vous laisse tester.

  20. #20
    Membre prolifique Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 786
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 786
    Par défaut
    Salut Jay M.

    J'ai testé le premier programme. En 1/4 d'heure, le message est apparu que deux fois seulement. Si j'appuie sur le bouton RESET, j'ai plein de messages.
    J'ai testé le deuxième programme et j'ai plein de messages.

    J'ai fusionné les deux programmes afin d'en faire un seul, que voici :
    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
    volatile	unsigned long long	 _Val;
    		unsigned long long	*_Cop;
     
    		hw_timer_t		*_Timer = NULL;
     
    void IRAM_ATTR onTrigger()
    {
    	 _Val = ~_Val;		// alterne 0xFFFFFFFFFFFFFFFF et 0x0
    }
     
    void setup()
    {
    	_Cop = (unsigned long long *)&_Val;
    	_Val = 0;
     
    	Serial.begin(115200);
     
    	_Timer = timerBegin(0, 80, true);
    	timerAttachInterrupt(_Timer, &onTrigger, true);
    	timerAlarmWrite(_Timer, 100, true);
    	timerAlarmEnable(_Timer);
     
    	delay(500);
    	Serial.println("\e[1;33mDébut\e[0m");
    }
     
    void loop()
    {
    	if (( _Val != 0xFFFFFFFFFFFFFFFF) && ( _Val != 0x0))	Serial.println("\e[1;32mVAL : C'est louche !\e[0m");
    	if ((*_Cop != 0xFFFFFFFFFFFFFFFF) && (*_Cop != 0x0))	Serial.println("\e[1;31mCOP : C'est louche !\e[0m");
    }
    Il faut attendre longtemps pour voir apparaitre les messages. Je constate que j'ai une fréquence plus importante pour le test sur _Val (x4) que sur _Cop (x1).

    Je pense que cela ne démontre pas l'utilité du volatile mais d'un problème de synchronisation des tests dans loop() vis-à-vis du déclencheur pnTrigger().
    Pour résoudre ce problème, il suffit d'installer le Mutex aussi bien dans loop() que dans onTrigger().

    Cordialement.
    Artemus24.
    @+

Discussions similaires

  1. Problème quote array PHP / SQL lettres et chiffres
    Par Irokoi dans le forum Requêtes
    Réponses: 1
    Dernier message: 18/03/2014, 09h29
  2. [SQL Serveur 2000] - Problème QUOTED-IDENTIFIER
    Par Silvia12 dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 07/06/2007, 14h17
  3. Problème quotes
    Par Anduriel dans le forum Langage
    Réponses: 6
    Dernier message: 16/11/2005, 19h04
  4. [Tableaux] problème avec while
    Par zimotep dans le forum Langage
    Réponses: 3
    Dernier message: 11/09/2005, 10h30

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