Forum: Mikrocontroller und Digitale Elektronik C++ auf einem MC, wie geht das?


von BastiDerBastler (Gast)


Lesenswert?

@W.S: Wie sieht denn Dein architektonischer High-Level Code aus, wenn Du 
solche Basis-sachen wie wiederbelegbare Pin-Referenzen und sowas nicht 
irgendwo wegkapselst? Der muss dann ja durchsetzt sein von 
Low-Level-Kram, der auf der Ebene gar nix zu suchen hat...

von Karl Käfer (Gast)


Lesenswert?

Hallo Basti,

BastiDerBastler schrieb:
> also ich habe den Code hier mal so hingefrickelt in meiner Bibliothek.

Da wäre es natürlich schön, die Bibliothek einmal zu sehen. ;-)

> Wollte jetzt kein Getriebe von einem Pin ableiten lassen usw.
> (Komposition wäre da eindeutig besser).

Ja, in einer realen Welt, in der ein Getriebe mehr Informationen hergibt 
als nur, ob ein Gang eingelegt ist, wäre das möglicherweise sinnvoll. In 
diesem Beispiel ist es allerdings unnötig.

> Vielleicht sollte man die Dinge auch nicht "pin" nennen, sondern
> "pin_ref", schließlich referenziert das ja nur einen real existierenden
> Pin.

Nein, sorry, es referenziert den Pin nicht, sondern repräsentiert 
ihn. Die Klasse "Pin" ist eine allgemeingültige Software-Repräsentation 
aller Hardware-Pins, und eine konkrete Instanz der Klasse "Pin" 
repräsentiert dann einen konkreten Hardware-Pin in der Software.

> "pb<3>" usw. sind "statische" Pin-Referenzen, die man auch verwenden
> könnte, aber da der Beispielcode oben ja Laufzeit-Werte genommen hat,
> habe ich das hier ebenso gemacht.

Bitte verzeih', aber "pb<3>" ist Unfug und jeder ordentliche Compiler 
sollte Dir das mit einer deutlichen Fehlermeldung um die Ohren hauen.

Du sitzt -- wie auch andere hier -- einem grundsätzlichen Mißverständnis 
bezüglich des C++-Sprachfeature Templates auf. Template-Programmierung 
ist ein Mechanismus, um einer generischen Klasse oder Funktion einen 
Datentyp zu übergeben, nicht einen Wert. Die "3" in "pb<3>" ist aber 
kein Typ, sondern ein Wert (genauer: eine Konstante) vom Typ Integer. 
"pb(3)" und "pb<int>" ergeben einen Sinn, "pb<3>" tut es nicht.

Ein Beispiel:
1
#include <iostream>
2
3
using namespace std;
4
5
template <typename T>
6
class Templateklasse {
7
public:
8
    T eins;
9
    T zwei;
10
    Templateklasse(T e, T z): eins(e), zwei(z) {}
11
    void ausgabe(void) { cout << this->eins << " " << this->zwei << endl; }
12
};
13
14
int main(int argc, char* argv[]) {
15
    Templateklasse<int>    a(1, 2);
16
    Templateklasse<string> b("Hallo", "Welt");
17
    Templateklasse<1> b(1, 1);
18
19
    a.ausgabe();
20
    b.ausgabe();
21
22
    return 0;
23
}

Die Klasse "Templateklasse" kann ich jetzt mit verschiedenen Datentypen 
verwenden, beispielsweise mit einem "int" und einem "string". Daraus 
erzeugt der Compiler dann eine Klasse "Templateklasse" für Integers, und 
eine Klasse "Templateklasse" für Strings.

Die Wikipedia hat eine ganz gute Erklärung zu Templates in C++: 
http://de.wikipedia.org/wiki/Template_%28Programmierung%29

HTH und liebe Grüße,
Karl

von Karl Käfer (Gast)


Lesenswert?

Hallo W,

W.S. schrieb:
> Der Volksmund sagt "getroffene Hunde bellen".

Bitte entschuldige, daß ich versucht habe, Deinen Horizont zu erweitern. 
Offensichtlich hast Du daran gar kein Interesse.

> Was also sollen solche billigen Dinge wie:
>
> pin motor = pb<3>();
> und
> motor.configure(inout());

Was das soll, kann ich Dir auch nicht sagen -- nur, daß es fehlerhaft 
ist und von einem guten Compiler mit einem Fehler quittiert werden 
sollte. g++ und clang++ tun das jedenfalls.

Und wenn Du mit mir diskutieren willst, dann solltest Du Dich auf meine 
Beispiele beziehen. Daß Du Dir stattdessen ein fehlerhaftes Beispiel von 
Basti heraussuchen mußt, um es dann mir unter die Nase zu reiben, zeigt 
mir allerdings, daß Du zu einer sachlichen Diskussion entweder nicht 
fähig bist, oder kein Interesse daran hast.

> Und man kann sogar mehrere Konstruktoren
> haben und nicht bloß einen einzigen mickrigen Konstruktor wi bei C++.

Natürlich geht das auch bei C++. Das zeigt, daß Du hier die ganze Zeit 
über Dinge redest, von denen Du offenbar keine Ahnung hast. Schade.

Liebe Grüße,
Karl

von Peter L. (localhost)


Lesenswert?


von Karl Käfer (Gast)


Lesenswert?

Hallo,

Karl Käfer schrieb:
>
1
>     Templateklasse<1> b(1, 1);
2
>

Oh, lustig: das ist natürlich ein Fehler und wurde von mir nur in den 
Code geschrieben um zu sehen, ob g++ und clang++ dabei für Fehler 
ausgeben. Sie tun es jedenfalls. Ansonsten ist diese Zeile Unfug und zu 
ignorieren.

Liebe Grüße,
Karl

von Peter L. (localhost)


Lesenswert?

template <int pin>
struct pb{
void set(){
ptr = (int*)0xDEADBEEF + pin;
*ptr = 0x1;
};

pb<1337> a;
a.set();

Sowas ist erlaubt.
Also husch nochmal paar template tutorials durcharbeiten.

: Bearbeitet durch User
von Karl Käfer (Gast)


Lesenswert?

Hallo Peter,

Peter L. schrieb:
> Hast du deinen Link auch mal selber gelesen?

Ja, natürlich.

> http://de.wikipedia.org/wiki/Template_%28Programmierung%29#Nichttyp-Parameter

Und das hat hier welche Relevanz? Für die Übergabe einer Pinnummer sind 
Nichttypparameter jedenfalls Unsinn -- und wer so weit ist, daß er 
solche Parameter braucht, der hat Templates weit genug verstanden, um 
das gar nicht erst versuchen zu wollen. Tipp: Nichttyp-Parameter sind 
Template-Parameter, also Parameter für Templates statt für Instanzen.

Liebe Grüße,
Karl

von Daniel A. (daniel-a)


Lesenswert?

Karl Käfer schrieb:
> Karl Käfer schrieb:
>>
1
>>     Templateklasse<1> b(1, 1);
2
>>
> Ansonsten ist diese Zeile Unfug und zu ignorieren.

Konstanten als Parameter sind eine grundlage der C++ Metaprogrammierung.

> Nichttyp-Parameter sind
> Template-Parameter, also Parameter für Templates statt für Instanzen.

Sehr richtig. Und da typen keinen Speicherplaz belegen, im gegensatz zu 
instanzen, und man Templateclassen nicht instanzieren muss, um auf 
dessen statische Variablen zuzugreifen, kann man damit viel Ram und 
Rechenzeit sparen.

C++ Metaprogramming kann ich nur emphelen:
http://de.m.wikipedia.org/wiki/C%2B%2B-Metaprogrammierung

Im funktionierenden Beispiel, das ich ganz weit oben mal Postete (Beide 
beiträge beachten), habe ich änliches gemacht. 0 bytes Overhead! Aber 
leider niemand, der den code kommentierte...

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Daniel A. schrieb:
> C++ Metaprogramming kann ich nur emphelen:

Das ist wirklich cool. :-) Mache ich auch!

Torsten C. schrieb:
> Aber mit den diversen IDEs, die ich für µCs benutze, hat es nie
> richtig funktioniert … beim Debuggen mit Breakpoints in die
> Instanz-Variablen zu schauen.

Aber mit welcher IDE geht das auch für µCs in der Praxis?

Was nützt all Eure Theorie? Bei Visual Studio .net für Windows wäre das 
alles kein Problem. Aber hier geht es doch um "C++ auf einem MC", oder?

: Bearbeitet durch User
von BastiDerBastler (Gast)


Lesenswert?

Karl Käfer:

Ich nehm's Dir nicht übel, weil ich sehe, dass Du Dich ernsthaft damit 
auseinandersetzt. Ich möchte meinen Quellcode hier nicht unbedingt 
breittreten, würde ihn Dir aber auf irgendeinem Weg zur Verfügung 
stellen. Ich glaube einschätzen zu können, dass das meiste darin Dir 
vielleicht etwas zu abgefahren ist (gemeint als: der Problematik nicht 
angemessen, nicht über Deinen Verstand, hehe).

Soviel: das pb<3>() dort, dient dem Konstruktor von "pin" nur als 
Information ("pb<3>" ist ein typ-alias für "static_pin<1,3>"), das 
temporäre Objekt selber ist irrelevant (und wird vom Compiler dann 
geschluckt).
Ich könnte aber auch pb<3>::set() schreiben, nur wäre das halt zur 
Compile-Zeit festverdrahtet. Ich finde das so eigentlich ziemlich 
ausdrucksstark.
Templates sind halt nicht nur über Typen parametrierbar, aber das haben 
meine Vorredner ja schon dargelegt.

von BastiDerBastler (Gast)


Lesenswert?

Karl Käfer:
Noch zu der Referenz-Sache, das habe ich versäumt.
1
    int a;
2
    int b;
3
4
    a = 1;
5
    b = 2;
6
    
7
    assert(a != b);  // unabhängige Objekte
8
9
    int c;
10
    int& d = c;
11
    int& e = c;
12
13
    d = 4;
14
    e = 2;
15
16
    assert( d == e ); // Referenzen auf ein Objekt
17
18
    pin f = pb<3>();
19
    pin g = pb<3>();
20
21
    f.set();
22
    g.reset();
23
24
    assert( f.get() == g.get() ); // ????

Was man da als Objekt der Klasse "pin" hat, besitzt für mich eindeutig 
Referenzcharakter (bis auf, dass man diese Referenz im Gegensatz zu 
C++-Referenzen neu setzen kann).

von Karl Käfer (Gast)


Lesenswert?

Hallo Peter,

Peter L. schrieb:
> template <int pin>
> struct pb{
> void set(){
> ptr = (int*)0xDEADBEEF + pin;
> *ptr = 0x1;
> };
>
> pb<1337> a;
> a.set();
>
> Sowas ist erlaubt.

Die Frage ist ja nicht, ob es erlaubt ist, sondern, ob es sinnvoll ist.

> Also husch nochmal paar template tutorials durcharbeiten.

;-)

Liebe Grüße,
Karl

von Karl Käfer (Gast)


Lesenswert?

Hallo Daniel,

Daniel A. schrieb:
> Sehr richtig. Und da typen keinen Speicherplaz belegen, im gegensatz zu
> instanzen, und man Templateclassen nicht instanzieren muss, um auf
> dessen statische Variablen zuzugreifen, kann man damit viel Ram und
> Rechenzeit sparen.

Na klar. Aber bei der Initialisierung eines Hardware-Pins mit
1
OutputPin ledPin(&DDRB, &PORTB, &PINB, PB0);
 sind DDRB, PORTB und PINB keine Variablen, also keine Instanzen, 
sondern Konstante.

> Im funktionierenden Beispiel, das ich ganz weit oben mal Postete (Beide
> beiträge beachten), habe ich änliches gemacht. 0 bytes Overhead! Aber
> leider niemand, der den code kommentierte...

Da schaue ich gerne hinein. Aber möchtest Du Dir vielleicht auch einmal 
meine Code-Beispiele in [1] und [2] anschauen? Viel Spaß!

Liebe Grüße,
Karl


[1] Beitrag "Re: C++ auf einem MC, wie geht das?"
[2] Beitrag "Re: C++ auf einem MC, wie geht das?"

von Karl Käfer (Gast)


Lesenswert?

Hallo Basti,

BastiDerBastler schrieb:
> Ich nehm's Dir nicht übel, weil ich sehe, dass Du Dich ernsthaft damit
> auseinandersetzt. Ich möchte meinen Quellcode hier nicht unbedingt
> breittreten, würde ihn Dir aber auf irgendeinem Weg zur Verfügung
> stellen.

Die E-Mail-Adresse karl@lukenukem.de sollte funktionieren. Dein Code ist 
bei mir in guten Händen.

> Ich glaube einschätzen zu können, dass das meiste darin Dir
> vielleicht etwas zu abgefahren ist (gemeint als: der Problematik nicht
> angemessen, nicht über Deinen Verstand, hehe).

Ob ein Code dem Problem angemessen ist, liegt doch immer am Problem. ;-)

> Soviel: das pb<3>() dort, dient dem Konstruktor von "pin" nur als
> Information ("pb<3>" ist ein typ-alias für "static_pin<1,3>"), das
> temporäre Objekt selber ist irrelevant (und wird vom Compiler dann
> geschluckt).
> Ich könnte aber auch pb<3>::set() schreiben, nur wäre das halt zur
> Compile-Zeit festverdrahtet. Ich finde das so eigentlich ziemlich
> ausdrucksstark.

Ok, dann habe ich Deine Kenntnisse offensichtlich flahsc eingeschätzt 
und muß um Verzeihung bitten.

Liebe Grüße,
Karl

von Torsten C. (torsten_c) Benutzerseite


Angehängte Dateien:

Lesenswert?

1
RCC_APB1PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
Was stimmt da nicht? Richtig, es muss heißen:
1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

Weil ich immer wieder meine Zeit mit solchen Mist verschwende, möchte 
ich nun auch endlich mal 'ne ordentliche HAL-API haben.

STM32CubeMX erstellt leider auch kein C++. Außerdem wird der STM32F103 
noch nicht unterstützt und gerade mit dem arbeite ich hauptsächlich, 
weil es den bei aliexpress für weniger als 2€ gibt.

Das "xpcc project" ^^ ist ja schon ziemlich dicht dran. Aber es gibt 
immer was, was einem nicht gefällt. Zum Beispiel könnte der USART 
zumindest beim TX auch den DMA-Controller nutzen, statt nur Interrupts:

http://xpcc.kreatives-chaos.com/api/classxpcc_1_1stm32_1_1_usart_hal1.html

Ausgezeichnet finde ich die Präsentation von Scott Meyers zu "Effective 
C++ in an Embedded Environment". Anbei ein Beispiel, wie man ein 
Peripherie-Register in c++ darstellen könnte. Auf den folgenden Slides 
werden viele Details besprochen und Alternativen zu dem Thema 
besprochen.

Bei uns im Wiki gib's ja noch nicht allzuviel zu dem Thema:

http://www.mikrocontroller.net/articles/Kategorie:C%2B%2B

Was ich bisher so an Quellen gefunden habe, sammle ich gerade unter:

https://notizblog.wordpress.com/%C2%B5c-programmierung-mit-c/

Dort ist auch ein Link zum PDF-Dokument von Scott Meyers.

Hat schon jemand die Sourcen vom "xpcc project" ausprobiert? Sind diese 
eine gute Basis, um darauf aufzubauen?

Macht es Sinn, unser gesammeltes Wissen in einem eigenen Wiki-Artikel zu 
sammeln?

: Bearbeitet durch User
von Jens (Gast)


Lesenswert?

Torsten C. schrieb:
> Macht es Sinn, unser gesammeltes Wissen in einem eigenen Wiki-Artikel zu
> sammeln?
Ja. Unbedingt.

von Torsten C. (torsten_c) Benutzerseite


Angehängte Dateien:

Lesenswert?

[ScoMe01] Slide 169 sagt:
> “A fundamental design goal is that design violations
>  should not compile.”

Jawohl! :-) Also auch, wenn PCLK1 oder PCLK2 verwechselt werden? Oder 
wenn es einen Konklikt beim DMA-Kanal gibt?

Torsten C. schrieb:
> Zum Beispiel könnte der USART zumindest beim TX auch
> den DMA-Controller nutzen, statt nur Interrupts.

Ich habe daher mal ganz einfach angefangen, mit dem USART.

Versteht jemand in diesem Zusammenhang diese drei Dinge?
1
calculateBaudrateSettings (uint32_t sabclk, uint32_t baudrate)
http://xpcc.kreatives-chaos.com/api/classxpcc_1_1stm32_1_1_uart_base.html

1. Ist "uint32_t baudrate" eine gute Idee, oder sollte das eher
   ein float sein?

2. Warum wird "sabclk" als Parameter übergeben und kein Pointer auf
   PCLK1 oder PCLK2 genutzt (rot im 2. Bild)?

3. Wie stellt man sicher, dass ein DMA-Kanal immer nur einmal verwendet
   wird, also z.B. SPI2_RX nicht von USART1_TX überschrieben wird?
   Beides zusammen geht nicht (1. Bild).

: Bearbeitet durch User
von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Torsten C. schrieb:
> Ausgezeichnet finde ich die Präsentation von Scott Meyers zu
> "Effective C++ in an Embedded Environment". … Dort ist auch
> ein Link zum PDF-Dokument von Scott Meyers.

@Peter Dannegger (peda): Ist Deine Frage "C++ auf einem MC, wie geht 
das?" damit beantwortet? Es ist so still geworden hier!

von Moby A. (moby-project) Benutzerseite


Lesenswert?

Torsten C. schrieb:
> Es ist so still geworden hier!

Das muß nun nicht wirklich verwundern.
C++ auf kleinen Controllern ist und bleibt eine Schnapsidee.

von Frank (Gast)


Lesenswert?

So wie ich PeDa einschätzte hat er sich nur von diesem Scheißartikel 
ausgeklinkt.
Durch die ganzen Möchtegern ASMler kommt doch hier sowieso nichts dabei 
rum.
Wie die kleinen Kinder.

Grüße Frank

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Jens schrieb:
> Torsten C. schrieb:
>> Macht es Sinn, unser gesammeltes Wissen in einem eigenen Wiki-Artikel zu
>> sammeln?
> Ja. Unbedingt.

Frank schrieb:
> kommt doch hier sowieso nichts dabei rum.

Es müsste schon eine "kritische Masse" an Leuten geben, die Ihr Wissen 
zusammentun und sich von "Möchtegern ASMlern" ^^ nicht stören lassen, 
also die Trolle nicht füttern.

Falls dies ein "Scheißartikel" ^^ ist und Interesse besteht, könnte man 
ja einen neuen aufmachen.

von Frank (Gast)


Lesenswert?

Torsten C. versteht das nicht falsch mit dem Scheißartikel. Ich bin 
absoluter Befürworter einer abstrakten objektorientierten Programmierung 
und das auch auf uC.
Ich nutzte dies in meinem beruflichen Alltag zu 95%.
In 5% gibt es Bereiche, die in ASM programmiert werden, dann aber wieder 
in einem einheitlichen Interface gekapselt werden.

Wobei es in diesem Artikel leider gar nicht um das "warum", sondern um 
das "wie" gehen sollte, so war ja auch die eigentlich gestellt 
Frage...deshalb Scheißartikel!

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Frank schrieb:
> sondern um
> das "wie" gehen sollte, so war ja auch die eigentlich gestellt
> Frage

Ja. Über das "warum" wurde schon genug debattiert. Wer's nicht machen 
will, kann die Klappe halten, weil seine Posts ignoriert werden. Alles 
heiße Luft!

Ich habe für das Dokument von "Scott Meyers"^^ bestimmt ein paar Stunden 
gebraucht, um alles zu verstehen, aber das "wie" ist hier schon fast 
umfassend erklärt.

Zusammen mit den Beispielen aus dem "xpcc project" hat man eigentlich 
schon fast alles, was man braucht.

Was nur noch fehlt, sind ein paar Leute, mit dem man Fragen, Vor- und 
Nachteile verschiedener Implementierungen usw. diskutieren kann. Da 
kommt hier wohl leider keine kritische Masse zustande. :-(

: Bearbeitet durch User
von Klaus W. (mfgkw)


Lesenswert?

Masse könnte ich beisteuern, aber ist wohl das falsche Forum hier.

von Moby A. (moby-project) Benutzerseite


Lesenswert?

Torsten C. schrieb:
> Da kommt hier wohl leider keine kritische Masse zustande. :-(

Na warum wohl? Stell Dir mal diese Frage!
Vielleicht, weil es mehr als

Torsten C. schrieb:
> ein paar Stunden (ge)braucht, um alles zu verstehen,

für ein auf kleinen Controllern letztlich zweifelhaftes Ergebnis?

von Klaus W. (mfgkw)


Lesenswert?

Au sder ursprünglichen Frage:

Peter Dannegger schrieb:
> ... MC-spezifische Abläufe ...

Das können kleine oder größere MC sein, wir leben im Jahr 2015.

Moby AVR schrieb im Beitrag #3972786:
> ... für ein auf kleinen Controllern ...

Es gibt nicht nur deine attiny-Welt.

Also geh doch bitte wieder in den Sandkasten, du hast genug genervt.

von Moby A. (moby-project) Benutzerseite


Lesenswert?

Klaus Wachtler schrieb:
> Es gibt nicht nur deine attiny-Welt.

Richtig. Da wären auch noch die Megas. Und die XMegas erst...

> Also geh doch bitte wieder in den Sandkasten

Was Du "Sandkasten" nennst, damit ist das Meiste hier problemlos lösbar. 
Da muß es nicht auf Biegen und Brechen die  Großbaustelle sein ;-)

: Bearbeitet durch User
von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

@Moderator: Geht das (siehe unten)?

Frank schrieb:
> Wie die kleinen Kinder.

Was leider mal wieder bewiesen wurde. :-(

Füttert keine Trolle!

Klaus Wachtler schrieb:
> Masse könnte ich beisteuern, aber ist wohl das falsche Forum hier.

Das klingt doch gut. Einfach diejenigen, die den Sinn diskutieren wollen 
ignorieren ist aber produktiver, egal in welchem Forum.

Welches Forum wäre besser?

Wir könnten hier ja auch einen neuen Thread aufmachen und mit den Mods 
sprechen, dass dann die gemeldeten Troll-Posts gelöscht werden. Dann 
wird nur über das "wie" diskutiert und nicht das "warum".

Ausgangsbasis?

* eine Kurzfassung von dem hier? http://wp.me/PCum-qm
* andere Vorschläge?

von Moby A. (moby-project) Benutzerseite


Lesenswert?

Torsten C. schrieb:
> Wir könnten hier ja auch einen neuen Thread aufmachen
> wird nur über das "wie" diskutiert und nicht das "warum".

Ob das daran was ändert:

Torsten C. schrieb:
> Es ist so still geworden hier!

???
Hilft doch nicht, der Frage nach dem Sinn und Zweck konsequent 
auszuweichen...

von Ben (Gast)


Lesenswert?

Torsten C. schrieb:
> Wir könnten hier ja auch einen neuen Thread aufmachen und mit den Mods
> sprechen, dass dann die gemeldeten Troll-Posts gelöscht werden. Dann
> wird nur über das "wie" diskutiert und nicht das "warum".

Ich würde mich dafür interessieren.
Ich denke, Ziel sollte es sein, eine Sammlung von Klassen zur Verfügung 
zu stellen um von der Hardware eines ATmega abstrahieren zu können.

Angefangen mit der oft Diskutierten Pin-Klasse. Man müsste beweisen dass 
diese Klasse keinen zusätzlichen Overhead verursacht. Davon ausgehend 
könnte man dann weitere Klassen nach ähnlichem Schema anlegen (UART, 
Timer, ...)

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


Lesenswert?

Torsten C. schrieb:
> @Moderator: Geht das (siehe unten)?

Nein.  Bleib mal bei einem Thread.

Wenn du einen Wiki-Artikel schreiben willst, dann musst du ihn allgemein
halten und möglichst unabhängig von Controllerfamilien (so, wie die
Überschrift gewählt ist).  Kann man sicher machen, aber dürfte viel
Arbeit werden.

Mir scheint, was du willst, ist eher ein Projekt, welches für ein oder
zwei ganz konkrete Controller(familien) die Abstraktion implementiert.

Sowie du das versuchst, auf viele Familien auszuweiten, geht das schnell
ins Uferlose.

Für Projekte wiederum gibt es hier die Möglichkeit, einen SVN-Server
zu hosten sowie das in "Projekte & Code" zu posten.

von Matthias (Gast)


Lesenswert?

Um ein wenig auf den Ursprungspost zurückzukommen. Der Aussage: "Es gibt 
kein verstehbares Lehrbuch" widerspreche ich zum Teil.

Grundsätzlich lässt sich C++ auf Embedded-Systemen wunderbar einsetzen, 
FALLS man ein umfassendes Verständnis der Sprachmittel hat. Und das in 
einem sehr viel grösseren Umfang als es bei C der Fall wäre. C++ birgt 
gerade durch den höheren Abstraktionsgrad die Gefahr dass banalste 
Statements zu Resourcen- oder Laufzeitfressern werden.
Für einen sauberen Spracheinstieg empfehle ich die Bücher C++ Primer (S. 
Lippman) und Principles and Practice Using C++ (B. Stroutsrup). Beide 
müsste es auch in deutsch geben, falls das beim Lesen leichter fällt.

Hat man C++ im Grundsatz auf dem Kasten kommt die absolute 
Pflichtlektüre:
Industrial Strength C++ (Nyquist)

Spätestens jetzt hat man genug Wissen um z.b. dynamische 
Speichverwaltung zu umgehen wo es nicht unbedingt notwendig ist.
Nur wer genau weiss was ein C++-Ausdruck auf dem Target zu Folge hat 
sollte darüber nachdenken C++ auf MCUs einzusetzen.

von Ralf G. (ralg)


Lesenswert?

Darf ich das hier noch mal schnell unterstreichen?:
Matthias schrieb:
> Grundsätzlich lässt sich C++ auf Embedded-Systemen wunderbar einsetzen,
> FALLS man ein umfassendes Verständnis der Sprachmittel hat.
Matthias schrieb:
> Nur wer genau weiss was ein C++-Ausdruck auf dem Target zu Folge hat
> sollte darüber nachdenken C++ auf MCUs einzusetzen.

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Jörg Wunsch schrieb:
> Mir scheint, was du willst, ist eher ein Projekt, welches für ein oder
> zwei ganz konkrete Controller(familien) die Abstraktion implementiert.

Ja, denn einerseits sind wir hier vielleicht eine Handvoll Leute, die 
zusammen was machen wollen, da wird man sich sicher schnell auf eine 
Untermenge einigen, damit das Projekt nicht ins Uferlose geht.

Ich kenne den AVR zwar auch gut, mache meine neuen Projekte aber mit 
STM32F1xx und STM32F4xx. Auf den STM32Fxxx läge bei mir daher der Focus.

Ben schrieb:
> … um von der Hardware eines ATmega abstrahieren zu können

Der ATmega darf natürlich nicht fehlen. Vielleicht reicht es auch, mit 
diesen Beiden anzufangen, um sich nicht zu verzetteln.

Beim Infineon XMC4500 ist z.B. wieder alles ganz anders. Der 
interessiert mich zwar auch, aber da würde ich erstmal nur einen Blick 
drauf werfen, damit sich die Bibliotheken später ohne komplette 
Umstrukturierung erweitern lassen.

Und der MSP430-Compiler von TI unterstützt z.B. eh keine Templates.

> Für Projekte wiederum gibt es hier die Möglichkeit, einen SVN-Server
> zu hosten sowie das in "Projekte & Code" zu posten.

Ich habe bisher Github genutzt, viele finden das einfacher. Ich selbst 
habe mir noch keine Meinung gebildet.

Legt jemand auf den µC.net-SVN-Server Wert? Oder soll ich auf Github ein 
Git für dieses Projekt anlegen?

Wie soll das Projekt (das Git, die Wiki-Seite, das SVN-Repository) 
heißen? "EmbeddedCpp" oder ist das zu kurz?

Jörg Wunsch schrieb:
> Bleib mal bei einem Thread.

OK, Gern. Langfristig, wenn das Ziel klar ist und wir uns einig sind, 
kann ich mir aber auch einen Thread in "Projekte & Code" vorstellen.

Fazit bisher:
¯¯¯¯¯¯¯¯¯¯¯¯¯
   3 Personen:
   ¯¯¯¯¯¯¯¯¯¯¯
      * Klaus Wachtler (mfgkw)
      * Ben (Gast)
      * Torsten C. (torsten_c)

   2 Targets:
   ¯¯¯¯¯¯¯¯¯¯
      * STM32-ARMs
      * ATMega-AVRs

   Erste Zwischenziele
   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
      * Pin-Klasse
      * weitere Klassen (UART, Timer, SPI, DMA, ...)

… also so wie  Ben schieb^^. Allerdings würde ich beim STM32 auch schon 
mit Takt-System anfangen, da ich ohne diesen Teil den Rest gar nicht 
vernünftig testen und einsetzen könnte.

Auch sowas wie <std::bitset> für Embedded fände ich z.B. interessant, 
das nutze ich gerade für das WordClock-Projekt in Java 
(java.util.BitSet).

Wenn was nicht paßt oder falsch verstanden wurde: Bitte einfach richtig 
stellen, ich will niemandem was unterstellen und niemandem übergehen!

: Bearbeitet durch User
von Hans-Georg L. (h-g-l)


Angehängte Dateien:

Lesenswert?

> Torsten C. schrieb:

> Angefangen mit der oft Diskutierten Pin-Klasse. Man müsste beweisen dass
> diese Klasse keinen zusätzlichen Overhead verursacht.

> Moby schrieb
> im Beitrag #3910583:
> auto_control ... Assembler code ...

Angeregt durch diesen Thread habe ich mich auch mit dem Problem 
beschäftigt ...

Der beiliegende Code ist die Umsetzung von Mobys Assembler Program in 
C++.

Der vom AtmelStudio 6,2.1153 erzeugte Code ist nicht schlechter wie der 
handgeschriebene von Moby.
 Verbrauch 28 Byte Flash und 0 Byte Ram !

00000034 <main>:
  34:  bb 9a         sbi  0x17, 3  ; 23     port motor init
  36:  bc 9a         sbi  0x17, 4  ; 23        port beleuchtung init

  while:
  ;startknopf gedrückt ?
  38:  b0 9b         sbis  0x16, 0  ; 22
  ;nein jmp startknopf nicht gedrückt
  3a:  07 c0         rjmp  .+14       ; 0x4a <__SREG__+0xb>
  ; ja
  3c:  c4 9a         sbi  0x18, 4  ; 24        beleuchtung ein
  ; gang eingelegt ?
  3e:  b1 9b         sbis  0x16, 1  ; 22
  ; nein jmp while
  40:  fb cf         rjmp  .-10       ; 0x38 <main+0x4>
  ;ja
  ;bremse nicht angezogen ?
  42:  b2 99         sbic  0x16, 2  ; 22
  ;nein Jmp while
  44:  f9 cf         rjmp  .-14       ; 0x38 <main+0x4>
  ;ja
  ; bremse nicht angezogen und gang eingelegt
  46:  c3 9a         sbi  0x18, 3  ; 24        motor ein
  ; jmp while
  48:  f7 cf         rjmp  .-18       ; 0x38 <main+0x4>

  ; startknopf nicht gedrückt :
  4a:  c3 98         cbi  0x18, 3  ; 24    motor aus
  4c:  c4 98         cbi  0x18, 4  ; 24    beleuchtung aus
  ; jmp while
  4e:  f4 cf         rjmp  .-24       ; 0x38 <main+0x4>

Das Prinzip lässt sich auf alle MC für die ein C++ Compiler gibt und die 
über SFR Register verfügen anwenden.

Man braucht man auch nicht das DDR bit mit einer Extra Methode/ Funktion 
setzen, wie bei anderen Implemetierungen die mir bisher begegnet sind, 
das macht bei mir der Konstrukor der Ein/Ausgabe Klasse.

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Hans-Georg Lehnard schrieb:
> auf alle MC für die ein C++ Compiler gibt und die
> über SFR Register verfügen

"SfrRegAccess" sagt mir jetzt noch nichts und spontan habe ich dazu auch 
nix in Google gefunden. Ich hatte das mal so ausprobiert wie in 
Modeling_a_Control_Register.png ^^. Da benötigte ich kein 
"SfrRegAccess::…".

Vielleicht ist das im Hintergrund das Gleiche?

: Bearbeitet durch User
von Hans-Georg L. (h-g-l)


Lesenswert?

was mir bisher im Internet zu dem Thema über den Weg gelaufen ist
und wie dabei IO Pins angesprochen werden ...

1. Arduino

pinMode(13, OUTPUT);
digitalWrite(13, HIGH);
digitalWrite(13, LOW);

2.) Nils Springob

http://avr.2057.n7.nabble.com/template-library-for-c-td4056.html
http://develissimo.com/forum/topic/8553/

typedef IOPin<system::IOPortB, 0, true> LedRed;
LedRed::enable(); // set DDR bit
LedRed::set(); // set PORT bit

3.) mutable-instruments avril
http://mutable-instruments.net/codetools

4.) win-avr
http://avr-cpp-lib.sourceforge.net/
http://sourceforge.net/projects/avr-cpp-lib/?source=typ_redirect


5.) PTL
http://pfalcon-oe.blogspot.de/2013/05/peripheral-template-library-attempt-to.html

board::LED::port::enable();
board::LED::output();
board::LED::high();
board::LED::low();

6.) BOOST

Ich meine in den BOOST Libs (mpl ?) ist auch etwas drin, finde es aber 
nicht mehr.

7.) Scott Meyers
Artikel kostenlos "Effektives C++ in Embedded Systems auf Deutsch"
http://www.aristeia.com/
Buch "Effective C++ in a Embedded Environment"

8.) Chris Kormanyos

Buch "Real Time C++"
Quellcode zum Buch: https://github.com/ckormanyos/real-time-cpp

von Hans-Georg L. (h-g-l)


Lesenswert?

Torsten C. schrieb:
> Hans-Georg Lehnard schrieb:
>> auf alle MC für die ein C++ Compiler gibt und die
>> über SFR Register verfügen
>
> "SfrRegAccess" sagt mir jetzt noch nichts und spontan habe ich dazu auch
> nix in Google gefunden. Ich hatte das mal so ausprobiert wie in
> Modeling_a_Control_Register.png ^^. Da benötigte ich kein
> "SfrRegAccess::…".
>
> Vielleicht ist das im Hintergrund das Gleiche?

Hallo Thorsten

SfrRegisterAccess ist einfach eine Template Klasse die den generellen 
Zugriff auf SFR-Register kapselt.

Du übergibst die Register Adresse und das bit das manipuliert werden 
soll.
Und dabei ist es egal ob es ein "port" register oder z.B. ein timer ctrl 
Register ist.

Du kannst auch darüber nichts in Google finden weil der Code bisher 
meine Festplatte nicht verlassen hatte :)

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Hans-Georg Lehnard schrieb:
> Angeregt durch diesen Thread habe ich mich auch mit dem Problem
> beschäftigt ...

Deine Lösung mit den Templates (Metaprogrammierung) gefällt mir deutlich 
besser als die mit preprocessor:

https://github.com/roboterclubaachen/xpcc/blob/da4cbb9f6dddaa0df8eaf0a13b95293360fd20f0/src/xpcc/architecture/platform/avr/xmega/gpio.hpp

Wie seht Ihr das mit den Bezeichern für die Methoden:

* Get()
* IsSet()
* IsNotSet()

Das sind zwar Kleinigkeiten, aber falls es hier schnell einen Konsens 
gibt, kann man's ja gleich richtig machen, dann hat man später weniger 
Arbeit. Vorschlag:

* get()
* isSet()

Welchen Vorteil siehst Du in "IsNotSet()"? Ein "!isSet()" ist doch auch 
gut lesbar. Oder Ist das für Dich besser Lesbar? Das ist ja eine 
Geschmacksfrage. Trotzdem können wir uns vielleicht einig werden. Ich 
möchte nur den Grund verstehen, weil sich das Thema ja an allen anderen 
Stellen wiederholt.

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Hans-Georg Lehnard schrieb:
> SfrRegisterAccess ist einfach eine Template Klasse die den generellen
> Zugriff auf SFR-Register kapselt

Ah, cool. Magst Du das Template auch mal posten?

von eKiwi (Gast)


Lesenswert?

Hallo,

nachdem ich die Diskussion im November hier schon einmal gesehen hatte 
bin ich heute erneut auf diesen Thread gestossen.

Seit zwei Jahren bin ich Mitentwickler der hier schon ein paar Mal 
zitierten xpcc Programmbibliothek.
Falls ihr euch bei dieser für den aktuellen Entwicklungscode 
interessiert, sind folgende Links gültig:
* Doku: http://develop.xpcc.io/
* API: http://develop.xpcc.io/api/
* Code: https://github.com/roboterclubaachen/xpcc
* Mailingliste [Englisch]: 
http://mailman.rwth-aachen.de/mailman/listinfo/xpcc-dev

Falls ihr eine eigene C++ Mikrocontroller Bibliothek von Grund auf neu 
schreiben wollt, kann ich das gut nachvollziehen. Denn nur so kann man 
von Anfang an auf Performance optimieren und alle Designentscheidungen 
selbst treffen.


Torsten C. schrieb:
> Zusammen mit den Beispielen aus dem "xpcc project" hat man eigentlich
> schon fast alles, was man braucht.

Sollte aber Interesse bestehen statt (oder auch vor) einer 
Eigenentwicklung sich die xpcc Library anzusehen könnte ich euch dazu 
eure Fragen beantworten. Entweder hier im Forum (vielleicht am besten 
als eigener Thread?) oder auf Englisch auf der Mailingliste.

Wenn ihr das ganze ausprobieren wollt könnt ihr das unter Linux nativ 
tun:
http://develop.xpcc.io/install/linux.html

Für Windows Benutzer empfehlen wir unsere Virtuelle Maschine mit Vagrant 
zu benutzen:
https://github.com/roboterclubaachen/xpcc#use-our-virtual-machine

An Hardware empfehle ich euch entweder das STM32F4 oder das STM32F3 
Discovery Board oder einen Arduino UNO (für AVR) da es dafür die am 
besten getesteten Examples gibt.

Vielleicht kann ich euch ja etwas weiterhelfen.

eKiwi

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

eKiwi schrieb:
> Sollte aber Interesse bestehen … sich die xpcc Library anzusehen
> könnte ich euch dazu eure Fragen beantworten.

Cool! :-) Ich muss jetzt erstmal viel lesen und verstehen, um die 
richtigen Fragen zu stellen. Danke vielmals für das Angebot, darauf 
werde wohl nicht nur ich allein zurückkommen. :-)

Hans-Georg Lehnard schrieb:
> was mir bisher im Internet zu dem Thema über den Weg gelaufen ist
> und wie dabei IO Pins angesprochen werden ..

Boah! Viel Stoff zum Lesen und Vergleichen, danke. :-) Aber bevor man 
das Rad neu erfindet, muss man sich das alles erstmal anschauen!

von Hans-Georg L. (h-g-l)


Lesenswert?

Torsten C. schrieb:
> Hans-Georg Lehnard schrieb:
>> SfrRegisterAccess ist einfach eine Template Klasse die den generellen
>> Zugriff auf SFR-Register kapselt
>
> Ah, cool. Magst Du das Template auch mal posten?

Ist doch alles dabei ...

Das ist kein Template sondern einfach eine normal C++ Klasse.
Weil aber alle Methoden dieser Klasse static sind gibt es davon keine 
Instanz oder Objekt. SfrRegisterAccess ist einfach ein namespace.

deshalb ja auch SfrRegisterAccess::Get( ..
und nicht       SfrRegisterAccess.Get(

von Hans-Georg L. (h-g-l)


Lesenswert?

Torsten C. schrieb:
> Aber bevor man das Rad neu erfindet, muss man sich das alles erstmal
> anschauen!

Ich will keine allgemeine Library schreiben, für mich ist das eine reine 
private Machbarkeitsstudie und Auffrischung meiner C++ Kentnisse.

Mit dem Code wollte ich hauptsächlich zeigen, das C++ auch auf ATTiny 
Sinn machen kann.

von Karl Käfer (Gast)


Lesenswert?

Hallo Moby,

Moby AVR schrieb im Beitrag #3971437:
> C++ auf kleinen Controllern ist und bleibt eine Schnapsidee.

Das kannst Du gerne noch hundertmal behaupten, aber wird dadurch kein 
bisschen richtiger. C++ ist auch auf dem Mikrocontroller eine prima 
Sache, um den Code besser zu strukturieren und zu modularisieren, und 
damit sowohl die Wartbarkeit als auch die Wiederverwendbarkeit des Code 
zu erhöhen.

Daß Du diesen Mehrwert nicht erkennst, spricht nicht gegen den Mehrwert, 
sondern nur gegen Deine Fähigkeiten zur Erkenntnis -- zumal Du grob die 
Hälfte der Diskussion offenbar nicht gelesen oder nicht verstanden hast.

Liebe Grüße,
Karl

von Karl Käfer (Gast)


Lesenswert?

Hallo Ben,

Ben schrieb:
> Ich denke, Ziel sollte es sein, eine Sammlung von Klassen zur Verfügung
> zu stellen um von der Hardware eines ATmega abstrahieren zu können.
>
> Angefangen mit der oft Diskutierten Pin-Klasse. Man müsste beweisen dass
> diese Klasse keinen zusätzlichen Overhead verursacht. Davon ausgehend
> könnte man dann weitere Klassen nach ähnlichem Schema anlegen (UART,
> Timer, ...)

Schau bitte mal etwas weiter oben, da habe ich ganz genau solche 
Pin-Klassen gepostet, die, wie gewünscht, keinen Overhead gegenüber 
funktional gleichen C-Programmen erzeugen, alles hübsch getestet mit dem 
GCC und mit Angaben von Kompilatsgrößen. Vielleicht ist das ein Ansatz, 
auf den man aufbauen kann.

HTH,
Karl

von Karl Käfer (Gast)


Lesenswert?

Hi Torsten,

Torsten C. schrieb:
> Fazit bisher:
> ¯¯¯¯¯¯¯¯¯¯¯¯¯
>    3 Personen:
>    ¯¯¯¯¯¯¯¯¯¯¯
>       * Klaus Wachtler (mfgkw)
>       * Ben (Gast)
>       * Torsten C. (torsten_c)

Da würde ich mich auch gerne beteiligen.

LG,
Karl

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Hans-Georg Lehnard schrieb:
> Ist doch alles dabei ...

Oops, ja, sorry. Jedenfalls sind die Templates …
1
template< class regs, PIN pin > class DigitalInput {};
2
template< class regs, PIN pin > class DigitalInput  {};
besser als die vielen "#define"^^:

Falls man "ins Uferlose" will, hier eine ToDo-Liste ;-)
http://mikrocontroller.bplaced.net/wordpress/?page_id=744

Hans-Georg Lehnard schrieb:
> Ich will keine allgemeine Library schreiben

OK, vielleicht macht ja jemand anders mit. Das hatte ich falsch 
verstanden.

Gibt es irgendwo eine geeignete Struktur, die man übernehmen sollte? 
Ansonsten hier eine Diskussionsgrundlage:
1
⊖ EmbeddedCpp
2
 ┣⊖ Documentation
3
 ┃ ┣⊖ General
4
 ┃ ┃ ┣⊕ API naming rules
5
 ┃ ┃ ┣⊕ Timeout management
6
 ┃ ┃ ┣⊕ Error management
7
 ┃ ┃ ┗⊕ …
8
 ┃ ┣⊖ HAL ("µC und integrierte Peripherie")
9
 ┃ ┃ ┣⊖ Clock
10
 ┃ ┃ ┃ ┗⊕ …
11
 ┃ ┃ ┣⊖ Power management
12
 ┃ ┃ ┃ ┗⊕ …
13
 ┃ ┃ ┣⊖ GPIOs
14
 ┃ ┃ ┃ ┗⊕ …
15
 ┃ ┃ ┣⊖ DMA
16
 ┃ ┃ ┃ ┗⊕ …
17
 ┃ ┃ ┗⊕ …
18
 ┃ ┣⊖ APIs ("externe Peripherie")
19
 ┃ ┃ ┣⊖ Displays
20
 ┃ ┃ ┃ ┗⊕ …
21
 ┃ ┃ ┣⊖ Sensors
22
 ┃ ┃ ┃ ┗⊕ …
23
 ┃ ┃ ┣⊖ Communication
24
 ┃ ┃ ┃ ┣⊖ ESP8266
25
 ┃ ┃ ┃ ┃ ┗⊕ …
26
 ┃ ┃ ┃ ┗⊕ …
27
 ┃ ┃ ┗⊕ …
28
 ┃ ┗⊕ …
29
 ┣⊖ Sources
30
 ┃ ┣⊖ STM32
31
 ┃ ┃ ┗⊕ …
32
 ┃ ┗⊕ ATMega
33
 ┗⊕ …

von Karl Käfer (Gast)


Lesenswert?

Hallo Torsten,

Torsten C. schrieb:
> Deine Lösung mit den Templates (Metaprogrammierung) gefällt mir deutlich
> besser als die mit preprocessor:

Ich verstehe immer noch nicht, warum so viele Leute geradezu krampfhaft 
was mit Templates machen wollen. Was soll das nutzen?

Liebe Grüße,
Karl

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Karl Käfer schrieb:
> Da würde ich mich auch gerne beteiligen.
Karl Käfer schrieb:
> Was soll das nutzen?

Hmmm. Wenn Du Dich beteiligen willst, solltest Du über die Frage "Was 
soll das nutzen?" doch schon hinweg sein, oder? Es wurde alles schon 
gesagt: Z.B. Wartbarkeit, Übersichtlichkeit und Wiederverwendbarkeit von 
Code.

Torsten C. schrieb:
> [ScoMe01] Slide 169 sagt:
>> “A fundamental design goal is that design violations
>>  should not compile.”

Das funktioniert mit #define statt enum {…} halt nicht so gut.

: Bearbeitet durch User
von Karl Käfer (Gast)


Lesenswert?

Hallo Torsten,

Torsten C. schrieb:
> Karl Käfer schrieb:
>> Was soll das nutzen?
>
> Hmmm. Wenn Du Dich beteiligen willst, solltest Du über die Frage "Was
> soll das nutzen?" doch schon hinweg sein, oder? Es wurde alles schon
> gesagt: Z.B. Wartbarkeit, Übersichtlichkeit und Wiederverwendbarkeit von
> Code.
>
> Torsten C. schrieb:
>> [ScoMe01] Slide 169 sagt:
>>> “A fundamental design goal is that design violations
>>>  should not compile.”
>
> Das funktioniert mit #define statt enum {…} halt nicht so gut.

Meine Frage bezieht sich explizit auf Templates -- und zwar nicht im 
Vergleich mit #defines und enums, sondern im Vergleich mit klasssischen 
C++-Klassen. Wozu? Was soll das? "Weil man es kann" ja ist kein 
Argument, und "weil man damit zeigen kann, was für ein toller 
C++-Experte man ist" ... och, nö. ;-)

Templates machen die Sache (im Mikrocontroller-Umfelt mit seinen 
meistens stark limitierten Ressourcen) nur komplizierter und 
unübersichtlicher, weil man sich jedes Mal überlegen muß, was der 
Compiler daraus macht -- und wenn man dabei nicht sehr, sehr sorgfältig 
vorgeht (oder einen blöden Compiler hat), kann das den Code ohne jede 
Not deutlich vergrößern. Um diese Kosten wieder einzuspielen, müßte die 
Template-Programmierung auf Mikrocontrollern einen Nutzen haben, der die 
Kosten deutlich übersteigt. Welcher Nutzen sollte das sein? Ich habe 
diese Frage schon mehrmals gestellt, auch hier, aber bisher konnte oder 
wollte sie mir niemand sinnvoll beantworten.

Da auch Du jetzt als Erstes nach Templates rufst, frage ich Dich: was 
ist der praktische Nutzen von Template-Metaprogrammierung für 
Mikrocontroller? Was versprichst Du Dir davon?

Liebe Grüße,
Karl

von Conny G. (conny_g)


Lesenswert?

Karl Käfer schrieb:
> Hi Torsten,
>
> Torsten C. schrieb:
>> Fazit bisher:
>> ¯¯¯¯¯¯¯¯¯¯¯¯¯
>>    3 Personen:
>>    ¯¯¯¯¯¯¯¯¯¯¯
>>       * Klaus Wachtler (mfgkw)
>>       * Ben (Gast)
>>       * Torsten C. (torsten_c)
>
> Da würde ich mich auch gerne beteiligen.
>
> LG,
> Karl

Wäre interessiert trollfrei mitzulesen, leider nicht viel Zeit 
beizutragen. Die Diskussion um den Sinn nervt mich auch, ich finde das 
Thema sehr spannend.

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Karl Käfer schrieb:
> was ist der praktische Nutzen von Template-Metaprogrammierung für
> Mikrocontroller?

Wie ist Deine Frage gemeint:
a) Wozu ein Codegenerator?
b) Wo ist der Vorteil von C++-Templates gegenüber Alternativen?

Das ist wie ein Serienbrief: Du kannst einen Brief 100x schreiben und 
von Hand die Adresse und Anrede tauschen oder z.B. mit Excel und Word 
einen Serienbrief erstellen.

Statt Template-Metaprogrammierung geht auch ein anderer Codegenerator 
z.B. mit XSLT, aber dann hat man mehr Tools in der Toolkette und mehr 
Schnittstellen.

Da es in C++ keine "partial class" wie in C# gibt, ist die 
Template-Metaprogrammierung vergleichsweise einfacher als die 
Alternativen.

: Bearbeitet durch User
von Scelumbro (Gast)


Lesenswert?

Meiner Meinung nach ein gutes und konkretes Beispiel für den Nutzen von 
Templates auf dem uC.

Festkommazahlen mit C++
Beitrag "Festkommazahlen mit C++"

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Conny G. schrieb:
> Wäre interessiert trollfrei mitzulesen, leider nicht viel Zeit …

Das geht mir auch so, im Postkasten:

> [µC.net] Neuer Beitrag in "C++ auf einem MC, wie geht das?"

Und wieder nur ein Troll-Post.

Irgendwann kommt ein neuer Beitrag in "Projekte & Code", da grenzen wir 
im Ausgangspost genau das Thema ab (auch was nicht zum Thema gehört) und 
melden alle gemeinsam die Off-Topic-Posts mit "Beitrag melden" an den 
Moderator. Irgendwann ebbt das Problem dann ab.

@Jörg Wunsch: Wäre das OK?

Die Formulierung des neuen Ausgangsposts in "Projekte & Code" würde ich 
hier zur Diskussion stellen, bevor ihn jemand anlegt.

Am besten verweisen wir dort noch auf einen anderen Thread um die 
"sonstigen Fragen" zu kanalisieren und damit der Plan noch besser 
funktioniert. Können wir als Verweis diesen Thread hier nehmen?

: Bearbeitet durch User
von Hans-Georg L. (h-g-l)


Lesenswert?

Karl Käfer schrieb:

> Ich verstehe immer noch nicht, warum so viele Leute geradezu krampfhaft
> was mit Templates machen wollen. Was soll das nutzen?
>

Hallo Karl,

wenn du Programme für einen dicken ARM mit viel (externen) MB Ram 
Speicher schreibst und auch noch Linux darauf läuft brauchst du dir über 
die Feinheiten der Template Programmierung keine Gedanken machen. Du 
benutzt normale OOP Klassen und dazu vielleicht noch STD oder BOOST 
Libs.
Das ist aber nur die eine Seite der embedded Programmierung. Auf der 
anderen Seite hast du z.B einen ATtiny mit 128 Byte RAM und da spielt es 
schon eine Rolle diesen Speicher effizient zu nutzen und dafür sind die 
Meta-Templates eben geeigneter. Das hat nichts mit Angeberei oder 
krampfhaft zu tun.

;)

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Hans-Georg Lehnard schrieb:
> und da spielt es
> schon eine Rolle diesen Speicher effizient zu nutzen und dafür sind die
> Meta-Templates eben geeigneter.

Gute Ergänzung, Danke. :-) Bei Vererbung (Interfaces, Polymorphie) 
werden  "Virtuelle Methoden-Tabellen" (VMTs) angelegt und dann greift 
das Argument: C++ ist langsamer und Ressourcen-fressend. VMTs lassen 
sich mit automatischer Code-Generierung umgehen, wenn die genaue Klasse 
bereits zur Entwurfszeit feststeht und nicht erst zur Laufzeit ermittelt 
werden muss.

: Bearbeitet durch User
von Daniel A. (daniel-a)


Lesenswert?

Torsten C. schrieb:
> Bei Vererbung (Interfaces, Polymorphie) werden  "Virtuelle
> Methoden-Tabellen" (VMTs) angelegt

Falsch, bei Vererbung werden keine VMTs angelegt, und Interfaces 
existieren in c++ nicht.

VMTs gibt es, wenn man man eine Classe instanziert, die virtuelle 
Methoden besitzt. Die anwendung von Polymorphie ist dafür nicht 
erforderlich.

von Stefan (Gast)


Lesenswert?

> Falsch, bei Vererbung werden keine VMTs angelegt, und Interfaces
> existieren in c++ nicht.

Auch falsch, ein Interface ist ein Konzept der OOP und ein Spezialfall 
der Mehrfachvererbung. C++ kennt das, auch wenn es das Schlüsselwort 
"interface" nicht gibt.

> VMTs gibt es, wenn man man eine Classe instanziert, die virtuelle
> Methoden besitzt. Die anwendung von Polymorphie ist dafür nicht
> erforderlich.

Wieder falsch. VMTs gibt es nur wenn eine Klasse instanziert wird die 
von einer anderen Klasse mit virtuellen Methoden geerbt hat.
Und auch nur dann wenn (virtuelle) Methoden über einen Pointer auf die 
Basisklasse aufgerufen werden: Polymorphie.
Wenn dein Compiler es in anderen Fällen tut, schalte die Optimierung ein 
oder schreib einen Bugreport.

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Danke für die Klarstellungen. So "Übergenau" sind meine Worte oft nicht.

Stefan schrieb:
> Und auch nur dann wenn (virtuelle) Methoden über einen Pointer auf die
> Basisklasse aufgerufen werden …

Bevor das zur akademischen Wortklauberei wird, viel wichtiger: Was muss 
man tun, damit virtuelle Methoden in der Embedded-SW garantiert nicht 
über einen Pointer auf die Basisklasse aufgerufen werden?

Ich dachte, das ist immer dann der Fall, wenn die Klasse bereits zur 
Entwurfszeit genau feststeht und nicht erst zur Laufzeit ermittelt
werden muss. Oder?

: Bearbeitet durch User
von DD4DA (Gast)


Lesenswert?

Um auch meinen Senf dazu geben zu wollen - etwas zu C++ auf dem MC.
Ich stimme in einigen Punkten der Meinung eines Vorschreibers bei, dass 
C++ auf einem MC keinen wirklichen Vorteil gegenüber C bringt.
Ich hatte sowas auch mal probiert und musste entnervt aufgeben denn 
mangels verfügbarer Libraries muss man einfach zu viel Arbeit 
investieren um keine besseren Ergebnisse zu erhalten. Meine Motivation 
mal C++ auf einem MC zu probieren war zur prüfen, ob der Vorteil der 
Übersichtlichkeit der per Klassendefinitionen gekapselten Instanzen und 
Variablen zu lasten anderer Nachteile geht. Mir gefällt die 
übersichtliche Art der Darstellung. Leider ist kaum eine Handfeste 
Unterstützung vorhanden. Der Grund dafür ist der Mange an Vorteilen und 
dass wurde ja auch mehrfach erwähnt. Man kann es auch mit einer anderen 
Art der Deklaration schaffen, Ordnung in den Quellen zu halten.
C++ ist auf kleinen System nicht wirklich hilfreich und macht eigentlich 
nur Mehrarbeit.

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

DD4DA schrieb:
> Leider ist kaum eine Handfeste Unterstützung vorhanden.

Das geht mir genau so. Aus diesem Grund hatte ich die Hoffnung, dass wir 
hier gemeinsam einen guten Leitfaden oder wenigstens eine gute Basis für 
eine Bibliothek erschaffen können.

PS zu "So 'Übergenau' sind meine Worte oft nicht."^^: Viele 
UML-Programme für C++ nutzen m.E. "Lollipop-Notation", wenn eine Klasse 
nur aus virtuellen Methoden besteht. Und dann gib's immer VMTs. Ist das 
so nun richtig?

Karl Käfer schrieb:
> was ist der praktische Nutzen von Template-Metaprogrammierung
> für Mikrocontroller?

Waren die Antworten verständlich und überzeugend? In einem Wiki-Artikel 
müsste das nämlich wohl auch erwähnt werden.

: Bearbeitet durch User
von Karl Käfer (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Hans-Georg,

Hans-Georg Lehnard schrieb:
> wenn du Programme für einen dicken ARM mit viel (externen) MB Ram
> Speicher schreibst und auch noch Linux darauf läuft brauchst du dir über
> die Feinheiten der Template Programmierung keine Gedanken machen. Du
> benutzt normale OOP Klassen und dazu vielleicht noch STD oder BOOST
> Libs.

Wenn ich Programme für Linux schreibe, benutze ich diverse 
Skriptsprachen; meistens Python. C++ verwende ich nur dann, wenn die zu 
viele Ressourcen verbrauchen. Dabei kann ich da dann auch die STL und 
die Boost-Libraries verwenden, denn dort mache ich mir vergleichsweise 
wenig Gedanken über den Speicherverbrauch. Nur, wenn mein Programm dann 
immer noch nicht mit den verfügbaren Ressourcen auskommt, fange ich an 
zu optimieren. Knuth wußte schon '74: "premature optimization is the 
root of all evil". ;-)

> Das ist aber nur die eine Seite der embedded Programmierung. Auf der
> anderen Seite hast du z.B einen ATtiny mit 128 Byte RAM und da spielt es
> schon eine Rolle diesen Speicher effizient zu nutzen und dafür sind die
> Meta-Templates eben geeigneter.

Ich habe mir Deinen Code oben angeschaut, übersetzt, und sehe immer noch 
keinerlei Vorteil darin, dabei Templates zu einzusetzen. Mein Code in 
Beitrag "Re: C++ auf einem MC, wie geht das?" (ganz unten) erzeugt 
beinah genau dasselbe .lss; das Kompilat ist nur sechs Byte größer, weil 
meine Klasse auch die Input-Pins initialisiert. (Daß Du das nicht 
machst, würde übrigens zu einem Fehler führen, wenn Du denselben Pin 
später als Input nutzen willst.)

Insofern spart die Template-Programmierung keinen Speicher zur Laufzeit, 
weder RAM noch Programmgröße. In einigen Situationen spart sie 
Quellcode, etwa bei der verlinkten Fließkommaberechnung. Bei den 
Pin-Klassen sparen Templates aber nichtmal Quellcode -- Dein und mein 
Quelltext haben genau gleich viele Zeilen Code (ohne "InoutPin").

Versteht mich bitte nicht falsch: ich habe nichts gegen Templates und 
nutze sie dort, wo sie echte Vorteile haben, sehr gerne. Aber für das 
Beispiel von Moby bieten Templates keinerlei Vorteil -- sein Assembler 
lustigerweise übrigens auch nicht. Dafür ist mein Quellcode einfacher, 
was sowohl der Wiederverwendbarkeit als auch der Wartbarkeit zugute, und 
auch Anfängern sicherlich entgegenkommt.

Bisher sehe ich also immer noch keinen Vorteil, dafür aber eine Reihe 
weicher, aber doch signifikanter Nachteile. Wenn jemand ein besseres 
Beispiel hat, lasse ich mich aber jederzeit gerne überzeugen.

Liebe Grüße,
Karl

PS: Der Einfachheit halber habe ich Deinen und meinen Code nochmal in 
ein Zip-Archiv gepackt und angehängt.

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Karl Käfer schrieb:
> Meine Frage bezieht sich explizit auf Templates -- und zwar nicht im
> Vergleich mit #defines und enums, sondern im Vergleich mit klasssischen
> C++-Klassen.

Ich glaube, genau hier reden wir aneinander vorbei.

Wie sind denn "DDRB" und "PORTB" bei Dir definiert?

Ich bereits schrieb:
>      RCC_APB1PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
> Was stimmt da nicht? Richtig, es muss heißen:
>      RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

Um sowas ^^ geht es im Satz von Scott Meyers: ^^
> “A fundamental design goal is that design violations
>  should not compile.”

Können bei Deinen "DDRB" und "PORTB" solche Verwechslungen vom Compiler 
erkannt werden? Bei Templates und Enums werden sie erkannt!

von lerner (Gast)


Lesenswert?

Lass doch. Als asm guru hat Moby sich in den letzten Posts auch nicht 
gerade empfohlen, von daher sollte man den Worten auch nicht übermäßig 
Gewicht geben.
Die c++ Diskussion ist jedenfalls fachlich nicht so ganz banal würde ich 
sagen (Ich kann jedenfalls nicht lückenlos folgen) und wenn dann weder 
bei asm noch oop intimeres Wissen da ist, sind doch Kommentare einfach 
zu ignorieren.
Es ist, auch in diesem thread, immer eine schwierige Aufgabe für sich 
festzustellen wessen Wort Gewicht haben soll und wessen Wort nur wichtig 
klingt.

Jeder fortgeschrittene Amateur oder Profi weiß was Moby meinen mag. Und 
jedem macht auch mal eine asm Knösterei Spaß - ganz bestimmt.
Jeder fortgeschrittene Amatuer wird aber auch ab gewissen Projekten 
interessiert sein, effizientere Werkzeuge zu haben. Moby kann aber 
mangels derzeitigen Wissen oder einfach aus Verweigerung, Erfahrung und 
Weitsicht halt nicht immer nachvollziehen, worüber die anderen reden.
Warum er das nicht einsieht oder den anderen glaubt weiß ich auch nciht. 
Hier reden keine PC Programmierer, die bei Adobe Arbeiten und Ressourcen 
aus dem Fenster schmeissen, noch Script Kiddies.

Warum streiten

von lerner (Gast)


Lesenswert?

edit: Wenn es dir hilft, Moby, sieh doch die oop Überlegungen als 
intellektuelle Herausforderung an. Wühl dich rein und lass dich von den 
anderen durch Fragen mit an Bord holen. So will ich es machen als jemand 
der nur asm/c Erfahrung hat.

von Hans-Georg L. (h-g-l)


Lesenswert?

Und hier ist ein Beispiel ..


Nachdem ich die Atmel defines rausgeschmissen habe kann ich alle Namen 
neu und sauber vergeben.

weiteres Templates z.B. in bordX.h

typedef Pin <PORTA, bit0> PA0;
...
typedef Pin <PORTA, bit7> PA7;

Damit kann ich im Anwendungscode schreiben:

DigitalInput<PA0> taster1;

Wenn es einen PIN bei diesen MCU Typ nicht gibt oder er auf der Platine 
nicht verdrahtet ist kann ich ihn einfach auskommentieren und der 
Compiler bringt einen Fehler wenn mein Anwendungscode ihn benutzt.

weitere Möglichkeit wäre ..

anstelle der Pin namen aus dem Datenblatt
typedef Pin <PORTA, bitX> PAX;
könnte ich dann auch
typedef Pin <PORTA, bit6> LCD_WR;  in avr_board1.h
typedef Pin <PORTC, bit2> LCD_WR;  in avr_board2.h
oder auch
typedef Pin <PORTA, bit31> LCD_WR;  in arm_board1.h
definieren

Bevor Diskussionen jetzt hier aufkommen PORTA und bit31 sind Datentypen 
und natürlich beim ARM anders wie bei einem AVR definiert aber der 
Compiler ist nicht doof und instanziiert das richtige Template anhand 
vom Datentyp.

Im Anwendungscode muss dann nur das richtige Board includet werden der 
eigendliche Code bleibt gleich.

#include avr_bord1.h oder avr_bord2.h oder arm_board1.h

DigitalOutput<LCD_WR>  lcd_wr;

usw ...

von Hans-Georg L. (h-g-l)


Lesenswert?

Moby schrieb im Beitrag #3975867:
> Karl Käfer schrieb:
>> C++ ist auch auf dem Mikrocontroller eine prima
>> Sache, um den Code besser zu strukturieren und zu modularisieren,
>
> Na eher eine prima Sache, um Code und Schreibbedarf aufzublähen, mit
> allerlei Gedankenakrobatik im Ganzen zu verkomplizieren und...
>

Mein lieber Moby,

ich bin zwar ein frischgebackener Rentner aber scheinbar im Kopf doch 
noch etwas flexibler wie du ;)

Mein C++ Code von deinem Beispiel ist weder im Code noch im 
Schreibbedarf grösser aber viel verständlicher.

Ich habe in meinem beruflichen Leben so viel Code-Reviews mitgemacht und 
da wärst du mit deinem Assembler gewurschtel wieder nach Hause geschickt 
worden. Aber wenn du damit zufrieden bist und nichts mehr dazu lernen 
willst ....

Bitteschön ...

von Stefan W. (dl6dx)


Lesenswert?

Matthias schrieb:
> Industrial Strength C++ (Nyquist)

Gibt es übrigens mittlerweile als Download beim Autor:
http://sannabremo.se/nyquist/industrial/

Grüße

Stefan

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Hans-Georg Lehnard schrieb:
> Im Anwendungscode muss dann nur das richtige Board includet werden der
> eigendliche Code bleibt gleich.

Genau so hätte ich es auch gern. :-) Danke!

Das ist ein weiteres "fundamental design goal"!

PS:

Das wäre doch schon mal eine Basis für ein Projekt "µC.net C++".

Wollen wir eins gemeinsames Projekt starten?

Zwei "design goals" hätten wir schon, wir brauchen noch einen Namen. Da 
muss ich nochmal die Mods nerven => nächster Beitrag.

: Bearbeitet durch User
von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Jörg Wunsch schrieb:
> Für Projekte wiederum gibt es hier die Möglichkeit, einen SVN-Server
> zu hosten sowie das in "Projekte & Code" zu posten.

Wir haben m.E. inzwischen zwei "Design-Ziele" ^^ und könnten damit 
langsam starten.

Vorausgesetzt, wir haben auch noch ein gemeinsames Projektziel …

    Eine C ++ Bibliothek mit folgenden Design-Zielen : …

… brauchen wir noch einen Projekt-Namen.

@Moderator: Darf der Name einen Bezug zum "mikrocontroller.net" haben, 
oder bedarf es da eines "Genehmigungsprozesses" oder gibt es 
Namensrechtliche Probleme?

Der Name sollte auch als Namespace ein gültiger Bezeichner sein, hier 
zwei Links dazu:
http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier#228797
http://www.cplusplus.com/doc/tutorial/variables/#identifiers

Um mal einen Stein ins Wasser zu werfen, über den weitestgehenden Antrag 
muss immer zuerst abgestimmt werden: ;-)

* "uCnet" als Namespace
* "µC.net C++ Bibliothek" als Projektbezeichnung

Es kann gern auch eine "Nummer kleiner" sein! Die Antwort ist nicht 
dringend, ich wollte nur, dass die Frage nicht übersehen wird.

… oder ist englisch (µC.net C++ library") besser? Aber im 
"embdev.net/forum/" gibt's ja gar kein Forum "projects & code".

Ich fände Deutsch besser. Klassen, Variablen, Funktionen sollten 
trotzdem in Englisch sein. Über die Sprache der Kommentare könnte man 
sich noch streiten.

Wer will µC.net SVN und wer will github?

: Bearbeitet durch User
von Micha (Gast)


Lesenswert?

@ Karl Käfer
Um deinen Vergleich noch anzusprechen: ich persönlich finde
1
DigitalOutput<PORT_B,P4> beleuchtung;
2
DigitalInput<PORT_B,P0> startknopf;
etwas schöner zu verwenden als
1
EinAus beleuchtung = EinAus(&DDRB, &PORTB, &PINB, PB2);
2
Eingabe startknopf = Eingabe(&DDRD, &PORTD, &PIND, PD1);
wobei dein
1
PINDEF(X,Y)
das relativieren würde, sofern es funktioniert. Der output scheint ja 
derselbe zu sein, weswegen von dieser Seite ja nichts gegen Templates 
spricht.

von Karl Käfer (Gast)


Lesenswert?

Hi Torsten,

Torsten C. schrieb:
> * "uCnet" als Namespace
> * "µC.net C++ Bibliothek" als Projektbezeichnung

Ich würde das "net" herauslassen, wegen der Verwechslungsgefahr mit 
.N(j)ET und der bekannten Klagefreudigkeit des Herstellers.

LG,
Karl

von Karl Käfer (Gast)


Lesenswert?

Hi Micha,

Micha schrieb:
> wobei dein
>
1
> PINDEF(X,Y)
2
>
> das relativieren würde, sofern es funktioniert.

Das funktioniert prima, probier's aus.

> Der output scheint ja derselbe zu sein, weswegen von dieser Seite ja
> nichts gegen Templates spricht.

Aber eben auch nichts dafür. Und Templates sind, wie erwähnt, eine recht 
komplexe Angelegenheit, die Anfänger regelmäßig überfordert. Warum denn 
Komplexität einbauen, ohne Not und ohne Vorteil?

Wozu Kosten und Einstiegshürden steigern, wenn kein Nutzen erkennbar 
ist? Das kann man machen, wenn man der einzige Nutzer ist und das aus 
eigenem Interesse macht. Aber bei einem Softwareprojekt, das sich auch 
an andere richtet, muß der Wurm dem Fisch schmecken und nicht dem 
Angler.

Liebe Grüße,
Karl

von Karl Käfer (Gast)


Lesenswert?

Hi Torsten,

Torsten C. schrieb:
> Karl Käfer schrieb:
>> Meine Frage bezieht sich explizit auf Templates -- und zwar nicht im
>> Vergleich mit #defines und enums, sondern im Vergleich mit klasssischen
>> C++-Klassen.
>
> Ich glaube, genau hier reden wir aneinander vorbei.

Möglich.

> Wie sind denn "DDRB" und "PORTB" bei Dir definiert?

Wie in avr/io.h.

> Ich bereits schrieb:
>>      RCC_APB1PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
>> Was stimmt da nicht? Richtig, es muss heißen:
>>      RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
>
> Um sowas ^^ geht es im Satz von Scott Meyers: ^^
>> “A fundamental design goal is that design violations
>>  should not compile.”
>
> Können bei Deinen "DDRB" und "PORTB" solche Verwechslungen vom Compiler
> erkannt werden?

Nö, aber ich halte das für einen logischen Fehler.

> Bei Templates und Enums werden sie erkannt!

Klingt spannend, wie stellst Du Dir das denn vor?

Liebe Grüße,
Karl

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Karl Käfer schrieb:
> Klingt spannend, wie stellst Du Dir das denn vor?

Nicht ich. Du hast gestern selbst die demo.h in
der "Code.zip" ^^ geposted.

Hast Du Dir die überhaupt angeschaut?
1
template< class regs, PIN pin >

PIN ist ein Enum.

Karl Käfer schrieb im Beitrag #3976273:
> können wir diesen "Herrn" nicht einfach alle ignorieren?

Off-Topic (also alles was nix bringt) zu ignorieren ist eine gute Idee.

Sich beim Ignorieren an einer Person statt am Thema zu orientieren ist 
keine gute Idee.

: Bearbeitet durch User
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Torsten C. schrieb:
> Können bei Deinen "DDRB" und "PORTB" solche Verwechslungen vom Compiler
> erkannt werden? Bei Templates und Enums werden sie erkannt!

Geht auch in C bei AVRs, siehe

   Beitrag "Re: AVR-Register als Bitfields"

Stichwort: "Registersichere Bitfields"

Das Projekt hatte ich mal angefangen, dann aber aus Zeitgründen liegen 
gelassen. Vielleicht sollte ich das mal wieder aufnehmen.,..

von Stefan V. (vollmars)


Lesenswert?

Ist es nicht möglich alle hier gestellten Forderungen unter einen Hut zu 
bringen?

Also ich versuche das hier mal zusammenzufassen:

* “A fundamental design goal is that design violations should not 
compile.”
* Genauso effektiv wie ein Zugriff in C (Speicherbedarf, Laufzeit)
* Möglichst leicht zu durchschauende, alt bekannte Sprachkonstrukte, 
evtl. verzicht auf Templates

Mir wäre ein Zugriff der Art:
1
EinAus beleuchtung = EinAus(PORT_B, P4);
am liebsten.

Ich bin jetzt nicht so der C++ Experte, das sollte sich doch aber zu 
realisieren lassen.

Gruß
Stefan

: Bearbeitet durch User
von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Frank M. schrieb:
> Geht auch in C bei AVRs,

Nur bei AVRs oder allgemeinin C?

Ein C-Compiler kann doch gar keine Typsicherheit festestellen. Dem ist 
doch egal, zu welchem Enum-Typ ein Enumerator gehört. Ich hab mir das 
Thema "Registersicher" fünfmal durchgelesen und nicht verstanden, was Du 
meinst.

Falls Du meinst, dass man das Problem mit "RCC_APB1PeriphClockCmd" ^^ 
auch in C (nicht C++) lösen kann, bin ich gespannt!

: Bearbeitet durch User
von Hans-Georg L. (h-g-l)


Lesenswert?

Torsten C. schrieb:

> Ein C-Compiler kann doch gar keine Typsicherheit festestellen. Dem ist
> doch egal, zu welchem Enum-Typ ein Enumerator gehört.

Ein C compiler kann das nicht aber ein C++11 Compiler kann das.

Der g++ im Atmel Studio 6.2 kann C++11 Sytax , wenn du das compilerflag
-std=c++11 setzt.

Beispiel:

enum class bit8_mask_t : uint8_t
{
  bit0 = 0x01U,
  bit1 = 0x02U,
  bit2 = 0x04U,
  bit3 = 0x08U,
  bit4 = 0x10U,
  bit5 = 0x20U,
  bit6 = 0x40U,
  bit7 = 0x80U
};

enum class bit16_mask_t: uint16_t
{
  bit0  = 0x0001U,
  bit1  = 0x0002U,
  bit2  = 0x0004U,
  bit3  = 0x0008U,
  bit4  = 0x0010U,
  bit5  = 0x0020U,
  bit6  = 0x0040U,
  bit7  = 0x0080U,
  bit8  = 0x0100U,
  bit9  = 0x0200U,
  bit10 = 0x0400U,
  bit11 = 0x0800U,
  bit12 = 0x1000U,
  bit13 = 0x2000U,
  bit14 = 0x4000U,
  bit15 = 0x8000U
};

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Torsten C. schrieb:
> Ein C-Compiler kann doch gar keine Typsicherheit festestellen. Dem ist
> doch egal, zu welchem Enum-Typ ein Enumerator gehört. Ich hab mir das
> Thema "Registersicher" fünfmal durchgelesen und nicht verstanden, was Du
> meinst.

z.B.
1
TCCR0A |= (1 << WGM02);

(Hint: WGM02 liegt in TCCR0B)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Torsten C. schrieb:
> Nur bei AVRs oder allgemeinin C?

Kannst Du natürlich auch auf andere µCs ausweichen.

> Ein C-Compiler kann doch gar keine Typsicherheit festestellen. Dem ist
> doch egal, zu welchem Enum-Typ ein Enumerator gehört. Ich hab mir das
> Thema "Registersicher" fünfmal durchgelesen und nicht verstanden, was Du
> meinst.

Der Compiler stellt sicher, dass Du WGM01 ausschließlich in TCCR0A 
setzen kannst und nicht in einem anderen Register. Da diese Bits gerne 
mal von AVR zu AVR in andere Register wechseln, weil Atmel das Spaß 
macht, gibt/gab es schon immer dieses Problem - gerade bei der 
Portierung von einem µC auf einen anderen.

In der klassischen Schreibweise

  TCCR0A |= (1<<WGM01);

frisst der Compiler auch dieses:

  TCCR0B |= (1<<WGM01);

Das ist aber ein Fehler, denn (meistens) sitzt das Bit WGM01 in TCCR0A 
und nicht in TCCR0B.

Mit "registersicheren Bitfields" kannst Du einfach schreiben:

  BFM_WGM01 = 1;

und Du musst überhaupt gar nicht wissen, in welchem Register das Bit 
überhaupt steckt. Das macht dann der Compiler.

> Falls Du meinst, dass man das Problem mit "RCC_APB1PeriphClockCmd" ^^
> auch in C (nicht C++) lösen kann, bin ich gespannt!

Hm, das ist eine Funktion... Da müsste es aber einen analogen Weg geben.

: Bearbeitet durch Moderator
von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Hans-Georg Lehnard schrieb:
> Ein C compiler kann das nicht aber ein C++11 Compiler kann das.

Ach so, na denn ist´s klar. Du hattest aber geschrieben "Geht auch in C 
bei AVRs". Und wollte nicht in meinem Kopf! Geht also auch in C++ bei 
AVRs!

Dann meinen wir das Gleiche und Du hast nochmal
schöne Beispiele gepostet. ;-)

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Torsten C. schrieb:
> Ach so, na denn ist´s klar. Du hattest aber geschrieben "Geht auch in C
> bei AVRs". Und wollte nicht in meinem Kopf! Geht also auch in C++ bei
> AVRs!


Du velwechserst grad zwei Postings von unterschiedlichen Leuten!

: Bearbeitet durch User
von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Torsten C. schrieb:
> Wie sind denn "DDRB" und "PORTB" bei Dir definiert? …
> Um sowas ^^ geht es im Satz von Scott Meyers: ^^
>> “A fundamental design goal is that design violations
>>  should not compile.”
> Können bei Deinen "DDRB" und "PORTB" solche Verwechslungen vom Compiler
> erkannt werden? Bei Templates und Enums werden sie erkannt!

Darauf Karl Käfer schrieb:
>> Wie sind denn "DDRB" und "PORTB" bei Dir definiert?
> Wie in avr/io.h.

Also mit #define und nicht mit enum!

Frank M. schrieb:
> Torsten C. schrieb:
>> … Bei Templates und Enums werden sie erkannt!
> Geht auch in C bei AVRs,

Also: Typsichere enums, damit Verwechslungen vom Compiler erkannt 
werden, gehen auch "in C bei AVRs"^^?! Nein, aber mit C++. Das ist ja 
nun geklärt.

Michael Reinelt schrieb:
> Du verwechserst grad zwei Postings von unterschiedlichen Leuten!

Sorry, falls ich was verwechselt haben sollte. Was meinst Du?

: Bearbeitet durch User
von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Ich frage Karl den Käfer nochmal …
… wie ich schrieb:
> Waren die Antworten verständlich und überzeugend? In einem Wiki-Art…

Danke fürs Aufräumen. Das hat mir viel verplemperte Zeit gespart! :-)
> Beitrag #3975867 wurde von einem Moderator gelöscht.
> Beitrag #3975873 wurde von einem Moderator gelöscht.
> Beitrag #3976273 wurde von einem Moderator gelöscht.
> Beitrag #3976354 wurde von einem Moderator gelöscht.
> Beitrag #3976354 wurde von einem Moderator gelöscht.
> Beitrag #3976413 wurde von einem Moderator gelöscht.
> Beitrag #3976471 wurde von einem Moderator gelöscht.
> Beitrag #3976507 wurde von einem Moderator gelöscht.
> Beitrag #3976530 wurde von einem Moderator gelöscht.
> Beitrag #3976878 wurde von einem Moderator gelöscht.
> Beitrag #3976908 wurde von einem Moderator gelöscht.

Um das nach den ganzen OT-Beiträgen nochmal in Erinnerung rufen:

Torsten C. schrieb:
> Wer will µC.net-SVN und wer will GitHub?

Karl Käfer schrieb:
> Torsten C. schrieb:
>> * "uCnet" als Namespace
>> * "µC.net C++ Bibliothek" als Projektbezeichnung
> Ich würde das "net" herauslassen …

Also wie genau? Nur "uC"? Neee …

: Bearbeitet durch User
von Jürgen (Gast)


Lesenswert?

Hier wird ja zensiert was das Zeug hält. Muß echt schlimm sein

EDIT durch Mod: Ist es, ist es ;-)

: Bearbeitet durch Moderator
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Torsten C. schrieb:

> Frank M. schrieb:
>> Torsten C. schrieb:
>>> … Bei Templates und Enums werden sie erkannt!
>> Geht auch in C bei AVRs,
>
> Also: Typsichere enums, damit Verwechslungen vom Compiler erkannt
> werden, gehen auch "in C bei AVRs"^^?! Nein, aber mit C++. Das ist ja
> nun geklärt.

Gewöhne Dir bitte an, genauer zu lesen. (Hatte ich Dir das nicht schon 
einmal empfohlen?)

Du schriebst:

> Können bei Deinen "DDRB" und "PORTB" solche Verwechslungen vom Compiler
> erkannt werden? Bei Templates und Enums werden sie erkannt!

Ich antwortete:

> Geht auch in C bei AVRs [...]

Ich habe also geschrieben, dass man Verwechselungen bzgl. DDRB und PORTB 
auch in C sicher abfangen kann und Dir einen Link geliefert, der Dir 
erklärt, wie das geht. Und sogar anschaulicher: Nämlich mit TCCR0A und 
WGM01. Ich habe NICHT geschrieben, dass man das über enums und 
Templates "in C" machen kann.

Oben hast Du das unvollständig zitiert. Und wahrscheinlich genauso 
unvollständig beim Lesen in Dich aufgenommen. Aber daran gewöhne ich 
mich langsam...

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Jürgen schrieb:
> Hier wird ja zensiert was das Zeug hält.

Neee, war bestimmt nur im falschen Tread "…wie geht das?" geposted: Mach 
einen neuen Thread auf: "… was soll das?", da wird dann vielleicht nicht 
zensiert. ;-) (War Spaß, gibt´s schon!)

BTW: Ich habe eine "Herausforderung" (aka. "ein Problem"):

Hans-Georg Lehnard schrieb:
> Der g++ im Atmel Studio 6.2 kann C++11 Sytax

Das passt! Ich bin ein großzügiger Patriarch ;-) (bitte Smilley beachen) 
und habe der Familie einen neuen "Kalender" gegönnt, siehe 
Beitrag "Re: Zeigt her Eure IoT Projekte"

Dieser ist heute angekommen. Die Family ist zwar begeistert, aber nun 
ist "Heimautomatisierung" angesagt. Frank (ukw) weiß Bescheid. Es müssen 
per Android-Touchscreen asap. Funkschaltsteckdosen mit ESP8266 
geschaltet werden!

Meine Wahl fiel auf den ATTINY1634, den ich mit "Atmel Studio 6.2" 
wunderbar mit C++11 Sytax ^^ programmieren kann und der auch noch in der 
Bastelkiste liegt! :-)

Was ich nun brauche sind:
* ein hierarchischer Zustandasautomat und
* eine C++-UART-lib.

Zum UART hane ich genug Input, aber beim Zustandasautomat könntet Ihr 
mir helfen:

Arbeitet mit Macros. Wie findet Ihr das?
http://ehiti.de/machine_objects/

Nutzt boost::any. Wie findet Ihr das?
http://collaboration.cmc.ec.gc.ca/science/rpn/biblio/ddj/Website/articles/CUJ/2005/0512/0512babitsky/0512babitsky.html

Gefällt spontan, habe ich aber noch nicht ausprobiert:
http://codereview.stackexchange.com/questions/40686/state-pattern-c-template-short-and-elegant-hierarchical-fsm-solution

"switch/case" finde ich doof:
http://www.eventhelix.com/realtimemantra/hierarchicalstatemachine.htm#.VL_27y4TV1A

Hier werden VMTs angelegt, oder?
http://accu.org/index.php/journals/252

Die Rergebnisse wären ein schönes "kick-off" für "Projekte & Code", aber 
ich benötige "Sparringspartner" und Tipps!

: Bearbeitet durch User
von Nils Friess (Gast)


Lesenswert?

Wer mal ein (meiner Meinung nach) einigermaßen gelungenes Beispiel 
nutzen, bzw. als Basis für eigene Libraries darauf aufbauen möchte, kann 
sich ja mal SAVR anschauen.

https://code.google.com/p/savr/

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Frank M. schrieb:
> Oben hast Du das unvollständig zitiert. Und wahrscheinlich genauso
> unvollständig beim Lesen in Dich aufgenommen.

Genau! Ich habe so zitiert, wie ich es aufgenommen hatte. Nobody is 
perfect! Sorry und danke für die Klarstellung.

PS:

Frank M. schrieb:
> Gewöhne Dir bitte an, genauer zu lesen.

Und in meinem Zeugnis steht dann …

Ich kann versichern: Ich bin stets bemüht! Sorry nochmal!

: Bearbeitet durch User
von Stefan (Gast)


Lesenswert?

Nils Friess schrieb
>Wer mal ein (meiner Meinung nach) einigermaßen gelungenes Beispiel
>nutzen, bzw. als Basis für eigene Libraries darauf aufbauen möchte, kann
>sich ja mal SAVR anschauen.
>https://code.google.com/p/savr/

Die original Arduino Funktionen-API ist für alle Mikrocontrollertypen 
gleich. Vor kurzem habe ich eine Programm 1:1 auf einem Arduino UNO mit 
Atmega und einem Arduino DUE mit ARM-SAM83x laufen lassen.
Die oben gezeigte Lib ist zwar schön, aber leider auf Atmegas begrenzt. 
Wenn man sich die Beiträge im MC-Netz so ansieht, würde ich sagen, die 
ARM-Beiträge überwiegen bald.

Ich fände eine Lib mit verschiedenen Abstraktionsschichten gut. Direkte 
Porbbezeichnunge wie PORTB und PB7 sind für die Portabilität nicht so 
gut.

Beitrag "BIOS für Mikrocontroller"

von robin (Gast)


Lesenswert?

Sollte nicht erst einmal geklärt werden, was das Ziel des ganzen ist, 
bevor man mit Templates, Klassen, assembler oder was auch immer um sich 
wirft.

Der Gedanke hinter diesem Vorhaben ist doch, eine einheitliche 
Schnittstelle zwischen der Software und verschiedener Hardware 
verschiedener Mikrocontrollertypen zu ermöglichen.

Als Beispiel würde ich hier eine HD44780 LCD library nennen. Sie besteht 
letztenendes nur aus Warten und I/O Pins setzen. Da sie eigentlich nur 
daraus besteht, muss sie auch für jeden Controller fast komplett neu 
geschrieben werden. Ein einheitlicher Standard, wie man 
Controller-unabhängig wartet und einen gpio Pin setzt, fehlt.
Ein weiteres Beispiel wäre ein PID-Regler, letzten Endes wird nur ein 
Ist- und Sollwert eingelesen, und ein Stellwert ausgegeben. Also 
get_ADC, set_DAC bzw set_PWM.

Man sollte sich also erst einmal einigen, was wird alles Benötigt, bevor 
man sich auf eine Syntax versteift, die später nicht mehr eingehalten 
wird.
Hier würde ich auch nicht all zu komplexe Funktionen einbauen, sondern 
recht einfache funktionen, die immer wieder kommen definieren.

Zum Beispiel würde ich folgendes Vorschlagen:
- startupcode
- gpio_einlesen
- gpio_setzen
- adc_einlesen
- dac_setzen
- delay
- pwm erzeugen
- timer der alle X ms bestimme funktionen abarbeitet
- uart, SPI, I²C/TWI, RS485
- ...

Mit diesen Paar Funktionen liesen sich schon allerhand Aufgaben Lösen 
und das Hardwareunabhängig. Für einen neuen Controller nur eine andere 
Library Laden, die Pins abändern und den Rest übernimmt der Compiler. 
Sofern die Library vorhanden ist.
Dann die ganzen Funktionen über eine Configdatei einstellen und fertig.

von Stefan (Gast)


Lesenswert?

>1 startupcode
>2 gpio_einlesen
>3 gpio_setzen
>4 adc_einlesen
>5 dac_setzen
>6 delay
>7 pwm erzeugen
>8 timer der alle X ms bestimme funktionen abarbeitet
>9 uart, SPI, I²C/TWI, RS485

Bei Arduino heißt das

2: digitalRead(pinNumber)
3: digitalWrite(pinNumber,value)
4: analogRead(Channel)
5: analogWrite(Channel,value)
6: delay(ms); delayMicroseconds(us)
7: weiß nicht, gibt's aber
8: -
9: Serial.print, SPI.transfer ..

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Stefan schrieb:
> delay(ms); delayMicroseconds(us)

Ist das Dein Ernst?

Was macht der µC in der der Zeit?

Einen RX-Buffer-Overflow?

: Bearbeitet durch User
von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Torsten C. schrieb:
> Zum UART habe ich genug Input, aber beim Zustandasautomat könntet Ihr
> mir helfen…

android.util.JsonReader sagt:
> beginArray() / endArray()
> beginObject() / endObject()
> …

org.xml.sax sagt:
> startDocument()
> startElement() / endElement()
> …

So ein Ereignis-gesteuertes Interface ist für µCs mit wenig RAM 
(512..2048 Bytes) m.E. die einzige Möglichkeit, um Daten in einem 
Zustandsautomaten schnell parsen zu können.

Da ich über den UART http-GET und http-POST bekomme, muss ich die 
UART-API auch so ähnlich wie oben umsetzen.

Hat jemand einen Vorschlag? Gibt's das schon? Vielleicht erfinde ich ja 
gerade ras Rad neu.
http://en.wikipedia.org/wiki/Reinventing_the_wheel

Grober Entwurf:
> startLine() / endLine()
> startIPD() / endIPD()
> startEcho() / endEcho()

… oder so ähnlich. ("IPD" = InPutData)

: Bearbeitet durch User
von jan (Gast)


Lesenswert?

hallo

Bin Anfänger aber hier ist doch ein Konzept C++ OOP das sieht doch gut 
aus?

http://avr-cpp.de/doku.php?id=grafische_programmierung_mit_der_uml

gruß
jan

von jan (Gast)


Lesenswert?

Peter Dannegger schrieb:
> Ich möchte gerne folgendes erreichen:  LED0 = KEY0.state;           //
> an solange Taste gedrückt
>   LED1.toggle = KEY1.press     // wechsel bei jeder Drückflanke
>   LED2.off = KEY2.press_short; // kurz drücken - aus
>   LED2.on = KEY2.press_long;   // lang drücken - an
>
> Geht sowas in C++ und wie könnte eine Implementierung aussehen?
>
> Besonders interessant wäre die Entprellung portweise parallel und nur
> das Auswerten der Tasten einzeln. Also irgendwie, jede Taste ist Teil
> der Klasse entprelle_port, die wiederum für mehre 8Bit-Ports verwendet
> werden kann. Z.B. 16 Tasten an 2 Ports.

hier wird soetwas ähnliches realisiert.
http://avr-cpp.de/doku.php?id=grafische_programmierung_mit_der_uml#zustaende

von F. F. (foldi)


Lesenswert?

jan schrieb:
> Peter Dannegger schrieb:
>> Ich möchte gerne folgendes erreichen:  LED0 = KEY0.state;           //
>
> hier wird soetwas ähnliches realisiert.
> http://avr-cpp.de/doku.php?id=grafische_programmie...

PScC geht ja wohl einen ähnlichen Weg und, man darf es kaum aussprechen, 
Arduino letztlich auch.

Wenn ich mir allerdings das Beispiel aus deinem Link ansehe, dann sind 
mir die paar Zeilen C dann doch angenehmer. Zumindest was dieses 
Beispiel betrifft.

von Stefan (Gast)


Lesenswert?

@Thorsten:

>> delay(ms); delayMicroseconds(us)
>
>Ist das Dein Ernst?

Das Zeug kommt aus der Arduino-Welt. Und da gibt es mehrere Tasks. daher 
kann da durchaus was anderes parallel laufen.

Gruß, Stefan

von Bastler (Gast)


Lesenswert?

Vielleicht hat es sich noch nicht durchgesetzt, weil man darüber nicht 
ungestört diskutieren darf. Bitte alle die schon jetzt überzeugt sich, 
daß es sich um "iwerzwerches Ziegs" handelt, wie man in meiner Heimat 
sagen würde, einfach wegschauen. Und bitte nix mehr schreiben!

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Stefan schrieb:
> Das Zeug kommt aus der Arduino-Welt. Und da gibt es mehrere Tasks. daher
> kann da durchaus was anderes parallel laufen.

Ich lerne immer gern dazu.

> the use of delay() in a sketch has significant drawbacks …, so in
> effect, it brings most other activity to a halt.
http://arduino.cc/en/pmwiki.php?n=Reference/Delay

Gibt es noch ein anderes delay?

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

In "Efficiently implementing objects" ist eine gute Erklärung, wann vom 
Compiler "virtual method tables" (VMTs) im "class instance record" (CIR) 
angelegt werden und wann nicht:

* http://www.toves.org/books/oops/index.html
* http://www.cburch.com/cs/230/test/re/index.html

Leider lässt sich für eine Bibliothek, die für mehrere Toolketten 
geeignet sein soll, nicht immer genau sagen, ob vom Comiler eine VMT 
angelegt wird oder nicht. :-(

Hier das Beispiel:
1
Container bag = new Suitcase(100);
2
bag.add(10);
> A compiler might look at this code and determine that, when the
> add method is being called, bag is of necessity a Suitcase. Thus,
> it could generate code to call Suitcase's add method directly,
> without reference to the VMT to which bag refers.

Frage: Macht eine Bibliothek, die für mehrere Toolketten geeignet sein 
soll, dann überhaupt Sinn?

Torsten C. schrieb:
> aber beim Zustandasautomat könntet Ihr mir helfen: …
> "switch/case" finde ich doof: …

… denn performanter als "switch/case" ist es, wenn jeder Zustand eine 
Klasse (Instanz) ist oder Funktionen (function-pointer) sind!

Und wir wollen in C++ ja nicht schlechter sein als in C!

Daraufhin jan schrieb:
> hier wird soetwas ähnliches realisiert.
http://avr-cpp.de/doku.php?id=grafische_programmierung_mit_der_uml#zustaende

Ein Grafischer Editor für Zustandasautomaten. Cool! Bei meinem ersten 
Versuch damit kam aber auch "switch/case" raus.

Schade. :-(

Eine Demoversion von SiSy läuft übrigens 70 Tage.

: Bearbeitet durch User
von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Ich bin ja kein C++-Profi und bei mir fallen die Groschen auch nur 
pfennigweise. Aber weil die Frage "Wozu Templates?" vielleicht (Käfer 
Karl?) noch nicht hinreichend beantwortet ist:

Man nutzt Vererbung ja oft, um Gemeinsamkeiten einmal in einer 
Basis-Klasse festzulegen. Falls dadurch VMTs entstehen (was ja nicht 
immer vorhersehbat ist^^), wird der C++-Code ineffizienter. Ich brauche 
aber höchste Effizienz (Zustandasautomat in einer ISR, s.u.)! Daher kann 
ich auch kein "switch/case"^^ im Zustandasautomaten gebrauchen.

Mit Templates können Gemeinsamkeiten und Unterschiede aber auch ohne 
Vererbung definiert werden, also immer ohne VMTs, unabhängig von der 
Toolkette. Ist das vielleicht die Begründung, warum Templates bei 
Embedded C++ so wichtig sind?

BTW: Das OOP Konzept "Containment" ist übrigens auch noch eine 
Alternative, um VMTs zu vermeiden:

http://www.codeproject.com/Articles/24948/Three-Ways-To-Extend-A-Class

PS zu "höchste Effizienz"^^:
Ich möchte die Ansätze für die neue "µC.Cet C++-Bibliothek" auf einem 
ATTiny1634 erstmalig nutzen, weil ich damit gerade mein aktuelles 
Projekt umsetze. Der ATTiny1634 hat 1KB RAM und ich muss HTTP-Requests 
direkt in der ISR bearbeiten, damit ich den RX-Puffer klein halten kann. 
"bearbeiten" heißt dabei parsen und wie bei "JsonReader" oder "sax"^^ 
entsprechende Ereignisse auslösen, z.B.

• NextChar(),
• EndOfLine(),
• NumCharsReached() oder
• TimeOut().

Diese Ereignisse müssen von einem effizienten Zustandasautomaten 
ausgewertet werden, denn der Zustandasautomat läuft in einer ISR!

PPS @Modertor: Wie sollen wir uns verhalten?

Ich habe 3978837#3978829 eben gemeldet. War das gewünscht?

: Bearbeitet durch User
von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Moby schrieb im Beitrag #3978856:
> Am besten wie ein Mann der Widerspruch ertragen kann

Mit Widerspruch habe ich kein Problem! Dass es mir um die überflüssigen
>  "[µC.net] Neuer Beitrag in "C++ auf einem MC, wie geht das?"
geht, hatte ich ja geschrieben!

350418#3978856 und 350418#3978862 können von mir aus gelöscht werden; 
wenn Moby kein Gast wäre, hätte ich natürlich 'ne PN geschrieben.

: Bearbeitet durch User
von Lars (Gast)


Lesenswert?

Thorsten und die Anderen, lasst euch nicht beirren von den Amöben ;-)

von Moby (Gast)


Lesenswert?

Torsten C. schrieb:
> Dass es mir um die überflüssigen
>>  "[µC.net] Neuer Beitrag in "C++ auf einem MC, wie geht das?"
> geht,

Nö.

Torsten C. schrieb:
> #3978829 eben gemeldet

... war ja wohl mein Beitrag, der hier ständig wegzensiert wird.

Torsten C. schrieb:
> "höchste Effizienz"^^:
> Ich möchte die Ansätze für die neue "µC.Cet C++-Bibliothek" auf einem
> ATTiny1634 erstmalig nutzen, weil ich damit gerade mein aktuelles
> Projekt umsetze.

Respekt. Da hast Du Dir was vorgenommen. Gutes Gelingen.

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Lars schrieb:
> Torsten und die Anderen, lasst euch nicht beirren von den Amöben

Ich sicher nicht. Ich antworte eher mal in einem "PS: …"
1
class UartStreamReaderBase {
2
    public:
3
        enum Event {
4
            nextChar,
5
            endOfLine,
6
            numChars,
7
        };
8
9
    private:
10
        virtual void ISR_NextChar();    // ISR, die ein Ereignis auslöst, wenn ein Zeichen im RX-Puffer ist
11
        virtual void ISR_EndOfLine();   // ISR, die ein Ereignis auslöst, wenn eine Zeilenende gefunden wurde.
12
        virtual void ISR_NumChars();    // ISR, die ein Ereignis auslöst, wenn eine bestimmte Anzahl von Zeichen im RX-Puffer ist
13
        // virtual void Timeout();      // Ereignis wird ausgelöst, wenn eine Zeit lang kein neues Zeichen im RX-Puffer erscheint (evt. später)
14
        virtual void NextChar();        // Ereignis wird von ISR_NextChar ausgelöst
15
        virtual void EndOfLine();       // Ereignis wird von ISR_EndOfLine ausgelöst
16
        virtual void NumCharsReached(); // Ereignis wird von ISR_NumChars ausgelöst
17
};
18
19
class Uart1StreamReader : UartStreamReaderBase {
20
    
21
};
22
23
class ESP8266Webserver : Uart1StreamReader, StateMachineBase {
24
    
25
};

So^^ denke ich gerade, einen Zustandsautomaten für die UART-ISR 
umzusetzen. Das wäre noch ohne Templates. Mal sehen, wann ich 
wirklich Templates brauche.

PS: Moby schrieb:
> war ja wohl mein Beitrag
… und meinen eigenen hatte ich auch aufgeführt.

Moby schrieb:
> Respekt. Da hast Du Dir was vorgenommen. Gutes Gelingen.

Danke. Falls Du Recht haben solltest und Embedded C++ wirklich Mist sein 
sollte, dann würde mir diese Erkenntnis auch nützlich sein. Aber mir 
ist das noch nicht klar!

: Bearbeitet durch User
von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Torsten C. schrieb:
1
class ESP8266Webserver : Uart1StreamReader, StateMachineBase {

PS: Ich muss mir noch den asm-Code anschauen. Falls diese 
Mehrfach-Vererbung eine VMT erzeugt, probiere ich mal "Containment"^^ 
aus. Oder kann das jemand vorhersagen?

von Karl Käfer (Gast)


Lesenswert?

Hi Torsten,

Torsten C. schrieb:
> Karl Käfer schrieb:
>> Torsten C. schrieb:
>>> * "uCnet" als Namespace
>>> * "µC.net C++ Bibliothek" als Projektbezeichnung
>> Ich würde das "net" herauslassen …
>
> Also wie genau? Nur "uC"? Neee …

uC++?

LG,
Karl

von Karl Käfer (Gast)


Lesenswert?

Hi Torsten,

Torsten C. schrieb:
> Ich bin ja kein C++-Profi und bei mir fallen die Groschen auch nur
> pfennigweise. Aber weil die Frage "Wozu Templates?" vielleicht (Käfer
> Karl?) noch nicht hinreichend beantwortet ist:

Bin (wieder) hier. Sorry, hin und wieder wünscht sich mein Arbeitgeber 
doch tatsächlich, daß ich auch mal das tue, wofür er mich bezahlt.

Ich bin zwar immer noch nicht überzeugt, aber die Mehrheit scheint wohl 
Templates zu bevorzugen und dem muß ich mich als guter Demokrat beugen. 
Aber sagt am Ende nicht, ich hätte nicht davor gewarnt! ;-)

Wie dem auch sei: laßt und doch vielleicht einfach mal zusammentragen, 
welche Hardware-Plattformen wir unterstützen wollen. Sicherlich AVRs, 
offensichtlich auch ARMs. Was ist mit PICs, PIC32 und MCP430?

Wenn wir die gewünschten Plattformen zusammengetragen und entschieden 
haben, sollten wir deren Gemeinsamkeiten und Unterschiede im Detail 
herausarbeiten. Erst dann können wir uns sinnvolle Gedanken über 
High-Level-APIs und die darunter liegenden Abstraktionsschichten für die 
konkrete Hardware aussehen können. Bei einem GPIO-Pin ist das ja simpel, 
aber spätestens bei den leicht unterschiedlichen Timer-Funktionalitäten 
verschiedener AVRs könnte das schon spannend genug werden.

Liebe Grüße,
Karl

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Torsten C. schrieb:
> Der Name sollte auch als Namespace ein gültiger Bezeichner sein, hier
> zwei Links dazu …

Daraufhin Karl Käfer schrieb:
> uC++?

Nee, "+" ist ein unerlaubtes Zeichen. Das geht nur in der 
"Projektbezeichnung". Du hattest das "net" aber auch im Namespace nicht 
haben wollen.

Karl Käfer schrieb:
> aber die Mehrheit scheint wohl Templates zu bevorzugen

Mal sehen, wie weit ich ohne komme. Ich versuche es erstmal ohne.

Karl Käfer schrieb:
> Was ist mit PICs, PIC32 und MCP430?

Dazu Jörg bereits schrieb:
> Sowie du das versuchst, auf viele Familien auszuweiten, geht das schnell
> ins Uferlose.

Zum MSP430 ich schrieb:
> Und der MSP430-Compiler von TI unterstützt z.B. eh keine Templates.

Daher sollten wir mit dem MSP430 auch erstmal abwarten.

Falls sich jemand berufen fühlt, das ganze aus der Sicht der PICs oder 
anderer µCs zu machen, habe ich natürlich überhaupt nix dagegen.

: Bearbeitet durch User
von Philip S. (phs)


Lesenswert?

Hi,

 ich finde, das ist ein sehr spannender Thread hier. Danke für die 
vielen wertvollen Gedanken!

 Bitte entschuldigt, dass ich Torstens Beitrag so zerstückelt zitiere. 
Aber da sind eigentlich zwei Punkte drin, auf die ich separat eingehen 
möchte: Dass Vererbung nicht immer ein guter Weg für Code Reuse ist. Und 
dass Templates helfen können, Polymorphismus ("Vererbung") zur Compile 
Zeit aufzulösen.

Torsten C. schrieb:
> Man nutzt Vererbung ja oft, um Gemeinsamkeiten einmal in einer
> Basis-Klasse festzulegen. [...]
> BTW: Das OOP Konzept "Containment" ist übrigens auch noch eine
> Alternative, um VMTs zu vermeiden:
>
> http://www.codeproject.com/Articles/24948/Three-Ways-To-Extend-A-Class

Ich denke, dass der Gedanke "durch Vererbung kann ich Code wieder 
verwenden" einer der größeren Irrtümer im Verständnis von 
Objektorientierung ist -- völlig unabhängig von C++. Wahrscheinlich ist 
das der "is-a" Sprechweise geschuldet ("Eine Katze ist ein Tier"). 
Vermutlich wäre es besser, wenn man darüber nachdenken würde, ob eine 
Komponente wie eine andere behandelt werden kann. Beim Bespiel Katze vs. 
Tier funktioniert das gut, denn man kann eine Katze ganz offensichtlich 
wie ein Tier behandeln.

Erst gestern hatte ich eine spannende Diskussion mit einem Kollegen zu 
dem Thema. Er brachte das Beispiel "Kreis vs. Ellipse" ein und meinte, 
dass ein Kreis aus mathematischer Sicht im Prinzip eine Spezalisierung 
einer Ellipse sei. Ich versteh nicht so viel von Mathe, aber wenn man 
sich "Quadrat vs. Rechteck" anschaut, dann ist's genauso anschaulich: 
Ein Quadrat ist ja nichts als ein Rechteck, das gleich lang wie breit 
ist. Man könnte also zunächst verleitet sein, eine Quadrat-Klasse von 
einer Rechteck-Klasse abzuleiten und z.B. die Funktion zum Berechnen der 
Fläche in der Basisklasse lassen. Man handelt sich dann aber relativ 
schnell Probleme ein, wenn man über die Attribute (Länge, Breite) 
nachdenkt. Wie stellt man im Quadrat sicher, dass sie immer gleich sind? 
Und warum sollte die Klasse, welche die Seitenlänge von Rechtecken 
abstrakt behandelt, plötzlich wissen, dass Länge und Breite immer gleich 
sein müssen?

Man erkennt hier sofort, dass die "is-a" Denkweise nicht so optimal ist. 
Denkt man stattdessen darüber nach, ob ein Quadrat wie ein Rechteck 
behandelt werden kann, dann ist's schnell klar, dass dem nicht so ist.

Der Ausweg aus der Situation ist Objekt-Komposition, wie in dem 
verlinkten Artikel beschrieben. Lässt man sich auf den Gedanken ein, 
dass ein Quadrat-Objekt halt ein Rechteck "hat", dann verschwinden 
plötzlich auch viele andere Probleme. Das Quadrat exportiert das eine 
Attribut "Kantenlänge" und sorgt halt dafür, dass das Rechteck immer mit 
Länge=Breite aufgesetzt wird. Die Methode zum Ausrechnen der Fläche wird 
dann einfach vom Quadrat an das Rechteck "durchgereicht" -- übrigens 
ohne "virtual" Deklaration und damit garantiert ohne Vtables/VMT.

Torsten C. schrieb:
> [...] Falls dadurch VMTs entstehen (was ja nicht
> immer vorhersehbat ist^^), wird der C++-Code ineffizienter. Ich brauche
> aber höchste Effizienz (Zustandasautomat in einer ISR, s.u.)! Daher kann
> ich auch kein "switch/case"^^ im Zustandasautomaten gebrauchen.
>
> Mit Templates können Gemeinsamkeiten und Unterschiede aber auch ohne
> Vererbung definiert werden, also immer ohne VMTs, unabhängig von der
> Toolkette. Ist das vielleicht die Begründung, warum Templates bei
> Embedded C++ so wichtig sind?
>

Siehe oben. Wenn Du vtables/VMT garantiert vermeiden willst, dann musst 
Du auf "virtual" Deklarationen verzichten. Falls Du dennoch 
Polymorphismus (im Sinne mehrerer Implementierungen eines Interfaces) 
brauchst/willst, dann können Dir Templates helfen. Das Stichwort heisst 
"Compile Time Polymorphism" bzw. "Static Polymorphism", siehe z.B. 
dieser Wikipedia Artikel:

http://en.wikipedia.org/wiki/Template_metaprogramming#Static_polymorphism

Ob das jetzt speziell für Embedded Code wichtig ist, kann ich nicht 
beurteilen. Aber es bietet sich halt immer dann an, wenn eigentlich 
schon zur Compile-Zeit feststeht, welche konkrete Implementierung eines 
Interfaces verwendet werden soll. Gerade das ist aber nicht ungewöhnlich 
für Mikrocontroller-Projekte ;-)

von Stefan (Gast)


Lesenswert?

Hi Torsten,

>> the use of delay() in a sketch has significant drawbacks …, so in
>> effect, it brings most other activity to a halt.
> http://arduino.cc/en/pmwiki.php?n=Reference/Delay
>
> Gibt es noch ein anderes delay?

Sorry, Du hast Recht. Ich glaube, ich habe da Arduino und Scratch 
verwechselt. Die laufen beide bei meinen Kindern auf dem Rechner.

Viele Grüße, Stefan

von Hans-Georg L. (h-g-l)


Lesenswert?

Lieber Torsten C. du hast jetzt zwar diesen Thread erobert ;) ...

Aber die Ursprungsfrage von Peter war nicht: wie erstelle ich eine C++ 
Library für uC. Also sollte dein Lib Peters Frage beantworten können.

@peda
Bist du noch dabei und hast du was aus diesem Thread mitnehmen können 
oder hat sich die Frage erledigt ?

von robin (Gast)


Lesenswert?

Ich denke auch man sollte einen neuen Thread aufmachen indem dann das 
was und wie diskutiert werden kann.

Im ersten Post sollte klar auf die erhofften Vorteile eingegeben werden 
und klar gestellt werden, dass das warum draußen bleiben soll.

Es geht ja letzten Endes darum eine einfache, performante, 
fehlerverhindernde und Controller unabhängige Schnittstelle für 
Standardfunktionen, die in jeden Projekt benötigt werden zu liefern.

So weit richtig?

Jetzt ist doch die wichtigste frage das was soll alles enthalten sein. 
Und da hilft es mMn. wenig, Code Beispiele zu Posten.

@Stefan: Ja ich kenne arduino. Aber es ist schon sehr Controller 
abhängig und ist stark eingeschränkt, bei der Verwendung von Pins.

von Ronny S. (duselbaer)


Lesenswert?

Servus!

Torsten C. schrieb:
>> Und der MSP430-Compiler von TI unterstützt z.B. eh keine Templates.
>
> Daher sollten wir mit dem MSP430 auch erstmal abwarten.

Bin mir gerade nicht sicher, daheim hab ich mspgcc oder msp430-gcc und 
damit kann ich C++11 schreiben. Structs, die einen Port beschreiben (wie 
heißen die Ports / Register für I2C, SPI, UART, ...) kann er auch 
wunderbar als Template an die Implementierung weitergeben.

Wenn man typedefs benutzt, behält man auch halbwegs den Überblick, 
welchen Typ man da gerade benutzt :)

Hab letztens auch zu dem Thema noch einen Talk "gelesen" :), da ich 
letztes Jahr leider nicht hingehen konnte...

http://meetingcpp.de/tl_files/2014/talks/objects%20-%20no%20thanks.pdf

Grüße,
Ronny

von Rolf Magnus (Gast)


Lesenswert?

Hans-Georg Lehnard schrieb:
> Aber die Ursprungsfrage von Peter war nicht: wie erstelle ich eine C++
> Library für uC.

Seine Frage war eigentlich genau das. Im Ursprungsposting ist der 
einzige Satz, der als Frage formuliert ist, folgender:

Peter Dannegger schrieb:
> Geht sowas in C++ und wie könnte eine Implementierung aussehen?

Unter "sowas" hat er sich mangels C++-Erfahrung die Lib zugegebenermaßen 
noch etwas anders vorgestellt.

von Hans-Georg L. (h-g-l)


Lesenswert?

Rolf Magnus schrieb:
> Hans-Georg Lehnard schrieb:
>> Aber die Ursprungsfrage von Peter war nicht: wie erstelle ich eine C++
>> Library für uC.
>
> Seine Frage war eigentlich genau das. Im Ursprungsposting ist der
> einzige Satz, der als Frage formuliert ist, folgender:
>
> Peter Dannegger schrieb:
>> Geht sowas in C++ und wie könnte eine Implementierung aussehen?
>
> Unter "sowas" hat er sich mangels C++-Erfahrung die Lib zugegebenermaßen
> noch etwas anders vorgestellt.

Hm ...

Du meinst Peter, hat mangels C++ Erfahrung die falsche Frage gestellt 
und eigendlich wollte er eine komplette Lib möglichst für alle 
erhältlichen MC haben ?.

Das sehe ich nicht so ...

von Rolf Magnus (Gast)


Lesenswert?

Hans-Georg Lehnard schrieb:
> Du meinst Peter, hat mangels C++ Erfahrung die falsche Frage gestellt
> und eigendlich wollte er eine komplette Lib möglichst für alle
> erhältlichen MC haben ?.

Wieso falsche Frage?

> Das sehe ich nicht so ...

Ich auch nicht. Das war aber auch nicht das, was ich gesagt hab.
Er wollte wissen, wie man eine C++-Bibliothek speziell für µCs macht und 
wie die aussehen könnte. Genau darüber wird gerade diskutiert. Er hat 
sie sich eben mangels der C++-Erfahrung vom Design her etwas anders 
vorgestellt, als die jetzt diskutierten Ideen.
Seine Frage zielte auch nicht auf einen ganz spezifischen Typ ab, 
sondern allgemein auf µCs.

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Philip S. schrieb:
> ich finde, das ist ein sehr spannender Thread hier.

Und er wurde Durch Deinen Beitrag sehr bereichert. Danke für die 
Hinweise, Stichwörter und Klarstellumgen. :-)

Philip S. schrieb:
> Das Stichwort heisst "Compile Time Polymorphism" bzw. "Static
> Polymorphism"

Das ist es! Genau das habe ich gebraucht! Ich hatte schon angefangen, 
mit non-static member function pointers (MFPs)eine Art Polymorphie zu 
basteln:
http://www.codeproject.com/Articles/7150/Member-Function-Pointers-and-the-Fastest-Possible

Vielleicht sind diese MFPs ja trotzdem noch zu was gut.

robin schrieb:
> Ich denke auch man sollte einen neuen Thread aufmachen indem dann das
> was und wie diskutiert werden kann.

Dazu Jörg Wunsch bereits schrieb:
> Nein.  Bleib mal bei einem Thread.
> Für Projekte wiederum gibt es hier die Möglichkeit, einen SVN-Server
> zu hosten sowie das in "Projekte & Code" zu posten.

@robin: Wie meinst Du das? Möchtest Du jetzt schon einen neuen Thread in 
"Projekte & Code" aufmachen oder noch einen weiteren neuen davor, indem 
dann z.B. das "was" (…ist das Projektziel) und das "wie" (…arbeiten wir 
zusammen) geklärt wird?

Den neuen Thread in "Projekte & Code" kann jeder selbst aufmachen, ich 
bin hier kein "Projektleiter" und wollte den Thread auch nicht 
"erobern". Ich will nur mal in die Pötte kommen.

Falls wir uns auf einen Namen einigen, würde auch ich den neuen Thread 
in "Projekte & Code" aufmachen.

Stefan schrieb:
> Auch falsch, ein Interface ist ein Konzept der OOP und ein Spezialfall
> der Mehrfachvererbung. C++ kennt das, auch wenn es das Schlüsselwort
> "interface" nicht gibt.

Die Vererbung muss gar nicht "mehrfach" sein. Wichtig ist, dass die 
virtuellen Methoden "pure virtual" sein müssen, also mit " = 0":
http://www.learncpp.com/cpp-tutorial/126-pure-virtual-functions-abstract-base-classes-and-interface-classes/

: Bearbeitet durch User
von Hans-Georg L. (h-g-l)


Lesenswert?

Rolf Magnus schrieb:
> Hans-Georg Lehnard schrieb:
>> Du meinst Peter, hat mangels C++ Erfahrung die falsche Frage gestellt
>> und eigendlich wollte er eine komplette Lib möglichst für alle
>> erhältlichen MC haben ?.
>
> Wieso falsche Frage?
>
>> Das sehe ich nicht so ...
>
> Ich auch nicht. Das war aber auch nicht das, was ich gesagt hab.
> Er wollte wissen, wie man eine C++-Bibliothek speziell für µCs macht und
> wie die aussehen könnte. Genau darüber wird gerade diskutiert. Er hat
> sie sich eben mangels der C++-Erfahrung vom Design her etwas anders
> vorgestellt, als die jetzt diskutierten Ideen.
> Seine Frage zielte auch nicht auf einen ganz spezifischen Typ ab,
> sondern allgemein auf µCs.

Nö, seine Frage war wie kann ich folgendes in C++ lösen bzw. wie kann 
ich das in C++ lernen ( in Assembler oder C schreibt er dir das im 
Schlaf):

a.  schalte Led solange Taste gedrückt
b.  toggle Led bei jeder (positiven) Drückflanke
c.  led aus wenn taster kurz gedrückt
d.  led an wenn taster lang gedrückt

und ich füge noch dazu:
e.  led blinkt schnell ( 1/2 sec) wenn taster kurz (<500ms) gedrückt
f.  led blinkt normal(1 sec) wenn taster normal(500 ..1500ms) gedrückt
g.  led blink langsam(2 sec) wenn taster lang( >1500ms) gedrückt
usw.

Und darauf ist die Antwort:
"Das kannst du mit unserer neuen uC++ Lib irgenwann mal machen"
genauso gut wie 42 oder schau in die gelbe Seiten ;)
Natürlich kann man alles in eine Lib verpacken.
Schau dir doch mal alle bekannten Libs in dieser Richtung an, da ist 
keine dabei die Peters Frage konkret und nachvollziehbar beantwortet.

Die Diskussion hier: wie müsste eine LIB aussehen, was müsste sie 
beinhalten und wie kann sie effektiv implementiert werden ist mit 
Sicherheit sinnvoll und nützlich aber sie beantwortet die ursprünglichen 
Fragen nicht. Mehr wollte ich mit meinem Post nicht sagen ...

> weiterhin schrieb peda
>In C wird ja für jeden Quark eine Funktion benötigt, was nicht besonders
>gut lesbar ist.
>In C++ könnte man Zuweisungen nehmen, wenn man nur wüßte, wie man das
>implementiert.
Da fragt er doch eher nach Überladung vom = operator und nicht nach 
einer LIB.

: Bearbeitet durch User
von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Hans-Georg Lehnard schrieb:
> Lieber Torsten C. du hast jetzt zwar diesen Thread erobert ;) ...

Lieber Hans-Georg,

der Eindruck mag entstehen und falls ich in Zukunft noch 'ne spezielle 
Frage zu meinen "Zustandsautomaten für die UART-ISR" ^^ habe, werde ich 
sie auch in einem separaten Thread stellen, denn "erobern" wollte ich 
den Thread nicht. Ich bleibe in Zukunft beim Zustandsautomaten für 
Taster!

Hans-Georg Lehnard schrieb:
> Und darauf ist die Antwort:
> "Das kannst du mit unserer neuen uC++ Lib irgenwann mal machen"

Die Diskussion um eine "neue uC++ Lib" ist ja nur Vorbereitung auf einen 
neuen Thread in "P&C" und behandelt - bis auf den Namen und die Liste 
der zu unterstützenden µC-Familien - genau auch das gefragte Thema "wie 
kann man 'folgendes' (effizient) in C++ lösen":

Zu "Taster kurz gedrückt" und "Taster lang gedrückt" hatte Jan auf den 
Zustandsautomaten verwiesen:

http://avr-cpp.de/lib/exe/detail.php?id=grafische_programmierung_mit_der_uml&cache=cache&media=smbutton.jpg

Hier heißt das nur anders: "OnHold", "OnBtnUp" und "OnClick".

Zum  Thema "effizient in C++ lösen" ist meine Anmerkung (nun weiß ich 
ja, wie das heißt): "Compile Time Polymorphism", "Static Polymorphism" 
oder "Member Function Pointers" sind effizienter als "switch/case" wie 
bei Jans SiSy.

Aber wie ich nun den Zustandsautomaten am besten umsetzen soll? Ich bin 
immer noch am lesen und probieren, wie ich das übersichtlich, flexibel, 
ohne "switch/case" und µC-tauglich ohne VMTs machen könnte.

Die Antwort wird die Gleiche sein, egal ob für die UART-ISR oder für 
Taster.

: Bearbeitet durch User
von chris_ (Gast)


Lesenswert?

>Aber wie ich nun den Zustandsautomaten am besten umsetzen soll? Ich bin
>immer noch am lesen und probieren, wie ich das übersichtlich, flexibel,
>ohne "switch/case" und µC-tauglich

Was stört dich an switch/case? Als Alternative sehe ich nur If/else oder 
im schlimmsten Fall so wie es Rational Rhapsody macht: mit "goto" ( 
wohlgemerkt in C ).
Allerdings könnte die "goto" Variante tatsächlich die schnellste sein.

von jan (Gast)


Lesenswert?

Ohne switch/case If/else einfach ein array von Funktionszeigern

http://www.mikrocontroller.net/articles/Funktionszeiger_in_C

von COW-boy (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Mark Brandis schrieb:
>> Nahezu alles, was man in C machen kann, kann man auch in C++
>> machen.
>> Naja, so gut wie alles. 99 Prozent.
> Aber auch in Brainfuck. Warum verwendet niemand Brainfuck? Es ist
> supereinfach zu lernen, verwenden und implementieren.

Give me five - Patsch!
Der war gut :-)

Ich habe auch spasseshalber mal ein bisschen mit Brainfuck 
experimentiert.

Vielleicht interessiert ja mal das "Hello World":
http://de.wikipedia.org/wiki/Brainfuck
oder das:
http://de.wikipedia.org/wiki/Esoterische_Programmiersprache

von COW-boy (Gast)


Lesenswert?

Cyblord ---- schrieb:
> Der Tag mag kommen an dem FH-Studenten mir Nachhilfe in
> Programmierkonzepten erteilen, aber heute ist das sicher noch nicht ;-)

Ein feiner, umgänglicher und bescheidener Herr, dieser Cyblord

von Hans-Georg L. (h-g-l)


Lesenswert?

Hallo Thorsten,

mein Post war ja auch mit einem Augenzwinkern versehen ...

Hast du dir schonmal die Umsetzung von state transition tables mit 
Templates angesehen ?

http://aristeia.com/TalkNotes/C++_Embedded_Deutsch.pdf
Ab Seite 114/folie244.

http://www.boost.org/doc/libs/1_55_0/libs/msm/doc/HTML/ch03s02.html

Das ist für mich die übersichtlichste Art wie man state machines im 
Quellcode darstellen kann.

Google findet noch mehr dazu.

Das Problem Taste entprellen, kurz, lang, mittel gedrückt und überhaupt 
timing im allgemeinen wird eine state machine alleine nicht lösen. Dazu 
wirst du wahrscheinlich auch ein mini OS mit SytemTimer und evtl Task 
Verwaltung brauchen. Du brauchst auf jeden Fall eine "call back" 
Funktion in deinen IO Ports die du beliebig auf PinChange oder Timer 
Callback konfigurieren kannst. Die CPU mit delay() schlafen legen ist 
eine schlechte Idee für eine MC lib. Und bei Batterie betriebenen 
Anwendungen kommt noch der Sleep Modus, den viele MC beherschen und der 
sich überall einmischt dazu.

Deshalb ist meine Meinung, das eine allgemeine uCpp Lib (Vorschlag für 
den Namen) nur Teilaspekte der Möglichkeiten heutiger MC modellieren 
kann. Das bedeutet, entweder sie ist: unvollständig, wird nie fertig, 
ist flexibel erweiterbar. Den letzten Punkt halte ich im Moment (noch) 
nicht für realisierbar.


Anhang Buchtips fals jemand ein WIKI zum Thema aufmachen möchte:

David Abrahams, Aleksey Gurtovoy :
C++ Template Metaprogramming: Concepts, Tools, and Techniques from Boost 
and Beyond

Scott Meyers :
Effective C++
Effective Modern C++
Effective C++ in an Embedded Environment

David Vandevoorde, Nicolai M. Josuttis :
C++ templates : The complete Guide

Christopher Michael Kormanyos
Real Time C++

von Hans-Georg L. (h-g-l)


Lesenswert?

Mob** schrieb im Beitrag #3980904:
> wie immer das gleiche ...

Es lebte einst ein kleiner Moby in seiner Assembler Welt und diese Welt 
war eine Scheibe. In dieser Welt leben immer weniger Menschen, weil sie 
lernten über den Tellerand zu schauen und sie merkten es gibt auch noch 
Scheibe++.
Nun sitzt er einsam da und jammert, aber keiner hört ihm zu ...

Galileo Galilei benannte später Scheibe++ in Kugel um.

von Bastler (Gast)


Lesenswert?

Wenn das Zensur ist, ist dann die Abwesenheit von Zensur jeder 
Nervensäge ausgeliefert zu sein? Wir haben verstanden, nicht jeder will 
den Algorithmus in lesbar vor sich liegen haben, mancher will lieber 
Registerdispatcher spielen. Das macht besonders bei Änderungen richtig 
Spaß.

von F. F. (foldi)


Lesenswert?

Ich beschäftige mich gerade mit Assembler (wenn ich denn mal Zeit habe) 
und sicher ist das für manche Sachen oder als inline ne gute Sache, aber 
komplexe Sachen damit machen?
Da blickst du selbst nach drei Jahren nicht mehr durch, wenn du was 
ändern willst.

von Hans-Georg L. (h-g-l)


Lesenswert?

F. Fo schrieb:
> Ich beschäftige mich gerade mit Assembler (wenn ich denn mal Zeit habe)
> und sicher ist das für manche Sachen oder als inline ne gute Sache, aber
> komplexe Sachen damit machen?
> Da blickst du selbst nach drei Jahren nicht mehr durch, wenn du was
> ändern willst.

Hallo Foldi,
spätestens wenn du deinen Assembler code auf einen anderen MC und/oder 
auf einen anderen Assembler Hersteller übertragen willst wirst du merken 
das das nicht so einfach geht. Versuch einfach mal Keil oder IAR 
Assembler auf Gnu Assembler oder dein AVR Assembler Code auf PIC zu 
portieren dann wirst du sehen, warum die Assembler Welten alles 
Scheibenwelten sind ...
Das gilt auch für inline Assembler in C.

Trotzdem wirst du Assembler Code verstehen lernen müssen, weil C erst 
bei main anfängt und C davon ausgeht das statische Variablen bis dahin 
initialisiert sind. Sinnvoll ist es auch wenn Interrupt Vektoren oder 
das Ende von main, wenn du die while(1) vergessen hast, nicht ins 
Nirwana zeigen. Der Prozessor startet aber schon viel früher bei einer 
bestimmten Adresse ( oft Adresse 0, muss aber nicht so sein ). Für 
Startup code oder Bootloader wirst du immer Assembler brauchen.

von chris_ (Gast)


Lesenswert?

>>Aber wie ich nun den Zustandsautomaten am besten umsetzen soll? Ich bin
>>immer noch am lesen und probieren, wie ich das übersichtlich, flexibel,
>>ohne "switch/case" und µC-tauglich
>Ohne switch/case If/else einfach ein array von Funktionszeigern
>http://www.mikrocontroller.net/articles/Funktionszeiger_in_C

Meiner Meinung nach kann man die Funktiosnzeiger aber auch als 
versteckte Art des "goto" betrachten:

http://www.thibault.org/newhome/thoughts/goto-and-fsms.html

von Moby (Gast)


Lesenswert?

Bastler schrieb:
> mancher will lieber
> Registerdispatcher spielen. Das macht besonders bei Änderungen richtig
> Spaß.

F. Fo schrieb:
> ber
> komplexe Sachen damit machen?
> Da blickst du selbst nach drei Jahren nicht mehr durch,

Da fehlts Euch a bisserl an Systematik... In Asm baut man mit der Zeit 
aus kleinen Bausteinen größere, und daraus durchaus auch komplexe 
Funktionen. Ohne freilich an Flexibilität, Size, Speed und totaler 
Codecontrolle zu verlieren. Den Rest übernimmt eine durchdachte 
Dokumentation.

Hans-Georg Lehnard schrieb:
> wenn du deinen Assembler code auf einen anderen MC und/oder
> auf einen anderen Assembler Hersteller übertragen willst

Sogesehen ist Asm natürlich schon eine kleine Scheibe. Wählt man seinen 
Controller aber geschickt (AVR), sorgt gerade das effiziente Asm dafür, 
daß man dabei lange lange bleiben kann und sich die Notwendigkeit eines 
Wechsels gar nicht ergibt. "Größere Teller" bedeuten dann nur noch 
unnützen Mehraufwand.

Hans-Georg Lehnard schrieb:
> Trotzdem wirst du Assembler Code verstehen lernen müssen,
> Für
> Startup code oder Bootloader wirst du immer Assembler brauchen

Na wenigstens eine Spur von Einsicht ;-)

von Hans-Georg L. (h-g-l)


Lesenswert?

Moby schrieb:
> Hans-Georg Lehnard schrieb:
>> Trotzdem wirst du Assembler Code verstehen lernen müssen,
>> Für
>> Startup code oder Bootloader wirst du immer Assembler brauchen
>
> Na wenigstens eine Spur von Einsicht ;-)

Das hat nichts mit Einsicht zu tun sodern mit dem Wissen das es außer 
Faustkeil auch Hammer und sogar Elektrowerkzeuge gibt, die einem das 
Leben erleichtern. Und diese Wissen hatte ich schon zu 8080 Zeiten wo 
ich sogar den Assembler selber gespielt habe weil Assembler und Code 
über Lochstreifen einlesen keinen wirklichen Spass gemacht hat. Oder 
sogar noch früher wo ich meine Selbstbau "Computer" mit 74181 mit dem 
Lötkolben (Dioden auf Lochraster-Rom) programmiert habe.

Geh dich doch einfach mal bewerben und erzähle dort ich kann nur 
Assembler und kleine avr und deine ganzen anderen Floskeln ...

: Bearbeitet durch User
von Moby A. (moby-project) Benutzerseite


Lesenswert?

Hans-Georg Lehnard schrieb:
> Geh dich doch einfach mal bewerben...

Der Hobbybastler ist zum Glück frei in seiner Entscheidung und kann sich 
auf das wirklich notwendige beschränken. ;-)

Zu Floskeln zähle ich Vergleiche mit Hammer, Faustkeil, Code mit 
Lochstreifen einlesen usw.

von Hans-Georg L. (h-g-l)


Lesenswert?

Moby AVR schrieb im Beitrag #3981655:
> Hans-Georg Lehnard schrieb:
>> Geh dich doch einfach mal bewerben...
>
> Der Hobbybastler ist zum Glück frei in seiner Entscheidung und kann sich
> auf das wirklich notwendige beschränken. ;-)
>
> Zu Floskeln zähle ich Vergleiche mit Hammer, Faustkeil, Code mit
> Lochstreifen einlesen usw.

Hier Bitteschön der Link auf das Intel Entwicklungssystem MDS-800 mit 
Lochstreifenleser und Stanzer:

https://docs.google.com/file/d/0B9rh9tVI0J5mRXJpSVViMGo0aGs/edit?pli=1

Und programmieren mit Dioden geht so :

http://www.darrinhodges.com/wp-content/uploads/2013/09/diode_rom.png

Das ist aber nicht meine Platine, die gibt es leider nicht mehr.

: Bearbeitet durch User
von F. F. (foldi)


Lesenswert?

Hans-Georg Lehnard schrieb:
> Hallo Foldi,
> spätestens wenn du deinen Assembler code auf einen anderen MC und/oder
> auf einen anderen Assembler Hersteller übertragen willst wirst du merken
> das das nicht so einfach geht.

Hans Georg, ich will das auch nicht lernen um hinterher in ASM zu 
programmieren, sondern eher um die Funktionsweise und die Abläufe im µC 
noch besser verstehen zu können.
Mein endgültiges Ziel ist (wenn ich noch alt genug werde) sowieso C++ zu 
lernen und zu programmieren.
Aber ich bin auch nicht so ein typischer "Fanboy".
Genauso, um bei vorgenannten Beispielen zu bleiben, nehme ich bei der 
Arbeit einen Hammer, wenn ich mit dem Hammer am leichtesten oder am 
besten zum Ziel komme. Einen 17ner Schlüssel für die 10ner Schraube.

Ich bin auch nicht der Verfechter eines bestimmten Mikrocontrollers und 
kann ehrlich gesagt auch da die Glaubenskriege nicht verstehen. Zumal in 
ein paar Jahren wieder was ganz neues hip sein kann.

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Hans-Georg Lehnard schrieb:
> Hast du dir schonmal die Umsetzung von state transition tables mit
> Templates angesehen ?
> http://aristeia.com/TalkNotes/C++_Embedded_Deutsch.pdf
> Ab Seite 114/folie244.

Cool, das verkauft Scott in Englisch für US$24,95!
http://www.artima.com/shop/effective_cpp_in_an_embedded_environment

Hans-Georg Lehnard schrieb:
> Scott Meyers: … Effective C++ in an Embedded Environment
Gut, dass ich mir nicht das "Effective C++…" [ScoMe01]^^ gekauft habe, 
das ist zu 90% das Gleiche!

Die Templates gefallen mir grundsätzlich, weil sie so klar gegliedert 
sind, also leicht zu verstehen und zu pflegen. Ich hatte sie schom mal 
gesehen, aber irgendwie sind sie in Vergessenheit geraten. Danke für den 
Hinweis!

Mich würde mal interessieren, wie der Code nach einer "template 
expansion" aussieht. Dann hätte Käfer Karl auch 'ne variante ohne 
Templates. ;-)

Mit "-fdump-rtl-all" kann man ja schon etwas davon sehen, ist aber 
unübersichtlich. Vielleicht kennt jemand was besseres dafür?

Hans-Georg Lehnard schrieb:
> http://www.boost.org/doc/libs/1_55_0/libs/msm/doc/HTML/ch03s02.html

Ob die BOOST-Version wohl ohne new(), also ohne dynamic memory 
allocation auskommt?

Gerade das finde ich beim AVR nämlich gut: Normalerweise hat der gar 
keine new()-Operator:
http://www.avrfreaks.net/forum/avr-c-micro-how?name=PNphpBB2&file=viewtopic&t=59453

jan schrieb:
> Ohne switch/case If/else einfach ein array von Funktionszeiger in C

Genau, weil´s schneller geht als mit enums. Die nächste Funktion ist ja 
schon klar, wenn man die int-Variable "state" auf den nächsten Wert 
setzt.

Warum soll man dann später nochmal ein "switch (state)" mit einem Haufen 
case-Anweisungen bauen???

Ich habe es nach viel Schweissarbeit endlich geschafft, einen kleinen 
Zustandsautomaten sogar mit Typ-Sicheren Funktionszeigern (Delegates) zu 
implementieren, ohne Templates, erstmal noch "geradeaus":

Das ist Option 4: pointer to member functions (fastest solution) aus:
http://stackoverflow.com/questions/9568150/what-is-a-c-delegate

Es gibt drei Zeiger-Typen:
1
/***********
2
* SM_RX_ISRs
3
************/
4
struct SM_OkEvents {
5
    void SM_noInitRestetOnOK();
6
};
7
typedef void(SM_OkEvents::*SM_OkEvent)(void);
8
SM_OkEvents sM_OkEvents;
9
SM_OkEvent onOKEvent = &SM_OkEvents::SM_noInitRestetOnOK;
10
/*************
11
* SM_ErrEvents
12
**************/
13
struct SM_ErrEvents {
14
    void SM_TrapOnError(){TrapCPU();};
15
    void SM_noInitEntry();
16
};
17
typedef void(SM_ErrEvents::*SM_ErrEvent)(void);
18
SM_ErrEvents sM_ErrEvents;
19
SM_ErrEvent onErrorEvent = &SM_ErrEvents::SM_TrapOnError;
20
/***********
21
* SM_RX_ISRs
22
************/
23
struct SM_RX_ISRs {
24
    void ESP_USART_RXdefault_ISR(){TrapCPU();};
25
    void ESP_USART_FindMagic_ISR();
26
    void ESP_USART_EatChars_ISR();
27
};
28
typedef void(SM_RX_ISRs::*SM_RX_ISR)(void);
29
SM_RX_ISRs sM_RX_ISRs;
30
SM_RX_ISR USART_RX_ISR = &SM_RX_ISRs::ESP_USART_RXdefault_ISR;

Die "SM_RX_ISRs" sind verschiedene ISRs für den "USART0_RX_vect", also 
so:
1
ISR(USART0_RX_vect) {
2
    // vectors are located in flash rom
3
    (sM_RX_ISRs.*USART_RX_ISR)();
4
    // TODO: In ASM würde man nur springen und würde den Funktionsaufruf vermeiden.
5
}

Und der Zustandsautomat (kleiner Web-Server), reagiert nur auf diese 
Interrupps und löst je nach eintretender Bedingung ein "SM_ErrEvent" 
oder ein "SM_OkEvent" aus, um damit den nächsten Zustandsübergang zu 
erreichen.

Da die Ereignisse (ohne swich/case/…) sehr schnell bearbeitet werden, 
kann der Automat hoffentlich komplett in der ISR laufen.

Hans-Georg Lehnard schrieb:
> mein Post war ja auch mit einem Augenzwinkern versehen ...

Hab´ ich gesehen, alles im grünen Bereich! Aber ich muss mal meckern:

Es nervt, wenn man hier im Thread mal was sucht und zwischen den ganzen 
"lustigen" Posts nix wieder findet ("da war doch mal ..."). Bald sind 
wir auf Seite 3 und dann geht das Hin-und-her-Geblättere los.

"Es lebte einst ein kleiner Moby in seiner Assembler Welt …" usw. war 
zwar ganz lustig, aber vielleicht kannst auch Du versuchen, den Thread 
übersichtlicher zu halten.

: Bearbeitet durch User
von Torsten C. (torsten_c) Benutzerseite


Angehängte Dateien:

Lesenswert?

chris_ schrieb:
> Allerdings könnte die "goto" Variante tatsächlich die schnellste sein.
chris_ schrieb:
> Meiner Meinung nach kann man die Funktiosnzeiger aber auch als
> versteckte Art des "goto" betrachten:

Was Du immer mit Deinem GoTo willst, musst Du mir mal erklären!

Torsten C. schrieb:
> Warum soll man dann später nochmal ein "switch (state)" mit einem Haufen
> case-Anweisungen bauen???

Mit "später nochmal" meine ich: Irgendwann, wenn das nächste Ereignis 
(Spalte "Event") eintritt. Dann wird halt ggf. nach der "Guard" 
geschaut, eine "Action" ausgeführt und der Zeiger auf eine Tabelle mit 
denjenigen Reihen ("a_row/_row") gesetzt, deren "Start" in der "Target" 
stehen.

Du hast dann pro Zustand eine Unter-Tabelle mit je einem 
Funktionszeiger in C pro Event.

Wo ist da Dein GoTo?

: Bearbeitet durch User
von chris_ (Gast)


Lesenswert?

>Wo ist da Dein GoTo?
Dein Bild hast du ja schon von der richtigen Seite kopiert.

3.ter Codeblock:

http://www.crystalclearsoftware.com/soc/coroutine/coroutine/finite_state_machines.html

von Hans-Georg L. (h-g-l)


Lesenswert?

F. Fo schrieb:
> Ich bin auch nicht der Verfechter eines bestimmten Mikrocontrollers und
> kann ehrlich gesagt auch da die Glaubenskriege nicht verstehen. Zumal in
> ein paar Jahren wieder was ganz neues hip sein kann.

Der einzige Glaubenskrieger hier ist Moby.

von Theoretiker (Gast)


Lesenswert?

Ein "verstecktes" Goto ist nicht schlimm. Jedes Bedingung, jede 
Schleife, jeder Funktions- oder Methodenaufruf ist ein "verstecktes" 
Goto.

Die spannende Frage ist, wie organisiert man in einer Sprache oder 
System all die "versteckten" Gotos so dass man sich nicht im Chaos 
verirrt.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Theoretiker schrieb:
> Ein "verstecktes" Goto ist nicht schlimm.

Auch ein offensichtliches, explizites Goto ist nicht schlimm.

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

chris_ schrieb:
> 3.ter Codeblock:

Ach mit "yield", das kannte ich bis eben noch gar nicht:

http://www.cplusplus.com/reference/thread/this_thread/yield/

OK, bei Multi-Threading kann man das auch mit GoTo machen, nun habe ich 
es verstanden.

Aber ob das auf einem µC Sinn macht? Interessante Fragestellung!

Falls ja, Multi-Threading wäre 'ne feine Sache und ein echter Pluspunkt 
für die Einfachheit der Programmierung, gerade bei Zustandsautomaten.

Aus Erfahrung mit Multi-Threading-Programmierung mit C# unter Windows 
kann ich jedoch berichten, dass sich solche Programme manchmal schwer 
debuggen lassen.

: Bearbeitet durch User
von Moby A. (moby-project) Benutzerseite


Lesenswert?

Hans-Georg Lehnard schrieb:
> Der einzige Glaubenskrieger hier ist Moby.

Man sollte die Dinge möglichst einfach halten.
Das Motto  "Keep it simple" ist keine Glaubensfrage , sondern eine Gebot 
rationaler Vernunft.

Oder wie sagte schon der große Karl der Käfer:

"Warum denn Komplexität einbauen, ohne Not und ohne Vorteil?
Wozu Kosten und Einstiegshürden steigern wenn kein Nutzen erkennbar?"

: Bearbeitet durch User
von Bastler (Gast)


Lesenswert?

Meine "rationale Vernuft" sagt mir: es gibt auch andere Architekturen. 
Ich hab nämlich in den letzten 35 Jahren schon einige erlebt. Das Motto 
"keep it simple" kenne ich zur Genüge von der Arbeit. Aber da gibt es 
immer 2 Seiten. Für den einen ist simple: nur eine Architektur (und nur 
so einfache Sachen, daß ASM reicht). Für andere ist es: eine 
Beschreibung der Lösung eines (gerne auch komplexeren) Problems, 
unabhängig von der Zielarchitektur. Wie ich schon weiter oben 
geschrieben hab: das Register-Dispatchen überlasse ich gern dem GCC.

von TriHexagon (Gast)


Lesenswert?

Moby AVR schrieb im Beitrag #3982637:
> Wozu Kosten und Einstiegshürden steigern wenn kein Nutzen erkennbar?"

Weil du keinen Nutzen siehst, gibt es keinen? Sag mal erleuchteter Moby 
welche Erfahrungen kannst du den mit C und C++ vorweisen, dass du das 
beurteilen kannst? Bin ja mal gespannt.

Nebenbei schon mal gemerkt dass es hier nicht um ASM vs. irgendwas geht?

von F. F. (foldi)


Lesenswert?

Wobei hier auch noch nicht viel von seinem ASM zu sehen war.

Außerdem, Moby, darfst du nicht ständig deinen Namen im Thread ändern. 
Das verbieten die Forenregeln.

von Chris D. (myfairtux) (Moderator) Benutzerseite


Lesenswert?

TriHexagon schrieb:
> Nebenbei schon mal gemerkt dass es hier nicht um ASM vs. irgendwas geht?

So ist es.

Ich bitte deswegen darum, wieder zum Thema zurückzukehren:

Peter Dannegger schrieb:
> LED0 = KEY0.state;           // an solange Taste gedrückt
> LED1.toggle = KEY1.press     // wechsel bei jeder Drückflanke
> LED2.off = KEY2.press_short; // kurz drücken - aus
> LED2.on = KEY2.press_long;   // lang drücken - an
> Geht sowas in C++ und wie könnte eine Implementierung aussehen?

Das interessiert nämlich wirklich einige - unter anderem mich.

Wenn jemand anderes diskutieren möchte,kann er dazu gerne einen eigenen 
Thread eröffnen.

Danke.

: Bearbeitet durch Moderator
von Theoretiker (Gast)


Lesenswert?

Chris D. schrieb:
> Das interessiert nämlich wirklich einige - unter anderem mich.

Man könnte sich ein "Port-System" überlegen, und mit einem überladendem 
Assignment-Operator einen Input-Port an einen Output-Port "binden".

von Moby (Gast)


Lesenswert?

Chris D. schrieb im Beitrag #3982854
> Das interessiert nämlich wirklich einige - unter anderem mich.

Nun existiert der Thread schon seit November und die versammelte C++ 
Expertenrunde hat auf die von Peter D. skizzierten Trivialaufgaben immer 
noch keine Antwort gefunden? Was sagt uns das bitteschön?

von Mark B. (markbrandis)


Lesenswert?

Moby schrieb:
> Nun existiert der Thread schon seit November und die versammelte C++
> Expertenrunde hat auf die von Peter D. skizzierten Trivialaufgaben immer
> noch keine Antwort gefunden? Was sagt uns das bitteschön?

Dass es so trivial wohl doch nicht ist. Zumindest dann nicht, wenn es 
eine für verschieden(st)e Mikrocontroller funktionierende Lösung werden 
soll.

: Bearbeitet durch User
von Moby (Gast)


Lesenswert?

Mark Brandis schrieb:
> Dass es so trivial wohl doch nicht ist

... diese Probleme mit C++ lösen zu wollen!
Was für ein Gestolper und Gewürge. Was für ein Kampf mit dessen 
wildwüchsigen Sprachkonstrukten schon bei diesen MC-Programm 
Grundfunktionalitäten ;-(

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Moby schrieb:
> ... diese Probleme mit C++ lösen zu wollen!

Naja, wenn Du meinst, dass Du mit Assembler eine plattformübergreifende 
Lösung schaffen kannst, dann stelle sie mal vor und beantworte Peters 
ursprüngliche Frage.

Achja, Du kannst ja gar nicht mit Assembler plattformübergreifende 
Programm-Bibliotheken schreiben. Was willst Du dann hier in diesem 
Thread?

von Chris D. (myfairtux) (Moderator) Benutzerseite


Lesenswert?

Moby schrieb:
> Mark Brandis schrieb:
>> Dass es so trivial wohl doch nicht ist
>
> ... diese Probleme mit C++ lösen zu wollen!
> Was für ein Gestolper und Gewürge. Was für ein Kampf mit dessen
> wildwüchsigen Sprachkonstrukten schon bei diesen MC-Programm
> Grundfunktionalitäten ;-(

Das unterscheidet jemanden, der sich damit auseinandergesetzt hat, von 
einem Laien: er weiss, dass trivial aussehende Probleme eben nicht 
trivial sind.

Hast Du auch Konstruktives zur Fragestellung des OPs beizutragen, 
nämlich Vorschläge zur Implementierung in C++, beizutragen?

Wenn nicht, dann halte Dich hier bitte einfach zurück.

Ist doch eigentlich nicht schwer: Ich weiss nicht viel von C++ -> also 
schreibe ich nichts dazu.

Sieh mal - selbst ich schaffe das: ich habe auch schon Jahre nicht mehr 
in C++ gearbeitet - also lese ich hier erstmal nur mit und versuche zu 
lernen.

Bau Du weiter Deine IP-Stacks, Web-Server und und Grafikbibliotheken in 
Assembler - ist doch ok.

Leute, die plattformübegreifend arbeiten müssen, interessiert aber eine 
effiziente Lösung dieses Problems.

Also: bitte zur Sache "Implementierung in C++" oder schweigen.

P.S.: Und hör bitte auf, hier mit mehreren Nicks aufzutreten - das ist 
Kindergartenniveau.

: Bearbeitet durch Moderator
von F. F. (foldi)


Lesenswert?

Eigentlich geht die ganze Diskussion, mal von Moby abgesehen, nur um 
das, was Arduino macht.
Dahinter verbirgt sich C++.

von Karl Käfer (Gast)


Lesenswert?

Hi foldi,

F. Fo schrieb:
> Eigentlich geht die ganze Diskussion, mal von Moby abgesehen, nur um
> das, was Arduino macht.
> Dahinter verbirgt sich C++.

Dahinter verbirgt sich eine Art C++, die dafür gemacht und optimiert 
wurde, von absoluten Anfängern und Nichttechnikern benutzt zu werden. 
Die Arduino-Entwickler haben überall Sicherheitsnetze eingebaut und 
versuchen da, jeden irgendwie denkbaren und undenkbaren Fehler 
abzufangen. Das ist ihnen zwar recht gut gelungen, aber leider auch 
nicht sonderlich effizient.

Ich habe mir die oben erwähnte und verlinkte xpcc-Bibliothek einmal 
näher angeschaut. Das scheint mir eher was für fortgeschrittene, 
effizienz- und ressourcenorientierte Entwickler zu sein als die 
Arduino-Bibliotheken.

Liebe Grüße,
Karl

von Hans-Georg L. (h-g-l)


Lesenswert?

Natürlich ist das Problem nicht trivial, aber das merkt man erst wenn 
man sich damit beschäftigt und nicht nur jammert.

Die Idee: "Hurra, wir machen ein Projekt daraus und entwickeln gemeinsam 
eine Lib" halte ich auch aus diesem Grunde für ein wenig blauäugig. 
Blauäugig in dem Sinne das das Projekt irgendwann mal fertig wird.
Ich bin aber überzeugt, das es prinzipiell geht und auch effektiv auf 
einem Tiny mit 2k Flash und 128Byte Ram laufen kann.

Denn: "Der Weg ist das Ziel" und "viele Wege führen ins ROM (Flash)".

von Mark B. (markbrandis)


Lesenswert?

Hans-Georg Lehnard schrieb:
> viele Wege führen ins ROM

:-)

von Conny G. (conny_g)


Lesenswert?

Frank M. schrieb:
> Moby schrieb:
>> ... diese Probleme mit C++ lösen zu wollen!
>
> Naja, wenn Du meinst, dass Du mit Assembler eine plattformübergreifende
> Lösung schaffen kannst, dann stelle sie mal vor und beantworte Peters
> ursprüngliche Frage.
>
> Achja, Du kannst ja gar nicht mit Assembler plattformübergreifende
> Programm-Bibliotheken schreiben. Was willst Du dann hier in diesem
> Thread?

Moby,
kannst Du jetzt mal aufhören mit Deinem unproduktiven Gestänkere, bitte.

von Moby (Gast)


Lesenswert?

Chris D. schrieb:
> Hast Du auch Konstruktives zur Fragestellung des OPs beizutragen,
> nämlich Vorschläge zur Implementierung in C++, beizutragen?

Der Hinweis, zum Einschlagen des Nagel besser einen einfachen Hammer zu 
verwenden ist sowas von konstruktiv...

Chris D. schrieb:
> trivial aussehende Probleme eben nicht trivial sind

... denn die von Peter D. skizzierten Problemchen SIND u.a. in Asm 
trivial zu lösen.

Chris D. schrieb:
> das ist
> Kindergartenniveau:

Richtig Herr Moderator. Nämlich inhaltlich mißliebige Beiträge in 
blanker Willkür zu löschen.

Conny G. schrieb:
> unproduktiven Gestänkere

Klar. Die konsequente Nachfrage nach Sinn und Zweck kann manchmal schon 
sehr nerven. Nun schaun mer mal, ob von diesem Thread mehr als heiße 
Luft bleibt. Wie eine einfache Lösung in hochgradig abstrakten C++ 
controllerübergreifend vielfältige Hardwaredifferenzen überbrücken soll 
wird hier bestimmt bald aufgedeckt! Ich warte ab und bin gespannt!

von 900ss (900ss)


Lesenswert?

Moby schrieb:
> Chris D. schrieb:
>> trivial aussehende Probleme eben nicht trivial sind
>
> ... denn die von Peter D. skizzierten Problemchen SIND u.a. in Asm
> trivial zu lösen.

Im Threadtitel fragt er, wie er das in C++ lösen kann, nicht in ASM 
oder?

>
> Chris D. schrieb:
>> das ist
>> Kindergartenniveau:
>
> Richtig Herr Moderator. Nämlich inhaltlich mißliebige Beiträge in
> blanker Willkür zu löschen.

Deine Beiträge nerven und gehen am Thema vollständig vorbei. Es geht 
nicht darum, ob ASM oder C++ besser ist, sondern wie das in C++ geht.

>
> Conny G. schrieb:
>> unproduktiven Gestänkere

Da kann ich nur beipflichten.

>
> Klar. Die konsequente Nachfrage nach Sinn und Zweck kann manchmal schon
> sehr nerven. Nun schaun mer mal, ob von diesem Thread mehr als heiße
> Luft bleibt. Wie eine einfache Lösung in hochgradig abstrakten C++
> controllerübergreifend vielfältige Hardwaredifferenzen überbrücken soll
> wird hier bestimmt bald aufgedeckt! Ich warte ab und bin gespannt!

Solange du das nicht in ASM vorweisen kannst, ist deine Kritik irgendwie 
unangebracht. Es geht hier auch nicht um ASM.

Und ehrlich gesagt glänzt du vollständig durch Inkompetenz.

Und bitte halte dich raus. Wenn es dir nicht paßt, dass hier C++ 
verwendet werden soll, dann halt doch einfach die Finger still oder hast 
du im Ernst den Eindruck, dass deine Texte hier jemand lesen möchte?

DANKE.

900ss

von Chris D. (myfairtux) (Moderator) Benutzerseite


Lesenswert?

Moby schrieb:
> ... denn die von Peter D. skizzierten Problemchen SIND u.a. in Asm
> trivial zu lösen.

Es geht hier aber nicht um Assembler, sondern um C++.
Ist das so schwer zu verstehen?

> Chris D. schrieb:
>> das ist
>> Kindergartenniveau:
>
> Richtig Herr Moderator. Nämlich inhaltlich mißliebige Beiträge in
> blanker Willkür zu löschen.

Ersetze "mißliebig" durch "permanent offtopic", dann passt es exakt.

> Ich warte ab und bin gespannt!

Dein Wort in Gottes Ohr. Ich glaube ja nicht dran.

von TriHexagon (Gast)


Lesenswert?

TriHexagon schrieb:
> Moby AVR schrieb im Beitrag #3982637:
>> Wozu Kosten und Einstiegshürden steigern wenn kein Nutzen erkennbar?"
>
> Weil du keinen Nutzen siehst, gibt es keinen? Sag mal erleuchteter Moby
> welche Erfahrungen kannst du den mit C und C++ vorweisen, dass du das
> beurteilen kannst? Bin ja mal gespannt.

Die Frage hast du mir immer noch nicht beantwortet.

Moby schrieb:
> Chris D. schrieb:
>> trivial aussehende Probleme eben nicht trivial sind
>
> ... denn die von Peter D. skizzierten Problemchen SIND u.a. in Asm
> trivial zu lösen.

Dann zeig doch mal.

Moby schrieb:
> Chris D. schrieb:
>> das ist
>> Kindergartenniveau:
>
> Richtig Herr Moderator. Nämlich inhaltlich mißliebige Beiträge in
> blanker Willkür zu löschen.

Ich verstehe immer noch nicht was du hier willst. Mit deinem getrolle 
störst du diese Diskussion, insofern ist es die Pflicht eines 
Moderators, deinen Müll zu entsorgen.

von DualZähler (Gast)


Lesenswert?

Moin,

Ihr habt ja jetzt viel geredet, wo gibt es denn eine 
Referenz-Implementierung von den ganzen Vorschlägen, die hier genannt 
wurden?

Hat da jemand schon ein GitHub/BitBucket/Sourceforge Repository 
angelegt, wo man die ganzen Ideen mal sammeln und kompilieren kann?

Dann könnte man sich nämlich einfach mal den vom C++-Compiler 
generierten ASM anschauen, und dann entscheiden, ob es da überhaupt 
Overhead gibt und wenn ja, ob er bzgl. der gewonnenen Abstraktion 
vertretbar ist.

Den Erkenntnisgewinn könnte man ja dann auch mal dokumentieren, sodass 
man dann darauf aufbauend sinnvolle Entscheidungen treffen könnte.

Grüße,
DualZähler

von spess53 (Gast)


Lesenswert?

Hi

>Hast Du auch Konstruktives zur Fragestellung des OPs beizutragen,
>nämlich Vorschläge zur Implementierung in C++, beizutragen?

Peter hatte eine einfache Frage gestellt. Da aber nicht wirklich etwas 
gekommen ist hat er sich schon seit Ende November nicht mehr beteiligt. 
Warum wohl? Es war, im Sinne des OT, nie nach einer Platform 
übergreifenden Lösung gefragt. Also haben hier fast alle nicht zur 
Fragestellung des OPs beigetragen. War eher eine Art der 
Selbstbeweiräucherung.

MfG Spess

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

spess53 schrieb:
> Peter hatte eine einfache Frage gestellt. Da aber nicht wirklich etwas
> gekommen ist hat er sich schon seit Ende November nicht mehr beteiligt.
> Warum wohl? Es war, im Sinne des OT, nie nach einer Platform
> übergreifenden Lösung gefragt.

Das stimmt. Ausserdem halte ich eine "plattformübergreifende Lösung" für 
ein Unterfangen, dass sehr viel Arbeit bedeutet, bei dem das Ziel in so 
weiter Ferne liegt, dass - wenn eine Lösung denn irgendwann existieren 
sollte - die Hardware dafür dann gar nicht mehr existieren wird.

Kurz: ich halte diesen Anspruch für ein Fass ohne Boden.

Die Arduinos haben sich auf wenige ausgesuchte Hardware konzentriert. 
Und schon da musste man auf Kosten von Effizienz Abstriche machen. Was 
hier aber besprochen wurde, geht viel weiter... und hat mit Peters 
einfachen Frage wirklich nichts mehr zu tun.

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Karl Käfer schrieb:
> Die Arduino-Entwickler haben überall Sicherheitsnetze eingebaut und
> versuchen da, jeden irgendwie denkbaren und undenkbaren Fehler
> abzufangen.

Und das machen sie teilweise zur Laufzeit. :-(

Wenn möglich, sollte ja schon zur Entwurfszeit sicher sein, dass bei 
einem illegalen Code möglichst der Compiler oder wenigstens der Linker 
meckert ("fundamental design goal: design violations should not 
compile"^^).

Um zum Ursprung zurück zu kommen:

Eine Lösung mit new(); (also dynamic memory) wollen wir PeDa sicher 
nicht empfehlen. Ich habe aber keine Idee, wie man folgende "design 
violation" ohne Konstruktor und ohne Laufzeit-Prüfungen geschickter 
absichern könnte:

http://xpcc.io/api/group__gpio.html#details sagt:
> When you use the pins directly outside any device driver class you have
> to remember to initialize them first. Call configure(), setInput() or
> setOutput() before the first use, otherwise the result is undefined and
> most likely not what you expect!

Können wir behaupten "das geht auch gar nicht" oder habe ich was 
übersehen?

: Bearbeitet durch User
von frischling (Gast)


Lesenswert?

Hallo Thorsten,

ich verstehe nicht wo jetzt das new() herkommt.
Objekte kann man doch auch statisch anlegen.

Auch hier wird ein/einer der CTors/DTors ausgefühert,
entweder implizit (z.b. der StandardKonstruktor) oder explizit.
1
class MyObject
2
{
3
   // MyStuff
4
   MyObject (Paramter, liste);
5
}
6
7
MyObject obj1(Parameter des CTor);

Kannst Du mir erklären wo ich gerade hänge ?

von Scelumbro (Gast)


Lesenswert?

Es gibt ja seit C++11 static_assert mit der man einiges zur Compilezeit 
überprüfen kann. Dazu constexpr funktionen um den Compiler Sachen 
berechnen zu lassen. Zusammen mit Templates (die Arduino leider , aber 
verständlicherweise nicht nutzt) kann man sehr viel festlegen und 
überprüfen bevor ausführbarer Code entsteht.

von Hans-Georg L. (h-g-l)


Lesenswert?

Torsten C. schrieb:
>
> Eine Lösung mit new(); (also dynamic memory) wollen wir PeDa sicher
> nicht empfehlen. Ich habe aber keine Idee, wie man folgende "design
> violation" ohne Konstruktor und ohne Laufzeit-Prüfungen geschickter
> absichern könnte:
>
> http://xpcc.io/api/group__gpio.html#details sagt:
>> When you use the pins directly outside any device driver class you have
>> to remember to initialize them first. Call configure(), setInput() or
>> setOutput() before the first use, otherwise the result is undefined and
>> most likely not what you expect!
>
> Können wir behaupten "das geht auch gar nicht" oder habe ich was
> übersehen?

Hallo Thorsten,

du kannst nicht verhindern, das jemand code dazu linkt, der nativ direkt 
auf die Register zugreift und sie verändert. Du kannst auch nicht 
verhindern, das jemand deinen Pin Ausgangspegel mit eine Strippe 
verändert.

Der moderne (c++11) Compiler hat die Fähigkeit zu erkennen was während 
der Compilierzeit konstant ist und zu optimieren und das nutzt man ganz 
gezielt aus. Du musst unterscheiden was "lebt" nur während der 
Compilierzeit und was landet im object File, wird gelinkt, und während 
der Laufzeit ausgeführt. Während der Compilierzeit gibt es keine Objekte 
oder Variable nur Konstante.

Ich habe auch immer gedacht ich kann C++ und was soll das alles mit dem 
C++11 das brauch ich doch nie aber genau hier für die Embedded 
Programmierung kann man es sehr gut gebrauchen. Der Nachteil ist, es ist 
nicht leicht verständlich und für Anfänger in C++ völlig ungeeignet. Die 
Compiler Fehlermeldungen sind alles andere als verständlich und debuggen 
im single-step lässt sich das erst recht nicht.

Hier wir so oft geschrieben, ich programmiere in Assembler weil ich 
verstehen will was mein MC genau macht. Ich programmiere mit 
Meta-Templates weil ich verstehen will, was mein Compiler genau macht. 
Naja, ich versuchs halt und lerne täglich dazu ;)

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

frischling schrieb:
> Kannst Du mir erklären wo ich gerade hänge?

Ja, Objekte kann man statisch anlegen und dabei gleich initialisieren.

❶ Zu dem Fehler ("vergessen von configure()…"):

Man sollte für GPIO-OUTPUT also einen ctor (constructor) mit "direction" 
als Parameter erstellen und keinen ctor ohne Parameter, um den Fehler 
auszuschließen, Richtig?

Oder gibt es vielleicht einen Grund, warum die das nicht so gemacht 
haben?

❷ Das Port-Register z.B. soll ja als const definiert sein, damit zur 
Entwurfszeit schon alle Werte feststehen, und C++ nicht langsamer wird 
als C.

Oder gerade ich hänge irgendwo?

Und das geht in einem ctor m.E. nicht. Sonst meldet
der Compiler:
> Der Ausdruck muss ein änderbarer lvalue sein.
> L-Wert gibt ein const-Objekt an

Ich komme aus der Java und C#-Welt und blicke da noch nicht ganz durch.

Scelumbro schrieb:
> Es gibt ja seit C++11 static_assert mit der man einiges zur Compilezeit
> überprüfen kann. Dazu constexpr funktionen …

Danke für den Hinweis. :-) Schaue ich mir an!

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Hans-Georg Lehnard schrieb:
> Ich habe auch immer gedacht ich kann C++ und was soll das alles mit dem
> C++11 das brauch ich doch nie aber genau hier für die Embedded
> Programmierung kann man es sehr gut gebrauchen. Der Nachteil ist, es ist
> nicht leicht verständlich und für Anfänger in C++ völlig ungeeignet.

OK, dann muss mal geklärt werden, wie wir hier "C++ auf einem MC, wie 
geht das?" beantworten: Ist C++11 gefragt oder nicht?

Eben deshalb, weil man C++11 für die Embedded Programmierung sehr gut 
gebrauchen kann, hätte ich kein Intersse an Lösungen ohne "11".

Lieber versuche ich es mit "11" und muss dann halt auch noch viel dazu 
lernen.

PS: Cooles Tutorial:

http://www.codeproject.com/Articles/257589/An-Idiots-Guide-to-Cplusplus-Templates-Part

: Bearbeitet durch User
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Torsten C. schrieb:
> Ich komme aus der Java und C#-Welt und blicke da noch nicht ganz durch.

Generic Methods (vergleichbar mit C++-Templates) gibts auch in Java ;-)

von Hans-Georg L. (h-g-l)


Lesenswert?

Torsten C. schrieb:
>
> OK, dann muss mal geklärt werden, wie wir hier "C++ auf einem MC, wie
> geht das?" beantworten: Ist C++11 gefragt oder nicht?
>
Hallo Thorsten,

Ich habe nicht geschrieben das es "nur" in C++11 geht es geht auch mit 
früheren Versionen ! Nur werden mit der 11er ein paar Sachen einfacher.

Du hast wie Scelumbro schon schrieb die static_assert und vor allen 
Dingen varadic templates. Dazu noch auto , constexpr usw ...

Du kannst dir nicht einfach isoliert ein paar Goodies herauspicken, 
sondern du musst verstehen: wann, wie und warum man code auf die 
Compilezeit verschieben kann und er zu Laufzeit nicht mehr auftaucht, 
sondern vom Compiler durch Konstanten ersetzt wurde.

von Scelumbro (Gast)


Lesenswert?

Torsten C. schrieb im Beitrag #3985508:
> Genau das ist es. Bis auf das "Warum" ist das auch ziemlich klar.
>
> Peter L. schrieb:template <int pin>
> struct pb{
>     void set(){
>         ptr = (int*)0xDEADBEEF + pin;
>         *ptr = 0x1;
>     }
> };
> pb<1337> a;
> a.set();> Sowas ist erlaubt.
>
> Aber ptr* sollte doch zur Compilezeit bereits feststehen. Ich habe noch
> nicht kapiert, wie das geht.

Im Idealfall wird der ganze code doch noch geinlinet und ist dann nicht 
kaum mehr als als ein einzige Assemblerinstruktion, die an die Adresse 
0xDEADBEEF+1337 die Zahl 0x1 schreibt. In C++ würde man wohl statt 
(int*)0xDEADBEEF + pin ein reinterpret_cast<int *>(0xDEADBEEF + pin); 
stehen.

von eKiwi (Gast)


Lesenswert?

Torsten C. schrieb:
> Man sollte für GPIO-OUTPUT also einen ctor (constructor) mit "direction"
> als Parameter erstellen und keinen ctor ohne Parameter, um den Fehler
> auszuschließen, Richtig?
>
> Oder gibt es vielleicht einen Grund, warum die das nicht so gemacht
> haben?

Also in xpcc erstellt man keine Instanz um einen Gpio benutzen zu 
können. Stattdessen wird sichergestellt, dass alle Pins, die beim 
benutzten Controller verfügbar sind, als Klassen mit rein statischen 
Methoden zur Verfügung stehen.[0] Daher gibt es auch keinen Konstruktor.

Die Entscheidung gegen Instanzen kommt daher, dass es mit Instanzen 
nicht so einfach ist, zu sehen, was der Compiler inlinen kann und was 
nicht. Statische Methoden verhalten sich dagegen fast wie C Funktionen.

Ausserdem macht die Entscheidung für statische Klassen den Einsatz von 
Compilezeit Polimorphismus einfach.[1] Es ist nämlich nicht trivial 
(oder vielleicht sogar unmöglich) einem Template eine Instanz zu 
übergeben. Sehrwohl ist es aber bei Templates vorgesehen Klassen zu 
übergeben.

Wenn nun also für jeden Gpio eine Instanz erstellt wird, dann wäre der 
"normale" Ansatz eine Gpio Basisklasse mit als "virtual" deklarierten 
Funktionen anzulegen z.B.:
1
class
2
AbstractGpio
3
{
4
public:
5
  virtual void set()=0;
6
  virtual void reset()=0;
7
  virtual bool read()=0;
8
}
9
10
class
11
GpioA0 : public AbstractGpio
12
{
13
public:
14
  GpioA0(...) { ... }
15
16
  void set()   { GPIOA->BSRRL = (1<<0); }
17
  void reset() { GPIOA->BSRRH = (1<<0); }
18
  bool read()  { return GPIOA->IDR & (1<<0); }
19
}


Dann kann man einer Klasse, welche Pins benutzen muss, Pointer auf 
AbstractGpio Instanzen übergeben und darüber die Pins ansprechen. Also 
der Standard Laufzeitpolymorphismus.
1
class
2
SopftwareI2C
3
{
4
  SopftwareI2C(AbstractGpio* Scl, AbstractGpio* Sda, ...) {...}
5
}
6
7
SopftwareI2C i2c(&gpioA0Instance, &gpioA1Instance);

Hierbei wird aber jegliches Inlinen durch den Compiler verhindert (denn 
die Bindung Pin zu Klasse findet ja erst zur Laufzeit statt) und 
ausserdem v-tables erzeugt. D.h. es gib einen Overhead.

Dieser wird durch den oben erwähnten Compilezeit Polymorphismus 
verhindert. Mit dem Nachteil, dass beim Compilezeit Polymorphismus nur 
statische Konstrukte unterstützt werden. Mit einer 
Laufzeitpolymorphismus Lösung kann man dagegen die Pins während der 
Laufzeit wechseln.
1
i2c.setScl(&gpioB0Instance);

Das ist nichts was man normalerweise auf einem Mikrocontroller machen 
möchte, aber doch ein Feature, dass manche User, die von der PC 
Programmierung her kommen erwarten und das z.B. bei Arduino mit der 
Adressierung von Pins über Integer realisiert wird.

eKiwi

PS: Natürlich kann man, statt für jeden Gpio eine eigene Klasse 
anzulegen, das ganze, wie weiter oben in diesem Thread schon erwähnt 
wurde, mit Hilfe von Template lösen. Ich habe das aber hier nicht 
beachtet, damit die Beispiele einfacher werden. Nur weil xpcc die Gpio 
Klassen mit jinja2 Templates erzeugt, heist das nicht, dass es der beste 
Weg ist. C++ Templates haben unter anderem den Vorteil, dass sie keine 
grossen Anforderungen an die Buildumgebung stellen.



[0]
Für diejenigen, die es interessiert ein paar Details am Beispiel des 
stm32f407vg:
1. Für unsere unterstützten Controller gibt es eine XML Beschreibung 
z.B.: 
https://github.com/roboterclubaachen/xpcc/blob/develop/src/xpcc/architecture/platform/devices/stm32/stm32f405_407_415_417-i_r_v_z-e_g.xml
2. Mit deren Hilfe werden für jeden verfügbaren (also auch gebondeten) 
Pin drei Klassen erzeugt: z.B. GpioA0, GpioOutputA0, GpioInputA0
Das Headerfiletemplate (jinja2) dazu sieht so aus: 
https://github.com/roboterclubaachen/xpcc/blob/develop/src/xpcc/architecture/platform/driver/gpio/stm32/gpio.hpp.in

[1]
Als Beispiel eignet sich unser Software I2C Treiber: 
https://github.com/roboterclubaachen/xpcc/blob/develop/src/xpcc/architecture/platform/driver/i2c/generic/i2c_master.hpp

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

@Scelumbro: Habe ich zu spät gemerkt, sorry, danke.

Es zwei da zwei unterschiedliche Ansätze.

Bei dem Code von Peter L. kommt "kaum mehr als als ein einzige 
Assemblerinstruktion"^^ raus, wenn set() als "inline" optimiert wird. Ob 
es was bringen würde, set() in die .h als "inline set() {… zu schreiben, 
ist ein separates Thema, kommt später!

^^ Das wäre der eine Ansatz.

Aber es gibt sicherlich auch komplexere Funktionen, die für die 
Beantwortung der Ausgangfrage erforderlich sind, bei denen "inline" wohl 
keinen Sinn mehr macht:
1
LED2.on = KEY2.press_long;   // lang drücken - an

Hier gibt es ja z.B. kein
1
KEY2.setLongPressTime();

Als ich eben schrieb: "Das Port-Register z.B. soll ja als const 
definiert sein", hatte ich ein schlechtes Beispiel. Vielleicht ist die 
LongPressTime ein besseres.

Angenommen, die longPressTime soll zur Compilezeit bereits feststehen.

Die "longPressTime "sollte in diesem Fall doch im ROM stehen, oder?

Würde man dem OP für 3 Tasten mit unterschiedlichen Zeiten (5s/6s/7s) 
empfehlen, dass er per Template 3 verschiedene Klassen erzeugt, also:
1
LPKey<5,1337> key1;
2
LPKey<6,1338> key2;
3
LPKey<7,1339> key3;

Und der Timer, der jeweils benutzt werden soll, muss ja auch 
parametrierbar sein, also => ein weiterer Template-Parameter. Wer weiss, 
was noch alles dazu kommt!

Das gibt einen Haufen Templates für Karl den Käfer ;-)

Irgendwann kommt man an den Punkt, wo man einen Parameter gern als 
Objekt-Eigenschaft definieren würde

Als const (so, wie oben):…
1
MyObject obj1(Parameter des CTor);
… geht das aber nicht, und damit steht die Zahl dann im RAM und wird zur 
Laufzeit ständig dynamisch ausgelesen, wenn man sich nicht auf die 
Compiler-Optimierung verlassen will.

Aber vielleicht machen const Eigenschaften auch keinen Sinn und man muss 
- wenn man den Parameter nicht als Template-Parameter übergibt - halt 
damit leben, dass der Parameter zur Laufzeit bei jedem Funktionsaufruf 
ausgewertet wird.

Frank M. schrieb:
> Generic Methods (vergleichbar mit C++-Templates) gibts auch in Java ;-)

Das war anders gemeint: Wenn z.B. die "LongPressTime" zur Compilezeit 
bereits fest steht, ist ein setLongPressTime() kontraproduktiv. In Java 
habe ich mir über "ROMable" nie Gedanken gemacht, das ist da auch 
unüblich und das Thema ist für mich Neuland.

von eKiwi (Gast)


Lesenswert?

Torsten C. schrieb:
> Man sollte für GPIO-OUTPUT also einen ctor (constructor) mit "direction"
> als Parameter erstellen und keinen ctor ohne Parameter, um den Fehler
> auszuschließen, Richtig?

Dazu ist mir noch ein Problem, unabhängig von Instanz/Klasse etc. 
eingefallen:
Falls ihr die Gpios alle statisch Instanzieren wollt wie hier:

frischling schrieb:
> class MyObject
> {
>    // MyStuff
>    MyObject (Paramter, liste);
> }
>
> MyObject obj1(Parameter des CTor);

Dann ist nicht immer garantiert in welcher Reihenfolge die CTors 
aufgerufen werden. (in einer compile unit mit gcc so weit ich weis 
schon, aber sobald das mehr als ein .cpp file wird, wird es 
komplizierter)

Das kann zu ungewollten "glitches" führen, falls der eine Pin zu frueh 
nach Masse oder VCC zieht, obwohl man eigentlich erst noch etwas anderes 
initialisieren muss.

von Hans-Georg L. (h-g-l)


Lesenswert?

> Peter L. schrieb:template <int pin>
> struct pb{
>     void set(){
>         ptr = (int*)0xDEADBEEF + pin;
>         *ptr = 0x1;
>     }
> };
> pb<1337> a;
> a.set();> Sowas ist erlaubt.



Ein ziemlich ungeschicktes Beispiel ...

Das Template ist überflüssig, du kannst Pin gleich als Parameter 
übergeben.

Und warum eine Speicheradresse erst als pointer definieren dann 
dereferenzieren ...

Und wenn nicht irgendwo im Programm später mal auf diese Addresse lesend 
zugegriffen wird, was z.B bei DDR-Degister oft der Fall ist, optimiert 
der Compiler alles weg, weil volatile fehlt.

: Bearbeitet durch User
von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Hallo eKiwi, Deine Antwort sehe ich erst jetzt, sehr gute Erklärung! :-)

eKiwi schrieb:
> Wenn nun also für jeden Gpio eine Instanz erstellt wird, dann wäre der
> "normale" Ansatz eine Gpio Basisklasse mit als "virtual" deklarierten
> Funktionen anzulegen

Beim GPIO habe ich ein blödes Beispiel gewählt. Die longPressTime ist 
hoffentlich besser:

Warum virtual? Da sitzt genau mein Klemmer:

Wenn sich nur die Daten unterscheiden, aber die Funktionen immer gleich 
sind, müssen die Funktionen doch nicht virtuell sein.

Trotzdem sollen die Daten im ROM liegen. Wahrscheinlich ist das ganz 
einfach und ich habe Tomaten auf den Augen.

eKiwi schrieb:
> Natürlich kann man, statt für jeden Gpio eine eigene Klasse
> anzulegen, das ganze, wie weiter oben in diesem Thread schon erwähnt
> wurde, mit Hilfe von Template lösen.

So "Natürlich" war das bis eben für mich nicht, aber dann scheint das 
wohl der einzige gangbare Weg für "enbedded" zu sein, um "vergessen von 
configure()…"^^ usw. zur Compilezeit zu detektieren.

: Bearbeitet durch User
von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Hans-Georg Lehnard schrieb:
> Das Template ist überflüssig, du kannst Pin gleich als Parameter
> übergeben.

Als Parameter an wen? Aktuell als Parameter an das Template. Das ist bis 
auf vergessene volatile und den Umweg über ptr* doch ganz nett für 
inline.

Meinst Du vielleicht als Parameter an einen constructor (ctor)? Dann 
wären wir wieder bei einer Instanz (also nicht static). Wäre der ptr 
dann noch ROMable? Ich wüsste nicht, wie.

: Bearbeitet durch User
von Scelumbro (Gast)


Lesenswert?

Torsten C. schrieb:
> Als const (so, wie oben):…MyObject obj1(Parameter des CTor);… geht das
> aber nicht, und damit steht die Zahl dann im RAM und wird zur
> Laufzeit ständig dynamisch ausgelesen, wenn man sich nicht auf die
> Compiler-Optimierung verlassen will.

Vielleicht habe ich das falsch verstanden, aber es gibt ja auch 
constexpr constructoren.

Torsten C. schrieb:
> [...] wenn man sich nicht auf die
> Compiler-Optimierung verlassen will.

In diesem Fällen hilft man dem Compiler zwar mit const/constexpr und 
template Geschichten auf die Sprünge. Aber letztendlich haben zumindest 
die GCC Programmierer auch schon ganze Arbeit geleistet, nicht unnötig 
Konstanten aus dem RAM zu holen. Wenn du ihnen nicht traust, dann schau 
mal ins lss. Ich war bei meinen template experimenten mit dem AVR-GCC 
auch immer wieder erstaunt zu was komplexe konstruktionen dann 
letztendlich zusammenschrumpfen.

Torsten C. schrieb:
> Und der Timer, der jeweils benutzt werden soll, muss ja auch
> parametrierbar sein, also => ein weiterer Template-Parameter. Wer weiss,
> was noch alles dazu kommt!

Du kannst ja für die Timer eine eigene Klasse anlegen.

Zusätzlich gibt es ja noch Sachen wie using mit der man durch Aliase in 
das entstehende Chaos aus eckigen Klammern wieder Ruhe bringen kann.

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Torsten C. schrieb:
> Hallo eKiwi, Deine Antwort sehe ich erst jetzt

PS: Ich willte damut sagen: Ich hatte inzwischen den Beitrag mit 
"longPressTime" geschrieben, der ging über Kreuz. Gesehen?

Scelumbro schrieb:
> aber es gibt ja auch constexpr constructoren

Ups, ja. Hatte ich vorhin gelesen, kannte ich vorher nicht, muss ich mir 
anschauen und geht nur in C++11. Letzteres wäre für mich -wie gesagt - 
OK.

Scelumbro schrieb:
> Du kannst ja für die Timer eine eigene Klasse anlegen.

OK, wenn der Compiler merkt, dass die zu verwendende Timer-Instanz zur 
Compilezeit bereits feststeht (constexpr??), könnte man das tun. Ob ich 
verstanden habe, wie man das programmiert, weiss ich erst, wenn ich es 
ausprobiert habe.

Scelumbro schrieb:
> Zusätzlich gibt es ja noch Sachen wie using

Auch ein guter Tipp. Danke. :-)

: Bearbeitet durch User
von eKiwi (Gast)


Lesenswert?

Torsten C. schrieb:
> Beim GPIO habe ich ein blödes Beispiel gewählt. Die longPressTime ist
> hoffentlich besser:

Naja, das ganze sind doch erst einmal verschiedene Baustellen:

Bei den Gpios will man für jeden eine eigene Klasse haben, da eben nicht 
die Daten sondern der zu erzeugende Code unterschiedlich ist.

Also zumindest wenn man das so wie oben z.B. von Micha erwähnt wurde 
macht. Das hat den Vorteil, dass eine Instanz der Klasse keine Daten 
enthält und daher praktisch eine Grösse von 0 hat.

Micha schrieb:
> @ Karl Käfer
> Um deinen Vergleich noch anzusprechen: ich persönlich
> findeDigitalOutput<PORT_B,P4> beleuchtung;
> DigitalInput<PORT_B,P0> startknopf;

Zugegeben hatte ich die Loesung von Karl vergessen:
Karl Käfer schrieb:
> #include <avr/io.h>
>
> class Pin {
> public:
>     volatile uint8_t* ddr;
>     volatile uint8_t* port;
>     volatile uint8_t* pin;
>     uint8_t num;
>
>     Pin(volatile uint8_t* ddr, volatile uint8_t* port,
>         volatile uint8_t* pin, uint8_t num):
>         ddr(ddr), port(port), pin(pin), num(num)
>     {}
> };
>
> class InputPin : public Pin {
> public:
>     InputPin(volatile uint8_t* ddr, volatile uint8_t* port,
>        volatile uint8_t* pin, uint8_t num):
>         Pin(ddr, port, pin, num) {
>         *this->ddr &= ~(1 << this->num);
>     }
>     int isHigh(void) { return (*this->pin & (1 << this->num)); };
>     int isLow(void) { return !((*this->pin & (1 << this->num))); };
> };
>
> class OutputPin : public Pin {
> public:
>     OutputPin(volatile uint8_t* ddr, volatile uint8_t* port,
>        volatile uint8_t* pin, uint8_t num):
>         Pin(ddr, port, pin, num) {
>         *this->ddr |= (1 << this->num);
>     }
>     void setHigh(void) { *this->port |= (1 << this->num); };
>     void setLow(void)  { *this->port &= ~(1 << this->num); };
>     void operator=(bool const &parm) {
>       if(parm) { this->setHigh(); }
>       else     { this->setLow(); }
>     }
> };
>
> int main(void) {
>
>     OutputPin ledPin (&DDRD, &PORTD, &PIND, PD0);
>     InputPin  btnPin (&DDRB, &PORTB, &PINB, PB0);
>
>     while(1) {
>         //...
>         ledPin.setHigh();
>         ledPin.setLow();
>         ledPin = btnPin.isHigh();
>     }
> }

Hier hast du wirklich eine Pin Klasse, bei der die Instanzen jeweils 
andere Daten erhalten. Hierauf treffen dann meine oben gemachten 
Kommentare nicht ganz zu. Mich würde aber noch interessieren wie weit 
man das ganze treiben kann, bis der Compiler Speicherplatz für ddr, 
port, pin und num anlegt. An sich aber auf jeden Fall ein interessanter 
Ansatz.

> Warum virtual? Da sitzt genau mein Klemmer:
>
> Wenn sich nur die Daten unterscheiden, aber die Funktionen immer gleich
> sind, müssen die Funktionen doch nicht virtuell sein.

Genau. Aber spätestens wenn du eine Funktion hast, die nicht direkt 
einen Pointer auf einen Pin benutzt, sondern einen Pointer, der ein 
Member der Klasse, zu der diese Methode gehört, ist, dann wird - nach 
meinem Verständnis - doch Speicher für die Datenmember des Pins angelegt 
werden muessen, da zur Compilezeit nicht bekannt ist, welcher Pin genau 
angesprochen wird.

z.B.
1
class
2
SoftwareI2C
3
{
4
public:
5
  SoftwareI2C(Pin* Scl, Pin* Sda) : scl(Scl), sda(Sda) {}
6
7
  void run()
8
  {
9
    // hier ist voraussichtlich zur Compilezeit nicht bekannt,
10
    // welcher pin das ist, also kann das nicht in einen simplen
11
    // ASM Befehl übersetzt werden
12
    // wahrscheinlich wird das eine function call an die Pin::set
13
    // Methode mit der Adresse in this->scl als Argument erzeugen
14
    // wobei in dieser Methode dann aus den Daten an dieser Adresse
15
    // das Register berechnet wird
16
    // an dieser Stelle sollte man sich aber wohl wirklich
17
    // mal den ASM Code ansehen
18
    // vielleicht habt ihr ja etwas cooles gefunden und das
19
    // ganze wird wegoptimiert (da gcc schlauer ist als ich denke)
20
    this->scl->set();
21
  }
22
23
private:
24
  Pin* scl;
25
  Pin* sda;
26
27
}


> Trotzdem sollen die Daten im ROM liegen. Wahrscheinlich ist das ganz
> einfach und ich habe Tomaten auf den Augen.

Dazu kann ich die bereits oben zitierten Folien empfehlen, dort steht 
ganz gut, wann etwas ins ROM kommt und wann nicht: 
http://aristeia.com/TalkNotes/C++_Embedded_Deutsch.pdf

von Ralf G. (ralg)


Lesenswert?

eKiwi schrieb:
> Mich würde aber noch interessieren wie weit
> man das ganze treiben kann, bis der Compiler Speicherplatz für ddr,
> port, pin und num anlegt.
... sobald man die Ports/ Pins 'richtig' verwenden will. Z.B. in einer 
LCD-Klasse, die Funktionen für die Ausgabe enthält und der man dann so 
ein paar Port-/ Pinobjekte übergibt. Dann hat sich's auch mit den 
schnellen IO-Zugriffen erledigt.
> An sich aber auf jeden Fall ein interessanter Ansatz.
Besser ist das mit Templates, da sieht der Compiler alles. Ich habe 
allerdings noch keinen Einfall, wie man solche Objekte universell in 
andere Objekte einbinden kann (ohne diese <>-Klammerlisten).

von eKiwi (Gast)


Lesenswert?

Ralf G. schrieb:
> Besser ist das mit Templates, da sieht der Compiler alles.

Da muss ich dir zustimmen. Deshalb benutzt xpcc ja auch generierte 
Klassen für die Gpio Pins. Ich wollte jetzt nur einen neuen Ansatz nicht 
sofort ausschliessen.

Ralf G. schrieb:
> Ich habe
> allerdings noch keinen Einfall, wie man solche Objekte universell in
> andere Objekte einbinden kann (ohne diese <>-Klammerlisten).

Wenn man universelle Klassen schreiben möchte muss man sich dann, früher 
oder später zwischen Lauf- und Compilezeitpolymorphismus (aka das Ding 
mit den <>-Klammerlisten) entscheiden. Bei den Gpio Pins war es in xpcc 
unsere Designentscheidung das über einen Compilezeitpolymorphismus zu 
lösen, da das ansteuern von Pins möglichst ohne Overhead funktionieren 
sollte.
So kann niemand auf die Idee kommen dafür direkt in die Register zu 
schreiben. Dies ist leider bei viel zu vielen Arduino Libraries der 
Fall, die dadurch nicht portabel sind. Deshalb konnten sich imho die ARM 
basierenden Arduinos nie richtig durchsetzen.

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

@Scelumbro + Hans-Georg: Danke und sorry, ich habe jetzt endlich das 
faszinierende Kapitel zu constexpr gelesen:

http://www.cprogramming.com/c++11/c++11-compile-time-processing-with-constexpr.html

Torsten C. schrieb:
> Wäre der ptr  dann noch ROMable? Ich wüsste nicht, wie.

Nun weiss ich wie! Das geht per constexpr wunderbar. Ich hab's gerade 
mit avr GCC 4.7.2 probiert. Das löst meinen Knoten im Kopf! :-)

Alex Allain sagt dort:
> In fact, the only compiler version I know of that fully
> supports constexpr is GCC 4.7.

Hmmm, die Aussage ist doch hoffentlich schon etwas älter, oder?

eKiwi schrieb:
> Ralf G. schrieb:
>> Ich habe
>> allerdings noch keinen Einfall, wie man solche Objekte universell in
>> andere Objekte einbinden kann (ohne diese <>-Klammerlisten).
>
> Wenn man universelle Klassen schreiben möchte muss man sich dann, früher
> oder später zwischen Lauf- und Compilezeitpolymorphismus (aka das Ding
> mit den <>-Klammerlisten) entscheiden.

Mit constexpr ist m.E. auch die Variante von Karl Käfer ROMable. Zur 
Frage, ob der Compiler Speicherplatz für ddr, port, pin und num anlegt. 
Bei
1
const uint8_t num;
sicherlich nicht. Die Eigenschaften ddr, port und  pin kann man doch 
sicher auch const machen.

Nun habe ich nur noch ein Problem mit Instanzen statt Templates: Kann 
man irgendwie verhindern, dass ein Pin doppelt instanziiert wird? Ich 
kenne dafür nur Singletons. Sollte man versuchen, Singletons umzusetzen?

: Bearbeitet durch User
von Hans-Georg L. (h-g-l)


Lesenswert?

Ralf G. schrieb:
> eKiwi schrieb:
>> Mich würde aber noch interessieren wie weit
>> man das ganze treiben kann, bis der Compiler Speicherplatz für ddr,
>> port, pin und num anlegt.

Das brauch er nicht, weil es den Speicher dafür schon gibt, das sind die 
SFR Register und die sind fix im RAM.

Beispiel: PORTA P7 und PORTA P4
Der Compiler kennt natürlich das nicht, du musst ihm irgenwie sagen 
Register PORTA.ddr gibt es schon und das liegt an der Speicheradresse XX 
und P7 ist das bit7 in diesem Register.

Für PORTA P4 gibt es kein neues PORTA.ddr P4 liegt an der gleichen 
Adresse und ist nur ein anderes Bit.

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Hans-Georg Lehnard schrieb:
> weil es den Speicher dafür schon gibt

Aber nicht für "uint8_t num", aber da gingen unsere Beiträge über 
Kreuz^^, ist also auch kein Problem.

: Bearbeitet durch User
von Hans-Georg L. (h-g-l)


Lesenswert?

Torsten C. schrieb:
>
> Nun weiss ich wie! Das geht per constexpr wunderbar. Ich hab's gerade
> mit avr GCC 4.7.2 probiert. Das löst meinen Knoten im Kopf! :-)
>
> Alex Allain sagt dort:
>> In fact, the only compiler version I know of that fully
>> supports constexpr is GCC 4.7.
>
> Hmmm, die Aussage ist doch hoffentlich schon etwas älter, oder?
>

Der Aktuelle Compiler im Atmel bei mir (4.8.1) ist nicht 100% C++11 
kompatibel. Vor allen Dingen die C++11 Libs fehlen.

Bisher ist mir nur aufgefallen, das "auto" mit Vorsicht zu geniessen 
ist.


> Mit constexpr ist m.E. auch die Variante von Karl Käfer ROMable. Zur
> Frage, ob der Compiler Speicherplatz für ddr, port, pin und num anlegt.
> Bei
>
1
const uint8_t num;
> sicherlich nicht. Die Eigenschaften ddr, port und  pin kann man doch
> sicher auch const machen.

Nochmal: ddr, port, pin usw. müssen Ram Speicher haben sonst könnte man 
ja nichts ändern! Aber den gibt es schon im SFR Bereich vom Ram, du must 
es dem Compiler nur erzählen.

> Nun habe ich nur noch ein Problem mit Instanzen statt Templates:

Der Begriff Instanz ist hier mehrdeutig. Templates werden immer 
instanziiert, leben aber nur im (PC)Arbeitsspeicher vom (Cross)Compiler. 
Das was du meinst sind Objektinstanzen einer Klasse die während der 
Laufzeit im Speicher vom Target MC leben.

> Kann man irgendwie verhindern, dass ein Pin doppelt instanziiert wird?
Wenn die erste (template) Instanz für den Compiler konstant ist und die 
2. versucht diese Konstante zu überschreiben sollte er eine 
Fehlermeldung bringen. Hab ich aber noch nicht probiert.

 > Ich kenne dafür nur Singletons.
Ja, ja die kleine wunderbare Welt der Java Programmierer ;)
ich hatte mal das Verknügen meinen Java Kollegen Thread Synchronisierung 
bei zu bringen ... Braucht man doch bei Java alles nicht hör ich gerade 
...
Aber nur wenn alle Threads in der gleichen VM leben.

Ein Embedded Programierer würde dafür eher pro Port ein Byte reservieren 
und dort ein Bit für jeden belegten Pin setzen.

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Hans-Georg Lehnard schrieb:
> Das was du meinst sind Objektinstanzen einer Klasse die während der
> Laufzeit im Speicher vom Target MC leben.

Genau, aber mein Problem^^ ist, wie man bei dieser Art der Modellierung 
eine doppelte instanziierung vermeiden kann. Ansonsten finde ich den 
Ansatz von Karl Käfer erstmal optimal. Mal sehen, was die Praxis sagt.

Im o.g. Port-Beispiel ist das vielleicht nicht so schlimm. Aber zwei 
RingBuffer auf einen und den selben UART wären z.B. doof.

Hans-Georg Lehnard schrieb:
> Nochmal: ddr, port, pin usw. müssen Ram Speicher haben sonst könnte man
> ja nichts ändern!

Ach. Aber die Adressen (Zeiger!!) ddr, port und pin sollen doch konstant 
also ROMable sein und nicht im RAM liegen. Oder? Nix ändern können fände 
ich doof. ;-) :-p
1
volatile uint8_t* ddr;
2
volatile uint8_t* port;
3
volatile uint8_t* pin;

Warum eigentlich drei getrennte Pointer? Einen einzigen fände ich 
übersichtlicher.

Ich bin gerade mit dem UART am basteln, da reicht ein ein einziger 
USART_t*:
1
typedef struct {
2
    volatile uint8_t udr;
3
    union {
4
        volatile uint16_t word;
5
        struct {
6
            volatile uint8_t low;
7
            volatile uint8_t high;
8
        } byte;
9
    } ubrr;
10
    volatile uint8_t ucsrd;
11
    volatile uint8_t ucsrc;
12
    volatile uint8_t ucsrb;
13
    volatile uint8_t ucsra;
14
} USART_t;

: Bearbeitet durch User
von Hans-Georg L. (h-g-l)


Lesenswert?

Torsten C. schrieb:
>
> Ach. Aber die Adressen (Zeiger!!) ddr, port und pin sollen doch konstant
> also ROMable sein und nicht im RAM liegen. Oder?

Der Compiler macht aus dem ganzen Theather was du veranstaltest um ein 
Bit im Register zu setzen und um ihm das schonend beizubringen ganz 
schnöde den Assembler Befehl z.B. "sbi 0x17, 3" und das wars.

0x17 ist dein Zeiger und 3 ist der Pin aber direkt codiert in einem 
Assembler Befehl.

Look mam no pointer ;)

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Hans-Georg Lehnard schrieb:
> Der Compiler macht aus dem ganzen Theather was du veranstaltest um ein
> Bit im Register zu setzen und um ihm das schonend beizubringen ganz
> schnöde den Assembler Befehl z.B. "sbi 0x17, 3" und das wars.

Das wäre cool! :-) Aber welches Theater?

eKiwi schrieb:
1
class Pin {
2
    public:
3
    volatile uint8_t* ddr;
4
    volatile uint8_t* port;
5
    volatile uint8_t* pin;
6
    uint8_t num;
7
};

Also kann auch mal jemand schreiben, dass sich das während der Laufzeit 
ändert:
1
Pin ichbinmaldiesmaldas(ddr, port, pin, num);
2
ichbinmaldiesmaldas.port = &einanderer; // ???

Ich meine, die Pointer  müssen konstant sein, damit der Compiler da 
wirklich zuverlässig z.B. "sbi 0x17, 3" draus macht und nicht nur 
zufällig je nach Compiler-Optimizing-Level.

Aber vielleicht weiss es jemand besser? Ich lerne gern dazu!

Also, falls ein "const" nötig ist, ich musste gerade selber mal googeln:

Bradley Jones sagt:
1
const char *       myPtr = &char_A; // pointer to a constant character. You cannot use this pointer to change the value being pointed to
2
      char * const myPtr = &char_A; // constant pointer to a character. The location stored in the pointer cannot change
3
const char * const myPtr = &char_A; // pointer to a character where both the pointer value and the value being pointed at will not change.
http://www.codeguru.com/cpp/cpp/cpp_mfc/general/article.php/c6967/Constant-Pointers-and-Pointers-to-Constants.htm

Das vergesse ich immer wieder. :-(

Ich habe meinen uart gerade compiliert und zumindest hatte der Compiler 
nix zu meckern:
1
class Uart {
2
    private:
3
        static const int SFR_OFFSET = 0x20;
4
    public:
5
        enum UartPtr {
6
            Uart0 = SFR_OFFSET + 0x20, // statt #define UDR0 _SFR_IO8(0x20)
7
            Uart1 = SFR_OFFSET + 0x73  // statt #define UDR1 _SFR_IO8(0x73)
8
        };
9
        Uart(UartPtr UartPtr) : registers((USART_t *) UartPtr) {}
10
    private:
11
        USART_t * const registers;
12
};

: Bearbeitet durch User
von Ralf G. (ralg)


Lesenswert?

Torsten C. schrieb:
> Ich meine, die Pointer  müssen konstant sein, damit der Compiler da
> wirklich z.B. "sbi 0x17, 3" draus macht, aber vielleicht weiss es
> jemand besser? Ich lerne gern dazu!

- Die Pointer müssen nicht konstant sein!
- DDRx, PORTx, PINx sind keine Pointer
- man kann einen Zeiger darauf definieren
- wenn der Compiler die Chance hat zu erkennen, dass dieser Pointer 
immer nur auf eine Adresse zeigt, dann optimiert er das!
- Wenn ein Pointer auf verschiedene Objekte 'gestellt' wird, kann der 
Compiler selbstverständlich nicht optimieren, weil im 'sbi'-Befehl die 
Adresse direkt codiert ist.
- ...

: Bearbeitet durch User
von Hans-Georg L. (h-g-l)


Lesenswert?

Ralf G. schrieb:
> Torsten C. schrieb:
>> Ich meine, die Pointer  müssen konstant sein, damit der Compiler da
>> wirklich z.B. "sbi 0x17, 3" draus macht, aber vielleicht weiss es
>> jemand besser? Ich lerne gern dazu!
>
> - Die Pointer müssen nicht konstant sein!
> - DDRx, PORTx, PINx sind keine Pointer
> - man kann einen Zeiger darauf definieren
> - wenn der Compiler die Chance hat zu erkennen, dass dieser Pointer
> immer nur auf eine Adresse zeigt, dann optimiert er das!
> - Wenn ein Pointer auf verschiedene Objekte 'gestellt' wird, kann der
> Compiler selbstverständlich nicht optimieren, weil im 'sbi'-Befehl die
> Adresse direkt codiert ist.
> - ...

Das hat aber weniger mit Pointern zu tun, das liegt daran das sbi nur 
auf bit-addressable Speicherbereiche und nicht im gesammten 
adressierbaren Speicher funktioniert.

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Ralf G. schrieb:
> DDRx, PORTx, PINx sind keine Pointer

Und wozu ist der Stern in "public: volatile uint8_t* ddr;"^^?

Oder hast Du einen Vorschlag, wie man das ohne Pointer macht? Dann würde 
hier nicht so eine ellenlange Debatte entstehen.

Ralf G. schrieb:
> - wenn der Compiler die Chance hat zu erkennen, dass dieser Pointer
> immer nur auf eine Adresse zeigt, dann optimiert er das!

Das kann er aber m.E. nur bei "private". Selbst bei "protected" könnte 
in einem anderen .cpp noch eine abgeleitete Klasse sein, die die Adresse 
verändert. Dagegen würde "final" helfen.

Aber falls das auch ohne Pointer geht, wozu dann das ganze Theather?

Lieber Ralf und lieber Hans-Georg, dann posted doch bitte einfach eine 
Alternative zu dem Vorschlag von Karl Käfer.

Ralf G. schrieb:
> - wenn der Compiler die Chance hat zu erkennen, dass dieser Pointer
> immer nur auf eine Adresse zeigt, dann optimiert er das!

Ich habe gelesen, dass das von Compiler zu Compiler unterschiedlich ist. 
Es mag sein, dass das nicht stimmt. Was stört Dich daran, das mit 
"const" bzw. "constexpr" abzusichern?

: Bearbeitet durch User
von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Torsten C. schrieb:
> eKiwi schrieb:class Pin {
>     public:
>     volatile uint8_t* ddr; …

PS: Da habe ich eine Zeile verschluckt. Den Vorschlag hat zwar eKiwi 
zitiert, aber er kommt von Karl Käfer aus Beitrag #3902529. Sorry.

Vorteil des Vorschlags:

 * Ohne diese <>-Klammerlisten^^

: Bearbeitet durch User
von Hans-Georg L. (h-g-l)


Lesenswert?

Torsten C. schrieb:
> Also kann auch mal jemand schreiben, dass sich das während der Laufzeit
> ändert:
>
1
Pin ichbinmaldiesmaldas(ddr, port, pin, num);
2
> ichbinmaldiesmaldas.port = &einanderer; // ???
>

Prinipiell hast du recht und das musst du verhindern. C++ erzeugt bei 
Klassen automatisch einen Copy Constructor und einen Destructor.
Die beiden sollte man "leer" überschreiben und als privat deklarieren 
dann ist das sicher.

Und vergiss nicht von allem was C++ kann ist nur ein Teil für die 
embedded Programmierung geeignet sonst hast du deinen mühsam gespaarten 
Speicher schnell, durch eine lib die automatisch dazugelinkt wird, 
wieder zunichte gemacht.

Sorry .. das ist ja ein gnu Linker und der linkt natürlich nicht dazu 
sondern dagegen ;)

: Bearbeitet durch User
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.