Comportement bizarre avec Serial

Bonjour à toutes et à tous,

Après quelques mois d'absence en programmation Arduino, je me trouve confronté à un problème que je ne m'explique pas.

Avec le sketch suivant :

int16_t pitch = 20, roll = 30;
String str = "";

void setup()
{
  Serial.begin(38400);
  Serial.setTimeout(100);
}

void loop() {
  if (Serial.available()) {
    str = Serial.readStringUntil('\n');
    if (str[1] = 'r') {
      Serial.println(str[1]);
      Serial.println(str);
      Serial.println(str.substring(2));
      Serial.println(roll);
      roll = str.substring(2).toInt();
    }
    if (str[1] = 'p') {
      Serial.println(str[1]);
      Serial.println(str);
      Serial.println(str.substring(2));
      Serial.println(pitch);
      pitch = str.substring(2).toInt();
    }
  }
}

J'obtiens le résultat suivant si au clavier j'entre r20

09:26:48.502 -> r
09:26:48.502 -> rr0
09:26:48.502 -> 0
09:26:48.502 -> 30
09:26:48.502 -> p
09:26:48.502 -> rp0
09:26:48.502 -> 0
09:26:48.502 -> 20

J'ai essayé avec un pro mini un Mega 2560 ; sous Windows et sous Ubuntu : même résultat.

J'ai essayé avec d'autres valeurs au clavier, je me retrouve toujours avec des r et des p dans le résultat.

Je me doute que l'erreur est grossière, mais je n'arrive pas a mettre la main dessus.

Merci de votre aide.

Pierre.

Bonjour,

Normal, str[1] n'est pas testé mais affecté avec 'r' et 'p' ;-)
Modifier le code avec l'opérateur == à la place de l'opérateur d'affectation =

if (str[1] == 'r')
...
if (str[1] == 'p')

A suivre...

il faut utiliser ==

oops - même message que @claudius01

Merci claudius01, je viens juste de m'apercevoir de cette erreur qui est due ... à 6 mois de programmation en Pascal ou le test se fait par un signe = et non pas un == comme cela doit être fait en c.

Je savais que l'erreur était énorme :slightly_frowning_face:

Cordialement.

Pierre.

il faut aussi se souvenir que les indices commencent à 0

int16_t pitch = 20, roll = 30;
String str = "";

void setup()
{
  Serial.begin(115200);
  Serial.setTimeout(100);
  Serial.println("prêt");
}

void loop() {
  if (Serial.available()) {
    str = Serial.readStringUntil('\n');
    switch (str[0]) {
      case 'r':
        roll = str.substring(1).toInt();
        Serial.print("Nouveau roll = ");
        Serial.println(roll);
        break;

      case 'p':
        pitch = str.substring(1).toInt();
        Serial.print("Nouveau pitch = ");
        Serial.println(pitch);
        break;

      default:
        Serial.println("commande inconnue "); Serial.println(str);
        break;
    }
  }
}

et si vous voulez détecter une entrée illégale il ne faut pas utiliser toInt() qui va vous dire 0 sans moyen de savoir si c'était vraiment 0 ou si c'était une entrée erronée

int16_t pitch = 20, roll = 30;
String str = "";

void setup()
{
  Serial.begin(115200);
  Serial.setTimeout(100);
  Serial.println("prêt");
}

void loop() {
  if (Serial.available()) {
    str = Serial.readStringUntil('\n');
    char cmd = str[0];
    char* endPtr;
    long value = strtol(str.c_str() + 1, &endPtr, 10);

    if (endPtr == str.c_str() + 1) {
      Serial.print("Erreur : valeur non valide pour la commande ");
      Serial.println(str);
      return;
    }

    switch (cmd) {
      case 'r':
        roll = value;
        Serial.print("Nouveau roll = ");
        Serial.println(roll);
        break;

      case 'p':
        pitch = value;
        Serial.print("Nouveau pitch = ");
        Serial.println(pitch);
        break;

      default:
        Serial.print("Commande inconnue ");
        Serial.println(str);
        break;
    }
  }
}

vous pourriez aussi rajouter un test sur value si elle sort des valeurs admissibles dans le switch/case

Si vous voulez pouvoir taper la commande en minuscule ou majuscule faites

switch (tolower(cmd)) { // on met la commande en minuscule
  ...

PS: notez que Serial.readStringUntil() est bloquant jusqu'à la fin de la réception de la commande donc à 38400 la réception de 5 caractères prendra 1.3ms - ça parait peu mais ça dépend de ce que le reste du code fait ou doit faire.

en passant comme dans mon exemple le terminal à 115200 bauds, on attend moins longtemps (0.4ms)

si vous voulez faire du totalement non bloquant il ne faut pas utiliser Serial.readStringUntil

Merci J-M-L pour ces compléments d'information.

Cordialement.

Pierre.