EDIT: microtherion donne une excellente réponse qui corrige certains de mes points ici, en particulier sur l'utilisation de la mémoire.
Comme vous l'avez identifié, il existe certaines situations où vous êtes obligé d'utiliser un #define, car le compilateur n'autorise pas une constvariable. De même, dans certaines situations, vous êtes obligé d'utiliser des variables, comme lorsque vous avez besoin d'un tableau de valeurs (c'est-à-dire que vous ne pouvez pas en avoir un #define).
Cependant, il existe de nombreuses autres situations où il n'y a pas nécessairement une seule réponse «correcte». Voici quelques directives que je suivrais:
Sécurité des types
Du point de vue de la programmation générale, les constvariables sont généralement préférables (si possible). La principale raison en est la sécurité de type.
Une #define(macro préprocesseur) copie directement la valeur littérale dans chaque emplacement du code, ce qui rend chaque utilisation indépendante. Cela peut hypothétiquement entraîner des ambiguïtés, car le type peut finir par être résolu différemment selon la façon dont il est utilisé.
Une constvariable n'est qu'un seul type, déterminé par sa déclaration et résolu lors de l'initialisation. Il nécessitera souvent une conversion explicite avant de se comporter différemment (bien qu'il existe diverses situations où il peut être implicitement promu par type en toute sécurité). À tout le moins, le compilateur peut (s'il est configuré correctement) émettre un avertissement plus fiable lorsqu'un problème de type se produit.
Une solution de contournement possible consiste à inclure une distribution explicite ou un suffixe de type dans a #define. Par exemple:
#define THE_ANSWER (int8_t)42
#define NOT_QUITE_PI 3.14f
Cette approche peut cependant causer des problèmes de syntaxe dans certains cas, selon la façon dont elle est utilisée.
Utilisation de la mémoire
Contrairement à l'informatique à usage général, la mémoire est évidemment à un prix élevé lorsqu'il s'agit de quelque chose comme un Arduino. L'utilisation d'une constvariable par rapport à a #definepeut affecter l'emplacement de stockage des données en mémoire, ce qui peut vous obliger à utiliser l'une ou l'autre.
const les variables seront (généralement) stockées dans SRAM, avec toutes les autres variables.
- Les valeurs littérales utilisées dans
#defineseront souvent stockées dans l'espace programme (mémoire Flash), à côté de l'esquisse elle-même.
(Notez que diverses choses peuvent affecter exactement comment et où quelque chose est stocké, comme la configuration et l'optimisation du compilateur.)
SRAM et Flash ont des limitations différentes (par exemple 2 Ko et 32 Ko respectivement pour l'Uno). Pour certaines applications, il est assez facile de manquer de SRAM, il peut donc être utile de déplacer certaines choses dans Flash. L'inverse est également possible, bien que probablement moins courant.
PROGMEM
Il est possible de bénéficier des avantages de la sécurité de type tout en stockant les données dans l'espace programme (Flash). Cela se fait à l'aide du PROGMEMmot - clé. Cela ne fonctionne pas pour tous les types, mais il est couramment utilisé pour les tableaux d'entiers ou de chaînes.
La forme générale donnée dans la documentation est la suivante:
dataType variableName[] PROGMEM = {dataInt0, dataInt1, dataInt3...};
Les tables de chaînes sont un peu plus compliquées, mais la documentation contient tous les détails.