Cette instruction est-elle bloquante ?

Bonjour à toutes et à tous,

  while(!Serial.available()) {} // Ne rien faire

Comme dit dans le titre, cette instruction est-elle bloquante ?

A mon avis, oui, car à chaque renouvellement de Serial.available(), le timeOut est réinitialisé ; quelque soit sa durée (qui est supérieure son exécution).

Donc, si on ne veut pas être bloqué, il faut entourer ça d'une autre condition du type : si un certain temps est écoulé, de toute façon, on poursuit :

  t0 = micros()
  while(!Serial3.available() || micros()-t0 < 1000000) {}  // 1 seconde par exemple

Cordialement.

Pierre.

Bonjour,

Effectivement cette instruction est bloquante.
Mais pourquoi mettre un while() et non un if() ?, qui permet de ne pas être bloqué.

Pas compris !

J'aurais dû mettre le code complet :

  uint32_t t0 = micros();
  while(!Serial3.available() || micros()-t0 < 100000) {} // On attend d'avoir un retour
  if (Serial3.available()) {
... // Traitement s'il y a une donnée
  } else {
... // Traitement s'il n'y a pas de donnée
  }

La boucle while me permet d'attendre une donnée qui, je l'espère, va venir dans moins une seconde selon mon exemple.

Si elle ne vient pas, je ne veux pas resté bloqué, je passe à la suite du traitement.

Cordialement.

Pierre.

Le while ne sert à rien dans ton code

Ce que veux dire @kamill, c'est que ta boucle pourrais être remplacer par un simple IF, car on suppose que le code incomplet que tu fournis est dans la focntion loop qui est elle même dans une boucle.

Si la suite du traitement est conditionné par le fait de recevoir le message, tu mets ce traitement à l'intérieur du test if (Serial3.available()) {
Tu peux aussi vérifier que le message reçu est bien valide.

Désolé, je ne vous comprends pas.

Mon traitement est dans une boucle, mais qui ne reviendra qu'après avoir fait d'autres choses. Je vais essayer d'être bref et précis.

Je mesure l'intensité solaire avec une cellule qui suit son mouvement en élévation et en azimut. Je fais une mesure toutes les quatre minutes. Ce processus est géré par un Mega2560.

Une fois la cellule positionnée, je lance l'ordre de mesure (via une liaison série) à un Pro mini qui lui, est chargé de faire la mesure. Celle-ci peut prendre du temps, mais inférieur à 3 secondes.

J'attends donc que le pro Mini me retourne ses mesures (via la liaison série). S'il y a défaillance, donc pas de softSerial.available(), je passe à la suite au bout de trois secondes.

Cela terminé, je mets à jour mes affichages dans le Mega, j'enregistre les valeurs dans une carte SD et j'attends les 4 minutes suivantes.

Voilà le morceau de code utilisé :

void DelaiSurNouvPoint(unsigned long t) { // Placer ici les instructions qui permettent de lire les capteurs
/*  orientePanneau(true); // Orientation au Sud et à 35° en élévation
  delay(500); // stabilisation après la rotation vers le Sud
  mesurePmax(&ptEnrg[0], &ptEnrg[1]);
  mesCourbes.ptCour[0] = ptEnrg[0]; // Affichage de la tension en mode Sud*/

  orientePanneau(false); // Orientation à l'Azimut et à la hauteur du soleil
  delay(500); // stabilisation après la rotation vers l'Azimut
  mesurePmax(&ptEnrg[2], &ptEnrg[3]);
  mesCourbes.ptCour[1] = ptEnrg[2]; // Affichage de la tension en mode Azimut

  edHauteur.affiche(dtostrf(ha, 4, 1, str)); // Affichage de la Hauteur
  edAzimut.affiche(dtostrf(az, 4, 1, str)); // Affichage de l'Azimut

  tPrec = t;
  if (uint32_t(t / dTemps) % DIV_AFF == 0)
    mesCourbes.majAff(); // déclenche la mise à jour de l'affichage
  if (enrgData.appuye) { // Si un enregistrement est demandé
    maSD.ouvreFichier(nomFch.texte + ".txt", 'E'); // ouvre la carte SD en mode Ecriture
    maSD.ecrit_DT_Data(&ptEnrg[0], dimPtEnrg); // affichage et enregistrement sur la SD de la date, de l'heure et des valeurs de ptEnrg
    maSD.fermeFichier(); // termine l'enregistrement sur la carte SD
  }
}

void mesurePmax(float *vMax, float *iMax) {
  Serial3.setTimeout(1000);
  char buff[4];
  Serial3.write('M'); // Demande de mesure
  uint32_t t0 = millis();
  while(!Serial3.available() && millis()-t0 < 3000) {} // On attend d'avoir un retour ... ou pas
  if (Serial3.available()) { // si le pro mini répond
    String strVI = Serial3.readStringUntil('#'); // Lecture du retour de mesure
    Serial3.setTimeout(10);
    Serial.println(Serial3.readBytes(buff, 4)); // pour supprimer les octets qui trainent !
    *vMax = strVI.substring(1, 13).toFloat();
    *iMax = strVI.substring(15, 27).toFloat();
  }
}

Si vous voyez comment se passer de la boucle while, je suis preneur.

Cordialement.

Pierre.

Comme tu ne mets pas le programme complet, difficile de te répondre.

Je suppose que mesurePmax() est appelé dans la loop(), donc le while() est inutile puisque en cas le message non disponible, la fonction sera appelé à l’exécution suivante de la loop()

Bonjour ChPr

Je pense que l'on peut se passer de timer, simplement attendre la réception de façon "indépendante" vu que s'il y en a, c'est forcément suite à:

Donc on peut mettre dans loop() quelque chose comme ceci, en supposant que, dans le Pro mini il y a;
Serial.println(mesures);

void setup()
{
	Serial3.begin(9600);

}

void loop()
{
	if (Serial3.available())
	{
		String mesuresRx = Serial3.readStringUntil('\n');     // Réception du Pro mini terminée par Nouvelle ligne
		mesuresRx.trim();     // Nettoyage réception

		float mesures  = mesuresRx.toFloat();
		//Afficher mesures
	}
}

S'il n'y a pas de terminaison à l'émission:
Serial.print(mesures);
Il faut ajouter un timer à la réception et modifier la façon de lire Serial3:

void setup()
{
	Serial3.begin(9600);
	Serial3.setTimeout(50);

}

void loop()
{
	if (Serial3.available())
	{
		String mesuresRx = Serial3.readString();     // Réception du Pro mini
		mesuresRx.trim();     // Nettoyage réception

		float mesures  = mesuresRx.toFloat();
		//Afficher mesures
	}
}
Ainsi, pas de blocage de la `loop()` ni d'attentes inutiles.

A+
Cordialement
jpbbricole

Le programme complet est très long, fait appel à plusieurs bibliothèques dont celle que j'ai développée pour le Mega 2560 (voir le lien que j'ai donné précédemment) et n’apporterait pas grand chose.

Pa contre, mon programme ne comporte pas de fonction loop() au sens habituel. La fonction loop() de mon programme est celle-ci :

NOTA : si vous savez faire un "deux points à la ligne" sans que ça génère un émoticone :grimacing: ...

void loop() {
  scruteEvent(); // fait tourner la boutique, c'est-à-dire scrute cycliquement si chacun des composants a quelque chose à faire
}

scruteEvent(); est un fonction qui, comme dans Windows ou Linux, scrute cycliquement si chaque composant (bouton, éditeur de texte, ...) a généré un évènement. Parmi ces composants, j'ai un compteur dont je scrute la fin de comptage , 4 minutes dans le cas présent. La fonction associée est :

void DelaiSurNouvPoint(unsigned long t) { // Placer ici les instructions qui permettent de lire les capteurs

C'est dans cette fonction que je déclenche mes mesures et viens les lire. Donc, si je les rate, je dois attendre 4 minutes pour les reprendre, mais alors, ces mesures ne correspondront plus à la position solaire précédente.

Voilà, je ne sais pas comment expliquer cela différemment. Ma seule loop() interne est le while(!Serial3.available() && millis()-t0 < 3000) que je suspends si l'attente est trop longue.

Cordialement.

Pierre.

jpbbricole : voir la réponse que j'ai faite à kamill.

Cordialement.

Pierre.

Je ne vois pas bien l'intérêt de scruteEvent(). Il suffisait de mettre ce qu'il y a dans scruteEvent() directement dans loop. Ca ne change rien au fait que le while ne sert à rien si mesurePmax() est appelé cycliquement

Si tu ne veux pas que les codes soient interprétés, il faut les encadrer avec des apostrophes inversées ``
Par exemple :) n'est pas interprété en :slight_smile:

Voici ce qu'il y a dans scruteEvent() :

void scruteEvent() { // scrutation d'évènements
  if (myTouch.dataAvailable()) {
    myTouch.read();
    dureeInactif = millis();
    compCour = compDeb;
    for (int i = 0; i < nbComp; i++) { // boucle qui permet de voir si un composant visuel a été appuyé
      compCour->ptrB->select(myTouch.getX(), myTouch.getY());
      compCour = compCour->suiv;
    }
  }
  courTemps = debTemps; // Voir biblioth�que BaseTemps
  for (int i = 0; i < indTemps; i++) { // boucle qui permet de voir si un composant temps a été activé
    courTemps->ptrT->select(millis());
    courTemps = courTemps->suiv;
  }
  compCour = compDeb;
  for (int i = 0; i < nbComp; i++) { // boucle qui permet de voir si il y a un composant ayant le tag = 0xF0 (composant infoDH par exemple)
    if (compCour->ptrB->tag == 0xF0) {
      compCour->ptrB->select(0, 0);
    }
    compCour = compCour->suiv;
  }
}

Je ne vois pas ce que ça apporterait. De toute façon, ce sont des variables privées de ma bibliothèque.

Tu dis :

"Ca ne change rien au fait que le while ne sert à rien si mesurePmax() est appelé cycliquement"

Mais justement, lors d'une mesure, cette fonction n'est pas appelée cycliquement. Elle ne l'est que toutes les 4 minutes.

Par ailleurs, aux essais pratiques,

  • Sans la boucle while() : je ne recueille pas les mesures ;
  • Avec la boucle while() : je recueille les mesures.

Cordialement.

Pierre.

Il suffit d'ajouter un espace après les deux points

Merci lesept :slightly_smiling_face:

Cordialement.

Pierre.

On peut aussi faire esc pour fermer le dialogue et faire le saut de ligne.

Une p'tite image

Cordialement.

Pierre.

J'ai du mal à comprendre ce que tu veux faire.
Si cela ne te dérrange pas de bloquer ton programme pour receptionner ton message, utilise ton while bloquant.
Si ce n'est pas ce que tu veux faire, c'est à dire que tu as besoin de faire des choses pendant l'attente de réception du message, il ne faut pas utiliser de while ou autre chose de bloquant, pour l'attente du message.

@ terwal :

J'ai du mal à comprendre ce que tu veux faire.

C'est pourtant simple : j'oriente ma cellule face au soleil, je fais une mesure de son intensité, j'attends d'avoir ce résultat pour le visualiser et l'enregistrer. J'attends 4 minutes et je reprends la manip à la nouvelle position solaire.

Si cela ne te dérange pas de bloquer ton programme pour réceptionner ton message, utilise ton (ce n'est pas le mien :wink:) while bloquant.

C'est exactement ce que je fais. A priori, je n'ai rien d'autre à faire donc le while bloquant ne me gène pas ... Encore que ...

Si ce n'est pas ce que tu veux faire, c'est à dire que tu as besoin de faire des choses pendant l'attente de réception du message, il ne faut pas utiliser de while ou autre chose de bloquant, pour l'attente du message.

Pendant que la mesure se fait (et aussi pendant de le panneau s'oriente), je pourrais avoir envie de modifier une valeur dans un éditeur ou cliquer sur un bouton. Du coup, j'ai rajouté un scruteEvent() à l'intérieur de la boucle while.

  while(!Serial3.available() && millis()-t0 < 10000) {
      scruteEvent('V'); // scrute seulement les composants visuels.
  } // On attend d'avoir un retour ... ou pas

et dans la boucle d'orientation de la cellule. J'ai bien accès à mes composants. Mais dans mon scruteEvent(), il y a aussi des composants temporels et la scrutation de ces derniers fiche la pagaille.

J'ai donc modifié cette fonction - qui passe de scruteEvent() à
scruteEvent(char cas) - pour que dans ces cas supplémentaires, elle ne scrute que les composants visuels ... et ça fonctionne :slightly_smiling_face:

Ben voilà, suffisait de me dire que j'aurais pu avoir autre chose à faire ! Dans le cas présent, ce n'est pas franchement utile, mais cela pourrait l'être dans d'autres applications.

Cordialement.

Pierre.

Surement pour toi, désolé d'être plus lent que toi :slight_smile:
Non ce n'est pas simple, puisque à priori l'instruction fait ce que tu veux mais que tu écris

Après sans vouloir t'offenser, c'est toujours difficile d'aider des personnes qui refuse de présenter tout leur code, car elle estime ce qui est important ou pas :frowning:
Par exemple tu avais écris ceci :

Alors que maintenant c'est :

C'est donc de notre faute! :slight_smile:
Pourtant @kamill t'a poser la question de l'utilité en #2
On ne t'a pas dis ça directement, simplement car on ne sait pas ce que tu fais dans le code que tu n'a pas montré.
Et surtout que tu peux très bien te passer du while en remplaçant avec un if, et utiliser la boucle du loop.

Après le IF à aussi l'avantage en plus de te permettre le jour ou tu en as besoin, de faire d'autre chose en même temps que tu attends.

Les deux code partiels suivant sont équivalents, si je n'ai pas fait d'erreur de frappe :slight_smile: :

void loop() {
  while(!Serial3.available() && millis()-t0 < 10000) {
    scruteEvent('V'); // scrute seulement les composants visuels.
  } // On attend d'avoir un retour ... ou pas
}

void loop() {
  if (!Serial3.available() && millis()-t0 < 10000) {
    scruteEvent('V'); // scrute seulement les composants visuels.
  } else {
    // On attend d'avoir un retour ... ou pas
  }
}