Go Down

Topic: Port Série et chaîne de caractères UTF8 (Read 288 times) previous topic - next topic

nico78

Jul 29, 2019, 06:00 pm Last Edit: Jul 29, 2019, 06:02 pm by nico78
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

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
}

J-M-L

Merci - extension sympa pour voir comment on décode de l'UTF8

(comprendre ce type d'encodage peut servir aussi pour les SMS)
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

nico78

Merci :)

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

Go Up