Hallo Forengemeinde, nachdem hier Beitrag "AVR Studio C++ vs. Arduino Processing" gerade ein interessanter Thread über den Einstieg über C oder C++ im Gange ist möchte ich hier noch einen separaten Thread speziell über C++ auf µCs starten. Ich bin gerade dabei mich in C++ einzuarbeiten weil ich die Hoffnung habe damit meine Software besser strukturieren zu können. Grundätzlich ist mir das Konzept von C++ denke ich auch klar aber ein "paar" Details verstehe ich eben noch nicht ganz und finde im Netz auch noch nicht richtig die Lösung dafür. So jetzt aber genug bla bla... Mein Projekt ist derzeit in C umgesetzt wobei ich versucht habe möglichst alles objektorientiert umzusetzen, d.h. es gibt keine globalen Variablen und der Zugriff auf Daten erfolgt über definierte Interfaces. Speziell geht es um die Ansteuerung und Regelung mehrer E-Motoren die über den gleichen Algorithmus angesteuert werden aber unterschiedliche Daten und Parameter besitzen. Weiterhin müssen gewisse Sicherheitsanforderungen erfüllt werden (z.B. dürfen die Motoren nicht zu heiß werden). Aus meiner Sicht schreit das ein wenig nach Klassen und das habe ich in C auch in etwa so umgesetzt. Die aktuelle Umsetzung ist so: Für jeden Motor gibt es eine Struktur die die Daten und Parameter enthält. Die Grundstruktur/Objekt ist so ausgelegt, dass sie/es die Parameter enthält und einen Pointer auf die Datenstruktur mit den Variablen. Funktionen erhalten jetzt einen Pointer auf eines dieser Objekte (also denke ich so eine Art this Pointer) und können damit Arbeiten. Das Grundobjekt liegt im Flash des Controllers. Das war mir wichtig, damit sicher gestellt ist das Parameter und Daten immer zusammen gehören. Im Hintergrund läuft eine CRC Routine über das Flash die das überprüft. Das Grundobjekt ist in einer Header Datei deklariert aber nicht näher definiert, d.h. im Header kann ich nur einen Pointer auf so ein Objekt definieren. Die genaue Spezifikation der Struktur befindet sich in der C-Quelle. Meine Problem.. .. ist nun, wie ich ein solches Konstrukt in C++ umsetzten kann (gerne auch einfacher) weil mein aktueller Code ein ziemliches Pointergrab ist. Ich habe zwar eine klar definierte Struktur die in allen meinen Modulen gleich ist aber für die Erzeugung der Objekte ist noch viel Handarbeit erforderlich was damit auch fehlerträchtig ist. Wenn mir das der C++ Compiler abnehmen würde wäre ich also dankbar. Was mir wichtig wäre ist, dass Parameter und Daten fest miteinander in Beziehung stehen. D.h. die Parameter eines Objekts würde ich gerne im Flash platzieren ebenso wie die Verknüpfung zu den dazugehörigen Variablen (macht das der C++ Compiler vielleicht irgendwie automatisch?). Die Parameter werden dann für jeden Motor anders initialisiert. Soweit ich C++ bisher verstanden habe werden selbst const definierte Elemente nicht zwangsweise im Flash plaziert. Bei C++11 gibt es wohl die constexpr aber soweit ich sehen konnte unterstützt der Keil Compiler den ich einsetzen muss kein C++11 und damit auch keine constexpr. Weiterhin suche ich noch nach einer Art Tutorial wo erklärt wird wie der Compiler bei der Platzierung der einzelnen Objekte vorgeht, d.h. was kommt wohin, welche Sections werden benötigt und wofür sind die einzelnen Memory Sections da. Mein Design soll völlig statisch sein, d.h. kein new oder delete verwenden. Einen Heap möchte ich also nicht verwenden. Gibt es für Meine Themen vielleicht fertige Entwurfsmuster mit denen sich sowas umsetzen lässt? Ich hoffe ich habe euch nicht mit zu viel Text erschlagen! Über ein paar Tipps von den Experten würde ich sehr freuen. Und wenn noch zu viel Glaskugel erforderlich ist einfach sagen ;-) Viele Grüße, Jupp
Jupp schrieb: > Das Grundobjekt liegt im Flash des Controllers. Na da liegen doch erstmal alle Daten. Und dann werden sie zur Laufzeit ins RAM geladen. Variablen, "Objekte" usw. enstehen dann im RAM. Jupp schrieb: > Im Hintergrund läuft eine CRC Routine über das Flash > die das überprüft. Im Ernst? Warum? Traust du dem Flash nicht? Vor allem: Wie machst du das? Jupp schrieb: > Weiterhin suche ich noch nach einer Art Tutorial wo erklärt wird wie der > Compiler bei der Platzierung der einzelnen Objekte vorgeht, d.h. was > kommt wohin, welche Sections werden benötigt und wofür sind die > einzelnen Memory Sections da. Du kannst dem Compiler ja gerne erzählen, in welche section welche Daten sollen. Wo diese sections nachher aber landen, mußt du schon dem Linker (im besagten ...script) mitteilen ...
Jupp schrieb: > Ich habe zwar eine klar definierte Struktur die in allen meinen Modulen > gleich ist aber für die Erzeugung der Objekte ist noch viel Handarbeit > erforderlich was damit auch fehlerträchtig ist. Ich wollte nur mal anmerken, dass du mit typedef eine Art Klasse erstellen kannst, aus der du mit einer Zeile neue Objekte gleichen Typs erzeugen kannst Beispiel: Button.h Auszug:
1 | typedef struct { |
2 | volatile uint8_t *port; |
3 | volatile uint8_t *pin; |
4 | volatile uint8_t *ddr; |
5 | uint8_t pinNr; |
6 | uint8_t internPullup; |
7 | uint8_t bounce_ms; |
8 | } type_BUTTON; |
9 | |
10 | void BUTTON_INIT (type_BUTTON *device); |
11 | uint8_t BUTTON_GET (type_BUTTON *device); |
12 | uint8_t BUTTON_WAIT (type_BUTTON *device, uint8_t press_release, uint16_t timeout_ms); |
main.c Auszug:
1 | type_BUTTON button_A; |
2 | type_BUTTON button_B; |
3 | |
4 | /// Configure Devices //////////////////////////////////////
|
5 | // Buttion A configuration
|
6 | button_A.ddr = &DDRC; |
7 | button_A.port = &PORTC; |
8 | button_A.pin = &PINC; |
9 | button_A.pinNr = PC7; |
10 | button_A.internPullup = True; |
11 | button_A.bounce_ms = 40; |
12 | |
13 | // Buttion B configuration
|
14 | button_B.ddr = &DDRC; |
15 | button_B.port = &PORTC; |
16 | button_B.pin = &PINC; |
17 | button_B.pinNr = PC4; |
18 | button_B.internPullup = True; |
19 | button_B.bounce_ms = 40; |
20 | /// END Configure Devices //////////////////////////////////
|
21 | |
22 | /// INIT Devices ///////////////////////////////////////////
|
23 | // INIT buttons
|
24 | BUTTON_INIT(&button_A); |
25 | BUTTON_INIT(&button_B); |
26 | /// END INIT Devices ///////////////////////////////////////
|
27 | |
28 | if(BUTTON_GET(&button_A)) |
29 | {
|
30 | // tue dies und das
|
31 | }
|
32 | |
33 | if(BUTTON_WAIT(&button_B, BUTTON_RELEASE, 2000) == Success) |
34 | {
|
35 | // Button wurde innerhalb von 2000ms losgelassen
|
36 | }
|
37 | else
|
38 | {
|
39 | // Timeout von 2000ms abegelaufen
|
40 | }
|
Das könntest du z.B. bei deinen mehreren Motoren so nutzen.
Jupp schrieb: > Ich bin gerade dabei mich in C++ einzuarbeiten weil ich die Hoffnung > habe damit meine Software besser strukturieren zu können. Grundätzlich > ist mir das Konzept von C++ denke ich auch klar aber ein "paar" Details > verstehe ich eben noch nicht ganz und finde im Netz auch noch nicht > richtig die Lösung dafür. Ne, du verstehst C++ nicht. C++ ist eine Multi-Paradigm-Sprache und die meisten Menschen (inkl. mir) tun sich schwer ein Paradigm komplett zu verstehen. Allein das Typsystem ist enorm komplex (erlaubt aber auch enorme Möglichkeiten, zur Compilezeit)... Simon S. schrieb: > Ich wollte nur mal anmerken, dass du mit typedef eine Art Klasse > erstellen kannst, aus der du mit einer Zeile neue Objekte gleichen Typs > erzeugen kannst Ne, du verstehst C nicht. ;) Das macht man hier nicht mit typedef, sondern struct erzeugt deine "Klasse" (im Prinzip machst du hier nix anderes als manuell das zu tun, was der C++ Compiler bei einfachen Klassen macht). typedef erzeugt nur das Alias, sodass du nicht "struct foo variable;" schreiben musst.
:
Bearbeitet durch User
kopfkratz Wo ist denn nun Dein eigentliches Problem ? Du erstellst eine Klasse MOTOR in der Du die Vorgaben für die Regelung kapselst und entsprechend Deiner Anforderung regelst. Oder verstehst Du Kapselung und Vererbung nicht richtig ? Stell einfach mal Dein aktuelles C Programm und Deine C++ Variante hier rein und man kann sehen wo es hapert ...
Mir drängt sich der Eindruck auf, dass C++ hauptsächlich für abstrakte multithread-Anwendungen geeigneter ist. Also eigentlich nix für einen Mikrocontrollör.
Danke für die schnellen Antworten! @Ähem: Das alles erst mal im Flash landet und von dort erzeugt wird ist prinzipiell klar. Das Problem das ich habe ist, das ich komplett Konstante Objekte (Parameter) habe und diese fest mit mit den dazugehörigen Daten verknüpft werden sollen. Die Objekte sollen also auch zur laufzeigt aus dem Flash laufen und nicht bei der Instanziierung ins RAM geladen werden. Dem RAM traue ich hier nicht so ganz und zum anderen habe ich recht viele Parameter und würde so sehr viel RAM mit konstanten Daten verschleudern. Dem Flash traue ich im Prinzip schon aber ich habe aus der Serie auch schon Controller mit Flash Fehlern zurück bekommen. Ist also nur eine Frage der Zeit und Stückzahl das sowas mal auftritt. Weiterhin ist die CRC Überprüfung eine Normanforderung (Safety Norm) und damit ein Muss weil die Software auch geprüft/zertifiziert wird. Mein Ziel ist eigentlich nur zur laufzeit sicher zu stellen, dass Parameter und Daten/Variablen zur Laufzeit nicht auseinander laufen. Durch was auch immer (Flash/RAM-Fehler, EMV, Software Bug ...) @Simon: So in der Art wie Du es schreibst habe ich es im Moment gelöst, d.h. über typedef werden die Modulobjekt definiert und dann instanziiert, also mit den entsprechenden Daten belegt. Für jeden Motor wird dann immer ein Objekt erzeugt und dann an die entsprechendne Funktionen per Pointer übergeben. Hier ein Beispiel wie es jetzt ungefähr aussieht:
1 | typedef struct _TModData{ |
2 | uint16_t bla; |
3 | ....
|
4 | }TModData; |
5 | |
6 | typedef struct _TModPar{ |
7 | uint16_t blub; |
8 | ....
|
9 | }TModPar; |
10 | |
11 | typedef struct _TGenericModObject{ |
12 | TModData* ptDat; |
13 | const TModPar* ptPar; |
14 | }TGenericModObject; |
15 | |
16 | static TModData Motor1ObjData = {0}; |
17 | |
18 | static const TModPar Motor1ObjPar = {0}; |
19 | |
20 | /* Verknüpfung zwishen Parametern und Daten im Flash => von CRC geprüft */
|
21 | static const TGenericModObject ModObjMotor1 = {&Motor1ObjData, &Motor1ObjPar}; |
22 | |
23 | /*
|
24 | Funktionen sehen dann so aus:
|
25 | In den Funktionen kann dann über den this-Pointer auf Daten und Parameter
|
26 | des Motors zugegriffen werden.
|
27 | */
|
28 | void Foo(const TGenericModObject* this); |
Was meint ihr? Sieht aus meiner Sicht nicht wirklich schön aus und erfordert in jedem Modul viel Handarbeit. Besonders die Zugriffe auf Daten und Parameter würde ich gerne einfacher gestalten. Wie macht ihr das mit sicherheitskritischen Parametern? Liegen die bei euch zur Laufzeit im RAM oder wie erfolgt der Schutz der Parameter zur Laufzeit?
Selbstverständlich liegen alle Laufzeitparameter im RAM. Wenn Du dem RAM nicht traust, kannst Du gleich alles wegwerfen. Manche Computer unterstützen automatische Fehlererkennung und Korrektur (Stichwort: ECC memory). Aber bei Mikrocontrollern eher nicht. Da sind Taktrate und Datendichte niedrig genug, um auch ohne ECC zuverlässig zu funktionieren. Manche Computer prüfen ihren Flash Speicher mit Hilfe einer Prüfsumme. Im Einfachsten Fall erstellt die Firmware beim allerersten Start eine Prüfsumme von sich selbst und legt sie im EEprom ab. Bei allen folgenden Starts kontrolliert sie, ob die Prüfsumme noch stimmt. Wenn nicht, ist der Flash SPeicher oder das EEprom ausgefallen, dann könnte man eine Fehlermeldung anzeigen. Aber ob das dann überhaupt noch funktioniert, ist wiederum fraglich. Eher warscheinlch ist, das bei einer Fehlfunktion des Flash Speichers nichtmal mehr die Selbstkontrolle funktioniert.
Diese Appnote hatte ich gestern in den Fingern: http://www.nxp.com/documents/application_note/IEC60335_ClassB_CM3.zip Und das nur für weiße Ware, die Maschinenschutzrichtlinien sind genauso heftig. Hast du denn schonmal geprüft was du umsetzen musst?
Gefällt mir, wie POST die Bezeichnung für die Tests, die vor der Ausführung stattfinden sollen, ist.
Jupp schrieb: > Wie macht ihr das mit sicherheitskritischen Parametern? Liegen die bei > euch zur Laufzeit im RAM oder wie erfolgt der Schutz der Parameter zur > Laufzeit? Mirroring ist eine mögliche Technik, benötigt bei geteilten Variablen aber locks.
Marian B. schrieb: > sondern struct erzeugt deine > "Klasse" (im Prinzip machst du hier nix anderes als manuell das zu tun, > was der C++ Compiler bei einfachen Klassen macht) Und selbst C++ verstanden? Zur Datenkapselung gehören auch die Zugriffsmethoden. Wie fummelst du die in eine struct? Wie schützt du die Datenbereiche (private)? C++ geht auch auf µC gut. Man muss es ja nicht mit einer dynamischen Speicherverwaltung umsetzen.
Stefanus schrieb: > Manche Computer unterstützen automatische Fehlererkennung und Korrektur > (Stichwort: ECC memory). Aber bei Mikrocontrollern eher nicht. Da sind > Taktrate und Datendichte niedrig genug, um auch ohne ECC zuverlässig zu > funktionieren. In der ARM-Cortex Gegend gibt es eine ganze Reihe von µC die ECC implementiert haben. Z.B.: http://www.ti.com/lsds/ti/arm/hercules_arm_cortex_r_safety_microcontrollers/arm_cortex_r4/tms570ls/overview.page
Hier mal ein kleines Beispiel wie das geht: http://ideone.com/fRXBnv Die eine Klasse landet im Flash (dank constexpr), die andere im RAM, und über die Referenz werden beide verbunden. Unten eine Beispiel wie man davon ein paar Instanzen anlegt. Mit dem GCC kann man das dann auch für C++11 zB für ARM oder AVR kompilieren. Jupp schrieb: > Weiterhin suche ich noch nach einer Art Tutorial wo erklärt wird wie der > Compiler bei der Platzierung der einzelnen Objekte vorgeht, d.h. was > kommt wohin, welche Sections werden benötigt und wofür sind die > einzelnen Memory Sections da. Das funktioniert genau wie in C. lokale Instanzen auf dem Stack, globale in .data und globale constexpr Instanzen in .text.
Roland Ertelt schrieb: > Mir drängt sich der Eindruck auf, dass C++ hauptsächlich für abstrakte > multithread-Anwendungen geeigneter ist. - Was ist eine abstrakte Anwendung? Klingt wie ein schwarzer Schimmel. - Was hat C++ mit Multithreading zu tun? Dass man PCs heute oft in C++ programmiert und aufgrund der aktuellen PC-Hardware tunlichst ausgiebig Multithreading nutzen sollte hat reinweg nichts mit der Sprache zu tun.
Compiler schrieb: > Und selbst C++ verstanden? Zur Datenkapselung gehören auch die > Zugriffsmethoden. Wie fummelst du die in eine struct? Wenn du unbedingt willst, als Funktionszeiger. Ansonsten per Namenskonvention: Methoden fangen halt mit dem Klassennamen an. > Wie schützt du die > Datenbereiche (private)? Split header files. Das public header file enthält nur "struct foo;" oder eine verkürzte Struktur mit nur den public members, das private dann alles. Ist nicht so, dass es sowas nicht schon gegeben hätte. Schau dir Motif an für ein Beispiel.
Compiler schrieb: >> "Klasse" (im Prinzip machst du hier nix anderes als manuell das zu tun, >> was der C++ Compiler bei einfachen Klassen macht) > > Und selbst C++ verstanden? Zur Datenkapselung gehören auch die > Zugriffsmethoden. Wie fummelst du die in eine struct? Wie schützt du die > Datenbereiche (private)? > > C++ geht auch auf µC gut. Man muss es ja nicht mit einer dynamischen > Speicherverwaltung umsetzen. Nö, ich behaupte nicht C++ verstanden zu haben, das wäre gelogen. Ich habe allerdings auch **einfache** Klassen geschrieben (keine Vererbung, Access protection, keine vtable, keine Templateklasse, ...)
Danke für die vielen Beiträge! Zur Datenkapselung in C: Bei mir habe ich das so in der Art gelöst wie Jörg das beschrieben hat, d.h. im Header ist nur ein algemeines struct definiert damit ich mir einen Pointer darauf generieren kann. Die Funktionen im Header bekommen dann also einen Pointer auf diese Struktur übergeben. Im C-File steht dann die ganze Wahrheit, wie also die Struktur im Detail aussieht. Damit ist alles was im Header ist public und die Implementierung im C-File private. Typprüfungen sind damit auch noch schön möglich. Mein Beispiel oben zeigt also eigentlich noch nicht ganz meine Umsetzung. @Dr. Sommer: Danke für den Code-Schnipsel! Hast Du das so auf die schnelle noch zusammengeklickert :-)? Geht das ganze auch ohne constexpr? Ich glaube das mein Keil ARM Compiler noch kein C++11 unterstützt :-(. Mein Target ist der alt bekannte STM32. @Stefanus: Dem RAM traue ich prinzipiell schon. Ich habe aber auch bei EMV-Versuchen schon bei diversen Controllern unterschiedlicher Hersteller die Erfahrung gemacht das sich im RAM bei gewissen Störungen mal was verändern kann wenn man es nicht will :-(. Der andere Punkt der mich ein wenig stört ist, dass Parameter, also nicht veränderliche Daten, ins RAM kopiert werden wenn man sie auch schon im Flash vorliegen hat. Hier fände ich es eleganter auf diese Verdopplung der Daten und des erforderlichen Speichers zu verzichten. @Marius: Mirroring ist klar eine Möglichkeit aber auch mit entsprechender Laufzeit und RAM-Speicherverlust verbunden. Wenn's geht wollte ich mir das ersparen. Die Norm fordert es im Moment auch noch nicht :-).
Jupp schrieb: > @Dr. Sommer: Danke für den Code-Schnipsel! Hast Du das so auf die > schnelle noch zusammengeklickert :-)? Jo klar > Geht das ganze auch ohne > constexpr? Mit Standard C++ nicht, denn C++ kennt, genau wie C, keinen "Flash". Da musst du mal im Manual vom Keil nachschauen wie das geht (wird wohl für C unc C++ gleich gehen), wie man die Instanz (Variable) in den Flash packt. Beim GCC wärs wohl mit __attribute__((section(".text"))). > Ich glaube das mein Keil ARM Compiler noch kein C++11 > unterstützt :-(. Ja, richtig. Den STM32 kann man auch wunderbar mit dem GCC programmieren, siehe STM32: GCC und ARM GCC.
Jörg Wunsch schrieb: > Wenn du unbedingt willst, als Funktionszeiger. Sach ich doch: gefummelt. ;-) Jörg Wunsch schrieb: > Split header files. Das public header file enthält nur "struct foo;" > oder eine verkürzte Struktur mit nur den public members, das private > dann alles. Wunderbar zu pflegen und völlig fehlerunanfällig. :-((( Und wie vererbst du das Ganze (hier ohne Polymorphie)?
Jupp schrieb: > Ich glaube das mein Keil ARM Compiler noch kein C++11 > unterstützt :-(. Mein Target ist der alt bekannte STM32. Das ist doch ein prima Päarchen für C++.
Compiler schrieb: > Und wie vererbst du das Ganze (hier ohne Polymorphie)? Wo ist das Problem? Das funktioniert grad so wie in C++, nur macht man das zu Fuss, was in C++ der Compiler macht. Abgeleitete Klassen müssen natürlich auf die Basisklassen voll zugreifen können. Klar ist das Fummelei. Das macht man nur, wenn bessere Alternativen nicht bestehen oder mangels Verbreitung nicht in Frage kommen.
A. K. schrieb: > nur macht man > das zu Fuss A. K. schrieb: > Klar ist das Fummelei. Das macht man nur, wenn bessere Alternativen > nicht bestehen oder mangels Verbreitung nicht in Frage kommen. Danke, genau meine Meinung. Aber er hat einen C++ Compiler auf 'nem STM32. Es also alles schön vorbereitet (verbreitet)! Warum dann nicht nutzen???
Compiler schrieb: >> Ich glaube das mein Keil ARM Compiler noch kein C++11 >> unterstützt :-(. Mein Target ist der alt bekannte STM32. > > Das ist doch ein prima Päarchen für C++. An sich ist der Compiler gut und alles funktioniert auch wunderbar. Soweit ich sehen kann ist auch die C++ Lib recht kompakt. Wenn ich aber Dinge in C++11 umsetzen will, klappt das nicht. Ich muss also mal sehen wie ich meine Anforderungen mit dem alten C++ Standard umsetzen kann. Meine andere Alternative ist eine gänzlich andere Lösung zu finden. Dr. Sommer schrieb: >> Ich glaube das mein Keil ARM Compiler noch kein C++11 >> unterstützt :-(. > Ja, richtig. Den STM32 kann man auch wunderbar mit dem GCC > programmieren, siehe STM32: GCC und ARM GCC. Ja, richtig. Bei privaten Projekten nutze ich den GCC auch. Beruflich bin ich aber leider gebunden :-(. Mein aktueller C Code ist auf jeden Fall nicht unbedingt optimal zu warten. Wenn man einmal drin ist, ist alles klar aber wenn man von außen draufschaut muss man erst mal überlegen. Von C++ verspreche ich mir also wie oben schon geschrieben eine bessere Struktur und Wartbarkeit.
würd mich wundern wenn keil so weit hinten wäre.. schon mal bei den language settings geschaut was man da einstellen kann? meiner erfahrung nach ist da keil an misra angelehnt und die leben seit 2013 schon im jahr 1999 ;) könnt also sein, das du nur einen neueren dialekt auswählen musst. 73
@Hans: Hab gerade mal ins aktuelle online Manual gesehen: The compiler compiles C++ as defined by the 2003 standard, excepting wide streams and export templates: ISO/IEC 14822:2003. The 2003 International Standard for C++. Sieht nach dem alten Standard aus :-(
was du in C gemacht hast, hat für mich nicht wirklich was mit Objektorientierung zu tun aber ich verstehe was du meinst :) Imho gehört zur Objektorinetierung (unter anderem) sachen wie Vererbung und Polymorphismus, die dann den Einsatz von C++ im vergleich zu C rechtfertigen. Wie andere schon geschrieben haben. In C++ bräuchtest du einfach eine Klasse Motor mit den gleichen Attributen wie in deinem struct und den methoden die du vorher als lose funktionen hattest. Ein weiteres schmankel könnten die sichtbarkeiten (private, protected, public) werden.
hans schrieb: > würd mich wundern wenn keil so weit hinten wäre.. Selbst Microsoft kriegt das in seinem Compiler noch nicht hin. GCC & Clang sind halt die besten :o) Jupp schrieb: > Ich muss also mal sehen > wie ich meine Anforderungen mit dem alten C++ Standard umsetzen kann. Musst halt im Keil Manual nachschauen wie man da Sachen in den Flash packt; geht vermutlich genau wie in C.
benwilliam schrieb: > Imho gehört zur Objektorinetierung (unter anderem) sachen wie Vererbung > und Polymorphismus, die dann den Einsatz von C++ im vergleich zu C > rechtfertigen. Polymorphismus ist zunächst einmal unabhängig von Objekt-Orientierung. Du kannst C++ Programme ohne Objekte aber mit Polimorphismus schreiben. Das sollten wir also nicht durchmischen. Die Polymorphie von Klassen in C++ auf die du hier (vermutlich) Bezug nimmst, begründet sich ausschließlich durch Vererbung. Vererbung ist auch in der C-Version möglich. Du musst halt das was der Compiler für dich übernimmt manuell erzeugen. D.h. ftable, vftable, Strukturüberdeckung der pseudo-Klassen und die Übergabe der (Unter-) Objektzeiger über deine Finger laufen lassen. Das ist nur in sofern Friemelei, als dass es einfach Fleissarbeit ist, die dir der C++ Compiler abnehmen würde, aber es ist kein Alleinstellungsmerkmal gegenüber C. Ich empfehle sowieso gerne sich mal sich das Kompilat einfacher C++ Programme anzusehen um mal zu sehen, wie diese Dinge umgesetzt werden, und ein Gespür dafür zu bekommen warum etwas funktioniert oder nicht funktioniert.
Hallo, ich stehe ebenfalls davor, mit der C++ Programmierung von µCs zu beginnen. Vor allem würde ich dafür Atmel Prozessoren und Atmel Studio verwenden. Könnte mir jemand einen Tipp für einen guten Start geben? Gibt es Literatur, die sich mit C++ für µC-Programmierung beschäftigt (Bücher, Anleitungen, Links, ...)? Ich habe massenweise Literatur für C gefunden und vorher auch in C Mikrokontroller programmiert. Allerdings finde ich keine passenden Informationen für µC-Programmierung in C++. Hat jemand einen Vorschlag? lG
Hey Leidensgenosse ;-) ich habe mir das folgende mal beschafft: Real-Time C++: Efficient Object-Oriented and Template Microcontroller Programming ISBN: 3642346871 Ist auf jeden Fall fokussiert auf µC. Die Beispiele darin sind für den AVR. Soweit ich auf den ersten Blick sehen kann ist das Buch aber nicht direkt für Anfänger geschrieben. Ich werde mich daher noch ein wenig mit "allgemeinem" C++ beschäftigen. Aber zunächst werfe ich mal wie oben empfohlen einfach mal den GCC Compiler an und spiel ein wenig rum. Mal sehen was da so alles hinter den Kulissen aus Klassen und Objekten gemacht wird :-)
Hey super, danke für den Tip! Also als kompletter Einsteiger würde ich mich nicht bezeichnen, hab in C++ zwar noch nicht viel programmiert, aber doch ein bisschen. Allerdings nicht auf µC Ebene. Von C bringe ich einiges an Erfahrung mit, auch das Prinzip der Obejktorientierung ist mir soweit klar. Danke, ich werde mir deinen Buchvorschlag mal zulegen! LG
Jupp schrieb: > Aus meiner Sicht schreit das ein wenig nach Klassen Da schreit gar nichts, alles ist ganz still. Wenn man wollte, könnte man das auch in purem Assembler-Code umsetzen. SCNR ;-)
nur mal so als Wegweiser zu dem Thema ;-) http://www.avr-cpp.de http://libavrstdcpp.codeplex.com/ http://mystm32.de/doku.php Gruß JZ
Liege ich richtig in der Annahme, dass die C++-Programmierung mit Atmel Studio bzw generell für µCs noch in der Anfangsphase ist? Man findet massenweise Information und Unterlagen zur µC-C-Programmierung, aber sehr wenig zu C++. Liegt das wirklich daran, dass C++ für die µC-Programmierung noch nicht lange verwendet wird? lG
Naja, C++ ist sehr problematisch auf kleineren Microcontrollern, da es sehr leicht mit den Standard-Libraries und verschiedenen Sprachfeatures zu aufgeblähtem Code führt. Das Problem gibt's ja bereits mit C und einigen Library-Funktionen, z.B. printf. Mit C++ ist das allerdings eine Zehnerpotenz schlimmer, und schon unscheinbare Konstrukte können zu großem Ballast führen, insbesondere Templates. Ich halte es für keine gute Idee, auf kleineren Controllern (wenig Flash/RAM) C++ zu verwenden.
das problem ist, das c++ ganz früher nicht so richtig geeignet war weil die compiler und die supportlibs noch nicht gut waren ... der mythos hält sich aber noch immer, dass c++ zwingend langsameren und größeren code macht als c... stimmt aber lange nicht... das selbe gilt für die anfangszeit von c... da war die welt auch der meinung man wird ewig asm am uC brauchen... oder auch die libc.. heute normal, vor 10 jahren wurdest du angeprangert für jeden sprintf... die errungenschaften der pc-sw-entwicklung dringen nur langsam in die industrie durch... in 10 jahren wird das ganz anders ausschaun... wir leben gottseidank nicht mehr in einer zeit wo 64k flash das höchste der gefühle war ;) 73
Werz schrieb: > Liege ich richtig in der Annahme, dass die C++-Programmierung mit Atmel > Studio bzw generell für µCs noch in der Anfangsphase ist? Nein es ist nicht "neu". Auch C++ hat in der uC Welt seine Verbreitung. Allerdings gibt es im Bereich des bare-metall, also dem Einsatz auf uC ohne zugrundeliegendes OS recht wenig C++. > Man findet > massenweise Information und Unterlagen zur µC-C-Programmierung, aber > sehr wenig zu C++. Liegt das wirklich daran, dass C++ für die > µC-Programmierung noch nicht lange verwendet wird? Das liegt eher an anderen Beschränkungen für die man eine direktere Kontrolle der verwendeten Resourcen haben will, so dass C++ seine Vorteile nicht ausspielen kann. (Z.B. uC mit sehr kleinem RAM)
Also liege ich richtig in der Annahme, dass es zur Zeit noch in der Anfangsphase ist und in Zukunft C++ für größere 32 Bit µCs durchaus Verwendung finden wird. Ich werde mir einmal das von Jupp angesprochene Buch aneignen, um mich in die C++ Programmierung von µCs einzuarbeiten :)
decimad schrieb: > Kannst Du ein problematisches Beispieltemplate zeigen? Da braucht man gar nichts konkretes zeigen. Wenn man ein Template mehrmals mit verschiedenen Typen instanziert um schönen typsicheren Code zu schreiben (ohne void-Pointer u.ä.), dann wird für jeden Typ eine Klasse erstellt. Das führt sehr schnell zu Bloat, wenn man nicht aufpasst. Wenn man hunderte KB Flash zur Verfügung hat, ist das vielleicht egal, aber auf einem kleinen MCU mit < 64 KB sieht es schon anders aus. Letztendlich muss man, wenn man C++ auf kleineren MCUs verwenden will, komplett auf die Standard-Library verzichten und auf diverse Sprachfeatures (Klassen, Exceptions, Templates). Dann kann man aber eigentlich gleich C verwenden.
greg schrieb: > decimad schrieb: >> Kannst Du ein problematisches Beispieltemplate zeigen? > > Da braucht man gar nichts konkretes zeigen. Wenn man ein Template > mehrmals mit verschiedenen Typen instanziert um schönen typsicheren Code > zu schreiben (ohne void-Pointer u.ä.), dann wird für jeden Typ eine > Klasse erstellt. Das führt sehr schnell zu Bloat, wenn man nicht > aufpasst. Ja, und für äquivalenten C-Code muss man das "template" mehrfach hinschreiben, was in der selben Code-Größe resultiert (und extrem hässlichen Sourcecode). Wenn die Funktion des Codes an sich Typ-Agnostisch ist, d.h. es wird nur mit void-Pointern rumhantiert, dann wird bei guten™ C++ Compilern auch nur 1 Template instanziert (d.h. wieder genau so gut wie der C Code); in anderen Compilern kann man sich mit etwas rumgecaste abhelfen und das template nur als schönes typsicher API verwenden. > Letztendlich muss man, wenn man C++ auf kleineren MCUs verwenden will, > komplett auf die Standard-Library verzichten Wieso sollte ich z.B. auf std::numeric_limits<size_t>::max() verzichten? Ist viel schöner&sicherer als INT_MAX o.ä., braucht aber 0 bytes mehr Speicher. > und auf diverse > Sprachfeatures (Klassen, Exceptions, Templates). Dann kann man aber > eigentlich gleich C verwenden. Wenn du auf Klassen verzichtest, solltest du aber auch auf structs in C verzichten, die sind nämlich 100% genauso verschwenderisch. templates hab ich oben schon erläutert. Bei Exceptions gebe ich dir sogar recht.
bullshit! ob eine funktion von einem double oder einem uint8_t ausgehn soll kann sie beim void* nicht schmecken... wegen so miesen praktiken hab ich mich meine anti-misra haltung schon derart oft verteidigen müssen, dass ich froh bin nur mehr indirekt production-code zu schreiben... anderer typ erfordert andere behandlung, wenn nicht, dann ist einer der beiden typen unnötig! ähnliches gilt für klassen... ich kenne das herumgecaste und structerweitern... weil ist ja nur was hinten im struct dazugekommen, da castet man dann einfach den v2-pointer auf v1 und der compiler meckert nicht mehr... der nächste ändert dann in der bearbeitungsroutine irgendwas belangloses und da ja sowas wie regression-testing auf embedded unmöglich ist, kommt der bug erst im feld auf... alles schon gehabt... nimm casses und subclasses und solange du nix virtual definierst gibts keinen einzigen unterschied im kompilat zu einer reinen c-struct und funktions implementierung... dafür ists überschaubar und wenn tatsächlich was nicht passt mäckert immerhin der compiler! exceptions geb ich dir recht... aber das liegt vor allem an der natur der sache... braucht man muss es auch sein... egal ob in c oder c++ für c++ sprechen dafür solche nettigkeiten: http://www.cprogramming.com/c++11/c++11-compile-time-processing-with-constexpr.html 73
hans schrieb: > exceptions geb ich dir recht... aber das liegt vor allem an der natur > der sache... braucht man muss es auch sein... egal ob in c oder c++ Meines Wissens nach gibt es Exceptions in C überhaupt nur durch extra nachgerüstete (Nicht-Standard) Bibliotheken; nativ gar nicht.
Dr. Sommer schrieb: > Wenn du auf Klassen verzichtest, solltest du aber auch auf structs in C > verzichten, die sind nämlich 100% genauso verschwenderisch. Sorry, da hab ich mich vertan. Was ich eigentlich meinte ist, dass man für den "new"-Operator die Standardlibrary braucht. Dynamische Allokation von Objekten geht also nur wie in C mit malloc/free, man kann C++-Klassen also nicht vollständig nutzen. > templates > hab ich oben schon erläutert. Bei Exceptions gebe ich dir sogar recht. Templates verführen einfach schnell zu einem Stil, der zwar schön typsicher ist, aber auch zu Bloat führt. Gerade wenn man die STL nutzt. Nicht mehr und nicht weniger. Mit C hat man solchen Bloat besser unter Kontrolle.
Nee, ich meinte die Frage schon ernst: An welchen Stellen kann man in C praktibel Code-Size sparen, an denen das mit templates (mit denen man höchstwahrscheinlich den Trick "sicherer" machen kann) nicht geht? @vorposter: Ich halte new jetzt eigentlich für kein so wichtiges Feature in C++, vor allem mal auf statischen µC-Programmen, in denen es sowieso nicht vorkommt (C++ != Java!). Ansonsten kann man sich das auch gerne auf malloc/free umbiegen.
Das der Code bei C++ größer wird habe ich bei meinen ersten Versuchen auch festgestellt. Ich muss aber glaube ich noch ein wenig suchen worans wirklich liegt weil ich bisher nur mal alles zusammenkopiert und zum compilieren gebracht habe. Genauer heißt das, dass ich mal ein C-Projekt von mir komplett entrümpelt habe, d.h. es ist nur noch die main-Funktion samt Endlosschleife, sowie der Startup Code und die System Init (Clock init) des STM32 vorhanden. Die Codegröße liegt dann bei ca. 11k. Mal sehen woran das liegt. Verwendet habe ich den CodeSourcery GCC Compiler. @Werz: Bzgl. des Buchs kann ich dir keine Empfehlung geben da ich es auch erst sehr frisch habe und noch nicht wirklich reinschauen konnte. Ich will nur vermeiden dass du umsonst Geld ausgibst ;-)
Mark Brandis schrieb: > Meines Wissens nach gibt es Exceptions in C überhaupt nur durch extra > nachgerüstete (Nicht-Standard) Bibliotheken; nativ gar nicht. Naja, longjmp/setjmp gibt's auch in C, und zumindest eine mögliche Implementierung von Exceptions arbeitet genau auf diesem Wege.
Hallo Jupp, ja ich hab mir das Inhaltsverzeichnis mal angeschaut. Ich denke, dass ich mir das Buch trotzdem zulegen werde, weil es kompakt von Grund auf das beschreibt, was ich lernen will, nämlich C++ für Mikrokontroller zu programmieren. Im Internet finde ich keine passende Information/Quelle, wo dies in der Art bechrieben ist.
greg schrieb: > Sorry, da hab ich mich vertan. Was ich eigentlich meinte ist, dass man > für den "new"-Operator die Standardlibrary braucht. Ja. Aber was hat das mit Klassen zu tun? Nix. Wie C-Structs kann man Klassen nach Wahl auf den Stack, auf den Heap oder global anlegen. > Dynamische > Allokation von Objekten geht also nur wie in C mit malloc/free, man kann > C++-Klassen also nicht vollständig nutzen. C-Structs aber auch nicht, da man sie nicht malloc()en kann. > Templates verführen einfach schnell zu einem Stil, der zwar schön > typsicher ist, aber auch zu Bloat führt. Eine wilde Behauptung. Dank Compiler-Optimierung wird so viel Code generiert wie das C-Äquivalent auch bräuchte. > Gerade wenn man die STL nutzt. Warum denken eigentlich immer alle dass die stdlib/STL nur aus std::vector und std::string besteht? Da gibt es noch viel mehr nützliche Dinge, wie zB std::numeric_limits<int>::max() - das ist ein Template, ist aber super effizient. > Nicht mehr und nicht weniger. Mit C hat man solchen Bloat besser unter > Kontrolle. Ja, weil man sich die Finger wund schreibt alles zu copy&pastan. Jupp schrieb: > Die Codegröße liegt dann bei ca. 11k. Mal > sehen woran das liegt. Verwendet habe ich den CodeSourcery GCC Compiler Habe mir ein ähnliches Dummy-Projekt in C++ angelegt und komme mit dem GCC-ARM-Embedded auf 328 Bytes, und das ist nur wegen der SystemInit so viel.
Jörg Wunsch schrieb: > Naja, longjmp/setjmp gibt's auch in C, und zumindest eine mögliche > Implementierung von Exceptions arbeitet genau auf diesem Wege. Ja gut. Aber will man das wirklich haben ;-)
1. Beim Einschalten ist das RAM leer, also werden die Daten vom Flash ins RAM geladen. Danach wird immer auf das RAM zugegriffen. Dies geht auch gar nicht anders da : Der Code direkt aus dem Flash ausgeführt wird und die Daten im RAM liegen müssen (Harvard). Das heißt zur Laufzeit kann ein wilderder Pointer, Stack Überlauf usw. jederzeit deine Motorparameter zerstören. Denn der µC lies deine Struktur nicht neu aus dem Flash (Es sei denn du Programmierst das so). Aber selbst wenn du das tust dann muß du Sie ins RAM lesen, denn nur von dort aus kannst du Sie benutzen ! tada !
Uwe schrieb: > 1. Beim Einschalten ist das RAM leer, also werden die Daten vom > Flash > ins RAM geladen. Danach wird immer auf das RAM zugegriffen. > Dies geht auch gar nicht anders da : > Der Code direkt aus dem Flash ausgeführt wird und die Daten im RAM > liegen müssen (Harvard). > Das heißt zur Laufzeit kann ein wilderder Pointer, Stack Überlauf usw. > jederzeit deine Motorparameter zerstören. > Denn der µC lies deine Struktur nicht neu aus dem Flash (Es sei denn du > Programmierst das so). Aber selbst wenn du das tust dann muß du Sie ins > RAM lesen, denn nur von dort aus kannst du Sie benutzen ! tada ! Alles was du schreibst gilt nur für AVR o.ä.. Der OP benutzt aber STM32, und der kann: * Code aus dem RAM oder Flash ausführen. * Daten aus dem Flash und RAM mit derselben Instruktion laden; die Daten können also problemlos im Flash bleiben und der Code sie ohne besondere Vorkehrungen direkt von da lesen ohne Umweg über den RAM. Nur schreiben geht nicht ohne weiteres.
Uwe schrieb: > Beim Einschalten ist das RAM leer, also werden die Daten vom Flash > ins RAM geladen. Jo, sehe ich auch so, das die Init-Werte der Variablen vom Startup Code ins RAM kopiert werden müssen. Uwe schrieb: > Das heißt zur Laufzeit kann ein wilderder Pointer, Stack Überlauf usw. > jederzeit deine Motorparameter zerstören. Warum sollte das so sein? Bei den Motorparametern steht zur Compilezeit fest das die Daten unveränderlich, also const sind. Damit wäre es auch möglich sie nur im Flash des Controllers zu halten. Wenn die Parameter im Code verwendet werden, werden sie zunächst in die entsprechenden CPU-Register geladen und dort verarbeitet.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.