@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...
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:
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
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
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
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
> 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...
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?
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.
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).
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
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
OutputPinledPin(&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?"
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
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?
[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?
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).
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!
Torsten C. schrieb:> Es ist so still geworden hier!
Das muß nun nicht wirklich verwundern.
C++ auf kleinen Controllern ist und bleibt eine Schnapsidee.
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
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.
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!
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. :-(
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?
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.
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 ;-)
@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?
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...
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, ...)
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.
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.
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.
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!
> 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.
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?
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 :)
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.
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?
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
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!
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(
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.
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
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
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
besser als die vielen "#define"^^:
Falls man "ins Uferlose" will, hier eine ToDo-Liste ;-)
http://mikrocontroller.bplaced.net/wordpress/?page_id=744Hans-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:
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
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.
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
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.
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.
Meiner Meinung nach ein gutes und konkretes Beispiel für den Nutzen von
Templates auf dem uC.
Festkommazahlen mit C++
Beitrag "Festkommazahlen mit C++"
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?
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.
;)
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.
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.
> 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.
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?
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.
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.
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.
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!
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
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.
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 ...
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 ...
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.
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#228797http://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?
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
> 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
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
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<classregs,PINpin>
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.
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.,..
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
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!
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
};
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.
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.
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. ;-)
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!
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?
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 …
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...
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/
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!
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"
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.
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)
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
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.
@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
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!
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?
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
Containerbag=newSuitcase(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.
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?
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.
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.
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!
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?
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
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
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.
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 ;-)
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
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 ?
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.
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
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.
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 ...
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.
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/
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.
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.
>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.
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
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
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++
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.
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ß.
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.
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.
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 ;-)
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 ...
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.
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.
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_environmentHans-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=59453jan 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:
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.
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?
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.
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.
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.
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?"
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.
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?
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.
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.
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".
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?
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.
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 ;-(
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 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.
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
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)".
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.
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!
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
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.
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.
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
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
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.
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?
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.
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.
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 ;)
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!
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
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 ;-)
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.
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.
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
virtualvoidset()=0;
6
virtualvoidreset()=0;
7
virtualboolread()=0;
8
}
9
10
class
11
GpioA0:publicAbstractGpio
12
{
13
public:
14
GpioA0(...){...}
15
16
voidset(){GPIOA->BSRRL=(1<<0);}
17
voidreset(){GPIOA->BSRRH=(1<<0);}
18
boolread(){returnGPIOA->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.
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
@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
MyObjectobj1(ParameterdesCTor);
… 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.
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.
> 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.
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.
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.
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.
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. :-)
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
voidrun()
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
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).
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.
@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.htmlTorsten 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
constuint8_tnum;
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?
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.
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.
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
constuint8_tnum;
> 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.
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
volatileuint8_t*ddr;
2
volatileuint8_t*port;
3
volatileuint8_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*:
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 ;)
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
classPin{
2
public:
3
volatileuint8_t*ddr;
4
volatileuint8_t*port;
5
volatileuint8_t*pin;
6
uint8_tnum;
7
};
Also kann auch mal jemand schreiben, dass sich das während der Laufzeit
ändert:
1
Pinichbinmaldiesmaldas(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
constchar*myPtr=&char_A;// pointer to a constant character. You cannot use this pointer to change the value being pointed to
2
char*constmyPtr=&char_A;// constant pointer to a character. The location stored in the pointer cannot change
3
constchar*constmyPtr=&char_A;// pointer to a character where both the pointer value and the value being pointed at will not change.
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.
- ...
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.
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?
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^^
Torsten C. schrieb:> Also kann auch mal jemand schreiben, dass sich das während der Laufzeit> ändert:>
1
Pinichbinmaldiesmaldas(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 ;)