Forum: Mikrocontroller und Digitale Elektronik C++ auf Mikrocontrollern


von Jupp (Gast)


Lesenswert?

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

von Ähem ... (Gast)


Lesenswert?

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 ...

von Simon S. (-schumi-)


Lesenswert?

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.

von Marian (phiarc) Benutzerseite


Lesenswert?

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
von kopfkratzer (Gast)


Lesenswert?

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 ...

von Roland E. (roland0815)


Lesenswert?

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.

von Jupp (Gast)


Lesenswert?

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?

von Stefanus (Gast)


Lesenswert?

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.

von JojoS (Gast)


Lesenswert?

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?

von decimad (Gast)


Lesenswert?

Gefällt mir, wie POST die Bezeichnung für die Tests, die vor der 
Ausführung stattfinden sollen, ist.

von Marian (phiarc) Benutzerseite


Lesenswert?

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.

von Compiler (Gast)


Lesenswert?

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.

von Irgenwer (Gast)


Lesenswert?

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

von Dr. Sommer (Gast)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Marian (phiarc) Benutzerseite


Lesenswert?

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, ...)

von Jupp (Gast)


Lesenswert?

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 :-).

von Dr. Sommer (Gast)


Lesenswert?

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.

von Compiler (Gast)


Lesenswert?

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)?

von Compiler (Gast)


Lesenswert?

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++.

von (prx) A. K. (prx)


Lesenswert?

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.

von Compiler (Gast)


Lesenswert?

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???

von Jupp (Gast)


Lesenswert?

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.

von hans (Gast)


Lesenswert?

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

von Jupp (Gast)


Lesenswert?

@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 :-(

von benwilliam (Gast)


Lesenswert?

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.

von Dr. Sommer (Gast)


Lesenswert?

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.

von Maxx (Gast)


Lesenswert?

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.

von Werz (Gast)


Lesenswert?

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

von Jupp (Gast)


Lesenswert?

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 :-)

von Werz (Gast)


Lesenswert?

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

von Mark B. (markbrandis)


Lesenswert?

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 ;-)

von Jupp (Gast)


Lesenswert?

;-)

von JochenZ (Gast)


Lesenswert?

nur mal so als Wegweiser zu dem Thema ;-)

http://www.avr-cpp.de
http://libavrstdcpp.codeplex.com/
http://mystm32.de/doku.php

Gruß JZ

von Werz (Gast)


Lesenswert?

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

von greg (Gast)


Lesenswert?

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.

von decimad (Gast)


Lesenswert?

Kannst Du ein problematisches Beispieltemplate zeigen?

von hans (Gast)


Lesenswert?

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

von Maxx (Gast)


Lesenswert?

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)

von Werz (Gast)


Lesenswert?

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 :)

von Werz (Gast)


Lesenswert?

Sorry Max, hatte deinen Thread erst jetzt gelesen...

von greg (Gast)


Lesenswert?

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.

von Dr. Sommer (Gast)


Lesenswert?

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.

von hans (Gast)


Lesenswert?

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

von Mark B. (markbrandis)


Lesenswert?

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.

von greg (Gast)


Lesenswert?

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.

von decimad (Gast)


Lesenswert?

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.

von Jupp (Gast)


Lesenswert?

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 ;-)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Werz (Gast)


Lesenswert?

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.

von Dr. Sommer (Gast)


Lesenswert?

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.

von Mark B. (markbrandis)


Lesenswert?

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 ;-)

von Uwe (Gast)


Lesenswert?

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 !

von Dr. Sommer (Gast)


Lesenswert?

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.

von Jupp (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.