Dies ist eher eine Meinung / ein Kommentar als eine Antwort.
Sie wollen und sollten nicht in C. programmieren. C ++ ist bei richtiger Verwendung weit überlegen. (OK, ich muss zugeben, wenn es falsch verwendet wird, ist es weitaus schlimmer als C.) Das beschränkt Sie auf Chips, die einen (modernen) C ++ - Compiler haben, der ungefähr alles ist, was von GCC unterstützt wird, einschließlich AVR (mit Bei einigen Einschränkungen erwähnt Filo die Probleme eines ungleichmäßigen Adressraums, schließt jedoch fast alle PICs aus (PIC32 könnte unterstützt werden, aber ich habe noch keinen anständigen Port gesehen).
Wenn Sie Algorithmen in C / C ++ programmieren, ist der Unterschied zwischen den von Ihnen erwähnten Auswahlmöglichkeiten gering (mit der Ausnahme, dass ein 8- oder 16-Bit-Chip einen schwerwiegenden Nachteil hat, wenn Sie viel 16-, 32- oder höhere Bit-Arithmetik ausführen). Wenn Sie die letzte Unze Leistung benötigen, müssen Sie wahrscheinlich Assembler verwenden (entweder Ihren eigenen oder den vom Anbieter oder einem Dritten bereitgestellten Code). In diesem Fall möchten Sie möglicherweise den von Ihnen ausgewählten Chip erneut berücksichtigen.
Wenn Sie auf die Hardware codieren, können Sie entweder eine Abstraktionsschicht (häufig vom Hersteller bereitgestellt) verwenden oder eine eigene schreiben (basierend auf dem Datenblatt und / oder dem Beispielcode). IME-vorhandene C-Abstraktionen (mbed, cmsis, ...) sind häufig funktional (fast) korrekt, versagen jedoch in Bezug auf Leistung (überprüfen Sie, ob oldfarts etwa 6 Indirektionsebenen für eine Pin-Set-Operation enthält), Benutzerfreundlichkeit und Portabilität. Sie möchten Ihnen alle Funktionen des jeweiligen Chips zur Verfügung stellen, die Sie in fast allen Fällen nicht benötigen und sich nicht darum kümmern, und sie sperren Ihren Code für diesen bestimmten Anbieter (und wahrscheinlich für diesen bestimmten Chip).
Hier kann C ++ viel besser: Wenn es richtig gemacht wird, kann ein Pin-Set 6 oder mehr Abstraktionsschichten durchlaufen (da dies eine bessere (tragbare!) Schnittstelle und kürzeren Code ermöglicht) und dennoch eine Schnittstelle bereitstellen, die zielunabhängig ist für die einfachen Fälle und führen immer noch zu demselben Maschinencode, den Sie in Assembler schreiben würden .
Ein Ausschnitt aus dem von mir verwendeten Codierungsstil, der Sie entweder begeistern oder sich entsetzt abwenden kann:
// 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 > >;
In Wirklichkeit gibt es noch einige weitere Abstraktionsebenen. Die endgültige Verwendung der LED, sagen wir zum Einschalten, zeigt jedoch nicht die Komplexität oder die Details des Ziels (für ein Arduin Uno oder eine blaue ST32-Pille wäre der Code identisch).
target::led::init();
target::led::set( 1 );
Der Compiler lässt sich von all diesen Ebenen nicht einschüchtern, und da keine virtuellen Funktionen beteiligt sind, sieht der Optimierer alles durch (einige Details wurden weggelassen, z. B. das Aktivieren der Peripherietakt):
mov.w r2, #134217728 ; 0x8000000
ldr r3, [pc, #24]
str r2, [r3, #16]
str r2, [r3, #48]
So hätte ich es in Assembler geschrieben - WENN ich erkannt hätte, dass die PIO-Register mit Offsets von einer gemeinsamen Basis verwendet werden können. In diesem Fall würde ich wahrscheinlich, aber der Compiler kann solche Dinge weitaus besser optimieren als ich.
Soweit ich eine Antwort habe, lautet diese: Schreiben Sie eine Abstraktionsschicht für Ihre Hardware, aber tun Sie dies in modernem C ++ (Konzepte, Vorlagen), damit Ihre Leistung nicht beeinträchtigt wird. Mit dieser Funktion können Sie problemlos zu einem anderen Chip wechseln. Sie können sogar mit der Entwicklung auf einem zufälligen Chip beginnen, den Sie herumliegen, mit dem Sie vertraut sind, für den Sie gute Debugging-Tools haben usw. und die endgültige Auswahl auf später verschieben (wenn Sie weitere Informationen über den erforderlichen Speicher, die CPU-Geschwindigkeit usw. haben).
IMO ist eine der Falschheiten der eingebetteten Entwicklung die Auswahl des Chips zuerst (es ist eine Frage, die in diesem Forum häufig gestellt wird: Für welchen Chip soll ich mich entscheiden ... Die beste Antwort ist im Allgemeinen: Es spielt keine Rolle.)
(Bearbeiten - Antwort auf "In Bezug auf die Leistung wäre C oder C ++ also auf dem gleichen Niveau?")
Für dieselben Konstrukte sind C und C ++ identisch. C ++ hat viel mehr Konstrukte für die Abstraktion (nur einige: Klassen, Vorlagen, constexpr), die wie jedes Tool zum Guten oder zum Schlechten verwendet werden können. Um die Diskussionen interessanter zu gestalten: Nicht alle sind sich einig, was gut oder schlecht ist ...