Il s'agit plus d'une opinion / d'un commentaire que d'une réponse.
Vous ne voulez pas et ne devriez pas programmer en C. C ++, lorsqu'il est utilisé de la bonne façon , est de loin supérieur. (OK, je dois admettre que lorsqu'il est utilisé de manière incorrecte, il est bien pire que C.) Cela vous limite aux puces qui ont un compilateur C ++ (moderne), qui est à peu près tout ce qui est pris en charge par GCC, y compris AVR (avec certaines limitations, filo mentionne les problèmes d'un espace d'adressage non uniforme), mais en excluant presque tous les PIC (PIC32 pourrait être pris en charge, mais je n'ai pas encore vu de port décent).
Lorsque vous programmez des algorithmes en C / C ++, la différence entre les choix que vous mentionnez est faible (sauf qu'une puce de 8 ou 16 bits sera fortement désavantagée lorsque vous effectuez beaucoup d'arithmétique de 16, 32 bits ou plus). Lorsque vous avez besoin de la dernière once de performances, vous devrez probablement utiliser l'assembleur (le vôtre ou le code fourni par le fournisseur ou un tiers). Dans ce cas, vous voudrez peut-être reconsidérer la puce que vous avez sélectionnée.
Lorsque vous codez pour le matériel, vous pouvez utiliser une couche d'abstraction (souvent fournie par le fabricant) ou écrire la vôtre (sur la base de la fiche technique et / ou d'un exemple de code). Les abstractions C existantes d'IME (mbed, cmsis, ...) sont souvent fonctionnellement (presque) correctes, mais échouent horriblement en termes de performances (vérifiez les oldfarts rant environ 6 couches d'indirection pour une opération de jeu de broches), l'utilisabilité et la portabilité. Ils veulent vous exposer toutes les fonctionnalités de la puce particulière, dont dans presque tous les cas vous n'aurez pas besoin et ne vous souciez pas, et cela verrouille votre code à ce fournisseur particulier (et probablement à cette puce particulière).
C'est là que le C ++ peut faire beaucoup mieux: lorsqu'il est fait correctement, un ensemble de broches peut traverser 6 couches d'abstraction ou plus (car cela rend une meilleure interface (portable!) Et un code plus court possible), tout en fournissant une interface indépendante de la cible pour les cas simples , et donnent toujours le même code machine que vous écririez dans l'assembleur .
Un extrait du style de codage que j'utilise, qui peut vous rendre enthousiaste ou vous détourner d'horreur:
// GPIO part of a HAL for atsam3xa
enum class _port { a = 0x400E0E00U, . . . };
template< _port P, uint32_t pin >
struct _pin_in_out_base : _pin_in_out_root {
static void direction_set_direct( pin_direction d ){
( ( d == pin_direction::input )
? ((Pio*)P)->PIO_ODR : ((Pio*)P)->PIO_OER ) = ( 0x1U << pin );
}
static void set_direct( bool v ){
( v ? ((Pio*)P)->PIO_SODR : ((Pio*)P)->PIO_CODR ) = ( 0x1U << pin );
}
};
// a general GPIO needs some boilerplate functionality
template< _port P, uint32_t pin >
using _pin_in_out = _box_creator< _pin_in_out_base< P, pin > >;
// an Arduino Due has an on-board led, and (suppose) it is active low
using _led = _pin_in_out< _port::b, 27 >;
using led = invert< pin_out< _led > >;
En réalité, il existe d'autres couches d'abstraction. Pourtant, l'utilisation finale de la led, disons pour l'allumer, ne montre pas la complexité ou les détails de la cible (pour une arduin uno ou une pilule bleue ST32 le code serait identique).
target::led::init();
target::led::set( 1 );
Le compilateur n'est pas intimidé par toutes ces couches, et comme aucune fonction virtuelle n'est impliquée, l'optimiseur voit tout (certains détails, omis, comme l'activation de l'horloge périphérique):
mov.w r2, #134217728 ; 0x8000000
ldr r3, [pc, #24]
str r2, [r3, #16]
str r2, [r3, #48]
C'est ainsi que je l'aurais écrit en assembleur - SI j'avais réalisé que les registres PIO peuvent être utilisés avec des décalages à partir d'une base commune. Dans ce cas, je le ferais probablement, mais le compilateur est bien meilleur pour optimiser de telles choses que moi.
Donc, pour autant que j'ai une réponse, c'est: écrivez une couche d'abstraction pour votre matériel, mais faites-le en C ++ moderne (concepts, modèles) afin que cela ne nuise pas à vos performances. Avec cela en place, vous pouvez facilement passer à une autre puce. Vous pouvez même commencer à développer sur une puce aléatoire que vous avez en place, que vous connaissez, avez de bons outils de débogage, etc. et reporter le choix final à plus tard (lorsque vous aurez plus d'informations sur la mémoire requise, la vitesse du processeur, etc.).
IMO, l'une des failles du développement intégré est de choisir d'abord la puce (c'est une question souvent posée sur ce forum: pour quelle puce dois-je choisir ... La meilleure réponse est généralement: cela n'a pas d'importance.)
(edit - réponse à "Donc, en termes de performances, C ou C ++ serait au même niveau?")
Pour les mêmes constructions, C et C ++ sont identiques. C ++ a beaucoup plus de constructions pour l'abstraction (juste quelques-unes: classes, modèles, constexpr) qui peuvent, comme tout outil, être utilisées pour le bien ou pour le mal. Pour rendre les discussions plus intéressantes: tout le monde n'est pas d'accord sur ce qui est bon ou mauvais ...