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

  1. #1
    Rédacteur

    Le navigateur aux commandes de l'Arduino - troisième partie
    Bonjour à tous .

    J'ai le plaisir de vous présenter le troisième et dernier volet de mon tutoriel consacré au pilotage d'un Arduino depuis un navigateur :




    Après nous être consacrés dans les première et deuxième parties à la programmation côté serveur, je vous propose, dans cette troisième et dernière partie, de nous intéresser à la programmation côté client avec JavaScript qui va nous permettre de manipuler le DOM, AJAX et JSON.
    Le navigateur aux commandes de l'Arduino
    Le navigateur aux commandes de l'Arduino - 2

    Vous en souhaitant bonne lecture,
    amicalement,
    naute

    Retrouvez les meilleurs cours et tutoriels pour apprendre Arduino

  2. #2
    Membre expérimenté
    Bravo pour ce 3ème volet très didactique !

    une petite faute de frappe dans
    la procédure setAttribut("attribut", "valeur") sert à modifier la valeur d’un attribut. Ici, nous travaillons sur l’attribut value de bouton que nous fixons à ON ou à OFF selon que son action sera d’allumer ou d’éteindre la LED ;
    il s'agit bien sûr de setAttribute() comme vous l'utilisez ensuite


    éventuellement une petite suggestion:

    La valeur 4 pour xhr.readyState signifie que l'opération de récupération est terminée. Cela peut signifier que le transfert de données s'est terminé avec succès ou a échoué. Donc pour être sûr que tout s'est bien passé on peut aussi tester le status (cf la liste des réponses possibles, 200 veut dire 'OK')
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
      xhr.onreadystatechange = function()
      {
        if (xhr.readyState == 4 && xhr.status == 200) {
          actualisation(xhr.responseText);
        }
      }



    Petite note au passage: on recommande souvent d'éviter les "nombres magiques" quand on programme et donc parfois au lieu de tester La propriété readyState avec sa valeur "en dur" (4) on voit du code qui compare avec XMLHttpRequest.DONE
    ça donnerait cela:
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
      xhr.onreadystatechange = function()
      {
        if (xhr.readyState == XMLHttpRequest.DONE) {
          actualisation(xhr.responseText);
        }
      }


    Cependant Internet Explorer jusqu'il y a peu n'appellait pas cela DONE mais READYSTATE_COMPLETE mais la valeur est bien 4. Donc en mettant 4 on met plus de chances de son côté que ça fonctionne partout...


    PS1:
    (pas de commentaires désobligeants quant à mon sens aigu de l’esthétique ;-)
    Je ne vois pas... à moins que vous ne disiez cela parce que vous avez oublié de fermer la parenthèse sur cette phrase ??


    PS2: la duplication de l'instance EthernetClient plutôt que son passage par référence est vraiment à éviter car la classe sous-jacente gère un nombre limité de sockets (donc ça pourrait coincer suivant l'activité du serveur) et vous vous retrouvez avec des pointeurs partagés sur des buffers mémoire et des variables qui se désynchronisent.

    PS3: je suppose qu'avec ce bout de code vous espérez échapper à un Stack Overflow ?
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
           char reception[127];
          memset(reception, 0, 127);
          if (reception == NULL)
          {
            while(1) {delay(1000);}
          }
    en fait reception est alloué sur la pile et son pointeur sera jamais NULL (et vous avez mis les 127 octets de mémoire à zéro avant de tester le pointeur!) et si la place n'est pas dispo, vous n'obtiendrez pas un pointeur null mais votre arduino va crasher direct au moment de la demande des 127 octets sur la pile... Comme votre app va vraiment souvent utiliser le web, le plus simple est de prendre un buffer en variable globale, comme cela le compilateur réservera la mémoire nécessaire. 127 est aussi un peu grand pour l'usage prévu dans votre cas, vous pourriez le réduire significativement.

    PS4: votre code pour l'analyse des chaînes est vraiment complexe, vous codez des fonctions qui existent dans les bibliothèques standard (et sont déjà présentes dans votre binaire sans doute).

    -> la longueur d'une cString (ce que vous faites avec dimChaine()) s'obtient par appel à strlen()

    -> concaténer deux cString (ce que vous faites avec ajoute()) s'obtient par appel à strcat()

    -> comparer deux cString se fait avec strcmp()

    -> vous pourriez simplement utiliser strstr() pour voir si la chaîne reçue contient le mot clé ajax.

    -> Si vous voulez vraiment voir si ce mot clé est à un endroit bien défini sur un certain nombre de caractères, pas la peine de décaler comme vous le faites tous les caractères dans le buffer (je suppose pour virer le "GET /") il suffit de faire un strncmp() avec comme pointeur vers la chaine source reception+5

    => il y a plein de fonctions sur les cString dans stdlib.h et string.h

  3. #3
    Rédacteur

    Bonjour .

    Citation Envoyé par Jay M Voir le message
    Bravo pour ce 3ème volet très didactique !
    Merci .

    Citation Envoyé par Jay M Voir le message
    une petite faute de frappe dans ...
    Il semblerait . En même temps, si c'est la seule...

    Citation Envoyé par Jay M Voir le message
    éventuellement une petite suggestion:...
    Le couple de tests classique est effectivement :
    Code javascript :Sélectionner tout -Visualiser dans une fenêtre à part
    (xhr.readyState == 4 && xhr.status == 200)

    Ce n'est pas un mystère.
    Pourquoi ai-je déchiré ce couple ? eh bien ! dans notre cas, le second membre ne servira pas à grand chose. Il ne s'agit pas ici d'un serveur Apache destiné à faire tourner le site web de la NASA (si tant est que la NASA utilise un serveur Apache). J'ai déjà eu l’occasion de le dire, et je le répète, nous sommes sur un Arduino UNO, dans un réseau local privé, pour des applications non critiques. On n'est pas obligé de sortir l'artillerie lourde, et c'est d’ailleurs pourquoi j'ai simplifié l'utilisation de XHR qui se fait très souvent par l'intermédiaire d'une fonction de callBack dont le mécanisme n'est pas toujours très facile à comprendre.
    Donc les deux points qui font que je n'utilise pas ce test sont :
    1 un paquet envoyé d'un poste à un autre sur un réseau local privé a bien peu de risque de ne pas arriver ;
    2 s'il n'arrive pas, c'est-à-dire si xhr.status != 200, il ne se passera rien et la chose la plus simple à faire est d'attendre l'arrivée du paquet suivant qui va suivre à une seconde d'intervalle. Faire ce test n'est intéressant que s'il est utile de traiter un éventuel résultat négatif, ce qui est superflu ici. Par contre, rien n'empêche l'utilisateur d'implémenter ce traitement si son application personnelle le nécessite.

    Citation Envoyé par Jay M Voir le message
    Petite note au passage:...
    Le chiffre "4" peut être considéré "magique" quand on ne connait pas sa signification. Dans notre cas, sa signification est explicitée quelques lignes plus haut, avec les autres valeurs que peut prendre le paramètre xhr.readyState. Il n'y a donc plus de magie. De plus, en toute rigueur, vous auriez donc dû mettre xhr.statusText == "OK" au lieu de xhr.status == 200 pour être en accord avec votre remarque.
    Je ne sais pas si on recommande vraiment de ne pas utiliser les "nombres magiques", mais ils sont pourtant présents dans tous les beaucoup de codes, ne serait-ce que dans ce test AJAX que j'ai toujours vu écrit comme ça. S'ils existent, c'est bien pour être utilisés. Il y a bien d'autres raccourcis de codage, dans le langage C notamment, qui me semblent bien plus magiques et incompréhensibles aux non initiés (dont je suis). Le tout est de savoir ce qu'on fait (et ce n'est pas toujours facile ;-).

    Citation Envoyé par Jay M Voir le message
    PS1:
    Ce n'est pas un oubli. C'est mon choix typographique (voir ci-dessus). Je trouve que "))" n'est pas très esthétique (dans une phrase du moins : dans du code, c'est standard). C'est évidemment tout à fait personnel. Je faisais bien entendu allusion à l'esthétique très basique de mon exemple .

    Citation Envoyé par Jay M Voir le message
    PS2:
    Dont acte !

    Citation Envoyé par Jay M Voir le message
    PS3:
    En fait, d'après ce que j'avais cru comprendre dans un tutoriel C que j'ai étudié, quand une demande d'allocation n'aboutissait pas, notamment par manque de place, un pointeur "NULL" était renvoyé : le but de ce test était donc en théorie de stopper le programme dans ce cas.
    Pour la dimension du tableau (127), je précise bien dans le chapitre VIII. Conclusion qu'elle peut être revue à la baisse en fonction des besoins.

    Citation Envoyé par Jay M Voir le message
    PS4:
    Complexe, mon code ?! Vous me flattez . Non, n'exagérons rien. Peut-être un peu lourd et on peut évidemment s'en passer. Seulement voilà.
    Je ne connais pas bien le C. Si l'EDI Arduino utilisait le Pascal (dans lequel, d'ailleurs, le traitement des chaînes de caractère est très différent) je serais au paradis, mais ce n'est pas le cas. Je me suis donc mis au C, sans forcément beaucoup d'enthousiasme, pour pouvoir "travailler" avec cette plateforme, et je suis bien certain de ne pas être le seul. Mais bon ! la programmation reste de la programmation, quelque soit le langage utilisé. Il faut s'adapter. Je n'ai rien contre le C, mais sa syntaxe est radicalement différente de celle du Pascal, et c'est un changement de paradigme délicat à intégrer. Par contre, sa similitude avec celle du JavaScript est un avantage quand on utilise les deux dans une même réalisation, comme ici.

    Je me doutais bien que ces fonctions existaient, mais j'ai estimé plus rapide de les écrire que de les chercher. Cela dit, pour mon usage personnel, j'utilise la classe String qui me convient très bien et qui ne m'a jamais causé de misère. Et comme pour les "nombres magiques", si elle existe, c'est bien pour être utilisée. Mais chacun a le droit d'avoir son opinion et ses habitudes. La richesse est dans la diversité.

    Merci pour votre intérêt et vos commentaires ,
    amicalement,
    naute

  4. #4
    Modérateur

    Un grand
    La science ne nous apprend rien : c'est l'expérience qui nous apprend quelque chose.
    Richard Feynman

  5. #5
    Rédacteur

    Merci Vincent .

  6. #6
    Membre expérimenté
    Salut

    Citation Envoyé par naute Voir le message
    Il semblerait . En même temps, si c'est la seule...
    Oui y'avait clairement eu du boulot de relecture avant. ça permet d'être un peu plus parfait : )

    Citation Envoyé par naute Voir le message

    Le couple de tests classique est effectivement :
    Code javascript :Sélectionner tout -Visualiser dans une fenêtre à part
    (xhr.readyState == 4 && xhr.status == 200)
    Ce n'est pas un mystère.
    Pourquoi ai-je déchiré ce couple ? eh bien ! dans notre cas, le second membre ne servira pas à grand chose. ... Par contre, rien n'empêche l'utilisateur d'implémenter ce traitement si son application personnelle le nécessite.
    C'était ce que je sous entendais: comme c'est un tuto - vous pourriez mentionner que readyState == 4 n'est pas suffisant mais que dans votre cas pas la peine de chercher plus loin.

    Citation Envoyé par naute Voir le message
    Je ne sais pas si on recommande vraiment de ne pas utiliser les "nombres magiques", mais ils sont pourtant présents dans tous les beaucoup de codes
    C'est une bonne pratique. vous trouverez cela dans tous les bons bouquins de programmation, quel que soit le langage. Dans ma vision d'un tuto, c'est pas mal de mettre en avant de bonnes habitudes et définir ces nombres magiques avec une #define ou mieux avec un const ou un constexpr, ça facilite la lecture quand on revient voir son code 6 mois plus tard et qu'on n'a pas le tuto sous la main.

    c'est pas nouveau cf Wikipedia:
    Constantes numériques non nommées
    Le terme de magic number peut également correspondre à l'utilisation de constantes numériques non nommées dans le code source d'un programme. L'utilisation de ces constantes viole les anciennes règles de programmation issues de COBOL, de FORTRAN et de PL/I9, ne rend pas plus clair le choix de cette valeur et provoque généralement des erreurs de programmation. Selon certains, le nommage de toutes les constantes rend le code plus lisible, plus compréhensible et plus facilement maintenable.
    Citation Envoyé par naute Voir le message
    Le chiffre "4" peut être considéré "magique" quand on ne connait pas sa signification. Dans notre cas, sa signification est explicitée quelques lignes plus haut, avec les autres valeurs que peut prendre le paramètre xhr.readyState. Il n'y a donc plus de magie. De plus, en toute rigueur, vous auriez donc dû mettre xhr.statusText == "OK" au lieu de xhr.status == 200 pour être en accord avec votre remarque.
    Oui 200 est aussi un nombre magique. Mon explication était plutôt là pour exprimer le fait que bien qu'en général on évite les nombres magiques, le manque de standardisation généralisée sur les noms associés aux nombres magiques pour AJAX fait qu'il est plus sûr d'utiliser le nombre magique directement. Donc dans certains cas il ne faut pas le faire et on peut expliquer pourquoi on ne le fait pas ==> j'y vois là un valeur éducative

    Ce n'est pas un oubli. C'est mon choix typographique (voir ci-dessus). Je trouve que "))" n'est pas très esthétique (dans une phrase du moins : dans du code, c'est standard). C'est évidemment tout à fait personnel. Je faisais bien entendu allusion à l'esthétique très basique de mon exemple .
    c'était un peu d'humour pour dire que je trouvais le reste tout à fait bien

    En fait, d'après ce que j'avais cru comprendre dans un tutoriel C que j'ai étudié, quand une demande d'allocation n'aboutissait pas, notamment par manque de place, un pointeur "NULL" était renvoyé : le but de ce test était donc en théorie de stopper le programme dans ce cas.
    c'est vrai pour l'allocation dynamique avec malloc() et ses dérivés ou l'instanciation, mais quand c'est sur la pile directement vous vous prenez un "Stack Overflow" direct. Dans les plateformes un peu avancées, on pourrait jouer avec du try/catch mais pour faire cela il faut plein de mémoire et justement ici on en manque... (tel que c'est écrit vous essayez de mettre à 0 la mémoire avant de tester si le pointeur est OK, donc c'est quand même un souci).

    Complexe, mon code ?! Vous me flattez . Non, n'exagérons rien. Peut-être un peu lourd et on peut évidemment s'en passer. Seulement voilà.
    Je ne connais pas bien le C. Si l'EDI Arduino utilisait le Pascal (dans lequel, d'ailleurs, le traitement des chaînes de caractère est très différent) je serais au paradis, mais ce n'est pas le cas. Je me suis donc mis au C, sans forcément beaucoup d'enthousiasme, pour pouvoir "travailler" avec cette plateforme, et je suis bien certain de ne pas être le seul. Mais bon ! la programmation reste de la programmation, quelque soit le langage utilisé. Il faut s'adapter. Je n'ai rien contre le C, mais sa syntaxe est radicalement différente de celle du Pascal, et c'est un changement de paradigme délicat à intégrer. Par contre, sa similitude avec celle du JavaScript est un avantage quand on utilise les deux dans une même réalisation, comme ici.

    Je me doutais bien que ces fonctions existaient, mais j'ai estimé plus rapide de les écrire que de les chercher.
    je comprends et me doutais que c'était la raison. Là encore, mon point de vue c'est que dans un tuto qui a un objectif pédagogique, il est bon d'encourager les bonnes pratiques générales.

    Je vous propose de remplacer - si vous le voulez bien - votre code (qui génère pas mal de warnings à la compilation) par celui ci, plus simple et utilisant la fonction strstr() qui recherche une sous-chaîne dans une chaîne. (je ne l'ai pas testé, c'est la traduction simplement de votre code). La seule optimisation importante effectuée c'est la génération du JSON à la volée plutôt que de construire un buffer inutile (et quelques modifications sur les noms des constantes, A0 au lieu de 0 par exemple, ou des définitions en const byte partout pour les pins et éviter une variable globale 'i' qui n'a aucun sens à être globale).

    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
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    //  *** LA GESTION DE LA CARTE SD ***
    #include <SdFat.h>
    SdFat carteSd;
    const byte csPinSD = 4;
     
    // *** LA GESTION ETHERNET ***
    #include <Ethernet.h>
    byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};  // notre adresse MAC
    IPAddress ip(192, 168, 1, 200); // notre adresse IP, à adapter à votre réseau local
    EthernetServer serveurHTTP(80); // 80 est le port standard du protocole HTTP
     
    const byte tailleMaxGETBuffer = 60; // taille max pour la commande GET reçue, à adapter aux besoins
     
    //  *** LES PINS UTILISÉES ***
    const byte ledPin = 2;    // une LED sur la broche numérique 2
    const byte LM35Pin = A0;  // le capteur de température sur la broche analogique 0
     
    // *** LES FONCTIONS UTILITAIRES ***
     
    void arHtml(EthernetClient& nomClient, const __FlashStringHelper* type) // on passe le type en utilisant la macro F("...") pour économiser la mémoire SRAM
    {
      nomClient.println(F("HTTP/1.1 200 OK"));
      nomClient.print(F("Content-Type: "));
      nomClient.println(type);
      nomClient.println(F("Connection: close"));
      nomClient.println();
    }
     
    void envoiFichier(EthernetClient& nomClient, const char* fichierEnCours)
    {
      if (carteSd.exists(fichierEnCours))
      {
        File fichier = carteSd.open(fichierEnCours, FILE_READ);
        if (fichier) { // si l'accès s'est bien passé
          while (fichier.available()) nomClient.write(fichier.read()); // on envoie le contenu du fichier
          fichier.close();  // puis on ferme le fichier
        }
      }
    }
     
    float temperature(byte broche, word iteration)
    {
      long lecture = 0;
      for (word i = 0; i < iteration; i++)
      {
        lecture += analogRead(broche);
      }
      return (float(lecture) * 500.0 / 1024.0 / iteration);
    }
     
     
    void maj(EthernetClient& nomClient)
    {
      float temperatureMoyenne = temperature(LM35Pin, 10);  // on calcule la moyenne de la température sur quelques échantillons
     
      // on va renvoyer un JSON
      arHtml(nomClient, F("application/json"));
     
      // on construit et emet notre JSON
      nomClient.print(F("{\"bouton\":\""));
      if (digitalRead(ledPin) == HIGH)
        nomClient.print(F("ledOn"));
      else
        nomClient.print(F("ledOff"));
      nomClient.print(F("\",\"temperature\":"));
      nomClient.print(temperatureMoyenne, 2); // on emet la température avec 2 chiffres après la virgule
      nomClient.println(F("}"));
    }
     
    // *** LE PROGRAMME PRINCIPAL ***
     
    void setup()
    {
      pinMode(ledPin, OUTPUT);
      Serial.begin(115200);
      carteSd.begin(csPinSD);
      Ethernet.begin(mac, ip);
    }
     
    void loop()
    {
      EthernetClient client = serveurHTTP.available();
      if (client)
      {
        if (client.connected())
        {
          char reception[tailleMaxGETBuffer + 1]; // +1 car une chaîne bien formée se termine par un '\0' invisible
     
          byte nbCar = 0;
          while (client.available())       // tant que des données sont disponibles
          {
            char carLu = client.read();     // on lit le prochain octet
            if (carLu != '\n')              // si ce n'est pas la marque de fin de ligne
            {
              if (nbCar < tailleMaxGETBuffer) reception[nbCar++] = carLu; // et si on a la place alors on conserve le caractère sinon on l'ignore
            }
            else break;                     // si on a reçu la fin de ligne on termine
          }
          reception[nbCar] = '\0';          // on met la marque de fin de notre chaîne correctement
     
          // on analyse maintenant ce que l'on a reçu en cherchant des mots clés en utilisant strstr() (cf http://www.cplusplus.com/reference/cstring/strstr/)
     
          // est-ce une demande de type ajax ?
          char *ajaxPtr = strstr(reception, "ajax?");
          if (ajaxPtr != NULL)
          {
            if (strstr(ajaxPtr, "ON") != NULL)  digitalWrite(ledPin, HIGH);       // si la requête demande d'allumer, on le fait
            else if (strstr(ajaxPtr, "OFF") != NULL) digitalWrite(ledPin, LOW);   // si la requête demande l'extinction, on le fait
            // puis on envoie une réponse JSON avec mise à jour
            maj(client);
          }
     
          // est-ce une demande pour telecommande.css
          else if (strstr(reception, "telecommande.css") != NULL)
          {
            arHtml(client, F("text/css"));
            envoiFichier(client, "telecommande.css");
          }
     
          // est-ce une demande pour telecommande.js
          else if (strstr(reception, "telecommande.js") != NULL)
          {
            arHtml(client, F("application/javascript"));
            envoiFichier(client, "telecommande.js");
          }
     
          // est-ce une demande pour icone.png
          else if (strstr(reception, "icone.png") != NULL)
          {
            arHtml(client, F("image/png"));
            envoiFichier(client, "icone.png");
          }
     
          // sinon on envoie la page standard
          else
          {
            arHtml(client, F("text/html"));
            envoiFichier(client, "telecommande.html");
          }
     
          delay(1);
        }
        client.stop();  // on se déconnecte du serveur. le buffer non lu est conservé jusqu'à disparition de l'instance client, ce qui se fait en fin de loop
      }
    }


    Cela dit, pour mon usage personnel, j'utilise la classe String qui me convient très bien et qui ne m'a jamais causé de misère. Et comme pour les "nombres magiques", si elle existe, c'est bien pour être utilisée. Mais chacun a le droit d'avoir son opinion et ses habitudes.
    Oui et dans de très nombreux cas la classe String ne créera pas de souci (Son seul problème vient que le jour où vous en aurez un, ce sera une grosse galère à débuger). Pour des petits programmes qui ne tournent pas pendant des mois ou qui font une usage raisonné de la classe (allocation avec reserve d'espace minimum, dé-allocation dans l'ordre inverse des allocations, ..) alors vous n'aurez aucun problème. Ma recommandation pour partager les bonnes pratiques serait simplement d'appeler reserve() juste après sa définition quand on sait que la String va grossir (reception) pour éviter le morcellement mémoire. ça permettrait aussi de tester si la mémoire a pu être allouée (même si le doc dit que la méthode ne retourne rien, elle répond en fait 0 ou 1 en fonction de si ça a marché ou pas).

    Donc avec la classe String ça donnerait un truc comme cela:

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    const byte tailleMaxGETBuffer = 60; // taille max pour la commande GET reçue, à adapter aux besoins
    ...
      String reception;
      if (reception.reserve(tailleMaxGETBuffer))  // si on a pu réserver la mémoire nécessaire 
      {
        ....
      }


    La richesse est dans la diversité.
    Tout à fait et pas de souci si vous ne souhaitez ne pas en tenir compte. C'est votre tuto !! Ce sont juste des remarques que j'espère constructives, pour encourager la prise de bonnes habitudes pour ceux qui liront votre tuto.

  7. #7
    Rédacteur

    Bonjour .

    Citation Envoyé par Jay M Voir le message
    c'était un peu d'humour...
    C'est ainsi que je l'avais compris .

    Citation Envoyé par Jay M Voir le message
    La seule optimisation importante effectuée c'est la génération du JSON à la volée plutôt que de construire un buffer inutile...
    S'agissant d'un tutoriel, je pense qu'il n'est pas absurde de construire entièrement la chaîne JSON avant de l'envoyer, plutôt que de l'envoyer par fragments. Il me semble que l'on "sent" mieux comme ça qu'il s'agit bien d'une chaîne structurée et que l'on en perçoit mieux la structure. Mais ce n'est qu'un point de vue.

    Citation Envoyé par Jay M Voir le message

    ...éviter une variable globale 'i' qui n'a aucun sens à être globale.
    Tout à fait d'accord sur le principe. La raison pour laquelle j'ai procédé ainsi est qu'à différents endroits de mon code, j'ai besoin d'une variable d'itération. Comme il n'y a aucune imbrication entre ces différentes itérations, plutôt que de redéfinir une variable à chacune d'entre elles, je la définis une fois pour toute.

    Citation Envoyé par Jay M Voir le message
    Tout à fait et pas de souci si vous ne souhaitez ne pas en tenir compte.
    Si je ne tiens pas compte des remarques que l'on me fait, il est inutile d'ouvrir un fil de discussion. Par contre, il serait plus judicieux de pouvoir faire ces mises au point en amont, avant publication (petit appel du pied ).

    Je mets en ligne la mise à jour.

    À bientôt, amicalement,
    naute

  8. #8
    Membre expérimenté
    Salut

    Citation Envoyé par naute Voir le message
    Par contre, il serait plus judicieux de pouvoir faire ces mises au point en amont, avant publication (petit appel du pied ).
    Certes ! Si on me demande, sur des sujets que je maitrise et que j'ai le temps, je veux bien


    Pour la variable 'i' ça ne mange pas de pain de la déclarer dans les fonctions ou directement dans la boucle for quand il y en a. Vous avez fait attention au fait que les fonctions n'étaient pas interdépendantes mais les débutants n'auront peut-être pas ce réflexe. Il vaut mieux mettre en global ce que l'on veut partager entre toutes les fonctions et laisser en local le reste.


    Pour la chaîne JSON, c'est effectivement un choix. Comme on essaye de minimiser l'impact mémoire et qu'on n'a pas besoin d'avoir la chaîne en mémoire, d'un point de vue émission ça ne change rien si on l'envoie par petits bouts.

    Sinon pour la construire on peut utiliser un buffer (local) puis strcpy(), strcat() et dtostrf() (attention à a taille du buffer) ou alors sprintf() (qui consommera un peu plus de mémoire car c'est une grosse fonction). Si ça vous intéresse de mettre cette alternative, voici 3 variantes (bien sûr il ne faudra en conserver qu'une !)

    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
    void maj(EthernetClient& nomClient)
    {
      float temperatureMoyenne = temperature(LM35Pin, 10);  // on calcule la moyenne de la température sur quelques échantillons
     
      // on va renvoyer un JSON
      arHtml(nomClient, F("application/json"));
     
      // on construit et emet notre JSON par petits bouts
      // avantage: pas de buffer, on peut conserver les chaînes en mémoire flash ce qui économise la SRAM
      nomClient.print(F("{\"bouton\":\""));
      if (digitalRead(ledPin) == HIGH)
        nomClient.print(F("ledOn"));
      else
        nomClient.print(F("ledOff"));
      nomClient.print(F("\",\"temperature\":"));
      nomClient.print(temperatureMoyenne, 2); // on emet la température avec 2 chiffres après la virgule
      nomClient.println(F("}"));
     
      /* solutions alternatives: on construit le JSON dans un buffer */
      const byte tailleMaxJSONBuffer = 50;
      char JSONBuffer[tailleMaxJSONBuffer]; // s'assurer qu'on a la place nécessaire
     
      /*version alternative #1: on utilise sprintf.
         inconvénients:
          - on a besoin d'un buffer temporaire
          - les chaînes ne seront pas en mémoire flash et prendront de la SRAM
          - sprintf est une grosse fonction qui prendra de la place en mémoire programme
      */
      sprintf(JSONBuffer, "{\"bouton\":\"%s\",\"temperature\":%.2f}", (digitalRead(ledPin) == HIGH) ? "ledOn" : "ledOff", (double) temperatureMoyenne);
      nomClient.println(JSONBuffer);
     
      /* solution alternative #2: on remplit le buffer un peu plus "à la main".
        inconvénients:
        - on a besoin d'un buffer temporaire
        - les chaînes ne seront pas en mémoire flash et prendront de la SRAM
        - les fonctions strcpy, strcat, dtostr occupent un peu de mémoire programme mais sont relativement peu couteuses et sans doute déjà utilisées ailleurs dans les bibliothèques
      */
      strcpy(JSONBuffer, "{\"bouton\":\"");
      if (digitalRead(ledPin) == HIGH)
        strcat(JSONBuffer, "ledOn");
      else
        strcat(JSONBuffer, "ledOff");
      strcat(JSONBuffer, "\",\"temperature\":");
      char* finDeChaine1 = JSONBuffer + strlen(JSONBuffer); // on cherche la fin, finDeChaine pointe sur le '\0' final
      dtostrf((double) temperatureMoyenne, 5, 2, finDeChaine1); // on concatène la conversion de la valeur au bon endroit
      strcat(JSONBuffer, "}");
      nomClient.println(JSONBuffer);
     
      /* solution alternative #3: on remplit le buffer un peu plus "à la main" et on utilise des chaînes en mémoire programme
        inconvénients:
        - on a besoin d'un buffer temporaire
        - c'est assez lourd à écrire
        - les fonctions strcpy_P, strcat_P sont spécifique au monde AVR. elles occupent un peu de mémoire programme mais sont relativement peu couteuses et sans doute déjà utilisées ailleurs dans les bibliothèques
      */
      const char jsonStart[]  PROGMEM = "{\"bouton\":\"";
      const char jsonLedON[]  PROGMEM =  "ledOn";
      const char jsonLedOFF[] PROGMEM =  "ledOff";
      const char jsonMiddle[] PROGMEM =  "\",\"temperature\":";
      const char jsonEnd[]    PROGMEM =  "}";
     
      strcpy_P(JSONBuffer, jsonStart);
      if (digitalRead(ledPin) == HIGH)
        strcat_P(JSONBuffer, jsonLedON);
      else
        strcat_P(JSONBuffer, jsonLedOFF);
      strcat_P(JSONBuffer, jsonMiddle);
      char* finDeChaine2 = JSONBuffer + strlen(JSONBuffer); // on cherche la fin, finDeChaine pointe sur le '\0' final
      dtostrf((double) temperatureMoyenne, 5, 2, finDeChaine2); // on concatène la conversion de la valeur au bon endroit
      strcat_P(JSONBuffer, jsonEnd);
      nomClient.println(JSONBuffer);
     
    }

  9. #9
    Membre actif
    Bonjour,

    Ce tutoriel est génial

    Bien vu, le lien vers le clone Arduino UNO avec Ethernet intégré

    Je travaille sur quelque chose de très similaire : des arduinos UNO reliés entre eux par Ethernet, mais avec en plus un écran TFT tactile sur chaque Arduino

    J'en ai beaucoup bavé mais ça fonctionne : https://www.developpez.net/forums/d2...s-arduino-uno/

    Une fusion entre ton tutoriel et mon projet aboutit à quelque chose de vraiment versatile : autant de modules que l'on veux avec chacun un bel écran couleur tactile, avec en plus un pilotage possible via un navigateur depuis un smartphone ou un ordinateur.

    Et comme tout fonctionne en câblage ethernet sur un réseau local (pas besoin de connectivité Internet et le WIFI peut être limité à ce qui est nécessaire avec un NANO ESP comme passerelle) on a un système fiable, immunisé contre les interférences et le piratage.

    A bientôt

  10. #10
    Rédacteur

    Bonjour .

    @Jay M

    Citation Envoyé par Jay M Voir le message
    Certes ! Si on me demande, sur des sujets que je maitrise et que j'ai le temps, je veux bien
    : relire du code C écrit pour de l'Arduino, ça a l'air d'être dans vos cordes.

    Citation Envoyé par Jay M Voir le message
    Il vaut mieux mettre en global ce que l'on veut partager entre toutes les fonctions et laisser en local le reste.
    Je suis bien d'accord.

    Citation Envoyé par Jay M Voir le message
    d'un point de vue émission ça ne change rien si on l'envoie par petits bouts.
    À l'évidence puisque les différents fichiers sont envoyés caractère par caractère.

    Citation Envoyé par Jay M Voir le message
    Si ça vous intéresse de mettre cette alternative, voici 3 variantes
    Je ne vais pas intégrer l'un de ces codes pour les deux raisons suivantes :
    • remplacer la fonction que vous fournissez dans le code optimisé par l'une des trois variantes que vous proposez ici n'a pas de sens, car du coup, le code serait "moins optimisé";
    • remplacer la mienne n'a non plus pas d'intérêt dans la mesure où j'utilise déjà la classe String dans le reste du tutoriel. La différence d'impact mémoire sera négligeable.

    Par contre, je vais les garder "sous le coude" pour un éventuel usage ultérieur .

    Citation Envoyé par Jay M Voir le message
    bien sûr il ne faudra en conserver qu'une !
    Je sais que mon code C n'est pas tip-top mais quand même .

    Petite remarque en rapport avec un post précédent. Le code :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    (digitalRead(ledPin) == HIGH) ? "ledOn" : "ledOff"

    est typique des raccourcis que j'ai qualifié de "magique" utilisés en C et qui n'ont aucun sens si on n'a pas le décodeur, ce qui est potentiellement le cas de ceux qui se sont mis au C uniquement pour programmer dans l'environnement Arduino.


    @electroremy

    Citation Envoyé par electroremy Voir le message
    Ce tutoriel est génial
    Merci .

    Citation Envoyé par electroremy Voir le message

    Je travaille sur quelque chose de très similaire : des arduinos UNO reliés entre eux par Ethernet, mais avec en plus un écran TFT tactile sur chaque Arduino
    J'en ai beaucoup bavé mais ça fonctionne
    Beau boulot .

    Citation Envoyé par electroremy Voir le message

    le WIFI peut être limité à ce qui est nécessaire avec un NANO ESP comme passerelle
    À partir du moment où tu utilises la WiFi, tu ouvres une porte sur l'extérieur. Mais bon ! qui va venir te pirater et est-ce qu'il y a vraiment quelque chose à pirater ? Honnêtement, dans mes réalisations, je ne tiens pas compte de ça. Mais peut-être que dans ton cas ça a une importance.

    Amicalement,
    naute

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

    Moi j'adore cette série d'articles parce que c'est très progressif. Je ne suis pas familier avec html, css, js et ajax donc il faut y aller doucement.

    Et ceux qui auront assimilé pourront facilement transposer s'ils utilisent d'autres cartes, comme des ESP8266/ESP32, avec d'autres bibliothèques.


  12. #12
    Responsable Modération

    Bonsoir Naute

    Un grand pour ce travail et les tutos.

    Citation Envoyé par naute Voir le message
    Je ne connais pas bien le C. Si l'EDI Arduino utilisait le Pascal (dans lequel, d'ailleurs, le traitement des chaînes de caractère est très différent) je serais au paradis, mais ce n'est pas le cas.
    Apparemment FreePascal peut compiler pour AVR et serait donc compatible avec les Arduino utilisant cette architecture. Mais cela implique de renoncer (du moins partiellement) aux librairies Arduino, et puis c'est encore en bêta.
    Un mal pour un bien , mais j'ai bien envie d'essayer.

    Bonne suite

    Delias

  13. #13
    Membre expérimenté
    Citation Envoyé par naute Voir le message
    @Jay M
    ...
    est typique des raccourcis que j'ai qualifié de "magique" utilisés en C et qui n'ont aucun sens si on n'a pas le décodeur,
    Mais c’est comme tout langage il faut avoir lu la doc et se former.

    L’opérateur ternaire existe dans plusieurs langage quand même ... Par exemple en C,C++, Objective C, C#, SWIFT, Java, JavaScript, voire dans ADA, Python3 ou FORTRAN sous une autre syntaxe. On le trouve aussi dans le scripting comme bash, action script, ...

    Pascal ne l’a pas (peut être en overload/variants avec IFF) mais vous trouvez quelque chose de similaire dans Object Pascal/Delphi avec IfThen

  14. #14
    Rédacteur

    Bonjour .

    @f-leb et Delias
    Merci pour vos encouragements : ça fait toujours plaisir .

    @Delias
    Citation Envoyé par Delias Voir le message
    Apparemment FreePascal peut compiler pour AVR et serait donc compatible avec les Arduino utilisant cette architecture
    Lazarus offre effectivement la possibilité de choisir parmis plusieurs CPU cible, dont l'AVR. L'un des problèmes réside dans la procédure de téléversement "non assisté" du binaire, mais ça reste faisable. Par contre, le problème d'accès aux bibliothèques, auquel tu fais allusion, est plus embêtant car il obligera, à priori, à travailler directement avec les registres du processeur, ce qui ne sera pas du goût de tout le monde, sans parler de la gestion des différents shields pour lesquels il faudra bien coder les pilotes, de même que pour les capteurs. On se rapproche du hardware et, toute proportion gardée, de la programmation en assembleur, et on perd dans une certaine mesure l'intérêt du langage de haut niveau.

    Tout ça dépasse un peu les capacités de l'utilisateur moyen, dont je fais partie. Toutefois, si quelques développeurs pêchus et intéressés pouvait nous concocter les unités Pascal ad hoc, comme d'autres le font avec les bibliothèques C, ça pourrait déboucher sur quelque chose d'intéressant. Seulement voila ! pour le C, ça s'est fait au fur et à mesure de la croissance de la plateforme Arduino, alors que pour le Pascal, il y a tout à faire. Je pense que c'est un trop gros boulot.

    @Jay M

    Citation Envoyé par Jay M Voir le message
    Mais c’est comme tout langage il faut avoir lu la doc et se former.
    On pourrait dire exactement la même chose sur les "nombres magiques". Il suffit de savoir à quoi ils correspondent, donc avoir lu la doc y afférente. Cela dit, polémiquer sur ce sujet n'a pas grand intérêt, surtout que je pense que nous sommes d'accord sur le fond.

    Citation Envoyé par Jay M Voir le message

    L’opérateur ternaire existe dans plusieurs langage quand même ... Par exemple en C,C++, Objective C, C#, SWIFT, Java, JavaScript, voire dans ADA, Python3 ou FORTRAN sous une autre syntaxe. On le trouve aussi dans le scripting comme bash, action script, ...
    Pascal ne l’a pas (peut être en overload/variants avec IFF) mais vous trouvez quelque chose de similaire dans Object Pascal/Delphi avec IfThen
    Je n'ai jamais dit le contraire et je répète que je n'ai rien contre le C que je n'incrimine en aucune façon. Je veux simplement dire qu'un nombre certainement non négligeable d'utilisateurs Arduino ne sont pas informaticiens, mais sont plutôt comme moi des "bidouilleurs" multiusage et n'ont pas forcément envie (ou le temps , ou quoi que ce soit d'autre) de plonger dans les arcanes d'un langage particulier, et en l'occurrence, Pascal ne fait pas exception à la règle, mais sont plutôt à la recherche d'une "recette de cuisine", pour peu qu'elle ne soit pas trop indigeste, pour satisfaire leurs éventuelles attentes. Je propose quant à moi, une recette qui fonctionne, mais qui, eu égard à la limitation de mes connaissances culinaires, n'est pas parfaite : et c'est là que vous intervenez pour améliorer le produit .

    Bon week-end,
    naute

  15. #15
    Membre expérimenté
    Je ne polémiquais pas - mais je pourrai (de manière constructive) discuter sur la comparaison avec les nombres magiques. L’un est du domaine de la connaissance du langage utilisé, l’expression ternaire est fréquente, et l’autre du domaine des bonnes pratiques recommandées par des pros et plus applicable aux gros programmes - c’est bcp plus subjectif et discutable j’en conviens pour des petits programmes d’un utilisateur occasionnel.

    Cependant personne n’est choqué quand on déclare un numéro de broche en constante ou #define (un pro dirait préférez l’usage de const byte pour des raisons de cohérence sémantique que le compilateur peut vérifier et d’usage mémoire) plutôt que de voir ce même numéro traîner dans tous les digitalRead() ou digitalWrite() dans le code. On comprend intuitivement que c’est plus simple comme cela a changer la pin sur laquelle on a branché une LED et c’est plus facile de lire (mais plus long à taper)
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    const byte brocheLedVerte = 3;   // LED Verte  sur D3 avec une résistance de limitation de courant de 220 Ohms en série connectée à GND
    const byte brocheNiveauSon = A1; // broche centrale du potentiomètre de réglage du niveau sonore connectée sur la pin analogique A1. (les 2 autres broches sur 5V et GND)
     
    ...
     
    digitalWrite(brocheLedVerte, HIGH);
    int niveauSon = analogRead(brocheNiveauSon);
    que
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    digitalWrite(3,1);
    int z = analogRead(55);
    dans cet exemple le second code marche pour MEGA (pin 55 = A1) mais pas sur UNO. on a perdu la portabilité.

    Comme la grande majorité des tutos nomme les broche, la majorité des codes des débutants que je vois passer le font aussi. Le mimétisme a du bon en pédagogie.

    Mon point de vue est que certains débutants se prendront aux jeu et feront carrière dans l’informatique. Ce fut mon cas il y a de nombreuses décennies. Prendre alors dès le départ des bonnes habitudes c’est bien, et je vois le rôle des tutos comme importants dans la transmission de ces bonnes pratiques.

    En plus çà n’est pas vraiment compliqué mais chacun fait bien comme il veut bien sûr, il ne s'agit pas pour moi de critiquer, juste d'exprimer ma vision d'une certaine ambition que l'on pourrait avoir dans la transmission du savoir.

    —/-

    Concernant Pascal c’est plus compliqué car on est un peu plus loin du matériel ce qui est important quand on doit gérer un timing précis, accéder à it particulier dans un registre (Ptr()) ou de a mémoire, gérer un protocole bas niveau. Ce n’est pas par hasard qu’une grande majorité des OS dominants du marché sont aujourd’hui écrit en C et C++.

    Ce serait sans doute plus jouable de travailler sur la phase d’édition de lien dans la compilation pout voir comment créer un pont entre des bibliothèques C++ compilées et ce que génère le compilateur pascal. Il faudra sans doute encapsuler en C les fonctions principales des bibliothèques mais c’est moins de travail que de tout récrire.

    Voici Un article sur la jonction entre C et (Free) Pascal par exemple

  16. #16
    Rédacteur

    Bonjour Jay M .


    Citation Envoyé par Jay M Voir le message
    Je ne polémiquais pas
    Pas d'inquiétude : ce n'était pas dirigé contre vous. Je m'incluais dans la "polémique". Je vous réponds en dehors de toute polémique.

    Citation Envoyé par Jay M Voir le message
    Cependant personne n’est choqué quand on déclare un numéro de broche en constante ou #define (un pro dirait préférez l’usage de const byte pour des raisons de cohérence sémantique que le compilateur peut vérifier et d’usage mémoire)
    Mon code :
    Code arduino :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    const int carteSD = 4;
    const int led = 2;
    const byte LM35 = 0;

    montre bien que je pratique ainsi.

    Citation Envoyé par Jay M Voir le message
    plutôt que de voir ce même numéro traîner dans tous les digitalRead() ou digitalWrite() dans le code. On comprend intuitivement que c’est plus simple comme cela a changer la pin sur laquelle on a branché une LED et c’est plus facile de lire (mais plus long à taper)
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    const byte brocheLedVerte = 3;   // LED Verte  sur D3 avec une résistance de limitation de courant de 220 Ohms en série connectée à GND
    const byte brocheNiveauSon = A1; // broche centrale du potentiomètre de réglage du niveau sonore connectée sur la pin analogique A1. (les 2 autres broches sur 5V et GND)
     
    ...
     
    digitalWrite(brocheLedVerte, HIGH);
    int niveauSon = analogRead(brocheNiveauSon);
    que
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    digitalWrite(3,1);
    int z = analogRead(55);
    Mon code :
    Code arduino :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    {
      digitalWrite(led, HIGH);
    }
    else if (reception == "OFF")
    {
      digitalWrite(led, LOW);
    }

    montre également que je pratique ainsi.

    En ce qui concerne le libellé de ces constantes (ou des variables d'ailleurs, ce qui est techniquement la même chose), cela dépend de la sensibilité de chacun. Par exemple, dans ce tutoriel on utilise une seule LED. Nommer "led" la constante permettant d'y faire référence ne me semble pas vraiment critiquable. Je ne vois pas comment ça pourrait être source de confusion ou d'incompréhension.

    En ce qui concerne les commentaires, je ne livre pas précisément le code "brut de coulée". Il est inclus dans du texte dont la raison d'être est justement de l'expliciter. C'est, me semble-t-il, le but même du tutoriel. J'estime que dans ce cas, les commentaires inclus dans le code alourdiraient celui-ci et feraient double emploi. Mais ce n'est effectivement que mon point de vue.

    En ce qui concerne la portabilité, ce tutoriel est principalement dédié à la carte UNO équipée du shield Ethernet2, et accessoirement à des clones compatibles. Si on reste dans ce contexte, la compatibilité est assurée.

    Citation Envoyé par Jay M Voir le message
    Comme la grande majorité des tutos nomme les broche, la majorité des codes des débutants que je vois passer le font aussi. Le mimétisme a du bon en pédagogie.
    C'en est même l'un des pilier : l'apprentissage par l'exemple.

    Citation Envoyé par Jay M Voir le message
    Prendre alors dès le départ des bonnes habitudes c’est bien, et je vois le rôle des tutos comme importants dans la transmission de ces bonnes pratiques.
    Je ne peux qu'être d'accord avec ça.

    Donc, globalement, nous sommes sur la même longueur d'onde, avec seulement, peut-être, quelques petites divergences sur la façon qu'aura le lecteur d'appréhender les explications et de faire le lien entre celles-ci et le code concerné. Il m'est arrivé comme à d'autres de lire des bouquins traitant d'un même sujet, mais abordé de manière différente. Aucun n'était parfait (pour autant que ça veuille dire quelque chose) mais tous étaient intéressants.

    Par contre, là :
    Citation Envoyé par Jay M Voir le message
    Ce n’est pas par hasard qu’une grande majorité des OS dominants du marché sont aujourd’hui écrit en C et C++.
    je suis moins d'accord (mon côté Pascalien, probable ). Sans prétendre détenir la vérité, j'ai un point de vue différent :
    • C et Pascal sont nés à peu près en même temps mais dans deux optiques différentes : C pour réécrire UNIX et Pascal dédié à l'enseignement de la programmation. On vois déjà là que l'avenir de ces deux langages va être différent ;
    • Pascal est verbeux et impose beaucoup de rigueur dans la programmation. Pas très geek ;
    • et surtout, Pascal est resté "propriétaire" très longtemps, donc payant, pendant que C était distribué dans les universités américaine pour une bouchée de pain, ce qui a largement nuit à sa "propagation".

    Une fois que la place a été occupée, la messe a été dite. Mais ce n'était pas lié spécifiquement, à l'époque, à une réelle différence dans les fonctionnalités.
    Citation Envoyé par wikipédia

    Le système d'exploitation des ordinateurs Apollo, ainsi qu'une partie du système du Macintosh ont été écrits en Pascal. La première version d'Adobe Photoshop également. Le compilateur GCC a été développé par Richard Stallman à partir d'un compilateur du LLNL, qui était écrit en langage Pastel, une extension du langage Pascal.
    Citation Envoyé par Jay M Voir le message

    Ce serait sans doute plus jouable de travailler sur la phase d’édition de lien dans la compilation pout voir comment créer un pont entre des bibliothèques C++ compilées et ce que génère le compilateur pascal. Il faudra sans doute encapsuler en C les fonctions principales des bibliothèques mais c’est moins de travail que de tout récrire.
    Ce serait certainement une meilleure option, mais qui n'est, je le crains, pas de mon niveau.

    Citation Envoyé par Jay M Voir le message
    Merci pour le lien .

    Amicalement,
    naute

  17. #17
    Membre expérimenté
    Salut @Naute

    oui on est d'accord et vous utilisez bien des noms pour les pins. le faire pour le reste c'est bien aussi est ce que j'essayais de dire.
    (bon on pourrait chipoter sur le const byte et le const int pour des raisons de cohérence mais au final le compilateur va les dégager)

    J'ai appris dans l'ordre le Fortran, le basic, le pascal, l'assembleur, le C et C++ et ensuite plein d'autres langages (dont certains très exotiques !) et j'ai beaucoup codé en Pascal et c'est un langage que j'ai bien aimé et je vous rejoins sur la rigueur nécessaire que je trouve un de ses points forts. C'est d'ailleurs pour cela sans doute que je chipote souvent sur des façons d'écrire en C (respect sémantique, usage du typage correct etc).

    Aujourd'hui si vous regardez des langages comme Swift, vous allez retrouvez des obligations de rigueur, donc ça revient


    Citation Envoyé par Jay M Voir le message
    Ce n’est pas par hasard qu’une grande majorité des OS dominants du marché sont aujourd’hui écrit en C et C++.
    je suis moins d'accord (mon côté Pascalien, probable ). Sans prétendre détenir la vérité, j'ai un point de vue différent :
    --> oui pour l'histoire. Je parle bien des OS dominants d'aujourd'hui. Le succès d'Unix dans le monde universitaire a aussi permis l'émergence de bibliothèques et code gratuits qui ont accéléré son adoption. Aujourd'hui on trouve UNIX ou quasi Unix à peu près partout dans le monde commercial, Linux sur une majorité de serveurs, Android, Chrome OS, Apple bien sûr utilise Unix sur tous ses produits, mais même Windows10 s'ouvre avec son initiative WSL.

  18. #18
    Rédacteur

    Bonjour Jay M .

    Citation Envoyé par Jay M Voir le message
    J'ai appris dans l'ordre le Fortran, le basic, le pascal, l'assembleur, le C et C++ et ensuite plein d'autres langages (dont certains très exotiques !)
    En ce qui me concerne, j'ai commencé par le Basic (très basique, sur TRS80), puis l'assembleur (8 bits, qui m'a facilité plus tard l'apprentissage de l'assembleur utilisé pour programmer les microcontrôleurs de MicroChip), puis le Pascal (TP4) et enfin le Pascal Objet (Delphi d'abord et Lazarus quand je suis passé à GNU-Linux).
    Je me suis par la suite intéressé au C, à Python et à Javascript pour pouvoir aborder, à petit niveau, des domaines que Pascal ne couvrait pas. Je ne compte pas le HTML et le CSS qui sont plutôt des langages de description de page. C'est avec Pascal que je suis le plus à l'aise, ce qui ne veut pas dire que je fasse des prouesses, mais je m'en sors correctement.

    Citation Envoyé par Jay M Voir le message
    Aujourd'hui si vous regardez des langages comme Swift, vous allez retrouvez des obligations de rigueur, donc ça revient
    Je veux bien vous croire, mais je pense honnêtement qu'il est plus raisonnable de me cantonner aux langages que je viens de citer et d'essayer d'y progresser dans la mesure du possible (pour faire de meilleurs tutos ).

    Amicalement,
    naute

  19. #19
    Membre expérimenté
    Citation Envoyé par naute Voir le message
    Bonjour Jay M .
    Je veux bien vous croire, mais je pense honnêtement qu'il est plus raisonnable de me cantonner aux langages que je viens de citer et d'essayer d'y progresser dans la mesure du possible (pour faire de meilleurs tutos ).
    Oui - Tout dépend du temps que vous pouvez y consacrer, des envies et des besoins. j'avais envie de développer des apps sur iPhone et iPad donc après Objective C, Swift était le passage obligé. Mais j'aime beaucoup ce langage à cause de son formalisme tout en permettant une flexibilité des langages modernes.

    j'ai pas mentionné toute la patrie web (HTML, CSS) car effectivement je ne classe pas vraiment cela dans le développement, c'est plus une couche d'UI/UX.

    après ça maintient les neurones en activité, c'est bon pour la santé

    PS/ et j'ai eu aussi mon ZX81, mon TRS80, un clone d'Apple II (un ITT 2020) et d'autres gadgets aux début de la grande époque

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



    Hervé, j'ai repris le tuto et tes codes pour l'adapter à un DevKit ESP32


    Une LED simule l'ouverture/fermeture de la serre, et la température est mesurée avec une sonde DS18B20.

    Le serveur est géré avec la bibliothèque ESPASyncWebServer (requêtes asynchrones). Les fichiers html, css, js et images sont en mémoire Flash grâce au système de fichiers SPIFFS.

    J'ouvrirai une discussion pour détailler tout ça

    Edit : la discussion ouverte ici

###raw>template_hook.ano_emploi###