Arduino Forum

International => Français => Tutoriels et cours => Topic started by: nico78 on Jul 29, 2019, 06:00 pm

Title: Port Série et chaîne de caractères UTF8
Post by: nico78 on Jul 29, 2019, 06:00 pm
A la lecture du sujet "Ecouter le Port Série ou un keypad (applicable à 1 flux de données asynchrone)" de J-M-L à cette adresse:
https://forum.arduino.cc/index.php?topic=500683.0 (https://forum.arduino.cc/index.php?topic=500683.0)

Je me suis dit que ça serait pas mal de faire la même chose avec une chaîne de texte UTF8, à savoir, séparer chaque caractère de la chaîne et montrer sa valeur avec tous les octets (de 1 à 4 octets par caractère en UTF8 compatible ASCII).

Code: [Select]
Par exemple, en tapant>un vélo à 120€, on obtient:

Fin de chaine détecté!
Octet lu: 0x75  u
Octet lu: 0x6E  n
Octet lu: 0x20  
Octet lu: 0x76  v
Octet lu: 0xC3  0xA9  é
Octet lu: 0x6C  l
Octet lu: 0x6F  o
Octet lu: 0x20  
Octet lu: 0xC3  0xA0  à
Octet lu: 0x20  
Octet lu: 0x31  1
Octet lu: 0x32  2
Octet lu: 0x30  0
Octet lu: 0xE2  0x82  0xAC  €
Nombre d'octets: 18
Nombre de caractères: 14
Phrase: [un vélo à 120€]


Voici le code:
Code: [Select]

// Pour le test, veuillez paramétrer le Moniteur série avec le 'Retour chariot' seulement et la vitesse à 115200 bauds

// ---------------------------------------------------------------------------------------------------------------------
// Nico78 > ajout d'une portion de code permettant de décoder les chaînes UTF8 sur le port série
// en séparant les caractères et en les affichant avec la valeur des octets correspondants en hexa
// ceci est une extension du code original de J-M-L qui fait suite
// au sujet: "Ecouter le Port Série ou un keypad (applicable à 1 flux de données asynchrone)"
// à cette adresse: https://forum.arduino.cc/index.php?topic=500683.0
// que je recommande pour comprendre et appréhender l'envoie de données sur le port série et le keypad
// ---------------------------------------------------------------------------------------------------------------------
// Pour info: le moniteur série affiche les caractères UTF8 depuis la version 1.8.2
// ---------------------------------------------------------------------------------------------------------------------

const byte tailleMessageMax = 254; // comprendre en octets et non en nombre de caractères avec des chaînes de texte UTF8
char message[tailleMessageMax + 1]; // +1 car on doit avoir un caractère de fin de chaîne en C, le '\0'
int nb_octets=0, nb_caracteres=0;

// ici le marquer de fin, un retour chariot, doit tenir sur un seul octet, donc doit être un caratère imprimable ou pas ascii!
const char marqueurDeFin = '\r';

boolean ecouter()
{
  static byte indexMessage = 0; // static pour se souvenir de cette variable entre 2 appels consécutifs. initialisée qu'une seule fois.
  boolean messageEnCours = true;

  while (Serial.available() && messageEnCours) {
    int c = Serial.read();
    if (c != -1) {
      switch (c) {
        case marqueurDeFin:
          Serial.println(F("Fin de chaine détecté!"));
          message[indexMessage] = '\0'; // on termine la c-string
          indexMessage = 0; // on se remet au début pour la prochaine fois
          messageEnCours = false;
          break;
        default:
          if (indexMessage < tailleMessageMax+1) message[indexMessage++] = (char) c; // on stocke le caractère et on passe à la case suivante
          else Serial.println(F("j'ignore!"));
          break;
      }
    }
  }
  return messageEnCours;
}

boolean decodeUTF8(char message[]){
    char utf8_char[4];
    byte ret, c, indice, align;
    int nb_utf8_char=0;
    
    nb_octets=0; nb_caracteres=0;
    nb_octets = strlen(message);

    for (int i=0; i<nb_octets; i++){
        align=0; ret=0;
        c = message[i];
        if (c>0 && c<128){
          // le caractère sera sur 1 octet
          align=1;
        }else if (c>191 && c<224){
          // le caractère sera sur 2 octets
          align=2;
        }else if (c>223 && c<240){
          // le caractère sera sur 3 octets
          align=3;
        }else if (c>239 && c<248){
          // le caractère sera sur 4 octets
          align=4;
        }
        
        if (align>0){
            indice = i;
            i=i+align-1;
            // test des octets qui suivent composant le caractère UTF8
            if (align>1){
                if (nb_octets+1>indice+align){
                    for (int j=indice+1; j<indice+align; j++){
                        c = message[j];
                        if (c>127 && c<192){ // les octets qui suivent doivent être compris entre 128 et 191 sinon erreur
                            ret=1;
                        }
                    }
                }
            }else{
                ret=1;
            }
        
            if (ret==1){  
              nb_caracteres+=1;
              memcpy(utf8_char, message + indice, align);
              utf8_char[align]='\0'; nb_utf8_char = strlen(utf8_char);
              // ---------------------------------------------------------------------------------------
              // code pour afficher la représentation en octet des caractères UTF8, peut être supprimé
              Serial.print(F("Octet lu: "));
              for (int k=0; k<nb_utf8_char; k++){
                Serial.print(F("0x")); Serial.print((byte) utf8_char[k], HEX); Serial.print("  ");
              }
              Serial.println(utf8_char);
              // ---------------------------------------------------------------------------------------
             }
        }        
        if (ret==0){
            message[0]='\0'; nb_octets=0; nb_caracteres=0;
            Serial.println("Erreur1");
            return false;
        }
    }
    return true;
}

void setup() {
  Serial.begin(115200);
}

void loop() {
  if (! ecouter()) {
    // on a reçu le marqueur de fin
    // traitement de la chaine reconnue comme UTF8, fonctionnera aussi avec de l'ASCII
    if (decodeUTF8(message)){
      Serial.print("Nombre d'octets: "); Serial.println(nb_octets);    
      Serial.print("Nombre de caractères: "); Serial.println(nb_caracteres);  
      Serial.print(F("Phrase: [")); Serial.print(message); Serial.println(F("]"));Serial.println("");
    }else{
      Serial.println("Chaîne de caractères non conforme"); Serial.println();
    }
  }
  // ici on peut faire autre chose
}
Title: Re: Port Série et chaîne de caractères UTF8
Post by: J-M-L on Aug 17, 2019, 03:02 pm
Merci - extension sympa pour voir comment on décode de l'UTF8

(comprendre ce type d'encodage peut servir aussi pour les SMS)
Title: Re: Port Série et chaîne de caractères UTF8
Post by: nico78 on Aug 17, 2019, 08:46 pm
Merci :)

Vous avez vu juste pour les sms, il faudra que je fasse un test à l'occasion.