Parlons Arduino > Bibliothèques

Bouton poussoir

(1/2) > >>

bricoleau:
Bonjour

Pour mon premier topic, je vais essayer d'apporter ma petite contribution au microcosme locoduino.

J'ai lu avec grand intérêt la plupart des articles du site, vraiment très bien faits et instructifs.
Au début, je galérais un peu dans la navigation pour en retrouver un sur lequel je voulais revenir, mais j'ai fini par trouver une petite bidouille : depuis la page d'accueil, je fais une recherche avec un mot clé au pif, puis je clique sur "tous les articles"   :P

Le dernier qui a attiré mon attention est celui sur les boutons poussoirs, un classique à destination des débutants.
J'aime beaucoup la structure de cet article ainsi que la qualité des illustrations

Concernant le code proposé avec la librairie bounce2, il me semble voir une petite amélioration possible :

--- Code: ---bouton.attach(bp, INPUT_PULLUP);
--- Fin du code ---
qui permet de rendre le code encore un peu plus simple en masquant l'usage de la primitive pinMode.

Bon, il reste encore le INPUT_PULLUP ::)

De mon côté, j'avais mis en ligne ailleurs une petite librairie qui me semble encore plus à la portée des débutants, surtout les francophones anglophobes   :D.
Elle définit complètement l'objet bouton poussoir dans son cablage le plus simple, et fournit toutes les fonctions de base en encapsulant toutes les primitives arduino.
Elle est aussi un poil plus économe en RAM que la bounce2.

Je vous la soumets donc comme une alternative possible, en pièce jointe (librairie complète avec exemples directement disponibles dans l'IDE arduino)

Thierry:
Bonjour, et bravo pour ta bibliothèque !

Quelques remarques d'un vieux développeur à propos de ton code source.

D'abord, il est bien structuré/formaté et documenté. C'est un plaisir à lire !

Quelques pistes d'amélioration:


* Tu utilises 'const' abondamment, ce qui est plutôt bien, même si l'intérêt sur les valeurs de retour est discutable... Par contre une fonction peut elle même être const si elle ne touche pas à 'this'. C'est le cas de toutes à part actualiser() et le constructeur bien sûr... Ça donnerai:

    bool estEnfonce() const;

et cela permettrai à un utilisateur de déclarer sa propre fonction const s'il le souhaite, ce qui n'est pas possible si l'une des fonctions appelées ne l'est pas !
* Ces mêmes fonctions sont très simples et parfaitement éligibles à 'inline'. Ce mot clé 'advanced user' du langage C permet de ne compiler une fonction que si elle est utilisée quelque part, contrairement aux fonctions classiques dans le cpp qui sont compilées même si elles ne sont pas utilisées ! En compilant l'exemple 'bouton 1' avec ta bibliothèque j'ai besoin de 2860 octets, avec ma version seulement 2782 ! Note que pour pouvoir compiler, j'en ai profité pour passer tes constantes d'état à l'intérieur de la classe, ce qui simplifie encore le .cpp .
* Enfin, et c'est plus une façon de faire venant d'une longue expérience des langages objet, je suis partisan de mettre un 'this->' devant l’accès à chaque élément d'une classe (donnée, fonction) afin d'être sûr que là on parle bien de quelque chose appartenant à l'objet en cours, et pas d'une variable locale...
Pour info, les fichiers d'exemple devraient être en .ino. Le .pde est plutôt destiné aux scripts 'Processing', même si l'IDE Arduino l'accepte.
Et pour terminer ma liste de critiques (que j'espère constructive !), tu devrais lire mon article http://www.locoduino.org/spip.php?article146 'Monter une bibliothèque' qui décrit tous les fichiers annexes nécessaires à ajouter dans le fichier zip pour pouvoir la gérer depuis le Gestionnaire de l'IDE 1.6.* ...

bricoleau:
Super

Merci pour les remarques, elles mettent le doigt sur des subtilités que je n'ai pas encore complètement appréhendées.
Je vais creuser tout ça dans le détail.

bricoleau:
Quelques heures plus tard...

Encore merci pour le temps consacré à ma petite librairie.

Voici quelques compléments & interrogations :

En préambule, ces derniers temps je développe surtout sur arduino, donc il est fort possible que certains bons usages généraux de coding me soient étrangers, car non nécessaires dans le cas de l'IDE arduino et ses options de compil (dont je ne me suis pas encore préoccupé)

1) pour le const, c'est très bête mais je les avais juste mis au début de la ligne au lieu de la fin, alors que mon intention était bien de marquer les méthodes qui n'altèrent pas l'objet. Je m'étais vaguement posé la question de comment le compilo fait la différence avec un const type, mais sans plus. Mea culpa

2) pour le inline, je suis troublé  ;D
Je n'ai jamais approfondi ce sujet, mais je ne l'associais pas à la suppression des fonctions non utilisées.
Pour moi c'était pour que le code exécutable de la fonction appelée soit inséré directement à l'endroit d'appel, au lieu de passer par un saut avec passage de valeurs via la pile etc.
Un peu comme une macro, mais en plus précis.

Quoi qu'il en soit, j'ai essayé de mettre des inline partout, par endroits ou nulle part, sans obtenir la moindre variation de la taille du fichier .hex sur cette seule modification.
Comme si le compilateur n'en faisait qu'à sa tête.

Par ailleurs, et sauf erreur de ma part, tout ce qui n'est pas utilisé est automatiquement dégagé à la compil (ou au link?), y compris les méthodes de classe non utilisées.
J'ai fait des tests, toujours avec le programme demo 1, de supprimer les méthodes non utilisées. Dans tous les cas le fichier .hex fait la même taille

Dans le même ordre d'idée, j'ai tendance à abuser des variables constantes isolées (comme les masquexxxx de ma lib) car elles disparaissent à la compil, et sont remplacés par leur valeur directement dans le code exécutable.
Les calculs entre elles sont effectués par le (pré?)compilateur.
Il suffit de faire un test en les remplaçant par des #define pour constater que le .hex et la ram utilisée sont les mêmes.
Nb : dans ta version (constantes dans la classe), j'ai observé que l'ajout de static est obligatoire pour arriver au même résultat. Le const seul ne suffit pas, alors que je le trouvais assez "explicite". Encore un truc que je ne maîtrise pas totalement.

Du coup j'ai cherché à comprendre pourquoi ton exécutable est moins lourd, et là je n'arrive pas à poser de verdict.
Cela semble être uniquement lié au fait de définir entièrement les méthodes "simples" dans le header, au lieu de les déporter dans le cpp.
J'ai testé pas mal de combinaisons (déport d'une seule méthode, de plusieurs, etc.) et j'obtiens des résultats que je ne m'explique pas.
Par exemple pour les méthodes estEnfonce() et estRelache(), cela ne fait aucune différence.
Alors que la méthode vientDEtreEnfonceOuRelache() donne un exécutable plus léger lorsqu'elle est entièrement dans le header. Un comble quand on voit que son code est quasi le même que EstRelache(), à une constante près.
Bref y a un truc qui m'échappe au niveau de la compilation.
Après, je ne suis pas assez compétent pour aller zieuter le fichier .hex et comprendre où sont les différences exactement.

3) pour le this-> j'ai encore du mal à me faire une religion
Sur le principe je suis assez d'accord
Par exemple, sur les propriétés privées j'utilise le préfixe _ justement pour bien les repérer.
Mais autant je suis partisan d'utiliser des noms à rallonge pour avoir un code plus lisible et facile à comprendre, autant je trouve que ces 6 caractères de préfixe polluent parfois à forte dose et finissent par nuire à la lisibilité.
Du coup j'ai tendance à les mettre ou non selon les endroits.

Enfin, j'essaye aussi d'avoir un header le plus simple possible à lire.
Je me dis qu'idéalement, tout ce qui relève de l'arrière cuisine ne devrait pas y être visible.
Mais bon, le C++ semble avoir ses limites sur ce point.
Par exemple, je n'ai toujours pas compris pourquoi une classe doit exposer ses parties privées en publique (si j'ose dire  ;D)

Je vais également tâcher de mettre en stricte application ton article sur la création de lib dans les règles de l'art. Je dois creuser ça aussi.

Encore merci

bricoleau:
Bonsoir

J'ai approfondi le point concernant le inline, et pense être arrivé à une explication qui me semble tenir la route.
Lorsque l'on met le corps d'une méthode de classe dans le .h il n'est pas nécessaire de le mettre en inline car c'est implicite.
Derrière le compilateur choisit ou non de suivre la directive, selon son analyse du code, car le inline a ses avantages et ses inconvénients. Tout n'est pas complètement clair pour moi.

Dans mes tests, j'ai l'impression que les méthodes utilisées seulement dans le programme principal conduisent à un .hex moins gros lorsqu'elles codées dans le .h, alors que celles qui sont aussi appelées depuis le .cpp n'ont pas d'impact sur la taille du .hex

Cela pourrait être cohérent avec un choix du compilo de les implémenter en inline, sauf si elles sont appelées depuis plusieurs endroits.

Quoi qu'il en soit, le gain est marginal (80 octets sur la flash, un débutant n'est pas à ça près).
Aussi je vais conserver mon optique de produire un .h le plus lisible possible, pour cette lib à destination des débutants.

Finalisation à suivre...

Navigation

[0] Index des messages

[#] Page suivante

Utiliser la version classique