IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Arduino Discussion :

Problème de format de variable avec erreur de comparaison


Sujet :

Arduino

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    pompier
    Inscrit en
    Janvier 2020
    Messages
    76
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Eure et Loir (Centre)

    Informations professionnelles :
    Activité : pompier

    Informations forums :
    Inscription : Janvier 2020
    Messages : 76
    Points : 36
    Points
    36
    Par défaut Problème de format de variable avec erreur de comparaison
    Bonjour,

    je viens de programmer un code de type "password".

    le programme choisi de façon aléatoire un numéro d'enregistrement, le joueur doit saisir un code.Red
    Pas de souci pour la saisie, sauf qu'au niveau de la comparaison, problème. J'ai bien le code_tapé mais celui-ci est sui de r et un carré.
    Je suppose que cela est dû au choix de la variable, mais je ne sais pas comment le résoudre char* password vs char code_tape

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
     
    //initialisation du clavier
    #include <Keypad.h> //include keypad library - first you must install library (library link in the video description)
     
    //initialisation du LCD I2C
    #include <Wire.h>
    #include <LiquidCrystal_I2C.h>
     
    LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display
     
     
    #define redLED 10 //define the LED pins
    #define blueLED 11
     
    char* password ;
    int i;
     
    const byte rows = 4; //number of the keypad's rows and columns
    const byte cols = 4;
     
    char keyMap [rows] [cols] = { //define the cymbols on the buttons of the keypad
     
      {'1', '2', '3', 'A'},
      {'4', '5', '6', 'B'},
      {'7', '8', '9', 'C'},
      {'*', '0', '#', 'D'}
    };
     
    byte rowPins [rows] = {13, 12, 11, 10}; //pins of the keypad
    byte colPins [cols] = {9, 8, 7, 6};
     
    Keypad myKeypad = Keypad( makeKeymap(keyMap), rowPins, colPins, rows, cols);
     
    // On définit le type crypto
    struct t_crypto {
      const char* ID;
      const char* Red;
      const char* Blue;
    };
     
    t_crypto Code[] = {
      {"A1C2", "8AA4", "7C9A" },
      {"C312", "651A", "8A52"},
      {"AA98", "74A1", "8C8A"},
      {"7A54", "A35C", "55C2"},
      {"3A3C", "3A3C", "01A5"},
      {"3C5A", "AAAA", "80C4"},
      {"648C", "CC1C", "92C1"},
      {"9761", "C7A4", "3333"}
    };
     
    void choisirCarteAleatoire()
    {
      long carteCrypto = random(0, 8);
     
      Serial.println(carteCrypto);
      Serial.println(F("Crypto carte: "));
      Serial.println(Code[carteCrypto].ID);
      Serial.println(Code[carteCrypto].Red);
      Serial.println(Code[carteCrypto].Blue);
      password = Code[carteCrypto].Red;
    Serial.print(password);
    }
    void   setup () {
      Serial.begin(115200);
      // Pour activer l'état HOLD
      unsigned int time_hold = 4;
     
      //Ecran
      lcd.init();
      // Print a message to the LCD.
      lcd.backlight();
      pinMode(redLED, OUTPUT);  //set the LED as an output
      pinMode(blueLED, OUTPUT);
      randomSeed(analogRead(A0)); // génération d'un peu d'aléatoire
      choisirCarteAleatoire();
    }
     
    void loop () {
     
      int taille_code = 4;
      char code_secret[taille_code] = {password}; //tableau contenant code
      char code_tape[taille_code] = {0};          //tableau contenant la saie
     
      for ( i = 0 ;  i < taille_code;  ) {
        char whichKey = myKeypad.getKey(); //define which key is pressed with getKey
        if (whichKey) {
          code_tape[i] = whichKey;
          Serial.print("*");
          Serial.println(code_tape[i]);
          i++;
        }
        if (i == 4) {
          Serial.println(code_tape);
          Serial.println(password);
          if (code_tape == password) {
            Serial.print("accès accordé");
          } else {
            Serial.print("code erreur");
          }
        }
      }
     
    }

  2. #2
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 711
    Points : 5 390
    Points
    5 390
    Par défaut
    Pour comparer deux cStings il faut qu’elles soient d’une part bien formées, c’est à dire un tableau de caractères se terminant pas un ‘\0’ et ensuite on ne peut pas faire == pour tester l’égalité il faut utiliser la fonction strcmp()

    On peut aussi comparer caractère par caractère, dans ce cas pas besoin du caractère NULL de fin de chaîne et on fait une boucle for sur le nombre de caractères à comparer deux à deux. La fonction memcmp() permet aussi de faire ça d’un coup

    Donc dans votre cas les chaînes définies entre guillemets sont des cString correctes mais pas celle que vous bâtissez avec la saisie au keypad.
    Il faut que code_tape est une case mémoire de plus dans laquelle vous métriez le caractère nul et ensuite vous pourriez faire un strcmp() avec passwd

    Sinon un memcmp() sur 4 octets va fonctionner

  3. #3
    Nouveau membre du Club
    Homme Profil pro
    pompier
    Inscrit en
    Janvier 2020
    Messages
    76
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Eure et Loir (Centre)

    Informations professionnelles :
    Activité : pompier

    Informations forums :
    Inscription : Janvier 2020
    Messages : 76
    Points : 36
    Points
    36
    Par défaut
    Moi qui croyais être plutôt bien…

    Citation Envoyé par Jay M Voir le message
    c’est à dire un tableau de caractères se terminant pas un ‘\0’
    Comme ça???
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    char code_tape[taille_code] = {'\0'};
    Après ce que je ne comprends pas c'est ça
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    char* code_secret[taille_code] = {password}; //tableau contenant code
    au final, ça me fait un code_secret[]={'pswd','','',''}
    du coup, je ne peux pas contrôler
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    for(i=0; i<taille_code; ){
    if(code_tape[i] != code_secret[i]){
    Serial.print("code faux")
    }else{
    Serial.Print("code ok");
    }
    }
    Faut-il que je découpe password pour injecter dans code_secret[taille_code]?
    Quelle fonction?

    Merci

  4. #4
    Nouveau membre du Club
    Homme Profil pro
    pompier
    Inscrit en
    Janvier 2020
    Messages
    76
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Eure et Loir (Centre)

    Informations professionnelles :
    Activité : pompier

    Informations forums :
    Inscription : Janvier 2020
    Messages : 76
    Points : 36
    Points
    36
    Par défaut
    après avoir fouillé le net et sur les conseil de JayM, j'ai un code qui fonctionne.

    Je ne sais pas si c'est propre ou bidouille mais ça fonctionne.
    Même si sur l'ecran série, il y a toujours un espèce de zibouiboui après l'affichage du code_tape

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
     
    //initialisation du clavier
    #include <Keypad.h> //include keypad library - first you must install library (library link in the video description)
     
    //initialisation du LCD I2C
    #include <Wire.h>
    #include <LiquidCrystal_I2C.h>
     
    LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display
     
     
    #define redLED 10 //define the LED pins
    #define blueLED 11
     
    String password ;
    int i;
    int taille_code = 4;
    char code_secret[] = {0}; //tableau contenant code
     
     
    const byte rows = 4; //number of the keypad's rows and columns
    const byte cols = 4;
     
    char keyMap [rows] [cols] = { //define the cymbols on the buttons of the keypad
     
      {'1', '2', '3', 'A'},
      {'4', '5', '6', 'B'},
      {'7', '8', '9', 'C'},
      {'*', '0', '#', 'D'}
    };
     
    byte rowPins [rows] = {13, 12, 11, 10}; //pins of the keypad
    byte colPins [cols] = {9, 8, 7, 6};
     
    Keypad myKeypad = Keypad( makeKeymap(keyMap), rowPins, colPins, rows, cols);
     
    // On définit le type crypto
    struct t_crypto {
      const char* ID;
      const char* Red;
      const char* Blue;
    };
     
    t_crypto Code[] = {
      {"A1C2", "8AA4", "7C9A" },
      {"C312", "651A", "8A52"},
      {"AA98", "74A1", "8C8A"},
      {"7A54", "A35C", "55C2"},
      {"3A3C", "3A3C", "01A5"},
      {"3C5A", "AAAA", "80C4"},
      {"648C", "CC1C", "92C1"},
      {"9761", "C7A4", "3333"}
    };
     
    void choisirCarteAleatoire()
    {
      long carteCrypto = random(0, 8);
     
      Serial.println(carteCrypto);
      Serial.println(F("Crypto carte: "));
      Serial.println(Code[carteCrypto].ID);
      Serial.println(Code[carteCrypto].Red);
      Serial.println(Code[carteCrypto].Blue);
      password = Code[carteCrypto].Red;
     
      code_secret[0] = (password.charAt(0));  //on prend le énième caractère de password et on le met dans code_secret à la même position
      code_secret[1] = (password.charAt(1));
      code_secret[2] = (password.charAt(2));
      code_secret[3] = (password.charAt(3));
      /*Serial.println(code_secret[0]);   
        Serial.println(code_secret[1]);
        Serial.println(code_secret[2]);
        Serial.println(code_secret[3]);*/
    }
    void   setup () {
      Serial.begin(115200);
      // Pour activer l'état HOLD
      unsigned int time_hold = 4;
      //anti rebond à calibrer
      //setDebounceTime(unsigned int time)
     
      //Ecran
      lcd.init();
      // Print a message to the LCD.
      lcd.backlight();
      pinMode(redLED, OUTPUT);  //set the LED as an output
      pinMode(blueLED, OUTPUT);
      randomSeed(analogRead(A0)); // génération d'un peu d'aléatoire
      choisirCarteAleatoire();
    }
     
    void loop () {
     
      //int taille_code = 4;
      char code_tape[taille_code] = {0};          //tableau contenant la saisie
     
      for ( i = 0 ;  i < taille_code;  ) {
        char whichKey = myKeypad.getKey(); //define which key is pressed with getKey
        if (whichKey) {
          code_tape[i] = whichKey;
          Serial.print("*");
          /*Serial.println(code_tape);
            Serial.print("CS");
            Serial.println(code_secret);*/
          i++;
        }
        if (i == 4) {
          for (i = 0; i < taille_code; ) {          //on regarde si les 2 tableaux sont différents ou pas
            if (code_tape[i] != code_secret[i]) {
              Serial.print("code faux");
              break;
            } else {
              Serial.print("code ok");
              break;
            }
          }
        }
      }
     
    }

  5. #5
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 711
    Points : 5 390
    Points
    5 390
    Par défaut
    salut

    ça ce n'est pas bon
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    char code_secret[] = {0}; //tableau contenant code
    vous créez un tableau qui n'a qu'une seule case et plus tard vous essayez de stocker 4 trucs dedans...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
      code_secret[0] = (password.charAt(0));  //on prend le énième caractère de password et on le met dans code_secret à la même position
      code_secret[1] = (password.charAt(1));
      code_secret[2] = (password.charAt(2));
      code_secret[3] = (password.charAt(3));
    vous étiez bien parti avec des const char*, ce n'est pas la peine d'introduire la classe String.

    un indice de boucle n'a JAMAIS besoin d'être une variable globale, enlevez et déclarez le soit juste dans la boucle, soit locale à la fonction si vous avez besoin de sa valeur en sortie de boucle.

    voici un code nettoyé à tester - j'ai enlevé le LCD pour se concentrer sur le fonctionnement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
     
    //initialisation du clavier
    #include <Keypad.h> //include keypad library - first you must install library (library link in the video description)
    const uint8_t rows = 4; //number of the keypad's rows and columns
    const uint8_t cols = 4;
     
    char keyMap [rows] [cols] = { //define the cymbols on the buttons of the keypad
      {'1', '2', '3', 'A'},
      {'4', '5', '6', 'B'},
      {'7', '8', '9', 'C'},
      {'*', '0', '#', 'D'}
    };
     
    uint8_t rowPins [rows] = {13, 12, 11, 10}; //pins of the keypad
    uint8_t colPins [cols] = {9, 8, 7, 6};
    Keypad myKeypad = Keypad( makeKeymap(keyMap), rowPins, colPins, rows, cols);
     
     
    //definition des pins
    const uint8_t redLEDPin  = 10;
    const uint8_t blueLEDPin = 11;
     
    // On définit le type crypto
    struct t_crypto {
      const char* ID;
      const char* Red;
      const char* Blue;
    };
     
    t_crypto Code[] = {
      {"A1C2", "8AA4", "7C9A"},
      {"C312", "651A", "8A52"},
      {"AA98", "74A1", "8C8A"},
      {"7A54", "A35C", "55C2"},
      {"3A3C", "3A3C", "01A5"},
      {"3C5A", "AAAA", "80C4"},
      {"648C", "CC1C", "92C1"},
      {"9761", "C7A4", "3333"}
    };
    const uint8_t nbCodes = sizeof(Code) / sizeof(Code[0]);
     
    const char* password ;
    int passwordLength;
     
    void choisirCodeAleatoire()
    {
      long carteCrypto = random(0, nbCodes);
     
      Serial.print(F("Crypto carte: "));  
      Serial.println(carteCrypto);
      Serial.println(Code[carteCrypto].ID);
      Serial.println(Code[carteCrypto].Red);
      Serial.println(Code[carteCrypto].Blue);
     
      password = Code[carteCrypto].Red;
      passwordLength = strlen(password);
      Serial.println(F("Tapez le code"));
    }
     
     
    void   setup ()
    {
      Serial.begin(115200);
      pinMode(redLEDPin, OUTPUT);  //set the LED as an output
      pinMode(blueLEDPin, OUTPUT);
      randomSeed(analogRead(A0)); // génération d'un peu d'aléatoire
      choisirCodeAleatoire();
    }
     
    void loop ()
    {
      char code_tape[passwordLength + 1] = {'\0'}; //tableau contenant la saisie, +1 pour un caractère NULL de fin de chaîne avec initialisation vide
      uint8_t indice = 0;
     
      while (indice < passwordLength) {
        char whichKey = myKeypad.getKey(); //define which key is pressed with getKey
        if (whichKey != NO_KEY) {
          code_tape[indice] = whichKey;
          Serial.print("*");
          indice++;
        }
      }
      code_tape[passwordLength] = '\0'; // pour faire une cString bien formée (superflu car intialisé déjà avec des '\0', donc plus à titre de bonne pratique)
     
      if (strcmp(code_tape, password) == 0) { // on peut utilsier strcmp() car les deux paramètres sont des cStrings bien formées
        Serial.println(F("\ncode OK\n"));
        choisirCodeAleatoire(); // on relance un jeu
      } else {
        Serial.println(F("\ncode Faux"));
      }
    }
    J'ai tapé ça ici depuis votre code, et j'ai rajouté le fait que si vous trouvez le code ça relance un nouveau jeu.


    Vous dites:
    Même si sur l'ecran série, il y a toujours un espèce de zibouiboui après l'affichage du code_tape
    ça c'est lié au fait que vous n'avez pas une vraie cString. En C ou C++ une chaîne, c'est un tableau de caractères qui se termine par le caractère nul, noté '\0'. C'est ce qui dit aux fonctions comme print() qu'il ne faut pas aller lire plus loin en mémoire, que c'est la fin de la chaîne. Ce '\0' est rajouté pour vous quand vous définissez une chaîne avec des guillemets, par exemple quand vous faites
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    char message[] = "Salut";
    le tableau message va contenir les 5 codes ASCII pour le mot Salut dans des octets successifs et un octet supplémentaire va être alloué (donc le tableau fait 6 cases mémoire) et rempli avec le fameux '\0'.

    Quand vous fabriquez à la main votre code_tape[], vous n'avez pas prévu de case supplémentaire pour le stockage de ce caractère nul et donc quand vous essayez de l'imprimer la fonction print() va balancer à l'écran des codes ASCII qui correspondent à ce qu'il y a en mémoire jusqu'à ce qu'on rencontre un '\0' --> les zibouiboui que vous voyez sont des octets n'ayant pas de représentation ASCII sans doute.

    Vous verrez que dans le code ci dessus j'ai alloué une case de plus
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      char code_tape[passwordLength + 1] = {'\0'}; //tableau contenant la saisie, +1 pour un caractère NULL de fin de chaîne avec initialisation vide
    et que une fois les n caractères du code saisis je met un '\0' dans cette dernière case afin d'avoir une cString bien formée
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      code_tape[passwordLength] = '\0'; // pour faire une cString bien formée (superflu car intialisé déjà avec des '\0', donc plus à titre de bonne pratique)
    Comme je le dis dans le commentaire c'est plus pour votre compréhension, en fait comme j'ai initialisé le tableau avec des caractères nuls partout, une fois le tableau rempli par ce que vous tapez (comme on ne va pas jusqu'au bout du tableau) le dernier caractère est déjà un caractère nul.

    Et donc maintenant que j'ai des chaînes bien formées (des cStrings) je peux utiliser strcmp() ou print() sans souci.

  6. #6
    Nouveau membre du Club
    Homme Profil pro
    pompier
    Inscrit en
    Janvier 2020
    Messages
    76
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Eure et Loir (Centre)

    Informations professionnelles :
    Activité : pompier

    Informations forums :
    Inscription : Janvier 2020
    Messages : 76
    Points : 36
    Points
    36
    Par défaut
    Bien,

    Tout fonctionne.

    Pouvez-vous m'expliquer
    Merci encore

  7. #7
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 711
    Points : 5 390
    Points
    5 390
    Par défaut
    La macro F(«xxx») met la chaîne xxx en mémoire flash et n’utilise pas de mémoire SRAM pour l’impression donc en mettant toutes nos impressions sur la console ou le lcd avec des F() on économise de la SRAM pour les autres variables importantes

    Cf la doc The F() macro à la fin de la page PROGMEM

    Le \n veut dire faire un saut à la ligne

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Problème de format de montant avec la commande BCP
    Par bestdali dans le forum Outils
    Réponses: 1
    Dernier message: 05/05/2011, 12h01
  2. Problème de type de variable avec la fonction find
    Par Sarune dans le forum Macros et VBA Excel
    Réponses: 6
    Dernier message: 12/11/2008, 17h06
  3. [BO 6.5.1][Deski]Problème de format de variable
    Par CélineM dans le forum Deski
    Réponses: 7
    Dernier message: 14/05/2008, 10h43
  4. Réponses: 2
    Dernier message: 15/11/2007, 15h15
  5. Réponses: 6
    Dernier message: 07/07/2006, 17h27

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo