Moniteur série -> Variable

Bonjour,

Je travaille sur un programme permettant de controler la position de moteurs à courant continu.
Mon objectif est de pouvoir entrer sur le moniteur série le positon ciblée, par exemple 2,25 tours.
Cette entrée sera ensuite assignée à une variable “target_tour” utilisée dans la suite du programme.

Actuellement, j’utilise le programme suivant qui me permet seulement d’entrer un entier comme position :

void MONITEUR(){
       
if (Serial.available()) {// teste s'il reste des données en attente
    String reception = "";
    while (Serial.available()) { //tant que des données sont en attente
      char c = Serial.read(); // lecture
      reception += String(c); //on ajoute à l'objet reception
      delay(10); //petite attente
    }
    reception.trim(); //on enlève le superflu en début et fin de chaîne
    reception = reception.substring(0, 1); // ne prend que le caractère 0
    Serial.print ("> Etat : ");
    //boucle de test par caractère
    for (int c = 0; c < 1; c++) {
      switch (reception.charAt(c)) {

        /************* COMMANDE M1 ***************/
        case '1': {
          Serial.print("\tM1  1 TOUR");
          target_tour_M1 = 1-POS_M1; // Nombre de tour(s) a effectué pour arriver à l'objectif = Objectif - Position actuelle
          }
          break;
        case '2': {
          Serial.print("\tM1  2 TOURS");
          target_tour_M1 = 2-POS_M1; 
          }
          break;
        case '3': {
          Serial.print("\tM1  3 TOURS");
          target_tour_M1 = 3-POS_M1; 
          }
          break;
        case '4': {
          Serial.print("\tM1  4 TOURS");
          target_tour_M1 = 4-POS_M1;
          }
          break;
        case '5': {
          Serial.print("\tM1  5 TOURS");
          target_tour_M1 = 5-POS_M1;
          }
          break;
          case '6': {
          Serial.print("\tM1  6 TOURS");
          target_tour_M1 = 6-POS_M1;
          }
          break;
        case '0': {
          Serial.print("\tM1 0 TOUR");
          target_tour_M1 = 0-POS_M1;
          }
          break;

Il permet de comparer l’entrée et d’affecter une valeur à target_tour après comparaison.

Est-il possible d’assigner directement l’entrée à une variable ? Sans comparaisons de tous les caractères ?

Bonjour,

Il suffit de convertir en flottant avec atof

void MONITEUR() {
  if (Serial.available())
  { // teste s'il reste des données en attente
    String reception = Serial.readString();
    float tour = atof(reception.c_str());
    Serial.print("M1 "); Serial.print(tour); Serial.println(tour);
    float target_tour = tour - pos_m1;
  }
}

Remarque: il vaudrait mieux ne pas utiliser de String mais des string C++ (char)

Merci beaucoup cela semble fonctionner !

Quel est l'intêret d'utiliser char plutot que String ?

String fait des allocations dynamique de mémoire.
Sur les processeurs avec peu de mémoire comme les avr on peut arriver a avoir une mémoire complètement morcelée ce qui peut conduire à un manque dé mémoire au bout d'un certain temps de fonctionnement du programme.

Merci pour ton aide.

J’ai essayé de programmer la fonction en char plutot qu’en string.

char reception[4];
float pos_m1 = 1.55;

void MONITEUR() {
    if (Serial.available()) {// teste s'il reste des données en attente
       for (int p=0;p<4;p++){ //on en lit 4
          char c=Serial.read(); // lecture
          reception[p]=c; //écriture dans le tableau
        }
        float tour = atof(reception);
        float target_tour = tour - pos_m1;
        Serial.println("M1 : "); 
        Serial.println(tour); 
        Serial.println(target_tour);
      }     
}

Malheureusement le résultat est le suivant si j’écris 1.23 :

M1 : 
1.00
-0.55
M1 : 
0.00
-1.55
M1 : 
2.00
0.45
M1 : 
3.00
1.45

Mon programme réalise le calcul pour chaque caractère au lieu de me renvoyer tour = 1.23

Peut être un problème avec la boucle for ?

Le problème est que ta boucle for est plus rapide que la réception des caractères, donc tu sors quand p vaut 4, mais tu n'as lu effectivement qu'un caractères (read n'attend pas).
Utilises readBytes pour lire sur la liaison

char reception[20];
float pos_m1 = 1.55;

void MONITEUR() {
  if (Serial.available()) {// teste s'il reste des données en attente
    int n = Serial.readBytes(reception, 4);
    reception[n] = 0;    // marque la fin de la chaine
    float tour = atof(reception);
    float target_tour = tour - pos_m1;
    Serial.print("M1 : ");
    Serial.print(tour);
    Serial.print(" , ");
    Serial.println(target_tour);
  }
}

Merci, ton programme fonctionne très bien.
Dernière question, j'aimerai que la fonction ne prenne en compte que les 4 premiers caractères, et ne fasse rien du reste.

Actuellement, si j'entre par exemple 1.235, j'obtient tour = 1.23 puis tour = 5.00.

Est-il possible de n'obtenir que tour = 1.23 ?

Cela permettrait d'éviter certaines erreurs dues à une donnée d'entrée de longueur trop élevée.

oui
Il suffit d'attendre plus de caractères

   int n = Serial.readBytes(reception, sizeof reception-1);

Tu as vu que j'ai mis la taille de réception à 20 caractères (tu peux réduire à 10)

On va sortir du readBytes à l'échéance d'un timeout

D'origine le timeout est de 1000 ms, mais tu peux le réduire à 50ms (voir 20ms) en mettant:
Serial.setTimeout(50); dans le setup.

Le programme fonctionne très bien, je te remercie pour ta précieuse aide @kamill.

Content de t'avoir aidé.