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 :

Effectuer une association entre deux tableaux


Sujet :

Arduino

  1. #61
    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
    Ca c'est une bonne idée, quitte à avoir les noms autant les utiliser pour ne pas avoir les enums.
    Les commandes des aiguilles ou des boutons (comme dans gareInitialisation()) se fait, dorénavent en invoquant le nom de l'objet, par exemple bpCommande("C2_V1"); ou aigCommande("B1_G");.
    La lecture en diagonale du code me rappelle votre message:
    Citation Envoyé par jpbbricole Voir le message
    mais il faut essayer da faire au plus simple, afin de ne pas effaroucher les gens qui débutent.
    Je suppose que ça démontre que quand on veut faire quelque chose d'un peu riche, on ne peut pas faire si "simple" que cela...

    bravo pour le boulot

    PS attention - la pin 0 doit être en input (Rx) si vous voulez utiliser Serial et vaut mieux pas faire de digitalWrite() dessus.

  2. #62
    Membre émérite
    Avatar de jpbbricole
    Homme Profil pro
    Retraité des réseaux informatiques
    Inscrit en
    Février 2013
    Messages
    1 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Retraité des réseaux informatiques
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Février 2013
    Messages : 1 012
    Points : 2 341
    Points
    2 341
    Par défaut
    Bonjour Jay M

    Citation Envoyé par Jay M Voir le message
    Ca c'est une bonne idée, quitte à avoir les noms autant les utiliser pour ne pas avoir les enums.
    Dans mes programme j'utilise, presque toujours, ce principe qui permet de "commander" le programme depuis la console ou depuis le port série du Bluetooth par exemple, ce qui ouvre pas mal de perspectives. Ainsi, dans ce programme, il serait possible, depuis la console, d'envoyer A2_G pour bouger une aiguille ou C1_V2 pour emuler la pression d'un bouton poussoir. Quelques lignes de programme suffisent à saisir ces ordres.

    Citation Envoyé par Jay M Voir le message
    La lecture en diagonale du code me rappelle votre message:
    Je suppose que ça démontre que quand on veut faire quelque chose d'un peu riche, on ne peut pas faire si "simple" que cela...
    Je plaide coupable, le sujet est tellement "inspirant", mais je pensait être resté dans le "calibre" Arduino.

    Citation Envoyé par Jay M Voir le message
    PS attention - la pin 0 doit être en input (Rx) si vous voulez utiliser Serial et vaut mieux pas faire de digitalWrite() dessus.
    Les pin à 0 des tableaux signifient pin non utilisée et j'ai oublié de mettre cette condition.

    Cordialement
    jpbbricole
    L'expérience est la seule chose qu'il ne faut acheter que d'occasion!

  3. #63
    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
    Citation Envoyé par jpbbricole Voir le message
    Je plaide coupable, le sujet est tellement "inspirant", mais je pensait être resté dans le "calibre" Arduino.
    Oui difficile de faire simple quand le cahier des charges s'étoffe. Par exemple, ce code n'est pas pour un débutant à mon avis vu le nombre d'indirections
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    String initCmd = aiguilles[aig].nom + "_" + aigPosLabelSh[aiguilles[aig].position];
    aigCommande(aiguilles[aig].nom + "_" + aigPosLabelSh[aiguilles[aig].position], false);
    c'est un peu la remarque que vous m'aviez faite sur mes nouvelles structures. Mais c'est OK, le projet est ambitieux, le code doit l'être aussi


    Citation Envoyé par jpbbricole Voir le message
    Les pin à 0 des tableaux signifient pin non utilisée et j'ai oublié de mettre cette condition.
    Oui j'avais compris (c'est pour cela que je proposais 255 dans ma version au moins ça ne mangeait pas une pin si on ne veut pas de Serial) et c'est normal de ne pas penser toujours à tout. La relecture de code ça aide toujours. Tous les développeurs passent par là.

    A ce sujet, vous n'avez pas ce bug pour le moment mais dans le futur il pourrait se produire: Vous appelez aigPosLabelSh[aiguilles[aig].position] et la position peut prendre une valeur parmi trois
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     enum aiguillesPositionIndex {aigPosGauche, aigPosDroite, aigPosNull};
    mais votre tableau aigPosLabelSh[] n'a que deux entrées. Je proposerais en première solution (si vous ne voulez pas tester si c'est droite ou gauche) de faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    String aigPosLabelSh[] ={"G", "D", "X"};
    . (et je donnerais comme type 'byte' à l'énumération aiguillesPositionIndex et réutiliserait ce type dans les struct au lieu de byte par cohérence)


    Dans mes programme j'utilise, presque toujours, ce principe qui permet de "commander" le programme depuis la console ou depuis le port série du Bluetooth par exemple, ce qui ouvre pas mal de perspectives. Ainsi, dans ce programme, il serait possible, depuis la console, d'envoyer A2_G pour bouger une aiguille ou C1_V2 pour emuler la pression d'un bouton poussoir. Quelques lignes de programme suffisent à saisir ces ordres.
    Oui c'est effectivement un moyen simple de tester sans avoir à mettre 36 boutons, on peut même s'en servir pour automatiser le test de code. C'est une bonne pratique d'avoir une API.

    Ma recommendation cependant vu votre bon niveau de compréhension serait d'explorer (même si c'est un peu rébarbatif au départ) la notion de cString. Sur une MEGA la mémoire reste limitée et l'usage fréquent comme vous le faites de concaténation et changement de String va morceler la mémoire et un jour ça va crasher sans qu'on sache pourquoi sur un Stack Overflow.

    Bien sûr on doit gérer à la main la taille du buffer mémoire mais il n'y a que quelques fonctions à connaître vraiment

    - strcpy() pour copier une chaîne dans une autre
    - strcat() pour concatèner deux chaînes
    - strdup() pour dupliquer une chaîne
    - strchr() ou strstr() pour rechercher au sein d'une chaîne
    - strcmp() pour comparer deux chaînes

    si on a de la place mémoire on peut utiliser sprintf() et sscanf() pour fabriquer des buffers un peu compliqués ou les analyser

    Vous trouverez toutes ces fonctions dans les bibliothèques string.h et stdlib.h/ (toutes les deux incluses par défaut)

    à l'occasion si vous vous ennuyez, ça peut occuper un week end pluvieux !

  4. #64
    Membre habitué
    Avatar de Jsiorat
    Homme Profil pro
    RETRAITE
    Inscrit en
    Juillet 2005
    Messages
    398
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 78
    Localisation : France, Ariège (Midi Pyrénées)

    Informations professionnelles :
    Activité : RETRAITE

    Informations forums :
    Inscription : Juillet 2005
    Messages : 398
    Points : 169
    Points
    169
    Par défaut
    Citation Envoyé par jpbbricole Voir le message
    Bonjour Jacques

    Ah!!! avoir remis le doigt de l'engrenage du train et de la programmation!!!, la dernière fois doit dater de plus de 30 ans!. Il faut dire que c'est super ce que l'on peut faire avec ces Arduino, entre autre.

    Je te "présente" la version multi-boutons, bibliothèque JC_Button.h. Cette version gère, également, les LED.

    J'ai, également travaillé le programme avec des LED Neopixel, c'est superbe! Le GROS avantage d'implémenter ces LED, c'est que ça n'utilises qu'un port sur ton Arduino quelque soit le nombre d'aiguilles, contre 18 actuellement, donc plus qu'un fil (+2 pour l'alim.) qui "court" sous ton pupitre.

    J'ai comme l'impression de prendre ton développement à mon compte!!, si tu en as marre de mes élucubrations ou tu trouves que je vais trop loin, ne te gène pas de me le faire savoir.

    A ta disposition
    Cordialement
    jpbbricole
    Moi, j'apprends ... et de lire le code que tu as écrit, ça me fout un peu le bourdon parce que je sais que je suis incapable d'en écrire autant ! Il y a quelques années, j'étais un "petit spécialiste " de MSAccess. J'ai conçu pas mal de programme pour le compte du Conseil Général à Pau. Ça remonte à l'époque ou François Bayrou était président du CG64 ! Pas hier non plus !
    Mais maintenant, lire, étudier, comprendre et écrire un bout de code en C pour Arduino ... à côté de toi, je me sens minuscule ! je n'ai plus la tète à ça ! Pour info, je n'ai jamais été plus loin que le Certificat d'étude Primaire, et j'ai appris la programmation dans la cabine de mon camion, je transportais des matières dangereuses de puis Lacq, dans le 64 à destination de toute l'Europe. C'était ... il y a ... Bof ! ça fait quelques années ! en 1980 / 85 ...
    Un grand merci pour ce code, étonnamment bien documenté, c'est clair et après une 1ère lecture (en travers comme dit Jay M !), je crois avoir compris l'ensemble ! Et pour savoir si je l'ai assimilé, je vais le modifier afin de l'utiliser pour la partie triage de mon circuit, basé sur le même principe : un bouton pressé provoque une destination bien précise (ex C1_T2 pour depuis C1 aller jusqu'au triage 2) avec l'information supplémentaire que deux aiguillages dans le lot, sont à 3 voies de sortie : Droite, Centre et Gauche. Dans ton code, tu retiens le côté droit et le côté gauche, moi je voudrais rajouter le centre. Pourrais-je te soumettre ces modifications un peu plus tard ?
    Pour ce qui est des LEDS sur le TCO, j'ai prévu un bout de code qui est sur le principe du "chenillard" ! Une suite de 4 ou 5 leds, voire plus, qui clignotent en indiquant quelle est la voie dont on vient de pressé le bouton de commande.

    Merci encore pour avoir passé du temps pour concevoir ce système. Ma petite cervelle va s'en inspirer et je vais transpirer !
    Cordialement, Jacques
    Être vieux, c'est être jeune depuis plus longtemps que les autres !

  5. #65
    Membre habitué
    Avatar de Jsiorat
    Homme Profil pro
    RETRAITE
    Inscrit en
    Juillet 2005
    Messages
    398
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 78
    Localisation : France, Ariège (Midi Pyrénées)

    Informations professionnelles :
    Activité : RETRAITE

    Informations forums :
    Inscription : Juillet 2005
    Messages : 398
    Points : 169
    Points
    169
    Par défaut
    Citation Envoyé par Jay M Voir le message
    Oui c'est effectivement un moyen simple de tester sans avoir à mettre 36 boutons, on peut même s'en servir pour automatiser le test de code. C'est une bonne pratique d'avoir une API.

    Ma recommendation cependant vu votre bon niveau de compréhension serait d'explorer (même si c'est un peu rébarbatif au départ) la notion de cString. Sur une MEGA la mémoire reste limitée et l'usage fréquent comme vous le faites de concaténation et changement de String va morceler la mémoire et un jour ça va crasher sans qu'on sache pourquoi sur un Stack Overflow.

    Bien sûr on doit gérer à la main la taille du buffer mémoire mais il n'y a que quelques fonctions à connaître vraiment

    - strcpy() pour copier une chaîne dans une autre
    - strcat() pour concatèner deux chaînes
    - strdup() pour dupliquer une chaîne
    - strchr() ou strstr() pour rechercher au sein d'une chaîne
    - strcmp() pour comparer deux chaînes

    si on a de la place mémoire on peut utiliser sprintf() et sscanf() pour fabriquer des buffers un peu compliqués ou les analyser

    Vous trouverez toutes ces fonctions dans les bibliothèques string.h et stdlib.h/ (toutes les deux incluses par défaut)

    à l'occasion si vous vous ennuyez, ça peut occuper un week end pluvieux !
    Bonsoir à toutes et tous ...

    Vous vous rendez compte j'espère, que pour un projet de base qui semblait simple (qui vous semblait simple, mais pour moi c'était hyper compliqué), VOUS en êtes arrivé à des considérations sur le code pour en faire 4 pages ! Je ne pensais pas que la discussion prendrait un tour aussi instructif pour tous ! A titre perso, j'ai déconnecté et je suis satisfait d'être à l'origine de tout ceci ! J'espère que tout un chacun pourra en retirer un petit quelque chose !
    Vous avez été sympa, vous avez été très prof, et pour ça ... je vous tire mon chapeau ! Merci Jay M, encore merci jpbbricole, merci Katlyn ...
    Jacques
    Être vieux, c'est être jeune depuis plus longtemps que les autres !

  6. #66
    Membre émérite
    Avatar de jpbbricole
    Homme Profil pro
    Retraité des réseaux informatiques
    Inscrit en
    Février 2013
    Messages
    1 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Retraité des réseaux informatiques
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Février 2013
    Messages : 1 012
    Points : 2 341
    Points
    2 341
    Par défaut
    Bonsoir Jacques

    J'espère t'avoir apporté quelque chose, que je ne t'ai pas trop "embrouillé" avec mes élucubrations "Arduinesques". Je te souhaite bonne continuation et suis à ta disposition pour toutes questions.
    Ah oui!, juste un petit reproche, celui de m'avoir "allumé" sur un sujet que j'avais réussi à éviter, jusqu'ici !! Je pense continuer le programme, pour le sport, jusqu'à l'allumage des blocs secteurs.

    Cordialement
    jpbbricole
    L'expérience est la seule chose qu'il ne faut acheter que d'occasion!

  7. #67
    Membre habitué
    Avatar de Jsiorat
    Homme Profil pro
    RETRAITE
    Inscrit en
    Juillet 2005
    Messages
    398
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 78
    Localisation : France, Ariège (Midi Pyrénées)

    Informations professionnelles :
    Activité : RETRAITE

    Informations forums :
    Inscription : Juillet 2005
    Messages : 398
    Points : 169
    Points
    169
    Par défaut
    Citation Envoyé par jpbbricole Voir le message
    Bonsoir Jacques

    J'espère t'avoir apporté quelque chose, que je ne t'ai pas trop "embrouillé" avec mes élucubrations "Arduinesques". Je te souhaite bonne continuation et suis à ta disposition pour toutes questions.
    Ah oui!, juste un petit reproche, celui de m'avoir "allumé" sur un sujet que j'avais réussi à éviter, jusqu'ici !! Je pense continuer le programme, pour le sport, jusqu'à l'allumage des blocs secteurs.

    Cordialement
    jpbbricole
    Salut,
    J'espère bien t'avoir allumé ! C'est grâce à cette lumière que j'ai pu me coucher le soir un peu plus instruit que je ne l'était auparavant ! Et ça va continuer ! Parce que des "élucubrations" comme celles-ci, je souhaite à toutes et tous d'y prendre goût !
    Chouette ton code ... je doute que l'on puisse écrire mieux ! j'ai juste rectifié l'initialisation de la gare : C1_V1, C2_V2 et C3_V3 en rapport avec les aiguillages. Pour déterminer la droite ou la gauche d'un aiguillage, je me souviens de mes cours quand j'étais jeune conducteur au Métro parisien : on pars du principe qu'on prend l'aiguille en pointe ou en talon ...
    La question que je n'arrive pas à mettre en œuvre ... : dans l'IDE Arduino, on active le moniteur série pour obtenir un résultat (fiable ou pas, peu importe !) Dans la ligne de commande, sous quelle forme je pourrais simuler l'appui su un bp ?
    Être vieux, c'est être jeune depuis plus longtemps que les autres !

  8. #68
    Membre émérite
    Avatar de jpbbricole
    Homme Profil pro
    Retraité des réseaux informatiques
    Inscrit en
    Février 2013
    Messages
    1 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Retraité des réseaux informatiques
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Février 2013
    Messages : 1 012
    Points : 2 341
    Points
    2 341
    Par défaut
    Bonjour Jacques

    Ce n'est pas implémenté dans le version du post #60, je vais modifier cette version, tu verras, ça change la vie pour le développement et pour l'exploitation.

    A +
    Cordialement
    jpbbricole
    L'expérience est la seule chose qu'il ne faut acheter que d'occasion!

  9. #69
    Membre émérite
    Avatar de jpbbricole
    Homme Profil pro
    Retraité des réseaux informatiques
    Inscrit en
    Février 2013
    Messages
    1 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Retraité des réseaux informatiques
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Février 2013
    Messages : 1 012
    Points : 2 341
    Points
    2 341
    Par défaut
    Bonjour Jacques

    J'ai implémente les commandes dans le programme. Ces commandes permettent de commander une aiguille (aig) et ou d'émuler la pression d'un bouton poussoir (bp).
    Tout se passe dans la ligne de commande du moniteur de l'IDE Arduino ou depuis un émulateur série. Le moniteur de l'Arduino doit être paramétré à 115200 et comme fin de ligne, Nouvelle ligne ou Les deux, NL et CR, CR étant éliminé. Ne fonctionnent pas, Retour chariot ou pas de fin de ligne.

    Ces commandes sont, sous la forme individuelle, ainsi:
    AIG=B1_G ou BP=C2_V3 (Aiguille B1 é gauche ou pression du bouton C2_V3)

    Ou sous la forme groupées, separées par une virgule, ainsi:
    AIG=B1_D, AIG=B3_D,BP=C2_V3,AIG=B1_D

    Les commandes ne sont pas sensibles aux majuscules ou minuscules, les espaces sont supprimés.

    Elles peuvent être mises dans le programme sous la forme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    monitCmdRecue("AIG=B3_D");	ou monitCmdRecue("BP=C3_V3"); 
    // ou
    monitCmdRecue("BP=C1_V1,AIG=B3_D,BP=C3_V3");
    Ainsi, l'initialisation de la gare passe de
    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
     
    void gareInitialisation()
    {
    	Serial.println(F("\n\t>>> Initialisation de la gare <<<"));
    	bpCommandeOk = bpCommande("C1_V1", true);
    	bpCommandeOk = bpCommande("C2_V2", true);
    	bpCommandeOk = bpCommande("C3_V3", true);
     
    	Serial.println(F(""));
    }
     
    // à
     
    void gareInitialisation()
    {
    	Serial.println(F("\n\t>>> Initialisation de la gare <<<"));
    	monitCmdRecue("BP=C1_V1,BP=C2_V2,BP=C3_V3");
     
    	Serial.println(F(""));
    }
    Le programme ARDDEV_AiguillagesBledMonit.ino
    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
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    /******************************************************************************
        Name:       Commande d'aiguillages et de leurs LED
        Created:    29.09.2020
        Author:     jpbbricole
            
            Remarques:      Version avec LED et commandes moniteur
    '******************************************************************************
    */
    #include <JC_Button.h>							// https://github.com/JChristensen/JC_Button 
     
    //===================================== Aiguilles
    #define aigMotEtatOn HIGH							                      // Etat pour moteur ON
    #define aigMotEtatOnTemps 50						                      // Moteur, temps de l'impulsiom ON
    enum aiguillesPositionIndex {aigPosGauche, aigPosDroite, aigPosNull};     // Pour indexer le tableau aiguilles[].motGDport[]
    String aigPosLabelSh[] ={"G", "D"};
     
    const int aigLedEtatOn = LOW;                                             // Etat du port pour allumer la LED
    boolean aigCommandOk;
     
    //------------------------------------- Structure de l'objet aiguille
    struct aiguilleDefinition
    {String nom; byte position; int motGDport[2]; int ledGDport[2];};
     
    aiguilleDefinition aiguilles[] =
    {
    	// Position donne la position de l'aiguille au demarrage du programme
    	//Nom,   Position, Moteur G, Moteur D, Led G, LED D   255 = port inutilise
    	{"G1", aigPosDroite, 255,       22,      255,   41},
    	{"A1", aigPosGauche,  23,       24,       42,   43},
    	{"A2", aigPosDroite,  25,       26,       44,   45},
    	{"A3", aigPosGauche,  27,       28,       46,   47},
    	{"A4", aigPosDroite,  29,       30,       48,   49},
    	{"B1", aigPosDroite,  31,       32,       50,   51},
    	{"B2", aigPosDroite,  33,       34,       52,   53},
    	{"B3", aigPosDroite,  35,       36,       A8,   A9},
    	{"B4", aigPosDroite,  37,       38,       A10,  A11}
    };
    const int aigNombreMax = sizeof(aiguilles)/sizeof(aiguilles[0]);
     
    //------------------------------------- Structure de l'objet aiguille en utilisation
    struct aigInUseDef
    {int index; byte motPosition; String motPosLabel; String motPosLabelSh;};
    aigInUseDef aigIu;                      // Aiguille en utilisation
     
    //===================================== Boutons
    #define bpMotNombreMax 4						// Nombre de moteurs max par bouton
    const boolean bpEtatPresseLOW = true;			// Etat lu du bouton presse
    boolean bpCommandeOk = false; 
     
    //------------------------------------- Structure de l'objet bouton d'aiguuille (bpAig)
    struct bpAigDefinition                                                  
    {String nom; byte port; boolean bpOn; String aig_Dir[bpMotNombreMax];};
     
    /*
    	remplissage de la structure des boutons bp[0] a bp[bpNombreMax-1]
    */
    bpAigDefinition bpAig[] = 
    {
    	// Nom,  Port, presse, aigCmd1, aigCmd2, aigCmd2,  aigCmd2 
    	{"C1_V1",  5,   false, "G1_D",   "A1_G",  "A3_D",     ""},
    	{"C1_V2",  6,   false, "G1_D",   "A1_D",  "A4_D",     ""},
    	{"C2_V1",  7,   false, "B1_G",   "B3_D",  "A2_G", "A3_G"},
    	{"C2_V2",  8,   false, "B1_G",   "B3_D",  "A2_D", "A4_G"},
    	{"C2_V3",  9,   false, "B1_D",   "B4_D",      "",     ""},
    	{"C3_V1", 10,   false, "B2_G",   "B3_G",  "A2_G", "A3_G"},
    	{"C3_V2", 11,   false, "B2_G",   "B3_G",  "A2_D", "A4_G"},
    	{"C3_V3", 12,   false, "B2_G",   "B4_G",      "",     ""}
    };
    const int bpNombreMax = sizeof(bpAig)/sizeof(bpAig[0]);
    Button *bpRead[bpNombreMax];                     // JC_Button.h
     
    //===================================== Commandes moniteur
    String monCommandRx;                   // Commande recue
    boolean monCommandNew;                 // Si nouvelle commande
     
     
    void setup()
    {
    	Serial.begin(115200);
     
    	bpInitialisation();
    	aigInitialisation();
    	aigIu.index = -1;                  // Pas d'aiguille selectionnee
     
    	gareInitialisation();
    }
     
    void loop()
    {
    	if (bpScanStatus())				   // S'il y a un bouton presse                             
    	{
    		delay(250);					   // Attendre d'eventuelles autres bp
    		bpScanStatus();
    		bpPressedAction();
    	}
     
    	/*---------------------------------------------------------------------------------------------------------------------- 
    	   Ecoute du moniteur série pour la réception éventuelle de commandes ou paramètres.
    	  ----------------------------------------------------------------------------------------------------------------------
    	*/
    	serialEvent();                     // Lecture du port serie
    	if (monCommandNew)                 // Si reçu une nouvelle commande
    	{
    		monitCmdRecue(monCommandRx);   // Evaluation de la commande
     
    		monCommandRx = "";
    		monCommandNew  = false;
    	}
    }
    //===================================== Aiguilles (aig)
    void aigInitialisation()
    {
    	for (int aig = 0; aig < aigNombreMax; aig ++)
    	{
    		for (int gd = 0; gd < 2; gd ++)
    		{
    			// Initialisation des moteurs d'aiguilles
    			pinMode(aiguilles[aig].motGDport[gd], OUTPUT);
    			digitalWrite(aiguilles[aig].motGDport[gd], !aigMotEtatOn);		// Moteur a l'arrêt
     
    			// Initialisation des LED
    			pinMode(aiguilles[aig].ledGDport[gd], OUTPUT);
    			digitalWrite(aiguilles[aig].ledGDport[gd], !aigLedEtatOn);		// LED eteinte
    		}
     
    		// Mise en position des aiguilles en fonction de aiguilles[x].position
    		String initCmd = aiguilles[aig].nom + "_" + aigPosLabelSh[aiguilles[aig].position];
    		aigCommandOk = aigCommande(aiguilles[aig].nom + "_" + aigPosLabelSh[aiguilles[aig].position], false);
    	}
    }
     
    /*------------------------------------- Commande d'aiguille
    	   G1_D                     A1_G  A3_D         00_0 
    	Äiguille G1 a droite  Äiguille A1 a gauche  Inutilise
    */
    boolean aigCommande(String aigCmd, boolean aigCmdEcho)
    {
    	boolean aigExecOk = false;
     
    	aigCmdSelection(aigCmd);             // Selection des parametres de l'aiguille en fonction de la commande
                                             // dans la structure aigIu (aiguille in use)
    	if (aigIu.index != -1)               // Si aiguille trouvee
    	{
    		aigMouvement(aigIu, aigCmdEcho);
    		aigLedOnOff(aigIu, aigCmdEcho);
     
    		aigExecOk = true;
    	} 
    	else
    	{
    		Serial.print(F("Commande; >> ")); Serial.print(aigCmd); Serial.println(F(" << Inconnue!!!"));
    	}
     
    	return aigExecOk;
    }
     
    /*------------------------------------- Index de l'aiguille
    	Selectionne une aiguille en fonction de la commande aiguille_parametre
    	G1 ou G1_D, recherche G1 dans le tableau aiguilles.nom[n]
    	retourne true si trouvee et renseigne 
    	aigIu.index (-1 si pas trouvee) et 
    	aigIu.motPosition (aigPosGauche , aigPosDroite ou aigPosNull)
    */
    void aigCmdSelection(String aigCmd)
    {
    	String aigName = "";
    	String aigParam = "";                                  // Ce qui est apres le separateur _
    	aigIu.index = -1;
     
    	aigCmd.toUpperCase();                                  // En majuscules
    	byte sepPos = aigCmd.indexOf("_");                     // Position du separateur _
     
    	if (sepPos)
    	{
    		aigName = aigCmd.substring(0, sepPos);             // On retire le _ et le parametre pour garder le nom
    		aigParam = aigCmd;
    		aigParam.replace(aigName + "_", "");               // On retire le nom et _ pour garder le parametre
    	} 
     
    	for (int aig = 0; aig < aigNombreMax; aig ++)          // Recherche si l'aiguille existe
    	{
    		if (aiguilles[aig].nom == aigName)
    		{
    			aigIu.index = aig;
    			break;
    		}
    	}
     
    	if (aigParam == "G")
    	{	
    		aigIu.motPosLabelSh = "G";
    		aigIu.motPosLabel = "Gauche";
    		aigIu.motPosition = aigPosGauche;
    	} 
    	else if (aigParam == "D")
    	{	
    		aigIu.motPosLabelSh = "D";
    		aigIu.motPosLabel = "Droite";
    		aigIu.motPosition = aigPosDroite;
    	}
    	else
    	{	aigIu.motPosition = aigPosNull;}
    }
     
    /*------------------------------------- Aiguille mouvement 
    	parametres dans  structure aigIu
    */
    void aigMouvement(aigInUseDef aigMouv, boolean echoCmd)
    {
    	byte motAigPort = aiguilles[aigMouv.index].motGDport[aigMouv.motPosition];
     
    	digitalWrite(motAigPort, aigMotEtatOn);       // Moteur ON
    	delay(aigMotEtatOnTemps);
    	digitalWrite(motAigPort, !aigMotEtatOn);      // Moteur NOT ON
    	delay(aigMotEtatOnTemps);
     
    	if (echoCmd)
    	{
    		Serial.print(F("\tAiguille ")); Serial.println(aiguilles[aigMouv.index].nom + " " + aigMouv.motPosLabel);
    	}
    }
     
    //------------------------------------- Aiguille led On/Off
    void aigLedOnOff(aigInUseDef aigMouv, boolean echoCmd)
    {
    	int ledOnPort = aiguilles[aigMouv.index].ledGDport[aigMouv.motPosition];     // Led a allumer
    	int ledOffPort = 0;
     
    	if (aigMouv.motPosition == aigPosDroite)                                   // Quelle LED eteindre
    	{
    		ledOffPort = aiguilles[aigMouv.index].ledGDport[aigPosGauche];
    	} 
    	else
    	{
    		ledOffPort = aiguilles[aigMouv.index].ledGDport[aigPosDroite];
    	}
     
    	digitalWrite(ledOnPort, aigLedEtatOn);		           // LED eteinte
    	digitalWrite(ledOffPort, !aigLedEtatOn);		       // LED eteinte
     
    	if (echoCmd)
    	{
    		Serial.print(F("\t\tLED ")); Serial.println(String(ledOnPort) + "\t On");
    		Serial.print(F("\t\tLED ")); Serial.println(String(ledOffPort) + "\t Off");
    	}
    }
     
    //===================================== Boutons poussoir (bp)
    void bpInitialisation()
    {
    	//--------------------------------- Initialisation des bp
    	for (int b = 0; b < bpNombreMax; b ++)
    	{
    		bpRead[b] = new Button(bpAig[b].port, 25, true, bpEtatPresseLOW);			// Port Antirebonds PULL_UP actif a LOW
    		bpRead[b]->begin();
    	}
    }
     
    /*------------------------------------- Commande de bp
    	   C1_V1 ou C2_V3....
    	   le syntaxe se trouve dans la structure bpAig[bpIndex].nom
    */
    boolean bpCommande(String bpCmd, boolean cmdEcho)
    {
    	boolean bpExecOk = false;
     
    	bpCmd.toUpperCase();
     
    	if (cmdEcho)
    	{
    		Serial.print(F("Commande bp ")); Serial.println(bpCmd);
    	}
     
    	for (int b = 0; b < bpNombreMax; b ++)                           // Balayage des bp
    	{
    		if (bpAig[b].nom == bpCmd)                                   // Si le nom du bp correspond
    		{
    			bpMotAction(b, cmdEcho);
    			bpExecOk = true;
    		}
    	}
    	return bpExecOk;
    }
     
    //------------------------------------- Lecture de l'etat des bp
    bool bpScanStatus()
    {
    	boolean bpEvent = false;
     
    	for (int b = 0; b < bpNombreMax; b ++)                           // Balayage des bp
    	{
    		bpRead[b]->read();
    		if (bpRead[b]->wasPressed())
    		{
    			bpAig[b].bpOn = true;
    			bpEvent = true;
    		}
    	}
    	return bpEvent;
    }
     
    //------------------------------------- Si bp est presse, action
    void bpPressedAction()
    {
    	Serial.println(F("\t>>> Aiguillage <<<"));
    	for (int b = 0; b < bpNombreMax; b ++)                           // Lister les boutons presses
    	{
    		if (bpAig[b].bpOn)                                           // Si ce bouton est presse
    		{
    			Serial.println(bpAig[b].nom);
    			bpMotAction(b, true);
    			bpAig[b].bpOn = false;                                   // tache bp b terminee
    		}
    	}
    	Serial.println("");
    }
    //------------------------------------- Mise en action des aiguilles/moteur du bouton
    void bpMotAction(int bpIndex, boolean cmdEcho)
    {
    	for (int mot = 0; mot < bpMotNombreMax; mot ++)                            // Lister les commandes d'aiguilles concernes
    	{
    		if (bpAig[bpIndex].aig_Dir[mot] != "")
    		{
    			aigCommandOk = aigCommande(bpAig[bpIndex].aig_Dir[mot], cmdEcho);  // Encoi de la commande d'aiguillage
    		}
    	}
    }
     
    //===================================== Divers
    //------------------------------------- Initialisation de la gare
    void gareInitialisation()
    {
    	Serial.println(F("\n\t>>> Initialisation de la gare <<<"));
    	monitCmdRecue("BP=C1_V1,BP=C2_V2,BP=C3_V3");
     
    	Serial.println(F(""));
    }
     
    //===================================== Commandes moniteur
    /*
    	Traite les commandes recues via la ligne do commande (moniteur)
    	AIG=B1_G ou BP=C2_V3 commandes individuelles ou 
    	AIG=B1_D, AIG=B3_D,BP=C2_V3,AIG=B1_D commandes groupees separees par une virgule.
    	Les commandes ne sont pas sensibles aux majuscules ou minuscules.
    	Elles peuvent etre mises dans le programme sous la forme:
    	monitCmdRecue("AIG=B3_D");	ou monitCmdRecue("BP=C3_V3"); ou
    	monitCmdRecue("BP=C1_V1,AIG=B3_D,BP=C3_V3");
    */
     
    void monitCmdRecue(String cmdRx)
    {
    	String cmdExec = "";
     
    	cmdRx.toUpperCase();                  // Tout en majuscules
    	cmdRx.replace(" ", "");               // Supprimer les espaces
    	Serial.print(F("\nCommande moniteur:\t")); Serial.println(cmdRx);
     
    	while(cmdRx.indexOf(",") > 0)                 // Tant qu'il y a une virgule
    	{
    		cmdExec = cmdRx.substring(0, cmdRx.indexOf(",") +1);
    		monitCmdExecute(cmdExec);
    		cmdRx.replace(cmdExec, "");
    	}
    	if (cmdRx.length() > 3)                       // S'il reste une commande dans la chaine cmdRx
    	{
    		monitCmdExecute(cmdRx);
    	}
    }
     
     
    void monitCmdExecute(String cmdExec)
    {
    	boolean cmdExecOk = false;
     
    	cmdExec.replace(",", "");                // Supprimer les virgules
     
     
    	if (cmdExec.startsWith("AIG="))          // Commande aiguillage
    	{
    		cmdExec.replace("AIG=", "");
    		cmdExecOk = aigCommande(cmdExec, false);
    	}
    	if (cmdExec.startsWith("BP="))
    	{
    		cmdExec.replace("BP=", "");
    		cmdExecOk = bpCommande(cmdExec, false);
    	}
     
    	Serial.print("Execution de: " + cmdExec);
    	if (cmdExecOk)
    	{
    		Serial.println(F("   = OK"));
    	}
    	else
    	{
    		Serial.println(F("   = Commande inconnue !!!"));
    	}
    }
     
    //===================================== Ecoute du port serie
    void serialEvent()                                                   // IDE monitor or DRO serial
    {
    	while (Serial.available())
    	{
    		char monChar = (char)Serial.read();                          // Char received from IDE monitor
    		if (monChar == '\n')                                         // If new line char received = end of command line
    		{
    			monCommandNew  = true;
    		}
    		else
    		{
    			if (monChar >= ' ') {monCommandRx += monChar;}           // >= ' ' to avoid not wanted ctrl char.
    		}
    	}
    }
    Ce programme n'a pas été testé à 200% donc ...

    Une fois le programme terminé et que l'on n'utilise plus l'environnement de développement, on peut le commander depuis un émulateur de terminal comme Terminal, via le câble USB ou via un interface Bluetooth/Série (HC-05 sous cette forme) (20 minutes de programmation pour l'implémentation), le Mega a assez de ports série, ce qui permet d'utiliser les nombreux interfaces BT (je suis Android) pour smartphone ou tablettes. On pourrait même envisager un programme en VBA dans Excel, par exemple.

    Cordialement
    jpbbricole
    L'expérience est la seule chose qu'il ne faut acheter que d'occasion!

  10. #70
    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 JP

    Bravo pour avoir poussé le boulot jusqu’au bout !

    La fonction serialEvent() est appelée automatiquement pour vous comme la loop(). Normalement on ne la met donc pas dans le code (même si ça ne gène pas de l’appeler plus souvent).

    Pourquoi avez vous un delay 250 et pourquoi rappeler ensuite le test de tous les boutons dans le if?il suffirait de tester les boutons les uns après les autres
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     if (bpScanStatus())				   // S'il y a un bouton presse                             
    	{
    		delay(250);					   // Attendre d'eventuelles autres bp
    		bpScanStatus();
    		bpPressedAction();
    	}

    Je renouvelle mon alerte sur le nombre de String utilisées et toutes leurs mini modifications qui risquent de conduire à un morcellement de la mémoire. Pour le buffer de commande, rajouter un reserve() dans le setup avec disons 50 caractères serait une bonne chose. Passer les String par référence lors des appels de fonction serait aussi à considérer (sinon elles sont dupliquées).

    Pour comprendre pourquoi c’est important d’y faire attention surtout sur un UNO ou MEGA, lisez The Evils of Arduino Strings

  11. #71
    Membre habitué
    Avatar de Jsiorat
    Homme Profil pro
    RETRAITE
    Inscrit en
    Juillet 2005
    Messages
    398
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 78
    Localisation : France, Ariège (Midi Pyrénées)

    Informations professionnelles :
    Activité : RETRAITE

    Informations forums :
    Inscription : Juillet 2005
    Messages : 398
    Points : 169
    Points
    169
    Par défaut
    Citation Envoyé par jpbbricole Voir le message
    Salut Jay M


    ETrop souvent les forums Arduino sont "hantés" par des "bolides" en C et autres C++, souvent en dénigrant le "concept Arduino" et qui répondent en C ou C++ sans respecter le dit concept. Personnellement, je fais, de l'Arduino, du moins je le pense car, sans cette super idée venue d'Italie du nord,
    Bonjour à toutes et tous !
    je suis parfaitement d'accord avec jpbbricole ! En tant que débutant et après avoir navigué sur de nombreux sites qui décrivent le concept Arduino, j'en ai découvert qui ne sont absolument pas utile parce ce que ne sont que des copies du site officiel Arduino. Pour se singulariser, ces sites racontent très souvent du n'importe quoi ce qui va à l'encontre de ce que nous recherchons, nous les apprentis-débutants (!!!).
    J'en ai plus appris à lire, relire, imprimer et re-saisir, tester et re-tester, ce que j'ai pu lire ici, sur ce forum. A titre perso, je reste avec CE forum et ainsi que "LOCODUINO" !
    Jacques, apprenti-débutant-pasencoreconfirmé !
    Être vieux, c'est être jeune depuis plus longtemps que les autres !

  12. #72
    Membre habitué
    Avatar de Jsiorat
    Homme Profil pro
    RETRAITE
    Inscrit en
    Juillet 2005
    Messages
    398
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 78
    Localisation : France, Ariège (Midi Pyrénées)

    Informations professionnelles :
    Activité : RETRAITE

    Informations forums :
    Inscription : Juillet 2005
    Messages : 398
    Points : 169
    Points
    169
    Par défaut
    Citation Envoyé par jpbbricole Voir le message
    Bonjour Jacques

    [/CODE]

    Ce programme n'a pas été testé à 200% donc ...

    Cordialement
    jpbbricole
    Bonjour ... avec le soleil aujourd'hui !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    F:\PROGRAMMATION PERSO\PERSO 10\Gestion_gare-2_jpbbricole\Gestion_gare-2_jpbbricole.ino: In function 'void aigLedOnOff(aigInUseDef, boolean)':
    F:\PROGRAMMATION PERSO\PERSO 10\Gestion_gare-2_jpbbricole\Gestion_gare-2_jpbbricole.ino:224:30: warning: unused parameter 'aigMouv' [-Wunused-parameter]
     void aigLedOnOff(aigInUseDef aigMouv, boolean echoCmd)
                                             ^~~~~~~
    Je ne comprends cette erreur ! (c'est la seule erreur dans tout le code ! CHAPEAU !) Ça n'empêche pas la compilation d'aller jusqu'au bout et là ou je trouve ça bizarre, c'est que quelques lignes plus haut, à la ligne 210, la même commande (aigMouv.index) utilise ce terme sans générer d'erreur.

    Jacques
    Être vieux, c'est être jeune depuis plus longtemps que les autres !

  13. #73
    Membre émérite
    Avatar de jpbbricole
    Homme Profil pro
    Retraité des réseaux informatiques
    Inscrit en
    Février 2013
    Messages
    1 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Retraité des réseaux informatiques
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Février 2013
    Messages : 1 012
    Points : 2 341
    Points
    2 341
    Par défaut
    Bonjour Jay M

    Citation Envoyé par Jay M Voir le message
    Bravo pour avoir poussé le boulot jusqu’au bout !
    Tant qu'à faire et je n'ai pas terminé.

    Citation Envoyé par Jay M Voir le message
    La fonction serialEvent() est appelée automatiquement pour vous comme la loop(). Normalement on ne la met donc pas dans le code (même si ça ne gène pas de l’appeler plus souvent).
    Parce que cela ne fonctionne pas avec tout les Arduino et, en cas de changement de machine, cela ne fonctionne plus!!! et pour trouver le bug??? et "ça ne mange pas de pain"!!!

    Citation Envoyé par Jay M Voir le message
    Pourquoi avez vous un delay 250 ....
    C'est indiqué en remarque // Attendre d'éventuelles autres bp
    Ainsi on peu grouper l'exécution de plusieurs boutons.

    Citation Envoyé par Jay M Voir le message
    Je renouvelle mon alerte sur le nombre de String utilisées et toutes leurs mini modifications...
    Oui, oui et reoui, j'ai lu beaucoup d'explications sur le sujet, je n'ai pas tout compris, ça sort de mes compétences et énormément de paragrammes (la plupart de ceux que j'ai croisés) tarvaillent ainsi! Je m'étonne qu'une classe comme String, qui tient une très grande place sur Arduino Reference soit si "dangereuse" à utiliser. Est-ce-que les gens d'Arduino sont si incompétents ou ces alertes sont le fait de "vieux reac" du C? Je me pose la question.

    Cordialement
    jpbbricole
    L'expérience est la seule chose qu'il ne faut acheter que d'occasion!

  14. #74
    Membre émérite
    Avatar de jpbbricole
    Homme Profil pro
    Retraité des réseaux informatiques
    Inscrit en
    Février 2013
    Messages
    1 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Retraité des réseaux informatiques
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Février 2013
    Messages : 1 012
    Points : 2 341
    Points
    2 341
    Par défaut
    Bonjour Jacques

    Déjà au boulot!
    Ce warning
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    C:\Users\AdminB\Arduino\Croquis\essai\essai.ino: In function 'void aigLedOnOff(aigInUseDef, boolean)':
     
    C:\Users\AdminB\Arduino\Croquis\essai\essai.ino:224:30: warning: unused parameter 'aigMouv' [-Wunused-parameter]
     
     void aigLedOnOff(aigInUseDef aigMouv, boolean echoCmd)
    Signale que l'argument, aigInUseDef aigMouv, passé comme argument dans la fonction aigLedOnOff, n'est pas utilisé dans celle-ci. En fait elle s'appelle aigIu, j'ai oublié de la renommer, ah! les joies du copier/coller. Mais, coup de bol, ça fonctionnais!
    Remplace la fonction void aigLedOnOff(aigInUseDef aigMouv, boolean echoCmd) par celle-ci
    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
    //------------------------------------- Aiguille led On/Off
    void aigLedOnOff(aigInUseDef aigMouv, boolean echoCmd)
    {
    	int ledOnPort = aiguilles[aigMouv.index].ledGDport[aigMouv.motPosition];     // Led a allumer
    	int ledOffPort = 0;
     
    	if (aigMouv.motPosition == aigPosDroite)                                   // Quelle LED eteindre
    	{
    		ledOffPort = aiguilles[aigMouv.index].ledGDport[aigPosGauche];
    	} 
    	else
    	{
    		ledOffPort = aiguilles[aigMouv.index].ledGDport[aigPosDroite];
    	}
     
    	digitalWrite(ledOnPort, aigLedEtatOn);		           // LED eteinte
    	digitalWrite(ledOffPort, !aigLedEtatOn);		       // LED eteinte
     
    	if (echoCmd)
    	{
    		Serial.print(F("\t\tLED ")); Serial.println(String(ledOnPort) + "\t On");
    		Serial.print(F("\t\tLED ")); Serial.println(String(ledOffPort) + "\t Off");
    	}
    }
    A+
    Cordialement
    jpbbricole
    L'expérience est la seule chose qu'il ne faut acheter que d'occasion!

  15. #75
    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
    Bonjour @jP

    quelques commentaires en vrac:

    Citation Envoyé par jpbbricole Voir le message
    Tant qu'à faire et je n'ai pas terminé.
    je n'en doutais pas ! je sais que vous aimez pousser jusqu'au bout les idées

    Citation Envoyé par jpbbricole Voir le message
    Parce que cela ne fonctionne pas avec tout les Arduino et, en cas de changement de machine, cela ne fonctionne plus!!! et pour trouver le bug??? et "ça ne mange pas de pain"!!!
    Bon point. (autant l'appeler différemment dans ce cas pour ne pas avoir de comportement différent selon les Arduinos).

    Citation Envoyé par jpbbricole Voir le message
    C'est indiqué en remarque // Attendre d'éventuelles autres bp. Ainsi on peu grouper l'exécution de plusieurs boutons.
    Oui, c'est ce que je ne comprends pas. Quel est le besoin de traiter le cas où l'utilisateur a appuyé deux boutons à un quart de seconde près ? si j'ai mis 300ms vous traiterez cela au prochain tour non ?

    Citation Envoyé par jpbbricole Voir le message
    Oui, oui et reoui, j'ai lu beaucoup d'explications sur le sujet, je n'ai pas tout compris, ça sort de mes compétences et énormément de programmes (la plupart de ceux que j'ai croisés) tarvaillent ainsi !
    Vous exagérez et minimisez vos compétences, je suis sûr que vous pouvez comprendre si vous le voulez.

    Pour faire simple si on joue avec la classe String on alloue et désalloue de la mémoire en permanence. Cette allocation se fait dans une zone mémoire appelée le TAS. les allocations se font de façon contiguës.

    Imaginez que vous allouez 3 Strings: un bloc A de 3 caractères, puis un bloc B de 2 caractères et un bloc C de 5 caractères. en mémoire dans le TAS ils seront rangés l'un derrière l'autre.
    Nom : t1.png
Affichages : 142
Taille : 25,1 Ko

    Maintenant imaginez que vous vouliez augmenter la taille de B pour passer de 2 à 3 caractères en concaténant un nouveau caractère, un peu comme quand vous faites
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     if (monChar >= ' ') {monCommandRx += monChar;}
    (à chaque caractère reçu vous demandez une extension d'un caractère).

    La classe String va se rendre compte qu'elle n'a plus de place, les 2 caractères de B étant déjà occupés, et va donc demander au TAS un bloc mémoire de 3 octets, puis déplacer les 2 caractères existant là bas et rajouter le 3ème à la fin. L'ancienne zone occupée par B (les deux caractères) va devenir libre, et ne sera utilisable que si quelqu'un demande au TAS un ou deux caractères puisque ces octets sont coincés en mémoire entre A et C => Il se peut que ce petit bloc devienne "perdu" pour le système.
    Nom : tas.png
Affichages : 156
Taille : 46,1 Ko

    Et si vous allouez une chaîne D avant de faire grandir à nouveau B (nouveau caractère reçu sur le port Série par exemple après différents traitements), vous allez potentiellement créer un nouveau trou
    Nom : nouv.png
Affichages : 151
Taille : 50,7 Ko


    Quand vous faites par exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     Serial.println(String(ledOnPort) + "\t On");
    vous générez une première String en convertissant la valeur de ledOnPort, puis vous demandez instantanément de générer une nouvelle String plus grande pour concaténer "\t On". Comme ça ne rentre pas dans le buffer qui avait dynamiquement alloué à la représentation de ledOnPort le TAS va devoir trouver une nouvelle place assez grande pour les deux chaînes et déplacer le contenu de la première, refaisant ainsi potentiellement un petit trou.

    Quand vous appelez votre fonction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     void monitCmdExecute(String cmdExec)
    la String en paramètre est dupliquée lors de l'appel. le compilateur demande donc au TAS de la place pour une nouvelle String (allocation mémoire) copie dedans la String en paramètre et exécute la fonction. Si la fonction dans son exécution requiert aussi des manipulations de String, vous morcelez un peu plus la mémoire: par exemple quand vous faites
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    cmdExec.replace(",", ""); // Supprimer les virgules
    vous générez une nouvelle copie de la copie avec les virgules en moins => Nouvelle demande au TAS pour allouer les octets nécessaires à la nouvelle String, copie de l'une dans l'autre sans les chaînes à remplacer, et ensuite libération de la première String.

    Tous ces enchaînement d'allocations, libérations, déplacements — suivant comment on les enchaîne — peuvent conduire à la perte d'un ou deux octets ici où là dans le TAS à chaque fois (allocation de petit blocs qui se trouvent coincés entre 2 blocs qui ne bougent pas).

    Tant qu'il reste de la place pour que le TAS grandisse et qu'il ne rejoint pas la PILE (utilisée pour les variables temporaire dans les appels de fonctions) tout va bien. Mais au moment où vous demanderez de déplacer un bloc qui fait 100 caractères pour en obtenir 101 mais que manque de bol il ne reste que 90 octets consécutifs même si vous avez 10 trous de 2 octets, l'allocation ne va pas fonctionner, et le programme va planter ou commencer à avoir un comportement erratique.

    Citation Envoyé par jpbbricole Voir le message
    Je m'étonne qu'une classe comme String, qui tient une très grande place sur Arduino Reference soit si "dangereuse" à utiliser. Est-ce-que les gens d'Arduino sont si incompétents ou ces alertes sont le fait de "vieux reac" du C? Je me pose la question.
    Non ce ne sont pas le vieux réactionnaires du C, ils utilisent la classe String sur PC ou Mac et autres smartphones et tablettes dans tous les langages un peu évolués ou en C++. Mais sur ces machines on a des giga-octets de RAM et un système d'exploitation évolué qui limite fortement les risques liés à l'allocation dynamique.

    Comme vous l'avez remarqué le monde Arduino c'est souvent du prototypage, des trucs qui tournent quelques minutes ou quelques heures puis on les éteints. Comme expliqué plus haut, les plantages n'arrivent pas tout de suite, les Strings sont souvent liées à une interaction avec l'utilisateur donc si votre programme nécessite disons 3K de RAM il reste 5K sur une MEGA pour ces "petites pertes". Si vous perdez deux octets à chaque interaction, il faudra plus de 2500 interactions utilisateur avant que cela ne se voit. Dans bien des cas l'arduino aura été éteint, rebooté avant ces 2500 interactions et donc on ne voit pas le problème et donc la fuite mémoire n'est pas un souci pour le développeur.

    ==> En gros on peut fermer les yeux, si jamais ça plante on Reboote et puis voilà. La classe String simplifie le codage de ce genre de systèmes et voilà pourquoi elle existe.


    Mais si vous voulez faire un programme qui peut fonctionner des mois sans rebooter ou va interagir avec d'autres systèmes électroniques en échange de texte (réception GPS, compteur Linky, serveur HTTP, gestion par SMS...) avec des requêtes fréquentes (toutes les secondes par exemple) alors "2500 interactions" vont arriver vite...

    La solution "propre" c'est d'éviter autant que possible toute allocation dynamique de mémoire. Vous êtes ainsi en plein contrôle de votre petit arduino. C'est ce que font souvent ceux qui maitrisent bien le C et le C++ et donc ils laissent cette classe de côté.

    Cela dit, on peut utiliser la classe String même pour ce genre de programmes quand on comprend ce que l'on fait et l'enchaînement déclenché par les opérations demandées. Il y a des trucs simples à retenir / appliquer:

    * Si vous avez une String et vous savez qu'elle va grandir (eg votre réception de commandes), allouez dès le départ une certain nombre de caractères dans le buffer, comme cela quand vous faites
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     if (monChar >= ' ') {monCommandRx += monChar;}
    la String monCommandRx a suffisamment de place en mémoire réservée et n'aura pas besoin d'une nouvelle allocation, de déplacer tout ce qui était déjà dans le buffer et de laisser un trou potentiel. Un simple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    monCommandRx.reserve(50); // on pré-alloue 50 octets pour notre buffer
    dans le setup() aura un gros impact: Si vous ne dépassez jamais plus de 50 caractères dans les commandes, cette String ne sera jamais déplacée en mémoire et donc ne créera aucun trou. Si vous dépassez les 50 le fonctionnement normal aura lieu mais vous laisserez un trou de 50 octets qui aura plus de chances d'être réutilisé qu'un trou de un ou deux octets.

    * Si vous avez des appels de fonctions et que travailler sur la String d'origine plutôt que sur une copie ne pose pas de souci, alors passez la String en référence au lieu de par valeur. C'est pas bien compliqué d'écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     void monitCmdExecute(String &cmdExec)
    au lieu de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     void monitCmdExecute(String cmdExec)
    * Eviter les concaténations inutiles. Par exemple on évitera de faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     Serial.println(String(ledOnPort) + "\t On");
    qui génère deux String intermédiaires et on fera à la place
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     Serial.print(ledOnPort);  Serial.println(F("\t On"));
    Comme ça pas d'allocations de String du tout.

    * On peut essayer d'éviter les manipulations de String qui créent des duplications en mémoire. Par exemple dans votre cas si vous ne stockiez pas les espaces lors de la réception de commande et passiez en majuscule à ce moment là
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     if (monChar > ' ') {monCommandRx += toupper(monChar); // http://www.cplusplus.com/reference/cctype/toupper/}
    vous n'auriez plus à appeler ensuite
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    cmdRx.toUpperCase();  // Tout en majuscules
    cmdRx.replace(" ", "");  // Supprimer les espaces
    * assurez vous d'allouer et désallouer les String en mode LIFO (dernière allouée, première libérée). Comme cela les blocs mémoires se libèrent dans l'ordre inverse et ça ne fait pas de trous.


    Bref, c'est comme tout il y a des avantages et des inconvénients, il faut être conscient des limites et en tenir compte si nécessaire.

  16. #76
    Membre habitué
    Avatar de Jsiorat
    Homme Profil pro
    RETRAITE
    Inscrit en
    Juillet 2005
    Messages
    398
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 78
    Localisation : France, Ariège (Midi Pyrénées)

    Informations professionnelles :
    Activité : RETRAITE

    Informations forums :
    Inscription : Juillet 2005
    Messages : 398
    Points : 169
    Points
    169
    Par défaut Extension .PDE
    Bonsoir à toutes et tous,

    En visitant différents exemples dans les dossiers de nombreuses librairies, j'ai pu voir des fichiers portant cette extension ".PDE".
    En flirtant avec internet, je suis tombé sur un site qui dit que cette extension est une extension par défaut de Arduino.
    Un double click sur ce fichier, n'ouvre pas l'IDE ! Alors, pouvez-vous m'éclairer ? Que vaut cette extension, comment et dans quels cas est-elle usitée ?
    Merci pour votre réponse,
    Cordialement Jacques
    Être vieux, c'est être jeune depuis plus longtemps que les autres !

  17. #77
    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
    Il y a très longtemps (avant la version 1.0 de l’IDE en novembre 2011) les scripts n’étaient pas en .ino mais en .pde (un héritage de l’environnement de développement Processing).

    Donc Si vous voyez un .pde dans les exemples c’est qu’il est «*super vieux*». Vous pouvez le remplacer par .ino mais comme il est vieux il n’aura pas été testé avec les nouveautés de l’IDE depuis et il se peut qu’il y ait des bugs.

  18. #78
    Membre habitué
    Avatar de Jsiorat
    Homme Profil pro
    RETRAITE
    Inscrit en
    Juillet 2005
    Messages
    398
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 78
    Localisation : France, Ariège (Midi Pyrénées)

    Informations professionnelles :
    Activité : RETRAITE

    Informations forums :
    Inscription : Juillet 2005
    Messages : 398
    Points : 169
    Points
    169
    Par défaut
    Merci Jay !

    Ces fichiers avec extension .PDE sont surtout des exemples traités avec les librairies ".h" ;
    Je pense que en tant qu'exemple, ils n'ont pas été mis à jour avec la nouvelle norme, ce qui est un peu logique au vu du travail à accomplir.
    Être vieux, c'est être jeune depuis plus longtemps que les autres !

  19. #79
    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
    Citation Envoyé par Jsiorat Voir le message
    Ces fichiers avec extension .PDE sont surtout des exemples traités avec les librairies ".h"
    Salut Jacques,

    Disons qu'il faut regarder sur GitHub la date de dernière modification de la bibliothèque en question

    Par exemple regardez celle ci (prise complètement aléatoirement, premier hit google d'exemple PDE)
    Nom : ex.png
Affichages : 144
Taille : 270,5 Ko


    si vous voyez que la date de la bibliothèque est plus récente et qu'ils n'ont pas changé les noms, c'est plutôt bon signe pour la compatibilité.

  20. #80
    Membre habitué
    Avatar de Jsiorat
    Homme Profil pro
    RETRAITE
    Inscrit en
    Juillet 2005
    Messages
    398
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 78
    Localisation : France, Ariège (Midi Pyrénées)

    Informations professionnelles :
    Activité : RETRAITE

    Informations forums :
    Inscription : Juillet 2005
    Messages : 398
    Points : 169
    Points
    169
    Par défaut une question particulière ...
    Bonjour à toutes et tous

    Mon idée ... (peut-être complètement aberrante !) :
    pour mon tableau de commande optique, le fameux TCO, j'ai prévu d'utiliser une UNO R3 avec un programme du style "chenillard" qui m'informera sur les voies sélectionnées.
    La carte Mega 2560 peut-elle commander la carte UNO lorsque j'utilise l'un des 8 boutons (C1_V2 par exemple) ?
    Avec le programme mis au point par JPB, je pensais utiliser les broches des LED pour activer la carte UNO ! ai-je raison ? tort ?
    Cordialement, Jacques
    Être vieux, c'est être jeune depuis plus longtemps que les autres !

Discussions similaires

  1. Requête pour effectuer une comparaison entre deux dates
    Par ktm26 dans le forum Langage SQL
    Réponses: 2
    Dernier message: 26/04/2017, 08h49
  2. Effectue une soustraction entre deux dates
    Par messi1987 dans le forum Développement
    Réponses: 2
    Dernier message: 05/03/2015, 14h22
  3. [XL-2003] Faire une liaison entre deux tableaux sur 2 classeurs différents
    Par Katell dans le forum Conception
    Réponses: 1
    Dernier message: 22/01/2015, 18h04
  4. implementer une association entre deux classes uml en java
    Par tabbabi dans le forum Persistance des données
    Réponses: 8
    Dernier message: 19/04/2011, 19h39
  5. Réponses: 1
    Dernier message: 11/06/2009, 23h39

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