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 :

Pourquoi affiche-t-il 1000 au lieu de 0000


Sujet :

Arduino

  1. #1
    Membre éprouvé
    Inscrit en
    Juillet 2004
    Messages
    928
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 928
    Par défaut Pourquoi affiche-t-il 1000 au lieu de 0000
    Bonjour à tous

    Je tourne en rond avec ce petit programme sous wokwi
    http://wokwi.com/projects/424243477486689281

    je voudrais savoir svp selon vous pourquoi :
    - à l'initialisation , il affiche le code "1000" au lieu de "0000" alors le code est initialisé à zéro
    - seul premier chiffre la roue codeuse part dans le sens contraire des aiguilles d'une montre mais pas les autres chiffres lorsqu'on veut incrémenter les chiffres

    un grand merci par avance
    pascal

  2. #2
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 449
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 449
    Par défaut
    Hello,

    Je ne suis pas familier de l'Arduino, donc il m'a fallu un moment pour me familiariser avec le langage, qui ressemble beaucoup à du C mais qui n'en est pas tout-à-fait, si bien que les particularités des initialisations du langage ne peuvent pas forcément être garanties. Il y a bien un bug dans ton programme mais j'ai l'impression que le compilateur l'est aussi (au moins dans le traitement de certaines chaînes)…

    Citation Envoyé par cobra38 Voir le message
    - à l'initialisation , il affiche le code "1000" au lieu de "0000" alors le code est initialisé à zéro
    Oui, mais au démarrage, currentStateCLK et lastStateClk ne le sont pas. Leur valeur est indéfinie aux lignes 426 et 427, si bien que la première itération de ta boucle détecte quand même cela comme un premier appui en ligne 442, avant que tout cela rentre dans l'ordre.

    Par contre, j'ai l'impression que l'opérateur « + » de la classe String (documentée ici) fonctionne mal, lui aussi. Tes chiffres s'affichent correctement mais lorsque je remplace le contenu de println() par String(56) + String(72), j'obtiens 72 à l'écran et pas 5672

    Je te suggère plutôt de calculer la valeur du code en amont dans un int puis de l'afficher en une fois, par exemple avec :

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    display.println(pottentionalvalue[0]*1000 + pottentionalvalue[1]*100 + pottentionalvalue[2]*10 + pottentionalvalue[3]);

    … le mieux étant de le déposer dans une variable dédiée dès la ligne 453 et ne travailler qu'avec elle ensuite (UPDATE : je m'aperçois que c'est ce que tu fais en fin de fonction, mais tu n'es pas obligé de recourir à pow(). C'est propre d'un point de vue mathématique mais c'est inutilement long à calculer).

    - seul premier chiffre la roue codeuse part dans le sens contraire des aiguilles d'une montre mais pas les autres chiffres lorsqu'on veut incrémenter les chiffres
    Tu ne remets pas counter à zéro après usage. En tout cas, pas au bon endroit. La ligne 436 devrait se trouver à l'intérieur de la boucle while(1) et pas en dehors.

    Bon courage.

  3. #3
    Responsable Arduino et Systèmes Embarqués


    Avatar de f-leb
    Homme Profil pro
    Enseignant
    Inscrit en
    Janvier 2009
    Messages
    13 122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Sarthe (Pays de la Loire)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Janvier 2009
    Messages : 13 122
    Billets dans le blog
    47
    Par défaut
    Citation Envoyé par Obsidian Voir le message
    Je ne suis pas familier de l'Arduino, donc il m'a fallu un moment pour me familiariser avec le langage…
    Enfin, tu t'y es mis, il était temps de combler cette lacune

  4. #4
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 449
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 449
    Par défaut
    Citation Envoyé par f-leb Voir le message
    Enfin, tu t'y es mis, il était temps de combler cette lacune
    Ah, malheureusement, si c'était la seule chose que j'avais négligée pendant les sept dernières années…

    Il est temps de revenir aux fondamentaux.

  5. #5
    Membre éprouvé
    Inscrit en
    Juillet 2004
    Messages
    928
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 928
    Par défaut
    Bonjour à tous

    merci Obsidian pour la réponse rapide

    Oui, mais au démarrage, currentStateCLK et lastStateClk ne le sont pas. Leur valeur est indéfinie aux lignes 426 et 427, si bien que la première itération de ta boucle détecte quand même cela comme un premier appui en ligne 442, avant que tout cela rentre dans l'ordre.
    Ok je comprends, est-ce à dire que quoique je fasse j'aurai toujours 1000 à l'initialisation ?

    Tu ne remets pas counter à zéro après usage. En tout cas, pas au bon endroit. La ligne 436 devrait se trouver à l'intérieur de la boucle while(1) et pas en dehors.
    j'ai essayé toutes les places mais rien ne changent vraiment désolé


    pascal

  6. #6
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 449
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 449
    Par défaut
    Hello,

    Citation Envoyé par cobra38 Voir le message
    j'ai essayé toutes les places mais rien ne changent vraiment désolé
    Oui, pardon, ça c'était une erreur de ma part. J'ai cru que « counter » ne servait qu'à appliquer « -1 » ou « +1 » au chiffre en cours mais en réalité, il sert bien à le définir complètement. Tu peux donc le laisser à sa place initiale. PAR CONTRE, tu ne gères pas correctement les débordements (quand ton chiffre dépasse 9 ou tombe en dessous de 0). La fonction abs() en ligne 455 ne suffit pas. Il te faut au minimum un modulo 10 (mais en gérant le signe quand même) ou une paire de if/else pour tenir compte des dépassements.

    Ok je comprends, est-ce à dire que quoique je fasse j'aurai toujours 1000 à l'initialisation ?
    Non, pas tout-à-fait. Je vois également que tu évites d'initialiser inutilement une variable quand elle va l'être plus loin ou quand sa valeur initiale n'a pas de sens. C'est une bonne chose en soi, surtout si on les regroupe après les variables initialisées (par contre, les professeurs risquent de tiquer dessus).

    En revanche, je vois && currentStateCLK == 1 en ligne 442. Or, le simulateur indique que CLK, comme pas mal d'autres signaux, est associé à une résistance de pull-up. Elle est implicite, elle n'est pas sur le schéma mais est indiquée sur l'étiquette de D2 à l'exécution quand on pose un breakpoint. Elle est donc à l'état bas quand on sollicite le bouton et il existe une macro LOW, que tu utilises à d'autres endroits, pour représenter cet état. Cela fonctionne donc mieux avec == LOW. En outre, si c'est bien comme cela que ça fonctionne et que l'on peut raisonnablement faire l'hypothèse que ce signal ne sera jamais que HIGH ou LOW, alors on peut d'emblée initialiser lastStateCLK à HIGH en ligne 426.

    Par contre, même si ça fonctionne mieux en l'état, souviens-toi qu'après les 5 secondes d'affichage du logo « coffre », le code ne sera présenté qu'après avoir sollicité le bouton au moins une fois. Comme il l'était implicitement jusqu'ici, on n'avait pas conscience du problème. Ceci signifie que si ta première action sur le bouton est une incrémentation, alors tu verras quand même « 1000 » parce que le chiffre viendra d'être mis à jour par cette action.

    Enfin, le simulateur est déjà suffisamment long et bugué en lui-même (surtout sur ma machine, sur laquelle les secondes du chronomètre durent au moins 1,5 seconde…). Souviens-toi que tu as toujours un delay(500) en ligne 464, ce qui t'impose d'observer une demi-seconde de délai entre chaque appui, faute de quoi il ne sera pas pris en compte.


    UPDATE : je viens de faire le test sur le simulateur et en prenant en compte tous les points exposés ci-dessus, ton code finit par fonctionner entièrement. J'ai pu définir un nouveau code, tenter d'ouvrir le coffre, me faire opposer un refus en cas de mauvais code et voir le servomoteur pivoter lors de la saisie du bon code, accompagnée de l'image bitmap du coffre ouvert. Je n'ai pas tenté de définir un nouveau code a posteriori.

  7. #7
    Membre éprouvé
    Inscrit en
    Juillet 2004
    Messages
    928
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 928
    Par défaut
    Bonjour Obsidian

    merci encore pour tous tes conseils
    PAR CONTRE, tu ne gères pas correctement les débordements (quand ton chiffre dépasse 9 ou tombe en dessous de 0). La fonction abs() en ligne 455 ne suffit pas. Il te faut au minimum un modulo 10 (mais en gérant le signe quand même) ou une paire de if/else pour tenir compte des dépassements.
    peux-tu développer stp , ce que je comprends mais mal peut-être c'est que je dois tester par if/else lorsque le chiffre arrive à 9 ou 0
    c'est la variable counter que je dois tester ?


    UPDATE : je viens de faire le test sur le simulateur et en prenant en compte tous les points exposés ci-dessus, ton code finit par fonctionner entièrement. J'ai pu définir un nouveau code, tenter d'ouvrir le coffre, me faire opposer un refus en cas de mauvais code et voir le servomoteur pivoter lors de la saisie du bon code, accompagnée de l'image bitmap du coffre ouvert. Je n'ai pas tenté de définir un nouveau code a posteriori.
    Aurais-tu réussi à avoir 0000 en lieu et place de 1000 ?


    cordialement
    pascal

  8. #8
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 449
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 449
    Par défaut
    Citation Envoyé par cobra38 Voir le message
    Peux-tu développer stp , ce que je comprends mais mal peut-être c'est que je dois tester par if/else lorsque le chiffre arrive à 9 ou 0
    c'est la variable counter que je dois tester ?
    Tout-à-fait.

    Si tu n'as pas envie de t'ennuyer avec ça, tu insères une ligne qui contient counter = (counter + 10) % 10; entre les lignes 453 et 454. Le + 10 central sert à s'assurer que l'on reste toujours dans une plage positive avant d'appliquer le modulo.

    Aurais-tu réussi à avoir 0000 en lieu et place de 1000 ?
    Oui, mais comme expliqué plus haut, tu n'affiches le code qu'à partir du moment où le bouton a été sollicité au moins une fois (en rotation ou en appui). Donc tu as bel et bien un 0000 au départ mais tu ne le vois jamais !

    L'affichage n'est rafraîchi que lorsque tu fais tourner le bouton la première fois et tu vois alors directement « 1000 ». Comme tu as écrit == 1 au lieu de == LOW (donc « == 0 » et pas 1 !) en ligne 442, la mise sous tension est considérée comme un appui et ton code est immédiatement mis à jour. Si tu corriges cette ligne, tout va fonctionner normalement mais tu ne verras pas le code initial (0000) parce qu'il n'aura pas été affiché au départ. Après les cinq premières secondes, tu resteras sur l'image du coffre jusqu'à ce que tu utilises le bouton : à ce stade, tu verras soit 1000 si tu l'as tourné vers la droite, soit 9000 si tu l'as tourné vers la gauche, soit 0000 si tu as appuyé dessus MAIS tu seras alors déjà sur le deuxième chiffre et pas sur le premier. C'est à toi de corriger cela également.

  9. #9
    Membre éprouvé
    Inscrit en
    Juillet 2004
    Messages
    928
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 928
    Par défaut
    RE..Obsidian

    voici un premier essai
    j'espère avoir intégrer tes conseils ...

    ton avis stp

    https://wokwi.com/projects/428325091821057025

  10. #10
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 449
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 449
    Par défaut
    Bravo, tout fonctionne comme attendu !

    Quelques remarques cependant, plus sur la forme que sur le fond, cette fois :

    • En ligne 427, ce n'est pas currentStateCLK mais lastStateCLK (la ligne du dessus) qu'il faut pré-initialiser, et pas à LOW mais à HIGH. Ce n'est pas bien grave ;
    • À partir de la ligne 436, tu as fait un copier-coller de ta fonction d'affichage (à quelques ajustements près) pour générer la vue initiale du code au démarrage. Tu aurais été tout autant avisé d'écrire une fonction dédiée et d'appeler cette fonction aux deux endroits où tu en as besoin (lignes 436 et 456) ;
    • Si tu le fais, veille à ne pas appeler clearDisplay() à l'intérieur de cette fonction mais juste avant, pour éviter les clignotements (c'est déjà ce que tu fais) et gagner en temps d'exécution. Tu peux également la décomposer en deux parties, une pour la reconstruction de l'écran entier (qui alors peut embarquer clearDisplay()) et une autre pour le rafraîchissement du code en particulier ;
    • Aux lignes 460 et 464, j'ai remarqué que tu as pensé à inverser ++ et -- car tes chiffres tournaient dans le mauvais sens. Par contre, tu as oublié de mettre à jour en conséquence les chaînes CW et CCW ;
    • Toujours au même endroit, tu aurais pu éventuellement inverser la condition en ligne 459 (remplacer != par ==). Ça revient au même, mais c'est plus facile s'il y a beaucoup de code dans le corps de chaque éventualité ;
    • Dans le même esprit, je lis dans la doc du bouton qu'en réalité, on détermine le sens de rotation en observant lequel des deux signaux CLK et DT passe au niveau bas le premier (sachant qu'ils le font tous les deux successivement). Cela veut dire que si ton programme met trop de temps à récupérer ces deux signaux, ta lecture peut être faussée car l'un des deux aura eu le temps de remonter ;
    • Comme on examine CLK en premier dans tous les cas, la ligne 459 telle qu'elle est écrite permet implicitement de le faire mais elle est un peu obscure. Je te suggère plutôt de récupérer directement les deux signaux en une fois en tête de procédure, voire en une seule opération atomique si c'est possible (je n'ai pas creusé pour le savoir), puis de faire tranquillement des comparaisons sur ces valeurs ensuite ;
    • Enfin, les commandes delay(500) aux lignes 445 et 479 ont-elle une utilité ? Sont-elles imposées par une spécification quelconque ? Parce qu'en l'état, elles ralentissent considérablement ton programme lorsque tu manipules le bouton. Ce sont mêmes elles qui devaient te donner l'impression que tu ne pouvais pas revenir en arrière.


    Bon courage !

  11. #11
    Membre éprouvé
    Inscrit en
    Juillet 2004
    Messages
    928
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 928
    Par défaut
    Un grand merci pour ton aide Obsidian

    je mets sur wokwi la dernière version à laquelle j'ai rajouté quelques images ou autres
    https://wokwi.com/projects/428379028200300545
    j'ai pris bonne note de tes derniers conseils du moins j'espère

    À partir de la ligne 436, tu as fait un copier-coller de ta fonction d'affichage (à quelques ajustements près) pour générer la vue initiale du code au démarrage. Tu aurais été tout autant avisé d'écrire une fonction dédiée et d'appeler cette fonction aux deux endroits où tu en as besoin (lignes 436 et 456) ;
    j'ai essayé de le faire mais il y a des appels à la fonction : int GetPin(String displayedText)
    et à la variable pottentionalvalue[digitToPrint]
    qui m'ont causé beaucoup de soucis , j'ai du abandonné ....

    encore mille mercis pour ta patience et pour ton temps

    Cordialement

    UPDATE : je pensais en avoir fini mais pb lorsque je coupe l'alimentation de l'arduino , je perds le code en mémoire EEPROM
    pourtant les tests avec l'alimentation fonctionnent bien


    pascal

  12. #12
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 449
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 449
    Par défaut
    Salut,

    Citation Envoyé par cobra38 Voir le message
    Un grand merci pour ton aide Obsidian
    je mets sur wokwi la dernière version à laquelle j'ai rajouté quelques images ou autres [… ]j'ai pris bonne note de tes derniers conseils du moins j'espère
    C'est du très beau travail, tout cela !
    Globalement tout fonctionne. J'ai pu admirer les nouveaux pictogrammes également et ton projet dans le simulateur, à présent libéré des temporisations inutiles, est nettement plus réactif !

    C'est une bonne chose d'avoir commencé à introduire des fonctions telles que startupAnimation(). Jadis on évitait d'introduire des sauts intermédiaires vers des procédures qui n'étaient appelées qu'une seule fois, spécialement en assembleur sur des machines lentes et il est toujours appréciable selon moi d'avoir toujours ces notions à l'esprit. Mais aujourd'hui, non seulement le coût de ces appels est négligeable mais la plupart des compilateurs sont capables d'en faire des fonctions inline par eux-mêmes si c'est utile, même sans les avoir déclarées comme telles.

    Ce qui est important aujourd'hui est de conserver un code clair car il est coûteux (en temps homme) à rédiger et difficile à maintenir ensuite. Donc il est important d'y introduire de la sémantique et c'est ce que tu fais en définissant des fonctions bien nommées. L'autre point crucial est de tenter de maintenir son code « sous forme irréductible », comme en maths, mais ton programme n'en souffre pas trop.

    Pour le reste, c'est tout bon. On pourrait te proposer encore pas mal d'améliorations sur la forme, mais il ne s'agirait que d'optimisations, pas de corrections.

    Si tu veux aller plus loin et que tu comptes à terme implémenter physiquement ce projet (avec de vrais modules électroniques), je te suggère de revoir la page consacrée au bouton et te pencher sur la manière dont il peut utiliser les interruptions, ainsi que sur les pages consacrées à la manipulation des ports sur le site de Arduino :

    https://docs.arduino.cc/retired/hack...tManipulation/
    https://docs.arduino.cc/language-ref...o/digitalread/

    En particulier, on constate deux choses :

    1. Le fait que Arduino suggère de s'appuyer en général sur digitalRead() plutôt que lire directement le port. C'est vrai quand on débute, que l'on veut être portable (si cela a un sens sur ce type de plateforme) et que l'on traite des signaux lents, mais toi tu tombes ici dans un cas où il faudra aller outre cette recommandation. Et tu vas goûter à ce que l'on faisait quand on programmait sur 8 bits dans les (glorieuses) années 1980… ;
    2. Un piège dans le deuxième exemple de la page du bouton : comme il utilise les interruptions, celles-ci sont déclenchées par CLK et le programme semble ne faire qu'un seul appel à digitalRead() ensuite (sur DT). En réalité, il va se passer un certain temps entre le changement d'état de CLK et celui où le processeur va atteindre la ligne digitalRead() et l'honorer, spécialement si l'événement se produit alors qu'il en train de traiter l'interruption précédente. Dans cette situation, les interruptions ultérieures sont inhibées jusqu'à ce qu'il se déclare comme à nouveau libre. Lorsque cela se produit, soit les interruptions entrantes dans l'intervalle sont totalement ignorées, soit elles se contentent d'armer le flag correspondant, qui sera ensuite traité en fin de procédure. Il déclenchera automatiquement une nouvelle interruption, mais une seule. À charge du programme de vérifier tout ce qui a pu rester en suspens.


    Dans ce deuxième cas, le mieux à faire est de mettre en place une procédure d'interruption (sur CLK) qui se content de lire le port D en une seule opération d'abord, le timestamp courant immédiatement après, déposer ces valeurs dans deux variables puis rendre la main immédiatement pour qu'elle reste la plus fugace possible. Tu laisses ensuite ta boucle principale examiner elle-même ces variables en conditions ordinaires pour mettre à jour tes chiffres. Ceci te donnera un système très réactif et tu seras sûr — même si tu les lis trop tard — que les relevés des valeurs de CLK et DT seront simultanés.


    j'ai essayé de le faire mais il y a des appels à la fonction : int GetPin(String displayedText)
    et à la variable pottentionalvalue[digitToPrint]
    qui m'ont causé beaucoup de soucis , j'ai du abandonné ....
    Tu as bien fait, en effet, de ne pas avoir essayé de tout corriger à la fois. On risque, sinon de tout casser, d'introduire au moins des régressions importantes difficiles à corriger ensuite. Tu sembles également avoir une certaine expérience du développement. Je ne saurais trop te conseiller d'utiliser un logiciel de versioning tel que Git si bien sûr tu ne le fais pas déjà…

  13. #13
    Membre éprouvé
    Inscrit en
    Juillet 2004
    Messages
    928
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 928
    Par défaut
    salut Obsidian

    désolé mais ....

    J'ai encore mon petit problème d'EEPROM
    en fait lorsque je rentre une valeur = 1111 à l'adresse 0 , le programme écrit une valeur = 87 à l'adresse 0 et une valeur = 0 à l'adresse 1
    en conséquence le programme fonctionne que si on met une valeur < 256 !!!

    je comprends que le programme stocke donc de 1 à 4 octets ( pour par ex une valeur max = 9999) dans la mémoire
    mais comment lire ces adresses ?
    faut-il commencer par "mesurer" la valeur pour en déterminer la longueur et ensuite boucler sur le nombre d'octets ?
    si oui comment faire çà ?

    pascal

  14. #14
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 449
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 449
    Par défaut
    Citation Envoyé par cobra38 Voir le message
    en fait lorsque je rentre une valeur = 1111 à l'adresse 0 , le programme écrit une valeur = 87 à l'adresse 0 et une valeur = 0 à l'adresse 1
    en conséquence le programme fonctionne que si on met une valeur < 256 !!!
    Oui car c'est bien un octet que tu écris et comme tu le soulignes, la valeur maximum d'un octet non signé est 255.

    Plus précisément, dans le cas présent, 111110 en décimal s'écrit 45716 en hexadécimal, et 8710 en décimal s'écrit 5716 en hexadécimal.

    Cela signifie que EEPROM.write(address, data) attend un byte comme deuxième argument. Ton code est donc d'abord transtypé par le compilateur vers le type byte, ce qui consiste à ne conserver que les bits de poids faible (donc 457 → 57) et éliminer ce qui dépasse, puis passé à la fonction write() qui se charge de le déposer en mémoire. Le « 0 » qui suit n'a probablement rien à voir.

    je comprends que le programme stocke donc de 1 à 4 octets (pour par ex une valeur max = 9999) dans la mémoire
    Il y a plusieurs manières de le faire. Soit tu déposes un chiffre par octet en mémoire parce que c'est plus simple, soit tu déposes la variable de type entier qui contient le code en tant que telle. Le mieux ici est d'utiliser un short. Celui-ci est réputé mesurer 16 bits sur toutes les plateformes, donc 2 octets, et peut recevoir une valeur entière comprise entre -32768 et +32767 inclus.

    mais comment lire ces adresses ?
    faut-il commencer par "mesurer" la valeur pour en déterminer la longueur et ensuite boucler sur le nombre d'octets ?
    si oui comment faire çà ?
    Tu peux organiser ta mémoire comme bon te semble mais en règle générale, quand on y dépose une donnée dont la longueur dépasse l'octet, elle est en principe déposée dans des octets consécutifs en incrémentant l'adresse à chaque fois. Donc n, puis n+1, puis n+2, etc.

    Il faut quand même rappeler quelques points concernant les différentes technologies de mémoire. En particulier, l'EEPROM peut être sollicitée en lecture sans limitation, mais elle n'a qu'un nombre limité de cycles d'effacement. Ce n'est pas une RAM. Lorsque tu veux y écrire, il faut d'abord demander l'effacement de la plage concernée (ce qui est relativement long du point de vue du microprocesseur) puis y faire une inscription. Si tu le fais trop souvent, elle finira par ne plus fonctionner. Même si les technologies les plus récentes atteignent le million de cycles, il faut toujours la voir comme un CD-RW réinscriptible. Elle tolère plusieurs mises à jour à condition qu'elles ne soient pas fréquentes.

    Ensuite, concernant Arduino en particulier, il y a là encore une documentation dédiée et tu disposes en fait de six primitives :

    EEPROM.read(address) : Lit l'octet à l'adresse indiquée (et retourne un byte) ;
    EEPROM.write(address, data) : Écrit un octet à l'adresse indiquée. Se charge de faire les effacements électriques préliminaires si nécessaire ;
    EEPROM.update(address, data) : Lit l'octet à l'adresse indiquée avec read et vérifie s'il diffère de data. Si c'est le cas, on écrase l'ancienne valeur avec la nouvelle (en utilisant write en interne) ;

    EEPROM.get(address, variable) : Détermine automatiquement le type de variable et lit autant d'octets que nécessaire pour la remplir, à partir de address (s'appuie sur read en interne) ;
    EEPROM.put(address, variable) : Détermine automatiquement le type de variable et écrit tous ses octets, un par un, à partir de address et en utilisant update ;

    EEPROM.length() : te renvoie automatiquement la taille de la mémoire EEPROM disponible en fonction de la plateforme sur laquelle tu travailles.

    Donc, en principe, tu n'as besoin de ne t'appuyer que sur get() et put() car elles font le travail à ta place. Dépose ton code dans une variable de type short et tout devrait aller pour le mieux.

  15. #15
    Membre éprouvé
    Inscrit en
    Juillet 2004
    Messages
    928
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 928
    Par défaut
    Bonjour Obsidian

    je pense que j'ai 1 petit souci :
    si j'ai bien tout compris, et que le code est constitué de 2 octets
    si je mets :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    EEPROM.update(PIN_CODE_ADDR, iSecretPIN);
    je ne réactualise qu'1 seul octet puisque EEPROM.update() n'est valable que pour les valeurs < 256
    j'ai donc modifier le programme en :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    EEPROM.put(PIN_CODE_ADDR, iSecretPIN);
    et là miracle mon code est sauvegardé ....

    Donc, en principe, tu n'as besoin de ne t'appuyer que sur get() et put() car elles font le travail à ta place. Dépose ton code dans une variable de type short et tout devrait aller pour le mieux.
    mais j'ai un doute : int ou short sont valables pour 2 octets ?

    pascal

  16. #16
    Responsable Arduino et Systèmes Embarqués


    Avatar de f-leb
    Homme Profil pro
    Enseignant
    Inscrit en
    Janvier 2009
    Messages
    13 122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Sarthe (Pays de la Loire)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Janvier 2009
    Messages : 13 122
    Billets dans le blog
    47
    Par défaut
    Salut,

    int dans le "langage" Arduino est un entier signé sur deux octets pour les Arduino Uno/nano avec un micro AVR, voir int.

    Si tu veux forcer un type quel que soit l'architecture du micro, tu peux utiliser par exemple le type uint16_t pour un entier non signé 16 bits (entre 0 et 65535).

    Et en effet, avec EEPROM.get/put/update tu n'auras pas de soucis.

  17. #17
    Membre éprouvé
    Inscrit en
    Juillet 2004
    Messages
    928
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 928
    Par défaut
    merci f-leb
    pour les précisions

    je vais clore le post cette fois ...

    UN GRAND MERCI A TOUS !!

    pascal

  18. #18
    Responsable Arduino et Systèmes Embarqués


    Avatar de f-leb
    Homme Profil pro
    Enseignant
    Inscrit en
    Janvier 2009
    Messages
    13 122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Sarthe (Pays de la Loire)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Janvier 2009
    Messages : 13 122
    Billets dans le blog
    47
    Par défaut
    Obsidian a fait tout le boulot

    Fais attention si tu écris de nouvelles données dans l'EEPROM. Si tu écris un int (2 octets) à l'adresse 0 (avec put ou update), la donnée suivante devra être écrite à partir de l'adresse 2.

  19. #19
    Membre éprouvé
    Inscrit en
    Juillet 2004
    Messages
    928
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 928
    Par défaut
    Fais attention si tu écris de nouvelles données dans l'EEPROM. Si tu écris un int (2 octets) à l'adresse 0 (avec put ou update), la donnée suivante devra être écrite à partir de l'adresse 2.
    Dans le cas présent f-leb
    je sauvegarde à l'adresse 0 , le code actuel
    si je change celui-ci , j'écrase donc toujours à l'adresse 0 l'ancien code
    en fait je n'utilise que 2 octets dans l'EEPROM

  20. #20
    Responsable Arduino et Systèmes Embarqués


    Avatar de f-leb
    Homme Profil pro
    Enseignant
    Inscrit en
    Janvier 2009
    Messages
    13 122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Sarthe (Pays de la Loire)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Janvier 2009
    Messages : 13 122
    Billets dans le blog
    47
    Par défaut
    oui, oui, j'ai bien vu... C'était un complément d'informations au cas où...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
            EEPROM.put(adresse, une_valeur_int);
            adresse += sizeof(int); // Pour passer à l'adresse suivante

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

Discussions similaires

  1. [JDOM] Afficher tous les champs au lieu de juste un seul.
    Par ranza dans le forum Format d'échange (XML, JSON...)
    Réponses: 14
    Dernier message: 18/05/2013, 01h48
  2. Réponses: 3
    Dernier message: 12/09/2012, 22h52
  3. Réponses: 1
    Dernier message: 08/03/2009, 11h26
  4. Page de garde s'affiche sur deux pages au lieu d'une
    Par MPEG4 dans le forum Mise en forme
    Réponses: 8
    Dernier message: 04/03/2009, 19h35
  5. Réponses: 1
    Dernier message: 07/02/2006, 12h52

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